aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Garrelou <simon.garrelou@gmail.com>2021-01-01 18:56:53 +0100
committerSimon Garrelou <simon.garrelou@gmail.com>2021-01-01 18:56:53 +0100
commit32d0425ff0594d93d1ef744003556f9355114c1d (patch)
treed809094586937109f42b117a5f19317d2625020b
downloadkindle-doom-0.1.tar.gz
kindle-doom-0.1.zip
First commitv0.1
-rw-r--r--.gitignore5
-rw-r--r--AUTHORS163
-rw-r--r--COPYING367
-rw-r--r--Makefile22
-rw-r--r--NEWS566
-rw-r--r--README.md53
-rw-r--r--README.old252
-rw-r--r--TODO1495
-rw-r--r--config.h209
-rw-r--r--data/Makefile.am12
-rw-r--r--data/Makefile.in362
-rw-r--r--data/prboom.txt207
-rw-r--r--data/prboom.wadbin0 -> 281020 bytes
-rw-r--r--extensions/prboom/config.xml12
-rw-r--r--extensions/prboom/menu.json15
-rw-r--r--extensions/prboom/run.sh7
-rw-r--r--src/KINDLE/i_joy.c68
-rw-r--r--src/KINDLE/i_main.c409
-rw-r--r--src/KINDLE/i_network.c292
-rw-r--r--src/KINDLE/i_sound.c534
-rw-r--r--src/KINDLE/i_sshot.c60
-rw-r--r--src/KINDLE/i_system.c460
-rw-r--r--src/KINDLE/i_video.c529
-rw-r--r--src/Makefile.am72
-rw-r--r--src/Makefile.in736
-rw-r--r--src/am_map.c1585
-rw-r--r--src/am_map.h111
-rw-r--r--src/d_client.c539
-rw-r--r--src/d_deh.c3090
-rw-r--r--src/d_deh.h1118
-rw-r--r--src/d_englsh.h707
-rw-r--r--src/d_event.h125
-rw-r--r--src/d_items.c140
-rw-r--r--src/d_items.h59
-rw-r--r--src/d_main.c1725
-rw-r--r--src/d_main.h82
-rw-r--r--src/d_net.h214
-rw-r--r--src/d_player.h234
-rw-r--r--src/d_think.h94
-rw-r--r--src/d_ticcmd.h59
-rw-r--r--src/doomdata.h204
-rw-r--r--src/doomdef.c48
-rw-r--r--src/doomdef.h330
-rw-r--r--src/doomstat.c108
-rw-r--r--src/doomstat.h332
-rw-r--r--src/doomtype.h128
-rw-r--r--src/dstrings.c85
-rw-r--r--src/dstrings.h80
-rw-r--r--src/f_finale.c668
-rw-r--r--src/f_finale.h56
-rw-r--r--src/f_wipe.c202
-rw-r--r--src/f_wipe.h45
-rw-r--r--src/g_game.c2970
-rw-r--r--src/g_game.h178
-rw-r--r--src/hu_lib.c767
-rw-r--r--src/hu_lib.h247
-rw-r--r--src/hu_stuff.c1593
-rw-r--r--src/hu_stuff.h90
-rw-r--r--src/i_joy.h47
-rw-r--r--src/i_main.h44
-rw-r--r--src/i_network.h74
-rw-r--r--src/i_sound.h120
-rw-r--r--src/i_system.h77
-rw-r--r--src/i_video.h82
-rw-r--r--src/info.c4899
-rw-r--r--src/info.h1498
-rw-r--r--src/lprintf.c382
-rw-r--r--src/lprintf.h68
-rw-r--r--src/m_argv.c58
-rw-r--r--src/m_argv.h47
-rw-r--r--src/m_bbox.c58
-rw-r--r--src/m_bbox.h56
-rw-r--r--src/m_cheat.c744
-rw-r--r--src/m_cheat.h58
-rw-r--r--src/m_fixed.h101
-rw-r--r--src/m_menu.c5559
-rw-r--r--src/m_menu.h182
-rw-r--r--src/m_misc.c1081
-rw-r--r--src/m_misc.h111
-rw-r--r--src/m_random.c147
-rw-r--r--src/m_random.h154
-rw-r--r--src/m_swap.h134
-rw-r--r--src/md5.c240
-rw-r--r--src/md5.h47
-rw-r--r--src/mmus2mid.c866
-rw-r--r--src/mmus2mid.h76
-rw-r--r--src/p_ceilng.c467
-rw-r--r--src/p_checksum.c100
-rw-r--r--src/p_checksum.h4
-rw-r--r--src/p_doors.c711
-rw-r--r--src/p_enemy.c2601
-rw-r--r--src/p_enemy.h118
-rw-r--r--src/p_floor.c1042
-rw-r--r--src/p_genlin.c1164
-rw-r--r--src/p_inter.c913
-rw-r--r--src/p_inter.h75
-rw-r--r--src/p_lights.c443
-rw-r--r--src/p_map.c2335
-rw-r--r--src/p_map.h92
-rw-r--r--src/p_maputl.c683
-rw-r--r--src/p_maputl.h89
-rw-r--r--src/p_mobj.c1526
-rw-r--r--src/p_mobj.h403
-rw-r--r--src/p_plats.c437
-rw-r--r--src/p_pspr.c829
-rw-r--r--src/p_pspr.h119
-rw-r--r--src/p_saveg.c1029
-rw-r--r--src/p_saveg.h66
-rw-r--r--src/p_setup.c1688
-rw-r--r--src/p_setup.h57
-rw-r--r--src/p_sight.c338
-rw-r--r--src/p_spec.c3353
-rw-r--r--src/p_spec.h1141
-rw-r--r--src/p_switch.c1150
-rw-r--r--src/p_telept.c345
-rw-r--r--src/p_tick.c291
-rw-r--r--src/p_tick.h75
-rw-r--r--src/p_user.c452
-rw-r--r--src/p_user.h47
-rw-r--r--src/protocol.h96
-rw-r--r--src/r_bsp.c664
-rw-r--r--src/r_bsp.h64
-rw-r--r--src/r_data.c745
-rw-r--r--src/r_data.h109
-rw-r--r--src/r_defs.h428
-rw-r--r--src/r_demo.c88
-rw-r--r--src/r_demo.h45
-rw-r--r--src/r_draw.c1128
-rw-r--r--src/r_draw.h163
-rw-r--r--src/r_drawcolpipeline.inl51
-rw-r--r--src/r_drawcolumn.inl378
-rw-r--r--src/r_drawflush.inl300
-rw-r--r--src/r_drawspan.inl160
-rw-r--r--src/r_filter.c119
-rw-r--r--src/r_filter.h174
-rw-r--r--src/r_fps.c450
-rw-r--r--src/r_fps.h76
-rw-r--r--src/r_main.c649
-rw-r--r--src/r_main.h120
-rw-r--r--src/r_patch.c786
-rw-r--r--src/r_patch.h111
-rw-r--r--src/r_plane.c468
-rw-r--r--src/r_plane.h67
-rw-r--r--src/r_segs.c854
-rw-r--r--src/r_segs.h44
-rw-r--r--src/r_sky.c56
-rw-r--r--src/r_sky.h55
-rw-r--r--src/r_state.h116
-rw-r--r--src/r_things.c1077
-rw-r--r--src/r_things.h72
-rw-r--r--src/s_sound.c688
-rw-r--r--src/s_sound.h100
-rw-r--r--src/sounds.c245
-rw-r--r--src/sounds.h305
-rw-r--r--src/st_lib.c374
-rw-r--r--src/st_lib.h209
-rw-r--r--src/st_stuff.c1160
-rw-r--r--src/st_stuff.h102
-rw-r--r--src/tables.c128
-rw-r--r--src/tables.h93
-rw-r--r--src/v_video.c1037
-rw-r--r--src/v_video.h207
-rw-r--r--src/version.c38
-rw-r--r--src/version.h40
-rw-r--r--src/w_mmap.c333
-rw-r--r--src/w_wad.c476
-rw-r--r--src/w_wad.h146
-rw-r--r--src/wi_stuff.c1968
-rw-r--r--src/wi_stuff.h64
-rw-r--r--src/z_bmalloc.c123
-rw-r--r--src/z_bmalloc.h52
-rw-r--r--src/z_zone.c705
-rw-r--r--src/z_zone.h129
173 files changed, 84548 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7d4d312
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
1Doom.wad
2*.o
3/prboom
4/extensions/prboom/prboom
5*.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 @@
1This file is now the amalgamated list of authors, contributors and credits
2for PrBoom. Hopefully by keeping these all in one place, they will remain
3more accurate.
4
5Doom was originally written by id software; when playing with any id main
6wad file, you can see their list of credits, which includes the list of
7programmers. After some years, they released the source code, to allow
8others to work on improving the game.
9
10One of the first projects was DosDoom, by Chi Hoang. This was a quick port
11of the released source code, which was for Linux, to DOS. This was then
12picked up by TeamTNT (http://www.teamtnt.com/), who produced Boom, a greatly
13debugged and extended version of Doom. The Boom programmers were Lee
14Killough, Jim Flynn, Rand Phares, Ty Halderman.
15
16Several projects started working from the Boom source code. One was PrBoom,
17made by Florian Schulze, that ported the code to Windows, added suport for
18higher resolutions and later OpenGL. Another was Marine's Best Friend
19(known as MBF) by Lee Killough, which fixed a lot of Boom bugs and added
20many new game features. Finally, there was LxDoom, a port of Boom to Linux
21by Colin Phipps.
22
23In October 1999, id Software re-released the Doom source code under the
24GNU General Public License. TeamTNT have also changed to the new license,
25and the other sources mentioned above have all allowed their code to be
26GPLed. So PrBoom is covered by the GPL.
27
28In May 2000, LxDoom, PrBoom, and a derived port called LSDLDoom, merged into
29one. The current authors of PrBoom are:
30
31Florian Schulze <florian.schulze@gmx.net>
32Colin Phipps <cph@moria.org.uk>
33Neil Stevens <neil@hakubi.us> - Mac OS X porting
34Andrey Budko <andrey.budko@gmail.com>
35Rob Young (RjY) <rjy@users.sourceforge.net>
36
37Our thanks go to all the authors of the ports mentioned above, and also the
38following people who contributed code to LxDoom or PrBoom:
39
40Jess Haas <JessH@lbjhs.net>
41Of LSDLdoom, who merged his project into PrBoom, contributing his SDL code.
42
43Nicolas Kalkhof <nkalkhof@gmx.net>
44Much work on the OpenGL renderer.
45
46James "Quasar" Haley <haleyjd@concentric.net>
47Ever willing to talk about source ideas, and has pointed me in the direction of
48a lot of Boom and MBF bugs; also various bits code from his port Eternity have
49been used, such as the BEX enhancements.
50
51Bob Aman (sporkmonger.com)
52Created the RMUDAnsiTextView class used in the Mac launcher.
53
54Gady Kozma gady@math.tau.ac.il
55Added hires to the SVGALib version of LxDoom, and other useful patches.
56
57Dick Leban
58Lots of feedback about portability issues and helping get the network code
59working properly back at v1.3.6.
60
61Eduardo Casino Almao
62Lots of helpful feedback and suggestions, but more importantly actually getting
63to grips with the code and giving very precise bug reports and patches.
64
65Joey Hess
66For numerous patches, like the glibc fixes and window manager updates, and
67help with the music.
68
69Ben Winslow
70Various useful patches, like the colour ENDOOM code.
71
72Josh Parsons josh@schlick.anu.edu.au
73Sent me the patches to use autoconf for configuring LxDoom.
74
75Steve Van Devender <stevev@efn.org>
76Found the bug causing slight noise at the start of sounds playing, and other
77patches.
78
79Barry Mead <bmead15@cox.net>
80Improvements to the mouse code and other odd patches.
81
82Mattias Kunkel <mattias@kunkel.freeservers.com>
83Made the lxdoom.spec file for creating LxDoom RPMs.
84
85Vicente Aguilar vicente@hal.dhis.org
86Handy patch for the file handling
87
88Benjamin L McGee <vuelto@netscape.net>
89Patch fixing the joystick code.
90
91Chris Young <young1@users.sourceforge.net>
92Patch improving the ENDOOM printing
93
94Peter Jay Salzman <p@belial.ucdavis.edu>
95Cleanup patches
96
97Oliver Kraus
98Send bug reports and patches for Solaris/Sparc.
99
100Paul S Jenner <psj@firstlinux.net>
101Nice patch to make RPM building easier
102
103Julian <julian@jplan.cjb.net>
104Fixed inline asm for gcc-2.95 (from Eternity)
105
106Lionel Ulmer <lionel.ulmer@free.fr>
107Patch to fix alignment problems on ARM processors.
108
109Ville Vuorinen <vv@ydin.org>
110Spotted and helped patch the player spawn bug, as well as helping with some
111Win32 issues.
112
113Steven Elliot <selliot4@users.sourceforge.net>
114Misc patches.
115
116Andreas Dehmel <zarquon@t-online.de>
117Spotted & patched a savegame bug.
118
119Jon Dowland
120Bug reports & fixes, documentation improvements.
121
122If you have sent in patches and I forgot to list you, I apologise. Please email
123me and I will add you.
124
125Also, thanks to the following people who have helped in various ways:
126
127Simon "fraggle" Howard <fraggle@alkali.org>
128More MBF bugs.
129
130Robert Phipps <rob@phipps.uklinux.net>
131Network game testing, feature suggestions etc.
132
133Udo Monk
134His port xdoom is very portable, and I referred to his code sometimes for help
135with the X stuff; also his collection of Doom tools (XWadTools) is the
136definitive tools collection for Linux.
137
138Andre Majorel <amajorel@teaser.fr>
139For Yadex, so I can debug those problematic levels more easily.
140
141Michael Heasley
142Author of musserver, which helped me first add music support.
143
144Rafael Reilova
145Helped with the music server program for LxDoom
146
147Frederic Oghdayan
148For useful feedback on LxDoom v1.0.1, and repeating his bug reports until I
149believed them :-).
150
151Adam Hegyi <ha211@hszk.bme.hu>
152Prompted me to hunt down those last few demo sync bugs, and provided some useful
153insights and example demos to help.
154
155Adam Williamson
156Pointing me toward yet another compatibility bug.
157
158Ingo van Lil
159Another bug spotter.
160
161Everyone who contributed indirectly to MBF and Boom and Doom; see the
162respective documentation files.
163
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f698bce
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,367 @@
1GNU GENERAL PUBLIC LICENSE
2Version 2, June 1991
3
4Copyright (C) 1989, 1991 Free Software Foundation, Inc.
559 Temple Place - Suite 330, Boston, MA 02111-1307, USA
6
7Everyone is permitted to copy and distribute verbatim copies
8of this license document, but changing it is not allowed.
9
10Preamble
11The licenses for most software are designed to take away your freedom
12to share and change it. By contrast, the GNU General Public License
13is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit
17to using it. (Some other Free Software Foundation software is covered
18by the GNU Library General Public License instead.) You can apply it
19to your programs, too.
20
21When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge
24for this service if you wish), that you receive source code or can
25get it if you want it, that you can change the software or use pieces
26of it in new free programs; and that you know you can do these
27things.
28
29To protect your rights, we need to make restrictions that forbid
30anyone to deny you these rights or to ask you to surrender the
31rights. These restrictions translate to certain responsibilities for
32you if you distribute copies of the software, or if you modify it.
33
34For example, if you distribute copies of such a program, whether
35gratis or for a fee, you must give the recipients all the rights that
36you have. You must make sure that they, too, receive or can get the
37source code. And you must show them these terms so they know their
38rights.
39
40We protect your rights with two steps: (1) copyright the software,
41and (2) offer you this license which gives you legal permission to
42copy, distribute and/or modify the software.
43
44Also, for each author's protection and ours, we want to make certain
45that everyone understands that there is no warranty for this free
46software. If the software is modified by someone else and passed on,
47we want its recipients to know that what they have is not the
48original, so that any problems introduced by others will not reflect
49on the original authors' reputations.
50
51Finally, any free program is threatened constantly by software
52patents. We wish to avoid the danger that redistributors of a free
53program will individually obtain patent licenses, in effect making
54the program proprietary. To prevent this, we have made it clear that
55any patent must be licensed for everyone's free use or not licensed
56at all.
57
58The precise terms and conditions for copying, distribution and
59modification follow.
60
61TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
620. This License applies to any program or other work which contains a
63notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the
75Program is covered only if its contents constitute a work based on
76the Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
791. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any
84warranty; and give any other recipients of the Program a copy of this
85License along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a
89fee.
90
912. You may modify your copy or copies of the Program or any portion
92of it, thus forming a work based on the Program, and copy and
93distribute such modifications or work under the terms of Section 1
94above, provided that you also meet all of these conditions:
95
96
97a) You must cause the modified files to carry prominent notices
98stating that you changed the files and the date of any change.
99
100b) You must cause any work that you distribute or publish, that in
101whole or in part contains or is derived from the Program or any part
102thereof, to be licensed as a whole at no charge to all third parties
103under the terms of this License.
104
105c) If the modified program normally reads commands interactively when
106run, you must cause it, when started running for such interactive use
107in the most ordinary way, to print or display an announcement
108including an appropriate copyright notice and a notice that there is
109no warranty (or else, saying that you provide a warranty) and that
110users may redistribute the program under these conditions, and
111telling the user how to view a copy of this License. (Exception: if
112the Program itself is interactive but does not normally print such an
113announcement, your work based on the Program is not required to print
114an announcement.)
115These requirements apply to the modified work as a whole. If
116identifiable sections of that work are not derived from the Program,
117and can be reasonably considered independent and separate works in
118themselves, then this License, and its terms, do not apply to those
119sections when you distribute them as separate works. But when you
120distribute the same sections as part of a whole which is a work based
121on the Program, the distribution of the whole must be on the terms of
122this License, whose permissions for other licensees extend to the
123entire whole, and thus to each and every part regardless of who wrote
124it.
125Thus, it is not the intent of this section to claim rights or contest
126your rights to work written entirely by you; rather, the intent is to
127exercise the right to control the distribution of derivative or
128collective works based on the Program.
129
130In addition, mere aggregation of another work not based on the
131Program with the Program (or with a work based on the Program) on a
132volume of a storage or distribution medium does not bring the other
133work under the scope of this License.
134
1353. You may copy and distribute the Program (or a work based on it,
136under Section 2) in object code or executable form under the terms of
137Sections 1 and 2 above provided that you also do one of the
138following:
139
140a) Accompany it with the complete corresponding machine-readable
141source code, which must be distributed under the terms of Sections 1
142and 2 above on a medium customarily used for software interchange;
143or,
144
145b) Accompany it with a written offer, valid for at least three years,
146to give any third party, for a charge no more than your cost of
147physically performing source distribution, a complete
148machine-readable copy of the corresponding source code, to be
149distributed under the terms of Sections 1 and 2 above on a medium
150customarily used for software interchange; or,
151
152c) Accompany it with the information you received as to the offer to
153distribute corresponding source code. (This alternative is allowed
154only for noncommercial distribution and only if you received the
155program in object code or executable form with such an offer, in
156accord with Subsection b above.)
157The source code for a work means the preferred form of the work for
158making modifications to it. For an executable work, complete source
159code means all the source code for all modules it contains, plus any
160associated interface definition files, plus the scripts used to
161control compilation and installation of the executable. However, as a
162special exception, the source code distributed need not include
163anything that is normally distributed (in either source or binary
164form) with the major components (compiler, kernel, and so on) of the
165operating system on which the executable runs, unless that component
166itself accompanies the executable.
167If distribution of executable or object code is made by offering
168access to copy from a designated place, then offering equivalent
169access to copy the source code from the same place counts as
170distribution of the source code, even though third parties are not
171compelled to copy the source along with the object code.
172
1734. You may not copy, modify, sublicense, or distribute the Program
174except as expressly provided under this License. Any attempt
175otherwise to copy, modify, sublicense or distribute the Program is
176void, and will automatically terminate your rights under this
177License. However, parties who have received copies, or rights, from
178you under this License will not have their licenses terminated so
179long as such parties remain in full compliance.
180
1815. You are not required to accept this License, since you have not
182signed it. However, nothing else grants you permission to modify or
183distribute the Program or its derivative works. These actions are
184prohibited by law if you do not accept this License. Therefore, by
185modifying or distributing the Program (or any work based on the
186Program), you indicate your acceptance of this License to do so, and
187all its terms and conditions for copying, distributing or modifying
188the Program or works based on it.
189
1906. Each time you redistribute the Program (or any work based on the
191Program), the recipient automatically receives a license from the
192original licensor to copy, distribute or modify the Program subject
193to these terms and conditions. You may not impose any further
194restrictions on the recipients' exercise of the rights granted
195herein. You are not responsible for enforcing compliance by third
196parties to this License.
197
1987. If, as a consequence of a court judgment or allegation of patent
199infringement or for any other reason (not limited to patent issues),
200conditions are imposed on you (whether by court order, agreement or
201otherwise) that contradict the conditions of this License, they do
202not excuse you from the conditions of this License. If you cannot
203distribute so as to satisfy simultaneously your obligations under
204this License and any other pertinent obligations, then as a
205consequence you may not distribute the Program at all. For example,
206if a patent license would not permit royalty-free redistribution of
207the Program by all those who receive copies directly or indirectly
208through you, then the only way you could satisfy both it and this
209License would be to refrain entirely from distribution of the
210Program.
211
212If any portion of this section is held invalid or unenforceable under
213any particular circumstance, the balance of the section is intended
214to apply and the section as a whole is intended to apply in other
215circumstances.
216
217It is not the purpose of this section to induce you to infringe any
218patents or other property right claims or to contest validity of any
219such claims; this section has the sole purpose of protecting the
220integrity of the free software distribution system, which is
221implemented by public license practices. Many people have made
222generous contributions to the wide range of software distributed
223through that system in reliance on consistent application of that
224system; it is up to the author/donor to decide if he or she is
225willing to distribute software through any other system and a
226licensee cannot impose that choice.
227
228This section is intended to make thoroughly clear what is believed to
229be a consequence of the rest of this License.
230
2318. If the distribution and/or use of the Program is restricted in
232certain countries either by patents or by copyrighted interfaces, the
233original copyright holder who places the Program under this License
234may add an explicit geographical distribution limitation excluding
235those countries, so that distribution is permitted only in or among
236countries not thus excluded. In such case, this License incorporates
237the limitation as if written in the body of this License.
238
2399. The Free Software Foundation may publish revised and/or new
240versions of the General Public License from time to time. Such new
241versions will be similar in spirit to the present version, but may
242differ in detail to address new problems or concerns.
243
244Each version is given a distinguishing version number. If the Program
245specifies a version number of this License which applies to it and
246"any later version", you have the option of following the terms and
247conditions either of that version or of any later version published
248by the Free Software Foundation. If the Program does not specify a
249version number of this License, you may choose any version ever
250published by the Free Software Foundation.
251
25210. If you wish to incorporate parts of the Program into other free
253programs whose distribution conditions are different, write to the
254author to ask for permission. For software which is copyrighted by
255the Free Software Foundation, write to the Free Software Foundation;
256we sometimes make exceptions for this. Our decision will be guided by
257the two goals of preserving the free status of all derivatives of our
258free software and of promoting the sharing and reuse of software
259generally.
260
261NO WARRANTY
262
26311. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
264WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
265EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
266OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
267KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
268IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
269PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
270PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
271THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
272
27312. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
274WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
275AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
276FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
277CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
278PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
279RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
280FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
281SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
282SUCH DAMAGES.
283
284
285END OF TERMS AND CONDITIONS
286How to Apply These Terms to Your New Programs
287If you develop a new program, and you want it to be of the greatest
288possible use to the public, the best way to achieve this is to make
289it free software which everyone can redistribute and change under
290these terms.
291
292To do so, attach the following notices to the program. It is safest
293to attach them to the start of each source file to most effectively
294convey the exclusion of warranty; and each file should have at least
295the "copyright" line and a pointer to where the full notice is found.
296
297one line to give the program's name and an idea of what it does.
298Copyright (C) yyyy name of author
299
300This program is free software; you can redistribute it and/or
301modify it under the terms of the GNU General Public License
302as published by the Free Software Foundation; either version 2
303of the License, or (at your option) any later version.
304
305This program is distributed in the hope that it will be useful,
306but WITHOUT ANY WARRANTY; without even the implied warranty of
307MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
308GNU General Public License for more details.
309
310You should have received a copy of the GNU General Public License
311along with this program; if not, write to the Free Software
312Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31302111-1307, USA.
314
315Also add information on how to contact you by electronic and paper
316mail.
317
318If the program is interactive, make it output a short notice like
319this when it starts in an interactive mode:
320
321Gnomovision version 69, Copyright (C) yyyy name of author
322Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
323type `show w'. This is free software, and you are welcome
324to redistribute it under certain conditions; type `show c'
325for details.
326
327The hypothetical commands `show w' and `show c' should show the
328appropriate parts of the General Public License. Of course, the
329commands you use may be called something other than `show w' and
330`show c'; they could even be mouse-clicks or menu items--whatever
331suits your program.
332
333You should also get your employer (if you work as a programmer) or
334your school, if any, to sign a "copyright disclaimer" for the
335program, if necessary. Here is a sample; alter the names:
336
337Yoyodyne, Inc., hereby disclaims all copyright
338interest in the program `Gnomovision'
339(which makes passes at compilers) written
340by James Hacker.
341
342signature of Ty Coon, 1 April 1989
343Ty Coon, President of Vice
344
345This General Public License does not permit incorporating your
346program into proprietary programs. If your program is a subroutine
347library, you may consider it more useful to permit linking
348proprietary applications with the library. If this is what you want
349to do, use the GNU Library General Public License instead of this
350License.
351
352
353----------------------------------------------------------------------
354----------
355Return to GNU's home page.
356FSF & GNU inquiries & questions to gnu@gnu.org. Other ways to contact
357the FSF.
358
359Comments on these web pages to webmasters@www.gnu.org, send other
360questions to gnu@gnu.org.
361
362Copyright notice above.
363Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
364MA 02111, USA
365
366Updated: 16 Feb 1998 tower
367
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2c5450d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,22 @@
1INCLUDE=-Isrc/ -Isrc/KINDLE -I.
2
3CFLAGS=$(INCLUDE) -D_GNU_SOURCE -DHAVE_CONFIG_H -DDISABLE_DOUBLEBUFFER
4
5C_FILES=$(wildcard src/*.c) $(wildcard src/KINDLE/*.c)
6OBJ_FILES=$(patsubst %.c,%.o,$(C_FILES))
7
8all: prboom
9
10src/%.o: src/%.c
11 $(CC) -c $(CFLAGS) $< -o $@
12
13prboom: $(OBJ_FILES) Makefile
14 $(CC) -static $(CFLAGS) -o prboom $(OBJ_FILES)
15
16extension: prboom
17 mv $< extensions/prboom/$<
18 zip -r PrBoom_KUAL.zip extensions
19
20clean:
21 rm -rf $(OBJ_FILES)
22 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 @@
1This file shows a history of changes between PrBoom versions since v2.1.0.
2For historical reference, the complete LxDoom changelog follows it.
3
4Changes from v2.4.7 to v2.5.0
5- Limit the game to one CPU core on a multicore machine [prb+]
6- Fix crash when out-of-range values are used in fixed point arithmetic [prb+]
7- Allow the game to build without SDL_mixer, add --without-mixer option to
8 ./configure to force this. Music support will be disabled in this case
9- Don't set the default game skill from the new game menu
10 Instead there is an option to set it explicitly in the General menu
11- Fix the brightness of the player's weapon
12- Fix linear filtering on flats in software mode
13- Fix crash when an unknown sprite is used with a non-zero frame number
14- Restore special case for trivial maps (bug #1837422)
15- Fix screenshots in high colour screen modes - if libpng is available at
16 build time it will be used, otherwise a BMP will be saved
17- Don't process mouse input in the menus [prb+]
18- Always use Doom's main menu order to avoid bugs with Alien Vendetta [prb+]
19- Remove line of junk graphics below status bar [prb+]
20- Restore Boom friction and bobbing code [prb+]
21- Fix crash by testing for null targets in mancubus fire code pointers
22- Restore last known enemy check in Boom compatibility [prb+]
23- Animated middle textures with zero index forced [prb+]
24- Better handling of unrecognised demo formats [prb+]
25- Fix for hanging decoration disappearing in Batman Doom MAP02 [prb+]
26- Fix menu description: pain elementals are limited to 21 lost souls
27- Manual page fixes from Debian
28- Fix position of netgame player arrows on the automap in rotate mode
29- Ignore chat key presses in multiplayer demo playback and -solo-net
30- In deathmatch demo playback always draw player arrows on the automap
31- In a multiplayer demo, don't reset view to console player on a new map
32- Fix crash when MP3 music is being used and the player changes back to
33 a piece of music that's already been loaded before
34- Avoid HOM effect on large maps such as epic.wad 5 [prb+]
35- Fix sound origins on large levels [prb+]
36- Handle demos with bad or missing headers [prb+]
37- Fix the colour of player 4 (red) in multiplayer
38- Play correct player pickup sounds in multiplayer demos
39- Don't allow solids to pass through no-clipping objects in Doom [prb+]
40- Restore Dehacked's ability to set the raisestate of a mobj [prb+]
41- Handle demos with a missing end marker [prb+]
42- Ignore switches that reference unknown textures instead of exiting
43- Fix crash when resetting a menu to defaults [prb+]
44- Fix crash when trying to play demos from Boom 2.00 [prb+]
45- Fix crash in multiplayer demos when there are still sounds playing
46 on map changes (e.g. players revving chainsaws) [prb+]
47- Fix mouse clicks on the intermission screen being ignored
48- Don't eat screenshot key presses (see sf bug #1843280)
49- Detect Hexen-format maps and refuse to play them, instead of crashing
50- Fix crash when loading maps with missing player starts
51- The backs of switches must be pressable in any demo recorded by
52 Boom 2.01, even those in Boom's "compatibility" mode [prb+]
53- Force comp_doorstuck=1 in Boom 2.01 compatibility mode [prb+]
54- comp_dropoff=1 was broken in MBF compatibility mode [prb+]
55- Restore --disable-dogs but make sure it doesn't break Dehacked
56- Fix desync if the user presses pause on the intermission screen [prb+]
57- comp_666 fixed: either cyberdemon or spider can end E2M8 or E3M8;
58 killing a baron on E3M8 won't cause the level to end any more [prb+]
59- Fix broken string matching in Dehacked [prb+]
60- Passing --without-net to ./configure will compile the game without
61 network support; this may help if your platform lacks SDL_net
62- Fix crash when reloading network savegames (bug #1590350)
63- Fix bug in transparency rendering caused by doing it in two places
64- Added high color rendering
65
66Changes from v2.4.6 to v2.4.7
67- Fixed comp_soul and comp_maskedanim options not actually being optional.
68- Fixed searching for IWAD/prboom.wad (bugs #1585185, #1585600)
69- Multiple sound crash fixes (bugs #1577495, #1586800)
70- Fix for previously introduced HOM error
71- Fix frame numbering problem in MBF dehacked patches (bug #1576151)
72
73Changes from v2.4.5 to v2.4.6
74- Mac OS X: Fixed music volume slider
75- Implemented patch clipping. This fixes bug #1557501.
76- Fixed update of compatibility options after use of TNTCOMP cheat
77- Reenabled padding if short or missing reject lumps.
78 Patch #1570517 by RjY.
79- Removed unaligned memory access in r_drawflush.inl. This should fix bus
80 errors on architectures where unaligned access is forbidden and should
81 give a slight speedup on other architectures.
82- Stop right after the quit sound stops, instead of waiting three seconds
83- Fixed sound origin for switches. This is compatibility optioned.
84 Patch #1533045 by RjY.
85- Fixed "oof" sound when hitting ground while already dead
86 Patch #1532700 by RjY.
87- Ported Eternitys fix to show the "ouch" face when severly hit
88- Unified drawing functions, this speeds things up a bit and fixes most
89 artifacts on small numbers and fonts in high resolution modes.
90- Mac OS X: Add resolution and video mode (OpenGL vs software) selection to
91 launcher
92- Added rendering filters for software mode, they are configurable in a new
93 page in general settings
94- Emulate some texture composition bugs
95- Fix more common WAD bugs that can cause crashes
96- Fixed random crashes caused by use of uninitialized memory
97- Fix some demo incompatibilities caused by slime trail removal
98- Fixed crashes with WADs which use newer gl nodes or don't have any nodes
99- Automatically load gwa files with gl nodes
100- Fixed integer overrun in automap on large levels (from PrBoom+)
101
102Changes from v2.4.4 to v2.4.5
103- fix crash when saving the game in levels with lots of monsters
104 (bug introduced in 2.4.4)
105- -nodeh option to disable automatic loading of dehacked-in-wad lump
106- Unified software and opengl engine into one binary
107- Added video mode selection to menu
108- fix demo desyncs on E1M5 on x86_64 systems
109- Fullscreen setting will only take effect after game restart
110- reduce red palette translation if the menu is up, so the menu can still be read
111- screenshots now in PNG format on Linux/Unix in GL mode too
112- Added experimental -checksum option for demo playback comparison
113- Merged new internal patch (graphics) format from PrBoom 2.3
114- Mac OS X: Launcher now uses drawers instead of tabs
115- Mac OS X: Fix some longstanding Wad chooser issues
116- Mac OS X: Add a console to display text output from PrBoom
117
118Changes from v2.4.3 to v2.4.4
119- Don't fail when a texture name can't be looked up
120- Increased several limits - Thanks to entryway and RjY
121 - Increased number of sidedef limit to 65534
122 - Increased number of vertexes limit to 65535
123 - Fixed crash when crossing sectors with very big height differences
124- fix crash on E4M8
125- New command-line options for setting a window (-window) or fullscreen
126 (-nowindow) mode temporarily.
127- The maximal supported resolution is increased from 1600x1200 to 2048x1536
128- GLBoom will use the closest supported resolution when running fullscreen
129- The "RUN" key inverts the autorun state
130- Live monsters are highlighted in a different colour on the iddt-automap
131- Fixed OpenGL sky rendering in Requiem and Memento Mori
132- The "Show coordinates of automap pointer" setting works now
133- merged many cleanups and fixes from PrBoom 2.3
134- fix translucency map file handle leak
135- fix consistency failures in netgames
136- prevent crashes at 800x600 caused by rounding errors with naive clipping
137- fixed slowdown at 1024x768 on some systems
138- ability to play tasdoom demos directly
139- -solo-net option is a shortcut for one-player network games
140- emulate spechit overflows for dosdoom and tasdoom compatibility
141- made several cleanups and fixes
142
143Changes from v2.4.2 to v2.4.3
144- Massive speed improvements in higher resolutions taken from Eternity.
145 Thanks to SoM and Quasar!!!
146- fix bugs in gameplay occurring with gcc-4.1
147- Mac OS X: Add "Show Game Folder" to menus, for easy installation of new
148 game wads
149- Mac OS X: Disable games in popup menu whose wads cannot be found
150- fix compilation warnings
151- tidy up configure script
152
153Changes from v2.4.1 to v2.4.2
154- Move gamma correction tables into prboom.wad
155- Clean up light level calculations for walls & sprites
156- CheckIWAD uses ANSI C streams for better portability and error handling
157- Make screen wipe time independent of resolution
158- Applied various small cleanups and fixes from PrBoom 2.3.1
159- Fix problems with dehacked substitution of long strings
160- End of level sound crash fixed
161- Mac OS X: Added simple launcher which allows to configure the most common
162 settings
163- Mac OS X: Uses Quicktime for music now to fix crashes (adapted from Jaakko
164 Keränen's work in Doomsday)
165- Windows: Converted project files to free Visual Studio 2005 Express Edition
166
167Changes from v2.4.0 to v2.4.1
168- PrBoom demos are now recorded with high-precision turning (like the
169 "Doom v1.91" hack that is floating around)
170- when both -nodraw and -nosound are supplied, then no graphics will be
171 initialized and no windows opened
172- add ultdoom compatibility level, and bring compatibility levels into line
173 with Prboom+
174- screenshots now use correct palette in software mode
175- screenshots now in PNG format on Linux/Unix where available
176- suppress use-supershotgun key in compatibility mode
177- removed obsolete video related code
178- fix screenshots on 64bit systems
179- fix comp_666
180
181Changes from v2.2.6 to v2.4.0
182- emulate reject overflows and spechit overflows - from prboom-plus
183- more original doom compatibility options
184- improve stretched graphics drawing for hires
185- fix super-shotgun reload on last shot
186- fix compilation with gcc 4.x
187- fix some more dehacked support problems (e.g. Hacx)
188- fix crash if pwad contains zero-length sound lumps
189- added possibility to use mmap for wad access, this leads to less memory usage
190- simplified the memory handling
191- removed old Doom v1.2 lumps from prboom.wad
192- windows also uses prboom.wad now
193- add Mac OS X bundle build
194- removed lumps and tables which are in prboom.wad from source
195
196Changes from v2.2.5 to v2.2.6
197- fix Inferno intermission screen crash
198- fix lockup for other netgame clients when one client quits
199- fix memory leak in netgame server
200- fix SDL_LockScreen crashes on Win32
201- fix fuzz drawing for hi-res
202- network games should survive temporary loss of connection
203- fix dehacked NOSECTOR/NOBLOCKMAP effects
204- fix player spawn sound
205
206Changes from v2.2.4 to v2.2.5
207- fix crash caused by long messages in HUD
208- live monster counter on HUD
209- notify server if client quits during startup wait
210- improved response file parser
211- fast forward to given map # in demo playback
212- fixes for various sound bugs
213- fix doom2 demos at levels with >10 deathmatch starts
214- and more compatibility and demo fixes
215- support higher-turning-resolution demos from v1.91
216- fix compilation with gcc 3.4.x
217
218Changes from v2.2.3 to v2.2.4
219- fixed sky-over-sky HOM
220- add sound compatibility option
221- improve sound volume accuracy
222- shared texture palette isn't the default anymore
223- better invulnerabilty rendering for non paletted OpenGL
224- network game server can now read config files to set game options
225- fix latency problems in LAN games
226- small compilation fixed for OpenGL on some unix platforms
227- fix for dehacked files which change frames
228- fixed name clash when compiling for some unix platforms
229- flag counted items with different colour on the IDDT automap
230- fixed extra shot sound when chaingun runs out of ammo
231- fix some telefragging related desyncs
232- fixed offsets for flipped sprites
233- hopefully fix problems with network games on big-endian platforms
234
235Changes from v2.2.2 to v2.2.3
236- improved mouse handling
237- intermission demo sync bug fixed
238- framebuffer update fixes (solves flicker on fbcon)
239- -forceoldbsp allowed in non-GL version, and saved in demos
240- fix player colours in multiplayer demos
241- apply workarounds for buggy pwads even during demo playback
242- fix numpad 5 key
243- allow compilation on systems where SDL is built without joystick support
244- fix comp_skymap
245- using anisotropic filtering when the OpenGL extension is available
246- using paletted textures when the OpenGL extension is available
247- added gl_use_paletted_texture option to glboom configuration file
248- using shared texture palette when the OpenGL extension is available
249- added gl_use_shared_texture_palette option to glboom configuration file
250
251Changes from v2.2.1 to v2.2.2
252- more demo sync problems for original Doom and Boom fixed
253- added changeable samplerate for soundmixing
254- added fullscreen/window toggle in option menu
255- added double buffering
256- floor rendering made more accurate
257- Win32 config file handling fixed
258- fix endian conversion problem on Linux/PPC
259
260Changes from v2.2.0 to v2.2.1
261- improved fix for demo sync problems with lost souls bouncing off floors
262- fixed bug where loading a -fast or -respawn savegame failed to restore
263 those options properly
264- fixed demo sync bug with doors also tagged to lift triggers
265- fix some endianness problems in the OpenGL renderer
266- hopefully fixed some problems compiling for Linux/ARM
267- fix multi-level demo time totals to agree with compet-n
268- linux rpm is now a bit more standardised
269
270Changes from v2.1.2 to v2.2.0
271- fix compiling problem on alpha processors (size_t != unsigned long)
272- fixed stair building (ex. TNT - Evilution MAP30)
273- fixed OpenGL menu drawing bug
274- hopefully fixed top sky line bug for some OpenGL drivers
275- added joystick support through SDL
276- made a (temporary) fix for the crash at 800x600 when timidity can't find cfg
277- fixed some key binding problems
278- fixed linking problems on some UNIX systems
279
280Changes from v2.1.1 to v2.1.2
281- fix problem with sound stereo
282- fix problem with new network games
283- supports demo files with base name >8 characters
284- enable IDDT and other display cheats in demo playback
285- various fixes for running on Solaris/sparc
286
287Changes from v2.1.0 to v2.1.1
288- config file is now prboom.cfg for the non-GL version, glboom.cfg
289 for the GL version. If you have used PrBoom (or LxDoom) before,
290 rename your old config file (boom.cfg) appropriately.
291- fullscreen is now default for new prboom.cfg
292- included sdl_mixer.dll now plays midi-files
293- if waveout is used for sound (Windows NT4) the sound doesn't stutter anymore
294- redid parts of the OpenGL renderer
295 - sprites behind translucent walls are rendered correctly
296 - translucent walls are rendered correctly
297 - support for glBSP nodes
298 - compliant to glBSP spec v2
299 - use_mipmapping option in boom.cfg
300 - the default for zone memory in OpenGL is now 16MB
301- fix screen melt transition
302- most Boom demos should now work
303- a lot more original Doom demos work
304- keycard switches are shown coloured on the map, like doors
305- improved ENDOOM rendering
306- non-highres rendering functions dropped
307
308-----------------------------------------------------------------------------
309This file is a log of all the changes to LxDoom since v1.0.0.
310Note that LxDoom v0.* was a seperate line of development.
311
312* Changes from v1.4.4 to the PrBoom merger
313- Fix rare demo sync problem (LxDoom v1.4.x bug, only noticed on Memento
314 Mori DEMO3)
315- Fix memory management bugs
316 - Memory wasted by bug in Z_FreeTags (original Doom bug)
317 - Store correct size in extra memory blocks (Boom/MBF bug, harmless
318 except when debugging)
319 - Fix level precaching
320 - Disabled by default, controlled by config file
321 - Fix needlessly locked lumps (bug since LxDoom v1.3.2)
322
323* Changes v1.4.3 to v1.4.4
324- Install documentation in the right directory
325- Sound code cleanup
326- Fix problem with network games often desyncing immediately at startup
327
328* Changes v1.4.2 to v1.4.3
329- Improved mouse resolution, thanks to a patch from Barry Mead
330- Various robustness fixed to the networking code
331- Fixed various build problems
332 - gcc 2.7.2 compile problems fixed
333 - uid_t problems on odd systems should be fixed
334
335* Changes v1.4.1 to v1.4.2
336- Fixed various build problems, including
337 - Networking not work on many systems
338 - Portability improvements, in particular for Sparc
339 - Autoconf getting confused on systems with X headers in the include path
340- Fix bug with music not looping after being unpaused
341- Misc minor improvements
342
343* Changes v1.4.0 to v1.4.1
344- Fixed occasional tutti fruiti on non-power-of-2 short textures
345- Fixed minor bug in the WAD autoloading code
346- Fixed the function keys in lsdoom, thanks to a patch from Chris Purnell
347- Fixed all compile warnings with the new gcc
348
349* Changes v1.3.7 to v1.4.0
350- License is now the GNU General Public License, see COPYING.
351- autoconf based setup makes compiling LxDoom simple on most systems;
352 automatically compiles only the versions and features your system
353 supports.
354- Fixed rendering bugs:
355 - tall vertical shafts did not block vision on the automap, and on x86
356 systems there could be crashes in the column rendering near such shafts (
357 bug from original Doom).
358 - fixed slowdown caused by non-power of 2 height textures in the case
359 where they don't tile (i.e. almost all cases) (this was the tutti-fruiti
360 "fix" from Boom, I've "fixed the fix" in a sense)
361 - fixed a slight slowdown caused by a bad optimisation (an old LxDoom bug)
362- Fixed bug where things were rendered brighter in high-res, depending on the
363 resolution (bug from PRBoom).
364- Improvements to the sound code:
365 - Fixed noise at the start of sounds playing (thanks to Steve Van Devender).
366 - LxDoom detects the music or sound server exiting (alright, so I mean
367 crashing ;-) and stops sending more data.
368- Performance improvements, including:
369 - New algorithm in P_GroupLines, saves seconds when loading big levels.
370- Fixed problems with the networking code, where multihomed machines could
371 get the wrong IP registered with the server.
372- Screen code improvements:
373 - Rewrote screen layout logic, fixing numerous bugs.
374 - Fixed bug with flipped patches in high-res that could cause crashes,
375 thanks to Gady Kozma.
376 - Independent x and y scaling of the status bar, by Gady Kozma.
377- Added warning messages whenever LxDoom auto-corrects errors in buggy
378 PWADs. Also made -devparm cause LxDoom to initialise all textures at
379 startup, so all texture errors are found at once.
380- Store config files and save games in ~/.lxdoom/ instead of the current
381 directory, removed the -cdrom parameter.
382- Fixed Doom bug where the "got a medikit you REALLY needed" message was
383 never used. Thanks to James "Quasar" Haley for pointing that one out.
384- Made the numeric keypad keys be treated differently from their normal
385 equivalents, so you can bind them to different actions.
386- Fixed bad importing of mobj pointer reference code from MBF.
387- The level completed screen is now shown after ExM8 levels in Doom 1/
388 Ultimate Doom.
389- Minor coop improvements:
390 - Total game time shown on the intermission screen, as for single player
391 - Quicksave enabled
392- Removed the frame rate dots, instead I added a cheat code "IDRATE" to show
393 various rendering stats, including the frame rate.
394- Fixed the intermission screen code to store its data right (bad code from
395 original Doom).
396
397* Changes v1.3.6 to v1.3.7
398- Client-server style net-games, including new server program
399- LxDoom starts faster, thanks to an idea borrowed from DosDoom
400- Player colours system sorted out, now your personal player colour is part of
401 your player preferences.
402- Fix for problems with 24bpp screens, new option in config file to deal with
403 this.
404- Fix key setup problems where certain choices of key setup could hinder
405 message typing in multi-player.
406- Misc stuff
407
408* Changes v1.3.5 to v1.3.6
409- Hires for the SVGALib version
410- Automap rotation/overlay
411- Modified to work with the new musserver
412- Various misc improvements
413
414* Changes v1.3.4 to v1.3.5
415- Fixed nasty overflow in I_GetTime_RealTime, causing hangs
416- Removed a load of I_GetTime references in m_menu.c
417- Added support for music pausing/unpausing
418
419* Changes from v1.3.3 to v1.3.4
420- More MBF features/improvements imported:
421 - Internal improvements (mobj pointer reference counting)
422 - Enhanced skies support
423- Status bar scaling for high-res
424- Bug fixes:
425 - Occasional corrupt save-games in large levels fixed (Boom/MBF bug)
426 - -loadgame crashes fixed
427- Performance improvements
428- Command line argument parsing logic changed for convenience in shell scripts
429 (later arguments take precedence)
430
431* Changes from v1.3.2 to v1.3.3
432- Optimised i386 assembly some more, about 2% improvement in fps
433- Tested to compile and run on FreeBSD
434- Modified #includes to use current headers
435- Updated makefile hints for FreeBSD compiling
436- Made install script more portable
437
438* Changes from v1.3.1 to v1.3.2
439- Imported/added some MBF features
440 - New code pointers added
441 - "Faster" sprite sorting
442 - Improved Dehacked handling (more reliable, Dehacked-in-a-PWAD)
443 - Fractional floor attributes saved in save-games
444 - Auto-correction of common errors in wads
445- Massive internal improvements, making LxDoom more stable - WAD lump locking,
446 rewritten patch drawing code.
447- Improved config file handling - now accepts (and writes out selected) numbers
448 in hex, entries are sorted into sections with headers, and internally the
449 handling is better.
450- Portability improvements - LxDoom is now near-completely endian-corrected, so it
451 should be compilable on big-endian machines, read the little endian Doom data
452 files fine, and even network with other machines regardless of endianness.
453 Also lots of misc portability stuff, explicitly signing some variables, a
454 lot more stuff made const, etc. The only problem I think is that save-games aren't
455 yet interchangeable across endiannesses.
456- More memory efficient - block memory allocator reduces memory fragmentation,
457 video buffers allocated only when needed, more things made constant and
458 initialised better.
459- Imported bug fixes from MBF:
460 - File handle leak in translucency code
461 - Water sector sprite problems
462 - No chat in demo playback
463 - Archville fire spawn
464 - Scroller calculations overflow
465 - Fast shots going through walls
466 - Improved d_deh.c fixed numerous SIGSEGV's and error code bugs
467 - Zombie players exiting levels
468 - New thing flags caused incompatibility with buggy Doom wads
469 - Setup menu backspace
470 - Indigo/Brown default chat keys reversed
471- Glide (3dfx) frame-buffer target (warning - released only in source code form and
472 only for alpha testing purposes, not ready for normal use).
473- Improved ENDOOM support - (optional) colour ENDOOM display, non-ASCII
474 characters displayed, sensible choice between ENDOOM and ENDBOOM (displays
475 any from a PWAD in preference, randomly chooses otherwise).
476- Minor improvements so LxDoom integrates more naturally into UNIX systems; sound
477 and music server are now searched for via the path, and wads are looked for in
478 /usr/local/games/wads/ if no DOOMWADDIR is set.
479- More keys work in the SVGALib version (notably PAUSE).
480- Monster-monster kills in coop are assigned to the player the monster was
481 targeting, or a random player if it wasn't targeting any, so coop
482 monster kills stats total 100% at the end-level screen.
483- Total game time is displayed on the intermission screens. This is a simple
484 total of the times shown on the end-level screens so far this game, not
485 including intermission times, and accurate to 1/35 of a second.
486- Low sound volume fixed.
487- Multi-player colours selectable in the config file.
488- Misc minor fixes and improvements inspired by MBF:
489 - Support for -noload parameter
490 - Support auto-loading of deh/BEX files as well as wads
491 - Removed limit on number of wad-files loaded.
492 - Fixed buffer overrun in menu text writing code by wrapping long lines.
493
494* Changes from v1.3.0 to v1.3.1
495- Fixed saving of config file (bug affected most Linux systems)
496- Binaries are now use libc.so.6.
497- 24 bpp and 32 bpp true colour X displays are now supported (untested) (24
498 bpp only supported for i386 systems).
499- Auto-loading of wad files - in the config file there is a new option
500 which lists wad files to be loaded automatically (several directories are
501 searched as for IWADs).
502- Loading saved games during a multi-player game now works. Very handy for
503 coop games :).
504- New config file option controls music pausing - when the game pauses
505 the music can either continue or be stopped. So people playing at home can
506 have the music continue while they read the map; people playing at work
507 can pause when the boss comes in and have the music stop ;).
508- Several more variables added to config file, most notably the
509 default size of the LxDoom window (for high-res).
510- PRBoom v2.02 networking code is now used. It still doesn't network with
511 PRBoom though. Net games with just LxDoom work fine still. Anyone with ideas
512 why it won't go with PRBoom let me know.
513- If saving a demo/screen-shot/save-game to disk fails an error message is
514 displayed. One of the most frustrating features of all versions of Doom that I
515 have used is that they always say "Game Saved" even if you are
516 out of disk space and it didn't save. I'm glad to have this one fixed.
517- Fixed the -cdrom parameter.
518- Fixed makefile hints for FreeBSD.
519- Fixed music pausing causing musserver crash.
520- Documentation updates.
521
522* Changes from v1.2.0 to v1.3.0
523- Hi-res added to X-windows version
524- Portability improvements (FreeBSD and RISC stuff in the makefile, minor code
525 changes included)
526- Minor bug-fixes
527
528* Changes from v1.1.1 to v1.2.0
529- Boom v2.02 updates incorporated (see TeamTNT's site for info on that)
530- Improved music comms code, to pass instruments and volume info
531- Code reorganisation & tweaking; video code is more logically organised,
532 and SVGALib code is neater now.
533
534* Changes from v1.1.0 to v1.1.1
535- Fixed crash using -warp parameter with SVGALib version
536- Fixed music server communication code
537- Should compile using glibc
538
539* Changes from v1.0.1 to v1.1.0
540- SVGALib version
541- Fixed timing problem on buggy kernels causing crashes in the wipe screens
542- Fixed bug in sound server communications which prevented Doom 1 working
543- Fixed problem with sound code causing accelerated sound on v2.1.125 kernel
544- Removed need for IPC in sound server communications, used pipe instead
545- Improved mouse grabbing/ungrabbing code in XFree86 version, now depends on
546 game and window status
547- Improved TrueColor/DirectColor 16 bpp support
548- X version is more multitasking friendly - detects when it is hidden or paused
549 or an intermission screen is up, and tries to free some more CPU time.
550
551* Changes from v1.0.0 to v1.0.1:
552- 16 bpp colour modes now supported. If you use a 16 bpp colour mode (65
553 thousand colours approx.), then you don't have to change your X setup to 256
554 colours (8 bpp) before using lxdoom anymore. However, it is still a good idea
555 to use 256 colours, because it is faster that way.
556- fixed a minor bug in routine used for the 8 bpp '-2' option (screen
557 doubling), which caused a couple of lines to be missed at the bottom of the
558 display window.
559- fixed a Boom bug which caused crashes in multi-player games. The bug occurred
560 when, during a single game session, first the players played one level at
561 which someone died, and then later exited that level, and later still another
562 player died. I.e in a multilevel death-match, or a long coop game. Caused one
563 machine to exit lxdoom with 'Segmentation Violation'. The version of PRBoom I
564 have also exhibits these symptoms, though obviously I can't be sure that this
565 is the cause; Boom v2.0 and v2.01 had this bug.
566
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..feb9548
--- /dev/null
+++ b/README.md
@@ -0,0 +1,53 @@
1# kindle-doom -- a port of PrBoom for the Kindle 4
2
3## Description
4
5This 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.
6
7## Installing & playing
8
9Prerequisites: copy your `doom.wad` and `prboom.wad` to the root of your Kindle USB partition. `prboom.wad` can be found [here](data/prboom.wad).
10
111. Download the latest release
122. Make sure you installed [KUAL](https://www.mobileread.com/forums/showthread.php?t=203326) on your Kindle.
133. Extract the release to the root of your Kindle USB partition
144. Run KUAL and run "Simon's Fun Land -> PrBoom"
15
16The controls are as follows:
17- Keypad to move
18- "OK" button to shoot
19- "Home" button to quit
20
21There's no "Use" key, because I haven't totally figured out how the other buttons work yet.
22
23## Compilation
24
25If 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.
26
27Export `CC` to the location of the GCC cross-compiler and run `make`.
28
29```shell
30$ export CC=/home/simon/armv7-eabihf--musl--stable-2020.08-1/bin/arm-linux-gcc
31$ make -j8
32```
33
34## Changes
35
36Based on [`prboom-2.5.0`](https://sourceforge.net/projects/prboom/files/prboom%20stable/2.5.0/).
37
38The 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.
39
40Resolution is hardcoded to 600x800 and cannot be changed.
41
42I removed all the autoconf stuff and wrote a Makefile by hand.
43
44## Known bugs
45
46- Demo playback doesn't seem to work correctly. I think this is due to tick calculation, but I'm not sure.
47- Because of this, it is not really possible to load the game directly, you have to "warp" to the beginning of the first level.
48
49## Limitations
50
51- The code is horrible, I only tried to hack together something that works.
52- There's no sound support, because my Kindle doesn't have speakers / aux output.
53- 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 @@
1PrBoom 2.5.0
2============
3
4PrBoom is a version of the classic 3D shoot'em'up game Doom, originally
5written by id Software.
6
7See the file AUTHORS in this distribution for a list of authors and
8other contributors, and a history of the projects PrBoom is derived
9from.
10
11PrBoom is made available under the GNU General Public License. See the
12file COPYING included in this distribution for details.
13
14Please see the NEWS file included for changes since the previous version.
15
16Game data - WADs
17----------------
18
19(This section is aimed at people not familiar with Doom and the
20data files it uses.)
21
22PrBoom is a game engine - it provides a program to play Doom levels, but
23it doesn't include any levels itself. More importantly, you need all the
24sounds, sprites, and other graphics that make up the Doom environment.
25So to play PrBoom, you need one of the main Doom date files from id
26Software - either doom.wad, doom2.wad, tnt.wad or plutonia.wad from one
27of the commercial Doom games, or the shareware doom1.wad. This file
28is called the IWAD.
29
30PrBoom also supports playing Doom add-on levels, called "PWADs", which
31are small extra .wad files which just contain extra levels or other
32resources. PWADs are ONLY ADD-ONS, you still need the original IWAD
33that they are designed to work with. In practice, most PWADs on the
34Internet require doom2.wad (although some work with doom.wad).
35
36If you don't own any of the Doom games, get the shareware doom1.wad
37from doom19s.zip on Doomworld's shareware download page. But note that you
38will not be able to play most add-ons.
39http://www.doomworld.com/files/shareware.shtml
40
41Windows Installation
42--------------------
43
44Just extract the zip to a directory of your choice and copy your IWAD
45files into it. Now you can make shortcuts and add "-iwad filename.wad"
46to them.
47
48The SDL_mixer library used by PrBoom supports software MIDI music
49synthesis. If you want to hear the Doom music, you need a set of
50Timidity instrument patches. Do a web search for timidity patch sets,
51there are plenty around.
52These patch sets are a large download (>5megs).
53SDL_mixer does not currently support hardware MIDI synthesis. But we
54have added a hacked version of SDL_mixer with native midi support. If
55you like to try it out, rename SDL_mixer_beta.dll to SDL_mixer.dll.
56You should rename the original SDL_mixer.dll before. Tell us if it
57works or not. Please note, that there might be bugs in the native midi
58implementation.
59
60Linux Installation
61------------------
62
63For UNIX, Linux, and other POSIX systems, you need the SDL libraries in
64order to use PrBoom. If you haven't already done so, visit
65http://prboom.sourceforge.net/linux.html and follow the instructions there
66for your system, downloading the necessary libraries, and either
67installing the binary RPM package or compiling PrBoom from source.
68
69Once you've done that, you'll need to copy your IWAD file (see the section
70above if you don't know what this is) to a directory where PrBoom can find
71it. Make /usr/local/share/games/doom/, and copy your IWAD (all of your
72IWADs, if you own more than one) to that directory.
73
74Mac OS Installation
75-------------------
76
77Copy your IWAD (see above) into your home folder under
78Library:Application Support:PrBoom (this folder will be created for you the
79first time you run PrBoom).
80
81First Use
82---------
83
84If it's the first time you've run PrBoom, you'll need to do some configuring
85to get the controls and display right for you.
86
87On a new installation, PrBoom runs at 640x480 resolution. If you have used
88PrBoom before, you may have an old config file in your home directory which
89specifies a lower resolution, such as Doom's normal 320x200. You can use the
90-width and -height parameters to select a higher resolution, e.g.:
91
92prboom -width 640 -height 400
93
94sets the resolution. This setting is remembered for future sessions. For
95other parameters, see the included README.command-line.
96
97You may also wish to customise the key bindings. PrBoom's default keybindings
98are the same as the original Doom; unlike original Doom, you can change key
99bindings in the game. In the in-game menus, go to Options, Settings, Key
100Bindings.
101
102On Mac OS X, you can't use the command line, but after running the program
103once, you can edit YOURHOME:Library:Application Support:PrBoom:prboom.cfg to
104change settings like your screen resolution.
105
106Features
107--------
108
109 This is all the features PrBoom has compared to the original Doom game
110 - it's intended to give you an idea of the enhancements, rather than
111 burying you in details.
112
113 See http://prboom.sourceforge.net/about.html for an HTML version of
114 this list.
115
116 This is shamelessly modelled on Boom's changes pages. By each
117 change, there's the name of the port the feature comes from (so it's
118 compatible with).
119
120Playing the game
121
122 * Supports loading dehacked files at the command line, or in WADs
123 (BOOM, MBF)
124 * Supports PWADs containing sprites and flats (BOOM)
125 * Save games and demos completely store game parameters (BOOM,
126 MBF)
127 * Savegames store list of loaded WAD files, warning if wrong files
128 loaded (BOOM, MBF)
129
130Game engine
131
132 * Player bobbing improved, optional (BOOM, MBF)
133 * Friction effects (BOOM), affecting players and monsters
134 (MBF)
135 * Wind, current, conveyor effects (BOOM)
136 * Far more flexible scrolling wall/floor types (BOOM)
137 * Always run (BOOM)
138 * Weapon change logic overhauled and improved (BOOM)
139 * Support for friendly monsters, helper dogs (MBF)
140 * Monster target finding code improved (MBF)
141 * AI improvements (MBF)
142 * Bouncy and touchy things (MBF)
143 * New code pointers (MBF)
144 * Per-level and animated skies (MBF)
145 * Generalised line types system gives complete flexibility
146 (BOOM)
147 * Elevators (BOOM)
148 * Translucent sprites, walls (BOOM)
149 * Independent floor and ceiling lighting (BOOM)
150 * Silent teleports (BOOM)
151 * Deep water, true underwater areas (BOOM)
152 * Icon of Sin telefragging made more consistent (MBF)
153 * Fix large numbers of game bugs (BOOM, MBF, LxDoom)
154 * Support arbitrary texture heights (BOOM)
155
156Screen
157
158 * High resolution support (PrBoom)
159 * Optional message console, multiple message lines (BOOM)
160 * Status bar shows health/armour/ammo in colours (BOOM)
161 * Heads up display, showing ammo, health, keys overlayed on view
162 (BOOM)
163
164Multiplayer
165
166 * Spy mode improved (BOOM)
167 * Support for loadgame in a net game (LxDoom)
168 * Client server style network games (LxDoom)
169
170Automap
171
172 * No limit on marks (BOOM)
173 * Rotation and overlay modes (DOSDoom, LxDoom)
174 * Map shows coordinates (BOOM), optionally follow pointer
175 (MBF)
176 * Teleport lines, key doors and switches marked specially (BOOM)
177 * Keys, secrets visible on map with cheat codes (BOOM)
178 * Colours fully configurable from menus (BOOM)
179
180Intermission screens
181
182 * Par times hidden when not relevant (BOOM)
183 * Total episode time shown (LxDoom)
184
185Menus
186
187 * F1 help screen shows current key setup (BOOM)
188 * Key bindings, monster behaviour, and compatibility settings all set
189 in menus (BOOM, MBF)
190
191Compatibility
192
193 * Game is capable of behaving like any of: original Doom v1.9, Boom
194 v2.02, MBF (BOOM, MBF, LxDoom)
195 * Plays most original Doom v1.9 demos (more than Boom or MBF)
196 * Plays most Boom v2.02 demos (apart from levels with friction
197 effects everything should work).
198 * Plays some DOSDoom, earlier Doom, earlier Boom, and LxDoom demos.
199 * Plays all MBF demos.
200 * Auto-correction of common bugs in old levels (MBF), with
201 warnings (LxDoom)
202 * Fine control of options controlling compatibility and new features
203 (MBF)
204
205Controls
206
207 * Greater control of key bindings from in game menus (BOOM)
208 * More accurate mouse sensitivity control (BOOM, LxDoom)
209
210Misc
211
212 * Screenshot code improved, supports BMPs (BOOM)
213 * Support for ENDOOM and ENDBOOM (BOOM, LxDoom)
214 * -timedemo and -fastdemo options (BOOM)
215 * Real time frame rate, segs, visplanes, sprites display
216 (LxDoom)
217 * Various extra cheat codes (BOOM, LxDoom)
218
219Internals
220
221 * Greatly improved internal memory management (BOOM, LxDoom)
222 * Startup time greatly shortened by lazy generation of some lookups
223 (DOSDoom, LxDoom)
224 * Removed internal limits (BOOM)
225
226Other Tips
227----------
228
229On Linux, SDL tries to detect an appropriate video device automatically.
230If you want to overrite the default, you can set the SDL_VIDEODRIVER
231enviromental variable. At a bash prompt, this is as easy as running:
232
233SDL_VIDEODRIVER=fbcon prboom
234or
235SDL_VIDEODRIVER=svga prboom
236
237Details
238-------
239
240Details on these extra features are split into separate text files:
241
242README.demos provides a guide to PrBoom's demo support
243README.compatibility describes PrBoom's various compatibility
244 options and modes
245README.command-line gives a command line reference for prboom,
246 prboom-game-server, and the format of boom.cfg.
247 On UNIX/Linux systems use the man pages instead.
248
249Editing features are not covered in the docs with this package. We plan
250to bundle the editing docs as a separate download. Watch our website
251for news.
252
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..51474b0
--- /dev/null
+++ b/TODO
@@ -0,0 +1,1495 @@
1Entrys marked by a * are fixed.
2
3--------------------------------------------------------------------------
433. (2000/12/24) Single key quit
5
6Colin: opulent wants the old 'q quits demo recording' feature back.
7 I suggest making it a configurable key setting, not bound to any
8 key by default.
9Proff: For 2.2.4?
10
11--------------------------------------------------------------------------
1234. (2002/07/28) Fix documentation
13
14Proff:
15- add mp3 stuff
16- add new opengl options
17- update FAQ?
18
19--------------------------------------------------------------------------
20*35. (2002/07/28) Fix OpenGL segfault on Linux
21
22Proff:
23Possibly caused by using gluImageScale when paletted textures used.
24Either write my own scaling functions, which would allow mipmapping
25for paletted textures, or just kick the scaling. I'm for the first
26if I get the time. Small fix would be disabling gluImageScale when
27paletted textures used.
28Proff: Will hopefully be fixed in 2.3.x
29
30--------------------------------------------------------------------------
31*36. (2002/07/28) Add option to move backward with second mousebutton
32
33Proff: like it was in my old prboom version
34Proff: 2.3.x
35
36--------------------------------------------------------------------------
37
38List of revisions from PrBoom 2.3:
39
40[!] - cph needs to check
41[+] - already merged
42[ ] - empty or not wanted
43[-] - interesting but not merged yet
44
45+ r597 | Add player number to spawn as a parameter to P_SpawnPlayer, repl
46+ r598 | Improved P_InterceptVector that isn't subject to overflows Remov
47+ r599 | Check whether usleep(3) is supported, and fall back on select(2)
48+ r602 | Changed long long to int_64_t.
49- r603 | Added chasecam patch and fixed long long problems. Worked withou
50 Chasecam
51- r604 | Added p_chase.*
52 Chasecam
53 r605 | Support saving games at all compat levels - this will be necessa
54+ r606 | Linux byteorder.h macros are unsigned, so we must force them to
55 r607 | Linux byteorder.h macros are unsigned, so we must force them to
56- r608 | Nice catch Quasar` - fix sprite clipping for cameras in underwat
57 Chasecam
58 r609 | Minor fix
59 r610 | General cleanup of EV_BuildStairs Fix scanning for multiple stai
60 r611 | Separate demo sync stuff into its own section Add Final Doom tel
61 r612 | Fix dropoff flag for Boom demos
62 r613 | Fix D_DoomExeDir. Win2000 and possibly others don't report the f
63+ r614 | Fix D_DoomExeDir. Win2000 and possibly others don't report the f
64 r615 | Bump version number
65 r616 | Merge rewritten R_DrawSpan from the dev tree
66 r617 | Final demo support refinements, inc. -complevel (which was docum
67 r618 | Include spec file in the tarball, and build RPM with -ta
68 r619 | From the 2.3.x tree: Cleaned up sound code. I_StartSound gets ch
69 r620 | Bump version number.
70 r621 | Various things for 2.2.2
71 r622 | Update with WAD generated from the dev tree, no v1.2 compat save
72 r623 | Imported doublebuffering and fullscreen toggle from dev tree.
73 r624 | Put samplerate a little bit down, because when timidity is used
74 r625 | Update boom.cfg.5 with new video options, from Proff Man page fi
75 r626 | This commit was manufactured by cvs2svn to create tag 'prboom_2_
76 r627 | Released 2.2.2
77+ r628 | comp_stairs fix and EV_BuildStairs cleanup from stable branch
78+ r629 | Boom dropoff compat fix, from stable branch
79+ r630 | *** empty log message ***
80+ r631 | Merge newer version from stable branch Switch to %configure and
81+ r632 | Very minor spacing fixes
82+ r633 | Must distribute prboom.txt so the make can pass prboom.wad
83 r634 | Distros have caught up with us and are shipping SDL 1.2 now Clea
84 r635 | Fix typo
85+ r636 | Rationalise the light level calcs for sprites and walls - new fu
86+ r637 | SDL video corectness fix - use SDL_MUSTLOCK to determine if we h
87+ r638 | We need malloc wrappers to do error handling etc; just go back t
88+ r639 | New I_Read wrapper for read(2) - partial read handling - error h
89+ r640 | Clear curline after use, so preventing R_ColourMap applying it t
90 r641 | New savegame format revision, save compat level in saves so we c
91+ r642 | Get rid of the SIGPIPE handler - it's been unused since we switc
92+ r643 | Merge in Proff's port of the BEX extensions from Eternity for mu
93+ r644 | Fix some d_deh.c compile warnings Make lots of internal processi
94+ r645 | Eliminate another static buffer in favour of doom_printf
95+ r646 | Doom v1.2 did not animate 2s middle textures (cf levels/d-f/dmsp
96 r647 | We always compile with SDL_mixer these days, so drop all the ho
97 (will break Mac)
98+ r648 | Clean up POSIX build process - remove obsolete stuff about no-ne
99+ r649 | Clarify the base[xy]scale logic a bit, use correct global variab
100+ r650 | Eliminate some redundant variables and calculations in R_StoreWa
101+ r651 | Remove sprite{width,offset,topoffset}, these were just caches of
102 r652 | Fixed latest changes for Visual C++.
103 (not necessary)
104 r653 | Added the new menu code from SMMU.
105 (we don't want the new menu code)
106 r654 | HEADER_SIZE must be derived from sizeof(memblock_t), which can b
107 r655 | Fix typo causing keypad 5 to map to PAD0
108+ r656 | Fix keypad 5 Use SDL_SetPalette (SDL1.2 feature which allows us
109 r657 | Update POSIX Makefile for new menu system files Remove obsoleted
110 (the useful stuff is already in)
111 r658 | Fix running with no existing config file (but the currently comm
112 (g_bind is not used)
113 r659 | Removed unused I_ConTextAttr.
114 r660 | I'm stupid or somewhat, I_ConTextAttr IS used. I should check th
115+ r661 | For consistency, keep all linked thinkers on a class list - have
116+ r662 | Remove duplicate extern for thinkercap from doomstat.h Move comm
117+ r663 | Remove old Linux joystick code
118 r667 | Move config file stuff to g_config.c Split out code for specific
119 (g_config)
120 r668 | Added g_config to VisualC project files.
121 (g_config)
122 r669 | Added g_config.h.
123 (g_config)
124+ r670 | Minor cleanup
125 r671 | Makefile change for g_config.[ch], which I forgot to commit yest
126 (g_config)
127 r672 | This commit was manufactured by cvs2svn to create branch 'axes_s
128 r673 | Robert Sherwood's axes patch
129 r674 | G_SaveDefaults callback set up only after G_LoadDefaults done Ad
130+ r675 | Removed Dreamcast stuff which doesn't belong here.
131 r676 | Updated Dreamcast stuff (some bugs left).
132 (Dreamcast)
133 r677 | Updated/cleaned up Dreamcast stuff (some bugs left). Fixed some
134 (Dreamcast)
135 r678 | Updated/cleaned up Dreamcast stuff. Works now, the bugs weren't
136 (Dreamcast)
137 r679 | Added sound to Dreamcast version.
138 (Dreamcast)
139 r680 | Fixed tolower(*s++) bug.
140 (Binding/Console)
141 r681 | Fixed D_DoomExeDir for Dreamcast.
142 (Dreamcast)
143 r682 | Added keyboard support for Dreamcast.
144 (Dreamcast)
145 r683 | From rsherwood: Axes now scale against the appropriate values (i
146 r684 | Added "Installation From CVS" (Steven Elliott).
147+ r685 | Added "Installation From CVS" (Steven Elliott).
148 (was already merged)
149 r686 | P_SpawnPlayer must only be called with mthing_t's from the playe
150+ r687 | On the right branch this time, merge the fix for my player start
151 (was already merged)
152 688-707
153 r708 | Updated.
154 (TODO)
155+ r709 | Intermission screen demo sync bug fixed Also fix a possible time
156 (was already merged)
157 r710 | Added additional check for extensions.
158 r711 | Fix for compiling prboom_server on windows.
159+ r712 | Fixed some z_zone related problems.
160 (was already merged)
161+ r713 | Fix WAD bugs that can cause crashes even in demo compatibility m
162 (was already merged)
163 r714 | New config file name prboom.config for both GL and non-GL versio
164 (new config format)
165+ r715 | Pull forward fixes from stable tree: Fix numeric keypad. Kill th
166 (was already merged)
167+ r716 | Another fix fromt he stable branch: Fix fastparm and respawnparm
168 (was already merged)
169 r717 | HEADER_SIZE must be derived from sizeof(memblock_t), which can b
170 r718 | Crop some old bits Update on progress Add comp_sound idea
171 r719 | Update some email addresses
172 r720 | *** empty log message ***
173 r721 | Correct compatibility levels comment
174 r722 | Import items from 2.2.2 and 2.2.3
175 r723 | pedantic html fix
176 r724 | Add super shotgun/A_CheckReload fix.
177+ r725 | Fix file handle leak in R_InitTranMap when called before WADs lo
178+ r726 | Make A_CheckReload actually work. Compatibility optioned for old
179 (was already merged)
180 r727 | Fix typo.
181+ r728 | Some patches from selliot to improve handling of missing monster
182+ r729 | Make M_ReadFile return -1 on error, so we can distniguish an emp
183 (parts were missing)
184+ r730 | LOL, backslash escaping, what was I thinking, the windows users
185 (was already merged)
186- r731 | Initialise gamestate so it's not GS_LEVEL. This stops a SEGV if
187 (Chasecam)
188- r732 | Merged in the axes stuff. It's a more general replacement of the
189 (Generalise axes handling for input devices)
190+ r733 | Clear player mobj's at level end - they're allocated PU_LEVEL so
191+ r734 | Add back in horrible kludge used in 2.2.x to stop desyncs in the
192 (was already merged)
193 r735 | i_joy.c is gone
194+ r736 | Removed now unused X11 and OSS.
195+ r737 | New comp_sound compatibility option: - player only ever hears th
196 (was already merged)
197 r738 | *** empty log message ***
198 r739 | Updated.
199+ r740 | Moved D_DoomExeDir and FindWADFile to i_system. Renamed to I_Doo
200 (cleaned up)
201+ r741 | -forceoldbsp is valid for non-GL builds
202 (was already merged)
203+ r742 | Fix comp_skymap. Looks like I just overlooked this one when I di
204 (was already merged)
205+ r743 | Added the MP3 loading. MP3 will only be loaded if the music lump
206 (was already merged)
207 r744 | Load default config from a wad if config file not found.
208 (new config format)
209 r745 | Strings in menuitem_t will be const
210 r746 | Add the latest new compatibility levels.
211 (console)
212 r747 | Enable gamma correction with new config system.
213 (console)
214 r748 | Extension usage from 2.2.x.
215 (from 2.2)
216- r749 | Save sensitivity settings.
217 (axes)
218 r750 | Small fix for keybinding names.
219 (binding)
220 r751 | Credits.
221 (new menu stuff)
222 r752 | Fix version strings.
223 r753 | Updated.
224 r754 | Hopefully fix some Linux/NVidia problems.
225 r755 | *** empty log message ***
226 r756 | Minor corrections
227 r757 | More corrections
228 r758 | Another HTML fix.
229 r759 | Move ssg fix to the right section.
230 r760 | Add DivlineSide coord-swapping bug. Add more info on p_sight.c d
231+ r761 | Fix swapped coord in LOS calcs involving east-west walls (this
232 (from 2.2)
233+ r762 | Auto-fix WAD bug where 1S line uses negative sidedef number othe
234 r763 | Add back screenshot capability.
235 (menu)
236 r764 | Eliminate tmthing, redundant. Save tmx & tmy over P_CreateSecNod
237+ r765 | Remove tmflags, redundant. Preserve tmx & tmy over calls to P_Cr
238 (was already merged)
239 r766 | Revised P_CreateSecNodeList details.
240+ r767 | Added fix for 800x600 bug by John Popplewell, but currently put
241 r768 | Enabled fix for 800x600 bug by John Popplewell. Finetuned the va
242 (skipped, related to previous)
243 r769 | Removed debug hack.
244 r770 | Added statusbar console variables. Worked a little bit on the me
245 (menu, console)
246 r771 | Added hud and cheat console variables. Worked a little bit on th
247+ r772 | Better invulnerability drawing for normal OpenGL (not paletted).
248 (2.2)
249- r773 | Added better dynamic OpenGL loader (Linux makefiles need updates
250 (Dynamic OpenGL)
251- r774 | Tried fixing release bug in tesselator. Not sucessful yet.
252 (Tesselator)
253 r775 | Sorting config file output (Lucas Pope).
254 (config)
255 r776 | Small bugfix for VC7. isprint doesn't like anything above 255 (L
256 (binding)
257 r777 | Disabling gluTesselator till it's fixed.
258 (Tesselator)
259- r778 | New and unified software rendering by Lucas Pope. This adds 16 a
260 (renderer)
261 r779 | Accidently added this in the last update. This is the new sound
262- r780 | Added fix for 800x600 bug by John Popplewell which wasn't in the
263 (renderer)
264- r781 | Unified patch rendering (filtering etc) (Lucas Pope).
265 (renderer)
266 r782 | Added more console commands.
267 (console)
268 r783 | Added more console commands. Fixed OpenGL mode.
269 (console)
270- r784 | Implemented on the fly video mode changing (8,16,32 bit).
271 (renderer)
272 r785 | updated
273 r786 | added s_samplerate console var
274 (console)
275 r787 | enclosed the signal handlers with #ifndef _DEBUG
276 r788 | small comment change
277 (binding)
278- r789 | added the RDRAW_FILTER_ROUNDED filter method that combines the s
279 (renderer)
280- r790 | added RDRAW_FILTER_ROUNDED support
281 (renderer)
282 r791 | Reverted back to old sound code, due to some problems.
283- r792 | fixed V_PlotPatch clipping, still not perfect, but better. also
284 (renderer)
285- r793 | added bufferWidth/Height and convertToBGRA parameters for the V_
286 (renderer)
287- r794 | Fixed some bugs in the V_GetPlotted* function family.
288 (renderer)
289- r795 | just some small little fixes
290 (renderer)
291- r796 | Using new V_GetPlotted functions for the OpenGL texture generati
292 (renderer)
293- r797 | Fix include filename case for compilation on Linux
294 (renderer)
295- r798 | __cdecl presumably only needed on Win32; not available with gcc
296 (renderer)
297- r799 | Case sensitive filename fixes
298 (renderer)
299- r800 | Removed __cdecl.
300 (renderer)
301 r801 | showMessages now defaults to on.
302 (console)
303- r802 | Fixed OpenGL/Software clash.
304 (renderer)
305- r803 | Made OpenGL library name configurable. Added dynamic screen reso
306 (renderer)
307- r804 | Removed test code.
308 (renderer)
309- r805 | Moved DrawLine from am_map to v_video. Added all wrappers for Op
310 (renderer)
311- r806 | Fixed resizing in windowed mode.
312 (renderer)
313- r807 | Fixed warnings about different const modifier. Added small check
314 (renderer)
315- r808 | Fixed some bugs (release version now works). Touched the memory
316 (renderer)
317 r809 | String const fix
318 (console)
319 r810 | Minor fixes
320 (menu)
321- r811 | Removed all references to V_DrawMemPatch.
322 (renderer)
323 r812 | More const fixes.
324 (console)
325- r813 | Screenshot is now a video system function.
326 (renderer)
327- r814 | Removed GL_DOOM.
328 (renderer)
329- r815 | Removed all remaining GL_DOOMs before full unification.
330 (renderer)
331- r816 | Unified software and OpenGL into one executable. Nothing changed
332 (renderer)
333+ r817 | cleaned up the PAUSE patch rendering
334+ r818 | fixed a major bug that caused any deh patch that modified a mons
335 (was already merged)
336 r819 | Made slowturntics variable.
337 (console)
338 r820 | Merge "time" portability fix fom dev branch (wi_stuff.c:1.6->1.7
339 r821 | Bump version numbers Add link to HP-UX compilation instructions
340- r822 | Fix inlining, min/max macros for gcc
341 (renderer)
342 r823 | Add gl_dyn.c, r_filter.h
343- r824 | new TPatch format, VIDD integration, many fixed video issues
344 (renderer)
345- r825 | new TPatch format, VIDD integration
346 (renderer)
347- r826 | Fixed OpenGL calls to the new patch functions. Updated VisualC++
348 (renderer)
349- r827 | Newlines at EOF to passify gcc.
350 (renderer)
351+ r828 | Remove duplicate BuildBEXTables (well spotted, Quasar`).
352 (was already merged)
353- r829 | Add r_patch.c.
354 (renderer)
355 r830 | BEX-equivalent strings output should have spaces around the = (
356+ r831 | BEX-equivalent strings output should have spaces around the = (
357 (was already merged)
358- r832 | Removed debug code.
359 (renderer)
360- r833 | More error checking.
361 (renderer)
362- r834 | Some code reorganisation. Added infinitePerspective which replac
363 (renderer)
364 r835 | Some code reorganisation.
365 r836 | Don't use paletted textures as default.
366 r837 | backported from 2.3.x: fixed a major bug that caused any deh pat
367- r838 | Removed glu tesselation code, as it doesn't work properly and is
368 (renderer)
369 r839 | Don't use paletted textures as default.
370 r840 | Backported better invulnerability drawing for normal OpenGL (not
371 r841 | Removed glu tesselation code, as it doesn't work properly and is
372 r842 | Updated.
373 r843 | Bumped version number.
374 r844 | Commit Mead's/my countable item automap highlighting.
375 r845 | Fix SEGV on failed lookup for BEX codepointer.
376 r846 | Always rangecheck patch drawing to the framebuffer, we have no g
377 r847 | Respawn frame bug "reported" on DW forums by Graf Zahl.
378 r848 | Don't treat linedef types in the 0x8000-0xffff range as generali
379 r849 | Fix DEH_MOBJINFOMAX.
380 r850 | Removed need for far clipping plane.
381 r851 | Updated and added some details.
382 r852 | Added some stuff from 2.2.x.
383 r853 | Update and cleanup.
384 r854 | Clean up some code indenting.
385 r855 | Split visplane duplication into new function. Fix sky-over-sky H
386+ r856 | From prboom_stable_2_2: Split visplane duplication into new func
387 (2.2)
388 r857 | Updated.
389 r858 | Fix erroneous extra shot noise when chaingun runs out of ammFix
390+ r859 | Fix chaingun bullet-noise-after-last-bullet bug.
391 (was already merged)
392 r860 | Compatibility option the chaingun sound fix (Bahdko made me, hon
393 r861 | Add chaingun extra shot sound fix. HTML cleanups. Obscure email
394 r862 | Obscure email addresses against spam harvesting.
395 r863 | Another email link obscured.
396 r864 | Fix for crash when trying to load empty slot.
397 (menu)
398 r865 | Removed $Id: $ lines. This is for the future switch to subversio
399 r866 | Removed $Id: $ lines. This is for the future switch to subversio
400 r867 | Wow, I totally messed up the last checkin. At all places where a
401 r868 | Wow, I totally messed up the last checkin. At all places where a
402 r869 | Fixed compiling of prboom_server.
403 r870 | Wow, I totally messed up the last checkin. At all places where a
404- r871 | Fixed double dcvars.translation mapping in 16 and 32 bit.
405 (renderer)
406- r872 | Fixed tranlation mapping for rounding filter in 8 bit.
407 (renderer)
408 r873 | Added r_patchfilter and r_patchslope console variables.
409 (console)
410- r874 | Patch drawing defaults to point filter and square borders as thi
411 (renderer)
412 r875 | Fix crash when doing timedemo from the menu.
413 (menu)
414- r876 | Added translucent patch drawing (used in video settings menu).
415 (renderer)
416- r877 | Added more menu graphics from smmu.
417 (menu graphics)
418 r878 | Added r_homflash console command.
419 (console)
420 r879 | Use smaller slider graphics from smmu. Boolean values are switch
421 (menu)
422 r880 | Output of lprintf now also goes to console.
423 (console)
424 r881 | Added names for keypad keys.
425 (binding)
426- r882 | Renamed r_videomode to r_rendermode. The r_width, r_height and r
427 (rendering)
428 r883 | Video settings menu is much more complete (OpenGL stuff missing)
429 (menu)
430 r884 | Updated.
431+ r885 | Made I_SoundInit callable more that once.
432 r886 | The snd_samplerate command is toggleable and only allows values
433 (console)
434 r887 | Fixed sound menu.
435 (menu)
436 r888 | Added use_mouse console variable.
437 (console)
438 r889 | Fixed compilation warning related to defdemoname. Made G_Compati
439 (console)
440 r890 | Moved default_compatibility_level and compatibility_level consol
441 (console)
442 r891 | Some small changes. Split up compatibility into two pages.
443 (menu)
444 r892 | Added p_cmd.c and made small related changes. This adds monster
445 (console)
446 r893 | Removed cvs log.
447 r894 | Removed non OpenGL versions.
448- r895 | Added OpenGL console commands. Added OpenGL settings to video me
449 (renderer)
450- r896 | Added ViddSys. Added viddsys project for VisualC6. Enabled vidd
451 (VIDD)
452 r897 | Added some stuff.
453 r898 | Removed unused stuff.
454 (console)
455 r899 | Reworked the menus a bit. Disabled some non working stuff for no
456 (menu)
457 r900 | Moved demo stuff from g_game to g_demo.
458 (g_demo)
459- r901 | Implemented iwad console command for on the fly iwad switching.
460 (IWAD switching)
461- r902 | Documentation for vidd.
462 (VIDD)
463 r903 | Fix drawing when console is fullscreen.
464 (console)
465 r904 | Added C_RunTextCmdf. Added c_addcommand_stats console command wh
466 (console)
467 r905 | Changed to use C_RunTextCmdf.
468 (menu)
469 r906 | Added iwad selection in "features->load wad".
470 (menu)
471- r907 | Changed iwad from console command to console string and prevent
472 (IWAD switching)
473 r908 | Using g_iwad (from iwad console string) for default iwad when no
474 (IWAD switching, menu)
475- r909 | Sound functions take const mobj_t * instead of void * for locati
476 (VIDD)
477 r910 | Moved includes bacuase of some changes in the header files.
478- r911 | Sound functions take const mobj_t * instead of void * for locati
479 (IWAD switching)
480 r912 | Added c_net from smmu.
481 (net from smmu)
482 r913 | Added fraggle script files from smmu, but didn't integrate it in
483 (fraggle script)
484- r914 | Made wall and floor filters seperatly selectable (to allow round
485 (renderer)
486- r915 | Added Lucas Pope to credits.
487 (renderer)
488 r916 | Several small changes to let fraggle script stuff compile. Added
489 (fraggle script)
490 r917 | Added fraggle script files. Moved some files into project subfol
491 (fraggle script)
492- r918 | Three font graphics from SMMU added.
493 (font graphics)
494- r919 | Merging more stuff from SMMU: v_misc added and moved font handli
495 (font handling - better get it from Eternity)
496- r920 | Using the new V_Text* functions here instead of implementing ess
497 (font handling)
498 r921 | Removed unused externs.
499 r922 | Some cleanup. Using V_IsPrint to check if char is printable. Add
500 (console)
501- r923 | Initialize the font in v_misc.
502 (font handling)
503 r924 | For iwad switching: Initialize patches (R_Init) before any call
504 r925 | Definitions for silentmove sector flags.
505 r926 | Added totalfrags in preparation for the coming smmu hud code.
506 (smmu hud)
507 r927 | Added lightlevel_t. Added prototypes for new functions from smmu
508 (fraggle script)
509 r928 | Fixed type cast compiler warnings.
510 (fraggle script)
511 r929 | Using the recently added V_DrawBox function.
512 (menu)
513 r930 | Prevent adding a command twice, as this causes an endless loop l
514 (console)
515- r931 | Typecast to prevent warning.
516 (renderer)
517 r932 | Added linedefs for scripting from smmu.
518 (fraggle script)
519 r933 | Last log entry is wrong. This added silentmove.
520 (fraggle script)
521- r934 | Adding silentmove and using plat_up, plat_stop and palt_down con
522 (some constants)
523- r935 | Added T_LightFade and P_FadeLight from smmu.
524 (P_FadeLight)
525 r936 | Enabled T_AddCommands and V_AddCommands. Some moving around of *
526 (console)
527 r937 | New hud from smmu with some small related changes. The fullscree
528 (HUD)
529 r938 | Removed cvs log.
530- r939 | Removed message from player_t, use doom_printf or player_printf
531 (Removed message from player_t, use doom_printf or player_printf instead)
532- r940 | Fix chasecam when teleporting.
533 (chasecam)
534- r941 | Added r_blockmap.
535 (blockmap)
536- r942 | Some code cleanups and documentation fixes. Very small changes f
537 (several changes)
538- r943 | Enabled V_FPSDrawer:
539 (FPS drawer)
540 r944 | Added and enabled more smmu stuff.
541 (smmu)
542- r945 | Fixed V_WriteTextXYGapFont call from using v_font to supplied fo
543 (font)
544 r946 | Small cleanups and added some variables from smmu.
545- r947 | prboom.wad now loaded together with iwad. Using IndentifyVersion
546 (IWAD switching)
547 r948 | Added deh_loaded variable from smmu.
548 (console)
549 r949 | gravity is now a variable.
550 (gravity variable)
551 r950 | Renamed G_DeferedInitNew to G_DeferedInitNewNum and G_InitNew to
552 (hubs)
553 r951 | Moved G_Ticker to the end of the file.
554 r952 | Added p_info and p_hubs from smmu.
555 (hubs)
556 r953 | Some definitions (intermission camera related) and the barest mi
557 (intermission camera)
558 r954 | Check if soundfx is enabled in S_StopSounds to fix crash.
559 r955 | Moved "extern int screenblocks;" to r_main.h
560 r956 | Removed now unused extern int key_* definitions. Added G_Scrambl
561- r957 | Print errors to console instead of calling I_Error.
562 (renderer)
563 r958 | Put code from g_game (G_DoLoadLevel) to init the sky texture nam
564 (smmu)
565 r959 | More things from smmu in P_SetupLevel.
566 (smmu)
567 r960 | Removed unused key_* definitions. Moved key_map_* definitions to
568- r961 | Z_PrintStats is Z_DrawStats now and called from HU_Drawer. It's
569 (font)
570 r962 | MAXLOADWADS now 2 again, cause prboom is implicitely loaded.
571- r963 | bodyqueue fix from mbf.
572 (bodyqueue)
573 r964 | New sound code from smmu.
574 (smmu - sound)
575 r965 | Reenabled quit sounds. Added i_endoom_delay to change delay when
576- r966 | Small changes and additions from smmu.
577 (chasecam)
578 r967 | P_SetupLevel and G_InitNew take a levelname instead of gameepiso
579 (smmu)
580 r968 | Added death messages from smmu.
581 (smmu)
582 r969 | Bump version number for autoconf.
583 r970 | Sprite offsets must be flipped for flipped sprites. Thanks to fr
584 r971 | Further improve the P_CreateSecNodeList global variable cleanups
585 r972 | Fix endianness issues in tic field of network packets. Should be
586 r973 | cf http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=174541 Remov
587 r974 | Get line lengths right in README.command-line
588 r975 | Added more intermission code from smmu. Made some functions stat
589 (smmu)
590 r976 | Added use_startmap and startlevel. Added functions for dynamic w
591 (smmu)
592 r977 | Enabled some smmu stuff which didn't work before.
593 (smmu)
594 r978 | Removed ChangeLog as it's generated.
595 r979 | Reintroduce -nomouse option; essential for debugging.
596 r980 | Add comp_sound stuff, backported from the development version.
597 r981 | Set compatiility options correctly in netgames in old compatibil
598 r982 | Add support to network game server for reading config files. It
599 r983 | Added explanation for AM_PATH_SDL problem to compile from cvs se
600 r984 | Added explanation for AM_PATH_SDL problem to compile from cvs se
601 r985 | Added correct eol property.
602 r986 | Added correct eol property.
603 r987 | Fixed Makefile.am. Small posix related fixes.
604 r988 | Added Visual Studio .NET project files.
605 r989 | Added tab before each line of files.
606 r990 | More Makefile and posix fixes.
607 r991 | Posix fixes for OpenGL. Now always compiled in, as there are no
608 r992 | Makefiles are weird. Replaced tabs with spaces in file list.
609 r993 | Added VISUALCNET to distribution.
610 r994 | Added inl and vidd directorys to makefiles.
611 r995 | Fix end of line.
612 r996 | Fix case.
613 r997 | Fix case.
614 r998 | Added src/inl/Makefile and src/vidd/Makefile.
615 r999 | Fix end of line.
616 r1000 | Removed trailing slashes in I_DoomExeDir.
617 r1001 | Moved includes from gl_intern.h to gl_main.c and gl_texture.c. P
618 r1002 | Remove ChangeLog from distribution tarball - we don't have one.
619 r1003 | Remove readme.txt from distribution, as it is not in the reposit
620 r1004 | Sanity checking for netcmd numbers. Add more entries to netcmd e
621 (console, net)
622- r1005 | Endian fixes.
623 (renderer)
624 r1006 | Removed PFNGLCOLORTABLEEXTPROC definition and added FAQ entry.
625 r1007 | Added GL_DOOM define.
626- r1008 | More endian fixes.
627 (renderer)
628 r1009 | Reorder comp_sound to match 2.2.4.
629+ r1010 | Import fixes from stable tree, revisions 823,825,827: - Respawn
630 (2.2)
631+ r1011 | Port forward fraggle's sprite offset flipping fix. Clean up and
632 (sprite clipping fix)
633+ r1012 | Port forward the fix for global variable overwriting (tmbbox) in
634 (2.2)
635 r1013 | New address for Barry Mead.
636 r1014 | Fix non-GL_Doom compilation.
637 r1015 | Allow s_sound.c to specify volume with greater precision. This a
638 r1016 | Work around defect in SDLNet_UDP_Bind channel support.
639 r1017 | Add a feedback mechanism to keep clients more accurately synchro
640 r1018 | Upadte email address and download address.
641 r1019 | Remove direct smpeg dependency - it should be pulled in automati
642 r1020 | Remove debugging accidentally committed yesterday, and update NE
643 r1021 | Add weapon pickup sounds, sprite flipping, and updated p_map.c f
644 r1022 | Protect another email address.
645 r1023 | Hide another email.
646 r1024 | Update for 2.2.4 release.
647+ r1025 | Bring forward generalised line range fix from 2.2.x branch.
648 (2.2)
649 r1026 | Fix xtratics - it was generating negative tic #s and the server
650 r1027 | Added Makefile.am for extra files in generated tar.
651 r1028 | Tag the 2.2.4 release.
652 r1029 | Added more missing files to the Makefiles.
653 r1030 | Added missing GenEnd.
654+ r1031 | Updates to spec file (from 2.2.4).
655 (2.2)
656+ r1032 | Do not link smpeg (ported from 2.2.4).
657 (2.2)
658+ r1033 | From 2.2.4, less strict automake checks.
659 (2.2)
660+ r1034 | Port back-off support from 2.2.4. Port endianness fixes from 2.2
661 (2.2)
662+ r1035 | As in 2.2.4, removed ChangeLog.
663 (2.2)
664+ r1036 | Improve accuracy of sound calculations (sound range fix ported f
665 (2.2)
666+ r1037 | Update NEWS with final 2.2.4 list.
667 (2.2)
668 r1038 | Tagging PrBoom 2.3.0
669 r1039 | PrBoom 2.3.0 released.
670 r1040 | Explain a bit that this is a rough'n'ready beta release. Solicit
671 r1041 | Windows release was bad.
672 r1042 | Some feedback.
673 r1043 | Updated.
674 r1044 | Correct the off-screen checking in HUlib_drawTextLine. This stop
675 r1045 | Bumped version number.
676 r1046 | Fix config.h for Windows. All references to "../config.h" were r
677 r1047 | Fix eol.
678 r1048 | Report error if port bind failed. Sanity checking on player numb
679 r1049 | Load OpenGL libraries only when needed.
680- r1050 | I think this description of the networking is worth saving.
681 (network explanation)
682 r1051 | Take screenshot - f12 Quit - f10 Gama correction - f11
683 (config)
684 r1052 | Added autorun to menu. Updated todo.
685 (menu)
686 r1053 | Moved and added stuff for redesign.
687 r1054 | Forgot to rename.
688 r1055 | Mostly working like the old pages. I have to fix the tool first.
689 r1056 | With SimpleTAL 3.5, a small hack in pubtal and some small fixes
690 r1057 | Add navigation and reordered some things.
691 r1058 | Added hover effect for links.
692 r1059 | Added missing template.
693 r1060 | A very small readme on how to build the website.
694 r1061 | Nicer rollover effect.
695 r1062 | Fix eol. I finally found the option to prevent my editor from me
696 r1063 | Fix eol. I finally found the option to prevent my editor from me
697- r1064 | More endian fixes. Now it works on big endian systems as far as
698 (renderer)
699 r1065 | Fixed ignore-filter.
700 r1066 | Not needed anymore.
701+ r1067 | Obvious bug in my attempts to fix the T_VerticalDoor corruption
702 (2.2)
703 r1068 | Fix overzealous safety check added in last update.
704 r1069 | If server is closed before game start, exit the client too.
705 r1070 | We should call D_QuitNetGame for any client exit after the serve
706 r1071 | Better management of players joining and quitting during startup
707 r1072 | Demo players are after this: total live monsters count in the HU
708 r1073 | Set savegame root.
709 r1074 | fake_contrast should be on by default (used to be on but configu
710 r1075 | Bump version number.
711 r1076 | Marked hub and script related stuff with ifdefs.
712 (hub)
713- r1077 | Fixed textcolours array, this caused segfaults.
714 (font)
715- r1078 | Fix prboom.wad not found [Patch 949349].
716 (IWAD switching)
717- r1079 | Fix texture pegging for upper textures [Patch 897801] [Bug 59999
718 (renderer)
719 r1080 | Set svn:eol-style property.
720 r1081 | Set svn:eol-style property.
721 r1082 | Make line_t junk static in A_LineEffect.
722+ r1083 | Make line_t junk static in A_LineEffect [Bug 946686].
723 (2.2)
724 r1084 | Fix for new GCC warnings.
725- r1085 | Wrap extremely long lines.
726 (renderer)
727 r1086 | Fix Bug #845129. Filenames with dots didn't work properly (and s
728- r1087 | Fixed Bug #929248. Buffer overflow in F_TextWrite.
729 (font)
730 r1088 | Added SDLK_CARET as console key.
731 r1089 | Fix compilation.
732- r1090 | (Partly) fix bug #851055. (Re)implemented multipatch textures. D
733 (renderer)
734- r1091 | Fix bug #810700. It was some rounding error introduced with the
735 (renderer)
736- r1092 | Limit the posts of a patch to the limits of the texture. As a si
737 (renderer)
738- r1093 | Removed some unused code. I think this got obsolete with the new
739 (renderer)
740 r1094 | Added an ifdef USE_ULL_SUFFIX. This should be added with a test
741 r1095 | Fix bug #826682. Unavailable IWADs get disabled.
742 (menu, iwad switching)
743 r1096 | Fix savegames (Bug #896092).
744 (smmu savegames)
745- r1097 | Fix multiple-patches-on-one-column textures (Bug #851055).
746 (renderer)
747 r1098 | Bump version number.
748 r1099 | Load OpenGL library only once.
749 r1100 | Fix bug #926548 and enhance widgets with the possibility to choo
750 (hud)
751 r1101 | Fix bug #810562. Bounded keys weren't checked when playing demo.
752 (binding)
753 r1102 | Tried to achive savegame compatibility with 2.2.x, but failed. T
754 (smmu savegame)
755 r1103 | Update email address.
756 r1104 | Use SDL_MUSTLOCK to determine whether si render direct to buffer
757 r1105 | Bump version number.
758 r1106 | A few minor fixes so far.
759 r1107 | Fix --enable-dogs
760 r1108 | Cheatcodes didn't work anymore and this change wasn't necessary
761 (binding)
762 r1109 | Updated.
763- r1110 | Removed W_UnlockLump* calls made obsolte by the new renderer.
764 (renderer)
765 r1111 | Added a sanity check to prevent problems.
766 r1112 | Prevent compiler warning.
767 r1113 | Fix position of automap text widgets when using high-res.
768 (hud)
769 r1114 | Added devparm as console command.
770 (console)
771- r1115 | Made R_GetTextureColumn simpler by using the new R_GetTextureCom
772 (renderer)
773- r1116 | Added missing R_GetTextureColumn call for dcvars.prevcolumn.
774 (renderer)
775- r1117 | Use user pointer on Z_Malloc.
776 (renderer)
777- r1118 | Use normal malloc instead of Z_Malloc.
778 (renderer)
779 r1119 | Fix compiler warnings and a weird compiler error in Visual Studi
780 (VIDD)
781 r1120 | Updated to Visual Studio .NET 2003.
782 r1121 | Added test for ULL number suffix.
783 r1122 | Import r418 from trunk: Simplify event handling, logic is all in
784 r1123 | Update for new dmalloc API.
785 r1124 | Import r1115 from trunk, fixing dmalloc support. More consistent
786 r1125 | Merge r941 from trunk (plus Lee's comments from MBF): bodyqueue
787 r1126 | Import r707 from trunk, for bug #592350: Use M_ReadFile for Find
788 r1127 | Import r417 from trunk: No need for screenshot to be a gameactio
789- r1128 | Fix texture offset when using linear filter in software mode.
790 (renderer)
791- r1129 | Fixed bug #834202. Translucency setting wasn't saved. Patches ar
792 (renderer)
793 r1130 | Fixed several compiler warnings.
794 r1131 | Import r514 from trunk: Better inline asm from Eternity.
795 r1132 | Fast forward to given map # in demo playback.
796 r1133 | Fix desync caused by timing differences in intermission screen w
797+ r1134 | Intermission screen desync on secrets counter. for e.g. 30cn3519
798 (2.2)
799 r1135 | Another demo sync fix for Boom.
800 r1136 | monkeys, traditional_menu, sts_always_red and weapon_recoil set
801 r1137 | Import r712 from trunk (needed to complement r418 imported yeste
802- r1138 | Imported new colour translation code from SMMU/Eternity.
803 (renderer)
804 r1139 | Fixed a few warnings. Let z_zone.c compile on windows. Add defau
805 r1140 | Import r708 from trunk, needed to complement r707 imported yeste
806 r1141 | Ripped out tranmap caching.
807- r1142 | Don't initialise sound before I_Init().
808 (init sound)
809 r1143 | Import 2.3.x prboom.wad.
810 r1144 | Blazing door hitting an obstacle should make a blazing door soun
811- r1145 | Blazing door closing and hitting something should make a blazing
812 (blazing door sound)
813+ r1146 | Live monster counter for HUD, imported from stable_2.2 r1064.
814 (2.2)
815 r1147 | Another blazing door noise bug.
816+ r1148 | The new simplified z_zone implementation. It's just a wrapper ar
817 (z_zone)
818 r1149 | #include "z_zone.h", for malloc.
819+ r1150 | Clear tmthing after each tic - could be referencing a freed obje
820 (z_zone)
821+ r1151 | Demo fast forward to given map #, from stable_2.2.
822 (2.2)
823 r1152 | Fix autoconf warning.
824+ r1153 | Live monster counter now worksa with archville resurrections.
825 (2.2)
826 r1154 | Live monster counter now counts archville resurrections.
827+ r1155 | Fix r1142: need p_map.h for P_Map*.
828 (z_zone)
829 r1156 | Fix a possible SEGV due to tmthing holding a dangling pointer if
830- r1157 | Made patches and texture composites of the new software renderer
831 (renderer)
832+ r1158 | Added memory_size variable, which is the threshold at which purg
833 (z_zone)
834+ r1159 | Fixed long standing backspace printing bug on windows.
835 (was already merged)
836 r1160 | Fixed long standing backspace printing bug on windows.
837+ r1161 | Fixed missing 0 at end of string.
838 (was already merged)
839 r1162 | Fixed missing 0 at end of string.
840 r1163 | Add \n when printing HUD messages to console.
841 (console)
842+ r1164 | Fixed rather big memory leak.
843 (was already merged)
844 r1165 | Fixed rather big memory leak.
845- r1166 | Set edgeSloping when combining posts.
846 (renderer)
847 r1167 | Fixed config for new PubTal. Changed CSS a little bit.
848 r1168 | Generalised doors now make sounds appropriate to their speed. Th
849- r1169 | Fix sounds based on speed of generalised doors. Fix comp_sound i
850 (sounds)
851- r1170 | More original Doom like default settings.
852 (default settings)
853 r1171 | Padding for short REJECT lumps (fixes rq22-318.lmp and probably
854 r1172 | Make it possible to abort network checking on windows.
855- r1173 | Make it possible to abort network checking on windows.
856 (networking on windows)
857- r1174 | Completely removed G_ChangedPlayerColour.
858 (G_ChangedPlayerColor)
859- r1175 | Added portable snprintf. Compile with warnings as errors on wind
860 (psnprintf)
861- r1176 | Made some buffers bigger, so they will not overrun.
862 (buffers)
863- r1177 | Small enhancements and bugfixes from Eternity. Fix indentation.
864 (renderer)
865 r1178 | Removed limit on aliases (from Eternity). Small enhancements and
866 (console)
867- r1179 | Unify V_WriteText* and V_StringWidth* functions.
868 (font)
869 r1180 | Small enhancements and bugfixes from Eternity. Fix indentation.
870 (console)
871 r1181 | Fix compilation with gcc 3.4.x - inconsistency between header an
872 r1182 | Add calls to SMMU/Eternity net code.
873 (net)
874 r1183 | Fix dist target for newer autoconf.
875 r1184 | Enhanced Edition v1.9 demo support.
876 r1185 | Fix compilation of server.
877 (net)
878 r1186 | Implemented printing of tabs.
879+ r1187 | Implemented printing of tabs.
880 (was already merged)
881 r1188 | Fix crash when player respawns in multiplayer due to new P_MapSt
882 r1189 | Small fix from Eternity. Small code cleanups. Fix compilation of
883 (net)
884- r1190 | Fix bug #810566. Music stops playing after sound settings change
885 (sound)
886+ r1191 | Fix player respawn crashes with new P_MapStart/End
887 (z_zone)
888 r1192 | Updated.
889 r1193 | Bug fixes from Eternity. Small code cleanups. Enabled some more
890 (smmu fixes from eternity)
891 r1194 | Bugfixes from Eternity. Small code cleanups. Enabled more stuff.
892 (smmu fixes from eternity)
893+ r1195 | Renamed namespace to li_namespace.
894 (was already merged)
895+ r1196 | Removed stealth monsters, they weren't supported in the renderer
896+ r1197 | Ripped out the remaining stealth monster bits. The flags in p_mo
897 r1198 | Added psnprntf.* and m_fcvt.*.
898 r1199 | Added pastebin.
899 r1200 | Start level code also uses P_Map* and must be wrapped (else P_Ma
900+ r1201 | Start level code also uses P_Map* and must be wrapped (else P_Ma
901 (2.2)
902 r1202 | Small changes to css. Moved passwords outside of pastebin.php. R
903- r1203 | Don't use systems snprintf as replacement for psnprintf.
904 (psnprintf)
905- r1204 | Use psnprintf instead of snprintf or sprintf.
906 (psnprintf)
907 r1205 | Fix for newer autoconf.
908! r1206 | Fix prboom_3_compatibility savegames.
909 (savegame)
910+ r1207 | Longtics/EE support ported from stable_2.2.
911 (2.2)
912 r1208 | doom2.exe only used the first 10 deathmatch starts.
913+ r1209 | doom2.exe only used the first 10 deathmatch starts.
914 (was already merged)
915 r1210 | Transmit data for tic 0. This probably caused the first-tic desy
916 r1211 | Experimental proxy server between ipxsetup.exe's IPX networking
917 r1212 | Works now - fixed packet sizes and tic wrapping calcs.
918 r1213 | Make the backoff stronger, needed to need down the lag with doom
919 r1214 | Pack and pad the packet header struct, and ensure that the paddi
920 r1215 | Make demo noise a bit less intrusive.
921 r1216 | Prevent SEGV if server incorrectly give a bad consoleplayer numb
922 r1217 | Extra confirmation phase, to deal with clients that quit or lose
923 r1218 | MF_BLOCKMAP missing from Doom -> PrBoom flags conversion, and th
924 r1219 | non-SDL_net net code is gone. Remove makefile conditionals, as t
925 r1220 | Move GL_DOOM and COMPILE_VIDD from project settings to config.h.
926- r1221 | Avoid crash when prboom.wad is not found.
927 (IWAD switching)
928- r1222 | Avoid crash when the opengl extension string is too long.
929 (renderer)
930- r1223 | Fix printing of opengl extension. The length was calculated inco
931 (renderer)
932+ r1224 | Another fix for tabulators in the windows console window.
933 (was already merged)
934 r1225 | Backport of the fix for printing opengl extensions and the tabul
935 r1226 | Fix up .NET project files.
936 r1227 | updated.
937- r1228 | Fix compilation of prboom_server.
938 (psnprintf)
939 r1229 | Fix compilation of prboom_server.
940 r1230 | EE got called v1.91
941 r1231 | EE got called v1.91
942+ r1232 | Fix dehacked mobj bits conversion, cf r1218 from stable branch a
943 (was already merged)
944 r1233 | monster_backing off by default too.
945 r1234 | Fix my email address.
946 r1235 | Bring my email addresses up to date.
947 r1236 | PrBoom 2.2.5.
948 r1237 | PrBoom 2.3.0.
949 r1238 | Small fix to prevent unwanted newlines.
950 r1239 | Created tag for PrBoom 2.2.5.
951 r1240 | Bump version number.
952 r1241 | autoconf and rpm disagree about the use of an explicit platform
953 r1242 | Created tag for PrBoom 2.3.1.
954 r1243 | Bumped version number.
955 r1244 | Fix intermission screen splat/YaH code, which was crashing due t
956+ r1245 | Fix off-screen you-are-here's on Inferno intermission screens.
957 (was already merged)
958- r1246 | Don't play music when volume is 0.
959 (music volume 0)
960+ r1247 | Fix fuzz drawing for hi-re.
961 (was already merged)
962 r1248 | Fix fuzz drawing for hi-re.
963- r1249 | Fixed patch drawing with VPT_FLIP.
964 (renderer)
965 r1250 | updated.
966 r1251 | Fix hang when one network client exits.
967 r1252 | Update default server parameters to match the client.
968 r1253 | Fix some serious memory leaks.
969 r1254 | and news for the mem leak.
970 r1255 | Nicer diagnostics of player states.
971 r1256 | Fix NOSECTOR and NOBLOCKMAP effects in old dehacked patches.
972+ r1257 | Fix nosector/noblockmap mixup.
973 (was already merged)
974 r1258 | and the NEWS item for the deh fix.
975- r1259 | Set default netgame options the same as the default prboom.confi
976 (defaults)
977 r1260 | Fixed player spawn sound.
978+ r1261 | Fixed player spawn sound.
979 (was already merged)
980 r1262 | Player reborn TFOG bug.
981- r1263 | No oof sound on open 2S lines when comp_sound.
982 (sounds)
983+ r1264 | Quick hack to enable network client to ride over temporary loss
984 (was already merged)
985 r1265 | Use g_game.h instead of redefining stuff. Backspace repeat.
986+ r1266 | Bring into line with intended protocol, from stable branch.
987 (2.2)
988+ r1267 | Bring slightly more into line with my work from 2.2.x. r1048+r10
989 (was already merged)
990 r1268 | Created bundle folder remotely.
991 r1269 | Created bundle for prboom2.
992+ r1270 | Make I_WaitForPacket more useful, have a timeout.
993 (2.2)
994 r1271 | Repeat init packet - it might get lost or server is slow startin
995+ r1272 | fix last commit.
996 (was already merged)
997+ r1273 | Return time to next tick.
998 (2.2)
999- r1274 | Enable key repeat.
1000 (key repeat)
1001 r1275 | Remove unused consdata in ticcmd.
1002 (console)
1003 r1276 | Treat warnings as errors.
1004 r1277 | Fix some warnings.
1005 r1278 | Don't what I mean, not what I say :-). Don't call SDL_GetTicks t
1006 r1279 | More intelligent timing in TryRunTics.
1007 r1280 | Smarter delays in TryRunTics. Also, listen for network packets w
1008 r1281 | Use packet_set for PKT_TICC.
1009 r1282 | Shorter delay while waiting on packet, so windows users have the
1010 r1283 | Fix tntem cheat.
1011- r1284 | Fix HOM detection drawing.
1012 (renderer)
1013- r1309 | Fix bug [1046368] and patch [1199312].
1014 ()
1015DONE!
1016
1017--------------------------------------------------------------------------
1018
1019PrBoom-plus revisions since "Stuff to port from prboom-plus"
1020<http://sourceforge.net/mailarchive/message.php?msg_name=BE37299E-8C02-48FA-924B-6E9F8C5CCDC8%40gmx.net>
1021
1022 unexamined
1023+ done
1024% partially done
1025- of interest
1026? not sure
1027x not of interest
1028 ! needs attention
1029
1030+ r2312 | fix of hanging decoration disappearing in Batman Doom MAP02
1031? r2313 | comp[comp_oofsound] - done
1032+ r2319 | the global variable r_NoInterpolate is not necessary any more (s
1033+ r2320 | don't thrash cpu during pausing (should be applied to prboom)
1034+ r2321 | do nothing if a pause has been pressed during playback. pausing
1035x r2322 | "-auto" for autoloading of wads according to the lmp file-name
1036?! r2323 | correction of smart items clipping code: not a fully dead corpse
1037?! r2324 | heh, previous commiting was unsaved version.fixed
1038?! r2325 | there are three modes of sprite clipping in opengl:
1039?! r2326 | gl_sprite_offset moved to globals; things with MF_MISSILE should
1040?! r2327 | some comment changed
1041+ r2328 | fixed(?) cph's bug(?) introduced in r1431
1042+ r2329 | fix for 2328. maybe better possible
1043x r2330 | bug with def_arr type (Z_Realloc do not fill additional region o
1044+ r2331 | comp_doorstuck should be forced for boom201 compatibility (at le
1045x r2332 | launcher
1046+ r2333 | cph's one more bug: The current behaviour with comp_666 is that
1047+ r2334 | Check for prevention of possible collisions between level of com
1048+ r2335 | revert to r2333
1049+ r2336 | Additional check of gameepisode in A_BossDeath is added, because
1050?! r2337 | small fix for opengl, sky and mouselook
1051x r2338 | progress bar during demo playback works during skipping
1052x r2339 | minimization of distinctions with trunk
1053x r2341 | Merged r2304:2340 from trunk
1054- r2342 | Optional removal of a quit sound delay (it is old Prboom-Plus's
1055- r2344 | Improved support for Doom v1.2:
1056x r2345 | - the progress bar did not work correctly for demos with more th
1057x r2346 | Predefined translucency setting (comp_translucency) should not o
1058x r2347 | Prevention of division by zero in G_DoPlayDemo() if players coun
1059+ r2348 | Handling of unrecognized demo formats
1060+ r2349 | fix for r2348 (Doom v1.2 demos)
1061+ r2350 | comments
1062x r2351 | Files for -auto should be searched in all standard places: curre
1063x r2352 | Sometimes the figures for kills, items, etc., stop getting updat
1064? r2353 | warning C4018: '==' : signed/unsigned mismatch
1065x r2356 | to avoid conflicts prboom-plus.wad should be added with full pat
1066x r2357 | launcher
1067x r2358 | launcher again
1068x r2359 | launcher again again
1069x r2360 | added I_vWarning() function
1070? r2361 | I_FindFile: searching exe dir before current dir, check wfname a
1071+ r2362 | Better compatibility with boom v2.01. There are no more desync o
1072+ r2363 | fix for r2362
1073+ r2364 | demover is global now. it's required for demos recorded in "demo
1074+ r2365 | Three separate definitions of max and min are moved in doomtype.
1075x r2366 | Compilation fixes:
1076+ r2367 | max, min are renamed to MAX, MIN to avoid all possible warnings
1077+ r2368 | removing unnecessary code (after r2367)
1078?! r2369 | spriteclip code shouldn't be applied to things with MF_NOGRAVITY
1079x r2370 | Removed files and folders with compiled pcre libs
1080x r2371 | pcre projects are added to main solution
1081? r2372 | New savegame format with continuous numbering. Now it is not nec
1082? r2373 | missed PACKAGEVERSION in VisualC6\config.h
1083? r2374 | ALL_IN_ONE define for having PrBoom-Plus.wad in the exe (win32 o
1084? r2375 | fix compilation
1085x r2376 | Merged r2340:2355 from trunk
1086+ r2377 | Fixed mbf_compatibility incompatibility. There is no more desync
1087x r2378 | Demo Progress Bar during skipping will be updated not more often
1088x r2380 | All-in-one doesn't find resource wad when using -auto
1089+ r2381 | "All boss types can trigger tag 666 at ExM8" -> "Emulate pre-Ult
1090+ r2382 | There is no more crashes on boom200 demos (wrongly header readin
1091+! r2383 | Animated middle textures with a zero index should be forced.
1092?! r2384 | New mouse code without SDL lags. Win32 mouse handling was remove
1093+ r2385 | non traditional menu was removed to avoid bugs with Alien Vendet
1094?! r2386 | New mouse code: Sounds as nonsense, but SDL mouse lags are depen
1095? r2387 | do not clear events queue at the start (like vanilla)
1096?! r2388 | some comments about new mouse code
1097?! r2389 | There is no more win32 specific code in new mouse code. Now it w
1098x r2390 | launcher: wrong strings in history combo
1099- r2391 | sound_noquitsound is renamed to misc_fastexit
1100?! r2392 | missed SDL_WM_GrabInput(SDL_GRAB_OFF)
1101+ r2393 | do not process mouse input in menu because it's buggy and annoyi
1102x r2394 | Merged r2355:2379 from trunk
1103% r2395 | fix some compilation problems on MAC and POSIX
1104?! r2396 | very small improvement
1105+ r2397 | Fixed Boom incompatibilities. There are no more desyncs on Donce
1106+ r2398 | Fixed Boom incompatibilities. Original friction and bobbing code
1107x r2399 | bump version to 2.4.8.2
1108x r2400 | REJECT overflow cannot be emulated if the REJECT size is not div
1109x r2401 | Not used function (RejectOverrunAddInt) has been removed
1110?! r2402 | Boom's color maps are supported in OpenGL mode
1111?! r2403 | Boom's colormaps: some comments are added
1112?! r2404 | Effect of invulnerability uses a colormap instead of hard-coding
1113?! r2405 | comp[comp_skymap] works in OpenGL mode now;
1114x r2406 | "Paper Items" setting is not applied to hanging things.
1115x r2407 | always grab the mouse in camera mode when playing levels and men
1116- r2408 | [-] PrBoom bug: %DOOMWADDIR% had no effect for PWADs.
1117?! r2409 | Boom's colormaps in OpenGL: fix crash in gld_Precache
1118-! r2410 | New mus -> mid conversion code thanks to Ben Ryves <benryves@ben
1119?! r2411 | [-] new invulnerability/colormap handling in
1120-! r2412 | some new files are removed before readding with corrected eol st
1121-! r2413 | New mus2mid conversion code. All tabs are replaced with spaces.
1122-! r2414 | Fixed eol style of files
1123? r2415 | fix compilation with vc2005
1124x r2416 | check of bounds of the matched part in autoplaydemo mode for cor
1125x r2417 | PCRE_NOTBOL flag is removed from regexec(). Not needed.
1126-! r2418 | A bug with the new music code: midi files (i.e. directly placed
1127x r2421 | fix warning with vc6
1128x r2422 | Merged r2379:2420 from trunk
1129+ r2424 | [-] Strip of rendered graphics appears under status bar
1130+ r2425 | fix for r2424 and OpenGL
1131x r2426 | Merged r2420:2423 from trunk
1132+ r2430 | fix for r2424 and MP: SP status bar displayed for DM
1133?! r2431 | Attempt to fix the bug #1653750: With OpenGL rendering, many of
1134-! r2432 | Make it compile on Mac OS X again. Music is disabled for now.
1135-! r2433 | Make music work again.
1136-! r2440 | better math: there are no more strips of rendered graphics (at 6
1137- r2441 | Fixed incompatibility with original EXE's (complevels 0..6) on l
1138? r2442 | Dynamic calculation of PACKAGEVERSION
1139x r2443 | duplicated code after old merge
1140? r2444 | global BETWEEN define
1141+ r2445 | In PRBoom the player's weapon is displayed much darker than in o
1142 r2446 | Boom's colormaps in OpenGL: fix for idbeholdl+idbeholdv
1143 r2449 | PrBoom-Plus bug: When radsuit ends, palette changes w/o warning
1144 r2450 | When playing back with -recordfromto, and before resuming record
1145 r2451 | Issue with lines (boxes) that appear around the elements that ch
1146 r2452 | small optimization of gld_InitGLVersion()
1147 r2453 | Post-process the texture data after the buffer has been created.
1148 r2460 | Fixes to the posix build system:
1149 r2462 | Improved support for Doom v1.2
1150 r2463 | Reorganization of the code for looking for bex/deh patches in al
1151 r2466 | Make "Not all required files are found" more user-friendly
1152 r2467 | [-] When a file with the bex extension is used in an autoloading
1153 r2468 | Correction for DEHs which swap the values of two strings.
1154 r2469 | interpolation for weapon bobbing
1155 r2470 | Two-pass method for better usability of automap:
1156 r2471 | New command-line switch "-emulate prboom_ver" for emulation of o
1157 r2473 | Kills/Items/Secrets percentage reported wrong if too high
1158 r2474 | -emulate and -force_* command-line switches work only during dem
1159 r2475 | comp_sound has been merged with comp_oofsound and moved to the c
1160 r2476 | - "Zombie players can exit levels"
1161 r2479 | bugs if USE_VERTEX_ARRAYS not defined
1162 r2480 | Add PC speaker code from chocolate-doom
1163 r2481 | added pcsound library
1164 r2482 | Boom's colormaps in OpenGL: memory leak
1165 r2483 | Do not clear video memory after loading on same level
1166 r2484 | (f)printf => lprintf in PCSOUND files
1167 r2485 | bug introduced in r2482 - wrong indexes were used
1168 r2486 | PrBoom bug: Par times are not shown
1169 r2487 | Sometimes the pistol sounds that play while the tallies are bein
1170 r2488 | Has made compatible my correction of par times (r2486) with "-au
1171 r2489 | fix "-emulation" code
1172 r2490 | let's show the warning if savegame is from the previous version
1173 r2491 | has made dynamic changing of gamespeed more smooth
1174 r2492 | "-force_lxdoom_demo_compatibility" comman-line switch for emulat
1175 r2493 | On ExM8 of movie runs, the total time is often displayed wrong.
1176 r2494 | -force_lxdoom_demo_compatibility: there are no more desynchs on
1177 r2495 | The ultimate 'ATI sucks' fix: Some of ATIs graphics cards are so
1178 r2496 | big comment for r2473:
1179 r2497 | fix for demoprogressbar with veeeeeeery long demos on high resol
1180 r2498 | fix compilation problems
1181 r2499 | gl_render_precise variable for control of the new seamless code
1182 r2500 | Move the window to the screen center if stupid SDL create it in
1183 r2501 | Fix crash when the program wants to S_AdjustSoundParams() for pl
1184 r2502 | The local variable should be used in G_ReadDemoHeader() instead
1185 r2503 | check for overrun in G_ReadDemoHeader()
1186 r2504 | allow -recordfromto for all levels of compatibility
1187 r2505 | "-emulate prboom_ver" includes bug with direct switch to SSG in
1188 r2506 | huge speedup (up to 10x) on levels with sectors which have many
1189 r2507 | fix for r2506
1190 r2508 | -emultae prboom-ver stuff: few new entries are added
1191 r2509 | Monsters spawned by Icon of Sin should not be countable for tota
1192 r2510 | comment for previous commit (r2509)
1193 r2511 | S_DISABLE and CR_DISABLE for disabled items in menu to avoid bug
1194 r2512 | Sound initialization was broken in r2508 if "-skipsec" command-l
1195 r2513 | Attempt to revert some old changes made in prboom+. Probably all
1196 r2514 | A lot of cleanups, speedups and bugfixes in render:
1197 r2515 | Avoid crashes at end of demos if DEMOMARKER (0x80) does not exis
1198 r2516 | fix for r2515
1199 r2517 | fix for r2506 (huge speedup on levels with sectors which have ma
1200 r2518 | Fox for "The ultimate 'ATI sucks' fix" (r2495)
1201 r2519 | fix compilation problems
1202 r2520 | Compatibility with common mapping errors "linedefs w/o tags appl
1203 r2521 | M_DoScreenShot did not work with "-videodriver directx" on fulls
1204 r2522 | Optimization of "quality" mode of "rendering quality" setting. V
1205 r2523 | fix compilation problems
1206 r2524 | Do not use seamless code ("quality" mode) in software mode
1207 r2525 | missed M_ChangeGLRenderPrecise call
1208 r2526 | In GL mode, the IDRATE info for sprites is always displayed as 0
1209 r2527 | Try to fix building prboom-plus under linux again.
1210 r2528 | Optimization of "quality" mode of "rendering quality" setting. F
1211 r2529 | fix r2513: statusbar were not updated in automap mode on softwar
1212 r2530 | There is no more visual glitches with sky on Icarus map14 and He
1213 r2531 | nothing. comment.
1214 r2532 | Fix of no warning (flashes between shadowed and solid) when invi
1215 r2533 | PrBoom bug: When putting -devparm in the command line, prboom-pl
1216 r2534 | Do not rebuild blockmap on the same level (after save/load)
1217 r2535 | Blinking during demoskip on fullscreen
1218 r2536 | Don't thrash cpu if the window doesnt have focus
1219 r2537 | Original P_FindNextHighestFloor() is restored for demo_compatibi
1220 r2538 | Ability to force -nomonsters and -respawn for playback of 1.2 de
1221 r2539 | 1. gl_boom_colormaps config's variable to reduce memory use
1222 r2540 | USE_GLU_IMAGESCALE is temporarily enabled to avoid some bugs
1223 r2541 | optimization: make heightlist static to avoid malloc/free pair i
1224 r2543 | DemoProgresBar continued to be displayed for in-wad demos (demo1
1225 r2544 | There are TWO bugs in the ouch face code. Not only was the condi
1226 r2545 | Move mouse sensitivity menu upwards a little to avoid overlap wi
1227 r2546 | The bug in algorithm of splitting of a sector into the closed co
1228 r2547 | There is a new command-line switch "-shorttics". This makes it p
1229 r2548 | fix compilation problem
1230 r2549 | Fix compilation on Mac OS X.
1231 r2550 | fix sound origin for large levels
1232 r2551 | fix previous revision r2550
1233 r2552 | Premature program exit during map26 in 4-player coop demo 29uv4p
1234 r2553 | dded two new precalculated float fields in GLTexture struct
1235 r2554 | Wrong calculation of x2 coordinate of a weapon in gld_DrawWeapon
1236 r2555 | fix for r2554
1237 r2556 | M_ChangeFOV() and M_ChangeGLRenderPrecise() should be under cond
1238 r2557 | two video pages should be cleared in gld_Init to avoid blink dur
1239 r2558 | Remove any line which has a clone with the same vertexes and ori
1240 r2559 | "Allow Boom colormaps" setting => "Allow colormaps"
1241 r2560 | wipe screen effect in OpenGL
1242 r2561 | wipe screen effect in OpenGL: fix memory overflow
1243 r2562 | fixed slowdown during screen melt at 1024x768 on some systems
1244 r2563 | fix menu bug after r2560 (wipe screen effect in OpenGL)
1245 r2564 | Changes in algorithm of GL wipe. Now it works more quickly, requ
1246 r2565 | Add gl_wipe.c to src/Makefile.am
1247 r2566 | Transferred sky texture on scrolled wall was not scrolled if mou
1248 r2567 | merge R_CheckTextureNumForName from prboom
1249 r2568 | Fix compilation on Mac OS X: add gl_wipe.c to src/MAC/Rakefile
1250 r2569 | vertical scroll on transferred sky texture works now too (if mou
1251 r2570 | scroll stuff from the latest revisions is temporally disabled
1252 r2571 | scroll on transferred sky texture is enabled again
1253 r2572 | [-] GL wipe: white screen during final screen animation in some
1254 r2573 | sky property-transfer linedef types should be applied only for M
1255 r2574 | sky transfer under prboom_comp now
1256 r2575 | Reuse of a current palette to avoid black screen at software ful
1257 r2576 | unnecessary (duplicated) call of UpdateGrab() is removed from D_
1258 r2577 | More adequate warning of possibility of desynch in compatibility
1259 r2578 | from chocolate-doom r958: Initialise tracksize variable before m
1260 r2580 | hires textures
1261 r2581 | hires:
1262 r2582 | hires patches
1263 r2583 | fake colormaps for hires patches
1264 r2584 | fix progress of load hires on fullscreen
1265 r2585 | hires: fix for hires patches and sts_always_red; optimization of
1266 r2586 | hires: another fix for progress bar
1267 r2587 | all gluBuild2DMipmaps entries had wrong second parameter: gl_tex
1268 r2588 | caching of non power of two hires textures. it speed up loading
1269 r2589 | Import the clipper code from gzdoom. Thanks to GrafZahl. PrBoom
1270 r2592 | new defaults
1271 r2593 | Type of useType in gl_hires.c/gld_HiresGetTextureName was unknow
1272 r2594 | HAVE_LIBSDL_IMAGE stuff: sources now are compilable even if you
1273 r2595 | configure.in: Test for SDL_image being installed.
1274 r2600 | duplicated items are removed in prboom-plus.wad
1275 r2601 | fix compilation problems with msvc2005
1276 r2602 | another fix compilation problems with msvc2005
1277 r2603 | definition for hires textures on MAC
1278 r2605 | plus needs SDL_image
1279 r2606 | Don't redefine M_PI when already defined; reduces compiler spew
1280 r2607 | Find hires textures on more platforms and with less case sensiti
1281 r2608 | Find hires textures in lowercase in cases of case-sensitive file
1282 r2609 | fix SEGV in HU_Start() when gamemap is not initialized
1283 r2610 | update docs
1284 r2611 | History is no longer stored on the Internet
1285 r2612 | strlwr is not portable
1286 r2613 | Update doc/Makefile.am to include prboom-plus-* documentation fi
1287 r2614 | Check for strlwr in configure.in (used in gl_hires.c)
1288 r2615 | Fixed crash in M_ResetDefaults().
1289 r2616 | fixed bug if translucency percentage is less than 50, then all t
1290 r2618 | Disabling transparency in OpenGL for original sprites which are
1291 r2619 | typo
1292 r2620 | allowing to bind mouse buttons through in-game menu was broken i
1293 r2621 | fix bug during recording non-compatible demos (complevel >= 9) w
1294 r2622 | do not update progress of loading hires more often than 35 times
1295 r2623 | Support for DDS format of hires textures. DDSes can be loaded wi
1296 r2624 | config.h: do not link SDL_image.lib if HAVE_LIBSDL_IMAGE is not
1297 r2625 | do not update progress of hires loading if no real hires was loa
1298 r2626 | configurable level of aniso (from in-game menu Off..16x)
1299 r2627 | Better distinguish the PrBoom launcher from the PrBoom Plus one
1300 r2628 | execution time of gld_Precache() -> stdout.txt
1301 r2629 | Mouse look did not work on automap in overlay mode.
1302 r2630 | Do not try to find hires textures in non existing dirs over and
1303 r2631 | universal SNPRINTF instead of
1304 r2632 | Applying SNPRINTF for whole code
1305 r2633 | small fix for SNPRINTF (defines)
1306 r2634 | wrong index in launcher. how it worked earlier?
1307 r2635 | Technique of rendering to texture; Real black and white effect f
1308 r2636 | some compatibility stuff with new invul effect and old hardware
1309 r2637 | More 'real' invul effect without using colormaps (needs opengl 1
1310 r2638 | More informative message if frame buffer object (FBO) has not be
1311 r2639 | GL_RGBA8 for SceneImageTextureFBO instead of gl_tex_format. Is i
1312 r2640 | Do not try to create a frame buffer if GL_EXT_framebuffer_object
1313+ r2641 | Ability to use only the allowed CPUs. For example it is necessar
1314+ r2642 | %d for GetLastError() instead of %s of course
1315 r2643 | gl_compatibility variable; all OpenGL extentions will be disable
1316 r2644 | FBO: cleanup
1317 r2645 | An alternative way of drawing the sky was added (gl_drawskys ==
1318 r2646 | Solution for Visual Studio 2008.
1319 r2647 | Bump version number to 2.4.8.3
1320 r2648 | OpenGL: Fake contrast should add/remove one light level for wall
1321 r2649 | Fix condition for bringing up the launcher if SHIFT key is press
1322 r2650 | fix Visual Studio 2008 solution
1323 r2651 | help_friends is zero by default now, because it super slow. I ha
1324 r2652 | wrong GL_TEXTURE_MAG_FILTER for detail texture
1325 r2653 | fixed bug in gl wipe
1326 r2654 | Fix bug in new clipper code. Some unnecessary lines were drawn.
1327 r2655 | Do not use FBO for all frames. Should be used only if motion blu
1328 r2656 | Never grab the mouse when window does not have focus
1329 r2657 | Check and fix wrong references to non-existent vertexes in SEGS
1330 r2658 | More informative warning for previous revision
1331 r2659 | Disable demo recording on levels with invalid nodes (see previou
1332 r2660 | fix for error quit message in r2659
1333 r2661 | More precise rotation of sprite if render_paperitems is equal to
1334 r2662 | Additional sector light mode was added (Options\General\Sector L
1335 r2665 | Fix compilation on Mac OS X 10.5 when using 10.4u SDK.
1336 r2667 | _exit() instead of ExitProcess() for "-resetgamma"
1337 r2668 | Restore of startup gamma if window loses focus
1338 r2669 | fix compilation problems
1339 r2672 | Unknown gl nodes will be ignored instead of I_Error message
1340 r2673 | Avoid zdoom's code in additional sector light mode. Now it is fr
1341 r2674 | optimization of sprite rotation
1342 r2675 | Restoring original visual behaviour for demo_compatibility. View
1343 r2676 | Ability to play wads with wrong flat names. Unknown flats will b
1344 r2677 | Make missing sounds non-fatal. Makes sense for doom.wad v1.2 for
1345 r2678 | fix bug of r2674
1346 r2679 | Revert r2530. Icarus map14 and Hell Revialed map20 will have pro
1347 r2680 | Refactor the intercepts overrun code so that it should work prop
1348 r2681 | Launcher (win32): Now you can associate the current EXE with DOO
1349 r2682 | New logic in music detection code from chocolate-doom.
1350 r2683 | sky property-transfer linedef types will be applied for boom com
1351 r2684 | Try to fix SmoothEdges on big endian systems; fixes sprite issue
1352 r2685 | refix SmoothEdges for little endian and tabs replaced with space
1353 r2686 | Fix bug with sky in the bottom part of an imaginary skybox aroun
1354 r2687 | opengl: more correct (similar to software) drawing of skies with
1355 r2688 | Clear the screen to black in V_AllocScreen(). Makes sense for wi
1356 r2689 | there is no restriction for length of midies. fix for r2682
1357 r2690 | process_affinity_mask is 1 by default
1358 r2691 | another try to fix problem with sky on map14 @ Icarus.wad sector
1359 r2696 | Fixed some warnings about uninitialized/unused variables and shu
1360 r2700 | Merged r2423:2699 from trunk (hicolor)
1361 r2701 | Advanced syntax for -geom command-line switch
1362 r2702 | Fix compilation. GCC doesn't like casted lvalues: (byte *)psrc -
1363 r2705 | fix for latest merge r2700 and r2440
1364 r2707 | added description to r_screenmultiply.c.h;
1365 r2708 | Screens works now for non 8-bit modes in software (16-bit, 32-bi
1366 r2712 | dogs
1367 r2719 | Merged r2699:2718 from trunk
1368 r2723 | Speed up in R_PointToAngleEx() in software mode
1369 r2726 | Merged r2718:2725 from trunk
1370 r2727 | gl_render_precise now is known as render_precise and applies to
1371 r2728 | comment added for r2727
1372 r2729 | better code for r2723
1373 r2730 | lower memory usage if glcolormaps are used
1374 r2731 | Clean the memory from GL textures, etc in I_ShutdownGraphics
1375 r2732 | Simplification of the code for the previous revision r2731
1376 r2733 | Speedup of level reloading in OpenGL mode
1377 r2735 | Fixed error in OpenGL if upper texture on the linedef with "Tran
1378 r2742 | Merged r2725:2741 from trunk
1379 r2743 | Fixed bug with GL gamma in GZDoom mode for some buggy drivers:
1380 r2744 | Use MEM_SEEK_SET for memio, not SEEK_SET (from chocolate-doom an
1381 r2755 | Fix for r2733 (Speedup of level reloading in OpenGL mode):
1382 r2756 | Remove duplicate declaration of G_ReadDemoHeader in e6y.h
1383 r2757 | Fix {m,c}alloc_IfSameLevel build failure
1384 r2758 | comperr_hangsolid: Pretend there's a fake ceiling under a body
1385 r2761 | explicit type was missed in r2733
1386 r2762 | Removal of duplicates from cfg.
1387 r2763 | Fix for r2682: non-MUS/MIDI music (MOD, S3M, etc) was broken the
1388 r2764 | Fixed crash (Not enough storage is available to process this com
1389 r2765 | Fixed crash if numbers of wads/lmps/dehs is greater than 100.
1390 r2766 | Fix vanilla unprecise calculation (vibrations) of the texture co
1391 r2767 | Fix wrong processing of the "Blue Armor Class" string from a DEH
1392 r2768 | Fix wrong processing of the "Green Armor Class" string from a DE
1393 r2769 | comments for the previous two revisions
1394 r2770 | Ability to play demos recorded with old prbooms with wrong proce
1395 r2771 | Previous fixes for wrong processing of armor classes from a deh
1396 r2772 | Pump the event loop (SDL_PumpEvents) in I_InitInputs() before fi
1397 r2773 | New 'mixed' lighting mode for opengl. It uses gamma ramps like i
1398 r2774 | hardware gamma stuff has been moved to gl_gamma.c
1399 r2775 | Fix build failure, add new file gl_gamma.c to src/Makefile.am
1400 r2776 | Fix compilation with MSVC2008
1401 r2777 | There is no more necessity to restart glboom after change of tex
1402 r2778 | Fix compilation problems for nongl configurations
1403 r2779 | More accurate patch drawing. Predefined arrays are used instead
1404 r2780 | fix gamma in glboom mode (introduced in r2773, r2774)
1405 r2781 | refix "Respawn frame" part of r2117
1406 r2782 | "Flashing HOM indicator" option did nothing. Fixed.
1407 r2783 | Ability to use negative numbers with -skipsec switch. "-skipsec
1408 r2784 | Fixed crash in case if WI_drawOnLnode will try to get access to
1409 r2785 | Added demo compatibility with chex.exe
1410 r2786 | The latest column of patches was not drawn. Introduced in r2779
1411 r2787 | The level of compatibility at which fix for comp_stairs should b
1412 r2788 | fixed stupid mistake in chex stuff (r2785)
1413 r2789 | key_setup was not saved in cfg
1414 r2790 | detection of more unsupported demo formats
1415 r2791 | Texture bug. GL only. Example in ksutra.wad map15, "COOL!" area.
1416 r2792 | videodriver name now saved in cfg
1417 r2793 | The fourth episode for pre ultimate doom complevels is not allow
1418 r2794 | More precise weapon drawing in GL: there is no more line of grap
1419 r2795 | make GL stuff from the previous revision (r2794) under GL_DOOM d
1420 r2796 | One more 'ATI sucks' revision.
1421 r2797 | fixed anisotropic filtering. 16x now is 16x instead of 4x
1422 r2798 | Prepare for release 2.4.8.3.
1423 r2799 | missed change log entries
1424 r2801 | Text mode emulation code from Chocolate-Doom
1425 r2802 | New application icon and loading it through SDL
1426 r2803 | Updated MSVC project files for using text mode emulation code
1427 r2804 | ENDOOM support using text mode emulation
1428 r2805 | missed icon.c and python script from chocolate-doom for generati
1429 r2806 | Add textscreen to autotools
1430 r2807 | Add icon.c and doomkeys.h to autotools
1431 r2808 | quick and lazy fix for memory overrun introduced in r2779
1432 r2809 | Restore version banner output on exit
1433 r2810 | -r2766
1434 r2811 | Separate out list of extensions to be added to music_tmp
1435 r2812 | Construct temporary filename from music_tmp with extension added
1436 r2813 | I_ShutdownMusic: delete music_tmp and all its possible extension
1437 r2814 | Minor music_tmp-related fixes
1438 r2815 | prevent recursive exits
1439 r2816 | stop music before shutdown
1440 r2817 | New algorithm for detection of fake flats and ceilings. It is mu
1441 r2818 | Fix build failure, add new file gl_missingtexture.c to src/Makef
1442 r2819 | r2817+: better handling of fake floors/ceilings for sectors with
1443 r2820 | bump version to 2.4.8.4
1444 r2821 | Update docs and change log
1445 r2822 | Fixed compilation on Mac?
1446 r2823 | added gl_gamma to Rakefile
1447 r2824 | Shift Mac build to 10.5 target
1448 r2825 | Remove headers from mac build
1449 r2827 | bump version to 2.4.8.5
1450 r2828 | Fixed crash when nodes used for in-wad demo playback are not equ
1451+ r2829 | Set processor affinity under non-Windows platforms using the POS
1452+ r2830 | random symbol after #endif
1453+ r2831 | I_SetAffinityMask() has moved to i_main.c from e6y.c
1454+ r2832 | Fix compilation on *nix
1455 r2833 | Eating of Alt-Tab event to prevent switching to the automap afte
1456 r2834 | Stupid bug in deh processing. Thanks Death-Destiny for the hint
1457 r2835 | Fixed old bug in searching responsefile.
1458 r2836 | fixed crash with @responsefile
1459 r2837 | change log for 2.4.8.5
1460 r2838 | bump version to 2.4.8.6
1461+ r2839 | For now, set a no-op I_SetAffinityMask for the Mac
1462 r2850 | Resolution limitation is removed. Memory usage has decreased as
1463 r2852 | fixed crash if screenblocks is not equal to 11 (introduced in th
1464 r2853 | fixed hi-color modes for r2850
1465 r2863 | fixed bug with caching planes heights (introduced in r2850)
1466 r2864 | "PrBoom-Plus" -> PACKAGE_TITLE
1467 r2865 | Temporarily define PACKAGE_TITLE in configure.in and MAC/config.
1468 r2866 | launcher_enable variable now has three values: "never", "smart"
1469 r2891 | Status Bar was affected by light level of the sector on some on-
1470+ r2892 | Fixed crash with FixedDiv(-2147483648,x)
1471+ r2893 | added comment for the previous revision r2892 to know what happe
1472+ r2894 | 2892++ (more detailed comment for crash in FixedDiv)
1473 r2907 | Unused ConvertMus() is removed. There are no more compiling erro
1474 r2912 | fix for r2793: do not try to show the fourth episode in menu for
1475 r2913 | Trying to optimise screen pitch for reducing of CPU cache misses
1476 r2914 | changed formatting of stdout for the previous revision (r2913)
1477 r2915 | fixed bug in r2817?
1478 r2916 | another try of r2766: Fix vanilla unprecise calculation (vibrati
1479 r2917 | fixed wipe in software
1480
1481--------------------------------------------------------------------------
1482
1483Unresolved issues mentioned in the Doomworld thread since 2.4.7
1484http://www.doomworld.com/vb/source-ports/23525-prboom-issues-thread/
1485
1486- http://www.doomworld.com/vb/post/644107
1487 mbf options lumps (bad idea, dehacked changing cheats is annoying enough)
1488- http://www.doomworld.com/vb/post/648619
1489 suggestion to steal chocolate-doom's netgame code
1490- http://www.doomworld.com/vb/post/654924
1491 cheat codes don't work in -altdeath in single player but do in vanilla
1492- http://www.doomworld.com/vb/post/699446
1493 http://www.doomworld.com/vb/post/700314
1494 http://www.doomworld.com/vb/post/712531
1495 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 @@
1/* config.h. Generated from config.h.in by configure. */
2/* config.h.in. Generated from configure.ac by autoheader. */
3
4/* Uncomment this to exhaustively run memory checks while the game is running
5 (this is EXTREMELY slow). */
6/* #undef CHECKHEAP */
7
8/* Define for support for MBF helper dogs */
9#define DOGS 1
10
11/* Define to be the path where Doom WADs are stored */
12#define DOOMWADDIR "/usr/local/share/games/doom"
13
14/* Define if you are building with OpenGL support */
15//#define GL_DOOM 1
16
17/* Define to 1 if you have the <asm/byteorder.h> header file. */
18//#define HAVE_ASM_BYTEORDER_H 1
19
20/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you
21 don't. */
22#define HAVE_DECL_SYS_SIGLIST 1
23
24/* Define to 1 if you have the `getopt' function. */
25#define HAVE_GETOPT 1
26
27/* Define to 1 if you have the `inet_aton' function. */
28#define HAVE_INET_ATON 1
29
30/* Define to 1 if you have the `inet_ntop' function. */
31#define HAVE_INET_NTOP 1
32
33/* Define to 1 if you have the `inet_pton' function. */
34#define HAVE_INET_PTON 1
35
36/* Define to 1 if you have the <inttypes.h> header file. */
37#define HAVE_INTTYPES_H 1
38
39/* Define if you have struct sockaddr_in6 */
40//#define HAVE_IPv6 1
41
42/* Define to 1 if you have the `m' library (-lm). */
43//#define HAVE_LIBM 1
44
45/* Define to 1 if you have the `png' library (-lpng). */
46//#define HAVE_LIBPNG 1
47
48/* Define to 1 if you have the `SDL_mixer' library (-lSDL_mixer). */
49/* #undef HAVE_LIBSDL_MIXER */
50
51/* Define if you have the SDL net library -lSDL_net */
52/* #undef HAVE_LIBSDL_NET */
53
54/* Define to 1 if you have the <memory.h> header file. */
55#define HAVE_MEMORY_H 1
56
57/* Define to 1 if you have the `mmap' function. */
58#define HAVE_MMAP 1
59
60/* Define if you want network game support */
61#undef HAVE_NET
62
63/* Define to 1 if you have the <sched.h> header file. */
64#define HAVE_SCHED_H 1
65
66/* Define to 1 if you have the `sched_setaffinity' function. */
67#define HAVE_SCHED_SETAFFINITY 1
68
69/* Define to 1 if you have the `SDL_JoystickGetAxis' function. */
70#define HAVE_SDL_JOYSTICKGETAXIS 1
71
72/* Define to 1 if you have the `snprintf' function. */
73#define HAVE_SNPRINTF 1
74
75/* Define to 1 if you have the <stdint.h> header file. */
76#define HAVE_STDINT_H 1
77
78/* Define to 1 if you have the <stdlib.h> header file. */
79#define HAVE_STDLIB_H 1
80
81/* Define to 1 if you have the <strings.h> header file. */
82#define HAVE_STRINGS_H 1
83
84/* Define to 1 if you have the <string.h> header file. */
85#define HAVE_STRING_H 1
86
87/* Define to 1 if you have the <sys/stat.h> header file. */
88#define HAVE_SYS_STAT_H 1
89
90/* Define to 1 if you have the <sys/types.h> header file. */
91#define HAVE_SYS_TYPES_H 1
92
93/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
94#define HAVE_SYS_WAIT_H 1
95
96/* Define to 1 if you have the <unistd.h> header file. */
97#define HAVE_UNISTD_H 1
98
99/* Define to 1 if you have the `usleep' function. */
100#define HAVE_USLEEP 1
101
102/* Define to 1 if you have the `vsnprintf' function. */
103#define HAVE_VSNPRINTF 1
104
105/* Uncomment this to cause heap dumps to be generated. Only useful if
106 INSTRUMENTED is also defined. */
107/* #undef HEAPDUMP */
108
109/* Define for high resolution support */
110//#define HIGHRES 1
111
112/* Define on targets supporting 386 assembly */
113//#define I386_ASM 1
114
115/* Define this to see real-time memory allocation statistics, and enable extra
116 debugging features */
117/* #undef INSTRUMENTED */
118
119/* If your platform has a fast version of max, define MAX to it */
120/* #undef MAX */
121
122/* If your platform has a fast version of min, define MIN to it */
123/* #undef MIN */
124
125/* Name of package */
126#define PACKAGE "prboom"
127
128/* Define to the address where bug reports for this package should be sent. */
129#define PACKAGE_BUGREPORT ""
130
131/* Define to the full name of this package. */
132#define PACKAGE_NAME "prboom"
133
134/* Define to the full name and version of this package. */
135#define PACKAGE_STRING "prboom 2.5.0"
136
137/* Define to the one symbol short name of this package. */
138#define PACKAGE_TARNAME "prboom"
139
140/* Define to the version of this package. */
141#define PACKAGE_VERSION "2.5.0"
142
143/* Set to the attribute to apply to struct definitions to make them packed */
144#define PACKEDATTR __attribute__((packed))
145
146/* Define to enable internal range checking */
147/* #undef RANGECHECK */
148
149/* Define if you have an old SDL_net, such that the UDPpacket structure has a
150 src member instead of an address member */
151/* #undef SDL_NET_UDP_PACKET_SRC */
152
153/* When defined this causes quick checks which only impose significant
154 overhead if a posible error is detected. */
155#define SIMPLECHECKS 1
156
157/* Define to 1 if you have the ANSI C header files. */
158#define STDC_HEADERS 1
159
160/* Defining this causes time stamps to be created each time a lump is locked,
161 and lumps locked for long periods of time are reported */
162/* #undef TIMEDIAG */
163
164/* Define if you want to use gluImageScale */
165#define USE_GLU_IMAGESCALE 1
166
167/* Define if you want to use gluBuild2DMipmaps */
168#define USE_GLU_MIPMAP 1
169
170/* Define if you want to use the SDL net lib */
171/* #undef USE_SDL_NET */
172
173/* Version number of package */
174#define VERSION "2.5.0"
175
176/* Define if using the dmalloc debugging malloc package */
177/* #undef WITH_DMALLOC */
178
179/* Define to 1 if your processor stores words with the most significant byte
180 first (like Motorola and SPARC, unlike Intel and VAX). */
181/* #undef WORDS_BIGENDIAN */
182
183/* Define this to perform id checks on zone blocks, to detect corrupted and
184 illegally freed blocks */
185#define ZONEIDCHECK 1
186
187/* Define to empty if `const' does not conform to ANSI C. */
188/* #undef const */
189
190/* Define to `int' if <sys/types.h> doesn't define. */
191/* #undef gid_t */
192
193/* Define to `__inline__' or `__inline' if that's what the C compiler
194 calls it, or to nothing if 'inline' is not supported under any name. */
195#ifndef __cplusplus
196/* #undef inline */
197#endif
198
199/* Define to `unsigned int' if <sys/types.h> does not define. */
200/* #undef size_t */
201
202/* Define to strcasecmp, if we have it */
203#define stricmp strcasecmp
204
205/* Define to strncasecmp, if we have it */
206#define strnicmp strncasecmp
207
208/* Define to `int' if <sys/types.h> doesn't define. */
209/* #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 @@
1#
2# Install, and make if needed, prboom.wad
3#
4
5waddir=$(DOOMWADDIR)
6wad_DATA=prboom.wad
7EXTRA_DIST=prboom.wad prboom.txt
8MAINTAINERCLEANFILES=prboom.wad
9
10prboom.wad : prboom.txt $(wildcard graphics/*.ppm sprites/*.ppm lumps/*.lmp sounds/*.wav)
11 -rm -f $@
12 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 @@
1# Makefile.in generated by automake 1.10 from Makefile.am.
2# @configure_input@
3
4# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
5# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
6# This Makefile.in is free software; the Free Software Foundation
7# gives unlimited permission to copy and/or distribute it,
8# with or without modifications, as long as this notice is preserved.
9
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
12# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13# PARTICULAR PURPOSE.
14
15@SET_MAKE@
16
17#
18# Install, and make if needed, prboom.wad
19#
20
21VPATH = @srcdir@
22pkgdatadir = $(datadir)/@PACKAGE@
23pkglibdir = $(libdir)/@PACKAGE@
24pkgincludedir = $(includedir)/@PACKAGE@
25am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
26install_sh_DATA = $(install_sh) -c -m 644
27install_sh_PROGRAM = $(install_sh) -c
28install_sh_SCRIPT = $(install_sh) -c
29INSTALL_HEADER = $(INSTALL_DATA)
30transform = $(program_transform_name)
31NORMAL_INSTALL = :
32PRE_INSTALL = :
33POST_INSTALL = :
34NORMAL_UNINSTALL = :
35PRE_UNINSTALL = :
36POST_UNINSTALL = :
37build_triplet = @build@
38host_triplet = @host@
39target_triplet = @target@
40subdir = data
41DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
42ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
43am__aclocal_m4_deps = $(top_srcdir)/autotools/ac_c_compile_flags.m4 \
44 $(top_srcdir)/autotools/ac_cpu_optimisations.m4 \
45 $(top_srcdir)/configure.ac
46am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
47 $(ACLOCAL_M4)
48mkinstalldirs = $(install_sh) -d
49CONFIG_HEADER = $(top_builddir)/config.h
50CONFIG_CLEAN_FILES =
51SOURCES =
52DIST_SOURCES =
53am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
54am__vpath_adj = case $$p in \
55 $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
56 *) f=$$p;; \
57 esac;
58am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
59am__installdirs = "$(DESTDIR)$(waddir)"
60wadDATA_INSTALL = $(INSTALL_DATA)
61DATA = $(wad_DATA)
62DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
63ACLOCAL = @ACLOCAL@
64AMTAR = @AMTAR@
65AUTOCONF = @AUTOCONF@
66AUTOHEADER = @AUTOHEADER@
67AUTOMAKE = @AUTOMAKE@
68AWK = @AWK@
69CC = @CC@
70CCDEPMODE = @CCDEPMODE@
71CFLAGS = @CFLAGS@
72CPP = @CPP@
73CPPFLAGS = @CPPFLAGS@
74CYGPATH_W = @CYGPATH_W@
75DEFS = @DEFS@
76DEPDIR = @DEPDIR@
77DOOMWADDIR = @DOOMWADDIR@
78ECHO_C = @ECHO_C@
79ECHO_N = @ECHO_N@
80ECHO_T = @ECHO_T@
81EGREP = @EGREP@
82EXEEXT = @EXEEXT@
83GL_LIBS = @GL_LIBS@
84GREP = @GREP@
85INSTALL = @INSTALL@
86INSTALL_DATA = @INSTALL_DATA@
87INSTALL_PROGRAM = @INSTALL_PROGRAM@
88INSTALL_SCRIPT = @INSTALL_SCRIPT@
89INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
90LDFLAGS = @LDFLAGS@
91LIBOBJS = @LIBOBJS@
92LIBS = @LIBS@
93LN_S = @LN_S@
94LTLIBOBJS = @LTLIBOBJS@
95MAKEINFO = @MAKEINFO@
96MATH_LIB = @MATH_LIB@
97MIXER_CFLAGS = @MIXER_CFLAGS@
98MIXER_LIBS = @MIXER_LIBS@
99MKDIR_P = @MKDIR_P@
100NET_CFLAGS = @NET_CFLAGS@
101NET_LIBS = @NET_LIBS@
102OBJEXT = @OBJEXT@
103PACKAGE = @PACKAGE@
104PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
105PACKAGE_NAME = @PACKAGE_NAME@
106PACKAGE_STRING = @PACKAGE_STRING@
107PACKAGE_TARNAME = @PACKAGE_TARNAME@
108PACKAGE_VERSION = @PACKAGE_VERSION@
109PATH_SEPARATOR = @PATH_SEPARATOR@
110RANLIB = @RANLIB@
111SDL_CFLAGS = @SDL_CFLAGS@
112SDL_CONFIG = @SDL_CONFIG@
113SDL_LIBS = @SDL_LIBS@
114SET_MAKE = @SET_MAKE@
115SHELL = @SHELL@
116STRIP = @STRIP@
117VERSION = @VERSION@
118abs_builddir = @abs_builddir@
119abs_srcdir = @abs_srcdir@
120abs_top_builddir = @abs_top_builddir@
121abs_top_srcdir = @abs_top_srcdir@
122ac_ct_CC = @ac_ct_CC@
123am__include = @am__include@
124am__leading_dot = @am__leading_dot@
125am__quote = @am__quote@
126am__tar = @am__tar@
127am__untar = @am__untar@
128bindir = @bindir@
129build = @build@
130build_alias = @build_alias@
131build_cpu = @build_cpu@
132build_os = @build_os@
133build_vendor = @build_vendor@
134builddir = @builddir@
135datadir = @datadir@
136datarootdir = @datarootdir@
137docdir = @docdir@
138dvidir = @dvidir@
139exec_prefix = @exec_prefix@
140host = @host@
141host_alias = @host_alias@
142host_cpu = @host_cpu@
143host_os = @host_os@
144host_vendor = @host_vendor@
145htmldir = @htmldir@
146includedir = @includedir@
147infodir = @infodir@
148install_sh = @install_sh@
149libdir = @libdir@
150libexecdir = @libexecdir@
151localedir = @localedir@
152localstatedir = @localstatedir@
153mandir = @mandir@
154mkdir_p = @mkdir_p@
155oldincludedir = @oldincludedir@
156pdfdir = @pdfdir@
157prefix = @prefix@
158program_transform_name = @program_transform_name@
159psdir = @psdir@
160sbindir = @sbindir@
161sharedstatedir = @sharedstatedir@
162srcdir = @srcdir@
163sysconfdir = @sysconfdir@
164target = @target@
165target_alias = @target_alias@
166target_cpu = @target_cpu@
167target_os = @target_os@
168target_vendor = @target_vendor@
169top_builddir = @top_builddir@
170top_srcdir = @top_srcdir@
171waddir = $(DOOMWADDIR)
172wad_DATA = prboom.wad
173EXTRA_DIST = prboom.wad prboom.txt
174MAINTAINERCLEANFILES = prboom.wad
175all: all-am
176
177.SUFFIXES:
178$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
179 @for dep in $?; do \
180 case '$(am__configure_deps)' in \
181 *$$dep*) \
182 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
183 && exit 0; \
184 exit 1;; \
185 esac; \
186 done; \
187 echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign data/Makefile'; \
188 cd $(top_srcdir) && \
189 $(AUTOMAKE) --foreign data/Makefile
190.PRECIOUS: Makefile
191Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
192 @case '$?' in \
193 *config.status*) \
194 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
195 *) \
196 echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
197 cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
198 esac;
199
200$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
201 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
202
203$(top_srcdir)/configure: $(am__configure_deps)
204 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
205$(ACLOCAL_M4): $(am__aclocal_m4_deps)
206 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
207install-wadDATA: $(wad_DATA)
208 @$(NORMAL_INSTALL)
209 test -z "$(waddir)" || $(MKDIR_P) "$(DESTDIR)$(waddir)"
210 @list='$(wad_DATA)'; for p in $$list; do \
211 if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
212 f=$(am__strip_dir) \
213 echo " $(wadDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(waddir)/$$f'"; \
214 $(wadDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(waddir)/$$f"; \
215 done
216
217uninstall-wadDATA:
218 @$(NORMAL_UNINSTALL)
219 @list='$(wad_DATA)'; for p in $$list; do \
220 f=$(am__strip_dir) \
221 echo " rm -f '$(DESTDIR)$(waddir)/$$f'"; \
222 rm -f "$(DESTDIR)$(waddir)/$$f"; \
223 done
224tags: TAGS
225TAGS:
226
227ctags: CTAGS
228CTAGS:
229
230
231distdir: $(DISTFILES)
232 @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
233 topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
234 list='$(DISTFILES)'; \
235 dist_files=`for file in $$list; do echo $$file; done | \
236 sed -e "s|^$$srcdirstrip/||;t" \
237 -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
238 case $$dist_files in \
239 */*) $(MKDIR_P) `echo "$$dist_files" | \
240 sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
241 sort -u` ;; \
242 esac; \
243 for file in $$dist_files; do \
244 if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
245 if test -d $$d/$$file; then \
246 dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
247 if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
248 cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
249 fi; \
250 cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
251 else \
252 test -f $(distdir)/$$file \
253 || cp -p $$d/$$file $(distdir)/$$file \
254 || exit 1; \
255 fi; \
256 done
257check-am: all-am
258check: check-am
259all-am: Makefile $(DATA)
260installdirs:
261 for dir in "$(DESTDIR)$(waddir)"; do \
262 test -z "$$dir" || $(MKDIR_P) "$$dir"; \
263 done
264install: install-am
265install-exec: install-exec-am
266install-data: install-data-am
267uninstall: uninstall-am
268
269install-am: all-am
270 @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
271
272installcheck: installcheck-am
273install-strip:
274 $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
275 install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
276 `test -z '$(STRIP)' || \
277 echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
278mostlyclean-generic:
279
280clean-generic:
281
282distclean-generic:
283 -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
284
285maintainer-clean-generic:
286 @echo "This command is intended for maintainers to use"
287 @echo "it deletes files that may require special tools to rebuild."
288 -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
289clean: clean-am
290
291clean-am: clean-generic mostlyclean-am
292
293distclean: distclean-am
294 -rm -f Makefile
295distclean-am: clean-am distclean-generic
296
297dvi: dvi-am
298
299dvi-am:
300
301html: html-am
302
303info: info-am
304
305info-am:
306
307install-data-am: install-wadDATA
308
309install-dvi: install-dvi-am
310
311install-exec-am:
312
313install-html: install-html-am
314
315install-info: install-info-am
316
317install-man:
318
319install-pdf: install-pdf-am
320
321install-ps: install-ps-am
322
323installcheck-am:
324
325maintainer-clean: maintainer-clean-am
326 -rm -f Makefile
327maintainer-clean-am: distclean-am maintainer-clean-generic
328
329mostlyclean: mostlyclean-am
330
331mostlyclean-am: mostlyclean-generic
332
333pdf: pdf-am
334
335pdf-am:
336
337ps: ps-am
338
339ps-am:
340
341uninstall-am: uninstall-wadDATA
342
343.MAKE: install-am install-strip
344
345.PHONY: all all-am check check-am clean clean-generic distclean \
346 distclean-generic distdir dvi dvi-am html html-am info info-am \
347 install install-am install-data install-data-am install-dvi \
348 install-dvi-am install-exec install-exec-am install-html \
349 install-html-am install-info install-info-am install-man \
350 install-pdf install-pdf-am install-ps install-ps-am \
351 install-strip install-wadDATA installcheck installcheck-am \
352 installdirs maintainer-clean maintainer-clean-generic \
353 mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \
354 uninstall-am uninstall-wadDATA
355
356
357prboom.wad : prboom.txt $(wildcard graphics/*.ppm sprites/*.ppm lumps/*.lmp sounds/*.wav)
358 -rm -f $@
359 deutex -make prboom.txt $@
360# Tell versions [3.59,3.63) of GNU make to not export all variables.
361# Otherwise a system limit (for SysV at least) may be exceeded.
362.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 @@
1# PWAD creation directives for prboom.wad
2# Initially generated by DeuTex 4.4.0
3
4# List of data Lumps
5[lumps]
6SWITCHES
7ANIMATED
8C_START
9WATERMAP
10C_END
11CRBRICK
12CRTAN
13CRGRAY
14CRGREEN
15CRBROWN
16CRGOLD
17CRRED
18CRBLUE
19CRBLUE2
20CRORANGE
21CRYELLOW
22
23# PrBoom internal data lumps (large data lumps removed from the source code)
24B_START
25SINETABL
26TANGTABL
27TANTOANG
28GAMMATBL
29B_END
30
31# List of Sounds
32[sounds]
33# MBF dog sounds
34DSDGSIT
35DSDGATK
36DSDGACT
37DSDGDTH
38DSDGPAIN
39
40# List of Pictures (with insertion point)
41[graphics]
42M_HORSEN 0 0
43M_VERSEN 0 0
44M_COMPAT 0 0
45M_GENERL 0 0
46STBR123 0 0
47STBR124 0 0
48STBR125 0 0
49STBR126 0 0
50STBR127 0 0
51DIG0 0 0
52DIG1 0 0
53DIG2 0 0
54DIG3 0 0
55DIG4 0 0
56DIG5 0 0
57DIG6 0 0
58DIG7 0 0
59DIG8 0 0
60DIG9 0 0
61DIGA 0 0
62DIGB 0 0
63DIGC 0 0
64DIGD 0 0
65DIGE 0 0
66DIGF 0 0
67DIGG 0 0
68DIGH 0 0
69DIGI 0 0
70DIGJ 0 0
71DIGK 0 0
72DIGL 0 0
73DIGM 0 0
74DIGN 0 0
75DIGO 0 0
76DIGP 0 0
77DIGQ 0 0
78DIGR 0 0
79DIGS 0 0
80DIGT 0 0
81DIGU 0 0
82DIGV 0 0
83DIGW 0 0
84DIGX 0 0
85DIGY 0 0
86DIGZ 0 0
87DIG45 0 0
88DIG47 0 0
89DIG58 0 0
90DIG91 0 0
91DIG93 0 0
92STKEYS6 0 0
93STKEYS7 0 0
94STKEYS8 0 0
95BOXUL 0 0
96BOXUC 0 0
97BOXUR 0 0
98BOXCL 0 0
99BOXCC 0 0
100BOXCR 0 0
101BOXLL 0 0
102BOXLC 0 0
103BOXLR 0 0
104PRBOOM 0 0
105HU_FRAGS 0 0
106HU_FRGBX 0 0
107M_SETUP 0 0
108M_KEYBND 0 0
109M_AUTO 0 0
110M_CHAT 0 0
111M_ENEM 0 0
112M_STAT 0 0
113M_WEAP 0 0
114M_MESS 0 0
115M_COLORS 0 0
116M_PALSEL 0 0
117M_PALNO 0 0
118M_SLIDEM 0 0
119M_SLIDEL 0 0
120M_SLIDEO 0 0
121M_SLIDER 0 0
122M_FEAT 0 0
123M_MULTI 0 0
124M_ABOUT 0 0
125M_DEMOS 0 0
126M_WAD 0 0
127M_SOUND 0 0
128M_VIDEO 0 0
129M_MOUSE 0 0
130M_KEYBND 0 0
131M_STAT 0 0
132M_HUD 0 0
133M_COMPAT 0 0
134M_VBOX 0 0
135STCFN096 0 0
136STCFN123 0 0
137STCFN124 0 0
138STCFN125 0 0
139M_BUTT1 0 0
140M_BUTT2 0 0
141
142# List of Sprites
143[sprites]
144# Empty sprite
145TNT1A0 0 0
146
147# MBF dog sprites
148DOGSD5 32 59
149DOGSH5 32 59
150DOGSC5 32 59
151DOGSG5 32 59
152DOGSB1 32 59
153DOGSA5 32 59
154DOGSE5 32 59
155DOGSC1 32 59
156DOGSD1 32 59
157DOGSB5 32 59
158DOGSF5 32 59
159DOGSA1 32 59
160DOGSE1 32 59
161DOGSF1 32 59
162DOGSD2D8 32 59
163DOGSH2 32 59
164DOGSG1 32 59
165DOGSH8 32 59
166DOGSE8 32 59
167DOGSD4D6 32 59
168DOGSH4 32 59
169DOGSA2A8 32 59
170DOGSE2 32 59
171DOGSF8 32 59
172DOGSH1 32 59
173DOGSA4A6 32 59
174DOGSE4 32 59
175DOGSB4B6 32 59
176DOGSF4 32 59
177DOGSH6 32 59
178DOGSB2B8 32 59
179DOGSF2 32 59
180DOGSC2C8 32 59
181DOGSG2 32 59
182DOGSG6 32 59
183DOGSC4C6 32 59
184DOGSG4 32 59
185DOGSG8 32 59
186DOGSF6 32 59
187DOGSN0 32 59
188DOGSE6 32 59
189DOGSD3D7 32 59
190DOGSH3 32 59
191DOGSH7 32 59
192DOGSI0 32 59
193DOGSA3A7 32 59
194DOGSE3 32 59
195DOGSB3B7 32 59
196DOGSF3 32 59
197DOGSF7 32 59
198DOGSE7 32 59
199DOGSC3C7 32 59
200DOGSG3 32 59
201DOGSG7 32 59
202DOGSJ0 32 59
203DOGSK0 32 59
204DOGSL0 32 59
205DOGSM0 32 59
206
207# End of extraction
diff --git a/data/prboom.wad b/data/prboom.wad
new file mode 100644
index 0000000..85dc155
--- /dev/null
+++ b/data/prboom.wad
Binary files 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 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<extension>
3 <information>
4 <name>PrBoom</name>
5 <version>1.0</version>
6 <author>simsor</author>
7 <id>SIMSOR-PRBOOM</id>
8 </information>
9 <menus>
10 <menu type="json" dynamic="true">menu.json</menu>
11 </menus>
12</extension> \ 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 @@
1{
2 "items": [
3 {
4 "name": "Simon's Fun Land",
5 "items": [
6 {
7 "name": "PrBoom",
8 "action": "./run.sh",
9 "refresh": false,
10 "exitmenu": false
11 }
12 ]
13 }
14 ]
15 } \ 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 @@
1#!/bin/sh
2
3/etc/init.d/framework stop
4/usr/bin/lipc-set-prop -- com.lab126.powerd preventScreenSaver 1
5./prboom -iwad /mnt/us/doom.wad -file /mnt/us/prboom.wad -nosound -nomusic -nosfx -warp 1 1
6/usr/bin/lipc-set-prop -- com.lab126.powerd preventScreenSaver 0
7/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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Joystick handling for Linux
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#ifndef lint
36#endif /* lint */
37
38#include <stdlib.h>
39
40#include "doomdef.h"
41#include "doomtype.h"
42#include "m_argv.h"
43#include "d_event.h"
44#include "d_main.h"
45#include "i_joy.h"
46#include "lprintf.h"
47
48int joyleft;
49int joyright;
50int joyup;
51int joydown;
52
53int usejoystick;
54
55static void I_EndJoystick(void)
56{
57 lprintf(LO_DEBUG, "I_EndJoystick : closing joystick\n");
58}
59
60void I_PollJoystick(void)
61{
62
63}
64
65void I_InitJoystick(void)
66{
67
68}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Startup and quit functions. Handles signals, inits the
31 * memory management, then calls D_DoomMain. Also contains
32 * I_Init which does other system-related startup stuff.
33 *
34 *-----------------------------------------------------------------------------
35 */
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43#ifdef USE_SDL
44#include "SDL.h"
45#endif
46#include "doomdef.h"
47#include "m_argv.h"
48#include "d_main.h"
49#include "m_fixed.h"
50#include "i_system.h"
51#include "i_video.h"
52#include "z_zone.h"
53#include "lprintf.h"
54#include "m_random.h"
55#include "doomstat.h"
56#include "g_game.h"
57#include "m_misc.h"
58#include "i_sound.h"
59#include "i_main.h"
60#include "r_fps.h"
61#include "lprintf.h"
62
63#include <signal.h>
64#include <stdio.h>
65#include <stdlib.h>
66
67/* Most of the following has been rewritten by Lee Killough
68 *
69 * I_GetTime
70 * killough 4/13/98: Make clock rate adjustable by scale factor
71 * cphipps - much made static
72 */
73
74int realtic_clock_rate = 100;
75static int_64_t I_GetTime_Scale = 1<<24;
76
77static int I_GetTime_Scaled(void)
78{
79 return (int)( (int_64_t) I_GetTime_RealTime() * I_GetTime_Scale >> 24);
80}
81
82
83
84static int I_GetTime_FastDemo(void)
85{
86 static int fasttic;
87 return fasttic++;
88}
89
90
91
92static int I_GetTime_Error(void)
93{
94 I_Error("I_GetTime_Error: GetTime() used before initialization");
95 return 0;
96}
97
98
99
100int (*I_GetTime)(void) = I_GetTime_Error;
101
102void I_Init(void)
103{
104 /* killough 4/14/98: Adjustable speedup based on realtic_clock_rate */
105 if (fastdemo)
106 I_GetTime = I_GetTime_FastDemo;
107 else
108 if (realtic_clock_rate != 100)
109 {
110 I_GetTime_Scale = ((int_64_t) realtic_clock_rate << 24) / 100;
111 I_GetTime = I_GetTime_Scaled;
112 }
113 else
114 I_GetTime = I_GetTime_RealTime;
115
116 {
117 /* killough 2/21/98: avoid sound initialization if no sound & no music */
118 if (!(nomusicparm && nosfxparm))
119 I_InitSound();
120 }
121
122 R_InitInterpolation();
123}
124
125/* cleanup handling -- killough:
126 */
127static void I_SignalHandler(int s)
128{
129 char buf[2048];
130
131 signal(s,SIG_IGN); /* Ignore future instances of this signal.*/
132
133 strcpy(buf,"Exiting on signal: ");
134 I_SigString(buf+strlen(buf),2000-strlen(buf),s);
135
136 /* If corrupted memory could cause crash, dump memory
137 * allocation history, which points out probable causes
138 */
139 if (s==SIGSEGV || s==SIGILL || s==SIGFPE)
140 Z_DumpHistory(buf);
141
142 I_Error("I_SignalHandler: %s", buf);
143}
144
145
146
147/* killough 2/22/98: Add support for ENDBOOM, which is PC-specific
148 *
149 * this converts BIOS color codes to ANSI codes.
150 * Its not pretty, but it does the job - rain
151 * CPhipps - made static
152 */
153
154inline static int convert(int color, int *bold)
155{
156 if (color > 7) {
157 color -= 8;
158 *bold = 1;
159 }
160 switch (color) {
161 case 0:
162 return 0;
163 case 1:
164 return 4;
165 case 2:
166 return 2;
167 case 3:
168 return 6;
169 case 4:
170 return 1;
171 case 5:
172 return 5;
173 case 6:
174 return 3;
175 case 7:
176 return 7;
177 }
178 return 0;
179}
180
181/* CPhipps - flags controlling ENDOOM behaviour */
182enum {
183 endoom_colours = 1,
184 endoom_nonasciichars = 2,
185 endoom_droplastline = 4
186};
187
188unsigned int endoom_mode;
189
190static void PrintVer(void)
191{
192 char vbuf[200];
193 lprintf(LO_INFO,"%s\n",I_GetVersionString(vbuf,200));
194}
195
196/* I_EndDoom
197 * Prints out ENDOOM or ENDBOOM, using some common sense to decide which.
198 * cphipps - moved to l_main.c, made static
199 */
200static void I_EndDoom(void)
201{
202 int lump_eb, lump_ed, lump = -1;
203
204 /* CPhipps - ENDOOM/ENDBOOM selection */
205 lump_eb = W_CheckNumForName("ENDBOOM");/* jff 4/1/98 sign our work */
206 lump_ed = W_CheckNumForName("ENDOOM"); /* CPhipps - also maybe ENDOOM */
207
208 if (lump_eb == -1)
209 lump = lump_ed;
210 else if (lump_ed == -1)
211 lump = lump_eb;
212 else
213 { /* Both ENDOOM and ENDBOOM are present */
214#define LUMP_IS_NEW(num) (!((lumpinfo[num].source == source_iwad) || (lumpinfo[num].source == source_auto_load)))
215 switch ((LUMP_IS_NEW(lump_ed) ? 1 : 0 ) |
216 (LUMP_IS_NEW(lump_eb) ? 2 : 0)) {
217 case 1:
218 lump = lump_ed;
219 break;
220 case 2:
221 lump = lump_eb;
222 break;
223 default:
224 /* Both lumps have equal priority, both present */
225 lump = (P_Random(pr_misc) & 1) ? lump_ed : lump_eb;
226 break;
227 }
228 }
229
230 if (lump != -1)
231 {
232 const char (*endoom)[2] = (const void*)W_CacheLumpNum(lump);
233 int i, l = W_LumpLength(lump) / 2;
234
235 /* cph - colour ENDOOM by rain */
236 int oldbg = -1, oldcolor = -1, bold = 0, oldbold = -1, color = 0;
237#ifndef _WIN32
238 if (endoom_mode & endoom_nonasciichars)
239 /* switch to secondary charset, and set to cp437 (IBM charset) */
240 printf("\e)K\016");
241#endif /* _WIN32 */
242
243 /* cph - optionally drop the last line, so everything fits on one screen */
244 if (endoom_mode & endoom_droplastline)
245 l -= 80;
246 lprintf(LO_INFO,"\n");
247 for (i=0; i<l; i++)
248 {
249#ifdef _WIN32
250 I_ConTextAttr(endoom[i][1]);
251#elif defined (DJGPP)
252 textattr(endoom[i][1]);
253#else
254 if (endoom_mode & endoom_colours)
255 {
256 if (!(i % 80))
257 {
258 /* reset color but not bold when we start a new line */
259 oldbg = -1;
260 oldcolor = -1;
261 printf("\e[39m\e[49m\n");
262 }
263 /* foreground color */
264 bold = 0;
265 color = endoom[i][1] % 16;
266 if (color != oldcolor)
267 {
268 oldcolor = color;
269 color = convert(color, &bold);
270 if (oldbold != bold)
271 {
272 oldbold = bold;
273 printf("\e[%cm", bold + '0');
274 if (!bold) oldbg = -1;
275 }
276 /* we buffer everything or output is horrendously slow */
277 printf("\e[%dm", color + 30);
278 bold = 0;
279 }
280 /* background color */
281 color = endoom[i][1] / 16;
282 if (color != oldbg)
283 {
284 oldbg = color;
285 color = convert(color, &bold);
286 printf("\e[%dm", color + 40);
287 }
288 }
289#endif
290 /* cph - portable ascii printout if requested */
291 if (isascii(endoom[i][0]) || (endoom_mode & endoom_nonasciichars))
292 lprintf(LO_INFO,"%c",endoom[i][0]);
293 else /* Probably a box character, so do #'s */
294 lprintf(LO_INFO,"#");
295 }
296#ifndef _WIN32
297 lprintf(LO_INFO,"\b"); /* hack workaround for extra newline at bottom of screen */
298 lprintf(LO_INFO,"\r");
299 if (endoom_mode & endoom_nonasciichars)
300 printf("%c",'\017'); /* restore primary charset */
301#endif /* _WIN32 */
302 W_UnlockLumpNum(lump);
303 }
304#ifndef _WIN32
305 if (endoom_mode & endoom_colours)
306 puts("\e[0m"); /* cph - reset colours */
307 PrintVer();
308#endif /* _WIN32 */
309}
310
311static int has_exited;
312
313/* I_SafeExit
314 * This function is called instead of exit() by functions that might be called
315 * during the exit process (i.e. after exit() has already been called)
316 * Prevent infinitely recursive exits -- killough
317 */
318
319void I_SafeExit(int rc)
320{
321 if (!has_exited) /* If it hasn't exited yet, exit now -- killough */
322 {
323 has_exited=rc ? 2 : 1;
324 exit(rc);
325 }
326}
327
328static void I_Quit (void)
329{
330 if (!has_exited)
331 has_exited=1; /* Prevent infinitely recursive exits -- killough */
332
333 if (has_exited == 1) {
334 I_EndDoom();
335 if (demorecording)
336 G_CheckDemoStatus();
337 M_SaveDefaults ();
338 }
339}
340
341#ifdef SECURE_UID
342uid_t stored_euid = -1;
343#endif
344
345//int main(int argc, const char * const * argv)
346int main(int argc, char **argv)
347{
348#ifdef SECURE_UID
349 /* First thing, revoke setuid status (if any) */
350 stored_euid = geteuid();
351 if (getuid() != stored_euid)
352 if (seteuid(getuid()) < 0)
353 fprintf(stderr, "Failed to revoke setuid\n");
354 else
355 fprintf(stderr, "Revoked uid %d\n",stored_euid);
356#endif
357
358 myargc = argc;
359 myargv = argv;
360
361#ifdef _WIN32
362 if (!M_CheckParm("-nodraw")) {
363 /* initialize the console window */
364 Init_ConsoleWin();
365 atexit(Done_ConsoleWin);
366 }
367#endif
368 /* Version info */
369 lprintf(LO_INFO,"\n");
370 PrintVer();
371
372 /* cph - Z_Close must be done after I_Quit, so we register it first. */
373 atexit(Z_Close);
374 /*
375 killough 1/98:
376
377 This fixes some problems with exit handling
378 during abnormal situations.
379
380 The old code called I_Quit() to end program,
381 while now I_Quit() is installed as an exit
382 handler and exit() is called to exit, either
383 normally or abnormally. Seg faults are caught
384 and the error handler is used, to prevent
385 being left in graphics mode or having very
386 loud SFX noise because the sound card is
387 left in an unstable state.
388 */
389
390 Z_Init(); /* 1/18/98 killough: start up memory stuff first */
391
392 atexit(I_Quit);
393#ifndef _DEBUG
394 signal(SIGSEGV, I_SignalHandler);
395 signal(SIGTERM, I_SignalHandler);
396 signal(SIGFPE, I_SignalHandler);
397 signal(SIGILL, I_SignalHandler);
398 signal(SIGINT, I_SignalHandler); /* killough 3/6/98: allow CTRL-BRK during init */
399 signal(SIGABRT, I_SignalHandler);
400#endif
401
402 I_SetAffinityMask();
403
404 /* cphipps - call to video specific startup code */
405 I_PreInitGraphics();
406
407 D_DoomMain ();
408 return 0;
409}
diff --git a/src/KINDLE/i_network.c b/src/KINDLE/i_network.c
new file mode 100644
index 0000000..4730d50
--- /dev/null
+++ b/src/KINDLE/i_network.c
@@ -0,0 +1,292 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Low level UDP network interface. This is shared between the server
31 * and client, with SERVER defined for the former to select some extra
32 * functions. Handles socket creation, and packet send and receive.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifdef HAVE_CONFIG_H
37# include "config.h"
38#endif
39#ifdef HAVE_NETINET_IN_H
40# include <netinet/in.h>
41#endif
42#include <stdlib.h>
43#include <errno.h>
44#ifdef HAVE_UNISTD_H
45#include <unistd.h>
46#endif
47#include <stdio.h>
48#include <fcntl.h>
49#include <string.h>
50
51#ifdef HAVE_NET
52
53#include "SDL.h"
54#include "SDL_net.h"
55
56#include "protocol.h"
57#include "i_network.h"
58#include "lprintf.h"
59//#include "doomstat.h"
60
61/* cph -
62 * Each client will either use the IPv4 socket or the IPv6 socket
63 * Each server will use whichever or both that are available
64 */
65UDP_CHANNEL sentfrom;
66IPaddress sentfrom_addr;
67UDP_SOCKET udp_socket;
68
69/* Statistics */
70size_t sentbytes, recvdbytes;
71
72UDP_PACKET *udp_packet;
73
74/* I_ShutdownNetwork
75 *
76 * Shutdown the network code
77 */
78void I_ShutdownNetwork(void)
79{
80 SDLNet_FreePacket(udp_packet);
81 SDLNet_Quit();
82}
83
84/* I_InitNetwork
85 *
86 * Sets up the network code
87 */
88void I_InitNetwork(void)
89{
90 SDLNet_Init();
91 atexit(I_ShutdownNetwork);
92 udp_packet = SDLNet_AllocPacket(10000);
93}
94
95UDP_PACKET *I_AllocPacket(int size)
96{
97 return(SDLNet_AllocPacket(size));
98}
99
100void I_FreePacket(UDP_PACKET *packet)
101{
102 SDLNet_FreePacket(packet);
103}
104
105
106/* cph - I_WaitForPacket - use select(2) via SDL_net's interface
107 * No more I_uSleep loop kludge */
108
109void I_WaitForPacket(int ms)
110{
111 SDLNet_SocketSet ss = SDLNet_AllocSocketSet(1);
112 SDLNet_UDP_AddSocket(ss, udp_socket);
113 SDLNet_CheckSockets(ss,ms);
114 SDLNet_FreeSocketSet(ss);
115#if (defined _WIN32 && !defined PRBOOM_SERVER)
116 I_UpdateConsole();
117#endif
118}
119
120/* I_ConnectToServer
121 *
122 * Connect to a server
123 */
124IPaddress serverIP;
125
126int I_ConnectToServer(const char *serv)
127{
128 char server[500], *p;
129 Uint16 port;
130
131 /* Split serv into address and port */
132 if (strlen(serv)>500) return 0;
133 strcpy(server,serv);
134 p = strchr(server, ':');
135 if(p)
136 {
137 *p++ = '\0';
138 port = atoi(p);
139 }
140 else
141 port = 5030; /* Default server port */
142
143 SDLNet_ResolveHost(&serverIP, server, port);
144 if ( serverIP.host == INADDR_NONE )
145 return -1;
146
147 if (SDLNet_UDP_Bind(udp_socket, 0, &serverIP) == -1)
148 return -1;
149
150 return 0;
151}
152
153/* I_Disconnect
154 *
155 * Disconnect from server
156 */
157void I_Disconnect(void)
158{
159/* int i;
160 UDP_PACKET *packet;
161 packet_header_t *pdata = (packet_header_t *)packet->data;
162 packet = I_AllocPacket(sizeof(packet_header_t) + 1);
163
164 packet->data[sizeof(packet_header_t)] = consoleplayer;
165 pdata->type = PKT_QUIT; pdata->tic = gametic;
166
167 for (i=0; i<4; i++) {
168 I_SendPacket(packet);
169 I_uSleep(10000);
170 }
171 I_FreePacket(packet);*/
172 SDLNet_UDP_Unbind(udp_socket, 0);
173}
174
175/*
176 * I_Socket
177 *
178 * Sets the given socket non-blocking, binds to the given port, or first
179 * available if none is given
180 */
181UDP_SOCKET I_Socket(Uint16 port)
182{
183 if(port)
184 return (SDLNet_UDP_Open(port));
185 else {
186 UDP_SOCKET sock;
187 port = IPPORT_RESERVED;
188 while( (sock = SDLNet_UDP_Open(port)) == NULL )
189 port++;
190 return sock;
191 }
192}
193
194void I_CloseSocket(UDP_SOCKET sock)
195{
196 SDLNet_UDP_Close(sock);
197}
198
199UDP_CHANNEL I_RegisterPlayer(IPaddress *ipaddr)
200{
201 static int freechannel;
202 return(SDLNet_UDP_Bind(udp_socket, freechannel++, ipaddr));
203}
204
205void I_UnRegisterPlayer(UDP_CHANNEL channel)
206{
207 SDLNet_UDP_Unbind(udp_socket, channel);
208}
209
210/*
211 * ChecksumPacket
212 *
213 * Returns the checksum of a given network packet
214 */
215static byte ChecksumPacket(const packet_header_t* buffer, size_t len)
216{
217 const byte* p = (const void*)buffer;
218 byte sum = 0;
219
220 if (len==0)
221 return 0;
222
223 while (p++, --len)
224 sum += *p;
225
226 return sum;
227}
228
229size_t I_GetPacket(packet_header_t* buffer, size_t buflen)
230{
231 int checksum;
232 size_t len;
233 int status;
234
235 status = SDLNet_UDP_Recv(udp_socket, udp_packet);
236 len = udp_packet->len;
237 if (buflen<len)
238 len=buflen;
239 if ( (status!=0) && (len>0) )
240 memcpy(buffer, udp_packet->data, len);
241 sentfrom=udp_packet->channel;
242#ifndef SDL_NET_UDP_PACKET_SRC
243 sentfrom_addr=udp_packet->address;
244#else
245 sentfrom_addr=udp_packet->src; /* cph - allow for old SDL_net library */
246#endif
247 checksum=buffer->checksum;
248 buffer->checksum=0;
249 if ( (status!=0) && (len>0)) {
250 byte psum = ChecksumPacket(buffer, udp_packet->len);
251/* fprintf(stderr, "recvlen = %u, stolen = %u, csum = %u, psum = %u\n",
252 udp_packet->len, len, checksum, psum); */
253 if (psum == checksum) return len;
254 }
255 return 0;
256}
257
258void I_SendPacket(packet_header_t* packet, size_t len)
259{
260 packet->checksum = ChecksumPacket(packet, len);
261 memcpy(udp_packet->data, packet, udp_packet->len = len);
262 SDLNet_UDP_Send(udp_socket, 0, udp_packet);
263}
264
265void I_SendPacketTo(packet_header_t* packet, size_t len, UDP_CHANNEL *to)
266{
267 packet->checksum = ChecksumPacket(packet, len);
268 memcpy(udp_packet->data, packet, udp_packet->len = len);
269 SDLNet_UDP_Send(udp_socket, *to, udp_packet);
270}
271
272void I_PrintAddress(FILE* fp, UDP_CHANNEL *addr)
273{
274/*
275 char *addy;
276 Uint16 port;
277 IPaddress *address;
278
279 address = SDLNet_UDP_GetPeerAddress(udp_socket, player);
280
281//FIXME: if it cant resolv it may freeze up
282 addy = SDLNet_ResolveIP(address);
283 port = address->port;
284
285 if(addy != NULL)
286 fprintf(fp, "%s:%d", addy, port);
287 else
288 fprintf(fp, "Error");
289*/
290}
291
292#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * System interface for sound.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38#ifdef HAVE_LIBSDL_MIXER
39#define HAVE_MIXER
40#endif
41#include <math.h>
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
45
46#ifdef HAVE_MIXER
47#include "SDL_mixer.h"
48#endif
49
50#include "z_zone.h"
51
52#include "m_swap.h"
53#include "i_sound.h"
54#include "m_argv.h"
55#include "m_misc.h"
56#include "w_wad.h"
57#include "lprintf.h"
58#include "s_sound.h"
59
60#include "doomdef.h"
61#include "doomstat.h"
62#include "doomtype.h"
63
64#include "d_main.h"
65
66// The number of internal mixing channels,
67// the samples calculated for each mixing step,
68// the size of the 16bit, 2 hardware channel (stereo)
69// mixing buffer, and the samplerate of the raw data.
70
71// Variables used by Boom from Allegro
72// created here to avoid changes to core Boom files
73int snd_card = 1;
74int mus_card = 1;
75int detect_voices = 0; // God knows
76
77static boolean sound_inited = false;
78static boolean first_sound_init = true;
79
80// Needed for calling the actual sound output.
81static int SAMPLECOUNT= 512;
82#define MAX_CHANNELS 32
83
84// MWM 2000-01-08: Sample rate in samples/second
85int snd_samplerate=11025;
86
87// The actual output device.
88int audio_fd;
89
90typedef struct {
91 // SFX id of the playing sound effect.
92 // Used to catch duplicates (like chainsaw).
93 int id;
94// The channel step amount...
95 unsigned int step;
96// ... and a 0.16 bit remainder of last step.
97 unsigned int stepremainder;
98 unsigned int samplerate;
99// The channel data pointers, start and end.
100 const unsigned char* data;
101 const unsigned char* enddata;
102// Time/gametic that the channel started playing,
103// used to determine oldest, which automatically
104// has lowest priority.
105// In case number of active sounds exceeds
106// available channels.
107 int starttime;
108 // Hardware left and right channel volume lookup.
109 int *leftvol_lookup;
110 int *rightvol_lookup;
111} channel_info_t;
112
113channel_info_t channelinfo[MAX_CHANNELS];
114
115// Pitch to stepping lookup, unused.
116int steptable[256];
117
118// Volume lookups.
119int vol_lookup[128*256];
120
121/* cph
122 * stopchan
123 * Stops a sound, unlocks the data
124 */
125
126static void stopchan(int i)
127{
128 if (channelinfo[i].data) /* cph - prevent excess unlocks */
129 {
130 channelinfo[i].data=NULL;
131 W_UnlockLumpNum(S_sfx[channelinfo[i].id].lumpnum);
132 }
133}
134
135//
136// This function adds a sound to the
137// list of currently active sounds,
138// which is maintained as a given number
139// (eight, usually) of internal channels.
140// Returns a handle.
141//
142static int addsfx(int sfxid, int channel, const unsigned char* data, size_t len)
143{
144 stopchan(channel);
145
146 channelinfo[channel].data = data;
147 /* Set pointer to end of raw data. */
148 channelinfo[channel].enddata = channelinfo[channel].data + len - 1;
149 channelinfo[channel].samplerate = (channelinfo[channel].data[3]<<8)+channelinfo[channel].data[2];
150 channelinfo[channel].data += 8; /* Skip header */
151
152 channelinfo[channel].stepremainder = 0;
153 // Should be gametic, I presume.
154 channelinfo[channel].starttime = gametic;
155
156 // Preserve sound SFX id,
157 // e.g. for avoiding duplicates of chainsaw.
158 channelinfo[channel].id = sfxid;
159
160 return channel;
161}
162
163static void updateSoundParams(int handle, int volume, int seperation, int pitch)
164{
165 int slot = handle;
166 int rightvol;
167 int leftvol;
168 int step = steptable[pitch];
169
170#ifdef RANGECHECK
171 if ((handle < 0) || (handle >= MAX_CHANNELS))
172 I_Error("I_UpdateSoundParams: handle out of range");
173#endif
174 // Set stepping
175 // MWM 2000-12-24: Calculates proportion of channel samplerate
176 // to global samplerate for mixing purposes.
177 // Patched to shift left *then* divide, to minimize roundoff errors
178 // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz
179 if (pitched_sounds)
180 channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/snd_samplerate)-65536);
181 else
182 channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/snd_samplerate);
183
184 // Separation, that is, orientation/stereo.
185 // range is: 1 - 256
186 seperation += 1;
187
188 // Per left/right channel.
189 // x^2 seperation,
190 // adjust volume properly.
191 leftvol = volume - ((volume*seperation*seperation) >> 16);
192 seperation = seperation - 257;
193 rightvol= volume - ((volume*seperation*seperation) >> 16);
194
195 // Sanity check, clamp volume.
196 if (rightvol < 0 || rightvol > 127)
197 I_Error("rightvol out of bounds");
198
199 if (leftvol < 0 || leftvol > 127)
200 I_Error("leftvol out of bounds");
201
202 // Get the proper lookup table piece
203 // for this volume level???
204 channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256];
205 channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256];
206}
207
208void I_UpdateSoundParams(int handle, int volume, int seperation, int pitch)
209{
210
211}
212
213//
214// SFX API
215// Note: this was called by S_Init.
216// However, whatever they did in the
217// old DPMS based DOS version, this
218// were simply dummies in the Linux
219// version.
220// See soundserver initdata().
221//
222void I_SetChannels(void)
223{
224 // Init internal lookups (raw data, mixing buffer, channels).
225 // This function sets up internal lookups used during
226 // the mixing process.
227 int i;
228 int j;
229
230 int* steptablemid = steptable + 128;
231
232 // Okay, reset internal mixing channels to zero.
233 for (i=0; i<MAX_CHANNELS; i++)
234 {
235 memset(&channelinfo[i],0,sizeof(channel_info_t));
236 }
237
238 // This table provides step widths for pitch parameters.
239 // I fail to see that this is currently used.
240 for (i=-128 ; i<128 ; i++)
241 steptablemid[i] = (int)(pow(1.2, ((double)i/(64.0*snd_samplerate/11025)))*65536.0);
242
243
244 // Generates volume lookup tables
245 // which also turn the unsigned samples
246 // into signed samples.
247 for (i=0 ; i<128 ; i++)
248 for (j=0 ; j<256 ; j++)
249 {
250 // proff - made this a little bit softer, because with
251 // full volume the sound clipped badly
252 vol_lookup[i*256+j] = (i*(j-128)*256)/191;
253 //vol_lookup[i*256+j] = (i*(j-128)*256)/127;
254 }
255}
256
257//
258// Retrieve the raw data lump index
259// for a given SFX name.
260//
261int I_GetSfxLumpNum(sfxinfo_t* sfx)
262{
263 char namebuf[9];
264 sprintf(namebuf, "ds%s", sfx->name);
265 return W_GetNumForName(namebuf);
266}
267
268//
269// Starting a sound means adding it
270// to the current list of active sounds
271// in the internal channels.
272// As the SFX info struct contains
273// e.g. a pointer to the raw data,
274// it is ignored.
275// As our sound handling does not handle
276// priority, it is ignored.
277// Pitching (that is, increased speed of playback)
278// is set, but currently not used by mixing.
279//
280int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority)
281{
282 return -1;
283}
284
285
286
287void I_StopSound (int handle)
288{
289#ifdef RANGECHECK
290 if ((handle < 0) || (handle >= MAX_CHANNELS))
291 I_Error("I_StopSound: handle out of range");
292#endif
293}
294
295
296boolean I_SoundIsPlaying(int handle)
297{
298#ifdef RANGECHECK
299 if ((handle < 0) || (handle >= MAX_CHANNELS))
300 I_Error("I_SoundIsPlaying: handle out of range");
301#endif
302 return channelinfo[handle].data != NULL;
303}
304
305
306boolean I_AnySoundStillPlaying(void)
307{
308 boolean result = false;
309 int i;
310
311 for (i=0; i<MAX_CHANNELS; i++)
312 result |= channelinfo[i].data != NULL;
313
314 return result;
315}
316
317
318//
319// This function loops all active (internal) sound
320// channels, retrieves a given number of samples
321// from the raw sound data, modifies it according
322// to the current (internal) channel parameters,
323// mixes the per channel samples into the given
324// mixing buffer, and clamping it to the allowed
325// range.
326//
327// This function currently supports only 16bit.
328//
329
330static void I_UpdateSound(void *unused, int *stream, int len)
331{
332
333}
334
335void I_ShutdownSound(void)
336{
337 if (sound_inited) {
338
339 }
340}
341
342//static SDL_AudioSpec audio;
343
344void I_InitSound(void)
345{
346
347}
348
349
350
351
352//
353// MUSIC API.
354//
355
356#ifndef HAVE_OWN_MUSIC
357
358#ifdef HAVE_MIXER
359#include "SDL_mixer.h"
360#include "mmus2mid.h"
361
362static Mix_Music *music[2] = { NULL, NULL };
363
364char* music_tmp = NULL; /* cph - name of music temporary file */
365
366#endif
367
368void I_ShutdownMusic(void)
369{
370#ifdef HAVE_MIXER
371 if (music_tmp) {
372 unlink(music_tmp);
373 lprintf(LO_DEBUG, "I_ShutdownMusic: removing %s\n", music_tmp);
374 free(music_tmp);
375 music_tmp = NULL;
376 }
377#endif
378}
379
380void I_InitMusic(void)
381{
382#ifdef HAVE_MIXER
383 if (!music_tmp) {
384#ifndef _WIN32
385 music_tmp = strdup("/tmp/prboom-music-XXXXXX");
386 {
387 int fd = mkstemp(music_tmp);
388 if (fd<0) {
389 lprintf(LO_ERROR, "I_InitMusic: failed to create music temp file %s", music_tmp);
390 free(music_tmp); return;
391 } else
392 close(fd);
393 }
394#else /* !_WIN32 */
395 music_tmp = strdup("doom.tmp");
396#endif
397 atexit(I_ShutdownMusic);
398 }
399#endif
400}
401
402void I_PlaySong(int handle, int looping)
403{
404#ifdef HAVE_MIXER
405 if ( music[handle] ) {
406 Mix_FadeInMusic(music[handle], looping ? -1 : 0, 500);
407 }
408#endif
409}
410
411extern int mus_pause_opt; // From m_misc.c
412
413void I_PauseSong (int handle)
414{
415#ifdef HAVE_MIXER
416 switch(mus_pause_opt) {
417 case 0:
418 I_StopSong(handle);
419 break;
420 case 1:
421 Mix_PauseMusic();
422 break;
423 }
424#endif
425 // Default - let music continue
426}
427
428void I_ResumeSong (int handle)
429{
430#ifdef HAVE_MIXER
431 switch(mus_pause_opt) {
432 case 0:
433 I_PlaySong(handle,1);
434 break;
435 case 1:
436 Mix_ResumeMusic();
437 break;
438 }
439#endif
440 /* Otherwise, music wasn't stopped */
441}
442
443void I_StopSong(int handle)
444{
445#ifdef HAVE_MIXER
446 Mix_FadeOutMusic(500);
447#endif
448}
449
450void I_UnRegisterSong(int handle)
451{
452#ifdef HAVE_MIXER
453 if ( music[handle] ) {
454 Mix_FreeMusic(music[handle]);
455 music[handle] = NULL;
456 }
457#endif
458}
459
460int I_RegisterSong(const void *data, size_t len)
461{
462#ifdef HAVE_MIXER
463 MIDI *mididata;
464 FILE *midfile;
465
466 if ( len < 32 )
467 return 0; // the data should at least as big as the MUS header
468 if ( music_tmp == NULL )
469 return 0;
470 midfile = fopen(music_tmp, "wb");
471 if ( midfile == NULL ) {
472 lprintf(LO_ERROR,"Couldn't write MIDI to %s\n", music_tmp);
473 return 0;
474 }
475 /* Convert MUS chunk to MIDI? */
476 if ( memcmp(data, "MUS", 3) == 0 )
477 {
478 UBYTE *mid;
479 int midlen;
480
481 mididata = malloc(sizeof(MIDI));
482 mmus2mid(data, mididata, 89, 0);
483 MIDIToMidi(mididata,&mid,&midlen);
484 M_WriteFile(music_tmp,mid,midlen);
485 free(mid);
486 free_mididata(mididata);
487 free(mididata);
488 } else {
489 fwrite(data, len, 1, midfile);
490 }
491 fclose(midfile);
492
493 music[0] = Mix_LoadMUS(music_tmp);
494 if ( music[0] == NULL ) {
495 lprintf(LO_ERROR,"Couldn't load MIDI from %s: %s\n", music_tmp, Mix_GetError());
496 }
497#endif
498 return (0);
499}
500
501// cournia - try to load a music file into SDL_Mixer
502// returns true if could not load the file
503int I_RegisterMusic( const char* filename, musicinfo_t *song )
504{
505#ifdef HAVE_MIXER
506 if (!filename) return 1;
507 if (!song) return 1;
508 music[0] = Mix_LoadMUS(filename);
509 if (music[0] == NULL)
510 {
511 lprintf(LO_WARN,"Couldn't load music from %s: %s\nAttempting to load default MIDI music.\n", filename, Mix_GetError());
512 return 1;
513 }
514 else
515 {
516 song->data = 0;
517 song->handle = 0;
518 song->lumpnum = 0;
519 return 0;
520 }
521#else
522 return 1;
523#endif
524}
525
526void I_SetMusicVolume(int volume)
527{
528#ifdef HAVE_MIXER
529 Mix_VolumeMusic(volume*8);
530#endif
531}
532
533#endif /* HAVE_OWN_MUSIC */
534
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2006 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Screenshot functions, moved out of i_video.c
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <stdlib.h>
40
41
42#ifdef HAVE_LIBPNG
43#include <png.h>
44#endif
45
46#include "doomstat.h"
47#include "doomdef.h"
48#include "doomtype.h"
49#include "v_video.h"
50#include "i_video.h"
51#include "z_zone.h"
52#include "lprintf.h"
53
54
55
56int I_ScreenShot (const char *fname)
57{
58
59}
60
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 @@
1
2
3#include <stdio.h>
4
5#include <stdarg.h>
6#include <stdlib.h>
7#include <ctype.h>
8#include <signal.h>
9#ifdef _MSC_VER
10#define F_OK 0 /* Check for file existence */
11#define W_OK 2 /* Check for write permission */
12#define R_OK 4 /* Check for read permission */
13#include <io.h>
14#include <direct.h>
15#else
16#include <unistd.h>
17#include <time.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <sys/time.h>
22#endif
23#include <sys/stat.h>
24
25#ifdef _WIN32
26#define WIN32_LEAN_AND_MEAN
27#include <windows.h>
28#endif
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33#ifdef HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36#ifdef HAVE_SCHED_H
37#include <sched.h>
38#endif
39#ifdef _MSC_VER
40#include <io.h>
41#endif
42#include <fcntl.h>
43#include <sys/stat.h>
44#include <errno.h>
45
46#ifndef PRBOOM_SERVER
47#include "m_argv.h"
48#endif
49#include "lprintf.h"
50#include "doomtype.h"
51#include "doomdef.h"
52#include "lprintf.h"
53#ifndef PRBOOM_SERVER
54#include "m_fixed.h"
55#include "r_fps.h"
56#endif
57#include "i_system.h"
58
59#ifdef __GNUG__
60#pragma implementation "i_system.h"
61#endif
62#include "i_system.h"
63
64#ifdef HAVE_CONFIG_H
65#include "config.h"
66#endif
67
68static unsigned int start_displaytime;
69static unsigned int displaytime;
70static boolean InDisplay = false;
71
72unsigned int SDL_GetTicks() {
73 struct timespec ts;
74 clock_gettime(CLOCK_REALTIME, &ts);
75
76 return ((unsigned int)ts.tv_sec*1000) + (ts.tv_nsec/1000);
77}
78
79boolean I_StartDisplay(void)
80{
81 if (InDisplay)
82 return false;
83
84 start_displaytime = SDL_GetTicks();
85 InDisplay = true;
86 return true;
87}
88
89void I_EndDisplay(void)
90{
91 displaytime = SDL_GetTicks() - start_displaytime;
92 InDisplay = false;
93}
94
95void I_uSleep(unsigned long usecs)
96{
97 sleep(usecs/1000);
98}
99
100int ms_to_next_tick;
101
102int I_GetTime_RealTime (void)
103{
104 /* int t = SDL_GetTicks();
105 int i = t*(TICRATE/5)/200;
106 ms_to_next_tick = (i+1)*200/(TICRATE/5) - t;
107 if (ms_to_next_tick > 1000/TICRATE || ms_to_next_tick<1) ms_to_next_tick = 1;
108 return i;*/
109 struct timeval tv;
110struct timezone tz;
111unsigned long thistimereply;
112
113gettimeofday(&tv, &tz);
114
115//tv_sec is seconds tv_usec is microseconds
116thistimereply = (tv.tv_sec * TICRATE + (tv.tv_usec * TICRATE) /
1171000000);
118return thistimereply;
119}
120
121#ifndef PRBOOM_SERVER
122fixed_t I_GetTimeFrac (void)
123{
124 unsigned long now;
125 fixed_t frac;
126
127 now = SDL_GetTicks();
128
129 if (tic_vars.step == 0)
130 return FRACUNIT;
131 else
132 {
133 frac = (fixed_t)((now - tic_vars.start + displaytime) * FRACUNIT / tic_vars.step);
134 if (frac < 0)
135 frac = 0;
136 if (frac > FRACUNIT)
137 frac = FRACUNIT;
138 return frac;
139 }
140}
141
142void I_GetTime_SaveMS(void)
143{
144 if (!movement_smooth)
145 return;
146
147 tic_vars.start = SDL_GetTicks();
148 tic_vars.next = (unsigned int) ((tic_vars.start * tic_vars.msec + 1.0f) / tic_vars.msec);
149 tic_vars.step = tic_vars.next - tic_vars.start;
150}
151#endif
152
153/*
154 * I_GetRandomTimeSeed
155 *
156 * CPhipps - extracted from G_ReloadDefaults because it is O/S based
157 */
158unsigned long I_GetRandomTimeSeed(void)
159{
160/* This isnt very random */
161 return(SDL_GetTicks());
162}
163
164/* cphipps - I_GetVersionString
165 * Returns a version string in the given buffer
166 */
167const char* I_GetVersionString(char* buf, size_t sz)
168{
169#ifdef HAVE_SNPRINTF
170 snprintf(buf,sz,"%s v%s (http://prboom.sourceforge.net/)",PACKAGE,VERSION);
171#else
172 sprintf(buf,"%s v%s (http://prboom.sourceforge.net/)",PACKAGE,VERSION);
173#endif
174 return buf;
175}
176
177/* cphipps - I_SigString
178 * Returns a string describing a signal number
179 */
180const char* I_SigString(char* buf, size_t sz, int signum)
181{
182#ifdef SYS_SIGLIST_DECLARED
183 if (strlen(sys_siglist[signum]) < sz)
184 strcpy(buf,sys_siglist[signum]);
185 else
186#endif
187#ifdef HAVE_SNPRINTF
188 snprintf(buf,sz,"signal %d",signum);
189#else
190 sprintf(buf,"signal %d",signum);
191#endif
192 return buf;
193}
194
195
196/*
197 * I_Read
198 *
199 * cph 2001/11/18 - wrapper for read(2) which handles partial reads and aborts
200 * on error.
201 */
202void I_Read(int fd, void* vbuf, size_t sz)
203{
204 unsigned char* buf = vbuf;
205
206 while (sz) {
207 int rc = read(fd,buf,sz);
208 if (rc <= 0) {
209 I_Error("I_Read: read failed: %s", rc ? strerror(errno) : "EOF");
210 }
211 sz -= rc; buf += rc;
212 }
213}
214
215/*
216 * I_Filelength
217 *
218 * Return length of an open file.
219 */
220
221int I_Filelength(int handle)
222{
223 struct stat fileinfo;
224 if (fstat(handle,&fileinfo) == -1)
225 I_Error("I_Filelength: %s",strerror(errno));
226 return fileinfo.st_size;
227}
228
229#ifndef PRBOOM_SERVER
230
231// Return the path where the executable lies -- Lee Killough
232// proff_fs 2002-07-04 - moved to i_system
233#ifdef _WIN32
234const char *I_DoomExeDir(void)
235{
236 static const char current_dir_dummy[] = {"."}; // proff - rem extra slash 8/21/03
237 static char *base;
238 if (!base) // cache multiple requests
239 {
240 size_t len = strlen(*myargv);
241 char *p = (base = malloc(len+1)) + len - 1;
242 strcpy(base,*myargv);
243 while (p > base && *p!='/' && *p!='\\')
244 *p--=0;
245 if (*p=='/' || *p=='\\')
246 *p--=0;
247 if (strlen(base)<2)
248 {
249 free(base);
250 base = malloc(1024);
251 if (!getcwd(base,1024))
252 strcpy(base, current_dir_dummy);
253 }
254 }
255 return base;
256}
257
258#elif defined(AMIGA)
259
260const char *I_DoomExeDir(void)
261{
262 return "PROGDIR:";
263}
264
265#elif defined(MACOSX)
266
267/* Defined elsewhere */
268
269#else
270// cph - V.Aguilar (5/30/99) suggested return ~/.lxdoom/, creating
271// if non-existant
272static const char prboom_dir[] = {"/.prboom"}; // Mead rem extra slash 8/21/03
273
274const char *I_DoomExeDir(void)
275{
276 static char *base;
277 if (!base) // cache multiple requests
278 {
279 char *home = getenv("HOME");
280 size_t len = strlen(home);
281
282 base = malloc(len + strlen(prboom_dir) + 1);
283 strcpy(base, home);
284 // I've had trouble with trailing slashes before...
285 if (base[len-1] == '/') base[len-1] = 0;
286 strcat(base, prboom_dir);
287 mkdir(base, S_IRUSR | S_IWUSR | S_IXUSR); // Make sure it exists
288 }
289 return base;
290}
291#endif
292
293/*
294 * HasTrailingSlash
295 *
296 * cphipps - simple test for trailing slash on dir names
297 */
298
299boolean HasTrailingSlash(const char* dn)
300{
301 return ( (dn[strlen(dn)-1] == '/')
302#if defined(AMIGA)
303 || (dn[strlen(dn)-1] == ':')
304#endif
305 );
306}
307
308/*
309 * I_FindFile
310 *
311 * proff_fs 2002-07-04 - moved to i_system
312 *
313 * cphipps 19/1999 - writen to unify the logic in FindIWADFile and the WAD
314 * autoloading code.
315 * Searches the standard dirs for a named WAD file
316 * The dirs are listed at the start of the function
317 */
318
319#ifndef MACOSX /* OSX defines its search paths elsewhere. */
320char* I_FindFile(const char* wfname, const char* ext)
321{
322 // lookup table of directories to search
323 static const struct {
324 const char *dir; // directory
325 const char *sub; // subdirectory
326 const char *env; // environment variable
327 const char *(*func)(void); // for I_DoomExeDir
328 } search[] = {
329 {NULL}, // current working directory
330 {NULL, NULL, "DOOMWADDIR"}, // run-time $DOOMWADDIR
331 {DOOMWADDIR}, // build-time configured DOOMWADDIR
332 {NULL, "doom", "HOME"}, // ~/doom
333 {NULL, NULL, "HOME"}, // ~
334 {NULL, NULL, NULL, I_DoomExeDir}, // config directory
335 {"/usr/local/share/games/doom"},
336 {"/usr/share/games/doom"},
337 {"/usr/local/share/doom"},
338 {"/usr/share/doom"},
339 };
340
341 int i;
342 /* Precalculate a length we will need in the loop */
343 size_t pl = strlen(wfname) + strlen(ext) + 4;
344
345 for (i = 0; i < sizeof(search)/sizeof(*search); i++) {
346 char * p;
347 const char * d = NULL;
348 const char * s = NULL;
349 /* Each entry in the switch sets d to the directory to look in,
350 * and optionally s to a subdirectory of d */
351 // switch replaced with lookup table
352 if (search[i].env) {
353 if (!(d = getenv(search[i].env)))
354 continue;
355 } else if (search[i].func)
356 d = search[i].func();
357 else
358 d = search[i].dir;
359 s = search[i].sub;
360
361 p = malloc((d ? strlen(d) : 0) + (s ? strlen(s) : 0) + pl);
362 sprintf(p, "%s%s%s%s%s", d ? d : "", (d && !HasTrailingSlash(d)) ? "/" : "",
363 s ? s : "", (s && !HasTrailingSlash(s)) ? "/" : "",
364 wfname);
365
366 if (access(p,F_OK))
367 strcat(p, ext);
368 if (!access(p,F_OK)) {
369 lprintf(LO_INFO, " found %s\n", p);
370 return p;
371 }
372 free(p);
373 }
374 return NULL;
375}
376#endif
377
378#ifdef _WIN32
379static char* WINError(void)
380{
381 static char *WinEBuff = NULL;
382 DWORD err = GetLastError();
383 char *ch;
384
385 if (WinEBuff)
386 {
387 LocalFree(WinEBuff);
388 }
389
390 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
391 NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
392 (LPTSTR) &WinEBuff, 0, NULL) == 0)
393 {
394 return "Unknown error";
395 }
396
397 if ((ch = strchr(WinEBuff, '\n')) != 0)
398 *ch = 0;
399 if ((ch = strchr(WinEBuff, '\r')) != 0)
400 *ch = 0;
401
402 return WinEBuff;
403}
404#endif
405
406#define DEFAULT_AFFINITY_MASK 1
407
408void I_SetAffinityMask(void)
409{
410 unsigned int process_affinity_mask = DEFAULT_AFFINITY_MASK;
411 int p = M_CheckParm("-affinity");
412
413 if (p && p < myargc-1)
414 process_affinity_mask = atoi(myargv[p+1]);
415
416 // Set the process affinity mask so that all threads
417 // run on the same processor. This is a workaround for a bug in
418 // SDL_mixer that causes occasional crashes.
419 if (process_affinity_mask)
420 {
421 const char *errbuf = NULL;
422#ifdef _WIN32
423 if (!SetProcessAffinityMask(GetCurrentProcess(), process_affinity_mask))
424 {
425 errbuf = WINError();
426 }
427#elif defined(HAVE_SCHED_SETAFFINITY)
428 // POSIX version:
429 int i;
430 {
431 cpu_set_t set;
432
433 CPU_ZERO(&set);
434
435 for(i = 0; i < 16; i++)
436 {
437 CPU_SET((process_affinity_mask>>i)&1, &set);
438 }
439
440 if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
441 {
442 errbuf = strerror(errno);
443 }
444 }
445#else
446 return;
447#endif
448
449 if (errbuf == NULL)
450 {
451 lprintf(LO_INFO, "I_SetAffinityMask: manual affinity mask is %d\n", process_affinity_mask);
452 }
453 else
454 {
455 lprintf(LO_ERROR, "I_SetAffinityMask: failed to set process affinity mask (%s)\n", errbuf);
456 }
457 }
458}
459
460#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2006 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * DOOM graphics stuff for SDL
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <stdlib.h>
40
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#include <errno.h>
44#include <sys/mman.h>
45#include <sys/types.h>
46#include <sys/stat.h>
47#include <fcntl.h>
48#include <sys/ioctl.h>
49#endif
50
51
52#include "m_argv.h"
53#include "doomstat.h"
54#include "doomdef.h"
55#include "doomtype.h"
56#include "v_video.h"
57#include "r_draw.h"
58#include "d_main.h"
59#include "d_event.h"
60#include "i_joy.h"
61#include "i_video.h"
62#include "z_zone.h"
63#include "s_sound.h"
64#include "sounds.h"
65#include "w_wad.h"
66#include "st_stuff.h"
67#include "lprintf.h"
68
69int gl_colorbuffer_bits=16;
70int gl_depthbuffer_bits=16;
71
72extern void M_QuitDOOM(int choice);
73#ifdef DISABLE_DOUBLEBUFFER
74int use_doublebuffer = 0;
75#else
76int use_doublebuffer = 1; // Included not to break m_misc, but not relevant to SDL
77#endif
78int use_fullscreen;
79int desired_fullscreen;
80static byte *screen;
81static int fbFd;
82static int kindleKeysFd;
83static int kindleKeysFd2;
84
85typedef struct {
86 int truc1;
87 int truc2;
88 unsigned short truc3;
89 unsigned short keyCode;
90 int status;
91} kindle_key_t;
92
93static kindle_key_t kkey;
94
95#define SCREEN_WIDTH 600
96#define SCREEN_HEIGHT 800
97
98/////////// FRAMEBUFFER STUFF
99static void init_framebuffer() {
100 fbFd = open("/dev/fb0", O_RDWR);
101 if (fbFd == -1) {
102 perror("open(/dev/fb0)");
103 exit(1);
104 }
105}
106
107static void update_framebuffer(int full) {
108 if (full) {
109 ioctl(fbFd, 0x46db, 1);
110 } else {
111 ioctl(fbFd, 0x46db, 0);
112 }
113}
114
115static void clear_framebuffer() {
116 ioctl(fbFd, 0x46e1, 0);
117}
118
119
120////// KINDLE EVENTS
121
122static void init_kindle_keys() {
123 kindleKeysFd = open("/dev/input/event1", O_RDONLY|O_NONBLOCK);
124 if (kindleKeysFd == -1) {
125 perror("open(/dev/input/event1)");
126 exit(1);
127 }
128
129 kindleKeysFd2 = open("/dev/input/event0", O_RDONLY|O_NONBLOCK);
130 if (kindleKeysFd2 == -1) {
131 perror("open(/dev/input/event0)");
132 exit(1);
133 }
134}
135
136static int kindle_poll_keys(kindle_key_t *k) {
137 int retval = read(kindleKeysFd, k, sizeof(kindle_key_t));
138 if (retval == -1) {
139 if (errno != EAGAIN) {
140 perror("read()");
141 exit(1);
142 }
143 } else if (retval > 0) {
144 return 1;
145 }
146
147 // This SHOULD NOT WORK: /dev/input/event0 doesn't have the same structure as event1
148 // For some reason it matches for the HOME key, but it's a kludge and doesn't allow us to detect the other buttons
149 retval = read(kindleKeysFd2, k, sizeof(kindle_key_t));
150 if (retval == -1) {
151 if (errno != EAGAIN) {
152 perror("read()");
153 exit(1);
154 }
155 } else if (retval > 0) {
156 return 1;
157 }
158
159 return 0;
160}
161
162////////////////////////////////////////////////////////////////////////////
163// Input code
164int leds_always_off = 0; // Expected by m_misc, not relevant
165
166// Mouse handling
167extern int usemouse; // config file var
168static boolean mouse_enabled; // usemouse, but can be overriden by -nomouse
169static boolean mouse_currently_grabbed;
170
171/////////////////////////////////////////////////////////////////////////////////
172// Keyboard handling
173
174//
175// Translates the key currently in key
176//
177
178#define KINDLE_LEFT 105
179#define KINDLE_RIGHT 106
180#define KINDLE_UP 103
181#define KINDLE_DOWN 108
182#define KINDE_OK 194
183#define KINDLE_HOME 102
184#define KINDLE_MENU 139
185#define KINDLE_BACK 158
186
187static int I_TranslateKey(unsigned short code)
188{
189 int rc = 0;
190
191 switch (code) {
192 case KINDLE_LEFT: rc = KEYD_LEFTARROW; break;
193 case KINDLE_RIGHT: rc = KEYD_RIGHTARROW; break;
194 case KINDLE_UP: rc = KEYD_UPARROW; break;
195 case KINDLE_DOWN: rc = KEYD_DOWNARROW; break;
196 case KINDE_OK: rc = KEYD_RCTRL; break;
197 default: break;
198 }
199
200
201 return rc;
202
203}
204
205/////////////////////////////////////////////////////////////////////////////////
206// Main input code
207
208/* cph - pulled out common button code logic */
209static int I_SDLtoDoomMouseState(int buttonstate)
210{
211 return 0;
212}
213
214static void I_GetEvent(kindle_key_t k)
215{
216 event_t event;
217
218 if (k.keyCode == 102 && k.status == 1) {
219 // Press HOME
220 exit(0);
221 }
222
223 switch (k.status) {
224 case 1: // SDL_KEYDOWN
225 event.type = ev_keydown;
226 event.data1 = I_TranslateKey(k.keyCode);
227 D_PostEvent(&event);
228 break;
229
230 case 0: // SDL_KEYUP
231 {
232 event.type = ev_keyup;
233 event.data1 = I_TranslateKey(k.keyCode);
234 D_PostEvent(&event);
235 }
236 break;
237
238 default:
239 break;
240 }
241}
242
243
244//
245// I_StartTic
246//
247
248void I_StartTic (void)
249{
250 while ( kindle_poll_keys(&kkey)) {
251 //printf("Keycode: %d // Status: %d\n", kkey.keyCode, kkey.status);
252 I_GetEvent(kkey);
253 }
254}
255
256//
257// I_StartFrame
258//
259void I_StartFrame (void)
260{
261}
262
263//
264// I_InitInputs
265//
266
267static void I_InitInputs(void)
268{
269 init_kindle_keys();
270}
271/////////////////////////////////////////////////////////////////////////////
272
273// I_SkipFrame
274//
275// Returns true if it thinks we can afford to skip this frame
276
277inline static boolean I_SkipFrame(void)
278{
279 static int frameno;
280
281 frameno++;
282 switch (gamestate) {
283 case GS_LEVEL:
284 if (!paused)
285 return false;
286 default:
287 // Skip odd frames
288 return (frameno & 1) ? true : false;
289 }
290}
291
292///////////////////////////////////////////////////////////
293// Palette stuff.
294//
295static void I_UploadNewPalette(int pal)
296{
297}
298
299//////////////////////////////////////////////////////////////////////////////
300// Graphics API
301
302void I_ShutdownGraphics(void)
303{
304}
305
306//
307// I_UpdateNoBlit
308//
309void I_UpdateNoBlit (void)
310{
311}
312
313//
314// I_FinishUpdate
315//
316static int newpal = 0;
317#define NO_PALETTE_CHANGE 1000
318
319void I_FinishUpdate (void)
320{
321 if (I_SkipFrame()) return;
322
323
324 int h;
325 byte *src;
326 byte *dest;
327
328
329 dest=screen;
330 src=screens[0].data;
331 h=SCREEN_HEIGHT;
332 for (; h>0; h--)
333 {
334 memcpy(dest,src,SCREENWIDTH); //*V_GetPixelDepth()
335 for (byte* off=dest; off < dest+SCREENWIDTH; off++) {
336 *off = ~*off; // Invert pixel color, 0xFF == black on the e-ink display
337 }
338 dest+=SCREEN_WIDTH;
339 src+=screens[0].byte_pitch;
340 }
341
342
343 update_framebuffer(0);
344}
345
346//
347// I_ScreenShot - moved to i_sshot.c
348//
349
350//
351// I_SetPalette
352//
353void I_SetPalette (int pal)
354{
355 newpal = pal;
356}
357
358// I_PreInitGraphics
359
360static void I_ShutdownSDL(void)
361{
362 clear_framebuffer();
363 close(fbFd);
364 return;
365}
366
367void I_PreInitGraphics(void)
368{
369 init_framebuffer();
370
371 atexit(I_ShutdownSDL);
372}
373
374// e6y
375// GLBoom use this function for trying to set the closest supported resolution if the requested mode can't be set correctly.
376// For example glboom.exe -geom 1025x768 -nowindow will set 1024x768.
377// It should be used only for fullscreen modes.
378static void I_ClosestResolution (int *width, int *height, int flags)
379{
380 *width=600;
381 *height=800;
382}
383
384// CPhipps -
385// I_CalculateRes
386// Calculates the screen resolution, possibly using the supplied guide
387void I_CalculateRes(unsigned int width, unsigned int height)
388{
389 // e6y: how about 1680x1050?
390 /*
391 SCREENWIDTH = (width+3) & ~3;
392 SCREENHEIGHT = (height+3) & ~3;
393 */
394
395// e6y
396// GLBoom will try to set the closest supported resolution
397// if the requested mode can't be set correctly.
398// For example glboom.exe -geom 1025x768 -nowindow will set 1024x768.
399// It affects only fullscreen modes.
400 if (V_GetMode() == VID_MODEGL) {
401 if ( desired_fullscreen )
402 {
403 I_ClosestResolution(&width, &height, 0);
404 }
405 SCREENWIDTH = width;
406 SCREENHEIGHT = height;
407 SCREENPITCH = SCREENWIDTH;
408 } else {
409 SCREENWIDTH = 600;//(width+15) & ~15;
410 SCREENHEIGHT = height;
411 if (!(SCREENWIDTH % 1024)) {
412 SCREENPITCH = SCREENWIDTH*V_GetPixelDepth()+32;
413 } else {
414 SCREENPITCH = SCREENWIDTH*V_GetPixelDepth();
415 }
416 }
417}
418
419// CPhipps -
420// I_SetRes
421// Sets the screen resolution
422void I_SetRes(void)
423{
424 int i;
425
426 I_CalculateRes(SCREENWIDTH, SCREENHEIGHT);
427
428 // set first three to standard values
429 for (i=0; i<3; i++) {
430 screens[i].width = SCREENWIDTH;
431 screens[i].height = SCREENHEIGHT;
432 screens[i].byte_pitch = SCREENPITCH;
433 screens[i].short_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE16);
434 screens[i].int_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE32);
435 }
436
437 // statusbar
438 screens[4].width = SCREENWIDTH;
439 screens[4].height = (ST_SCALED_HEIGHT+1);
440 screens[4].byte_pitch = SCREENPITCH;
441 screens[4].short_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE16);
442 screens[4].int_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE32);
443
444 lprintf(LO_INFO,"I_SetRes: Using resolution %dx%d\n", SCREENWIDTH, SCREENHEIGHT);
445}
446
447void I_InitGraphics(void)
448{
449 char titlebuffer[2048];
450 static int firsttime=1;
451
452 if (firsttime)
453 {
454 firsttime = 0;
455
456 atexit(I_ShutdownGraphics);
457 lprintf(LO_INFO, "I_InitGraphics: %dx%d\n", SCREENWIDTH, SCREENHEIGHT);
458
459 /* Set the video mode */
460 I_UpdateVideoMode();
461
462 /* Setup the window title */
463 strcpy(titlebuffer,PACKAGE);
464 strcat(titlebuffer," ");
465 strcat(titlebuffer,VERSION);
466 printf("Title: %s\n", titlebuffer);
467
468 /* Initialize the input system */
469 I_InitInputs();
470 }
471}
472
473int I_GetModeFromString(const char *modestr)
474{
475 video_mode_t mode;
476
477
478 mode = VID_MODE8;
479
480 return mode;
481}
482
483void I_UpdateVideoMode(void)
484{
485 int init_flags;
486 int i;
487 video_mode_t mode;
488
489 lprintf(LO_INFO, "I_UpdateVideoMode: %dx%d (%s)\n", SCREENWIDTH, SCREENHEIGHT, desired_fullscreen ? "fullscreen" : "nofullscreen");
490
491 mode = I_GetModeFromString(default_videomode);
492 if ((i=M_CheckParm("-vidmode")) && i<myargc-1) {
493 mode = I_GetModeFromString(myargv[i+1]);
494 }
495
496 V_InitMode(mode);
497 V_DestroyUnusedTrueColorPalettes();
498 V_FreeScreens();
499
500 I_SetRes();
501
502
503 screen = mmap(NULL, 600 * 800, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fbFd, 0);
504
505 if(screen == NULL) {
506 I_Error("Couldn't set %dx%d video mode", SCREENWIDTH, SCREENHEIGHT);
507 }
508
509 lprintf(LO_INFO, "I_UpdateVideoMode: 0x%x, %s, %s\n", init_flags, "", "");
510
511 mouse_currently_grabbed = false;
512
513 // Get the info needed to render to the display
514
515 screens[0].not_on_heap = true;
516 screens[0].data = (unsigned char *) (screen);
517 screens[0].byte_pitch = SCREEN_WIDTH;
518 screens[0].short_pitch = SCREEN_WIDTH; // screen->pitch / V_GetModePixelDepth(VID_MODE16);
519 screens[0].int_pitch = SCREEN_WIDTH; // screen->pitch / V_GetModePixelDepth(VID_MODE32);
520
521
522 V_AllocScreens();
523
524 // Hide pointer while over this window
525 //SDL_ShowCursor(0);
526
527 R_InitBuffer(SCREENWIDTH, SCREENHEIGHT);
528
529}
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 @@
1#
2# automake Makefile.am for the PrBoom source directory
3#
4#
5# Process this file with automake to produce Makefile.in
6#
7#
8
9SUBDIRS = SDL POSIX MAC
10
11gamesdir=$(prefix)/games
12games_PROGRAMS = prboom prboom-game-server
13
14CFLAGS = @CFLAGS@ @SDL_CFLAGS@
15
16prboom_game_server_SOURCES = d_server.c protocol.h
17prboom_game_server_LDADD = POSIX/libposixdoom.a SDL/i_network.o @NET_LIBS@ @SDL_LIBS@
18
19COMMON_SRC = \
20 am_map.c g_game.c p_maputl.h r_plane.h \
21 am_map.h g_game.h p_mobj.c r_demo.c r_segs.c \
22 hu_lib.c lprintf.c p_mobj.h r_demo.h r_segs.h \
23 hu_lib.h lprintf.h p_plats.c r_sky.c \
24 d_deh.c hu_stuff.c m_argv.c p_pspr.c r_sky.h \
25 d_deh.h hu_stuff.h m_argv.h p_pspr.h r_state.h \
26 d_englsh.h i_joy.h m_bbox.c p_saveg.c r_things.c \
27 d_event.h m_bbox.h p_saveg.h r_things.h \
28 d_items.c i_network.h m_cheat.c p_setup.c s_sound.c \
29 d_items.h i_sound.h m_cheat.h p_setup.h s_sound.h \
30 d_main.c i_system.h m_fixed.h p_sight.c sounds.c \
31 d_main.h i_video.h m_menu.c p_spec.c sounds.h \
32 info.c m_menu.h p_spec.h st_lib.c \
33 d_net.h info.h m_misc.c p_switch.c st_lib.h \
34 d_player.h m_misc.h p_telept.c st_stuff.c \
35 m_random.c p_tick.c st_stuff.h i_main.h \
36 d_think.h m_random.h p_tick.h tables.c \
37 d_ticcmd.h m_swap.h p_user.c tables.h \
38 doomdata.h p_ceilng.c p_user.h v_video.c \
39 doomdef.c p_doors.c protocol.h v_video.h \
40 doomdef.h p_enemy.c r_bsp.c version.c \
41 doomstat.c p_enemy.h r_bsp.h version.h \
42 doomstat.h p_floor.c r_data.c w_wad.c \
43 doomtype.h p_genlin.c r_data.h w_wad.h \
44 dstrings.c p_inter.c r_defs.h wi_stuff.c \
45 dstrings.h p_inter.h r_draw.c wi_stuff.h \
46 f_finale.c p_lights.c r_draw.h z_bmalloc.c \
47 f_finale.h p_map.c r_main.c z_bmalloc.h \
48 f_wipe.c p_map.h r_main.h z_zone.c \
49 f_wipe.h p_maputl.c r_plane.c z_zone.h \
50 md5.c md5.h p_checksum.h p_checksum.c \
51 r_patch.c r_patch.h r_fps.c r_fps.h \
52 r_filter.c r_filter.h
53
54NET_CLIENT_SRC = d_client.c
55
56if BUILD_GL
57USE_GL_SRC = gl_intern.h gl_main.c gl_struct.h gl_texture.c
58else
59USE_GL_SRC =
60endif
61
62if WAD_MMAP
63WAD_SRC = w_mmap.c
64else
65WAD_SRC = w_memcache.c
66endif
67
68prboom_SOURCES = mmus2mid.c mmus2mid.h $(COMMON_SRC) $(NET_CLIENT_SRC) $(USE_GL_SRC) $(WAD_SRC)
69prboom_LDADD = SDL/libsdldoom.a @MIXER_LIBS@ @NET_LIBS@ @SDL_LIBS@ @GL_LIBS@ @MATH_LIB@
70
71EXTRA_DIST = \
72 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 @@
1# Makefile.in generated by automake 1.10 from Makefile.am.
2# @configure_input@
3
4# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
5# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
6# This Makefile.in is free software; the Free Software Foundation
7# gives unlimited permission to copy and/or distribute it,
8# with or without modifications, as long as this notice is preserved.
9
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
12# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13# PARTICULAR PURPOSE.
14
15@SET_MAKE@
16
17#
18# automake Makefile.am for the PrBoom source directory
19#
20#
21# Process this file with automake to produce Makefile.in
22#
23#
24
25VPATH = @srcdir@
26pkgdatadir = $(datadir)/@PACKAGE@
27pkglibdir = $(libdir)/@PACKAGE@
28pkgincludedir = $(includedir)/@PACKAGE@
29am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
30install_sh_DATA = $(install_sh) -c -m 644
31install_sh_PROGRAM = $(install_sh) -c
32install_sh_SCRIPT = $(install_sh) -c
33INSTALL_HEADER = $(INSTALL_DATA)
34transform = $(program_transform_name)
35NORMAL_INSTALL = :
36PRE_INSTALL = :
37POST_INSTALL = :
38NORMAL_UNINSTALL = :
39PRE_UNINSTALL = :
40POST_UNINSTALL = :
41build_triplet = @build@
42host_triplet = @host@
43target_triplet = @target@
44games_PROGRAMS = prboom$(EXEEXT) prboom-game-server$(EXEEXT)
45subdir = src
46DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
47ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
48am__aclocal_m4_deps = $(top_srcdir)/autotools/ac_c_compile_flags.m4 \
49 $(top_srcdir)/autotools/ac_cpu_optimisations.m4 \
50 $(top_srcdir)/configure.ac
51am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
52 $(ACLOCAL_M4)
53mkinstalldirs = $(install_sh) -d
54CONFIG_HEADER = $(top_builddir)/config.h
55CONFIG_CLEAN_FILES =
56am__installdirs = "$(DESTDIR)$(gamesdir)"
57gamesPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
58PROGRAMS = $(games_PROGRAMS)
59am__prboom_SOURCES_DIST = mmus2mid.c mmus2mid.h am_map.c g_game.c \
60 p_maputl.h r_plane.h am_map.h g_game.h p_mobj.c r_demo.c \
61 r_segs.c hu_lib.c lprintf.c p_mobj.h r_demo.h r_segs.h \
62 hu_lib.h lprintf.h p_plats.c r_sky.c d_deh.c hu_stuff.c \
63 m_argv.c p_pspr.c r_sky.h d_deh.h hu_stuff.h m_argv.h p_pspr.h \
64 r_state.h d_englsh.h i_joy.h m_bbox.c p_saveg.c r_things.c \
65 d_event.h m_bbox.h p_saveg.h r_things.h d_items.c i_network.h \
66 m_cheat.c p_setup.c s_sound.c d_items.h i_sound.h m_cheat.h \
67 p_setup.h s_sound.h d_main.c i_system.h m_fixed.h p_sight.c \
68 sounds.c d_main.h i_video.h m_menu.c p_spec.c sounds.h info.c \
69 m_menu.h p_spec.h st_lib.c d_net.h info.h m_misc.c p_switch.c \
70 st_lib.h d_player.h m_misc.h p_telept.c st_stuff.c m_random.c \
71 p_tick.c st_stuff.h i_main.h d_think.h m_random.h p_tick.h \
72 tables.c d_ticcmd.h m_swap.h p_user.c tables.h doomdata.h \
73 p_ceilng.c p_user.h v_video.c doomdef.c p_doors.c protocol.h \
74 v_video.h doomdef.h p_enemy.c r_bsp.c version.c doomstat.c \
75 p_enemy.h r_bsp.h version.h doomstat.h p_floor.c r_data.c \
76 w_wad.c doomtype.h p_genlin.c r_data.h w_wad.h dstrings.c \
77 p_inter.c r_defs.h wi_stuff.c dstrings.h p_inter.h r_draw.c \
78 wi_stuff.h f_finale.c p_lights.c r_draw.h z_bmalloc.c \
79 f_finale.h p_map.c r_main.c z_bmalloc.h f_wipe.c p_map.h \
80 r_main.h z_zone.c f_wipe.h p_maputl.c r_plane.c z_zone.h md5.c \
81 md5.h p_checksum.h p_checksum.c r_patch.c r_patch.h r_fps.c \
82 r_fps.h r_filter.c r_filter.h d_client.c gl_intern.h gl_main.c \
83 gl_struct.h gl_texture.c w_memcache.c w_mmap.c
84am__objects_1 = am_map.$(OBJEXT) g_game.$(OBJEXT) p_mobj.$(OBJEXT) \
85 r_demo.$(OBJEXT) r_segs.$(OBJEXT) hu_lib.$(OBJEXT) \
86 lprintf.$(OBJEXT) p_plats.$(OBJEXT) r_sky.$(OBJEXT) \
87 d_deh.$(OBJEXT) hu_stuff.$(OBJEXT) m_argv.$(OBJEXT) \
88 p_pspr.$(OBJEXT) m_bbox.$(OBJEXT) p_saveg.$(OBJEXT) \
89 r_things.$(OBJEXT) d_items.$(OBJEXT) m_cheat.$(OBJEXT) \
90 p_setup.$(OBJEXT) s_sound.$(OBJEXT) d_main.$(OBJEXT) \
91 p_sight.$(OBJEXT) sounds.$(OBJEXT) m_menu.$(OBJEXT) \
92 p_spec.$(OBJEXT) info.$(OBJEXT) st_lib.$(OBJEXT) \
93 m_misc.$(OBJEXT) p_switch.$(OBJEXT) p_telept.$(OBJEXT) \
94 st_stuff.$(OBJEXT) m_random.$(OBJEXT) p_tick.$(OBJEXT) \
95 tables.$(OBJEXT) p_user.$(OBJEXT) p_ceilng.$(OBJEXT) \
96 v_video.$(OBJEXT) doomdef.$(OBJEXT) p_doors.$(OBJEXT) \
97 p_enemy.$(OBJEXT) r_bsp.$(OBJEXT) version.$(OBJEXT) \
98 doomstat.$(OBJEXT) p_floor.$(OBJEXT) r_data.$(OBJEXT) \
99 w_wad.$(OBJEXT) p_genlin.$(OBJEXT) dstrings.$(OBJEXT) \
100 p_inter.$(OBJEXT) wi_stuff.$(OBJEXT) r_draw.$(OBJEXT) \
101 f_finale.$(OBJEXT) p_lights.$(OBJEXT) z_bmalloc.$(OBJEXT) \
102 p_map.$(OBJEXT) r_main.$(OBJEXT) f_wipe.$(OBJEXT) \
103 z_zone.$(OBJEXT) p_maputl.$(OBJEXT) r_plane.$(OBJEXT) \
104 md5.$(OBJEXT) p_checksum.$(OBJEXT) r_patch.$(OBJEXT) \
105 r_fps.$(OBJEXT) r_filter.$(OBJEXT)
106am__objects_2 = d_client.$(OBJEXT)
107@BUILD_GL_TRUE@am__objects_3 = gl_main.$(OBJEXT) gl_texture.$(OBJEXT)
108@WAD_MMAP_FALSE@am__objects_4 = w_memcache.$(OBJEXT)
109@WAD_MMAP_TRUE@am__objects_4 = w_mmap.$(OBJEXT)
110am_prboom_OBJECTS = mmus2mid.$(OBJEXT) $(am__objects_1) \
111 $(am__objects_2) $(am__objects_3) $(am__objects_4)
112prboom_OBJECTS = $(am_prboom_OBJECTS)
113prboom_DEPENDENCIES = SDL/libsdldoom.a
114am_prboom_game_server_OBJECTS = d_server.$(OBJEXT)
115prboom_game_server_OBJECTS = $(am_prboom_game_server_OBJECTS)
116prboom_game_server_DEPENDENCIES = POSIX/libposixdoom.a SDL/i_network.o
117DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
118depcomp = $(SHELL) $(top_srcdir)/autotools/depcomp
119am__depfiles_maybe = depfiles
120COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
121 $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
122CCLD = $(CC)
123LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
124SOURCES = $(prboom_SOURCES) $(prboom_game_server_SOURCES)
125DIST_SOURCES = $(am__prboom_SOURCES_DIST) \
126 $(prboom_game_server_SOURCES)
127RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
128 html-recursive info-recursive install-data-recursive \
129 install-dvi-recursive install-exec-recursive \
130 install-html-recursive install-info-recursive \
131 install-pdf-recursive install-ps-recursive install-recursive \
132 installcheck-recursive installdirs-recursive pdf-recursive \
133 ps-recursive uninstall-recursive
134RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
135 distclean-recursive maintainer-clean-recursive
136ETAGS = etags
137CTAGS = ctags
138DIST_SUBDIRS = $(SUBDIRS)
139DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
140ACLOCAL = @ACLOCAL@
141AMTAR = @AMTAR@
142AUTOCONF = @AUTOCONF@
143AUTOHEADER = @AUTOHEADER@
144AUTOMAKE = @AUTOMAKE@
145AWK = @AWK@
146CC = @CC@
147CCDEPMODE = @CCDEPMODE@
148CFLAGS = @CFLAGS@ @SDL_CFLAGS@
149CPP = @CPP@
150CPPFLAGS = @CPPFLAGS@
151CYGPATH_W = @CYGPATH_W@
152DEFS = @DEFS@
153DEPDIR = @DEPDIR@
154DOOMWADDIR = @DOOMWADDIR@
155ECHO_C = @ECHO_C@
156ECHO_N = @ECHO_N@
157ECHO_T = @ECHO_T@
158EGREP = @EGREP@
159EXEEXT = @EXEEXT@
160GL_LIBS = @GL_LIBS@
161GREP = @GREP@
162INSTALL = @INSTALL@
163INSTALL_DATA = @INSTALL_DATA@
164INSTALL_PROGRAM = @INSTALL_PROGRAM@
165INSTALL_SCRIPT = @INSTALL_SCRIPT@
166INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
167LDFLAGS = @LDFLAGS@
168LIBOBJS = @LIBOBJS@
169LIBS = @LIBS@
170LN_S = @LN_S@
171LTLIBOBJS = @LTLIBOBJS@
172MAKEINFO = @MAKEINFO@
173MATH_LIB = @MATH_LIB@
174MIXER_CFLAGS = @MIXER_CFLAGS@
175MIXER_LIBS = @MIXER_LIBS@
176MKDIR_P = @MKDIR_P@
177NET_CFLAGS = @NET_CFLAGS@
178NET_LIBS = @NET_LIBS@
179OBJEXT = @OBJEXT@
180PACKAGE = @PACKAGE@
181PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
182PACKAGE_NAME = @PACKAGE_NAME@
183PACKAGE_STRING = @PACKAGE_STRING@
184PACKAGE_TARNAME = @PACKAGE_TARNAME@
185PACKAGE_VERSION = @PACKAGE_VERSION@
186PATH_SEPARATOR = @PATH_SEPARATOR@
187RANLIB = @RANLIB@
188SDL_CFLAGS = @SDL_CFLAGS@
189SDL_CONFIG = @SDL_CONFIG@
190SDL_LIBS = @SDL_LIBS@
191SET_MAKE = @SET_MAKE@
192SHELL = @SHELL@
193STRIP = @STRIP@
194VERSION = @VERSION@
195abs_builddir = @abs_builddir@
196abs_srcdir = @abs_srcdir@
197abs_top_builddir = @abs_top_builddir@
198abs_top_srcdir = @abs_top_srcdir@
199ac_ct_CC = @ac_ct_CC@
200am__include = @am__include@
201am__leading_dot = @am__leading_dot@
202am__quote = @am__quote@
203am__tar = @am__tar@
204am__untar = @am__untar@
205bindir = @bindir@
206build = @build@
207build_alias = @build_alias@
208build_cpu = @build_cpu@
209build_os = @build_os@
210build_vendor = @build_vendor@
211builddir = @builddir@
212datadir = @datadir@
213datarootdir = @datarootdir@
214docdir = @docdir@
215dvidir = @dvidir@
216exec_prefix = @exec_prefix@
217host = @host@
218host_alias = @host_alias@
219host_cpu = @host_cpu@
220host_os = @host_os@
221host_vendor = @host_vendor@
222htmldir = @htmldir@
223includedir = @includedir@
224infodir = @infodir@
225install_sh = @install_sh@
226libdir = @libdir@
227libexecdir = @libexecdir@
228localedir = @localedir@
229localstatedir = @localstatedir@
230mandir = @mandir@
231mkdir_p = @mkdir_p@
232oldincludedir = @oldincludedir@
233pdfdir = @pdfdir@
234prefix = @prefix@
235program_transform_name = @program_transform_name@
236psdir = @psdir@
237sbindir = @sbindir@
238sharedstatedir = @sharedstatedir@
239srcdir = @srcdir@
240sysconfdir = @sysconfdir@
241target = @target@
242target_alias = @target_alias@
243target_cpu = @target_cpu@
244target_os = @target_os@
245target_vendor = @target_vendor@
246top_builddir = @top_builddir@
247top_srcdir = @top_srcdir@
248SUBDIRS = SDL POSIX MAC
249gamesdir = $(prefix)/games
250prboom_game_server_SOURCES = d_server.c protocol.h
251prboom_game_server_LDADD = POSIX/libposixdoom.a SDL/i_network.o @NET_LIBS@ @SDL_LIBS@
252COMMON_SRC = \
253 am_map.c g_game.c p_maputl.h r_plane.h \
254 am_map.h g_game.h p_mobj.c r_demo.c r_segs.c \
255 hu_lib.c lprintf.c p_mobj.h r_demo.h r_segs.h \
256 hu_lib.h lprintf.h p_plats.c r_sky.c \
257 d_deh.c hu_stuff.c m_argv.c p_pspr.c r_sky.h \
258 d_deh.h hu_stuff.h m_argv.h p_pspr.h r_state.h \
259 d_englsh.h i_joy.h m_bbox.c p_saveg.c r_things.c \
260 d_event.h m_bbox.h p_saveg.h r_things.h \
261 d_items.c i_network.h m_cheat.c p_setup.c s_sound.c \
262 d_items.h i_sound.h m_cheat.h p_setup.h s_sound.h \
263 d_main.c i_system.h m_fixed.h p_sight.c sounds.c \
264 d_main.h i_video.h m_menu.c p_spec.c sounds.h \
265 info.c m_menu.h p_spec.h st_lib.c \
266 d_net.h info.h m_misc.c p_switch.c st_lib.h \
267 d_player.h m_misc.h p_telept.c st_stuff.c \
268 m_random.c p_tick.c st_stuff.h i_main.h \
269 d_think.h m_random.h p_tick.h tables.c \
270 d_ticcmd.h m_swap.h p_user.c tables.h \
271 doomdata.h p_ceilng.c p_user.h v_video.c \
272 doomdef.c p_doors.c protocol.h v_video.h \
273 doomdef.h p_enemy.c r_bsp.c version.c \
274 doomstat.c p_enemy.h r_bsp.h version.h \
275 doomstat.h p_floor.c r_data.c w_wad.c \
276 doomtype.h p_genlin.c r_data.h w_wad.h \
277 dstrings.c p_inter.c r_defs.h wi_stuff.c \
278 dstrings.h p_inter.h r_draw.c wi_stuff.h \
279 f_finale.c p_lights.c r_draw.h z_bmalloc.c \
280 f_finale.h p_map.c r_main.c z_bmalloc.h \
281 f_wipe.c p_map.h r_main.h z_zone.c \
282 f_wipe.h p_maputl.c r_plane.c z_zone.h \
283 md5.c md5.h p_checksum.h p_checksum.c \
284 r_patch.c r_patch.h r_fps.c r_fps.h \
285 r_filter.c r_filter.h
286
287NET_CLIENT_SRC = d_client.c
288@BUILD_GL_FALSE@USE_GL_SRC =
289@BUILD_GL_TRUE@USE_GL_SRC = gl_intern.h gl_main.c gl_struct.h gl_texture.c
290@WAD_MMAP_FALSE@WAD_SRC = w_memcache.c
291@WAD_MMAP_TRUE@WAD_SRC = w_mmap.c
292prboom_SOURCES = mmus2mid.c mmus2mid.h $(COMMON_SRC) $(NET_CLIENT_SRC) $(USE_GL_SRC) $(WAD_SRC)
293prboom_LDADD = SDL/libsdldoom.a @MIXER_LIBS@ @NET_LIBS@ @SDL_LIBS@ @GL_LIBS@ @MATH_LIB@
294EXTRA_DIST = \
295 r_drawcolumn.inl r_drawflush.inl r_drawspan.inl r_drawcolpipeline.inl
296
297all: all-recursive
298
299.SUFFIXES:
300.SUFFIXES: .c .o .obj
301$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
302 @for dep in $?; do \
303 case '$(am__configure_deps)' in \
304 *$$dep*) \
305 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
306 && exit 0; \
307 exit 1;; \
308 esac; \
309 done; \
310 echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
311 cd $(top_srcdir) && \
312 $(AUTOMAKE) --foreign src/Makefile
313.PRECIOUS: Makefile
314Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
315 @case '$?' in \
316 *config.status*) \
317 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
318 *) \
319 echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
320 cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
321 esac;
322
323$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
324 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
325
326$(top_srcdir)/configure: $(am__configure_deps)
327 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
328$(ACLOCAL_M4): $(am__aclocal_m4_deps)
329 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
330install-gamesPROGRAMS: $(games_PROGRAMS)
331 @$(NORMAL_INSTALL)
332 test -z "$(gamesdir)" || $(MKDIR_P) "$(DESTDIR)$(gamesdir)"
333 @list='$(games_PROGRAMS)'; for p in $$list; do \
334 p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
335 if test -f $$p \
336 ; then \
337 f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
338 echo " $(INSTALL_PROGRAM_ENV) $(gamesPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(gamesdir)/$$f'"; \
339 $(INSTALL_PROGRAM_ENV) $(gamesPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(gamesdir)/$$f" || exit 1; \
340 else :; fi; \
341 done
342
343uninstall-gamesPROGRAMS:
344 @$(NORMAL_UNINSTALL)
345 @list='$(games_PROGRAMS)'; for p in $$list; do \
346 f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
347 echo " rm -f '$(DESTDIR)$(gamesdir)/$$f'"; \
348 rm -f "$(DESTDIR)$(gamesdir)/$$f"; \
349 done
350
351clean-gamesPROGRAMS:
352 -test -z "$(games_PROGRAMS)" || rm -f $(games_PROGRAMS)
353prboom$(EXEEXT): $(prboom_OBJECTS) $(prboom_DEPENDENCIES)
354 @rm -f prboom$(EXEEXT)
355 $(LINK) $(prboom_OBJECTS) $(prboom_LDADD) $(LIBS)
356prboom-game-server$(EXEEXT): $(prboom_game_server_OBJECTS) $(prboom_game_server_DEPENDENCIES)
357 @rm -f prboom-game-server$(EXEEXT)
358 $(LINK) $(prboom_game_server_OBJECTS) $(prboom_game_server_LDADD) $(LIBS)
359
360mostlyclean-compile:
361 -rm -f *.$(OBJEXT)
362
363distclean-compile:
364 -rm -f *.tab.c
365
366@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/am_map.Po@am__quote@
367@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_client.Po@am__quote@
368@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_deh.Po@am__quote@
369@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_items.Po@am__quote@
370@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_main.Po@am__quote@
371@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_server.Po@am__quote@
372@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doomdef.Po@am__quote@
373@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doomstat.Po@am__quote@
374@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dstrings.Po@am__quote@
375@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/f_finale.Po@am__quote@
376@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/f_wipe.Po@am__quote@
377@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/g_game.Po@am__quote@
378@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gl_main.Po@am__quote@
379@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gl_texture.Po@am__quote@
380@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hu_lib.Po@am__quote@
381@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hu_stuff.Po@am__quote@
382@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@
383@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lprintf.Po@am__quote@
384@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_argv.Po@am__quote@
385@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_bbox.Po@am__quote@
386@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_cheat.Po@am__quote@
387@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_menu.Po@am__quote@
388@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_misc.Po@am__quote@
389@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_random.Po@am__quote@
390@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
391@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmus2mid.Po@am__quote@
392@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_ceilng.Po@am__quote@
393@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_checksum.Po@am__quote@
394@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_doors.Po@am__quote@
395@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_enemy.Po@am__quote@
396@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_floor.Po@am__quote@
397@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_genlin.Po@am__quote@
398@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_inter.Po@am__quote@
399@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_lights.Po@am__quote@
400@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_map.Po@am__quote@
401@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_maputl.Po@am__quote@
402@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_mobj.Po@am__quote@
403@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_plats.Po@am__quote@
404@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_pspr.Po@am__quote@
405@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_saveg.Po@am__quote@
406@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_setup.Po@am__quote@
407@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_sight.Po@am__quote@
408@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_spec.Po@am__quote@
409@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_switch.Po@am__quote@
410@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_telept.Po@am__quote@
411@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_tick.Po@am__quote@
412@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_user.Po@am__quote@
413@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_bsp.Po@am__quote@
414@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_data.Po@am__quote@
415@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_demo.Po@am__quote@
416@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_draw.Po@am__quote@
417@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_filter.Po@am__quote@
418@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_fps.Po@am__quote@
419@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_main.Po@am__quote@
420@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_patch.Po@am__quote@
421@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_plane.Po@am__quote@
422@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_segs.Po@am__quote@
423@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_sky.Po@am__quote@
424@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_things.Po@am__quote@
425@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_sound.Po@am__quote@
426@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sounds.Po@am__quote@
427@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/st_lib.Po@am__quote@
428@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/st_stuff.Po@am__quote@
429@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tables.Po@am__quote@
430@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/v_video.Po@am__quote@
431@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
432@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w_memcache.Po@am__quote@
433@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w_mmap.Po@am__quote@
434@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w_wad.Po@am__quote@
435@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wi_stuff.Po@am__quote@
436@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/z_bmalloc.Po@am__quote@
437@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/z_zone.Po@am__quote@
438
439.c.o:
440@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
441@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
442@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
443@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
444@am__fastdepCC_FALSE@ $(COMPILE) -c $<
445
446.c.obj:
447@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
448@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
449@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
450@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
451@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
452
453# This directory's subdirectories are mostly independent; you can cd
454# into them and run `make' without going through this Makefile.
455# To change the values of `make' variables: instead of editing Makefiles,
456# (1) if the variable is set in `config.status', edit `config.status'
457# (which will cause the Makefiles to be regenerated when you run `make');
458# (2) otherwise, pass the desired values on the `make' command line.
459$(RECURSIVE_TARGETS):
460 @failcom='exit 1'; \
461 for f in x $$MAKEFLAGS; do \
462 case $$f in \
463 *=* | --[!k]*);; \
464 *k*) failcom='fail=yes';; \
465 esac; \
466 done; \
467 dot_seen=no; \
468 target=`echo $@ | sed s/-recursive//`; \
469 list='$(SUBDIRS)'; for subdir in $$list; do \
470 echo "Making $$target in $$subdir"; \
471 if test "$$subdir" = "."; then \
472 dot_seen=yes; \
473 local_target="$$target-am"; \
474 else \
475 local_target="$$target"; \
476 fi; \
477 (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
478 || eval $$failcom; \
479 done; \
480 if test "$$dot_seen" = "no"; then \
481 $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
482 fi; test -z "$$fail"
483
484$(RECURSIVE_CLEAN_TARGETS):
485 @failcom='exit 1'; \
486 for f in x $$MAKEFLAGS; do \
487 case $$f in \
488 *=* | --[!k]*);; \
489 *k*) failcom='fail=yes';; \
490 esac; \
491 done; \
492 dot_seen=no; \
493 case "$@" in \
494 distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
495 *) list='$(SUBDIRS)' ;; \
496 esac; \
497 rev=''; for subdir in $$list; do \
498 if test "$$subdir" = "."; then :; else \
499 rev="$$subdir $$rev"; \
500 fi; \
501 done; \
502 rev="$$rev ."; \
503 target=`echo $@ | sed s/-recursive//`; \
504 for subdir in $$rev; do \
505 echo "Making $$target in $$subdir"; \
506 if test "$$subdir" = "."; then \
507 local_target="$$target-am"; \
508 else \
509 local_target="$$target"; \
510 fi; \
511 (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
512 || eval $$failcom; \
513 done && test -z "$$fail"
514tags-recursive:
515 list='$(SUBDIRS)'; for subdir in $$list; do \
516 test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
517 done
518ctags-recursive:
519 list='$(SUBDIRS)'; for subdir in $$list; do \
520 test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
521 done
522
523ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
524 list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
525 unique=`for i in $$list; do \
526 if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
527 done | \
528 $(AWK) ' { files[$$0] = 1; } \
529 END { for (i in files) print i; }'`; \
530 mkid -fID $$unique
531tags: TAGS
532
533TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
534 $(TAGS_FILES) $(LISP)
535 tags=; \
536 here=`pwd`; \
537 if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
538 include_option=--etags-include; \
539 empty_fix=.; \
540 else \
541 include_option=--include; \
542 empty_fix=; \
543 fi; \
544 list='$(SUBDIRS)'; for subdir in $$list; do \
545 if test "$$subdir" = .; then :; else \
546 test ! -f $$subdir/TAGS || \
547 tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
548 fi; \
549 done; \
550 list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
551 unique=`for i in $$list; do \
552 if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
553 done | \
554 $(AWK) ' { files[$$0] = 1; } \
555 END { for (i in files) print i; }'`; \
556 if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
557 test -n "$$unique" || unique=$$empty_fix; \
558 $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
559 $$tags $$unique; \
560 fi
561ctags: CTAGS
562CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
563 $(TAGS_FILES) $(LISP)
564 tags=; \
565 here=`pwd`; \
566 list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
567 unique=`for i in $$list; do \
568 if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
569 done | \
570 $(AWK) ' { files[$$0] = 1; } \
571 END { for (i in files) print i; }'`; \
572 test -z "$(CTAGS_ARGS)$$tags$$unique" \
573 || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
574 $$tags $$unique
575
576GTAGS:
577 here=`$(am__cd) $(top_builddir) && pwd` \
578 && cd $(top_srcdir) \
579 && gtags -i $(GTAGS_ARGS) $$here
580
581distclean-tags:
582 -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
583
584distdir: $(DISTFILES)
585 @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
586 topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
587 list='$(DISTFILES)'; \
588 dist_files=`for file in $$list; do echo $$file; done | \
589 sed -e "s|^$$srcdirstrip/||;t" \
590 -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
591 case $$dist_files in \
592 */*) $(MKDIR_P) `echo "$$dist_files" | \
593 sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
594 sort -u` ;; \
595 esac; \
596 for file in $$dist_files; do \
597 if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
598 if test -d $$d/$$file; then \
599 dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
600 if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
601 cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
602 fi; \
603 cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
604 else \
605 test -f $(distdir)/$$file \
606 || cp -p $$d/$$file $(distdir)/$$file \
607 || exit 1; \
608 fi; \
609 done
610 list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
611 if test "$$subdir" = .; then :; else \
612 test -d "$(distdir)/$$subdir" \
613 || $(MKDIR_P) "$(distdir)/$$subdir" \
614 || exit 1; \
615 distdir=`$(am__cd) $(distdir) && pwd`; \
616 top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
617 (cd $$subdir && \
618 $(MAKE) $(AM_MAKEFLAGS) \
619 top_distdir="$$top_distdir" \
620 distdir="$$distdir/$$subdir" \
621 am__remove_distdir=: \
622 am__skip_length_check=: \
623 distdir) \
624 || exit 1; \
625 fi; \
626 done
627check-am: all-am
628check: check-recursive
629all-am: Makefile $(PROGRAMS)
630installdirs: installdirs-recursive
631installdirs-am:
632 for dir in "$(DESTDIR)$(gamesdir)"; do \
633 test -z "$$dir" || $(MKDIR_P) "$$dir"; \
634 done
635install: install-recursive
636install-exec: install-exec-recursive
637install-data: install-data-recursive
638uninstall: uninstall-recursive
639
640install-am: all-am
641 @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
642
643installcheck: installcheck-recursive
644install-strip:
645 $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
646 install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
647 `test -z '$(STRIP)' || \
648 echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
649mostlyclean-generic:
650
651clean-generic:
652
653distclean-generic:
654 -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
655
656maintainer-clean-generic:
657 @echo "This command is intended for maintainers to use"
658 @echo "it deletes files that may require special tools to rebuild."
659clean: clean-recursive
660
661clean-am: clean-gamesPROGRAMS clean-generic mostlyclean-am
662
663distclean: distclean-recursive
664 -rm -rf ./$(DEPDIR)
665 -rm -f Makefile
666distclean-am: clean-am distclean-compile distclean-generic \
667 distclean-tags
668
669dvi: dvi-recursive
670
671dvi-am:
672
673html: html-recursive
674
675info: info-recursive
676
677info-am:
678
679install-data-am: install-gamesPROGRAMS
680
681install-dvi: install-dvi-recursive
682
683install-exec-am:
684
685install-html: install-html-recursive
686
687install-info: install-info-recursive
688
689install-man:
690
691install-pdf: install-pdf-recursive
692
693install-ps: install-ps-recursive
694
695installcheck-am:
696
697maintainer-clean: maintainer-clean-recursive
698 -rm -rf ./$(DEPDIR)
699 -rm -f Makefile
700maintainer-clean-am: distclean-am maintainer-clean-generic
701
702mostlyclean: mostlyclean-recursive
703
704mostlyclean-am: mostlyclean-compile mostlyclean-generic
705
706pdf: pdf-recursive
707
708pdf-am:
709
710ps: ps-recursive
711
712ps-am:
713
714uninstall-am: uninstall-gamesPROGRAMS
715
716.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
717 install-strip
718
719.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
720 all all-am check check-am clean clean-gamesPROGRAMS \
721 clean-generic ctags ctags-recursive distclean \
722 distclean-compile distclean-generic distclean-tags distdir dvi \
723 dvi-am html html-am info info-am install install-am \
724 install-data install-data-am install-dvi install-dvi-am \
725 install-exec install-exec-am install-gamesPROGRAMS \
726 install-html install-html-am install-info install-info-am \
727 install-man install-pdf install-pdf-am install-ps \
728 install-ps-am install-strip installcheck installcheck-am \
729 installdirs installdirs-am maintainer-clean \
730 maintainer-clean-generic mostlyclean mostlyclean-compile \
731 mostlyclean-generic pdf pdf-am ps ps-am tags tags-recursive \
732 uninstall uninstall-am uninstall-gamesPROGRAMS
733
734# Tell versions [3.59,3.63) of GNU make to not export all variables.
735# Otherwise a system limit (for SysV at least) may be exceeded.
736.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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * the automap code
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include "doomstat.h"
40#include "st_stuff.h"
41#include "r_main.h"
42#include "p_setup.h"
43#include "p_maputl.h"
44#include "w_wad.h"
45#include "v_video.h"
46#include "p_spec.h"
47#include "am_map.h"
48#include "dstrings.h"
49#include "d_deh.h" // Ty 03/27/98 - externalizations
50#include "lprintf.h" // jff 08/03/98 - declaration of lprintf
51#include "g_game.h"
52
53//jff 1/7/98 default automap colors added
54int mapcolor_back; // map background
55int mapcolor_grid; // grid lines color
56int mapcolor_wall; // normal 1s wall color
57int mapcolor_fchg; // line at floor height change color
58int mapcolor_cchg; // line at ceiling height change color
59int mapcolor_clsd; // line at sector with floor=ceiling color
60int mapcolor_rkey; // red key color
61int mapcolor_bkey; // blue key color
62int mapcolor_ykey; // yellow key color
63int mapcolor_rdor; // red door color (diff from keys to allow option)
64int mapcolor_bdor; // blue door color (of enabling one but not other )
65int mapcolor_ydor; // yellow door color
66int mapcolor_tele; // teleporter line color
67int mapcolor_secr; // secret sector boundary color
68int mapcolor_exit; // jff 4/23/98 add exit line color
69int mapcolor_unsn; // computer map unseen line color
70int mapcolor_flat; // line with no floor/ceiling changes
71int mapcolor_sprt; // general sprite color
72int mapcolor_item; // item sprite color
73int mapcolor_frnd; // friendly sprite color
74int mapcolor_enemy; // enemy sprite color
75int mapcolor_hair; // crosshair color
76int mapcolor_sngl; // single player arrow color
77int mapcolor_plyr[4] = { 112, 88, 64, 32 }; // colors for player arrows in multiplayer
78
79//jff 3/9/98 add option to not show secret sectors until entered
80int map_secret_after;
81//jff 4/3/98 add symbols for "no-color" for disable and "black color" for black
82#define NC 0
83#define BC 247
84
85// drawing stuff
86#define FB 0
87
88// scale on entry
89#define INITSCALEMTOF (.2*FRACUNIT)
90// how much the automap moves window per tic in frame-buffer coordinates
91// moves 140 pixels in 1 second
92#define F_PANINC 4
93// how much zoom-in per tic
94// goes to 2x in 1 second
95#define M_ZOOMIN ((int) (1.02*FRACUNIT))
96// how much zoom-out per tic
97// pulls out to 0.5x in 1 second
98#define M_ZOOMOUT ((int) (FRACUNIT/1.02))
99
100#define PLAYERRADIUS (16*(1<<MAPBITS)) // e6y
101
102// translates between frame-buffer and map distances
103#define FTOM(x) FixedMul(((x)<<16),scale_ftom)
104#define MTOF(x) (FixedMul((x),scale_mtof)>>16)
105// translates between frame-buffer and map coordinates
106#define CXMTOF(x) (f_x + MTOF((x)-m_x))
107#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
108
109typedef struct
110{
111 mpoint_t a, b;
112} mline_t;
113
114//
115// The vector graphics for the automap.
116// A line drawing of the player pointing right,
117// starting from the middle.
118//
119#define R ((8*PLAYERRADIUS)/7)
120mline_t player_arrow[] =
121{
122 { { -R+R/8, 0 }, { R, 0 } }, // -----
123 { { R, 0 }, { R-R/2, R/4 } }, // ----->
124 { { R, 0 }, { R-R/2, -R/4 } },
125 { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
126 { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
127 { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
128 { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
129};
130#undef R
131#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
132
133#define R ((8*PLAYERRADIUS)/7)
134mline_t cheat_player_arrow[] =
135{ // killough 3/22/98: He's alive, Jim :)
136 { { -R+R/8, 0 }, { R, 0 } }, // -----
137 { { R, 0 }, { R-R/2, R/4 } }, // ----->
138 { { R, 0 }, { R-R/2, -R/4 } },
139 { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
140 { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
141 { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
142 { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } },
143 { { -R/10-R/6, R/4}, {-R/10-R/6, -R/4} }, // J
144 { { -R/10-R/6, -R/4}, {-R/10-R/6-R/8, -R/4} },
145 { { -R/10-R/6-R/8, -R/4}, {-R/10-R/6-R/8, -R/8} },
146 { { -R/10, R/4}, {-R/10, -R/4}}, // F
147 { { -R/10, R/4}, {-R/10+R/8, R/4}},
148 { { -R/10+R/4, R/4}, {-R/10+R/4, -R/4}}, // F
149 { { -R/10+R/4, R/4}, {-R/10+R/4+R/8, R/4}},
150};
151#undef R
152#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
153
154#define R (FRACUNIT)
155mline_t triangle_guy[] =
156{
157{ { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)( .867*R), (fixed_t)(-.5*R) } },
158{ { (fixed_t)( .867*R), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)( R) } },
159{ { (fixed_t)(0 ), (fixed_t)( R) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } }
160};
161#undef R
162#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
163
164//jff 1/5/98 new symbol for keys on automap
165#define R (FRACUNIT)
166mline_t cross_mark[] =
167{
168 { { -R, 0 }, { R, 0} },
169 { { 0, -R }, { 0, R } },
170};
171#undef R
172#define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t))
173//jff 1/5/98 end of new symbol
174
175#define R (FRACUNIT)
176mline_t thintriangle_guy[] =
177{
178{ { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)( R), (fixed_t)( 0) } },
179{ { (fixed_t)( R), (fixed_t)( 0) }, { (fixed_t)(-.5*R), (fixed_t)( .7*R) } },
180{ { (fixed_t)(-.5*R), (fixed_t)( .7*R) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } }
181};
182#undef R
183#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
184
185int ddt_cheating = 0; // killough 2/7/98: make global, rename to ddt_*
186
187static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
188
189enum automapmode_e automapmode; // Mode that the automap is in
190
191// location of window on screen
192static int f_x;
193static int f_y;
194
195// size of window on screen
196static int f_w;
197static int f_h;
198
199static mpoint_t m_paninc; // how far the window pans each tic (map coords)
200static fixed_t mtof_zoommul; // how far the window zooms each tic (map coords)
201static fixed_t ftom_zoommul; // how far the window zooms each tic (fb coords)
202
203static fixed_t m_x, m_y; // LL x,y window location on the map (map coords)
204static fixed_t m_x2, m_y2; // UR x,y window location on the map (map coords)
205
206//
207// width/height of window on map (map coords)
208//
209static fixed_t m_w;
210static fixed_t m_h;
211
212// based on level size
213static fixed_t min_x;
214static fixed_t min_y;
215static fixed_t max_x;
216static fixed_t max_y;
217
218static fixed_t max_w; // max_x-min_x,
219static fixed_t max_h; // max_y-min_y
220
221// based on player size
222static fixed_t min_w;
223static fixed_t min_h;
224
225
226static fixed_t min_scale_mtof; // used to tell when to stop zooming out
227static fixed_t max_scale_mtof; // used to tell when to stop zooming in
228
229// old stuff for recovery later
230static fixed_t old_m_w, old_m_h;
231static fixed_t old_m_x, old_m_y;
232
233// old location used by the Follower routine
234static mpoint_t f_oldloc;
235
236// used by MTOF to scale from map-to-frame-buffer coords
237static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF;
238// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
239static fixed_t scale_ftom;
240
241static player_t *plr; // the player represented by an arrow
242
243// killough 2/22/98: Remove limit on automap marks,
244// and make variables external for use in savegames.
245
246mpoint_t *markpoints = NULL; // where the points are
247int markpointnum = 0; // next point to be assigned (also number of points now)
248int markpointnum_max = 0; // killough 2/22/98
249
250static boolean stopped = true;
251
252//
253// AM_activateNewScale()
254//
255// Changes the map scale after zooming or translating
256//
257// Passed nothing, returns nothing
258//
259static void AM_activateNewScale(void)
260{
261 m_x += m_w/2;
262 m_y += m_h/2;
263 m_w = FTOM(f_w);
264 m_h = FTOM(f_h);
265 m_x -= m_w/2;
266 m_y -= m_h/2;
267 m_x2 = m_x + m_w;
268 m_y2 = m_y + m_h;
269}
270
271//
272// AM_saveScaleAndLoc()
273//
274// Saves the current center and zoom
275// Affects the variables that remember old scale and loc
276//
277// Passed nothing, returns nothing
278//
279static void AM_saveScaleAndLoc(void)
280{
281 old_m_x = m_x;
282 old_m_y = m_y;
283 old_m_w = m_w;
284 old_m_h = m_h;
285}
286
287//
288// AM_restoreScaleAndLoc()
289//
290// restores the center and zoom from locally saved values
291// Affects global variables for location and scale
292//
293// Passed nothing, returns nothing
294//
295static void AM_restoreScaleAndLoc(void)
296{
297 m_w = old_m_w;
298 m_h = old_m_h;
299 if (!(automapmode & am_follow))
300 {
301 m_x = old_m_x;
302 m_y = old_m_y;
303 }
304 else
305 {
306 m_x = (plr->mo->x >> FRACTOMAPBITS) - m_w/2;//e6y
307 m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2;//e6y
308 }
309 m_x2 = m_x + m_w;
310 m_y2 = m_y + m_h;
311
312 // Change the scaling multipliers
313 scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
314 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
315}
316
317//
318// AM_addMark()
319//
320// Adds a marker at the current location
321// Affects global variables for marked points
322//
323// Passed nothing, returns nothing
324//
325static void AM_addMark(void)
326{
327 // killough 2/22/98:
328 // remove limit on automap marks
329
330 if (markpointnum >= markpointnum_max)
331 markpoints = realloc(markpoints,
332 (markpointnum_max = markpointnum_max ?
333 markpointnum_max*2 : 16) * sizeof(*markpoints));
334
335 markpoints[markpointnum].x = m_x + m_w/2;
336 markpoints[markpointnum].y = m_y + m_h/2;
337 markpointnum++;
338}
339
340//
341// AM_findMinMaxBoundaries()
342//
343// Determines bounding box of all vertices,
344// sets global variables controlling zoom range.
345//
346// Passed nothing, returns nothing
347//
348static void AM_findMinMaxBoundaries(void)
349{
350 int i;
351 fixed_t a;
352 fixed_t b;
353
354 min_x = min_y = INT_MAX;
355 max_x = max_y = -INT_MAX;
356
357 for (i=0;i<numvertexes;i++)
358 {
359 if (vertexes[i].x < min_x)
360 min_x = vertexes[i].x;
361 else if (vertexes[i].x > max_x)
362 max_x = vertexes[i].x;
363
364 if (vertexes[i].y < min_y)
365 min_y = vertexes[i].y;
366 else if (vertexes[i].y > max_y)
367 max_y = vertexes[i].y;
368 }
369
370 max_w = (max_x >>= FRACTOMAPBITS) - (min_x >>= FRACTOMAPBITS);//e6y
371 max_h = (max_y >>= FRACTOMAPBITS) - (min_y >>= FRACTOMAPBITS);//e6y
372
373 min_w = 2*PLAYERRADIUS; // const? never changed?
374 min_h = 2*PLAYERRADIUS;
375
376 a = FixedDiv(f_w<<FRACBITS, max_w);
377 b = FixedDiv(f_h<<FRACBITS, max_h);
378
379 min_scale_mtof = a < b ? a : b;
380 max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
381}
382
383//
384// AM_changeWindowLoc()
385//
386// Moves the map window by the global variables m_paninc.x, m_paninc.y
387//
388// Passed nothing, returns nothing
389//
390static void AM_changeWindowLoc(void)
391{
392 if (m_paninc.x || m_paninc.y)
393 {
394 automapmode &= ~am_follow;
395 f_oldloc.x = INT_MAX;
396 }
397
398 m_x += m_paninc.x;
399 m_y += m_paninc.y;
400
401 if (m_x + m_w/2 > max_x)
402 m_x = max_x - m_w/2;
403 else if (m_x + m_w/2 < min_x)
404 m_x = min_x - m_w/2;
405
406 if (m_y + m_h/2 > max_y)
407 m_y = max_y - m_h/2;
408 else if (m_y + m_h/2 < min_y)
409 m_y = min_y - m_h/2;
410
411 m_x2 = m_x + m_w;
412 m_y2 = m_y + m_h;
413}
414
415
416//
417// AM_initVariables()
418//
419// Initialize the variables for the automap
420//
421// Affects the automap global variables
422// Status bar is notified that the automap has been entered
423// Passed nothing, returns nothing
424//
425static void AM_initVariables(void)
426{
427 int pnum;
428 static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 };
429
430 automapmode |= am_active;
431
432 f_oldloc.x = INT_MAX;
433
434 m_paninc.x = m_paninc.y = 0;
435 ftom_zoommul = FRACUNIT;
436 mtof_zoommul = FRACUNIT;
437
438 m_w = FTOM(f_w);
439 m_h = FTOM(f_h);
440
441 // find player to center on initially
442 if (!playeringame[pnum = consoleplayer])
443 for (pnum=0;pnum<MAXPLAYERS;pnum++)
444 if (playeringame[pnum])
445 break;
446
447 plr = &players[pnum];
448 m_x = (plr->mo->x >> FRACTOMAPBITS) - m_w/2;//e6y
449 m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2;//e6y
450 AM_changeWindowLoc();
451
452 // for saving & restoring
453 old_m_x = m_x;
454 old_m_y = m_y;
455 old_m_w = m_w;
456 old_m_h = m_h;
457
458 // inform the status bar of the change
459 ST_Responder(&st_notify);
460}
461
462//
463// AM_loadPics()
464//
465static void AM_loadPics(void)
466{
467 // cph - mark numbers no longer needed cached
468}
469
470//
471// AM_unloadPics()
472//
473static void AM_unloadPics(void)
474{
475 // cph - mark numbers no longer needed cached
476}
477
478//
479// AM_clearMarks()
480//
481// Sets the number of marks to 0, thereby clearing them from the display
482//
483// Affects the global variable markpointnum
484// Passed nothing, returns nothing
485//
486void AM_clearMarks(void)
487{
488 markpointnum = 0;
489}
490
491//
492// AM_LevelInit()
493//
494// Initialize the automap at the start of a new level
495// should be called at the start of every level
496//
497// Passed nothing, returns nothing
498// Affects automap's global variables
499//
500// CPhipps - get status bar height from status bar code
501static void AM_LevelInit(void)
502{
503 leveljuststarted = 0;
504
505 f_x = f_y = 0;
506 f_w = SCREENWIDTH; // killough 2/7/98: get rid of finit_ vars
507 f_h = SCREENHEIGHT-ST_SCALED_HEIGHT;// to allow runtime setting of width/height
508
509 AM_findMinMaxBoundaries();
510 scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
511 if (scale_mtof > max_scale_mtof)
512 scale_mtof = min_scale_mtof;
513 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
514}
515
516//
517// AM_Stop()
518//
519// Cease automap operations, unload patches, notify status bar
520//
521// Passed nothing, returns nothing
522//
523void AM_Stop (void)
524{
525 static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 };
526
527 AM_unloadPics();
528 automapmode &= ~am_active;
529 ST_Responder(&st_notify);
530 stopped = true;
531}
532
533//
534// AM_Start()
535//
536// Start up automap operations,
537// if a new level, or game start, (re)initialize level variables
538// init map variables
539// load mark patches
540//
541// Passed nothing, returns nothing
542//
543void AM_Start(void)
544{
545 static int lastlevel = -1, lastepisode = -1;
546
547 if (!stopped)
548 AM_Stop();
549 stopped = false;
550 if (lastlevel != gamemap || lastepisode != gameepisode)
551 {
552 AM_LevelInit();
553 lastlevel = gamemap;
554 lastepisode = gameepisode;
555 }
556 AM_initVariables();
557 AM_loadPics();
558}
559
560//
561// AM_minOutWindowScale()
562//
563// Set the window scale to the maximum size
564//
565// Passed nothing, returns nothing
566//
567static void AM_minOutWindowScale(void)
568{
569 scale_mtof = min_scale_mtof;
570 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
571 AM_activateNewScale();
572}
573
574//
575// AM_maxOutWindowScale(void)
576//
577// Set the window scale to the minimum size
578//
579// Passed nothing, returns nothing
580//
581static void AM_maxOutWindowScale(void)
582{
583 scale_mtof = max_scale_mtof;
584 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
585 AM_activateNewScale();
586}
587
588//
589// AM_Responder()
590//
591// Handle events (user inputs) in automap mode
592//
593// Passed an input event, returns true if its handled
594//
595boolean AM_Responder
596( event_t* ev )
597{
598 int rc;
599 static int cheatstate=0;
600 static int bigstate=0;
601 int ch; // phares
602
603 rc = false;
604
605 if (!(automapmode & am_active))
606 {
607 if (ev->type == ev_keydown && ev->data1 == key_map) // phares
608 {
609 AM_Start ();
610 rc = true;
611 }
612 }
613 else if (ev->type == ev_keydown)
614 {
615 rc = true;
616 ch = ev->data1; // phares
617 if (ch == key_map_right) // |
618 if (!(automapmode & am_follow)) // V
619 m_paninc.x = FTOM(F_PANINC);
620 else
621 rc = false;
622 else if (ch == key_map_left)
623 if (!(automapmode & am_follow))
624 m_paninc.x = -FTOM(F_PANINC);
625 else
626 rc = false;
627 else if (ch == key_map_up)
628 if (!(automapmode & am_follow))
629 m_paninc.y = FTOM(F_PANINC);
630 else
631 rc = false;
632 else if (ch == key_map_down)
633 if (!(automapmode & am_follow))
634 m_paninc.y = -FTOM(F_PANINC);
635 else
636 rc = false;
637 else if (ch == key_map_zoomout)
638 {
639 mtof_zoommul = M_ZOOMOUT;
640 ftom_zoommul = M_ZOOMIN;
641 }
642 else if (ch == key_map_zoomin)
643 {
644 mtof_zoommul = M_ZOOMIN;
645 ftom_zoommul = M_ZOOMOUT;
646 }
647 else if (ch == key_map)
648 {
649 bigstate = 0;
650 AM_Stop ();
651 }
652 else if (ch == key_map_gobig)
653 {
654 bigstate = !bigstate;
655 if (bigstate)
656 {
657 AM_saveScaleAndLoc();
658 AM_minOutWindowScale();
659 }
660 else
661 AM_restoreScaleAndLoc();
662 }
663 else if (ch == key_map_follow)
664 {
665 automapmode ^= am_follow; // CPhipps - put all automap mode stuff into one enum
666 f_oldloc.x = INT_MAX;
667 // Ty 03/27/98 - externalized
668 plr->message = (automapmode & am_follow) ? s_AMSTR_FOLLOWON : s_AMSTR_FOLLOWOFF;
669 }
670 else if (ch == key_map_grid)
671 {
672 automapmode ^= am_grid; // CPhipps
673 // Ty 03/27/98 - *not* externalized
674 plr->message = (automapmode & am_grid) ? s_AMSTR_GRIDON : s_AMSTR_GRIDOFF;
675 }
676 else if (ch == key_map_mark)
677 {
678 /* Ty 03/27/98 - *not* externalized
679 * cph 2001/11/20 - use doom_printf so we don't have our own buffer */
680 doom_printf("%s %d", s_AMSTR_MARKEDSPOT, markpointnum);
681 AM_addMark();
682 }
683 else if (ch == key_map_clear)
684 {
685 AM_clearMarks(); // Ty 03/27/98 - *not* externalized
686 plr->message = s_AMSTR_MARKSCLEARED; // ^
687 } // |
688 else if (ch == key_map_rotate) {
689 automapmode ^= am_rotate;
690 plr->message = (automapmode & am_rotate) ? s_AMSTR_ROTATEON : s_AMSTR_ROTATEOFF;
691 }
692 else if (ch == key_map_overlay) {
693 automapmode ^= am_overlay;
694 plr->message = (automapmode & am_overlay) ? s_AMSTR_OVERLAYON : s_AMSTR_OVERLAYOFF;
695 }
696 else // phares
697 {
698 cheatstate=0;
699 rc = false;
700 }
701 }
702 else if (ev->type == ev_keyup)
703 {
704 rc = false;
705 ch = ev->data1;
706 if (ch == key_map_right)
707 {
708 if (!(automapmode & am_follow))
709 m_paninc.x = 0;
710 }
711 else if (ch == key_map_left)
712 {
713 if (!(automapmode & am_follow))
714 m_paninc.x = 0;
715 }
716 else if (ch == key_map_up)
717 {
718 if (!(automapmode & am_follow))
719 m_paninc.y = 0;
720 }
721 else if (ch == key_map_down)
722 {
723 if (!(automapmode & am_follow))
724 m_paninc.y = 0;
725 }
726 else if ((ch == key_map_zoomout) || (ch == key_map_zoomin))
727 {
728 mtof_zoommul = FRACUNIT;
729 ftom_zoommul = FRACUNIT;
730 }
731 }
732 return rc;
733}
734
735//
736// AM_rotate()
737//
738// Rotation in 2D.
739// Used to rotate player arrow line character.
740//
741// Passed the coordinates of a point, and an angle
742// Returns the coordinates rotated by the angle
743//
744// CPhipps - made static & enhanced for automap rotation
745
746static void AM_rotate(fixed_t* x, fixed_t* y, angle_t a, fixed_t xorig, fixed_t yorig)
747{
748 fixed_t tmpx;
749
750 //e6y
751 xorig>>=FRACTOMAPBITS;
752 yorig>>=FRACTOMAPBITS;
753
754 tmpx =
755 FixedMul(*x - xorig,finecosine[a>>ANGLETOFINESHIFT])
756 - FixedMul(*y - yorig,finesine[a>>ANGLETOFINESHIFT]);
757
758 *y = yorig +
759 FixedMul(*x - xorig,finesine[a>>ANGLETOFINESHIFT])
760 + FixedMul(*y - yorig,finecosine[a>>ANGLETOFINESHIFT]);
761
762 *x = tmpx + xorig;
763}
764
765//
766// AM_changeWindowScale()
767//
768// Automap zooming
769//
770// Passed nothing, returns nothing
771//
772static void AM_changeWindowScale(void)
773{
774 // Change the scaling multipliers
775 scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
776 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
777
778 if (scale_mtof < min_scale_mtof)
779 AM_minOutWindowScale();
780 else if (scale_mtof > max_scale_mtof)
781 AM_maxOutWindowScale();
782 else
783 AM_activateNewScale();
784}
785
786//
787// AM_doFollowPlayer()
788//
789// Turn on follow mode - the map scrolls opposite to player motion
790//
791// Passed nothing, returns nothing
792//
793static void AM_doFollowPlayer(void)
794{
795 if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
796 {
797 m_x = FTOM(MTOF(plr->mo->x >> FRACTOMAPBITS)) - m_w/2;//e6y
798 m_y = FTOM(MTOF(plr->mo->y >> FRACTOMAPBITS)) - m_h/2;//e6y
799 m_x2 = m_x + m_w;
800 m_y2 = m_y + m_h;
801 f_oldloc.x = plr->mo->x;
802 f_oldloc.y = plr->mo->y;
803 }
804}
805
806//
807// AM_Ticker()
808//
809// Updates on gametic - enter follow mode, zoom, or change map location
810//
811// Passed nothing, returns nothing
812//
813void AM_Ticker (void)
814{
815 if (!(automapmode & am_active))
816 return;
817
818 if (automapmode & am_follow)
819 AM_doFollowPlayer();
820
821 // Change the zoom if necessary
822 if (ftom_zoommul != FRACUNIT)
823 AM_changeWindowScale();
824
825 // Change x,y location
826 if (m_paninc.x || m_paninc.y)
827 AM_changeWindowLoc();
828}
829
830//
831// AM_clipMline()
832//
833// Automap clipping of lines.
834//
835// Based on Cohen-Sutherland clipping algorithm but with a slightly
836// faster reject and precalculated slopes. If the speed is needed,
837// use a hash algorithm to handle the common cases.
838//
839// Passed the line's coordinates on map and in the frame buffer performs
840// clipping on them in the lines frame coordinates.
841// Returns true if any part of line was not clipped
842//
843static boolean AM_clipMline
844( mline_t* ml,
845 fline_t* fl )
846{
847 enum
848 {
849 LEFT =1,
850 RIGHT =2,
851 BOTTOM =4,
852 TOP =8
853 };
854
855 register int outcode1 = 0;
856 register int outcode2 = 0;
857 register int outside;
858
859 fpoint_t tmp;
860 int dx;
861 int dy;
862
863
864#define DOOUTCODE(oc, mx, my) \
865 (oc) = 0; \
866 if ((my) < 0) (oc) |= TOP; \
867 else if ((my) >= f_h) (oc) |= BOTTOM; \
868 if ((mx) < 0) (oc) |= LEFT; \
869 else if ((mx) >= f_w) (oc) |= RIGHT;
870
871
872 // do trivial rejects and outcodes
873 if (ml->a.y > m_y2)
874 outcode1 = TOP;
875 else if (ml->a.y < m_y)
876 outcode1 = BOTTOM;
877
878 if (ml->b.y > m_y2)
879 outcode2 = TOP;
880 else if (ml->b.y < m_y)
881 outcode2 = BOTTOM;
882
883 if (outcode1 & outcode2)
884 return false; // trivially outside
885
886 if (ml->a.x < m_x)
887 outcode1 |= LEFT;
888 else if (ml->a.x > m_x2)
889 outcode1 |= RIGHT;
890
891 if (ml->b.x < m_x)
892 outcode2 |= LEFT;
893 else if (ml->b.x > m_x2)
894 outcode2 |= RIGHT;
895
896 if (outcode1 & outcode2)
897 return false; // trivially outside
898
899 // transform to frame-buffer coordinates.
900 fl->a.x = CXMTOF(ml->a.x);
901 fl->a.y = CYMTOF(ml->a.y);
902 fl->b.x = CXMTOF(ml->b.x);
903 fl->b.y = CYMTOF(ml->b.y);
904
905 DOOUTCODE(outcode1, fl->a.x, fl->a.y);
906 DOOUTCODE(outcode2, fl->b.x, fl->b.y);
907
908 if (outcode1 & outcode2)
909 return false;
910
911 while (outcode1 | outcode2)
912 {
913 // may be partially inside box
914 // find an outside point
915 if (outcode1)
916 outside = outcode1;
917 else
918 outside = outcode2;
919
920 // clip to each side
921 if (outside & TOP)
922 {
923 dy = fl->a.y - fl->b.y;
924 dx = fl->b.x - fl->a.x;
925 tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
926 tmp.y = 0;
927 }
928 else if (outside & BOTTOM)
929 {
930 dy = fl->a.y - fl->b.y;
931 dx = fl->b.x - fl->a.x;
932 tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
933 tmp.y = f_h-1;
934 }
935 else if (outside & RIGHT)
936 {
937 dy = fl->b.y - fl->a.y;
938 dx = fl->b.x - fl->a.x;
939 tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
940 tmp.x = f_w-1;
941 }
942 else if (outside & LEFT)
943 {
944 dy = fl->b.y - fl->a.y;
945 dx = fl->b.x - fl->a.x;
946 tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
947 tmp.x = 0;
948 }
949
950 if (outside == outcode1)
951 {
952 fl->a = tmp;
953 DOOUTCODE(outcode1, fl->a.x, fl->a.y);
954 }
955 else
956 {
957 fl->b = tmp;
958 DOOUTCODE(outcode2, fl->b.x, fl->b.y);
959 }
960
961 if (outcode1 & outcode2)
962 return false; // trivially outside
963 }
964
965 return true;
966}
967#undef DOOUTCODE
968
969//
970// AM_drawMline()
971//
972// Clip lines, draw visible parts of lines.
973//
974// Passed the map coordinates of the line, and the color to draw it
975// Color -1 is special and prevents drawing. Color 247 is special and
976// is translated to black, allowing Color 0 to represent feature disable
977// in the defaults file.
978// Returns nothing.
979//
980static void AM_drawMline
981( mline_t* ml,
982 int color )
983{
984 static fline_t fl;
985
986 if (color==-1) // jff 4/3/98 allow not drawing any sort of line
987 return; // by setting its color to -1
988 if (color==247) // jff 4/3/98 if color is 247 (xparent), use black
989 color=0;
990
991 if (AM_clipMline(ml, &fl))
992 V_DrawLine(&fl, color); // draws it on frame buffer using fb coords
993}
994
995//
996// AM_drawGrid()
997//
998// Draws blockmap aligned grid lines.
999//
1000// Passed the color to draw the grid lines
1001// Returns nothing
1002//
1003static void AM_drawGrid(int color)
1004{
1005 fixed_t x, y;
1006 fixed_t start, end;
1007 mline_t ml;
1008
1009 // Figure out start of vertical gridlines
1010 start = m_x;
1011 if ((start-bmaporgx)%(MAPBLOCKUNITS<<MAPBITS))//e6y
1012 start += (MAPBLOCKUNITS<<MAPBITS)//e6y
1013 - ((start-bmaporgx)%(MAPBLOCKUNITS<<MAPBITS));//e6y
1014 end = m_x + m_w;
1015
1016 // draw vertical gridlines
1017 ml.a.y = m_y;
1018 ml.b.y = m_y+m_h;
1019 for (x=start; x<end; x+=(MAPBLOCKUNITS<<MAPBITS))//e6y
1020 {
1021 ml.a.x = x;
1022 ml.b.x = x;
1023 AM_drawMline(&ml, color);
1024 }
1025
1026 // Figure out start of horizontal gridlines
1027 start = m_y;
1028 if ((start-bmaporgy)%(MAPBLOCKUNITS<<MAPBITS))//e6y
1029 start += (MAPBLOCKUNITS<<MAPBITS)//e6y
1030 - ((start-bmaporgy)%(MAPBLOCKUNITS<<MAPBITS));//e6y
1031 end = m_y + m_h;
1032
1033 // draw horizontal gridlines
1034 ml.a.x = m_x;
1035 ml.b.x = m_x + m_w;
1036 for (y=start; y<end; y+=(MAPBLOCKUNITS<<MAPBITS))//e6y
1037 {
1038 ml.a.y = y;
1039 ml.b.y = y;
1040 AM_drawMline(&ml, color);
1041 }
1042}
1043
1044//
1045// AM_DoorColor()
1046//
1047// Returns the 'color' or key needed for a door linedef type
1048//
1049// Passed the type of linedef, returns:
1050// -1 if not a keyed door
1051// 0 if a red key required
1052// 1 if a blue key required
1053// 2 if a yellow key required
1054// 3 if a multiple keys required
1055//
1056// jff 4/3/98 add routine to get color of generalized keyed door
1057//
1058static int AM_DoorColor(int type)
1059{
1060 if (GenLockedBase <= type && type< GenDoorBase)
1061 {
1062 type -= GenLockedBase;
1063 type = (type & LockedKey) >> LockedKeyShift;
1064 if (!type || type==7)
1065 return 3; //any or all keys
1066 else return (type-1)%3;
1067 }
1068 switch (type) // closed keyed door
1069 {
1070 case 26: case 32: case 99: case 133:
1071 /*bluekey*/
1072 return 1;
1073 case 27: case 34: case 136: case 137:
1074 /*yellowkey*/
1075 return 2;
1076 case 28: case 33: case 134: case 135:
1077 /*redkey*/
1078 return 0;
1079 default:
1080 return -1; //not a keyed door
1081 }
1082}
1083
1084//
1085// Determines visible lines, draws them.
1086// This is LineDef based, not LineSeg based.
1087//
1088// jff 1/5/98 many changes in this routine
1089// backward compatibility not needed, so just changes, no ifs
1090// addition of clauses for:
1091// doors opening, keyed door id, secret sectors,
1092// teleports, exit lines, key things
1093// ability to suppress any of added features or lines with no height changes
1094//
1095// support for gamma correction in automap abandoned
1096//
1097// jff 4/3/98 changed mapcolor_xxxx=0 as control to disable feature
1098// jff 4/3/98 changed mapcolor_xxxx=-1 to disable drawing line completely
1099//
1100static void AM_drawWalls(void)
1101{
1102 int i;
1103 static mline_t l;
1104
1105 // draw the unclipped visible portions of all lines
1106 for (i=0;i<numlines;i++)
1107 {
1108 l.a.x = lines[i].v1->x >> FRACTOMAPBITS;//e6y
1109 l.a.y = lines[i].v1->y >> FRACTOMAPBITS;//e6y
1110 l.b.x = lines[i].v2->x >> FRACTOMAPBITS;//e6y
1111 l.b.y = lines[i].v2->y >> FRACTOMAPBITS;//e6y
1112
1113 if (automapmode & am_rotate) {
1114 AM_rotate(&l.a.x, &l.a.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y);
1115 AM_rotate(&l.b.x, &l.b.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y);
1116 }
1117
1118 // if line has been seen or IDDT has been used
1119 if (ddt_cheating || (lines[i].flags & ML_MAPPED))
1120 {
1121 if ((lines[i].flags & ML_DONTDRAW) && !ddt_cheating)
1122 continue;
1123 {
1124 /* cph - show keyed doors and lines */
1125 int amd;
1126 if ((mapcolor_bdor || mapcolor_ydor || mapcolor_rdor) &&
1127 !(lines[i].flags & ML_SECRET) && /* non-secret */
1128 (amd = AM_DoorColor(lines[i].special)) != -1
1129 )
1130 {
1131 {
1132 switch (amd) /* closed keyed door */
1133 {
1134 case 1:
1135 /*bluekey*/
1136 AM_drawMline(&l,
1137 mapcolor_bdor? mapcolor_bdor : mapcolor_cchg);
1138 continue;
1139 case 2:
1140 /*yellowkey*/
1141 AM_drawMline(&l,
1142 mapcolor_ydor? mapcolor_ydor : mapcolor_cchg);
1143 continue;
1144 case 0:
1145 /*redkey*/
1146 AM_drawMline(&l,
1147 mapcolor_rdor? mapcolor_rdor : mapcolor_cchg);
1148 continue;
1149 case 3:
1150 /*any or all*/
1151 AM_drawMline(&l,
1152 mapcolor_clsd? mapcolor_clsd : mapcolor_cchg);
1153 continue;
1154 }
1155 }
1156 }
1157 }
1158 if /* jff 4/23/98 add exit lines to automap */
1159 (
1160 mapcolor_exit &&
1161 (
1162 lines[i].special==11 ||
1163 lines[i].special==52 ||
1164 lines[i].special==197 ||
1165 lines[i].special==51 ||
1166 lines[i].special==124 ||
1167 lines[i].special==198
1168 )
1169 ) {
1170 AM_drawMline(&l, mapcolor_exit); /* exit line */
1171 continue;
1172 }
1173
1174 if (!lines[i].backsector)
1175 {
1176 // jff 1/10/98 add new color for 1S secret sector boundary
1177 if (mapcolor_secr && //jff 4/3/98 0 is disable
1178 (
1179 (
1180 map_secret_after &&
1181 P_WasSecret(lines[i].frontsector) &&
1182 !P_IsSecret(lines[i].frontsector)
1183 )
1184 ||
1185 (
1186 !map_secret_after &&
1187 P_WasSecret(lines[i].frontsector)
1188 )
1189 )
1190 )
1191 AM_drawMline(&l, mapcolor_secr); // line bounding secret sector
1192 else //jff 2/16/98 fixed bug
1193 AM_drawMline(&l, mapcolor_wall); // special was cleared
1194 }
1195 else /* now for 2S lines */
1196 {
1197 // jff 1/10/98 add color change for all teleporter types
1198 if
1199 (
1200 mapcolor_tele && !(lines[i].flags & ML_SECRET) &&
1201 (lines[i].special == 39 || lines[i].special == 97 ||
1202 lines[i].special == 125 || lines[i].special == 126)
1203 )
1204 { // teleporters
1205 AM_drawMline(&l, mapcolor_tele);
1206 }
1207 else if (lines[i].flags & ML_SECRET) // secret door
1208 {
1209 AM_drawMline(&l, mapcolor_wall); // wall color
1210 }
1211 else if
1212 (
1213 mapcolor_clsd &&
1214 !(lines[i].flags & ML_SECRET) && // non-secret closed door
1215 ((lines[i].backsector->floorheight==lines[i].backsector->ceilingheight) ||
1216 (lines[i].frontsector->floorheight==lines[i].frontsector->ceilingheight))
1217 )
1218 {
1219 AM_drawMline(&l, mapcolor_clsd); // non-secret closed door
1220 } //jff 1/6/98 show secret sector 2S lines
1221 else if
1222 (
1223 mapcolor_secr && //jff 2/16/98 fixed bug
1224 ( // special was cleared after getting it
1225 (map_secret_after &&
1226 (
1227 (P_WasSecret(lines[i].frontsector)
1228 && !P_IsSecret(lines[i].frontsector)) ||
1229 (P_WasSecret(lines[i].backsector)
1230 && !P_IsSecret(lines[i].backsector))
1231 )
1232 )
1233 || //jff 3/9/98 add logic to not show secret til after entered
1234 ( // if map_secret_after is true
1235 !map_secret_after &&
1236 (P_WasSecret(lines[i].frontsector) ||
1237 P_WasSecret(lines[i].backsector))
1238 )
1239 )
1240 )
1241 {
1242 AM_drawMline(&l, mapcolor_secr); // line bounding secret sector
1243 } //jff 1/6/98 end secret sector line change
1244 else if (lines[i].backsector->floorheight !=
1245 lines[i].frontsector->floorheight)
1246 {
1247 AM_drawMline(&l, mapcolor_fchg); // floor level change
1248 }
1249 else if (lines[i].backsector->ceilingheight !=
1250 lines[i].frontsector->ceilingheight)
1251 {
1252 AM_drawMline(&l, mapcolor_cchg); // ceiling level change
1253 }
1254 else if (mapcolor_flat && ddt_cheating)
1255 {
1256 AM_drawMline(&l, mapcolor_flat); //2S lines that appear only in IDDT
1257 }
1258 }
1259 } // now draw the lines only visible because the player has computermap
1260 else if (plr->powers[pw_allmap]) // computermap visible lines
1261 {
1262 if (!(lines[i].flags & ML_DONTDRAW)) // invisible flag lines do not show
1263 {
1264 if
1265 (
1266 mapcolor_flat
1267 ||
1268 !lines[i].backsector
1269 ||
1270 lines[i].backsector->floorheight
1271 != lines[i].frontsector->floorheight
1272 ||
1273 lines[i].backsector->ceilingheight
1274 != lines[i].frontsector->ceilingheight
1275 )
1276 AM_drawMline(&l, mapcolor_unsn);
1277 }
1278 }
1279 }
1280}
1281
1282//
1283// AM_drawLineCharacter()
1284//
1285// Draws a vector graphic according to numerous parameters
1286//
1287// Passed the structure defining the vector graphic shape, the number
1288// of vectors in it, the scale to draw it at, the angle to draw it at,
1289// the color to draw it with, and the map coordinates to draw it at.
1290// Returns nothing
1291//
1292static void AM_drawLineCharacter
1293( mline_t* lineguy,
1294 int lineguylines,
1295 fixed_t scale,
1296 angle_t angle,
1297 int color,
1298 fixed_t x,
1299 fixed_t y )
1300{
1301 int i;
1302 mline_t l;
1303
1304 if (automapmode & am_rotate) angle -= plr->mo->angle - ANG90; // cph
1305
1306 for (i=0;i<lineguylines;i++)
1307 {
1308 l.a.x = lineguy[i].a.x;
1309 l.a.y = lineguy[i].a.y;
1310
1311 if (scale)
1312 {
1313 l.a.x = FixedMul(scale, l.a.x);
1314 l.a.y = FixedMul(scale, l.a.y);
1315 }
1316
1317 if (angle)
1318 AM_rotate(&l.a.x, &l.a.y, angle, 0, 0);
1319
1320 l.a.x += x;
1321 l.a.y += y;
1322
1323 l.b.x = lineguy[i].b.x;
1324 l.b.y = lineguy[i].b.y;
1325
1326 if (scale)
1327 {
1328 l.b.x = FixedMul(scale, l.b.x);
1329 l.b.y = FixedMul(scale, l.b.y);
1330 }
1331
1332 if (angle)
1333 AM_rotate(&l.b.x, &l.b.y, angle, 0, 0);
1334
1335 l.b.x += x;
1336 l.b.y += y;
1337
1338 AM_drawMline(&l, color);
1339 }
1340}
1341
1342//
1343// AM_drawPlayers()
1344//
1345// Draws the player arrow in single player,
1346// or all the player arrows in a netgame.
1347//
1348// Passed nothing, returns nothing
1349//
1350static void AM_drawPlayers(void)
1351{
1352 int i;
1353
1354 if (!netgame)
1355 {
1356 if (ddt_cheating)
1357 AM_drawLineCharacter
1358 (
1359 cheat_player_arrow,
1360 NUMCHEATPLYRLINES,
1361 0,
1362 plr->mo->angle,
1363 mapcolor_sngl, //jff color
1364 plr->mo->x >> FRACTOMAPBITS,//e6y
1365 plr->mo->y >> FRACTOMAPBITS//e6y
1366 );
1367 else
1368 AM_drawLineCharacter
1369 (
1370 player_arrow,
1371 NUMPLYRLINES,
1372 0,
1373 plr->mo->angle,
1374 mapcolor_sngl, //jff color
1375 plr->mo->x >> FRACTOMAPBITS,//e6y
1376 plr->mo->y >> FRACTOMAPBITS);//e6y
1377 return;
1378 }
1379
1380 for (i=0;i<MAXPLAYERS;i++) {
1381 player_t* p = &players[i];
1382
1383 if ( (deathmatch && !demoplayback) && p != plr)
1384 continue;
1385
1386 if (playeringame[i]) {
1387 fixed_t x = p->mo->x >> FRACTOMAPBITS, y = p->mo->y >> FRACTOMAPBITS;//e6y
1388 if (automapmode & am_rotate)
1389 AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y);
1390
1391 AM_drawLineCharacter (player_arrow, NUMPLYRLINES, 0, p->mo->angle,
1392 p->powers[pw_invisibility] ? 246 /* *close* to black */
1393 : mapcolor_plyr[i], //jff 1/6/98 use default color
1394 x, y);
1395 }
1396 }
1397}
1398
1399//
1400// AM_drawThings()
1401//
1402// Draws the things on the automap in double IDDT cheat mode
1403//
1404// Passed colors and colorrange, no longer used
1405// Returns nothing
1406//
1407static void AM_drawThings(void)
1408{
1409 int i;
1410 mobj_t* t;
1411
1412 // for all sectors
1413 for (i=0;i<numsectors;i++)
1414 {
1415 t = sectors[i].thinglist;
1416 while (t) // for all things in that sector
1417 {
1418 fixed_t x = t->x >> FRACTOMAPBITS, y = t->y >> FRACTOMAPBITS;//e6y
1419
1420 if (automapmode & am_rotate)
1421 AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y);
1422
1423 //jff 1/5/98 case over doomednum of thing being drawn
1424 if (mapcolor_rkey || mapcolor_ykey || mapcolor_bkey)
1425 {
1426 switch(t->info->doomednum)
1427 {
1428 //jff 1/5/98 treat keys special
1429 case 38: case 13: //jff red key
1430 AM_drawLineCharacter
1431 (
1432 cross_mark,
1433 NUMCROSSMARKLINES,
1434 16<<MAPBITS,//e6y
1435 t->angle,
1436 mapcolor_rkey!=-1? mapcolor_rkey : mapcolor_sprt,
1437 x, y
1438 );
1439 t = t->snext;
1440 continue;
1441 case 39: case 6: //jff yellow key
1442 AM_drawLineCharacter
1443 (
1444 cross_mark,
1445 NUMCROSSMARKLINES,
1446 16<<MAPBITS,//e6y
1447 t->angle,
1448 mapcolor_ykey!=-1? mapcolor_ykey : mapcolor_sprt,
1449 x, y
1450 );
1451 t = t->snext;
1452 continue;
1453 case 40: case 5: //jff blue key
1454 AM_drawLineCharacter
1455 (
1456 cross_mark,
1457 NUMCROSSMARKLINES,
1458 16<<MAPBITS,//e6y
1459 t->angle,
1460 mapcolor_bkey!=-1? mapcolor_bkey : mapcolor_sprt,
1461 x, y
1462 );
1463 t = t->snext;
1464 continue;
1465 default:
1466 break;
1467 }
1468 }
1469 //jff 1/5/98 end added code for keys
1470 //jff previously entire code
1471 AM_drawLineCharacter
1472 (
1473 thintriangle_guy,
1474 NUMTHINTRIANGLEGUYLINES,
1475 16<<MAPBITS,//e6y
1476 t->angle,
1477 t->flags & MF_FRIEND && !t->player ? mapcolor_frnd :
1478 /* cph 2006/07/30 - Show count-as-kills in red. */
1479 ((t->flags & (MF_COUNTKILL | MF_CORPSE)) == MF_COUNTKILL) ? mapcolor_enemy :
1480 /* bbm 2/28/03 Show countable items in yellow. */
1481 t->flags & MF_COUNTITEM ? mapcolor_item : mapcolor_sprt,
1482 x, y
1483 );
1484 t = t->snext;
1485 }
1486 }
1487}
1488
1489//
1490// AM_drawMarks()
1491//
1492// Draw the marked locations on the automap
1493//
1494// Passed nothing, returns nothing
1495//
1496// killough 2/22/98:
1497// Rewrote AM_drawMarks(). Removed limit on marks.
1498//
1499static void AM_drawMarks(void)
1500{
1501 int i;
1502 for (i=0;i<markpointnum;i++) // killough 2/22/98: remove automap mark limit
1503 if (markpoints[i].x != -1)
1504 {
1505 int w = 5;
1506 int h = 6;
1507 int fx = markpoints[i].x;
1508 int fy = markpoints[i].y;
1509 int j = i;
1510
1511 if (automapmode & am_rotate)
1512 AM_rotate(&fx, &fy, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y);
1513
1514 fx = CXMTOF(fx); fy = CYMTOF(fy);
1515
1516 do
1517 {
1518 int d = j % 10;
1519 if (d==1) // killough 2/22/98: less spacing for '1'
1520 fx++;
1521
1522 if (fx >= f_x && fx < f_w - w && fy >= f_y && fy < f_h - h) {
1523 // cph - construct patch name and draw marker
1524 char namebuf[] = { 'A', 'M', 'M', 'N', 'U', 'M', '0'+d, 0 };
1525
1526 V_DrawNamePatch(fx, fy, FB, namebuf, CR_DEFAULT, VPT_NONE);
1527 }
1528 fx -= w-1; // killough 2/22/98: 1 space backwards
1529 j /= 10;
1530 }
1531 while (j>0);
1532 }
1533}
1534
1535//
1536// AM_drawCrosshair()
1537//
1538// Draw the single point crosshair representing map center
1539//
1540// Passed the color to draw the pixel with
1541// Returns nothing
1542//
1543// CPhipps - made static inline, and use the general pixel plotter function
1544
1545inline static void AM_drawCrosshair(int color)
1546{
1547 fline_t line;
1548
1549 line.a.x = (f_w/2)-1;
1550 line.a.y = (f_h/2);
1551 line.b.x = (f_w/2)+1;
1552 line.b.y = (f_h/2);
1553 V_DrawLine(&line, color);
1554
1555 line.a.x = (f_w/2);
1556 line.a.y = (f_h/2)-1;
1557 line.b.x = (f_w/2);
1558 line.b.y = (f_h/2)+1;
1559 V_DrawLine(&line, color);
1560}
1561
1562//
1563// AM_Drawer()
1564//
1565// Draws the entire automap
1566//
1567// Passed nothing, returns nothing
1568//
1569void AM_Drawer (void)
1570{
1571 // CPhipps - all automap modes put into one enum
1572 if (!(automapmode & am_active)) return;
1573
1574 if (!(automapmode & am_overlay)) // cph - If not overlay mode, clear background for the automap
1575 V_FillRect(FB, f_x, f_y, f_w, f_h, (byte)mapcolor_back); //jff 1/5/98 background default color
1576 if (automapmode & am_grid)
1577 AM_drawGrid(mapcolor_grid); //jff 1/7/98 grid default color
1578 AM_drawWalls();
1579 AM_drawPlayers();
1580 if (ddt_cheating==2)
1581 AM_drawThings(); //jff 1/5/98 default double IDDT sprite
1582 AM_drawCrosshair(mapcolor_hair); //jff 1/7/98 default crosshair color
1583
1584 AM_drawMarks();
1585}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * AutoMap module.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __AMMAP_H__
35#define __AMMAP_H__
36
37#include "d_event.h"
38
39#define MAPBITS 12
40#define FRACTOMAPBITS (FRACBITS-MAPBITS)
41
42// Used by ST StatusBar stuff.
43#define AM_MSGHEADER (('a'<<24)+('m'<<16))
44#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
45#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8))
46
47// Called by main loop.
48boolean AM_Responder (event_t* ev);
49
50// Called by main loop.
51void AM_Ticker (void);
52
53// Called by main loop,
54// called instead of view drawer if automap active.
55void AM_Drawer (void);
56
57// Called to force the automap to quit
58// if the level is completed while it is up.
59void AM_Stop (void);
60
61// killough 2/22/98: for saving automap information in savegame:
62
63extern void AM_Start(void);
64
65//jff 4/16/98 make externally available
66
67extern void AM_clearMarks(void);
68
69typedef struct
70{
71 fixed_t x,y;
72} mpoint_t;
73
74extern mpoint_t *markpoints;
75extern int markpointnum, markpointnum_max;
76
77// end changes -- killough 2/22/98
78
79// killough 5/2/98: moved from m_misc.c
80
81//jff 1/7/98 automap colors added
82extern int mapcolor_back; // map background
83extern int mapcolor_grid; // grid lines color
84extern int mapcolor_wall; // normal 1s wall color
85extern int mapcolor_fchg; // line at floor height change color
86extern int mapcolor_cchg; // line at ceiling height change color
87extern int mapcolor_clsd; // line at sector with floor=ceiling color
88extern int mapcolor_rkey; // red key color
89extern int mapcolor_bkey; // blue key color
90extern int mapcolor_ykey; // yellow key color
91extern int mapcolor_rdor; // red door color (diff from keys to allow option)
92extern int mapcolor_bdor; // blue door color (of enabling one not other)
93extern int mapcolor_ydor; // yellow door color
94extern int mapcolor_tele; // teleporter line color
95extern int mapcolor_secr; // secret sector boundary color
96//jff 4/23/98
97extern int mapcolor_exit; // exit line
98extern int mapcolor_unsn; // computer map unseen line color
99extern int mapcolor_flat; // line with no floor/ceiling changes
100extern int mapcolor_sprt; // general sprite color
101extern int mapcolor_item; // item sprite color
102extern int mapcolor_enemy; // enemy sprite color
103extern int mapcolor_frnd; // friendly sprite color
104extern int mapcolor_hair; // crosshair color
105extern int mapcolor_sngl; // single player arrow color
106extern int mapcolor_plyr[4]; // colors for players in multiplayer
107extern int mapcolor_me; // consoleplayer's chosen colour
108//jff 3/9/98
109extern int map_secret_after; // secrets do not appear til after bagged
110
111#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Network client. Passes information to/from server, staying
31 * synchronised.
32 * Contains the main wait loop, waiting for network input or
33 * time before doing the next tic.
34 * Rewritten for LxDoom, but based around bits of the old code.
35 *
36 *-----------------------------------------------------------------------------
37 */
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42#include <sys/types.h>
43#ifdef HAVE_UNISTD_H
44#include <unistd.h>
45#endif
46#ifdef HAVE_SYS_WAIT_H
47#include <sys/wait.h>
48#endif
49
50#ifdef USE_SDL_NET
51 #include "SDL.h"
52#endif
53
54#include "doomtype.h"
55#include "doomstat.h"
56#include "d_net.h"
57#include "z_zone.h"
58
59#include "d_main.h"
60#include "g_game.h"
61#include "m_menu.h"
62#include "p_checksum.h"
63
64#include "protocol.h"
65#include "i_network.h"
66#include "i_system.h"
67#include "i_main.h"
68#include "i_video.h"
69#include "m_argv.h"
70#include "r_fps.h"
71#include "lprintf.h"
72
73static boolean server;
74static int remotetic; // Tic expected from the remote
75static int remotesend; // Tic expected by the remote
76ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
77static ticcmd_t* localcmds;
78static unsigned numqueuedpackets;
79static packet_header_t** queuedpacket;
80int maketic;
81int ticdup = 1;
82static int xtratics = 0;
83int wanted_player_number;
84
85static boolean isExtraDDisplay = false;
86
87static void D_QuitNetGame (void);
88
89#ifndef HAVE_NET
90doomcom_t* doomcom;
91#endif
92
93#ifdef HAVE_NET
94void D_InitNetGame (void)
95{
96 int i;
97 int numplayers = 1;
98
99 i = M_CheckParm("-net");
100 if (i && i < myargc-1) i++;
101
102 if (!(netgame = server = !!i)) {
103 playeringame[consoleplayer = 0] = true;
104 // e6y
105 // for play, recording or playback using "single-player coop" mode.
106 // Equivalent to using prboom_server with -N 1
107 netgame = M_CheckParm("-solo-net");
108 } else {
109 // Get game info from server
110 packet_header_t *packet = Z_Malloc(1000, PU_STATIC, NULL);
111 struct setup_packet_s *sinfo = (void*)(packet+1);
112 struct { packet_header_t head; short pn; } PACKEDATTR initpacket;
113
114 I_InitNetwork();
115 udp_socket = I_Socket(0);
116 I_ConnectToServer(myargv[i]);
117
118 do
119 {
120 do {
121 // Send init packet
122 initpacket.pn = doom_htons(wanted_player_number);
123 packet_set(&initpacket.head, PKT_INIT, 0);
124 I_SendPacket(&initpacket.head, sizeof(initpacket));
125 I_WaitForPacket(5000);
126 } while (!I_GetPacket(packet, 1000));
127 if (packet->type == PKT_DOWN) I_Error("Server aborted the game");
128 } while (packet->type != PKT_SETUP);
129
130 // Once we have been accepted by the server, we should tell it when we leave
131 atexit(D_QuitNetGame);
132
133 // Get info from the setup packet
134 consoleplayer = sinfo->yourplayer;
135 compatibility_level = sinfo->complevel;
136 G_Compatibility();
137 startskill = sinfo->skill;
138 deathmatch = sinfo->deathmatch;
139 startmap = sinfo->level;
140 startepisode = sinfo->episode;
141 ticdup = sinfo->ticdup;
142 xtratics = sinfo->extratic;
143 G_ReadOptions(sinfo->game_options);
144
145 lprintf(LO_INFO, "\tjoined game as player %d/%d; %d WADs specified\n",
146 consoleplayer+1, numplayers = sinfo->players, sinfo->numwads);
147 {
148 char *p = sinfo->wadnames;
149 int i = sinfo->numwads;
150
151 while (i--) {
152 D_AddFile(p, source_net);
153 p += strlen(p) + 1;
154 }
155 }
156 Z_Free(packet);
157 }
158 localcmds = netcmds[displayplayer = consoleplayer];
159 for (i=0; i<numplayers; i++)
160 playeringame[i] = true;
161 for (; i<MAXPLAYERS; i++)
162 playeringame[i] = false;
163 if (!playeringame[consoleplayer]) I_Error("D_InitNetGame: consoleplayer not in game");
164}
165#else
166void D_InitNetGame (void)
167{
168 int i;
169
170 doomcom = Z_Malloc(sizeof *doomcom, PU_STATIC, NULL);
171 doomcom->consoleplayer = 0;
172 doomcom->numnodes = 0; doomcom->numplayers = 1;
173 localcmds = netcmds[consoleplayer];
174 netgame = (M_CheckParm("-solo-net") != 0);
175
176 for (i=0; i<doomcom->numplayers; i++)
177 playeringame[i] = true;
178 for (; i<MAXPLAYERS; i++)
179 playeringame[i] = false;
180
181 consoleplayer = displayplayer = doomcom->consoleplayer;
182}
183#endif // HAVE_NET
184
185#ifdef HAVE_NET
186void D_CheckNetGame(void)
187{
188 packet_header_t *packet = Z_Malloc(sizeof(packet_header_t)+1, PU_STATIC, NULL);
189
190 if (server) {
191 lprintf(LO_INFO, "D_CheckNetGame: waiting for server to signal game start\n");
192 do {
193 while (!I_GetPacket(packet, sizeof(packet_header_t)+1)) {
194 packet_set(packet, PKT_GO, 0);
195 *(byte*)(packet+1) = consoleplayer;
196 I_SendPacket(packet, sizeof(packet_header_t)+1);
197 I_uSleep(100000);
198 }
199 } while (packet->type != PKT_GO);
200 }
201 Z_Free(packet);
202}
203
204boolean D_NetGetWad(const char* name)
205{
206#if defined(HAVE_WAIT_H)
207 size_t psize = sizeof(packet_header_t) + strlen(name) + 500;
208 packet_header_t *packet;
209 boolean done = false;
210
211 if (!server || strchr(name, '/')) return false; // If it contains path info, reject
212
213 do {
214 // Send WAD request to remote
215 packet = Z_Malloc(psize, PU_STATIC, NULL);
216 packet_set(packet, PKT_WAD, 0);
217 *(byte*)(packet+1) = consoleplayer;
218 strcpy(1+(byte*)(packet+1), name);
219 I_SendPacket(packet, sizeof(packet_header_t) + strlen(name) + 2);
220
221 I_uSleep(10000);
222 } while (!I_GetPacket(packet, psize) || (packet->type != PKT_WAD));
223 Z_Free(packet);
224
225 if (!strcasecmp((void*)(packet+1), name)) {
226 pid_t pid;
227 int rv;
228 byte *p = (byte*)(packet+1) + strlen(name) + 1;
229
230 /* Automatic wad file retrieval using wget (supports http and ftp, using URLs)
231 * Unix systems have all these commands handy, this kind of thing is easy
232 * Any windo$e port will have some awkward work replacing these.
233 */
234 /* cph - caution here. This is data from an untrusted source.
235 * Don't pass it via a shell. */
236 if ((pid = fork()) == -1)
237 perror("fork");
238 else if (!pid) {
239 /* Child chains to wget, does the download */
240 execlp("wget", "wget", p, NULL);
241 }
242 /* This is the parent, i.e. main LxDoom process */
243 wait(&rv);
244 if (!(done = !access(name, R_OK))) {
245 if (!strcmp(p+strlen(p)-4, ".zip")) {
246 p = strrchr(p, '/')+1;
247 if ((pid = fork()) == -1)
248 perror("fork");
249 else if (!pid) {
250 /* Child executes decompressor */
251 execlp("unzip", "unzip", p, name, NULL);
252 }
253 /* Parent waits for the file */
254 wait(&rv);
255 done = !!access(name, R_OK);
256 }
257 /* Add more decompression protocols here as desired */
258 }
259 Z_Free(buffer);
260 }
261 return done;
262#else /* HAVE_WAIT_H */
263 return false;
264#endif
265}
266
267void NetUpdate(void)
268{
269 static int lastmadetic;
270 if (isExtraDDisplay)
271 return;
272 if (server) { // Receive network packets
273 size_t recvlen;
274 packet_header_t *packet = Z_Malloc(10000, PU_STATIC, NULL);
275 while ((recvlen = I_GetPacket(packet, 10000))) {
276 switch(packet->type) {
277 case PKT_TICS:
278 {
279 byte *p = (void*)(packet+1);
280 int tics = *p++;
281 unsigned long ptic = doom_ntohl(packet->tic);
282 if (ptic > (unsigned)remotetic) { // Missed some
283 packet_set(packet, PKT_RETRANS, remotetic);
284 *(byte*)(packet+1) = consoleplayer;
285 I_SendPacket(packet, sizeof(*packet)+1);
286 } else {
287 if (ptic + tics <= (unsigned)remotetic) break; // Will not improve things
288 remotetic = ptic;
289 while (tics--) {
290 int players = *p++;
291 while (players--) {
292 int n = *p++;
293 RawToTic(&netcmds[n][remotetic%BACKUPTICS], p);
294 p += sizeof(ticcmd_t);
295 }
296 remotetic++;
297 }
298 }
299 }
300 break;
301 case PKT_RETRANS: // Resend request
302 remotesend = doom_ntohl(packet->tic);
303 break;
304 case PKT_DOWN: // Server downed
305 {
306 int j;
307 for (j=0; j<MAXPLAYERS; j++)
308 if (j != consoleplayer) playeringame[j] = false;
309 server = false;
310 doom_printf("Server is down\nAll other players are no longer in the game\n");
311 }
312 break;
313 case PKT_EXTRA: // Misc stuff
314 case PKT_QUIT: // Player quit
315 // Queue packet to be processed when its tic time is reached
316 queuedpacket = Z_Realloc(queuedpacket, ++numqueuedpackets * sizeof *queuedpacket,
317 PU_STATIC, NULL);
318 queuedpacket[numqueuedpackets-1] = Z_Malloc(recvlen, PU_STATIC, NULL);
319 memcpy(queuedpacket[numqueuedpackets-1], packet, recvlen);
320 break;
321 case PKT_BACKOFF:
322 /* cph 2003-09-18 -
323 * The server sends this when we have got ahead of the other clients. We should
324 * stall the input side on this client, to allow other clients to catch up.
325 */
326 lastmadetic++;
327 break;
328 default: // Other packet, unrecognised or redundant
329 break;
330 }
331 }
332 Z_Free(packet);
333 }
334 { // Build new ticcmds
335 int newtics = I_GetTime() - lastmadetic;
336 newtics = (newtics > 0 ? newtics : 0);
337 lastmadetic += newtics;
338 if (ffmap) newtics++;
339 while (newtics--) {
340 I_StartTic();
341 if (maketic - gametic > BACKUPTICS/2) break;
342 G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]);
343 maketic++;
344 }
345 if (server && maketic > remotesend) { // Send the tics to the server
346 int sendtics;
347 remotesend -= xtratics;
348 if (remotesend < 0) remotesend = 0;
349 sendtics = maketic - remotesend;
350 {
351 size_t pkt_size = sizeof(packet_header_t) + 2 + sendtics * sizeof(ticcmd_t);
352 packet_header_t *packet = Z_Malloc(pkt_size, PU_STATIC, NULL);
353
354 packet_set(packet, PKT_TICC, maketic - sendtics);
355 *(byte*)(packet+1) = sendtics;
356 *(((byte*)(packet+1))+1) = consoleplayer;
357 {
358 void *tic = ((byte*)(packet+1)) +2;
359 while (sendtics--) {
360 TicToRaw(tic, &localcmds[remotesend++%BACKUPTICS]);
361 tic = (byte *)tic + sizeof(ticcmd_t);
362 }
363 }
364 I_SendPacket(packet, pkt_size);
365 Z_Free(packet);
366 }
367 }
368 }
369}
370#else
371
372void D_BuildNewTiccmds(void)
373{
374 static int lastmadetic;
375 int newtics = I_GetTime() - lastmadetic;
376 lastmadetic += newtics;
377 while (newtics--)
378 {
379 I_StartTic();
380 if (maketic - gametic > BACKUPTICS/2) break;
381 G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]);
382 maketic++;
383 }
384}
385#endif
386
387#ifdef HAVE_NET
388/* cph - data passed to this must be in the Doom (little-) endian */
389void D_NetSendMisc(netmisctype_t type, size_t len, void* data)
390{
391 if (server) {
392 size_t size = sizeof(packet_header_t) + 3*sizeof(int) + len;
393 packet_header_t *packet = Z_Malloc(size, PU_STATIC, NULL);
394 int *p = (void*)(packet+1);
395
396 packet_set(packet, PKT_EXTRA, gametic);
397 *p++ = LONG(type); *p++ = LONG(consoleplayer); *p++ = LONG(len);
398 memcpy(p, data, len);
399 I_SendPacket(packet, size);
400
401 Z_Free(packet);
402 }
403}
404
405static void CheckQueuedPackets(void)
406{
407 int i;
408 for (i=0; (unsigned)i<numqueuedpackets; i++)
409 if (doom_ntohl(queuedpacket[i]->tic) <= gametic)
410 switch (queuedpacket[i]->type) {
411 case PKT_QUIT: // Player quit the game
412 {
413 int pn = *(byte*)(queuedpacket[i]+1);
414 playeringame[pn] = false;
415 doom_printf("Player %d left the game\n", pn);
416 }
417 break;
418 case PKT_EXTRA:
419 {
420 int *p = (int*)(queuedpacket[i]+1);
421 size_t len = LONG(*(p+2));
422 switch (LONG(*p)) {
423 case nm_plcolour:
424 G_ChangedPlayerColour(LONG(*(p+1)), LONG(*(p+3)));
425 break;
426 case nm_savegamename:
427 if (len < SAVEDESCLEN) {
428 memcpy(savedescription, p+3, len);
429 // Force terminating 0 in case
430 savedescription[len] = 0;
431 }
432 break;
433 }
434 }
435 break;
436 default: // Should not be queued
437 break;
438 }
439
440 { // Requeue remaining packets
441 int newnum = 0;
442 packet_header_t **newqueue = NULL;
443
444 for (i=0; (unsigned)i<numqueuedpackets; i++)
445 if (doom_ntohl(queuedpacket[i]->tic) > gametic) {
446 newqueue = Z_Realloc(newqueue, ++newnum * sizeof *newqueue,
447 PU_STATIC, NULL);
448 newqueue[newnum-1] = queuedpacket[i];
449 } else Z_Free(queuedpacket[i]);
450
451 Z_Free(queuedpacket);
452 numqueuedpackets = newnum; queuedpacket = newqueue;
453 }
454}
455#endif // HAVE_NET
456
457void TryRunTics (void)
458{
459 int runtics;
460 int entertime = I_GetTime();
461
462 // Wait for tics to run
463 while (1) {
464#ifdef HAVE_NET
465 NetUpdate();
466#else
467 D_BuildNewTiccmds();
468#endif
469 runtics = (server ? remotetic : maketic) - gametic;
470 if (!runtics) {
471 if (!movement_smooth) {
472#ifdef HAVE_NET
473 if (server)
474 I_WaitForPacket(ms_to_next_tick);
475 else
476#endif
477 I_uSleep(ms_to_next_tick*1000);
478 }
479 if (I_GetTime() - entertime > 10) {
480#ifdef HAVE_NET
481 if (server) {
482 char buf[sizeof(packet_header_t)+1];
483 remotesend--;
484 packet_set((packet_header_t *)buf, PKT_RETRANS, remotetic);
485 buf[sizeof(buf)-1] = consoleplayer;
486 I_SendPacket((packet_header_t *)buf, sizeof buf);
487 }
488#endif
489 M_Ticker(); return;
490 }
491 //if ((displaytime) < (tic_vars.next-SDL_GetTicks()))
492 {
493 WasRenderedInTryRunTics = true;
494 if (V_GetMode() == VID_MODEGL ?
495 movement_smooth :
496 movement_smooth && gamestate==wipegamestate)
497 {
498 isExtraDDisplay = true;
499 D_Display();
500 isExtraDDisplay = false;
501 }
502 }
503 } else break;
504 }
505
506 while (runtics--) {
507#ifdef HAVE_NET
508 if (server) CheckQueuedPackets();
509#endif
510 if (advancedemo)
511 D_DoAdvanceDemo ();
512 M_Ticker ();
513 I_GetTime_SaveMS();
514 G_Ticker ();
515 P_Checksum(gametic);
516 gametic++;
517#ifdef HAVE_NET
518 NetUpdate(); // Keep sending our tics to avoid stalling remote nodes
519#endif
520 }
521}
522
523#ifdef HAVE_NET
524static void D_QuitNetGame (void)
525{
526 byte buf[1 + sizeof(packet_header_t)];
527 packet_header_t *packet = (void*)buf;
528 int i;
529
530 if (!server) return;
531 buf[sizeof(packet_header_t)] = consoleplayer;
532 packet_set(packet, PKT_QUIT, gametic);
533
534 for (i=0; i<4; i++) {
535 I_SendPacket(packet, 1 + sizeof(packet_header_t));
536 I_uSleep(10000);
537 }
538}
539#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2004 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Dehacked file support
31 * New for the TeamTNT "Boom" engine
32 *
33 * Author: Ty Halderman, TeamTNT
34 *
35 *--------------------------------------------------------------------*/
36
37// killough 5/2/98: fixed headers, removed rendunant external declarations:
38#include "doomdef.h"
39#include "doomtype.h"
40#include "doomstat.h"
41#include "d_deh.h"
42#include "sounds.h"
43#include "info.h"
44#include "m_cheat.h"
45#include "p_inter.h"
46#include "p_enemy.h"
47#include "g_game.h"
48#include "d_think.h"
49#include "w_wad.h"
50
51// CPhipps - modify to use logical output routine
52#include "lprintf.h"
53
54#define TRUE 1
55#define FALSE 0
56
57#ifndef HAVE_STRLWR
58#include <ctype.h>
59
60static char* strlwr(char* str)
61{
62 char* p;
63 for (p=str; *p; p++) *p = tolower(*p);
64 return str;
65}
66#endif
67
68// killough 10/98: new functions, to allow processing DEH files in-memory
69// (e.g. from wads)
70
71typedef struct {
72 /* cph 2006/08/06 -
73 * if lump != NULL, lump is the start of the lump,
74 * inp is the current read pos. */
75 const byte *inp, *lump;
76 long size;
77 /* else, !lump, and f is the file being read */
78 FILE* f;
79} DEHFILE;
80
81// killough 10/98: emulate IO whether input really comes from a file or not
82
83static char *dehfgets(char *buf, size_t n, DEHFILE *fp)
84{
85 if (!fp->lump) // If this is a real file,
86 return (fgets)(buf, n, fp->f); // return regular fgets
87 if (!n || !*fp->inp || fp->size<=0) // If no more characters
88 return NULL;
89 if (n==1)
90 fp->size--, *buf = *fp->inp++;
91 else
92 { // copy buffer
93 char *p = buf;
94 while (n>1 && *fp->inp && fp->size &&
95 (n--, fp->size--, *p++ = *fp->inp++) != '\n')
96 ;
97 *p = 0;
98 }
99 return buf; // Return buffer pointer
100}
101
102static int dehfeof(DEHFILE *fp)
103{
104 return !fp->lump ? feof(fp->f) : !*fp->inp || fp->size<=0;
105}
106
107static int dehfgetc(DEHFILE *fp)
108{
109 return !fp->lump ? fgetc(fp->f) : fp->size > 0 ?
110 fp->size--, *fp->inp++ : EOF;
111}
112
113// haleyjd 9/22/99
114int HelperThing = -1; // in P_SpawnMapThing to substitute helper thing
115
116// variables used in other routines
117boolean deh_pars = FALSE; // in wi_stuff to allow pars in modified games
118
119// #include "d_deh.h" -- we don't do that here but we declare the
120// variables. This externalizes everything that there is a string
121// set for in the language files. See d_deh.h for detailed comments,
122// original English values etc. These are set to the macro values,
123// which are set by D_ENGLSH.H or D_FRENCH.H(etc). BEX files are a
124// better way of changing these strings globally by language.
125
126// ====================================================================
127// Any of these can be changed using the bex extensions
128#include "dstrings.h" // to get the initial values
129/* cph - const's
130 * - removed redundant "can't XXX in a netgame" strings.
131 */
132const char *s_D_DEVSTR = D_DEVSTR;
133const char *s_D_CDROM = D_CDROM;
134const char *s_PRESSKEY = PRESSKEY;
135const char *s_PRESSYN = PRESSYN;
136const char *s_QUITMSG = QUITMSG;
137const char *s_QSAVESPOT = QSAVESPOT; // PRESSKEY;
138const char *s_SAVEDEAD = SAVEDEAD; // PRESSKEY; // remove duplicate y/n
139const char *s_QSPROMPT = QSPROMPT; // PRESSYN;
140const char *s_QLPROMPT = QLPROMPT; // PRESSYN;
141const char *s_NEWGAME = NEWGAME; // PRESSKEY;
142const char *s_RESTARTLEVEL= RESTARTLEVEL; // PRESSYN;
143const char *s_NIGHTMARE = NIGHTMARE; // PRESSYN;
144const char *s_SWSTRING = SWSTRING; // PRESSKEY;
145const char *s_MSGOFF = MSGOFF;
146const char *s_MSGON = MSGON;
147const char *s_NETEND = NETEND; // PRESSKEY;
148const char *s_ENDGAME = ENDGAME; // PRESSYN; // killough 4/4/98: end
149const char *s_DOSY = DOSY;
150const char *s_DETAILHI = DETAILHI;
151const char *s_DETAILLO = DETAILLO;
152const char *s_GAMMALVL0 = GAMMALVL0;
153const char *s_GAMMALVL1 = GAMMALVL1;
154const char *s_GAMMALVL2 = GAMMALVL2;
155const char *s_GAMMALVL3 = GAMMALVL3;
156const char *s_GAMMALVL4 = GAMMALVL4;
157const char *s_EMPTYSTRING = EMPTYSTRING;
158const char *s_GOTARMOR = GOTARMOR;
159const char *s_GOTMEGA = GOTMEGA;
160const char *s_GOTHTHBONUS = GOTHTHBONUS;
161const char *s_GOTARMBONUS = GOTARMBONUS;
162const char *s_GOTSTIM = GOTSTIM;
163const char *s_GOTMEDINEED = GOTMEDINEED;
164const char *s_GOTMEDIKIT = GOTMEDIKIT;
165const char *s_GOTSUPER = GOTSUPER;
166const char *s_GOTBLUECARD = GOTBLUECARD;
167const char *s_GOTYELWCARD = GOTYELWCARD;
168const char *s_GOTREDCARD = GOTREDCARD;
169const char *s_GOTBLUESKUL = GOTBLUESKUL;
170const char *s_GOTYELWSKUL = GOTYELWSKUL;
171const char *s_GOTREDSKULL = GOTREDSKULL;
172const char *s_GOTINVUL = GOTINVUL;
173const char *s_GOTBERSERK = GOTBERSERK;
174const char *s_GOTINVIS = GOTINVIS;
175const char *s_GOTSUIT = GOTSUIT;
176const char *s_GOTMAP = GOTMAP;
177const char *s_GOTVISOR = GOTVISOR;
178const char *s_GOTMSPHERE = GOTMSPHERE;
179const char *s_GOTCLIP = GOTCLIP;
180const char *s_GOTCLIPBOX = GOTCLIPBOX;
181const char *s_GOTROCKET = GOTROCKET;
182const char *s_GOTROCKBOX = GOTROCKBOX;
183const char *s_GOTCELL = GOTCELL;
184const char *s_GOTCELLBOX = GOTCELLBOX;
185const char *s_GOTSHELLS = GOTSHELLS;
186const char *s_GOTSHELLBOX = GOTSHELLBOX;
187const char *s_GOTBACKPACK = GOTBACKPACK;
188const char *s_GOTBFG9000 = GOTBFG9000;
189const char *s_GOTCHAINGUN = GOTCHAINGUN;
190const char *s_GOTCHAINSAW = GOTCHAINSAW;
191const char *s_GOTLAUNCHER = GOTLAUNCHER;
192const char *s_GOTPLASMA = GOTPLASMA;
193const char *s_GOTSHOTGUN = GOTSHOTGUN;
194const char *s_GOTSHOTGUN2 = GOTSHOTGUN2;
195const char *s_PD_BLUEO = PD_BLUEO;
196const char *s_PD_REDO = PD_REDO;
197const char *s_PD_YELLOWO = PD_YELLOWO;
198const char *s_PD_BLUEK = PD_BLUEK;
199const char *s_PD_REDK = PD_REDK;
200const char *s_PD_YELLOWK = PD_YELLOWK;
201const char *s_PD_BLUEC = PD_BLUEC;
202const char *s_PD_REDC = PD_REDC;
203const char *s_PD_YELLOWC = PD_YELLOWC;
204const char *s_PD_BLUES = PD_BLUES;
205const char *s_PD_REDS = PD_REDS;
206const char *s_PD_YELLOWS = PD_YELLOWS;
207const char *s_PD_ANY = PD_ANY;
208const char *s_PD_ALL3 = PD_ALL3;
209const char *s_PD_ALL6 = PD_ALL6;
210const char *s_GGSAVED = GGSAVED;
211const char *s_HUSTR_MSGU = HUSTR_MSGU;
212const char *s_HUSTR_E1M1 = HUSTR_E1M1;
213const char *s_HUSTR_E1M2 = HUSTR_E1M2;
214const char *s_HUSTR_E1M3 = HUSTR_E1M3;
215const char *s_HUSTR_E1M4 = HUSTR_E1M4;
216const char *s_HUSTR_E1M5 = HUSTR_E1M5;
217const char *s_HUSTR_E1M6 = HUSTR_E1M6;
218const char *s_HUSTR_E1M7 = HUSTR_E1M7;
219const char *s_HUSTR_E1M8 = HUSTR_E1M8;
220const char *s_HUSTR_E1M9 = HUSTR_E1M9;
221const char *s_HUSTR_E2M1 = HUSTR_E2M1;
222const char *s_HUSTR_E2M2 = HUSTR_E2M2;
223const char *s_HUSTR_E2M3 = HUSTR_E2M3;
224const char *s_HUSTR_E2M4 = HUSTR_E2M4;
225const char *s_HUSTR_E2M5 = HUSTR_E2M5;
226const char *s_HUSTR_E2M6 = HUSTR_E2M6;
227const char *s_HUSTR_E2M7 = HUSTR_E2M7;
228const char *s_HUSTR_E2M8 = HUSTR_E2M8;
229const char *s_HUSTR_E2M9 = HUSTR_E2M9;
230const char *s_HUSTR_E3M1 = HUSTR_E3M1;
231const char *s_HUSTR_E3M2 = HUSTR_E3M2;
232const char *s_HUSTR_E3M3 = HUSTR_E3M3;
233const char *s_HUSTR_E3M4 = HUSTR_E3M4;
234const char *s_HUSTR_E3M5 = HUSTR_E3M5;
235const char *s_HUSTR_E3M6 = HUSTR_E3M6;
236const char *s_HUSTR_E3M7 = HUSTR_E3M7;
237const char *s_HUSTR_E3M8 = HUSTR_E3M8;
238const char *s_HUSTR_E3M9 = HUSTR_E3M9;
239const char *s_HUSTR_E4M1 = HUSTR_E4M1;
240const char *s_HUSTR_E4M2 = HUSTR_E4M2;
241const char *s_HUSTR_E4M3 = HUSTR_E4M3;
242const char *s_HUSTR_E4M4 = HUSTR_E4M4;
243const char *s_HUSTR_E4M5 = HUSTR_E4M5;
244const char *s_HUSTR_E4M6 = HUSTR_E4M6;
245const char *s_HUSTR_E4M7 = HUSTR_E4M7;
246const char *s_HUSTR_E4M8 = HUSTR_E4M8;
247const char *s_HUSTR_E4M9 = HUSTR_E4M9;
248const char *s_HUSTR_1 = HUSTR_1;
249const char *s_HUSTR_2 = HUSTR_2;
250const char *s_HUSTR_3 = HUSTR_3;
251const char *s_HUSTR_4 = HUSTR_4;
252const char *s_HUSTR_5 = HUSTR_5;
253const char *s_HUSTR_6 = HUSTR_6;
254const char *s_HUSTR_7 = HUSTR_7;
255const char *s_HUSTR_8 = HUSTR_8;
256const char *s_HUSTR_9 = HUSTR_9;
257const char *s_HUSTR_10 = HUSTR_10;
258const char *s_HUSTR_11 = HUSTR_11;
259const char *s_HUSTR_12 = HUSTR_12;
260const char *s_HUSTR_13 = HUSTR_13;
261const char *s_HUSTR_14 = HUSTR_14;
262const char *s_HUSTR_15 = HUSTR_15;
263const char *s_HUSTR_16 = HUSTR_16;
264const char *s_HUSTR_17 = HUSTR_17;
265const char *s_HUSTR_18 = HUSTR_18;
266const char *s_HUSTR_19 = HUSTR_19;
267const char *s_HUSTR_20 = HUSTR_20;
268const char *s_HUSTR_21 = HUSTR_21;
269const char *s_HUSTR_22 = HUSTR_22;
270const char *s_HUSTR_23 = HUSTR_23;
271const char *s_HUSTR_24 = HUSTR_24;
272const char *s_HUSTR_25 = HUSTR_25;
273const char *s_HUSTR_26 = HUSTR_26;
274const char *s_HUSTR_27 = HUSTR_27;
275const char *s_HUSTR_28 = HUSTR_28;
276const char *s_HUSTR_29 = HUSTR_29;
277const char *s_HUSTR_30 = HUSTR_30;
278const char *s_HUSTR_31 = HUSTR_31;
279const char *s_HUSTR_32 = HUSTR_32;
280const char *s_PHUSTR_1 = PHUSTR_1;
281const char *s_PHUSTR_2 = PHUSTR_2;
282const char *s_PHUSTR_3 = PHUSTR_3;
283const char *s_PHUSTR_4 = PHUSTR_4;
284const char *s_PHUSTR_5 = PHUSTR_5;
285const char *s_PHUSTR_6 = PHUSTR_6;
286const char *s_PHUSTR_7 = PHUSTR_7;
287const char *s_PHUSTR_8 = PHUSTR_8;
288const char *s_PHUSTR_9 = PHUSTR_9;
289const char *s_PHUSTR_10 = PHUSTR_10;
290const char *s_PHUSTR_11 = PHUSTR_11;
291const char *s_PHUSTR_12 = PHUSTR_12;
292const char *s_PHUSTR_13 = PHUSTR_13;
293const char *s_PHUSTR_14 = PHUSTR_14;
294const char *s_PHUSTR_15 = PHUSTR_15;
295const char *s_PHUSTR_16 = PHUSTR_16;
296const char *s_PHUSTR_17 = PHUSTR_17;
297const char *s_PHUSTR_18 = PHUSTR_18;
298const char *s_PHUSTR_19 = PHUSTR_19;
299const char *s_PHUSTR_20 = PHUSTR_20;
300const char *s_PHUSTR_21 = PHUSTR_21;
301const char *s_PHUSTR_22 = PHUSTR_22;
302const char *s_PHUSTR_23 = PHUSTR_23;
303const char *s_PHUSTR_24 = PHUSTR_24;
304const char *s_PHUSTR_25 = PHUSTR_25;
305const char *s_PHUSTR_26 = PHUSTR_26;
306const char *s_PHUSTR_27 = PHUSTR_27;
307const char *s_PHUSTR_28 = PHUSTR_28;
308const char *s_PHUSTR_29 = PHUSTR_29;
309const char *s_PHUSTR_30 = PHUSTR_30;
310const char *s_PHUSTR_31 = PHUSTR_31;
311const char *s_PHUSTR_32 = PHUSTR_32;
312const char *s_THUSTR_1 = THUSTR_1;
313const char *s_THUSTR_2 = THUSTR_2;
314const char *s_THUSTR_3 = THUSTR_3;
315const char *s_THUSTR_4 = THUSTR_4;
316const char *s_THUSTR_5 = THUSTR_5;
317const char *s_THUSTR_6 = THUSTR_6;
318const char *s_THUSTR_7 = THUSTR_7;
319const char *s_THUSTR_8 = THUSTR_8;
320const char *s_THUSTR_9 = THUSTR_9;
321const char *s_THUSTR_10 = THUSTR_10;
322const char *s_THUSTR_11 = THUSTR_11;
323const char *s_THUSTR_12 = THUSTR_12;
324const char *s_THUSTR_13 = THUSTR_13;
325const char *s_THUSTR_14 = THUSTR_14;
326const char *s_THUSTR_15 = THUSTR_15;
327const char *s_THUSTR_16 = THUSTR_16;
328const char *s_THUSTR_17 = THUSTR_17;
329const char *s_THUSTR_18 = THUSTR_18;
330const char *s_THUSTR_19 = THUSTR_19;
331const char *s_THUSTR_20 = THUSTR_20;
332const char *s_THUSTR_21 = THUSTR_21;
333const char *s_THUSTR_22 = THUSTR_22;
334const char *s_THUSTR_23 = THUSTR_23;
335const char *s_THUSTR_24 = THUSTR_24;
336const char *s_THUSTR_25 = THUSTR_25;
337const char *s_THUSTR_26 = THUSTR_26;
338const char *s_THUSTR_27 = THUSTR_27;
339const char *s_THUSTR_28 = THUSTR_28;
340const char *s_THUSTR_29 = THUSTR_29;
341const char *s_THUSTR_30 = THUSTR_30;
342const char *s_THUSTR_31 = THUSTR_31;
343const char *s_THUSTR_32 = THUSTR_32;
344const char *s_HUSTR_CHATMACRO1 = HUSTR_CHATMACRO1;
345const char *s_HUSTR_CHATMACRO2 = HUSTR_CHATMACRO2;
346const char *s_HUSTR_CHATMACRO3 = HUSTR_CHATMACRO3;
347const char *s_HUSTR_CHATMACRO4 = HUSTR_CHATMACRO4;
348const char *s_HUSTR_CHATMACRO5 = HUSTR_CHATMACRO5;
349const char *s_HUSTR_CHATMACRO6 = HUSTR_CHATMACRO6;
350const char *s_HUSTR_CHATMACRO7 = HUSTR_CHATMACRO7;
351const char *s_HUSTR_CHATMACRO8 = HUSTR_CHATMACRO8;
352const char *s_HUSTR_CHATMACRO9 = HUSTR_CHATMACRO9;
353const char *s_HUSTR_CHATMACRO0 = HUSTR_CHATMACRO0;
354const char *s_HUSTR_TALKTOSELF1 = HUSTR_TALKTOSELF1;
355const char *s_HUSTR_TALKTOSELF2 = HUSTR_TALKTOSELF2;
356const char *s_HUSTR_TALKTOSELF3 = HUSTR_TALKTOSELF3;
357const char *s_HUSTR_TALKTOSELF4 = HUSTR_TALKTOSELF4;
358const char *s_HUSTR_TALKTOSELF5 = HUSTR_TALKTOSELF5;
359const char *s_HUSTR_MESSAGESENT = HUSTR_MESSAGESENT;
360const char *s_HUSTR_PLRGREEN = HUSTR_PLRGREEN;
361const char *s_HUSTR_PLRINDIGO = HUSTR_PLRINDIGO;
362const char *s_HUSTR_PLRBROWN = HUSTR_PLRBROWN;
363const char *s_HUSTR_PLRRED = HUSTR_PLRRED;
364const char *s_AMSTR_FOLLOWON = AMSTR_FOLLOWON;
365const char *s_AMSTR_FOLLOWOFF = AMSTR_FOLLOWOFF;
366const char *s_AMSTR_GRIDON = AMSTR_GRIDON;
367const char *s_AMSTR_GRIDOFF = AMSTR_GRIDOFF;
368const char *s_AMSTR_MARKEDSPOT = AMSTR_MARKEDSPOT;
369const char *s_AMSTR_MARKSCLEARED = AMSTR_MARKSCLEARED;
370// CPhipps - automap rotate & overlay
371const char* s_AMSTR_ROTATEON = AMSTR_ROTATEON;
372const char* s_AMSTR_ROTATEOFF = AMSTR_ROTATEOFF;
373const char* s_AMSTR_OVERLAYON = AMSTR_OVERLAYON;
374const char* s_AMSTR_OVERLAYOFF = AMSTR_OVERLAYOFF;
375const char *s_STSTR_MUS = STSTR_MUS;
376const char *s_STSTR_NOMUS = STSTR_NOMUS;
377const char *s_STSTR_DQDON = STSTR_DQDON;
378const char *s_STSTR_DQDOFF = STSTR_DQDOFF;
379const char *s_STSTR_KFAADDED = STSTR_KFAADDED;
380const char *s_STSTR_FAADDED = STSTR_FAADDED;
381const char *s_STSTR_NCON = STSTR_NCON;
382const char *s_STSTR_NCOFF = STSTR_NCOFF;
383const char *s_STSTR_BEHOLD = STSTR_BEHOLD;
384const char *s_STSTR_BEHOLDX = STSTR_BEHOLDX;
385const char *s_STSTR_CHOPPERS = STSTR_CHOPPERS;
386const char *s_STSTR_CLEV = STSTR_CLEV;
387const char *s_STSTR_COMPON = STSTR_COMPON;
388const char *s_STSTR_COMPOFF = STSTR_COMPOFF;
389const char *s_E1TEXT = E1TEXT;
390const char *s_E2TEXT = E2TEXT;
391const char *s_E3TEXT = E3TEXT;
392const char *s_E4TEXT = E4TEXT;
393const char *s_C1TEXT = C1TEXT;
394const char *s_C2TEXT = C2TEXT;
395const char *s_C3TEXT = C3TEXT;
396const char *s_C4TEXT = C4TEXT;
397const char *s_C5TEXT = C5TEXT;
398const char *s_C6TEXT = C6TEXT;
399const char *s_P1TEXT = P1TEXT;
400const char *s_P2TEXT = P2TEXT;
401const char *s_P3TEXT = P3TEXT;
402const char *s_P4TEXT = P4TEXT;
403const char *s_P5TEXT = P5TEXT;
404const char *s_P6TEXT = P6TEXT;
405const char *s_T1TEXT = T1TEXT;
406const char *s_T2TEXT = T2TEXT;
407const char *s_T3TEXT = T3TEXT;
408const char *s_T4TEXT = T4TEXT;
409const char *s_T5TEXT = T5TEXT;
410const char *s_T6TEXT = T6TEXT;
411const char *s_CC_ZOMBIE = CC_ZOMBIE;
412const char *s_CC_SHOTGUN = CC_SHOTGUN;
413const char *s_CC_HEAVY = CC_HEAVY;
414const char *s_CC_IMP = CC_IMP;
415const char *s_CC_DEMON = CC_DEMON;
416const char *s_CC_LOST = CC_LOST;
417const char *s_CC_CACO = CC_CACO;
418const char *s_CC_HELL = CC_HELL;
419const char *s_CC_BARON = CC_BARON;
420const char *s_CC_ARACH = CC_ARACH;
421const char *s_CC_PAIN = CC_PAIN;
422const char *s_CC_REVEN = CC_REVEN;
423const char *s_CC_MANCU = CC_MANCU;
424const char *s_CC_ARCH = CC_ARCH;
425const char *s_CC_SPIDER = CC_SPIDER;
426const char *s_CC_CYBER = CC_CYBER;
427const char *s_CC_HERO = CC_HERO;
428// Ty 03/30/98 - new substitutions for background textures
429// during int screens
430const char *bgflatE1 = "FLOOR4_8"; // end of DOOM Episode 1
431const char *bgflatE2 = "SFLR6_1"; // end of DOOM Episode 2
432const char *bgflatE3 = "MFLR8_4"; // end of DOOM Episode 3
433const char *bgflatE4 = "MFLR8_3"; // end of DOOM Episode 4
434const char *bgflat06 = "SLIME16"; // DOOM2 after MAP06
435const char *bgflat11 = "RROCK14"; // DOOM2 after MAP11
436const char *bgflat20 = "RROCK07"; // DOOM2 after MAP20
437const char *bgflat30 = "RROCK17"; // DOOM2 after MAP30
438const char *bgflat15 = "RROCK13"; // DOOM2 going MAP15 to MAP31
439const char *bgflat31 = "RROCK19"; // DOOM2 going MAP31 to MAP32
440const char *bgcastcall = "BOSSBACK"; // Panel behind cast call
441
442const char *startup1 = ""; // blank lines are default and are not printed
443const char *startup2 = "";
444const char *startup3 = "";
445const char *startup4 = "";
446const char *startup5 = "";
447
448/* Ty 05/03/98 - externalized
449 * cph - updated for prboom */
450const char *savegamename = "prbmsav";
451
452// end d_deh.h variable declarations
453// ====================================================================
454
455// Do this for a lookup--the pointer (loaded above) is cross-referenced
456// to a string key that is the same as the define above. We will use
457// strdups to set these new values that we read from the file, orphaning
458// the original value set above.
459
460// CPhipps - make strings pointed to const
461typedef struct {
462 const char **ppstr; // doubly indirect pointer to string
463 const char *lookup; // pointer to lookup string name
464} deh_strs;
465
466/* CPhipps - const, static
467 * - removed redundant "Can't XXX in a netgame" strings
468 */
469static const deh_strs deh_strlookup[] = {
470 {&s_D_DEVSTR,"D_DEVSTR"},
471 {&s_D_CDROM,"D_CDROM"},
472 {&s_PRESSKEY,"PRESSKEY"},
473 {&s_PRESSYN,"PRESSYN"},
474 {&s_QUITMSG,"QUITMSG"},
475 {&s_QSAVESPOT,"QSAVESPOT"},
476 {&s_SAVEDEAD,"SAVEDEAD"},
477 /* cph - disabled to prevent format string attacks in WAD files
478 {&s_QSPROMPT,"QSPROMPT"},
479 {&s_QLPROMPT,"QLPROMPT"},*/
480 {&s_NEWGAME,"NEWGAME"},
481 {&s_RESTARTLEVEL,"RESTARTLEVEL"},
482 {&s_NIGHTMARE,"NIGHTMARE"},
483 {&s_SWSTRING,"SWSTRING"},
484 {&s_MSGOFF,"MSGOFF"},
485 {&s_MSGON,"MSGON"},
486 {&s_NETEND,"NETEND"},
487 {&s_ENDGAME,"ENDGAME"},
488 {&s_DOSY,"DOSY"},
489 {&s_DETAILHI,"DETAILHI"},
490 {&s_DETAILLO,"DETAILLO"},
491 {&s_GAMMALVL0,"GAMMALVL0"},
492 {&s_GAMMALVL1,"GAMMALVL1"},
493 {&s_GAMMALVL2,"GAMMALVL2"},
494 {&s_GAMMALVL3,"GAMMALVL3"},
495 {&s_GAMMALVL4,"GAMMALVL4"},
496 {&s_EMPTYSTRING,"EMPTYSTRING"},
497 {&s_GOTARMOR,"GOTARMOR"},
498 {&s_GOTMEGA,"GOTMEGA"},
499 {&s_GOTHTHBONUS,"GOTHTHBONUS"},
500 {&s_GOTARMBONUS,"GOTARMBONUS"},
501 {&s_GOTSTIM,"GOTSTIM"},
502 {&s_GOTMEDINEED,"GOTMEDINEED"},
503 {&s_GOTMEDIKIT,"GOTMEDIKIT"},
504 {&s_GOTSUPER,"GOTSUPER"},
505 {&s_GOTBLUECARD,"GOTBLUECARD"},
506 {&s_GOTYELWCARD,"GOTYELWCARD"},
507 {&s_GOTREDCARD,"GOTREDCARD"},
508 {&s_GOTBLUESKUL,"GOTBLUESKUL"},
509 {&s_GOTYELWSKUL,"GOTYELWSKUL"},
510 {&s_GOTREDSKULL,"GOTREDSKULL"},
511 {&s_GOTINVUL,"GOTINVUL"},
512 {&s_GOTBERSERK,"GOTBERSERK"},
513 {&s_GOTINVIS,"GOTINVIS"},
514 {&s_GOTSUIT,"GOTSUIT"},
515 {&s_GOTMAP,"GOTMAP"},
516 {&s_GOTVISOR,"GOTVISOR"},
517 {&s_GOTMSPHERE,"GOTMSPHERE"},
518 {&s_GOTCLIP,"GOTCLIP"},
519 {&s_GOTCLIPBOX,"GOTCLIPBOX"},
520 {&s_GOTROCKET,"GOTROCKET"},
521 {&s_GOTROCKBOX,"GOTROCKBOX"},
522 {&s_GOTCELL,"GOTCELL"},
523 {&s_GOTCELLBOX,"GOTCELLBOX"},
524 {&s_GOTSHELLS,"GOTSHELLS"},
525 {&s_GOTSHELLBOX,"GOTSHELLBOX"},
526 {&s_GOTBACKPACK,"GOTBACKPACK"},
527 {&s_GOTBFG9000,"GOTBFG9000"},
528 {&s_GOTCHAINGUN,"GOTCHAINGUN"},
529 {&s_GOTCHAINSAW,"GOTCHAINSAW"},
530 {&s_GOTLAUNCHER,"GOTLAUNCHER"},
531 {&s_GOTPLASMA,"GOTPLASMA"},
532 {&s_GOTSHOTGUN,"GOTSHOTGUN"},
533 {&s_GOTSHOTGUN2,"GOTSHOTGUN2"},
534 {&s_PD_BLUEO,"PD_BLUEO"},
535 {&s_PD_REDO,"PD_REDO"},
536 {&s_PD_YELLOWO,"PD_YELLOWO"},
537 {&s_PD_BLUEK,"PD_BLUEK"},
538 {&s_PD_REDK,"PD_REDK"},
539 {&s_PD_YELLOWK,"PD_YELLOWK"},
540 {&s_PD_BLUEC,"PD_BLUEC"},
541 {&s_PD_REDC,"PD_REDC"},
542 {&s_PD_YELLOWC,"PD_YELLOWC"},
543 {&s_PD_BLUES,"PD_BLUES"},
544 {&s_PD_REDS,"PD_REDS"},
545 {&s_PD_YELLOWS,"PD_YELLOWS"},
546 {&s_PD_ANY,"PD_ANY"},
547 {&s_PD_ALL3,"PD_ALL3"},
548 {&s_PD_ALL6,"PD_ALL6"},
549 {&s_GGSAVED,"GGSAVED"},
550 {&s_HUSTR_MSGU,"HUSTR_MSGU"},
551 {&s_HUSTR_E1M1,"HUSTR_E1M1"},
552 {&s_HUSTR_E1M2,"HUSTR_E1M2"},
553 {&s_HUSTR_E1M3,"HUSTR_E1M3"},
554 {&s_HUSTR_E1M4,"HUSTR_E1M4"},
555 {&s_HUSTR_E1M5,"HUSTR_E1M5"},
556 {&s_HUSTR_E1M6,"HUSTR_E1M6"},
557 {&s_HUSTR_E1M7,"HUSTR_E1M7"},
558 {&s_HUSTR_E1M8,"HUSTR_E1M8"},
559 {&s_HUSTR_E1M9,"HUSTR_E1M9"},
560 {&s_HUSTR_E2M1,"HUSTR_E2M1"},
561 {&s_HUSTR_E2M2,"HUSTR_E2M2"},
562 {&s_HUSTR_E2M3,"HUSTR_E2M3"},
563 {&s_HUSTR_E2M4,"HUSTR_E2M4"},
564 {&s_HUSTR_E2M5,"HUSTR_E2M5"},
565 {&s_HUSTR_E2M6,"HUSTR_E2M6"},
566 {&s_HUSTR_E2M7,"HUSTR_E2M7"},
567 {&s_HUSTR_E2M8,"HUSTR_E2M8"},
568 {&s_HUSTR_E2M9,"HUSTR_E2M9"},
569 {&s_HUSTR_E3M1,"HUSTR_E3M1"},
570 {&s_HUSTR_E3M2,"HUSTR_E3M2"},
571 {&s_HUSTR_E3M3,"HUSTR_E3M3"},
572 {&s_HUSTR_E3M4,"HUSTR_E3M4"},
573 {&s_HUSTR_E3M5,"HUSTR_E3M5"},
574 {&s_HUSTR_E3M6,"HUSTR_E3M6"},
575 {&s_HUSTR_E3M7,"HUSTR_E3M7"},
576 {&s_HUSTR_E3M8,"HUSTR_E3M8"},
577 {&s_HUSTR_E3M9,"HUSTR_E3M9"},
578 {&s_HUSTR_E4M1,"HUSTR_E4M1"},
579 {&s_HUSTR_E4M2,"HUSTR_E4M2"},
580 {&s_HUSTR_E4M3,"HUSTR_E4M3"},
581 {&s_HUSTR_E4M4,"HUSTR_E4M4"},
582 {&s_HUSTR_E4M5,"HUSTR_E4M5"},
583 {&s_HUSTR_E4M6,"HUSTR_E4M6"},
584 {&s_HUSTR_E4M7,"HUSTR_E4M7"},
585 {&s_HUSTR_E4M8,"HUSTR_E4M8"},
586 {&s_HUSTR_E4M9,"HUSTR_E4M9"},
587 {&s_HUSTR_1,"HUSTR_1"},
588 {&s_HUSTR_2,"HUSTR_2"},
589 {&s_HUSTR_3,"HUSTR_3"},
590 {&s_HUSTR_4,"HUSTR_4"},
591 {&s_HUSTR_5,"HUSTR_5"},
592 {&s_HUSTR_6,"HUSTR_6"},
593 {&s_HUSTR_7,"HUSTR_7"},
594 {&s_HUSTR_8,"HUSTR_8"},
595 {&s_HUSTR_9,"HUSTR_9"},
596 {&s_HUSTR_10,"HUSTR_10"},
597 {&s_HUSTR_11,"HUSTR_11"},
598 {&s_HUSTR_12,"HUSTR_12"},
599 {&s_HUSTR_13,"HUSTR_13"},
600 {&s_HUSTR_14,"HUSTR_14"},
601 {&s_HUSTR_15,"HUSTR_15"},
602 {&s_HUSTR_16,"HUSTR_16"},
603 {&s_HUSTR_17,"HUSTR_17"},
604 {&s_HUSTR_18,"HUSTR_18"},
605 {&s_HUSTR_19,"HUSTR_19"},
606 {&s_HUSTR_20,"HUSTR_20"},
607 {&s_HUSTR_21,"HUSTR_21"},
608 {&s_HUSTR_22,"HUSTR_22"},
609 {&s_HUSTR_23,"HUSTR_23"},
610 {&s_HUSTR_24,"HUSTR_24"},
611 {&s_HUSTR_25,"HUSTR_25"},
612 {&s_HUSTR_26,"HUSTR_26"},
613 {&s_HUSTR_27,"HUSTR_27"},
614 {&s_HUSTR_28,"HUSTR_28"},
615 {&s_HUSTR_29,"HUSTR_29"},
616 {&s_HUSTR_30,"HUSTR_30"},
617 {&s_HUSTR_31,"HUSTR_31"},
618 {&s_HUSTR_32,"HUSTR_32"},
619 {&s_PHUSTR_1,"PHUSTR_1"},
620 {&s_PHUSTR_2,"PHUSTR_2"},
621 {&s_PHUSTR_3,"PHUSTR_3"},
622 {&s_PHUSTR_4,"PHUSTR_4"},
623 {&s_PHUSTR_5,"PHUSTR_5"},
624 {&s_PHUSTR_6,"PHUSTR_6"},
625 {&s_PHUSTR_7,"PHUSTR_7"},
626 {&s_PHUSTR_8,"PHUSTR_8"},
627 {&s_PHUSTR_9,"PHUSTR_9"},
628 {&s_PHUSTR_10,"PHUSTR_10"},
629 {&s_PHUSTR_11,"PHUSTR_11"},
630 {&s_PHUSTR_12,"PHUSTR_12"},
631 {&s_PHUSTR_13,"PHUSTR_13"},
632 {&s_PHUSTR_14,"PHUSTR_14"},
633 {&s_PHUSTR_15,"PHUSTR_15"},
634 {&s_PHUSTR_16,"PHUSTR_16"},
635 {&s_PHUSTR_17,"PHUSTR_17"},
636 {&s_PHUSTR_18,"PHUSTR_18"},
637 {&s_PHUSTR_19,"PHUSTR_19"},
638 {&s_PHUSTR_20,"PHUSTR_20"},
639 {&s_PHUSTR_21,"PHUSTR_21"},
640 {&s_PHUSTR_22,"PHUSTR_22"},
641 {&s_PHUSTR_23,"PHUSTR_23"},
642 {&s_PHUSTR_24,"PHUSTR_24"},
643 {&s_PHUSTR_25,"PHUSTR_25"},
644 {&s_PHUSTR_26,"PHUSTR_26"},
645 {&s_PHUSTR_27,"PHUSTR_27"},
646 {&s_PHUSTR_28,"PHUSTR_28"},
647 {&s_PHUSTR_29,"PHUSTR_29"},
648 {&s_PHUSTR_30,"PHUSTR_30"},
649 {&s_PHUSTR_31,"PHUSTR_31"},
650 {&s_PHUSTR_32,"PHUSTR_32"},
651 {&s_THUSTR_1,"THUSTR_1"},
652 {&s_THUSTR_2,"THUSTR_2"},
653 {&s_THUSTR_3,"THUSTR_3"},
654 {&s_THUSTR_4,"THUSTR_4"},
655 {&s_THUSTR_5,"THUSTR_5"},
656 {&s_THUSTR_6,"THUSTR_6"},
657 {&s_THUSTR_7,"THUSTR_7"},
658 {&s_THUSTR_8,"THUSTR_8"},
659 {&s_THUSTR_9,"THUSTR_9"},
660 {&s_THUSTR_10,"THUSTR_10"},
661 {&s_THUSTR_11,"THUSTR_11"},
662 {&s_THUSTR_12,"THUSTR_12"},
663 {&s_THUSTR_13,"THUSTR_13"},
664 {&s_THUSTR_14,"THUSTR_14"},
665 {&s_THUSTR_15,"THUSTR_15"},
666 {&s_THUSTR_16,"THUSTR_16"},
667 {&s_THUSTR_17,"THUSTR_17"},
668 {&s_THUSTR_18,"THUSTR_18"},
669 {&s_THUSTR_19,"THUSTR_19"},
670 {&s_THUSTR_20,"THUSTR_20"},
671 {&s_THUSTR_21,"THUSTR_21"},
672 {&s_THUSTR_22,"THUSTR_22"},
673 {&s_THUSTR_23,"THUSTR_23"},
674 {&s_THUSTR_24,"THUSTR_24"},
675 {&s_THUSTR_25,"THUSTR_25"},
676 {&s_THUSTR_26,"THUSTR_26"},
677 {&s_THUSTR_27,"THUSTR_27"},
678 {&s_THUSTR_28,"THUSTR_28"},
679 {&s_THUSTR_29,"THUSTR_29"},
680 {&s_THUSTR_30,"THUSTR_30"},
681 {&s_THUSTR_31,"THUSTR_31"},
682 {&s_THUSTR_32,"THUSTR_32"},
683 {&s_HUSTR_CHATMACRO1,"HUSTR_CHATMACRO1"},
684 {&s_HUSTR_CHATMACRO2,"HUSTR_CHATMACRO2"},
685 {&s_HUSTR_CHATMACRO3,"HUSTR_CHATMACRO3"},
686 {&s_HUSTR_CHATMACRO4,"HUSTR_CHATMACRO4"},
687 {&s_HUSTR_CHATMACRO5,"HUSTR_CHATMACRO5"},
688 {&s_HUSTR_CHATMACRO6,"HUSTR_CHATMACRO6"},
689 {&s_HUSTR_CHATMACRO7,"HUSTR_CHATMACRO7"},
690 {&s_HUSTR_CHATMACRO8,"HUSTR_CHATMACRO8"},
691 {&s_HUSTR_CHATMACRO9,"HUSTR_CHATMACRO9"},
692 {&s_HUSTR_CHATMACRO0,"HUSTR_CHATMACRO0"},
693 {&s_HUSTR_TALKTOSELF1,"HUSTR_TALKTOSELF1"},
694 {&s_HUSTR_TALKTOSELF2,"HUSTR_TALKTOSELF2"},
695 {&s_HUSTR_TALKTOSELF3,"HUSTR_TALKTOSELF3"},
696 {&s_HUSTR_TALKTOSELF4,"HUSTR_TALKTOSELF4"},
697 {&s_HUSTR_TALKTOSELF5,"HUSTR_TALKTOSELF5"},
698 {&s_HUSTR_MESSAGESENT,"HUSTR_MESSAGESENT"},
699 {&s_HUSTR_PLRGREEN,"HUSTR_PLRGREEN"},
700 {&s_HUSTR_PLRINDIGO,"HUSTR_PLRINDIGO"},
701 {&s_HUSTR_PLRBROWN,"HUSTR_PLRBROWN"},
702 {&s_HUSTR_PLRRED,"HUSTR_PLRRED"},
703 //{c_HUSTR_KEYGREEN,"HUSTR_KEYGREEN"},
704 //{c_HUSTR_KEYINDIGO,"HUSTR_KEYINDIGO"},
705 //{c_HUSTR_KEYBROWN,"HUSTR_KEYBROWN"},
706 //{c_HUSTR_KEYRED,"HUSTR_KEYRED"},
707 {&s_AMSTR_FOLLOWON,"AMSTR_FOLLOWON"},
708 {&s_AMSTR_FOLLOWOFF,"AMSTR_FOLLOWOFF"},
709 {&s_AMSTR_GRIDON,"AMSTR_GRIDON"},
710 {&s_AMSTR_GRIDOFF,"AMSTR_GRIDOFF"},
711 {&s_AMSTR_MARKEDSPOT,"AMSTR_MARKEDSPOT"},
712 {&s_AMSTR_MARKSCLEARED,"AMSTR_MARKSCLEARED"},
713 {&s_STSTR_MUS,"STSTR_MUS"},
714 {&s_STSTR_NOMUS,"STSTR_NOMUS"},
715 {&s_STSTR_DQDON,"STSTR_DQDON"},
716 {&s_STSTR_DQDOFF,"STSTR_DQDOFF"},
717 {&s_STSTR_KFAADDED,"STSTR_KFAADDED"},
718 {&s_STSTR_FAADDED,"STSTR_FAADDED"},
719 {&s_STSTR_NCON,"STSTR_NCON"},
720 {&s_STSTR_NCOFF,"STSTR_NCOFF"},
721 {&s_STSTR_BEHOLD,"STSTR_BEHOLD"},
722 {&s_STSTR_BEHOLDX,"STSTR_BEHOLDX"},
723 {&s_STSTR_CHOPPERS,"STSTR_CHOPPERS"},
724 {&s_STSTR_CLEV,"STSTR_CLEV"},
725 {&s_STSTR_COMPON,"STSTR_COMPON"},
726 {&s_STSTR_COMPOFF,"STSTR_COMPOFF"},
727 {&s_E1TEXT,"E1TEXT"},
728 {&s_E2TEXT,"E2TEXT"},
729 {&s_E3TEXT,"E3TEXT"},
730 {&s_E4TEXT,"E4TEXT"},
731 {&s_C1TEXT,"C1TEXT"},
732 {&s_C2TEXT,"C2TEXT"},
733 {&s_C3TEXT,"C3TEXT"},
734 {&s_C4TEXT,"C4TEXT"},
735 {&s_C5TEXT,"C5TEXT"},
736 {&s_C6TEXT,"C6TEXT"},
737 {&s_P1TEXT,"P1TEXT"},
738 {&s_P2TEXT,"P2TEXT"},
739 {&s_P3TEXT,"P3TEXT"},
740 {&s_P4TEXT,"P4TEXT"},
741 {&s_P5TEXT,"P5TEXT"},
742 {&s_P6TEXT,"P6TEXT"},
743 {&s_T1TEXT,"T1TEXT"},
744 {&s_T2TEXT,"T2TEXT"},
745 {&s_T3TEXT,"T3TEXT"},
746 {&s_T4TEXT,"T4TEXT"},
747 {&s_T5TEXT,"T5TEXT"},
748 {&s_T6TEXT,"T6TEXT"},
749 {&s_CC_ZOMBIE,"CC_ZOMBIE"},
750 {&s_CC_SHOTGUN,"CC_SHOTGUN"},
751 {&s_CC_HEAVY,"CC_HEAVY"},
752 {&s_CC_IMP,"CC_IMP"},
753 {&s_CC_DEMON,"CC_DEMON"},
754 {&s_CC_LOST,"CC_LOST"},
755 {&s_CC_CACO,"CC_CACO"},
756 {&s_CC_HELL,"CC_HELL"},
757 {&s_CC_BARON,"CC_BARON"},
758 {&s_CC_ARACH,"CC_ARACH"},
759 {&s_CC_PAIN,"CC_PAIN"},
760 {&s_CC_REVEN,"CC_REVEN"},
761 {&s_CC_MANCU,"CC_MANCU"},
762 {&s_CC_ARCH,"CC_ARCH"},
763 {&s_CC_SPIDER,"CC_SPIDER"},
764 {&s_CC_CYBER,"CC_CYBER"},
765 {&s_CC_HERO,"CC_HERO"},
766 {&bgflatE1,"BGFLATE1"},
767 {&bgflatE2,"BGFLATE2"},
768 {&bgflatE3,"BGFLATE3"},
769 {&bgflatE4,"BGFLATE4"},
770 {&bgflat06,"BGFLAT06"},
771 {&bgflat11,"BGFLAT11"},
772 {&bgflat20,"BGFLAT20"},
773 {&bgflat30,"BGFLAT30"},
774 {&bgflat15,"BGFLAT15"},
775 {&bgflat31,"BGFLAT31"},
776 {&bgcastcall,"BGCASTCALL"},
777 // Ty 04/08/98 - added 5 general purpose startup announcement
778 // strings for hacker use. See m_menu.c
779 {&startup1,"STARTUP1"},
780 {&startup2,"STARTUP2"},
781 {&startup3,"STARTUP3"},
782 {&startup4,"STARTUP4"},
783 {&startup5,"STARTUP5"},
784 {&savegamename,"SAVEGAMENAME"}, // Ty 05/03/98
785};
786
787static int deh_numstrlookup =
788sizeof(deh_strlookup)/sizeof(deh_strlookup[0]);
789
790const char *deh_newlevel = "NEWLEVEL"; // CPhipps - const
791
792// DOOM shareware/registered/retail (Ultimate) names.
793// CPhipps - const**const
794const char **const mapnames[] =
795{
796 &s_HUSTR_E1M1,
797 &s_HUSTR_E1M2,
798 &s_HUSTR_E1M3,
799 &s_HUSTR_E1M4,
800 &s_HUSTR_E1M5,
801 &s_HUSTR_E1M6,
802 &s_HUSTR_E1M7,
803 &s_HUSTR_E1M8,
804 &s_HUSTR_E1M9,
805
806 &s_HUSTR_E2M1,
807 &s_HUSTR_E2M2,
808 &s_HUSTR_E2M3,
809 &s_HUSTR_E2M4,
810 &s_HUSTR_E2M5,
811 &s_HUSTR_E2M6,
812 &s_HUSTR_E2M7,
813 &s_HUSTR_E2M8,
814 &s_HUSTR_E2M9,
815
816 &s_HUSTR_E3M1,
817 &s_HUSTR_E3M2,
818 &s_HUSTR_E3M3,
819 &s_HUSTR_E3M4,
820 &s_HUSTR_E3M5,
821 &s_HUSTR_E3M6,
822 &s_HUSTR_E3M7,
823 &s_HUSTR_E3M8,
824 &s_HUSTR_E3M9,
825
826 &s_HUSTR_E4M1,
827 &s_HUSTR_E4M2,
828 &s_HUSTR_E4M3,
829 &s_HUSTR_E4M4,
830 &s_HUSTR_E4M5,
831 &s_HUSTR_E4M6,
832 &s_HUSTR_E4M7,
833 &s_HUSTR_E4M8,
834 &s_HUSTR_E4M9,
835
836 &deh_newlevel, // spares? Unused.
837 &deh_newlevel,
838 &deh_newlevel,
839 &deh_newlevel,
840 &deh_newlevel,
841 &deh_newlevel,
842 &deh_newlevel,
843 &deh_newlevel,
844 &deh_newlevel
845};
846
847// CPhipps - const**const
848const char **const mapnames2[] = // DOOM 2 map names.
849{
850 &s_HUSTR_1,
851 &s_HUSTR_2,
852 &s_HUSTR_3,
853 &s_HUSTR_4,
854 &s_HUSTR_5,
855 &s_HUSTR_6,
856 &s_HUSTR_7,
857 &s_HUSTR_8,
858 &s_HUSTR_9,
859 &s_HUSTR_10,
860 &s_HUSTR_11,
861
862 &s_HUSTR_12,
863 &s_HUSTR_13,
864 &s_HUSTR_14,
865 &s_HUSTR_15,
866 &s_HUSTR_16,
867 &s_HUSTR_17,
868 &s_HUSTR_18,
869 &s_HUSTR_19,
870 &s_HUSTR_20,
871
872 &s_HUSTR_21,
873 &s_HUSTR_22,
874 &s_HUSTR_23,
875 &s_HUSTR_24,
876 &s_HUSTR_25,
877 &s_HUSTR_26,
878 &s_HUSTR_27,
879 &s_HUSTR_28,
880 &s_HUSTR_29,
881 &s_HUSTR_30,
882 &s_HUSTR_31,
883 &s_HUSTR_32,
884};
885
886// CPhipps - const**const
887const char **const mapnamesp[] = // Plutonia WAD map names.
888{
889 &s_PHUSTR_1,
890 &s_PHUSTR_2,
891 &s_PHUSTR_3,
892 &s_PHUSTR_4,
893 &s_PHUSTR_5,
894 &s_PHUSTR_6,
895 &s_PHUSTR_7,
896 &s_PHUSTR_8,
897 &s_PHUSTR_9,
898 &s_PHUSTR_10,
899 &s_PHUSTR_11,
900
901 &s_PHUSTR_12,
902 &s_PHUSTR_13,
903 &s_PHUSTR_14,
904 &s_PHUSTR_15,
905 &s_PHUSTR_16,
906 &s_PHUSTR_17,
907 &s_PHUSTR_18,
908 &s_PHUSTR_19,
909 &s_PHUSTR_20,
910
911 &s_PHUSTR_21,
912 &s_PHUSTR_22,
913 &s_PHUSTR_23,
914 &s_PHUSTR_24,
915 &s_PHUSTR_25,
916 &s_PHUSTR_26,
917 &s_PHUSTR_27,
918 &s_PHUSTR_28,
919 &s_PHUSTR_29,
920 &s_PHUSTR_30,
921 &s_PHUSTR_31,
922 &s_PHUSTR_32,
923};
924
925// CPhipps - const**const
926const char **const mapnamest[] = // TNT WAD map names.
927{
928 &s_THUSTR_1,
929 &s_THUSTR_2,
930 &s_THUSTR_3,
931 &s_THUSTR_4,
932 &s_THUSTR_5,
933 &s_THUSTR_6,
934 &s_THUSTR_7,
935 &s_THUSTR_8,
936 &s_THUSTR_9,
937 &s_THUSTR_10,
938 &s_THUSTR_11,
939
940 &s_THUSTR_12,
941 &s_THUSTR_13,
942 &s_THUSTR_14,
943 &s_THUSTR_15,
944 &s_THUSTR_16,
945 &s_THUSTR_17,
946 &s_THUSTR_18,
947 &s_THUSTR_19,
948 &s_THUSTR_20,
949
950 &s_THUSTR_21,
951 &s_THUSTR_22,
952 &s_THUSTR_23,
953 &s_THUSTR_24,
954 &s_THUSTR_25,
955 &s_THUSTR_26,
956 &s_THUSTR_27,
957 &s_THUSTR_28,
958 &s_THUSTR_29,
959 &s_THUSTR_30,
960 &s_THUSTR_31,
961 &s_THUSTR_32,
962};
963
964// Function prototypes
965void lfstrip(char *); // strip the \r and/or \n off of a line
966void rstrip(char *); // strip trailing whitespace
967char * ptr_lstrip(char *); // point past leading whitespace
968boolean deh_GetData(char *, char *, uint_64_t *, char **, FILE *);
969boolean deh_procStringSub(char *, char *, char *, FILE *);
970char * dehReformatStr(char *);
971
972// Prototypes for block processing functions
973// Pointers to these functions are used as the blocks are encountered.
974
975static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line);
976static void deh_procFrame(DEHFILE *, FILE*, char *);
977static void deh_procPointer(DEHFILE *, FILE*, char *);
978static void deh_procSounds(DEHFILE *, FILE*, char *);
979static void deh_procAmmo(DEHFILE *, FILE*, char *);
980static void deh_procWeapon(DEHFILE *, FILE*, char *);
981static void deh_procSprite(DEHFILE *, FILE*, char *);
982static void deh_procCheat(DEHFILE *, FILE*, char *);
983static void deh_procMisc(DEHFILE *, FILE*, char *);
984static void deh_procText(DEHFILE *, FILE*, char *);
985static void deh_procPars(DEHFILE *, FILE*, char *);
986static void deh_procStrings(DEHFILE *, FILE*, char *);
987static void deh_procError(DEHFILE *, FILE*, char *);
988static void deh_procBexCodePointers(DEHFILE *, FILE*, char *);
989static void deh_procHelperThing(DEHFILE *, FILE *, char *); // haleyjd 9/22/99
990// haleyjd: handlers to fully deprecate the DeHackEd text section
991static void deh_procBexSounds(DEHFILE *, FILE *, char *);
992static void deh_procBexMusic(DEHFILE *, FILE *, char *);
993static void deh_procBexSprites(DEHFILE *, FILE *, char *);
994
995// Structure deh_block is used to hold the block names that can
996// be encountered, and the routines to use to decipher them
997
998typedef struct
999{
1000 const char *key; // a mnemonic block code name // CPhipps - const*
1001 void (*const fptr)(DEHFILE *, FILE*, char *); // handler
1002} deh_block;
1003
1004#define DEH_BUFFERMAX 1024 // input buffer area size, hardcodedfor now
1005// killough 8/9/98: make DEH_BLOCKMAX self-adjusting
1006#define DEH_BLOCKMAX (sizeof deh_blocks/sizeof*deh_blocks) // size of array
1007#define DEH_MAXKEYLEN 32 // as much of any key as we'll look at
1008#define DEH_MOBJINFOMAX 24 // number of ints in the mobjinfo_t structure (!)
1009
1010// Put all the block header values, and the function to be called when that
1011// one is encountered, in this array:
1012static const deh_block deh_blocks[] = { // CPhipps - static const
1013 /* 0 */ {"Thing",deh_procThing},
1014 /* 1 */ {"Frame",deh_procFrame},
1015 /* 2 */ {"Pointer",deh_procPointer},
1016 /* 3 */ {"Sound",deh_procSounds}, // Ty 03/16/98 corrected from "Sounds"
1017 /* 4 */ {"Ammo",deh_procAmmo},
1018 /* 5 */ {"Weapon",deh_procWeapon},
1019 /* 6 */ {"Sprite",deh_procSprite},
1020 /* 7 */ {"Cheat",deh_procCheat},
1021 /* 8 */ {"Misc",deh_procMisc},
1022 /* 9 */ {"Text",deh_procText}, // -- end of standard "deh" entries,
1023
1024 // begin BOOM Extensions (BEX)
1025
1026 /* 10 */ {"[STRINGS]",deh_procStrings}, // new string changes
1027 /* 11 */ {"[PARS]",deh_procPars}, // alternative block marker
1028 /* 12 */ {"[CODEPTR]",deh_procBexCodePointers}, // bex codepointers by mnemonic
1029 /* 13 */ {"[HELPER]", deh_procHelperThing}, // helper thing substitution haleyjd 9/22/99
1030 /* 14 */ {"[SPRITES]", deh_procBexSprites}, // bex style sprites
1031 /* 15 */ {"[SOUNDS]", deh_procBexSounds}, // bex style sounds
1032 /* 16 */ {"[MUSIC]", deh_procBexMusic}, // bex style music
1033 /* 17 */ {"", deh_procError} // dummy to handle anything else
1034};
1035
1036// flag to skip included deh-style text, used with INCLUDE NOTEXT directive
1037static boolean includenotext = false;
1038
1039// MOBJINFO - Dehacked block name = "Thing"
1040// Usage: Thing nn (name)
1041// These are for mobjinfo_t types. Each is an integer
1042// within the structure, so we can use index of the string in this
1043// array to offset by sizeof(int) into the mobjinfo_t array at [nn]
1044// * things are base zero but dehacked considers them to start at #1. ***
1045// CPhipps - static const
1046
1047static const char *deh_mobjinfo[DEH_MOBJINFOMAX] =
1048{
1049 "ID #", // .doomednum
1050 "Initial frame", // .spawnstate
1051 "Hit points", // .spawnhealth
1052 "First moving frame", // .seestate
1053 "Alert sound", // .seesound
1054 "Reaction time", // .reactiontime
1055 "Attack sound", // .attacksound
1056 "Injury frame", // .painstate
1057 "Pain chance", // .painchance
1058 "Pain sound", // .painsound
1059 "Close attack frame", // .meleestate
1060 "Far attack frame", // .missilestate
1061 "Death frame", // .deathstate
1062 "Exploding frame", // .xdeathstate
1063 "Death sound", // .deathsound
1064 "Speed", // .speed
1065 "Width", // .radius
1066 "Height", // .height
1067 "Mass", // .mass
1068 "Missile damage", // .damage
1069 "Action sound", // .activesound
1070 "Bits", // .flags
1071 "Bits2", // .flags
1072 "Respawn frame" // .raisestate
1073};
1074
1075// Strings that are used to indicate flags ("Bits" in mobjinfo)
1076// This is an array of bit masks that are related to p_mobj.h
1077// values, using the smae names without the MF_ in front.
1078// Ty 08/27/98 new code
1079//
1080// killough 10/98:
1081//
1082// Convert array to struct to allow multiple values, make array size variable
1083
1084#define DEH_MOBJFLAGMAX (sizeof deh_mobjflags/sizeof*deh_mobjflags)
1085
1086struct deh_mobjflags_s {
1087 const char *name; // CPhipps - const*
1088 uint_64_t value;
1089};
1090
1091// CPhipps - static const
1092static const struct deh_mobjflags_s deh_mobjflags[] = {
1093 {"SPECIAL", MF_SPECIAL}, // call P_Specialthing when touched
1094 {"SOLID", MF_SOLID}, // block movement
1095 {"SHOOTABLE", MF_SHOOTABLE}, // can be hit
1096 {"NOSECTOR", MF_NOSECTOR}, // invisible but touchable
1097 {"NOBLOCKMAP", MF_NOBLOCKMAP}, // inert but displayable
1098 {"AMBUSH", MF_AMBUSH}, // deaf monster
1099 {"JUSTHIT", MF_JUSTHIT}, // will try to attack right back
1100 {"JUSTATTACKED", MF_JUSTATTACKED}, // take at least 1 step before attacking
1101 {"SPAWNCEILING", MF_SPAWNCEILING}, // initially hang from ceiling
1102 {"NOGRAVITY", MF_NOGRAVITY}, // don't apply gravity during play
1103 {"DROPOFF", MF_DROPOFF}, // can jump from high places
1104 {"PICKUP", MF_PICKUP}, // will pick up items
1105 {"NOCLIP", MF_NOCLIP}, // goes through walls
1106 {"SLIDE", MF_SLIDE}, // keep info about sliding along walls
1107 {"FLOAT", MF_FLOAT}, // allow movement to any height
1108 {"TELEPORT", MF_TELEPORT}, // don't cross lines or look at heights
1109 {"MISSILE", MF_MISSILE}, // don't hit same species, explode on block
1110 {"DROPPED", MF_DROPPED}, // dropped, not spawned (like ammo clip)
1111 {"SHADOW", MF_SHADOW}, // use fuzzy draw like spectres
1112 {"NOBLOOD", MF_NOBLOOD}, // puffs instead of blood when shot
1113 {"CORPSE", MF_CORPSE}, // so it will slide down steps when dead
1114 {"INFLOAT", MF_INFLOAT}, // float but not to target height
1115 {"COUNTKILL", MF_COUNTKILL}, // count toward the kills total
1116 {"COUNTITEM", MF_COUNTITEM}, // count toward the items total
1117 {"SKULLFLY", MF_SKULLFLY}, // special handling for flying skulls
1118 {"NOTDMATCH", MF_NOTDMATCH}, // do not spawn in deathmatch
1119
1120 // killough 10/98: TRANSLATION consists of 2 bits, not 1:
1121
1122 {"TRANSLATION", MF_TRANSLATION1}, // for Boom bug-compatibility
1123 {"TRANSLATION1", MF_TRANSLATION1}, // use translation table for color (players)
1124 {"TRANSLATION2", MF_TRANSLATION2}, // use translation table for color (players)
1125 {"UNUSED1", MF_TRANSLATION2}, // unused bit # 1 -- For Boom bug-compatibility
1126 {"UNUSED2", MF_UNUSED2}, // unused bit # 2 -- For Boom compatibility
1127 {"UNUSED3", MF_UNUSED3}, // unused bit # 3 -- For Boom compatibility
1128 {"UNUSED4", MF_TRANSLUCENT}, // unused bit # 4 -- For Boom compatibility
1129 {"TRANSLUCENT", MF_TRANSLUCENT}, // apply translucency to sprite (BOOM)
1130 {"TOUCHY", MF_TOUCHY}, // dies on contact with solid objects (MBF)
1131 {"BOUNCES", MF_BOUNCES}, // bounces off floors, ceilings and maybe walls (MBF)
1132 {"FRIEND", MF_FRIEND}, // a friend of the player(s) (MBF)
1133};
1134
1135// STATE - Dehacked block name = "Frame" and "Pointer"
1136// Usage: Frame nn
1137// Usage: Pointer nn (Frame nn)
1138// These are indexed separately, for lookup to the actual
1139// function pointers. Here we'll take whatever Dehacked gives
1140// us and go from there. The (Frame nn) after the pointer is the
1141// real place to put this value. The "Pointer" value is an xref
1142// that Dehacked uses and is useless to us.
1143// * states are base zero and have a dummy #0 (TROO)
1144
1145static const char *deh_state[] = // CPhipps - static const*
1146{
1147 "Sprite number", // .sprite (spritenum_t) // an enum
1148 "Sprite subnumber", // .frame (long)
1149 "Duration", // .tics (long)
1150 "Next frame", // .nextstate (statenum_t)
1151 // This is set in a separate "Pointer" block from Dehacked
1152 "Codep Frame", // pointer to first use of action (actionf_t)
1153 "Unknown 1", // .misc1 (long)
1154 "Unknown 2" // .misc2 (long)
1155};
1156
1157// SFXINFO_STRUCT - Dehacked block name = "Sounds"
1158// Sound effects, typically not changed (redirected, and new sfx put
1159// into the pwad, but not changed here. Can you tell that Gregdidn't
1160// know what they were for, mostly? Can you tell that I don't either?
1161// Mostly I just put these into the same slots as they are in the struct.
1162// This may not be supported in our -deh option if it doesn't make sense by then.
1163
1164// * sounds are base zero but have a dummy #0
1165
1166static const char *deh_sfxinfo[] = // CPhipps - static const*
1167{
1168 "Offset", // pointer to a name string, changed in text
1169 "Zero/One", // .singularity (int, one at a time flag)
1170 "Value", // .priority
1171 "Zero 1", // .link (sfxinfo_t*) referenced sound if linked
1172 "Zero 2", // .pitch
1173 "Zero 3", // .volume
1174 "Zero 4", // .data (SAMPLE*) sound data
1175 "Neg. One 1", // .usefulness
1176 "Neg. One 2" // .lumpnum
1177};
1178
1179// MUSICINFO is not supported in Dehacked. Ignored here.
1180// * music entries are base zero but have a dummy #0
1181
1182// SPRITE - Dehacked block name = "Sprite"
1183// Usage = Sprite nn
1184// Sprite redirection by offset into the text area - unsupported by BOOM
1185// * sprites are base zero and dehacked uses it that way.
1186
1187// static const char *deh_sprite[] = // CPhipps - static const*
1188// {
1189// "Offset" // supposed to be the offset into the text section
1190// };
1191
1192// AMMO - Dehacked block name = "Ammo"
1193// usage = Ammo n (name)
1194// Ammo information for the few types of ammo
1195
1196static const char *deh_ammo[] = // CPhipps - static const*
1197{
1198 "Max ammo", // maxammo[]
1199 "Per ammo" // clipammo[]
1200};
1201
1202// WEAPONS - Dehacked block name = "Weapon"
1203// Usage: Weapon nn (name)
1204// Basically a list of frames and what kind of ammo (see above)it uses.
1205
1206static const char *deh_weapon[] = // CPhipps - static const*
1207{
1208 "Ammo type", // .ammo
1209 "Deselect frame", // .upstate
1210 "Select frame", // .downstate
1211 "Bobbing frame", // .readystate
1212 "Shooting frame", // .atkstate
1213 "Firing frame" // .flashstate
1214};
1215
1216// CHEATS - Dehacked block name = "Cheat"
1217// Usage: Cheat 0
1218// Always uses a zero in the dehacked file, for consistency. No meaning.
1219// These are just plain funky terms compared with id's
1220//
1221// killough 4/18/98: integrated into main cheat table now (see st_stuff.c)
1222
1223// MISC - Dehacked block name = "Misc"
1224// Usage: Misc 0
1225// Always uses a zero in the dehacked file, for consistency. No meaning.
1226
1227static const char *deh_misc[] = // CPhipps - static const*
1228{
1229 "Initial Health", // initial_health
1230 "Initial Bullets", // initial_bullets
1231 "Max Health", // maxhealth
1232 "Max Armor", // max_armor
1233 "Green Armor Class", // green_armor_class
1234 "Blue Armor Class", // blue_armor_class
1235 "Max Soulsphere", // max_soul
1236 "Soulsphere Health", // soul_health
1237 "Megasphere Health", // mega_health
1238 "God Mode Health", // god_health
1239 "IDFA Armor", // idfa_armor
1240 "IDFA Armor Class", // idfa_armor_class
1241 "IDKFA Armor", // idkfa_armor
1242 "IDKFA Armor Class", // idkfa_armor_class
1243 "BFG Cells/Shot", // BFGCELLS
1244 "Monsters Infight" // Unknown--not a specific number it seems, but
1245 // the logic has to be here somewhere or
1246 // it'd happen always
1247};
1248
1249// TEXT - Dehacked block name = "Text"
1250// Usage: Text fromlen tolen
1251// Dehacked allows a bit of adjustment to the length (why?)
1252
1253// BEX extension [CODEPTR]
1254// Usage: Start block, then each line is:
1255// FRAME nnn = PointerMnemonic
1256
1257typedef struct {
1258 actionf_t cptr; // actual pointer to the subroutine
1259 const char *lookup; // mnemonic lookup string to be specified in BEX
1260 // CPhipps - const*
1261} deh_bexptr;
1262
1263static const deh_bexptr deh_bexptrs[] = // CPhipps - static const
1264{
1265 {A_Light0, "A_Light0"},
1266 {A_WeaponReady, "A_WeaponReady"},
1267 {A_Lower, "A_Lower"},
1268 {A_Raise, "A_Raise"},
1269 {A_Punch, "A_Punch"},
1270 {A_ReFire, "A_ReFire"},
1271 {A_FirePistol, "A_FirePistol"},
1272 {A_Light1, "A_Light1"},
1273 {A_FireShotgun, "A_FireShotgun"},
1274 {A_Light2, "A_Light2"},
1275 {A_FireShotgun2, "A_FireShotgun2"},
1276 {A_CheckReload, "A_CheckReload"},
1277 {A_OpenShotgun2, "A_OpenShotgun2"},
1278 {A_LoadShotgun2, "A_LoadShotgun2"},
1279 {A_CloseShotgun2, "A_CloseShotgun2"},
1280 {A_FireCGun, "A_FireCGun"},
1281 {A_GunFlash, "A_GunFlash"},
1282 {A_FireMissile, "A_FireMissile"},
1283 {A_Saw, "A_Saw"},
1284 {A_FirePlasma, "A_FirePlasma"},
1285 {A_BFGsound, "A_BFGsound"},
1286 {A_FireBFG, "A_FireBFG"},
1287 {A_BFGSpray, "A_BFGSpray"},
1288 {A_Explode, "A_Explode"},
1289 {A_Pain, "A_Pain"},
1290 {A_PlayerScream, "A_PlayerScream"},
1291 {A_Fall, "A_Fall"},
1292 {A_XScream, "A_XScream"},
1293 {A_Look, "A_Look"},
1294 {A_Chase, "A_Chase"},
1295 {A_FaceTarget, "A_FaceTarget"},
1296 {A_PosAttack, "A_PosAttack"},
1297 {A_Scream, "A_Scream"},
1298 {A_SPosAttack, "A_SPosAttack"},
1299 {A_VileChase, "A_VileChase"},
1300 {A_VileStart, "A_VileStart"},
1301 {A_VileTarget, "A_VileTarget"},
1302 {A_VileAttack, "A_VileAttack"},
1303 {A_StartFire, "A_StartFire"},
1304 {A_Fire, "A_Fire"},
1305 {A_FireCrackle, "A_FireCrackle"},
1306 {A_Tracer, "A_Tracer"},
1307 {A_SkelWhoosh, "A_SkelWhoosh"},
1308 {A_SkelFist, "A_SkelFist"},
1309 {A_SkelMissile, "A_SkelMissile"},
1310 {A_FatRaise, "A_FatRaise"},
1311 {A_FatAttack1, "A_FatAttack1"},
1312 {A_FatAttack2, "A_FatAttack2"},
1313 {A_FatAttack3, "A_FatAttack3"},
1314 {A_BossDeath, "A_BossDeath"},
1315 {A_CPosAttack, "A_CPosAttack"},
1316 {A_CPosRefire, "A_CPosRefire"},
1317 {A_TroopAttack, "A_TroopAttack"},
1318 {A_SargAttack, "A_SargAttack"},
1319 {A_HeadAttack, "A_HeadAttack"},
1320 {A_BruisAttack, "A_BruisAttack"},
1321 {A_SkullAttack, "A_SkullAttack"},
1322 {A_Metal, "A_Metal"},
1323 {A_SpidRefire, "A_SpidRefire"},
1324 {A_BabyMetal, "A_BabyMetal"},
1325 {A_BspiAttack, "A_BspiAttack"},
1326 {A_Hoof, "A_Hoof"},
1327 {A_CyberAttack, "A_CyberAttack"},
1328 {A_PainAttack, "A_PainAttack"},
1329 {A_PainDie, "A_PainDie"},
1330 {A_KeenDie, "A_KeenDie"},
1331 {A_BrainPain, "A_BrainPain"},
1332 {A_BrainScream, "A_BrainScream"},
1333 {A_BrainDie, "A_BrainDie"},
1334 {A_BrainAwake, "A_BrainAwake"},
1335 {A_BrainSpit, "A_BrainSpit"},
1336 {A_SpawnSound, "A_SpawnSound"},
1337 {A_SpawnFly, "A_SpawnFly"},
1338 {A_BrainExplode, "A_BrainExplode"},
1339 {A_Detonate, "A_Detonate"}, // killough 8/9/98
1340 {A_Mushroom, "A_Mushroom"}, // killough 10/98
1341 {A_Die, "A_Die"}, // killough 11/98
1342 {A_Spawn, "A_Spawn"}, // killough 11/98
1343 {A_Turn, "A_Turn"}, // killough 11/98
1344 {A_Face, "A_Face"}, // killough 11/98
1345 {A_Scratch, "A_Scratch"}, // killough 11/98
1346 {A_PlaySound, "A_PlaySound"}, // killough 11/98
1347 {A_RandomJump, "A_RandomJump"}, // killough 11/98
1348 {A_LineEffect, "A_LineEffect"}, // killough 11/98
1349
1350 // This NULL entry must be the last in the list
1351 {NULL, "A_NULL"}, // Ty 05/16/98
1352};
1353
1354// to hold startup code pointers from INFO.C
1355// CPhipps - static
1356static actionf_t deh_codeptr[NUMSTATES];
1357
1358// haleyjd: support for BEX SPRITES, SOUNDS, and MUSIC
1359char *deh_spritenames[NUMSPRITES + 1];
1360char *deh_musicnames[NUMMUSIC + 1];
1361char *deh_soundnames[NUMSFX + 1];
1362
1363void D_BuildBEXTables(void)
1364{
1365 int i;
1366
1367 // moved from ProcessDehFile, then we don't need the static int i
1368 for (i = 0; i < NUMSTATES; i++) // remember what they start as for deh xref
1369 deh_codeptr[i] = states[i].action;
1370
1371 for(i = 0; i < NUMSPRITES; i++)
1372 deh_spritenames[i] = strdup(sprnames[i]);
1373 deh_spritenames[NUMSPRITES] = NULL;
1374
1375 for(i = 1; i < NUMMUSIC; i++)
1376 deh_musicnames[i] = strdup(S_music[i].name);
1377 deh_musicnames[0] = deh_musicnames[NUMMUSIC] = NULL;
1378
1379 for(i = 1; i < NUMSFX; i++)
1380 deh_soundnames[i] = strdup(S_sfx[i].name);
1381 deh_soundnames[0] = deh_soundnames[NUMSFX] = NULL;
1382}
1383
1384// ====================================================================
1385// ProcessDehFile
1386// Purpose: Read and process a DEH or BEX file
1387// Args: filename -- name of the DEH/BEX file
1388// outfilename -- output file (DEHOUT.TXT), appended to here
1389// Returns: void
1390//
1391// killough 10/98:
1392// substantially modified to allow input from wad lumps instead of .deh files.
1393
1394void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum)
1395{
1396 static FILE *fileout; // In case -dehout was used
1397 DEHFILE infile, *filein = &infile; // killough 10/98
1398 char inbuffer[DEH_BUFFERMAX]; // Place to put the primary infostring
1399
1400 // Open output file if we're writing output
1401 if (outfilename && *outfilename && !fileout)
1402 {
1403 static boolean firstfile = true; // to allow append to output log
1404 if (!strcmp(outfilename, "-"))
1405 fileout = stdout;
1406 else
1407 if (!(fileout=fopen(outfilename, firstfile ? "wt" : "at")))
1408 {
1409 lprintf(LO_WARN, "Could not open -dehout file %s\n... using stdout.\n",
1410 outfilename);
1411 fileout = stdout;
1412 }
1413 firstfile = false;
1414 }
1415
1416 // killough 10/98: allow DEH files to come from wad lumps
1417
1418 if (filename)
1419 {
1420 if (!(infile.f = fopen(filename,"rt")))
1421 {
1422 lprintf(LO_WARN, "-deh file %s not found\n",filename);
1423 return; // should be checked up front anyway
1424 }
1425 infile.lump = NULL;
1426 }
1427 else // DEH file comes from lump indicated by third argument
1428 {
1429 infile.size = W_LumpLength(lumpnum);
1430 infile.inp = infile.lump = W_CacheLumpNum(lumpnum);
1431 filename = "(WAD)";
1432 }
1433
1434 lprintf(LO_INFO, "Loading DEH file %s\n",filename);
1435 if (fileout) fprintf(fileout,"\nLoading DEH file %s\n\n",filename);
1436
1437 // move deh_codeptr initialisation to D_BuildBEXTables
1438
1439 // loop until end of file
1440
1441 while (dehfgets(inbuffer,sizeof(inbuffer),filein))
1442 {
1443 unsigned i;
1444
1445 lfstrip(inbuffer);
1446 if (fileout) fprintf(fileout,"Line='%s'\n",inbuffer);
1447 if (!*inbuffer || *inbuffer == '#' || *inbuffer == ' ')
1448 continue; /* Blank line or comment line */
1449
1450 // -- If DEH_BLOCKMAX is set right, the processing is independently
1451 // -- handled based on data in the deh_blocks[] structure array
1452
1453 // killough 10/98: INCLUDE code rewritten to allow arbitrary nesting,
1454 // and to greatly simplify code, fix memory leaks, other bugs
1455
1456 if (!strnicmp(inbuffer,"INCLUDE",7)) // include a file
1457 {
1458 // preserve state while including a file
1459 // killough 10/98: moved to here
1460
1461 char *nextfile;
1462 boolean oldnotext = includenotext; // killough 10/98
1463
1464 // killough 10/98: exclude if inside wads (only to discourage
1465 // the practice, since the code could otherwise handle it)
1466
1467 if (infile.lump)
1468 {
1469 if (fileout)
1470 fprintf(fileout,
1471 "No files may be included from wads: %s\n",inbuffer);
1472 continue;
1473 }
1474
1475 // check for no-text directive, used when including a DEH
1476 // file but using the BEX format to handle strings
1477
1478 if (!strnicmp(nextfile = ptr_lstrip(inbuffer+7),"NOTEXT",6))
1479 includenotext = true, nextfile = ptr_lstrip(nextfile+6);
1480
1481 if (fileout)
1482 fprintf(fileout,"Branching to include file %s...\n", nextfile);
1483
1484 // killough 10/98:
1485 // Second argument must be NULL to prevent closing fileout too soon
1486
1487 ProcessDehFile(nextfile,NULL,0); // do the included file
1488
1489 includenotext = oldnotext;
1490 if (fileout) fprintf(fileout,"...continuing with %s\n",filename);
1491 continue;
1492 }
1493
1494 for (i=0; i<DEH_BLOCKMAX; i++)
1495 if (!strncasecmp(inbuffer,deh_blocks[i].key,strlen(deh_blocks[i].key)))
1496 { // matches one
1497 if (fileout)
1498 fprintf(fileout,"Processing function [%d] for %s\n",
1499 i, deh_blocks[i].key);
1500 deh_blocks[i].fptr(filein,fileout,inbuffer); // call function
1501 break; // we got one, that's enough for this block
1502 }
1503 }
1504
1505 if (infile.lump)
1506 W_UnlockLumpNum(lumpnum); // Mark purgable
1507 else
1508 fclose(infile.f); // Close real file
1509
1510 if (outfilename) // killough 10/98: only at top recursion level
1511 {
1512 if (fileout != stdout)
1513 fclose(fileout);
1514 fileout = NULL;
1515 }
1516}
1517
1518// ====================================================================
1519// deh_procBexCodePointers
1520// Purpose: Handle [CODEPTR] block, BOOM Extension
1521// Args: fpin -- input file stream
1522// fpout -- output file stream (DEHOUT.TXT)
1523// line -- current line in file to process
1524// Returns: void
1525//
1526static void deh_procBexCodePointers(DEHFILE *fpin, FILE* fpout, char *line)
1527{
1528 char key[DEH_MAXKEYLEN];
1529 char inbuffer[DEH_BUFFERMAX];
1530 int indexnum;
1531 char mnemonic[DEH_MAXKEYLEN]; // to hold the codepointer mnemonic
1532 int i; // looper
1533 boolean found; // know if we found this one during lookup or not
1534
1535 // Ty 05/16/98 - initialize it to something, dummy!
1536 strncpy(inbuffer,line,DEH_BUFFERMAX);
1537
1538 // for this one, we just read 'em until we hit a blank line
1539 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1540 {
1541 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1542 lfstrip(inbuffer);
1543 if (!*inbuffer) break; // killough 11/98: really exit on blank line
1544
1545 // killough 8/98: allow hex numbers in input:
1546 if ( (3 != sscanf(inbuffer,"%s %i = %s", key, &indexnum, mnemonic))
1547 || (stricmp(key,"FRAME")) ) // NOTE: different format from normal
1548 {
1549 if (fpout) fprintf(fpout,
1550 "Invalid BEX codepointer line - must start with 'FRAME': '%s'\n",
1551 inbuffer);
1552 return; // early return
1553 }
1554
1555 if (fpout) fprintf(fpout,"Processing pointer at index %d: %s\n",
1556 indexnum, mnemonic);
1557 if (indexnum < 0 || indexnum >= NUMSTATES)
1558 {
1559 if (fpout) fprintf(fpout,"Bad pointer number %d of %d\n",
1560 indexnum, NUMSTATES);
1561 return; // killough 10/98: fix SegViol
1562 }
1563 strcpy(key,"A_"); // reusing the key area to prefix the mnemonic
1564 strcat(key,ptr_lstrip(mnemonic));
1565
1566 found = FALSE;
1567 i= -1; // incremented to start at zero at the top of the loop
1568 do // Ty 05/16/98 - fix loop logic to look for null ending entry
1569 {
1570 ++i;
1571 if (!stricmp(key,deh_bexptrs[i].lookup))
1572 { // Ty 06/01/98 - add to states[].action for new djgcc version
1573 states[indexnum].action = deh_bexptrs[i].cptr; // assign
1574 if (fpout) fprintf(fpout,
1575 " - applied %s from codeptr[%d] to states[%d]\n",
1576 deh_bexptrs[i].lookup,i,indexnum);
1577 found = TRUE;
1578 }
1579 } while (!found && (deh_bexptrs[i].cptr != NULL));
1580
1581 if (!found)
1582 if (fpout) fprintf(fpout,
1583 "Invalid frame pointer mnemonic '%s' at %d\n",
1584 mnemonic, indexnum);
1585 }
1586 return;
1587}
1588
1589//---------------------------------------------------------------------------
1590// To be on the safe, compatible side, we manually convert DEH bitflags
1591// to prboom types - POPE
1592//---------------------------------------------------------------------------
1593static uint_64_t getConvertedDEHBits(uint_64_t bits) {
1594 static const uint_64_t bitMap[32] = {
1595 /* cf linuxdoom-1.10 p_mobj.h */
1596 MF_SPECIAL, // 0 Can be picked up - When touched the thing can be picked up.
1597 MF_SOLID, // 1 Obstacle - The thing is solid and will not let you (or others) pass through it
1598 MF_SHOOTABLE, // 2 Shootable - Can be shot.
1599 MF_NOSECTOR, // 3 Total Invisibility - Invisible, but can be touched
1600 MF_NOBLOCKMAP, // 4 Don't use the blocklinks (inert but displayable)
1601 MF_AMBUSH, // 5 Semi deaf - The thing is a deaf monster
1602 MF_JUSTHIT, // 6 In pain - Will try to attack right back after being hit
1603 MF_JUSTATTACKED, // 7 Steps before attack - Will take at least one step before attacking
1604 MF_SPAWNCEILING, // 8 Hangs from ceiling - When the level starts, this thing will be at ceiling height.
1605 MF_NOGRAVITY, // 9 No gravity - Gravity does not affect this thing
1606 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.
1607 MF_PICKUP, // 11 Pick up items - The thing can pick up gettable items.
1608 MF_NOCLIP, // 12 No clipping - Thing can walk through walls.
1609 MF_SLIDE, // 13 Slides along walls - Keep info about sliding along walls (don't really know much about this one).
1610 MF_FLOAT, // 14 Floating - Thing can move to any height
1611 MF_TELEPORT, // 15 Semi no clipping - Don't cross lines or look at teleport heights. (don't really know much about this one either).
1612 MF_MISSILE, // 16 Projectiles - Behaves like a projectile, explodes when hitting something that blocks movement
1613 MF_DROPPED, // 17 Disappearing weapon - Dropped, not spawned (like an ammo clip) I have not had much success in using this one.
1614 MF_SHADOW, // 18 Partial invisibility - Drawn like a spectre.
1615 MF_NOBLOOD, // 19 Puffs (vs. bleeds) - If hit will spawn bullet puffs instead of blood splats.
1616 MF_CORPSE, // 20 Sliding helpless - Will slide down steps when dead.
1617 MF_INFLOAT, // 21 No auto levelling - float but not to target height (?)
1618 MF_COUNTKILL, // 22 Affects kill % - counted as a killable enemy and affects percentage kills on level summary.
1619 MF_COUNTITEM, // 23 Affects item % - affects percentage items gathered on level summary.
1620 MF_SKULLFLY, // 24 Running - special handling for flying skulls.
1621 MF_NOTDMATCH, // 25 Not in deathmatch - do not spawn in deathmatch (like keys)
1622 MF_TRANSLATION1, // 26 Color 1 (grey / red)
1623 MF_TRANSLATION2, // 27 Color 2 (brown / red)
1624 // Convert bit 28 to MF_TOUCHY, not (MF_TRANSLATION1|MF_TRANSLATION2)
1625 // fixes bug #1576151 (part 1)
1626 MF_TOUCHY, // 28 - explodes on contact (MBF)
1627 MF_BOUNCES, // 29 - bounces off walls and floors (MBF)
1628 MF_FRIEND, // 30 - friendly monster helps players (MBF)
1629 MF_TRANSLUCENT // e6y: Translucency via dehacked/bex doesn't work without it
1630 };
1631 int i;
1632 uint_64_t shiftBits = bits;
1633 uint_64_t convertedBits = 0;
1634 for (i=0; i<32; i++) {
1635 if (shiftBits & 0x1) convertedBits |= bitMap[i];
1636 shiftBits >>= 1;
1637 }
1638 return convertedBits;
1639}
1640
1641//---------------------------------------------------------------------------
1642// See usage below for an explanation of this function's existence - POPE
1643//---------------------------------------------------------------------------
1644static void setMobjInfoValue(int mobjInfoIndex, int keyIndex, uint_64_t value) {
1645 mobjinfo_t *mi;
1646 if (mobjInfoIndex >= NUMMOBJTYPES || mobjInfoIndex < 0) return;
1647 mi = &mobjinfo[mobjInfoIndex];
1648 switch (keyIndex) {
1649 case 0: mi->doomednum = (int)value; return;
1650 case 1: mi->spawnstate = (int)value; return;
1651 case 2: mi->spawnhealth = (int)value; return;
1652 case 3: mi->seestate = (int)value; return;
1653 case 4: mi->seesound = (int)value; return;
1654 case 5: mi->reactiontime = (int)value; return;
1655 case 6: mi->attacksound = (int)value; return;
1656 case 7: mi->painstate = (int)value; return;
1657 case 8: mi->painchance = (int)value; return;
1658 case 9: mi->painsound = (int)value; return;
1659 case 10: mi->meleestate = (int)value; return;
1660 case 11: mi->missilestate = (int)value; return;
1661 case 12: mi->deathstate = (int)value; return;
1662 case 13: mi->xdeathstate = (int)value; return;
1663 case 14: mi->deathsound = (int)value; return;
1664 case 15: mi->speed = (int)value; return;
1665 case 16: mi->radius = (int)value; return;
1666 case 17: mi->height = (int)value; return;
1667 case 18: mi->mass = (int)value; return;
1668 case 19: mi->damage = (int)value; return;
1669 case 20: mi->activesound = (int)value; return;
1670 case 21: mi->flags = value; return;
1671 case 22: return; // "Bits2", unused
1672 case 23: mi->raisestate = (int)value; return;
1673 default: return;
1674 }
1675}
1676
1677// ====================================================================
1678// deh_procThing
1679// Purpose: Handle DEH Thing block
1680// Args: fpin -- input file stream
1681// fpout -- output file stream (DEHOUT.TXT)
1682// line -- current line in file to process
1683// Returns: void
1684//
1685// Ty 8/27/98 - revised to also allow mnemonics for
1686// bit masks for monster attributes
1687//
1688
1689static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line)
1690{
1691 char key[DEH_MAXKEYLEN];
1692 char inbuffer[DEH_BUFFERMAX];
1693 uint_64_t value; // All deh values are ints or longs
1694 int indexnum;
1695 int ix;
1696 char *strval;
1697
1698 strncpy(inbuffer,line,DEH_BUFFERMAX);
1699 if (fpout) fprintf(fpout,"Thing line: '%s'\n",inbuffer);
1700
1701 // killough 8/98: allow hex numbers in input:
1702 ix = sscanf(inbuffer,"%s %i",key, &indexnum);
1703 if (fpout) fprintf(fpout,"count=%d, Thing %d\n",ix, indexnum);
1704
1705 // Note that the mobjinfo[] array is base zero, but object numbers
1706 // in the dehacked file start with one. Grumble.
1707 --indexnum;
1708
1709 // now process the stuff
1710 // Note that for Things we can look up the key and use its offset
1711 // in the array of key strings as an int offset in the structure
1712
1713 // get a line until a blank or end of file--it's not
1714 // blank now because it has our incoming key in it
1715 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1716 {
1717 // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
1718 // No more desync on HACX demos.
1719 int bGetData;
1720
1721 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1722 lfstrip(inbuffer); // toss the end of line
1723
1724 // killough 11/98: really bail out on blank lines (break != continue)
1725 if (!*inbuffer) break; // bail out with blank line between sections
1726
1727 // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
1728 // No more desync on HACX demos.
1729 bGetData = deh_GetData(inbuffer,key,&value,&strval,fpout);
1730 if (!bGetData)
1731 // Old code: if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
1732 {
1733 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1734 continue;
1735 }
1736 for (ix=0; ix<DEH_MOBJINFOMAX; ix++) {
1737 if (strcasecmp(key,deh_mobjinfo[ix])) continue;
1738
1739 if (strcasecmp(key,"bits")) {
1740 // standard value set
1741
1742 // The old code here was the cause of a DEH-related bug in prboom.
1743 // When the mobjinfo_t.flags member was graduated to an int64, this
1744 // code was caught unawares and was indexing each property of the
1745 // mobjinfo as if it were still an int32. This caused sets of the
1746 // "raisestate" member to partially overwrite the "flags" member,
1747 // thus screwing everything up and making most DEH patches result in
1748 // unshootable enemy types. Moved to a separate function above
1749 // and stripped of all hairy struct address indexing. - POPE
1750 setMobjInfoValue(indexnum, ix, value);
1751 }
1752 else {
1753 // bit set
1754 // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
1755 // No more desync on HACX demos.
1756 if (bGetData==1) { // proff
1757 value = getConvertedDEHBits(value);
1758 mobjinfo[indexnum].flags = value;
1759 }
1760 else {
1761 // figure out what the bits are
1762 value = 0;
1763
1764 // killough 10/98: replace '+' kludge with strtok() loop
1765 // Fix error-handling case ('found' var wasn't being reset)
1766 //
1767 // Use OR logic instead of addition, to allow repetition
1768 for (;(strval = strtok(strval,",+| \t\f\r")); strval = NULL) {
1769 size_t iy;
1770 for (iy=0; iy < DEH_MOBJFLAGMAX; iy++) {
1771 if (strcasecmp(strval,deh_mobjflags[iy].name)) continue;
1772 if (fpout) {
1773 fprintf(fpout,
1774 "ORed value 0x%08lX%08lX %s\n",
1775 (unsigned long)(deh_mobjflags[iy].value>>32) & 0xffffffff,
1776 (unsigned long)deh_mobjflags[iy].value & 0xffffffff, strval
1777 );
1778 }
1779 value |= deh_mobjflags[iy].value;
1780 break;
1781 }
1782 if (iy >= DEH_MOBJFLAGMAX && fpout) {
1783 fprintf(fpout, "Could not find bit mnemonic %s\n", strval);
1784 }
1785 }
1786
1787 // Don't worry about conversion -- simply print values
1788 if (fpout) {
1789 fprintf(fpout,
1790 "Bits = 0x%08lX%08lX\n",
1791 (unsigned long)(value>>32) & 0xffffffff,
1792 (unsigned long)value & 0xffffffff
1793 );
1794 }
1795 mobjinfo[indexnum].flags = value; // e6y
1796 }
1797 }
1798 if (fpout) {
1799 fprintf(fpout,
1800 "Assigned 0x%08lx%08lx to %s(%d) at index %d\n",
1801 (unsigned long)(value>>32) & 0xffffffff,
1802 (unsigned long)value & 0xffffffff, key, indexnum, ix
1803 );
1804 }
1805 }
1806 }
1807 return;
1808}
1809
1810// ====================================================================
1811// deh_procFrame
1812// Purpose: Handle DEH Frame block
1813// Args: fpin -- input file stream
1814// fpout -- output file stream (DEHOUT.TXT)
1815// line -- current line in file to process
1816// Returns: void
1817//
1818static void deh_procFrame(DEHFILE *fpin, FILE* fpout, char *line)
1819{
1820 char key[DEH_MAXKEYLEN];
1821 char inbuffer[DEH_BUFFERMAX];
1822 uint_64_t value; // All deh values are ints or longs
1823 int indexnum;
1824
1825 strncpy(inbuffer,line,DEH_BUFFERMAX);
1826
1827 // killough 8/98: allow hex numbers in input:
1828 sscanf(inbuffer,"%s %i",key, &indexnum);
1829 if (fpout) fprintf(fpout,"Processing Frame at index %d: %s\n",indexnum,key);
1830 if (indexnum < 0 || indexnum >= NUMSTATES)
1831 if (fpout) fprintf(fpout,"Bad frame number %d of %d\n",indexnum, NUMSTATES);
1832
1833 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1834 {
1835 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1836 lfstrip(inbuffer);
1837 if (!*inbuffer) break; // killough 11/98
1838 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
1839 {
1840 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1841 continue;
1842 }
1843 if (!strcasecmp(key,deh_state[0])) // Sprite number
1844 {
1845 if (fpout) fprintf(fpout," - sprite = %lld\n",value);
1846 states[indexnum].sprite = (spritenum_t)value;
1847 }
1848 else
1849 if (!strcasecmp(key,deh_state[1])) // Sprite subnumber
1850 {
1851 if (fpout) fprintf(fpout," - frame = %lld\n",value);
1852 states[indexnum].frame = (long)value; // long
1853 }
1854 else
1855 if (!strcasecmp(key,deh_state[2])) // Duration
1856 {
1857 if (fpout) fprintf(fpout," - tics = %lld\n",value);
1858 states[indexnum].tics = (long)value; // long
1859 }
1860 else
1861 if (!strcasecmp(key,deh_state[3])) // Next frame
1862 {
1863 if (fpout) fprintf(fpout," - nextstate = %lld\n",value);
1864 states[indexnum].nextstate = (statenum_t)value;
1865 }
1866 else
1867 if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block)
1868 {
1869 if (fpout) fprintf(fpout," - codep, should not be set in Frame section!\n");
1870 /* nop */ ;
1871 }
1872 else
1873 if (!strcasecmp(key,deh_state[5])) // Unknown 1
1874 {
1875 if (fpout) fprintf(fpout," - misc1 = %lld\n",value);
1876 states[indexnum].misc1 = (long)value; // long
1877 }
1878 else
1879 if (!strcasecmp(key,deh_state[6])) // Unknown 2
1880 {
1881 if (fpout) fprintf(fpout," - misc2 = %lld\n",value);
1882 states[indexnum].misc2 = (long)value; // long
1883 }
1884 else
1885 if (fpout) fprintf(fpout,"Invalid frame string index for '%s'\n",key);
1886 }
1887 return;
1888}
1889
1890// ====================================================================
1891// deh_procPointer
1892// Purpose: Handle DEH Code pointer block, can use BEX [CODEPTR] instead
1893// Args: fpin -- input file stream
1894// fpout -- output file stream (DEHOUT.TXT)
1895// line -- current line in file to process
1896// Returns: void
1897//
1898static void deh_procPointer(DEHFILE *fpin, FILE* fpout, char *line) // done
1899{
1900 char key[DEH_MAXKEYLEN];
1901 char inbuffer[DEH_BUFFERMAX];
1902 uint_64_t value; // All deh values are ints or longs
1903 int indexnum;
1904 int i; // looper
1905
1906 strncpy(inbuffer,line,DEH_BUFFERMAX);
1907 // NOTE: different format from normal
1908
1909 // killough 8/98: allow hex numbers in input, fix error case:
1910 if (sscanf(inbuffer,"%*s %*i (%s %i)",key, &indexnum) != 2)
1911 {
1912 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1913 return;
1914 }
1915
1916 if (fpout) fprintf(fpout,"Processing Pointer at index %d: %s\n",indexnum, key);
1917 if (indexnum < 0 || indexnum >= NUMSTATES)
1918 {
1919 if (fpout)
1920 fprintf(fpout,"Bad pointer number %d of %d\n",indexnum, NUMSTATES);
1921 return;
1922 }
1923
1924 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1925 {
1926 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1927 lfstrip(inbuffer);
1928 if (!*inbuffer) break; // killough 11/98
1929 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
1930 {
1931 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1932 continue;
1933 }
1934
1935 if (value < 0 || value >= NUMSTATES)
1936 {
1937 if (fpout)
1938 fprintf(fpout,"Bad pointer number %lld of %d\n",value, NUMSTATES);
1939 return;
1940 }
1941
1942 if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block)
1943 {
1944 states[indexnum].action = deh_codeptr[value];
1945 if (fpout) fprintf(fpout," - applied from codeptr[%lld] to states[%d]\n",
1946 value,indexnum);
1947 // Write BEX-oriented line to match:
1948 // for (i=0;i<NUMSTATES;i++) could go past the end of the array
1949 for (i=0;i<sizeof(deh_bexptrs)/sizeof(*deh_bexptrs);i++)
1950 {
1951 if (!memcmp(&deh_bexptrs[i].cptr,&deh_codeptr[value],sizeof(actionf_t)))
1952 {
1953 if (fpout) fprintf(fpout,"BEX [CODEPTR] -> FRAME %d = %s\n",
1954 indexnum, &deh_bexptrs[i].lookup[2]);
1955 break;
1956 }
1957 if (deh_bexptrs[i].cptr == NULL) // stop at null entry
1958 break;
1959 }
1960 }
1961 else
1962 if (fpout) fprintf(fpout,"Invalid frame pointer index for '%s' at %lld\n",
1963 key, value);
1964 }
1965 return;
1966}
1967
1968// ====================================================================
1969// deh_procSounds
1970// Purpose: Handle DEH Sounds block
1971// Args: fpin -- input file stream
1972// fpout -- output file stream (DEHOUT.TXT)
1973// line -- current line in file to process
1974// Returns: void
1975//
1976static void deh_procSounds(DEHFILE *fpin, FILE* fpout, char *line)
1977{
1978 char key[DEH_MAXKEYLEN];
1979 char inbuffer[DEH_BUFFERMAX];
1980 uint_64_t value; // All deh values are ints or longs
1981 int indexnum;
1982
1983 strncpy(inbuffer,line,DEH_BUFFERMAX);
1984
1985 // killough 8/98: allow hex numbers in input:
1986 sscanf(inbuffer,"%s %i",key, &indexnum);
1987 if (fpout) fprintf(fpout,"Processing Sounds at index %d: %s\n",
1988 indexnum, key);
1989 if (indexnum < 0 || indexnum >= NUMSFX)
1990 if (fpout) fprintf(fpout,"Bad sound number %d of %d\n",
1991 indexnum, NUMSFX);
1992
1993 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1994 {
1995 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1996 lfstrip(inbuffer);
1997 if (!*inbuffer) break; // killough 11/98
1998 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
1999 {
2000 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2001 continue;
2002 }
2003 if (!strcasecmp(key,deh_sfxinfo[0])) // Offset
2004 /* nop */ ; // we don't know what this is, I don't think
2005 else
2006 if (!strcasecmp(key,deh_sfxinfo[1])) // Zero/One
2007 S_sfx[indexnum].singularity = (int)value;
2008 else
2009 if (!strcasecmp(key,deh_sfxinfo[2])) // Value
2010 S_sfx[indexnum].priority = (int)value;
2011 else
2012 if (!strcasecmp(key,deh_sfxinfo[3])) // Zero 1
2013 S_sfx[indexnum].link = (sfxinfo_t *)value;
2014 else
2015 if (!strcasecmp(key,deh_sfxinfo[4])) // Zero 2
2016 S_sfx[indexnum].pitch = (int)value;
2017 else
2018 if (!strcasecmp(key,deh_sfxinfo[5])) // Zero 3
2019 S_sfx[indexnum].volume = (int)value;
2020 else
2021 if (!strcasecmp(key,deh_sfxinfo[6])) // Zero 4
2022 S_sfx[indexnum].data = (void *) value; // killough 5/3/98: changed cast
2023 else
2024 if (!strcasecmp(key,deh_sfxinfo[7])) // Neg. One 1
2025 S_sfx[indexnum].usefulness = (int)value;
2026 else
2027 if (!strcasecmp(key,deh_sfxinfo[8])) // Neg. One 2
2028 S_sfx[indexnum].lumpnum = (int)value;
2029 else
2030 if (fpout) fprintf(fpout,
2031 "Invalid sound string index for '%s'\n",key);
2032 }
2033 return;
2034}
2035
2036// ====================================================================
2037// deh_procAmmo
2038// Purpose: Handle DEH Ammo block
2039// Args: fpin -- input file stream
2040// fpout -- output file stream (DEHOUT.TXT)
2041// line -- current line in file to process
2042// Returns: void
2043//
2044static void deh_procAmmo(DEHFILE *fpin, FILE* fpout, char *line)
2045{
2046 char key[DEH_MAXKEYLEN];
2047 char inbuffer[DEH_BUFFERMAX];
2048 uint_64_t value; // All deh values are ints or longs
2049 int indexnum;
2050
2051 strncpy(inbuffer,line,DEH_BUFFERMAX);
2052
2053 // killough 8/98: allow hex numbers in input:
2054 sscanf(inbuffer,"%s %i",key, &indexnum);
2055 if (fpout) fprintf(fpout,"Processing Ammo at index %d: %s\n",
2056 indexnum, key);
2057 if (indexnum < 0 || indexnum >= NUMAMMO)
2058 if (fpout) fprintf(fpout,"Bad ammo number %d of %d\n",
2059 indexnum,NUMAMMO);
2060
2061 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2062 {
2063 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2064 lfstrip(inbuffer);
2065 if (!*inbuffer) break; // killough 11/98
2066 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2067 {
2068 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2069 continue;
2070 }
2071 if (!strcasecmp(key,deh_ammo[0])) // Max ammo
2072 maxammo[indexnum] = (int)value;
2073 else
2074 if (!strcasecmp(key,deh_ammo[1])) // Per ammo
2075 clipammo[indexnum] = (int)value;
2076 else
2077 if (fpout) fprintf(fpout,"Invalid ammo string index for '%s'\n",key);
2078 }
2079 return;
2080}
2081
2082// ====================================================================
2083// deh_procWeapon
2084// Purpose: Handle DEH Weapon block
2085// Args: fpin -- input file stream
2086// fpout -- output file stream (DEHOUT.TXT)
2087// line -- current line in file to process
2088// Returns: void
2089//
2090static void deh_procWeapon(DEHFILE *fpin, FILE* fpout, char *line)
2091{
2092 char key[DEH_MAXKEYLEN];
2093 char inbuffer[DEH_BUFFERMAX];
2094 uint_64_t value; // All deh values are ints or longs
2095 int indexnum;
2096
2097 strncpy(inbuffer,line,DEH_BUFFERMAX);
2098
2099 // killough 8/98: allow hex numbers in input:
2100 sscanf(inbuffer,"%s %i",key, &indexnum);
2101 if (fpout) fprintf(fpout,"Processing Weapon at index %d: %s\n",
2102 indexnum, key);
2103 if (indexnum < 0 || indexnum >= NUMWEAPONS)
2104 if (fpout) fprintf(fpout,"Bad weapon number %d of %d\n",
2105 indexnum, NUMAMMO);
2106
2107 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2108 {
2109 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2110 lfstrip(inbuffer);
2111 if (!*inbuffer) break; // killough 11/98
2112 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2113 {
2114 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2115 continue;
2116 }
2117 if (!strcasecmp(key,deh_weapon[0])) // Ammo type
2118 weaponinfo[indexnum].ammo = (ammotype_t)value;
2119 else
2120 if (!strcasecmp(key,deh_weapon[1])) // Deselect frame
2121 weaponinfo[indexnum].upstate = (int)value;
2122 else
2123 if (!strcasecmp(key,deh_weapon[2])) // Select frame
2124 weaponinfo[indexnum].downstate = (int)value;
2125 else
2126 if (!strcasecmp(key,deh_weapon[3])) // Bobbing frame
2127 weaponinfo[indexnum].readystate = (int)value;
2128 else
2129 if (!strcasecmp(key,deh_weapon[4])) // Shooting frame
2130 weaponinfo[indexnum].atkstate = (int)value;
2131 else
2132 if (!strcasecmp(key,deh_weapon[5])) // Firing frame
2133 weaponinfo[indexnum].flashstate = (int)value;
2134 else
2135 if (fpout) fprintf(fpout,"Invalid weapon string index for '%s'\n",key);
2136 }
2137 return;
2138}
2139
2140// ====================================================================
2141// deh_procSprite
2142// Purpose: Dummy - we do not support the DEH Sprite block
2143// Args: fpin -- input file stream
2144// fpout -- output file stream (DEHOUT.TXT)
2145// line -- current line in file to process
2146// Returns: void
2147//
2148static void deh_procSprite(DEHFILE *fpin, FILE* fpout, char *line) // Not supported
2149{
2150 char key[DEH_MAXKEYLEN];
2151 char inbuffer[DEH_BUFFERMAX];
2152 int indexnum;
2153
2154 // Too little is known about what this is supposed to do, and
2155 // there are better ways of handling sprite renaming. Not supported.
2156
2157 strncpy(inbuffer,line,DEH_BUFFERMAX);
2158
2159 // killough 8/98: allow hex numbers in input:
2160 sscanf(inbuffer,"%s %i",key, &indexnum);
2161 if (fpout) fprintf(fpout,
2162 "Ignoring Sprite offset change at index %d: %s\n",indexnum, key);
2163 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2164 {
2165 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2166 lfstrip(inbuffer);
2167 if (!*inbuffer) break; // killough 11/98
2168 // ignore line
2169 if (fpout) fprintf(fpout,"- %s\n",inbuffer);
2170 }
2171 return;
2172}
2173
2174// ====================================================================
2175// deh_procPars
2176// Purpose: Handle BEX extension for PAR times
2177// Args: fpin -- input file stream
2178// fpout -- output file stream (DEHOUT.TXT)
2179// line -- current line in file to process
2180// Returns: void
2181//
2182static void deh_procPars(DEHFILE *fpin, FILE* fpout, char *line) // extension
2183{
2184 char key[DEH_MAXKEYLEN];
2185 char inbuffer[DEH_BUFFERMAX];
2186 int indexnum;
2187 int episode, level, partime, oldpar;
2188
2189 // new item, par times
2190 // usage: After [PARS] Par 0 section identifier, use one or more of these
2191 // lines:
2192 // par 3 5 120
2193 // par 14 230
2194 // The first would make the par for E3M5 be 120 seconds, and the
2195 // second one makes the par for MAP14 be 230 seconds. The number
2196 // of parameters on the line determines which group of par values
2197 // is being changed. Error checking is done based on current fixed
2198 // array sizes of[4][10] and [32]
2199
2200 strncpy(inbuffer,line,DEH_BUFFERMAX);
2201
2202 // killough 8/98: allow hex numbers in input:
2203 sscanf(inbuffer,"%s %i",key, &indexnum);
2204 if (fpout) fprintf(fpout,
2205 "Processing Par value at index %d: %s\n",indexnum, key);
2206 // indexnum is a dummy entry
2207 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2208 {
2209 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2210 lfstrip(strlwr(inbuffer)); // lowercase it
2211 if (!*inbuffer) break; // killough 11/98
2212 if (3 != sscanf(inbuffer,"par %i %i %i",&episode, &level, &partime))
2213 { // not 3
2214 if (2 != sscanf(inbuffer,"par %i %i",&level, &partime))
2215 { // not 2
2216 if (fpout) fprintf(fpout,"Invalid par time setting string: %s\n",inbuffer);
2217 }
2218 else
2219 { // is 2
2220 // Ty 07/11/98 - wrong range check, not zero-based
2221 if (level < 1 || level > 32) // base 0 array (but 1-based parm)
2222 {
2223 if (fpout) fprintf(fpout,"Invalid MAPnn value MAP%d\n",level);
2224 }
2225 else
2226 {
2227 oldpar = cpars[level-1];
2228 if (fpout) fprintf(fpout,"Changed par time for MAP%02d from %d to %d\n",level,oldpar,partime);
2229 cpars[level-1] = partime;
2230 deh_pars = TRUE;
2231 }
2232 }
2233 }
2234 else
2235 { // is 3
2236 // note that though it's a [4][10] array, the "left" and "top" aren't used,
2237 // effectively making it a base 1 array.
2238 // Ty 07/11/98 - level was being checked against max 3 - dumb error
2239 // Note that episode 4 does not have par times per original design
2240 // in Ultimate DOOM so that is not supported here.
2241 if (episode < 1 || episode > 3 || level < 1 || level > 9)
2242 {
2243 if (fpout) fprintf(fpout,
2244 "Invalid ExMx values E%dM%d\n",episode, level);
2245 }
2246 else
2247 {
2248 oldpar = pars[episode][level];
2249 pars[episode][level] = partime;
2250 if (fpout) fprintf(fpout,
2251 "Changed par time for E%dM%d from %d to %d\n",
2252 episode,level,oldpar,partime);
2253 deh_pars = TRUE;
2254 }
2255 }
2256 }
2257 return;
2258}
2259
2260// ====================================================================
2261// deh_procCheat
2262// Purpose: Handle DEH Cheat block
2263// Args: fpin -- input file stream
2264// fpout -- output file stream (DEHOUT.TXT)
2265// line -- current line in file to process
2266// Returns: void
2267//
2268static void deh_procCheat(DEHFILE *fpin, FILE* fpout, char *line) // done
2269{
2270 char key[DEH_MAXKEYLEN];
2271 char inbuffer[DEH_BUFFERMAX];
2272 uint_64_t value; // All deh values are ints or longs
2273 char ch = 0; // CPhipps - `writable' null string to initialise...
2274 char *strval = &ch; // pointer to the value area
2275 int ix, iy; // array indices
2276 char *p; // utility pointer
2277
2278 if (fpout) fprintf(fpout,"Processing Cheat: %s\n",line);
2279
2280 strncpy(inbuffer,line,DEH_BUFFERMAX);
2281 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2282 {
2283 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2284 lfstrip(inbuffer);
2285 if (!*inbuffer) break; // killough 11/98
2286 if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2287 {
2288 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2289 continue;
2290 }
2291 // Otherwise we got a (perhaps valid) cheat name,
2292 // so look up the key in the array
2293
2294 // killough 4/18/98: use main cheat code table in st_stuff.c now
2295 for (ix=0; cheat[ix].cheat; ix++)
2296 if (cheat[ix].deh_cheat) // killough 4/18/98: skip non-deh
2297 {
2298 if (!stricmp(key,cheat[ix].deh_cheat)) // found the cheat, ignored case
2299 {
2300 // replace it but don't overflow it. Use current length as limit.
2301 // Ty 03/13/98 - add 0xff code
2302 // Deal with the fact that the cheats in deh files are extended
2303 // with character 0xFF to the original cheat length, which we don't do.
2304 for (iy=0; strval[iy]; iy++)
2305 strval[iy] = (strval[iy]==(char)0xff) ? '\0' : strval[iy];
2306
2307 iy = ix; // killough 4/18/98
2308
2309 // Ty 03/14/98 - skip leading spaces
2310 p = strval;
2311 while (*p == ' ') ++p;
2312 // Ty 03/16/98 - change to use a strdup and orphan the original
2313 // Also has the advantage of allowing length changes.
2314 // strncpy(cheat[iy].cheat,p,strlen(cheat[iy].cheat));
2315#if 0
2316 { // killough 9/12/98: disable cheats which are prefixes of this one
2317 int i;
2318 for (i=0; cheat[i].cheat; i++)
2319 if (cheat[i].when & not_deh &&
2320 !strncasecmp(cheat[i].cheat,
2321 cheat[iy].cheat,
2322 strlen(cheat[i].cheat)) && i != iy)
2323 cheat[i].deh_modified = true;
2324 }
2325#endif
2326 cheat[iy].cheat = strdup(p);
2327 if (fpout) fprintf(fpout,
2328 "Assigned new cheat '%s' to cheat '%s'at index %d\n",
2329 p, cheat[ix].deh_cheat, iy); // killough 4/18/98
2330 }
2331 }
2332 if (fpout) fprintf(fpout,"- %s\n",inbuffer);
2333 }
2334 return;
2335}
2336
2337// ====================================================================
2338// deh_procMisc
2339// Purpose: Handle DEH Misc block
2340// Args: fpin -- input file stream
2341// fpout -- output file stream (DEHOUT.TXT)
2342// line -- current line in file to process
2343// Returns: void
2344//
2345static void deh_procMisc(DEHFILE *fpin, FILE* fpout, char *line) // done
2346{
2347 char key[DEH_MAXKEYLEN];
2348 char inbuffer[DEH_BUFFERMAX];
2349 uint_64_t value; // All deh values are ints or longs
2350
2351 strncpy(inbuffer,line,DEH_BUFFERMAX);
2352 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2353 {
2354 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2355 lfstrip(inbuffer);
2356 if (!*inbuffer) break; // killough 11/98
2357 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2358 {
2359 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2360 continue;
2361 }
2362 // Otherwise it's ok
2363 if (fpout) fprintf(fpout,"Processing Misc item '%s'\n", key);
2364
2365 if (!strcasecmp(key,deh_misc[0])) // Initial Health
2366 initial_health = (int)value;
2367 else
2368 if (!strcasecmp(key,deh_misc[1])) // Initial Bullets
2369 initial_bullets = (int)value;
2370 else
2371 if (!strcasecmp(key,deh_misc[2])) // Max Health
2372 maxhealth = (int)value;
2373 else
2374 if (!strcasecmp(key,deh_misc[3])) // Max Armor
2375 max_armor = (int)value;
2376 else
2377 if (!strcasecmp(key,deh_misc[4])) // Green Armor Class
2378 green_armor_class = (int)value;
2379 else
2380 if (!strcasecmp(key,deh_misc[5])) // Blue Armor Class
2381 blue_armor_class = (int)value;
2382 else
2383 if (!strcasecmp(key,deh_misc[6])) // Max Soulsphere
2384 max_soul = (int)value;
2385 else
2386 if (!strcasecmp(key,deh_misc[7])) // Soulsphere Health
2387 soul_health = (int)value;
2388 else
2389 if (!strcasecmp(key,deh_misc[8])) // Megasphere Health
2390 mega_health = (int)value;
2391 else
2392 if (!strcasecmp(key,deh_misc[9])) // God Mode Health
2393 god_health = (int)value;
2394 else
2395 if (!strcasecmp(key,deh_misc[10])) // IDFA Armor
2396 idfa_armor = (int)value;
2397 else
2398 if (!strcasecmp(key,deh_misc[11])) // IDFA Armor Class
2399 idfa_armor_class = (int)value;
2400 else
2401 if (!strcasecmp(key,deh_misc[12])) // IDKFA Armor
2402 idkfa_armor = (int)value;
2403 else
2404 if (!strcasecmp(key,deh_misc[13])) // IDKFA Armor Class
2405 idkfa_armor_class = (int)value;
2406 else
2407 if (!strcasecmp(key,deh_misc[14])) // BFG Cells/Shot
2408 bfgcells = (int)value;
2409 else
2410 if (!strcasecmp(key,deh_misc[15])) { // Monsters Infight
2411 // e6y: Dehacked support - monsters infight
2412 if (value == 202) monsters_infight = 0;
2413 else if (value == 221) monsters_infight = 1;
2414 else if (fpout) fprintf(fpout,
2415 "Invalid value for 'Monsters Infight': %i", (int)value);
2416
2417 /* No such switch in DOOM - nop */ //e6y ;
2418 } else
2419 if (fpout) fprintf(fpout,
2420 "Invalid misc item string index for '%s'\n",key);
2421 }
2422 return;
2423}
2424
2425// ====================================================================
2426// deh_procText
2427// Purpose: Handle DEH Text block
2428// Notes: We look things up in the current information and if found
2429// we replace it. At the same time we write the new and
2430// improved BEX syntax to the log file for future use.
2431// Args: fpin -- input file stream
2432// fpout -- output file stream (DEHOUT.TXT)
2433// line -- current line in file to process
2434// Returns: void
2435//
2436static void deh_procText(DEHFILE *fpin, FILE* fpout, char *line)
2437{
2438 char key[DEH_MAXKEYLEN];
2439 char inbuffer[DEH_BUFFERMAX*2]; // can't use line -- double size buffer too.
2440 int i; // loop variable
2441 int fromlen, tolen; // as specified on the text block line
2442 int usedlen; // shorter of fromlen and tolen if not matched
2443 boolean found = FALSE; // to allow early exit once found
2444 char* line2 = NULL; // duplicate line for rerouting
2445
2446 // Ty 04/11/98 - Included file may have NOTEXT skip flag set
2447 if (includenotext) // flag to skip included deh-style text
2448 {
2449 if (fpout) fprintf(fpout,
2450 "Skipped text block because of notext directive\n");
2451 strcpy(inbuffer,line);
2452 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2453 dehfgets(inbuffer, sizeof(inbuffer), fpin); // skip block
2454 // Ty 05/17/98 - don't care if this fails
2455 return; // ************** Early return
2456 }
2457
2458 // killough 8/98: allow hex numbers in input:
2459 sscanf(line,"%s %i %i",key,&fromlen,&tolen);
2460 if (fpout) fprintf(fpout,
2461 "Processing Text (key=%s, from=%d, to=%d)\n",
2462 key, fromlen, tolen);
2463
2464 // killough 10/98: fix incorrect usage of feof
2465 {
2466 int c, totlen = 0;
2467 while (totlen < fromlen + tolen && (c = dehfgetc(fpin)) != EOF)
2468 if (c != '\r')
2469 inbuffer[totlen++] = c;
2470 inbuffer[totlen]='\0';
2471 }
2472
2473 // if the from and to are 4, this may be a sprite rename. Check it
2474 // against the array and process it as such if it matches. Remember
2475 // that the original names are (and should remain) uppercase.
2476 // Future: this will be from a separate [SPRITES] block.
2477 if (fromlen==4 && tolen==4)
2478 {
2479 i=0;
2480 while (sprnames[i]) // null terminated list in info.c //jff 3/19/98
2481 { //check pointer
2482 if (!strnicmp(sprnames[i],inbuffer,fromlen)) //not first char
2483 {
2484 if (fpout) fprintf(fpout,
2485 "Changing name of sprite at index %d from %s to %*s\n",
2486 i,sprnames[i],tolen,&inbuffer[fromlen]);
2487 // Ty 03/18/98 - not using strdup because length is fixed
2488
2489 // killough 10/98: but it's an array of pointers, so we must
2490 // use strdup unless we redeclare sprnames and change all else
2491 {
2492 // CPhipps - fix constness problem
2493 char *s;
2494 sprnames[i] = s = strdup(sprnames[i]);
2495
2496 strncpy(s,&inbuffer[fromlen],tolen);
2497 }
2498 found = TRUE;
2499 break; // only one will match--quit early
2500 }
2501 ++i; // next array element
2502 }
2503 }
2504 else
2505 if (fromlen < 7 && tolen < 7) // lengths of music and sfx are 6 or shorter
2506 {
2507 usedlen = (fromlen < tolen) ? fromlen : tolen;
2508 if (fromlen != tolen)
2509 if (fpout) fprintf(fpout,
2510 "Warning: Mismatched lengths from=%d, to=%d, used %d\n",
2511 fromlen, tolen, usedlen);
2512 // Try sound effects entries - see sounds.c
2513 for (i=1; i<NUMSFX; i++)
2514 {
2515 // avoid short prefix erroneous match
2516 if (strlen(S_sfx[i].name) != (size_t)fromlen) continue;
2517 if (!strnicmp(S_sfx[i].name,inbuffer,fromlen))
2518 {
2519 if (fpout) fprintf(fpout,
2520 "Changing name of sfx from %s to %*s\n",
2521 S_sfx[i].name,usedlen,&inbuffer[fromlen]);
2522
2523 S_sfx[i].name = strdup(&inbuffer[fromlen]);
2524 found = TRUE;
2525 break; // only one matches, quit early
2526 }
2527 }
2528 if (!found) // not yet
2529 {
2530 // Try music name entries - see sounds.c
2531 for (i=1; i<NUMMUSIC; i++)
2532 {
2533 // avoid short prefix erroneous match
2534 if (strlen(S_music[i].name) != (size_t)fromlen) continue;
2535 if (!strnicmp(S_music[i].name,inbuffer,fromlen))
2536 {
2537 if (fpout) fprintf(fpout,
2538 "Changing name of music from %s to %*s\n",
2539 S_music[i].name,usedlen,&inbuffer[fromlen]);
2540
2541 S_music[i].name = strdup(&inbuffer[fromlen]);
2542 found = TRUE;
2543 break; // only one matches, quit early
2544 }
2545 }
2546 } // end !found test
2547 }
2548
2549 if (!found) // Nothing we want to handle here--see if strings can deal with it.
2550 {
2551 if (fpout) fprintf(fpout,"Checking text area through strings for '%.12s%s' from=%d to=%d\n",inbuffer, (strlen(inbuffer) > 12) ? "..." : "",fromlen,tolen);
2552 if ((size_t)fromlen <= strlen(inbuffer))
2553 {
2554 line2 = strdup(&inbuffer[fromlen]);
2555 inbuffer[fromlen] = '\0';
2556 }
2557
2558 deh_procStringSub(NULL, inbuffer, line2, fpout);
2559 }
2560 free(line2); // may be NULL, ignored by free()
2561 return;
2562}
2563
2564static void deh_procError(DEHFILE *fpin, FILE* fpout, char *line)
2565{
2566 char inbuffer[DEH_BUFFERMAX];
2567
2568 strncpy(inbuffer,line,DEH_BUFFERMAX);
2569 if (fpout) fprintf(fpout,"Unmatched Block: '%s'\n",inbuffer);
2570 return;
2571}
2572
2573// ====================================================================
2574// deh_procStrings
2575// Purpose: Handle BEX [STRINGS] extension
2576// Args: fpin -- input file stream
2577// fpout -- output file stream (DEHOUT.TXT)
2578// line -- current line in file to process
2579// Returns: void
2580//
2581static void deh_procStrings(DEHFILE *fpin, FILE* fpout, char *line)
2582{
2583 char key[DEH_MAXKEYLEN];
2584 char inbuffer[DEH_BUFFERMAX];
2585 uint_64_t value; // All deh values are ints or longs
2586 char *strval; // holds the string value of the line
2587 static int maxstrlen = 128; // maximum string length, bumped 128 at
2588 // a time as needed
2589 // holds the final result of the string after concatenation
2590 static char *holdstring = NULL;
2591 boolean found = false; // looking for string continuation
2592
2593 if (fpout) fprintf(fpout,"Processing extended string substitution\n");
2594
2595 if (!holdstring) holdstring = malloc(maxstrlen*sizeof(*holdstring));
2596
2597 *holdstring = '\0'; // empty string to start with
2598 strncpy(inbuffer,line,DEH_BUFFERMAX);
2599 // Ty 04/24/98 - have to allow inbuffer to start with a blank for
2600 // the continuations of C1TEXT etc.
2601 while (!dehfeof(fpin) && *inbuffer) /* && (*inbuffer != ' ') */
2602 {
2603 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2604 if (*inbuffer == '#') continue; // skip comment lines
2605 lfstrip(inbuffer);
2606 if (!*inbuffer) break; // killough 11/98
2607 if (!*holdstring) // first one--get the key
2608 {
2609 if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2610 {
2611 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2612 continue;
2613 }
2614 }
2615 while (strlen(holdstring) + strlen(inbuffer) > (size_t)maxstrlen) // Ty03/29/98 - fix stupid error
2616 {
2617 // killough 11/98: allocate enough the first time
2618 maxstrlen += strlen(holdstring) + strlen(inbuffer) - maxstrlen;
2619 if (fpout) fprintf(fpout,
2620 "* increased buffer from to %d for buffer size %d\n",
2621 maxstrlen,(int)strlen(inbuffer));
2622 holdstring = realloc(holdstring,maxstrlen*sizeof(*holdstring));
2623 }
2624 // concatenate the whole buffer if continuation or the value iffirst
2625 strcat(holdstring,ptr_lstrip(((*holdstring) ? inbuffer : strval)));
2626 rstrip(holdstring);
2627 // delete any trailing blanks past the backslash
2628 // note that blanks before the backslash will be concatenated
2629 // but ones at the beginning of the next line will not, allowing
2630 // indentation in the file to read well without affecting the
2631 // string itself.
2632 if (holdstring[strlen(holdstring)-1] == '\\')
2633 {
2634 holdstring[strlen(holdstring)-1] = '\0';
2635 continue; // ready to concatenate
2636 }
2637 if (*holdstring) // didn't have a backslash, trap above would catch that
2638 {
2639 // go process the current string
2640 found = deh_procStringSub(key, NULL, holdstring, fpout); // supply keyand not search string
2641
2642 if (!found)
2643 if (fpout) fprintf(fpout,
2644 "Invalid string key '%s', substitution skipped.\n",key);
2645
2646 *holdstring = '\0'; // empty string for the next one
2647 }
2648 }
2649 return;
2650}
2651
2652// ====================================================================
2653// deh_procStringSub
2654// Purpose: Common string parsing and handling routine for DEH and BEX
2655// Args: key -- place to put the mnemonic for the string if found
2656// lookfor -- original value string to look for
2657// newstring -- string to put in its place if found
2658// fpout -- file stream pointer for log file (DEHOUT.TXT)
2659// Returns: boolean: True if string found, false if not
2660//
2661boolean deh_procStringSub(char *key, char *lookfor, char *newstring, FILE *fpout)
2662{
2663 boolean found; // loop exit flag
2664 int i; // looper
2665
2666 found = false;
2667 for (i=0;i<deh_numstrlookup;i++)
2668 {
2669 found = lookfor ?
2670 !stricmp(*deh_strlookup[i].ppstr,lookfor) :
2671 !stricmp(deh_strlookup[i].lookup,key);
2672
2673 if (found)
2674 {
2675 char *t;
2676 *deh_strlookup[i].ppstr = t = strdup(newstring); // orphan originalstring
2677 found = true;
2678 // Handle embedded \n's in the incoming string, convert to 0x0a's
2679 {
2680 const char *s;
2681 for (s=*deh_strlookup[i].ppstr; *s; ++s, ++t)
2682 {
2683 if (*s == '\\' && (s[1] == 'n' || s[1] == 'N')) //found one
2684 ++s, *t = '\n'; // skip one extra for second character
2685 else
2686 *t = *s;
2687 }
2688 *t = '\0'; // cap off the target string
2689 }
2690
2691 if (key)
2692 if (fpout) fprintf(fpout,
2693 "Assigned key %s => '%s'\n",key,newstring);
2694
2695 if (!key)
2696 if (fpout) fprintf(fpout,
2697 "Assigned '%.12s%s' to'%.12s%s' at key %s\n",
2698 lookfor, (strlen(lookfor) > 12) ? "..." : "",
2699 newstring, (strlen(newstring) > 12) ? "..." :"",
2700 deh_strlookup[i].lookup);
2701
2702 if (!key) // must have passed an old style string so showBEX
2703 if (fpout) fprintf(fpout,
2704 "*BEX FORMAT:\n%s = %s\n*END BEX\n",
2705 deh_strlookup[i].lookup,
2706 dehReformatStr(newstring));
2707
2708 break;
2709 }
2710 }
2711 if (!found)
2712 if (fpout) fprintf(fpout,
2713 "Could not find '%.12s'\n",key ? key: lookfor);
2714
2715 return found;
2716}
2717
2718//========================================================================
2719// haleyjd 9/22/99
2720//
2721// deh_procHelperThing
2722//
2723// Allows handy substitution of any thing for helper dogs. DEH patches
2724// are being made frequently for this purpose and it requires a complete
2725// rewiring of the DOG thing. I feel this is a waste of effort, and so
2726// have added this new [HELPER] BEX block
2727
2728static void deh_procHelperThing(DEHFILE *fpin, FILE *fpout, char *line)
2729{
2730 char key[DEH_MAXKEYLEN];
2731 char inbuffer[DEH_BUFFERMAX];
2732 uint_64_t value; // All deh values are ints or longs
2733
2734 strncpy(inbuffer,line,DEH_BUFFERMAX);
2735 while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2736 {
2737 if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2738 lfstrip(inbuffer);
2739 if (!*inbuffer) break;
2740 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2741 {
2742 if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2743 continue;
2744 }
2745 // Otherwise it's ok
2746 if (fpout)
2747 {
2748 fprintf(fpout,"Processing Helper Thing item '%s'\n", key);
2749 fprintf(fpout,"value is %i", (int)value);
2750 }
2751 if (!strncasecmp(key, "type", 4))
2752 HelperThing = (int)value;
2753 }
2754 return;
2755}
2756
2757//
2758// deh_procBexSprites
2759//
2760// Supports sprite name substitutions without requiring use
2761// of the DeHackEd Text block
2762//
2763static void deh_procBexSprites(DEHFILE *fpin, FILE *fpout, char *line)
2764{
2765 char key[DEH_MAXKEYLEN];
2766 char inbuffer[DEH_BUFFERMAX];
2767 uint_64_t value; // All deh values are ints or longs
2768 char *strval; // holds the string value of the line
2769 char candidate[5];
2770 int rover;
2771
2772 if(fpout)
2773 fprintf(fpout,"Processing sprite name substitution\n");
2774
2775 strncpy(inbuffer,line,DEH_BUFFERMAX);
2776
2777 while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2778 {
2779 if(!dehfgets(inbuffer, sizeof(inbuffer), fpin))
2780 break;
2781 if(*inbuffer == '#')
2782 continue; // skip comment lines
2783 lfstrip(inbuffer);
2784 if(!*inbuffer)
2785 break; // killough 11/98
2786 if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2787 {
2788 if(fpout)
2789 fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2790 continue;
2791 }
2792 // do it
2793 memset(candidate, 0, sizeof(candidate));
2794 strncpy(candidate, ptr_lstrip(strval), 4);
2795 if(strlen(candidate) != 4)
2796 {
2797 if(fpout)
2798 fprintf(fpout, "Bad length for sprite name '%s'\n",
2799 candidate);
2800 continue;
2801 }
2802
2803 rover = 0;
2804 while(deh_spritenames[rover])
2805 {
2806 if(!strncasecmp(deh_spritenames[rover], key, 4))
2807 {
2808 if(fpout)
2809 fprintf(fpout, "Substituting '%s' for sprite '%s'\n",
2810 candidate, deh_spritenames[rover]);
2811
2812 sprnames[rover] = strdup(candidate);
2813 break;
2814 }
2815 rover++;
2816 }
2817 }
2818}
2819
2820// ditto for sound names
2821static void deh_procBexSounds(DEHFILE *fpin, FILE *fpout, char *line)
2822{
2823 char key[DEH_MAXKEYLEN];
2824 char inbuffer[DEH_BUFFERMAX];
2825 uint_64_t value; // All deh values are ints or longs
2826 char *strval; // holds the string value of the line
2827 char candidate[7];
2828 int rover, len;
2829
2830 if(fpout)
2831 fprintf(fpout,"Processing sound name substitution\n");
2832
2833 strncpy(inbuffer,line,DEH_BUFFERMAX);
2834
2835 while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2836 {
2837 if(!dehfgets(inbuffer, sizeof(inbuffer), fpin))
2838 break;
2839 if(*inbuffer == '#')
2840 continue; // skip comment lines
2841 lfstrip(inbuffer);
2842 if(!*inbuffer)
2843 break; // killough 11/98
2844 if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2845 {
2846 if(fpout)
2847 fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2848 continue;
2849 }
2850 // do it
2851 memset(candidate, 0, 7);
2852 strncpy(candidate, ptr_lstrip(strval), 6);
2853 len = strlen(candidate);
2854 if(len < 1 || len > 6)
2855 {
2856 if(fpout)
2857 fprintf(fpout, "Bad length for sound name '%s'\n",
2858 candidate);
2859 continue;
2860 }
2861
2862 rover = 1;
2863 while(deh_soundnames[rover])
2864 {
2865 if(!strncasecmp(deh_soundnames[rover], key, 6))
2866 {
2867 if(fpout)
2868 fprintf(fpout, "Substituting '%s' for sound '%s'\n",
2869 candidate, deh_soundnames[rover]);
2870
2871 S_sfx[rover].name = strdup(candidate);
2872 break;
2873 }
2874 rover++;
2875 }
2876 }
2877}
2878
2879// ditto for music names
2880static void deh_procBexMusic(DEHFILE *fpin, FILE *fpout, char *line)
2881{
2882 char key[DEH_MAXKEYLEN];
2883 char inbuffer[DEH_BUFFERMAX];
2884 uint_64_t value; // All deh values are ints or longs
2885 char *strval; // holds the string value of the line
2886 char candidate[7];
2887 int rover, len;
2888
2889 if(fpout)
2890 fprintf(fpout,"Processing music name substitution\n");
2891
2892 strncpy(inbuffer,line,DEH_BUFFERMAX);
2893
2894 while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2895 {
2896 if(!dehfgets(inbuffer, sizeof(inbuffer), fpin))
2897 break;
2898 if(*inbuffer == '#')
2899 continue; // skip comment lines
2900 lfstrip(inbuffer);
2901 if(!*inbuffer)
2902 break; // killough 11/98
2903 if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2904 {
2905 if(fpout)
2906 fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2907 continue;
2908 }
2909 // do it
2910 memset(candidate, 0, 7);
2911 strncpy(candidate, ptr_lstrip(strval), 6);
2912 len = strlen(candidate);
2913 if(len < 1 || len > 6)
2914 {
2915 if(fpout)
2916 fprintf(fpout, "Bad length for music name '%s'\n",
2917 candidate);
2918 continue;
2919 }
2920
2921 rover = 1;
2922 while(deh_musicnames[rover])
2923 {
2924 if(!strncasecmp(deh_musicnames[rover], key, 6))
2925 {
2926 if(fpout)
2927 fprintf(fpout, "Substituting '%s' for music '%s'\n",
2928 candidate, deh_musicnames[rover]);
2929
2930 S_music[rover].name = strdup(candidate);
2931 break;
2932 }
2933 rover++;
2934 }
2935 }
2936}
2937
2938// ====================================================================
2939// General utility function(s)
2940// ====================================================================
2941
2942// ====================================================================
2943// dehReformatStr
2944// Purpose: Convert a string into a continuous string with embedded
2945// linefeeds for "\n" sequences in the source string
2946// Args: string -- the string to convert
2947// Returns: the converted string (converted in a static buffer)
2948//
2949char *dehReformatStr(char *string)
2950{
2951 static char buff[DEH_BUFFERMAX]; // only processing the changed string,
2952 // don't need double buffer
2953 char *s, *t;
2954
2955 s = string; // source
2956 t = buff; // target
2957 // let's play...
2958
2959 while (*s)
2960 {
2961 if (*s == '\n')
2962 ++s, *t++ = '\\', *t++ = 'n', *t++ = '\\', *t++='\n';
2963 else
2964 *t++ = *s++;
2965 }
2966 *t = '\0';
2967 return buff;
2968}
2969
2970// ====================================================================
2971// lfstrip
2972// Purpose: Strips CR/LF off the end of a string
2973// Args: s -- the string to work on
2974// Returns: void -- the string is modified in place
2975//
2976// killough 10/98: only strip at end of line, not entire string
2977
2978void lfstrip(char *s) // strip the \r and/or \n off of a line
2979{
2980 char *p = s+strlen(s);
2981 while (p > s && (*--p=='\r' || *p=='\n'))
2982 *p = 0;
2983}
2984
2985// ====================================================================
2986// rstrip
2987// Purpose: Strips trailing blanks off a string
2988// Args: s -- the string to work on
2989// Returns: void -- the string is modified in place
2990//
2991void rstrip(char *s) // strip trailing whitespace
2992{
2993 char *p = s+strlen(s); // killough 4/4/98: same here
2994 while (p > s && isspace(*--p)) // break on first non-whitespace
2995 *p='\0';
2996}
2997
2998// ====================================================================
2999// ptr_lstrip
3000// Purpose: Points past leading whitespace in a string
3001// Args: s -- the string to work on
3002// Returns: char * pointing to the first nonblank character in the
3003// string. The original string is not changed.
3004//
3005char *ptr_lstrip(char *p) // point past leading whitespace
3006{
3007 while (isspace(*p))
3008 p++;
3009 return p;
3010}
3011
3012// e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
3013// No more desync on HACX demos.
3014// FIXME!!! (lame)
3015static boolean StrToInt(char *s, long *l)
3016{
3017 return (
3018 (sscanf(s, " 0x%lx", l) == 1) ||
3019 (sscanf(s, " 0X%lx", l) == 1) ||
3020 (sscanf(s, " 0%lo", l) == 1) ||
3021 (sscanf(s, " %ld", l) == 1)
3022 );
3023}
3024
3025// ====================================================================
3026// deh_GetData
3027// Purpose: Get a key and data pair from a passed string
3028// Args: s -- the string to be examined
3029// k -- a place to put the key
3030// l -- pointer to a long integer to store the number
3031// strval -- a pointer to the place in s where the number
3032// value comes from. Pass NULL to not use this.
3033// fpout -- stream pointer to output log (DEHOUT.TXT)
3034// Notes: Expects a key phrase, optional space, equal sign,
3035// optional space and a value, mostly an int but treated
3036// as a long just in case. The passed pointer to hold
3037// the key must be DEH_MAXKEYLEN in size.
3038
3039boolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, FILE *fpout)
3040{
3041 char *t; // current char
3042 long val; // to hold value of pair
3043 char buffer[DEH_MAXKEYLEN]; // to hold key in progress
3044 // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
3045 // No more desync on HACX demos.
3046 boolean okrc = 1; // assume good unless we have problems
3047 int i; // iterator
3048
3049 *buffer = '\0';
3050 val = 0; // defaults in case not otherwise set
3051 for (i=0, t=s; *t && i < DEH_MAXKEYLEN; t++, i++)
3052 {
3053 if (*t == '=') break;
3054 buffer[i] = *t; // copy it
3055 }
3056 buffer[--i] = '\0'; // terminate the key before the '='
3057 if (!*t) // end of string with no equal sign
3058 {
3059 okrc = FALSE;
3060 }
3061 else
3062 {
3063 if (!*++t)
3064 {
3065 val = 0; // in case "thiskey =" with no value
3066 okrc = FALSE;
3067 }
3068 // we've incremented t
3069 // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
3070 // No more desync on HACX demos.
3071 // Old code: e6y val = strtol(t,NULL,0); // killough 8/9/98: allow hex or octal input
3072 if (!StrToInt(t,&val))
3073 {
3074 val = 0;
3075 okrc = 2;
3076 }
3077 }
3078
3079 // go put the results in the passed pointers
3080 *l = val; // may be a faked zero
3081
3082 // if spaces between key and equal sign, strip them
3083 strcpy(k,ptr_lstrip(buffer)); // could be a zero-length string
3084
3085 if (strval != NULL) // pass NULL if you don't want this back
3086 *strval = t; // pointer, has to be somewhere in s,
3087 // even if pointing at the zero byte.
3088
3089 return(okrc);
3090}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2006 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Dehacked file support
31 * New for the TeamTNT "Boom" engine
32 *
33 * Author: Ty Halderman, TeamTNT
34 *
35 * Description: This file translates the #defined string constants
36 * to named variables to externalize them for deh/bex changes.
37 * Should be able to compile with D_FRENCH (for example) and still
38 * work (untested).
39 *
40 */
41
42#ifndef __D_DEH__
43#define __D_DEH__
44
45void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum);
46
47//
48// Ty 03/22/98 - note that we are keeping the english versions and
49// comments in this file
50// New string names all start with an extra s_ to avoid conflicts,
51// but are otherwise identical to the original including uppercase.
52// This is partly to keep the changes simple and partly for easier
53// identification of the locations in which they're used.
54//
55// Printed strings for translation
56//
57
58//
59// D_Main.C
60//
61//#define D_DEVSTR "Development mode ON.\n"
62extern const char *s_D_DEVSTR; // = D_DEVSTR;
63//#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n"
64extern const char *s_D_CDROM; // = D_CDROM;
65
66//
67// M_Menu.C
68//
69//#define PRESSKEY "press a key."
70extern const char *s_PRESSKEY; // = PRESSKEY;
71//#define PRESSYN "press y or n."
72extern const char *s_PRESSYN; // = PRESSYN;
73//#define QUITMSG "are you sure you want to\nquit this great game?"
74extern const char *s_QUITMSG; // = QUITMSG;
75//#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY
76extern const char *s_LOADNET; // = LOADNET;
77//#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
78extern const char *s_QLOADNET; // = QLOADNET;
79//#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY
80extern const char *s_QSAVESPOT; // = QSAVESPOT;
81//#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY
82extern const char *s_SAVEDEAD; // = SAVEDEAD;
83//#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
84extern const char *s_QSPROMPT; // = QSPROMPT;
85//#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN
86extern const char *s_QLPROMPT; // = QLPROMPT;
87
88/*
89#define NEWGAME \
90"you can't start a new game\n"\
91"while in a network game.\n\n"PRESSKEY
92*/
93extern const char *s_NEWGAME; // = NEWGAME;
94
95// CPhipps - message given when asked if to restart the level
96extern const char *s_RESTARTLEVEL;
97
98/*
99#define NIGHTMARE \
100"are you sure? this skill level\n"\
101"isn't even remotely fair.\n\n"PRESSYN
102*/
103extern const char *s_NIGHTMARE; // = NIGHTMARE;
104
105/*
106#define SWSTRING \
107"this is the shareware version of doom.\n\n"\
108"you need to order the entire trilogy.\n\n"PRESSKEY
109*/
110extern const char *s_SWSTRING; // = SWSTRING;
111
112//#define MSGOFF "Messages OFF"
113extern const char *s_MSGOFF; // = MSGOFF;
114//#define MSGON "Messages ON"
115extern const char *s_MSGON; // = MSGON;
116//#define NETEND "you can't end a netgame!\n\n"PRESSKEY
117extern const char *s_NETEND; // = NETEND;
118//#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN
119extern const char *s_ENDGAME; // = ENDGAME;
120
121//#define DOSY "(press y to quit)"
122extern const char *s_DOSY; // = DOSY;
123
124//#define DETAILHI "High detail"
125extern const char *s_DETAILHI; // = DETAILHI;
126//#define DETAILLO "Low detail"
127extern const char *s_DETAILLO; // = DETAILLO;
128//#define GAMMALVL0 "Gamma correction OFF"
129extern const char *s_GAMMALVL0; // = GAMMALVL0;
130//#define GAMMALVL1 "Gamma correction level 1"
131extern const char *s_GAMMALVL1; // = GAMMALVL1;
132//#define GAMMALVL2 "Gamma correction level 2"
133extern const char *s_GAMMALVL2; // = GAMMALVL2;
134//#define GAMMALVL3 "Gamma correction level 3"
135extern const char *s_GAMMALVL3; // = GAMMALVL3;
136//#define GAMMALVL4 "Gamma correction level 4"
137extern const char *s_GAMMALVL4; // = GAMMALVL4;
138//#define EMPTYSTRING "empty slot"
139extern const char *s_EMPTYSTRING; // = EMPTYSTRING;
140
141//
142// P_inter.C
143//
144//#define GOTARMOR "Picked up the armor."
145extern const char *s_GOTARMOR; // = GOTARMOR;
146//#define GOTMEGA "Picked up the MegaArmor!"
147extern const char *s_GOTMEGA; // = GOTMEGA;
148//#define GOTHTHBONUS "Picked up a health bonus."
149extern const char *s_GOTHTHBONUS; // = GOTHTHBONUS;
150//#define GOTARMBONUS "Picked up an armor bonus."
151extern const char *s_GOTARMBONUS; // = GOTARMBONUS;
152//#define GOTSTIM "Picked up a stimpack."
153extern const char *s_GOTSTIM; // = GOTSTIM;
154//#define GOTMEDINEED "Picked up a medikit that you REALLY need!"
155extern const char *s_GOTMEDINEED; // = GOTMEDINEED;
156//#define GOTMEDIKIT "Picked up a medikit."
157extern const char *s_GOTMEDIKIT; // = GOTMEDIKIT;
158//#define GOTSUPER "Supercharge!"
159extern const char *s_GOTSUPER; // = GOTSUPER;
160
161//#define GOTBLUECARD "Picked up a blue keycard."
162extern const char *s_GOTBLUECARD; // = GOTBLUECARD;
163//#define GOTYELWCARD "Picked up a yellow keycard."
164extern const char *s_GOTYELWCARD; // = GOTYELWCARD;
165//#define GOTREDCARD "Picked up a red keycard."
166extern const char *s_GOTREDCARD; // = GOTREDCARD;
167//#define GOTBLUESKUL "Picked up a blue skull key."
168extern const char *s_GOTBLUESKUL; // = GOTBLUESKUL;
169//#define GOTYELWSKUL "Picked up a yellow skull key."
170extern const char *s_GOTYELWSKUL; // = GOTYELWSKUL;
171//#define GOTREDSKULL "Picked up a red skull key."
172extern const char *s_GOTREDSKULL; // = GOTREDSKULL;
173
174//#define GOTINVUL "Invulnerability!"
175extern const char *s_GOTINVUL; // = GOTINVUL;
176//#define GOTBERSERK "Berserk!"
177extern const char *s_GOTBERSERK; // = GOTBERSERK;
178//#define GOTINVIS "Partial Invisibility"
179extern const char *s_GOTINVIS; // = GOTINVIS;
180//#define GOTSUIT "Radiation Shielding Suit"
181extern const char *s_GOTSUIT; // = GOTSUIT;
182//#define GOTMAP "Computer Area Map"
183extern const char *s_GOTMAP; // = GOTMAP;
184//#define GOTVISOR "Light Amplification Visor"
185extern const char *s_GOTVISOR; // = GOTVISOR;
186//#define GOTMSPHERE "MegaSphere!"
187extern const char *s_GOTMSPHERE; // = GOTMSPHERE;
188
189//#define GOTCLIP "Picked up a clip."
190extern const char *s_GOTCLIP; // = GOTCLIP;
191//#define GOTCLIPBOX "Picked up a box of bullets."
192extern const char *s_GOTCLIPBOX; // = GOTCLIPBOX;
193//#define GOTROCKET "Picked up a rocket."
194extern const char *s_GOTROCKET; // = GOTROCKET;
195//#define GOTROCKBOX "Picked up a box of rockets."
196extern const char *s_GOTROCKBOX; // = GOTROCKBOX;
197//#define GOTCELL "Picked up an energy cell."
198extern const char *s_GOTCELL; // = GOTCELL;
199//#define GOTCELLBOX "Picked up an energy cell pack."
200extern const char *s_GOTCELLBOX; // = GOTCELLBOX;
201//#define GOTSHELLS "Picked up 4 shotgun shells."
202extern const char *s_GOTSHELLS; // = GOTSHELLS;
203//#define GOTSHELLBOX "Picked up a box of shotgun shells."
204extern const char *s_GOTSHELLBOX; // = GOTSHELLBOX;
205//#define GOTBACKPACK "Picked up a backpack full of ammo!"
206extern const char *s_GOTBACKPACK; // = GOTBACKPACK;
207
208//#define GOTBFG9000 "You got the BFG9000! Oh, yes."
209extern const char *s_GOTBFG9000; // = GOTBFG9000;
210//#define GOTCHAINGUN "You got the chaingun!"
211extern const char *s_GOTCHAINGUN; // = GOTCHAINGUN;
212//#define GOTCHAINSAW "A chainsaw! Find some meat!"
213extern const char *s_GOTCHAINSAW; // = GOTCHAINSAW;
214//#define GOTLAUNCHER "You got the rocket launcher!"
215extern const char *s_GOTLAUNCHER; // = GOTLAUNCHER;
216//#define GOTPLASMA "You got the plasma gun!"
217extern const char *s_GOTPLASMA; // = GOTPLASMA;
218//#define GOTSHOTGUN "You got the shotgun!"
219extern const char *s_GOTSHOTGUN; // = GOTSHOTGUN;
220//#define GOTSHOTGUN2 "You got the super shotgun!"
221extern const char *s_GOTSHOTGUN2; // = GOTSHOTGUN2;
222
223//
224// P_Doors.C
225//
226//#define PD_BLUEO "You need a blue key to activate this object"
227extern const char *s_PD_BLUEO; // = PD_BLUEO;
228//#define PD_REDO "You need a red key to activate this object"
229extern const char *s_PD_REDO; // = PD_REDO;
230//#define PD_YELLOWO "You need a yellow key to activate this object"
231extern const char *s_PD_YELLOWO; // = PD_YELLOWO;
232//#define PD_BLUEK "You need a blue key to open this door"
233extern const char *s_PD_BLUEK; // = PD_BLUEK;
234//#define PD_REDK "You need a red key to open this door"
235extern const char *s_PD_REDK; // = PD_REDK;
236//#define PD_YELLOWK "You need a yellow key to open this door"
237extern const char *s_PD_YELLOWK; // = PD_YELLOWK;
238//jff 02/05/98 Create messages specific to card and skull keys
239//#define PD_BLUEC "You need a blue card to open this door"
240extern const char *s_PD_BLUEC; // = PD_BLUEC;
241//#define PD_REDC "You need a red card to open this door"
242extern const char *s_PD_REDC; // = PD_REDC;
243//#define PD_YELLOWC "You need a yellow card to open this door"
244extern const char *s_PD_YELLOWC; // = PD_YELLOWC;
245//#define PD_BLUES "You need a blue skull to open this door"
246extern const char *s_PD_BLUES; // = PD_BLUES;
247//#define PD_REDS "You need a red skull to open this door"
248extern const char *s_PD_REDS; // = PD_REDS;
249//#define PD_YELLOWS "You need a yellow skull to open this door"
250extern const char *s_PD_YELLOWS; // = PD_YELLOWS;
251//#define PD_ANY "Any key will open this door"
252extern const char *s_PD_ANY; // = PD_ANY;
253//#define PD_ALL3 "You need all three keys to open this door"
254extern const char *s_PD_ALL3; // = PD_ALL3;
255//#define PD_ALL6 "You need all six keys to open this door"
256extern const char *s_PD_ALL6; // = PD_ALL6;
257
258//
259// G_game.C
260//
261//#define GGSAVED "game saved."
262extern const char *s_GGSAVED; // = GGSAVED;
263
264//
265// HU_stuff.C
266//
267//#define HUSTR_MSGU "[Message unsent]"
268extern const char *s_HUSTR_MSGU; // = HUSTR_MSGU;
269
270//#define HUSTR_E1M1 "E1M1: Hangar"
271extern const char *s_HUSTR_E1M1; // = HUSTR_E1M1;
272//#define HUSTR_E1M2 "E1M2: Nuclear Plant"
273extern const char *s_HUSTR_E1M2; // = HUSTR_E1M2;
274//#define HUSTR_E1M3 "E1M3: Toxin Refinery"
275extern const char *s_HUSTR_E1M3; // = HUSTR_E1M3;
276//#define HUSTR_E1M4 "E1M4: Command Control"
277extern const char *s_HUSTR_E1M4; // = HUSTR_E1M4;
278//#define HUSTR_E1M5 "E1M5: Phobos Lab"
279extern const char *s_HUSTR_E1M5; // = HUSTR_E1M5;
280//#define HUSTR_E1M6 "E1M6: Central Processing"
281extern const char *s_HUSTR_E1M6; // = HUSTR_E1M6;
282//#define HUSTR_E1M7 "E1M7: Computer Station"
283extern const char *s_HUSTR_E1M7; // = HUSTR_E1M7;
284//#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
285extern const char *s_HUSTR_E1M8; // = HUSTR_E1M8;
286//#define HUSTR_E1M9 "E1M9: Military Base"
287extern const char *s_HUSTR_E1M9; // = HUSTR_E1M9;
288
289//#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
290extern const char *s_HUSTR_E2M1; // = HUSTR_E2M1;
291//#define HUSTR_E2M2 "E2M2: Containment Area"
292extern const char *s_HUSTR_E2M2; // = HUSTR_E2M2;
293//#define HUSTR_E2M3 "E2M3: Refinery"
294extern const char *s_HUSTR_E2M3; // = HUSTR_E2M3;
295//#define HUSTR_E2M4 "E2M4: Deimos Lab"
296extern const char *s_HUSTR_E2M4; // = HUSTR_E2M4;
297//#define HUSTR_E2M5 "E2M5: Command Center"
298extern const char *s_HUSTR_E2M5; // = HUSTR_E2M5;
299//#define HUSTR_E2M6 "E2M6: Halls of the Damned"
300extern const char *s_HUSTR_E2M6; // = HUSTR_E2M6;
301//#define HUSTR_E2M7 "E2M7: Spawning Vats"
302extern const char *s_HUSTR_E2M7; // = HUSTR_E2M7;
303//#define HUSTR_E2M8 "E2M8: Tower of Babel"
304extern const char *s_HUSTR_E2M8; // = HUSTR_E2M8;
305//#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
306extern const char *s_HUSTR_E2M9; // = HUSTR_E2M9;
307
308//#define HUSTR_E3M1 "E3M1: Hell Keep"
309extern const char *s_HUSTR_E3M1; // = HUSTR_E3M1;
310//#define HUSTR_E3M2 "E3M2: Slough of Despair"
311extern const char *s_HUSTR_E3M2; // = HUSTR_E3M2;
312//#define HUSTR_E3M3 "E3M3: Pandemonium"
313extern const char *s_HUSTR_E3M3; // = HUSTR_E3M3;
314//#define HUSTR_E3M4 "E3M4: House of Pain"
315extern const char *s_HUSTR_E3M4; // = HUSTR_E3M4;
316//#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
317extern const char *s_HUSTR_E3M5; // = HUSTR_E3M5;
318//#define HUSTR_E3M6 "E3M6: Mt. Erebus"
319extern const char *s_HUSTR_E3M6; // = HUSTR_E3M6;
320//#define HUSTR_E3M7 "E3M7: Limbo"
321extern const char *s_HUSTR_E3M7; // = HUSTR_E3M7;
322//#define HUSTR_E3M8 "E3M8: Dis"
323extern const char *s_HUSTR_E3M8; // = HUSTR_E3M8;
324//#define HUSTR_E3M9 "E3M9: Warrens"
325extern const char *s_HUSTR_E3M9; // = HUSTR_E3M9;
326
327//#define HUSTR_E4M1 "E4M1: Hell Beneath"
328extern const char *s_HUSTR_E4M1; // = HUSTR_E4M1;
329//#define HUSTR_E4M2 "E4M2: Perfect Hatred"
330extern const char *s_HUSTR_E4M2; // = HUSTR_E4M2;
331//#define HUSTR_E4M3 "E4M3: Sever The Wicked"
332extern const char *s_HUSTR_E4M3; // = HUSTR_E4M3;
333//#define HUSTR_E4M4 "E4M4: Unruly Evil"
334extern const char *s_HUSTR_E4M4; // = HUSTR_E4M4;
335//#define HUSTR_E4M5 "E4M5: They Will Repent"
336extern const char *s_HUSTR_E4M5; // = HUSTR_E4M5;
337//#define HUSTR_E4M6 "E4M6: Against Thee Wickedly"
338extern const char *s_HUSTR_E4M6; // = HUSTR_E4M6;
339//#define HUSTR_E4M7 "E4M7: And Hell Followed"
340extern const char *s_HUSTR_E4M7; // = HUSTR_E4M7;
341//#define HUSTR_E4M8 "E4M8: Unto The Cruel"
342extern const char *s_HUSTR_E4M8; // = HUSTR_E4M8;
343//#define HUSTR_E4M9 "E4M9: Fear"
344extern const char *s_HUSTR_E4M9; // = HUSTR_E4M9;
345
346//#define HUSTR_1 "level 1: entryway"
347extern const char *s_HUSTR_1; // = HUSTR_1;
348//#define HUSTR_2 "level 2: underhalls"
349extern const char *s_HUSTR_2; // = HUSTR_2;
350//#define HUSTR_3 "level 3: the gantlet"
351extern const char *s_HUSTR_3; // = HUSTR_3;
352//#define HUSTR_4 "level 4: the focus"
353extern const char *s_HUSTR_4; // = HUSTR_4;
354//#define HUSTR_5 "level 5: the waste tunnels"
355extern const char *s_HUSTR_5; // = HUSTR_5;
356//#define HUSTR_6 "level 6: the crusher"
357extern const char *s_HUSTR_6; // = HUSTR_6;
358//#define HUSTR_7 "level 7: dead simple"
359extern const char *s_HUSTR_7; // = HUSTR_7;
360//#define HUSTR_8 "level 8: tricks and traps"
361extern const char *s_HUSTR_8; // = HUSTR_8;
362//#define HUSTR_9 "level 9: the pit"
363extern const char *s_HUSTR_9; // = HUSTR_9;
364//#define HUSTR_10 "level 10: refueling base"
365extern const char *s_HUSTR_10; // = HUSTR_10;
366//#define HUSTR_11 "level 11: 'o' of destruction!"
367extern const char *s_HUSTR_11; // = HUSTR_11;
368
369//#define HUSTR_12 "level 12: the factory"
370extern const char *s_HUSTR_12; // = HUSTR_12;
371//#define HUSTR_13 "level 13: downtown"
372extern const char *s_HUSTR_13; // = HUSTR_13;
373//#define HUSTR_14 "level 14: the inmost dens"
374extern const char *s_HUSTR_14; // = HUSTR_14;
375//#define HUSTR_15 "level 15: industrial zone"
376extern const char *s_HUSTR_15; // = HUSTR_15;
377//#define HUSTR_16 "level 16: suburbs"
378extern const char *s_HUSTR_16; // = HUSTR_16;
379//#define HUSTR_17 "level 17: tenements"
380extern const char *s_HUSTR_17; // = HUSTR_17;
381//#define HUSTR_18 "level 18: the courtyard"
382extern const char *s_HUSTR_18; // = HUSTR_18;
383//#define HUSTR_19 "level 19: the citadel"
384extern const char *s_HUSTR_19; // = HUSTR_19;
385//#define HUSTR_20 "level 20: gotcha!"
386extern const char *s_HUSTR_20; // = HUSTR_20;
387
388//#define HUSTR_21 "level 21: nirvana"
389extern const char *s_HUSTR_21; // = HUSTR_21;
390//#define HUSTR_22 "level 22: the catacombs"
391extern const char *s_HUSTR_22; // = HUSTR_22;
392//#define HUSTR_23 "level 23: barrels o' fun"
393extern const char *s_HUSTR_23; // = HUSTR_23;
394//#define HUSTR_24 "level 24: the chasm"
395extern const char *s_HUSTR_24; // = HUSTR_24;
396//#define HUSTR_25 "level 25: bloodfalls"
397extern const char *s_HUSTR_25; // = HUSTR_25;
398//#define HUSTR_26 "level 26: the abandoned mines"
399extern const char *s_HUSTR_26; // = HUSTR_26;
400//#define HUSTR_27 "level 27: monster condo"
401extern const char *s_HUSTR_27; // = HUSTR_27;
402//#define HUSTR_28 "level 28: the spirit world"
403extern const char *s_HUSTR_28; // = HUSTR_28;
404//#define HUSTR_29 "level 29: the living end"
405extern const char *s_HUSTR_29; // = HUSTR_29;
406//#define HUSTR_30 "level 30: icon of sin"
407extern const char *s_HUSTR_30; // = HUSTR_30;
408
409//#define HUSTR_31 "level 31: wolfenstein"
410extern const char *s_HUSTR_31; // = HUSTR_31;
411//#define HUSTR_32 "level 32: grosse"
412extern const char *s_HUSTR_32; // = HUSTR_32;
413
414//#define PHUSTR_1 "level 1: congo"
415extern const char *s_PHUSTR_1; // = PHUSTR_1;
416//#define PHUSTR_2 "level 2: well of souls"
417extern const char *s_PHUSTR_2; // = PHUSTR_2;
418//#define PHUSTR_3 "level 3: aztec"
419extern const char *s_PHUSTR_3; // = PHUSTR_3;
420//#define PHUSTR_4 "level 4: caged"
421extern const char *s_PHUSTR_4; // = PHUSTR_4;
422//#define PHUSTR_5 "level 5: ghost town"
423extern const char *s_PHUSTR_5; // = PHUSTR_5;
424//#define PHUSTR_6 "level 6: baron's lair"
425extern const char *s_PHUSTR_6; // = PHUSTR_6;
426//#define PHUSTR_7 "level 7: caughtyard"
427extern const char *s_PHUSTR_7; // = PHUSTR_7;
428//#define PHUSTR_8 "level 8: realm"
429extern const char *s_PHUSTR_8; // = PHUSTR_8;
430//#define PHUSTR_9 "level 9: abattoire"
431extern const char *s_PHUSTR_9; // = PHUSTR_9;
432//#define PHUSTR_10 "level 10: onslaught"
433extern const char *s_PHUSTR_10; // = PHUSTR_10;
434//#define PHUSTR_11 "level 11: hunted"
435extern const char *s_PHUSTR_11; // = PHUSTR_11;
436
437//#define PHUSTR_12 "level 12: speed"
438extern const char *s_PHUSTR_12; // = PHUSTR_12;
439//#define PHUSTR_13 "level 13: the crypt"
440extern const char *s_PHUSTR_13; // = PHUSTR_13;
441//#define PHUSTR_14 "level 14: genesis"
442extern const char *s_PHUSTR_14; // = PHUSTR_14;
443//#define PHUSTR_15 "level 15: the twilight"
444extern const char *s_PHUSTR_15; // = PHUSTR_15;
445//#define PHUSTR_16 "level 16: the omen"
446extern const char *s_PHUSTR_16; // = PHUSTR_16;
447//#define PHUSTR_17 "level 17: compound"
448extern const char *s_PHUSTR_17; // = PHUSTR_17;
449//#define PHUSTR_18 "level 18: neurosphere"
450extern const char *s_PHUSTR_18; // = PHUSTR_18;
451//#define PHUSTR_19 "level 19: nme"
452extern const char *s_PHUSTR_19; // = PHUSTR_19;
453//#define PHUSTR_20 "level 20: the death domain"
454extern const char *s_PHUSTR_20; // = PHUSTR_20;
455
456//#define PHUSTR_21 "level 21: slayer"
457extern const char *s_PHUSTR_21; // = PHUSTR_21;
458//#define PHUSTR_22 "level 22: impossible mission"
459extern const char *s_PHUSTR_22; // = PHUSTR_22;
460//#define PHUSTR_23 "level 23: tombstone"
461extern const char *s_PHUSTR_23; // = PHUSTR_23;
462//#define PHUSTR_24 "level 24: the final frontier"
463extern const char *s_PHUSTR_24; // = PHUSTR_24;
464//#define PHUSTR_25 "level 25: the temple of darkness"
465extern const char *s_PHUSTR_25; // = PHUSTR_25;
466//#define PHUSTR_26 "level 26: bunker"
467extern const char *s_PHUSTR_26; // = PHUSTR_26;
468//#define PHUSTR_27 "level 27: anti-christ"
469extern const char *s_PHUSTR_27; // = PHUSTR_27;
470//#define PHUSTR_28 "level 28: the sewers"
471extern const char *s_PHUSTR_28; // = PHUSTR_28;
472//#define PHUSTR_29 "level 29: odyssey of noises"
473extern const char *s_PHUSTR_29; // = PHUSTR_29;
474//#define PHUSTR_30 "level 30: the gateway of hell"
475extern const char *s_PHUSTR_30; // = PHUSTR_30;
476
477//#define PHUSTR_31 "level 31: cyberden"
478extern const char *s_PHUSTR_31; // = PHUSTR_31;
479//#define PHUSTR_32 "level 32: go 2 it"
480extern const char *s_PHUSTR_32; // = PHUSTR_32;
481
482//#define THUSTR_1 "level 1: system control"
483extern const char *s_THUSTR_1; // = THUSTR_1;
484//#define THUSTR_2 "level 2: human bbq"
485extern const char *s_THUSTR_2; // = THUSTR_2;
486//#define THUSTR_3 "level 3: power control"
487extern const char *s_THUSTR_3; // = THUSTR_3;
488//#define THUSTR_4 "level 4: wormhole"
489extern const char *s_THUSTR_4; // = THUSTR_4;
490//#define THUSTR_5 "level 5: hanger"
491extern const char *s_THUSTR_5; // = THUSTR_5;
492//#define THUSTR_6 "level 6: open season"
493extern const char *s_THUSTR_6; // = THUSTR_6;
494//#define THUSTR_7 "level 7: prison"
495extern const char *s_THUSTR_7; // = THUSTR_7;
496//#define THUSTR_8 "level 8: metal"
497extern const char *s_THUSTR_8; // = THUSTR_8;
498//#define THUSTR_9 "level 9: stronghold"
499extern const char *s_THUSTR_9; // = THUSTR_9;
500//#define THUSTR_10 "level 10: redemption"
501extern const char *s_THUSTR_10; // = THUSTR_10;
502//#define THUSTR_11 "level 11: storage facility"
503extern const char *s_THUSTR_11; // = THUSTR_11;
504
505//#define THUSTR_12 "level 12: crater"
506extern const char *s_THUSTR_12; // = THUSTR_12;
507//#define THUSTR_13 "level 13: nukage processing"
508extern const char *s_THUSTR_13; // = THUSTR_13;
509//#define THUSTR_14 "level 14: steel works"
510extern const char *s_THUSTR_14; // = THUSTR_14;
511//#define THUSTR_15 "level 15: dead zone"
512extern const char *s_THUSTR_15; // = THUSTR_15;
513//#define THUSTR_16 "level 16: deepest reaches"
514extern const char *s_THUSTR_16; // = THUSTR_16;
515//#define THUSTR_17 "level 17: processing area"
516extern const char *s_THUSTR_17; // = THUSTR_17;
517//#define THUSTR_18 "level 18: mill"
518extern const char *s_THUSTR_18; // = THUSTR_18;
519//#define THUSTR_19 "level 19: shipping/respawning"
520extern const char *s_THUSTR_19; // = THUSTR_19;
521//#define THUSTR_20 "level 20: central processing"
522extern const char *s_THUSTR_20; // = THUSTR_20;
523
524//#define THUSTR_21 "level 21: administration center"
525extern const char *s_THUSTR_21; // = THUSTR_21;
526//#define THUSTR_22 "level 22: habitat"
527extern const char *s_THUSTR_22; // = THUSTR_22;
528//#define THUSTR_23 "level 23: lunar mining project"
529extern const char *s_THUSTR_23; // = THUSTR_23;
530//#define THUSTR_24 "level 24: quarry"
531extern const char *s_THUSTR_24; // = THUSTR_24;
532//#define THUSTR_25 "level 25: baron's den"
533extern const char *s_THUSTR_25; // = THUSTR_25;
534//#define THUSTR_26 "level 26: ballistyx"
535extern const char *s_THUSTR_26; // = THUSTR_26;
536//#define THUSTR_27 "level 27: mount pain"
537extern const char *s_THUSTR_27; // = THUSTR_27;
538//#define THUSTR_28 "level 28: heck"
539extern const char *s_THUSTR_28; // = THUSTR_28;
540//#define THUSTR_29 "level 29: river styx"
541extern const char *s_THUSTR_29; // = THUSTR_29;
542//#define THUSTR_30 "level 30: last call"
543extern const char *s_THUSTR_30; // = THUSTR_30;
544
545//#define THUSTR_31 "level 31: pharaoh"
546extern const char *s_THUSTR_31; // = THUSTR_31;
547//#define THUSTR_32 "level 32: caribbean"
548extern const char *s_THUSTR_32; // = THUSTR_32;
549
550//#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
551extern const char *s_HUSTR_CHATMACRO1; // = HUSTR_CHATMACRO1;
552//#define HUSTR_CHATMACRO2 "I'm OK."
553extern const char *s_HUSTR_CHATMACRO2; // = HUSTR_CHATMACRO2;
554//#define HUSTR_CHATMACRO3 "I'm not looking too good!"
555extern const char *s_HUSTR_CHATMACRO3; // = HUSTR_CHATMACRO3;
556//#define HUSTR_CHATMACRO4 "Help!"
557extern const char *s_HUSTR_CHATMACRO4; // = HUSTR_CHATMACRO4;
558//#define HUSTR_CHATMACRO5 "You suck!"
559extern const char *s_HUSTR_CHATMACRO5; // = HUSTR_CHATMACRO5;
560//#define HUSTR_CHATMACRO6 "Next time, scumbag..."
561extern const char *s_HUSTR_CHATMACRO6; // = HUSTR_CHATMACRO6;
562//#define HUSTR_CHATMACRO7 "Come here!"
563extern const char *s_HUSTR_CHATMACRO7; // = HUSTR_CHATMACRO7;
564//#define HUSTR_CHATMACRO8 "I'll take care of it."
565extern const char *s_HUSTR_CHATMACRO8; // = HUSTR_CHATMACRO8;
566//#define HUSTR_CHATMACRO9 "Yes"
567extern const char *s_HUSTR_CHATMACRO9; // = HUSTR_CHATMACRO9;
568//#define HUSTR_CHATMACRO0 "No"
569extern const char *s_HUSTR_CHATMACRO0; // = HUSTR_CHATMACRO0;
570
571//#define HUSTR_TALKTOSELF1 "You mumble to yourself"
572extern const char *s_HUSTR_TALKTOSELF1; // = HUSTR_TALKTOSELF1;
573//#define HUSTR_TALKTOSELF2 "Who's there?"
574extern const char *s_HUSTR_TALKTOSELF2; // = HUSTR_TALKTOSELF2;
575//#define HUSTR_TALKTOSELF3 "You scare yourself"
576extern const char *s_HUSTR_TALKTOSELF3; // = HUSTR_TALKTOSELF3;
577//#define HUSTR_TALKTOSELF4 "You start to rave"
578extern const char *s_HUSTR_TALKTOSELF4; // = HUSTR_TALKTOSELF4;
579//#define HUSTR_TALKTOSELF5 "You've lost it..."
580extern const char *s_HUSTR_TALKTOSELF5; // = HUSTR_TALKTOSELF5;
581
582//#define HUSTR_MESSAGESENT "[Message Sent]"
583extern const char *s_HUSTR_MESSAGESENT; // = HUSTR_MESSAGESENT;
584
585// The following should NOT be changed unless it seems
586// just AWFULLY necessary
587
588//#define HUSTR_PLRGREEN "Green: "
589extern const char *s_HUSTR_PLRGREEN; // = HUSTR_PLRGREEN;
590//#define HUSTR_PLRINDIGO "Indigo: "
591extern const char *s_HUSTR_PLRINDIGO; // = HUSTR_PLRINDIGO;
592//#define HUSTR_PLRBROWN "Brown: "
593extern const char *s_HUSTR_PLRBROWN; // = HUSTR_PLRBROWN;
594//#define HUSTR_PLRRED "Red: "
595extern const char *s_HUSTR_PLRRED; // = HUSTR_PLRRED;
596
597//
598// AM_map.C
599//
600
601//#define AMSTR_FOLLOWON "Follow Mode ON"
602extern const char* s_AMSTR_FOLLOWON; // = AMSTR_FOLLOWON;
603//#define AMSTR_FOLLOWOFF "Follow Mode OFF"
604extern const char* s_AMSTR_FOLLOWOFF; // = AMSTR_FOLLOWOFF;
605
606//#define AMSTR_GRIDON "Grid ON"
607extern const char* s_AMSTR_GRIDON; // = AMSTR_GRIDON;
608//#define AMSTR_GRIDOFF "Grid OFF"
609extern const char* s_AMSTR_GRIDOFF; // = AMSTR_GRIDOFF;
610
611//#define AMSTR_MARKEDSPOT "Marked Spot"
612extern const char* s_AMSTR_MARKEDSPOT; // = AMSTR_MARKEDSPOT;
613//#define AMSTR_MARKSCLEARED "All Marks Cleared"
614extern const char* s_AMSTR_MARKSCLEARED; // = AMSTR_MARKSCLEARED;
615
616// CPhipps - automap rotate & overlay
617extern const char* s_AMSTR_ROTATEON;
618extern const char* s_AMSTR_ROTATEOFF;
619extern const char* s_AMSTR_OVERLAYON;
620extern const char* s_AMSTR_OVERLAYOFF;
621
622//
623// ST_stuff.C
624//
625
626//#define STSTR_MUS "Music Change"
627extern const char* s_STSTR_MUS; // = STSTR_MUS;
628//#define STSTR_NOMUS "IMPOSSIBLE SELECTION"
629extern const char* s_STSTR_NOMUS; // = STSTR_NOMUS;
630//#define STSTR_DQDON "Degreelessness Mode On"
631extern const char* s_STSTR_DQDON; // = STSTR_DQDON;
632//#define STSTR_DQDOFF "Degreelessness Mode Off"
633extern const char* s_STSTR_DQDOFF; // = STSTR_DQDOFF;
634
635//#define STSTR_KFAADDED "Very Happy Ammo Added"
636extern const char* s_STSTR_KFAADDED; // = STSTR_KFAADDED;
637//#define STSTR_FAADDED "Ammo (no keys) Added"
638extern const char* s_STSTR_FAADDED; // = STSTR_FAADDED;
639
640//#define STSTR_NCON "No Clipping Mode ON"
641extern const char* s_STSTR_NCON; // = STSTR_NCON;
642//#define STSTR_NCOFF "No Clipping Mode OFF"
643extern const char* s_STSTR_NCOFF; // = STSTR_NCOFF;
644
645//#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
646extern const char* s_STSTR_BEHOLD; // = STSTR_BEHOLD;
647//#define STSTR_BEHOLDX "Power-up Toggled"
648extern const char* s_STSTR_BEHOLDX; // = STSTR_BEHOLDX;
649
650//#define STSTR_CHOPPERS "... doesn't suck - GM"
651extern const char* s_STSTR_CHOPPERS; // = STSTR_CHOPPERS;
652//#define STSTR_CLEV "Changing Level..."
653extern const char* s_STSTR_CLEV; // = STSTR_CLEV;
654
655//
656// F_Finale.C
657//
658/*
659#define E1TEXT \
660"Once you beat the big badasses and\n"\
661"clean out the moon base you're supposed\n"\
662"to win, aren't you? Aren't you? Where's\n"\
663"your fat reward and ticket home? What\n"\
664"the hell is this? It's not supposed to\n"\
665"end this way!\n"\
666"\n" \
667"It stinks like rotten meat, but looks\n"\
668"like the lost Deimos base. Looks like\n"\
669"you're stuck on The Shores of Hell.\n"\
670"The only way out is through.\n"\
671"\n"\
672"To continue the DOOM experience, play\n"\
673"The Shores of Hell and its amazing\n"\
674"sequel, Inferno!\n"
675*/
676extern const char* s_E1TEXT; // = E1TEXT;
677
678
679/*
680#define E2TEXT \
681"You've done it! The hideous cyber-\n"\
682"demon lord that ruled the lost Deimos\n"\
683"moon base has been slain and you\n"\
684"are triumphant! But ... where are\n"\
685"you? You clamber to the edge of the\n"\
686"moon and look down to see the awful\n"\
687"truth.\n" \
688"\n"\
689"Deimos floats above Hell itself!\n"\
690"You've never heard of anyone escaping\n"\
691"from Hell, but you'll make the bastards\n"\
692"sorry they ever heard of you! Quickly,\n"\
693"you rappel down to the surface of\n"\
694"Hell.\n"\
695"\n" \
696"Now, it's on to the final chapter of\n"\
697"DOOM! -- Inferno."
698*/
699extern const char* s_E2TEXT; // = E2TEXT;
700
701
702/*
703#define E3TEXT \
704"The loathsome spiderdemon that\n"\
705"masterminded the invasion of the moon\n"\
706"bases and caused so much death has had\n"\
707"its ass kicked for all time.\n"\
708"\n"\
709"A hidden doorway opens and you enter.\n"\
710"You've proven too tough for Hell to\n"\
711"contain, and now Hell at last plays\n"\
712"fair -- for you emerge from the door\n"\
713"to see the green fields of Earth!\n"\
714"Home at last.\n" \
715"\n"\
716"You wonder what's been happening on\n"\
717"Earth while you were battling evil\n"\
718"unleashed. It's good that no Hell-\n"\
719"spawn could have come through that\n"\
720"door with you ..."
721*/
722extern const char* s_E3TEXT; // = E3TEXT;
723
724
725/*
726#define E4TEXT \
727"the spider mastermind must have sent forth\n"\
728"its legions of hellspawn before your\n"\
729"final confrontation with that terrible\n"\
730"beast from hell. but you stepped forward\n"\
731"and brought forth eternal damnation and\n"\
732"suffering upon the horde as a true hero\n"\
733"would in the face of something so evil.\n"\
734"\n"\
735"besides, someone was gonna pay for what\n"\
736"happened to daisy, your pet rabbit.\n"\
737"\n"\
738"but now, you see spread before you more\n"\
739"potential pain and gibbitude as a nation\n"\
740"of demons run amok among our cities.\n"\
741"\n"\
742"next stop, hell on earth!"
743*/
744extern const char* s_E4TEXT; // = E4TEXT;
745
746
747// after level 6, put this:
748
749/*
750#define C1TEXT \
751"YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \
752"STARPORT. BUT SOMETHING IS WRONG. THE\n" \
753"MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \
754"WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \
755"IS BEING SUBVERTED BY THEIR PRESENCE.\n" \
756"\n"\
757"AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \
758"FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \
759"YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \
760"OF THE STARBASE AND FIND THE CONTROLLING\n" \
761"SWITCH WHICH HOLDS EARTH'S POPULATION\n" \
762"HOSTAGE."
763*/
764extern const char* s_C1TEXT; // = C1TEXT;
765
766// After level 11, put this:
767
768/*
769#define C2TEXT \
770"YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \
771"HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\
772"THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\
773"HUMAN LEFT ON THE FACE OF THE PLANET.\n"\
774"CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\
775"AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\
776"YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\
777"THAT YOU HAVE SAVED YOUR SPECIES.\n"\
778"\n"\
779"BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\
780"MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\
781"THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\
782"GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\
783"ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\
784"YOUR OWN HOME CITY, NOT FAR FROM THE\n"\
785"STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\
786"UP AND RETURN TO THE FRAY."
787*/
788extern const char* s_C2TEXT; // = C2TEXT;
789
790
791// After level 20, put this:
792
793/*
794#define C3TEXT \
795"YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\
796"SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\
797"YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\
798"ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\
799"TEETH AND PLUNGE THROUGH IT.\n"\
800"\n"\
801"THERE MUST BE A WAY TO CLOSE IT ON THE\n"\
802"OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\
803"GOT TO GO THROUGH HELL TO GET TO IT?"
804*/
805extern const char* s_C3TEXT; // = C3TEXT;
806
807
808// After level 29, put this:
809
810/*
811#define C4TEXT \
812"THE HORRENDOUS VISAGE OF THE BIGGEST\n"\
813"DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\
814"YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\
815"HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\
816"UP AND DIES, ITS THRASHING LIMBS\n"\
817"DEVASTATING UNTOLD MILES OF HELL'S\n"\
818"SURFACE.\n"\
819"\n"\
820"YOU'VE DONE IT. THE INVASION IS OVER.\n"\
821"EARTH IS SAVED. HELL IS A WRECK. YOU\n"\
822"WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\
823"DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\
824"FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\
825"HOME. REBUILDING EARTH OUGHT TO BE A\n"\
826"LOT MORE FUN THAN RUINING IT WAS.\n"
827*/
828extern const char* s_C4TEXT; // = C4TEXT;
829
830
831
832// Before level 31, put this:
833
834/*
835#define C5TEXT \
836"CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\
837"LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\
838"HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\
839"WHO THE INMATES OF THIS CORNER OF HELL\n"\
840"WILL BE."
841*/
842extern const char* s_C5TEXT; // = C5TEXT;
843
844
845// Before level 32, put this:
846
847/*
848#define C6TEXT \
849"CONGRATULATIONS, YOU'VE FOUND THE\n"\
850"SUPER SECRET LEVEL! YOU'D BETTER\n"\
851"BLAZE THROUGH THIS ONE!\n"
852*/
853extern const char* s_C6TEXT; // = C6TEXT;
854
855
856// after map 06
857
858/*
859#define P1TEXT \
860"You gloat over the steaming carcass of the\n"\
861"Guardian. With its death, you've wrested\n"\
862"the Accelerator from the stinking claws\n"\
863"of Hell. You relax and glance around the\n"\
864"room. Damn! There was supposed to be at\n"\
865"least one working prototype, but you can't\n"\
866"see it. The demons must have taken it.\n"\
867"\n"\
868"You must find the prototype, or all your\n"\
869"struggles will have been wasted. Keep\n"\
870"moving, keep fighting, keep killing.\n"\
871"Oh yes, keep living, too."
872*/
873extern const char* s_P1TEXT; // = P1TEXT;
874
875
876// after map 11
877
878/*
879#define P2TEXT \
880"Even the deadly Arch-Vile labyrinth could\n"\
881"not stop you, and you've gotten to the\n"\
882"prototype Accelerator which is soon\n"\
883"efficiently and permanently deactivated.\n"\
884"\n"\
885"You're good at that kind of thing."
886*/
887extern const char* s_P2TEXT; // = P2TEXT;
888
889
890// after map 20
891
892/*
893#define P3TEXT \
894"You've bashed and battered your way into\n"\
895"the heart of the devil-hive. Time for a\n"\
896"Search-and-Destroy mission, aimed at the\n"\
897"Gatekeeper, whose foul offspring is\n"\
898"cascading to Earth. Yeah, he's bad. But\n"\
899"you know who's worse!\n"\
900"\n"\
901"Grinning evilly, you check your gear, and\n"\
902"get ready to give the bastard a little Hell\n"\
903"of your own making!"
904*/
905extern const char* s_P3TEXT; // = P3TEXT;
906
907// after map 30
908
909/*
910#define P4TEXT \
911"The Gatekeeper's evil face is splattered\n"\
912"all over the place. As its tattered corpse\n"\
913"collapses, an inverted Gate forms and\n"\
914"sucks down the shards of the last\n"\
915"prototype Accelerator, not to mention the\n"\
916"few remaining demons. You're done. Hell\n"\
917"has gone back to pounding bad dead folks \n"\
918"instead of good live ones. Remember to\n"\
919"tell your grandkids to put a rocket\n"\
920"launcher in your coffin. If you go to Hell\n"\
921"when you die, you'll need it for some\n"\
922"final cleaning-up ..."
923*/
924extern const char* s_P4TEXT; // = P4TEXT;
925
926// before map 31
927
928/*
929#define P5TEXT \
930"You've found the second-hardest level we\n"\
931"got. Hope you have a saved game a level or\n"\
932"two previous. If not, be prepared to die\n"\
933"aplenty. For master marines only."
934*/
935extern const char* s_P5TEXT; // = P5TEXT;
936
937// before map 32
938
939/*
940#define P6TEXT \
941"Betcha wondered just what WAS the hardest\n"\
942"level we had ready for ya? Now you know.\n"\
943"No one gets out alive."
944*/
945extern const char* s_P6TEXT; // = P6TEXT;
946
947
948/*
949#define T1TEXT \
950"You've fought your way out of the infested\n"\
951"experimental labs. It seems that UAC has\n"\
952"once again gulped it down. With their\n"\
953"high turnover, it must be hard for poor\n"\
954"old UAC to buy corporate health insurance\n"\
955"nowadays..\n"\
956"\n"\
957"Ahead lies the military complex, now\n"\
958"swarming with diseased horrors hot to get\n"\
959"their teeth into you. With luck, the\n"\
960"complex still has some warlike ordnance\n"\
961"laying around."
962*/
963extern const char* s_T1TEXT; // = T1TEXT;
964
965
966/*
967#define T2TEXT \
968"You hear the grinding of heavy machinery\n"\
969"ahead. You sure hope they're not stamping\n"\
970"out new hellspawn, but you're ready to\n"\
971"ream out a whole herd if you have to.\n"\
972"They might be planning a blood feast, but\n"\
973"you feel about as mean as two thousand\n"\
974"maniacs packed into one mad killer.\n"\
975"\n"\
976"You don't plan to go down easy."
977*/
978extern const char* s_T2TEXT; // = T2TEXT;
979
980
981/*
982#define T3TEXT \
983"The vista opening ahead looks real damn\n"\
984"familiar. Smells familiar, too -- like\n"\
985"fried excrement. You didn't like this\n"\
986"place before, and you sure as hell ain't\n"\
987"planning to like it now. The more you\n"\
988"brood on it, the madder you get.\n"\
989"Hefting your gun, an evil grin trickles\n"\
990"onto your face. Time to take some names."
991*/
992extern const char* s_T3TEXT; // = T3TEXT;
993
994/*
995#define T4TEXT \
996"Suddenly, all is silent, from one horizon\n"\
997"to the other. The agonizing echo of Hell\n"\
998"fades away, the nightmare sky turns to\n"\
999"blue, the heaps of monster corpses start \n"\
1000"to evaporate along with the evil stench \n"\
1001"that filled the air. Jeeze, maybe you've\n"\
1002"done it. Have you really won?\n"\
1003"\n"\
1004"Something rumbles in the distance.\n"\
1005"A blue light begins to glow inside the\n"\
1006"ruined skull of the demon-spitter."
1007*/
1008extern const char* s_T4TEXT; // = T4TEXT;
1009
1010
1011/*
1012#define T5TEXT \
1013"What now? Looks totally different. Kind\n"\
1014"of like King Tut's condo. Well,\n"\
1015"whatever's here can't be any worse\n"\
1016"than usual. Can it? Or maybe it's best\n"\
1017"to let sleeping gods lie.."
1018*/
1019extern const char* s_T5TEXT; // = T5TEXT;
1020
1021
1022/*
1023#define T6TEXT \
1024"Time for a vacation. You've burst the\n"\
1025"bowels of hell and by golly you're ready\n"\
1026"for a break. You mutter to yourself,\n"\
1027"Maybe someone else can kick Hell's ass\n"\
1028"next time around. Ahead lies a quiet town,\n"\
1029"with peaceful flowing water, quaint\n"\
1030"buildings, and presumably no Hellspawn.\n"\
1031"\n"\
1032"As you step off the transport, you hear\n"\
1033"the stomp of a cyberdemon's iron shoe."
1034*/
1035extern const char* s_T6TEXT; // = T6TEXT;
1036
1037//
1038// Character cast strings F_FINALE.C
1039//
1040//#define CC_ZOMBIE "ZOMBIEMAN"
1041extern const char* s_CC_ZOMBIE; // = CC_ZOMBIE;
1042//#define CC_SHOTGUN "SHOTGUN GUY"
1043extern const char* s_CC_SHOTGUN; // = CC_SHOTGUN;
1044//#define CC_HEAVY "HEAVY WEAPON DUDE"
1045extern const char* s_CC_HEAVY; // = CC_HEAVY;
1046//#define CC_IMP "IMP"
1047extern const char* s_CC_IMP; // = CC_IMP;
1048//#define CC_DEMON "DEMON"
1049extern const char* s_CC_DEMON; // = CC_DEMON;
1050//#define CC_LOST "LOST SOUL"
1051extern const char* s_CC_LOST; // = CC_LOST;
1052//#define CC_CACO "CACODEMON"
1053extern const char* s_CC_CACO; // = CC_CACO;
1054//#define CC_HELL "HELL KNIGHT"
1055extern const char* s_CC_HELL; // = CC_HELL;
1056//#define CC_BARON "BARON OF HELL"
1057extern const char* s_CC_BARON; // = CC_BARON;
1058//#define CC_ARACH "ARACHNOTRON"
1059extern const char* s_CC_ARACH; // = CC_ARACH;
1060//#define CC_PAIN "PAIN ELEMENTAL"
1061extern const char* s_CC_PAIN; // = CC_PAIN;
1062//#define CC_REVEN "REVENANT"
1063extern const char* s_CC_REVEN; // = CC_REVEN;
1064//#define CC_MANCU "MANCUBUS"
1065extern const char* s_CC_MANCU; // = CC_MANCU;
1066//#define CC_ARCH "ARCH-VILE"
1067extern const char* s_CC_ARCH; // = CC_ARCH;
1068//#define CC_SPIDER "THE SPIDER MASTERMIND"
1069extern const char* s_CC_SPIDER; // = CC_SPIDER;
1070//#define CC_CYBER "THE CYBERDEMON"
1071extern const char* s_CC_CYBER; // = CC_CYBER;
1072//#define CC_HERO "OUR HERO"
1073extern const char* s_CC_HERO; // = CC_HERO;
1074
1075// Ty 03/30/98 - new substitutions for background textures during int screens
1076// char* bgflatE1 = "FLOOR4_8";
1077extern const char* bgflatE1;
1078// char* bgflatE2 = "SFLR6_1";
1079extern const char* bgflatE2;
1080// char* bgflatE3 = "MFLR8_4";
1081extern const char* bgflatE3;
1082// char* bgflatE4 = "MFLR8_3";
1083extern const char* bgflatE4;
1084
1085// char* bgflat06 = "SLIME16";
1086extern const char* bgflat06;
1087// char* bgflat11 = "RROCK14";
1088extern const char* bgflat11;
1089// char* bgflat20 = "RROCK07";
1090extern const char* bgflat20;
1091// char* bgflat30 = "RROCK17";
1092extern const char* bgflat30;
1093// char* bgflat15 = "RROCK13";
1094extern const char* bgflat15;
1095// char* bgflat31 = "RROCK19";
1096extern const char* bgflat31;
1097
1098// char* bgcastcall = "BOSSBACK"; // panel behind cast call
1099extern const char* bgcastcall;
1100
1101// ignored if blank, general purpose startup announcements
1102// char* startup1 = "";
1103extern const char* startup1;
1104// char* startup2 = "";
1105extern const char* startup2;
1106// char* startup3 = "";
1107extern const char* startup3;
1108// char* startup4 = "";
1109extern const char* startup4;
1110// char* startup5 = "";
1111extern const char* startup5;
1112
1113// from g_game.c, prefix for savegame name like "boomsav"
1114extern const char* savegamename;
1115
1116void D_BuildBEXTables(void);
1117
1118#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Printed strings for translation.
31 * English language support (default).
32 * See dstrings.h for suggestions about foreign language BEX support
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifndef __D_ENGLSH__
37#define __D_ENGLSH__
38
39/* d_main.c */
40#define D_DEVSTR "Development mode ON.\n"
41#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n"
42
43/* m_menu.c */
44#define PRESSKEY "press a key."
45#define PRESSYN "press y or n."
46#define QUITMSG "are you sure you want to\nquit this great game?"
47#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY
48#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
49#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY
50#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY
51#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
52#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN
53
54#define NEWGAME \
55 "you can't start a new game\n"\
56 "while in a network game.\n\n"PRESSKEY
57
58#define NIGHTMARE \
59 "are you sure? this skill level\n"\
60 "isn't even remotely fair.\n\n"PRESSYN
61
62#define SWSTRING \
63 "this is the shareware version of doom.\n\n"\
64 "you need to order the entire trilogy.\n\n"PRESSKEY
65
66#define MSGOFF "Messages OFF"
67#define MSGON "Messages ON"
68#define NETEND "you can't end a netgame!\n\n"PRESSKEY
69#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN
70#define RESTARTLEVEL "restart the level?\n\n"PRESSYN
71
72#define DOSY "(press y to quit)"
73
74#define DETAILHI "High detail"
75#define DETAILLO "Low detail"
76#define GAMMALVL0 "Gamma correction OFF"
77#define GAMMALVL1 "Gamma correction level 1"
78#define GAMMALVL2 "Gamma correction level 2"
79#define GAMMALVL3 "Gamma correction level 3"
80#define GAMMALVL4 "Gamma correction level 4"
81#define EMPTYSTRING "empty slot"
82
83/* p_inter.c */
84#define GOTARMOR "Picked up the armor."
85#define GOTMEGA "Picked up the MegaArmor!"
86#define GOTHTHBONUS "Picked up a health bonus."
87#define GOTARMBONUS "Picked up an armor bonus."
88#define GOTSTIM "Picked up a stimpack."
89#define GOTMEDINEED "Picked up a medikit that you REALLY need!"
90#define GOTMEDIKIT "Picked up a medikit."
91#define GOTSUPER "Supercharge!"
92
93#define GOTBLUECARD "Picked up a blue keycard."
94#define GOTYELWCARD "Picked up a yellow keycard."
95#define GOTREDCARD "Picked up a red keycard."
96#define GOTBLUESKUL "Picked up a blue skull key."
97#define GOTYELWSKUL "Picked up a yellow skull key."
98#define GOTREDSKULL "Picked up a red skull key."
99
100#define GOTINVUL "Invulnerability!"
101#define GOTBERSERK "Berserk!"
102#define GOTINVIS "Partial Invisibility"
103#define GOTSUIT "Radiation Shielding Suit"
104#define GOTMAP "Computer Area Map"
105#define GOTVISOR "Light Amplification Visor"
106#define GOTMSPHERE "MegaSphere!"
107
108#define GOTCLIP "Picked up a clip."
109#define GOTCLIPBOX "Picked up a box of bullets."
110#define GOTROCKET "Picked up a rocket."
111#define GOTROCKBOX "Picked up a box of rockets."
112#define GOTCELL "Picked up an energy cell."
113#define GOTCELLBOX "Picked up an energy cell pack."
114#define GOTSHELLS "Picked up 4 shotgun shells."
115#define GOTSHELLBOX "Picked up a box of shotgun shells."
116#define GOTBACKPACK "Picked up a backpack full of ammo!"
117
118#define GOTBFG9000 "You got the BFG9000! Oh, yes."
119#define GOTCHAINGUN "You got the chaingun!"
120#define GOTCHAINSAW "A chainsaw! Find some meat!"
121#define GOTLAUNCHER "You got the rocket launcher!"
122#define GOTPLASMA "You got the plasma gun!"
123#define GOTSHOTGUN "You got the shotgun!"
124#define GOTSHOTGUN2 "You got the super shotgun!"
125
126/* p_doors.c */
127#define PD_BLUEO "You need a blue key to activate this object"
128#define PD_REDO "You need a red key to activate this object"
129#define PD_YELLOWO "You need a yellow key to activate this object"
130#define PD_BLUEK "You need a blue key to open this door"
131#define PD_REDK "You need a red key to open this door"
132#define PD_YELLOWK "You need a yellow key to open this door"
133/* jff 02/05/98 Create messages specific to card and skull keys */
134#define PD_BLUEC "You need a blue card to open this door"
135#define PD_REDC "You need a red card to open this door"
136#define PD_YELLOWC "You need a yellow card to open this door"
137#define PD_BLUES "You need a blue skull to open this door"
138#define PD_REDS "You need a red skull to open this door"
139#define PD_YELLOWS "You need a yellow skull to open this door"
140#define PD_ANY "Any key will open this door"
141#define PD_ALL3 "You need all three keys to open this door"
142#define PD_ALL6 "You need all six keys to open this door"
143
144/* g_game.c */
145#define GGSAVED "game saved."
146
147/* hu_stuff.c */
148#define HUSTR_MSGU "[Message unsent]"
149
150#define HUSTR_E1M1 "E1M1: Hangar"
151#define HUSTR_E1M2 "E1M2: Nuclear Plant"
152#define HUSTR_E1M3 "E1M3: Toxin Refinery"
153#define HUSTR_E1M4 "E1M4: Command Control"
154#define HUSTR_E1M5 "E1M5: Phobos Lab"
155#define HUSTR_E1M6 "E1M6: Central Processing"
156#define HUSTR_E1M7 "E1M7: Computer Station"
157#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
158#define HUSTR_E1M9 "E1M9: Military Base"
159
160#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
161#define HUSTR_E2M2 "E2M2: Containment Area"
162#define HUSTR_E2M3 "E2M3: Refinery"
163#define HUSTR_E2M4 "E2M4: Deimos Lab"
164#define HUSTR_E2M5 "E2M5: Command Center"
165#define HUSTR_E2M6 "E2M6: Halls of the Damned"
166#define HUSTR_E2M7 "E2M7: Spawning Vats"
167#define HUSTR_E2M8 "E2M8: Tower of Babel"
168#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
169
170#define HUSTR_E3M1 "E3M1: Hell Keep"
171#define HUSTR_E3M2 "E3M2: Slough of Despair"
172#define HUSTR_E3M3 "E3M3: Pandemonium"
173#define HUSTR_E3M4 "E3M4: House of Pain"
174#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
175#define HUSTR_E3M6 "E3M6: Mt. Erebus"
176#define HUSTR_E3M7 "E3M7: Limbo"
177#define HUSTR_E3M8 "E3M8: Dis"
178#define HUSTR_E3M9 "E3M9: Warrens"
179
180#define HUSTR_E4M1 "E4M1: Hell Beneath"
181#define HUSTR_E4M2 "E4M2: Perfect Hatred"
182#define HUSTR_E4M3 "E4M3: Sever The Wicked"
183#define HUSTR_E4M4 "E4M4: Unruly Evil"
184#define HUSTR_E4M5 "E4M5: They Will Repent"
185#define HUSTR_E4M6 "E4M6: Against Thee Wickedly"
186#define HUSTR_E4M7 "E4M7: And Hell Followed"
187#define HUSTR_E4M8 "E4M8: Unto The Cruel"
188#define HUSTR_E4M9 "E4M9: Fear"
189
190#define HUSTR_1 "level 1: entryway"
191#define HUSTR_2 "level 2: underhalls"
192#define HUSTR_3 "level 3: the gantlet"
193#define HUSTR_4 "level 4: the focus"
194#define HUSTR_5 "level 5: the waste tunnels"
195#define HUSTR_6 "level 6: the crusher"
196#define HUSTR_7 "level 7: dead simple"
197#define HUSTR_8 "level 8: tricks and traps"
198#define HUSTR_9 "level 9: the pit"
199#define HUSTR_10 "level 10: refueling base"
200#define HUSTR_11 "level 11: 'o' of destruction!"
201
202#define HUSTR_12 "level 12: the factory"
203#define HUSTR_13 "level 13: downtown"
204#define HUSTR_14 "level 14: the inmost dens"
205#define HUSTR_15 "level 15: industrial zone"
206#define HUSTR_16 "level 16: suburbs"
207#define HUSTR_17 "level 17: tenements"
208#define HUSTR_18 "level 18: the courtyard"
209#define HUSTR_19 "level 19: the citadel"
210#define HUSTR_20 "level 20: gotcha!"
211
212#define HUSTR_21 "level 21: nirvana"
213#define HUSTR_22 "level 22: the catacombs"
214#define HUSTR_23 "level 23: barrels o' fun"
215#define HUSTR_24 "level 24: the chasm"
216#define HUSTR_25 "level 25: bloodfalls"
217#define HUSTR_26 "level 26: the abandoned mines"
218#define HUSTR_27 "level 27: monster condo"
219#define HUSTR_28 "level 28: the spirit world"
220#define HUSTR_29 "level 29: the living end"
221#define HUSTR_30 "level 30: icon of sin"
222
223#define HUSTR_31 "level 31: wolfenstein"
224#define HUSTR_32 "level 32: grosse"
225
226#define PHUSTR_1 "level 1: congo"
227#define PHUSTR_2 "level 2: well of souls"
228#define PHUSTR_3 "level 3: aztec"
229#define PHUSTR_4 "level 4: caged"
230#define PHUSTR_5 "level 5: ghost town"
231#define PHUSTR_6 "level 6: baron's lair"
232#define PHUSTR_7 "level 7: caughtyard"
233#define PHUSTR_8 "level 8: realm"
234#define PHUSTR_9 "level 9: abattoire"
235#define PHUSTR_10 "level 10: onslaught"
236#define PHUSTR_11 "level 11: hunted"
237
238#define PHUSTR_12 "level 12: speed"
239#define PHUSTR_13 "level 13: the crypt"
240#define PHUSTR_14 "level 14: genesis"
241#define PHUSTR_15 "level 15: the twilight"
242#define PHUSTR_16 "level 16: the omen"
243#define PHUSTR_17 "level 17: compound"
244#define PHUSTR_18 "level 18: neurosphere"
245#define PHUSTR_19 "level 19: nme"
246#define PHUSTR_20 "level 20: the death domain"
247
248#define PHUSTR_21 "level 21: slayer"
249#define PHUSTR_22 "level 22: impossible mission"
250#define PHUSTR_23 "level 23: tombstone"
251#define PHUSTR_24 "level 24: the final frontier"
252#define PHUSTR_25 "level 25: the temple of darkness"
253#define PHUSTR_26 "level 26: bunker"
254#define PHUSTR_27 "level 27: anti-christ"
255#define PHUSTR_28 "level 28: the sewers"
256#define PHUSTR_29 "level 29: odyssey of noises"
257#define PHUSTR_30 "level 30: the gateway of hell"
258
259#define PHUSTR_31 "level 31: cyberden"
260#define PHUSTR_32 "level 32: go 2 it"
261
262#define THUSTR_1 "level 1: system control"
263#define THUSTR_2 "level 2: human bbq"
264#define THUSTR_3 "level 3: power control"
265#define THUSTR_4 "level 4: wormhole"
266#define THUSTR_5 "level 5: hanger"
267#define THUSTR_6 "level 6: open season"
268#define THUSTR_7 "level 7: prison"
269#define THUSTR_8 "level 8: metal"
270#define THUSTR_9 "level 9: stronghold"
271#define THUSTR_10 "level 10: redemption"
272#define THUSTR_11 "level 11: storage facility"
273
274#define THUSTR_12 "level 12: crater"
275#define THUSTR_13 "level 13: nukage processing"
276#define THUSTR_14 "level 14: steel works"
277#define THUSTR_15 "level 15: dead zone"
278#define THUSTR_16 "level 16: deepest reaches"
279#define THUSTR_17 "level 17: processing area"
280#define THUSTR_18 "level 18: mill"
281#define THUSTR_19 "level 19: shipping/respawning"
282#define THUSTR_20 "level 20: central processing"
283
284#define THUSTR_21 "level 21: administration center"
285#define THUSTR_22 "level 22: habitat"
286#define THUSTR_23 "level 23: lunar mining project"
287#define THUSTR_24 "level 24: quarry"
288#define THUSTR_25 "level 25: baron's den"
289#define THUSTR_26 "level 26: ballistyx"
290#define THUSTR_27 "level 27: mount pain"
291#define THUSTR_28 "level 28: heck"
292#define THUSTR_29 "level 29: river styx"
293#define THUSTR_30 "level 30: last call"
294
295#define THUSTR_31 "level 31: pharaoh"
296#define THUSTR_32 "level 32: caribbean"
297
298#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
299#define HUSTR_CHATMACRO2 "I'm OK."
300#define HUSTR_CHATMACRO3 "I'm not looking too good!"
301#define HUSTR_CHATMACRO4 "Help!"
302#define HUSTR_CHATMACRO5 "You suck!"
303#define HUSTR_CHATMACRO6 "Next time, scumbag..."
304#define HUSTR_CHATMACRO7 "Come here!"
305#define HUSTR_CHATMACRO8 "I'll take care of it."
306#define HUSTR_CHATMACRO9 "Yes"
307#define HUSTR_CHATMACRO0 "No"
308
309#define HUSTR_TALKTOSELF1 "You mumble to yourself"
310#define HUSTR_TALKTOSELF2 "Who's there?"
311#define HUSTR_TALKTOSELF3 "You scare yourself"
312#define HUSTR_TALKTOSELF4 "You start to rave"
313#define HUSTR_TALKTOSELF5 "You've lost it..."
314
315#define HUSTR_MESSAGESENT "[Message Sent]"
316
317/* The following should NOT be changed unless it seems
318 * just AWFULLY necessary */
319
320#define HUSTR_PLRGREEN "Player 1: "
321#define HUSTR_PLRINDIGO "Player 2: "
322#define HUSTR_PLRBROWN "Player 3: "
323#define HUSTR_PLRRED "Player 4: "
324
325#define HUSTR_KEYGREEN 'g'
326#define HUSTR_KEYINDIGO 'i'
327#define HUSTR_KEYBROWN 'b'
328#define HUSTR_KEYRED 'r'
329
330/* am_map.c */
331
332#define AMSTR_FOLLOWON "Follow Mode ON"
333#define AMSTR_FOLLOWOFF "Follow Mode OFF"
334
335#define AMSTR_GRIDON "Grid ON"
336#define AMSTR_GRIDOFF "Grid OFF"
337
338#define AMSTR_MARKEDSPOT "Marked Spot"
339#define AMSTR_MARKSCLEARED "All Marks Cleared"
340
341#define AMSTR_ROTATEON "Rotate Mode ON"
342#define AMSTR_ROTATEOFF "Rotate Mode OFF"
343
344#define AMSTR_OVERLAYON "Overlay Mode ON"
345#define AMSTR_OVERLAYOFF "Overlay Mode OFF"
346
347/* st_stuff.c */
348
349#define STSTR_MUS "Music Change"
350#define STSTR_NOMUS "IMPOSSIBLE SELECTION"
351#define STSTR_DQDON "Degreelessness Mode On"
352#define STSTR_DQDOFF "Degreelessness Mode Off"
353
354#define STSTR_KFAADDED "Very Happy Ammo Added"
355#define STSTR_FAADDED "Ammo (no keys) Added"
356
357#define STSTR_NCON "No Clipping Mode ON"
358#define STSTR_NCOFF "No Clipping Mode OFF"
359
360#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
361#define STSTR_BEHOLDX "Power-up Toggled"
362
363#define STSTR_CHOPPERS "... doesn't suck - GM"
364#define STSTR_CLEV "Changing Level..."
365
366#define STSTR_COMPON "Compatibility Mode On" /* phares */
367#define STSTR_COMPOFF "Compatibility Mode Off" /* phares */
368
369/* f_finale.c */
370
371#define E1TEXT \
372 "Once you beat the big badasses and\n"\
373 "clean out the moon base you're supposed\n"\
374 "to win, aren't you? Aren't you? Where's\n"\
375 "your fat reward and ticket home? What\n"\
376 "the hell is this? It's not supposed to\n"\
377 "end this way!\n"\
378 "\n" \
379 "It stinks like rotten meat, but looks\n"\
380 "like the lost Deimos base. Looks like\n"\
381 "you're stuck on The Shores of Hell.\n"\
382 "The only way out is through.\n"\
383 "\n"\
384 "To continue the DOOM experience, play\n"\
385 "The Shores of Hell and its amazing\n"\
386 "sequel, Inferno!\n"
387
388
389#define E2TEXT \
390 "You've done it! The hideous cyber-\n"\
391 "demon lord that ruled the lost Deimos\n"\
392 "moon base has been slain and you\n"\
393 "are triumphant! But ... where are\n"\
394 "you? You clamber to the edge of the\n"\
395 "moon and look down to see the awful\n"\
396 "truth.\n" \
397 "\n"\
398 "Deimos floats above Hell itself!\n"\
399 "You've never heard of anyone escaping\n"\
400 "from Hell, but you'll make the bastards\n"\
401 "sorry they ever heard of you! Quickly,\n"\
402 "you rappel down to the surface of\n"\
403 "Hell.\n"\
404 "\n" \
405 "Now, it's on to the final chapter of\n"\
406 "DOOM! -- Inferno."
407
408
409#define E3TEXT \
410 "The loathsome spiderdemon that\n"\
411 "masterminded the invasion of the moon\n"\
412 "bases and caused so much death has had\n"\
413 "its ass kicked for all time.\n"\
414 "\n"\
415 "A hidden doorway opens and you enter.\n"\
416 "You've proven too tough for Hell to\n"\
417 "contain, and now Hell at last plays\n"\
418 "fair -- for you emerge from the door\n"\
419 "to see the green fields of Earth!\n"\
420 "Home at last.\n" \
421 "\n"\
422 "You wonder what's been happening on\n"\
423 "Earth while you were battling evil\n"\
424 "unleashed. It's good that no Hell-\n"\
425 "spawn could have come through that\n"\
426 "door with you ..."
427
428
429#define E4TEXT \
430 "the spider mastermind must have sent forth\n"\
431 "its legions of hellspawn before your\n"\
432 "final confrontation with that terrible\n"\
433 "beast from hell. but you stepped forward\n"\
434 "and brought forth eternal damnation and\n"\
435 "suffering upon the horde as a true hero\n"\
436 "would in the face of something so evil.\n"\
437 "\n"\
438 "besides, someone was gonna pay for what\n"\
439 "happened to daisy, your pet rabbit.\n"\
440 "\n"\
441 "but now, you see spread before you more\n"\
442 "potential pain and gibbitude as a nation\n"\
443 "of demons run amok among our cities.\n"\
444 "\n"\
445 "next stop, hell on earth!"
446
447
448/* after level 6, put this: */
449
450#define C1TEXT \
451 "YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \
452 "STARPORT. BUT SOMETHING IS WRONG. THE\n" \
453 "MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \
454 "WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \
455 "IS BEING SUBVERTED BY THEIR PRESENCE.\n" \
456 "\n"\
457 "AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \
458 "FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \
459 "YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \
460 "OF THE STARBASE AND FIND THE CONTROLLING\n" \
461 "SWITCH WHICH HOLDS EARTH'S POPULATION\n" \
462 "HOSTAGE."
463
464/* After level 11, put this: */
465
466#define C2TEXT \
467 "YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \
468 "HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\
469 "THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\
470 "HUMAN LEFT ON THE FACE OF THE PLANET.\n"\
471 "CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\
472 "AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\
473 "YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\
474 "THAT YOU HAVE SAVED YOUR SPECIES.\n"\
475 "\n"\
476 "BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\
477 "MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\
478 "THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\
479 "GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\
480 "ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\
481 "YOUR OWN HOME CITY, NOT FAR FROM THE\n"\
482 "STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\
483 "UP AND RETURN TO THE FRAY."
484
485
486/* After level 20, put this: */
487
488#define C3TEXT \
489 "YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\
490 "SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\
491 "YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\
492 "ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\
493 "TEETH AND PLUNGE THROUGH IT.\n"\
494 "\n"\
495 "THERE MUST BE A WAY TO CLOSE IT ON THE\n"\
496 "OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\
497 "GOT TO GO THROUGH HELL TO GET TO IT?"
498
499
500/* After level 29, put this: */
501
502#define C4TEXT \
503 "THE HORRENDOUS VISAGE OF THE BIGGEST\n"\
504 "DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\
505 "YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\
506 "HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\
507 "UP AND DIES, ITS THRASHING LIMBS\n"\
508 "DEVASTATING UNTOLD MILES OF HELL'S\n"\
509 "SURFACE.\n"\
510 "\n"\
511 "YOU'VE DONE IT. THE INVASION IS OVER.\n"\
512 "EARTH IS SAVED. HELL IS A WRECK. YOU\n"\
513 "WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\
514 "DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\
515 "FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\
516 "HOME. REBUILDING EARTH OUGHT TO BE A\n"\
517 "LOT MORE FUN THAN RUINING IT WAS.\n"
518
519/* Before level 31, put this: */
520
521#define C5TEXT \
522 "CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\
523 "LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\
524 "HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\
525 "WHO THE INMATES OF THIS CORNER OF HELL\n"\
526 "WILL BE."
527
528
529/* Before level 32, put this: */
530
531#define C6TEXT \
532 "CONGRATULATIONS, YOU'VE FOUND THE\n"\
533 "SUPER SECRET LEVEL! YOU'D BETTER\n"\
534 "BLAZE THROUGH THIS ONE!\n"
535
536/*** Plutonia ***/
537/* after map 06 */
538
539#define P1TEXT \
540 "You gloat over the steaming carcass of the\n"\
541 "Guardian. With its death, you've wrested\n"\
542 "the Accelerator from the stinking claws\n"\
543 "of Hell. You relax and glance around the\n"\
544 "room. Damn! There was supposed to be at\n"\
545 "least one working prototype, but you can't\n"\
546 "see it. The demons must have taken it.\n"\
547 "\n"\
548 "You must find the prototype, or all your\n"\
549 "struggles will have been wasted. Keep\n"\
550 "moving, keep fighting, keep killing.\n"\
551 "Oh yes, keep living, too."
552
553
554/* after map 11 */
555
556#define P2TEXT \
557 "Even the deadly Arch-Vile labyrinth could\n"\
558 "not stop you, and you've gotten to the\n"\
559 "prototype Accelerator which is soon\n"\
560 "efficiently and permanently deactivated.\n"\
561 "\n"\
562 "You're good at that kind of thing."
563
564
565/* after map 20 */
566
567#define P3TEXT \
568 "You've bashed and battered your way into\n"\
569 "the heart of the devil-hive. Time for a\n"\
570 "Search-and-Destroy mission, aimed at the\n"\
571 "Gatekeeper, whose foul offspring is\n"\
572 "cascading to Earth. Yeah, he's bad. But\n"\
573 "you know who's worse!\n"\
574 "\n"\
575 "Grinning evilly, you check your gear, and\n"\
576 "get ready to give the bastard a little Hell\n"\
577 "of your own making!"
578
579/* after map 30 */
580
581#define P4TEXT \
582 "The Gatekeeper's evil face is splattered\n"\
583 "all over the place. As its tattered corpse\n"\
584 "collapses, an inverted Gate forms and\n"\
585 "sucks down the shards of the last\n"\
586 "prototype Accelerator, not to mention the\n"\
587 "few remaining demons. You're done. Hell\n"\
588 "has gone back to pounding bad dead folks \n"\
589 "instead of good live ones. Remember to\n"\
590 "tell your grandkids to put a rocket\n"\
591 "launcher in your coffin. If you go to Hell\n"\
592 "when you die, you'll need it for some\n"\
593 "final cleaning-up ..."
594
595/* before map 31 */
596
597#define P5TEXT \
598 "You've found the second-hardest level we\n"\
599 "got. Hope you have a saved game a level or\n"\
600 "two previous. If not, be prepared to die\n"\
601 "aplenty. For master marines only."
602
603/* before map 32 */
604
605#define P6TEXT \
606 "Betcha wondered just what WAS the hardest\n"\
607 "level we had ready for ya? Now you know.\n"\
608 "No one gets out alive."
609
610/*** TNT: Evilution ***/
611
612#define T1TEXT \
613 "You've fought your way out of the infested\n"\
614 "experimental labs. It seems that UAC has\n"\
615 "once again gulped it down. With their\n"\
616 "high turnover, it must be hard for poor\n"\
617 "old UAC to buy corporate health insurance\n"\
618 "nowadays..\n"\
619 "\n"\
620 "Ahead lies the military complex, now\n"\
621 "swarming with diseased horrors hot to get\n"\
622 "their teeth into you. With luck, the\n"\
623 "complex still has some warlike ordnance\n"\
624 "laying around."
625
626
627#define T2TEXT \
628 "You hear the grinding of heavy machinery\n"\
629 "ahead. You sure hope they're not stamping\n"\
630 "out new hellspawn, but you're ready to\n"\
631 "ream out a whole herd if you have to.\n"\
632 "They might be planning a blood feast, but\n"\
633 "you feel about as mean as two thousand\n"\
634 "maniacs packed into one mad killer.\n"\
635 "\n"\
636 "You don't plan to go down easy."
637
638
639#define T3TEXT \
640 "The vista opening ahead looks real damn\n"\
641 "familiar. Smells familiar, too -- like\n"\
642 "fried excrement. You didn't like this\n"\
643 "place before, and you sure as hell ain't\n"\
644 "planning to like it now. The more you\n"\
645 "brood on it, the madder you get.\n"\
646 "Hefting your gun, an evil grin trickles\n"\
647 "onto your face. Time to take some names."
648
649#define T4TEXT \
650 "Suddenly, all is silent, from one horizon\n"\
651 "to the other. The agonizing echo of Hell\n"\
652 "fades away, the nightmare sky turns to\n"\
653 "blue, the heaps of monster corpses start \n"\
654 "to evaporate along with the evil stench \n"\
655 "that filled the air. Jeeze, maybe you've\n"\
656 "done it. Have you really won?\n"\
657 "\n"\
658 "Something rumbles in the distance.\n"\
659 "A blue light begins to glow inside the\n"\
660 "ruined skull of the demon-spitter."
661
662
663#define T5TEXT \
664 "What now? Looks totally different. Kind\n"\
665 "of like King Tut's condo. Well,\n"\
666 "whatever's here can't be any worse\n"\
667 "than usual. Can it? Or maybe it's best\n"\
668 "to let sleeping gods lie.."
669
670
671#define T6TEXT \
672 "Time for a vacation. You've burst the\n"\
673 "bowels of hell and by golly you're ready\n"\
674 "for a break. You mutter to yourself,\n"\
675 "Maybe someone else can kick Hell's ass\n"\
676 "next time around. Ahead lies a quiet town,\n"\
677 "with peaceful flowing water, quaint\n"\
678 "buildings, and presumably no Hellspawn.\n"\
679 "\n"\
680 "As you step off the transport, you hear\n"\
681 "the stomp of a cyberdemon's iron shoe."
682
683
684
685/*
686 * Character cast strings F_FINALE.C
687 */
688#define CC_ZOMBIE "ZOMBIEMAN"
689#define CC_SHOTGUN "SHOTGUN GUY"
690#define CC_HEAVY "HEAVY WEAPON DUDE"
691#define CC_IMP "IMP"
692#define CC_DEMON "DEMON"
693#define CC_LOST "LOST SOUL"
694#define CC_CACO "CACODEMON"
695#define CC_HELL "HELL KNIGHT"
696#define CC_BARON "BARON OF HELL"
697#define CC_ARACH "ARACHNOTRON"
698#define CC_PAIN "PAIN ELEMENTAL"
699#define CC_REVEN "REVENANT"
700#define CC_MANCU "MANCUBUS"
701#define CC_ARCH "ARCH-VILE"
702#define CC_SPIDER "THE SPIDER MASTERMIND"
703#define CC_CYBER "THE CYBERDEMON"
704#define CC_HERO "OUR HERO"
705
706
707#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Event information structures.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __D_EVENT__
36#define __D_EVENT__
37
38
39#include "doomtype.h"
40
41
42//
43// Event handling.
44//
45
46// Input event types.
47typedef enum
48{
49 ev_keydown,
50 ev_keyup,
51 ev_mouse,
52 ev_joystick
53} evtype_t;
54
55// Event structure.
56typedef struct
57{
58 evtype_t type;
59 int data1; // keys / mouse/joystick buttons
60 int data2; // mouse/joystick x move
61 int data3; // mouse/joystick y move
62} event_t;
63
64
65typedef enum
66{
67 ga_nothing,
68 ga_loadlevel,
69 ga_newgame,
70 ga_loadgame,
71 ga_savegame,
72 ga_playdemo,
73 ga_completed,
74 ga_victory,
75 ga_worlddone,
76} gameaction_t;
77
78
79
80//
81// Button/action code definitions.
82//
83typedef enum
84{
85 // Press "Fire".
86 BT_ATTACK = 1,
87
88 // Use button, to open doors, activate switches.
89 BT_USE = 2,
90
91 // Flag: game events, not really buttons.
92 BT_SPECIAL = 128,
93 BT_SPECIALMASK = 3,
94
95 // Flag, weapon change pending.
96 // If true, the next 4 bits hold weapon num.
97 BT_CHANGE = 4,
98
99 // The 4bit weapon mask and shift, convenience.
100//BT_WEAPONMASK = (8+16+32),
101 BT_WEAPONMASK = (8+16+32+64), // extended to pick up SSG // phares
102 BT_WEAPONSHIFT = 3,
103
104 // Special events
105 BTS_LOADGAME = 0, // Loads a game
106 // Pause the game.
107 BTS_PAUSE = 1,
108 // Save the game at each console.
109 BTS_SAVEGAME = 2,
110 BTS_RESTARTLEVEL= 3, // Restarts the current level
111
112 // Savegame slot numbers occupy the second byte of buttons.
113 BTS_SAVEMASK = (4+8+16),
114 BTS_SAVESHIFT = 2,
115
116} buttoncode_t;
117
118
119//
120// GLOBAL VARIABLES
121//
122
123extern gameaction_t gameaction;
124
125#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Something to do with weapon sprite frames. Don't ask me.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35// We are referring to sprite numbers.
36#include "doomtype.h"
37#include "info.h"
38
39#ifdef __GNUG__
40#pragma implementation "d_items.h"
41#endif
42#include "d_items.h"
43
44
45//
46// PSPRITE ACTIONS for waepons.
47// This struct controls the weapon animations.
48//
49// Each entry is:
50// ammo/amunition type
51// upstate
52// downstate
53// readystate
54// atkstate, i.e. attack/fire/hit frame
55// flashstate, muzzle flash
56//
57weaponinfo_t weaponinfo[NUMWEAPONS] =
58{
59 {
60 // fist
61 am_noammo,
62 S_PUNCHUP,
63 S_PUNCHDOWN,
64 S_PUNCH,
65 S_PUNCH1,
66 S_NULL
67 },
68 {
69 // pistol
70 am_clip,
71 S_PISTOLUP,
72 S_PISTOLDOWN,
73 S_PISTOL,
74 S_PISTOL1,
75 S_PISTOLFLASH
76 },
77 {
78 // shotgun
79 am_shell,
80 S_SGUNUP,
81 S_SGUNDOWN,
82 S_SGUN,
83 S_SGUN1,
84 S_SGUNFLASH1
85 },
86 {
87 // chaingun
88 am_clip,
89 S_CHAINUP,
90 S_CHAINDOWN,
91 S_CHAIN,
92 S_CHAIN1,
93 S_CHAINFLASH1
94 },
95 {
96 // missile launcher
97 am_misl,
98 S_MISSILEUP,
99 S_MISSILEDOWN,
100 S_MISSILE,
101 S_MISSILE1,
102 S_MISSILEFLASH1
103 },
104 {
105 // plasma rifle
106 am_cell,
107 S_PLASMAUP,
108 S_PLASMADOWN,
109 S_PLASMA,
110 S_PLASMA1,
111 S_PLASMAFLASH1
112 },
113 {
114 // bfg 9000
115 am_cell,
116 S_BFGUP,
117 S_BFGDOWN,
118 S_BFG,
119 S_BFG1,
120 S_BFGFLASH1
121 },
122 {
123 // chainsaw
124 am_noammo,
125 S_SAWUP,
126 S_SAWDOWN,
127 S_SAW,
128 S_SAW1,
129 S_NULL
130 },
131 {
132 // super shotgun
133 am_shell,
134 S_DSGUNUP,
135 S_DSGUNDOWN,
136 S_DSGUN,
137 S_DSGUN1,
138 S_DSGUNFLASH1
139 },
140};
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Items: key cards, artifacts, weapon, ammunition.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __D_ITEMS__
36#define __D_ITEMS__
37
38#include "doomdef.h"
39
40#ifdef __GNUG__
41#pragma interface
42#endif
43
44
45/* Weapon info: sprite frames, ammunition use. */
46typedef struct
47{
48 ammotype_t ammo;
49 int upstate;
50 int downstate;
51 int readystate;
52 int atkstate;
53 int flashstate;
54
55} weaponinfo_t;
56
57extern weaponinfo_t weaponinfo[NUMWEAPONS];
58
59#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2004 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
31 * plus functions to determine game mode (shareware, registered),
32 * parse command line parameters, configure game parameters (turbo),
33 * and call the startup functions.
34 *
35 *-----------------------------------------------------------------------------
36 */
37
38
39#ifdef _MSC_VER
40#define F_OK 0 /* Check for file existence */
41#define W_OK 2 /* Check for write permission */
42#define R_OK 4 /* Check for read permission */
43#include <io.h>
44#include <direct.h>
45#else
46#include <unistd.h>
47#endif
48#include <sys/types.h>
49#include <sys/stat.h>
50#include <fcntl.h>
51
52#include "doomdef.h"
53#include "doomtype.h"
54#include "doomstat.h"
55#include "d_net.h"
56#include "dstrings.h"
57#include "sounds.h"
58#include "z_zone.h"
59#include "w_wad.h"
60#include "s_sound.h"
61#include "v_video.h"
62#include "f_finale.h"
63#include "f_wipe.h"
64#include "m_argv.h"
65#include "m_misc.h"
66#include "m_menu.h"
67#include "p_checksum.h"
68#include "i_main.h"
69#include "i_system.h"
70#include "i_sound.h"
71#include "i_video.h"
72#include "g_game.h"
73#include "hu_stuff.h"
74#include "wi_stuff.h"
75#include "st_stuff.h"
76#include "am_map.h"
77#include "p_setup.h"
78#include "r_draw.h"
79#include "r_main.h"
80#include "r_fps.h"
81#include "d_main.h"
82#include "d_deh.h" // Ty 04/08/98 - Externalizations
83#include "lprintf.h" // jff 08/03/98 - declaration of lprintf
84#include "am_map.h"
85
86void GetFirstMap(int *ep, int *map); // Ty 08/29/98 - add "-warp x" functionality
87static void D_PageDrawer(void);
88
89// CPhipps - removed wadfiles[] stuff
90
91boolean devparm; // started game with -devparm
92
93// jff 1/24/98 add new versions of these variables to remember command line
94boolean clnomonsters; // checkparm of -nomonsters
95boolean clrespawnparm; // checkparm of -respawn
96boolean clfastparm; // checkparm of -fast
97// jff 1/24/98 end definition of command line version of play mode switches
98
99boolean nomonsters; // working -nomonsters
100boolean respawnparm; // working -respawn
101boolean fastparm; // working -fast
102
103boolean singletics = false; // debug flag to cancel adaptiveness
104
105//jff 1/22/98 parms for disabling music and sound
106boolean nosfxparm;
107boolean nomusicparm;
108
109//jff 4/18/98
110extern boolean inhelpscreens;
111
112skill_t startskill;
113int startepisode;
114int startmap;
115boolean autostart;
116FILE *debugfile;
117int ffmap;
118
119boolean advancedemo;
120
121char wadfile[PATH_MAX+1]; // primary wad file
122char mapdir[PATH_MAX+1]; // directory of development maps
123char baseiwad[PATH_MAX+1]; // jff 3/23/98: iwad directory
124char basesavegame[PATH_MAX+1]; // killough 2/16/98: savegame directory
125
126//jff 4/19/98 list of standard IWAD names
127const char *const standard_iwads[]=
128{
129 "doom2f.wad",
130 "doom2.wad",
131 "plutonia.wad",
132 "tnt.wad",
133 "doom.wad",
134 "doom1.wad",
135 "doomu.wad", /* CPhipps - alow doomu.wad */
136 "freedoom.wad", /* wart@kobold.org: added freedoom for Fedora Extras */
137};
138static const int nstandard_iwads = sizeof standard_iwads/sizeof*standard_iwads;
139
140/*
141 * D_PostEvent - Event handling
142 *
143 * Called by I/O functions when an event is received.
144 * Try event handlers for each code area in turn.
145 * cph - in the true spirit of the Boom source, let the
146 * short ciruit operator madness begin!
147 */
148
149void D_PostEvent(event_t *ev)
150{
151 /* cph - suppress all input events at game start
152 * FIXME: This is a lousy kludge */
153 if (gametic < 3) return;
154 M_Responder(ev) ||
155 (gamestate == GS_LEVEL && (
156 HU_Responder(ev) ||
157 ST_Responder(ev) ||
158 AM_Responder(ev)
159 )
160 ) ||
161 G_Responder(ev);
162}
163
164//
165// D_Wipe
166//
167// CPhipps - moved the screen wipe code from D_Display to here
168// The screens to wipe between are already stored, this just does the timing
169// and screen updating
170
171static void D_Wipe(void)
172{
173 boolean done;
174 int wipestart = I_GetTime () - 1;
175
176 do
177 {
178 int nowtime, tics;
179 do
180 {
181 I_uSleep(5000); // CPhipps - don't thrash cpu in this loop
182 nowtime = I_GetTime();
183 tics = nowtime - wipestart;
184 }
185 while (!tics);
186 wipestart = nowtime;
187 done = wipe_ScreenWipe(tics);
188 I_UpdateNoBlit();
189 M_Drawer(); // menu is drawn even on top of wipes
190 I_FinishUpdate(); // page flip or blit buffer
191 }
192 while (!done);
193}
194
195//
196// D_Display
197// draw current display, possibly wiping it from the previous
198//
199
200// wipegamestate can be set to -1 to force a wipe on the next draw
201gamestate_t wipegamestate = GS_DEMOSCREEN;
202extern boolean setsizeneeded;
203extern int showMessages;
204
205void D_Display (void)
206{
207 static boolean inhelpscreensstate = false;
208 static boolean isborderstate = false;
209 static boolean borderwillneedredraw = false;
210 static gamestate_t oldgamestate = -1;
211 boolean wipe;
212 boolean viewactive = false, isborder = false;
213
214 if (nodrawers) // for comparative timing / profiling
215 return;
216
217 if (!I_StartDisplay())
218 return;
219
220 // save the current screen if about to wipe
221 if ((wipe = gamestate != wipegamestate) && (V_GetMode() != VID_MODEGL))
222 wipe_StartScreen();
223
224 if (gamestate != GS_LEVEL) { // Not a level
225 switch (oldgamestate) {
226 case -1:
227 case GS_LEVEL:
228 V_SetPalette(0); // cph - use default (basic) palette
229 default:
230 break;
231 }
232
233 switch (gamestate) {
234 case GS_INTERMISSION:
235 WI_Drawer();
236 break;
237 case GS_FINALE:
238 F_Drawer();
239 break;
240 case GS_DEMOSCREEN:
241 D_PageDrawer();
242 break;
243 default:
244 break;
245 }
246 } else if (gametic != basetic) { // In a level
247 boolean redrawborderstuff;
248
249 HU_Erase();
250
251 if (setsizeneeded) { // change the view size if needed
252 R_ExecuteSetViewSize();
253 oldgamestate = -1; // force background redraw
254 }
255
256 // Work out if the player view is visible, and if there is a border
257 viewactive = (!(automapmode & am_active) || (automapmode & am_overlay)) && !inhelpscreens;
258 isborder = viewactive ? (viewheight != SCREENHEIGHT) : (!inhelpscreens && (automapmode & am_active));
259
260 if (oldgamestate != GS_LEVEL) {
261 R_FillBackScreen (); // draw the pattern into the back screen
262 redrawborderstuff = isborder;
263 } else {
264 // CPhipps -
265 // If there is a border, and either there was no border last time,
266 // or the border might need refreshing, then redraw it.
267 redrawborderstuff = isborder && (!isborderstate || borderwillneedredraw);
268 // The border may need redrawing next time if the border surrounds the screen,
269 // and there is a menu being displayed
270 borderwillneedredraw = menuactive && isborder && viewactive && (viewwidth != SCREENWIDTH);
271 }
272 if (redrawborderstuff || (V_GetMode() == VID_MODEGL))
273 R_DrawViewBorder();
274
275 // Now do the drawing
276 if (viewactive)
277 R_RenderPlayerView (&players[displayplayer]);
278 if (automapmode & am_active)
279 AM_Drawer();
280 ST_Drawer((viewheight != SCREENHEIGHT) || ((automapmode & am_active) && !(automapmode & am_overlay)), redrawborderstuff);
281 if (V_GetMode() != VID_MODEGL)
282 R_DrawViewBorder();
283 HU_Drawer();
284 }
285
286 inhelpscreensstate = inhelpscreens;
287 isborderstate = isborder;
288 oldgamestate = wipegamestate = gamestate;
289
290 // draw pause pic
291 if (paused) {
292 // Simplified the "logic" here and no need for x-coord caching - POPE
293 V_DrawNamePatch((320 - V_NamePatchWidth("M_PAUSE"))/2, 4,
294 0, "M_PAUSE", CR_DEFAULT, VPT_STRETCH);
295 }
296
297 // menus go directly to the screen
298 M_Drawer(); // menu is drawn even on top of everything
299#ifdef HAVE_NET
300 NetUpdate(); // send out any new accumulation
301#else
302 D_BuildNewTiccmds();
303#endif
304
305 // normal update
306 if (!wipe || (V_GetMode() == VID_MODEGL))
307 I_FinishUpdate (); // page flip or blit buffer
308 else {
309 // wipe update
310 wipe_EndScreen();
311 D_Wipe();
312 }
313
314 I_EndDisplay();
315
316 //e6y: don't thrash cpu during pausing
317 if (paused) {
318 I_uSleep(1000);
319 }
320}
321
322// CPhipps - Auto screenshot Variables
323
324static int auto_shot_count, auto_shot_time;
325static const char *auto_shot_fname;
326
327//
328// D_DoomLoop()
329//
330// Not a globally visible function,
331// just included for source reference,
332// called by D_DoomMain, never exits.
333// Manages timing and IO,
334// calls all ?_Responder, ?_Ticker, and ?_Drawer,
335// calls I_GetTime, I_StartFrame, and I_StartTic
336//
337
338static void D_DoomLoop(void)
339{
340 for (;;)
341 {
342 WasRenderedInTryRunTics = false;
343 // frame syncronous IO operations
344 I_StartFrame ();
345
346 if (ffmap == gamemap) ffmap = 0;
347
348 // process one or more tics
349 if (singletics)
350 {
351 I_StartTic ();
352 G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
353 if (advancedemo)
354 D_DoAdvanceDemo ();
355 M_Ticker ();
356 G_Ticker ();
357 P_Checksum(gametic);
358 gametic++;
359 maketic++;
360 }
361 else
362 TryRunTics (); // will run at least one tic
363
364 // killough 3/16/98: change consoleplayer to displayplayer
365 if (players[displayplayer].mo) // cph 2002/08/10
366 S_UpdateSounds(players[displayplayer].mo);// move positional sounds
367
368 if (V_GetMode() == VID_MODEGL ?
369 !movement_smooth || !WasRenderedInTryRunTics :
370 !movement_smooth || !WasRenderedInTryRunTics || gamestate != wipegamestate
371 )
372 {
373 // Update display, next frame, with current state.
374 D_Display();
375 }
376
377 // CPhipps - auto screenshot
378 if (auto_shot_fname && !--auto_shot_count) {
379 auto_shot_count = auto_shot_time;
380 M_DoScreenShot(auto_shot_fname);
381 }
382 }
383}
384
385//
386// DEMO LOOP
387//
388
389static int demosequence; // killough 5/2/98: made static
390static int pagetic;
391static const char *pagename; // CPhipps - const
392
393//
394// D_PageTicker
395// Handles timing for warped projection
396//
397void D_PageTicker(void)
398{
399 if (--pagetic < 0)
400 D_AdvanceDemo();
401}
402
403//
404// D_PageDrawer
405//
406static void D_PageDrawer(void)
407{
408 // proff/nicolas 09/14/98 -- now stretchs bitmaps to fullscreen!
409 // CPhipps - updated for new patch drawing
410 // proff - added M_DrawCredits
411 if (pagename)
412 {
413 V_DrawNamePatch(0, 0, 0, pagename, CR_DEFAULT, VPT_STRETCH);
414 }
415 else
416 M_DrawCredits();
417}
418
419//
420// D_AdvanceDemo
421// Called after each demo or intro demosequence finishes
422//
423void D_AdvanceDemo (void)
424{
425 advancedemo = true;
426}
427
428/* killough 11/98: functions to perform demo sequences
429 * cphipps 10/99: constness fixes
430 */
431
432static void D_SetPageName(const char *name)
433{
434 pagename = name;
435}
436
437static void D_DrawTitle1(const char *name)
438{
439 S_StartMusic(mus_intro);
440 pagetic = (TICRATE*170)/35;
441 D_SetPageName(name);
442}
443
444static void D_DrawTitle2(const char *name)
445{
446 S_StartMusic(mus_dm2ttl);
447 D_SetPageName(name);
448}
449
450/* killough 11/98: tabulate demo sequences
451 */
452
453static struct
454{
455 void (*func)(const char *);
456 const char *name;
457} const demostates[][4] =
458 {
459 {
460 {D_DrawTitle1, "TITLEPIC"},
461 {D_DrawTitle1, "TITLEPIC"},
462 {D_DrawTitle2, "TITLEPIC"},
463 {D_DrawTitle1, "TITLEPIC"},
464 },
465
466 {
467 {G_DeferedPlayDemo, "demo1"},
468 {G_DeferedPlayDemo, "demo1"},
469 {G_DeferedPlayDemo, "demo1"},
470 {G_DeferedPlayDemo, "demo1"},
471 },
472 {
473 {D_SetPageName, NULL},
474 {D_SetPageName, NULL},
475 {D_SetPageName, NULL},
476 {D_SetPageName, NULL},
477 },
478
479 {
480 {G_DeferedPlayDemo, "demo2"},
481 {G_DeferedPlayDemo, "demo2"},
482 {G_DeferedPlayDemo, "demo2"},
483 {G_DeferedPlayDemo, "demo2"},
484 },
485
486 {
487 {D_SetPageName, "HELP2"},
488 {D_SetPageName, "HELP2"},
489 {D_SetPageName, "CREDIT"},
490 {D_DrawTitle1, "TITLEPIC"},
491 },
492
493 {
494 {G_DeferedPlayDemo, "demo3"},
495 {G_DeferedPlayDemo, "demo3"},
496 {G_DeferedPlayDemo, "demo3"},
497 {G_DeferedPlayDemo, "demo3"},
498 },
499
500 {
501 {NULL},
502 {NULL},
503 {NULL},
504 {D_SetPageName, "CREDIT"},
505 },
506
507 {
508 {NULL},
509 {NULL},
510 {NULL},
511 {G_DeferedPlayDemo, "demo4"},
512 },
513
514 {
515 {NULL},
516 {NULL},
517 {NULL},
518 {NULL},
519 }
520 };
521
522/*
523 * This cycles through the demo sequences.
524 * killough 11/98: made table-driven
525 */
526
527void D_DoAdvanceDemo(void)
528{
529 players[consoleplayer].playerstate = PST_LIVE; /* not reborn */
530 advancedemo = usergame = paused = false;
531 gameaction = ga_nothing;
532
533 pagetic = TICRATE * 11; /* killough 11/98: default behavior */
534 gamestate = GS_DEMOSCREEN;
535
536 if (netgame && !demoplayback) {
537 demosequence = 0;
538 } else
539 if (!demostates[++demosequence][gamemode].func)
540 demosequence = 0;
541 demostates[demosequence][gamemode].func
542 (demostates[demosequence][gamemode].name);
543}
544
545//
546// D_StartTitle
547//
548void D_StartTitle (void)
549{
550 gameaction = ga_nothing;
551 demosequence = -1;
552 D_AdvanceDemo();
553}
554
555//
556// D_AddFile
557//
558// Rewritten by Lee Killough
559//
560// Ty 08/29/98 - add source parm to indicate where this came from
561// CPhipps - static, const char* parameter
562// - source is an enum
563// - modified to allocate & use new wadfiles array
564void D_AddFile (const char *file, wad_source_t source)
565{
566 char *gwa_filename=NULL;
567
568 wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1));
569 wadfiles[numwadfiles].name =
570 AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad");
571 wadfiles[numwadfiles].src = source; // Ty 08/29/98
572 numwadfiles++;
573 // proff: automatically try to add the gwa files
574 // proff - moved from w_wad.c
575 gwa_filename=AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad");
576 if (strlen(gwa_filename)>4)
577 if (!strcasecmp(gwa_filename+(strlen(gwa_filename)-4),".wad"))
578 {
579 char *ext;
580 ext = &gwa_filename[strlen(gwa_filename)-4];
581 ext[1] = 'g'; ext[2] = 'w'; ext[3] = 'a';
582 wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1));
583 wadfiles[numwadfiles].name = gwa_filename;
584 wadfiles[numwadfiles].src = source; // Ty 08/29/98
585 numwadfiles++;
586 }
587}
588
589// killough 10/98: support -dehout filename
590// cph - made const, don't cache results
591static const char *D_dehout(void)
592{
593 int p = M_CheckParm("-dehout");
594 if (!p)
595 p = M_CheckParm("-bexout");
596 return (p && ++p < myargc ? myargv[p] : NULL);
597}
598
599//
600// CheckIWAD
601//
602// Verify a file is indeed tagged as an IWAD
603// Scan its lumps for levelnames and return gamemode as indicated
604// Detect missing wolf levels in DOOM II
605//
606// The filename to check is passed in iwadname, the gamemode detected is
607// returned in gmode, hassec returns the presence of secret levels
608//
609// jff 4/19/98 Add routine to test IWAD for validity and determine
610// the gamemode from it. Also note if DOOM II, whether secret levels exist
611// CPhipps - const char* for iwadname, made static
612static void CheckIWAD(const char *iwadname,GameMode_t *gmode,boolean *hassec)
613{
614 if ( !access (iwadname,R_OK) )
615 {
616 int ud=0,rg=0,sw=0,cm=0,sc=0;
617 FILE* fp;
618
619 // Identify IWAD correctly
620 if ((fp = fopen(iwadname, "rb")))
621 {
622 wadinfo_t header;
623
624 // read IWAD header
625 if (fread(&header, sizeof(header), 1, fp) == 1 && !strncmp(header.identification, "IWAD", 4))
626 {
627 size_t length;
628 filelump_t *fileinfo;
629
630 // read IWAD directory
631 header.numlumps = LONG(header.numlumps);
632 header.infotableofs = LONG(header.infotableofs);
633 length = header.numlumps;
634 fileinfo = malloc(length*sizeof(filelump_t));
635 if (fseek (fp, header.infotableofs, SEEK_SET) ||
636 fread (fileinfo, sizeof(filelump_t), length, fp) != length ||
637 fclose(fp))
638 I_Error("CheckIWAD: failed to read directory %s",iwadname);
639
640 // scan directory for levelname lumps
641 while (length--)
642 if (fileinfo[length].name[0] == 'E' &&
643 fileinfo[length].name[2] == 'M' &&
644 fileinfo[length].name[4] == 0)
645 {
646 if (fileinfo[length].name[1] == '4')
647 ++ud;
648 else if (fileinfo[length].name[1] == '3')
649 ++rg;
650 else if (fileinfo[length].name[1] == '2')
651 ++rg;
652 else if (fileinfo[length].name[1] == '1')
653 ++sw;
654 }
655 else if (fileinfo[length].name[0] == 'M' &&
656 fileinfo[length].name[1] == 'A' &&
657 fileinfo[length].name[2] == 'P' &&
658 fileinfo[length].name[5] == 0)
659 {
660 ++cm;
661 if (fileinfo[length].name[3] == '3')
662 if (fileinfo[length].name[4] == '1' ||
663 fileinfo[length].name[4] == '2')
664 ++sc;
665 }
666
667 free(fileinfo);
668 }
669 else // missing IWAD tag in header
670 I_Error("CheckIWAD: IWAD tag %s not present", iwadname);
671 }
672 else // error from open call
673 I_Error("CheckIWAD: Can't open IWAD %s", iwadname);
674
675 // Determine game mode from levels present
676 // Must be a full set for whichever mode is present
677 // Lack of wolf-3d levels also detected here
678
679 *gmode = indetermined;
680 *hassec = false;
681 if (cm>=30)
682 {
683 *gmode = commercial;
684 *hassec = sc>=2;
685 }
686 else if (ud>=9)
687 *gmode = retail;
688 else if (rg>=18)
689 *gmode = registered;
690 else if (sw>=9)
691 *gmode = shareware;
692 }
693 else // error from access call
694 I_Error("CheckIWAD: IWAD %s not readable", iwadname);
695}
696
697
698
699// NormalizeSlashes
700//
701// Remove trailing slashes, translate backslashes to slashes
702// The string to normalize is passed and returned in str
703//
704// jff 4/19/98 Make killoughs slash fixer a subroutine
705//
706static void NormalizeSlashes(char *str)
707{
708 int l;
709
710 // killough 1/18/98: Neater / \ handling.
711 // Remove trailing / or \ to prevent // /\ \/ \\, and change \ to /
712
713 if (!str || !(l = strlen(str)))
714 return;
715 if (str[--l]=='/' || str[l]=='\\') // killough 1/18/98
716 str[l]=0;
717 while (l--)
718 if (str[l]=='\\')
719 str[l]='/';
720}
721
722/*
723 * FindIWADFIle
724 *
725 * Search for one of the standard IWADs
726 * CPhipps - static, proper prototype
727 * - 12/1999 - rewritten to use I_FindFile
728 */
729static char *FindIWADFile(void)
730{
731 int i;
732 char * iwad = NULL;
733
734 i = M_CheckParm("-iwad");
735 if (i && (++i < myargc)) {
736 iwad = I_FindFile(myargv[i], ".wad");
737 } else {
738 for (i=0; !iwad && i<nstandard_iwads; i++)
739 iwad = I_FindFile(standard_iwads[i], ".wad");
740 }
741 return iwad;
742}
743
744//
745// IdentifyVersion
746//
747// Set the location of the defaults file and the savegame root
748// Locate and validate an IWAD file
749// Determine gamemode from the IWAD
750//
751// supports IWADs with custom names. Also allows the -iwad parameter to
752// specify which iwad is being searched for if several exist in one dir.
753// The -iwad parm may specify:
754//
755// 1) a specific pathname, which must exist (.wad optional)
756// 2) or a directory, which must contain a standard IWAD,
757// 3) or a filename, which must be found in one of the standard places:
758// a) current dir,
759// b) exe dir
760// c) $DOOMWADDIR
761// d) or $HOME
762//
763// jff 4/19/98 rewritten to use a more advanced search algorithm
764
765static void IdentifyVersion (void)
766{
767 int i; //jff 3/24/98 index of args on commandline
768 struct stat sbuf; //jff 3/24/98 used to test save path for existence
769 char *iwad;
770
771 // set save path to -save parm or current dir
772
773 //jff 3/27/98 default to current dir
774 //V.Aguilar (5/30/99): In LiNUX, default to $HOME/.lxdoom
775 {
776 // CPhipps - use DOOMSAVEDIR if defined
777 char* p = getenv("DOOMSAVEDIR");
778
779 if (p != NULL)
780 if (strlen(p) > PATH_MAX-12) p = NULL;
781
782 strcpy(basesavegame,(p == NULL) ? I_DoomExeDir() : p);
783 }
784 if ((i=M_CheckParm("-save")) && i<myargc-1) //jff 3/24/98 if -save present
785 {
786 if (!stat(myargv[i+1],&sbuf) && S_ISDIR(sbuf.st_mode)) // and is a dir
787 {
788 strcpy(basesavegame,myargv[i+1]); //jff 3/24/98 use that for savegame
789 NormalizeSlashes(basesavegame); //jff 9/22/98 fix c:\ not working
790 }
791 //jff 9/3/98 use logical output routine
792 else lprintf(LO_ERROR,"Error: -save path does not exist, using %s\n", basesavegame);
793 }
794
795 // locate the IWAD and determine game mode from it
796
797 iwad = FindIWADFile();
798
799#if (defined(GL_DOOM) && defined(_DEBUG))
800 // proff 11/99: used for debugging
801 {
802 FILE *f;
803 f=fopen("levelinfo.txt","w");
804 if (f)
805 {
806 fprintf(f,"%s\n",iwad);
807 fclose(f);
808 }
809 }
810#endif
811
812 if (iwad && *iwad)
813 {
814 //jff 9/3/98 use logical output routine
815 lprintf(LO_CONFIRM,"IWAD found: %s\n",iwad); //jff 4/20/98 print only if found
816 CheckIWAD(iwad,&gamemode,&haswolflevels);
817
818 /* jff 8/23/98 set gamemission global appropriately in all cases
819 * cphipps 12/1999 - no version output here, leave that to the caller
820 */
821 switch(gamemode)
822 {
823 case retail:
824 case registered:
825 case shareware:
826 gamemission = doom;
827 break;
828 case commercial:
829 i = strlen(iwad);
830 gamemission = doom2;
831 if (i>=10 && !strnicmp(iwad+i-10,"doom2f.wad",10))
832 language=french;
833 else if (i>=7 && !strnicmp(iwad+i-7,"tnt.wad",7))
834 gamemission = pack_tnt;
835 else if (i>=12 && !strnicmp(iwad+i-12,"plutonia.wad",12))
836 gamemission = pack_plut;
837 break;
838 default:
839 gamemission = none;
840 break;
841 }
842 if (gamemode == indetermined)
843 //jff 9/3/98 use logical output routine
844 lprintf(LO_WARN,"Unknown Game Version, may not work\n");
845 D_AddFile(iwad,source_iwad);
846 free(iwad);
847 }
848 else
849 I_Error("IdentifyVersion: IWAD not found\n");
850}
851
852
853
854// killough 5/3/98: old code removed
855//
856// Find a Response File
857//
858
859#define MAXARGVS 100
860
861static void FindResponseFile (void)
862{
863 int i;
864
865 for (i = 1;i < myargc;i++)
866 if (myargv[i][0] == '@')
867 {
868 int size;
869 int index;
870 int indexinfile;
871 byte *file = NULL;
872 const char **moreargs = malloc(myargc * sizeof(const char*));
873 const char **newargv;
874 // proff 04/05/2000: Added for searching responsefile
875 char fname[PATH_MAX+1];
876
877 strcpy(fname,&myargv[i][1]);
878 AddDefaultExtension(fname,".rsp");
879
880 // READ THE RESPONSE FILE INTO MEMORY
881 // proff 04/05/2000: changed for searching responsefile
882 // cph 2002/08/09 - use M_ReadFile for simplicity
883 size = M_ReadFile(fname, &file);
884 // proff 04/05/2000: Added for searching responsefile
885 if (size < 0)
886 {
887 strcat(strcpy(fname,I_DoomExeDir()),&myargv[i][1]);
888 AddDefaultExtension(fname,".rsp");
889 size = M_ReadFile(fname, &file);
890 }
891 if (size < 0)
892 {
893 /* proff 04/05/2000: Changed from LO_FATAL
894 * proff 04/05/2000: Simply removed the exit(1);
895 * cph - made fatal, don't drop through and SEGV
896 */
897 I_Error("No such response file: %s",fname);
898 }
899 //jff 9/3/98 use logical output routine
900 lprintf(LO_CONFIRM,"Found response file %s\n",fname);
901 // proff 04/05/2000: Added check for empty rsp file
902 if (size<=0)
903 {
904 int k;
905 lprintf(LO_ERROR,"\nResponse file empty!\n");
906
907 newargv = calloc(sizeof(char *),MAXARGVS);
908 newargv[0] = myargv[0];
909 for (k = 1,index = 1;k < myargc;k++)
910 {
911 if (i!=k)
912 newargv[index++] = myargv[k];
913 }
914 myargc = index; myargv = newargv;
915 return;
916 }
917
918 // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
919 memcpy((void *)moreargs,&myargv[i+1],(index = myargc - i - 1) * sizeof(myargv[0]));
920
921 {
922 const char *firstargv = myargv[0];
923 newargv = calloc(sizeof(char *),MAXARGVS);
924 newargv[0] = firstargv;
925 }
926
927 {
928 byte *infile = file;
929 indexinfile = 0;
930 indexinfile++; // SKIP PAST ARGV[0] (KEEP IT)
931 do {
932 while (size > 0 && isspace(*infile)) { infile++; size--; }
933 if (size > 0) {
934 char *s = malloc(size+1);
935 char *p = s;
936 int quoted = 0;
937
938 while (size > 0) {
939 // Whitespace terminates the token unless quoted
940 if (!quoted && isspace(*infile)) break;
941 if (*infile == '\"') {
942 // Quotes are removed but remembered
943 infile++; size--; quoted ^= 1;
944 } else {
945 *p++ = *infile++; size--;
946 }
947 }
948 if (quoted) I_Error("Runaway quoted string in response file");
949
950 // Terminate string, realloc and add to argv
951 *p = 0;
952 newargv[indexinfile++] = realloc(s,strlen(s)+1);
953 }
954 } while(size > 0);
955 }
956 free(file);
957
958 memcpy((void *)&newargv[indexinfile],moreargs,index*sizeof(moreargs[0]));
959 free((void *)moreargs);
960
961 myargc = indexinfile+index; myargv = newargv;
962
963 // DISPLAY ARGS
964 //jff 9/3/98 use logical output routine
965 lprintf(LO_CONFIRM,"%d command-line args:\n",myargc);
966 for (index=1;index<myargc;index++)
967 //jff 9/3/98 use logical output routine
968 lprintf(LO_CONFIRM,"%s\n",myargv[index]);
969 break;
970 }
971}
972
973//
974// DoLooseFiles
975//
976// Take any file names on the command line before the first switch parm
977// and insert the appropriate -file, -deh or -playdemo switch in front
978// of them.
979//
980// Note that more than one -file, etc. entry on the command line won't
981// work, so we have to go get all the valid ones if any that show up
982// after the loose ones. This means that boom fred.wad -file wilma
983// will still load fred.wad and wilma.wad, in that order.
984// The response file code kludges up its own version of myargv[] and
985// unfortunately we have to do the same here because that kludge only
986// happens if there _is_ a response file. Truth is, it's more likely
987// that there will be a need to do one or the other so it probably
988// isn't important. We'll point off to the original argv[], or the
989// area allocated in FindResponseFile, or our own areas from strdups.
990//
991// CPhipps - OUCH! Writing into *myargv is too dodgy, damn
992
993static void DoLooseFiles(void)
994{
995 char *wads[MAXARGVS]; // store the respective loose filenames
996 char *lmps[MAXARGVS];
997 char *dehs[MAXARGVS];
998 int wadcount = 0; // count the loose filenames
999 int lmpcount = 0;
1000 int dehcount = 0;
1001 int i,j,p;
1002 const char **tmyargv; // use these to recreate the argv array
1003 int tmyargc;
1004 boolean skip[MAXARGVS]; // CPhipps - should these be skipped at the end
1005
1006 for (i=0; i<MAXARGVS; i++)
1007 skip[i] = false;
1008
1009 for (i=1;i<myargc;i++)
1010 {
1011 if (*myargv[i] == '-') break; // quit at first switch
1012
1013 // so now we must have a loose file. Find out what kind and store it.
1014 j = strlen(myargv[i]);
1015 if (!stricmp(&myargv[i][j-4],".wad"))
1016 wads[wadcount++] = strdup(myargv[i]);
1017 if (!stricmp(&myargv[i][j-4],".lmp"))
1018 lmps[lmpcount++] = strdup(myargv[i]);
1019 if (!stricmp(&myargv[i][j-4],".deh"))
1020 dehs[dehcount++] = strdup(myargv[i]);
1021 if (!stricmp(&myargv[i][j-4],".bex"))
1022 dehs[dehcount++] = strdup(myargv[i]);
1023 if (myargv[i][j-4] != '.') // assume wad if no extension
1024 wads[wadcount++] = strdup(myargv[i]);
1025 skip[i] = true; // nuke that entry so it won't repeat later
1026 }
1027
1028 // Now, if we didn't find any loose files, we can just leave.
1029 if (wadcount+lmpcount+dehcount == 0) return; // ******* early return ****
1030
1031 if ((p = M_CheckParm ("-file")))
1032 {
1033 skip[p] = true; // nuke the entry
1034 while (++p != myargc && *myargv[p] != '-')
1035 {
1036 wads[wadcount++] = strdup(myargv[p]);
1037 skip[p] = true; // null any we find and save
1038 }
1039 }
1040
1041 if ((p = M_CheckParm ("-deh")))
1042 {
1043 skip[p] = true; // nuke the entry
1044 while (++p != myargc && *myargv[p] != '-')
1045 {
1046 dehs[dehcount++] = strdup(myargv[p]);
1047 skip[p] = true; // null any we find and save
1048 }
1049 }
1050
1051 if ((p = M_CheckParm ("-playdemo")))
1052 {
1053 skip[p] = true; // nuke the entry
1054 while (++p != myargc && *myargv[p] != '-')
1055 {
1056 lmps[lmpcount++] = strdup(myargv[p]);
1057 skip[p] = true; // null any we find and save
1058 }
1059 }
1060
1061 // Now go back and redo the whole myargv array with our stuff in it.
1062 // First, create a new myargv array to copy into
1063 tmyargv = calloc(sizeof(char *),MAXARGVS);
1064 tmyargv[0] = myargv[0]; // invocation
1065 tmyargc = 1;
1066
1067 // put our stuff into it
1068 if (wadcount > 0)
1069 {
1070 tmyargv[tmyargc++] = strdup("-file"); // put the switch in
1071 for (i=0;i<wadcount;)
1072 tmyargv[tmyargc++] = wads[i++]; // allocated by strdup above
1073 }
1074
1075 // for -deh
1076 if (dehcount > 0)
1077 {
1078 tmyargv[tmyargc++] = strdup("-deh");
1079 for (i=0;i<dehcount;)
1080 tmyargv[tmyargc++] = dehs[i++];
1081 }
1082
1083 // for -playdemo
1084 if (lmpcount > 0)
1085 {
1086 tmyargv[tmyargc++] = strdup("-playdemo");
1087 for (i=0;i<lmpcount;)
1088 tmyargv[tmyargc++] = lmps[i++];
1089 }
1090
1091 // then copy everything that's there now
1092 for (i=1;i<myargc;i++)
1093 {
1094 if (!skip[i]) // skip any zapped entries
1095 tmyargv[tmyargc++] = myargv[i]; // pointers are still valid
1096 }
1097 // now make the global variables point to our array
1098 myargv = tmyargv;
1099 myargc = tmyargc;
1100}
1101
1102/* cph - MBF-like wad/deh/bex autoload code */
1103const char *wad_files[MAXLOADFILES], *deh_files[MAXLOADFILES];
1104
1105// CPhipps - misc screen stuff
1106unsigned int desired_screenwidth, desired_screenheight;
1107
1108static void L_SetupConsoleMasks(void) {
1109 int p;
1110 int i;
1111 const char *cena="ICWEFDA",*pos; //jff 9/3/98 use this for parsing console masks // CPhipps - const char*'s
1112
1113 //jff 9/3/98 get mask for console output filter
1114 if ((p = M_CheckParm ("-cout"))) {
1115 lprintf(LO_DEBUG, "mask for stdout console output: ");
1116 if (++p != myargc && *myargv[p] != '-')
1117 for (i=0,cons_output_mask=0;(size_t)i<strlen(myargv[p]);i++)
1118 if ((pos = strchr(cena,toupper(myargv[p][i])))) {
1119 cons_output_mask |= (1<<(pos-cena));
1120 lprintf(LO_DEBUG, "%c", toupper(myargv[p][i]));
1121 }
1122 lprintf(LO_DEBUG, "\n");
1123 }
1124
1125 //jff 9/3/98 get mask for redirected console error filter
1126 if ((p = M_CheckParm ("-cerr"))) {
1127 lprintf(LO_DEBUG, "mask for stderr console output: ");
1128 if (++p != myargc && *myargv[p] != '-')
1129 for (i=0,cons_error_mask=0;(size_t)i<strlen(myargv[p]);i++)
1130 if ((pos = strchr(cena,toupper(myargv[p][i])))) {
1131 cons_error_mask |= (1<<(pos-cena));
1132 lprintf(LO_DEBUG, "%c", toupper(myargv[p][i]));
1133 }
1134 lprintf(LO_DEBUG, "\n");
1135 }
1136}
1137
1138//
1139// D_DoomMainSetup
1140//
1141// CPhipps - the old contents of D_DoomMain, but moved out of the main
1142// line of execution so its stack space can be freed
1143
1144static void D_DoomMainSetup(void)
1145{
1146 int p,slot;
1147
1148 L_SetupConsoleMasks();
1149
1150 setbuf(stdout,NULL);
1151
1152 // proff 04/05/2000: Added support for include response files
1153 /* proff 2001/7/1 - Moved up, so -config can be in response files */
1154 {
1155 boolean rsp_found;
1156 int i;
1157
1158 do {
1159 rsp_found=false;
1160 for (i=0; i<myargc; i++)
1161 if (myargv[i][0]=='@')
1162 rsp_found=true;
1163 FindResponseFile();
1164 } while (rsp_found==true);
1165 }
1166
1167 lprintf(LO_INFO,"M_LoadDefaults: Load system defaults.\n");
1168 M_LoadDefaults(); // load before initing other systems
1169
1170 // figgi 09/18/00-- added switch to force classic bsp nodes
1171 if (M_CheckParm ("-forceoldbsp"))
1172 {
1173 extern boolean forceOldBsp;
1174 forceOldBsp = true;
1175 }
1176
1177 DoLooseFiles(); // Ty 08/29/98 - handle "loose" files on command line
1178 IdentifyVersion();
1179
1180 // e6y: DEH files preloaded in wrong order
1181 // http://sourceforge.net/tracker/index.php?func=detail&aid=1418158&group_id=148658&atid=772943
1182 // The dachaked stuff has been moved below an autoload
1183
1184 // jff 1/24/98 set both working and command line value of play parms
1185 nomonsters = clnomonsters = M_CheckParm ("-nomonsters");
1186 respawnparm = clrespawnparm = M_CheckParm ("-respawn");
1187 fastparm = clfastparm = M_CheckParm ("-fast");
1188 // jff 1/24/98 end of set to both working and command line value
1189
1190 devparm = M_CheckParm ("-devparm");
1191
1192 if (M_CheckParm ("-altdeath"))
1193 deathmatch = 2;
1194 else
1195 if (M_CheckParm ("-deathmatch"))
1196 deathmatch = 1;
1197
1198 {
1199 // CPhipps - localise title variable
1200 // print title for every printed line
1201 // cph - code cleaned and made smaller
1202 const char* doomverstr;
1203
1204 switch ( gamemode ) {
1205 case retail:
1206 doomverstr = "The Ultimate DOOM";
1207 break;
1208 case shareware:
1209 doomverstr = "DOOM Shareware";
1210 break;
1211 case registered:
1212 doomverstr = "DOOM Registered";
1213 break;
1214 case commercial: // Ty 08/27/98 - fixed gamemode vs gamemission
1215 switch (gamemission)
1216 {
1217 case pack_plut:
1218 doomverstr = "DOOM 2: Plutonia Experiment";
1219 break;
1220 case pack_tnt:
1221 doomverstr = "DOOM 2: TNT - Evilution";
1222 break;
1223 default:
1224 doomverstr = "DOOM 2: Hell on Earth";
1225 break;
1226 }
1227 break;
1228 default:
1229 doomverstr = "Public DOOM";
1230 break;
1231 }
1232
1233 /* cphipps - the main display. This shows the build date, copyright, and game type */
1234 lprintf(LO_ALWAYS,"PrBoom (built %s), playing: %s\n"
1235 "PrBoom is released under the GNU General Public license v2.0.\n"
1236 "You are welcome to redistribute it under certain conditions.\n"
1237 "It comes with ABSOLUTELY NO WARRANTY. See the file COPYING for details.\n",
1238 version_date, doomverstr);
1239 }
1240
1241 if (devparm)
1242 //jff 9/3/98 use logical output routine
1243 lprintf(LO_CONFIRM,"%s",D_DEVSTR);
1244
1245 // turbo option
1246 if ((p=M_CheckParm ("-turbo")))
1247 {
1248 int scale = 200;
1249 extern int forwardmove[2];
1250 extern int sidemove[2];
1251
1252 if (p<myargc-1)
1253 scale = atoi(myargv[p+1]);
1254 if (scale < 10)
1255 scale = 10;
1256 if (scale > 400)
1257 scale = 400;
1258 //jff 9/3/98 use logical output routine
1259 lprintf (LO_CONFIRM,"turbo scale: %i%%\n",scale);
1260 forwardmove[0] = forwardmove[0]*scale/100;
1261 forwardmove[1] = forwardmove[1]*scale/100;
1262 sidemove[0] = sidemove[0]*scale/100;
1263 sidemove[1] = sidemove[1]*scale/100;
1264 }
1265
1266 modifiedgame = false;
1267
1268 // get skill / episode / map from parms
1269
1270 startskill = sk_none; // jff 3/24/98 was sk_medium, just note not picked
1271 startepisode = 1;
1272 startmap = 1;
1273 autostart = false;
1274
1275 if ((p = M_CheckParm ("-skill")) && p < myargc-1)
1276 {
1277 startskill = myargv[p+1][0]-'1';
1278 autostart = true;
1279 }
1280
1281 if ((p = M_CheckParm ("-episode")) && p < myargc-1)
1282 {
1283 startepisode = myargv[p+1][0]-'0';
1284 startmap = 1;
1285 autostart = true;
1286 }
1287
1288 if ((p = M_CheckParm ("-timer")) && p < myargc-1 && deathmatch)
1289 {
1290 int time = atoi(myargv[p+1]);
1291 //jff 9/3/98 use logical output routine
1292 lprintf(LO_CONFIRM,"Levels will end after %d minute%s.\n", time, time>1 ? "s" : "");
1293 }
1294
1295 if ((p = M_CheckParm ("-avg")) && p < myargc-1 && deathmatch)
1296 //jff 9/3/98 use logical output routine
1297 lprintf(LO_CONFIRM,"Austin Virtual Gaming: Levels will end after 20 minutes\n");
1298
1299 if ((p = M_CheckParm ("-warp")) || // killough 5/2/98
1300 (p = M_CheckParm ("-wart")))
1301 // Ty 08/29/98 - moved this check later so we can have -warp alone: && p < myargc-1)
1302 {
1303 startmap = 0; // Ty 08/29/98 - allow "-warp x" to go to first map in wad(s)
1304 autostart = true; // Ty 08/29/98 - move outside the decision tree
1305 if (gamemode == commercial)
1306 {
1307 if (p < myargc-1)
1308 startmap = atoi(myargv[p+1]); // Ty 08/29/98 - add test if last parm
1309 }
1310 else // 1/25/98 killough: fix -warp xxx from crashing Doom 1 / UD
1311 {
1312 if (p < myargc-2)
1313 {
1314 startepisode = atoi(myargv[++p]);
1315 startmap = atoi(myargv[p+1]);
1316 }
1317 }
1318 }
1319 // Ty 08/29/98 - later we'll check for startmap=0 and autostart=true
1320 // as a special case that -warp * was used. Actually -warp with any
1321 // non-numeric will do that but we'll only document "*"
1322
1323 //jff 1/22/98 add command line parms to disable sound and music
1324 {
1325 int nosound = M_CheckParm("-nosound");
1326 nomusicparm = nosound || M_CheckParm("-nomusic");
1327 nosfxparm = nosound || M_CheckParm("-nosfx");
1328 }
1329 //jff end of sound/music command line parms
1330
1331 // killough 3/2/98: allow -nodraw -noblit generally
1332 nodrawers = M_CheckParm ("-nodraw");
1333 noblit = M_CheckParm ("-noblit");
1334
1335 //proff 11/22/98: Added setting of viewangleoffset
1336 p = M_CheckParm("-viewangle");
1337 if (p)
1338 {
1339 viewangleoffset = atoi(myargv[p+1]);
1340 viewangleoffset = viewangleoffset<0 ? 0 : (viewangleoffset>7 ? 7 : viewangleoffset);
1341 viewangleoffset = (8-viewangleoffset) * ANG45;
1342 }
1343
1344 // init subsystems
1345
1346 G_ReloadDefaults(); // killough 3/4/98: set defaults just loaded.
1347 // jff 3/24/98 this sets startskill if it was -1
1348
1349 // Video stuff
1350 if ((p = M_CheckParm("-width")))
1351 if (myargv[p+1])
1352 desired_screenwidth = atoi(myargv[p+1]);
1353
1354 if ((p = M_CheckParm("-height")))
1355 if (myargv[p+1])
1356 desired_screenheight = atoi(myargv[p+1]);
1357
1358 if ((p = M_CheckParm("-fullscreen")))
1359 use_fullscreen = 1;
1360
1361 if ((p = M_CheckParm("-nofullscreen")))
1362 use_fullscreen = 0;
1363
1364 // e6y
1365 // New command-line options for setting a window (-window)
1366 // or fullscreen (-nowindow) mode temporarily which is not saved in cfg.
1367 // It works like "-geom" switch
1368 desired_fullscreen = use_fullscreen;
1369 if ((p = M_CheckParm("-window")))
1370 desired_fullscreen = 0;
1371
1372 if ((p = M_CheckParm("-nowindow")))
1373 desired_fullscreen = 1;
1374
1375 { // -geometry handling, change screen size for this session only
1376 // e6y: new code by me
1377 int w, h;
1378
1379 if (!(p = M_CheckParm("-geom")))
1380 p = M_CheckParm("-geometry");
1381
1382 if (!(p && (p+1<myargc) && sscanf(myargv[p+1], "%dx%d", &w, &h) == 2))
1383 {
1384 w = desired_screenwidth;
1385 h = desired_screenheight;
1386 }
1387 I_CalculateRes(w, h);
1388 }
1389
1390#ifdef GL_DOOM
1391 // proff 04/05/2000: for GL-specific switches
1392 gld_InitCommandLine();
1393#endif
1394
1395 //jff 9/3/98 use logical output routine
1396 lprintf(LO_INFO,"V_Init: allocate screens.\n");
1397 V_Init();
1398
1399 // CPhipps - autoloading of wads
1400 // Designed to be general, instead of specific to boomlump.wad
1401 // Some people might find this useful
1402 // cph - support MBF -noload parameter
1403 if (!M_CheckParm("-noload")) {
1404 int i;
1405
1406 for (i=0; i<MAXLOADFILES*2; i++) {
1407 const char *fname = (i < MAXLOADFILES) ? wad_files[i]
1408 : deh_files[i - MAXLOADFILES];
1409 char *fpath;
1410
1411 if (!(fname && *fname)) continue;
1412 // Filename is now stored as a zero terminated string
1413 fpath = I_FindFile(fname, (i < MAXLOADFILES) ? ".wad" : ".bex");
1414 if (!fpath)
1415 lprintf(LO_WARN, "Failed to autoload %s\n", fname);
1416 else {
1417 if (i >= MAXLOADFILES)
1418 ProcessDehFile(fpath, D_dehout(), 0);
1419 else {
1420 D_AddFile(fpath,source_auto_load);
1421 }
1422 modifiedgame = true;
1423 free(fpath);
1424 }
1425 }
1426 }
1427
1428 // e6y: DEH files preloaded in wrong order
1429 // http://sourceforge.net/tracker/index.php?func=detail&aid=1418158&group_id=148658&atid=772943
1430 // The dachaked stuff has been moved from above
1431
1432 // ty 03/09/98 do dehacked stuff
1433 // Note: do this before any other since it is expected by
1434 // the deh patch author that this is actually part of the EXE itself
1435 // Using -deh in BOOM, others use -dehacked.
1436 // Ty 03/18/98 also allow .bex extension. .bex overrides if both exist.
1437
1438 D_BuildBEXTables(); // haleyjd
1439
1440 p = M_CheckParm ("-deh");
1441 if (p)
1442 {
1443 char file[PATH_MAX+1]; // cph - localised
1444 // the parms after p are deh/bex file names,
1445 // until end of parms or another - preceded parm
1446 // Ty 04/11/98 - Allow multiple -deh files in a row
1447
1448 while (++p != myargc && *myargv[p] != '-')
1449 {
1450 AddDefaultExtension(strcpy(file, myargv[p]), ".bex");
1451 if (access(file, F_OK)) // nope
1452 {
1453 AddDefaultExtension(strcpy(file, myargv[p]), ".deh");
1454 if (access(file, F_OK)) // still nope
1455 I_Error("D_DoomMainSetup: Cannot find .deh or .bex file named %s",myargv[p]);
1456 }
1457 // during the beta we have debug output to dehout.txt
1458 ProcessDehFile(file,D_dehout(),0);
1459 }
1460 }
1461 // ty 03/09/98 end of do dehacked stuff
1462
1463 // add any files specified on the command line with -file wadfile
1464 // to the wad list
1465
1466 // killough 1/31/98, 5/2/98: reload hack removed, -wart same as -warp now.
1467
1468 if ((p = M_CheckParm ("-file")))
1469 {
1470 // the parms after p are wadfile/lump names,
1471 // until end of parms or another - preceded parm
1472 modifiedgame = true; // homebrew levels
1473 while (++p != myargc && *myargv[p] != '-')
1474 D_AddFile(myargv[p],source_pwad);
1475 }
1476
1477 if (!(p = M_CheckParm("-playdemo")) || p >= myargc-1) { /* killough */
1478 if ((p = M_CheckParm ("-fastdemo")) && p < myargc-1) /* killough */
1479 fastdemo = true; // run at fastest speed possible
1480 else
1481 p = M_CheckParm ("-timedemo");
1482 }
1483
1484 if (p && p < myargc-1)
1485 {
1486 char file[PATH_MAX+1]; // cph - localised
1487 strcpy(file,myargv[p+1]);
1488 AddDefaultExtension(file,".lmp"); // killough
1489 D_AddFile (file,source_lmp);
1490 //jff 9/3/98 use logical output routine
1491 lprintf(LO_CONFIRM,"Playing demo %s\n",file);
1492 if ((p = M_CheckParm ("-ffmap")) && p < myargc-1) {
1493 ffmap = atoi(myargv[p+1]);
1494 }
1495
1496 }
1497
1498 // internal translucency set to config file value // phares
1499 general_translucency = default_translucency; // phares
1500
1501 // 1/18/98 killough: Z_Init() call moved to i_main.c
1502
1503 // CPhipps - move up netgame init
1504 //jff 9/3/98 use logical output routine
1505 lprintf(LO_INFO,"D_InitNetGame: Checking for network game.\n");
1506 D_InitNetGame();
1507
1508 //jff 9/3/98 use logical output routine
1509 lprintf(LO_INFO,"W_Init: Init WADfiles.\n");
1510 W_Init(); // CPhipps - handling of wadfiles init changed
1511
1512 lprintf(LO_INFO,"\n"); // killough 3/6/98: add a newline, by popular demand :)
1513
1514 // e6y
1515 // option to disable automatic loading of dehacked-in-wad lump
1516 if (!M_CheckParm ("-nodeh"))
1517 if ((p = W_CheckNumForName("DEHACKED")) != -1) // cph - add dehacked-in-a-wad support
1518 ProcessDehFile(NULL, D_dehout(), p);
1519
1520 V_InitColorTranslation(); //jff 4/24/98 load color translation lumps
1521
1522 // killough 2/22/98: copyright / "modified game" / SPA banners removed
1523
1524 // Ty 04/08/98 - Add 5 lines of misc. data, only if nonblank
1525 // The expectation is that these will be set in a .bex file
1526 //jff 9/3/98 use logical output routine
1527 if (*startup1) lprintf(LO_INFO,"%s",startup1);
1528 if (*startup2) lprintf(LO_INFO,"%s",startup2);
1529 if (*startup3) lprintf(LO_INFO,"%s",startup3);
1530 if (*startup4) lprintf(LO_INFO,"%s",startup4);
1531 if (*startup5) lprintf(LO_INFO,"%s",startup5);
1532 // End new startup strings
1533
1534 //jff 9/3/98 use logical output routine
1535 lprintf(LO_INFO,"M_Init: Init miscellaneous info.\n");
1536 M_Init();
1537
1538#ifdef HAVE_NET
1539 // CPhipps - now wait for netgame start
1540 D_CheckNetGame();
1541#endif
1542
1543 //jff 9/3/98 use logical output routine
1544 lprintf(LO_INFO,"R_Init: Init DOOM refresh daemon - ");
1545 R_Init();
1546
1547 //jff 9/3/98 use logical output routine
1548 lprintf(LO_INFO,"\nP_Init: Init Playloop state.\n");
1549 P_Init();
1550
1551 //jff 9/3/98 use logical output routine
1552 lprintf(LO_INFO,"I_Init: Setting up machine state.\n");
1553 I_Init();
1554
1555 //jff 9/3/98 use logical output routine
1556 lprintf(LO_INFO,"S_Init: Setting up sound.\n");
1557 S_Init(snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ );
1558
1559 //jff 9/3/98 use logical output routine
1560 lprintf(LO_INFO,"HU_Init: Setting up heads up display.\n");
1561 HU_Init();
1562
1563 if (!(M_CheckParm("-nodraw") && M_CheckParm("-nosound")))
1564 I_InitGraphics();
1565
1566 //jff 9/3/98 use logical output routine
1567 lprintf(LO_INFO,"ST_Init: Init status bar.\n");
1568 ST_Init();
1569
1570 idmusnum = -1; //jff 3/17/98 insure idmus number is blank
1571
1572 // CPhipps - auto screenshots
1573 if ((p = M_CheckParm("-autoshot")) && (p < myargc-2))
1574 if ((auto_shot_count = auto_shot_time = atoi(myargv[p+1])))
1575 auto_shot_fname = myargv[p+2];
1576
1577 // start the apropriate game based on parms
1578
1579 // killough 12/98:
1580 // Support -loadgame with -record and reimplement -recordfrom.
1581
1582 if ((slot = M_CheckParm("-recordfrom")) && (p = slot+2) < myargc)
1583 G_RecordDemo(myargv[p]);
1584 else
1585 {
1586 slot = M_CheckParm("-loadgame");
1587 if ((p = M_CheckParm("-record")) && ++p < myargc)
1588 {
1589 autostart = true;
1590 G_RecordDemo(myargv[p]);
1591 }
1592 }
1593
1594 if ((p = M_CheckParm ("-checksum")) && ++p < myargc)
1595 {
1596 P_RecordChecksum (myargv[p]);
1597 }
1598
1599 if ((p = M_CheckParm ("-fastdemo")) && ++p < myargc)
1600 { // killough
1601 fastdemo = true; // run at fastest speed possible
1602 timingdemo = true; // show stats after quit
1603 G_DeferedPlayDemo(myargv[p]);
1604 singledemo = true; // quit after one demo
1605 }
1606 else
1607 if ((p = M_CheckParm("-timedemo")) && ++p < myargc)
1608 {
1609 singletics = true;
1610 timingdemo = true; // show stats after quit
1611 G_DeferedPlayDemo(myargv[p]);
1612 singledemo = true; // quit after one demo
1613 }
1614 else
1615 if ((p = M_CheckParm("-playdemo")) && ++p < myargc)
1616 {
1617 G_DeferedPlayDemo(myargv[p]);
1618 singledemo = true; // quit after one demo
1619 }
1620
1621 if (slot && ++slot < myargc)
1622 {
1623 slot = atoi(myargv[slot]); // killough 3/16/98: add slot info
1624 G_LoadGame(slot, true); // killough 5/15/98: add command flag // cph - no filename
1625 }
1626 else
1627 if (!singledemo) { /* killough 12/98 */
1628 if (autostart || netgame)
1629 {
1630 G_InitNew(startskill, startepisode, startmap);
1631 if (demorecording)
1632 G_BeginRecording();
1633 }
1634 else
1635 D_StartTitle(); // start up intro loop
1636 }
1637}
1638
1639//
1640// D_DoomMain
1641//
1642
1643void D_DoomMain(void)
1644{
1645 D_DoomMainSetup(); // CPhipps - setup out of main execution stack
1646
1647 D_DoomLoop (); // never returns
1648}
1649
1650//
1651// GetFirstMap
1652//
1653// Ty 08/29/98 - determine first available map from the loaded wads and run it
1654//
1655
1656void GetFirstMap(int *ep, int *map)
1657{
1658 int i,j; // used to generate map name
1659 boolean done = false; // Ty 09/13/98 - to exit inner loops
1660 char test[6]; // MAPxx or ExMx plus terminator for testing
1661 char name[6]; // MAPxx or ExMx plus terminator for display
1662 boolean newlevel = false; // Ty 10/04/98 - to test for new level
1663 int ix; // index for lookup
1664
1665 strcpy(name,""); // initialize
1666 if (*map == 0) // unknown so go search for first changed one
1667 {
1668 *ep = 1;
1669 *map = 1; // default E1M1 or MAP01
1670 if (gamemode == commercial)
1671 {
1672 for (i=1;!done && i<33;i++) // Ty 09/13/98 - add use of !done
1673 {
1674 sprintf(test,"MAP%02d",i);
1675 ix = W_CheckNumForName(test);
1676 if (ix != -1) // Ty 10/04/98 avoid -1 subscript
1677 {
1678 if (lumpinfo[ix].source == source_pwad)
1679 {
1680 *map = i;
1681 strcpy(name,test); // Ty 10/04/98
1682 done = true; // Ty 09/13/98
1683 newlevel = true; // Ty 10/04/98
1684 }
1685 else
1686 {
1687 if (!*name) // found one, not pwad. First default.
1688 strcpy(name,test);
1689 }
1690 }
1691 }
1692 }
1693 else // one of the others
1694 {
1695 strcpy(name,"E1M1"); // Ty 10/04/98 - default for display
1696 for (i=1;!done && i<5;i++) // Ty 09/13/98 - add use of !done
1697 {
1698 for (j=1;!done && j<10;j++) // Ty 09/13/98 - add use of !done
1699 {
1700 sprintf(test,"E%dM%d",i,j);
1701 ix = W_CheckNumForName(test);
1702 if (ix != -1) // Ty 10/04/98 avoid -1 subscript
1703 {
1704 if (lumpinfo[ix].source == source_pwad)
1705 {
1706 *ep = i;
1707 *map = j;
1708 strcpy(name,test); // Ty 10/04/98
1709 done = true; // Ty 09/13/98
1710 newlevel = true; // Ty 10/04/98
1711 }
1712 else
1713 {
1714 if (!*name) // found one, not pwad. First default.
1715 strcpy(name,test);
1716 }
1717 }
1718 }
1719 }
1720 }
1721 //jff 9/3/98 use logical output routine
1722 lprintf(LO_CONFIRM,"Auto-warping to first %slevel: %s\n",
1723 newlevel ? "new " : "", name); // Ty 10/04/98 - new level test
1724 }
1725}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Main startup and splash screenstuff.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __D_MAIN__
35#define __D_MAIN__
36
37#include "d_event.h"
38#include "w_wad.h"
39
40#ifdef __GNUG__
41#pragma interface
42#endif
43
44/* CPhipps - removed wadfiles[] stuff to w_wad.h */
45
46extern char basesavegame[]; // killough 2/16/98: savegame path
47
48//jff 1/24/98 make command line copies of play modes available
49extern boolean clnomonsters; // checkparm of -nomonsters
50extern boolean clrespawnparm; // checkparm of -respawn
51extern boolean clfastparm; // checkparm of -fast
52//jff end of external declaration of command line playmode
53
54extern boolean nosfxparm;
55extern boolean nomusicparm;
56extern int ffmap;
57
58// Called by IO functions when input is detected.
59void D_PostEvent(event_t* ev);
60
61// Demo stuff
62extern boolean advancedemo;
63void D_AdvanceDemo(void);
64void D_DoAdvanceDemo (void);
65
66//
67// BASE LEVEL
68//
69
70void D_Display(void);
71void D_PageTicker(void);
72void D_StartTitle(void);
73void D_DoomMain(void);
74void D_AddFile (const char *file, wad_source_t source);
75
76/* cph - MBF-like wad/deh/bex autoload code */
77/* proff 2001/7/1 - added prboom.wad as last entry so it's always loaded and
78 doesn't overlap with the cfg settings */
79#define MAXLOADFILES 3
80extern const char *wad_files[MAXLOADFILES], *deh_files[MAXLOADFILES];
81
82#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Networking stuff.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __D_NET__
36#define __D_NET__
37
38#include "d_player.h"
39
40
41#ifdef __GNUG__
42#pragma interface
43#endif
44
45
46//
47// Network play related stuff.
48// There is a data struct that stores network
49// communication related stuff, and another
50// one that defines the actual packets to
51// be transmitted.
52//
53
54#define DOOMCOM_ID 0x12345678l
55
56// Max computers/players in a game.
57#define MAXNETNODES 8
58
59
60typedef enum
61{
62 CMD_SEND = 1,
63 CMD_GET = 2
64
65} command_t;
66
67
68//
69// Network packet data.
70//
71typedef struct
72{
73 // High bit is retransmit request.
74 unsigned checksum;
75 // Only valid if NCMD_RETRANSMIT.
76 byte retransmitfrom;
77
78 byte starttic;
79 byte player;
80 byte numtics;
81 ticcmd_t cmds[BACKUPTICS];
82
83} doomdata_t;
84
85//
86// Startup packet difference
87// SG: 4/12/98
88// Added so we can send more startup data to synch things like
89// bobbing, recoil, etc.
90// this is just mapped over the ticcmd_t array when setup packet is sent
91//
92// Note: the original code takes care of startskill, deathmatch, nomonsters
93// respawn, startepisode, startmap
94// Note: for phase 1 we need to add monsters_remember, variable_friction,
95// weapon_recoil, allow_pushers, over_under, player_bobbing,
96// fastparm, demo_insurance, and the rngseed
97//Stick all options into bytes so we don't need to mess with bitfields
98//WARNING: make sure this doesn't exceed the size of the ticcmds area!
99//sizeof(ticcmd_t)*BACKUPTICS
100//This is the current length of our extra stuff
101//
102//killough 5/2/98: this should all be replaced by calls to G_WriteOptions()
103//and G_ReadOptions(), which were specifically designed to set up packets.
104//By creating a separate struct and functions to read/write the options,
105//you now have two functions and data to maintain instead of just one.
106//If the array in g_game.c which G_WriteOptions()/G_ReadOptions() operates
107//on, is too large (more than sizeof(ticcmd_t)*BACKUPTICS), it can
108//either be shortened, or the net code needs to divide it up
109//automatically into packets. The STARTUPLEN below is non-portable.
110//There's a portable way to do it without having to know the sizes.
111
112#define STARTUPLEN 12
113typedef struct
114{
115 byte monsters_remember;
116 byte variable_friction;
117 byte weapon_recoil;
118 byte allow_pushers;
119 byte over_under;
120 byte player_bobbing;
121 byte fastparm;
122 byte demo_insurance;
123 unsigned long rngseed;
124 char filler[sizeof(ticcmd_t)*BACKUPTICS-STARTUPLEN];
125} startup_t;
126
127typedef enum {
128 // Leave space, so low values corresponding to normal netgame setup packets can be ignored
129 nm_plcolour = 3,
130 nm_savegamename = 4,
131} netmisctype_t;
132
133typedef struct
134{
135 netmisctype_t type;
136 size_t len;
137 byte value[sizeof(ticcmd_t)*BACKUPTICS - sizeof(netmisctype_t) - sizeof(size_t)];
138} netmisc_t;
139
140typedef struct
141{
142 // Supposed to be DOOMCOM_ID?
143 long id;
144
145 // DOOM executes an int to execute commands.
146 short intnum;
147 // Communication between DOOM and the driver.
148 // Is CMD_SEND or CMD_GET.
149 short command;
150 // Is dest for send, set by get (-1 = no packet).
151 short remotenode;
152
153 // Number of bytes in doomdata to be sent
154 short datalength;
155
156 // Info common to all nodes.
157 // Console is allways node 0.
158 short numnodes;
159 // Flag: 1 = no duplication, 2-5 = dup for slow nets.
160 short ticdup;
161 // Flag: 1 = send a backup tic in every packet.
162 short extratics;
163 // Flag: 1 = deathmatch.
164 short deathmatch;
165 // Flag: -1 = new game, 0-5 = load savegame
166 short savegame;
167 short episode; // 1-3
168 short map; // 1-9
169 short skill; // 1-5
170
171 // Info specific to this node.
172 short consoleplayer;
173 short numplayers;
174
175 // These are related to the 3-display mode,
176 // in which two drones looking left and right
177 // were used to render two additional views
178 // on two additional computers.
179 // Probably not operational anymore.
180 // 1 = left, 0 = center, -1 = right
181 short angleoffset;
182 // 1 = drone
183 short drone;
184
185 // The packet data to be sent.
186 doomdata_t data;
187
188} doomcom_t;
189
190// Create any new ticcmds and broadcast to other players.
191#ifdef HAVE_NET
192void NetUpdate (void);
193#else
194void D_BuildNewTiccmds(void);
195#endif
196
197//? how many ticks to run?
198void TryRunTics (void);
199
200// CPhipps - move to header file
201void D_InitNetGame (void); // This does the setup
202void D_CheckNetGame(void); // This waits for game start
203
204// CPhipps - misc info broadcast
205void D_NetSendMisc(netmisctype_t type, size_t len, void* data);
206
207// CPhipps - ask server for a wad file we need
208boolean D_NetGetWad(const char* name);
209
210// Netgame stuff (buffers and pointers, i.e. indices).
211extern doomcom_t *doomcom;
212extern doomdata_t *netbuffer; // This points inside doomcom.
213
214#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Player state structure.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __D_PLAYER__
36#define __D_PLAYER__
37
38
39// The player data structure depends on a number
40// of other structs: items (internal inventory),
41// animation states (closely tied to the sprites
42// used to represent them, unfortunately).
43#include "d_items.h"
44#include "p_pspr.h"
45
46// In addition, the player is just a special
47// case of the generic moving object/actor.
48#include "p_mobj.h"
49
50// Finally, for odd reasons, the player input
51// is buffered within the player data struct,
52// as commands per game tick.
53#include "d_ticcmd.h"
54
55#ifdef __GNUG__
56#pragma interface
57#endif
58
59
60//
61// Player states.
62//
63typedef enum
64{
65 // Playing or camping.
66 PST_LIVE,
67 // Dead on the ground, view follows killer.
68 PST_DEAD,
69 // Ready to restart/respawn???
70 PST_REBORN
71
72} playerstate_t;
73
74
75//
76// Player internal flags, for cheats and debug.
77//
78typedef enum
79{
80 // No clipping, walk through barriers.
81 CF_NOCLIP = 1,
82 // No damage, no health loss.
83 CF_GODMODE = 2,
84 // Not really a cheat, just a debug aid.
85 CF_NOMOMENTUM = 4
86
87} cheat_t;
88
89
90//
91// Extended player object info: player_t
92//
93typedef struct player_s
94{
95 mobj_t* mo;
96 playerstate_t playerstate;
97 ticcmd_t cmd;
98
99 // Determine POV,
100 // including viewpoint bobbing during movement.
101 // Focal origin above r.z
102 fixed_t viewz;
103 // Base height above floor for viewz.
104 fixed_t viewheight;
105 // Bob/squat speed.
106 fixed_t deltaviewheight;
107 // bounded/scaled total momentum.
108 fixed_t bob;
109
110 /* killough 10/98: used for realistic bobbing (i.e. not simply overall speed)
111 * mo->momx and mo->momy represent true momenta experienced by player.
112 * This only represents the thrust that the player applies himself.
113 * This avoids anomolies with such things as Boom ice and conveyors.
114 */
115 fixed_t momx, momy; // killough 10/98
116
117 // This is only used between levels,
118 // mo->health is used during levels.
119 int health;
120 int armorpoints;
121 // Armor type is 0-2.
122 int armortype;
123
124 // Power ups. invinc and invis are tic counters.
125 int powers[NUMPOWERS];
126 boolean cards[NUMCARDS];
127 boolean backpack;
128
129 // Frags, kills of other players.
130 int frags[MAXPLAYERS];
131 weapontype_t readyweapon;
132
133 // Is wp_nochange if not changing.
134 weapontype_t pendingweapon;
135
136 boolean weaponowned[NUMWEAPONS];
137 int ammo[NUMAMMO];
138 int maxammo[NUMAMMO];
139
140 // True if button down last tic.
141 int attackdown;
142 int usedown;
143
144 // Bit flags, for cheats and debug.
145 // See cheat_t, above.
146 int cheats;
147
148 // Refired shots are less accurate.
149 int refire;
150
151 // For intermission stats.
152 int killcount;
153 int itemcount;
154 int secretcount;
155
156 // Hint messages. // CPhipps - const
157 const char* message;
158
159 // For screen flashing (red or bright).
160 int damagecount;
161 int bonuscount;
162
163 // Who did damage (NULL for floors/ceilings).
164 mobj_t* attacker;
165
166 // So gun flashes light up areas.
167 int extralight;
168
169 // Current PLAYPAL, ???
170 // can be set to REDCOLORMAP for pain, etc.
171 int fixedcolormap;
172
173 // Player skin colorshift,
174 // 0-3 for which color to draw player.
175 int colormap;
176
177 // Overlay view sprites (gun, etc).
178 pspdef_t psprites[NUMPSPRITES];
179
180 // True if secret level has been done.
181 boolean didsecret;
182
183} player_t;
184
185
186//
187// INTERMISSION
188// Structure passed e.g. to WI_Start(wb)
189//
190typedef struct
191{
192 boolean in; // whether the player is in game
193
194 // Player stats, kills, collected items etc.
195 int skills;
196 int sitems;
197 int ssecret;
198 int stime;
199 int frags[4];
200 int score; // current score on entry, modified on return
201
202} wbplayerstruct_t;
203
204typedef struct
205{
206 int epsd; // episode # (0-2)
207
208 // if true, splash the secret level
209 boolean didsecret;
210
211 // previous and next levels, origin 0
212 int last;
213 int next;
214
215 int maxkills;
216 int maxitems;
217 int maxsecret;
218 int maxfrags;
219
220 // the par time
221 int partime;
222
223 // index of this player in game
224 int pnum;
225
226 wbplayerstruct_t plyr[MAXPLAYERS];
227
228 // CPhipps - total game time for completed levels so far
229 int totaltimes;
230
231} wbstartstruct_t;
232
233
234#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * MapObj data. Map Objects or mobjs are actors, entities,
31 * thinker, take-your-pick... anything that moves, acts, or
32 * suffers state changes of more or less violent nature.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifndef __D_THINK__
37#define __D_THINK__
38
39#ifdef __GNUG__
40#pragma interface
41#endif
42
43/*
44 * Experimental stuff.
45 * To compile this as "ANSI C with classes"
46 * we will need to handle the various
47 * action functions cleanly.
48 */
49// killough 11/98: convert back to C instead of C++
50typedef void (*actionf_t)();
51//typedef void (*actionf_v)();
52//typedef void (*actionf_p1)( void* );
53//typedef void (*actionf_p2)( void*, void* );
54
55/* Note: In d_deh.c you will find references to these
56 * wherever code pointers and function handlers exist
57 */
58/*
59typedef union
60{
61 actionf_p1 acp1;
62 actionf_v acv;
63 actionf_p2 acp2;
64
65} actionf_t;
66*/
67
68/* Historically, "think_t" is yet another
69 * function pointer to a routine to handle
70 * an actor.
71 */
72typedef actionf_t think_t;
73
74
75/* Doubly linked list of actors. */
76typedef struct thinker_s
77{
78 struct thinker_s* prev;
79 struct thinker_s* next;
80 think_t function;
81
82 /* killough 8/29/98: we maintain thinkers in several equivalence classes,
83 * according to various criteria, so as to allow quicker searches.
84 */
85
86 struct thinker_s *cnext, *cprev; /* Next, previous thinkers in same class */
87
88 /* killough 11/98: count of how many other objects reference
89 * this one using pointers. Used for garbage collection.
90 */
91 unsigned references;
92} thinker_t;
93
94#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * System specific interface stuff.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __D_TICCMD__
35#define __D_TICCMD__
36
37#include "doomtype.h"
38
39#ifdef __GNUG__
40#pragma interface
41#endif
42
43/* The data sampled per tick (single player)
44 * and transmitted to other peers (multiplayer).
45 * Mainly movements/button commands per game tick,
46 * plus a checksum for internal state consistency.
47 * CPhipps - explicitely signed the elements, since they have to be signed to work right
48 */
49typedef struct
50{
51 signed char forwardmove; /* *2048 for move */
52 signed char sidemove; /* *2048 for move */
53 signed short angleturn; /* <<16 for angle delta */
54 short consistancy; /* checks for net game */
55 byte chatchar;
56 byte buttons;
57} ticcmd_t;
58
59#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * all external data is defined here
31 * most of the data is loaded into different structures at run time
32 * some internal structures shared by many modules are here
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifndef __DOOMDATA__
37#define __DOOMDATA__
38
39// The most basic types we use, portability.
40#include "config.h"
41#include "doomtype.h"
42
43//
44// Map level types.
45// The following data structures define the persistent format
46// used in the lumps of the WAD files.
47//
48
49// Lump order in a map WAD: each map needs a couple of lumps
50// to provide a complete scene geometry description.
51enum {
52 ML_LABEL, // A separator, name, ExMx or MAPxx
53 ML_THINGS, // Monsters, items..
54 ML_LINEDEFS, // LineDefs, from editing
55 ML_SIDEDEFS, // SideDefs, from editing
56 ML_VERTEXES, // Vertices, edited and BSP splits generated
57 ML_SEGS, // LineSegs, from LineDefs split by BSP
58 ML_SSECTORS, // SubSectors, list of LineSegs
59 ML_NODES, // BSP nodes
60 ML_SECTORS, // Sectors, from editing
61 ML_REJECT, // LUT, sector-sector visibility
62 ML_BLOCKMAP // LUT, motion clipping, walls/grid element
63};
64
65#ifdef _MSC_VER // proff: This is the same as __attribute__ ((packed)) in GNUC
66#pragma pack(push)
67#pragma pack(1)
68#endif //_MSC_VER
69
70// A single Vertex.
71typedef struct {
72 short x,y;
73} PACKEDATTR mapvertex_t;
74
75// A SideDef, defining the visual appearance of a wall,
76// by setting textures and offsets.
77typedef struct {
78 short textureoffset;
79 short rowoffset;
80 char toptexture[8];
81 char bottomtexture[8];
82 char midtexture[8];
83 short sector; // Front sector, towards viewer.
84} PACKEDATTR mapsidedef_t;
85
86// A LineDef, as used for editing, and as input to the BSP builder.
87
88typedef struct {
89 unsigned short v1;
90 unsigned short v2;
91 unsigned short flags;
92 short special;
93 short tag;
94 // proff 07/23/2006 - support more than 32768 sidedefs
95 // use the unsigned value and special case the -1
96 // sidenum[1] will be -1 (NO_INDEX) if one sided
97 unsigned short sidenum[2];
98} PACKEDATTR maplinedef_t;
99
100#define NO_INDEX ((unsigned short)-1)
101
102//
103// LineDef attributes.
104//
105
106// Solid, is an obstacle.
107#define ML_BLOCKING 1
108
109// Blocks monsters only.
110#define ML_BLOCKMONSTERS 2
111
112// Backside will not be drawn if not two sided.
113#define ML_TWOSIDED 4
114
115// If a texture is pegged, the texture will have
116// the end exposed to air held constant at the
117// top or bottom of the texture (stairs or pulled
118// down things) and will move with a height change
119// of one of the neighbor sectors.
120// Unpegged textures always have the first row of
121// the texture at the top pixel of the line for both
122// top and bottom textures (use next to windows).
123
124// upper texture unpegged
125#define ML_DONTPEGTOP 8
126
127// lower texture unpegged
128#define ML_DONTPEGBOTTOM 16
129
130// In AutoMap: don't map as two sided: IT'S A SECRET!
131#define ML_SECRET 32
132
133// Sound rendering: don't let sound cross two of these.
134#define ML_SOUNDBLOCK 64
135
136// Don't draw on the automap at all.
137#define ML_DONTDRAW 128
138
139// Set if already seen, thus drawn in automap.
140#define ML_MAPPED 256
141
142//jff 3/21/98 Set if line absorbs use by player
143//allow multiple push/switch triggers to be used on one push
144#define ML_PASSUSE 512
145
146// Sector definition, from editing.
147typedef struct {
148 short floorheight;
149 short ceilingheight;
150 char floorpic[8];
151 char ceilingpic[8];
152 short lightlevel;
153 short special;
154 short tag;
155} PACKEDATTR mapsector_t;
156
157// SubSector, as generated by BSP.
158typedef struct {
159 unsigned short numsegs;
160 unsigned short firstseg; // Index of first one; segs are stored sequentially.
161} PACKEDATTR mapsubsector_t;
162
163// LineSeg, generated by splitting LineDefs
164// using partition lines selected by BSP builder.
165typedef struct {
166 unsigned short v1;
167 unsigned short v2;
168 short angle;
169 unsigned short linedef;
170 short side;
171 short offset;
172} PACKEDATTR mapseg_t;
173
174// BSP node structure.
175
176// Indicate a leaf.
177#define NF_SUBSECTOR 0x8000
178
179typedef struct {
180 short x; // Partition line from (x,y) to x+dx,y+dy)
181 short y;
182 short dx;
183 short dy;
184 // Bounding box for each child, clip against view frustum.
185 short bbox[2][4];
186 // If NF_SUBSECTOR its a subsector, else it's a node of another subtree.
187 unsigned short children[2];
188} PACKEDATTR mapnode_t;
189
190// Thing definition, position, orientation and type,
191// plus skill/visibility flags and attributes.
192typedef struct {
193 short x;
194 short y;
195 short angle;
196 short type;
197 short options;
198} PACKEDATTR mapthing_t;
199
200#ifdef _MSC_VER
201#pragma pack(pop)
202#endif //_MSC_VER
203
204#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * DoomDef - basic defines for DOOM, e.g. Version, game mode
31 * and skill level, and display parameters.
32 *
33 *-----------------------------------------------------------------------------
34 */
35
36#ifdef __GNUG__
37#pragma implementation "doomdef.h"
38#endif
39
40#include "doomdef.h"
41
42// Location for any defines turned variables.
43// None.
44
45// proff 08/17/98: Changed for high-res
46int SCREENWIDTH=320;
47int SCREENHEIGHT=200;
48int 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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Internally used data structures for virtually everything,
31 * key definitions, lots of other stuff.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#ifndef __DOOMDEF__
36#define __DOOMDEF__
37
38/* use config.h if autoconf made one -- josh */
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43// killough 4/25/98: Make gcc extensions mean nothing on other compilers
44#ifndef __GNUC__
45#define __attribute__(x)
46#endif
47
48// This must come first, since it redefines malloc(), free(), etc. -- killough:
49#include "z_zone.h"
50
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <ctype.h>
55#include <limits.h>
56
57// this should go here, not in makefile/configure.ac -- josh
58#ifndef O_BINARY
59#define O_BINARY 0
60#endif
61
62#include "m_swap.h"
63#include "version.h"
64
65// Game mode handling - identify IWAD version
66// to handle IWAD dependend animations etc.
67typedef enum {
68 shareware, // DOOM 1 shareware, E1, M9
69 registered, // DOOM 1 registered, E3, M27
70 commercial, // DOOM 2 retail, E1 M34 (DOOM 2 german edition not handled)
71 retail, // DOOM 1 retail, E4, M36
72 indetermined // Well, no IWAD found.
73} GameMode_t;
74
75// Mission packs - might be useful for TC stuff?
76typedef enum {
77 doom, // DOOM 1
78 doom2, // DOOM 2
79 pack_tnt, // TNT mission pack
80 pack_plut, // Plutonia pack
81 none
82} GameMission_t;
83
84// Identify language to use, software localization.
85typedef enum {
86 english,
87 french,
88 german,
89 unknown
90} Language_t;
91
92//
93// For resize of screen, at start of game.
94//
95
96#define BASE_WIDTH 320
97
98// It is educational but futile to change this
99// scaling e.g. to 2. Drawing of status bar,
100// menues etc. is tied to the scale implied
101// by the graphics.
102
103#define INV_ASPECT_RATIO 0.625 /* 0.75, ideally */
104
105// killough 2/8/98: MAX versions for maximum screen sizes
106// allows us to avoid the overhead of dynamic allocation
107// when multiple screen sizes are supported
108
109// proff 08/17/98: Changed for high-res
110#define MAX_SCREENWIDTH 2048
111#define MAX_SCREENHEIGHT 1536
112
113// SCREENWIDTH and SCREENHEIGHT define the visible size
114extern int SCREENWIDTH;
115extern int SCREENHEIGHT;
116// SCREENPITCH is the size of one line in the buffer and
117// can be bigger than the SCREENWIDTH depending on the size
118// of one pixel (8, 16 or 32 bit) and the padding at the
119// end of the line caused by hardware considerations
120extern int SCREENPITCH;
121
122// The maximum number of players, multiplayer/networking.
123#define MAXPLAYERS 4
124
125// phares 5/14/98:
126// DOOM Editor Numbers (aka doomednum in mobj_t)
127
128#define DEN_PLAYER5 4001
129#define DEN_PLAYER6 4002
130#define DEN_PLAYER7 4003
131#define DEN_PLAYER8 4004
132
133// State updates, number of tics / second.
134#define TICRATE 35
135
136// The current state of the game: whether we are playing, gazing
137// at the intermission screen, the game final animation, or a demo.
138
139typedef enum {
140 GS_LEVEL,
141 GS_INTERMISSION,
142 GS_FINALE,
143 GS_DEMOSCREEN
144} gamestate_t;
145
146//
147// Difficulty/skill settings/filters.
148//
149// These are Thing flags
150
151// Skill flags.
152#define MTF_EASY 1
153#define MTF_NORMAL 2
154#define MTF_HARD 4
155// Deaf monsters/do not react to sound.
156#define MTF_AMBUSH 8
157
158/* killough 11/98 */
159#define MTF_NOTSINGLE 16
160#define MTF_NOTDM 32
161#define MTF_NOTCOOP 64
162#define MTF_FRIEND 128
163#define MTF_RESERVED 256
164
165typedef enum {
166 sk_none=-1, //jff 3/24/98 create unpicked skill setting
167 sk_baby=0,
168 sk_easy,
169 sk_medium,
170 sk_hard,
171 sk_nightmare
172} skill_t;
173
174//
175// Key cards.
176//
177
178typedef enum {
179 it_bluecard,
180 it_yellowcard,
181 it_redcard,
182 it_blueskull,
183 it_yellowskull,
184 it_redskull,
185 NUMCARDS
186} card_t;
187
188// The defined weapons, including a marker
189// indicating user has not changed weapon.
190typedef enum {
191 wp_fist,
192 wp_pistol,
193 wp_shotgun,
194 wp_chaingun,
195 wp_missile,
196 wp_plasma,
197 wp_bfg,
198 wp_chainsaw,
199 wp_supershotgun,
200
201 NUMWEAPONS,
202 wp_nochange // No pending weapon change.
203} weapontype_t;
204
205// Ammunition types defined.
206typedef enum {
207 am_clip, // Pistol / chaingun ammo.
208 am_shell, // Shotgun / double barreled shotgun.
209 am_cell, // Plasma rifle, BFG.
210 am_misl, // Missile launcher.
211 NUMAMMO,
212 am_noammo // Unlimited for chainsaw / fist.
213} ammotype_t;
214
215// Power up artifacts.
216typedef enum {
217 pw_invulnerability,
218 pw_strength,
219 pw_invisibility,
220 pw_ironfeet,
221 pw_allmap,
222 pw_infrared,
223 NUMPOWERS
224} powertype_t;
225
226// Power up durations (how many seconds till expiration).
227typedef enum {
228 INVULNTICS = (30*TICRATE),
229 INVISTICS = (60*TICRATE),
230 INFRATICS = (120*TICRATE),
231 IRONTICS = (60*TICRATE)
232} powerduration_t;
233
234// DOOM keyboard definition.
235// This is the stuff configured by Setup.Exe.
236// Most key data are simple ascii (uppercased).
237
238#define KEYD_RIGHTARROW 0xae
239#define KEYD_LEFTARROW 0xac
240#define KEYD_UPARROW 0xad
241#define KEYD_DOWNARROW 0xaf
242#define KEYD_ESCAPE 27
243#define KEYD_ENTER 13
244#define KEYD_TAB 9
245#define KEYD_F1 (0x80+0x3b)
246#define KEYD_F2 (0x80+0x3c)
247#define KEYD_F3 (0x80+0x3d)
248#define KEYD_F4 (0x80+0x3e)
249#define KEYD_F5 (0x80+0x3f)
250#define KEYD_F6 (0x80+0x40)
251#define KEYD_F7 (0x80+0x41)
252#define KEYD_F8 (0x80+0x42)
253#define KEYD_F9 (0x80+0x43)
254#define KEYD_F10 (0x80+0x44)
255#define KEYD_F11 (0x80+0x57)
256#define KEYD_F12 (0x80+0x58)
257#define KEYD_BACKSPACE 127
258#define KEYD_PAUSE 0xff
259#define KEYD_EQUALS 0x3d
260#define KEYD_MINUS 0x2d
261#define KEYD_RSHIFT (0x80+0x36)
262#define KEYD_RCTRL (0x80+0x1d)
263#define KEYD_RALT (0x80+0x38)
264#define KEYD_LALT KEYD_RALT
265#define KEYD_CAPSLOCK 0xba // phares
266
267// phares 3/2/98:
268#define KEYD_INSERT 0xd2
269#define KEYD_HOME 0xc7
270#define KEYD_PAGEUP 0xc9
271#define KEYD_PAGEDOWN 0xd1
272#define KEYD_DEL 0xc8
273#define KEYD_END 0xcf
274#define KEYD_SCROLLLOCK 0xc6
275#define KEYD_SPACEBAR 0x20
276// phares 3/2/98
277
278#define KEYD_NUMLOCK 0xC5 // killough 3/6/98
279
280// cph - Add the numeric keypad keys, as suggested by krose 4/22/99:
281// The way numbers are assigned to keys is a mess, but it's too late to
282// change that easily. At least these additions are don neatly.
283// Codes 0x100-0x200 are reserved for number pad
284
285#define KEYD_KEYPAD0 (0x100 + '0')
286#define KEYD_KEYPAD1 (0x100 + '1')
287#define KEYD_KEYPAD2 (0x100 + '2')
288#define KEYD_KEYPAD3 (0x100 + '3')
289#define KEYD_KEYPAD4 (0x100 + '4')
290#define KEYD_KEYPAD5 (0x100 + '5')
291#define KEYD_KEYPAD6 (0x100 + '6')
292#define KEYD_KEYPAD7 (0x100 + '7')
293#define KEYD_KEYPAD8 (0x100 + '8')
294#define KEYD_KEYPAD9 (0x100 + '9')
295#define KEYD_KEYPADENTER (0x100 + KEYD_ENTER)
296#define KEYD_KEYPADDIVIDE (0x100 + '/')
297#define KEYD_KEYPADMULTIPLY (0x100 + '*')
298#define KEYD_KEYPADMINUS (0x100 + '-')
299#define KEYD_KEYPADPLUS (0x100 + '+')
300#define KEYD_KEYPADPERIOD (0x100 + '.')
301
302// phares 4/19/98:
303// Defines Setup Screen groups that config variables appear in.
304// Used when resetting the defaults for every item in a Setup group.
305
306typedef enum {
307 ss_none,
308 ss_keys,
309 ss_weap,
310 ss_stat,
311 ss_auto,
312 ss_enem,
313 ss_mess,
314 ss_chat,
315 ss_gen, /* killough 10/98 */
316 ss_comp, /* killough 10/98 */
317 ss_max
318} ss_types;
319
320// phares 3/20/98:
321//
322// Player friction is variable, based on controlling
323// linedefs. More friction can create mud, sludge,
324// magnetized floors, etc. Less friction can create ice.
325
326#define MORE_FRICTION_MOMENTUM 15000 // mud factor based on momentum
327#define ORIG_FRICTION 0xE800 // original value
328#define ORIG_FRICTION_FACTOR 2048 // original value
329
330#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Put all global state variables here.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#ifdef __GNUG__
36#pragma implementation "doomstat.h"
37#endif
38#include "doomstat.h"
39
40// Game Mode - identify IWAD as shareware, retail etc.
41GameMode_t gamemode = indetermined;
42GameMission_t gamemission = doom;
43
44// Language.
45Language_t language = english;
46
47// Set if homebrew PWAD stuff has been added.
48boolean modifiedgame;
49
50//-----------------------------------------------------------------------------
51
52// CPhipps - compatibility vars
53complevel_t compatibility_level, default_compatibility_level;
54
55int comp[COMP_TOTAL], default_comp[COMP_TOTAL]; // killough 10/98
56
57// v1.1-like pitched sounds
58int pitched_sounds; // killough
59
60int default_translucency; // config file says // phares
61boolean general_translucency; // true if translucency is ok // phares
62
63int demo_insurance, default_demo_insurance; // killough 1/16/98
64
65int allow_pushers = 1; // MT_PUSH Things // phares 3/10/98
66int default_allow_pushers; // killough 3/1/98: make local to each game
67
68int variable_friction = 1; // ice & mud // phares 3/10/98
69int default_variable_friction; // killough 3/1/98: make local to each game
70
71int weapon_recoil; // weapon recoil // phares
72int default_weapon_recoil; // killough 3/1/98: make local to each game
73
74int player_bobbing; // whether player bobs or not // phares 2/25/98
75int default_player_bobbing; // killough 3/1/98: make local to each game
76
77int monsters_remember; // killough 3/1/98
78int default_monsters_remember;
79
80int monster_infighting=1; // killough 7/19/98: monster<=>monster attacks
81int default_monster_infighting=1;
82
83int monster_friction=1; // killough 10/98: monsters affected by friction
84int default_monster_friction=1;
85
86#ifdef DOGS
87int dogs, default_dogs; // killough 7/19/98: Marine's best friend :)
88int dog_jumping, default_dog_jumping; // killough 10/98
89#endif
90
91// killough 8/8/98: distance friends tend to move towards players
92int distfriend = 128, default_distfriend = 128;
93
94// killough 9/8/98: whether monsters are allowed to strafe or retreat
95int monster_backing, default_monster_backing;
96
97// killough 9/9/98: whether monsters are able to avoid hazards (e.g. crushers)
98int monster_avoid_hazards, default_monster_avoid_hazards;
99
100// killough 9/9/98: whether monsters help friends
101int help_friends, default_help_friends;
102
103int flashing_hom; // killough 10/98
104
105int doom_weapon_toggles; // killough 10/98
106
107int monkeys, default_monkeys;
108
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2006 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * All the global variables that store the internal state.
31 * Theoretically speaking, the internal state of the engine
32 * should be found by looking at the variables collected
33 * here, and every relevant module will have to include
34 * this header file.
35 * In practice, things are a bit messy.
36 *
37 *-----------------------------------------------------------------------------*/
38
39#ifndef __D_STATE__
40#define __D_STATE__
41
42// We need the playr data structure as well.
43#include "d_player.h"
44
45#ifdef __GNUG__
46#pragma interface
47#endif
48
49// ------------------------
50// Command line parameters.
51//
52
53extern boolean nomonsters; // checkparm of -nomonsters
54extern boolean respawnparm; // checkparm of -respawn
55extern boolean fastparm; // checkparm of -fast
56extern boolean devparm; // DEBUG: launched with -devparm
57
58// -----------------------------------------------------
59// Game Mode - identify IWAD as shareware, retail etc.
60//
61
62extern GameMode_t gamemode;
63extern GameMission_t gamemission;
64
65// Set if homebrew PWAD stuff has been added.
66extern boolean modifiedgame;
67
68// CPhipps - new compatibility handling
69extern complevel_t compatibility_level, default_compatibility_level;
70
71// CPhipps - old compatibility testing flags aliased to new handling
72#define compatibility (compatibility_level<=boom_compatibility_compatibility)
73#define demo_compatibility (compatibility_level < boom_compatibility_compatibility)
74#define mbf_features (compatibility_level>=mbf_compatibility)
75
76// v1.1-like pitched sounds
77extern int pitched_sounds; // killough
78
79extern int default_translucency; // config file says // phares
80extern boolean general_translucency; // true if translucency is ok // phares
81
82extern int demo_insurance, default_demo_insurance; // killough 4/5/98
83
84// -------------------------------------------
85// killough 10/98: compatibility vector
86
87enum {
88 comp_telefrag,
89 comp_dropoff,
90 comp_vile,
91 comp_pain,
92 comp_skull,
93 comp_blazing,
94 comp_doorlight,
95 comp_model,
96 comp_god,
97 comp_falloff,
98 comp_floors,
99 comp_skymap,
100 comp_pursuit,
101 comp_doorstuck,
102 comp_staylift,
103 comp_zombie,
104 comp_stairs,
105 comp_infcheat,
106 comp_zerotags,
107 comp_moveblock,
108 comp_respawn, /* cph - this is the inverse of comp_respawnfix from eternity */
109 comp_sound,
110 comp_666,
111 comp_soul,
112 comp_maskedanim,
113 COMP_NUM, /* cph - should be last in sequence */
114 COMP_TOTAL=32 // Some extra room for additional variables
115};
116
117extern int comp[COMP_TOTAL], default_comp[COMP_TOTAL];
118
119// -------------------------------------------
120// Language.
121extern Language_t language;
122
123// -------------------------------------------
124// Selected skill type, map etc.
125//
126
127// Defaults for menu, methinks.
128extern skill_t startskill;
129extern int startepisode;
130extern int startmap;
131
132extern boolean autostart;
133
134// Selected by user.
135extern skill_t gameskill;
136extern int gameepisode;
137extern int gamemap;
138
139// Nightmare mode flag, single player.
140extern boolean respawnmonsters;
141
142// Netgame? Only true if >1 player.
143extern boolean netgame;
144
145// Flag: true only if started as net deathmatch.
146// An enum might handle altdeath/cooperative better.
147extern boolean deathmatch;
148
149// ------------------------------------------
150// Internal parameters for sound rendering.
151// These have been taken from the DOS version,
152// but are not (yet) supported with Linux
153// (e.g. no sound volume adjustment with menu.
154
155// These are not used, but should be (menu).
156// From m_menu.c:
157// Sound FX volume has default, 0 - 15
158// Music volume has default, 0 - 15
159// These are multiplied by 8.
160extern int snd_SfxVolume; // maximum volume for sound
161extern int snd_MusicVolume; // maximum volume for music
162
163// CPhipps - screen parameters
164extern unsigned int desired_screenwidth, desired_screenheight;
165
166// -------------------------
167// Status flags for refresh.
168//
169
170enum automapmode_e {
171 am_active = 1, // currently shown
172 am_overlay= 2, // covers the screen, i.e. not overlay mode
173 am_rotate = 4, // rotates to the player facing direction
174 am_follow = 8, // keep the player centred
175 am_grid =16, // show grid
176};
177extern enum automapmode_e automapmode; // Mode that the automap is in
178
179extern boolean menuactive; // Menu overlayed?
180extern boolean paused; // Game Pause?
181extern boolean nodrawers;
182extern boolean noblit;
183
184// This one is related to the 3-screen display mode.
185// ANG90 = left side, ANG270 = right
186extern int viewangleoffset;
187
188// Player taking events, and displaying.
189extern int consoleplayer;
190extern int displayplayer;
191
192// -------------------------------------
193// Scores, rating.
194// Statistics on a given map, for intermission.
195//
196extern int totalkills, totallive;
197extern int totalitems;
198extern int totalsecret;
199
200// Timer, for scores.
201extern int basetic; /* killough 9/29/98: levelstarttic, adjusted */
202extern int leveltime; // tics in game play for par
203
204// --------------------------------------
205// DEMO playback/recording related stuff.
206
207extern boolean usergame;
208extern boolean demoplayback;
209extern boolean demorecording;
210extern int demover;
211
212// Quit after playing a demo from cmdline.
213extern boolean singledemo;
214// Print timing information after quitting. killough
215extern boolean timingdemo;
216// Run tick clock at fastest speed possible while playing demo. killough
217extern boolean fastdemo;
218
219extern gamestate_t gamestate;
220
221//-----------------------------
222// Internal parameters, fixed.
223// These are set by the engine, and not changed
224// according to user inputs. Partly load from
225// WAD, partly set at startup time.
226
227extern int gametic;
228
229
230// Bookkeeping on players - state.
231extern player_t players[MAXPLAYERS];
232
233// Alive? Disconnected?
234extern boolean playeringame[MAXPLAYERS];
235extern boolean realplayeringame[MAXPLAYERS];
236
237extern mapthing_t *deathmatchstarts; // killough
238extern size_t num_deathmatchstarts; // killough
239
240extern mapthing_t *deathmatch_p;
241
242// Player spawn spots.
243extern mapthing_t playerstarts[];
244
245// Intermission stats.
246// Parameters for world map / intermission.
247extern wbstartstruct_t wminfo;
248
249//-----------------------------------------
250// Internal parameters, used for engine.
251//
252
253// File handling stuff.
254extern FILE *debugfile;
255
256// if true, load all graphics at level load
257extern boolean precache;
258
259// wipegamestate can be set to -1
260// to force a wipe on the next draw
261extern gamestate_t wipegamestate;
262
263extern int mouseSensitivity_horiz; // killough
264extern int mouseSensitivity_vert;
265
266// debug flag to cancel adaptiveness
267extern boolean singletics;
268
269extern int bodyqueslot;
270
271// Needed to store the number of the dummy sky flat.
272// Used for rendering, as well as tracking projectiles etc.
273
274extern int skyflatnum;
275
276extern int maketic;
277
278// Networking and tick handling related.
279#define BACKUPTICS 12
280
281extern ticcmd_t netcmds[][BACKUPTICS];
282extern int ticdup;
283
284//-----------------------------------------------------------------------------
285
286extern int allow_pushers; // MT_PUSH Things // phares 3/10/98
287extern int default_allow_pushers;
288
289extern int variable_friction; // ice & mud // phares 3/10/98
290extern int default_variable_friction;
291
292extern int monsters_remember; // killough 3/1/98
293extern int default_monsters_remember;
294
295extern int weapon_recoil; // weapon recoil // phares
296extern int default_weapon_recoil;
297
298extern int player_bobbing; // whether player bobs or not // phares 2/25/98
299extern int default_player_bobbing; // killough 3/1/98: make local to each game
300
301#ifdef DOGS
302extern int dogs, default_dogs; // killough 7/19/98: Marine's best friend :)
303extern int dog_jumping, default_dog_jumping; // killough 10/98
304#endif
305
306/* killough 8/8/98: distance friendly monsters tend to stay from player */
307extern int distfriend, default_distfriend;
308
309/* killough 9/8/98: whether monsters are allowed to strafe or retreat */
310extern int monster_backing, default_monster_backing;
311
312/* killough 9/9/98: whether monsters intelligently avoid hazards */
313extern int monster_avoid_hazards, default_monster_avoid_hazards;
314
315/* killough 10/98: whether monsters are affected by friction */
316extern int monster_friction, default_monster_friction;
317
318/* killough 9/9/98: whether monsters help friends */
319extern int help_friends, default_help_friends;
320
321extern int flashing_hom; // killough 10/98
322
323extern int doom_weapon_toggles; // killough 10/98
324
325/* killough 7/19/98: whether monsters should fight against each other */
326extern int monster_infighting, default_monster_infighting;
327
328extern int monkeys, default_monkeys;
329
330extern int HelperThing; // type of thing to use for helper
331
332#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2006 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Simple basic typedefs, isolated here to make it easier
31 * separating modules.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#ifndef __DOOMTYPE__
36#define __DOOMTYPE__
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#ifndef __BYTEBOOL__
43#define __BYTEBOOL__
44/* Fixed to use builtin bool type with C++. */
45#ifdef __cplusplus
46typedef bool boolean;
47#else
48typedef enum {false, true} boolean;
49#endif
50typedef unsigned char byte;
51#endif
52
53//e6y
54#ifndef MAX
55#define MAX(a,b) ((a)>(b)?(a):(b))
56#endif
57#ifndef MIN
58#define MIN(a,b) ((a)<(b)?(a):(b))
59#endif
60
61/* cph - Wrapper for the long long type, as Win32 used a different name.
62 * Except I don't know what to test as it's compiler specific
63 * Proff - I fixed it */
64#ifndef _MSC_VER
65typedef signed long long int_64_t;
66typedef unsigned long long uint_64_t;
67// define compiled-specific long-long contstant notation here
68#define LONGLONG(num) (uint_64_t)num ## ll
69#else
70typedef __int64 int_64_t;
71typedef unsigned __int64 uint_64_t;
72// define compiled-specific long-long contstant notation here
73#define LONGLONG(num) (uint_64_t)num
74#undef PATH_MAX
75#define PATH_MAX 1024
76#define strcasecmp _stricmp
77#define strncasecmp _strnicmp
78#define S_ISDIR(x) (((sbuf.st_mode & S_IFDIR)==S_IFDIR)?1:0)
79#endif
80
81#ifdef __GNUC__
82#define CONSTFUNC __attribute__((const))
83#define PUREFUNC __attribute__((pure))
84#define NORETURN __attribute__ ((noreturn))
85#else
86#define CONSTFUNC
87#define PUREFUNC
88#define NORETURN
89#endif
90
91/* CPhipps - use limits.h instead of depreciated values.h */
92#include <limits.h>
93
94/* cph - move compatibility levels here so we can use them in d_server.c */
95typedef enum {
96 doom_12_compatibility, /* Doom v1.2 */
97 doom_1666_compatibility, /* Doom v1.666 */
98 doom2_19_compatibility, /* Doom & Doom 2 v1.9 */
99 ultdoom_compatibility, /* Doom 2 v1.9 */
100 finaldoom_compatibility, /* Final & Ultimate Doom v1.9, and Doom95 */
101 dosdoom_compatibility, /* Early dosdoom & tasdoom */
102 tasdoom_compatibility, /* Early dosdoom & tasdoom */
103 boom_compatibility_compatibility, /* Boom's compatibility mode */
104 boom_201_compatibility, /* Compatible with Boom v2.01 */
105 boom_202_compatibility, /* Compatible with Boom v2.01 */
106 lxdoom_1_compatibility, /* LxDoom v1.3.2+ */
107 mbf_compatibility, /* MBF */
108 prboom_1_compatibility, /* PrBoom 2.03beta? */
109 prboom_2_compatibility, /* PrBoom 2.1.0-2.1.1 */
110 prboom_3_compatibility, /* PrBoom 2.2.x */
111 prboom_4_compatibility, /* PrBoom 2.3.x */
112 prboom_5_compatibility, /* PrBoom 2.4.0 */
113 prboom_6_compatibility, /* Latest PrBoom */
114 MAX_COMPATIBILITY_LEVEL, /* Must be last entry */
115 /* Aliases follow */
116 boom_compatibility = boom_201_compatibility, /* Alias used by G_Compatibility */
117 best_compatibility = prboom_6_compatibility,
118} complevel_t;
119
120/* cph - from v_video.h, needed by gl_struct.h */
121enum patch_translation_e {
122 VPT_NONE = 0, // Normal
123 VPT_FLIP = 1, // Flip image horizontally
124 VPT_TRANS = 2, // Translate image via a translation table
125 VPT_STRETCH = 4, // Stretch to compensate for high-res
126};
127
128#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Globally defined strings.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#ifdef __GNUG__
36#pragma implementation "dstrings.h"
37#endif
38#include "dstrings.h"
39
40
41// killough 1/18/98: remove hardcoded limit, add const:
42const char *const endmsg[]=
43{
44 // DOOM1
45 QUITMSG,
46 "please don't leave, there's more\ndemons to toast!",
47 "let's beat it -- this is turning\ninto a bloodbath!",
48 "i wouldn't leave if i were you.\ndos is much worse.",
49 "you're trying to say you like dos\nbetter than me, right?",
50 "don't leave yet -- there's a\ndemon around that corner!",
51 "ya know, next time you come in here\ni'm gonna toast ya.",
52 "go ahead and leave. see if i care.", // 1/15/98 killough
53
54 // QuitDOOM II messages
55 "you want to quit?\nthen, thou hast lost an eighth!",
56 "don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!",
57 "get outta here and go back\nto your boring programs.",
58 "if i were your boss, i'd \n deathmatch ya in a minute!",
59 "look, bud. you leave now\nand you forfeit your body count!",
60 "just leave. when you come\nback, i'll be waiting with a bat.",
61 "you're lucky i don't smack\nyou for thinking about leaving.", // 1/15/98 killough
62
63 // FinalDOOM?
64
65// Note that these ending "bad taste" strings were commented out
66// in the original id code as the #else case of an #if 1
67// Obviously they were internal playthings before the release of
68// DOOM2 and were not intended for public use.
69//
70// Following messages commented out for now. Bad taste. // phares
71
72// "fuck you, pussy!\nget the fuck out!",
73// "you quit and i'll jizz\nin your cystholes!",
74// "if you leave, i'll make\nthe lord drink my jizz.",
75// "hey, ron! can we say\n'fuck' in the game?",
76// "i'd leave: this is just\nmore monsters and levels.\nwhat a load.",
77// "suck it down, asshole!\nyou're a fucking wimp!",
78// "don't quit now! we're \nstill spending your money!",
79
80 // Internal debug. Different style, too.
81 "THIS IS NO MESSAGE!\nPage intentionally left blank.", // 1/15/98 killough
82};
83
84// killough 1/18/98: remove hardcoded limit and replace with var (silly hack):
85const 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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * DOOM strings, by language.
31 * Note: In BOOM, some new strings hav ebeen defined that are
32 * not found in the French version. A better approach is
33 * to create a BEX text-replacement file for other
34 * languages since any language can be supported that way
35 * without recompiling the program.
36 *
37 *-----------------------------------------------------------------------------*/
38
39#ifndef __DSTRINGS__
40#define __DSTRINGS__
41
42/* All important printed strings.
43 * Language selection (message strings).
44 * Use -DFRENCH etc.
45 */
46
47#ifdef FRENCH
48#include "d_french.h"
49#else
50#include "d_englsh.h"
51#endif
52
53/* Note this is not externally modifiable through DEH/BEX
54 * Misc. other strings.
55 * #define SAVEGAMENAME "boomsav" * killough 3/22/98 *
56 * Ty 05/04/98 - replaced with a modifiable string, see d_deh.c
57 */
58
59/*
60 * File locations,
61 * relative to current position.
62 * Path names are OS-sensitive.
63 */
64#define DEVMAPS "devmaps"
65#define DEVDATA "devdata"
66
67
68/* Not done in french?
69 * QuitDOOM messages *
70 * killough 1/18/98:
71 * replace hardcoded limit with extern var (silly hack, I know)
72 */
73
74#include <stddef.h>
75
76extern const size_t NUM_QUITMESSAGES; /* Calculated in dstrings.c */
77
78extern const char* const endmsg[]; /* killough 1/18/98 const added */
79
80#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Game completion, final screen animation.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#include "doomstat.h"
36#include "d_event.h"
37#include "v_video.h"
38#include "w_wad.h"
39#include "s_sound.h"
40#include "sounds.h"
41#include "d_deh.h" // Ty 03/22/98 - externalizations
42#include "f_finale.h" // CPhipps - hmm...
43
44// Stage of animation:
45// 0 = text, 1 = art screen, 2 = character cast
46static int finalestage; // cph -
47static int finalecount; // made static
48static const char* finaletext; // cph -
49static const char* finaleflat; // made static const
50
51// defines for the end mission display text // phares
52
53#define TEXTSPEED 3 // original value // phares
54#define TEXTWAIT 250 // original value // phares
55#define NEWTEXTSPEED 0.01f // new value // phares
56#define NEWTEXTWAIT 1000 // new value // phares
57
58// CPhipps - removed the old finale screen text message strings;
59// they were commented out for ages already
60// Ty 03/22/98 - ... the new s_WHATEVER extern variables are used
61// in the code below instead.
62
63void F_StartCast (void);
64void F_CastTicker (void);
65boolean F_CastResponder (event_t *ev);
66void F_CastDrawer (void);
67
68void WI_checkForAccelerate(void); // killough 3/28/98: used to
69extern int acceleratestage; // accelerate intermission screens
70static int midstage; // whether we're in "mid-stage"
71
72//
73// F_StartFinale
74//
75void F_StartFinale (void)
76{
77 gameaction = ga_nothing;
78 gamestate = GS_FINALE;
79 automapmode &= ~am_active;
80
81 // killough 3/28/98: clear accelerative text flags
82 acceleratestage = midstage = 0;
83
84 // Okay - IWAD dependend stuff.
85 // This has been changed severly, and
86 // some stuff might have changed in the process.
87 switch ( gamemode )
88 {
89 // DOOM 1 - E1, E3 or E4, but each nine missions
90 case shareware:
91 case registered:
92 case retail:
93 {
94 S_ChangeMusic(mus_victor, true);
95
96 switch (gameepisode)
97 {
98 case 1:
99 finaleflat = bgflatE1; // Ty 03/30/98 - new externalized bg flats
100 finaletext = s_E1TEXT; // Ty 03/23/98 - Was e1text variable.
101 break;
102 case 2:
103 finaleflat = bgflatE2;
104 finaletext = s_E2TEXT; // Ty 03/23/98 - Same stuff for each
105 break;
106 case 3:
107 finaleflat = bgflatE3;
108 finaletext = s_E3TEXT;
109 break;
110 case 4:
111 finaleflat = bgflatE4;
112 finaletext = s_E4TEXT;
113 break;
114 default:
115 // Ouch.
116 break;
117 }
118 break;
119 }
120
121 // DOOM II and missions packs with E1, M34
122 case commercial:
123 {
124 S_ChangeMusic(mus_read_m, true);
125
126 // Ty 08/27/98 - added the gamemission logic
127 switch (gamemap)
128 {
129 case 6:
130 finaleflat = bgflat06;
131 finaletext = (gamemission==pack_tnt) ? s_T1TEXT :
132 (gamemission==pack_plut) ? s_P1TEXT : s_C1TEXT;
133 break;
134 case 11:
135 finaleflat = bgflat11;
136 finaletext = (gamemission==pack_tnt) ? s_T2TEXT :
137 (gamemission==pack_plut) ? s_P2TEXT : s_C2TEXT;
138 break;
139 case 20:
140 finaleflat = bgflat20;
141 finaletext = (gamemission==pack_tnt) ? s_T3TEXT :
142 (gamemission==pack_plut) ? s_P3TEXT : s_C3TEXT;
143 break;
144 case 30:
145 finaleflat = bgflat30;
146 finaletext = (gamemission==pack_tnt) ? s_T4TEXT :
147 (gamemission==pack_plut) ? s_P4TEXT : s_C4TEXT;
148 break;
149 case 15:
150 finaleflat = bgflat15;
151 finaletext = (gamemission==pack_tnt) ? s_T5TEXT :
152 (gamemission==pack_plut) ? s_P5TEXT : s_C5TEXT;
153 break;
154 case 31:
155 finaleflat = bgflat31;
156 finaletext = (gamemission==pack_tnt) ? s_T6TEXT :
157 (gamemission==pack_plut) ? s_P6TEXT : s_C6TEXT;
158 break;
159 default:
160 // Ouch.
161 break;
162 }
163 break;
164 // Ty 08/27/98 - end gamemission logic
165 }
166
167 // Indeterminate.
168 default: // Ty 03/30/98 - not externalized
169 S_ChangeMusic(mus_read_m, true);
170 finaleflat = "F_SKY1"; // Not used anywhere else.
171 finaletext = s_C1TEXT; // FIXME - other text, music?
172 break;
173 }
174
175 finalestage = 0;
176 finalecount = 0;
177}
178
179
180
181boolean F_Responder (event_t *event)
182{
183 if (finalestage == 2)
184 return F_CastResponder (event);
185
186 return false;
187}
188
189// Get_TextSpeed() returns the value of the text display speed // phares
190// Rewritten to allow user-directed acceleration -- killough 3/28/98
191
192static float Get_TextSpeed(void)
193{
194 return midstage ? NEWTEXTSPEED : (midstage=acceleratestage) ?
195 acceleratestage=0, NEWTEXTSPEED : TEXTSPEED;
196}
197
198
199//
200// F_Ticker
201//
202// killough 3/28/98: almost totally rewritten, to use
203// player-directed acceleration instead of constant delays.
204// Now the player can accelerate the text display by using
205// the fire/use keys while it is being printed. The delay
206// automatically responds to the user, and gives enough
207// time to read.
208//
209// killough 5/10/98: add back v1.9 demo compatibility
210//
211
212void F_Ticker(void)
213{
214 int i;
215 if (!demo_compatibility)
216 WI_checkForAccelerate(); // killough 3/28/98: check for acceleration
217 else
218 if (gamemode == commercial && finalecount > 50) // check for skipping
219 for (i=0; i<MAXPLAYERS; i++)
220 if (players[i].cmd.buttons)
221 goto next_level; // go on to the next level
222
223 // advance animation
224 finalecount++;
225
226 if (finalestage == 2)
227 F_CastTicker();
228
229 if (!finalestage)
230 {
231 float speed = demo_compatibility ? TEXTSPEED : Get_TextSpeed();
232 /* killough 2/28/98: changed to allow acceleration */
233 if (finalecount > strlen(finaletext)*speed +
234 (midstage ? NEWTEXTWAIT : TEXTWAIT) ||
235 (midstage && acceleratestage)) {
236 if (gamemode != commercial) // Doom 1 / Ultimate Doom episode end
237 { // with enough time, it's automatic
238 finalecount = 0;
239 finalestage = 1;
240 wipegamestate = -1; // force a wipe
241 if (gameepisode == 3)
242 S_StartMusic(mus_bunny);
243 }
244 else // you must press a button to continue in Doom 2
245 if (!demo_compatibility && midstage)
246 {
247 next_level:
248 if (gamemap == 30)
249 F_StartCast(); // cast of Doom 2 characters
250 else
251 gameaction = ga_worlddone; // next level, e.g. MAP07
252 }
253 }
254 }
255}
256
257//
258// F_TextWrite
259//
260// This program displays the background and text at end-mission // phares
261// text time. It draws both repeatedly so that other displays, // |
262// like the main menu, can be drawn over it dynamically and // V
263// erased dynamically. The TEXTSPEED constant is changed into
264// the Get_TextSpeed function so that the speed of writing the // ^
265// text can be increased, and there's still time to read what's // |
266// written. // phares
267// CPhipps - reformatted
268
269#include "hu_stuff.h"
270extern patchnum_t hu_font[HU_FONTSIZE];
271
272
273static void F_TextWrite (void)
274{
275 V_DrawBackground(finaleflat, 0);
276 { // draw some of the text onto the screen
277 int cx = 10;
278 int cy = 10;
279 const char* ch = finaletext; // CPhipps - const
280 int count = (int)((float)(finalecount - 10)/Get_TextSpeed()); // phares
281 int w;
282
283 if (count < 0)
284 count = 0;
285
286 for ( ; count ; count-- ) {
287 int c = *ch++;
288
289 if (!c)
290 break;
291 if (c == '\n') {
292 cx = 10;
293 cy += 11;
294 continue;
295 }
296
297 c = toupper(c) - HU_FONTSTART;
298 if (c < 0 || c> HU_FONTSIZE) {
299 cx += 4;
300 continue;
301 }
302
303 w = hu_font[c].width;
304 if (cx+w > SCREENWIDTH)
305 break;
306 // CPhipps - patch drawing updated
307 V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
308 cx+=w;
309 }
310 }
311}
312
313//
314// Final DOOM 2 animation
315// Casting by id Software.
316// in order of appearance
317//
318typedef struct
319{
320 const char **name; // CPhipps - const**
321 mobjtype_t type;
322} castinfo_t;
323
324#define MAX_CASTORDER 18 /* Ty - hard coded for now */
325static const castinfo_t castorder[] = { // CPhipps - static const, initialised here
326 { &s_CC_ZOMBIE, MT_POSSESSED },
327 { &s_CC_SHOTGUN, MT_SHOTGUY },
328 { &s_CC_HEAVY, MT_CHAINGUY },
329 { &s_CC_IMP, MT_TROOP },
330 { &s_CC_DEMON, MT_SERGEANT },
331 { &s_CC_LOST, MT_SKULL },
332 { &s_CC_CACO, MT_HEAD },
333 { &s_CC_HELL, MT_KNIGHT },
334 { &s_CC_BARON, MT_BRUISER },
335 { &s_CC_ARACH, MT_BABY },
336 { &s_CC_PAIN, MT_PAIN },
337 { &s_CC_REVEN, MT_UNDEAD },
338 { &s_CC_MANCU, MT_FATSO },
339 { &s_CC_ARCH, MT_VILE },
340 { &s_CC_SPIDER, MT_SPIDER },
341 { &s_CC_CYBER, MT_CYBORG },
342 { &s_CC_HERO, MT_PLAYER },
343 { NULL, 0}
344 };
345
346int castnum;
347int casttics;
348state_t* caststate;
349boolean castdeath;
350int castframes;
351int castonmelee;
352boolean castattacking;
353
354
355//
356// F_StartCast
357//
358
359void F_StartCast (void)
360{
361 wipegamestate = -1; // force a screen wipe
362 castnum = 0;
363 caststate = &states[mobjinfo[castorder[castnum].type].seestate];
364 casttics = caststate->tics;
365 castdeath = false;
366 finalestage = 2;
367 castframes = 0;
368 castonmelee = 0;
369 castattacking = false;
370 S_ChangeMusic(mus_evil, true);
371}
372
373
374//
375// F_CastTicker
376//
377void F_CastTicker (void)
378{
379 int st;
380 int sfx;
381
382 if (--casttics > 0)
383 return; // not time to change state yet
384
385 if (caststate->tics == -1 || caststate->nextstate == S_NULL)
386 {
387 // switch from deathstate to next monster
388 castnum++;
389 castdeath = false;
390 if (castorder[castnum].name == NULL)
391 castnum = 0;
392 if (mobjinfo[castorder[castnum].type].seesound)
393 S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound);
394 caststate = &states[mobjinfo[castorder[castnum].type].seestate];
395 castframes = 0;
396 }
397 else
398 {
399 // just advance to next state in animation
400 if (caststate == &states[S_PLAY_ATK1])
401 goto stopattack; // Oh, gross hack!
402 st = caststate->nextstate;
403 caststate = &states[st];
404 castframes++;
405
406 // sound hacks....
407 switch (st)
408 {
409 case S_PLAY_ATK1: sfx = sfx_dshtgn; break;
410 case S_POSS_ATK2: sfx = sfx_pistol; break;
411 case S_SPOS_ATK2: sfx = sfx_shotgn; break;
412 case S_VILE_ATK2: sfx = sfx_vilatk; break;
413 case S_SKEL_FIST2: sfx = sfx_skeswg; break;
414 case S_SKEL_FIST4: sfx = sfx_skepch; break;
415 case S_SKEL_MISS2: sfx = sfx_skeatk; break;
416 case S_FATT_ATK8:
417 case S_FATT_ATK5:
418 case S_FATT_ATK2: sfx = sfx_firsht; break;
419 case S_CPOS_ATK2:
420 case S_CPOS_ATK3:
421 case S_CPOS_ATK4: sfx = sfx_shotgn; break;
422 case S_TROO_ATK3: sfx = sfx_claw; break;
423 case S_SARG_ATK2: sfx = sfx_sgtatk; break;
424 case S_BOSS_ATK2:
425 case S_BOS2_ATK2:
426 case S_HEAD_ATK2: sfx = sfx_firsht; break;
427 case S_SKULL_ATK2: sfx = sfx_sklatk; break;
428 case S_SPID_ATK2:
429 case S_SPID_ATK3: sfx = sfx_shotgn; break;
430 case S_BSPI_ATK2: sfx = sfx_plasma; break;
431 case S_CYBER_ATK2:
432 case S_CYBER_ATK4:
433 case S_CYBER_ATK6: sfx = sfx_rlaunc; break;
434 case S_PAIN_ATK3: sfx = sfx_sklatk; break;
435 default: sfx = 0; break;
436 }
437
438 if (sfx)
439 S_StartSound (NULL, sfx);
440 }
441
442 if (castframes == 12)
443 {
444 // go into attack frame
445 castattacking = true;
446 if (castonmelee)
447 caststate=&states[mobjinfo[castorder[castnum].type].meleestate];
448 else
449 caststate=&states[mobjinfo[castorder[castnum].type].missilestate];
450 castonmelee ^= 1;
451 if (caststate == &states[S_NULL])
452 {
453 if (castonmelee)
454 caststate=
455 &states[mobjinfo[castorder[castnum].type].meleestate];
456 else
457 caststate=
458 &states[mobjinfo[castorder[castnum].type].missilestate];
459 }
460 }
461
462 if (castattacking)
463 {
464 if (castframes == 24
465 || caststate == &states[mobjinfo[castorder[castnum].type].seestate] )
466 {
467 stopattack:
468 castattacking = false;
469 castframes = 0;
470 caststate = &states[mobjinfo[castorder[castnum].type].seestate];
471 }
472 }
473
474 casttics = caststate->tics;
475 if (casttics == -1)
476 casttics = 15;
477}
478
479
480//
481// F_CastResponder
482//
483
484boolean F_CastResponder (event_t* ev)
485{
486 if (ev->type != ev_keydown)
487 return false;
488
489 if (castdeath)
490 return true; // already in dying frames
491
492 // go into death frame
493 castdeath = true;
494 caststate = &states[mobjinfo[castorder[castnum].type].deathstate];
495 casttics = caststate->tics;
496 castframes = 0;
497 castattacking = false;
498 if (mobjinfo[castorder[castnum].type].deathsound)
499 S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
500
501 return true;
502}
503
504
505static void F_CastPrint (const char* text) // CPhipps - static, const char*
506{
507 const char* ch; // CPhipps - const
508 int c;
509 int cx;
510 int w;
511 int width;
512
513 // find width
514 ch = text;
515 width = 0;
516
517 while (ch)
518 {
519 c = *ch++;
520 if (!c)
521 break;
522 c = toupper(c) - HU_FONTSTART;
523 if (c < 0 || c> HU_FONTSIZE)
524 {
525 width += 4;
526 continue;
527 }
528
529 w = hu_font[c].width;
530 width += w;
531 }
532
533 // draw it
534 cx = 160-width/2;
535 ch = text;
536 while (ch)
537 {
538 c = *ch++;
539 if (!c)
540 break;
541 c = toupper(c) - HU_FONTSTART;
542 if (c < 0 || c> HU_FONTSIZE)
543 {
544 cx += 4;
545 continue;
546 }
547
548 w = hu_font[c].width;
549 // CPhipps - patch drawing updated
550 V_DrawNumPatch(cx, 180, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
551 cx+=w;
552 }
553}
554
555
556//
557// F_CastDrawer
558//
559
560void F_CastDrawer (void)
561{
562 spritedef_t* sprdef;
563 spriteframe_t* sprframe;
564 int lump;
565 boolean flip;
566
567 // erase the entire screen to a background
568 // CPhipps - patch drawing updated
569 V_DrawNamePatch(0,0,0, bgcastcall, CR_DEFAULT, VPT_STRETCH); // Ty 03/30/98 bg texture extern
570
571 F_CastPrint (*(castorder[castnum].name));
572
573 // draw the current frame in the middle of the screen
574 sprdef = &sprites[caststate->sprite];
575 sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK];
576 lump = sprframe->lump[0];
577 flip = (boolean)sprframe->flip[0];
578
579 // CPhipps - patch drawing updated
580 V_DrawNumPatch(160, 170, 0, lump+firstspritelump, CR_DEFAULT,
581 VPT_STRETCH | (flip ? VPT_FLIP : 0));
582}
583
584//
585// F_BunnyScroll
586//
587static const char pfub2[] = { "PFUB2" };
588static const char pfub1[] = { "PFUB1" };
589
590static void F_BunnyScroll (void)
591{
592 char name[10];
593 int stage;
594 static int laststage;
595
596 {
597 int scrolled = 320 - (finalecount-230)/2;
598 if (scrolled <= 0) {
599 V_DrawNamePatch(0, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH);
600 } else if (scrolled >= 320) {
601 V_DrawNamePatch(0, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH);
602 } else {
603 V_DrawNamePatch(320-scrolled, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH);
604 V_DrawNamePatch(-scrolled, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH);
605 }
606 }
607
608 if (finalecount < 1130)
609 return;
610 if (finalecount < 1180)
611 {
612 // CPhipps - patch drawing updated
613 V_DrawNamePatch((320-13*8)/2, (200-8*8)/2,0, "END0", CR_DEFAULT, VPT_STRETCH);
614 laststage = 0;
615 return;
616 }
617
618 stage = (finalecount-1180) / 5;
619 if (stage > 6)
620 stage = 6;
621 if (stage > laststage)
622 {
623 S_StartSound (NULL, sfx_pistol);
624 laststage = stage;
625 }
626
627 sprintf (name,"END%i",stage);
628 // CPhipps - patch drawing updated
629 V_DrawNamePatch((320-13*8)/2, (200-8*8)/2, 0, name, CR_DEFAULT, VPT_STRETCH);
630}
631
632
633//
634// F_Drawer
635//
636void F_Drawer (void)
637{
638 if (finalestage == 2)
639 {
640 F_CastDrawer ();
641 return;
642 }
643
644 if (!finalestage)
645 F_TextWrite ();
646 else
647 {
648 switch (gameepisode)
649 {
650 // CPhipps - patch drawing updated
651 case 1:
652 if ( gamemode == retail )
653 V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH);
654 else
655 V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH);
656 break;
657 case 2:
658 V_DrawNamePatch(0, 0, 0, "VICTORY2", CR_DEFAULT, VPT_STRETCH);
659 break;
660 case 3:
661 F_BunnyScroll ();
662 break;
663 case 4:
664 V_DrawNamePatch(0, 0, 0, "ENDPIC", CR_DEFAULT, VPT_STRETCH);
665 break;
666 }
667 }
668}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Related to f_finale.c, which is called at the end of a level
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __F_FINALE__
36#define __F_FINALE__
37
38#include "doomtype.h"
39#include "d_event.h"
40
41/*
42 * FINALE
43 */
44
45/* Called by main loop. */
46boolean F_Responder (event_t* ev);
47
48/* Called by main loop. */
49void F_Ticker (void);
50
51/* Called by main loop. */
52void F_Drawer (void);
53
54void F_StartFinale (void);
55
56#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Mission begin melt/wipe screen special effect.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40#include "z_zone.h"
41#include "doomdef.h"
42#include "i_video.h"
43#include "v_video.h"
44#include "m_random.h"
45#include "f_wipe.h"
46
47//
48// SCREEN WIPE PACKAGE
49//
50
51// Parts re-written to support true-color video modes. Column-major
52// formatting removed. - POPE
53
54// CPhipps - macros for the source and destination screens
55#define SRC_SCR 2
56#define DEST_SCR 3
57
58static screeninfo_t wipe_scr_start;
59static screeninfo_t wipe_scr_end;
60static screeninfo_t wipe_scr;
61
62static int y_lookup[MAX_SCREENWIDTH];
63
64
65static int wipe_initMelt(int ticks)
66{
67 int i;
68
69 // copy start screen to main screen
70 for(i=0;i<SCREENHEIGHT;i++)
71 memcpy(wipe_scr.data+i*wipe_scr.byte_pitch,
72 wipe_scr_start.data+i*wipe_scr.byte_pitch,
73 SCREENWIDTH*V_GetPixelDepth());
74
75 // setup initial column positions (y<0 => not ready to scroll yet)
76 y_lookup[0] = -(M_Random()%16);
77 for (i=1;i<SCREENWIDTH;i++)
78 {
79 int r = (M_Random()%3) - 1;
80 y_lookup[i] = y_lookup[i-1] + r;
81 if (y_lookup[i] > 0)
82 y_lookup[i] = 0;
83 else
84 if (y_lookup[i] == -16)
85 y_lookup[i] = -15;
86 }
87 return 0;
88}
89
90static int wipe_doMelt(int ticks)
91{
92 boolean done = true;
93 int i;
94 const int depth = V_GetPixelDepth();
95
96 while (ticks--) {
97 for (i=0;i<(SCREENWIDTH);i++) {
98 if (y_lookup[i]<0) {
99 y_lookup[i]++;
100 done = false;
101 continue;
102 }
103 if (y_lookup[i] < SCREENHEIGHT) {
104 byte *s, *d;
105 int j, k, dy;
106
107 /* cph 2001/07/29 -
108 * The original melt rate was 8 pixels/sec, i.e. 25 frames to melt
109 * the whole screen, so make the melt rate depend on SCREENHEIGHT
110 * so it takes no longer in high res
111 */
112 dy = (y_lookup[i] < 16) ? y_lookup[i]+1 : SCREENHEIGHT/25;
113 if (y_lookup[i]+dy >= SCREENHEIGHT)
114 dy = SCREENHEIGHT - y_lookup[i];
115
116 s = wipe_scr_end.data + (y_lookup[i]*wipe_scr_end.byte_pitch+(i*depth));
117 d = wipe_scr.data + (y_lookup[i]*wipe_scr.byte_pitch+(i*depth));
118 for (j=dy;j;j--) {
119 for (k=0; k<depth; k++)
120 d[k] = s[k];
121 d += wipe_scr.byte_pitch;
122 s += wipe_scr_end.byte_pitch;
123 }
124 y_lookup[i] += dy;
125 s = wipe_scr_start.data + (i*depth);
126 d = wipe_scr.data + (y_lookup[i]*wipe_scr.byte_pitch+(i*depth));
127 for (j=SCREENHEIGHT-y_lookup[i];j;j--) {
128 for (k=0; k<depth; k++)
129 d[k] = s[k];
130 d += wipe_scr.byte_pitch;
131 s += wipe_scr_end.byte_pitch;
132 }
133 done = false;
134 }
135 }
136 }
137 return done;
138}
139
140// CPhipps - modified to allocate and deallocate screens[2 to 3] as needed, saving memory
141
142static int wipe_exitMelt(int ticks)
143{
144 V_FreeScreen(&wipe_scr_start);
145 wipe_scr_start.width = 0;
146 wipe_scr_start.height = 0;
147 V_FreeScreen(&wipe_scr_end);
148 wipe_scr_end.width = 0;
149 wipe_scr_end.height = 0;
150 // Paranoia
151 screens[SRC_SCR] = wipe_scr_start;
152 screens[DEST_SCR] = wipe_scr_end;
153 return 0;
154}
155
156int wipe_StartScreen(void)
157{
158 wipe_scr_start.width = SCREENWIDTH;
159 wipe_scr_start.height = SCREENHEIGHT;
160 wipe_scr_start.byte_pitch = screens[0].byte_pitch;
161 wipe_scr_start.short_pitch = screens[0].short_pitch;
162 wipe_scr_start.int_pitch = screens[0].int_pitch;
163 wipe_scr_start.not_on_heap = false;
164 V_AllocScreen(&wipe_scr_start);
165 screens[SRC_SCR] = wipe_scr_start;
166 V_CopyRect(0, 0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0, SRC_SCR, VPT_NONE ); // Copy start screen to buffer
167 return 0;
168}
169
170int wipe_EndScreen(void)
171{
172 wipe_scr_end.width = SCREENWIDTH;
173 wipe_scr_end.height = SCREENHEIGHT;
174 wipe_scr_end.byte_pitch = screens[0].byte_pitch;
175 wipe_scr_end.short_pitch = screens[0].short_pitch;
176 wipe_scr_end.int_pitch = screens[0].int_pitch;
177 wipe_scr_end.not_on_heap = false;
178 V_AllocScreen(&wipe_scr_end);
179 screens[DEST_SCR] = wipe_scr_end;
180 V_CopyRect(0, 0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0, DEST_SCR, VPT_NONE); // Copy end screen to buffer
181 V_CopyRect(0, 0, SRC_SCR, SCREENWIDTH, SCREENHEIGHT, 0, 0, 0 , VPT_NONE); // restore start screen
182 return 0;
183}
184
185// killough 3/5/98: reformatted and cleaned up
186int wipe_ScreenWipe(int ticks)
187{
188 static boolean go; // when zero, stop the wipe
189 if (!go) // initial stuff
190 {
191 go = 1;
192 wipe_scr = screens[0];
193 wipe_initMelt(ticks);
194 }
195 // do a piece of wipe-in
196 if (wipe_doMelt(ticks)) // final stuff
197 {
198 wipe_exitMelt(ticks);
199 go = 0;
200 }
201 return !go;
202}
diff --git a/src/f_wipe.h b/src/f_wipe.h
new file mode 100644
index 0000000..d991a50
--- /dev/null
+++ b/src/f_wipe.h
@@ -0,0 +1,45 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Mission start screen wipe/melt, special effects.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __F_WIPE_H__
35#define __F_WIPE_H__
36
37/*
38 * SCREEN WIPE PACKAGE
39 */
40
41int wipe_ScreenWipe (int ticks);
42int wipe_StartScreen(void);
43int wipe_EndScreen (void);
44
45#endif
diff --git a/src/g_game.c b/src/g_game.c
new file mode 100644
index 0000000..c7984b9
--- /dev/null
+++ b/src/g_game.c
@@ -0,0 +1,2970 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2004 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: none
30 * The original Doom description was none, basically because this file
31 * has everything. This ties up the game logic, linking the menu and
32 * input code to the underlying game by creating & respawning players,
33 * building game tics, calling the underlying thing logic.
34 *
35 *-----------------------------------------------------------------------------
36 */
37
38#include <stdio.h>
39#include <stdarg.h>
40#include <stdlib.h>
41#ifdef _MSC_VER
42#define F_OK 0 /* Check for file existence */
43#define W_OK 2 /* Check for write permission */
44#define R_OK 4 /* Check for read permission */
45#include <io.h>
46#else
47#include <unistd.h>
48#endif
49#include <fcntl.h>
50
51#ifdef HAVE_CONFIG_H
52#include "config.h"
53#endif
54
55#include "doomstat.h"
56#include "d_net.h"
57#include "f_finale.h"
58#include "m_argv.h"
59#include "m_misc.h"
60#include "m_menu.h"
61#include "m_random.h"
62#include "p_setup.h"
63#include "p_saveg.h"
64#include "p_tick.h"
65#include "p_map.h"
66#include "p_checksum.h"
67#include "d_main.h"
68#include "wi_stuff.h"
69#include "hu_stuff.h"
70#include "st_stuff.h"
71#include "am_map.h"
72#include "w_wad.h"
73#include "r_main.h"
74#include "r_draw.h"
75#include "p_map.h"
76#include "s_sound.h"
77#include "dstrings.h"
78#include "sounds.h"
79#include "r_data.h"
80#include "r_sky.h"
81#include "d_deh.h" // Ty 3/27/98 deh declarations
82#include "p_inter.h"
83#include "g_game.h"
84#include "lprintf.h"
85#include "i_main.h"
86#include "i_system.h"
87#include "r_demo.h"
88#include "r_fps.h"
89
90#define SAVEGAMESIZE 0x20000
91#define SAVESTRINGSIZE 24
92
93static size_t savegamesize = SAVEGAMESIZE; // killough
94static boolean netdemo;
95static const byte *demobuffer; /* cph - only used for playback */
96static int demolength; // check for overrun (missing DEMOMARKER)
97static FILE *demofp; /* cph - record straight to file */
98static const byte *demo_p;
99static short consistancy[MAXPLAYERS][BACKUPTICS];
100
101gameaction_t gameaction;
102gamestate_t gamestate;
103skill_t gameskill;
104boolean respawnmonsters;
105int gameepisode;
106int gamemap;
107boolean paused;
108// CPhipps - moved *_loadgame vars here
109static boolean forced_loadgame = false;
110static boolean command_loadgame = false;
111
112boolean usergame; // ok to save / end game
113boolean timingdemo; // if true, exit with report on completion
114boolean fastdemo; // if true, run at full speed -- killough
115boolean nodrawers; // for comparative timing purposes
116boolean noblit; // for comparative timing purposes
117int starttime; // for comparative timing purposes
118boolean deathmatch; // only if started as net death
119boolean netgame; // only true if packets are broadcast
120boolean playeringame[MAXPLAYERS];
121player_t players[MAXPLAYERS];
122int consoleplayer; // player taking events and displaying
123int displayplayer; // view being displayed
124int gametic;
125int basetic; /* killough 9/29/98: for demo sync */
126int totalkills, totallive, totalitems, totalsecret; // for intermission
127boolean demorecording;
128boolean demoplayback;
129int demover;
130boolean singledemo; // quit after playing a demo from cmdline
131wbstartstruct_t wminfo; // parms for world map / intermission
132boolean haswolflevels = false;// jff 4/18/98 wolf levels present
133static byte *savebuffer; // CPhipps - static
134int autorun = false; // always running? // phares
135int totalleveltimes; // CPhipps - total time for all completed levels
136int longtics;
137
138//
139// controls (have defaults)
140//
141
142int key_right;
143int key_left;
144int key_up;
145int key_down;
146int key_menu_right; // phares 3/7/98
147int key_menu_left; // |
148int key_menu_up; // V
149int key_menu_down;
150int key_menu_backspace; // ^
151int key_menu_escape; // |
152int key_menu_enter; // phares 3/7/98
153int key_strafeleft;
154int key_straferight;
155int key_fire;
156int key_use;
157int key_strafe;
158int key_speed;
159int key_escape = KEYD_ESCAPE; // phares 4/13/98
160int key_savegame; // phares
161int key_loadgame; // |
162int key_autorun; // V
163int key_reverse;
164int key_zoomin;
165int key_zoomout;
166int key_chat;
167int key_backspace;
168int key_enter;
169int key_map_right;
170int key_map_left;
171int key_map_up;
172int key_map_down;
173int key_map_zoomin;
174int key_map_zoomout;
175int key_map;
176int key_map_gobig;
177int key_map_follow;
178int key_map_mark;
179int key_map_clear;
180int key_map_grid;
181int key_map_overlay; // cph - map overlay
182int key_map_rotate; // cph - map rotation
183int key_help = KEYD_F1; // phares 4/13/98
184int key_soundvolume;
185int key_hud;
186int key_quicksave;
187int key_endgame;
188int key_messages;
189int key_quickload;
190int key_quit;
191int key_gamma;
192int key_spy;
193int key_pause;
194int key_setup;
195int destination_keys[MAXPLAYERS];
196int key_weapontoggle;
197int key_weapon1;
198int key_weapon2;
199int key_weapon3;
200int key_weapon4;
201int key_weapon5;
202int key_weapon6;
203int key_weapon7; // ^
204int key_weapon8; // |
205int key_weapon9; // phares
206
207int key_screenshot; // killough 2/22/98: screenshot key
208int mousebfire;
209int mousebstrafe;
210int mousebforward;
211int joybfire;
212int joybstrafe;
213int joybuse;
214int joybspeed;
215
216#define MAXPLMOVE (forwardmove[1])
217#define TURBOTHRESHOLD 0x32
218#define SLOWTURNTICS 6
219#define QUICKREVERSE (short)32768 // 180 degree reverse // phares
220#define NUMKEYS 512
221
222fixed_t forwardmove[2] = {0x19, 0x32};
223fixed_t sidemove[2] = {0x18, 0x28};
224fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
225
226// CPhipps - made lots of key/button state vars static
227static boolean gamekeydown[NUMKEYS];
228static int turnheld; // for accelerative turning
229
230static boolean mousearray[4];
231static boolean *mousebuttons = &mousearray[1]; // allow [-1]
232
233// mouse values are used once
234static int mousex;
235static int mousey;
236static int dclicktime;
237static int dclickstate;
238static int dclicks;
239static int dclicktime2;
240static int dclickstate2;
241static int dclicks2;
242
243// joystick values are repeated
244static int joyxmove;
245static int joyymove;
246static boolean joyarray[5];
247static boolean *joybuttons = &joyarray[1]; // allow [-1]
248
249// Game events info
250static buttoncode_t special_event; // Event triggered by local player, to send
251static byte savegameslot; // Slot to load if gameaction == ga_loadgame
252char savedescription[SAVEDESCLEN]; // Description to save in savegame if gameaction == ga_savegame
253
254//jff 3/24/98 define defaultskill here
255int defaultskill; //note 1-based
256
257// killough 2/8/98: make corpse queue variable in size
258int bodyqueslot, bodyquesize; // killough 2/8/98
259mobj_t **bodyque = 0; // phares 8/10/98
260
261static void G_DoSaveGame (boolean menu);
262static const byte* G_ReadDemoHeader(const byte* demo_p, size_t size, boolean failonerror);
263
264//
265// G_BuildTiccmd
266// Builds a ticcmd from all of the available inputs
267// or reads it from the demo buffer.
268// If recording a demo, write it out
269//
270static inline signed char fudgef(signed char b)
271{
272 static int c;
273 if (!b || !demo_compatibility || longtics) return b;
274 if (++c & 0x1f) return b;
275 b |= 1; if (b>2) b-=2;
276 return b;
277}
278
279static inline signed short fudgea(signed short b)
280{
281 if (!b || !demo_compatibility || !longtics) return b;
282 b |= 1; if (b>2) b-=2;
283 return b;
284}
285
286
287void G_BuildTiccmd(ticcmd_t* cmd)
288{
289 boolean strafe;
290 boolean bstrafe;
291 int speed;
292 int tspeed;
293 int forward;
294 int side;
295 int newweapon; // phares
296 /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */
297 memset(cmd,0,sizeof*cmd);
298 cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS];
299
300 strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
301 || joybuttons[joybstrafe];
302 //e6y: the "RUN" key inverts the autorun state
303 speed = (gamekeydown[key_speed] || joybuttons[joybspeed] ? !autorun : autorun); // phares
304
305 forward = side = 0;
306
307 // use two stage accelerative turning
308 // on the keyboard and joystick
309 if (joyxmove < 0 || joyxmove > 0 ||
310 gamekeydown[key_right] || gamekeydown[key_left])
311 turnheld += ticdup;
312 else
313 turnheld = 0;
314
315 if (turnheld < SLOWTURNTICS)
316 tspeed = 2; // slow turn
317 else
318 tspeed = speed;
319
320 // turn 180 degrees in one keystroke? // phares
321 // |
322 if (gamekeydown[key_reverse]) // V
323 {
324 cmd->angleturn += QUICKREVERSE; // ^
325 gamekeydown[key_reverse] = false; // |
326 } // phares
327
328 // let movement keys cancel each other out
329
330 if (strafe)
331 {
332 if (gamekeydown[key_right])
333 side += sidemove[speed];
334 if (gamekeydown[key_left])
335 side -= sidemove[speed];
336 if (joyxmove > 0)
337 side += sidemove[speed];
338 if (joyxmove < 0)
339 side -= sidemove[speed];
340 }
341 else
342 {
343 if (gamekeydown[key_right])
344 cmd->angleturn -= angleturn[tspeed];
345 if (gamekeydown[key_left])
346 cmd->angleturn += angleturn[tspeed];
347 if (joyxmove > 0)
348 cmd->angleturn -= angleturn[tspeed];
349 if (joyxmove < 0)
350 cmd->angleturn += angleturn[tspeed];
351 }
352
353 if (gamekeydown[key_up])
354 forward += forwardmove[speed];
355 if (gamekeydown[key_down])
356 forward -= forwardmove[speed];
357 if (joyymove < 0)
358 forward += forwardmove[speed];
359 if (joyymove > 0)
360 forward -= forwardmove[speed];
361 if (gamekeydown[key_straferight])
362 side += sidemove[speed];
363 if (gamekeydown[key_strafeleft])
364 side -= sidemove[speed];
365
366 // buttons
367 cmd->chatchar = HU_dequeueChatChar();
368
369 if (gamekeydown[key_fire] || mousebuttons[mousebfire] ||
370 joybuttons[joybfire])
371 cmd->buttons |= BT_ATTACK;
372
373 if (gamekeydown[key_use] || joybuttons[joybuse])
374 {
375 cmd->buttons |= BT_USE;
376 // clear double clicks if hit use button
377 dclicks = 0;
378 }
379
380 // Toggle between the top 2 favorite weapons. // phares
381 // If not currently aiming one of these, switch to // phares
382 // the favorite. Only switch if you possess the weapon. // phares
383
384 // killough 3/22/98:
385 //
386 // Perform automatic weapons switch here rather than in p_pspr.c,
387 // except in demo_compatibility mode.
388 //
389 // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left
390
391 if ((!demo_compatibility && players[consoleplayer].attackdown && // killough
392 !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle])
393 newweapon = P_SwitchWeapon(&players[consoleplayer]); // phares
394 else
395 { // phares 02/26/98: Added gamemode checks
396 newweapon =
397 gamekeydown[key_weapon1] ? wp_fist : // killough 5/2/98: reformatted
398 gamekeydown[key_weapon2] ? wp_pistol :
399 gamekeydown[key_weapon3] ? wp_shotgun :
400 gamekeydown[key_weapon4] ? wp_chaingun :
401 gamekeydown[key_weapon5] ? wp_missile :
402 gamekeydown[key_weapon6] && gamemode != shareware ? wp_plasma :
403 gamekeydown[key_weapon7] && gamemode != shareware ? wp_bfg :
404 gamekeydown[key_weapon8] ? wp_chainsaw :
405 (!demo_compatibility && gamekeydown[key_weapon9] && gamemode == commercial) ? wp_supershotgun :
406 wp_nochange;
407
408 // killough 3/22/98: For network and demo consistency with the
409 // new weapons preferences, we must do the weapons switches here
410 // instead of in p_user.c. But for old demos we must do it in
411 // p_user.c according to the old rules. Therefore demo_compatibility
412 // determines where the weapons switch is made.
413
414 // killough 2/8/98:
415 // Allow user to switch to fist even if they have chainsaw.
416 // Switch to fist or chainsaw based on preferences.
417 // Switch to shotgun or SSG based on preferences.
418
419 if (!demo_compatibility)
420 {
421 const player_t *player = &players[consoleplayer];
422
423 // only select chainsaw from '1' if it's owned, it's
424 // not already in use, and the player prefers it or
425 // the fist is already in use, or the player does not
426 // have the berserker strength.
427
428 if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] &&
429 player->readyweapon!=wp_chainsaw &&
430 (player->readyweapon==wp_fist ||
431 !player->powers[pw_strength] ||
432 P_WeaponPreferred(wp_chainsaw, wp_fist)))
433 newweapon = wp_chainsaw;
434
435 // Select SSG from '3' only if it's owned and the player
436 // does not have a shotgun, or if the shotgun is already
437 // in use, or if the SSG is not already in use and the
438 // player prefers it.
439
440 if (newweapon == wp_shotgun && gamemode == commercial &&
441 player->weaponowned[wp_supershotgun] &&
442 (!player->weaponowned[wp_shotgun] ||
443 player->readyweapon == wp_shotgun ||
444 (player->readyweapon != wp_supershotgun &&
445 P_WeaponPreferred(wp_supershotgun, wp_shotgun))))
446 newweapon = wp_supershotgun;
447 }
448 // killough 2/8/98, 3/22/98 -- end of weapon selection changes
449 }
450
451 if (newweapon != wp_nochange)
452 {
453 cmd->buttons |= BT_CHANGE;
454 cmd->buttons |= newweapon<<BT_WEAPONSHIFT;
455 }
456
457 // mouse
458 if (mousebuttons[mousebforward])
459 forward += forwardmove[speed];
460
461 // forward double click
462 if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
463 {
464 dclickstate = mousebuttons[mousebforward];
465 if (dclickstate)
466 dclicks++;
467 if (dclicks == 2)
468 {
469 cmd->buttons |= BT_USE;
470 dclicks = 0;
471 }
472 else
473 dclicktime = 0;
474 }
475 else
476 if ((dclicktime += ticdup) > 20)
477 {
478 dclicks = 0;
479 dclickstate = 0;
480 }
481
482 // strafe double click
483
484 bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
485 if (bstrafe != dclickstate2 && dclicktime2 > 1 )
486 {
487 dclickstate2 = bstrafe;
488 if (dclickstate2)
489 dclicks2++;
490 if (dclicks2 == 2)
491 {
492 cmd->buttons |= BT_USE;
493 dclicks2 = 0;
494 }
495 else
496 dclicktime2 = 0;
497 }
498 else
499 if ((dclicktime2 += ticdup) > 20)
500 {
501 dclicks2 = 0;
502 dclickstate2 = 0;
503 }
504 forward += mousey;
505 if (strafe)
506 side += mousex / 4; /* mead Don't want to strafe as fast as turns.*/
507 else
508 cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */
509
510 mousex = mousey = 0;
511
512 if (forward > MAXPLMOVE)
513 forward = MAXPLMOVE;
514 else if (forward < -MAXPLMOVE)
515 forward = -MAXPLMOVE;
516 if (side > MAXPLMOVE)
517 side = MAXPLMOVE;
518 else if (side < -MAXPLMOVE)
519 side = -MAXPLMOVE;
520
521 cmd->forwardmove += fudgef((signed char)forward);
522 cmd->sidemove += side;
523 cmd->angleturn = fudgea(cmd->angleturn);
524
525 // CPhipps - special events (game new/load/save/pause)
526 if (special_event & BT_SPECIAL) {
527 cmd->buttons = special_event;
528 special_event = 0;
529 }
530}
531
532//
533// G_RestartLevel
534//
535
536void G_RestartLevel(void)
537{
538 special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK);
539}
540
541#include "z_bmalloc.h"
542//
543// G_DoLoadLevel
544//
545
546static void G_DoLoadLevel (void)
547{
548 int i;
549
550 // Set the sky map.
551 // First thing, we have a dummy sky texture name,
552 // a flat. The data is in the WAD only because
553 // we look for an actual index, instead of simply
554 // setting one.
555
556 skyflatnum = R_FlatNumForName ( SKYFLATNAME );
557
558 // DOOM determines the sky texture to be used
559 // depending on the current episode, and the game version.
560 if (gamemode == commercial)
561 // || gamemode == pack_tnt //jff 3/27/98 sorry guys pack_tnt,pack_plut
562 // || gamemode == pack_plut) //aren't gamemodes, this was matching retail
563 {
564 skytexture = R_TextureNumForName ("SKY3");
565 if (gamemap < 12)
566 skytexture = R_TextureNumForName ("SKY1");
567 else
568 if (gamemap < 21)
569 skytexture = R_TextureNumForName ("SKY2");
570 }
571 else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh?
572 switch (gameepisode)
573 {
574 case 1:
575 skytexture = R_TextureNumForName ("SKY1");
576 break;
577 case 2:
578 skytexture = R_TextureNumForName ("SKY2");
579 break;
580 case 3:
581 skytexture = R_TextureNumForName ("SKY3");
582 break;
583 case 4: // Special Edition sky
584 skytexture = R_TextureNumForName ("SKY4");
585 break;
586 }//jff 3/27/98 end sky setting fix
587
588 /* cph 2006/07/31 - took out unused levelstarttic variable */
589
590 if (!demo_compatibility && !mbf_features) // killough 9/29/98
591 basetic = gametic;
592
593 if (wipegamestate == GS_LEVEL)
594 wipegamestate = -1; // force a wipe
595
596 gamestate = GS_LEVEL;
597
598 for (i=0 ; i<MAXPLAYERS ; i++)
599 {
600 if (playeringame[i] && players[i].playerstate == PST_DEAD)
601 players[i].playerstate = PST_REBORN;
602 memset (players[i].frags,0,sizeof(players[i].frags));
603 }
604
605 // initialize the msecnode_t freelist. phares 3/25/98
606 // any nodes in the freelist are gone by now, cleared
607 // by Z_FreeTags() when the previous level ended or player
608 // died.
609
610 {
611 DECLARE_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
612 NULL_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
613 //extern msecnode_t *headsecnode; // phares 3/25/98
614 //headsecnode = NULL;
615 }
616
617 P_SetupLevel (gameepisode, gamemap, 0, gameskill);
618 if (!demoplayback) // Don't switch views if playing a demo
619 displayplayer = consoleplayer; // view the guy you are playing
620 gameaction = ga_nothing;
621 Z_CheckHeap ();
622
623 // clear cmd building stuff
624 memset (gamekeydown, 0, sizeof(gamekeydown));
625 joyxmove = joyymove = 0;
626 mousex = mousey = 0;
627 special_event = 0; paused = false;
628 memset (mousebuttons, 0, sizeof(mousebuttons));
629 memset (joybuttons, 0, sizeof(joybuttons));
630
631 // killough 5/13/98: in case netdemo has consoleplayer other than green
632 ST_Start();
633 HU_Start();
634}
635
636
637//
638// G_Responder
639// Get info needed to make ticcmd_ts for the players.
640//
641
642boolean G_Responder (event_t* ev)
643{
644 // allow spy mode changes even during the demo
645 // killough 2/22/98: even during DM demo
646 //
647 // killough 11/98: don't autorepeat spy mode switch
648
649 if (ev->data1 == key_spy && netgame && (demoplayback || !deathmatch) &&
650 gamestate == GS_LEVEL)
651 {
652 if (ev->type == ev_keyup)
653 gamekeydown[key_spy] = false;
654 if (ev->type == ev_keydown && !gamekeydown[key_spy])
655 {
656 gamekeydown[key_spy] = true;
657 do // spy mode
658 if (++displayplayer >= MAXPLAYERS)
659 displayplayer = 0;
660 while (!playeringame[displayplayer] && displayplayer!=consoleplayer);
661
662 ST_Start(); // killough 3/7/98: switch status bar views too
663 HU_Start();
664 S_UpdateSounds(players[displayplayer].mo);
665 R_ActivateSectorInterpolations();
666 R_SmoothPlaying_Reset(NULL);
667 }
668 return true;
669 }
670
671 // any other key pops up menu if in demos
672 //
673 // killough 8/2/98: enable automap in -timedemo demos
674 //
675 // killough 9/29/98: make any key pop up menu regardless of
676 // which kind of demo, and allow other events during playback
677
678 if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN))
679 {
680 // killough 9/29/98: allow user to pause demos during playback
681 if (ev->type == ev_keydown && ev->data1 == key_pause)
682 {
683 if (paused ^= 2)
684 S_PauseSound();
685 else
686 S_ResumeSound();
687 return true;
688 }
689
690 // killough 10/98:
691 // Don't pop up menu, if paused in middle
692 // of demo playback, or if automap active.
693 // Don't suck up keys, which may be cheats
694
695 return gamestate == GS_DEMOSCREEN &&
696 !(paused & 2) && !(automapmode & am_active) &&
697 ((ev->type == ev_keydown) ||
698 (ev->type == ev_mouse && ev->data1) ||
699 (ev->type == ev_joystick && ev->data1)) ?
700 M_StartControlPanel(), true : false;
701 }
702
703 if (gamestate == GS_FINALE && F_Responder(ev))
704 return true; // finale ate the event
705
706 switch (ev->type)
707 {
708 case ev_keydown:
709 if (ev->data1 == key_pause) // phares
710 {
711 special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK);
712 return true;
713 }
714 if (ev->data1 <NUMKEYS)
715 gamekeydown[ev->data1] = true;
716 return true; // eat key down events
717
718 case ev_keyup:
719 if (ev->data1 <NUMKEYS)
720 gamekeydown[ev->data1] = false;
721 return false; // always let key up events filter down
722
723 case ev_mouse:
724 mousebuttons[0] = ev->data1 & 1;
725 mousebuttons[1] = ev->data1 & 2;
726 mousebuttons[2] = ev->data1 & 4;
727 /*
728 * bmead@surfree.com
729 * Modified by Barry Mead after adding vastly more resolution
730 * to the Mouse Sensitivity Slider in the options menu 1-9-2000
731 * Removed the mouseSensitivity "*4" to allow more low end
732 * sensitivity resolution especially for lsdoom users.
733 */
734 mousex += (ev->data2*(mouseSensitivity_horiz))/10; /* killough */
735 mousey += (ev->data3*(mouseSensitivity_vert))/10; /*Mead rm *4 */
736 return true; // eat events
737
738 case ev_joystick:
739 joybuttons[0] = ev->data1 & 1;
740 joybuttons[1] = ev->data1 & 2;
741 joybuttons[2] = ev->data1 & 4;
742 joybuttons[3] = ev->data1 & 8;
743 joyxmove = ev->data2;
744 joyymove = ev->data3;
745 return true; // eat events
746
747 default:
748 break;
749 }
750 return false;
751}
752
753//
754// G_Ticker
755// Make ticcmd_ts for the players.
756//
757
758void G_Ticker (void)
759{
760 int i;
761 static gamestate_t prevgamestate;
762
763 // CPhipps - player colour changing
764 if (!demoplayback && mapcolor_plyr[consoleplayer] != mapcolor_me) {
765 // Changed my multiplayer colour - Inform the whole game
766 int net_cl = LONG(mapcolor_me);
767#ifdef HAVE_NET
768 D_NetSendMisc(nm_plcolour, sizeof(net_cl), &net_cl);
769#endif
770 G_ChangedPlayerColour(consoleplayer, mapcolor_me);
771 }
772 P_MapStart();
773 // do player reborns if needed
774 for (i=0 ; i<MAXPLAYERS ; i++)
775 if (playeringame[i] && players[i].playerstate == PST_REBORN)
776 G_DoReborn (i);
777 P_MapEnd();
778
779 // do things to change the game state
780 while (gameaction != ga_nothing)
781 {
782 switch (gameaction)
783 {
784 case ga_loadlevel:
785 // force players to be initialized on level reload
786 for (i=0 ; i<MAXPLAYERS ; i++)
787 players[i].playerstate = PST_REBORN;
788 G_DoLoadLevel ();
789 break;
790 case ga_newgame:
791 G_DoNewGame ();
792 break;
793 case ga_loadgame:
794 G_DoLoadGame ();
795 break;
796 case ga_savegame:
797 G_DoSaveGame (false);
798 break;
799 case ga_playdemo:
800 G_DoPlayDemo ();
801 break;
802 case ga_completed:
803 G_DoCompleted ();
804 break;
805 case ga_victory:
806 F_StartFinale ();
807 break;
808 case ga_worlddone:
809 G_DoWorldDone ();
810 break;
811 case ga_nothing:
812 break;
813 }
814 }
815
816 if (paused & 2 || (!demoplayback && menuactive && !netgame))
817 basetic++; // For revenant tracers and RNG -- we must maintain sync
818 else {
819 // get commands, check consistancy, and build new consistancy check
820 int buf = (gametic/ticdup)%BACKUPTICS;
821
822 for (i=0 ; i<MAXPLAYERS ; i++) {
823 if (playeringame[i])
824 {
825 ticcmd_t *cmd = &players[i].cmd;
826
827 memcpy(cmd, &netcmds[i][buf], sizeof *cmd);
828
829 if (demoplayback)
830 G_ReadDemoTiccmd (cmd);
831 if (demorecording)
832 G_WriteDemoTiccmd (cmd);
833
834 // check for turbo cheats
835 // killough 2/14/98, 2/20/98 -- only warn in netgames and demos
836
837 if ((netgame || demoplayback) && cmd->forwardmove > TURBOTHRESHOLD &&
838 !(gametic&31) && ((gametic>>5)&3) == i )
839 {
840 extern char *player_names[];
841 /* cph - don't use sprintf, use doom_printf */
842 doom_printf ("%s is turbo!", player_names[i]);
843 }
844
845 if (netgame && !netdemo && !(gametic%ticdup) )
846 {
847 if (gametic > BACKUPTICS
848 && consistancy[i][buf] != cmd->consistancy)
849 I_Error("G_Ticker: Consistency failure (%i should be %i)",
850 cmd->consistancy, consistancy[i][buf]);
851 if (players[i].mo)
852 consistancy[i][buf] = players[i].mo->x;
853 else
854 consistancy[i][buf] = 0; // killough 2/14/98
855 }
856 }
857 }
858
859 // check for special buttons
860 for (i=0; i<MAXPLAYERS; i++) {
861 if (playeringame[i])
862 {
863 if (players[i].cmd.buttons & BT_SPECIAL)
864 {
865 switch (players[i].cmd.buttons & BT_SPECIALMASK)
866 {
867 case BTS_PAUSE:
868 paused ^= 1;
869 if (paused)
870 S_PauseSound ();
871 else
872 S_ResumeSound ();
873 break;
874
875 case BTS_SAVEGAME:
876 if (!savedescription[0])
877 strcpy(savedescription, "NET GAME");
878 savegameslot =
879 (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
880 gameaction = ga_savegame;
881 break;
882
883 // CPhipps - remote loadgame request
884 case BTS_LOADGAME:
885 savegameslot =
886 (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
887 gameaction = ga_loadgame;
888 forced_loadgame = netgame; // Force if a netgame
889 command_loadgame = false;
890 break;
891
892 // CPhipps - Restart the level
893 case BTS_RESTARTLEVEL:
894 if (demoplayback || (compatibility_level < lxdoom_1_compatibility))
895 break; // CPhipps - Ignore in demos or old games
896 gameaction = ga_loadlevel;
897 break;
898 }
899 players[i].cmd.buttons = 0;
900 }
901 }
902 }
903 }
904
905 // cph - if the gamestate changed, we may need to clean up the old gamestate
906 if (gamestate != prevgamestate) {
907 switch (prevgamestate) {
908 case GS_LEVEL:
909 // This causes crashes at level end - Neil Stevens
910 // The crash is because the sounds aren't stopped before freeing them
911 // the following is a possible fix
912 // This fix does avoid the crash wowever, with this fix in, the exit
913 // switch sound is cut off
914 // S_Stop();
915 // Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
916 break;
917 case GS_INTERMISSION:
918 WI_End();
919 default:
920 break;
921 }
922 prevgamestate = gamestate;
923 }
924
925 // e6y
926 // do nothing if a pause has been pressed during playback
927 // pausing during intermission can cause desynchs without that
928 if (paused & 2 && gamestate != GS_LEVEL)
929 return;
930
931 // do main actions
932 switch (gamestate)
933 {
934 case GS_LEVEL:
935 P_Ticker ();
936 ST_Ticker ();
937 AM_Ticker ();
938 HU_Ticker ();
939 break;
940
941 case GS_INTERMISSION:
942 WI_Ticker ();
943 break;
944
945 case GS_FINALE:
946 F_Ticker ();
947 break;
948
949 case GS_DEMOSCREEN:
950 D_PageTicker ();
951 break;
952 }
953}
954
955//
956// PLAYER STRUCTURE FUNCTIONS
957// also see P_SpawnPlayer in P_Things
958//
959
960//
961// G_PlayerFinishLevel
962// Can when a player completes a level.
963//
964
965static void G_PlayerFinishLevel(int player)
966{
967 player_t *p = &players[player];
968 memset(p->powers, 0, sizeof p->powers);
969 memset(p->cards, 0, sizeof p->cards);
970 p->mo = NULL; // cph - this is allocated PU_LEVEL so it's gone
971 p->extralight = 0; // cancel gun flashes
972 p->fixedcolormap = 0; // cancel ir gogles
973 p->damagecount = 0; // no palette changes
974 p->bonuscount = 0;
975}
976
977// CPhipps - G_SetPlayerColour
978// Player colours stuff
979//
980// G_SetPlayerColour
981
982#include "r_draw.h"
983
984void G_ChangedPlayerColour(int pn, int cl)
985{
986 int i;
987
988 if (!netgame) return;
989
990 mapcolor_plyr[pn] = cl;
991
992 // Rebuild colour translation tables accordingly
993 R_InitTranslationTables();
994 // Change translations on existing player mobj's
995 for (i=0; i<MAXPLAYERS; i++) {
996 if ((gamestate == GS_LEVEL) && playeringame[i] && (players[i].mo != NULL)) {
997 players[i].mo->flags &= ~MF_TRANSLATION;
998 players[i].mo->flags |= playernumtotrans[i] << MF_TRANSSHIFT;
999 }
1000 }
1001}
1002
1003//
1004// G_PlayerReborn
1005// Called after a player dies
1006// almost everything is cleared and initialized
1007//
1008
1009void G_PlayerReborn (int player)
1010{
1011 player_t *p;
1012 int i;
1013 int frags[MAXPLAYERS];
1014 int killcount;
1015 int itemcount;
1016 int secretcount;
1017
1018 memcpy (frags, players[player].frags, sizeof frags);
1019 killcount = players[player].killcount;
1020 itemcount = players[player].itemcount;
1021 secretcount = players[player].secretcount;
1022
1023 p = &players[player];
1024
1025 // killough 3/10/98,3/21/98: preserve cheats across idclev
1026 {
1027 int cheats = p->cheats;
1028 memset (p, 0, sizeof(*p));
1029 p->cheats = cheats;
1030 }
1031
1032 memcpy(players[player].frags, frags, sizeof(players[player].frags));
1033 players[player].killcount = killcount;
1034 players[player].itemcount = itemcount;
1035 players[player].secretcount = secretcount;
1036
1037 p->usedown = p->attackdown = true; // don't do anything immediately
1038 p->playerstate = PST_LIVE;
1039 p->health = initial_health; // Ty 03/12/98 - use dehacked values
1040 p->readyweapon = p->pendingweapon = wp_pistol;
1041 p->weaponowned[wp_fist] = true;
1042 p->weaponowned[wp_pistol] = true;
1043 p->ammo[am_clip] = initial_bullets; // Ty 03/12/98 - use dehacked values
1044
1045 for (i=0 ; i<NUMAMMO ; i++)
1046 p->maxammo[i] = maxammo[i];
1047}
1048
1049//
1050// G_CheckSpot
1051// Returns false if the player cannot be respawned
1052// at the given mapthing_t spot
1053// because something is occupying it
1054//
1055
1056static boolean G_CheckSpot(int playernum, mapthing_t *mthing)
1057{
1058 fixed_t x,y;
1059 subsector_t *ss;
1060 int i;
1061
1062 if (!players[playernum].mo)
1063 {
1064 // first spawn of level, before corpses
1065 for (i=0 ; i<playernum ; i++)
1066 if (players[i].mo->x == mthing->x << FRACBITS
1067 && players[i].mo->y == mthing->y << FRACBITS)
1068 return false;
1069 return true;
1070 }
1071
1072 x = mthing->x << FRACBITS;
1073 y = mthing->y << FRACBITS;
1074
1075 // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid
1076 // corpse to detect collisions with other players in DM starts
1077 //
1078 // Old code:
1079 // if (!P_CheckPosition (players[playernum].mo, x, y))
1080 // return false;
1081
1082 players[playernum].mo->flags |= MF_SOLID;
1083 i = P_CheckPosition(players[playernum].mo, x, y);
1084 players[playernum].mo->flags &= ~MF_SOLID;
1085 if (!i)
1086 return false;
1087
1088 // flush an old corpse if needed
1089 // killough 2/8/98: make corpse queue have an adjustable limit
1090 // killough 8/1/98: Fix bugs causing strange crashes
1091
1092 if (bodyquesize > 0)
1093 {
1094 static int queuesize;
1095 if (queuesize < bodyquesize)
1096 {
1097 bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque);
1098 memset(bodyque+queuesize, 0,
1099 (bodyquesize-queuesize)*sizeof*bodyque);
1100 queuesize = bodyquesize;
1101 }
1102 if (bodyqueslot >= bodyquesize)
1103 P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]);
1104 bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo;
1105 }
1106 else
1107 if (!bodyquesize)
1108 P_RemoveMobj(players[playernum].mo);
1109
1110 // spawn a teleport fog
1111 ss = R_PointInSubsector (x,y);
1112 { // Teleport fog at respawn point
1113 fixed_t xa,ya;
1114 int an;
1115 mobj_t *mo;
1116
1117/* BUG: an can end up negative, because mthing->angle is (signed) short.
1118 * We have to emulate original Doom's behaviour, deferencing past the start
1119 * of the array, into the previous array (finetangent) */
1120 an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT;
1121 xa = finecosine[an];
1122 ya = finesine[an];
1123
1124 if (compatibility_level <= finaldoom_compatibility || compatibility_level == prboom_4_compatibility)
1125 switch (an) {
1126 case -4096: xa = finetangent[2048]; // finecosine[-4096]
1127 ya = finetangent[0]; // finesine[-4096]
1128 break;
1129 case -3072: xa = finetangent[3072]; // finecosine[-3072]
1130 ya = finetangent[1024]; // finesine[-3072]
1131 break;
1132 case -2048: xa = finesine[0]; // finecosine[-2048]
1133 ya = finetangent[2048]; // finesine[-2048]
1134 break;
1135 case -1024: xa = finesine[1024]; // finecosine[-1024]
1136 ya = finetangent[3072]; // finesine[-1024]
1137 break;
1138 case 1024:
1139 case 2048:
1140 case 3072:
1141 case 4096:
1142 case 0: break; /* correct angles set above */
1143 default: I_Error("G_CheckSpot: unexpected angle %d\n",an);
1144 }
1145
1146 mo = P_SpawnMobj(x+20*xa, y+20*ya, ss->sector->floorheight, MT_TFOG);
1147
1148 if (players[consoleplayer].viewz != 1)
1149 S_StartSound(mo, sfx_telept); // don't start sound on first frame
1150 }
1151
1152 return true;
1153}
1154
1155
1156// G_DeathMatchSpawnPlayer
1157// Spawns a player at one of the random death match spots
1158// called at level load and each death
1159//
1160void G_DeathMatchSpawnPlayer (int playernum)
1161{
1162 int j, selections = deathmatch_p - deathmatchstarts;
1163
1164 if (selections < MAXPLAYERS)
1165 I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required",
1166 selections, MAXPLAYERS);
1167
1168 for (j=0 ; j<20 ; j++)
1169 {
1170 int i = P_Random(pr_dmspawn) % selections;
1171 if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
1172 {
1173 deathmatchstarts[i].type = playernum+1;
1174 P_SpawnPlayer (playernum, &deathmatchstarts[i]);
1175 return;
1176 }
1177 }
1178
1179 // no good spot, so the player will probably get stuck
1180 P_SpawnPlayer (playernum, &playerstarts[playernum]);
1181}
1182
1183//
1184// G_DoReborn
1185//
1186
1187void G_DoReborn (int playernum)
1188{
1189 if (!netgame)
1190 gameaction = ga_loadlevel; // reload the level from scratch
1191 else
1192 { // respawn at the start
1193 int i;
1194
1195 // first dissasociate the corpse
1196 players[playernum].mo->player = NULL;
1197
1198 // spawn at random spot if in death match
1199 if (deathmatch)
1200 {
1201 G_DeathMatchSpawnPlayer (playernum);
1202 return;
1203 }
1204
1205 if (G_CheckSpot (playernum, &playerstarts[playernum]) )
1206 {
1207 P_SpawnPlayer (playernum, &playerstarts[playernum]);
1208 return;
1209 }
1210
1211 // try to spawn at one of the other players spots
1212 for (i=0 ; i<MAXPLAYERS ; i++)
1213 {
1214 if (G_CheckSpot (playernum, &playerstarts[i]) )
1215 {
1216 P_SpawnPlayer (playernum, &playerstarts[i]);
1217 return;
1218 }
1219 // he's going to be inside something. Too bad.
1220 }
1221 P_SpawnPlayer (playernum, &playerstarts[playernum]);
1222 }
1223}
1224
1225// DOOM Par Times
1226int pars[4][10] = {
1227 {0},
1228 {0,30,75,120,90,165,180,180,30,165},
1229 {0,90,90,90,120,90,360,240,30,170},
1230 {0,90,45,90,150,90,90,165,30,135}
1231};
1232
1233// DOOM II Par Times
1234int cpars[32] = {
1235 30,90,120,120,90,150,120,120,270,90, // 1-10
1236 210,150,150,150,210,150,420,150,210,150, // 11-20
1237 240,150,180,150,150,300,330,420,300,180, // 21-30
1238 120,30 // 31-32
1239};
1240
1241static boolean secretexit;
1242
1243void G_ExitLevel (void)
1244{
1245 secretexit = false;
1246 gameaction = ga_completed;
1247}
1248
1249// Here's for the german edition.
1250// IF NO WOLF3D LEVELS, NO SECRET EXIT!
1251
1252void G_SecretExitLevel (void)
1253{
1254 if (gamemode!=commercial || haswolflevels)
1255 secretexit = true;
1256 else
1257 secretexit = false;
1258 gameaction = ga_completed;
1259}
1260
1261//
1262// G_DoCompleted
1263//
1264
1265void G_DoCompleted (void)
1266{
1267 int i;
1268
1269 gameaction = ga_nothing;
1270
1271 for (i=0; i<MAXPLAYERS; i++)
1272 if (playeringame[i])
1273 G_PlayerFinishLevel(i); // take away cards and stuff
1274
1275 if (automapmode & am_active)
1276 AM_Stop();
1277
1278 if (gamemode != commercial) // kilough 2/7/98
1279 switch(gamemap)
1280 {
1281 // cph - Remove ExM8 special case, so it gets summary screen displayed
1282 case 9:
1283 for (i=0 ; i<MAXPLAYERS ; i++)
1284 players[i].didsecret = true;
1285 break;
1286 }
1287
1288 wminfo.didsecret = players[consoleplayer].didsecret;
1289 wminfo.epsd = gameepisode -1;
1290 wminfo.last = gamemap -1;
1291
1292 // wminfo.next is 0 biased, unlike gamemap
1293 if (gamemode == commercial)
1294 {
1295 if (secretexit)
1296 switch(gamemap)
1297 {
1298 case 15:
1299 wminfo.next = 30; break;
1300 case 31:
1301 wminfo.next = 31; break;
1302 }
1303 else
1304 switch(gamemap)
1305 {
1306 case 31:
1307 case 32:
1308 wminfo.next = 15; break;
1309 default:
1310 wminfo.next = gamemap;
1311 }
1312 }
1313 else
1314 {
1315 if (secretexit)
1316 wminfo.next = 8; // go to secret level
1317 else
1318 if (gamemap == 9)
1319 {
1320 // returning from secret level
1321 switch (gameepisode)
1322 {
1323 case 1:
1324 wminfo.next = 3;
1325 break;
1326 case 2:
1327 wminfo.next = 5;
1328 break;
1329 case 3:
1330 wminfo.next = 6;
1331 break;
1332 case 4:
1333 wminfo.next = 2;
1334 break;
1335 }
1336 }
1337 else
1338 wminfo.next = gamemap; // go to next level
1339 }
1340
1341 wminfo.maxkills = totalkills;
1342 wminfo.maxitems = totalitems;
1343 wminfo.maxsecret = totalsecret;
1344 wminfo.maxfrags = 0;
1345
1346 if ( gamemode == commercial )
1347 wminfo.partime = TICRATE*cpars[gamemap-1];
1348 else
1349 wminfo.partime = TICRATE*pars[gameepisode][gamemap];
1350
1351 wminfo.pnum = consoleplayer;
1352
1353 for (i=0 ; i<MAXPLAYERS ; i++)
1354 {
1355 wminfo.plyr[i].in = playeringame[i];
1356 wminfo.plyr[i].skills = players[i].killcount;
1357 wminfo.plyr[i].sitems = players[i].itemcount;
1358 wminfo.plyr[i].ssecret = players[i].secretcount;
1359 wminfo.plyr[i].stime = leveltime;
1360 memcpy (wminfo.plyr[i].frags, players[i].frags,
1361 sizeof(wminfo.plyr[i].frags));
1362 }
1363
1364 /* cph - modified so that only whole seconds are added to the totalleveltimes
1365 * value; so our total is compatible with the "naive" total of just adding
1366 * the times in seconds shown for each level. Also means our total time
1367 * will agree with Compet-n.
1368 */
1369 wminfo.totaltimes = (totalleveltimes += (leveltime - leveltime%35));
1370
1371 gamestate = GS_INTERMISSION;
1372 automapmode &= ~am_active;
1373
1374 // lmpwatch.pl engine-side demo testing support
1375 // print "FINISHED: <mapname>" when the player exits the current map
1376 if (nodrawers && (demoplayback || timingdemo)) {
1377 if (gamemode == commercial)
1378 lprintf(LO_INFO, "FINISHED: MAP%02d\n", gamemap);
1379 else
1380 lprintf(LO_INFO, "FINISHED: E%dM%d\n", gameepisode, gamemap);
1381 }
1382
1383 WI_Start (&wminfo);
1384}
1385
1386//
1387// G_WorldDone
1388//
1389
1390void G_WorldDone (void)
1391{
1392 gameaction = ga_worlddone;
1393
1394 if (secretexit)
1395 players[consoleplayer].didsecret = true;
1396
1397 if (gamemode == commercial)
1398 {
1399 switch (gamemap)
1400 {
1401 case 15:
1402 case 31:
1403 if (!secretexit)
1404 break;
1405 case 6:
1406 case 11:
1407 case 20:
1408 case 30:
1409 F_StartFinale ();
1410 break;
1411 }
1412 }
1413 else if (gamemap == 8)
1414 gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff
1415}
1416
1417void G_DoWorldDone (void)
1418{
1419 idmusnum = -1; //jff 3/17/98 allow new level's music to be loaded
1420 gamestate = GS_LEVEL;
1421 gamemap = wminfo.next+1;
1422 G_DoLoadLevel();
1423 gameaction = ga_nothing;
1424 AM_clearMarks(); //jff 4/12/98 clear any marks on the automap
1425}
1426
1427// killough 2/28/98: A ridiculously large number
1428// of players, the most you'll ever need in a demo
1429// or savegame. This is used to prevent problems, in
1430// case more players in a game are supported later.
1431
1432#define MIN_MAXPLAYERS 32
1433
1434extern boolean setsizeneeded;
1435
1436//CPhipps - savename variable redundant
1437
1438/* killough 12/98:
1439 * This function returns a signature for the current wad.
1440 * It is used to distinguish between wads, for the purposes
1441 * of savegame compatibility warnings, and options lookups.
1442 */
1443
1444static uint_64_t G_UpdateSignature(uint_64_t s, const char *name)
1445{
1446 int i, lump = W_CheckNumForName(name);
1447 if (lump != -1 && (i = lump+10) < numlumps)
1448 do
1449 {
1450 int size = W_LumpLength(i);
1451 const byte *p = W_CacheLumpNum(i);
1452 while (size--)
1453 s <<= 1, s += *p++;
1454 W_UnlockLumpNum(i);
1455 }
1456 while (--i > lump);
1457 return s;
1458}
1459
1460static uint_64_t G_Signature(void)
1461{
1462 static uint_64_t s = 0;
1463 static boolean computed = false;
1464 char name[9];
1465 int episode, map;
1466
1467 if (!computed) {
1468 computed = true;
1469 if (gamemode == commercial)
1470 for (map = haswolflevels ? 32 : 30; map; map--)
1471 sprintf(name, "map%02d", map), s = G_UpdateSignature(s, name);
1472 else
1473 for (episode = gamemode==retail ? 4 :
1474 gamemode==shareware ? 1 : 3; episode; episode--)
1475 for (map = 9; map; map--)
1476 sprintf(name, "E%dM%d", episode, map), s = G_UpdateSignature(s, name);
1477 }
1478 return s;
1479}
1480
1481//
1482// killough 5/15/98: add forced loadgames, which allow user to override checks
1483//
1484
1485void G_ForcedLoadGame(void)
1486{
1487 // CPhipps - net loadgames are always forced, so we only reach here
1488 // in single player
1489 gameaction = ga_loadgame;
1490 forced_loadgame = true;
1491}
1492
1493// killough 3/16/98: add slot info
1494// killough 5/15/98: add command-line
1495void G_LoadGame(int slot, boolean command)
1496{
1497 if (!demoplayback && !command) {
1498 // CPhipps - handle savegame filename in G_DoLoadGame
1499 // - Delay load so it can be communicated in net game
1500 // - store info in special_event
1501 special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) |
1502 ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
1503 forced_loadgame = netgame; // CPhipps - always force load netgames
1504 } else {
1505 // Do the old thing, immediate load
1506 gameaction = ga_loadgame;
1507 forced_loadgame = false;
1508 savegameslot = slot;
1509 demoplayback = false;
1510 // Don't stay in netgame state if loading single player save
1511 // while watching multiplayer demo
1512 netgame = false;
1513 }
1514 command_loadgame = command;
1515 R_SmoothPlaying_Reset(NULL); // e6y
1516}
1517
1518// killough 5/15/98:
1519// Consistency Error when attempting to load savegame.
1520
1521static void G_LoadGameErr(const char *msg)
1522{
1523 Z_Free(savebuffer); // Free the savegame buffer
1524 M_ForcedLoadGame(msg); // Print message asking for 'Y' to force
1525 if (command_loadgame) // If this was a command-line -loadgame
1526 {
1527 D_StartTitle(); // Start the title screen
1528 gamestate = GS_DEMOSCREEN; // And set the game state accordingly
1529 }
1530}
1531
1532// CPhipps - size of version header
1533#define VERSIONSIZE 16
1534
1535const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] =
1536{ "doom v1.2", "doom v1.666", "doom/doom2 v1.9", "ultimate doom", "final doom",
1537 "dosdoom compatibility", "tasdoom compatibility", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+",
1538 "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1", "PrBoom v2.1.2-v2.2.6",
1539 "PrBoom v2.3.x", "PrBoom 2.4.0", "Current PrBoom" };
1540
1541// comp_options_by_version removed - see G_Compatibility
1542
1543static byte map_old_comp_levels[] =
1544{ 0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
1545
1546static const struct {
1547 int comp_level;
1548 const char* ver_printf;
1549 int version;
1550} version_headers[] = {
1551 /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since
1552 * the file format is unchanged. */
1553 { prboom_3_compatibility, "PrBoom %d", 210},
1554 { prboom_5_compatibility, "PrBoom %d", 211},
1555 { prboom_6_compatibility, "PrBoom %d", 212}
1556};
1557
1558static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]);
1559
1560void G_DoLoadGame(void)
1561{
1562 int length, i;
1563 // CPhipps - do savegame filename stuff here
1564 char name[PATH_MAX+1]; // killough 3/22/98
1565 int savegame_compatibility = -1;
1566
1567 G_SaveGameName(name,sizeof(name),savegameslot, demoplayback);
1568
1569 gameaction = ga_nothing;
1570
1571 length = M_ReadFile(name, &savebuffer);
1572 if (length<=0)
1573 I_Error("Couldn't read file %s: %s", name, "(Unknown Error)");
1574 save_p = savebuffer + SAVESTRINGSIZE;
1575
1576 // CPhipps - read the description field, compare with supported ones
1577 for (i=0; (size_t)i<num_version_headers; i++) {
1578 char vcheck[VERSIONSIZE];
1579 // killough 2/22/98: "proprietary" version string :-)
1580 sprintf (vcheck, version_headers[i].ver_printf, version_headers[i].version);
1581
1582 if (!strncmp(save_p, vcheck, VERSIONSIZE)) {
1583 savegame_compatibility = version_headers[i].comp_level;
1584 i = num_version_headers;
1585 }
1586 }
1587 if (savegame_compatibility == -1) {
1588 if (forced_loadgame) {
1589 savegame_compatibility = MAX_COMPATIBILITY_LEVEL-1;
1590 } else {
1591 G_LoadGameErr("Unrecognised savegame version!\nAre you sure? (y/n) ");
1592 return;
1593 }
1594 }
1595
1596 save_p += VERSIONSIZE;
1597
1598 // CPhipps - always check savegames even when forced,
1599 // only print a warning if forced
1600 { // killough 3/16/98: check lump name checksum (independent of order)
1601 uint_64_t checksum = 0;
1602
1603 checksum = G_Signature();
1604
1605 if (memcmp(&checksum, save_p, sizeof checksum)) {
1606 if (!forced_loadgame) {
1607 char *msg = malloc(strlen(save_p + sizeof checksum) + 128);
1608 strcpy(msg,"Incompatible Savegame!!!\n");
1609 if (save_p[sizeof checksum])
1610 strcat(strcat(msg,"Wads expected:\n\n"), save_p + sizeof checksum);
1611 strcat(msg, "\nAre you sure?");
1612 G_LoadGameErr(msg);
1613 free(msg);
1614 return;
1615 } else
1616 lprintf(LO_WARN, "G_DoLoadGame: Incompatible savegame\n");
1617 }
1618 save_p += sizeof checksum;
1619 }
1620
1621 save_p += strlen(save_p)+1;
1622
1623 compatibility_level = (savegame_compatibility >= prboom_4_compatibility) ? *save_p : savegame_compatibility;
1624 if (savegame_compatibility < prboom_6_compatibility)
1625 compatibility_level = map_old_comp_levels[compatibility_level];
1626 save_p++;
1627
1628 gameskill = *save_p++;
1629 gameepisode = *save_p++;
1630 gamemap = *save_p++;
1631
1632 for (i=0 ; i<MAXPLAYERS ; i++)
1633 playeringame[i] = *save_p++;
1634 save_p += MIN_MAXPLAYERS-MAXPLAYERS; // killough 2/28/98
1635
1636 idmusnum = *save_p++; // jff 3/17/98 restore idmus music
1637 if (idmusnum==255) idmusnum=-1; // jff 3/18/98 account for unsigned byte
1638
1639 /* killough 3/1/98: Read game options
1640 * killough 11/98: move down to here
1641 */
1642 save_p = (char*)G_ReadOptions(save_p);
1643
1644 // load a base level
1645 G_InitNew (gameskill, gameepisode, gamemap);
1646
1647 /* get the times - killough 11/98: save entire word */
1648 memcpy(&leveltime, save_p, sizeof leveltime);
1649 save_p += sizeof leveltime;
1650
1651 /* cph - total episode time */
1652 if (compatibility_level >= prboom_2_compatibility) {
1653 memcpy(&totalleveltimes, save_p, sizeof totalleveltimes);
1654 save_p += sizeof totalleveltimes;
1655 }
1656 else totalleveltimes = 0;
1657
1658 // killough 11/98: load revenant tracer state
1659 basetic = gametic - *save_p++;
1660
1661 // dearchive all the modifications
1662 P_MapStart();
1663 P_UnArchivePlayers ();
1664 P_UnArchiveWorld ();
1665 P_UnArchiveThinkers ();
1666 P_UnArchiveSpecials ();
1667 P_UnArchiveRNG (); // killough 1/18/98: load RNG information
1668 P_UnArchiveMap (); // killough 1/22/98: load automap information
1669 P_MapEnd();
1670 R_SmoothPlaying_Reset(NULL); // e6y
1671
1672 if (*save_p != 0xe6)
1673 I_Error ("G_DoLoadGame: Bad savegame");
1674
1675 // done
1676 Z_Free (savebuffer);
1677
1678 if (setsizeneeded)
1679 R_ExecuteSetViewSize ();
1680
1681 // draw the pattern into the back screen
1682 R_FillBackScreen ();
1683
1684 /* killough 12/98: support -recordfrom and -loadgame -playdemo */
1685 if (!command_loadgame)
1686 singledemo = false; /* Clear singledemo flag if loading from menu */
1687 else
1688 if (singledemo) {
1689 gameaction = ga_loadgame; /* Mark that we're loading a game before demo */
1690 G_DoPlayDemo(); /* This will detect it and won't reinit level */
1691 } else /* Command line + record means it's a recordfrom */
1692 if (demorecording)
1693 G_BeginRecording();
1694}
1695
1696//
1697// G_SaveGame
1698// Called by the menu task.
1699// Description is a 24 byte text string
1700//
1701
1702void G_SaveGame(int slot, char *description)
1703{
1704 strcpy(savedescription, description);
1705 if (demoplayback) {
1706 /* cph - We're doing a user-initiated save game while a demo is
1707 * running so, go outside normal mechanisms
1708 */
1709 savegameslot = slot;
1710 G_DoSaveGame(true);
1711 }
1712 // CPhipps - store info in special_event
1713 special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) |
1714 ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
1715#ifdef HAVE_NET
1716 D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription);
1717#endif
1718}
1719
1720// Check for overrun and realloc if necessary -- Lee Killough 1/22/98
1721void (CheckSaveGame)(size_t size, const char* file, int line)
1722{
1723 size_t pos = save_p - savebuffer;
1724
1725#ifdef RANGECHECK
1726 /* cph 2006/08/07 - after-the-fact sanity checking of CheckSaveGame calls */
1727 static size_t prev_check;
1728 static const char* prevf;
1729 static int prevl;
1730
1731 if (pos > prev_check)
1732 I_Error("CheckSaveGame at %s:%d called for insufficient buffer (%u < %u)", prevf, prevl, prev_check, pos);
1733 prev_check = size + pos;
1734 prevf = file;
1735 prevl = line;
1736#endif
1737
1738 size += 1024; // breathing room
1739 if (pos+size > savegamesize)
1740 save_p = (savebuffer = realloc(savebuffer,
1741 savegamesize += (size+1023) & ~1023)) + pos;
1742}
1743
1744/* killough 3/22/98: form savegame name in one location
1745 * (previously code was scattered around in multiple places)
1746 * cph - Avoid possible buffer overflow problems by passing
1747 * size to this function and using snprintf */
1748
1749void G_SaveGameName(char *name, size_t size, int slot, boolean demoplayback)
1750{
1751 const char* sgn = demoplayback ? "demosav" : savegamename;
1752#ifdef HAVE_SNPRINTF
1753 snprintf (name, size, "%s/%s%d.dsg", basesavegame, sgn, slot);
1754#else
1755 sprintf (name, "%s/%s%d.dsg", basesavegame, sgn, slot);
1756#endif
1757}
1758
1759static void G_DoSaveGame (boolean menu)
1760{
1761 char name[PATH_MAX+1];
1762 char name2[VERSIONSIZE];
1763 char *description;
1764 int length, i;
1765
1766 gameaction = ga_nothing; // cph - cancel savegame at top of this function,
1767 // in case later problems cause a premature exit
1768
1769 G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu);
1770
1771 description = savedescription;
1772
1773 save_p = savebuffer = malloc(savegamesize);
1774
1775 CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(uint_64_t));
1776 memcpy (save_p, description, SAVESTRINGSIZE);
1777 save_p += SAVESTRINGSIZE;
1778 memset (name2,0,sizeof(name2));
1779
1780 // CPhipps - scan for the version header
1781 for (i=0; (size_t)i<num_version_headers; i++)
1782 if (version_headers[i].comp_level == best_compatibility) {
1783 // killough 2/22/98: "proprietary" version string :-)
1784 sprintf (name2,version_headers[i].ver_printf,version_headers[i].version);
1785 memcpy (save_p, name2, VERSIONSIZE);
1786 i = num_version_headers+1;
1787 }
1788
1789 save_p += VERSIONSIZE;
1790
1791 { /* killough 3/16/98, 12/98: store lump name checksum */
1792 uint_64_t checksum = G_Signature();
1793 memcpy(save_p, &checksum, sizeof checksum);
1794 save_p += sizeof checksum;
1795 }
1796
1797 // killough 3/16/98: store pwad filenames in savegame
1798 {
1799 // CPhipps - changed for new wadfiles handling
1800 size_t i;
1801 for (i = 0; i<numwadfiles; i++)
1802 {
1803 const char *const w = wadfiles[i].name;
1804 CheckSaveGame(strlen(w)+2);
1805 strcpy(save_p, w);
1806 save_p += strlen(save_p);
1807 *save_p++ = '\n';
1808 }
1809 *save_p++ = 0;
1810 }
1811
1812 CheckSaveGame(GAME_OPTION_SIZE+MIN_MAXPLAYERS+14);
1813
1814 *save_p++ = compatibility_level;
1815
1816 *save_p++ = gameskill;
1817 *save_p++ = gameepisode;
1818 *save_p++ = gamemap;
1819
1820 for (i=0 ; i<MAXPLAYERS ; i++)
1821 *save_p++ = playeringame[i];
1822
1823 for (;i<MIN_MAXPLAYERS;i++) // killough 2/28/98
1824 *save_p++ = 0;
1825
1826 *save_p++ = idmusnum; // jff 3/17/98 save idmus state
1827
1828 save_p = G_WriteOptions(save_p); // killough 3/1/98: save game options
1829
1830 /* cph - FIXME - endianness? */
1831 /* killough 11/98: save entire word */
1832 memcpy(save_p, &leveltime, sizeof leveltime);
1833 save_p += sizeof leveltime;
1834
1835 /* cph - total episode time */
1836 if (compatibility_level >= prboom_2_compatibility) {
1837 memcpy(save_p, &totalleveltimes, sizeof totalleveltimes);
1838 save_p += sizeof totalleveltimes;
1839 }
1840 else totalleveltimes = 0;
1841
1842 // killough 11/98: save revenant tracer state
1843 *save_p++ = (gametic-basetic) & 255;
1844
1845 // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency
1846 Z_CheckHeap();
1847 P_ArchivePlayers();
1848 Z_CheckHeap();
1849
1850 // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the
1851 // indices can be used by P_ArchiveWorld when the sectors are saved.
1852 // This is so we can save the index of the mobj_t of the thinker that
1853 // caused a sound, referenced by sector_t->soundtarget.
1854 P_ThinkerToIndex();
1855
1856 P_ArchiveWorld();
1857 Z_CheckHeap();
1858 P_ArchiveThinkers();
1859
1860 // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply
1861 // for symmetry with the P_ThinkerToIndex call above.
1862
1863 P_IndexToThinker();
1864
1865 Z_CheckHeap();
1866 P_ArchiveSpecials();
1867 P_ArchiveRNG(); // killough 1/18/98: save RNG information
1868 Z_CheckHeap();
1869 P_ArchiveMap(); // killough 1/22/98: save automap information
1870
1871 *save_p++ = 0xe6; // consistancy marker
1872
1873 length = save_p - savebuffer;
1874
1875 Z_CheckHeap();
1876 doom_printf( "%s", M_WriteFile(name, savebuffer, length)
1877 ? s_GGSAVED /* Ty - externalised */
1878 : "Game save failed!"); // CPhipps - not externalised
1879
1880 free(savebuffer); // killough
1881 savebuffer = save_p = NULL;
1882
1883 savedescription[0] = 0;
1884}
1885
1886static skill_t d_skill;
1887static int d_episode;
1888static int d_map;
1889
1890void G_DeferedInitNew(skill_t skill, int episode, int map)
1891{
1892 d_skill = skill;
1893 d_episode = episode;
1894 d_map = map;
1895 gameaction = ga_newgame;
1896}
1897
1898/* cph -
1899 * G_Compatibility
1900 *
1901 * Initialises the comp[] array based on the compatibility_level
1902 * For reference, MBF did:
1903 * for (i=0; i < COMP_TOTAL; i++)
1904 * comp[i] = compatibility;
1905 *
1906 * Instead, we have a lookup table showing at what version a fix was
1907 * introduced, and made optional (replaces comp_options_by_version)
1908 */
1909
1910void G_Compatibility(void)
1911{
1912 static const struct {
1913 complevel_t fix; // level at which fix/change was introduced
1914 complevel_t opt; // level at which fix/change was made optional
1915 } levels[] = {
1916 // comp_telefrag - monsters used to telefrag only on MAP30, now they do it for spawners only
1917 { mbf_compatibility, mbf_compatibility },
1918 // comp_dropoff - MBF encourages things to drop off of overhangs
1919 { mbf_compatibility, mbf_compatibility },
1920 // comp_vile - original Doom archville bugs like ghosts
1921 { boom_compatibility, mbf_compatibility },
1922 // comp_pain - original Doom limits Pain Elementals from spawning too many skulls
1923 { boom_compatibility, mbf_compatibility },
1924 // comp_skull - original Doom let skulls be spit through walls by Pain Elementals
1925 { boom_compatibility, mbf_compatibility },
1926 // comp_blazing - original Doom duplicated blazing door sound
1927 { boom_compatibility, mbf_compatibility },
1928 // e6y: "Tagged doors don't trigger special lighting" handled wrong
1929 // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943
1930 // comp_doorlight - MBF made door lighting changes more gradual
1931 { boom_compatibility, mbf_compatibility },
1932 // comp_model - improvements to the game physics
1933 { boom_compatibility, mbf_compatibility },
1934 // comp_god - fixes to God mode
1935 { boom_compatibility, mbf_compatibility },
1936 // comp_falloff - MBF encourages things to drop off of overhangs
1937 { mbf_compatibility, mbf_compatibility },
1938 // comp_floors - fixes for moving floors bugs
1939 { boom_compatibility_compatibility, mbf_compatibility },
1940 // comp_skymap
1941 { boom_compatibility, mbf_compatibility },
1942 // comp_pursuit - MBF AI change, limited pursuit?
1943 { mbf_compatibility, mbf_compatibility },
1944 // comp_doorstuck - monsters stuck in doors fix
1945 { boom_202_compatibility, mbf_compatibility },
1946 // comp_staylift - MBF AI change, monsters try to stay on lifts
1947 { mbf_compatibility, mbf_compatibility },
1948 // comp_zombie - prevent dead players triggering stuff
1949 { lxdoom_1_compatibility, mbf_compatibility },
1950 // comp_stairs - see p_floor.c
1951 { boom_compatibility_compatibility, mbf_compatibility },
1952 // comp_infcheat - FIXME
1953 { mbf_compatibility, mbf_compatibility },
1954 // comp_zerotags - allow zero tags in wads */
1955 { boom_compatibility, mbf_compatibility },
1956 // comp_moveblock - enables keygrab and mancubi shots going thru walls
1957 { lxdoom_1_compatibility, prboom_2_compatibility },
1958 // comp_respawn - objects which aren't on the map at game start respawn at (0,0)
1959 { prboom_2_compatibility, prboom_2_compatibility },
1960 // comp_sound - see s_sound.c
1961 { boom_compatibility_compatibility, prboom_3_compatibility },
1962 // comp_666 - enables tag 666 in non-ExM8 levels
1963 { ultdoom_compatibility, prboom_4_compatibility },
1964 // comp_soul - enables lost souls bouncing (see P_ZMovement)
1965 { prboom_4_compatibility, prboom_4_compatibility },
1966 // comp_maskedanim - 2s mid textures don't animate
1967 { doom_1666_compatibility, prboom_4_compatibility },
1968 };
1969 int i;
1970
1971 if (sizeof(levels)/sizeof(*levels) != COMP_NUM)
1972 I_Error("G_Compatibility: consistency error");
1973
1974 for (i = 0; i < sizeof(levels)/sizeof(*levels); i++)
1975 if (compatibility_level < levels[i].opt)
1976 comp[i] = (compatibility_level < levels[i].fix);
1977
1978 if (!mbf_features) {
1979 monster_infighting = 1;
1980 monster_backing = 0;
1981 monster_avoid_hazards = 0;
1982 monster_friction = 0;
1983 help_friends = 0;
1984
1985#ifdef DOGS
1986 dogs = 0;
1987 dog_jumping = 0;
1988#endif
1989
1990 monkeys = 0;
1991 }
1992}
1993
1994#ifdef DOGS
1995/* killough 7/19/98: Marine's best friend :) */
1996static int G_GetHelpers(void)
1997{
1998 int j = M_CheckParm ("-dog");
1999
2000 if (!j)
2001 j = M_CheckParm ("-dogs");
2002 return j ? j+1 < myargc ? atoi(myargv[j+1]) : 1 : default_dogs;
2003}
2004#endif
2005
2006// killough 3/1/98: function to reload all the default parameter
2007// settings before a new game begins
2008
2009void G_ReloadDefaults(void)
2010{
2011 // killough 3/1/98: Initialize options based on config file
2012 // (allows functions above to load different values for demos
2013 // and savegames without messing up defaults).
2014
2015 weapon_recoil = default_weapon_recoil; // weapon recoil
2016
2017 player_bobbing = default_player_bobbing; // whether player bobs or not
2018
2019 /* cph 2007/06/31 - for some reason, the default_* of the next 2 vars was never implemented */
2020 variable_friction = default_variable_friction;
2021 allow_pushers = default_allow_pushers;
2022
2023
2024 monsters_remember = default_monsters_remember; // remember former enemies
2025
2026 monster_infighting = default_monster_infighting; // killough 7/19/98
2027
2028#ifdef DOGS
2029 dogs = netgame ? 0 : G_GetHelpers(); // killough 7/19/98
2030 dog_jumping = default_dog_jumping;
2031#endif
2032
2033 distfriend = default_distfriend; // killough 8/8/98
2034
2035 monster_backing = default_monster_backing; // killough 9/8/98
2036
2037 monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98
2038
2039 monster_friction = default_monster_friction; // killough 10/98
2040
2041 help_friends = default_help_friends; // killough 9/9/98
2042
2043 monkeys = default_monkeys;
2044
2045 // jff 1/24/98 reset play mode to command line spec'd version
2046 // killough 3/1/98: moved to here
2047 respawnparm = clrespawnparm;
2048 fastparm = clfastparm;
2049 nomonsters = clnomonsters;
2050
2051 //jff 3/24/98 set startskill from defaultskill in config file, unless
2052 // it has already been set by a -skill parameter
2053 if (startskill==sk_none)
2054 startskill = (skill_t)(defaultskill-1);
2055
2056 demoplayback = false;
2057 singledemo = false; // killough 9/29/98: don't stop after 1 demo
2058 netdemo = false;
2059
2060 // killough 2/21/98:
2061 memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1));
2062
2063 consoleplayer = 0;
2064
2065 compatibility_level = default_compatibility_level;
2066 {
2067 int i = M_CheckParm("-complevel");
2068 if (i && (1+i) < myargc) {
2069 int l = atoi(myargv[i+1]);;
2070 if (l >= -1) compatibility_level = l;
2071 }
2072 }
2073 if (compatibility_level == -1)
2074 compatibility_level = best_compatibility;
2075
2076 if (mbf_features)
2077 memcpy(comp, default_comp, sizeof comp);
2078 G_Compatibility();
2079
2080 // killough 3/31/98, 4/5/98: demo sync insurance
2081 demo_insurance = default_demo_insurance == 1;
2082
2083 rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps
2084}
2085
2086void G_DoNewGame (void)
2087{
2088 G_ReloadDefaults(); // killough 3/1/98
2089 netgame = false; // killough 3/29/98
2090 deathmatch = false;
2091 G_InitNew (d_skill, d_episode, d_map);
2092 gameaction = ga_nothing;
2093
2094 //jff 4/26/98 wake up the status bar in case were coming out of a DM demo
2095 ST_Start();
2096}
2097
2098// killough 4/10/98: New function to fix bug which caused Doom
2099// lockups when idclev was used in conjunction with -fast.
2100
2101void G_SetFastParms(int fast_pending)
2102{
2103 static int fast = 0; // remembers fast state
2104 int i;
2105 if (fast != fast_pending) { /* only change if necessary */
2106 if ((fast = fast_pending))
2107 {
2108 for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2109 if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98
2110 states[i].tics >>= 1; // don't change 1->0 since it causes cycles
2111 mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
2112 mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
2113 mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
2114 }
2115 else
2116 {
2117 for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2118 states[i].tics <<= 1;
2119 mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
2120 mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
2121 mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
2122 }
2123 }
2124}
2125
2126//
2127// G_InitNew
2128// Can be called by the startup code or the menu task,
2129// consoleplayer, displayplayer, playeringame[] should be set.
2130//
2131
2132void G_InitNew(skill_t skill, int episode, int map)
2133{
2134 int i;
2135
2136 if (paused)
2137 {
2138 paused = false;
2139 S_ResumeSound();
2140 }
2141
2142 if (skill > sk_nightmare)
2143 skill = sk_nightmare;
2144
2145 if (episode < 1)
2146 episode = 1;
2147
2148 if (gamemode == retail)
2149 {
2150 if (episode > 4)
2151 episode = 4;
2152 }
2153 else
2154 if (gamemode == shareware)
2155 {
2156 if (episode > 1)
2157 episode = 1; // only start episode 1 on shareware
2158 }
2159 else
2160 if (episode > 3)
2161 episode = 3;
2162
2163 if (map < 1)
2164 map = 1;
2165 if (map > 9 && gamemode != commercial)
2166 map = 9;
2167
2168 G_SetFastParms(fastparm || skill == sk_nightmare); // killough 4/10/98
2169
2170 M_ClearRandom();
2171
2172 respawnmonsters = skill == sk_nightmare || respawnparm;
2173
2174 // force players to be initialized upon first level load
2175 for (i=0 ; i<MAXPLAYERS ; i++)
2176 players[i].playerstate = PST_REBORN;
2177
2178 usergame = true; // will be set false if a demo
2179 paused = false;
2180 automapmode &= ~am_active;
2181 gameepisode = episode;
2182 gamemap = map;
2183 gameskill = skill;
2184
2185 totalleveltimes = 0; // cph
2186
2187 //jff 4/16/98 force marks on automap cleared every new level start
2188 AM_clearMarks();
2189
2190 G_DoLoadLevel ();
2191}
2192
2193//
2194// DEMO RECORDING
2195//
2196
2197#define DEMOMARKER 0x80
2198
2199void G_ReadDemoTiccmd (ticcmd_t* cmd)
2200{
2201 unsigned char at; // e6y: tasdoom stuff
2202
2203 if (*demo_p == DEMOMARKER)
2204 G_CheckDemoStatus(); // end of demo data stream
2205 else if (demoplayback && demo_p + (longtics?5:4) > demobuffer + demolength)
2206 {
2207 lprintf(LO_WARN, "G_ReadDemoTiccmd: missing DEMOMARKER\n");
2208 G_CheckDemoStatus();
2209 }
2210 else
2211 {
2212 cmd->forwardmove = ((signed char)*demo_p++);
2213 cmd->sidemove = ((signed char)*demo_p++);
2214 if (!longtics) {
2215 cmd->angleturn = ((unsigned char)(at = *demo_p++))<<8;
2216 } else {
2217 unsigned int lowbyte = (unsigned char)*demo_p++;
2218 cmd->angleturn = (((signed int)(*demo_p++))<<8) + lowbyte;
2219 }
2220 cmd->buttons = (unsigned char)*demo_p++;
2221 // e6y: ability to play tasdoom demos directly
2222 if (compatibility_level == tasdoom_compatibility)
2223 {
2224 signed char k = cmd->forwardmove;
2225 cmd->forwardmove = cmd->sidemove;
2226 cmd->sidemove = (signed char)at;
2227 cmd->angleturn = ((unsigned char)cmd->buttons)<<8;
2228 cmd->buttons = (byte)k;
2229 }
2230 }
2231}
2232
2233/* Demo limits removed -- killough
2234 * cph - record straight to file
2235 */
2236void G_WriteDemoTiccmd (ticcmd_t* cmd)
2237{
2238 char buf[5];
2239 char *p = buf;
2240
2241 *p++ = cmd->forwardmove;
2242 *p++ = cmd->sidemove;
2243 if (!longtics) {
2244 *p++ = (cmd->angleturn+128)>>8;
2245 } else {
2246 signed short a = cmd->angleturn;
2247 *p++ = a & 0xff;
2248 *p++ = (a >> 8) & 0xff;
2249 }
2250 *p++ = cmd->buttons;
2251 if (fwrite(buf, p-buf, 1, demofp) != 1)
2252 I_Error("G_WriteDemoTiccmd: error writing demo");
2253
2254 /* cph - alias demo_p to it so we can read it back */
2255 demo_p = buf;
2256 G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
2257}
2258
2259//
2260// G_RecordDemo
2261//
2262
2263void G_RecordDemo (const char* name)
2264{
2265 char demoname[PATH_MAX];
2266 usergame = false;
2267 AddDefaultExtension(strcpy(demoname, name), ".lmp"); // 1/18/98 killough
2268 demorecording = true;
2269 /* cph - Record demos straight to file
2270 * If file already exists, try to continue existing demo
2271 */
2272 if (access(demoname, F_OK)) {
2273 demofp = fopen(demoname, "wb");
2274 } else {
2275 demofp = fopen(demoname, "r+");
2276 if (demofp) {
2277 int slot = -1;
2278 int rc;
2279 int bytes_per_tic;
2280 const byte* pos;
2281
2282 { /* Read the demo header for options etc */
2283 byte buf[200];
2284 size_t len = fread(buf, 1, sizeof(buf), demofp);
2285 pos = G_ReadDemoHeader(buf, len, false);
2286 if (pos)
2287 {
2288 fseek(demofp, pos - buf, SEEK_SET);
2289 }
2290 }
2291 bytes_per_tic = longtics ? 5 : 4;
2292 if (pos)
2293 /* Now read the demo to find the last save slot */
2294 do {
2295 byte buf[5];
2296
2297 rc = fread(buf, 1, bytes_per_tic, demofp);
2298 if (buf[0] == DEMOMARKER) break;
2299 if (buf[bytes_per_tic-1] & BT_SPECIAL)
2300 if ((buf[bytes_per_tic-1] & BT_SPECIALMASK) == BTS_SAVEGAME)
2301 slot = (buf[bytes_per_tic-1] & BTS_SAVEMASK)>>BTS_SAVESHIFT;
2302 } while (rc == bytes_per_tic);
2303
2304 if (slot == -1) I_Error("G_RecordDemo: No save in demo, can't continue");
2305
2306 /* Return to the last save position, and load the relevant savegame */
2307 fseek(demofp, -rc, SEEK_CUR);
2308 G_LoadGame(slot, false);
2309 autostart = false;
2310 }
2311 }
2312 if (!demofp) I_Error("G_RecordDemo: failed to open %s", name);
2313}
2314
2315// These functions are used to read and write game-specific options in demos
2316// and savegames so that demo sync is preserved and savegame restoration is
2317// complete. Not all options (for example "compatibility"), however, should
2318// be loaded and saved here. It is extremely important to use the same
2319// positions as before for the variables, so if one becomes obsolete, the
2320// byte(s) should still be skipped over or padded with 0's.
2321// Lee Killough 3/1/98
2322
2323extern int forceOldBsp;
2324
2325byte *G_WriteOptions(byte *demo_p)
2326{
2327 byte *target = demo_p + GAME_OPTION_SIZE;
2328
2329 *demo_p++ = monsters_remember; // part of monster AI
2330
2331 *demo_p++ = variable_friction; // ice & mud
2332
2333 *demo_p++ = weapon_recoil; // weapon recoil
2334
2335 *demo_p++ = allow_pushers; // MT_PUSH Things
2336
2337 *demo_p++ = 0;
2338
2339 *demo_p++ = player_bobbing; // whether player bobs or not
2340
2341 // killough 3/6/98: add parameters to savegame, move around some in demos
2342 *demo_p++ = respawnparm;
2343 *demo_p++ = fastparm;
2344 *demo_p++ = nomonsters;
2345
2346 *demo_p++ = demo_insurance; // killough 3/31/98
2347
2348 // killough 3/26/98: Added rngseed. 3/31/98: moved here
2349 *demo_p++ = (byte)((rngseed >> 24) & 0xff);
2350 *demo_p++ = (byte)((rngseed >> 16) & 0xff);
2351 *demo_p++ = (byte)((rngseed >> 8) & 0xff);
2352 *demo_p++ = (byte)( rngseed & 0xff);
2353
2354 // Options new to v2.03 begin here
2355
2356 *demo_p++ = monster_infighting; // killough 7/19/98
2357
2358#ifdef DOGS
2359 *demo_p++ = dogs; // killough 7/19/98
2360#else
2361 *demo_p++ = 0;
2362#endif
2363
2364 *demo_p++ = 0;
2365 *demo_p++ = 0;
2366
2367 *demo_p++ = (distfriend >> 8) & 0xff; // killough 8/8/98
2368 *demo_p++ = distfriend & 0xff; // killough 8/8/98
2369
2370 *demo_p++ = monster_backing; // killough 9/8/98
2371
2372 *demo_p++ = monster_avoid_hazards; // killough 9/9/98
2373
2374 *demo_p++ = monster_friction; // killough 10/98
2375
2376 *demo_p++ = help_friends; // killough 9/9/98
2377
2378#ifdef DOGS
2379 *demo_p++ = dog_jumping;
2380#else
2381 *demo_p++ = 0;
2382#endif
2383
2384 *demo_p++ = monkeys;
2385
2386 { // killough 10/98: a compatibility vector now
2387 int i;
2388 for (i=0; i < COMP_TOTAL; i++)
2389 *demo_p++ = comp[i] != 0;
2390 }
2391
2392 *demo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20
2393
2394 //----------------
2395 // Padding at end
2396 //----------------
2397 while (demo_p < target)
2398 *demo_p++ = 0;
2399
2400 if (demo_p != target)
2401 I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small");
2402
2403 return target;
2404}
2405
2406/* Same, but read instead of write
2407 * cph - const byte*'s
2408 */
2409
2410const byte *G_ReadOptions(const byte *demo_p)
2411{
2412 const byte *target = demo_p + GAME_OPTION_SIZE;
2413
2414 monsters_remember = *demo_p++;
2415
2416 variable_friction = *demo_p; // ice & mud
2417 demo_p++;
2418
2419 weapon_recoil = *demo_p; // weapon recoil
2420 demo_p++;
2421
2422 allow_pushers = *demo_p; // MT_PUSH Things
2423 demo_p++;
2424
2425 demo_p++;
2426
2427 player_bobbing = *demo_p; // whether player bobs or not
2428 demo_p++;
2429
2430 // killough 3/6/98: add parameters to savegame, move from demo
2431 respawnparm = *demo_p++;
2432 fastparm = *demo_p++;
2433 nomonsters = *demo_p++;
2434
2435 demo_insurance = *demo_p++; // killough 3/31/98
2436
2437 // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here
2438
2439 rngseed = *demo_p++ & 0xff;
2440 rngseed <<= 8;
2441 rngseed += *demo_p++ & 0xff;
2442 rngseed <<= 8;
2443 rngseed += *demo_p++ & 0xff;
2444 rngseed <<= 8;
2445 rngseed += *demo_p++ & 0xff;
2446
2447 // Options new to v2.03
2448 if (mbf_features)
2449 {
2450 monster_infighting = *demo_p++; // killough 7/19/98
2451
2452#ifdef DOGS
2453 dogs = *demo_p++; // killough 7/19/98
2454#else
2455 demo_p++;
2456#endif
2457
2458 demo_p += 2;
2459
2460 distfriend = *demo_p++ << 8; // killough 8/8/98
2461 distfriend+= *demo_p++;
2462
2463 monster_backing = *demo_p++; // killough 9/8/98
2464
2465 monster_avoid_hazards = *demo_p++; // killough 9/9/98
2466
2467 monster_friction = *demo_p++; // killough 10/98
2468
2469 help_friends = *demo_p++; // killough 9/9/98
2470
2471#ifdef DOGS
2472 dog_jumping = *demo_p++; // killough 10/98
2473#else
2474 demo_p++;
2475#endif
2476
2477 monkeys = *demo_p++;
2478
2479 { // killough 10/98: a compatibility vector now
2480 int i;
2481 for (i=0; i < COMP_TOTAL; i++)
2482 comp[i] = *demo_p++;
2483 }
2484
2485 forceOldBsp = *demo_p++; // cph 2002/07/20
2486 }
2487 else /* defaults for versions <= 2.02 */
2488 {
2489 /* G_Compatibility will set these */
2490 }
2491
2492 G_Compatibility();
2493 return target;
2494}
2495
2496void G_BeginRecording (void)
2497{
2498 int i;
2499 byte *demostart, *demo_p;
2500 demostart = demo_p = malloc(1000);
2501 longtics = 0;
2502
2503 /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */
2504 if (mbf_features) {
2505 { /* Write version code into demo */
2506 unsigned char v;
2507 switch(compatibility_level) {
2508 case mbf_compatibility: v = 203; break; // e6y: Bug in MBF compatibility mode fixed
2509 case prboom_2_compatibility: v = 210; break;
2510 case prboom_3_compatibility: v = 211; break;
2511 case prboom_4_compatibility: v = 212; break;
2512 case prboom_5_compatibility: v = 213; break;
2513 case prboom_6_compatibility:
2514 v = 214;
2515 longtics = 1;
2516 break;
2517 }
2518 *demo_p++ = v;
2519 }
2520
2521 // signature
2522 *demo_p++ = 0x1d;
2523 *demo_p++ = 'M';
2524 *demo_p++ = 'B';
2525 *demo_p++ = 'F';
2526 *demo_p++ = 0xe6;
2527 *demo_p++ = '\0';
2528
2529 /* killough 2/22/98: save compatibility flag in new demos
2530 * cph - FIXME? MBF demos will always be not in compat. mode */
2531 *demo_p++ = 0;
2532
2533 *demo_p++ = gameskill;
2534 *demo_p++ = gameepisode;
2535 *demo_p++ = gamemap;
2536 *demo_p++ = deathmatch;
2537 *demo_p++ = consoleplayer;
2538
2539 demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
2540
2541 for (i=0 ; i<MAXPLAYERS ; i++)
2542 *demo_p++ = playeringame[i];
2543
2544 // killough 2/28/98:
2545 // We always store at least MIN_MAXPLAYERS bytes in demo, to
2546 // support enhancements later w/o losing demo compatibility
2547
2548 for (; i<MIN_MAXPLAYERS; i++)
2549 *demo_p++ = 0;
2550
2551 } else if (compatibility_level > boom_compatibility_compatibility) {
2552 byte v, c; /* Nominally, version and compatibility bits */
2553 switch (compatibility_level) {
2554 case boom_compatibility_compatibility: v = 202, c = 1; break;
2555 case boom_201_compatibility: v = 201; c = 0; break;
2556 case boom_202_compatibility: v = 202, c = 0; break;
2557 default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?");
2558 }
2559 *demo_p++ = v;
2560
2561 // signature
2562 *demo_p++ = 0x1d;
2563 *demo_p++ = 'B';
2564 *demo_p++ = 'o';
2565 *demo_p++ = 'o';
2566 *demo_p++ = 'm';
2567 *demo_p++ = 0xe6;
2568
2569 /* CPhipps - save compatibility level in demos */
2570 *demo_p++ = c;
2571
2572 *demo_p++ = gameskill;
2573 *demo_p++ = gameepisode;
2574 *demo_p++ = gamemap;
2575 *demo_p++ = deathmatch;
2576 *demo_p++ = consoleplayer;
2577
2578 demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
2579
2580 for (i=0 ; i<MAXPLAYERS ; i++)
2581 *demo_p++ = playeringame[i];
2582
2583 // killough 2/28/98:
2584 // We always store at least MIN_MAXPLAYERS bytes in demo, to
2585 // support enhancements later w/o losing demo compatibility
2586
2587 for (; i<MIN_MAXPLAYERS; i++)
2588 *demo_p++ = 0;
2589 } else { // cph - write old v1.9 demos (might even sync)
2590 longtics = M_CheckParm("-longtics");
2591 *demo_p++ = longtics ? 111 : 109; // v1.9 has best chance of syncing these
2592 *demo_p++ = gameskill;
2593 *demo_p++ = gameepisode;
2594 *demo_p++ = gamemap;
2595 *demo_p++ = deathmatch;
2596 *demo_p++ = respawnparm;
2597 *demo_p++ = fastparm;
2598 *demo_p++ = nomonsters;
2599 *demo_p++ = consoleplayer;
2600 for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough
2601 *demo_p++ = playeringame[i];
2602 }
2603
2604 if (fwrite(demostart, 1, demo_p-demostart, demofp) != (size_t)(demo_p-demostart))
2605 I_Error("G_BeginRecording: Error writing demo header");
2606 free(demostart);
2607}
2608
2609//
2610// G_PlayDemo
2611//
2612
2613static const char *defdemoname;
2614
2615void G_DeferedPlayDemo (const char* name)
2616{
2617 defdemoname = name;
2618 gameaction = ga_playdemo;
2619}
2620
2621static int demolumpnum = -1;
2622
2623static int G_GetOriginalDoomCompatLevel(int ver)
2624{
2625 {
2626 int lev;
2627 int i = M_CheckParm("-complevel");
2628 if (i && (i+1 < myargc))
2629 {
2630 lev = atoi(myargv[i+1]);
2631 if (lev>=0)
2632 return lev;
2633 }
2634 }
2635 if (ver < 107) return doom_1666_compatibility;
2636 if (gamemode == retail) return ultdoom_compatibility;
2637 if (gamemission >= pack_tnt) return finaldoom_compatibility;
2638 return doom2_19_compatibility;
2639}
2640
2641//e6y: Check for overrun
2642static boolean CheckForOverrun(const byte *start_p, const byte *current_p, size_t maxsize, size_t size, boolean failonerror)
2643{
2644 size_t pos = current_p - start_p;
2645 if (pos + size > maxsize)
2646 {
2647 if (failonerror)
2648 I_Error("G_ReadDemoHeader: wrong demo header\n");
2649 else
2650 return true;
2651 }
2652 return false;
2653}
2654
2655static const byte* G_ReadDemoHeader(const byte *demo_p, size_t size, boolean failonerror)
2656{
2657 skill_t skill;
2658 int i, episode, map;
2659
2660 // e6y
2661 // The local variable should be used instead of demobuffer,
2662 // because demobuffer can be uninitialized
2663 const byte *header_p = demo_p;
2664
2665 const byte *option_p = NULL; /* killough 11/98 */
2666
2667 basetic = gametic; // killough 9/29/98
2668
2669 // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly.
2670 // Old demos turn on demo_compatibility => compatibility; new demos load
2671 // compatibility flag, and other flags as well, as a part of the demo.
2672
2673 //e6y: check for overrun
2674 if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
2675 return NULL;
2676
2677 demover = *demo_p++;
2678 longtics = 0;
2679
2680 // e6y
2681 // Handling of unrecognized demo formats
2682 // Versions up to 1.2 use a 7-byte header - first byte is a skill level.
2683 // Versions after 1.2 use a 13-byte header - first byte is a demoversion.
2684 // BOOM's demoversion starts from 200
2685 if (!((demover >= 0 && demover <= 4) ||
2686 (demover >= 104 && demover <= 111) ||
2687 (demover >= 200 && demover <= 214)))
2688 {
2689 I_Error("G_ReadDemoHeader: Unknown demo format %d.", demover);
2690 }
2691
2692 if (demover < 200) // Autodetect old demos
2693 {
2694 if (demover >= 111) longtics = 1;
2695
2696 // killough 3/2/98: force these variables to be 0 in demo_compatibility
2697
2698 variable_friction = 0;
2699
2700 weapon_recoil = 0;
2701
2702 allow_pushers = 0;
2703
2704 monster_infighting = 1; // killough 7/19/98
2705
2706#ifdef DOGS
2707 dogs = 0; // killough 7/19/98
2708 dog_jumping = 0; // killough 10/98
2709#endif
2710
2711 monster_backing = 0; // killough 9/8/98
2712
2713 monster_avoid_hazards = 0; // killough 9/9/98
2714
2715 monster_friction = 0; // killough 10/98
2716 help_friends = 0; // killough 9/9/98
2717 monkeys = 0;
2718
2719 // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm,
2720 // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions())
2721
2722 if ((skill=demover) >= 100) // For demos from versions >= 1.4
2723 {
2724 //e6y: check for overrun
2725 if (CheckForOverrun(header_p, demo_p, size, 8, failonerror))
2726 return NULL;
2727
2728 compatibility_level = G_GetOriginalDoomCompatLevel(demover);
2729 skill = *demo_p++;
2730 episode = *demo_p++;
2731 map = *demo_p++;
2732 deathmatch = *demo_p++;
2733 respawnparm = *demo_p++;
2734 fastparm = *demo_p++;
2735 nomonsters = *demo_p++;
2736 consoleplayer = *demo_p++;
2737 }
2738 else
2739 {
2740 //e6y: check for overrun
2741 if (CheckForOverrun(header_p, demo_p, size, 2, failonerror))
2742 return NULL;
2743
2744 compatibility_level = doom_12_compatibility;
2745 episode = *demo_p++;
2746 map = *demo_p++;
2747 deathmatch = respawnparm = fastparm =
2748 nomonsters = consoleplayer = 0;
2749 }
2750 G_Compatibility();
2751 }
2752 else // new versions of demos
2753 {
2754 demo_p += 6; // skip signature;
2755 switch (demover) {
2756 case 200: /* BOOM */
2757 case 201:
2758 //e6y: check for overrun
2759 if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
2760 return NULL;
2761
2762 if (!*demo_p++)
2763 compatibility_level = boom_201_compatibility;
2764 else
2765 compatibility_level = boom_compatibility_compatibility;
2766 break;
2767 case 202:
2768 //e6y: check for overrun
2769 if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
2770 return NULL;
2771
2772 if (!*demo_p++)
2773 compatibility_level = boom_202_compatibility;
2774 else
2775 compatibility_level = boom_compatibility_compatibility;
2776 break;
2777 case 203:
2778 /* LxDoom or MBF - determine from signature
2779 * cph - load compatibility level */
2780 switch (*(header_p + 2)) {
2781 case 'B': /* LxDoom */
2782 /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */
2783 compatibility_level = lxdoom_1_compatibility;
2784 break;
2785 case 'M':
2786 compatibility_level = mbf_compatibility;
2787 demo_p++;
2788 break;
2789 }
2790 break;
2791 case 210:
2792 compatibility_level = prboom_2_compatibility;
2793 demo_p++;
2794 break;
2795 case 211:
2796 compatibility_level = prboom_3_compatibility;
2797 demo_p++;
2798 break;
2799 case 212:
2800 compatibility_level = prboom_4_compatibility;
2801 demo_p++;
2802 break;
2803 case 213:
2804 compatibility_level = prboom_5_compatibility;
2805 demo_p++;
2806 break;
2807 case 214:
2808 compatibility_level = prboom_6_compatibility;
2809 longtics = 1;
2810 demo_p++;
2811 break;
2812 }
2813 //e6y: check for overrun
2814 if (CheckForOverrun(header_p, demo_p, size, 5, failonerror))
2815 return NULL;
2816
2817 skill = *demo_p++;
2818 episode = *demo_p++;
2819 map = *demo_p++;
2820 deathmatch = *demo_p++;
2821 consoleplayer = *demo_p++;
2822
2823 /* killough 11/98: save option pointer for below */
2824 if (mbf_features)
2825 option_p = demo_p;
2826
2827 //e6y: check for overrun
2828 if (CheckForOverrun(header_p, demo_p, size, GAME_OPTION_SIZE, failonerror))
2829 return NULL;
2830
2831 demo_p = G_ReadOptions(demo_p); // killough 3/1/98: Read game options
2832
2833 if (demover == 200) // killough 6/3/98: partially fix v2.00 demos
2834 demo_p += 256-GAME_OPTION_SIZE;
2835 }
2836
2837 if (sizeof(comp_lev_str)/sizeof(comp_lev_str[0]) != MAX_COMPATIBILITY_LEVEL)
2838 I_Error("G_ReadDemoHeader: compatibility level strings incomplete");
2839 lprintf(LO_INFO, "G_DoPlayDemo: playing demo with %s compatibility\n",
2840 comp_lev_str[compatibility_level]);
2841
2842 if (demo_compatibility) // only 4 players can exist in old demos
2843 {
2844 //e6y: check for overrun
2845 if (CheckForOverrun(header_p, demo_p, size, 4, failonerror))
2846 return NULL;
2847
2848 for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough
2849 playeringame[i] = *demo_p++;
2850 for (;i < MAXPLAYERS; i++)
2851 playeringame[i] = 0;
2852 }
2853 else
2854 {
2855 //e6y: check for overrun
2856 if (CheckForOverrun(header_p, demo_p, size, MAXPLAYERS, failonerror))
2857 return NULL;
2858
2859 for (i=0 ; i < MAXPLAYERS; i++)
2860 playeringame[i] = *demo_p++;
2861 demo_p += MIN_MAXPLAYERS - MAXPLAYERS;
2862 }
2863
2864 if (playeringame[1])
2865 {
2866 netgame = true;
2867 netdemo = true;
2868 }
2869
2870 if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */
2871 G_InitNew(skill, episode, map);
2872 }
2873
2874 for (i=0; i<MAXPLAYERS;i++) // killough 4/24/98
2875 players[i].cheats = 0;
2876
2877 return demo_p;
2878}
2879
2880void G_DoPlayDemo(void)
2881{
2882 char basename[9];
2883
2884 ExtractFileBase(defdemoname,basename); // killough
2885 basename[8] = 0;
2886
2887 /* cph - store lump number for unlocking later */
2888 demolumpnum = W_GetNumForName(basename);
2889 demobuffer = W_CacheLumpNum(demolumpnum);
2890 demolength = W_LumpLength(demolumpnum);
2891
2892 demo_p = G_ReadDemoHeader(demobuffer, demolength, true);
2893
2894 gameaction = ga_nothing;
2895 usergame = false;
2896
2897 demoplayback = true;
2898 R_SmoothPlaying_Reset(NULL); // e6y
2899
2900 starttime = I_GetTime_RealTime ();
2901}
2902
2903/* G_CheckDemoStatus
2904 *
2905 * Called after a death or level completion to allow demos to be cleaned up
2906 * Returns true if a new demo loop action will take place
2907 */
2908boolean G_CheckDemoStatus (void)
2909{
2910 P_ChecksumFinal();
2911
2912 if (demorecording)
2913 {
2914 demorecording = false;
2915 fputc(DEMOMARKER, demofp);
2916 I_Error("G_CheckDemoStatus: Demo recorded");
2917 return false; // killough
2918 }
2919
2920 if (timingdemo)
2921 {
2922 int endtime = I_GetTime_RealTime ();
2923 // killough -- added fps information and made it work for longer demos:
2924 unsigned realtics = endtime-starttime;
2925 I_Error ("Timed %u gametics in %u realtics = %-.1f frames per second",
2926 (unsigned) gametic,realtics,
2927 (unsigned) gametic * (double) TICRATE / realtics);
2928 }
2929
2930 if (demoplayback)
2931 {
2932 if (singledemo)
2933 exit(0); // killough
2934
2935 if (demolumpnum != -1) {
2936 // cph - unlock the demo lump
2937 W_UnlockLumpNum(demolumpnum);
2938 demolumpnum = -1;
2939 }
2940 G_ReloadDefaults(); // killough 3/1/98
2941 netgame = false; // killough 3/29/98
2942 deathmatch = false;
2943 D_AdvanceDemo ();
2944 return true;
2945 }
2946 return false;
2947}
2948
2949// killough 1/22/98: this is a "Doom printf" for messages. I've gotten
2950// tired of using players->message=... and so I've added this dprintf.
2951//
2952// killough 3/6/98: Made limit static to allow z_zone functions to call
2953// this function, without calling realloc(), which seems to cause problems.
2954
2955#define MAX_MESSAGE_SIZE 1024
2956
2957// CPhipps - renamed to doom_printf to avoid name collision with glibc
2958void doom_printf(const char *s, ...)
2959{
2960 static char msg[MAX_MESSAGE_SIZE];
2961 va_list v;
2962 va_start(v,s);
2963#ifdef HAVE_VSNPRINTF
2964 vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */
2965#else
2966 vsprintf(msg,s,v);
2967#endif
2968 va_end(v);
2969 players[consoleplayer].message = msg; // set new message
2970}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: Main game control interface.
30 *-----------------------------------------------------------------------------*/
31
32#ifndef __G_GAME__
33#define __G_GAME__
34
35#include "doomdef.h"
36#include "d_event.h"
37#include "d_ticcmd.h"
38
39//
40// GAME
41//
42
43// killough 5/2/98: number of bytes reserved for saving options
44#define GAME_OPTION_SIZE 64
45
46boolean G_Responder(event_t *ev);
47boolean G_CheckDemoStatus(void);
48void G_DeathMatchSpawnPlayer(int playernum);
49void G_InitNew(skill_t skill, int episode, int map);
50void G_DeferedInitNew(skill_t skill, int episode, int map);
51void G_DeferedPlayDemo(const char *demo); // CPhipps - const
52void G_LoadGame(int slot, boolean is_command); // killough 5/15/98
53void G_ForcedLoadGame(void); // killough 5/15/98: forced loadgames
54void G_DoLoadGame(void);
55void G_SaveGame(int slot, char *description); // Called by M_Responder.
56void G_BeginRecording(void);
57// CPhipps - const on these string params
58void G_RecordDemo(const char *name); // Only called by startup code.
59void G_ExitLevel(void);
60void G_SecretExitLevel(void);
61void G_WorldDone(void);
62void G_EndGame(void); /* cph - make m_menu.c call a G_* function for this */
63void G_Ticker(void);
64void G_ReloadDefaults(void); // killough 3/1/98: loads game defaults
65void G_SaveGameName(char *, size_t, int, boolean); /* killough 3/22/98: sets savegame filename */
66void G_SetFastParms(int); // killough 4/10/98: sets -fast parameters
67void G_DoNewGame(void);
68void G_DoReborn(int playernum);
69void G_DoPlayDemo(void);
70void G_DoCompleted(void);
71void G_ReadDemoTiccmd(ticcmd_t *cmd);
72void G_WriteDemoTiccmd(ticcmd_t *cmd);
73void G_DoWorldDone(void);
74void G_Compatibility(void);
75const byte *G_ReadOptions(const byte *demo_p); /* killough 3/1/98 - cph: const byte* */
76byte *G_WriteOptions(byte *demo_p); // killough 3/1/98
77void G_PlayerReborn(int player);
78void G_RestartLevel(void); // CPhipps - menu involked level restart
79void G_DoVictory(void);
80void G_BuildTiccmd (ticcmd_t* cmd); // CPhipps - move decl to header
81void G_ChangedPlayerColour(int pn, int cl); // CPhipps - On-the-fly player colour changing
82void G_MakeSpecialEvent(buttoncode_t bc, ...); /* cph - new event stuff */
83
84// killough 1/18/98: Doom-style printf; killough 4/25/98: add gcc attributes
85// CPhipps - renames to doom_printf to avoid name collision with glibc
86void doom_printf(const char *, ...) __attribute__((format(printf,1,2)));
87
88// killough 5/2/98: moved from m_misc.c:
89
90extern int key_right;
91extern int key_left;
92extern int key_up;
93extern int key_down;
94extern int key_menu_right; // phares 3/7/98
95extern int key_menu_left; // |
96extern int key_menu_up; // V
97extern int key_menu_down;
98extern int key_menu_backspace; // ^
99extern int key_menu_escape; // |
100extern int key_menu_enter; // phares 3/7/98
101extern int key_strafeleft;
102extern int key_straferight;
103
104extern int key_fire;
105extern int key_use;
106extern int key_strafe;
107extern int key_speed;
108extern int key_escape; // phares
109extern int key_savegame; // |
110extern int key_loadgame; // V
111extern int key_autorun;
112extern int key_reverse;
113extern int key_zoomin;
114extern int key_zoomout;
115extern int key_chat;
116extern int key_backspace;
117extern int key_enter;
118extern int key_help;
119extern int key_soundvolume;
120extern int key_hud;
121extern int key_quicksave;
122extern int key_endgame;
123extern int key_messages;
124extern int key_quickload;
125extern int key_quit;
126extern int key_gamma;
127extern int key_spy;
128extern int key_pause;
129extern int key_setup;
130extern int key_forward;
131extern int key_leftturn;
132extern int key_rightturn;
133extern int key_backward;
134extern int key_weapontoggle;
135extern int key_weapon1;
136extern int key_weapon2;
137extern int key_weapon3;
138extern int key_weapon4;
139extern int key_weapon5;
140extern int key_weapon6;
141extern int key_weapon7;
142extern int key_weapon8;
143extern int key_weapon9;
144extern int destination_keys[MAXPLAYERS];
145extern int key_map_right;
146extern int key_map_left;
147extern int key_map_up;
148extern int key_map_down;
149extern int key_map_zoomin;
150extern int key_map_zoomout;
151extern int key_map;
152extern int key_map_gobig;
153extern int key_map_follow;
154extern int key_map_mark; // ^
155extern int key_map_clear; // |
156extern int key_map_grid; // phares
157extern int key_map_rotate; // cph - map rotation
158extern int key_map_overlay;// cph - map overlay
159extern int key_screenshot; // killough 2/22/98 -- add key for screenshot
160extern int autorun; // always running? // phares
161
162extern int defaultskill; //jff 3/24/98 default skill
163extern boolean haswolflevels; //jff 4/18/98 wolf levels present
164
165extern int bodyquesize; // killough 2/8/98: adustable corpse limit
166
167// killough 5/2/98: moved from d_deh.c:
168// Par times (new item with BOOM) - from g_game.c
169extern int pars[4][10]; // hardcoded array size
170extern int cpars[32]; // hardcoded array size
171// CPhipps - Make savedesciption visible in wider scope
172#define SAVEDESCLEN 32
173extern char savedescription[SAVEDESCLEN]; // Description to save in savegame
174
175/* cph - compatibility level strings */
176extern const char * comp_lev_str[];
177
178#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: heads-up text and input code
30 *
31 *-----------------------------------------------------------------------------
32 */
33
34#include "doomdef.h"
35#include "doomstat.h"
36#include "v_video.h"
37#include "m_swap.h"
38#include "hu_lib.h"
39#include "hu_stuff.h"
40#include "r_main.h"
41#include "r_draw.h"
42
43// boolean : whether the screen is always erased
44#define noterased viewwindowx
45
46extern int key_backspace; // phares
47extern int key_enter; // phares
48
49//
50// not used currently
51// code to initialize HUlib would go here if needed
52//
53static void HUlib_init(void)
54{
55}
56
57////////////////////////////////////////////////////////
58//
59// Basic text line widget
60//
61////////////////////////////////////////////////////////
62
63//
64// HUlib_clearTextLine()
65//
66// Blank the internal text line in a hu_textline_t widget
67//
68// Passed a hu_textline_t, returns nothing
69//
70void HUlib_clearTextLine(hu_textline_t* t)
71{
72 t->linelen = // killough 1/23 98: support multiple lines
73 t->len = 0;
74 t->l[0] = 0;
75 t->needsupdate = true;
76}
77
78//
79// HUlib_initTextLine()
80//
81// Initialize a hu_textline_t widget. Set the position, font, start char
82// of the font, and color range to be used.
83//
84// Passed a hu_textline_t, and the values used to initialize
85// Returns nothing
86//
87void HUlib_initTextLine(hu_textline_t* t, int x, int y,
88 const patchnum_t* f, int sc, int cm )
89 //jff 2/16/98 add color range parameter
90{
91 t->x = x;
92 t->y = y;
93 t->f = f;
94 t->sc = sc;
95 t->cm = cm;
96 HUlib_clearTextLine(t);
97}
98
99//
100// HUlib_addCharToTextLine()
101//
102// Adds a character at the end of the text line in a hu_textline_t widget
103//
104// Passed the hu_textline_t and the char to add
105// Returns false if already at length limit, true if the character added
106//
107boolean HUlib_addCharToTextLine
108( hu_textline_t* t,
109 char ch )
110{
111 // killough 1/23/98 -- support multiple lines
112 if (t->linelen == HU_MAXLINELENGTH)
113 return false;
114 else
115 {
116 t->linelen++;
117 if (ch == '\n')
118 t->linelen=0;
119
120 t->l[t->len++] = ch;
121 t->l[t->len] = 0;
122 t->needsupdate = 4;
123 return true;
124 }
125
126}
127
128//
129// HUlib_delCharFromTextLine()
130//
131// Deletes a character at the end of the text line in a hu_textline_t widget
132//
133// Passed the hu_textline_t
134// Returns false if already empty, true if the character deleted
135//
136static boolean HUlib_delCharFromTextLine(hu_textline_t* t)
137{
138 if (!t->len) return false;
139 else
140 {
141 t->l[--t->len] = 0;
142 t->needsupdate = 4;
143 return true;
144 }
145}
146
147//
148// HUlib_drawTextLine()
149//
150// Draws a hu_textline_t widget
151//
152// Passed the hu_textline_t and flag whether to draw a cursor
153// Returns nothing
154//
155void HUlib_drawTextLine
156( hu_textline_t* l,
157 boolean drawcursor )
158{
159
160 int i;
161 int w;
162 int x;
163 unsigned char c;
164 int oc = l->cm; //jff 2/17/98 remember default color
165 int y = l->y; // killough 1/18/98 -- support multiple lines
166
167 // draw the new stuff
168 x = l->x;
169 for (i=0;i<l->len;i++)
170 {
171 c = toupper(l->l[i]); //jff insure were not getting a cheap toupper conv.
172
173 if (c=='\n') // killough 1/18/98 -- support multiple lines
174 x=0,y+=8;
175 else if (c=='\t') // killough 1/23/98 -- support tab stops
176 x=x-x%80+80;
177 else if (c=='\x1b') //jff 2/17/98 escape code for color change
178 { //jff 3/26/98 changed to actual escape char
179 if (++i<l->len)
180 if (l->l[i]>='0' && l->l[i]<='9')
181 l->cm = l->l[i]-'0';
182 }
183 else if (c != ' ' && c >= l->sc && c <= 127)
184 {
185 w = l->f[c - l->sc].width;
186 if (x+w > BASE_WIDTH)
187 break;
188 // killough 1/18/98 -- support multiple lines:
189 // CPhipps - patch drawing updated
190 V_DrawNumPatch(x, y, FG, l->f[c - l->sc].lumpnum, l->cm, VPT_TRANS | VPT_STRETCH);
191 x += w;
192 }
193 else
194 {
195 x += 4;
196 if (x >= BASE_WIDTH)
197 break;
198 }
199 }
200 l->cm = oc; //jff 2/17/98 restore original color
201
202 // draw the cursor if requested
203 if (drawcursor && x + l->f['_' - l->sc].width <= BASE_WIDTH)
204 {
205 // killough 1/18/98 -- support multiple lines
206 // CPhipps - patch drawing updated
207 V_DrawNumPatch(x, y, FG, l->f['_' - l->sc].lumpnum, CR_DEFAULT, VPT_NONE | VPT_STRETCH);
208 }
209}
210
211//
212// HUlib_eraseTextLine()
213//
214// Erases a hu_textline_t widget when screen border is behind text
215// Sorta called by HU_Erase and just better darn get things straight
216//
217// Passed the hu_textline_t
218// Returns nothing
219//
220void HUlib_eraseTextLine(hu_textline_t* l)
221{
222 int lh;
223 int y;
224
225 // Only erases when NOT in automap and the screen is reduced,
226 // and the text must either need updating or refreshing
227 // (because of a recent change back from the automap)
228
229 if (!(automapmode & am_active) && viewwindowx && l->needsupdate)
230 {
231 lh = l->f[0].height + 1;
232 for (y=l->y; y<l->y+lh ; y++)
233 {
234 if (y < viewwindowy || y >= viewwindowy + viewheight)
235 R_VideoErase(0, y, SCREENWIDTH); // erase entire line
236 else
237 {
238 // erase left border
239 R_VideoErase(0, y, viewwindowx);
240 // erase right border
241 R_VideoErase(viewwindowx + viewwidth, y, viewwindowx);
242 }
243 }
244 }
245
246 if (l->needsupdate) l->needsupdate--;
247}
248
249////////////////////////////////////////////////////////
250//
251// Player message widget (up to 4 lines of text)
252//
253////////////////////////////////////////////////////////
254
255//
256// HUlib_initSText()
257//
258// Initialize a hu_stext_t widget. Set the position, number of lines, font,
259// start char of the font, and color range to be used, and whether enabled.
260//
261// Passed a hu_stext_t, and the values used to initialize
262// Returns nothing
263//
264void HUlib_initSText
265( hu_stext_t* s,
266 int x,
267 int y,
268 int h,
269 const patchnum_t* font,
270 int startchar,
271 int cm, //jff 2/16/98 add color range parameter
272 boolean* on )
273{
274
275 int i;
276
277 s->h = h;
278 s->on = on;
279 s->laston = true;
280 s->cl = 0;
281 for (i=0;i<h;i++)
282 HUlib_initTextLine
283 (
284 &s->l[i],
285 x,
286 y - i*(font[0].height+1),
287 font,
288 startchar,
289 cm
290 );
291}
292
293//
294// HUlib_addLineToSText()
295//
296// Adds a blank line to a hu_stext_t widget
297//
298// Passed a hu_stext_t
299// Returns nothing
300//
301static void HUlib_addLineToSText(hu_stext_t* s)
302{
303
304 int i;
305
306 // add a clear line
307 if (++s->cl == s->h)
308 s->cl = 0;
309 HUlib_clearTextLine(&s->l[s->cl]);
310
311 // everything needs updating
312 for (i=0 ; i<s->h ; i++)
313 s->l[i].needsupdate = 4;
314
315}
316
317//
318// HUlib_addMessageToSText()
319//
320// Adds a message line with prefix to a hu_stext_t widget
321//
322// Passed a hu_stext_t, the prefix string, and a message string
323// Returns nothing
324//
325void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg)
326{
327 HUlib_addLineToSText(s);
328 if (prefix)
329 while (*prefix)
330 HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++));
331
332 while (*msg)
333 HUlib_addCharToTextLine(&s->l[s->cl], *(msg++));
334}
335
336//
337// HUlib_drawSText()
338//
339// Displays a hu_stext_t widget
340//
341// Passed a hu_stext_t
342// Returns nothing
343//
344void HUlib_drawSText(hu_stext_t* s)
345{
346 int i, idx;
347 hu_textline_t *l;
348
349 if (!*s->on)
350 return; // if not on, don't draw
351
352 // draw everything
353 for (i=0 ; i<s->h ; i++)
354 {
355 idx = s->cl - i;
356 if (idx < 0)
357 idx += s->h; // handle queue of lines
358
359 l = &s->l[idx];
360
361 // need a decision made here on whether to skip the draw
362 HUlib_drawTextLine(l, false); // no cursor, please
363 }
364}
365
366//
367// HUlib_eraseSText()
368//
369// Erases a hu_stext_t widget, when the screen is not fullsize
370//
371// Passed a hu_stext_t
372// Returns nothing
373//
374void HUlib_eraseSText(hu_stext_t* s)
375{
376 int i;
377
378 for (i=0 ; i<s->h ; i++)
379 {
380 if (s->laston && !*s->on)
381 s->l[i].needsupdate = 4;
382 HUlib_eraseTextLine(&s->l[i]);
383 }
384 s->laston = *s->on;
385}
386
387////////////////////////////////////////////////////////
388//
389// Scrolling message review widget
390//
391// jff added 2/26/98
392//
393////////////////////////////////////////////////////////
394
395//
396// HUlib_initMText()
397//
398// Initialize a hu_mtext_t widget. Set the position, width, number of lines,
399// font, start char of the font, color range, background font, and whether
400// enabled.
401//
402// Passed a hu_mtext_t, and the values used to initialize
403// Returns nothing
404//
405void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h,
406 const patchnum_t* font, int startchar, int cm,
407 const patchnum_t* bgfont, boolean *on)
408{
409 int i;
410
411 m->nl = 0;
412 m->nr = 0;
413 m->cl = -1; //jff 4/28/98 prepare for pre-increment
414 m->x = x;
415 m->y = y;
416 m->w = w;
417 m->h = h;
418 m->bg = bgfont;
419 m->on = on;
420 for (i=0;i<HU_MAXMESSAGES;i++)
421 {
422 HUlib_initTextLine
423 (
424 &m->l[i],
425 x,
426 y + (hud_list_bgon? i+1 : i)*HU_REFRESHSPACING,
427 font,
428 startchar,
429 cm
430 );
431 }
432}
433
434//
435// HUlib_addLineToMText()
436//
437// Adds a blank line to a hu_mtext_t widget
438//
439// Passed a hu_mtext_t
440// Returns nothing
441//
442static void HUlib_addLineToMText(hu_mtext_t* m)
443{
444 // add a clear line
445 if (++m->cl == hud_msg_lines)
446 m->cl = 0;
447 HUlib_clearTextLine(&m->l[m->cl]);
448
449 if (m->nl<hud_msg_lines)
450 m->nl++;
451
452 // needs updating
453 m->l[m->cl].needsupdate = 4;
454}
455
456//
457// HUlib_addMessageToMText()
458//
459// Adds a message line with prefix to a hu_mtext_t widget
460//
461// Passed a hu_mtext_t, the prefix string, and a message string
462// Returns nothing
463//
464void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg)
465{
466 HUlib_addLineToMText(m);
467 if (prefix)
468 while (*prefix)
469 HUlib_addCharToTextLine(&m->l[m->cl], *(prefix++));
470
471 while (*msg)
472 HUlib_addCharToTextLine(&m->l[m->cl], *(msg++));
473}
474
475//
476// HUlib_drawMBg()
477//
478// Draws a background box which the message display review widget can
479// display over
480//
481// Passed position, width, height, and the background patches
482// Returns nothing
483//
484void HUlib_drawMBg
485( int x,
486 int y,
487 int w,
488 int h,
489 const patchnum_t* bgp
490)
491{
492 int xs = bgp[0].width;
493 int ys = bgp[0].height;
494 int i,j;
495
496 // CPhipps - patch drawing updated
497 // top rows
498 V_DrawNumPatch(x, y, FG, bgp[0].lumpnum, CR_DEFAULT, VPT_STRETCH); // ul
499 for (j=x+xs;j<x+w-xs;j+=xs) // uc
500 V_DrawNumPatch(j, y, FG, bgp[1].lumpnum, CR_DEFAULT, VPT_STRETCH);
501 V_DrawNumPatch(j, y, FG, bgp[2].lumpnum, CR_DEFAULT, VPT_STRETCH); // ur
502
503 // middle rows
504 for (i=y+ys;i<y+h-ys;i+=ys)
505 {
506 V_DrawNumPatch(x, i, FG, bgp[3].lumpnum, CR_DEFAULT, VPT_STRETCH); // cl
507 for (j=x+xs;j<x+w-xs;j+=xs) // cc
508 V_DrawNumPatch(j, i, FG, bgp[4].lumpnum, CR_DEFAULT, VPT_STRETCH);
509 V_DrawNumPatch(j, i, FG, bgp[5].lumpnum, CR_DEFAULT, VPT_STRETCH); // cr
510 }
511
512 // bottom row
513 V_DrawNumPatch(x, i, FG, bgp[6].lumpnum, CR_DEFAULT, VPT_STRETCH); // ll
514 for (j=x+xs;j<x+w-xs;j+=xs) // lc
515 V_DrawNumPatch(j, i, FG, bgp[7].lumpnum, CR_DEFAULT, VPT_STRETCH);
516 V_DrawNumPatch(j, i, FG, bgp[8].lumpnum, CR_DEFAULT, VPT_STRETCH); // lr
517}
518
519//
520// HUlib_drawMText()
521//
522// Displays a hu_mtext_t widget
523//
524// Passed a hu_mtext_t
525// Returns nothing
526//
527void HUlib_drawMText(hu_mtext_t* m)
528{
529 int i, idx, y;
530 hu_textline_t *l;
531
532 if (!*m->on)
533 return; // if not on, don't draw
534
535 // draw everything
536 if (hud_list_bgon)
537 HUlib_drawMBg(m->x,m->y,m->w,m->h,m->bg);
538 y = m->y + HU_REFRESHSPACING;
539 for (i=0 ; i<m->nl ; i++)
540 {
541 idx = m->cl - i;
542 if (idx < 0)
543 idx += m->nl; // handle queue of lines
544
545 l = &m->l[idx];
546 if (hud_list_bgon)
547 {
548 l->x = m->x + 4;
549 l->y = m->y + (i+1)*HU_REFRESHSPACING;
550 }
551 else
552 {
553 l->x = m->x;
554 l->y = m->y + i*HU_REFRESHSPACING;
555 }
556
557 // need a decision made here on whether to skip the draw
558 HUlib_drawTextLine(l, false); // no cursor, please
559 }
560}
561
562//
563// HUlib_eraseMBg()
564//
565// Erases background behind hu_mtext_t widget, when the screen is not fullsize
566//
567// Passed a hu_mtext_t
568// Returns nothing
569//
570static void HUlib_eraseMBg(hu_mtext_t* m)
571{
572 int lh;
573 int y;
574
575 // Only erases when NOT in automap and the screen is reduced,
576 // and the text must either need updating or refreshing
577 // (because of a recent change back from the automap)
578
579 if (!(automapmode & am_active) && viewwindowx)
580 {
581 lh = m->l[0].f[0].height + 1;
582 for (y=m->y; y<m->y+lh*(hud_msg_lines+2) ; y++)
583 {
584 if (y < viewwindowy || y >= viewwindowy + viewheight)
585 R_VideoErase(0, y, SCREENWIDTH); // erase entire line
586 else
587 {
588 // erase left border
589 R_VideoErase(0, y, viewwindowx);
590 // erase right border
591 R_VideoErase(viewwindowx + viewwidth, y, viewwindowx);
592
593 }
594 }
595 }
596}
597
598//
599// HUlib_eraseMText()
600//
601// Erases a hu_mtext_t widget, when the screen is not fullsize
602//
603// Passed a hu_mtext_t
604// Returns nothing
605//
606void HUlib_eraseMText(hu_mtext_t* m)
607{
608 int i;
609
610 if (hud_list_bgon)
611 HUlib_eraseMBg(m);
612
613 for (i=0 ; i< m->nl ; i++)
614 {
615 m->l[i].needsupdate = 4;
616 HUlib_eraseTextLine(&m->l[i]);
617 }
618}
619
620////////////////////////////////////////////////////////
621//
622// Interactive text entry widget
623//
624////////////////////////////////////////////////////////
625
626//
627// HUlib_initIText()
628//
629// Initialize a hu_itext_t widget. Set the position, font,
630// start char of the font, color range, and whether enabled.
631//
632// Passed a hu_itext_t, and the values used to initialize
633// Returns nothing
634//
635void HUlib_initIText
636( hu_itext_t* it,
637 int x,
638 int y,
639 const patchnum_t* font,
640 int startchar,
641 int cm, //jff 2/16/98 add color range parameter
642 boolean* on )
643{
644 it->lm = 0; // default left margin is start of text
645 it->on = on;
646 it->laston = true;
647 HUlib_initTextLine(&it->l, x, y, font, startchar, cm);
648}
649
650// The following deletion routines adhere to the left margin restriction
651
652//
653// HUlib_delCharFromIText()
654//
655// Deletes a character at the end of the text line in a hu_itext_t widget
656//
657// Passed the hu_itext_t
658// Returns nothing
659//
660static void HUlib_delCharFromIText(hu_itext_t* it)
661{
662 if (it->l.len != it->lm)
663 HUlib_delCharFromTextLine(&it->l);
664}
665
666//
667// HUlib_eraseLineFromIText()
668//
669// Deletes all characters from a hu_itext_t widget
670//
671// Passed the hu_itext_t
672// Returns nothing
673//
674static void HUlib_eraseLineFromIText(hu_itext_t* it)
675{
676 while (it->lm != it->l.len)
677 HUlib_delCharFromTextLine(&it->l);
678}
679
680//
681// HUlib_resetIText()
682//
683// Deletes all characters from a hu_itext_t widget
684// Resets left margin as well
685//
686// Passed the hu_itext_t
687// Returns nothing
688//
689void HUlib_resetIText(hu_itext_t* it)
690{
691 it->lm = 0;
692 HUlib_clearTextLine(&it->l);
693}
694
695//
696// HUlib_addPrefixToIText()
697//
698// Adds a prefix string passed to a hu_itext_t widget
699// Sets left margin to length of string added
700//
701// Passed the hu_itext_t and the prefix string
702// Returns nothing
703//
704void HUlib_addPrefixToIText
705( hu_itext_t* it,
706 char* str )
707{
708 while (*str)
709 HUlib_addCharToTextLine(&it->l, *(str++));
710 it->lm = it->l.len;
711}
712
713//
714// HUlib_keyInIText()
715//
716// Wrapper function for handling general keyed input.
717//
718// Passed the hu_itext_t and the char input
719// Returns true if it ate the key
720//
721boolean HUlib_keyInIText
722( hu_itext_t* it,
723 unsigned char ch )
724{
725
726 if (ch >= ' ' && ch <= '_')
727 HUlib_addCharToTextLine(&it->l, (char) ch);
728 else if (ch == key_backspace) // phares
729 HUlib_delCharFromIText(it);
730 else if (ch != key_enter) // phares
731 return false; // did not eat key
732
733 return true; // ate the key
734}
735
736//
737// HUlib_drawIText()
738//
739// Displays a hu_itext_t widget
740//
741// Passed the hu_itext_t
742// Returns nothing
743//
744void HUlib_drawIText(hu_itext_t* it)
745{
746 hu_textline_t *l = &it->l;
747
748 if (!*it->on)
749 return;
750 HUlib_drawTextLine(l, true); // draw the line w/ cursor
751}
752
753//
754// HUlib_eraseIText()
755//
756// Erases a hu_itext_t widget when the screen is not fullsize
757//
758// Passed the hu_itext_t
759// Returns nothing
760//
761void HUlib_eraseIText(hu_itext_t* it)
762{
763 if (it->laston && !*it->on)
764 it->l.needsupdate = 4;
765 HUlib_eraseTextLine(&it->l);
766 it->laston = *it->on;
767}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: none
30 *
31 *-----------------------------------------------------------------------------*/
32
33#ifndef __HULIB__
34#define __HULIB__
35
36// We are referring to patches.
37#include "r_defs.h"
38#include "v_video.h" //jff 2/16/52 include color range defs
39
40
41/* background and foreground screen numbers
42 * different from other modules. */
43#define BG 1
44#define FG 0
45
46/* font stuff
47 * #define HU_CHARERASE KEYD_BACKSPACE / not used / phares
48 */
49
50#define HU_MAXLINES 4
51#define HU_MAXLINELENGTH 80
52#define HU_REFRESHSPACING 8 /*jff 2/26/98 space lines in text refresh widget*/
53/*jff 2/26/98 maximum number of messages allowed in refresh list */
54#define HU_MAXMESSAGES 16
55
56/*
57 * Typedefs of widgets
58 */
59
60/* Text Line widget
61 * (parent of Scrolling Text and Input Text widgets) */
62typedef struct
63{
64 // left-justified position of scrolling text window
65 int x;
66 int y;
67
68 const patchnum_t* f; // font
69 int sc; // start character
70 //const char *cr; //jff 2/16/52 output color range
71 // Proff - Made this an int again. Needed for OpenGL
72 int cm; //jff 2/16/52 output color range
73
74 // killough 1/23/98: Support multiple lines:
75 #define MAXLINES 25
76
77 int linelen;
78 char l[HU_MAXLINELENGTH*MAXLINES+1]; // line of text
79 int len; // current line length
80
81 // whether this line needs to be udpated
82 int needsupdate;
83
84} hu_textline_t;
85
86
87
88// Scrolling Text window widget
89// (child of Text Line widget)
90typedef struct
91{
92 hu_textline_t l[HU_MAXLINES]; // text lines to draw
93 int h; // height in lines
94 int cl; // current line number
95
96 // pointer to boolean stating whether to update window
97 boolean* on;
98 boolean laston; // last value of *->on.
99
100} hu_stext_t;
101
102//jff 2/26/98 new widget to display last hud_msg_lines of messages
103// Message refresh window widget
104typedef struct
105{
106 hu_textline_t l[HU_MAXMESSAGES]; // text lines to draw
107 int nl; // height in lines
108 int nr; // total height in rows
109 int cl; // current line number
110
111 int x,y,w,h; // window position and size
112 const patchnum_t *bg; // patches for background
113
114 // pointer to boolean stating whether to update window
115 boolean* on;
116 boolean laston; // last value of *->on.
117
118} hu_mtext_t;
119
120
121
122// Input Text Line widget
123// (child of Text Line widget)
124typedef struct
125{
126 hu_textline_t l; // text line to input on
127
128 // left margin past which I am not to delete characters
129 int lm;
130
131 // pointer to boolean stating whether to update window
132 boolean* on;
133 boolean laston; // last value of *->on;
134
135} hu_itext_t;
136
137
138//
139// Widget creation, access, and update routines
140//
141
142//
143// textline code
144//
145
146// clear a line of text
147void HUlib_clearTextLine(hu_textline_t *t);
148
149void HUlib_initTextLine
150(
151 hu_textline_t *t,
152 int x,
153 int y,
154 const patchnum_t *f,
155 int sc,
156 int cm //jff 2/16/98 add color range parameter
157);
158
159// returns success
160boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch);
161
162// draws tline
163void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor);
164
165// erases text line
166void HUlib_eraseTextLine(hu_textline_t *l);
167
168
169//
170// Scrolling Text window widget routines
171//
172
173// initialize an stext widget
174void HUlib_initSText
175( hu_stext_t* s,
176 int x,
177 int y,
178 int h,
179 const patchnum_t* font,
180 int startchar,
181 int cm, //jff 2/16/98 add color range parameter
182 boolean* on );
183
184// add a text message to an stext widget
185void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg);
186
187// draws stext
188void HUlib_drawSText(hu_stext_t* s);
189
190// erases all stext lines
191void HUlib_eraseSText(hu_stext_t* s);
192
193//jff 2/26/98 message refresh widget
194// initialize refresh text widget
195void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h, const patchnum_t* font,
196 int startchar, int cm, const patchnum_t* bgfont, boolean *on);
197
198//jff 2/26/98 message refresh widget
199// add a text message to refresh text widget
200void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg);
201
202//jff 2/26/98 new routine to display a background on which
203// the list of last hud_msg_lines are displayed
204void HUlib_drawMBg
205( int x,
206 int y,
207 int w,
208 int h,
209 const patchnum_t* bgp
210);
211
212//jff 2/26/98 message refresh widget
213// draws mtext
214void HUlib_drawMText(hu_mtext_t* m);
215
216//jff 4/28/98 erases behind message list
217void HUlib_eraseMText(hu_mtext_t* m);
218
219// Input Text Line widget routines
220void HUlib_initIText
221( hu_itext_t* it,
222 int x,
223 int y,
224 const patchnum_t* font,
225 int startchar,
226 int cm, //jff 2/16/98 add color range parameter
227 boolean* on );
228
229// resets line and left margin
230void HUlib_resetIText(hu_itext_t* it);
231
232// left of left-margin
233void HUlib_addPrefixToIText
234( hu_itext_t* it,
235 char* str );
236
237// whether eaten
238boolean HUlib_keyInIText
239( hu_itext_t* it,
240 unsigned char ch );
241
242void HUlib_drawIText(hu_itext_t* it);
243
244// erases all itext lines
245void HUlib_eraseIText(hu_itext_t* it);
246
247#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: Heads-up displays
30 *
31 *-----------------------------------------------------------------------------
32 */
33
34// killough 5/3/98: remove unnecessary headers
35
36#include "doomstat.h"
37#include "hu_stuff.h"
38#include "hu_lib.h"
39#include "st_stuff.h" /* jff 2/16/98 need loc of status bar */
40#include "w_wad.h"
41#include "s_sound.h"
42#include "dstrings.h"
43#include "sounds.h"
44#include "d_deh.h" /* Ty 03/27/98 - externalization of mapnamesx arrays */
45#include "g_game.h"
46#include "r_main.h"
47
48// global heads up display controls
49
50int hud_active; //jff 2/17/98 controls heads-up display mode
51int hud_displayed; //jff 2/23/98 turns heads-up display on/off
52int hud_nosecrets; //jff 2/18/98 allows secrets line to be disabled in HUD
53int hud_distributed; //jff 3/4/98 display HUD in different places on screen
54int hud_graph_keys=1; //jff 3/7/98 display HUD keys as graphics
55
56//
57// Locally used constants, shortcuts.
58//
59// Ty 03/28/98 -
60// These four shortcuts modifed to reflect char ** of mapnamesx[]
61#define HU_TITLE (*mapnames[(gameepisode-1)*9+gamemap-1])
62#define HU_TITLE2 (*mapnames2[gamemap-1])
63#define HU_TITLEP (*mapnamesp[gamemap-1])
64#define HU_TITLET (*mapnamest[gamemap-1])
65#define HU_TITLEHEIGHT 1
66#define HU_TITLEX 0
67//jff 2/16/98 change 167 to ST_Y-1
68// CPhipps - changed to ST_TY
69// proff - changed to 200-ST_HEIGHT for stretching
70#define HU_TITLEY ((200-ST_HEIGHT) - 1 - hu_font[0].height)
71
72//jff 2/16/98 add coord text widget coordinates
73// proff - changed to SCREENWIDTH to 320 for stretching
74#define HU_COORDX (320 - 13*hu_font2['A'-HU_FONTSTART].width)
75//jff 3/3/98 split coord widget into three lines in upper right of screen
76#define HU_COORDX_Y (1 + 0*hu_font['A'-HU_FONTSTART].height)
77#define HU_COORDY_Y (2 + 1*hu_font['A'-HU_FONTSTART].height)
78#define HU_COORDZ_Y (3 + 2*hu_font['A'-HU_FONTSTART].height)
79
80//jff 2/16/98 add ammo, health, armor widgets, 2/22/98 less gap
81#define HU_GAPY 8
82#define HU_HUDHEIGHT (6*HU_GAPY)
83#define HU_HUDX 2
84#define HU_HUDY (200-HU_HUDHEIGHT-1)
85#define HU_MONSECX (HU_HUDX)
86#define HU_MONSECY (HU_HUDY+0*HU_GAPY)
87#define HU_KEYSX (HU_HUDX)
88//jff 3/7/98 add offset for graphic key widget
89#define HU_KEYSGX (HU_HUDX+4*hu_font2['A'-HU_FONTSTART].width)
90#define HU_KEYSY (HU_HUDY+1*HU_GAPY)
91#define HU_WEAPX (HU_HUDX)
92#define HU_WEAPY (HU_HUDY+2*HU_GAPY)
93#define HU_AMMOX (HU_HUDX)
94#define HU_AMMOY (HU_HUDY+3*HU_GAPY)
95#define HU_HEALTHX (HU_HUDX)
96#define HU_HEALTHY (HU_HUDY+4*HU_GAPY)
97#define HU_ARMORX (HU_HUDX)
98#define HU_ARMORY (HU_HUDY+5*HU_GAPY)
99
100//jff 3/4/98 distributed HUD positions
101#define HU_HUDX_LL 2
102#define HU_HUDY_LL (200-2*HU_GAPY-1)
103// proff/nicolas 09/20/98: Changed for high-res
104#define HU_HUDX_LR (320-120)
105#define HU_HUDY_LR (200-2*HU_GAPY-1)
106// proff/nicolas 09/20/98: Changed for high-res
107#define HU_HUDX_UR (320-96)
108#define HU_HUDY_UR 2
109#define HU_MONSECX_D (HU_HUDX_LL)
110#define HU_MONSECY_D (HU_HUDY_LL+0*HU_GAPY)
111#define HU_KEYSX_D (HU_HUDX_LL)
112#define HU_KEYSGX_D (HU_HUDX_LL+4*hu_font2['A'-HU_FONTSTART].width)
113#define HU_KEYSY_D (HU_HUDY_LL+1*HU_GAPY)
114#define HU_WEAPX_D (HU_HUDX_LR)
115#define HU_WEAPY_D (HU_HUDY_LR+0*HU_GAPY)
116#define HU_AMMOX_D (HU_HUDX_LR)
117#define HU_AMMOY_D (HU_HUDY_LR+1*HU_GAPY)
118#define HU_HEALTHX_D (HU_HUDX_UR)
119#define HU_HEALTHY_D (HU_HUDY_UR+0*HU_GAPY)
120#define HU_ARMORX_D (HU_HUDX_UR)
121#define HU_ARMORY_D (HU_HUDY_UR+1*HU_GAPY)
122
123//#define HU_INPUTTOGGLE 't' // not used // phares
124#define HU_INPUTX HU_MSGX
125#define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(hu_font[0].height) +1)
126#define HU_INPUTWIDTH 64
127#define HU_INPUTHEIGHT 1
128
129#define key_alt KEYD_RALT
130#define key_shift KEYD_RSHIFT
131
132const char* chat_macros[] =
133// Ty 03/27/98 - *not* externalized
134// CPhipps - const char*
135{
136 HUSTR_CHATMACRO0,
137 HUSTR_CHATMACRO1,
138 HUSTR_CHATMACRO2,
139 HUSTR_CHATMACRO3,
140 HUSTR_CHATMACRO4,
141 HUSTR_CHATMACRO5,
142 HUSTR_CHATMACRO6,
143 HUSTR_CHATMACRO7,
144 HUSTR_CHATMACRO8,
145 HUSTR_CHATMACRO9
146};
147
148const char* player_names[] =
149// Ty 03/27/98 - *not* externalized
150// CPhipps - const char*
151{
152 HUSTR_PLRGREEN,
153 HUSTR_PLRINDIGO,
154 HUSTR_PLRBROWN,
155 HUSTR_PLRRED
156};
157
158//jff 3/17/98 translate player colmap to text color ranges
159int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED};
160
161char chat_char; // remove later.
162static player_t* plr;
163
164// font sets
165patchnum_t hu_font[HU_FONTSIZE];
166patchnum_t hu_font2[HU_FONTSIZE];
167patchnum_t hu_fontk[HU_FONTSIZE];//jff 3/7/98 added for graphic key indicators
168patchnum_t hu_msgbg[9]; //jff 2/26/98 add patches for message background
169
170// widgets
171static hu_textline_t w_title;
172static hu_stext_t w_message;
173static hu_itext_t w_chat;
174static hu_itext_t w_inputbuffer[MAXPLAYERS];
175static hu_textline_t w_coordx; //jff 2/16/98 new coord widget for automap
176static hu_textline_t w_coordy; //jff 3/3/98 split coord widgets automap
177static hu_textline_t w_coordz; //jff 3/3/98 split coord widgets automap
178static hu_textline_t w_ammo; //jff 2/16/98 new ammo widget for hud
179static hu_textline_t w_health; //jff 2/16/98 new health widget for hud
180static hu_textline_t w_armor; //jff 2/16/98 new armor widget for hud
181static hu_textline_t w_weapon; //jff 2/16/98 new weapon widget for hud
182static hu_textline_t w_keys; //jff 2/16/98 new keys widget for hud
183static hu_textline_t w_gkeys; //jff 3/7/98 graphic keys widget for hud
184static hu_textline_t w_monsec; //jff 2/16/98 new kill/secret widget for hud
185static hu_mtext_t w_rtext; //jff 2/26/98 text message refresh widget
186
187static boolean always_off = false;
188static char chat_dest[MAXPLAYERS];
189boolean chat_on;
190static boolean message_on;
191static boolean message_list; //2/26/98 enable showing list of messages
192boolean message_dontfuckwithme;
193static boolean message_nottobefuckedwith;
194static int message_counter;
195extern int showMessages;
196extern boolean automapactive;
197static boolean headsupactive = false;
198
199//jff 2/16/98 hud supported automap colors added
200int hudcolor_titl; // color range of automap level title
201int hudcolor_xyco; // color range of new coords on automap
202//jff 2/16/98 hud text colors, controls added
203int hudcolor_mesg; // color range of scrolling messages
204int hudcolor_chat; // color range of chat lines
205int hud_msg_lines; // number of message lines in window
206//jff 2/26/98 hud text colors, controls added
207int hudcolor_list; // list of messages color
208int hud_list_bgon; // enable for solid window background for message list
209
210//jff 2/16/98 initialization strings for ammo, health, armor widgets
211static char hud_coordstrx[32];
212static char hud_coordstry[32];
213static char hud_coordstrz[32];
214static char hud_ammostr[80];
215static char hud_healthstr[80];
216static char hud_armorstr[80];
217static char hud_weapstr[80];
218static char hud_keysstr[80];
219static char hud_gkeysstr[80]; //jff 3/7/98 add support for graphic key display
220static char hud_monsecstr[80];
221
222//
223// Builtin map names.
224// The actual names can be found in DStrings.h.
225//
226// Ty 03/27/98 - externalized map name arrays - now in d_deh.c
227// and converted to arrays of pointers to char *
228// See modified HUTITLEx macros
229extern char **mapnames[];
230extern char **mapnames2[];
231extern char **mapnamesp[];
232extern char **mapnamest[];
233
234extern int map_point_coordinates;
235
236// key tables
237// jff 5/10/98 french support removed,
238// as it was not being used and couldn't be easily tested
239//
240const char* shiftxform;
241
242const char english_shiftxform[] =
243{
244 0,
245 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
246 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
247 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
248 31,
249 ' ', '!', '"', '#', '$', '%', '&',
250 '"', // shift-'
251 '(', ')', '*', '+',
252 '<', // shift-,
253 '_', // shift--
254 '>', // shift-.
255 '?', // shift-/
256 ')', // shift-0
257 '!', // shift-1
258 '@', // shift-2
259 '#', // shift-3
260 '$', // shift-4
261 '%', // shift-5
262 '^', // shift-6
263 '&', // shift-7
264 '*', // shift-8
265 '(', // shift-9
266 ':',
267 ':', // shift-;
268 '<',
269 '+', // shift-=
270 '>', '?', '@',
271 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
272 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
273 '[', // shift-[
274 '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
275 ']', // shift-]
276 '"', '_',
277 '\'', // shift-`
278 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
279 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
280 '{', '|', '}', '~', 127
281};
282
283//
284// HU_Init()
285//
286// Initialize the heads-up display, text that overwrites the primary display
287//
288// Passed nothing, returns nothing
289//
290void HU_Init(void)
291{
292
293 int i;
294 int j;
295 char buffer[9];
296
297 shiftxform = english_shiftxform;
298
299 // load the heads-up font
300 j = HU_FONTSTART;
301 for (i=0;i<HU_FONTSIZE;i++,j++)
302 {
303 if ('0'<=j && j<='9')
304 {
305 sprintf(buffer, "DIG%.1d",j-48);
306 R_SetPatchNum(&hu_font2[i], buffer);
307 sprintf(buffer, "STCFN%.3d",j);
308 R_SetPatchNum(&hu_font[i], buffer);
309 }
310 else if ('A'<=j && j<='Z')
311 {
312 sprintf(buffer, "DIG%c",j);
313 R_SetPatchNum(&hu_font2[i], buffer);
314 sprintf(buffer, "STCFN%.3d",j);
315 R_SetPatchNum(&hu_font[i], buffer);
316 }
317 else if (j=='-')
318 {
319 R_SetPatchNum(&hu_font2[i], "DIG45");
320 R_SetPatchNum(&hu_font[i], "STCFN045");
321 }
322 else if (j=='/')
323 {
324 R_SetPatchNum(&hu_font2[i], "DIG47");
325 R_SetPatchNum(&hu_font[i], "STCFN047");
326 }
327 else if (j==':')
328 {
329 R_SetPatchNum(&hu_font2[i], "DIG58");
330 R_SetPatchNum(&hu_font[i], "STCFN058");
331 }
332 else if (j=='[')
333 {
334 R_SetPatchNum(&hu_font2[i], "DIG91");
335 R_SetPatchNum(&hu_font[i], "STCFN091");
336 }
337 else if (j==']')
338 {
339 R_SetPatchNum(&hu_font2[i], "DIG93");
340 R_SetPatchNum(&hu_font[i], "STCFN093");
341 }
342 else if (j<97)
343 {
344 sprintf(buffer, "STCFN%.3d",j);
345 R_SetPatchNum(&hu_font2[i], buffer);
346 R_SetPatchNum(&hu_font[i], buffer);
347 //jff 2/23/98 make all font chars defined, useful or not
348 }
349 else if (j>122)
350 {
351 sprintf(buffer, "STBR%.3d",j);
352 R_SetPatchNum(&hu_font2[i], buffer);
353 R_SetPatchNum(&hu_font[i], buffer);
354 }
355 else
356 hu_font[i] = hu_font[0]; //jff 2/16/98 account for gap
357 }
358
359 // CPhipps - load patches for message background
360 for (i=0; i<9; i++) {
361 sprintf(buffer, "BOX%c%c", "UCL"[i/3], "LCR"[i%3]);
362 R_SetPatchNum(&hu_msgbg[i], buffer);
363 }
364
365 // CPhipps - load patches for keys and double keys
366 for (i=0; i<6; i++) {
367 sprintf(buffer, "STKEYS%d", i);
368 R_SetPatchNum(&hu_fontk[i], buffer);
369 }
370}
371
372//
373// HU_Stop()
374//
375// Make the heads-up displays inactive
376//
377// Passed nothing, returns nothing
378//
379static void HU_Stop(void)
380{
381 headsupactive = false;
382}
383
384//
385// HU_Start(void)
386//
387// Create and initialize the heads-up widgets, software machines to
388// maintain, update, and display information over the primary display
389//
390// This routine must be called after any change to the heads up configuration
391// in order for the changes to take effect in the actual displays
392//
393// Passed nothing, returns nothing
394//
395void HU_Start(void)
396{
397
398 int i;
399 const char* s; /* cph - const */
400
401 if (headsupactive) // stop before starting
402 HU_Stop();
403
404 plr = &players[displayplayer]; // killough 3/7/98
405 message_on = false;
406 message_dontfuckwithme = false;
407 message_nottobefuckedwith = false;
408 chat_on = false;
409
410 // create the message widget
411 // messages to player in upper-left of screen
412 HUlib_initSText
413 (
414 &w_message,
415 HU_MSGX,
416 HU_MSGY,
417 HU_MSGHEIGHT,
418 hu_font,
419 HU_FONTSTART,
420 hudcolor_mesg,
421 &message_on
422 );
423
424 //jff 2/16/98 added some HUD widgets
425 // create the map title widget - map title display in lower left of automap
426 HUlib_initTextLine
427 (
428 &w_title,
429 HU_TITLEX,
430 HU_TITLEY,
431 hu_font,
432 HU_FONTSTART,
433 hudcolor_titl
434 );
435
436 // create the hud health widget
437 // bargraph and number for amount of health,
438 // lower left or upper right of screen
439 HUlib_initTextLine
440 (
441 &w_health,
442 hud_distributed? HU_HEALTHX_D : HU_HEALTHX, //3/4/98 distribute
443 hud_distributed? HU_HEALTHY_D : HU_HEALTHY,
444 hu_font2,
445 HU_FONTSTART,
446 CR_GREEN
447 );
448
449 // create the hud armor widget
450 // bargraph and number for amount of armor,
451 // lower left or upper right of screen
452 HUlib_initTextLine
453 (
454 &w_armor,
455 hud_distributed? HU_ARMORX_D : HU_ARMORX, //3/4/98 distribute
456 hud_distributed? HU_ARMORY_D : HU_ARMORY,
457 hu_font2,
458 HU_FONTSTART,
459 CR_GREEN
460 );
461
462 // create the hud ammo widget
463 // bargraph and number for amount of ammo for current weapon,
464 // lower left or lower right of screen
465 HUlib_initTextLine
466 (
467 &w_ammo,
468 hud_distributed? HU_AMMOX_D : HU_AMMOX, //3/4/98 distribute
469 hud_distributed? HU_AMMOY_D : HU_AMMOY,
470 hu_font2,
471 HU_FONTSTART,
472 CR_GOLD
473 );
474
475 // create the hud weapons widget
476 // list of numbers of weapons possessed
477 // lower left or lower right of screen
478 HUlib_initTextLine
479 (
480 &w_weapon,
481 hud_distributed? HU_WEAPX_D : HU_WEAPX, //3/4/98 distribute
482 hud_distributed? HU_WEAPY_D : HU_WEAPY,
483 hu_font2,
484 HU_FONTSTART,
485 CR_GRAY
486 );
487
488 // create the hud keys widget
489 // display of key letters possessed
490 // lower left of screen
491 HUlib_initTextLine
492 (
493 &w_keys,
494 hud_distributed? HU_KEYSX_D : HU_KEYSX, //3/4/98 distribute
495 hud_distributed? HU_KEYSY_D : HU_KEYSY,
496 hu_font2,
497 HU_FONTSTART,
498 CR_GRAY
499 );
500
501 // create the hud graphic keys widget
502 // display of key graphics possessed
503 // lower left of screen
504 HUlib_initTextLine
505 (
506 &w_gkeys,
507 hud_distributed? HU_KEYSGX_D : HU_KEYSGX, //3/4/98 distribute
508 hud_distributed? HU_KEYSY_D : HU_KEYSY,
509 hu_fontk,
510 HU_FONTSTART,
511 CR_RED
512 );
513
514 // create the hud monster/secret widget
515 // totals and current values for kills, items, secrets
516 // lower left of screen
517 HUlib_initTextLine
518 (
519 &w_monsec,
520 hud_distributed? HU_MONSECX_D : HU_MONSECX, //3/4/98 distribute
521 hud_distributed? HU_MONSECY_D : HU_MONSECY,
522 hu_font2,
523 HU_FONTSTART,
524 CR_GRAY
525 );
526
527 // create the hud text refresh widget
528 // scrolling display of last hud_msg_lines messages received
529 if (hud_msg_lines>HU_MAXMESSAGES)
530 hud_msg_lines=HU_MAXMESSAGES;
531 //jff 4/21/98 if setup has disabled message list while active, turn it off
532 message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways
533 //jff 2/26/98 add the text refresh widget initialization
534 HUlib_initMText
535 (
536 &w_rtext,
537 0,
538 0,
539 320,
540// SCREENWIDTH,
541 (hud_msg_lines+2)*HU_REFRESHSPACING,
542 hu_font,
543 HU_FONTSTART,
544 hudcolor_list,
545 hu_msgbg,
546 &message_list
547 );
548
549 // initialize the automap's level title widget
550 if (gamestate == GS_LEVEL) /* cph - stop SEGV here when not in level */
551 switch (gamemode)
552 {
553 case shareware:
554 case registered:
555 case retail:
556 s = HU_TITLE;
557 break;
558
559 case commercial:
560 default: // Ty 08/27/98 - modified to check mission for TNT/Plutonia
561 s = (gamemission==pack_tnt) ? HU_TITLET :
562 (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2;
563 break;
564 } else s = "";
565 while (*s)
566 HUlib_addCharToTextLine(&w_title, *(s++));
567
568 // create the automaps coordinate widget
569 // jff 3/3/98 split coord widget into three lines: x,y,z
570 // jff 2/16/98 added
571 HUlib_initTextLine
572 (
573 &w_coordx,
574 HU_COORDX,
575 HU_COORDX_Y,
576 hu_font,
577 HU_FONTSTART,
578 hudcolor_xyco
579 );
580 HUlib_initTextLine
581 (
582 &w_coordy,
583 HU_COORDX,
584 HU_COORDY_Y,
585 hu_font,
586 HU_FONTSTART,
587 hudcolor_xyco
588 );
589 HUlib_initTextLine
590 (
591 &w_coordz,
592 HU_COORDX,
593 HU_COORDZ_Y,
594 hu_font,
595 HU_FONTSTART,
596 hudcolor_xyco
597 );
598
599 // initialize the automaps coordinate widget
600 //jff 3/3/98 split coordstr widget into 3 parts
601 if (map_point_coordinates)
602 {
603 sprintf(hud_coordstrx,"X: %-5d",0); //jff 2/22/98 added z
604 s = hud_coordstrx;
605 while (*s)
606 HUlib_addCharToTextLine(&w_coordx, *(s++));
607 sprintf(hud_coordstry,"Y: %-5d",0); //jff 3/3/98 split x,y,z
608 s = hud_coordstry;
609 while (*s)
610 HUlib_addCharToTextLine(&w_coordy, *(s++));
611 sprintf(hud_coordstrz,"Z: %-5d",0); //jff 3/3/98 split x,y,z
612 s = hud_coordstrz;
613 while (*s)
614 HUlib_addCharToTextLine(&w_coordz, *(s++));
615 }
616
617 //jff 2/16/98 initialize ammo widget
618 strcpy(hud_ammostr,"AMM ");
619 s = hud_ammostr;
620 while (*s)
621 HUlib_addCharToTextLine(&w_ammo, *(s++));
622
623 //jff 2/16/98 initialize health widget
624 strcpy(hud_healthstr,"HEL ");
625 s = hud_healthstr;
626 while (*s)
627 HUlib_addCharToTextLine(&w_health, *(s++));
628
629 //jff 2/16/98 initialize armor widget
630 strcpy(hud_armorstr,"ARM ");
631 s = hud_armorstr;
632 while (*s)
633 HUlib_addCharToTextLine(&w_armor, *(s++));
634
635 //jff 2/17/98 initialize weapons widget
636 strcpy(hud_weapstr,"WEA ");
637 s = hud_weapstr;
638 while (*s)
639 HUlib_addCharToTextLine(&w_weapon, *(s++));
640
641 //jff 2/17/98 initialize keys widget
642 if (!deathmatch) //jff 3/17/98 show frags in deathmatch mode
643 strcpy(hud_keysstr,"KEY ");
644 else
645 strcpy(hud_keysstr,"FRG ");
646 s = hud_keysstr;
647 while (*s)
648 HUlib_addCharToTextLine(&w_keys, *(s++));
649
650 //jff 2/17/98 initialize graphic keys widget
651 strcpy(hud_gkeysstr," ");
652 s = hud_gkeysstr;
653 while (*s)
654 HUlib_addCharToTextLine(&w_gkeys, *(s++));
655
656 //jff 2/17/98 initialize kills/items/secret widget
657 strcpy(hud_monsecstr,"STS ");
658 s = hud_monsecstr;
659 while (*s)
660 HUlib_addCharToTextLine(&w_monsec, *(s++));
661
662 // create the chat widget
663 HUlib_initIText
664 (
665 &w_chat,
666 HU_INPUTX,
667 HU_INPUTY,
668 hu_font,
669 HU_FONTSTART,
670 hudcolor_chat,
671 &chat_on
672 );
673
674 // create the inputbuffer widgets, one per player
675 for (i=0 ; i<MAXPLAYERS ; i++)
676 HUlib_initIText
677 (
678 &w_inputbuffer[i],
679 0,
680 0,
681 0,
682 0,
683 hudcolor_chat,
684 &always_off
685 );
686
687 // now allow the heads-up display to run
688 headsupactive = true;
689}
690
691//
692// HU_MoveHud()
693//
694// Move the HUD display from distributed to compact mode or vice-versa
695//
696// Passed nothing, returns nothing
697//
698//jff 3/9/98 create this externally callable to avoid glitch
699// when menu scatter's HUD due to delay in change of position
700//
701void HU_MoveHud(void)
702{
703 static int ohud_distributed=-1;
704
705 //jff 3/4/98 move displays around on F5 changing hud_distributed
706 if (hud_distributed!=ohud_distributed)
707 {
708 w_ammo.x = hud_distributed? HU_AMMOX_D : HU_AMMOX;
709 w_ammo.y = hud_distributed? HU_AMMOY_D : HU_AMMOY;
710 w_weapon.x = hud_distributed? HU_WEAPX_D : HU_WEAPX;
711 w_weapon.y = hud_distributed? HU_WEAPY_D : HU_WEAPY;
712 w_keys.x = hud_distributed? HU_KEYSX_D : HU_KEYSX;
713 w_keys.y = hud_distributed? HU_KEYSY_D : HU_KEYSY;
714 w_gkeys.x = hud_distributed? HU_KEYSGX_D : HU_KEYSGX;
715 w_gkeys.y = hud_distributed? HU_KEYSY_D : HU_KEYSY;
716 w_monsec.x = hud_distributed? HU_MONSECX_D : HU_MONSECX;
717 w_monsec.y = hud_distributed? HU_MONSECY_D : HU_MONSECY;
718 w_health.x = hud_distributed? HU_HEALTHX_D : HU_HEALTHX;
719 w_health.y = hud_distributed? HU_HEALTHY_D : HU_HEALTHY;
720 w_armor.x = hud_distributed? HU_ARMORX_D : HU_ARMORX;
721 w_armor.y = hud_distributed? HU_ARMORY_D : HU_ARMORY;
722 }
723 ohud_distributed = hud_distributed;
724}
725
726//
727// HU_Drawer()
728//
729// Draw all the pieces of the heads-up display
730//
731// Passed nothing, returns nothing
732//
733void HU_Drawer(void)
734{
735 char *s;
736 player_t *plr;
737 char ammostr[80]; //jff 3/8/98 allow plenty room for dehacked mods
738 char healthstr[80];//jff
739 char armorstr[80]; //jff
740 int i,doit;
741
742 plr = &players[displayplayer]; // killough 3/7/98
743 // draw the automap widgets if automap is displayed
744 if (automapmode & am_active)
745 {
746 // map title
747 HUlib_drawTextLine(&w_title, false);
748
749 //jff 2/16/98 output new coord display
750 // x-coord
751 if (map_point_coordinates)
752 {
753 sprintf(hud_coordstrx,"X: %-5d", (plr->mo->x)>>FRACBITS);
754 HUlib_clearTextLine(&w_coordx);
755 s = hud_coordstrx;
756 while (*s)
757 HUlib_addCharToTextLine(&w_coordx, *(s++));
758 HUlib_drawTextLine(&w_coordx, false);
759
760 //jff 3/3/98 split coord display into x,y,z lines
761 // y-coord
762 sprintf(hud_coordstry,"Y: %-5d", (plr->mo->y)>>FRACBITS);
763 HUlib_clearTextLine(&w_coordy);
764 s = hud_coordstry;
765 while (*s)
766 HUlib_addCharToTextLine(&w_coordy, *(s++));
767 HUlib_drawTextLine(&w_coordy, false);
768
769 //jff 3/3/98 split coord display into x,y,z lines
770 //jff 2/22/98 added z
771 // z-coord
772 sprintf(hud_coordstrz,"Z: %-5d", (plr->mo->z)>>FRACBITS);
773 HUlib_clearTextLine(&w_coordz);
774 s = hud_coordstrz;
775 while (*s)
776 HUlib_addCharToTextLine(&w_coordz, *(s++));
777 HUlib_drawTextLine(&w_coordz, false);
778 }
779 }
780
781 // draw the weapon/health/ammo/armor/kills/keys displays if optioned
782 //jff 2/17/98 allow new hud stuff to be turned off
783 // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY
784 if
785 (
786 hud_active>0 && // hud optioned on
787 hud_displayed && // hud on from fullscreen key
788 viewheight==SCREENHEIGHT && // fullscreen mode is active
789 !(automapmode & am_active) // automap is not active
790 )
791 {
792 doit = !(gametic&1); //jff 3/4/98 speed update up for slow systems
793 if (doit) //jff 8/7/98 update every time, avoid lag in update
794 {
795 HU_MoveHud(); // insure HUD display coords are correct
796
797 // do the hud ammo display
798 // clear the widgets internal line
799 HUlib_clearTextLine(&w_ammo);
800 strcpy(hud_ammostr,"AMM ");
801 if (weaponinfo[plr->readyweapon].ammo == am_noammo)
802 { // special case for weapon with no ammo selected - blank bargraph + N/A
803 strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A");
804 w_ammo.cm = CR_GRAY;
805 }
806 else
807 {
808 int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo];
809 int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo];
810 int ammopct = (100*ammo)/fullammo;
811 int ammobars = ammopct/4;
812
813 // build the numeric amount init string
814 sprintf(ammostr,"%d/%d",ammo,fullammo);
815 // build the bargraph string
816 // full bargraph chars
817 for (i=4;i<4+ammobars/4;)
818 hud_ammostr[i++] = 123;
819 // plus one last character with 0,1,2,3 bars
820 switch(ammobars%4)
821 {
822 case 0:
823 break;
824 case 1:
825 hud_ammostr[i++] = 126;
826 break;
827 case 2:
828 hud_ammostr[i++] = 125;
829 break;
830 case 3:
831 hud_ammostr[i++] = 124;
832 break;
833 }
834 // pad string with blank bar characters
835 while(i<4+7)
836 hud_ammostr[i++] = 127;
837 hud_ammostr[i] = '\0';
838 strcat(hud_ammostr,ammostr);
839
840 // set the display color from the percentage of total ammo held
841 if (ammopct<ammo_red)
842 w_ammo.cm = CR_RED;
843 else if (ammopct<ammo_yellow)
844 w_ammo.cm = CR_GOLD;
845 else
846 w_ammo.cm = CR_GREEN;
847 }
848 // transfer the init string to the widget
849 s = hud_ammostr;
850 while (*s)
851 HUlib_addCharToTextLine(&w_ammo, *(s++));
852 }
853 // display the ammo widget every frame
854 HUlib_drawTextLine(&w_ammo, false);
855
856 // do the hud health display
857 if (doit)
858 {
859 int health = plr->health;
860 int healthbars = health>100? 25 : health/4;
861
862 // clear the widgets internal line
863 HUlib_clearTextLine(&w_health);
864
865 // build the numeric amount init string
866 sprintf(healthstr,"%3d",health);
867 // build the bargraph string
868 // full bargraph chars
869 for (i=4;i<4+healthbars/4;)
870 hud_healthstr[i++] = 123;
871 // plus one last character with 0,1,2,3 bars
872 switch(healthbars%4)
873 {
874 case 0:
875 break;
876 case 1:
877 hud_healthstr[i++] = 126;
878 break;
879 case 2:
880 hud_healthstr[i++] = 125;
881 break;
882 case 3:
883 hud_healthstr[i++] = 124;
884 break;
885 }
886 // pad string with blank bar characters
887 while(i<4+7)
888 hud_healthstr[i++] = 127;
889 hud_healthstr[i] = '\0';
890 strcat(hud_healthstr,healthstr);
891
892 // set the display color from the amount of health posessed
893 if (health<health_red)
894 w_health.cm = CR_RED;
895 else if (health<health_yellow)
896 w_health.cm = CR_GOLD;
897 else if (health<=health_green)
898 w_health.cm = CR_GREEN;
899 else
900 w_health.cm = CR_BLUE;
901
902 // transfer the init string to the widget
903 s = hud_healthstr;
904 while (*s)
905 HUlib_addCharToTextLine(&w_health, *(s++));
906 }
907 // display the health widget every frame
908 HUlib_drawTextLine(&w_health, false);
909
910 // do the hud armor display
911 if (doit)
912 {
913 int armor = plr->armorpoints;
914 int armorbars = armor>100? 25 : armor/4;
915
916 // clear the widgets internal line
917 HUlib_clearTextLine(&w_armor);
918 // build the numeric amount init string
919 sprintf(armorstr,"%3d",armor);
920 // build the bargraph string
921 // full bargraph chars
922 for (i=4;i<4+armorbars/4;)
923 hud_armorstr[i++] = 123;
924 // plus one last character with 0,1,2,3 bars
925 switch(armorbars%4)
926 {
927 case 0:
928 break;
929 case 1:
930 hud_armorstr[i++] = 126;
931 break;
932 case 2:
933 hud_armorstr[i++] = 125;
934 break;
935 case 3:
936 hud_armorstr[i++] = 124;
937 break;
938 }
939 // pad string with blank bar characters
940 while(i<4+7)
941 hud_armorstr[i++] = 127;
942 hud_armorstr[i] = '\0';
943 strcat(hud_armorstr,armorstr);
944
945 // set the display color from the amount of armor posessed
946 if (armor<armor_red)
947 w_armor.cm = CR_RED;
948 else if (armor<armor_yellow)
949 w_armor.cm = CR_GOLD;
950 else if (armor<=armor_green)
951 w_armor.cm = CR_GREEN;
952 else
953 w_armor.cm = CR_BLUE;
954
955 // transfer the init string to the widget
956 s = hud_armorstr;
957 while (*s)
958 HUlib_addCharToTextLine(&w_armor, *(s++));
959 }
960 // display the armor widget every frame
961 HUlib_drawTextLine(&w_armor, false);
962
963 // do the hud weapon display
964 if (doit)
965 {
966 int w;
967 int ammo,fullammo,ammopct;
968
969 // clear the widgets internal line
970 HUlib_clearTextLine(&w_weapon);
971 i=4; hud_weapstr[i] = '\0'; //jff 3/7/98 make sure ammo goes away
972
973 // do each weapon that exists in current gamemode
974 for (w=0;w<=wp_supershotgun;w++) //jff 3/4/98 show fists too, why not?
975 {
976 int ok=1;
977 //jff avoid executing for weapons that do not exist
978 switch (gamemode)
979 {
980 case shareware:
981 if (w>=wp_plasma && w!=wp_chainsaw)
982 ok=0;
983 break;
984 case retail:
985 case registered:
986 if (w>=wp_supershotgun)
987 ok=0;
988 break;
989 default:
990 case commercial:
991 break;
992 }
993 if (!ok) continue;
994
995 ammo = plr->ammo[weaponinfo[w].ammo];
996 fullammo = plr->maxammo[weaponinfo[w].ammo];
997 ammopct=0;
998
999 // skip weapons not currently posessed
1000 if (!plr->weaponowned[w])
1001 continue;
1002
1003 ammopct = fullammo? (100*ammo)/fullammo : 100;
1004
1005 // display each weapon number in a color related to the ammo for it
1006 hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1007 if (weaponinfo[w].ammo==am_noammo) //jff 3/14/98 show berserk on HUD
1008 hud_weapstr[i++] = plr->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY;
1009 else if (ammopct<ammo_red)
1010 hud_weapstr[i++] = '0'+CR_RED;
1011 else if (ammopct<ammo_yellow)
1012 hud_weapstr[i++] = '0'+CR_GOLD;
1013 else
1014 hud_weapstr[i++] = '0'+CR_GREEN;
1015 hud_weapstr[i++] = '0'+w+1;
1016 hud_weapstr[i++] = ' ';
1017 hud_weapstr[i] = '\0';
1018 }
1019
1020 // transfer the init string to the widget
1021 s = hud_weapstr;
1022 while (*s)
1023 HUlib_addCharToTextLine(&w_weapon, *(s++));
1024 }
1025 // display the weapon widget every frame
1026 HUlib_drawTextLine(&w_weapon, false);
1027
1028 if (doit && hud_active>1)
1029 {
1030 int k;
1031
1032 hud_keysstr[4] = '\0'; //jff 3/7/98 make sure deleted keys go away
1033 //jff add case for graphic key display
1034 if (!deathmatch && hud_graph_keys)
1035 {
1036 i=0;
1037 hud_gkeysstr[i] = '\0'; //jff 3/7/98 init graphic keys widget string
1038 // build text string whose characters call out graphic keys from fontk
1039 for (k=0;k<6;k++)
1040 {
1041 // skip keys not possessed
1042 if (!plr->cards[k])
1043 continue;
1044
1045 hud_gkeysstr[i++] = '!'+k; // key number plus '!' is char for key
1046 hud_gkeysstr[i++] = ' '; // spacing
1047 hud_gkeysstr[i++] = ' ';
1048 }
1049 hud_gkeysstr[i]='\0';
1050 }
1051 else // not possible in current code, unless deathmatching,
1052 {
1053 i=4;
1054 hud_keysstr[i] = '\0'; //jff 3/7/98 make sure deleted keys go away
1055
1056 // if deathmatch, build string showing top four frag counts
1057 if (deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch
1058 {
1059 int top1=-999,top2=-999,top3=-999,top4=-999;
1060 int idx1=-1,idx2=-1,idx3=-1,idx4=-1;
1061 int fragcount,m;
1062 char numbuf[32];
1063
1064 // scan thru players
1065 for (k=0;k<MAXPLAYERS;k++)
1066 {
1067 // skip players not in game
1068 if (!playeringame[k])
1069 continue;
1070
1071 fragcount = 0;
1072 // compute number of times they've fragged each player
1073 // minus number of times they've been fragged by them
1074 for (m=0;m<MAXPLAYERS;m++)
1075 {
1076 if (!playeringame[m]) continue;
1077 fragcount += (m!=k)? players[k].frags[m] : -players[k].frags[m];
1078 }
1079
1080 // very primitive sort of frags to find top four
1081 if (fragcount>top1)
1082 {
1083 top4=top3; top3=top2; top2 = top1; top1=fragcount;
1084 idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k;
1085 }
1086 else if (fragcount>top2)
1087 {
1088 top4=top3; top3=top2; top2=fragcount;
1089 idx4=idx3; idx3=idx2; idx2=k;
1090 }
1091 else if (fragcount>top3)
1092 {
1093 top4=top3; top3=fragcount;
1094 idx4=idx3; idx3=k;
1095 }
1096 else if (fragcount>top4)
1097 {
1098 top4=fragcount;
1099 idx4=k;
1100 }
1101 }
1102 // if the biggest number exists, put it in the init string
1103 if (idx1>-1)
1104 {
1105 sprintf(numbuf,"%5d",top1);
1106 // make frag count in player's color via escape code
1107 hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1108 hud_keysstr[i++] = '0'+plyrcoltran[idx1&3];
1109 s = numbuf;
1110 while (*s)
1111 hud_keysstr[i++] = *(s++);
1112 }
1113 // if the second biggest number exists, put it in the init string
1114 if (idx2>-1)
1115 {
1116 sprintf(numbuf,"%5d",top2);
1117 // make frag count in player's color via escape code
1118 hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1119 hud_keysstr[i++] = '0'+plyrcoltran[idx2&3];
1120 s = numbuf;
1121 while (*s)
1122 hud_keysstr[i++] = *(s++);
1123 }
1124 // if the third biggest number exists, put it in the init string
1125 if (idx3>-1)
1126 {
1127 sprintf(numbuf,"%5d",top3);
1128 // make frag count in player's color via escape code
1129 hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1130 hud_keysstr[i++] = '0'+plyrcoltran[idx3&3];
1131 s = numbuf;
1132 while (*s)
1133 hud_keysstr[i++] = *(s++);
1134 }
1135 // if the fourth biggest number exists, put it in the init string
1136 if (idx4>-1)
1137 {
1138 sprintf(numbuf,"%5d",top4);
1139 // make frag count in player's color via escape code
1140 hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1141 hud_keysstr[i++] = '0'+plyrcoltran[idx4&3];
1142 s = numbuf;
1143 while (*s)
1144 hud_keysstr[i++] = *(s++);
1145 }
1146 hud_keysstr[i] = '\0';
1147 } //jff 3/17/98 end of deathmatch clause
1148 else // build alphabetical key display (not used currently)
1149 {
1150 // scan the keys
1151 for (k=0;k<6;k++)
1152 {
1153 // skip any not possessed by the displayed player's stats
1154 if (!plr->cards[k])
1155 continue;
1156
1157 // use color escapes to make text in key's color
1158 hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1159 switch(k)
1160 {
1161 case 0:
1162 hud_keysstr[i++] = '0'+CR_BLUE;
1163 hud_keysstr[i++] = 'B';
1164 hud_keysstr[i++] = 'C';
1165 hud_keysstr[i++] = ' ';
1166 break;
1167 case 1:
1168 hud_keysstr[i++] = '0'+CR_GOLD;
1169 hud_keysstr[i++] = 'Y';
1170 hud_keysstr[i++] = 'C';
1171 hud_keysstr[i++] = ' ';
1172 break;
1173 case 2:
1174 hud_keysstr[i++] = '0'+CR_RED;
1175 hud_keysstr[i++] = 'R';
1176 hud_keysstr[i++] = 'C';
1177 hud_keysstr[i++] = ' ';
1178 break;
1179 case 3:
1180 hud_keysstr[i++] = '0'+CR_BLUE;
1181 hud_keysstr[i++] = 'B';
1182 hud_keysstr[i++] = 'S';
1183 hud_keysstr[i++] = ' ';
1184 break;
1185 case 4:
1186 hud_keysstr[i++] = '0'+CR_GOLD;
1187 hud_keysstr[i++] = 'Y';
1188 hud_keysstr[i++] = 'S';
1189 hud_keysstr[i++] = ' ';
1190 break;
1191 case 5:
1192 hud_keysstr[i++] = '0'+CR_RED;
1193 hud_keysstr[i++] = 'R';
1194 hud_keysstr[i++] = 'S';
1195 hud_keysstr[i++] = ' ';
1196 break;
1197 }
1198 hud_keysstr[i]='\0';
1199 }
1200 }
1201 }
1202 }
1203 // display the keys/frags line each frame
1204 if (hud_active>1)
1205 {
1206 HUlib_clearTextLine(&w_keys); // clear the widget strings
1207 HUlib_clearTextLine(&w_gkeys);
1208
1209 // transfer the built string (frags or key title) to the widget
1210 s = hud_keysstr; //jff 3/7/98 display key titles/key text or frags
1211 while (*s)
1212 HUlib_addCharToTextLine(&w_keys, *(s++));
1213 HUlib_drawTextLine(&w_keys, false);
1214
1215 //jff 3/17/98 show graphic keys in non-DM only
1216 if (!deathmatch) //jff 3/7/98 display graphic keys
1217 {
1218 // transfer the graphic key text to the widget
1219 s = hud_gkeysstr;
1220 while (*s)
1221 HUlib_addCharToTextLine(&w_gkeys, *(s++));
1222 // display the widget
1223 HUlib_drawTextLine(&w_gkeys, false);
1224 }
1225 }
1226
1227 // display the hud kills/items/secret display if optioned
1228 if (!hud_nosecrets)
1229 {
1230 if (hud_active>1 && doit)
1231 {
1232 // clear the internal widget text buffer
1233 HUlib_clearTextLine(&w_monsec);
1234 //jff 3/26/98 use ESC not '\' for paths
1235 // build the init string with fixed colors
1236 sprintf
1237 (
1238 hud_monsecstr,
1239 "STS \x1b\x36K \x1b\x33%d \x1b\x36M \x1b\x33%d \x1b\x37I \x1b\x33%d/%d \x1b\x35S \x1b\x33%d/%d",
1240 plr->killcount,totallive,
1241 plr->itemcount,totalitems,
1242 plr->secretcount,totalsecret
1243 );
1244 // transfer the init string to the widget
1245 s = hud_monsecstr;
1246 while (*s)
1247 HUlib_addCharToTextLine(&w_monsec, *(s++));
1248 }
1249 // display the kills/items/secrets each frame, if optioned
1250 if (hud_active>1)
1251 HUlib_drawTextLine(&w_monsec, false);
1252 }
1253 }
1254
1255 //jff 3/4/98 display last to give priority
1256 HU_Erase(); // jff 4/24/98 Erase current lines before drawing current
1257 // needed when screen not fullsize
1258
1259 //jff 4/21/98 if setup has disabled message list while active, turn it off
1260 if (hud_msg_lines<=1)
1261 message_list = false;
1262
1263 // if the message review not enabled, show the standard message widget
1264 if (!message_list)
1265 HUlib_drawSText(&w_message);
1266
1267 // if the message review is enabled show the scrolling message review
1268 if (hud_msg_lines>1 && message_list)
1269 HUlib_drawMText(&w_rtext);
1270
1271 // display the interactive buffer for chat entry
1272 HUlib_drawIText(&w_chat);
1273}
1274
1275//
1276// HU_Erase()
1277//
1278// Erase hud display lines that can be trashed by small screen display
1279//
1280// Passed nothing, returns nothing
1281//
1282void HU_Erase(void)
1283{
1284 // erase the message display or the message review display
1285 if (!message_list)
1286 HUlib_eraseSText(&w_message);
1287 else
1288 HUlib_eraseMText(&w_rtext);
1289
1290 // erase the interactive text buffer for chat entry
1291 HUlib_eraseIText(&w_chat);
1292
1293 // erase the automap title
1294 HUlib_eraseTextLine(&w_title);
1295}
1296
1297//
1298// HU_Ticker()
1299//
1300// Update the hud displays once per frame
1301//
1302// Passed nothing, returns nothing
1303//
1304static boolean bsdown; // Is backspace down?
1305static int bscounter;
1306
1307void HU_Ticker(void)
1308{
1309 int i, rc;
1310 char c;
1311
1312 // tick down message counter if message is up
1313 if (message_counter && !--message_counter)
1314 {
1315 message_on = false;
1316 message_nottobefuckedwith = false;
1317 }
1318 if (bsdown && bscounter++ > 9) {
1319 HUlib_keyInIText(&w_chat, (unsigned char)key_backspace);
1320 bscounter = 8;
1321 }
1322
1323 // if messages on, or "Messages Off" is being displayed
1324 // this allows the notification of turning messages off to be seen
1325 if (showMessages || message_dontfuckwithme)
1326 {
1327 // display message if necessary
1328 if ((plr->message && !message_nottobefuckedwith)
1329 || (plr->message && message_dontfuckwithme))
1330 {
1331 //post the message to the message widget
1332 HUlib_addMessageToSText(&w_message, 0, plr->message);
1333 //jff 2/26/98 add message to refresh text widget too
1334 HUlib_addMessageToMText(&w_rtext, 0, plr->message);
1335
1336 // clear the message to avoid posting multiple times
1337 plr->message = 0;
1338 // note a message is displayed
1339 message_on = true;
1340 // start the message persistence counter
1341 message_counter = HU_MSGTIMEOUT;
1342 // transfer "Messages Off" exception to the "being displayed" variable
1343 message_nottobefuckedwith = message_dontfuckwithme;
1344 // clear the flag that "Messages Off" is being posted
1345 message_dontfuckwithme = 0;
1346 }
1347 }
1348
1349 // check for incoming chat characters
1350 if (netgame)
1351 {
1352 for (i=0; i<MAXPLAYERS; i++)
1353 {
1354 if (!playeringame[i])
1355 continue;
1356 if (i != consoleplayer
1357 && (c = players[i].cmd.chatchar))
1358 {
1359 if (c <= HU_BROADCAST)
1360 chat_dest[i] = c;
1361 else
1362 {
1363 if (c >= 'a' && c <= 'z')
1364 c = (char) shiftxform[(unsigned char) c];
1365 rc = HUlib_keyInIText(&w_inputbuffer[i], c);
1366 if (rc && c == KEYD_ENTER)
1367 {
1368 if (w_inputbuffer[i].l.len
1369 && (chat_dest[i] == consoleplayer+1
1370 || chat_dest[i] == HU_BROADCAST))
1371 {
1372 HUlib_addMessageToSText(&w_message,
1373 player_names[i],
1374 w_inputbuffer[i].l.l);
1375
1376 message_nottobefuckedwith = true;
1377 message_on = true;
1378 message_counter = HU_MSGTIMEOUT;
1379 if ( gamemode == commercial )
1380 S_StartSound(0, sfx_radio);
1381 else
1382 S_StartSound(0, sfx_tink);
1383 }
1384 HUlib_resetIText(&w_inputbuffer[i]);
1385 }
1386 }
1387 players[i].cmd.chatchar = 0;
1388 }
1389 }
1390 }
1391}
1392
1393#define QUEUESIZE 128
1394
1395static char chatchars[QUEUESIZE];
1396static int head = 0;
1397static int tail = 0;
1398
1399//
1400// HU_queueChatChar()
1401//
1402// Add an incoming character to the circular chat queue
1403//
1404// Passed the character to queue, returns nothing
1405//
1406static void HU_queueChatChar(char c)
1407{
1408 if (((head + 1) & (QUEUESIZE-1)) == tail)
1409 {
1410 plr->message = HUSTR_MSGU;
1411 }
1412 else
1413 {
1414 chatchars[head] = c;
1415 head = (head + 1) & (QUEUESIZE-1);
1416 }
1417}
1418
1419//
1420// HU_dequeueChatChar()
1421//
1422// Remove the earliest added character from the circular chat queue
1423//
1424// Passed nothing, returns the character dequeued
1425//
1426char HU_dequeueChatChar(void)
1427{
1428 char c;
1429
1430 if (head != tail)
1431 {
1432 c = chatchars[tail];
1433 tail = (tail + 1) & (QUEUESIZE-1);
1434 }
1435 else
1436 {
1437 c = 0;
1438 }
1439 return c;
1440}
1441
1442//
1443// HU_Responder()
1444//
1445// Responds to input events that affect the heads up displays
1446//
1447// Passed the event to respond to, returns true if the event was handled
1448//
1449boolean HU_Responder(event_t *ev)
1450{
1451
1452 static char lastmessage[HU_MAXLINELENGTH+1];
1453 const char* macromessage; // CPhipps - const char*
1454 boolean eatkey = false;
1455 static boolean shiftdown = false;
1456 static boolean altdown = false;
1457 unsigned char c;
1458 int i;
1459 int numplayers;
1460
1461 static int num_nobrainers = 0;
1462
1463 numplayers = 0;
1464 for (i=0 ; i<MAXPLAYERS ; i++)
1465 numplayers += playeringame[i];
1466
1467 if (ev->data1 == key_shift)
1468 {
1469 shiftdown = ev->type == ev_keydown;
1470 return false;
1471 }
1472 else if (ev->data1 == key_alt)
1473 {
1474 altdown = ev->type == ev_keydown;
1475 return false;
1476 }
1477 else if (ev->data1 == key_backspace)
1478 {
1479 bsdown = ev->type == ev_keydown;
1480 bscounter = 0;
1481 }
1482
1483 if (ev->type != ev_keydown)
1484 return false;
1485
1486 if (!chat_on)
1487 {
1488 if (ev->data1 == key_enter) // phares
1489 {
1490#ifndef INSTRUMENTED // never turn on message review if INSTRUMENTED defined
1491 if (hud_msg_lines>1) // it posts multi-line messages that will trash
1492 {
1493 if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages
1494 message_list = !message_list; //jff 2/26/98 toggle list of messages
1495 }
1496#endif
1497 if (!message_list) // if not message list, refresh message
1498 {
1499 message_on = true;
1500 message_counter = HU_MSGTIMEOUT;
1501 }
1502 eatkey = true;
1503 }//jff 2/26/98 no chat if message review is displayed
1504 // killough 10/02/98: no chat if demo playback
1505 // no chat in -solo-net mode
1506 else if (!demoplayback && !message_list && netgame && numplayers > 1)
1507 {
1508 if (ev->data1 == key_chat)
1509 {
1510 eatkey = chat_on = true;
1511 HUlib_resetIText(&w_chat);
1512 HU_queueChatChar(HU_BROADCAST);
1513 }
1514 else if (numplayers > 2)
1515 {
1516 for (i=0; i<MAXPLAYERS ; i++)
1517 {
1518 if (ev->data1 == destination_keys[i])
1519 {
1520 if (playeringame[i] && i!=consoleplayer)
1521 {
1522 eatkey = chat_on = true;
1523 HUlib_resetIText(&w_chat);
1524 HU_queueChatChar((char)(i+1));
1525 break;
1526 }
1527 else if (i == consoleplayer)
1528 {
1529 num_nobrainers++;
1530 if (num_nobrainers < 3)
1531 plr->message = HUSTR_TALKTOSELF1;
1532 else if (num_nobrainers < 6)
1533 plr->message = HUSTR_TALKTOSELF2;
1534 else if (num_nobrainers < 9)
1535 plr->message = HUSTR_TALKTOSELF3;
1536 else if (num_nobrainers < 32)
1537 plr->message = HUSTR_TALKTOSELF4;
1538 else
1539 plr->message = HUSTR_TALKTOSELF5;
1540 }
1541 }
1542 }
1543 }
1544 }
1545 }//jff 2/26/98 no chat functions if message review is displayed
1546 else if (!message_list)
1547 {
1548 c = ev->data1;
1549 // send a macro
1550 if (altdown)
1551 {
1552 c = c - '0';
1553 if (c > 9)
1554 return false;
1555 macromessage = chat_macros[c];
1556
1557 // kill last message with a '\n'
1558 HU_queueChatChar((char)key_enter); // DEBUG!!! // phares
1559
1560 // send the macro message
1561 while (*macromessage)
1562 HU_queueChatChar(*macromessage++);
1563 HU_queueChatChar((char)key_enter); // phares
1564
1565 // leave chat mode and notify that it was sent
1566 chat_on = false;
1567 strcpy(lastmessage, chat_macros[c]);
1568 plr->message = lastmessage;
1569 eatkey = true;
1570 }
1571 else
1572 {
1573 if (shiftdown || (c >= 'a' && c <= 'z'))
1574 c = shiftxform[c];
1575 eatkey = HUlib_keyInIText(&w_chat, c);
1576 if (eatkey)
1577 HU_queueChatChar(c);
1578
1579 if (c == key_enter) // phares
1580 {
1581 chat_on = false;
1582 if (w_chat.l.len)
1583 {
1584 strcpy(lastmessage, w_chat.l.l);
1585 plr->message = lastmessage;
1586 }
1587 }
1588 else if (c == key_escape) // phares
1589 chat_on = false;
1590 }
1591 }
1592 return eatkey;
1593}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: Head up display
30 *
31 *-----------------------------------------------------------------------------*/
32
33#ifndef __HU_STUFF_H__
34#define __HU_STUFF_H__
35
36#include "d_event.h"
37
38/*
39 * Globally visible constants.
40 */
41#define HU_FONTSTART '!' /* the first font characters */
42#define HU_FONTEND (0x7f) /*jff 2/16/98 '_' the last font characters */
43
44/* Calculate # of glyphs in font. */
45#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
46
47#define HU_BROADCAST 5
48
49/*#define HU_MSGREFRESH KEYD_ENTER phares */
50#define HU_MSGX 0
51#define HU_MSGY 0
52#define HU_MSGWIDTH 64 /* in characters */
53#define HU_MSGHEIGHT 1 /* in lines */
54
55#define HU_MSGTIMEOUT (4*TICRATE)
56
57/*
58 * Heads up text
59 */
60void HU_Init(void);
61void HU_Start(void);
62
63boolean HU_Responder(event_t* ev);
64
65void HU_Ticker(void);
66void HU_Drawer(void);
67char HU_dequeueChatChar(void);
68void HU_Erase(void);
69void HU_MoveHud(void); // jff 3/9/98 avoid glitch in HUD display
70
71/* killough 5/2/98: moved from m_misc.c: */
72
73/* jff 2/16/98 hud supported automap colors added */
74extern int hudcolor_titl; /* color range of automap level title */
75extern int hudcolor_xyco; /* color range of new coords on automap */
76/* jff 2/16/98 hud text colors, controls added */
77extern int hudcolor_mesg; /* color range of scrolling messages */
78extern int hudcolor_chat; /* color range of chat lines */
79/* jff 2/26/98 hud message list color and background enable */
80extern int hudcolor_list; /* color of list of past messages */
81extern int hud_list_bgon; /* solid window background for list of messages */
82extern int hud_msg_lines; /* number of message lines in window up to 16 */
83extern int hud_distributed; /* whether hud is all in lower left or distributed */
84/* jff 2/23/98 hud is currently displayed */
85extern int hud_displayed; /* hud is displayed */
86/* jff 2/18/98 hud/status control */
87extern int hud_active; /* hud mode 0=off, 1=small, 2=full */
88extern int hud_nosecrets; /* status does not list secrets/items/kills */
89
90#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Joystick interface.
31 *
32 *-----------------------------------------------------------------------------*/
33
34extern int joybfire;
35extern int joybstrafe;
36extern int joybuse;
37extern int joybspeed;
38
39extern int joyleft;
40extern int joyright;
41extern int joyup;
42extern int joydown;
43
44extern int usejoystick;
45
46void I_InitJoystick(void);
47void 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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * General system functions. Signal related stuff, exit function
31 * prototypes, and programmable Doom clock.
32 *
33 *-----------------------------------------------------------------------------
34 */
35
36#ifndef __I_MAIN__
37#define __I_MAIN__
38
39void I_Init(void);
40void I_SafeExit(int rc);
41
42extern int (*I_GetTime)(void);
43
44#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Low level network interface.
31 *-----------------------------------------------------------------------------*/
32
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
36
37#ifdef USE_SDL_NET
38 #include "SDL_net.h"
39 #define UDP_SOCKET UDPsocket
40 #define UDP_PACKET UDPpacket
41 #define AF_INET
42 #define UDP_CHANNEL int
43 extern UDP_SOCKET udp_socket;
44#else
45 #define UDP_CHANNEL struct sockaddr
46#endif
47
48#ifndef IPPORT_RESERVED
49 #define IPPORT_RESERVED 1024
50#endif
51
52void I_InitNetwork(void);
53size_t I_GetPacket(packet_header_t* buffer, size_t buflen);
54void I_SendPacket(packet_header_t* packet, size_t len);
55void I_WaitForPacket(int ms);
56
57#ifdef USE_SDL_NET
58UDP_SOCKET I_Socket(Uint16 port);
59int I_ConnectToServer(const char *serv);
60UDP_CHANNEL I_RegisterPlayer(IPaddress *ipaddr);
61void I_UnRegisterPlayer(UDP_CHANNEL channel);
62extern IPaddress sentfrom_addr;
63#endif
64
65#ifdef AF_INET
66void I_SendPacketTo(packet_header_t* packet, size_t len, UDP_CHANNEL *to);
67void I_SetupSocket(int sock, int port, int family);
68void I_PrintAddress(FILE* fp, UDP_CHANNEL *addr);
69
70extern UDP_CHANNEL sentfrom;
71extern int v4socket, v6socket;
72#endif
73
74extern 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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * System interface, sound.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __I_SOUND__
35#define __I_SOUND__
36
37#include "sounds.h"
38#include "doomtype.h"
39
40#define SNDSERV
41#undef SNDINTR
42
43#ifndef SNDSERV
44#include "l_soundgen.h"
45#endif
46
47// Init at program start...
48void I_InitSound(void);
49
50// ... shut down and relase at program termination.
51void I_ShutdownSound(void);
52
53//
54// SFX I/O
55//
56
57// Initialize channels?
58void I_SetChannels(void);
59
60// Get raw data lump index for sound descriptor.
61int I_GetSfxLumpNum (sfxinfo_t *sfxinfo);
62
63// Starts a sound in a particular sound channel.
64int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority);
65
66// Stops a sound channel.
67void I_StopSound(int handle);
68
69// Called by S_*() functions
70// to see if a channel is still playing.
71// Returns 0 if no longer playing, 1 if playing.
72boolean I_SoundIsPlaying(int handle);
73
74// Called by m_menu.c to let the quit sound play and quit right after it stops
75boolean I_AnySoundStillPlaying(void);
76
77// Updates the volume, separation,
78// and pitch of a sound channel.
79void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
80
81//
82// MUSIC I/O
83//
84void I_InitMusic(void);
85void I_ShutdownMusic(void);
86
87void I_UpdateMusic(void);
88
89// Volume.
90void I_SetMusicVolume(int volume);
91
92// PAUSE game handling.
93void I_PauseSong(int handle);
94void I_ResumeSong(int handle);
95
96// Registers a song handle to song data.
97int I_RegisterSong(const void *data, size_t len);
98
99// cournia - tries to load a music file
100int I_RegisterMusic( const char* filename, musicinfo_t *music );
101
102// Called by anything that wishes to start music.
103// plays a song, and when the song is done,
104// starts playing it again in an endless loop.
105// Horrible thing to do, considering.
106void I_PlaySong(int handle, int looping);
107
108// Stops a song over 3 seconds.
109void I_StopSong(int handle);
110
111// See above (register), then think backwards
112void I_UnRegisterSong(int handle);
113
114// Allegro card support jff 1/18/98
115extern int snd_card;
116extern int mus_card;
117// CPhipps - put these in config file
118extern int snd_samplerate;
119
120#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * System specific interface stuff.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __I_SYSTEM__
35#define __I_SYSTEM__
36
37#ifdef __GNUG__
38#pragma interface
39#endif
40
41extern int ms_to_next_tick;
42boolean I_StartDisplay(void);
43void I_EndDisplay(void);
44int I_GetTime_RealTime(void); /* killough */
45#ifndef PRBOOM_SERVER
46fixed_t I_GetTimeFrac (void);
47#endif
48void I_GetTime_SaveMS(void);
49
50unsigned long I_GetRandomTimeSeed(void); /* cphipps */
51
52void I_uSleep(unsigned long usecs);
53
54/* cphipps - I_GetVersionString
55 * Returns a version string in the given buffer
56 */
57const char* I_GetVersionString(char* buf, size_t sz);
58
59/* cphipps - I_SigString
60 * Returns a string describing a signal number
61 */
62const char* I_SigString(char* buf, size_t sz, int signum);
63
64const char *I_DoomExeDir(void); // killough 2/16/98: path to executable's dir
65
66boolean HasTrailingSlash(const char* dn);
67char* I_FindFile(const char* wfname, const char* ext);
68
69/* cph 2001/11/18 - wrapper for read(2) which deals with partial reads */
70void I_Read(int fd, void* buf, size_t sz);
71
72/* cph 2001/11/18 - Move W_Filelength to i_system.c */
73int I_Filelength(int handle);
74
75void I_SetAffinityMask(void);
76
77#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * System specific interface stuff.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __I_VIDEO__
35#define __I_VIDEO__
36
37#include "doomtype.h"
38#include "v_video.h"
39
40#ifdef __GNUG__
41#pragma interface
42#endif
43
44void I_PreInitGraphics(void); /* CPhipps - do stuff immediately on start */
45void I_CalculateRes(unsigned int width, unsigned int height); /* calculate resolution */
46void I_SetRes(void); /* set resolution */
47void I_InitGraphics (void);
48void I_UpdateVideoMode(void);
49void I_ShutdownGraphics(void);
50
51/* Takes full 8 bit values. */
52void I_SetPalette(int pal); /* CPhipps - pass down palette number */
53
54void I_UpdateNoBlit (void);
55void I_FinishUpdate (void);
56
57int I_ScreenShot (const char *fname);
58
59/* I_StartTic
60 * Called by D_DoomLoop,
61 * called before processing each tic in a frame.
62 * Quick syncronous operations are performed here.
63 * Can call D_PostEvent.
64 */
65void I_StartTic (void);
66
67/* I_StartFrame
68 * Called by D_DoomLoop,
69 * called before processing any tics in a frame
70 * (just after displaying a frame).
71 * Time consuming syncronous operations
72 * are performed here (joystick reading).
73 * Can call D_PostEvent.
74 */
75
76void I_StartFrame (void);
77
78extern int use_doublebuffer; /* proff 2001-7-4 - controls wether to use doublebuffering*/
79extern int use_fullscreen; /* proff 21/05/2000 */
80extern int desired_fullscreen; //e6y
81
82#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Thing frame/state LUT,
31 * generated by multigen utilitiy.
32 * This one is the original DOOM version, preserved.
33 * BOOM changes include commenting and addition of predefined lumps
34 * for providing things that aren't in the IWAD without sending a
35 * separate must-use wad file around with the EXE.
36 *
37 *-----------------------------------------------------------------------------
38 */
39
40#include "doomdef.h"
41#include "sounds.h"
42#include "m_fixed.h"
43#include "p_mobj.h"
44#include "p_enemy.h"
45#include "p_pspr.h"
46#include "w_wad.h"
47
48#ifdef __GNUG__
49#pragma implementation "info.h"
50#endif
51#include "info.h"
52
53
54// ********************************************************************
55// Sprite names
56// ********************************************************************
57// This is the list of sprite 4-character prefixes. They are searched
58// through, with a NULL entry terminating the list. In DOOM originally
59// this NULL entry was missing, and coincidentally the next thing in
60// memory was the dummy state_t[] entry that started with zero bytes.
61// killough 1/17/98: add an explicit NULL entry.
62// NUMSPRITES is an enum from info.h where all these are listed
63// as SPR_xxxx
64
65const char *sprnames[NUMSPRITES+1] = {
66 "TROO","SHTG","PUNG","PISG","PISF","SHTF","SHT2","CHGG","CHGF","MISG",
67 "MISF","SAWG","PLSG","PLSF","BFGG","BFGF","BLUD","PUFF","BAL1","BAL2",
68 "PLSS","PLSE","MISL","BFS1","BFE1","BFE2","TFOG","IFOG","PLAY","POSS",
69 "SPOS","VILE","FIRE","FATB","FBXP","SKEL","MANF","FATT","CPOS","SARG",
70 "HEAD","BAL7","BOSS","BOS2","SKUL","SPID","BSPI","APLS","APBX","CYBR",
71 "PAIN","SSWV","KEEN","BBRN","BOSF","ARM1","ARM2","BAR1","BEXP","FCAN",
72 "BON1","BON2","BKEY","RKEY","YKEY","BSKU","RSKU","YSKU","STIM","MEDI",
73 "SOUL","PINV","PSTR","PINS","MEGA","SUIT","PMAP","PVIS","CLIP","AMMO",
74 "ROCK","BROK","CELL","CELP","SHEL","SBOX","BPAK","BFUG","MGUN","CSAW",
75 "LAUN","PLAS","SHOT","SGN2","COLU","SMT2","GOR1","POL2","POL5","POL4",
76 "POL3","POL1","POL6","GOR2","GOR3","GOR4","GOR5","SMIT","COL1","COL2",
77 "COL3","COL4","CAND","CBRA","COL6","TRE1","TRE2","ELEC","CEYE","FSKU",
78 "COL5","TBLU","TGRN","TRED","SMBT","SMGT","SMRT","HDB1","HDB2","HDB3",
79 "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2",
80 "TNT1", // invisible sprite phares 3/9/98
81#ifdef DOGS
82 "DOGS", /* killough 7/19/98: Marine's best friend :) */
83#endif
84 NULL
85};
86
87// ********************************************************************
88// State or "frame" information
89// ********************************************************************
90// Each of the states, otherwise known as "frames", is outlined
91// here. The data in each element of the array is the way it is
92// initialized, with sprite names identified by their enumerator
93// value such as SPR_SHTG. These correlate to the above sprite
94// array so don't change them around unless you understand what
95// you're doing.
96//
97// The commented name beginning with S_ at the end of each line
98// is there to help figure out where the next-frame pointer is
99// pointing. These are also additionally identified in info.h
100// as enumerated values. From a change-and-recompile point of
101// view this is fairly workable, but it adds a lot to the effort
102// when trying to change things externally. See also the d_deh.c
103// parts where frame rewiring is done for more details and the
104// extended way a BEX file can handle this.
105
106state_t states[NUMSTATES] = {
107 {SPR_TROO,0,-1,NULL,S_NULL,0,0}, // S_NULL
108 {SPR_SHTG,4,0,A_Light0,S_NULL,0,0}, // S_LIGHTDONE
109 {SPR_PUNG,0,1,A_WeaponReady,S_PUNCH,0,0}, // S_PUNCH
110 {SPR_PUNG,0,1,A_Lower,S_PUNCHDOWN,0,0}, // S_PUNCHDOWN
111 {SPR_PUNG,0,1,A_Raise,S_PUNCHUP,0,0}, // S_PUNCHUP
112 {SPR_PUNG,1,4,NULL,S_PUNCH2,0,0}, // S_PUNCH1
113 {SPR_PUNG,2,4,A_Punch,S_PUNCH3,0,0}, // S_PUNCH2
114 {SPR_PUNG,3,5,NULL,S_PUNCH4,0,0}, // S_PUNCH3
115 {SPR_PUNG,2,4,NULL,S_PUNCH5,0,0}, // S_PUNCH4
116 {SPR_PUNG,1,5,A_ReFire,S_PUNCH,0,0}, // S_PUNCH5
117 {SPR_PISG,0,1,A_WeaponReady,S_PISTOL,0,0},// S_PISTOL
118 {SPR_PISG,0,1,A_Lower,S_PISTOLDOWN,0,0}, // S_PISTOLDOWN
119 {SPR_PISG,0,1,A_Raise,S_PISTOLUP,0,0}, // S_PISTOLUP
120 {SPR_PISG,0,4,NULL,S_PISTOL2,0,0}, // S_PISTOL1
121 {SPR_PISG,1,6,A_FirePistol,S_PISTOL3,0,0},// S_PISTOL2
122 {SPR_PISG,2,4,NULL,S_PISTOL4,0,0}, // S_PISTOL3
123 {SPR_PISG,1,5,A_ReFire,S_PISTOL,0,0}, // S_PISTOL4
124 {SPR_PISF,32768,7,A_Light1,S_LIGHTDONE,0,0}, // S_PISTOLFLASH
125 {SPR_SHTG,0,1,A_WeaponReady,S_SGUN,0,0}, // S_SGUN
126 {SPR_SHTG,0,1,A_Lower,S_SGUNDOWN,0,0}, // S_SGUNDOWN
127 {SPR_SHTG,0,1,A_Raise,S_SGUNUP,0,0}, // S_SGUNUP
128 {SPR_SHTG,0,3,NULL,S_SGUN2,0,0}, // S_SGUN1
129 {SPR_SHTG,0,7,A_FireShotgun,S_SGUN3,0,0}, // S_SGUN2
130 {SPR_SHTG,1,5,NULL,S_SGUN4,0,0}, // S_SGUN3
131 {SPR_SHTG,2,5,NULL,S_SGUN5,0,0}, // S_SGUN4
132 {SPR_SHTG,3,4,NULL,S_SGUN6,0,0}, // S_SGUN5
133 {SPR_SHTG,2,5,NULL,S_SGUN7,0,0}, // S_SGUN6
134 {SPR_SHTG,1,5,NULL,S_SGUN8,0,0}, // S_SGUN7
135 {SPR_SHTG,0,3,NULL,S_SGUN9,0,0}, // S_SGUN8
136 {SPR_SHTG,0,7,A_ReFire,S_SGUN,0,0}, // S_SGUN9
137 {SPR_SHTF,32768,4,A_Light1,S_SGUNFLASH2,0,0}, // S_SGUNFLASH1
138 {SPR_SHTF,32769,3,A_Light2,S_LIGHTDONE,0,0}, // S_SGUNFLASH2
139 {SPR_SHT2,0,1,A_WeaponReady,S_DSGUN,0,0}, // S_DSGUN
140 {SPR_SHT2,0,1,A_Lower,S_DSGUNDOWN,0,0}, // S_DSGUNDOWN
141 {SPR_SHT2,0,1,A_Raise,S_DSGUNUP,0,0}, // S_DSGUNUP
142 {SPR_SHT2,0,3,NULL,S_DSGUN2,0,0}, // S_DSGUN1
143 {SPR_SHT2,0,7,A_FireShotgun2,S_DSGUN3,0,0}, // S_DSGUN2
144 {SPR_SHT2,1,7,NULL,S_DSGUN4,0,0}, // S_DSGUN3
145 {SPR_SHT2,2,7,A_CheckReload,S_DSGUN5,0,0}, // S_DSGUN4
146 {SPR_SHT2,3,7,A_OpenShotgun2,S_DSGUN6,0,0}, // S_DSGUN5
147 {SPR_SHT2,4,7,NULL,S_DSGUN7,0,0}, // S_DSGUN6
148 {SPR_SHT2,5,7,A_LoadShotgun2,S_DSGUN8,0,0}, // S_DSGUN7
149 {SPR_SHT2,6,6,NULL,S_DSGUN9,0,0}, // S_DSGUN8
150 {SPR_SHT2,7,6,A_CloseShotgun2,S_DSGUN10,0,0}, // S_DSGUN9
151 {SPR_SHT2,0,5,A_ReFire,S_DSGUN,0,0}, // S_DSGUN10
152 {SPR_SHT2,1,7,NULL,S_DSNR2,0,0}, // S_DSNR1
153 {SPR_SHT2,0,3,NULL,S_DSGUNDOWN,0,0}, // S_DSNR2
154 {SPR_SHT2,32776,5,A_Light1,S_DSGUNFLASH2,0,0}, // S_DSGUNFLASH1
155 {SPR_SHT2,32777,4,A_Light2,S_LIGHTDONE,0,0}, // S_DSGUNFLASH2
156 {SPR_CHGG,0,1,A_WeaponReady,S_CHAIN,0,0}, // S_CHAIN
157 {SPR_CHGG,0,1,A_Lower,S_CHAINDOWN,0,0}, // S_CHAINDOWN
158 {SPR_CHGG,0,1,A_Raise,S_CHAINUP,0,0}, // S_CHAINUP
159 {SPR_CHGG,0,4,A_FireCGun,S_CHAIN2,0,0}, // S_CHAIN1
160 {SPR_CHGG,1,4,A_FireCGun,S_CHAIN3,0,0}, // S_CHAIN2
161 {SPR_CHGG,1,0,A_ReFire,S_CHAIN,0,0}, // S_CHAIN3
162 {SPR_CHGF,32768,5,A_Light1,S_LIGHTDONE,0,0}, // S_CHAINFLASH1
163 {SPR_CHGF,32769,5,A_Light2,S_LIGHTDONE,0,0}, // S_CHAINFLASH2
164 {SPR_MISG,0,1,A_WeaponReady,S_MISSILE,0,0}, // S_MISSILE
165 {SPR_MISG,0,1,A_Lower,S_MISSILEDOWN,0,0}, // S_MISSILEDOWN
166 {SPR_MISG,0,1,A_Raise,S_MISSILEUP,0,0}, // S_MISSILEUP
167 {SPR_MISG,1,8,A_GunFlash,S_MISSILE2,0,0}, // S_MISSILE1
168 {SPR_MISG,1,12,A_FireMissile,S_MISSILE3,0,0}, // S_MISSILE2
169 {SPR_MISG,1,0,A_ReFire,S_MISSILE,0,0}, // S_MISSILE3
170 {SPR_MISF,32768,3,A_Light1,S_MISSILEFLASH2,0,0}, // S_MISSILEFLASH1
171 {SPR_MISF,32769,4,NULL,S_MISSILEFLASH3,0,0}, // S_MISSILEFLASH2
172 {SPR_MISF,32770,4,A_Light2,S_MISSILEFLASH4,0,0}, // S_MISSILEFLASH3
173 {SPR_MISF,32771,4,A_Light2,S_LIGHTDONE,0,0}, // S_MISSILEFLASH4
174 {SPR_SAWG,2,4,A_WeaponReady,S_SAWB,0,0}, // S_SAW
175 {SPR_SAWG,3,4,A_WeaponReady,S_SAW,0,0}, // S_SAWB
176 {SPR_SAWG,2,1,A_Lower,S_SAWDOWN,0,0}, // S_SAWDOWN
177 {SPR_SAWG,2,1,A_Raise,S_SAWUP,0,0}, // S_SAWUP
178 {SPR_SAWG,0,4,A_Saw,S_SAW2,0,0}, // S_SAW1
179 {SPR_SAWG,1,4,A_Saw,S_SAW3,0,0}, // S_SAW2
180 {SPR_SAWG,1,0,A_ReFire,S_SAW,0,0}, // S_SAW3
181 {SPR_PLSG,0,1,A_WeaponReady,S_PLASMA,0,0}, // S_PLASMA
182 {SPR_PLSG,0,1,A_Lower,S_PLASMADOWN,0,0}, // S_PLASMADOWN
183 {SPR_PLSG,0,1,A_Raise,S_PLASMAUP,0,0}, // S_PLASMAUP
184 {SPR_PLSG,0,3,A_FirePlasma,S_PLASMA2,0,0}, // S_PLASMA1
185 {SPR_PLSG,1,20,A_ReFire,S_PLASMA,0,0}, // S_PLASMA2
186 {SPR_PLSF,32768,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH1
187 {SPR_PLSF,32769,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH2
188 {SPR_BFGG,0,1,A_WeaponReady,S_BFG,0,0}, // S_BFG
189 {SPR_BFGG,0,1,A_Lower,S_BFGDOWN,0,0}, // S_BFGDOWN
190 {SPR_BFGG,0,1,A_Raise,S_BFGUP,0,0}, // S_BFGUP
191 {SPR_BFGG,0,20,A_BFGsound,S_BFG2,0,0}, // S_BFG1
192 {SPR_BFGG,1,10,A_GunFlash,S_BFG3,0,0}, // S_BFG2
193 {SPR_BFGG,1,10,A_FireBFG,S_BFG4,0,0}, // S_BFG3
194 {SPR_BFGG,1,20,A_ReFire,S_BFG,0,0}, // S_BFG4
195 {SPR_BFGF,32768,11,A_Light1,S_BFGFLASH2,0,0}, // S_BFGFLASH1
196 {SPR_BFGF,32769,6,A_Light2,S_LIGHTDONE,0,0}, // S_BFGFLASH2
197 {SPR_BLUD,2,8,NULL,S_BLOOD2,0,0}, // S_BLOOD1
198 {SPR_BLUD,1,8,NULL,S_BLOOD3,0,0}, // S_BLOOD2
199 {SPR_BLUD,0,8,NULL,S_NULL,0,0}, // S_BLOOD3
200 {SPR_PUFF,32768,4,NULL,S_PUFF2,0,0}, // S_PUFF1
201 {SPR_PUFF,1,4,NULL,S_PUFF3,0,0}, // S_PUFF2
202 {SPR_PUFF,2,4,NULL,S_PUFF4,0,0}, // S_PUFF3
203 {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_PUFF4
204 {SPR_BAL1,32768,4,NULL,S_TBALL2,0,0}, // S_TBALL1
205 {SPR_BAL1,32769,4,NULL,S_TBALL1,0,0}, // S_TBALL2
206 {SPR_BAL1,32770,6,NULL,S_TBALLX2,0,0}, // S_TBALLX1
207 {SPR_BAL1,32771,6,NULL,S_TBALLX3,0,0}, // S_TBALLX2
208 {SPR_BAL1,32772,6,NULL,S_NULL,0,0}, // S_TBALLX3
209 {SPR_BAL2,32768,4,NULL,S_RBALL2,0,0}, // S_RBALL1
210 {SPR_BAL2,32769,4,NULL,S_RBALL1,0,0}, // S_RBALL2
211 {SPR_BAL2,32770,6,NULL,S_RBALLX2,0,0}, // S_RBALLX1
212 {SPR_BAL2,32771,6,NULL,S_RBALLX3,0,0}, // S_RBALLX2
213 {SPR_BAL2,32772,6,NULL,S_NULL,0,0}, // S_RBALLX3
214 {SPR_PLSS,32768,6,NULL,S_PLASBALL2,0,0}, // S_PLASBALL
215 {SPR_PLSS,32769,6,NULL,S_PLASBALL,0,0}, // S_PLASBALL2
216 {SPR_PLSE,32768,4,NULL,S_PLASEXP2,0,0}, // S_PLASEXP
217 {SPR_PLSE,32769,4,NULL,S_PLASEXP3,0,0}, // S_PLASEXP2
218 {SPR_PLSE,32770,4,NULL,S_PLASEXP4,0,0}, // S_PLASEXP3
219 {SPR_PLSE,32771,4,NULL,S_PLASEXP5,0,0}, // S_PLASEXP4
220 {SPR_PLSE,32772,4,NULL,S_NULL,0,0}, // S_PLASEXP5
221 {SPR_MISL,32768,1,NULL,S_ROCKET,0,0}, // S_ROCKET
222 {SPR_BFS1,32768,4,NULL,S_BFGSHOT2,0,0}, // S_BFGSHOT
223 {SPR_BFS1,32769,4,NULL,S_BFGSHOT,0,0}, // S_BFGSHOT2
224 {SPR_BFE1,32768,8,NULL,S_BFGLAND2,0,0}, // S_BFGLAND
225 {SPR_BFE1,32769,8,NULL,S_BFGLAND3,0,0}, // S_BFGLAND2
226 {SPR_BFE1,32770,8,A_BFGSpray,S_BFGLAND4,0,0}, // S_BFGLAND3
227 {SPR_BFE1,32771,8,NULL,S_BFGLAND5,0,0}, // S_BFGLAND4
228 {SPR_BFE1,32772,8,NULL,S_BFGLAND6,0,0}, // S_BFGLAND5
229 {SPR_BFE1,32773,8,NULL,S_NULL,0,0}, // S_BFGLAND6
230 {SPR_BFE2,32768,8,NULL,S_BFGEXP2,0,0}, // S_BFGEXP
231 {SPR_BFE2,32769,8,NULL,S_BFGEXP3,0,0}, // S_BFGEXP2
232 {SPR_BFE2,32770,8,NULL,S_BFGEXP4,0,0}, // S_BFGEXP3
233 {SPR_BFE2,32771,8,NULL,S_NULL,0,0}, // S_BFGEXP4
234 {SPR_MISL,32769,8,A_Explode,S_EXPLODE2,0,0}, // S_EXPLODE1
235 {SPR_MISL,32770,6,NULL,S_EXPLODE3,0,0}, // S_EXPLODE2
236 {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_EXPLODE3
237 {SPR_TFOG,32768,6,NULL,S_TFOG01,0,0}, // S_TFOG
238 {SPR_TFOG,32769,6,NULL,S_TFOG02,0,0}, // S_TFOG01
239 {SPR_TFOG,32768,6,NULL,S_TFOG2,0,0}, // S_TFOG02
240 {SPR_TFOG,32769,6,NULL,S_TFOG3,0,0}, // S_TFOG2
241 {SPR_TFOG,32770,6,NULL,S_TFOG4,0,0}, // S_TFOG3
242 {SPR_TFOG,32771,6,NULL,S_TFOG5,0,0}, // S_TFOG4
243 {SPR_TFOG,32772,6,NULL,S_TFOG6,0,0}, // S_TFOG5
244 {SPR_TFOG,32773,6,NULL,S_TFOG7,0,0}, // S_TFOG6
245 {SPR_TFOG,32774,6,NULL,S_TFOG8,0,0}, // S_TFOG7
246 {SPR_TFOG,32775,6,NULL,S_TFOG9,0,0}, // S_TFOG8
247 {SPR_TFOG,32776,6,NULL,S_TFOG10,0,0}, // S_TFOG9
248 {SPR_TFOG,32777,6,NULL,S_NULL,0,0}, // S_TFOG10
249 {SPR_IFOG,32768,6,NULL,S_IFOG01,0,0}, // S_IFOG
250 {SPR_IFOG,32769,6,NULL,S_IFOG02,0,0}, // S_IFOG01
251 {SPR_IFOG,32768,6,NULL,S_IFOG2,0,0}, // S_IFOG02
252 {SPR_IFOG,32769,6,NULL,S_IFOG3,0,0}, // S_IFOG2
253 {SPR_IFOG,32770,6,NULL,S_IFOG4,0,0}, // S_IFOG3
254 {SPR_IFOG,32771,6,NULL,S_IFOG5,0,0}, // S_IFOG4
255 {SPR_IFOG,32772,6,NULL,S_NULL,0,0}, // S_IFOG5
256 {SPR_PLAY,0,-1,NULL,S_NULL,0,0}, // S_PLAY
257 {SPR_PLAY,0,4,NULL,S_PLAY_RUN2,0,0}, // S_PLAY_RUN1
258 {SPR_PLAY,1,4,NULL,S_PLAY_RUN3,0,0}, // S_PLAY_RUN2
259 {SPR_PLAY,2,4,NULL,S_PLAY_RUN4,0,0}, // S_PLAY_RUN3
260 {SPR_PLAY,3,4,NULL,S_PLAY_RUN1,0,0}, // S_PLAY_RUN4
261 {SPR_PLAY,4,12,NULL,S_PLAY,0,0}, // S_PLAY_ATK1
262 {SPR_PLAY,32773,6,NULL,S_PLAY_ATK1,0,0}, // S_PLAY_ATK2
263 {SPR_PLAY,6,4,NULL,S_PLAY_PAIN2,0,0}, // S_PLAY_PAIN
264 {SPR_PLAY,6,4,A_Pain,S_PLAY,0,0}, // S_PLAY_PAIN2
265 {SPR_PLAY,7,10,NULL,S_PLAY_DIE2,0,0}, // S_PLAY_DIE1
266 {SPR_PLAY,8,10,A_PlayerScream,S_PLAY_DIE3,0,0}, // S_PLAY_DIE2
267 {SPR_PLAY,9,10,A_Fall,S_PLAY_DIE4,0,0}, // S_PLAY_DIE3
268 {SPR_PLAY,10,10,NULL,S_PLAY_DIE5,0,0}, // S_PLAY_DIE4
269 {SPR_PLAY,11,10,NULL,S_PLAY_DIE6,0,0}, // S_PLAY_DIE5
270 {SPR_PLAY,12,10,NULL,S_PLAY_DIE7,0,0}, // S_PLAY_DIE6
271 {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_PLAY_DIE7
272 {SPR_PLAY,14,5,NULL,S_PLAY_XDIE2,0,0}, // S_PLAY_XDIE1
273 {SPR_PLAY,15,5,A_XScream,S_PLAY_XDIE3,0,0}, // S_PLAY_XDIE2
274 {SPR_PLAY,16,5,A_Fall,S_PLAY_XDIE4,0,0}, // S_PLAY_XDIE3
275 {SPR_PLAY,17,5,NULL,S_PLAY_XDIE5,0,0}, // S_PLAY_XDIE4
276 {SPR_PLAY,18,5,NULL,S_PLAY_XDIE6,0,0}, // S_PLAY_XDIE5
277 {SPR_PLAY,19,5,NULL,S_PLAY_XDIE7,0,0}, // S_PLAY_XDIE6
278 {SPR_PLAY,20,5,NULL,S_PLAY_XDIE8,0,0}, // S_PLAY_XDIE7
279 {SPR_PLAY,21,5,NULL,S_PLAY_XDIE9,0,0}, // S_PLAY_XDIE8
280 {SPR_PLAY,22,-1,NULL,S_NULL,0,0}, // S_PLAY_XDIE9
281 {SPR_POSS,0,10,A_Look,S_POSS_STND2,0,0}, // S_POSS_STND
282 {SPR_POSS,1,10,A_Look,S_POSS_STND,0,0}, // S_POSS_STND2
283 {SPR_POSS,0,4,A_Chase,S_POSS_RUN2,0,0}, // S_POSS_RUN1
284 {SPR_POSS,0,4,A_Chase,S_POSS_RUN3,0,0}, // S_POSS_RUN2
285 {SPR_POSS,1,4,A_Chase,S_POSS_RUN4,0,0}, // S_POSS_RUN3
286 {SPR_POSS,1,4,A_Chase,S_POSS_RUN5,0,0}, // S_POSS_RUN4
287 {SPR_POSS,2,4,A_Chase,S_POSS_RUN6,0,0}, // S_POSS_RUN5
288 {SPR_POSS,2,4,A_Chase,S_POSS_RUN7,0,0}, // S_POSS_RUN6
289 {SPR_POSS,3,4,A_Chase,S_POSS_RUN8,0,0}, // S_POSS_RUN7
290 {SPR_POSS,3,4,A_Chase,S_POSS_RUN1,0,0}, // S_POSS_RUN8
291 {SPR_POSS,4,10,A_FaceTarget,S_POSS_ATK2,0,0}, // S_POSS_ATK1
292 {SPR_POSS,5,8,A_PosAttack,S_POSS_ATK3,0,0}, // S_POSS_ATK2
293 {SPR_POSS,4,8,NULL,S_POSS_RUN1,0,0}, // S_POSS_ATK3
294 {SPR_POSS,6,3,NULL,S_POSS_PAIN2,0,0}, // S_POSS_PAIN
295 {SPR_POSS,6,3,A_Pain,S_POSS_RUN1,0,0}, // S_POSS_PAIN2
296 {SPR_POSS,7,5,NULL,S_POSS_DIE2,0,0}, // S_POSS_DIE1
297 {SPR_POSS,8,5,A_Scream,S_POSS_DIE3,0,0}, // S_POSS_DIE2
298 {SPR_POSS,9,5,A_Fall,S_POSS_DIE4,0,0}, // S_POSS_DIE3
299 {SPR_POSS,10,5,NULL,S_POSS_DIE5,0,0}, // S_POSS_DIE4
300 {SPR_POSS,11,-1,NULL,S_NULL,0,0}, // S_POSS_DIE5
301 {SPR_POSS,12,5,NULL,S_POSS_XDIE2,0,0}, // S_POSS_XDIE1
302 {SPR_POSS,13,5,A_XScream,S_POSS_XDIE3,0,0}, // S_POSS_XDIE2
303 {SPR_POSS,14,5,A_Fall,S_POSS_XDIE4,0,0}, // S_POSS_XDIE3
304 {SPR_POSS,15,5,NULL,S_POSS_XDIE5,0,0}, // S_POSS_XDIE4
305 {SPR_POSS,16,5,NULL,S_POSS_XDIE6,0,0}, // S_POSS_XDIE5
306 {SPR_POSS,17,5,NULL,S_POSS_XDIE7,0,0}, // S_POSS_XDIE6
307 {SPR_POSS,18,5,NULL,S_POSS_XDIE8,0,0}, // S_POSS_XDIE7
308 {SPR_POSS,19,5,NULL,S_POSS_XDIE9,0,0}, // S_POSS_XDIE8
309 {SPR_POSS,20,-1,NULL,S_NULL,0,0}, // S_POSS_XDIE9
310 {SPR_POSS,10,5,NULL,S_POSS_RAISE2,0,0}, // S_POSS_RAISE1
311 {SPR_POSS,9,5,NULL,S_POSS_RAISE3,0,0}, // S_POSS_RAISE2
312 {SPR_POSS,8,5,NULL,S_POSS_RAISE4,0,0}, // S_POSS_RAISE3
313 {SPR_POSS,7,5,NULL,S_POSS_RUN1,0,0}, // S_POSS_RAISE4
314 {SPR_SPOS,0,10,A_Look,S_SPOS_STND2,0,0}, // S_SPOS_STND
315 {SPR_SPOS,1,10,A_Look,S_SPOS_STND,0,0}, // S_SPOS_STND2
316 {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN2,0,0}, // S_SPOS_RUN1
317 {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN3,0,0}, // S_SPOS_RUN2
318 {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN4,0,0}, // S_SPOS_RUN3
319 {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN5,0,0}, // S_SPOS_RUN4
320 {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN6,0,0}, // S_SPOS_RUN5
321 {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN7,0,0}, // S_SPOS_RUN6
322 {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN8,0,0}, // S_SPOS_RUN7
323 {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN1,0,0}, // S_SPOS_RUN8
324 {SPR_SPOS,4,10,A_FaceTarget,S_SPOS_ATK2,0,0}, // S_SPOS_ATK1
325 {SPR_SPOS,32773,10,A_SPosAttack,S_SPOS_ATK3,0,0}, // S_SPOS_ATK2
326 {SPR_SPOS,4,10,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_ATK3
327 {SPR_SPOS,6,3,NULL,S_SPOS_PAIN2,0,0}, // S_SPOS_PAIN
328 {SPR_SPOS,6,3,A_Pain,S_SPOS_RUN1,0,0}, // S_SPOS_PAIN2
329 {SPR_SPOS,7,5,NULL,S_SPOS_DIE2,0,0}, // S_SPOS_DIE1
330 {SPR_SPOS,8,5,A_Scream,S_SPOS_DIE3,0,0}, // S_SPOS_DIE2
331 {SPR_SPOS,9,5,A_Fall,S_SPOS_DIE4,0,0}, // S_SPOS_DIE3
332 {SPR_SPOS,10,5,NULL,S_SPOS_DIE5,0,0}, // S_SPOS_DIE4
333 {SPR_SPOS,11,-1,NULL,S_NULL,0,0}, // S_SPOS_DIE5
334 {SPR_SPOS,12,5,NULL,S_SPOS_XDIE2,0,0}, // S_SPOS_XDIE1
335 {SPR_SPOS,13,5,A_XScream,S_SPOS_XDIE3,0,0}, // S_SPOS_XDIE2
336 {SPR_SPOS,14,5,A_Fall,S_SPOS_XDIE4,0,0}, // S_SPOS_XDIE3
337 {SPR_SPOS,15,5,NULL,S_SPOS_XDIE5,0,0}, // S_SPOS_XDIE4
338 {SPR_SPOS,16,5,NULL,S_SPOS_XDIE6,0,0}, // S_SPOS_XDIE5
339 {SPR_SPOS,17,5,NULL,S_SPOS_XDIE7,0,0}, // S_SPOS_XDIE6
340 {SPR_SPOS,18,5,NULL,S_SPOS_XDIE8,0,0}, // S_SPOS_XDIE7
341 {SPR_SPOS,19,5,NULL,S_SPOS_XDIE9,0,0}, // S_SPOS_XDIE8
342 {SPR_SPOS,20,-1,NULL,S_NULL,0,0}, // S_SPOS_XDIE9
343 {SPR_SPOS,11,5,NULL,S_SPOS_RAISE2,0,0}, // S_SPOS_RAISE1
344 {SPR_SPOS,10,5,NULL,S_SPOS_RAISE3,0,0}, // S_SPOS_RAISE2
345 {SPR_SPOS,9,5,NULL,S_SPOS_RAISE4,0,0}, // S_SPOS_RAISE3
346 {SPR_SPOS,8,5,NULL,S_SPOS_RAISE5,0,0}, // S_SPOS_RAISE4
347 {SPR_SPOS,7,5,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_RAISE5
348 {SPR_VILE,0,10,A_Look,S_VILE_STND2,0,0}, // S_VILE_STND
349 {SPR_VILE,1,10,A_Look,S_VILE_STND,0,0}, // S_VILE_STND2
350 {SPR_VILE,0,2,A_VileChase,S_VILE_RUN2,0,0}, // S_VILE_RUN1
351 {SPR_VILE,0,2,A_VileChase,S_VILE_RUN3,0,0}, // S_VILE_RUN2
352 {SPR_VILE,1,2,A_VileChase,S_VILE_RUN4,0,0}, // S_VILE_RUN3
353 {SPR_VILE,1,2,A_VileChase,S_VILE_RUN5,0,0}, // S_VILE_RUN4
354 {SPR_VILE,2,2,A_VileChase,S_VILE_RUN6,0,0}, // S_VILE_RUN5
355 {SPR_VILE,2,2,A_VileChase,S_VILE_RUN7,0,0}, // S_VILE_RUN6
356 {SPR_VILE,3,2,A_VileChase,S_VILE_RUN8,0,0}, // S_VILE_RUN7
357 {SPR_VILE,3,2,A_VileChase,S_VILE_RUN9,0,0}, // S_VILE_RUN8
358 {SPR_VILE,4,2,A_VileChase,S_VILE_RUN10,0,0}, // S_VILE_RUN9
359 {SPR_VILE,4,2,A_VileChase,S_VILE_RUN11,0,0}, // S_VILE_RUN10
360 {SPR_VILE,5,2,A_VileChase,S_VILE_RUN12,0,0}, // S_VILE_RUN11
361 {SPR_VILE,5,2,A_VileChase,S_VILE_RUN1,0,0}, // S_VILE_RUN12
362 {SPR_VILE,32774,0,A_VileStart,S_VILE_ATK2,0,0}, // S_VILE_ATK1
363 {SPR_VILE,32774,10,A_FaceTarget,S_VILE_ATK3,0,0}, // S_VILE_ATK2
364 {SPR_VILE,32775,8,A_VileTarget,S_VILE_ATK4,0,0}, // S_VILE_ATK3
365 {SPR_VILE,32776,8,A_FaceTarget,S_VILE_ATK5,0,0}, // S_VILE_ATK4
366 {SPR_VILE,32777,8,A_FaceTarget,S_VILE_ATK6,0,0}, // S_VILE_ATK5
367 {SPR_VILE,32778,8,A_FaceTarget,S_VILE_ATK7,0,0}, // S_VILE_ATK6
368 {SPR_VILE,32779,8,A_FaceTarget,S_VILE_ATK8,0,0}, // S_VILE_ATK7
369 {SPR_VILE,32780,8,A_FaceTarget,S_VILE_ATK9,0,0}, // S_VILE_ATK8
370 {SPR_VILE,32781,8,A_FaceTarget,S_VILE_ATK10,0,0}, // S_VILE_ATK9
371 {SPR_VILE,32782,8,A_VileAttack,S_VILE_ATK11,0,0}, // S_VILE_ATK10
372 {SPR_VILE,32783,20,NULL,S_VILE_RUN1,0,0}, // S_VILE_ATK11
373 {SPR_VILE,32794,10,NULL,S_VILE_HEAL2,0,0}, // S_VILE_HEAL1
374 {SPR_VILE,32795,10,NULL,S_VILE_HEAL3,0,0}, // S_VILE_HEAL2
375 {SPR_VILE,32796,10,NULL,S_VILE_RUN1,0,0}, // S_VILE_HEAL3
376 {SPR_VILE,16,5,NULL,S_VILE_PAIN2,0,0}, // S_VILE_PAIN
377 {SPR_VILE,16,5,A_Pain,S_VILE_RUN1,0,0}, // S_VILE_PAIN2
378 {SPR_VILE,16,7,NULL,S_VILE_DIE2,0,0}, // S_VILE_DIE1
379 {SPR_VILE,17,7,A_Scream,S_VILE_DIE3,0,0}, // S_VILE_DIE2
380 {SPR_VILE,18,7,A_Fall,S_VILE_DIE4,0,0}, // S_VILE_DIE3
381 {SPR_VILE,19,7,NULL,S_VILE_DIE5,0,0}, // S_VILE_DIE4
382 {SPR_VILE,20,7,NULL,S_VILE_DIE6,0,0}, // S_VILE_DIE5
383 {SPR_VILE,21,7,NULL,S_VILE_DIE7,0,0}, // S_VILE_DIE6
384 {SPR_VILE,22,7,NULL,S_VILE_DIE8,0,0}, // S_VILE_DIE7
385 {SPR_VILE,23,5,NULL,S_VILE_DIE9,0,0}, // S_VILE_DIE8
386 {SPR_VILE,24,5,NULL,S_VILE_DIE10,0,0}, // S_VILE_DIE9
387 {SPR_VILE,25,-1,NULL,S_NULL,0,0}, // S_VILE_DIE10
388 {SPR_FIRE,32768,2,A_StartFire,S_FIRE2,0,0}, // S_FIRE1
389 {SPR_FIRE,32769,2,A_Fire,S_FIRE3,0,0}, // S_FIRE2
390 {SPR_FIRE,32768,2,A_Fire,S_FIRE4,0,0}, // S_FIRE3
391 {SPR_FIRE,32769,2,A_Fire,S_FIRE5,0,0}, // S_FIRE4
392 {SPR_FIRE,32770,2,A_FireCrackle,S_FIRE6,0,0}, // S_FIRE5
393 {SPR_FIRE,32769,2,A_Fire,S_FIRE7,0,0}, // S_FIRE6
394 {SPR_FIRE,32770,2,A_Fire,S_FIRE8,0,0}, // S_FIRE7
395 {SPR_FIRE,32769,2,A_Fire,S_FIRE9,0,0}, // S_FIRE8
396 {SPR_FIRE,32770,2,A_Fire,S_FIRE10,0,0}, // S_FIRE9
397 {SPR_FIRE,32771,2,A_Fire,S_FIRE11,0,0}, // S_FIRE10
398 {SPR_FIRE,32770,2,A_Fire,S_FIRE12,0,0}, // S_FIRE11
399 {SPR_FIRE,32771,2,A_Fire,S_FIRE13,0,0}, // S_FIRE12
400 {SPR_FIRE,32770,2,A_Fire,S_FIRE14,0,0}, // S_FIRE13
401 {SPR_FIRE,32771,2,A_Fire,S_FIRE15,0,0}, // S_FIRE14
402 {SPR_FIRE,32772,2,A_Fire,S_FIRE16,0,0}, // S_FIRE15
403 {SPR_FIRE,32771,2,A_Fire,S_FIRE17,0,0}, // S_FIRE16
404 {SPR_FIRE,32772,2,A_Fire,S_FIRE18,0,0}, // S_FIRE17
405 {SPR_FIRE,32771,2,A_Fire,S_FIRE19,0,0}, // S_FIRE18
406 {SPR_FIRE,32772,2,A_FireCrackle,S_FIRE20,0,0}, // S_FIRE19
407 {SPR_FIRE,32773,2,A_Fire,S_FIRE21,0,0}, // S_FIRE20
408 {SPR_FIRE,32772,2,A_Fire,S_FIRE22,0,0}, // S_FIRE21
409 {SPR_FIRE,32773,2,A_Fire,S_FIRE23,0,0}, // S_FIRE22
410 {SPR_FIRE,32772,2,A_Fire,S_FIRE24,0,0}, // S_FIRE23
411 {SPR_FIRE,32773,2,A_Fire,S_FIRE25,0,0}, // S_FIRE24
412 {SPR_FIRE,32774,2,A_Fire,S_FIRE26,0,0}, // S_FIRE25
413 {SPR_FIRE,32775,2,A_Fire,S_FIRE27,0,0}, // S_FIRE26
414 {SPR_FIRE,32774,2,A_Fire,S_FIRE28,0,0}, // S_FIRE27
415 {SPR_FIRE,32775,2,A_Fire,S_FIRE29,0,0}, // S_FIRE28
416 {SPR_FIRE,32774,2,A_Fire,S_FIRE30,0,0}, // S_FIRE29
417 {SPR_FIRE,32775,2,A_Fire,S_NULL,0,0}, // S_FIRE30
418 {SPR_PUFF,1,4,NULL,S_SMOKE2,0,0}, // S_SMOKE1
419 {SPR_PUFF,2,4,NULL,S_SMOKE3,0,0}, // S_SMOKE2
420 {SPR_PUFF,1,4,NULL,S_SMOKE4,0,0}, // S_SMOKE3
421 {SPR_PUFF,2,4,NULL,S_SMOKE5,0,0}, // S_SMOKE4
422 {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_SMOKE5
423 {SPR_FATB,32768,2,A_Tracer,S_TRACER2,0,0}, // S_TRACER
424 {SPR_FATB,32769,2,A_Tracer,S_TRACER,0,0}, // S_TRACER2
425 {SPR_FBXP,32768,8,NULL,S_TRACEEXP2,0,0}, // S_TRACEEXP1
426 {SPR_FBXP,32769,6,NULL,S_TRACEEXP3,0,0}, // S_TRACEEXP2
427 {SPR_FBXP,32770,4,NULL,S_NULL,0,0}, // S_TRACEEXP3
428 {SPR_SKEL,0,10,A_Look,S_SKEL_STND2,0,0}, // S_SKEL_STND
429 {SPR_SKEL,1,10,A_Look,S_SKEL_STND,0,0}, // S_SKEL_STND2
430 {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN2,0,0}, // S_SKEL_RUN1
431 {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN3,0,0}, // S_SKEL_RUN2
432 {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN4,0,0}, // S_SKEL_RUN3
433 {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN5,0,0}, // S_SKEL_RUN4
434 {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN6,0,0}, // S_SKEL_RUN5
435 {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN7,0,0}, // S_SKEL_RUN6
436 {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN8,0,0}, // S_SKEL_RUN7
437 {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN9,0,0}, // S_SKEL_RUN8
438 {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN10,0,0}, // S_SKEL_RUN9
439 {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN11,0,0}, // S_SKEL_RUN10
440 {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN12,0,0}, // S_SKEL_RUN11
441 {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN1,0,0}, // S_SKEL_RUN12
442 {SPR_SKEL,6,0,A_FaceTarget,S_SKEL_FIST2,0,0}, // S_SKEL_FIST1
443 {SPR_SKEL,6,6,A_SkelWhoosh,S_SKEL_FIST3,0,0}, // S_SKEL_FIST2
444 {SPR_SKEL,7,6,A_FaceTarget,S_SKEL_FIST4,0,0}, // S_SKEL_FIST3
445 {SPR_SKEL,8,6,A_SkelFist,S_SKEL_RUN1,0,0}, // S_SKEL_FIST4
446 {SPR_SKEL,32777,0,A_FaceTarget,S_SKEL_MISS2,0,0}, // S_SKEL_MISS1
447 {SPR_SKEL,32777,10,A_FaceTarget,S_SKEL_MISS3,0,0}, // S_SKEL_MISS2
448 {SPR_SKEL,10,10,A_SkelMissile,S_SKEL_MISS4,0,0}, // S_SKEL_MISS3
449 {SPR_SKEL,10,10,A_FaceTarget,S_SKEL_RUN1,0,0}, // S_SKEL_MISS4
450 {SPR_SKEL,11,5,NULL,S_SKEL_PAIN2,0,0}, // S_SKEL_PAIN
451 {SPR_SKEL,11,5,A_Pain,S_SKEL_RUN1,0,0}, // S_SKEL_PAIN2
452 {SPR_SKEL,11,7,NULL,S_SKEL_DIE2,0,0}, // S_SKEL_DIE1
453 {SPR_SKEL,12,7,NULL,S_SKEL_DIE3,0,0}, // S_SKEL_DIE2
454 {SPR_SKEL,13,7,A_Scream,S_SKEL_DIE4,0,0}, // S_SKEL_DIE3
455 {SPR_SKEL,14,7,A_Fall,S_SKEL_DIE5,0,0}, // S_SKEL_DIE4
456 {SPR_SKEL,15,7,NULL,S_SKEL_DIE6,0,0}, // S_SKEL_DIE5
457 {SPR_SKEL,16,-1,NULL,S_NULL,0,0}, // S_SKEL_DIE6
458 {SPR_SKEL,16,5,NULL,S_SKEL_RAISE2,0,0}, // S_SKEL_RAISE1
459 {SPR_SKEL,15,5,NULL,S_SKEL_RAISE3,0,0}, // S_SKEL_RAISE2
460 {SPR_SKEL,14,5,NULL,S_SKEL_RAISE4,0,0}, // S_SKEL_RAISE3
461 {SPR_SKEL,13,5,NULL,S_SKEL_RAISE5,0,0}, // S_SKEL_RAISE4
462 {SPR_SKEL,12,5,NULL,S_SKEL_RAISE6,0,0}, // S_SKEL_RAISE5
463 {SPR_SKEL,11,5,NULL,S_SKEL_RUN1,0,0}, // S_SKEL_RAISE6
464 {SPR_MANF,32768,4,NULL,S_FATSHOT2,0,0}, // S_FATSHOT1
465 {SPR_MANF,32769,4,NULL,S_FATSHOT1,0,0}, // S_FATSHOT2
466 {SPR_MISL,32769,8,NULL,S_FATSHOTX2,0,0}, // S_FATSHOTX1
467 {SPR_MISL,32770,6,NULL,S_FATSHOTX3,0,0}, // S_FATSHOTX2
468 {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_FATSHOTX3
469 {SPR_FATT,0,15,A_Look,S_FATT_STND2,0,0}, // S_FATT_STND
470 {SPR_FATT,1,15,A_Look,S_FATT_STND,0,0}, // S_FATT_STND2
471 {SPR_FATT,0,4,A_Chase,S_FATT_RUN2,0,0}, // S_FATT_RUN1
472 {SPR_FATT,0,4,A_Chase,S_FATT_RUN3,0,0}, // S_FATT_RUN2
473 {SPR_FATT,1,4,A_Chase,S_FATT_RUN4,0,0}, // S_FATT_RUN3
474 {SPR_FATT,1,4,A_Chase,S_FATT_RUN5,0,0}, // S_FATT_RUN4
475 {SPR_FATT,2,4,A_Chase,S_FATT_RUN6,0,0}, // S_FATT_RUN5
476 {SPR_FATT,2,4,A_Chase,S_FATT_RUN7,0,0}, // S_FATT_RUN6
477 {SPR_FATT,3,4,A_Chase,S_FATT_RUN8,0,0}, // S_FATT_RUN7
478 {SPR_FATT,3,4,A_Chase,S_FATT_RUN9,0,0}, // S_FATT_RUN8
479 {SPR_FATT,4,4,A_Chase,S_FATT_RUN10,0,0}, // S_FATT_RUN9
480 {SPR_FATT,4,4,A_Chase,S_FATT_RUN11,0,0}, // S_FATT_RUN10
481 {SPR_FATT,5,4,A_Chase,S_FATT_RUN12,0,0}, // S_FATT_RUN11
482 {SPR_FATT,5,4,A_Chase,S_FATT_RUN1,0,0}, // S_FATT_RUN12
483 {SPR_FATT,6,20,A_FatRaise,S_FATT_ATK2,0,0}, // S_FATT_ATK1
484 {SPR_FATT,32775,10,A_FatAttack1,S_FATT_ATK3,0,0}, // S_FATT_ATK2
485 {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK4,0,0}, // S_FATT_ATK3
486 {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK5,0,0}, // S_FATT_ATK4
487 {SPR_FATT,32775,10,A_FatAttack2,S_FATT_ATK6,0,0}, // S_FATT_ATK5
488 {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK7,0,0}, // S_FATT_ATK6
489 {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK8,0,0}, // S_FATT_ATK7
490 {SPR_FATT,32775,10,A_FatAttack3,S_FATT_ATK9,0,0}, // S_FATT_ATK8
491 {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK10,0,0}, // S_FATT_ATK9
492 {SPR_FATT,6,5,A_FaceTarget,S_FATT_RUN1,0,0}, // S_FATT_ATK10
493 {SPR_FATT,9,3,NULL,S_FATT_PAIN2,0,0}, // S_FATT_PAIN
494 {SPR_FATT,9,3,A_Pain,S_FATT_RUN1,0,0}, // S_FATT_PAIN2
495 {SPR_FATT,10,6,NULL,S_FATT_DIE2,0,0}, // S_FATT_DIE1
496 {SPR_FATT,11,6,A_Scream,S_FATT_DIE3,0,0}, // S_FATT_DIE2
497 {SPR_FATT,12,6,A_Fall,S_FATT_DIE4,0,0}, // S_FATT_DIE3
498 {SPR_FATT,13,6,NULL,S_FATT_DIE5,0,0}, // S_FATT_DIE4
499 {SPR_FATT,14,6,NULL,S_FATT_DIE6,0,0}, // S_FATT_DIE5
500 {SPR_FATT,15,6,NULL,S_FATT_DIE7,0,0}, // S_FATT_DIE6
501 {SPR_FATT,16,6,NULL,S_FATT_DIE8,0,0}, // S_FATT_DIE7
502 {SPR_FATT,17,6,NULL,S_FATT_DIE9,0,0}, // S_FATT_DIE8
503 {SPR_FATT,18,6,NULL,S_FATT_DIE10,0,0}, // S_FATT_DIE9
504 {SPR_FATT,19,-1,A_BossDeath,S_NULL,0,0}, // S_FATT_DIE10
505 {SPR_FATT,17,5,NULL,S_FATT_RAISE2,0,0}, // S_FATT_RAISE1
506 {SPR_FATT,16,5,NULL,S_FATT_RAISE3,0,0}, // S_FATT_RAISE2
507 {SPR_FATT,15,5,NULL,S_FATT_RAISE4,0,0}, // S_FATT_RAISE3
508 {SPR_FATT,14,5,NULL,S_FATT_RAISE5,0,0}, // S_FATT_RAISE4
509 {SPR_FATT,13,5,NULL,S_FATT_RAISE6,0,0}, // S_FATT_RAISE5
510 {SPR_FATT,12,5,NULL,S_FATT_RAISE7,0,0}, // S_FATT_RAISE6
511 {SPR_FATT,11,5,NULL,S_FATT_RAISE8,0,0}, // S_FATT_RAISE7
512 {SPR_FATT,10,5,NULL,S_FATT_RUN1,0,0}, // S_FATT_RAISE8
513 {SPR_CPOS,0,10,A_Look,S_CPOS_STND2,0,0}, // S_CPOS_STND
514 {SPR_CPOS,1,10,A_Look,S_CPOS_STND,0,0}, // S_CPOS_STND2
515 {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN2,0,0}, // S_CPOS_RUN1
516 {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN3,0,0}, // S_CPOS_RUN2
517 {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN4,0,0}, // S_CPOS_RUN3
518 {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN5,0,0}, // S_CPOS_RUN4
519 {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN6,0,0}, // S_CPOS_RUN5
520 {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN7,0,0}, // S_CPOS_RUN6
521 {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN8,0,0}, // S_CPOS_RUN7
522 {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN1,0,0}, // S_CPOS_RUN8
523 {SPR_CPOS,4,10,A_FaceTarget,S_CPOS_ATK2,0,0}, // S_CPOS_ATK1
524 {SPR_CPOS,32773,4,A_CPosAttack,S_CPOS_ATK3,0,0}, // S_CPOS_ATK2
525 {SPR_CPOS,32772,4,A_CPosAttack,S_CPOS_ATK4,0,0}, // S_CPOS_ATK3
526 {SPR_CPOS,5,1,A_CPosRefire,S_CPOS_ATK2,0,0}, // S_CPOS_ATK4
527 {SPR_CPOS,6,3,NULL,S_CPOS_PAIN2,0,0}, // S_CPOS_PAIN
528 {SPR_CPOS,6,3,A_Pain,S_CPOS_RUN1,0,0}, // S_CPOS_PAIN2
529 {SPR_CPOS,7,5,NULL,S_CPOS_DIE2,0,0}, // S_CPOS_DIE1
530 {SPR_CPOS,8,5,A_Scream,S_CPOS_DIE3,0,0}, // S_CPOS_DIE2
531 {SPR_CPOS,9,5,A_Fall,S_CPOS_DIE4,0,0}, // S_CPOS_DIE3
532 {SPR_CPOS,10,5,NULL,S_CPOS_DIE5,0,0}, // S_CPOS_DIE4
533 {SPR_CPOS,11,5,NULL,S_CPOS_DIE6,0,0}, // S_CPOS_DIE5
534 {SPR_CPOS,12,5,NULL,S_CPOS_DIE7,0,0}, // S_CPOS_DIE6
535 {SPR_CPOS,13,-1,NULL,S_NULL,0,0}, // S_CPOS_DIE7
536 {SPR_CPOS,14,5,NULL,S_CPOS_XDIE2,0,0}, // S_CPOS_XDIE1
537 {SPR_CPOS,15,5,A_XScream,S_CPOS_XDIE3,0,0}, // S_CPOS_XDIE2
538 {SPR_CPOS,16,5,A_Fall,S_CPOS_XDIE4,0,0}, // S_CPOS_XDIE3
539 {SPR_CPOS,17,5,NULL,S_CPOS_XDIE5,0,0}, // S_CPOS_XDIE4
540 {SPR_CPOS,18,5,NULL,S_CPOS_XDIE6,0,0}, // S_CPOS_XDIE5
541 {SPR_CPOS,19,-1,NULL,S_NULL,0,0}, // S_CPOS_XDIE6
542 {SPR_CPOS,13,5,NULL,S_CPOS_RAISE2,0,0}, // S_CPOS_RAISE1
543 {SPR_CPOS,12,5,NULL,S_CPOS_RAISE3,0,0}, // S_CPOS_RAISE2
544 {SPR_CPOS,11,5,NULL,S_CPOS_RAISE4,0,0}, // S_CPOS_RAISE3
545 {SPR_CPOS,10,5,NULL,S_CPOS_RAISE5,0,0}, // S_CPOS_RAISE4
546 {SPR_CPOS,9,5,NULL,S_CPOS_RAISE6,0,0}, // S_CPOS_RAISE5
547 {SPR_CPOS,8,5,NULL,S_CPOS_RAISE7,0,0}, // S_CPOS_RAISE6
548 {SPR_CPOS,7,5,NULL,S_CPOS_RUN1,0,0}, // S_CPOS_RAISE7
549 {SPR_TROO,0,10,A_Look,S_TROO_STND2,0,0}, // S_TROO_STND
550 {SPR_TROO,1,10,A_Look,S_TROO_STND,0,0}, // S_TROO_STND2
551 {SPR_TROO,0,3,A_Chase,S_TROO_RUN2,0,0}, // S_TROO_RUN1
552 {SPR_TROO,0,3,A_Chase,S_TROO_RUN3,0,0}, // S_TROO_RUN2
553 {SPR_TROO,1,3,A_Chase,S_TROO_RUN4,0,0}, // S_TROO_RUN3
554 {SPR_TROO,1,3,A_Chase,S_TROO_RUN5,0,0}, // S_TROO_RUN4
555 {SPR_TROO,2,3,A_Chase,S_TROO_RUN6,0,0}, // S_TROO_RUN5
556 {SPR_TROO,2,3,A_Chase,S_TROO_RUN7,0,0}, // S_TROO_RUN6
557 {SPR_TROO,3,3,A_Chase,S_TROO_RUN8,0,0}, // S_TROO_RUN7
558 {SPR_TROO,3,3,A_Chase,S_TROO_RUN1,0,0}, // S_TROO_RUN8
559 {SPR_TROO,4,8,A_FaceTarget,S_TROO_ATK2,0,0}, // S_TROO_ATK1
560 {SPR_TROO,5,8,A_FaceTarget,S_TROO_ATK3,0,0}, // S_TROO_ATK2
561 {SPR_TROO,6,6,A_TroopAttack,S_TROO_RUN1,0,0}, // S_TROO_ATK3
562 {SPR_TROO,7,2,NULL,S_TROO_PAIN2,0,0}, // S_TROO_PAIN
563 {SPR_TROO,7,2,A_Pain,S_TROO_RUN1,0,0}, // S_TROO_PAIN2
564 {SPR_TROO,8,8,NULL,S_TROO_DIE2,0,0}, // S_TROO_DIE1
565 {SPR_TROO,9,8,A_Scream,S_TROO_DIE3,0,0}, // S_TROO_DIE2
566 {SPR_TROO,10,6,NULL,S_TROO_DIE4,0,0}, // S_TROO_DIE3
567 {SPR_TROO,11,6,A_Fall,S_TROO_DIE5,0,0}, // S_TROO_DIE4
568 {SPR_TROO,12,-1,NULL,S_NULL,0,0}, // S_TROO_DIE5
569 {SPR_TROO,13,5,NULL,S_TROO_XDIE2,0,0}, // S_TROO_XDIE1
570 {SPR_TROO,14,5,A_XScream,S_TROO_XDIE3,0,0}, // S_TROO_XDIE2
571 {SPR_TROO,15,5,NULL,S_TROO_XDIE4,0,0}, // S_TROO_XDIE3
572 {SPR_TROO,16,5,A_Fall,S_TROO_XDIE5,0,0}, // S_TROO_XDIE4
573 {SPR_TROO,17,5,NULL,S_TROO_XDIE6,0,0}, // S_TROO_XDIE5
574 {SPR_TROO,18,5,NULL,S_TROO_XDIE7,0,0}, // S_TROO_XDIE6
575 {SPR_TROO,19,5,NULL,S_TROO_XDIE8,0,0}, // S_TROO_XDIE7
576 {SPR_TROO,20,-1,NULL,S_NULL,0,0}, // S_TROO_XDIE8
577 {SPR_TROO,12,8,NULL,S_TROO_RAISE2,0,0}, // S_TROO_RAISE1
578 {SPR_TROO,11,8,NULL,S_TROO_RAISE3,0,0}, // S_TROO_RAISE2
579 {SPR_TROO,10,6,NULL,S_TROO_RAISE4,0,0}, // S_TROO_RAISE3
580 {SPR_TROO,9,6,NULL,S_TROO_RAISE5,0,0}, // S_TROO_RAISE4
581 {SPR_TROO,8,6,NULL,S_TROO_RUN1,0,0}, // S_TROO_RAISE5
582 {SPR_SARG,0,10,A_Look,S_SARG_STND2,0,0}, // S_SARG_STND
583 {SPR_SARG,1,10,A_Look,S_SARG_STND,0,0}, // S_SARG_STND2
584 {SPR_SARG,0,2,A_Chase,S_SARG_RUN2,0,0}, // S_SARG_RUN1
585 {SPR_SARG,0,2,A_Chase,S_SARG_RUN3,0,0}, // S_SARG_RUN2
586 {SPR_SARG,1,2,A_Chase,S_SARG_RUN4,0,0}, // S_SARG_RUN3
587 {SPR_SARG,1,2,A_Chase,S_SARG_RUN5,0,0}, // S_SARG_RUN4
588 {SPR_SARG,2,2,A_Chase,S_SARG_RUN6,0,0}, // S_SARG_RUN5
589 {SPR_SARG,2,2,A_Chase,S_SARG_RUN7,0,0}, // S_SARG_RUN6
590 {SPR_SARG,3,2,A_Chase,S_SARG_RUN8,0,0}, // S_SARG_RUN7
591 {SPR_SARG,3,2,A_Chase,S_SARG_RUN1,0,0}, // S_SARG_RUN8
592 {SPR_SARG,4,8,A_FaceTarget,S_SARG_ATK2,0,0}, // S_SARG_ATK1
593 {SPR_SARG,5,8,A_FaceTarget,S_SARG_ATK3,0,0}, // S_SARG_ATK2
594 {SPR_SARG,6,8,A_SargAttack,S_SARG_RUN1,0,0}, // S_SARG_ATK3
595 {SPR_SARG,7,2,NULL,S_SARG_PAIN2,0,0}, // S_SARG_PAIN
596 {SPR_SARG,7,2,A_Pain,S_SARG_RUN1,0,0}, // S_SARG_PAIN2
597 {SPR_SARG,8,8,NULL,S_SARG_DIE2,0,0}, // S_SARG_DIE1
598 {SPR_SARG,9,8,A_Scream,S_SARG_DIE3,0,0}, // S_SARG_DIE2
599 {SPR_SARG,10,4,NULL,S_SARG_DIE4,0,0}, // S_SARG_DIE3
600 {SPR_SARG,11,4,A_Fall,S_SARG_DIE5,0,0}, // S_SARG_DIE4
601 {SPR_SARG,12,4,NULL,S_SARG_DIE6,0,0}, // S_SARG_DIE5
602 {SPR_SARG,13,-1,NULL,S_NULL,0,0}, // S_SARG_DIE6
603 {SPR_SARG,13,5,NULL,S_SARG_RAISE2,0,0}, // S_SARG_RAISE1
604 {SPR_SARG,12,5,NULL,S_SARG_RAISE3,0,0}, // S_SARG_RAISE2
605 {SPR_SARG,11,5,NULL,S_SARG_RAISE4,0,0}, // S_SARG_RAISE3
606 {SPR_SARG,10,5,NULL,S_SARG_RAISE5,0,0}, // S_SARG_RAISE4
607 {SPR_SARG,9,5,NULL,S_SARG_RAISE6,0,0}, // S_SARG_RAISE5
608 {SPR_SARG,8,5,NULL,S_SARG_RUN1,0,0}, // S_SARG_RAISE6
609 {SPR_HEAD,0,10,A_Look,S_HEAD_STND,0,0}, // S_HEAD_STND
610 {SPR_HEAD,0,3,A_Chase,S_HEAD_RUN1,0,0}, // S_HEAD_RUN1
611 {SPR_HEAD,1,5,A_FaceTarget,S_HEAD_ATK2,0,0}, // S_HEAD_ATK1
612 {SPR_HEAD,2,5,A_FaceTarget,S_HEAD_ATK3,0,0}, // S_HEAD_ATK2
613 {SPR_HEAD,32771,5,A_HeadAttack,S_HEAD_RUN1,0,0}, // S_HEAD_ATK3
614 {SPR_HEAD,4,3,NULL,S_HEAD_PAIN2,0,0}, // S_HEAD_PAIN
615 {SPR_HEAD,4,3,A_Pain,S_HEAD_PAIN3,0,0}, // S_HEAD_PAIN2
616 {SPR_HEAD,5,6,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_PAIN3
617 {SPR_HEAD,6,8,NULL,S_HEAD_DIE2,0,0}, // S_HEAD_DIE1
618 {SPR_HEAD,7,8,A_Scream,S_HEAD_DIE3,0,0}, // S_HEAD_DIE2
619 {SPR_HEAD,8,8,NULL,S_HEAD_DIE4,0,0}, // S_HEAD_DIE3
620 {SPR_HEAD,9,8,NULL,S_HEAD_DIE5,0,0}, // S_HEAD_DIE4
621 {SPR_HEAD,10,8,A_Fall,S_HEAD_DIE6,0,0}, // S_HEAD_DIE5
622 {SPR_HEAD,11,-1,NULL,S_NULL,0,0}, // S_HEAD_DIE6
623 {SPR_HEAD,11,8,NULL,S_HEAD_RAISE2,0,0}, // S_HEAD_RAISE1
624 {SPR_HEAD,10,8,NULL,S_HEAD_RAISE3,0,0}, // S_HEAD_RAISE2
625 {SPR_HEAD,9,8,NULL,S_HEAD_RAISE4,0,0}, // S_HEAD_RAISE3
626 {SPR_HEAD,8,8,NULL,S_HEAD_RAISE5,0,0}, // S_HEAD_RAISE4
627 {SPR_HEAD,7,8,NULL,S_HEAD_RAISE6,0,0}, // S_HEAD_RAISE5
628 {SPR_HEAD,6,8,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_RAISE6
629 {SPR_BAL7,32768,4,NULL,S_BRBALL2,0,0}, // S_BRBALL1
630 {SPR_BAL7,32769,4,NULL,S_BRBALL1,0,0}, // S_BRBALL2
631 {SPR_BAL7,32770,6,NULL,S_BRBALLX2,0,0}, // S_BRBALLX1
632 {SPR_BAL7,32771,6,NULL,S_BRBALLX3,0,0}, // S_BRBALLX2
633 {SPR_BAL7,32772,6,NULL,S_NULL,0,0}, // S_BRBALLX3
634 {SPR_BOSS,0,10,A_Look,S_BOSS_STND2,0,0}, // S_BOSS_STND
635 {SPR_BOSS,1,10,A_Look,S_BOSS_STND,0,0}, // S_BOSS_STND2
636 {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN2,0,0}, // S_BOSS_RUN1
637 {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN3,0,0}, // S_BOSS_RUN2
638 {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN4,0,0}, // S_BOSS_RUN3
639 {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN5,0,0}, // S_BOSS_RUN4
640 {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN6,0,0}, // S_BOSS_RUN5
641 {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN7,0,0}, // S_BOSS_RUN6
642 {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN8,0,0}, // S_BOSS_RUN7
643 {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN1,0,0}, // S_BOSS_RUN8
644 {SPR_BOSS,4,8,A_FaceTarget,S_BOSS_ATK2,0,0}, // S_BOSS_ATK1
645 {SPR_BOSS,5,8,A_FaceTarget,S_BOSS_ATK3,0,0}, // S_BOSS_ATK2
646 {SPR_BOSS,6,8,A_BruisAttack,S_BOSS_RUN1,0,0}, // S_BOSS_ATK3
647 {SPR_BOSS,7,2,NULL,S_BOSS_PAIN2,0,0}, // S_BOSS_PAIN
648 {SPR_BOSS,7,2,A_Pain,S_BOSS_RUN1,0,0}, // S_BOSS_PAIN2
649 {SPR_BOSS,8,8,NULL,S_BOSS_DIE2,0,0}, // S_BOSS_DIE1
650 {SPR_BOSS,9,8,A_Scream,S_BOSS_DIE3,0,0}, // S_BOSS_DIE2
651 {SPR_BOSS,10,8,NULL,S_BOSS_DIE4,0,0}, // S_BOSS_DIE3
652 {SPR_BOSS,11,8,A_Fall,S_BOSS_DIE5,0,0}, // S_BOSS_DIE4
653 {SPR_BOSS,12,8,NULL,S_BOSS_DIE6,0,0}, // S_BOSS_DIE5
654 {SPR_BOSS,13,8,NULL,S_BOSS_DIE7,0,0}, // S_BOSS_DIE6
655 {SPR_BOSS,14,-1,A_BossDeath,S_NULL,0,0}, // S_BOSS_DIE7
656 {SPR_BOSS,14,8,NULL,S_BOSS_RAISE2,0,0}, // S_BOSS_RAISE1
657 {SPR_BOSS,13,8,NULL,S_BOSS_RAISE3,0,0}, // S_BOSS_RAISE2
658 {SPR_BOSS,12,8,NULL,S_BOSS_RAISE4,0,0}, // S_BOSS_RAISE3
659 {SPR_BOSS,11,8,NULL,S_BOSS_RAISE5,0,0}, // S_BOSS_RAISE4
660 {SPR_BOSS,10,8,NULL,S_BOSS_RAISE6,0,0}, // S_BOSS_RAISE5
661 {SPR_BOSS,9,8,NULL,S_BOSS_RAISE7,0,0}, // S_BOSS_RAISE6
662 {SPR_BOSS,8,8,NULL,S_BOSS_RUN1,0,0}, // S_BOSS_RAISE7
663 {SPR_BOS2,0,10,A_Look,S_BOS2_STND2,0,0}, // S_BOS2_STND
664 {SPR_BOS2,1,10,A_Look,S_BOS2_STND,0,0}, // S_BOS2_STND2
665 {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN2,0,0}, // S_BOS2_RUN1
666 {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN3,0,0}, // S_BOS2_RUN2
667 {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN4,0,0}, // S_BOS2_RUN3
668 {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN5,0,0}, // S_BOS2_RUN4
669 {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN6,0,0}, // S_BOS2_RUN5
670 {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN7,0,0}, // S_BOS2_RUN6
671 {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN8,0,0}, // S_BOS2_RUN7
672 {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN1,0,0}, // S_BOS2_RUN8
673 {SPR_BOS2,4,8,A_FaceTarget,S_BOS2_ATK2,0,0}, // S_BOS2_ATK1
674 {SPR_BOS2,5,8,A_FaceTarget,S_BOS2_ATK3,0,0}, // S_BOS2_ATK2
675 {SPR_BOS2,6,8,A_BruisAttack,S_BOS2_RUN1,0,0}, // S_BOS2_ATK3
676 {SPR_BOS2,7,2,NULL,S_BOS2_PAIN2,0,0}, // S_BOS2_PAIN
677 {SPR_BOS2,7,2,A_Pain,S_BOS2_RUN1,0,0}, // S_BOS2_PAIN2
678 {SPR_BOS2,8,8,NULL,S_BOS2_DIE2,0,0}, // S_BOS2_DIE1
679 {SPR_BOS2,9,8,A_Scream,S_BOS2_DIE3,0,0}, // S_BOS2_DIE2
680 {SPR_BOS2,10,8,NULL,S_BOS2_DIE4,0,0}, // S_BOS2_DIE3
681 {SPR_BOS2,11,8,A_Fall,S_BOS2_DIE5,0,0}, // S_BOS2_DIE4
682 {SPR_BOS2,12,8,NULL,S_BOS2_DIE6,0,0}, // S_BOS2_DIE5
683 {SPR_BOS2,13,8,NULL,S_BOS2_DIE7,0,0}, // S_BOS2_DIE6
684 {SPR_BOS2,14,-1,NULL,S_NULL,0,0}, // S_BOS2_DIE7
685 {SPR_BOS2,14,8,NULL,S_BOS2_RAISE2,0,0}, // S_BOS2_RAISE1
686 {SPR_BOS2,13,8,NULL,S_BOS2_RAISE3,0,0}, // S_BOS2_RAISE2
687 {SPR_BOS2,12,8,NULL,S_BOS2_RAISE4,0,0}, // S_BOS2_RAISE3
688 {SPR_BOS2,11,8,NULL,S_BOS2_RAISE5,0,0}, // S_BOS2_RAISE4
689 {SPR_BOS2,10,8,NULL,S_BOS2_RAISE6,0,0}, // S_BOS2_RAISE5
690 {SPR_BOS2,9,8,NULL,S_BOS2_RAISE7,0,0}, // S_BOS2_RAISE6
691 {SPR_BOS2,8,8,NULL,S_BOS2_RUN1,0,0}, // S_BOS2_RAISE7
692 {SPR_SKUL,32768,10,A_Look,S_SKULL_STND2,0,0}, // S_SKULL_STND
693 {SPR_SKUL,32769,10,A_Look,S_SKULL_STND,0,0}, // S_SKULL_STND2
694 {SPR_SKUL,32768,6,A_Chase,S_SKULL_RUN2,0,0}, // S_SKULL_RUN1
695 {SPR_SKUL,32769,6,A_Chase,S_SKULL_RUN1,0,0}, // S_SKULL_RUN2
696 {SPR_SKUL,32770,10,A_FaceTarget,S_SKULL_ATK2,0,0}, // S_SKULL_ATK1
697 {SPR_SKUL,32771,4,A_SkullAttack,S_SKULL_ATK3,0,0}, // S_SKULL_ATK2
698 {SPR_SKUL,32770,4,NULL,S_SKULL_ATK4,0,0}, // S_SKULL_ATK3
699 {SPR_SKUL,32771,4,NULL,S_SKULL_ATK3,0,0}, // S_SKULL_ATK4
700 {SPR_SKUL,32772,3,NULL,S_SKULL_PAIN2,0,0}, // S_SKULL_PAIN
701 {SPR_SKUL,32772,3,A_Pain,S_SKULL_RUN1,0,0}, // S_SKULL_PAIN2
702 {SPR_SKUL,32773,6,NULL,S_SKULL_DIE2,0,0}, // S_SKULL_DIE1
703 {SPR_SKUL,32774,6,A_Scream,S_SKULL_DIE3,0,0}, // S_SKULL_DIE2
704 {SPR_SKUL,32775,6,NULL,S_SKULL_DIE4,0,0}, // S_SKULL_DIE3
705 {SPR_SKUL,32776,6,A_Fall,S_SKULL_DIE5,0,0}, // S_SKULL_DIE4
706 {SPR_SKUL,9,6,NULL,S_SKULL_DIE6,0,0}, // S_SKULL_DIE5
707 {SPR_SKUL,10,6,NULL,S_NULL,0,0}, // S_SKULL_DIE6
708 {SPR_SPID,0,10,A_Look,S_SPID_STND2,0,0}, // S_SPID_STND
709 {SPR_SPID,1,10,A_Look,S_SPID_STND,0,0}, // S_SPID_STND2
710 {SPR_SPID,0,3,A_Metal,S_SPID_RUN2,0,0}, // S_SPID_RUN1
711 {SPR_SPID,0,3,A_Chase,S_SPID_RUN3,0,0}, // S_SPID_RUN2
712 {SPR_SPID,1,3,A_Chase,S_SPID_RUN4,0,0}, // S_SPID_RUN3
713 {SPR_SPID,1,3,A_Chase,S_SPID_RUN5,0,0}, // S_SPID_RUN4
714 {SPR_SPID,2,3,A_Metal,S_SPID_RUN6,0,0}, // S_SPID_RUN5
715 {SPR_SPID,2,3,A_Chase,S_SPID_RUN7,0,0}, // S_SPID_RUN6
716 {SPR_SPID,3,3,A_Chase,S_SPID_RUN8,0,0}, // S_SPID_RUN7
717 {SPR_SPID,3,3,A_Chase,S_SPID_RUN9,0,0}, // S_SPID_RUN8
718 {SPR_SPID,4,3,A_Metal,S_SPID_RUN10,0,0}, // S_SPID_RUN9
719 {SPR_SPID,4,3,A_Chase,S_SPID_RUN11,0,0}, // S_SPID_RUN10
720 {SPR_SPID,5,3,A_Chase,S_SPID_RUN12,0,0}, // S_SPID_RUN11
721 {SPR_SPID,5,3,A_Chase,S_SPID_RUN1,0,0}, // S_SPID_RUN12
722 {SPR_SPID,32768,20,A_FaceTarget,S_SPID_ATK2,0,0}, // S_SPID_ATK1
723 {SPR_SPID,32774,4,A_SPosAttack,S_SPID_ATK3,0,0}, // S_SPID_ATK2
724 {SPR_SPID,32775,4,A_SPosAttack,S_SPID_ATK4,0,0}, // S_SPID_ATK3
725 {SPR_SPID,32775,1,A_SpidRefire,S_SPID_ATK2,0,0}, // S_SPID_ATK4
726 {SPR_SPID,8,3,NULL,S_SPID_PAIN2,0,0}, // S_SPID_PAIN
727 {SPR_SPID,8,3,A_Pain,S_SPID_RUN1,0,0}, // S_SPID_PAIN2
728 {SPR_SPID,9,20,A_Scream,S_SPID_DIE2,0,0}, // S_SPID_DIE1
729 {SPR_SPID,10,10,A_Fall,S_SPID_DIE3,0,0}, // S_SPID_DIE2
730 {SPR_SPID,11,10,NULL,S_SPID_DIE4,0,0}, // S_SPID_DIE3
731 {SPR_SPID,12,10,NULL,S_SPID_DIE5,0,0}, // S_SPID_DIE4
732 {SPR_SPID,13,10,NULL,S_SPID_DIE6,0,0}, // S_SPID_DIE5
733 {SPR_SPID,14,10,NULL,S_SPID_DIE7,0,0}, // S_SPID_DIE6
734 {SPR_SPID,15,10,NULL,S_SPID_DIE8,0,0}, // S_SPID_DIE7
735 {SPR_SPID,16,10,NULL,S_SPID_DIE9,0,0}, // S_SPID_DIE8
736 {SPR_SPID,17,10,NULL,S_SPID_DIE10,0,0}, // S_SPID_DIE9
737 {SPR_SPID,18,30,NULL,S_SPID_DIE11,0,0}, // S_SPID_DIE10
738 {SPR_SPID,18,-1,A_BossDeath,S_NULL,0,0}, // S_SPID_DIE11
739 {SPR_BSPI,0,10,A_Look,S_BSPI_STND2,0,0}, // S_BSPI_STND
740 {SPR_BSPI,1,10,A_Look,S_BSPI_STND,0,0}, // S_BSPI_STND2
741 {SPR_BSPI,0,20,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_SIGHT
742 {SPR_BSPI,0,3,A_BabyMetal,S_BSPI_RUN2,0,0}, // S_BSPI_RUN1
743 {SPR_BSPI,0,3,A_Chase,S_BSPI_RUN3,0,0}, // S_BSPI_RUN2
744 {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN4,0,0}, // S_BSPI_RUN3
745 {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN5,0,0}, // S_BSPI_RUN4
746 {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN6,0,0}, // S_BSPI_RUN5
747 {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN7,0,0}, // S_BSPI_RUN6
748 {SPR_BSPI,3,3,A_BabyMetal,S_BSPI_RUN8,0,0}, // S_BSPI_RUN7
749 {SPR_BSPI,3,3,A_Chase,S_BSPI_RUN9,0,0}, // S_BSPI_RUN8
750 {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN10,0,0}, // S_BSPI_RUN9
751 {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN11,0,0}, // S_BSPI_RUN10
752 {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN12,0,0}, // S_BSPI_RUN11
753 {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN1,0,0}, // S_BSPI_RUN12
754 {SPR_BSPI,32768,20,A_FaceTarget,S_BSPI_ATK2,0,0}, // S_BSPI_ATK1
755 {SPR_BSPI,32774,4,A_BspiAttack,S_BSPI_ATK3,0,0}, // S_BSPI_ATK2
756 {SPR_BSPI,32775,4,NULL,S_BSPI_ATK4,0,0}, // S_BSPI_ATK3
757 {SPR_BSPI,32775,1,A_SpidRefire,S_BSPI_ATK2,0,0}, // S_BSPI_ATK4
758 {SPR_BSPI,8,3,NULL,S_BSPI_PAIN2,0,0}, // S_BSPI_PAIN
759 {SPR_BSPI,8,3,A_Pain,S_BSPI_RUN1,0,0}, // S_BSPI_PAIN2
760 {SPR_BSPI,9,20,A_Scream,S_BSPI_DIE2,0,0}, // S_BSPI_DIE1
761 {SPR_BSPI,10,7,A_Fall,S_BSPI_DIE3,0,0}, // S_BSPI_DIE2
762 {SPR_BSPI,11,7,NULL,S_BSPI_DIE4,0,0}, // S_BSPI_DIE3
763 {SPR_BSPI,12,7,NULL,S_BSPI_DIE5,0,0}, // S_BSPI_DIE4
764 {SPR_BSPI,13,7,NULL,S_BSPI_DIE6,0,0}, // S_BSPI_DIE5
765 {SPR_BSPI,14,7,NULL,S_BSPI_DIE7,0,0}, // S_BSPI_DIE6
766 {SPR_BSPI,15,-1,A_BossDeath,S_NULL,0,0}, // S_BSPI_DIE7
767 {SPR_BSPI,15,5,NULL,S_BSPI_RAISE2,0,0}, // S_BSPI_RAISE1
768 {SPR_BSPI,14,5,NULL,S_BSPI_RAISE3,0,0}, // S_BSPI_RAISE2
769 {SPR_BSPI,13,5,NULL,S_BSPI_RAISE4,0,0}, // S_BSPI_RAISE3
770 {SPR_BSPI,12,5,NULL,S_BSPI_RAISE5,0,0}, // S_BSPI_RAISE4
771 {SPR_BSPI,11,5,NULL,S_BSPI_RAISE6,0,0}, // S_BSPI_RAISE5
772 {SPR_BSPI,10,5,NULL,S_BSPI_RAISE7,0,0}, // S_BSPI_RAISE6
773 {SPR_BSPI,9,5,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_RAISE7
774 {SPR_APLS,32768,5,NULL,S_ARACH_PLAZ2,0,0}, // S_ARACH_PLAZ
775 {SPR_APLS,32769,5,NULL,S_ARACH_PLAZ,0,0}, // S_ARACH_PLAZ2
776 {SPR_APBX,32768,5,NULL,S_ARACH_PLEX2,0,0}, // S_ARACH_PLEX
777 {SPR_APBX,32769,5,NULL,S_ARACH_PLEX3,0,0}, // S_ARACH_PLEX2
778 {SPR_APBX,32770,5,NULL,S_ARACH_PLEX4,0,0}, // S_ARACH_PLEX3
779 {SPR_APBX,32771,5,NULL,S_ARACH_PLEX5,0,0}, // S_ARACH_PLEX4
780 {SPR_APBX,32772,5,NULL,S_NULL,0,0}, // S_ARACH_PLEX5
781 {SPR_CYBR,0,10,A_Look,S_CYBER_STND2,0,0}, // S_CYBER_STND
782 {SPR_CYBR,1,10,A_Look,S_CYBER_STND,0,0}, // S_CYBER_STND2
783 {SPR_CYBR,0,3,A_Hoof,S_CYBER_RUN2,0,0}, // S_CYBER_RUN1
784 {SPR_CYBR,0,3,A_Chase,S_CYBER_RUN3,0,0}, // S_CYBER_RUN2
785 {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN4,0,0}, // S_CYBER_RUN3
786 {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN5,0,0}, // S_CYBER_RUN4
787 {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN6,0,0}, // S_CYBER_RUN5
788 {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN7,0,0}, // S_CYBER_RUN6
789 {SPR_CYBR,3,3,A_Metal,S_CYBER_RUN8,0,0}, // S_CYBER_RUN7
790 {SPR_CYBR,3,3,A_Chase,S_CYBER_RUN1,0,0}, // S_CYBER_RUN8
791 {SPR_CYBR,4,6,A_FaceTarget,S_CYBER_ATK2,0,0}, // S_CYBER_ATK1
792 {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK3,0,0}, // S_CYBER_ATK2
793 {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK4,0,0}, // S_CYBER_ATK3
794 {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK5,0,0}, // S_CYBER_ATK4
795 {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK6,0,0}, // S_CYBER_ATK5
796 {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_RUN1,0,0}, // S_CYBER_ATK6
797 {SPR_CYBR,6,10,A_Pain,S_CYBER_RUN1,0,0}, // S_CYBER_PAIN
798 {SPR_CYBR,7,10,NULL,S_CYBER_DIE2,0,0}, // S_CYBER_DIE1
799 {SPR_CYBR,8,10,A_Scream,S_CYBER_DIE3,0,0}, // S_CYBER_DIE2
800 {SPR_CYBR,9,10,NULL,S_CYBER_DIE4,0,0}, // S_CYBER_DIE3
801 {SPR_CYBR,10,10,NULL,S_CYBER_DIE5,0,0}, // S_CYBER_DIE4
802 {SPR_CYBR,11,10,NULL,S_CYBER_DIE6,0,0}, // S_CYBER_DIE5
803 {SPR_CYBR,12,10,A_Fall,S_CYBER_DIE7,0,0}, // S_CYBER_DIE6
804 {SPR_CYBR,13,10,NULL,S_CYBER_DIE8,0,0}, // S_CYBER_DIE7
805 {SPR_CYBR,14,10,NULL,S_CYBER_DIE9,0,0}, // S_CYBER_DIE8
806 {SPR_CYBR,15,30,NULL,S_CYBER_DIE10,0,0}, // S_CYBER_DIE9
807 {SPR_CYBR,15,-1,A_BossDeath,S_NULL,0,0}, // S_CYBER_DIE10
808 {SPR_PAIN,0,10,A_Look,S_PAIN_STND,0,0}, // S_PAIN_STND
809 {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN2,0,0}, // S_PAIN_RUN1
810 {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN3,0,0}, // S_PAIN_RUN2
811 {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN4,0,0}, // S_PAIN_RUN3
812 {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN5,0,0}, // S_PAIN_RUN4
813 {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN6,0,0}, // S_PAIN_RUN5
814 {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN1,0,0}, // S_PAIN_RUN6
815 {SPR_PAIN,3,5,A_FaceTarget,S_PAIN_ATK2,0,0}, // S_PAIN_ATK1
816 {SPR_PAIN,4,5,A_FaceTarget,S_PAIN_ATK3,0,0}, // S_PAIN_ATK2
817 {SPR_PAIN,32773,5,A_FaceTarget,S_PAIN_ATK4,0,0}, // S_PAIN_ATK3
818 {SPR_PAIN,32773,0,A_PainAttack,S_PAIN_RUN1,0,0}, // S_PAIN_ATK4
819 {SPR_PAIN,6,6,NULL,S_PAIN_PAIN2,0,0}, // S_PAIN_PAIN
820 {SPR_PAIN,6,6,A_Pain,S_PAIN_RUN1,0,0}, // S_PAIN_PAIN2
821 {SPR_PAIN,32775,8,NULL,S_PAIN_DIE2,0,0}, // S_PAIN_DIE1
822 {SPR_PAIN,32776,8,A_Scream,S_PAIN_DIE3,0,0}, // S_PAIN_DIE2
823 {SPR_PAIN,32777,8,NULL,S_PAIN_DIE4,0,0}, // S_PAIN_DIE3
824 {SPR_PAIN,32778,8,NULL,S_PAIN_DIE5,0,0}, // S_PAIN_DIE4
825 {SPR_PAIN,32779,8,A_PainDie,S_PAIN_DIE6,0,0}, // S_PAIN_DIE5
826 {SPR_PAIN,32780,8,NULL,S_NULL,0,0}, // S_PAIN_DIE6
827 {SPR_PAIN,12,8,NULL,S_PAIN_RAISE2,0,0}, // S_PAIN_RAISE1
828 {SPR_PAIN,11,8,NULL,S_PAIN_RAISE3,0,0}, // S_PAIN_RAISE2
829 {SPR_PAIN,10,8,NULL,S_PAIN_RAISE4,0,0}, // S_PAIN_RAISE3
830 {SPR_PAIN,9,8,NULL,S_PAIN_RAISE5,0,0}, // S_PAIN_RAISE4
831 {SPR_PAIN,8,8,NULL,S_PAIN_RAISE6,0,0}, // S_PAIN_RAISE5
832 {SPR_PAIN,7,8,NULL,S_PAIN_RUN1,0,0}, // S_PAIN_RAISE6
833 {SPR_SSWV,0,10,A_Look,S_SSWV_STND2,0,0}, // S_SSWV_STND
834 {SPR_SSWV,1,10,A_Look,S_SSWV_STND,0,0}, // S_SSWV_STND2
835 {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN2,0,0}, // S_SSWV_RUN1
836 {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN3,0,0}, // S_SSWV_RUN2
837 {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN4,0,0}, // S_SSWV_RUN3
838 {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN5,0,0}, // S_SSWV_RUN4
839 {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN6,0,0}, // S_SSWV_RUN5
840 {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN7,0,0}, // S_SSWV_RUN6
841 {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN8,0,0}, // S_SSWV_RUN7
842 {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN1,0,0}, // S_SSWV_RUN8
843 {SPR_SSWV,4,10,A_FaceTarget,S_SSWV_ATK2,0,0}, // S_SSWV_ATK1
844 {SPR_SSWV,5,10,A_FaceTarget,S_SSWV_ATK3,0,0}, // S_SSWV_ATK2
845 {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK4,0,0}, // S_SSWV_ATK3
846 {SPR_SSWV,5,6,A_FaceTarget,S_SSWV_ATK5,0,0}, // S_SSWV_ATK4
847 {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK6,0,0}, // S_SSWV_ATK5
848 {SPR_SSWV,5,1,A_CPosRefire,S_SSWV_ATK2,0,0}, // S_SSWV_ATK6
849 {SPR_SSWV,7,3,NULL,S_SSWV_PAIN2,0,0}, // S_SSWV_PAIN
850 {SPR_SSWV,7,3,A_Pain,S_SSWV_RUN1,0,0}, // S_SSWV_PAIN2
851 {SPR_SSWV,8,5,NULL,S_SSWV_DIE2,0,0}, // S_SSWV_DIE1
852 {SPR_SSWV,9,5,A_Scream,S_SSWV_DIE3,0,0}, // S_SSWV_DIE2
853 {SPR_SSWV,10,5,A_Fall,S_SSWV_DIE4,0,0}, // S_SSWV_DIE3
854 {SPR_SSWV,11,5,NULL,S_SSWV_DIE5,0,0}, // S_SSWV_DIE4
855 {SPR_SSWV,12,-1,NULL,S_NULL,0,0}, // S_SSWV_DIE5
856 {SPR_SSWV,13,5,NULL,S_SSWV_XDIE2,0,0}, // S_SSWV_XDIE1
857 {SPR_SSWV,14,5,A_XScream,S_SSWV_XDIE3,0,0}, // S_SSWV_XDIE2
858 {SPR_SSWV,15,5,A_Fall,S_SSWV_XDIE4,0,0}, // S_SSWV_XDIE3
859 {SPR_SSWV,16,5,NULL,S_SSWV_XDIE5,0,0}, // S_SSWV_XDIE4
860 {SPR_SSWV,17,5,NULL,S_SSWV_XDIE6,0,0}, // S_SSWV_XDIE5
861 {SPR_SSWV,18,5,NULL,S_SSWV_XDIE7,0,0}, // S_SSWV_XDIE6
862 {SPR_SSWV,19,5,NULL,S_SSWV_XDIE8,0,0}, // S_SSWV_XDIE7
863 {SPR_SSWV,20,5,NULL,S_SSWV_XDIE9,0,0}, // S_SSWV_XDIE8
864 {SPR_SSWV,21,-1,NULL,S_NULL,0,0}, // S_SSWV_XDIE9
865 {SPR_SSWV,12,5,NULL,S_SSWV_RAISE2,0,0}, // S_SSWV_RAISE1
866 {SPR_SSWV,11,5,NULL,S_SSWV_RAISE3,0,0}, // S_SSWV_RAISE2
867 {SPR_SSWV,10,5,NULL,S_SSWV_RAISE4,0,0}, // S_SSWV_RAISE3
868 {SPR_SSWV,9,5,NULL,S_SSWV_RAISE5,0,0}, // S_SSWV_RAISE4
869 {SPR_SSWV,8,5,NULL,S_SSWV_RUN1,0,0}, // S_SSWV_RAISE5
870 {SPR_KEEN,0,-1,NULL,S_KEENSTND,0,0}, // S_KEENSTND
871 {SPR_KEEN,0,6,NULL,S_COMMKEEN2,0,0}, // S_COMMKEEN
872 {SPR_KEEN,1,6,NULL,S_COMMKEEN3,0,0}, // S_COMMKEEN2
873 {SPR_KEEN,2,6,A_Scream,S_COMMKEEN4,0,0}, // S_COMMKEEN3
874 {SPR_KEEN,3,6,NULL,S_COMMKEEN5,0,0}, // S_COMMKEEN4
875 {SPR_KEEN,4,6,NULL,S_COMMKEEN6,0,0}, // S_COMMKEEN5
876 {SPR_KEEN,5,6,NULL,S_COMMKEEN7,0,0}, // S_COMMKEEN6
877 {SPR_KEEN,6,6,NULL,S_COMMKEEN8,0,0}, // S_COMMKEEN7
878 {SPR_KEEN,7,6,NULL,S_COMMKEEN9,0,0}, // S_COMMKEEN8
879 {SPR_KEEN,8,6,NULL,S_COMMKEEN10,0,0}, // S_COMMKEEN9
880 {SPR_KEEN,9,6,NULL,S_COMMKEEN11,0,0}, // S_COMMKEEN10
881 {SPR_KEEN,10,6,A_KeenDie,S_COMMKEEN12,0,0},// S_COMMKEEN11
882 {SPR_KEEN,11,-1,NULL,S_NULL,0,0}, // S_COMMKEEN12
883 {SPR_KEEN,12,4,NULL,S_KEENPAIN2,0,0}, // S_KEENPAIN
884 {SPR_KEEN,12,8,A_Pain,S_KEENSTND,0,0}, // S_KEENPAIN2
885 {SPR_BBRN,0,-1,NULL,S_NULL,0,0}, // S_BRAIN
886 {SPR_BBRN,1,36,A_BrainPain,S_BRAIN,0,0}, // S_BRAIN_PAIN
887 {SPR_BBRN,0,100,A_BrainScream,S_BRAIN_DIE2,0,0}, // S_BRAIN_DIE1
888 {SPR_BBRN,0,10,NULL,S_BRAIN_DIE3,0,0}, // S_BRAIN_DIE2
889 {SPR_BBRN,0,10,NULL,S_BRAIN_DIE4,0,0}, // S_BRAIN_DIE3
890 {SPR_BBRN,0,-1,A_BrainDie,S_NULL,0,0}, // S_BRAIN_DIE4
891 {SPR_SSWV,0,10,A_Look,S_BRAINEYE,0,0}, // S_BRAINEYE
892 {SPR_SSWV,0,181,A_BrainAwake,S_BRAINEYE1,0,0}, // S_BRAINEYESEE
893 {SPR_SSWV,0,150,A_BrainSpit,S_BRAINEYE1,0,0}, // S_BRAINEYE1
894 {SPR_BOSF,32768,3,A_SpawnSound,S_SPAWN2,0,0}, // S_SPAWN1
895 {SPR_BOSF,32769,3,A_SpawnFly,S_SPAWN3,0,0}, // S_SPAWN2
896 {SPR_BOSF,32770,3,A_SpawnFly,S_SPAWN4,0,0}, // S_SPAWN3
897 {SPR_BOSF,32771,3,A_SpawnFly,S_SPAWN1,0,0}, // S_SPAWN4
898 {SPR_FIRE,32768,4,A_Fire,S_SPAWNFIRE2,0,0}, // S_SPAWNFIRE1
899 {SPR_FIRE,32769,4,A_Fire,S_SPAWNFIRE3,0,0}, // S_SPAWNFIRE2
900 {SPR_FIRE,32770,4,A_Fire,S_SPAWNFIRE4,0,0}, // S_SPAWNFIRE3
901 {SPR_FIRE,32771,4,A_Fire,S_SPAWNFIRE5,0,0}, // S_SPAWNFIRE4
902 {SPR_FIRE,32772,4,A_Fire,S_SPAWNFIRE6,0,0}, // S_SPAWNFIRE5
903 {SPR_FIRE,32773,4,A_Fire,S_SPAWNFIRE7,0,0}, // S_SPAWNFIRE6
904 {SPR_FIRE,32774,4,A_Fire,S_SPAWNFIRE8,0,0}, // S_SPAWNFIRE7
905 {SPR_FIRE,32775,4,A_Fire,S_NULL,0,0}, // S_SPAWNFIRE8
906 {SPR_MISL,32769,10,NULL,S_BRAINEXPLODE2,0,0}, // S_BRAINEXPLODE1
907 {SPR_MISL,32770,10,NULL,S_BRAINEXPLODE3,0,0}, // S_BRAINEXPLODE2
908 {SPR_MISL,32771,10,A_BrainExplode,S_NULL,0,0}, // S_BRAINEXPLODE3
909 {SPR_ARM1,0,6,NULL,S_ARM1A,0,0}, // S_ARM1
910 {SPR_ARM1,32769,7,NULL,S_ARM1,0,0}, // S_ARM1A
911 {SPR_ARM2,0,6,NULL,S_ARM2A,0,0}, // S_ARM2
912 {SPR_ARM2,32769,6,NULL,S_ARM2,0,0}, // S_ARM2A
913 {SPR_BAR1,0,6,NULL,S_BAR2,0,0}, // S_BAR1
914 {SPR_BAR1,1,6,NULL,S_BAR1,0,0}, // S_BAR2
915 {SPR_BEXP,32768,5,NULL,S_BEXP2,0,0}, // S_BEXP
916 {SPR_BEXP,32769,5,A_Scream,S_BEXP3,0,0}, // S_BEXP2
917 {SPR_BEXP,32770,5,NULL,S_BEXP4,0,0}, // S_BEXP3
918 {SPR_BEXP,32771,10,A_Explode,S_BEXP5,0,0}, // S_BEXP4
919 {SPR_BEXP,32772,10,NULL,S_NULL,0,0}, // S_BEXP5
920 {SPR_FCAN,32768,4,NULL,S_BBAR2,0,0}, // S_BBAR1
921 {SPR_FCAN,32769,4,NULL,S_BBAR3,0,0}, // S_BBAR2
922 {SPR_FCAN,32770,4,NULL,S_BBAR1,0,0}, // S_BBAR3
923 {SPR_BON1,0,6,NULL,S_BON1A,0,0}, // S_BON1
924 {SPR_BON1,1,6,NULL,S_BON1B,0,0}, // S_BON1A
925 {SPR_BON1,2,6,NULL,S_BON1C,0,0}, // S_BON1B
926 {SPR_BON1,3,6,NULL,S_BON1D,0,0}, // S_BON1C
927 {SPR_BON1,2,6,NULL,S_BON1E,0,0}, // S_BON1D
928 {SPR_BON1,1,6,NULL,S_BON1,0,0}, // S_BON1E
929 {SPR_BON2,0,6,NULL,S_BON2A,0,0}, // S_BON2
930 {SPR_BON2,1,6,NULL,S_BON2B,0,0}, // S_BON2A
931 {SPR_BON2,2,6,NULL,S_BON2C,0,0}, // S_BON2B
932 {SPR_BON2,3,6,NULL,S_BON2D,0,0}, // S_BON2C
933 {SPR_BON2,2,6,NULL,S_BON2E,0,0}, // S_BON2D
934 {SPR_BON2,1,6,NULL,S_BON2,0,0}, // S_BON2E
935 {SPR_BKEY,0,10,NULL,S_BKEY2,0,0}, // S_BKEY
936 {SPR_BKEY,32769,10,NULL,S_BKEY,0,0}, // S_BKEY2
937 {SPR_RKEY,0,10,NULL,S_RKEY2,0,0}, // S_RKEY
938 {SPR_RKEY,32769,10,NULL,S_RKEY,0,0}, // S_RKEY2
939 {SPR_YKEY,0,10,NULL,S_YKEY2,0,0}, // S_YKEY
940 {SPR_YKEY,32769,10,NULL,S_YKEY,0,0}, // S_YKEY2
941 {SPR_BSKU,0,10,NULL,S_BSKULL2,0,0}, // S_BSKULL
942 {SPR_BSKU,32769,10,NULL,S_BSKULL,0,0}, // S_BSKULL2
943 {SPR_RSKU,0,10,NULL,S_RSKULL2,0,0}, // S_RSKULL
944 {SPR_RSKU,32769,10,NULL,S_RSKULL,0,0}, // S_RSKULL2
945 {SPR_YSKU,0,10,NULL,S_YSKULL2,0,0}, // S_YSKULL
946 {SPR_YSKU,32769,10,NULL,S_YSKULL,0,0}, // S_YSKULL2
947 {SPR_STIM,0,-1,NULL,S_NULL,0,0}, // S_STIM
948 {SPR_MEDI,0,-1,NULL,S_NULL,0,0}, // S_MEDI
949 {SPR_SOUL,32768,6,NULL,S_SOUL2,0,0}, // S_SOUL
950 {SPR_SOUL,32769,6,NULL,S_SOUL3,0,0}, // S_SOUL2
951 {SPR_SOUL,32770,6,NULL,S_SOUL4,0,0}, // S_SOUL3
952 {SPR_SOUL,32771,6,NULL,S_SOUL5,0,0}, // S_SOUL4
953 {SPR_SOUL,32770,6,NULL,S_SOUL6,0,0}, // S_SOUL5
954 {SPR_SOUL,32769,6,NULL,S_SOUL,0,0}, // S_SOUL6
955 {SPR_PINV,32768,6,NULL,S_PINV2,0,0}, // S_PINV
956 {SPR_PINV,32769,6,NULL,S_PINV3,0,0}, // S_PINV2
957 {SPR_PINV,32770,6,NULL,S_PINV4,0,0}, // S_PINV3
958 {SPR_PINV,32771,6,NULL,S_PINV,0,0}, // S_PINV4
959 {SPR_PSTR,32768,-1,NULL,S_NULL,0,0}, // S_PSTR
960 {SPR_PINS,32768,6,NULL,S_PINS2,0,0}, // S_PINS
961 {SPR_PINS,32769,6,NULL,S_PINS3,0,0}, // S_PINS2
962 {SPR_PINS,32770,6,NULL,S_PINS4,0,0}, // S_PINS3
963 {SPR_PINS,32771,6,NULL,S_PINS,0,0}, // S_PINS4
964 {SPR_MEGA,32768,6,NULL,S_MEGA2,0,0}, // S_MEGA
965 {SPR_MEGA,32769,6,NULL,S_MEGA3,0,0}, // S_MEGA2
966 {SPR_MEGA,32770,6,NULL,S_MEGA4,0,0}, // S_MEGA3
967 {SPR_MEGA,32771,6,NULL,S_MEGA,0,0}, // S_MEGA4
968 {SPR_SUIT,32768,-1,NULL,S_NULL,0,0}, // S_SUIT
969 {SPR_PMAP,32768,6,NULL,S_PMAP2,0,0}, // S_PMAP
970 {SPR_PMAP,32769,6,NULL,S_PMAP3,0,0}, // S_PMAP2
971 {SPR_PMAP,32770,6,NULL,S_PMAP4,0,0}, // S_PMAP3
972 {SPR_PMAP,32771,6,NULL,S_PMAP5,0,0}, // S_PMAP4
973 {SPR_PMAP,32770,6,NULL,S_PMAP6,0,0}, // S_PMAP5
974 {SPR_PMAP,32769,6,NULL,S_PMAP,0,0}, // S_PMAP6
975 {SPR_PVIS,32768,6,NULL,S_PVIS2,0,0}, // S_PVIS
976 {SPR_PVIS,1,6,NULL,S_PVIS,0,0}, // S_PVIS2
977 {SPR_CLIP,0,-1,NULL,S_NULL,0,0}, // S_CLIP
978 {SPR_AMMO,0,-1,NULL,S_NULL,0,0}, // S_AMMO
979 {SPR_ROCK,0,-1,NULL,S_NULL,0,0}, // S_ROCK
980 {SPR_BROK,0,-1,NULL,S_NULL,0,0}, // S_BROK
981 {SPR_CELL,0,-1,NULL,S_NULL,0,0}, // S_CELL
982 {SPR_CELP,0,-1,NULL,S_NULL,0,0}, // S_CELP
983 {SPR_SHEL,0,-1,NULL,S_NULL,0,0}, // S_SHEL
984 {SPR_SBOX,0,-1,NULL,S_NULL,0,0}, // S_SBOX
985 {SPR_BPAK,0,-1,NULL,S_NULL,0,0}, // S_BPAK
986 {SPR_BFUG,0,-1,NULL,S_NULL,0,0}, // S_BFUG
987 {SPR_MGUN,0,-1,NULL,S_NULL,0,0}, // S_MGUN
988 {SPR_CSAW,0,-1,NULL,S_NULL,0,0}, // S_CSAW
989 {SPR_LAUN,0,-1,NULL,S_NULL,0,0}, // S_LAUN
990 {SPR_PLAS,0,-1,NULL,S_NULL,0,0}, // S_PLAS
991 {SPR_SHOT,0,-1,NULL,S_NULL,0,0}, // S_SHOT
992 {SPR_SGN2,0,-1,NULL,S_NULL,0,0}, // S_SHOT2
993 {SPR_COLU,32768,-1,NULL,S_NULL,0,0}, // S_COLU
994 {SPR_SMT2,0,-1,NULL,S_NULL,0,0}, // S_STALAG
995 {SPR_GOR1,0,10,NULL,S_BLOODYTWITCH2,0,0}, // S_BLOODYTWITCH
996 {SPR_GOR1,1,15,NULL,S_BLOODYTWITCH3,0,0}, // S_BLOODYTWITCH2
997 {SPR_GOR1,2,8,NULL,S_BLOODYTWITCH4,0,0}, // S_BLOODYTWITCH3
998 {SPR_GOR1,1,6,NULL,S_BLOODYTWITCH,0,0}, // S_BLOODYTWITCH4
999 {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_DEADTORSO
1000 {SPR_PLAY,18,-1,NULL,S_NULL,0,0}, // S_DEADBOTTOM
1001 {SPR_POL2,0,-1,NULL,S_NULL,0,0}, // S_HEADSONSTICK
1002 {SPR_POL5,0,-1,NULL,S_NULL,0,0}, // S_GIBS
1003 {SPR_POL4,0,-1,NULL,S_NULL,0,0}, // S_HEADONASTICK
1004 {SPR_POL3,32768,6,NULL,S_HEADCANDLES2,0,0}, // S_HEADCANDLES
1005 {SPR_POL3,32769,6,NULL,S_HEADCANDLES,0,0}, // S_HEADCANDLES2
1006 {SPR_POL1,0,-1,NULL,S_NULL,0,0}, // S_DEADSTICK
1007 {SPR_POL6,0,6,NULL,S_LIVESTICK2,0,0}, // S_LIVESTICK
1008 {SPR_POL6,1,8,NULL,S_LIVESTICK,0,0}, // S_LIVESTICK2
1009 {SPR_GOR2,0,-1,NULL,S_NULL,0,0}, // S_MEAT2
1010 {SPR_GOR3,0,-1,NULL,S_NULL,0,0}, // S_MEAT3
1011 {SPR_GOR4,0,-1,NULL,S_NULL,0,0}, // S_MEAT4
1012 {SPR_GOR5,0,-1,NULL,S_NULL,0,0}, // S_MEAT5
1013 {SPR_SMIT,0,-1,NULL,S_NULL,0,0}, // S_STALAGTITE
1014 {SPR_COL1,0,-1,NULL,S_NULL,0,0}, // S_TALLGRNCOL
1015 {SPR_COL2,0,-1,NULL,S_NULL,0,0}, // S_SHRTGRNCOL
1016 {SPR_COL3,0,-1,NULL,S_NULL,0,0}, // S_TALLREDCOL
1017 {SPR_COL4,0,-1,NULL,S_NULL,0,0}, // S_SHRTREDCOL
1018 {SPR_CAND,32768,-1,NULL,S_NULL,0,0}, // S_CANDLESTIK
1019 {SPR_CBRA,32768,-1,NULL,S_NULL,0,0}, // S_CANDELABRA
1020 {SPR_COL6,0,-1,NULL,S_NULL,0,0}, // S_SKULLCOL
1021 {SPR_TRE1,0,-1,NULL,S_NULL,0,0}, // S_TORCHTREE
1022 {SPR_TRE2,0,-1,NULL,S_NULL,0,0}, // S_BIGTREE
1023 {SPR_ELEC,0,-1,NULL,S_NULL,0,0}, // S_TECHPILLAR
1024 {SPR_CEYE,32768,6,NULL,S_EVILEYE2,0,0}, // S_EVILEYE
1025 {SPR_CEYE,32769,6,NULL,S_EVILEYE3,0,0}, // S_EVILEYE2
1026 {SPR_CEYE,32770,6,NULL,S_EVILEYE4,0,0}, // S_EVILEYE3
1027 {SPR_CEYE,32769,6,NULL,S_EVILEYE,0,0}, // S_EVILEYE4
1028 {SPR_FSKU,32768,6,NULL,S_FLOATSKULL2,0,0}, // S_FLOATSKULL
1029 {SPR_FSKU,32769,6,NULL,S_FLOATSKULL3,0,0}, // S_FLOATSKULL2
1030 {SPR_FSKU,32770,6,NULL,S_FLOATSKULL,0,0}, // S_FLOATSKULL3
1031 {SPR_COL5,0,14,NULL,S_HEARTCOL2,0,0}, // S_HEARTCOL
1032 {SPR_COL5,1,14,NULL,S_HEARTCOL,0,0}, // S_HEARTCOL2
1033 {SPR_TBLU,32768,4,NULL,S_BLUETORCH2,0,0}, // S_BLUETORCH
1034 {SPR_TBLU,32769,4,NULL,S_BLUETORCH3,0,0}, // S_BLUETORCH2
1035 {SPR_TBLU,32770,4,NULL,S_BLUETORCH4,0,0}, // S_BLUETORCH3
1036 {SPR_TBLU,32771,4,NULL,S_BLUETORCH,0,0}, // S_BLUETORCH4
1037 {SPR_TGRN,32768,4,NULL,S_GREENTORCH2,0,0}, // S_GREENTORCH
1038 {SPR_TGRN,32769,4,NULL,S_GREENTORCH3,0,0}, // S_GREENTORCH2
1039 {SPR_TGRN,32770,4,NULL,S_GREENTORCH4,0,0}, // S_GREENTORCH3
1040 {SPR_TGRN,32771,4,NULL,S_GREENTORCH,0,0}, // S_GREENTORCH4
1041 {SPR_TRED,32768,4,NULL,S_REDTORCH2,0,0}, // S_REDTORCH
1042 {SPR_TRED,32769,4,NULL,S_REDTORCH3,0,0}, // S_REDTORCH2
1043 {SPR_TRED,32770,4,NULL,S_REDTORCH4,0,0}, // S_REDTORCH3
1044 {SPR_TRED,32771,4,NULL,S_REDTORCH,0,0}, // S_REDTORCH4
1045 {SPR_SMBT,32768,4,NULL,S_BTORCHSHRT2,0,0}, // S_BTORCHSHRT
1046 {SPR_SMBT,32769,4,NULL,S_BTORCHSHRT3,0,0}, // S_BTORCHSHRT2
1047 {SPR_SMBT,32770,4,NULL,S_BTORCHSHRT4,0,0}, // S_BTORCHSHRT3
1048 {SPR_SMBT,32771,4,NULL,S_BTORCHSHRT,0,0}, // S_BTORCHSHRT4
1049 {SPR_SMGT,32768,4,NULL,S_GTORCHSHRT2,0,0}, // S_GTORCHSHRT
1050 {SPR_SMGT,32769,4,NULL,S_GTORCHSHRT3,0,0}, // S_GTORCHSHRT2
1051 {SPR_SMGT,32770,4,NULL,S_GTORCHSHRT4,0,0}, // S_GTORCHSHRT3
1052 {SPR_SMGT,32771,4,NULL,S_GTORCHSHRT,0,0}, // S_GTORCHSHRT4
1053 {SPR_SMRT,32768,4,NULL,S_RTORCHSHRT2,0,0}, // S_RTORCHSHRT
1054 {SPR_SMRT,32769,4,NULL,S_RTORCHSHRT3,0,0}, // S_RTORCHSHRT2
1055 {SPR_SMRT,32770,4,NULL,S_RTORCHSHRT4,0,0}, // S_RTORCHSHRT3
1056 {SPR_SMRT,32771,4,NULL,S_RTORCHSHRT,0,0}, // S_RTORCHSHRT4
1057 {SPR_HDB1,0,-1,NULL,S_NULL,0,0}, // S_HANGNOGUTS
1058 {SPR_HDB2,0,-1,NULL,S_NULL,0,0}, // S_HANGBNOBRAIN
1059 {SPR_HDB3,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKDN
1060 {SPR_HDB4,0,-1,NULL,S_NULL,0,0}, // S_HANGTSKULL
1061 {SPR_HDB5,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKUP
1062 {SPR_HDB6,0,-1,NULL,S_NULL,0,0}, // S_HANGTNOBRAIN
1063 {SPR_POB1,0,-1,NULL,S_NULL,0,0}, // S_COLONGIBS
1064 {SPR_POB2,0,-1,NULL,S_NULL,0,0}, // S_SMALLPOOL
1065 {SPR_BRS1,0,-1,NULL,S_NULL,0,0}, // S_BRAINSTEM
1066 {SPR_TLMP,32768,4,NULL,S_TECHLAMP2,0,0}, // S_TECHLAMP
1067 {SPR_TLMP,32769,4,NULL,S_TECHLAMP3,0,0}, // S_TECHLAMP2
1068 {SPR_TLMP,32770,4,NULL,S_TECHLAMP4,0,0}, // S_TECHLAMP3
1069 {SPR_TLMP,32771,4,NULL,S_TECHLAMP,0,0}, // S_TECHLAMP4
1070 {SPR_TLP2,32768,4,NULL,S_TECH2LAMP2,0,0}, // S_TECH2LAMP
1071 {SPR_TLP2,32769,4,NULL,S_TECH2LAMP3,0,0}, // S_TECH2LAMP2
1072 {SPR_TLP2,32770,4,NULL,S_TECH2LAMP4,0,0}, // S_TECH2LAMP3
1073 {SPR_TLP2,32771,4,NULL,S_TECH2LAMP,0,0}, // S_TECH2LAMP4
1074 {SPR_TNT1,0,-1,NULL,S_TNT1,0,0}, // S_TNT1 // phares 3/8/98
1075
1076 // killough 8/9/98: grenade
1077 {SPR_MISL,32768,1000,A_Die,S_GRENADE}, // S_GRENADE
1078
1079 // killough 8/10/98: variable damage explosion
1080 {SPR_MISL,32769,4,A_Scream,S_DETONATE2}, // S_DETONATE
1081 {SPR_MISL,32770,6,A_Detonate,S_DETONATE3}, // S_DETONATE2
1082 {SPR_MISL,32771,10,NULL,S_NULL}, // S_DETONATE3
1083
1084#ifdef DOGS
1085 // killough 7/19/98: Marine's best friend :)
1086 {SPR_DOGS,0,10,A_Look,S_DOGS_STND2}, // S_DOGS_STND
1087 {SPR_DOGS,1,10,A_Look,S_DOGS_STND}, // S_DOGS_STND2
1088 {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN2}, // S_DOGS_RUN1
1089 {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN3}, // S_DOGS_RUN2
1090 {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN4}, // S_DOGS_RUN3
1091 {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN5}, // S_DOGS_RUN4
1092 {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN6}, // S_DOGS_RUN5
1093 {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN7}, // S_DOGS_RUN6
1094 {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN8}, // S_DOGS_RUN7
1095 {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN1}, // S_DOGS_RUN8
1096 {SPR_DOGS,4,8,A_FaceTarget,S_DOGS_ATK2}, // S_DOGS_ATK1
1097 {SPR_DOGS,5,8,A_FaceTarget,S_DOGS_ATK3}, // S_DOGS_ATK2
1098 {SPR_DOGS,6,8,A_SargAttack,S_DOGS_RUN1}, // S_DOGS_ATK3
1099 {SPR_DOGS,7,2,NULL,S_DOGS_PAIN2}, // S_DOGS_PAIN
1100 {SPR_DOGS,7,2,A_Pain,S_DOGS_RUN1}, // S_DOGS_PAIN2
1101 {SPR_DOGS,8,8,NULL,S_DOGS_DIE2}, // S_DOGS_DIE1
1102 {SPR_DOGS,9,8,A_Scream,S_DOGS_DIE3}, // S_DOGS_DIE2
1103 {SPR_DOGS,10,4,NULL,S_DOGS_DIE4}, // S_DOGS_DIE3
1104 {SPR_DOGS,11,4,A_Fall,S_DOGS_DIE5}, // S_DOGS_DIE4
1105 {SPR_DOGS,12,4,NULL,S_DOGS_DIE6}, // S_DOGS_DIE5
1106 {SPR_DOGS,13,-1,NULL,S_NULL}, // S_DOGS_DIE6
1107 {SPR_DOGS,13,5,NULL,S_DOGS_RAISE2}, // S_DOGS_RAISE1
1108 {SPR_DOGS,12,5,NULL,S_DOGS_RAISE3}, // S_DOGS_RAISE2
1109 {SPR_DOGS,11,5,NULL,S_DOGS_RAISE4}, // S_DOGS_RAISE3
1110 {SPR_DOGS,10,5,NULL,S_DOGS_RAISE5}, // S_DOGS_RAISE4
1111 {SPR_DOGS,9,5,NULL,S_DOGS_RAISE6}, // S_DOGS_RAISE5
1112 {SPR_DOGS,8,5,NULL,S_DOGS_RUN1}, // S_DOGS_RAISE6
1113#else
1114 // if dogs are disabled, dummy states are required for dehacked compatibility
1115 {0,0,-1,NULL,S_NULL}, // S_DOGS_STND
1116 {0,0,-1,NULL,S_NULL}, // S_DOGS_STND2
1117 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN1
1118 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN2
1119 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN3
1120 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN4
1121 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN5
1122 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN6
1123 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN7
1124 {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN8
1125 {0,0,-1,NULL,S_NULL}, // S_DOGS_ATK1
1126 {0,0,-1,NULL,S_NULL}, // S_DOGS_ATK2
1127 {0,0,-1,NULL,S_NULL}, // S_DOGS_ATK3
1128 {0,0,-1,NULL,S_NULL}, // S_DOGS_PAIN
1129 {0,0,-1,NULL,S_NULL}, // S_DOGS_PAIN2
1130 {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE1
1131 {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE2
1132 {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE3
1133 {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE4
1134 {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE5
1135 {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE6
1136 {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE1
1137 {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE2
1138 {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE3
1139 {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE4
1140 {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE5
1141 {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE6
1142#endif
1143
1144 // add dummy beta bfg / lost soul frames for dehacked compatibility
1145 // fixes bug #1576151 (part 2)
1146 {0,0,-1,NULL,S_NULL}, // S_OLDBFG1
1147 {0,0,-1,NULL,S_NULL}, // S_OLDBFG2
1148 {0,0,-1,NULL,S_NULL}, // S_OLDBFG3
1149 {0,0,-1,NULL,S_NULL}, // S_OLDBFG4
1150 {0,0,-1,NULL,S_NULL}, // S_OLDBFG5
1151 {0,0,-1,NULL,S_NULL}, // S_OLDBFG6
1152 {0,0,-1,NULL,S_NULL}, // S_OLDBFG7
1153 {0,0,-1,NULL,S_NULL}, // S_OLDBFG8
1154 {0,0,-1,NULL,S_NULL}, // S_OLDBFG9
1155 {0,0,-1,NULL,S_NULL}, // S_OLDBFG10
1156 {0,0,-1,NULL,S_NULL}, // S_OLDBFG11
1157 {0,0,-1,NULL,S_NULL}, // S_OLDBFG12
1158 {0,0,-1,NULL,S_NULL}, // S_OLDBFG13
1159 {0,0,-1,NULL,S_NULL}, // S_OLDBFG14
1160 {0,0,-1,NULL,S_NULL}, // S_OLDBFG15
1161 {0,0,-1,NULL,S_NULL}, // S_OLDBFG16
1162 {0,0,-1,NULL,S_NULL}, // S_OLDBFG17
1163 {0,0,-1,NULL,S_NULL}, // S_OLDBFG18
1164 {0,0,-1,NULL,S_NULL}, // S_OLDBFG19
1165 {0,0,-1,NULL,S_NULL}, // S_OLDBFG20
1166 {0,0,-1,NULL,S_NULL}, // S_OLDBFG21
1167 {0,0,-1,NULL,S_NULL}, // S_OLDBFG22
1168 {0,0,-1,NULL,S_NULL}, // S_OLDBFG23
1169 {0,0,-1,NULL,S_NULL}, // S_OLDBFG24
1170 {0,0,-1,NULL,S_NULL}, // S_OLDBFG25
1171 {0,0,-1,NULL,S_NULL}, // S_OLDBFG26
1172 {0,0,-1,NULL,S_NULL}, // S_OLDBFG27
1173 {0,0,-1,NULL,S_NULL}, // S_OLDBFG28
1174 {0,0,-1,NULL,S_NULL}, // S_OLDBFG29
1175 {0,0,-1,NULL,S_NULL}, // S_OLDBFG30
1176 {0,0,-1,NULL,S_NULL}, // S_OLDBFG31
1177 {0,0,-1,NULL,S_NULL}, // S_OLDBFG32
1178 {0,0,-1,NULL,S_NULL}, // S_OLDBFG33
1179 {0,0,-1,NULL,S_NULL}, // S_OLDBFG34
1180 {0,0,-1,NULL,S_NULL}, // S_OLDBFG35
1181 {0,0,-1,NULL,S_NULL}, // S_OLDBFG36
1182 {0,0,-1,NULL,S_NULL}, // S_OLDBFG37
1183 {0,0,-1,NULL,S_NULL}, // S_OLDBFG38
1184 {0,0,-1,NULL,S_NULL}, // S_OLDBFG39
1185 {0,0,-1,NULL,S_NULL}, // S_OLDBFG40
1186 {0,0,-1,NULL,S_NULL}, // S_OLDBFG41
1187 {0,0,-1,NULL,S_NULL}, // S_OLDBFG42
1188 {0,0,-1,NULL,S_NULL}, // S_OLDBFG43
1189
1190 {0,0,-1,NULL,S_NULL}, // S_PLS1BALL
1191 {0,0,-1,NULL,S_NULL}, // S_PLS1BALL2
1192 {0,0,-1,NULL,S_NULL}, // S_PLS1EXP
1193 {0,0,-1,NULL,S_NULL}, // S_PLS1EXP2
1194 {0,0,-1,NULL,S_NULL}, // S_PLS1EXP3
1195 {0,0,-1,NULL,S_NULL}, // S_PLS1EXP4
1196 {0,0,-1,NULL,S_NULL}, // S_PLS1EXP5
1197
1198 {0,0,-1,NULL,S_NULL}, // S_PLS2BALL
1199 {0,0,-1,NULL,S_NULL}, // S_PLS2BALL2
1200 {0,0,-1,NULL,S_NULL}, // S_PLS2BALLX1
1201 {0,0,-1,NULL,S_NULL}, // S_PLS2BALLX2
1202 {0,0,-1,NULL,S_NULL}, // S_PLS2BALLX3
1203
1204 {0,0,-1,NULL,S_NULL}, // S_BON3
1205 {0,0,-1,NULL,S_NULL}, // S_BON4
1206
1207 {0,0,-1,NULL,S_NULL}, // S_BSKUL_STND
1208 {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN1
1209 {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN2
1210 {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN3
1211 {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN4
1212 {0,0,-1,NULL,S_NULL}, // S_BSKUL_ATK1
1213 {0,0,-1,NULL,S_NULL}, // S_BSKUL_ATK2
1214 {0,0,-1,NULL,S_NULL}, // S_BSKUL_ATK3
1215 {0,0,-1,NULL,S_NULL}, // S_BSKUL_PAIN1
1216 {0,0,-1,NULL,S_NULL}, // S_BSKUL_PAIN2
1217 {0,0,-1,NULL,S_NULL}, // S_BSKUL_PAIN3
1218 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE1
1219 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE2
1220 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE3
1221 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE4
1222 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE5
1223 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE6
1224 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE7
1225 {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE8
1226
1227 // killough 10/98: mushroom effect
1228 {SPR_MISL,32769,8,A_Mushroom,S_EXPLODE2}, // S_MUSHROOM
1229};
1230
1231// ********************************************************************
1232// Object "Thing" definitions
1233// ********************************************************************
1234// Now we get to the actual objects and their characteristics. If
1235// you've seen Dehacked, much of this is where the Bits are set,
1236// commented below as "flags", as well as where you wire in which
1237// frames are the beginning frames for near and far attack, death,
1238// and such. Sounds are hooked in here too, as well as how much
1239// mass, speed and so forth a Thing has. Everything you ever wanted
1240// to know...
1241//
1242// Like all this other stuff, the MT_* entries are enumerated in info.h
1243//
1244// Note that these are all just indices of the elements involved, and
1245// not real pointers to them. For example, the player's death sequence
1246// is S_PLAY_DIE1, which just evaluates to the index in the states[]
1247// array above, which actually knows what happens then and what the
1248// sprite looks like, if it makes noise or not, etc.
1249//
1250// Additional comments about each of the entries are located in info.h
1251// next to the mobjinfo_t structure definition.
1252//
1253// This goes on for the next 3000+ lines...
1254
1255mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
1256 { // MT_PLAYER
1257 -1, // doomednum
1258 S_PLAY, // spawnstate
1259 100, // spawnhealth
1260 S_PLAY_RUN1, // seestate
1261 sfx_None, // seesound
1262 0, // reactiontime
1263 sfx_None, // attacksound
1264 S_PLAY_PAIN, // painstate
1265 255, // painchance
1266 sfx_plpain, // painsound
1267 S_NULL, // meleestate
1268 S_PLAY_ATK1, // missilestate
1269 S_PLAY_DIE1, // deathstate
1270 S_PLAY_XDIE1, // xdeathstate
1271 sfx_pldeth, // deathsound
1272 0, // speed
1273 16*FRACUNIT, // radius
1274 56*FRACUNIT, // height
1275 100, // mass
1276 0, // damage
1277 sfx_None, // activesound
1278 MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags
1279 S_NULL // raisestate
1280 },
1281
1282 { // MT_POSSESSED
1283 3004, // doomednum
1284 S_POSS_STND, // spawnstate
1285 20, // spawnhealth
1286 S_POSS_RUN1, // seestate
1287 sfx_posit1, // seesound
1288 8, // reactiontime
1289 sfx_pistol, // attacksound
1290 S_POSS_PAIN, // painstate
1291 200, // painchance
1292 sfx_popain, // painsound
1293 0, // meleestate
1294 S_POSS_ATK1, // missilestate
1295 S_POSS_DIE1, // deathstate
1296 S_POSS_XDIE1, // xdeathstate
1297 sfx_podth1, // deathsound
1298 8, // speed
1299 20*FRACUNIT, // radius
1300 56*FRACUNIT, // height
1301 100, // mass
1302 0, // damage
1303 sfx_posact, // activesound
1304 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1305 S_POSS_RAISE1 // raisestate
1306 },
1307
1308 { // MT_SHOTGUY
1309 9, // doomednum
1310 S_SPOS_STND, // spawnstate
1311 30, // spawnhealth
1312 S_SPOS_RUN1, // seestate
1313 sfx_posit2, // seesound
1314 8, // reactiontime
1315 0, // attacksound
1316 S_SPOS_PAIN, // painstate
1317 170, // painchance
1318 sfx_popain, // painsound
1319 0, // meleestate
1320 S_SPOS_ATK1, // missilestate
1321 S_SPOS_DIE1, // deathstate
1322 S_SPOS_XDIE1, // xdeathstate
1323 sfx_podth2, // deathsound
1324 8, // speed
1325 20*FRACUNIT, // radius
1326 56*FRACUNIT, // height
1327 100, // mass
1328 0, // damage
1329 sfx_posact, // activesound
1330 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1331 S_SPOS_RAISE1 // raisestate
1332 },
1333
1334 { // MT_VILE
1335 64, // doomednum
1336 S_VILE_STND, // spawnstate
1337 700, // spawnhealth
1338 S_VILE_RUN1, // seestate
1339 sfx_vilsit, // seesound
1340 8, // reactiontime
1341 0, // attacksound
1342 S_VILE_PAIN, // painstate
1343 10, // painchance
1344 sfx_vipain, // painsound
1345 0, // meleestate
1346 S_VILE_ATK1, // missilestate
1347 S_VILE_DIE1, // deathstate
1348 S_NULL, // xdeathstate
1349 sfx_vildth, // deathsound
1350 15, // speed
1351 20*FRACUNIT, // radius
1352 56*FRACUNIT, // height
1353 500, // mass
1354 0, // damage
1355 sfx_vilact, // activesound
1356 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1357 S_NULL // raisestate
1358 },
1359
1360 { // MT_FIRE
1361 -1, // doomednum
1362 S_FIRE1, // spawnstate
1363 1000, // spawnhealth
1364 S_NULL, // seestate
1365 sfx_None, // seesound
1366 8, // reactiontime
1367 sfx_None, // attacksound
1368 S_NULL, // painstate
1369 0, // painchance
1370 sfx_None, // painsound
1371 S_NULL, // meleestate
1372 S_NULL, // missilestate
1373 S_NULL, // deathstate
1374 S_NULL, // xdeathstate
1375 sfx_None, // deathsound
1376 0, // speed
1377 20*FRACUNIT, // radius
1378 16*FRACUNIT, // height
1379 100, // mass
1380 0, // damage
1381 sfx_None, // activesound
1382 MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // killough 2/21/98
1383 S_NULL // raisestate
1384 },
1385
1386 { // MT_UNDEAD
1387 66, // doomednum
1388 S_SKEL_STND, // spawnstate
1389 300, // spawnhealth
1390 S_SKEL_RUN1, // seestate
1391 sfx_skesit, // seesound
1392 8, // reactiontime
1393 0, // attacksound
1394 S_SKEL_PAIN, // painstate
1395 100, // painchance
1396 sfx_popain, // painsound
1397 S_SKEL_FIST1, // meleestate
1398 S_SKEL_MISS1, // missilestate
1399 S_SKEL_DIE1, // deathstate
1400 S_NULL, // xdeathstate
1401 sfx_skedth, // deathsound
1402 10, // speed
1403 20*FRACUNIT, // radius
1404 56*FRACUNIT, // height
1405 500, // mass
1406 0, // damage
1407 sfx_skeact, // activesound
1408 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1409 S_SKEL_RAISE1 // raisestate
1410 },
1411
1412 { // MT_TRACER
1413 -1, // doomednum
1414 S_TRACER, // spawnstate
1415 1000, // spawnhealth
1416 S_NULL, // seestate
1417 sfx_skeatk, // seesound
1418 8, // reactiontime
1419 sfx_None, // attacksound
1420 S_NULL, // painstate
1421 0, // painchance
1422 sfx_None, // painsound
1423 S_NULL, // meleestate
1424 S_NULL, // missilestate
1425 S_TRACEEXP1, // deathstate
1426 S_NULL, // xdeathstate
1427 sfx_barexp, // deathsound
1428 10*FRACUNIT, // speed
1429 11*FRACUNIT, // radius
1430 8*FRACUNIT, // height
1431 100, // mass
1432 10, // damage
1433 sfx_None, // activesound
1434 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
1435 S_NULL // raisestate
1436 },
1437
1438 { // MT_SMOKE
1439 -1, // doomednum
1440 S_SMOKE1, // spawnstate
1441 1000, // spawnhealth
1442 S_NULL, // seestate
1443 sfx_None, // seesound
1444 8, // reactiontime
1445 sfx_None, // attacksound
1446 S_NULL, // painstate
1447 0, // painchance
1448 sfx_None, // painsound
1449 S_NULL, // meleestate
1450 S_NULL, // missilestate
1451 S_NULL, // deathstate
1452 S_NULL, // xdeathstate
1453 sfx_None, // deathsound
1454 0, // speed
1455 20*FRACUNIT, // radius
1456 16*FRACUNIT, // height
1457 100, // mass
1458 0, // damage
1459 sfx_None, // activesound
1460 MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
1461 S_NULL // raisestate
1462 },
1463
1464 { // MT_FATSO
1465 67, // doomednum
1466 S_FATT_STND, // spawnstate
1467 600, // spawnhealth
1468 S_FATT_RUN1, // seestate
1469 sfx_mansit, // seesound
1470 8, // reactiontime
1471 0, // attacksound
1472 S_FATT_PAIN, // painstate
1473 80, // painchance
1474 sfx_mnpain, // painsound
1475 0, // meleestate
1476 S_FATT_ATK1, // missilestate
1477 S_FATT_DIE1, // deathstate
1478 S_NULL, // xdeathstate
1479 sfx_mandth, // deathsound
1480 8, // speed
1481 48*FRACUNIT, // radius
1482 64*FRACUNIT, // height
1483 1000, // mass
1484 0, // damage
1485 sfx_posact, // activesound
1486 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1487 S_FATT_RAISE1 // raisestate
1488 },
1489
1490 { // MT_FATSHOT
1491 -1, // doomednum
1492 S_FATSHOT1, // spawnstate
1493 1000, // spawnhealth
1494 S_NULL, // seestate
1495 sfx_firsht, // seesound
1496 8, // reactiontime
1497 sfx_None, // attacksound
1498 S_NULL, // painstate
1499 0, // painchance
1500 sfx_None, // painsound
1501 S_NULL, // meleestate
1502 S_NULL, // missilestate
1503 S_FATSHOTX1, // deathstate
1504 S_NULL, // xdeathstate
1505 sfx_firxpl, // deathsound
1506 20*FRACUNIT, // speed
1507 6*FRACUNIT, // radius
1508 8*FRACUNIT, // height
1509 100, // mass
1510 8, // damage
1511 sfx_None, // activesound
1512 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags \\ killough 2/21/98
1513 S_NULL // raisestate
1514 },
1515
1516 { // MT_CHAINGUY
1517 65, // doomednum
1518 S_CPOS_STND, // spawnstate
1519 70, // spawnhealth
1520 S_CPOS_RUN1, // seestate
1521 sfx_posit2, // seesound
1522 8, // reactiontime
1523 0, // attacksound
1524 S_CPOS_PAIN, // painstate
1525 170, // painchance
1526 sfx_popain, // painsound
1527 0, // meleestate
1528 S_CPOS_ATK1, // missilestate
1529 S_CPOS_DIE1, // deathstate
1530 S_CPOS_XDIE1, // xdeathstate
1531 sfx_podth2, // deathsound
1532 8, // speed
1533 20*FRACUNIT, // radius
1534 56*FRACUNIT, // height
1535 100, // mass
1536 0, // damage
1537 sfx_posact, // activesound
1538 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1539 S_CPOS_RAISE1 // raisestate
1540 },
1541
1542 { // MT_TROOP
1543 3001, // doomednum
1544 S_TROO_STND, // spawnstate
1545 60, // spawnhealth
1546 S_TROO_RUN1, // seestate
1547 sfx_bgsit1, // seesound
1548 8, // reactiontime
1549 0, // attacksound
1550 S_TROO_PAIN, // painstate
1551 200, // painchance
1552 sfx_popain, // painsound
1553 S_TROO_ATK1, // meleestate
1554 S_TROO_ATK1, // missilestate
1555 S_TROO_DIE1, // deathstate
1556 S_TROO_XDIE1, // xdeathstate
1557 sfx_bgdth1, // deathsound
1558 8, // speed
1559 20*FRACUNIT, // radius
1560 56*FRACUNIT, // height
1561 100, // mass
1562 0, // damage
1563 sfx_bgact, // activesound
1564 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // killough |MF_TRANSLUCENT, // flags // phares
1565 S_TROO_RAISE1 // raisestate
1566 },
1567
1568 { // MT_SERGEANT
1569 3002, // doomednum
1570 S_SARG_STND, // spawnstate
1571 150, // spawnhealth
1572 S_SARG_RUN1, // seestate
1573 sfx_sgtsit, // seesound
1574 8, // reactiontime
1575 sfx_sgtatk, // attacksound
1576 S_SARG_PAIN, // painstate
1577 180, // painchance
1578 sfx_dmpain, // painsound
1579 S_SARG_ATK1, // meleestate
1580 0, // missilestate
1581 S_SARG_DIE1, // deathstate
1582 S_NULL, // xdeathstate
1583 sfx_sgtdth, // deathsound
1584 10, // speed
1585 30*FRACUNIT, // radius
1586 56*FRACUNIT, // height
1587 400, // mass
1588 0, // damage
1589 sfx_dmact, // activesound
1590 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1591 S_SARG_RAISE1 // raisestate
1592 },
1593
1594 { // MT_SHADOWS
1595 58, // doomednum
1596 S_SARG_STND, // spawnstate
1597 150, // spawnhealth
1598 S_SARG_RUN1, // seestate
1599 sfx_sgtsit, // seesound
1600 8, // reactiontime
1601 sfx_sgtatk, // attacksound
1602 S_SARG_PAIN, // painstate
1603 180, // painchance
1604 sfx_dmpain, // painsound
1605 S_SARG_ATK1, // meleestate
1606 0, // missilestate
1607 S_SARG_DIE1, // deathstate
1608 S_NULL, // xdeathstate
1609 sfx_sgtdth, // deathsound
1610 10, // speed
1611 30*FRACUNIT, // radius
1612 56*FRACUNIT, // height
1613 400, // mass
1614 0, // damage
1615 sfx_dmact, // activesound
1616 MF_SOLID|MF_SHOOTABLE|MF_SHADOW|MF_COUNTKILL, // flags
1617 S_SARG_RAISE1 // raisestate
1618 },
1619
1620 { // MT_HEAD
1621 3005, // doomednum
1622 S_HEAD_STND, // spawnstate
1623 400, // spawnhealth
1624 S_HEAD_RUN1, // seestate
1625 sfx_cacsit, // seesound
1626 8, // reactiontime
1627 0, // attacksound
1628 S_HEAD_PAIN, // painstate
1629 128, // painchance
1630 sfx_dmpain, // painsound
1631 0, // meleestate
1632 S_HEAD_ATK1, // missilestate
1633 S_HEAD_DIE1, // deathstate
1634 S_NULL, // xdeathstate
1635 sfx_cacdth, // deathsound
1636 8, // speed
1637 31*FRACUNIT, // radius
1638 56*FRACUNIT, // height
1639 400, // mass
1640 0, // damage
1641 sfx_dmact, // activesound
1642 MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags
1643 S_HEAD_RAISE1 // raisestate
1644 },
1645
1646 { // MT_BRUISER
1647 3003, // doomednum
1648 S_BOSS_STND, // spawnstate
1649 1000, // spawnhealth
1650 S_BOSS_RUN1, // seestate
1651 sfx_brssit, // seesound
1652 8, // reactiontime
1653 0, // attacksound
1654 S_BOSS_PAIN, // painstate
1655 50, // painchance
1656 sfx_dmpain, // painsound
1657 S_BOSS_ATK1, // meleestate
1658 S_BOSS_ATK1, // missilestate
1659 S_BOSS_DIE1, // deathstate
1660 S_NULL, // xdeathstate
1661 sfx_brsdth, // deathsound
1662 8, // speed
1663 24*FRACUNIT, // radius
1664 64*FRACUNIT, // height
1665 1000, // mass
1666 0, // damage
1667 sfx_dmact, // activesound
1668 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1669 S_BOSS_RAISE1 // raisestate
1670 },
1671
1672 { // MT_BRUISERSHOT
1673 -1, // doomednum
1674 S_BRBALL1, // spawnstate
1675 1000, // spawnhealth
1676 S_NULL, // seestate
1677 sfx_firsht, // seesound
1678 8, // reactiontime
1679 sfx_None, // attacksound
1680 S_NULL, // painstate
1681 0, // painchance
1682 sfx_None, // painsound
1683 S_NULL, // meleestate
1684 S_NULL, // missilestate
1685 S_BRBALLX1, // deathstate
1686 S_NULL, // xdeathstate
1687 sfx_firxpl, // deathsound
1688 15*FRACUNIT, // speed
1689 6*FRACUNIT, // radius
1690 8*FRACUNIT, // height
1691 100, // mass
1692 8, // damage
1693 sfx_None, // activesound
1694 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags killough 2/21/98
1695 S_NULL // raisestate
1696 },
1697
1698 { // MT_KNIGHT
1699 69, // doomednum
1700 S_BOS2_STND, // spawnstate
1701 500, // spawnhealth
1702 S_BOS2_RUN1, // seestate
1703 sfx_kntsit, // seesound
1704 8, // reactiontime
1705 0, // attacksound
1706 S_BOS2_PAIN, // painstate
1707 50, // painchance
1708 sfx_dmpain, // painsound
1709 S_BOS2_ATK1, // meleestate
1710 S_BOS2_ATK1, // missilestate
1711 S_BOS2_DIE1, // deathstate
1712 S_NULL, // xdeathstate
1713 sfx_kntdth, // deathsound
1714 8, // speed
1715 24*FRACUNIT, // radius
1716 64*FRACUNIT, // height
1717 1000, // mass
1718 0, // damage
1719 sfx_dmact, // activesound
1720 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1721 S_BOS2_RAISE1 // raisestate
1722 },
1723
1724 { // MT_SKULL
1725 3006, // doomednum
1726 S_SKULL_STND, // spawnstate
1727 100, // spawnhealth
1728 S_SKULL_RUN1, // seestate
1729 0, // seesound
1730 8, // reactiontime
1731 sfx_sklatk, // attacksound
1732 S_SKULL_PAIN, // painstate
1733 256, // painchance
1734 sfx_dmpain, // painsound
1735 0, // meleestate
1736 S_SKULL_ATK1, // missilestate
1737 S_SKULL_DIE1, // deathstate
1738 S_NULL, // xdeathstate
1739 sfx_firxpl, // deathsound
1740 8, // speed
1741 16*FRACUNIT, // radius
1742 56*FRACUNIT, // height
1743 50, // mass
1744 3, // damage
1745 sfx_dmact, // activesound
1746 MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY, // flags
1747 S_NULL // raisestate
1748 },
1749
1750 { // MT_SPIDER
1751 7, // doomednum
1752 S_SPID_STND, // spawnstate
1753 3000, // spawnhealth
1754 S_SPID_RUN1, // seestate
1755 sfx_spisit, // seesound
1756 8, // reactiontime
1757 sfx_shotgn, // attacksound
1758 S_SPID_PAIN, // painstate
1759 40, // painchance
1760 sfx_dmpain, // painsound
1761 0, // meleestate
1762 S_SPID_ATK1, // missilestate
1763 S_SPID_DIE1, // deathstate
1764 S_NULL, // xdeathstate
1765 sfx_spidth, // deathsound
1766 12, // speed
1767 128*FRACUNIT, // radius
1768 100*FRACUNIT, // height
1769 1000, // mass
1770 0, // damage
1771 sfx_dmact, // activesound
1772 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1773 S_NULL // raisestate
1774 },
1775
1776 { // MT_BABY
1777 68, // doomednum
1778 S_BSPI_STND, // spawnstate
1779 500, // spawnhealth
1780 S_BSPI_SIGHT, // seestate
1781 sfx_bspsit, // seesound
1782 8, // reactiontime
1783 0, // attacksound
1784 S_BSPI_PAIN, // painstate
1785 128, // painchance
1786 sfx_dmpain, // painsound
1787 0, // meleestate
1788 S_BSPI_ATK1, // missilestate
1789 S_BSPI_DIE1, // deathstate
1790 S_NULL, // xdeathstate
1791 sfx_bspdth, // deathsound
1792 12, // speed
1793 64*FRACUNIT, // radius
1794 64*FRACUNIT, // height
1795 600, // mass
1796 0, // damage
1797 sfx_bspact, // activesound
1798 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1799 S_BSPI_RAISE1 // raisestate
1800 },
1801
1802 { // MT_CYBORG
1803 16, // doomednum
1804 S_CYBER_STND, // spawnstate
1805 4000, // spawnhealth
1806 S_CYBER_RUN1, // seestate
1807 sfx_cybsit, // seesound
1808 8, // reactiontime
1809 0, // attacksound
1810 S_CYBER_PAIN, // painstate
1811 20, // painchance
1812 sfx_dmpain, // painsound
1813 0, // meleestate
1814 S_CYBER_ATK1, // missilestate
1815 S_CYBER_DIE1, // deathstate
1816 S_NULL, // xdeathstate
1817 sfx_cybdth, // deathsound
1818 16, // speed
1819 40*FRACUNIT, // radius
1820 110*FRACUNIT, // height
1821 1000, // mass
1822 0, // damage
1823 sfx_dmact, // activesound
1824 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1825 S_NULL // raisestate
1826 },
1827
1828 { // MT_PAIN
1829 71, // doomednum
1830 S_PAIN_STND, // spawnstate
1831 400, // spawnhealth
1832 S_PAIN_RUN1, // seestate
1833 sfx_pesit, // seesound
1834 8, // reactiontime
1835 0, // attacksound
1836 S_PAIN_PAIN, // painstate
1837 128, // painchance
1838 sfx_pepain, // painsound
1839 0, // meleestate
1840 S_PAIN_ATK1, // missilestate
1841 S_PAIN_DIE1, // deathstate
1842 S_NULL, // xdeathstate
1843 sfx_pedth, // deathsound
1844 8, // speed
1845 31*FRACUNIT, // radius
1846 56*FRACUNIT, // height
1847 400, // mass
1848 0, // damage
1849 sfx_dmact, // activesound
1850 MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags
1851 S_PAIN_RAISE1 // raisestate
1852 },
1853
1854 { // MT_WOLFSS
1855 84, // doomednum
1856 S_SSWV_STND, // spawnstate
1857 50, // spawnhealth
1858 S_SSWV_RUN1, // seestate
1859 sfx_sssit, // seesound
1860 8, // reactiontime
1861 0, // attacksound
1862 S_SSWV_PAIN, // painstate
1863 170, // painchance
1864 sfx_popain, // painsound
1865 0, // meleestate
1866 S_SSWV_ATK1, // missilestate
1867 S_SSWV_DIE1, // deathstate
1868 S_SSWV_XDIE1, // xdeathstate
1869 sfx_ssdth, // deathsound
1870 8, // speed
1871 20*FRACUNIT, // radius
1872 56*FRACUNIT, // height
1873 100, // mass
1874 0, // damage
1875 sfx_posact, // activesound
1876 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
1877 S_SSWV_RAISE1 // raisestate
1878 },
1879
1880 { // MT_KEEN
1881 72, // doomednum
1882 S_KEENSTND, // spawnstate
1883 100, // spawnhealth
1884 S_NULL, // seestate
1885 sfx_None, // seesound
1886 8, // reactiontime
1887 sfx_None, // attacksound
1888 S_KEENPAIN, // painstate
1889 256, // painchance
1890 sfx_keenpn, // painsound
1891 S_NULL, // meleestate
1892 S_NULL, // missilestate
1893 S_COMMKEEN, // deathstate
1894 S_NULL, // xdeathstate
1895 sfx_keendt, // deathsound
1896 0, // speed
1897 16*FRACUNIT, // radius
1898 72*FRACUNIT, // height
1899 10000000, // mass
1900 0, // damage
1901 sfx_None, // activesound
1902 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SHOOTABLE|MF_COUNTKILL, // flags
1903 S_NULL // raisestate
1904 },
1905
1906 { // MT_BOSSBRAIN
1907 88, // doomednum
1908 S_BRAIN, // spawnstate
1909 250, // spawnhealth
1910 S_NULL, // seestate
1911 sfx_None, // seesound
1912 8, // reactiontime
1913 sfx_None, // attacksound
1914 S_BRAIN_PAIN, // painstate
1915 255, // painchance
1916 sfx_bospn, // painsound
1917 S_NULL, // meleestate
1918 S_NULL, // missilestate
1919 S_BRAIN_DIE1, // deathstate
1920 S_NULL, // xdeathstate
1921 sfx_bosdth, // deathsound
1922 0, // speed
1923 16*FRACUNIT, // radius
1924 16*FRACUNIT, // height
1925 10000000, // mass
1926 0, // damage
1927 sfx_None, // activesound
1928 MF_SOLID|MF_SHOOTABLE, // flags
1929 S_NULL // raisestate
1930 },
1931
1932 { // MT_BOSSSPIT
1933 89, // doomednum
1934 S_BRAINEYE, // spawnstate
1935 1000, // spawnhealth
1936 S_BRAINEYESEE, // seestate
1937 sfx_None, // seesound
1938 8, // reactiontime
1939 sfx_None, // attacksound
1940 S_NULL, // painstate
1941 0, // painchance
1942 sfx_None, // painsound
1943 S_NULL, // meleestate
1944 S_NULL, // missilestate
1945 S_NULL, // deathstate
1946 S_NULL, // xdeathstate
1947 sfx_None, // deathsound
1948 0, // speed
1949 20*FRACUNIT, // radius
1950 32*FRACUNIT, // height
1951 100, // mass
1952 0, // damage
1953 sfx_None, // activesound
1954 MF_NOBLOCKMAP|MF_NOSECTOR, // flags
1955 S_NULL // raisestate
1956 },
1957
1958 { // MT_BOSSTARGET
1959 87, // doomednum
1960 S_NULL, // spawnstate
1961 1000, // spawnhealth
1962 S_NULL, // seestate
1963 sfx_None, // seesound
1964 8, // reactiontime
1965 sfx_None, // attacksound
1966 S_NULL, // painstate
1967 0, // painchance
1968 sfx_None, // painsound
1969 S_NULL, // meleestate
1970 S_NULL, // missilestate
1971 S_NULL, // deathstate
1972 S_NULL, // xdeathstate
1973 sfx_None, // deathsound
1974 0, // speed
1975 20*FRACUNIT, // radius
1976 32*FRACUNIT, // height
1977 100, // mass
1978 0, // damage
1979 sfx_None, // activesound
1980 MF_NOBLOCKMAP|MF_NOSECTOR, // flags
1981 S_NULL // raisestate
1982 },
1983
1984 { // MT_SPAWNSHOT
1985 -1, // doomednum
1986 S_SPAWN1, // spawnstate
1987 1000, // spawnhealth
1988 S_NULL, // seestate
1989 sfx_bospit, // seesound
1990 8, // reactiontime
1991 sfx_None, // attacksound
1992 S_NULL, // painstate
1993 0, // painchance
1994 sfx_None, // painsound
1995 S_NULL, // meleestate
1996 S_NULL, // missilestate
1997 S_NULL, // deathstate
1998 S_NULL, // xdeathstate
1999 sfx_firxpl, // deathsound
2000 10*FRACUNIT, // speed
2001 6*FRACUNIT, // radius
2002 32*FRACUNIT, // height
2003 100, // mass
2004 3, // damage
2005 sfx_None, // activesound
2006 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP, // flags
2007 S_NULL // raisestate
2008 },
2009
2010 { // MT_SPAWNFIRE
2011 -1, // doomednum
2012 S_SPAWNFIRE1, // spawnstate
2013 1000, // spawnhealth
2014 S_NULL, // seestate
2015 sfx_None, // seesound
2016 8, // reactiontime
2017 sfx_None, // attacksound
2018 S_NULL, // painstate
2019 0, // painchance
2020 sfx_None, // painsound
2021 S_NULL, // meleestate
2022 S_NULL, // missilestate
2023 S_NULL, // deathstate
2024 S_NULL, // xdeathstate
2025 sfx_None, // deathsound
2026 0, // speed
2027 20*FRACUNIT, // radius
2028 16*FRACUNIT, // height
2029 100, // mass
2030 0, // damage
2031 sfx_None, // activesound
2032 MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2033 S_NULL // raisestate
2034 },
2035
2036 { // MT_BARREL
2037 2035, // doomednum
2038 S_BAR1, // spawnstate
2039 20, // spawnhealth
2040 S_NULL, // seestate
2041 sfx_None, // seesound
2042 8, // reactiontime
2043 sfx_None, // attacksound
2044 S_NULL, // painstate
2045 0, // painchance
2046 sfx_None, // painsound
2047 S_NULL, // meleestate
2048 S_NULL, // missilestate
2049 S_BEXP, // deathstate
2050 S_NULL, // xdeathstate
2051 sfx_barexp, // deathsound
2052 0, // speed
2053 10*FRACUNIT, // radius
2054 42*FRACUNIT, // height
2055 100, // mass
2056 0, // damage
2057 sfx_None, // activesound
2058 MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags
2059 S_NULL // raisestate
2060 },
2061
2062 { // MT_TROOPSHOT
2063 -1, // doomednum
2064 S_TBALL1, // spawnstate
2065 1000, // spawnhealth
2066 S_NULL, // seestate
2067 sfx_firsht, // seesound
2068 8, // reactiontime
2069 sfx_None, // attacksound
2070 S_NULL, // painstate
2071 0, // painchance
2072 sfx_None, // painsound
2073 S_NULL, // meleestate
2074 S_NULL, // missilestate
2075 S_TBALLX1, // deathstate
2076 S_NULL, // xdeathstate
2077 sfx_firxpl, // deathsound
2078 10*FRACUNIT, // speed
2079 6*FRACUNIT, // radius
2080 8*FRACUNIT, // height
2081 100, // mass
2082 3, // damage
2083 sfx_None, // activesound
2084 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2085 S_NULL // raisestate
2086 },
2087
2088 { // MT_HEADSHOT
2089 -1, // doomednum
2090 S_RBALL1, // spawnstate
2091 1000, // spawnhealth
2092 S_NULL, // seestate
2093 sfx_firsht, // seesound
2094 8, // reactiontime
2095 sfx_None, // attacksound
2096 S_NULL, // painstate
2097 0, // painchance
2098 sfx_None, // painsound
2099 S_NULL, // meleestate
2100 S_NULL, // missilestate
2101 S_RBALLX1, // deathstate
2102 S_NULL, // xdeathstate
2103 sfx_firxpl, // deathsound
2104 10*FRACUNIT, // speed
2105 6*FRACUNIT, // radius
2106 8*FRACUNIT, // height
2107 100, // mass
2108 5, // damage
2109 sfx_None, // activesound
2110 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares, // flags
2111 S_NULL // raisestate
2112 },
2113
2114 { // MT_ROCKET
2115 -1, // doomednum
2116 S_ROCKET, // spawnstate
2117 1000, // spawnhealth
2118 S_NULL, // seestate
2119 sfx_rlaunc, // seesound
2120 8, // reactiontime
2121 sfx_None, // attacksound
2122 S_NULL, // painstate
2123 0, // painchance
2124 sfx_None, // painsound
2125 S_NULL, // meleestate
2126 S_NULL, // missilestate
2127 S_EXPLODE1, // deathstate
2128 S_NULL, // xdeathstate
2129 sfx_barexp, // deathsound
2130 20*FRACUNIT, // speed
2131 11*FRACUNIT, // radius
2132 8*FRACUNIT, // height
2133 100, // mass
2134 20, // damage
2135 sfx_None, // activesound
2136 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
2137 S_NULL // raisestate
2138 },
2139
2140 { // MT_PLASMA
2141 -1, // doomednum
2142 S_PLASBALL, // spawnstate
2143 1000, // spawnhealth
2144 S_NULL, // seestate
2145 sfx_plasma, // seesound
2146 8, // reactiontime
2147 sfx_None, // attacksound
2148 S_NULL, // painstate
2149 0, // painchance
2150 sfx_None, // painsound
2151 S_NULL, // meleestate
2152 S_NULL, // missilestate
2153 S_PLASEXP, // deathstate
2154 S_NULL, // xdeathstate
2155 sfx_firxpl, // deathsound
2156 25*FRACUNIT, // speed
2157 13*FRACUNIT, // radius
2158 8*FRACUNIT, // height
2159 100, // mass
2160 5, // damage
2161 sfx_None, // activesound
2162 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2163 S_NULL // raisestate
2164 },
2165
2166 { // MT_BFG
2167 -1, // doomednum
2168 S_BFGSHOT, // spawnstate
2169 1000, // spawnhealth
2170 S_NULL, // seestate
2171 0, // seesound
2172 8, // reactiontime
2173 sfx_None, // attacksound
2174 S_NULL, // painstate
2175 0, // painchance
2176 sfx_None, // painsound
2177 S_NULL, // meleestate
2178 S_NULL, // missilestate
2179 S_BFGLAND, // deathstate
2180 S_NULL, // xdeathstate
2181 sfx_rxplod, // deathsound
2182 25*FRACUNIT, // speed
2183 13*FRACUNIT, // radius
2184 8*FRACUNIT, // height
2185 100, // mass
2186 100, // damage
2187 sfx_None, // activesound
2188 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2189 S_NULL // raisestate
2190 },
2191
2192 { // MT_ARACHPLAZ
2193 -1, // doomednum
2194 S_ARACH_PLAZ, // spawnstate
2195 1000, // spawnhealth
2196 S_NULL, // seestate
2197 sfx_plasma, // seesound
2198 8, // reactiontime
2199 sfx_None, // attacksound
2200 S_NULL, // painstate
2201 0, // painchance
2202 sfx_None, // painsound
2203 S_NULL, // meleestate
2204 S_NULL, // missilestate
2205 S_ARACH_PLEX, // deathstate
2206 S_NULL, // xdeathstate
2207 sfx_firxpl, // deathsound
2208 25*FRACUNIT, // speed
2209 13*FRACUNIT, // radius
2210 8*FRACUNIT, // height
2211 100, // mass
2212 5, // damage
2213 sfx_None, // activesound
2214 MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2215 S_NULL // raisestate
2216 },
2217
2218 { // MT_PUFF
2219 -1, // doomednum
2220 S_PUFF1, // spawnstate
2221 1000, // spawnhealth
2222 S_NULL, // seestate
2223 sfx_None, // seesound
2224 8, // reactiontime
2225 sfx_None, // attacksound
2226 S_NULL, // painstate
2227 0, // painchance
2228 sfx_None, // painsound
2229 S_NULL, // meleestate
2230 S_NULL, // missilestate
2231 S_NULL, // deathstate
2232 S_NULL, // xdeathstate
2233 sfx_None, // deathsound
2234 0, // speed
2235 20*FRACUNIT, // radius
2236 16*FRACUNIT, // height
2237 100, // mass
2238 0, // damage
2239 sfx_None, // activesound
2240 MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2241 S_NULL // raisestate
2242 },
2243
2244 { // MT_BLOOD
2245 -1, // doomednum
2246 S_BLOOD1, // spawnstate
2247 1000, // spawnhealth
2248 S_NULL, // seestate
2249 sfx_None, // seesound
2250 8, // reactiontime
2251 sfx_None, // attacksound
2252 S_NULL, // painstate
2253 0, // painchance
2254 sfx_None, // painsound
2255 S_NULL, // meleestate
2256 S_NULL, // missilestate
2257 S_NULL, // deathstate
2258 S_NULL, // xdeathstate
2259 sfx_None, // deathsound
2260 0, // speed
2261 20*FRACUNIT, // radius
2262 16*FRACUNIT, // height
2263 100, // mass
2264 0, // damage
2265 sfx_None, // activesound
2266 MF_NOBLOCKMAP, // flags
2267 S_NULL // raisestate
2268 },
2269
2270 { // MT_TFOG
2271 -1, // doomednum
2272 S_TFOG, // spawnstate
2273 1000, // spawnhealth
2274 S_NULL, // seestate
2275 sfx_None, // seesound
2276 8, // reactiontime
2277 sfx_None, // attacksound
2278 S_NULL, // painstate
2279 0, // painchance
2280 sfx_None, // painsound
2281 S_NULL, // meleestate
2282 S_NULL, // missilestate
2283 S_NULL, // deathstate
2284 S_NULL, // xdeathstate
2285 sfx_None, // deathsound
2286 0, // speed
2287 20*FRACUNIT, // radius
2288 16*FRACUNIT, // height
2289 100, // mass
2290 0, // damage
2291 sfx_None, // activesound
2292 MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2293 S_NULL // raisestate
2294 },
2295
2296 { // MT_IFOG
2297 -1, // doomednum
2298 S_IFOG, // spawnstate
2299 1000, // spawnhealth
2300 S_NULL, // seestate
2301 sfx_None, // seesound
2302 8, // reactiontime
2303 sfx_None, // attacksound
2304 S_NULL, // painstate
2305 0, // painchance
2306 sfx_None, // painsound
2307 S_NULL, // meleestate
2308 S_NULL, // missilestate
2309 S_NULL, // deathstate
2310 S_NULL, // xdeathstate
2311 sfx_None, // deathsound
2312 0, // speed
2313 20*FRACUNIT, // radius
2314 16*FRACUNIT, // height
2315 100, // mass
2316 0, // damage
2317 sfx_None, // activesound
2318 MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares
2319 S_NULL // raisestate
2320 },
2321
2322 { // MT_TELEPORTMAN
2323 14, // doomednum
2324 S_NULL, // spawnstate
2325 1000, // spawnhealth
2326 S_NULL, // seestate
2327 sfx_None, // seesound
2328 8, // reactiontime
2329 sfx_None, // attacksound
2330 S_NULL, // painstate
2331 0, // painchance
2332 sfx_None, // painsound
2333 S_NULL, // meleestate
2334 S_NULL, // missilestate
2335 S_NULL, // deathstate
2336 S_NULL, // xdeathstate
2337 sfx_None, // deathsound
2338 0, // speed
2339 20*FRACUNIT, // radius
2340 16*FRACUNIT, // height
2341 100, // mass
2342 0, // damage
2343 sfx_None, // activesound
2344 MF_NOBLOCKMAP|MF_NOSECTOR, // flags
2345 S_NULL // raisestate
2346 },
2347
2348 { // MT_EXTRABFG
2349 -1, // doomednum
2350 S_BFGEXP, // spawnstate
2351 1000, // spawnhealth
2352 S_NULL, // seestate
2353 sfx_None, // seesound
2354 8, // reactiontime
2355 sfx_None, // attacksound
2356 S_NULL, // painstate
2357 0, // painchance
2358 sfx_None, // painsound
2359 S_NULL, // meleestate
2360 S_NULL, // missilestate
2361 S_NULL, // deathstate
2362 S_NULL, // xdeathstate
2363 sfx_None, // deathsound
2364 0, // speed
2365 20*FRACUNIT, // radius
2366 16*FRACUNIT, // height
2367 100, // mass
2368 0, // damage
2369 sfx_None, // activesound
2370 MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
2371 S_NULL // raisestate
2372 },
2373
2374 { // MT_MISC0
2375 2018, // doomednum
2376 S_ARM1, // spawnstate
2377 1000, // spawnhealth
2378 S_NULL, // seestate
2379 sfx_None, // seesound
2380 8, // reactiontime
2381 sfx_None, // attacksound
2382 S_NULL, // painstate
2383 0, // painchance
2384 sfx_None, // painsound
2385 S_NULL, // meleestate
2386 S_NULL, // missilestate
2387 S_NULL, // deathstate
2388 S_NULL, // xdeathstate
2389 sfx_None, // deathsound
2390 0, // speed
2391 20*FRACUNIT, // radius
2392 16*FRACUNIT, // height
2393 100, // mass
2394 0, // damage
2395 sfx_None, // activesound
2396 MF_SPECIAL, // flags
2397 S_NULL // raisestate
2398 },
2399
2400 { // MT_MISC1
2401 2019, // doomednum
2402 S_ARM2, // spawnstate
2403 1000, // spawnhealth
2404 S_NULL, // seestate
2405 sfx_None, // seesound
2406 8, // reactiontime
2407 sfx_None, // attacksound
2408 S_NULL, // painstate
2409 0, // painchance
2410 sfx_None, // painsound
2411 S_NULL, // meleestate
2412 S_NULL, // missilestate
2413 S_NULL, // deathstate
2414 S_NULL, // xdeathstate
2415 sfx_None, // deathsound
2416 0, // speed
2417 20*FRACUNIT, // radius
2418 16*FRACUNIT, // height
2419 100, // mass
2420 0, // damage
2421 sfx_None, // activesound
2422 MF_SPECIAL, // flags
2423 S_NULL // raisestate
2424 },
2425
2426 { // MT_MISC2
2427 2014, // doomednum
2428 S_BON1, // spawnstate
2429 1000, // spawnhealth
2430 S_NULL, // seestate
2431 sfx_None, // seesound
2432 8, // reactiontime
2433 sfx_None, // attacksound
2434 S_NULL, // painstate
2435 0, // painchance
2436 sfx_None, // painsound
2437 S_NULL, // meleestate
2438 S_NULL, // missilestate
2439 S_NULL, // deathstate
2440 S_NULL, // xdeathstate
2441 sfx_None, // deathsound
2442 0, // speed
2443 20*FRACUNIT, // radius
2444 16*FRACUNIT, // height
2445 100, // mass
2446 0, // damage
2447 sfx_None, // activesound
2448 MF_SPECIAL|MF_COUNTITEM, // flags
2449 S_NULL // raisestate
2450 },
2451
2452 { // MT_MISC3
2453 2015, // doomednum
2454 S_BON2, // spawnstate
2455 1000, // spawnhealth
2456 S_NULL, // seestate
2457 sfx_None, // seesound
2458 8, // reactiontime
2459 sfx_None, // attacksound
2460 S_NULL, // painstate
2461 0, // painchance
2462 sfx_None, // painsound
2463 S_NULL, // meleestate
2464 S_NULL, // missilestate
2465 S_NULL, // deathstate
2466 S_NULL, // xdeathstate
2467 sfx_None, // deathsound
2468 0, // speed
2469 20*FRACUNIT, // radius
2470 16*FRACUNIT, // height
2471 100, // mass
2472 0, // damage
2473 sfx_None, // activesound
2474 MF_SPECIAL|MF_COUNTITEM, // flags
2475 S_NULL // raisestate
2476 },
2477
2478 { // MT_MISC4
2479 5, // doomednum
2480 S_BKEY, // spawnstate
2481 1000, // spawnhealth
2482 S_NULL, // seestate
2483 sfx_None, // seesound
2484 8, // reactiontime
2485 sfx_None, // attacksound
2486 S_NULL, // painstate
2487 0, // painchance
2488 sfx_None, // painsound
2489 S_NULL, // meleestate
2490 S_NULL, // missilestate
2491 S_NULL, // deathstate
2492 S_NULL, // xdeathstate
2493 sfx_None, // deathsound
2494 0, // speed
2495 20*FRACUNIT, // radius
2496 16*FRACUNIT, // height
2497 100, // mass
2498 0, // damage
2499 sfx_None, // activesound
2500 MF_SPECIAL|MF_NOTDMATCH, // flags
2501 S_NULL // raisestate
2502 },
2503
2504 { // MT_MISC5
2505 13, // doomednum
2506 S_RKEY, // spawnstate
2507 1000, // spawnhealth
2508 S_NULL, // seestate
2509 sfx_None, // seesound
2510 8, // reactiontime
2511 sfx_None, // attacksound
2512 S_NULL, // painstate
2513 0, // painchance
2514 sfx_None, // painsound
2515 S_NULL, // meleestate
2516 S_NULL, // missilestate
2517 S_NULL, // deathstate
2518 S_NULL, // xdeathstate
2519 sfx_None, // deathsound
2520 0, // speed
2521 20*FRACUNIT, // radius
2522 16*FRACUNIT, // height
2523 100, // mass
2524 0, // damage
2525 sfx_None, // activesound
2526 MF_SPECIAL|MF_NOTDMATCH, // flags
2527 S_NULL // raisestate
2528 },
2529
2530 { // MT_MISC6
2531 6, // doomednum
2532 S_YKEY, // spawnstate
2533 1000, // spawnhealth
2534 S_NULL, // seestate
2535 sfx_None, // seesound
2536 8, // reactiontime
2537 sfx_None, // attacksound
2538 S_NULL, // painstate
2539 0, // painchance
2540 sfx_None, // painsound
2541 S_NULL, // meleestate
2542 S_NULL, // missilestate
2543 S_NULL, // deathstate
2544 S_NULL, // xdeathstate
2545 sfx_None, // deathsound
2546 0, // speed
2547 20*FRACUNIT, // radius
2548 16*FRACUNIT, // height
2549 100, // mass
2550 0, // damage
2551 sfx_None, // activesound
2552 MF_SPECIAL|MF_NOTDMATCH, // flags
2553 S_NULL // raisestate
2554 },
2555
2556 { // MT_MISC7
2557 39, // doomednum
2558 S_YSKULL, // spawnstate
2559 1000, // spawnhealth
2560 S_NULL, // seestate
2561 sfx_None, // seesound
2562 8, // reactiontime
2563 sfx_None, // attacksound
2564 S_NULL, // painstate
2565 0, // painchance
2566 sfx_None, // painsound
2567 S_NULL, // meleestate
2568 S_NULL, // missilestate
2569 S_NULL, // deathstate
2570 S_NULL, // xdeathstate
2571 sfx_None, // deathsound
2572 0, // speed
2573 20*FRACUNIT, // radius
2574 16*FRACUNIT, // height
2575 100, // mass
2576 0, // damage
2577 sfx_None, // activesound
2578 MF_SPECIAL|MF_NOTDMATCH, // flags
2579 S_NULL // raisestate
2580 },
2581
2582 { // MT_MISC8
2583 38, // doomednum
2584 S_RSKULL, // spawnstate
2585 1000, // spawnhealth
2586 S_NULL, // seestate
2587 sfx_None, // seesound
2588 8, // reactiontime
2589 sfx_None, // attacksound
2590 S_NULL, // painstate
2591 0, // painchance
2592 sfx_None, // painsound
2593 S_NULL, // meleestate
2594 S_NULL, // missilestate
2595 S_NULL, // deathstate
2596 S_NULL, // xdeathstate
2597 sfx_None, // deathsound
2598 0, // speed
2599 20*FRACUNIT, // radius
2600 16*FRACUNIT, // height
2601 100, // mass
2602 0, // damage
2603 sfx_None, // activesound
2604 MF_SPECIAL|MF_NOTDMATCH, // flags
2605 S_NULL // raisestate
2606 },
2607
2608 { // MT_MISC9
2609 40, // doomednum
2610 S_BSKULL, // spawnstate
2611 1000, // spawnhealth
2612 S_NULL, // seestate
2613 sfx_None, // seesound
2614 8, // reactiontime
2615 sfx_None, // attacksound
2616 S_NULL, // painstate
2617 0, // painchance
2618 sfx_None, // painsound
2619 S_NULL, // meleestate
2620 S_NULL, // missilestate
2621 S_NULL, // deathstate
2622 S_NULL, // xdeathstate
2623 sfx_None, // deathsound
2624 0, // speed
2625 20*FRACUNIT, // radius
2626 16*FRACUNIT, // height
2627 100, // mass
2628 0, // damage
2629 sfx_None, // activesound
2630 MF_SPECIAL|MF_NOTDMATCH, // flags
2631 S_NULL // raisestate
2632 },
2633
2634 { // MT_MISC10
2635 2011, // doomednum
2636 S_STIM, // spawnstate
2637 1000, // spawnhealth
2638 S_NULL, // seestate
2639 sfx_None, // seesound
2640 8, // reactiontime
2641 sfx_None, // attacksound
2642 S_NULL, // painstate
2643 0, // painchance
2644 sfx_None, // painsound
2645 S_NULL, // meleestate
2646 S_NULL, // missilestate
2647 S_NULL, // deathstate
2648 S_NULL, // xdeathstate
2649 sfx_None, // deathsound
2650 0, // speed
2651 20*FRACUNIT, // radius
2652 16*FRACUNIT, // height
2653 100, // mass
2654 0, // damage
2655 sfx_None, // activesound
2656 MF_SPECIAL, // flags
2657 S_NULL // raisestate
2658 },
2659
2660 { // MT_MISC11
2661 2012, // doomednum
2662 S_MEDI, // spawnstate
2663 1000, // spawnhealth
2664 S_NULL, // seestate
2665 sfx_None, // seesound
2666 8, // reactiontime
2667 sfx_None, // attacksound
2668 S_NULL, // painstate
2669 0, // painchance
2670 sfx_None, // painsound
2671 S_NULL, // meleestate
2672 S_NULL, // missilestate
2673 S_NULL, // deathstate
2674 S_NULL, // xdeathstate
2675 sfx_None, // deathsound
2676 0, // speed
2677 20*FRACUNIT, // radius
2678 16*FRACUNIT, // height
2679 100, // mass
2680 0, // damage
2681 sfx_None, // activesound
2682 MF_SPECIAL, // flags
2683 S_NULL // raisestate
2684 },
2685
2686 { // MT_MISC12
2687 2013, // doomednum
2688 S_SOUL, // spawnstate
2689 1000, // spawnhealth
2690 S_NULL, // seestate
2691 sfx_None, // seesound
2692 8, // reactiontime
2693 sfx_None, // attacksound
2694 S_NULL, // painstate
2695 0, // painchance
2696 sfx_None, // painsound
2697 S_NULL, // meleestate
2698 S_NULL, // missilestate
2699 S_NULL, // deathstate
2700 S_NULL, // xdeathstate
2701 sfx_None, // deathsound
2702 0, // speed
2703 20*FRACUNIT, // radius
2704 16*FRACUNIT, // height
2705 100, // mass
2706 0, // damage
2707 sfx_None, // activesound
2708 MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98
2709 S_NULL // raisestate
2710 },
2711
2712 { // MT_INV
2713 2022, // doomednum
2714 S_PINV, // spawnstate
2715 1000, // spawnhealth
2716 S_NULL, // seestate
2717 sfx_None, // seesound
2718 8, // reactiontime
2719 sfx_None, // attacksound
2720 S_NULL, // painstate
2721 0, // painchance
2722 sfx_None, // painsound
2723 S_NULL, // meleestate
2724 S_NULL, // missilestate
2725 S_NULL, // deathstate
2726 S_NULL, // xdeathstate
2727 sfx_None, // deathsound
2728 0, // speed
2729 20*FRACUNIT, // radius
2730 16*FRACUNIT, // height
2731 100, // mass
2732 0, // damage
2733 sfx_None, // activesound
2734 MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98
2735 S_NULL // raisestate
2736 },
2737
2738 { // MT_MISC13
2739 2023, // doomednum
2740 S_PSTR, // spawnstate
2741 1000, // spawnhealth
2742 S_NULL, // seestate
2743 sfx_None, // seesound
2744 8, // reactiontime
2745 sfx_None, // attacksound
2746 S_NULL, // painstate
2747 0, // painchance
2748 sfx_None, // painsound
2749 S_NULL, // meleestate
2750 S_NULL, // missilestate
2751 S_NULL, // deathstate
2752 S_NULL, // xdeathstate
2753 sfx_None, // deathsound
2754 0, // speed
2755 20*FRACUNIT, // radius
2756 16*FRACUNIT, // height
2757 100, // mass
2758 0, // damage
2759 sfx_None, // activesound
2760 MF_SPECIAL|MF_COUNTITEM, // flags
2761 S_NULL // raisestate
2762 },
2763
2764 { // MT_INS
2765 2024, // doomednum
2766 S_PINS, // spawnstate
2767 1000, // spawnhealth
2768 S_NULL, // seestate
2769 sfx_None, // seesound
2770 8, // reactiontime
2771 sfx_None, // attacksound
2772 S_NULL, // painstate
2773 0, // painchance
2774 sfx_None, // painsound
2775 S_NULL, // meleestate
2776 S_NULL, // missilestate
2777 S_NULL, // deathstate
2778 S_NULL, // xdeathstate
2779 sfx_None, // deathsound
2780 0, // speed
2781 20*FRACUNIT, // radius
2782 16*FRACUNIT, // height
2783 100, // mass
2784 0, // damage
2785 sfx_None, // activesound
2786 MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98
2787 S_NULL // raisestate
2788 },
2789
2790 { // MT_MISC14
2791 2025, // doomednum
2792 S_SUIT, // spawnstate
2793 1000, // spawnhealth
2794 S_NULL, // seestate
2795 sfx_None, // seesound
2796 8, // reactiontime
2797 sfx_None, // attacksound
2798 S_NULL, // painstate
2799 0, // painchance
2800 sfx_None, // painsound
2801 S_NULL, // meleestate
2802 S_NULL, // missilestate
2803 S_NULL, // deathstate
2804 S_NULL, // xdeathstate
2805 sfx_None, // deathsound
2806 0, // speed
2807 20*FRACUNIT, // radius
2808 16*FRACUNIT, // height
2809 100, // mass
2810 0, // damage
2811 sfx_None, // activesound
2812 MF_SPECIAL, // flags
2813 S_NULL // raisestate
2814 },
2815
2816 { // MT_MISC15
2817 2026, // doomednum
2818 S_PMAP, // spawnstate
2819 1000, // spawnhealth
2820 S_NULL, // seestate
2821 sfx_None, // seesound
2822 8, // reactiontime
2823 sfx_None, // attacksound
2824 S_NULL, // painstate
2825 0, // painchance
2826 sfx_None, // painsound
2827 S_NULL, // meleestate
2828 S_NULL, // missilestate
2829 S_NULL, // deathstate
2830 S_NULL, // xdeathstate
2831 sfx_None, // deathsound
2832 0, // speed
2833 20*FRACUNIT, // radius
2834 16*FRACUNIT, // height
2835 100, // mass
2836 0, // damage
2837 sfx_None, // activesound
2838 MF_SPECIAL|MF_COUNTITEM, // flags
2839 S_NULL // raisestate
2840 },
2841
2842 { // MT_MISC16
2843 2045, // doomednum
2844 S_PVIS, // spawnstate
2845 1000, // spawnhealth
2846 S_NULL, // seestate
2847 sfx_None, // seesound
2848 8, // reactiontime
2849 sfx_None, // attacksound
2850 S_NULL, // painstate
2851 0, // painchance
2852 sfx_None, // painsound
2853 S_NULL, // meleestate
2854 S_NULL, // missilestate
2855 S_NULL, // deathstate
2856 S_NULL, // xdeathstate
2857 sfx_None, // deathsound
2858 0, // speed
2859 20*FRACUNIT, // radius
2860 16*FRACUNIT, // height
2861 100, // mass
2862 0, // damage
2863 sfx_None, // activesound
2864 MF_SPECIAL|MF_COUNTITEM, // flags
2865 S_NULL // raisestate
2866 },
2867
2868 { // MT_MEGA
2869 83, // doomednum
2870 S_MEGA, // spawnstate
2871 1000, // spawnhealth
2872 S_NULL, // seestate
2873 sfx_None, // seesound
2874 8, // reactiontime
2875 sfx_None, // attacksound
2876 S_NULL, // painstate
2877 0, // painchance
2878 sfx_None, // painsound
2879 S_NULL, // meleestate
2880 S_NULL, // missilestate
2881 S_NULL, // deathstate
2882 S_NULL, // xdeathstate
2883 sfx_None, // deathsound
2884 0, // speed
2885 20*FRACUNIT, // radius
2886 16*FRACUNIT, // height
2887 100, // mass
2888 0, // damage
2889 sfx_None, // activesound
2890 MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98
2891 S_NULL // raisestate
2892 },
2893
2894 { // MT_CLIP
2895 2007, // doomednum
2896 S_CLIP, // spawnstate
2897 1000, // spawnhealth
2898 S_NULL, // seestate
2899 sfx_None, // seesound
2900 8, // reactiontime
2901 sfx_None, // attacksound
2902 S_NULL, // painstate
2903 0, // painchance
2904 sfx_None, // painsound
2905 S_NULL, // meleestate
2906 S_NULL, // missilestate
2907 S_NULL, // deathstate
2908 S_NULL, // xdeathstate
2909 sfx_None, // deathsound
2910 0, // speed
2911 20*FRACUNIT, // radius
2912 16*FRACUNIT, // height
2913 100, // mass
2914 0, // damage
2915 sfx_None, // activesound
2916 MF_SPECIAL, // flags
2917 S_NULL // raisestate
2918 },
2919
2920 { // MT_MISC17
2921 2048, // doomednum
2922 S_AMMO, // spawnstate
2923 1000, // spawnhealth
2924 S_NULL, // seestate
2925 sfx_None, // seesound
2926 8, // reactiontime
2927 sfx_None, // attacksound
2928 S_NULL, // painstate
2929 0, // painchance
2930 sfx_None, // painsound
2931 S_NULL, // meleestate
2932 S_NULL, // missilestate
2933 S_NULL, // deathstate
2934 S_NULL, // xdeathstate
2935 sfx_None, // deathsound
2936 0, // speed
2937 20*FRACUNIT, // radius
2938 16*FRACUNIT, // height
2939 100, // mass
2940 0, // damage
2941 sfx_None, // activesound
2942 MF_SPECIAL, // flags
2943 S_NULL // raisestate
2944 },
2945
2946 { // MT_MISC18
2947 2010, // doomednum
2948 S_ROCK, // spawnstate
2949 1000, // spawnhealth
2950 S_NULL, // seestate
2951 sfx_None, // seesound
2952 8, // reactiontime
2953 sfx_None, // attacksound
2954 S_NULL, // painstate
2955 0, // painchance
2956 sfx_None, // painsound
2957 S_NULL, // meleestate
2958 S_NULL, // missilestate
2959 S_NULL, // deathstate
2960 S_NULL, // xdeathstate
2961 sfx_None, // deathsound
2962 0, // speed
2963 20*FRACUNIT, // radius
2964 16*FRACUNIT, // height
2965 100, // mass
2966 0, // damage
2967 sfx_None, // activesound
2968 MF_SPECIAL, // flags
2969 S_NULL // raisestate
2970 },
2971
2972 { // MT_MISC19
2973 2046, // doomednum
2974 S_BROK, // spawnstate
2975 1000, // spawnhealth
2976 S_NULL, // seestate
2977 sfx_None, // seesound
2978 8, // reactiontime
2979 sfx_None, // attacksound
2980 S_NULL, // painstate
2981 0, // painchance
2982 sfx_None, // painsound
2983 S_NULL, // meleestate
2984 S_NULL, // missilestate
2985 S_NULL, // deathstate
2986 S_NULL, // xdeathstate
2987 sfx_None, // deathsound
2988 0, // speed
2989 20*FRACUNIT, // radius
2990 16*FRACUNIT, // height
2991 100, // mass
2992 0, // damage
2993 sfx_None, // activesound
2994 MF_SPECIAL, // flags
2995 S_NULL // raisestate
2996 },
2997
2998 { // MT_MISC20
2999 2047, // doomednum
3000 S_CELL, // spawnstate
3001 1000, // spawnhealth
3002 S_NULL, // seestate
3003 sfx_None, // seesound
3004 8, // reactiontime
3005 sfx_None, // attacksound
3006 S_NULL, // painstate
3007 0, // painchance
3008 sfx_None, // painsound
3009 S_NULL, // meleestate
3010 S_NULL, // missilestate
3011 S_NULL, // deathstate
3012 S_NULL, // xdeathstate
3013 sfx_None, // deathsound
3014 0, // speed
3015 20*FRACUNIT, // radius
3016 16*FRACUNIT, // height
3017 100, // mass
3018 0, // damage
3019 sfx_None, // activesound
3020 MF_SPECIAL, // flags
3021 S_NULL // raisestate
3022 },
3023
3024 { // MT_MISC21
3025 17, // doomednum
3026 S_CELP, // spawnstate
3027 1000, // spawnhealth
3028 S_NULL, // seestate
3029 sfx_None, // seesound
3030 8, // reactiontime
3031 sfx_None, // attacksound
3032 S_NULL, // painstate
3033 0, // painchance
3034 sfx_None, // painsound
3035 S_NULL, // meleestate
3036 S_NULL, // missilestate
3037 S_NULL, // deathstate
3038 S_NULL, // xdeathstate
3039 sfx_None, // deathsound
3040 0, // speed
3041 20*FRACUNIT, // radius
3042 16*FRACUNIT, // height
3043 100, // mass
3044 0, // damage
3045 sfx_None, // activesound
3046 MF_SPECIAL, // flags
3047 S_NULL // raisestate
3048 },
3049
3050 { // MT_MISC22
3051 2008, // doomednum
3052 S_SHEL, // spawnstate
3053 1000, // spawnhealth
3054 S_NULL, // seestate
3055 sfx_None, // seesound
3056 8, // reactiontime
3057 sfx_None, // attacksound
3058 S_NULL, // painstate
3059 0, // painchance
3060 sfx_None, // painsound
3061 S_NULL, // meleestate
3062 S_NULL, // missilestate
3063 S_NULL, // deathstate
3064 S_NULL, // xdeathstate
3065 sfx_None, // deathsound
3066 0, // speed
3067 20*FRACUNIT, // radius
3068 16*FRACUNIT, // height
3069 100, // mass
3070 0, // damage
3071 sfx_None, // activesound
3072 MF_SPECIAL, // flags
3073 S_NULL // raisestate
3074 },
3075
3076 { // MT_MISC23
3077 2049, // doomednum
3078 S_SBOX, // spawnstate
3079 1000, // spawnhealth
3080 S_NULL, // seestate
3081 sfx_None, // seesound
3082 8, // reactiontime
3083 sfx_None, // attacksound
3084 S_NULL, // painstate
3085 0, // painchance
3086 sfx_None, // painsound
3087 S_NULL, // meleestate
3088 S_NULL, // missilestate
3089 S_NULL, // deathstate
3090 S_NULL, // xdeathstate
3091 sfx_None, // deathsound
3092 0, // speed
3093 20*FRACUNIT, // radius
3094 16*FRACUNIT, // height
3095 100, // mass
3096 0, // damage
3097 sfx_None, // activesound
3098 MF_SPECIAL, // flags
3099 S_NULL // raisestate
3100 },
3101
3102 { // MT_MISC24
3103 8, // doomednum
3104 S_BPAK, // spawnstate
3105 1000, // spawnhealth
3106 S_NULL, // seestate
3107 sfx_None, // seesound
3108 8, // reactiontime
3109 sfx_None, // attacksound
3110 S_NULL, // painstate
3111 0, // painchance
3112 sfx_None, // painsound
3113 S_NULL, // meleestate
3114 S_NULL, // missilestate
3115 S_NULL, // deathstate
3116 S_NULL, // xdeathstate
3117 sfx_None, // deathsound
3118 0, // speed
3119 20*FRACUNIT, // radius
3120 16*FRACUNIT, // height
3121 100, // mass
3122 0, // damage
3123 sfx_None, // activesound
3124 MF_SPECIAL, // flags
3125 S_NULL // raisestate
3126 },
3127
3128 { // MT_MISC25
3129 2006, // doomednum
3130 S_BFUG, // spawnstate
3131 1000, // spawnhealth
3132 S_NULL, // seestate
3133 sfx_None, // seesound
3134 8, // reactiontime
3135 sfx_None, // attacksound
3136 S_NULL, // painstate
3137 0, // painchance
3138 sfx_None, // painsound
3139 S_NULL, // meleestate
3140 S_NULL, // missilestate
3141 S_NULL, // deathstate
3142 S_NULL, // xdeathstate
3143 sfx_None, // deathsound
3144 0, // speed
3145 20*FRACUNIT, // radius
3146 16*FRACUNIT, // height
3147 100, // mass
3148 0, // damage
3149 sfx_None, // activesound
3150 MF_SPECIAL, // flags
3151 S_NULL // raisestate
3152 },
3153
3154 { // MT_CHAINGUN
3155 2002, // doomednum
3156 S_MGUN, // spawnstate
3157 1000, // spawnhealth
3158 S_NULL, // seestate
3159 sfx_None, // seesound
3160 8, // reactiontime
3161 sfx_None, // attacksound
3162 S_NULL, // painstate
3163 0, // painchance
3164 sfx_None, // painsound
3165 S_NULL, // meleestate
3166 S_NULL, // missilestate
3167 S_NULL, // deathstate
3168 S_NULL, // xdeathstate
3169 sfx_None, // deathsound
3170 0, // speed
3171 20*FRACUNIT, // radius
3172 16*FRACUNIT, // height
3173 100, // mass
3174 0, // damage
3175 sfx_None, // activesound
3176 MF_SPECIAL, // flags
3177 S_NULL // raisestate
3178 },
3179
3180 { // MT_MISC26
3181 2005, // doomednum
3182 S_CSAW, // spawnstate
3183 1000, // spawnhealth
3184 S_NULL, // seestate
3185 sfx_None, // seesound
3186 8, // reactiontime
3187 sfx_None, // attacksound
3188 S_NULL, // painstate
3189 0, // painchance
3190 sfx_None, // painsound
3191 S_NULL, // meleestate
3192 S_NULL, // missilestate
3193 S_NULL, // deathstate
3194 S_NULL, // xdeathstate
3195 sfx_None, // deathsound
3196 0, // speed
3197 20*FRACUNIT, // radius
3198 16*FRACUNIT, // height
3199 100, // mass
3200 0, // damage
3201 sfx_None, // activesound
3202 MF_SPECIAL, // flags
3203 S_NULL // raisestate
3204 },
3205
3206 { // MT_MISC27
3207 2003, // doomednum
3208 S_LAUN, // spawnstate
3209 1000, // spawnhealth
3210 S_NULL, // seestate
3211 sfx_None, // seesound
3212 8, // reactiontime
3213 sfx_None, // attacksound
3214 S_NULL, // painstate
3215 0, // painchance
3216 sfx_None, // painsound
3217 S_NULL, // meleestate
3218 S_NULL, // missilestate
3219 S_NULL, // deathstate
3220 S_NULL, // xdeathstate
3221 sfx_None, // deathsound
3222 0, // speed
3223 20*FRACUNIT, // radius
3224 16*FRACUNIT, // height
3225 100, // mass
3226 0, // damage
3227 sfx_None, // activesound
3228 MF_SPECIAL, // flags
3229 S_NULL // raisestate
3230 },
3231
3232 { // MT_MISC28
3233 2004, // doomednum
3234 S_PLAS, // spawnstate
3235 1000, // spawnhealth
3236 S_NULL, // seestate
3237 sfx_None, // seesound
3238 8, // reactiontime
3239 sfx_None, // attacksound
3240 S_NULL, // painstate
3241 0, // painchance
3242 sfx_None, // painsound
3243 S_NULL, // meleestate
3244 S_NULL, // missilestate
3245 S_NULL, // deathstate
3246 S_NULL, // xdeathstate
3247 sfx_None, // deathsound
3248 0, // speed
3249 20*FRACUNIT, // radius
3250 16*FRACUNIT, // height
3251 100, // mass
3252 0, // damage
3253 sfx_None, // activesound
3254 MF_SPECIAL, // flags
3255 S_NULL // raisestate
3256 },
3257
3258 { // MT_SHOTGUN
3259 2001, // doomednum
3260 S_SHOT, // spawnstate
3261 1000, // spawnhealth
3262 S_NULL, // seestate
3263 sfx_None, // seesound
3264 8, // reactiontime
3265 sfx_None, // attacksound
3266 S_NULL, // painstate
3267 0, // painchance
3268 sfx_None, // painsound
3269 S_NULL, // meleestate
3270 S_NULL, // missilestate
3271 S_NULL, // deathstate
3272 S_NULL, // xdeathstate
3273 sfx_None, // deathsound
3274 0, // speed
3275 20*FRACUNIT, // radius
3276 16*FRACUNIT, // height
3277 100, // mass
3278 0, // damage
3279 sfx_None, // activesound
3280 MF_SPECIAL, // flags
3281 S_NULL // raisestate
3282 },
3283
3284 { // MT_SUPERSHOTGUN
3285 82, // doomednum
3286 S_SHOT2, // spawnstate
3287 1000, // spawnhealth
3288 S_NULL, // seestate
3289 sfx_None, // seesound
3290 8, // reactiontime
3291 sfx_None, // attacksound
3292 S_NULL, // painstate
3293 0, // painchance
3294 sfx_None, // painsound
3295 S_NULL, // meleestate
3296 S_NULL, // missilestate
3297 S_NULL, // deathstate
3298 S_NULL, // xdeathstate
3299 sfx_None, // deathsound
3300 0, // speed
3301 20*FRACUNIT, // radius
3302 16*FRACUNIT, // height
3303 100, // mass
3304 0, // damage
3305 sfx_None, // activesound
3306 MF_SPECIAL, // flags
3307 S_NULL // raisestate
3308 },
3309
3310 { // MT_MISC29
3311 85, // doomednum
3312 S_TECHLAMP, // spawnstate
3313 1000, // spawnhealth
3314 S_NULL, // seestate
3315 sfx_None, // seesound
3316 8, // reactiontime
3317 sfx_None, // attacksound
3318 S_NULL, // painstate
3319 0, // painchance
3320 sfx_None, // painsound
3321 S_NULL, // meleestate
3322 S_NULL, // missilestate
3323 S_NULL, // deathstate
3324 S_NULL, // xdeathstate
3325 sfx_None, // deathsound
3326 0, // speed
3327 16*FRACUNIT, // radius
3328 16*FRACUNIT, // height
3329 100, // mass
3330 0, // damage
3331 sfx_None, // activesound
3332 MF_SOLID, // flags
3333 S_NULL // raisestate
3334 },
3335
3336 { // MT_MISC30
3337 86, // doomednum
3338 S_TECH2LAMP, // spawnstate
3339 1000, // spawnhealth
3340 S_NULL, // seestate
3341 sfx_None, // seesound
3342 8, // reactiontime
3343 sfx_None, // attacksound
3344 S_NULL, // painstate
3345 0, // painchance
3346 sfx_None, // painsound
3347 S_NULL, // meleestate
3348 S_NULL, // missilestate
3349 S_NULL, // deathstate
3350 S_NULL, // xdeathstate
3351 sfx_None, // deathsound
3352 0, // speed
3353 16*FRACUNIT, // radius
3354 16*FRACUNIT, // height
3355 100, // mass
3356 0, // damage
3357 sfx_None, // activesound
3358 MF_SOLID, // flags
3359 S_NULL // raisestate
3360 },
3361
3362 { // MT_MISC31
3363 2028, // doomednum
3364 S_COLU, // spawnstate
3365 1000, // spawnhealth
3366 S_NULL, // seestate
3367 sfx_None, // seesound
3368 8, // reactiontime
3369 sfx_None, // attacksound
3370 S_NULL, // painstate
3371 0, // painchance
3372 sfx_None, // painsound
3373 S_NULL, // meleestate
3374 S_NULL, // missilestate
3375 S_NULL, // deathstate
3376 S_NULL, // xdeathstate
3377 sfx_None, // deathsound
3378 0, // speed
3379 16*FRACUNIT, // radius
3380 16*FRACUNIT, // height
3381 100, // mass
3382 0, // damage
3383 sfx_None, // activesound
3384 MF_SOLID, // flags
3385 S_NULL // raisestate
3386 },
3387
3388 { // MT_MISC32
3389 30, // doomednum
3390 S_TALLGRNCOL, // spawnstate
3391 1000, // spawnhealth
3392 S_NULL, // seestate
3393 sfx_None, // seesound
3394 8, // reactiontime
3395 sfx_None, // attacksound
3396 S_NULL, // painstate
3397 0, // painchance
3398 sfx_None, // painsound
3399 S_NULL, // meleestate
3400 S_NULL, // missilestate
3401 S_NULL, // deathstate
3402 S_NULL, // xdeathstate
3403 sfx_None, // deathsound
3404 0, // speed
3405 16*FRACUNIT, // radius
3406 16*FRACUNIT, // height
3407 100, // mass
3408 0, // damage
3409 sfx_None, // activesound
3410 MF_SOLID, // flags
3411 S_NULL // raisestate
3412 },
3413
3414 { // MT_MISC33
3415 31, // doomednum
3416 S_SHRTGRNCOL, // spawnstate
3417 1000, // spawnhealth
3418 S_NULL, // seestate
3419 sfx_None, // seesound
3420 8, // reactiontime
3421 sfx_None, // attacksound
3422 S_NULL, // painstate
3423 0, // painchance
3424 sfx_None, // painsound
3425 S_NULL, // meleestate
3426 S_NULL, // missilestate
3427 S_NULL, // deathstate
3428 S_NULL, // xdeathstate
3429 sfx_None, // deathsound
3430 0, // speed
3431 16*FRACUNIT, // radius
3432 16*FRACUNIT, // height
3433 100, // mass
3434 0, // damage
3435 sfx_None, // activesound
3436 MF_SOLID, // flags
3437 S_NULL // raisestate
3438 },
3439
3440 { // MT_MISC34
3441 32, // doomednum
3442 S_TALLREDCOL, // spawnstate
3443 1000, // spawnhealth
3444 S_NULL, // seestate
3445 sfx_None, // seesound
3446 8, // reactiontime
3447 sfx_None, // attacksound
3448 S_NULL, // painstate
3449 0, // painchance
3450 sfx_None, // painsound
3451 S_NULL, // meleestate
3452 S_NULL, // missilestate
3453 S_NULL, // deathstate
3454 S_NULL, // xdeathstate
3455 sfx_None, // deathsound
3456 0, // speed
3457 16*FRACUNIT, // radius
3458 16*FRACUNIT, // height
3459 100, // mass
3460 0, // damage
3461 sfx_None, // activesound
3462 MF_SOLID, // flags
3463 S_NULL // raisestate
3464 },
3465
3466 { // MT_MISC35
3467 33, // doomednum
3468 S_SHRTREDCOL, // spawnstate
3469 1000, // spawnhealth
3470 S_NULL, // seestate
3471 sfx_None, // seesound
3472 8, // reactiontime
3473 sfx_None, // attacksound
3474 S_NULL, // painstate
3475 0, // painchance
3476 sfx_None, // painsound
3477 S_NULL, // meleestate
3478 S_NULL, // missilestate
3479 S_NULL, // deathstate
3480 S_NULL, // xdeathstate
3481 sfx_None, // deathsound
3482 0, // speed
3483 16*FRACUNIT, // radius
3484 16*FRACUNIT, // height
3485 100, // mass
3486 0, // damage
3487 sfx_None, // activesound
3488 MF_SOLID, // flags
3489 S_NULL // raisestate
3490 },
3491
3492 { // MT_MISC36
3493 37, // doomednum
3494 S_SKULLCOL, // spawnstate
3495 1000, // spawnhealth
3496 S_NULL, // seestate
3497 sfx_None, // seesound
3498 8, // reactiontime
3499 sfx_None, // attacksound
3500 S_NULL, // painstate
3501 0, // painchance
3502 sfx_None, // painsound
3503 S_NULL, // meleestate
3504 S_NULL, // missilestate
3505 S_NULL, // deathstate
3506 S_NULL, // xdeathstate
3507 sfx_None, // deathsound
3508 0, // speed
3509 16*FRACUNIT, // radius
3510 16*FRACUNIT, // height
3511 100, // mass
3512 0, // damage
3513 sfx_None, // activesound
3514 MF_SOLID, // flags
3515 S_NULL // raisestate
3516 },
3517
3518 { // MT_MISC37
3519 36, // doomednum
3520 S_HEARTCOL, // spawnstate
3521 1000, // spawnhealth
3522 S_NULL, // seestate
3523 sfx_None, // seesound
3524 8, // reactiontime
3525 sfx_None, // attacksound
3526 S_NULL, // painstate
3527 0, // painchance
3528 sfx_None, // painsound
3529 S_NULL, // meleestate
3530 S_NULL, // missilestate
3531 S_NULL, // deathstate
3532 S_NULL, // xdeathstate
3533 sfx_None, // deathsound
3534 0, // speed
3535 16*FRACUNIT, // radius
3536 16*FRACUNIT, // height
3537 100, // mass
3538 0, // damage
3539 sfx_None, // activesound
3540 MF_SOLID, // flags
3541 S_NULL // raisestate
3542 },
3543
3544 { // MT_MISC38
3545 41, // doomednum
3546 S_EVILEYE, // spawnstate
3547 1000, // spawnhealth
3548 S_NULL, // seestate
3549 sfx_None, // seesound
3550 8, // reactiontime
3551 sfx_None, // attacksound
3552 S_NULL, // painstate
3553 0, // painchance
3554 sfx_None, // painsound
3555 S_NULL, // meleestate
3556 S_NULL, // missilestate
3557 S_NULL, // deathstate
3558 S_NULL, // xdeathstate
3559 sfx_None, // deathsound
3560 0, // speed
3561 16*FRACUNIT, // radius
3562 16*FRACUNIT, // height
3563 100, // mass
3564 0, // damage
3565 sfx_None, // activesound
3566 MF_SOLID, // flags
3567 S_NULL // raisestate
3568 },
3569
3570 { // MT_MISC39
3571 42, // doomednum
3572 S_FLOATSKULL, // spawnstate
3573 1000, // spawnhealth
3574 S_NULL, // seestate
3575 sfx_None, // seesound
3576 8, // reactiontime
3577 sfx_None, // attacksound
3578 S_NULL, // painstate
3579 0, // painchance
3580 sfx_None, // painsound
3581 S_NULL, // meleestate
3582 S_NULL, // missilestate
3583 S_NULL, // deathstate
3584 S_NULL, // xdeathstate
3585 sfx_None, // deathsound
3586 0, // speed
3587 16*FRACUNIT, // radius
3588 16*FRACUNIT, // height
3589 100, // mass
3590 0, // damage
3591 sfx_None, // activesound
3592 MF_SOLID, // flags
3593 S_NULL // raisestate
3594 },
3595
3596 { // MT_MISC40
3597 43, // doomednum
3598 S_TORCHTREE, // spawnstate
3599 1000, // spawnhealth
3600 S_NULL, // seestate
3601 sfx_None, // seesound
3602 8, // reactiontime
3603 sfx_None, // attacksound
3604 S_NULL, // painstate
3605 0, // painchance
3606 sfx_None, // painsound
3607 S_NULL, // meleestate
3608 S_NULL, // missilestate
3609 S_NULL, // deathstate
3610 S_NULL, // xdeathstate
3611 sfx_None, // deathsound
3612 0, // speed
3613 16*FRACUNIT, // radius
3614 16*FRACUNIT, // height
3615 100, // mass
3616 0, // damage
3617 sfx_None, // activesound
3618 MF_SOLID, // flags
3619 S_NULL // raisestate
3620 },
3621
3622 { // MT_MISC41
3623 44, // doomednum
3624 S_BLUETORCH, // spawnstate
3625 1000, // spawnhealth
3626 S_NULL, // seestate
3627 sfx_None, // seesound
3628 8, // reactiontime
3629 sfx_None, // attacksound
3630 S_NULL, // painstate
3631 0, // painchance
3632 sfx_None, // painsound
3633 S_NULL, // meleestate
3634 S_NULL, // missilestate
3635 S_NULL, // deathstate
3636 S_NULL, // xdeathstate
3637 sfx_None, // deathsound
3638 0, // speed
3639 16*FRACUNIT, // radius
3640 16*FRACUNIT, // height
3641 100, // mass
3642 0, // damage
3643 sfx_None, // activesound
3644 MF_SOLID, // flags
3645 S_NULL // raisestate
3646 },
3647
3648 { // MT_MISC42
3649 45, // doomednum
3650 S_GREENTORCH, // spawnstate
3651 1000, // spawnhealth
3652 S_NULL, // seestate
3653 sfx_None, // seesound
3654 8, // reactiontime
3655 sfx_None, // attacksound
3656 S_NULL, // painstate
3657 0, // painchance
3658 sfx_None, // painsound
3659 S_NULL, // meleestate
3660 S_NULL, // missilestate
3661 S_NULL, // deathstate
3662 S_NULL, // xdeathstate
3663 sfx_None, // deathsound
3664 0, // speed
3665 16*FRACUNIT, // radius
3666 16*FRACUNIT, // height
3667 100, // mass
3668 0, // damage
3669 sfx_None, // activesound
3670 MF_SOLID, // flags
3671 S_NULL // raisestate
3672 },
3673
3674 { // MT_MISC43
3675 46, // doomednum
3676 S_REDTORCH, // spawnstate
3677 1000, // spawnhealth
3678 S_NULL, // seestate
3679 sfx_None, // seesound
3680 8, // reactiontime
3681 sfx_None, // attacksound
3682 S_NULL, // painstate
3683 0, // painchance
3684 sfx_None, // painsound
3685 S_NULL, // meleestate
3686 S_NULL, // missilestate
3687 S_NULL, // deathstate
3688 S_NULL, // xdeathstate
3689 sfx_None, // deathsound
3690 0, // speed
3691 16*FRACUNIT, // radius
3692 16*FRACUNIT, // height
3693 100, // mass
3694 0, // damage
3695 sfx_None, // activesound
3696 MF_SOLID, // flags
3697 S_NULL // raisestate
3698 },
3699
3700 { // MT_MISC44
3701 55, // doomednum
3702 S_BTORCHSHRT, // spawnstate
3703 1000, // spawnhealth
3704 S_NULL, // seestate
3705 sfx_None, // seesound
3706 8, // reactiontime
3707 sfx_None, // attacksound
3708 S_NULL, // painstate
3709 0, // painchance
3710 sfx_None, // painsound
3711 S_NULL, // meleestate
3712 S_NULL, // missilestate
3713 S_NULL, // deathstate
3714 S_NULL, // xdeathstate
3715 sfx_None, // deathsound
3716 0, // speed
3717 16*FRACUNIT, // radius
3718 16*FRACUNIT, // height
3719 100, // mass
3720 0, // damage
3721 sfx_None, // activesound
3722 MF_SOLID, // flags
3723 S_NULL // raisestate
3724 },
3725
3726 { // MT_MISC45
3727 56, // doomednum
3728 S_GTORCHSHRT, // spawnstate
3729 1000, // spawnhealth
3730 S_NULL, // seestate
3731 sfx_None, // seesound
3732 8, // reactiontime
3733 sfx_None, // attacksound
3734 S_NULL, // painstate
3735 0, // painchance
3736 sfx_None, // painsound
3737 S_NULL, // meleestate
3738 S_NULL, // missilestate
3739 S_NULL, // deathstate
3740 S_NULL, // xdeathstate
3741 sfx_None, // deathsound
3742 0, // speed
3743 16*FRACUNIT, // radius
3744 16*FRACUNIT, // height
3745 100, // mass
3746 0, // damage
3747 sfx_None, // activesound
3748 MF_SOLID, // flags
3749 S_NULL // raisestate
3750 },
3751
3752 { // MT_MISC46
3753 57, // doomednum
3754 S_RTORCHSHRT, // spawnstate
3755 1000, // spawnhealth
3756 S_NULL, // seestate
3757 sfx_None, // seesound
3758 8, // reactiontime
3759 sfx_None, // attacksound
3760 S_NULL, // painstate
3761 0, // painchance
3762 sfx_None, // painsound
3763 S_NULL, // meleestate
3764 S_NULL, // missilestate
3765 S_NULL, // deathstate
3766 S_NULL, // xdeathstate
3767 sfx_None, // deathsound
3768 0, // speed
3769 16*FRACUNIT, // radius
3770 16*FRACUNIT, // height
3771 100, // mass
3772 0, // damage
3773 sfx_None, // activesound
3774 MF_SOLID, // flags
3775 S_NULL // raisestate
3776 },
3777
3778 { // MT_MISC47
3779 47, // doomednum
3780 S_STALAGTITE, // spawnstate
3781 1000, // spawnhealth
3782 S_NULL, // seestate
3783 sfx_None, // seesound
3784 8, // reactiontime
3785 sfx_None, // attacksound
3786 S_NULL, // painstate
3787 0, // painchance
3788 sfx_None, // painsound
3789 S_NULL, // meleestate
3790 S_NULL, // missilestate
3791 S_NULL, // deathstate
3792 S_NULL, // xdeathstate
3793 sfx_None, // deathsound
3794 0, // speed
3795 16*FRACUNIT, // radius
3796 16*FRACUNIT, // height
3797 100, // mass
3798 0, // damage
3799 sfx_None, // activesound
3800 MF_SOLID, // flags
3801 S_NULL // raisestate
3802 },
3803
3804 { // MT_MISC48
3805 48, // doomednum
3806 S_TECHPILLAR, // spawnstate
3807 1000, // spawnhealth
3808 S_NULL, // seestate
3809 sfx_None, // seesound
3810 8, // reactiontime
3811 sfx_None, // attacksound
3812 S_NULL, // painstate
3813 0, // painchance
3814 sfx_None, // painsound
3815 S_NULL, // meleestate
3816 S_NULL, // missilestate
3817 S_NULL, // deathstate
3818 S_NULL, // xdeathstate
3819 sfx_None, // deathsound
3820 0, // speed
3821 16*FRACUNIT, // radius
3822 16*FRACUNIT, // height
3823 100, // mass
3824 0, // damage
3825 sfx_None, // activesound
3826 MF_SOLID, // flags
3827 S_NULL // raisestate
3828 },
3829
3830 { // MT_MISC49
3831 34, // doomednum
3832 S_CANDLESTIK, // spawnstate
3833 1000, // spawnhealth
3834 S_NULL, // seestate
3835 sfx_None, // seesound
3836 8, // reactiontime
3837 sfx_None, // attacksound
3838 S_NULL, // painstate
3839 0, // painchance
3840 sfx_None, // painsound
3841 S_NULL, // meleestate
3842 S_NULL, // missilestate
3843 S_NULL, // deathstate
3844 S_NULL, // xdeathstate
3845 sfx_None, // deathsound
3846 0, // speed
3847 20*FRACUNIT, // radius
3848 16*FRACUNIT, // height
3849 100, // mass
3850 0, // damage
3851 sfx_None, // activesound
3852 0, // flags
3853 S_NULL // raisestate
3854 },
3855
3856 { // MT_MISC50
3857 35, // doomednum
3858 S_CANDELABRA, // spawnstate
3859 1000, // spawnhealth
3860 S_NULL, // seestate
3861 sfx_None, // seesound
3862 8, // reactiontime
3863 sfx_None, // attacksound
3864 S_NULL, // painstate
3865 0, // painchance
3866 sfx_None, // painsound
3867 S_NULL, // meleestate
3868 S_NULL, // missilestate
3869 S_NULL, // deathstate
3870 S_NULL, // xdeathstate
3871 sfx_None, // deathsound
3872 0, // speed
3873 16*FRACUNIT, // radius
3874 16*FRACUNIT, // height
3875 100, // mass
3876 0, // damage
3877 sfx_None, // activesound
3878 MF_SOLID, // flags
3879 S_NULL // raisestate
3880 },
3881
3882 { // MT_MISC51
3883 49, // doomednum
3884 S_BLOODYTWITCH, // spawnstate
3885 1000, // spawnhealth
3886 S_NULL, // seestate
3887 sfx_None, // seesound
3888 8, // reactiontime
3889 sfx_None, // attacksound
3890 S_NULL, // painstate
3891 0, // painchance
3892 sfx_None, // painsound
3893 S_NULL, // meleestate
3894 S_NULL, // missilestate
3895 S_NULL, // deathstate
3896 S_NULL, // xdeathstate
3897 sfx_None, // deathsound
3898 0, // speed
3899 16*FRACUNIT, // radius
3900 68*FRACUNIT, // height
3901 100, // mass
3902 0, // damage
3903 sfx_None, // activesound
3904 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
3905 S_NULL // raisestate
3906 },
3907
3908 { // MT_MISC52
3909 50, // doomednum
3910 S_MEAT2, // spawnstate
3911 1000, // spawnhealth
3912 S_NULL, // seestate
3913 sfx_None, // seesound
3914 8, // reactiontime
3915 sfx_None, // attacksound
3916 S_NULL, // painstate
3917 0, // painchance
3918 sfx_None, // painsound
3919 S_NULL, // meleestate
3920 S_NULL, // missilestate
3921 S_NULL, // deathstate
3922 S_NULL, // xdeathstate
3923 sfx_None, // deathsound
3924 0, // speed
3925 16*FRACUNIT, // radius
3926 84*FRACUNIT, // height
3927 100, // mass
3928 0, // damage
3929 sfx_None, // activesound
3930 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
3931 S_NULL // raisestate
3932 },
3933
3934 { // MT_MISC53
3935 51, // doomednum
3936 S_MEAT3, // spawnstate
3937 1000, // spawnhealth
3938 S_NULL, // seestate
3939 sfx_None, // seesound
3940 8, // reactiontime
3941 sfx_None, // attacksound
3942 S_NULL, // painstate
3943 0, // painchance
3944 sfx_None, // painsound
3945 S_NULL, // meleestate
3946 S_NULL, // missilestate
3947 S_NULL, // deathstate
3948 S_NULL, // xdeathstate
3949 sfx_None, // deathsound
3950 0, // speed
3951 16*FRACUNIT, // radius
3952 84*FRACUNIT, // height
3953 100, // mass
3954 0, // damage
3955 sfx_None, // activesound
3956 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
3957 S_NULL // raisestate
3958 },
3959
3960 { // MT_MISC54
3961 52, // doomednum
3962 S_MEAT4, // spawnstate
3963 1000, // spawnhealth
3964 S_NULL, // seestate
3965 sfx_None, // seesound
3966 8, // reactiontime
3967 sfx_None, // attacksound
3968 S_NULL, // painstate
3969 0, // painchance
3970 sfx_None, // painsound
3971 S_NULL, // meleestate
3972 S_NULL, // missilestate
3973 S_NULL, // deathstate
3974 S_NULL, // xdeathstate
3975 sfx_None, // deathsound
3976 0, // speed
3977 16*FRACUNIT, // radius
3978 68*FRACUNIT, // height
3979 100, // mass
3980 0, // damage
3981 sfx_None, // activesound
3982 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
3983 S_NULL // raisestate
3984 },
3985
3986 { // MT_MISC55
3987 53, // doomednum
3988 S_MEAT5, // spawnstate
3989 1000, // spawnhealth
3990 S_NULL, // seestate
3991 sfx_None, // seesound
3992 8, // reactiontime
3993 sfx_None, // attacksound
3994 S_NULL, // painstate
3995 0, // painchance
3996 sfx_None, // painsound
3997 S_NULL, // meleestate
3998 S_NULL, // missilestate
3999 S_NULL, // deathstate
4000 S_NULL, // xdeathstate
4001 sfx_None, // deathsound
4002 0, // speed
4003 16*FRACUNIT, // radius
4004 52*FRACUNIT, // height
4005 100, // mass
4006 0, // damage
4007 sfx_None, // activesound
4008 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4009 S_NULL // raisestate
4010 },
4011
4012 { // MT_MISC56
4013 59, // doomednum
4014 S_MEAT2, // spawnstate
4015 1000, // spawnhealth
4016 S_NULL, // seestate
4017 sfx_None, // seesound
4018 8, // reactiontime
4019 sfx_None, // attacksound
4020 S_NULL, // painstate
4021 0, // painchance
4022 sfx_None, // painsound
4023 S_NULL, // meleestate
4024 S_NULL, // missilestate
4025 S_NULL, // deathstate
4026 S_NULL, // xdeathstate
4027 sfx_None, // deathsound
4028 0, // speed
4029 20*FRACUNIT, // radius
4030 84*FRACUNIT, // height
4031 100, // mass
4032 0, // damage
4033 sfx_None, // activesound
4034 MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4035 S_NULL // raisestate
4036 },
4037
4038 { // MT_MISC57
4039 60, // doomednum
4040 S_MEAT4, // spawnstate
4041 1000, // spawnhealth
4042 S_NULL, // seestate
4043 sfx_None, // seesound
4044 8, // reactiontime
4045 sfx_None, // attacksound
4046 S_NULL, // painstate
4047 0, // painchance
4048 sfx_None, // painsound
4049 S_NULL, // meleestate
4050 S_NULL, // missilestate
4051 S_NULL, // deathstate
4052 S_NULL, // xdeathstate
4053 sfx_None, // deathsound
4054 0, // speed
4055 20*FRACUNIT, // radius
4056 68*FRACUNIT, // height
4057 100, // mass
4058 0, // damage
4059 sfx_None, // activesound
4060 MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4061 S_NULL // raisestate
4062 },
4063
4064 { // MT_MISC58
4065 61, // doomednum
4066 S_MEAT3, // spawnstate
4067 1000, // spawnhealth
4068 S_NULL, // seestate
4069 sfx_None, // seesound
4070 8, // reactiontime
4071 sfx_None, // attacksound
4072 S_NULL, // painstate
4073 0, // painchance
4074 sfx_None, // painsound
4075 S_NULL, // meleestate
4076 S_NULL, // missilestate
4077 S_NULL, // deathstate
4078 S_NULL, // xdeathstate
4079 sfx_None, // deathsound
4080 0, // speed
4081 20*FRACUNIT, // radius
4082 52*FRACUNIT, // height
4083 100, // mass
4084 0, // damage
4085 sfx_None, // activesound
4086 MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4087 S_NULL // raisestate
4088 },
4089
4090 { // MT_MISC59
4091 62, // doomednum
4092 S_MEAT5, // spawnstate
4093 1000, // spawnhealth
4094 S_NULL, // seestate
4095 sfx_None, // seesound
4096 8, // reactiontime
4097 sfx_None, // attacksound
4098 S_NULL, // painstate
4099 0, // painchance
4100 sfx_None, // painsound
4101 S_NULL, // meleestate
4102 S_NULL, // missilestate
4103 S_NULL, // deathstate
4104 S_NULL, // xdeathstate
4105 sfx_None, // deathsound
4106 0, // speed
4107 20*FRACUNIT, // radius
4108 52*FRACUNIT, // height
4109 100, // mass
4110 0, // damage
4111 sfx_None, // activesound
4112 MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4113 S_NULL // raisestate
4114 },
4115
4116 { // MT_MISC60
4117 63, // doomednum
4118 S_BLOODYTWITCH, // spawnstate
4119 1000, // spawnhealth
4120 S_NULL, // seestate
4121 sfx_None, // seesound
4122 8, // reactiontime
4123 sfx_None, // attacksound
4124 S_NULL, // painstate
4125 0, // painchance
4126 sfx_None, // painsound
4127 S_NULL, // meleestate
4128 S_NULL, // missilestate
4129 S_NULL, // deathstate
4130 S_NULL, // xdeathstate
4131 sfx_None, // deathsound
4132 0, // speed
4133 20*FRACUNIT, // radius
4134 68*FRACUNIT, // height
4135 100, // mass
4136 0, // damage
4137 sfx_None, // activesound
4138 MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4139 S_NULL // raisestate
4140 },
4141
4142 { // MT_MISC61
4143 22, // doomednum
4144 S_HEAD_DIE6, // spawnstate
4145 1000, // spawnhealth
4146 S_NULL, // seestate
4147 sfx_None, // seesound
4148 8, // reactiontime
4149 sfx_None, // attacksound
4150 S_NULL, // painstate
4151 0, // painchance
4152 sfx_None, // painsound
4153 S_NULL, // meleestate
4154 S_NULL, // missilestate
4155 S_NULL, // deathstate
4156 S_NULL, // xdeathstate
4157 sfx_None, // deathsound
4158 0, // speed
4159 20*FRACUNIT, // radius
4160 16*FRACUNIT, // height
4161 100, // mass
4162 0, // damage
4163 sfx_None, // activesound
4164 0, // flags
4165 S_NULL // raisestate
4166 },
4167
4168 { // MT_MISC62
4169 15, // doomednum
4170 S_PLAY_DIE7, // spawnstate
4171 1000, // spawnhealth
4172 S_NULL, // seestate
4173 sfx_None, // seesound
4174 8, // reactiontime
4175 sfx_None, // attacksound
4176 S_NULL, // painstate
4177 0, // painchance
4178 sfx_None, // painsound
4179 S_NULL, // meleestate
4180 S_NULL, // missilestate
4181 S_NULL, // deathstate
4182 S_NULL, // xdeathstate
4183 sfx_None, // deathsound
4184 0, // speed
4185 20*FRACUNIT, // radius
4186 16*FRACUNIT, // height
4187 100, // mass
4188 0, // damage
4189 sfx_None, // activesound
4190 0, // flags
4191 S_NULL // raisestate
4192 },
4193
4194 { // MT_MISC63
4195 18, // doomednum
4196 S_POSS_DIE5, // spawnstate
4197 1000, // spawnhealth
4198 S_NULL, // seestate
4199 sfx_None, // seesound
4200 8, // reactiontime
4201 sfx_None, // attacksound
4202 S_NULL, // painstate
4203 0, // painchance
4204 sfx_None, // painsound
4205 S_NULL, // meleestate
4206 S_NULL, // missilestate
4207 S_NULL, // deathstate
4208 S_NULL, // xdeathstate
4209 sfx_None, // deathsound
4210 0, // speed
4211 20*FRACUNIT, // radius
4212 16*FRACUNIT, // height
4213 100, // mass
4214 0, // damage
4215 sfx_None, // activesound
4216 0, // flags
4217 S_NULL // raisestate
4218 },
4219
4220 { // MT_MISC64
4221 21, // doomednum
4222 S_SARG_DIE6, // spawnstate
4223 1000, // spawnhealth
4224 S_NULL, // seestate
4225 sfx_None, // seesound
4226 8, // reactiontime
4227 sfx_None, // attacksound
4228 S_NULL, // painstate
4229 0, // painchance
4230 sfx_None, // painsound
4231 S_NULL, // meleestate
4232 S_NULL, // missilestate
4233 S_NULL, // deathstate
4234 S_NULL, // xdeathstate
4235 sfx_None, // deathsound
4236 0, // speed
4237 20*FRACUNIT, // radius
4238 16*FRACUNIT, // height
4239 100, // mass
4240 0, // damage
4241 sfx_None, // activesound
4242 0, // flags
4243 S_NULL // raisestate
4244 },
4245
4246 { // MT_MISC65
4247 23, // doomednum
4248 S_SKULL_DIE6, // spawnstate
4249 1000, // spawnhealth
4250 S_NULL, // seestate
4251 sfx_None, // seesound
4252 8, // reactiontime
4253 sfx_None, // attacksound
4254 S_NULL, // painstate
4255 0, // painchance
4256 sfx_None, // painsound
4257 S_NULL, // meleestate
4258 S_NULL, // missilestate
4259 S_NULL, // deathstate
4260 S_NULL, // xdeathstate
4261 sfx_None, // deathsound
4262 0, // speed
4263 20*FRACUNIT, // radius
4264 16*FRACUNIT, // height
4265 100, // mass
4266 0, // damage
4267 sfx_None, // activesound
4268 0, // flags
4269 S_NULL // raisestate
4270 },
4271
4272 { // MT_MISC66
4273 20, // doomednum
4274 S_TROO_DIE5, // spawnstate
4275 1000, // spawnhealth
4276 S_NULL, // seestate
4277 sfx_None, // seesound
4278 8, // reactiontime
4279 sfx_None, // attacksound
4280 S_NULL, // painstate
4281 0, // painchance
4282 sfx_None, // painsound
4283 S_NULL, // meleestate
4284 S_NULL, // missilestate
4285 S_NULL, // deathstate
4286 S_NULL, // xdeathstate
4287 sfx_None, // deathsound
4288 0, // speed
4289 20*FRACUNIT, // radius
4290 16*FRACUNIT, // height
4291 100, // mass
4292 0, // damage
4293 sfx_None, // activesound
4294 0, // flags
4295 S_NULL // raisestate
4296 },
4297
4298 { // MT_MISC67
4299 19, // doomednum
4300 S_SPOS_DIE5, // spawnstate
4301 1000, // spawnhealth
4302 S_NULL, // seestate
4303 sfx_None, // seesound
4304 8, // reactiontime
4305 sfx_None, // attacksound
4306 S_NULL, // painstate
4307 0, // painchance
4308 sfx_None, // painsound
4309 S_NULL, // meleestate
4310 S_NULL, // missilestate
4311 S_NULL, // deathstate
4312 S_NULL, // xdeathstate
4313 sfx_None, // deathsound
4314 0, // speed
4315 20*FRACUNIT, // radius
4316 16*FRACUNIT, // height
4317 100, // mass
4318 0, // damage
4319 sfx_None, // activesound
4320 0, // flags
4321 S_NULL // raisestate
4322 },
4323
4324 { // MT_MISC68
4325 10, // doomednum
4326 S_PLAY_XDIE9, // spawnstate
4327 1000, // spawnhealth
4328 S_NULL, // seestate
4329 sfx_None, // seesound
4330 8, // reactiontime
4331 sfx_None, // attacksound
4332 S_NULL, // painstate
4333 0, // painchance
4334 sfx_None, // painsound
4335 S_NULL, // meleestate
4336 S_NULL, // missilestate
4337 S_NULL, // deathstate
4338 S_NULL, // xdeathstate
4339 sfx_None, // deathsound
4340 0, // speed
4341 20*FRACUNIT, // radius
4342 16*FRACUNIT, // height
4343 100, // mass
4344 0, // damage
4345 sfx_None, // activesound
4346 0, // flags
4347 S_NULL // raisestate
4348 },
4349
4350 { // MT_MISC69
4351 12, // doomednum
4352 S_PLAY_XDIE9, // spawnstate
4353 1000, // spawnhealth
4354 S_NULL, // seestate
4355 sfx_None, // seesound
4356 8, // reactiontime
4357 sfx_None, // attacksound
4358 S_NULL, // painstate
4359 0, // painchance
4360 sfx_None, // painsound
4361 S_NULL, // meleestate
4362 S_NULL, // missilestate
4363 S_NULL, // deathstate
4364 S_NULL, // xdeathstate
4365 sfx_None, // deathsound
4366 0, // speed
4367 20*FRACUNIT, // radius
4368 16*FRACUNIT, // height
4369 100, // mass
4370 0, // damage
4371 sfx_None, // activesound
4372 0, // flags
4373 S_NULL // raisestate
4374 },
4375
4376 { // MT_MISC70
4377 28, // doomednum
4378 S_HEADSONSTICK, // spawnstate
4379 1000, // spawnhealth
4380 S_NULL, // seestate
4381 sfx_None, // seesound
4382 8, // reactiontime
4383 sfx_None, // attacksound
4384 S_NULL, // painstate
4385 0, // painchance
4386 sfx_None, // painsound
4387 S_NULL, // meleestate
4388 S_NULL, // missilestate
4389 S_NULL, // deathstate
4390 S_NULL, // xdeathstate
4391 sfx_None, // deathsound
4392 0, // speed
4393 16*FRACUNIT, // radius
4394 16*FRACUNIT, // height
4395 100, // mass
4396 0, // damage
4397 sfx_None, // activesound
4398 MF_SOLID, // flags
4399 S_NULL // raisestate
4400 },
4401
4402 { // MT_MISC71
4403 24, // doomednum
4404 S_GIBS, // spawnstate
4405 1000, // spawnhealth
4406 S_NULL, // seestate
4407 sfx_None, // seesound
4408 8, // reactiontime
4409 sfx_None, // attacksound
4410 S_NULL, // painstate
4411 0, // painchance
4412 sfx_None, // painsound
4413 S_NULL, // meleestate
4414 S_NULL, // missilestate
4415 S_NULL, // deathstate
4416 S_NULL, // xdeathstate
4417 sfx_None, // deathsound
4418 0, // speed
4419 20*FRACUNIT, // radius
4420 16*FRACUNIT, // height
4421 100, // mass
4422 0, // damage
4423 sfx_None, // activesound
4424 0, // flags
4425 S_NULL // raisestate
4426 },
4427
4428 { // MT_MISC72
4429 27, // doomednum
4430 S_HEADONASTICK, // spawnstate
4431 1000, // spawnhealth
4432 S_NULL, // seestate
4433 sfx_None, // seesound
4434 8, // reactiontime
4435 sfx_None, // attacksound
4436 S_NULL, // painstate
4437 0, // painchance
4438 sfx_None, // painsound
4439 S_NULL, // meleestate
4440 S_NULL, // missilestate
4441 S_NULL, // deathstate
4442 S_NULL, // xdeathstate
4443 sfx_None, // deathsound
4444 0, // speed
4445 16*FRACUNIT, // radius
4446 16*FRACUNIT, // height
4447 100, // mass
4448 0, // damage
4449 sfx_None, // activesound
4450 MF_SOLID, // flags
4451 S_NULL // raisestate
4452 },
4453
4454 { // MT_MISC73
4455 29, // doomednum
4456 S_HEADCANDLES, // spawnstate
4457 1000, // spawnhealth
4458 S_NULL, // seestate
4459 sfx_None, // seesound
4460 8, // reactiontime
4461 sfx_None, // attacksound
4462 S_NULL, // painstate
4463 0, // painchance
4464 sfx_None, // painsound
4465 S_NULL, // meleestate
4466 S_NULL, // missilestate
4467 S_NULL, // deathstate
4468 S_NULL, // xdeathstate
4469 sfx_None, // deathsound
4470 0, // speed
4471 16*FRACUNIT, // radius
4472 16*FRACUNIT, // height
4473 100, // mass
4474 0, // damage
4475 sfx_None, // activesound
4476 MF_SOLID, // flags
4477 S_NULL // raisestate
4478 },
4479
4480 { // MT_MISC74
4481 25, // doomednum
4482 S_DEADSTICK, // spawnstate
4483 1000, // spawnhealth
4484 S_NULL, // seestate
4485 sfx_None, // seesound
4486 8, // reactiontime
4487 sfx_None, // attacksound
4488 S_NULL, // painstate
4489 0, // painchance
4490 sfx_None, // painsound
4491 S_NULL, // meleestate
4492 S_NULL, // missilestate
4493 S_NULL, // deathstate
4494 S_NULL, // xdeathstate
4495 sfx_None, // deathsound
4496 0, // speed
4497 16*FRACUNIT, // radius
4498 16*FRACUNIT, // height
4499 100, // mass
4500 0, // damage
4501 sfx_None, // activesound
4502 MF_SOLID, // flags
4503 S_NULL // raisestate
4504 },
4505
4506 { // MT_MISC75
4507 26, // doomednum
4508 S_LIVESTICK, // spawnstate
4509 1000, // spawnhealth
4510 S_NULL, // seestate
4511 sfx_None, // seesound
4512 8, // reactiontime
4513 sfx_None, // attacksound
4514 S_NULL, // painstate
4515 0, // painchance
4516 sfx_None, // painsound
4517 S_NULL, // meleestate
4518 S_NULL, // missilestate
4519 S_NULL, // deathstate
4520 S_NULL, // xdeathstate
4521 sfx_None, // deathsound
4522 0, // speed
4523 16*FRACUNIT, // radius
4524 16*FRACUNIT, // height
4525 100, // mass
4526 0, // damage
4527 sfx_None, // activesound
4528 MF_SOLID, // flags
4529 S_NULL // raisestate
4530 },
4531
4532 { // MT_MISC76
4533 54, // doomednum
4534 S_BIGTREE, // spawnstate
4535 1000, // spawnhealth
4536 S_NULL, // seestate
4537 sfx_None, // seesound
4538 8, // reactiontime
4539 sfx_None, // attacksound
4540 S_NULL, // painstate
4541 0, // painchance
4542 sfx_None, // painsound
4543 S_NULL, // meleestate
4544 S_NULL, // missilestate
4545 S_NULL, // deathstate
4546 S_NULL, // xdeathstate
4547 sfx_None, // deathsound
4548 0, // speed
4549 32*FRACUNIT, // radius
4550 16*FRACUNIT, // height
4551 100, // mass
4552 0, // damage
4553 sfx_None, // activesound
4554 MF_SOLID, // flags
4555 S_NULL // raisestate
4556 },
4557
4558 { // MT_MISC77
4559 70, // doomednum
4560 S_BBAR1, // spawnstate
4561 1000, // spawnhealth
4562 S_NULL, // seestate
4563 sfx_None, // seesound
4564 8, // reactiontime
4565 sfx_None, // attacksound
4566 S_NULL, // painstate
4567 0, // painchance
4568 sfx_None, // painsound
4569 S_NULL, // meleestate
4570 S_NULL, // missilestate
4571 S_NULL, // deathstate
4572 S_NULL, // xdeathstate
4573 sfx_None, // deathsound
4574 0, // speed
4575 16*FRACUNIT, // radius
4576 16*FRACUNIT, // height
4577 100, // mass
4578 0, // damage
4579 sfx_None, // activesound
4580 MF_SOLID, // flags
4581 S_NULL // raisestate
4582 },
4583
4584 { // MT_MISC78
4585 73, // doomednum
4586 S_HANGNOGUTS, // spawnstate
4587 1000, // spawnhealth
4588 S_NULL, // seestate
4589 sfx_None, // seesound
4590 8, // reactiontime
4591 sfx_None, // attacksound
4592 S_NULL, // painstate
4593 0, // painchance
4594 sfx_None, // painsound
4595 S_NULL, // meleestate
4596 S_NULL, // missilestate
4597 S_NULL, // deathstate
4598 S_NULL, // xdeathstate
4599 sfx_None, // deathsound
4600 0, // speed
4601 16*FRACUNIT, // radius
4602 88*FRACUNIT, // height
4603 100, // mass
4604 0, // damage
4605 sfx_None, // activesound
4606 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4607 S_NULL // raisestate
4608 },
4609
4610 { // MT_MISC79
4611 74, // doomednum
4612 S_HANGBNOBRAIN, // spawnstate
4613 1000, // spawnhealth
4614 S_NULL, // seestate
4615 sfx_None, // seesound
4616 8, // reactiontime
4617 sfx_None, // attacksound
4618 S_NULL, // painstate
4619 0, // painchance
4620 sfx_None, // painsound
4621 S_NULL, // meleestate
4622 S_NULL, // missilestate
4623 S_NULL, // deathstate
4624 S_NULL, // xdeathstate
4625 sfx_None, // deathsound
4626 0, // speed
4627 16*FRACUNIT, // radius
4628 88*FRACUNIT, // height
4629 100, // mass
4630 0, // damage
4631 sfx_None, // activesound
4632 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4633 S_NULL // raisestate
4634 },
4635
4636 { // MT_MISC80
4637 75, // doomednum
4638 S_HANGTLOOKDN, // spawnstate
4639 1000, // spawnhealth
4640 S_NULL, // seestate
4641 sfx_None, // seesound
4642 8, // reactiontime
4643 sfx_None, // attacksound
4644 S_NULL, // painstate
4645 0, // painchance
4646 sfx_None, // painsound
4647 S_NULL, // meleestate
4648 S_NULL, // missilestate
4649 S_NULL, // deathstate
4650 S_NULL, // xdeathstate
4651 sfx_None, // deathsound
4652 0, // speed
4653 16*FRACUNIT, // radius
4654 64*FRACUNIT, // height
4655 100, // mass
4656 0, // damage
4657 sfx_None, // activesound
4658 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4659 S_NULL // raisestate
4660 },
4661
4662 { // MT_MISC81
4663 76, // doomednum
4664 S_HANGTSKULL, // spawnstate
4665 1000, // spawnhealth
4666 S_NULL, // seestate
4667 sfx_None, // seesound
4668 8, // reactiontime
4669 sfx_None, // attacksound
4670 S_NULL, // painstate
4671 0, // painchance
4672 sfx_None, // painsound
4673 S_NULL, // meleestate
4674 S_NULL, // missilestate
4675 S_NULL, // deathstate
4676 S_NULL, // xdeathstate
4677 sfx_None, // deathsound
4678 0, // speed
4679 16*FRACUNIT, // radius
4680 64*FRACUNIT, // height
4681 100, // mass
4682 0, // damage
4683 sfx_None, // activesound
4684 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4685 S_NULL // raisestate
4686 },
4687
4688 { // MT_MISC82
4689 77, // doomednum
4690 S_HANGTLOOKUP, // spawnstate
4691 1000, // spawnhealth
4692 S_NULL, // seestate
4693 sfx_None, // seesound
4694 8, // reactiontime
4695 sfx_None, // attacksound
4696 S_NULL, // painstate
4697 0, // painchance
4698 sfx_None, // painsound
4699 S_NULL, // meleestate
4700 S_NULL, // missilestate
4701 S_NULL, // deathstate
4702 S_NULL, // xdeathstate
4703 sfx_None, // deathsound
4704 0, // speed
4705 16*FRACUNIT, // radius
4706 64*FRACUNIT, // height
4707 100, // mass
4708 0, // damage
4709 sfx_None, // activesound
4710 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4711 S_NULL // raisestate
4712 },
4713
4714 { // MT_MISC83
4715 78, // doomednum
4716 S_HANGTNOBRAIN, // spawnstate
4717 1000, // spawnhealth
4718 S_NULL, // seestate
4719 sfx_None, // seesound
4720 8, // reactiontime
4721 sfx_None, // attacksound
4722 S_NULL, // painstate
4723 0, // painchance
4724 sfx_None, // painsound
4725 S_NULL, // meleestate
4726 S_NULL, // missilestate
4727 S_NULL, // deathstate
4728 S_NULL, // xdeathstate
4729 sfx_None, // deathsound
4730 0, // speed
4731 16*FRACUNIT, // radius
4732 64*FRACUNIT, // height
4733 100, // mass
4734 0, // damage
4735 sfx_None, // activesound
4736 MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
4737 S_NULL // raisestate
4738 },
4739
4740 { // MT_MISC84
4741 79, // doomednum
4742 S_COLONGIBS, // spawnstate
4743 1000, // spawnhealth
4744 S_NULL, // seestate
4745 sfx_None, // seesound
4746 8, // reactiontime
4747 sfx_None, // attacksound
4748 S_NULL, // painstate
4749 0, // painchance
4750 sfx_None, // painsound
4751 S_NULL, // meleestate
4752 S_NULL, // missilestate
4753 S_NULL, // deathstate
4754 S_NULL, // xdeathstate
4755 sfx_None, // deathsound
4756 0, // speed
4757 20*FRACUNIT, // radius
4758 16*FRACUNIT, // height
4759 100, // mass
4760 0, // damage
4761 sfx_None, // activesound
4762 MF_NOBLOCKMAP, // flags
4763 S_NULL // raisestate
4764 },
4765
4766 { // MT_MISC85
4767 80, // doomednum
4768 S_SMALLPOOL, // spawnstate
4769 1000, // spawnhealth
4770 S_NULL, // seestate
4771 sfx_None, // seesound
4772 8, // reactiontime
4773 sfx_None, // attacksound
4774 S_NULL, // painstate
4775 0, // painchance
4776 sfx_None, // painsound
4777 S_NULL, // meleestate
4778 S_NULL, // missilestate
4779 S_NULL, // deathstate
4780 S_NULL, // xdeathstate
4781 sfx_None, // deathsound
4782 0, // speed
4783 20*FRACUNIT, // radius
4784 16*FRACUNIT, // height
4785 100, // mass
4786 0, // damage
4787 sfx_None, // activesound
4788 MF_NOBLOCKMAP, // flags
4789 S_NULL // raisestate
4790 },
4791
4792 { // MT_MISC86
4793 81, // doomednum
4794 S_BRAINSTEM, // spawnstate
4795 1000, // spawnhealth
4796 S_NULL, // seestate
4797 sfx_None, // seesound
4798 8, // reactiontime
4799 sfx_None, // attacksound
4800 S_NULL, // painstate
4801 0, // painchance
4802 sfx_None, // painsound
4803 S_NULL, // meleestate
4804 S_NULL, // missilestate
4805 S_NULL, // deathstate
4806 S_NULL, // xdeathstate
4807 sfx_None, // deathsound
4808 0, // speed
4809 20*FRACUNIT, // radius
4810 16*FRACUNIT, // height
4811 100, // mass
4812 0, // damage
4813 sfx_None, // activesound
4814 MF_NOBLOCKMAP, // flags
4815 S_NULL // raisestate
4816 },
4817
4818 // For use with wind and current effects
4819 { // MT_PUSH // phares
4820 5001, // doomednum // | //jff 5/11/98 deconflict
4821 S_TNT1, // spawnstate // V // with DOSDoom
4822 1000, // spawnhealth
4823 S_NULL, // seestate
4824 sfx_None, // seesound
4825 8, // reactiontime
4826 sfx_None, // attacksound
4827 S_NULL, // painstate
4828 0, // painchance
4829 sfx_None, // painsound
4830 S_NULL, // meleestate
4831 S_NULL, // missilestate
4832 S_NULL, // deathstate
4833 S_NULL, // xdeathstate
4834 sfx_None, // deathsound
4835 0, // speed
4836 8, // radius
4837 8, // height
4838 10, // mass
4839 0, // damage
4840 sfx_None, // activesound
4841 MF_NOBLOCKMAP, // flags
4842 S_NULL // raisestate
4843 },
4844
4845 // For use with wind and current effects
4846 { // MT_PULL
4847 5002, // doomednum //jff 5/11/98 deconflict
4848 S_TNT1, // spawnstate // with DOSDoom
4849 1000, // spawnhealth
4850 S_NULL, // seestate
4851 sfx_None, // seesound
4852 8, // reactiontime
4853 sfx_None, // attacksound
4854 S_NULL, // painstate
4855 0, // painchance
4856 sfx_None, // painsound
4857 S_NULL, // meleestate
4858 S_NULL, // missilestate
4859 S_NULL, // deathstate
4860 S_NULL, // xdeathstate
4861 sfx_None, // deathsound
4862 0, // speed
4863 8, // radius
4864 8, // height
4865 10, // mass
4866 0, // damage
4867 sfx_None, // activesound
4868 MF_NOBLOCKMAP, // flags
4869 S_NULL // raisestate
4870 },
4871#ifdef DOGS
4872 // Marine's best friend :) // killough 7/19/98
4873 { // MT_DOGS
4874 888, // doomednum
4875 S_DOGS_STND, // spawnstate
4876 500, // spawnhealth
4877 S_DOGS_RUN1, // seestate
4878 sfx_dgsit, // seesound
4879 8, // reactiontime
4880 sfx_dgatk, // attacksound
4881 S_DOGS_PAIN, // painstate
4882 180, // painchance
4883 sfx_dgpain, // painsound
4884 S_DOGS_ATK1, // meleestate
4885 0, // missilestate
4886 S_DOGS_DIE1, // deathstate
4887 S_NULL, // xdeathstate
4888 sfx_dgdth, // deathsound
4889 10, // speed
4890 12*FRACUNIT, // radius
4891 28*FRACUNIT, // height
4892 100, // mass
4893 0, // damage
4894 sfx_dgact, // activesound
4895 MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
4896 S_DOGS_RAISE1 // raisestate
4897 },
4898#endif
4899};
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Thing frame/state LUT,
31 * generated by multigen utilitiy.
32 * This one is the original DOOM version, preserved.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifndef __INFO__
37#define __INFO__
38
39/* Needed for action function pointer handling. */
40#include "d_think.h"
41
42/********************************************************************
43 * Sprite name enumeration - must match info.c *
44 ********************************************************************/
45typedef enum
46{
47 SPR_TROO,
48 SPR_SHTG,
49 SPR_PUNG,
50 SPR_PISG,
51 SPR_PISF,
52 SPR_SHTF,
53 SPR_SHT2,
54 SPR_CHGG,
55 SPR_CHGF,
56 SPR_MISG,
57 SPR_MISF,
58 SPR_SAWG,
59 SPR_PLSG,
60 SPR_PLSF,
61 SPR_BFGG,
62 SPR_BFGF,
63 SPR_BLUD,
64 SPR_PUFF,
65 SPR_BAL1,
66 SPR_BAL2,
67 SPR_PLSS,
68 SPR_PLSE,
69 SPR_MISL,
70 SPR_BFS1,
71 SPR_BFE1,
72 SPR_BFE2,
73 SPR_TFOG,
74 SPR_IFOG,
75 SPR_PLAY,
76 SPR_POSS,
77 SPR_SPOS,
78 SPR_VILE,
79 SPR_FIRE,
80 SPR_FATB,
81 SPR_FBXP,
82 SPR_SKEL,
83 SPR_MANF,
84 SPR_FATT,
85 SPR_CPOS,
86 SPR_SARG,
87 SPR_HEAD,
88 SPR_BAL7,
89 SPR_BOSS,
90 SPR_BOS2,
91 SPR_SKUL,
92 SPR_SPID,
93 SPR_BSPI,
94 SPR_APLS,
95 SPR_APBX,
96 SPR_CYBR,
97 SPR_PAIN,
98 SPR_SSWV,
99 SPR_KEEN,
100 SPR_BBRN,
101 SPR_BOSF,
102 SPR_ARM1,
103 SPR_ARM2,
104 SPR_BAR1,
105 SPR_BEXP,
106 SPR_FCAN,
107 SPR_BON1,
108 SPR_BON2,
109 SPR_BKEY,
110 SPR_RKEY,
111 SPR_YKEY,
112 SPR_BSKU,
113 SPR_RSKU,
114 SPR_YSKU,
115 SPR_STIM,
116 SPR_MEDI,
117 SPR_SOUL,
118 SPR_PINV,
119 SPR_PSTR,
120 SPR_PINS,
121 SPR_MEGA,
122 SPR_SUIT,
123 SPR_PMAP,
124 SPR_PVIS,
125 SPR_CLIP,
126 SPR_AMMO,
127 SPR_ROCK,
128 SPR_BROK,
129 SPR_CELL,
130 SPR_CELP,
131 SPR_SHEL,
132 SPR_SBOX,
133 SPR_BPAK,
134 SPR_BFUG,
135 SPR_MGUN,
136 SPR_CSAW,
137 SPR_LAUN,
138 SPR_PLAS,
139 SPR_SHOT,
140 SPR_SGN2,
141 SPR_COLU,
142 SPR_SMT2,
143 SPR_GOR1,
144 SPR_POL2,
145 SPR_POL5,
146 SPR_POL4,
147 SPR_POL3,
148 SPR_POL1,
149 SPR_POL6,
150 SPR_GOR2,
151 SPR_GOR3,
152 SPR_GOR4,
153 SPR_GOR5,
154 SPR_SMIT,
155 SPR_COL1,
156 SPR_COL2,
157 SPR_COL3,
158 SPR_COL4,
159 SPR_CAND,
160 SPR_CBRA,
161 SPR_COL6,
162 SPR_TRE1,
163 SPR_TRE2,
164 SPR_ELEC,
165 SPR_CEYE,
166 SPR_FSKU,
167 SPR_COL5,
168 SPR_TBLU,
169 SPR_TGRN,
170 SPR_TRED,
171 SPR_SMBT,
172 SPR_SMGT,
173 SPR_SMRT,
174 SPR_HDB1,
175 SPR_HDB2,
176 SPR_HDB3,
177 SPR_HDB4,
178 SPR_HDB5,
179 SPR_HDB6,
180 SPR_POB1,
181 SPR_POB2,
182 SPR_BRS1,
183 SPR_TLMP,
184 SPR_TLP2,
185 SPR_TNT1, /* add invisible sprite phares 3/8/98 */
186
187#ifdef DOGS
188 SPR_DOGS, /* killough 7/19/98: Marine's best friend :) */
189#endif
190
191 NUMSPRITES /* counter of how many there are */
192
193} spritenum_t;
194
195/********************************************************************
196 * States (frames) enumeration -- must match info.c *
197 ********************************************************************/
198
199typedef enum
200{
201 S_NULL,
202 S_LIGHTDONE,
203 S_PUNCH,
204 S_PUNCHDOWN,
205 S_PUNCHUP,
206 S_PUNCH1,
207 S_PUNCH2,
208 S_PUNCH3,
209 S_PUNCH4,
210 S_PUNCH5,
211 S_PISTOL,
212 S_PISTOLDOWN,
213 S_PISTOLUP,
214 S_PISTOL1,
215 S_PISTOL2,
216 S_PISTOL3,
217 S_PISTOL4,
218 S_PISTOLFLASH,
219 S_SGUN,
220 S_SGUNDOWN,
221 S_SGUNUP,
222 S_SGUN1,
223 S_SGUN2,
224 S_SGUN3,
225 S_SGUN4,
226 S_SGUN5,
227 S_SGUN6,
228 S_SGUN7,
229 S_SGUN8,
230 S_SGUN9,
231 S_SGUNFLASH1,
232 S_SGUNFLASH2,
233 S_DSGUN,
234 S_DSGUNDOWN,
235 S_DSGUNUP,
236 S_DSGUN1,
237 S_DSGUN2,
238 S_DSGUN3,
239 S_DSGUN4,
240 S_DSGUN5,
241 S_DSGUN6,
242 S_DSGUN7,
243 S_DSGUN8,
244 S_DSGUN9,
245 S_DSGUN10,
246 S_DSNR1,
247 S_DSNR2,
248 S_DSGUNFLASH1,
249 S_DSGUNFLASH2,
250 S_CHAIN,
251 S_CHAINDOWN,
252 S_CHAINUP,
253 S_CHAIN1,
254 S_CHAIN2,
255 S_CHAIN3,
256 S_CHAINFLASH1,
257 S_CHAINFLASH2,
258 S_MISSILE,
259 S_MISSILEDOWN,
260 S_MISSILEUP,
261 S_MISSILE1,
262 S_MISSILE2,
263 S_MISSILE3,
264 S_MISSILEFLASH1,
265 S_MISSILEFLASH2,
266 S_MISSILEFLASH3,
267 S_MISSILEFLASH4,
268 S_SAW,
269 S_SAWB,
270 S_SAWDOWN,
271 S_SAWUP,
272 S_SAW1,
273 S_SAW2,
274 S_SAW3,
275 S_PLASMA,
276 S_PLASMADOWN,
277 S_PLASMAUP,
278 S_PLASMA1,
279 S_PLASMA2,
280 S_PLASMAFLASH1,
281 S_PLASMAFLASH2,
282 S_BFG,
283 S_BFGDOWN,
284 S_BFGUP,
285 S_BFG1,
286 S_BFG2,
287 S_BFG3,
288 S_BFG4,
289 S_BFGFLASH1,
290 S_BFGFLASH2,
291 S_BLOOD1,
292 S_BLOOD2,
293 S_BLOOD3,
294 S_PUFF1,
295 S_PUFF2,
296 S_PUFF3,
297 S_PUFF4,
298 S_TBALL1,
299 S_TBALL2,
300 S_TBALLX1,
301 S_TBALLX2,
302 S_TBALLX3,
303 S_RBALL1,
304 S_RBALL2,
305 S_RBALLX1,
306 S_RBALLX2,
307 S_RBALLX3,
308 S_PLASBALL,
309 S_PLASBALL2,
310 S_PLASEXP,
311 S_PLASEXP2,
312 S_PLASEXP3,
313 S_PLASEXP4,
314 S_PLASEXP5,
315 S_ROCKET,
316 S_BFGSHOT,
317 S_BFGSHOT2,
318 S_BFGLAND,
319 S_BFGLAND2,
320 S_BFGLAND3,
321 S_BFGLAND4,
322 S_BFGLAND5,
323 S_BFGLAND6,
324 S_BFGEXP,
325 S_BFGEXP2,
326 S_BFGEXP3,
327 S_BFGEXP4,
328 S_EXPLODE1,
329 S_EXPLODE2,
330 S_EXPLODE3,
331 S_TFOG,
332 S_TFOG01,
333 S_TFOG02,
334 S_TFOG2,
335 S_TFOG3,
336 S_TFOG4,
337 S_TFOG5,
338 S_TFOG6,
339 S_TFOG7,
340 S_TFOG8,
341 S_TFOG9,
342 S_TFOG10,
343 S_IFOG,
344 S_IFOG01,
345 S_IFOG02,
346 S_IFOG2,
347 S_IFOG3,
348 S_IFOG4,
349 S_IFOG5,
350 S_PLAY,
351 S_PLAY_RUN1,
352 S_PLAY_RUN2,
353 S_PLAY_RUN3,
354 S_PLAY_RUN4,
355 S_PLAY_ATK1,
356 S_PLAY_ATK2,
357 S_PLAY_PAIN,
358 S_PLAY_PAIN2,
359 S_PLAY_DIE1,
360 S_PLAY_DIE2,
361 S_PLAY_DIE3,
362 S_PLAY_DIE4,
363 S_PLAY_DIE5,
364 S_PLAY_DIE6,
365 S_PLAY_DIE7,
366 S_PLAY_XDIE1,
367 S_PLAY_XDIE2,
368 S_PLAY_XDIE3,
369 S_PLAY_XDIE4,
370 S_PLAY_XDIE5,
371 S_PLAY_XDIE6,
372 S_PLAY_XDIE7,
373 S_PLAY_XDIE8,
374 S_PLAY_XDIE9,
375 S_POSS_STND,
376 S_POSS_STND2,
377 S_POSS_RUN1,
378 S_POSS_RUN2,
379 S_POSS_RUN3,
380 S_POSS_RUN4,
381 S_POSS_RUN5,
382 S_POSS_RUN6,
383 S_POSS_RUN7,
384 S_POSS_RUN8,
385 S_POSS_ATK1,
386 S_POSS_ATK2,
387 S_POSS_ATK3,
388 S_POSS_PAIN,
389 S_POSS_PAIN2,
390 S_POSS_DIE1,
391 S_POSS_DIE2,
392 S_POSS_DIE3,
393 S_POSS_DIE4,
394 S_POSS_DIE5,
395 S_POSS_XDIE1,
396 S_POSS_XDIE2,
397 S_POSS_XDIE3,
398 S_POSS_XDIE4,
399 S_POSS_XDIE5,
400 S_POSS_XDIE6,
401 S_POSS_XDIE7,
402 S_POSS_XDIE8,
403 S_POSS_XDIE9,
404 S_POSS_RAISE1,
405 S_POSS_RAISE2,
406 S_POSS_RAISE3,
407 S_POSS_RAISE4,
408 S_SPOS_STND,
409 S_SPOS_STND2,
410 S_SPOS_RUN1,
411 S_SPOS_RUN2,
412 S_SPOS_RUN3,
413 S_SPOS_RUN4,
414 S_SPOS_RUN5,
415 S_SPOS_RUN6,
416 S_SPOS_RUN7,
417 S_SPOS_RUN8,
418 S_SPOS_ATK1,
419 S_SPOS_ATK2,
420 S_SPOS_ATK3,
421 S_SPOS_PAIN,
422 S_SPOS_PAIN2,
423 S_SPOS_DIE1,
424 S_SPOS_DIE2,
425 S_SPOS_DIE3,
426 S_SPOS_DIE4,
427 S_SPOS_DIE5,
428 S_SPOS_XDIE1,
429 S_SPOS_XDIE2,
430 S_SPOS_XDIE3,
431 S_SPOS_XDIE4,
432 S_SPOS_XDIE5,
433 S_SPOS_XDIE6,
434 S_SPOS_XDIE7,
435 S_SPOS_XDIE8,
436 S_SPOS_XDIE9,
437 S_SPOS_RAISE1,
438 S_SPOS_RAISE2,
439 S_SPOS_RAISE3,
440 S_SPOS_RAISE4,
441 S_SPOS_RAISE5,
442 S_VILE_STND,
443 S_VILE_STND2,
444 S_VILE_RUN1,
445 S_VILE_RUN2,
446 S_VILE_RUN3,
447 S_VILE_RUN4,
448 S_VILE_RUN5,
449 S_VILE_RUN6,
450 S_VILE_RUN7,
451 S_VILE_RUN8,
452 S_VILE_RUN9,
453 S_VILE_RUN10,
454 S_VILE_RUN11,
455 S_VILE_RUN12,
456 S_VILE_ATK1,
457 S_VILE_ATK2,
458 S_VILE_ATK3,
459 S_VILE_ATK4,
460 S_VILE_ATK5,
461 S_VILE_ATK6,
462 S_VILE_ATK7,
463 S_VILE_ATK8,
464 S_VILE_ATK9,
465 S_VILE_ATK10,
466 S_VILE_ATK11,
467 S_VILE_HEAL1,
468 S_VILE_HEAL2,
469 S_VILE_HEAL3,
470 S_VILE_PAIN,
471 S_VILE_PAIN2,
472 S_VILE_DIE1,
473 S_VILE_DIE2,
474 S_VILE_DIE3,
475 S_VILE_DIE4,
476 S_VILE_DIE5,
477 S_VILE_DIE6,
478 S_VILE_DIE7,
479 S_VILE_DIE8,
480 S_VILE_DIE9,
481 S_VILE_DIE10,
482 S_FIRE1,
483 S_FIRE2,
484 S_FIRE3,
485 S_FIRE4,
486 S_FIRE5,
487 S_FIRE6,
488 S_FIRE7,
489 S_FIRE8,
490 S_FIRE9,
491 S_FIRE10,
492 S_FIRE11,
493 S_FIRE12,
494 S_FIRE13,
495 S_FIRE14,
496 S_FIRE15,
497 S_FIRE16,
498 S_FIRE17,
499 S_FIRE18,
500 S_FIRE19,
501 S_FIRE20,
502 S_FIRE21,
503 S_FIRE22,
504 S_FIRE23,
505 S_FIRE24,
506 S_FIRE25,
507 S_FIRE26,
508 S_FIRE27,
509 S_FIRE28,
510 S_FIRE29,
511 S_FIRE30,
512 S_SMOKE1,
513 S_SMOKE2,
514 S_SMOKE3,
515 S_SMOKE4,
516 S_SMOKE5,
517 S_TRACER,
518 S_TRACER2,
519 S_TRACEEXP1,
520 S_TRACEEXP2,
521 S_TRACEEXP3,
522 S_SKEL_STND,
523 S_SKEL_STND2,
524 S_SKEL_RUN1,
525 S_SKEL_RUN2,
526 S_SKEL_RUN3,
527 S_SKEL_RUN4,
528 S_SKEL_RUN5,
529 S_SKEL_RUN6,
530 S_SKEL_RUN7,
531 S_SKEL_RUN8,
532 S_SKEL_RUN9,
533 S_SKEL_RUN10,
534 S_SKEL_RUN11,
535 S_SKEL_RUN12,
536 S_SKEL_FIST1,
537 S_SKEL_FIST2,
538 S_SKEL_FIST3,
539 S_SKEL_FIST4,
540 S_SKEL_MISS1,
541 S_SKEL_MISS2,
542 S_SKEL_MISS3,
543 S_SKEL_MISS4,
544 S_SKEL_PAIN,
545 S_SKEL_PAIN2,
546 S_SKEL_DIE1,
547 S_SKEL_DIE2,
548 S_SKEL_DIE3,
549 S_SKEL_DIE4,
550 S_SKEL_DIE5,
551 S_SKEL_DIE6,
552 S_SKEL_RAISE1,
553 S_SKEL_RAISE2,
554 S_SKEL_RAISE3,
555 S_SKEL_RAISE4,
556 S_SKEL_RAISE5,
557 S_SKEL_RAISE6,
558 S_FATSHOT1,
559 S_FATSHOT2,
560 S_FATSHOTX1,
561 S_FATSHOTX2,
562 S_FATSHOTX3,
563 S_FATT_STND,
564 S_FATT_STND2,
565 S_FATT_RUN1,
566 S_FATT_RUN2,
567 S_FATT_RUN3,
568 S_FATT_RUN4,
569 S_FATT_RUN5,
570 S_FATT_RUN6,
571 S_FATT_RUN7,
572 S_FATT_RUN8,
573 S_FATT_RUN9,
574 S_FATT_RUN10,
575 S_FATT_RUN11,
576 S_FATT_RUN12,
577 S_FATT_ATK1,
578 S_FATT_ATK2,
579 S_FATT_ATK3,
580 S_FATT_ATK4,
581 S_FATT_ATK5,
582 S_FATT_ATK6,
583 S_FATT_ATK7,
584 S_FATT_ATK8,
585 S_FATT_ATK9,
586 S_FATT_ATK10,
587 S_FATT_PAIN,
588 S_FATT_PAIN2,
589 S_FATT_DIE1,
590 S_FATT_DIE2,
591 S_FATT_DIE3,
592 S_FATT_DIE4,
593 S_FATT_DIE5,
594 S_FATT_DIE6,
595 S_FATT_DIE7,
596 S_FATT_DIE8,
597 S_FATT_DIE9,
598 S_FATT_DIE10,
599 S_FATT_RAISE1,
600 S_FATT_RAISE2,
601 S_FATT_RAISE3,
602 S_FATT_RAISE4,
603 S_FATT_RAISE5,
604 S_FATT_RAISE6,
605 S_FATT_RAISE7,
606 S_FATT_RAISE8,
607 S_CPOS_STND,
608 S_CPOS_STND2,
609 S_CPOS_RUN1,
610 S_CPOS_RUN2,
611 S_CPOS_RUN3,
612 S_CPOS_RUN4,
613 S_CPOS_RUN5,
614 S_CPOS_RUN6,
615 S_CPOS_RUN7,
616 S_CPOS_RUN8,
617 S_CPOS_ATK1,
618 S_CPOS_ATK2,
619 S_CPOS_ATK3,
620 S_CPOS_ATK4,
621 S_CPOS_PAIN,
622 S_CPOS_PAIN2,
623 S_CPOS_DIE1,
624 S_CPOS_DIE2,
625 S_CPOS_DIE3,
626 S_CPOS_DIE4,
627 S_CPOS_DIE5,
628 S_CPOS_DIE6,
629 S_CPOS_DIE7,
630 S_CPOS_XDIE1,
631 S_CPOS_XDIE2,
632 S_CPOS_XDIE3,
633 S_CPOS_XDIE4,
634 S_CPOS_XDIE5,
635 S_CPOS_XDIE6,
636 S_CPOS_RAISE1,
637 S_CPOS_RAISE2,
638 S_CPOS_RAISE3,
639 S_CPOS_RAISE4,
640 S_CPOS_RAISE5,
641 S_CPOS_RAISE6,
642 S_CPOS_RAISE7,
643 S_TROO_STND,
644 S_TROO_STND2,
645 S_TROO_RUN1,
646 S_TROO_RUN2,
647 S_TROO_RUN3,
648 S_TROO_RUN4,
649 S_TROO_RUN5,
650 S_TROO_RUN6,
651 S_TROO_RUN7,
652 S_TROO_RUN8,
653 S_TROO_ATK1,
654 S_TROO_ATK2,
655 S_TROO_ATK3,
656 S_TROO_PAIN,
657 S_TROO_PAIN2,
658 S_TROO_DIE1,
659 S_TROO_DIE2,
660 S_TROO_DIE3,
661 S_TROO_DIE4,
662 S_TROO_DIE5,
663 S_TROO_XDIE1,
664 S_TROO_XDIE2,
665 S_TROO_XDIE3,
666 S_TROO_XDIE4,
667 S_TROO_XDIE5,
668 S_TROO_XDIE6,
669 S_TROO_XDIE7,
670 S_TROO_XDIE8,
671 S_TROO_RAISE1,
672 S_TROO_RAISE2,
673 S_TROO_RAISE3,
674 S_TROO_RAISE4,
675 S_TROO_RAISE5,
676 S_SARG_STND,
677 S_SARG_STND2,
678 S_SARG_RUN1,
679 S_SARG_RUN2,
680 S_SARG_RUN3,
681 S_SARG_RUN4,
682 S_SARG_RUN5,
683 S_SARG_RUN6,
684 S_SARG_RUN7,
685 S_SARG_RUN8,
686 S_SARG_ATK1,
687 S_SARG_ATK2,
688 S_SARG_ATK3,
689 S_SARG_PAIN,
690 S_SARG_PAIN2,
691 S_SARG_DIE1,
692 S_SARG_DIE2,
693 S_SARG_DIE3,
694 S_SARG_DIE4,
695 S_SARG_DIE5,
696 S_SARG_DIE6,
697 S_SARG_RAISE1,
698 S_SARG_RAISE2,
699 S_SARG_RAISE3,
700 S_SARG_RAISE4,
701 S_SARG_RAISE5,
702 S_SARG_RAISE6,
703 S_HEAD_STND,
704 S_HEAD_RUN1,
705 S_HEAD_ATK1,
706 S_HEAD_ATK2,
707 S_HEAD_ATK3,
708 S_HEAD_PAIN,
709 S_HEAD_PAIN2,
710 S_HEAD_PAIN3,
711 S_HEAD_DIE1,
712 S_HEAD_DIE2,
713 S_HEAD_DIE3,
714 S_HEAD_DIE4,
715 S_HEAD_DIE5,
716 S_HEAD_DIE6,
717 S_HEAD_RAISE1,
718 S_HEAD_RAISE2,
719 S_HEAD_RAISE3,
720 S_HEAD_RAISE4,
721 S_HEAD_RAISE5,
722 S_HEAD_RAISE6,
723 S_BRBALL1,
724 S_BRBALL2,
725 S_BRBALLX1,
726 S_BRBALLX2,
727 S_BRBALLX3,
728 S_BOSS_STND,
729 S_BOSS_STND2,
730 S_BOSS_RUN1,
731 S_BOSS_RUN2,
732 S_BOSS_RUN3,
733 S_BOSS_RUN4,
734 S_BOSS_RUN5,
735 S_BOSS_RUN6,
736 S_BOSS_RUN7,
737 S_BOSS_RUN8,
738 S_BOSS_ATK1,
739 S_BOSS_ATK2,
740 S_BOSS_ATK3,
741 S_BOSS_PAIN,
742 S_BOSS_PAIN2,
743 S_BOSS_DIE1,
744 S_BOSS_DIE2,
745 S_BOSS_DIE3,
746 S_BOSS_DIE4,
747 S_BOSS_DIE5,
748 S_BOSS_DIE6,
749 S_BOSS_DIE7,
750 S_BOSS_RAISE1,
751 S_BOSS_RAISE2,
752 S_BOSS_RAISE3,
753 S_BOSS_RAISE4,
754 S_BOSS_RAISE5,
755 S_BOSS_RAISE6,
756 S_BOSS_RAISE7,
757 S_BOS2_STND,
758 S_BOS2_STND2,
759 S_BOS2_RUN1,
760 S_BOS2_RUN2,
761 S_BOS2_RUN3,
762 S_BOS2_RUN4,
763 S_BOS2_RUN5,
764 S_BOS2_RUN6,
765 S_BOS2_RUN7,
766 S_BOS2_RUN8,
767 S_BOS2_ATK1,
768 S_BOS2_ATK2,
769 S_BOS2_ATK3,
770 S_BOS2_PAIN,
771 S_BOS2_PAIN2,
772 S_BOS2_DIE1,
773 S_BOS2_DIE2,
774 S_BOS2_DIE3,
775 S_BOS2_DIE4,
776 S_BOS2_DIE5,
777 S_BOS2_DIE6,
778 S_BOS2_DIE7,
779 S_BOS2_RAISE1,
780 S_BOS2_RAISE2,
781 S_BOS2_RAISE3,
782 S_BOS2_RAISE4,
783 S_BOS2_RAISE5,
784 S_BOS2_RAISE6,
785 S_BOS2_RAISE7,
786 S_SKULL_STND,
787 S_SKULL_STND2,
788 S_SKULL_RUN1,
789 S_SKULL_RUN2,
790 S_SKULL_ATK1,
791 S_SKULL_ATK2,
792 S_SKULL_ATK3,
793 S_SKULL_ATK4,
794 S_SKULL_PAIN,
795 S_SKULL_PAIN2,
796 S_SKULL_DIE1,
797 S_SKULL_DIE2,
798 S_SKULL_DIE3,
799 S_SKULL_DIE4,
800 S_SKULL_DIE5,
801 S_SKULL_DIE6,
802 S_SPID_STND,
803 S_SPID_STND2,
804 S_SPID_RUN1,
805 S_SPID_RUN2,
806 S_SPID_RUN3,
807 S_SPID_RUN4,
808 S_SPID_RUN5,
809 S_SPID_RUN6,
810 S_SPID_RUN7,
811 S_SPID_RUN8,
812 S_SPID_RUN9,
813 S_SPID_RUN10,
814 S_SPID_RUN11,
815 S_SPID_RUN12,
816 S_SPID_ATK1,
817 S_SPID_ATK2,
818 S_SPID_ATK3,
819 S_SPID_ATK4,
820 S_SPID_PAIN,
821 S_SPID_PAIN2,
822 S_SPID_DIE1,
823 S_SPID_DIE2,
824 S_SPID_DIE3,
825 S_SPID_DIE4,
826 S_SPID_DIE5,
827 S_SPID_DIE6,
828 S_SPID_DIE7,
829 S_SPID_DIE8,
830 S_SPID_DIE9,
831 S_SPID_DIE10,
832 S_SPID_DIE11,
833 S_BSPI_STND,
834 S_BSPI_STND2,
835 S_BSPI_SIGHT,
836 S_BSPI_RUN1,
837 S_BSPI_RUN2,
838 S_BSPI_RUN3,
839 S_BSPI_RUN4,
840 S_BSPI_RUN5,
841 S_BSPI_RUN6,
842 S_BSPI_RUN7,
843 S_BSPI_RUN8,
844 S_BSPI_RUN9,
845 S_BSPI_RUN10,
846 S_BSPI_RUN11,
847 S_BSPI_RUN12,
848 S_BSPI_ATK1,
849 S_BSPI_ATK2,
850 S_BSPI_ATK3,
851 S_BSPI_ATK4,
852 S_BSPI_PAIN,
853 S_BSPI_PAIN2,
854 S_BSPI_DIE1,
855 S_BSPI_DIE2,
856 S_BSPI_DIE3,
857 S_BSPI_DIE4,
858 S_BSPI_DIE5,
859 S_BSPI_DIE6,
860 S_BSPI_DIE7,
861 S_BSPI_RAISE1,
862 S_BSPI_RAISE2,
863 S_BSPI_RAISE3,
864 S_BSPI_RAISE4,
865 S_BSPI_RAISE5,
866 S_BSPI_RAISE6,
867 S_BSPI_RAISE7,
868 S_ARACH_PLAZ,
869 S_ARACH_PLAZ2,
870 S_ARACH_PLEX,
871 S_ARACH_PLEX2,
872 S_ARACH_PLEX3,
873 S_ARACH_PLEX4,
874 S_ARACH_PLEX5,
875 S_CYBER_STND,
876 S_CYBER_STND2,
877 S_CYBER_RUN1,
878 S_CYBER_RUN2,
879 S_CYBER_RUN3,
880 S_CYBER_RUN4,
881 S_CYBER_RUN5,
882 S_CYBER_RUN6,
883 S_CYBER_RUN7,
884 S_CYBER_RUN8,
885 S_CYBER_ATK1,
886 S_CYBER_ATK2,
887 S_CYBER_ATK3,
888 S_CYBER_ATK4,
889 S_CYBER_ATK5,
890 S_CYBER_ATK6,
891 S_CYBER_PAIN,
892 S_CYBER_DIE1,
893 S_CYBER_DIE2,
894 S_CYBER_DIE3,
895 S_CYBER_DIE4,
896 S_CYBER_DIE5,
897 S_CYBER_DIE6,
898 S_CYBER_DIE7,
899 S_CYBER_DIE8,
900 S_CYBER_DIE9,
901 S_CYBER_DIE10,
902 S_PAIN_STND,
903 S_PAIN_RUN1,
904 S_PAIN_RUN2,
905 S_PAIN_RUN3,
906 S_PAIN_RUN4,
907 S_PAIN_RUN5,
908 S_PAIN_RUN6,
909 S_PAIN_ATK1,
910 S_PAIN_ATK2,
911 S_PAIN_ATK3,
912 S_PAIN_ATK4,
913 S_PAIN_PAIN,
914 S_PAIN_PAIN2,
915 S_PAIN_DIE1,
916 S_PAIN_DIE2,
917 S_PAIN_DIE3,
918 S_PAIN_DIE4,
919 S_PAIN_DIE5,
920 S_PAIN_DIE6,
921 S_PAIN_RAISE1,
922 S_PAIN_RAISE2,
923 S_PAIN_RAISE3,
924 S_PAIN_RAISE4,
925 S_PAIN_RAISE5,
926 S_PAIN_RAISE6,
927 S_SSWV_STND,
928 S_SSWV_STND2,
929 S_SSWV_RUN1,
930 S_SSWV_RUN2,
931 S_SSWV_RUN3,
932 S_SSWV_RUN4,
933 S_SSWV_RUN5,
934 S_SSWV_RUN6,
935 S_SSWV_RUN7,
936 S_SSWV_RUN8,
937 S_SSWV_ATK1,
938 S_SSWV_ATK2,
939 S_SSWV_ATK3,
940 S_SSWV_ATK4,
941 S_SSWV_ATK5,
942 S_SSWV_ATK6,
943 S_SSWV_PAIN,
944 S_SSWV_PAIN2,
945 S_SSWV_DIE1,
946 S_SSWV_DIE2,
947 S_SSWV_DIE3,
948 S_SSWV_DIE4,
949 S_SSWV_DIE5,
950 S_SSWV_XDIE1,
951 S_SSWV_XDIE2,
952 S_SSWV_XDIE3,
953 S_SSWV_XDIE4,
954 S_SSWV_XDIE5,
955 S_SSWV_XDIE6,
956 S_SSWV_XDIE7,
957 S_SSWV_XDIE8,
958 S_SSWV_XDIE9,
959 S_SSWV_RAISE1,
960 S_SSWV_RAISE2,
961 S_SSWV_RAISE3,
962 S_SSWV_RAISE4,
963 S_SSWV_RAISE5,
964 S_KEENSTND,
965 S_COMMKEEN,
966 S_COMMKEEN2,
967 S_COMMKEEN3,
968 S_COMMKEEN4,
969 S_COMMKEEN5,
970 S_COMMKEEN6,
971 S_COMMKEEN7,
972 S_COMMKEEN8,
973 S_COMMKEEN9,
974 S_COMMKEEN10,
975 S_COMMKEEN11,
976 S_COMMKEEN12,
977 S_KEENPAIN,
978 S_KEENPAIN2,
979 S_BRAIN,
980 S_BRAIN_PAIN,
981 S_BRAIN_DIE1,
982 S_BRAIN_DIE2,
983 S_BRAIN_DIE3,
984 S_BRAIN_DIE4,
985 S_BRAINEYE,
986 S_BRAINEYESEE,
987 S_BRAINEYE1,
988 S_SPAWN1,
989 S_SPAWN2,
990 S_SPAWN3,
991 S_SPAWN4,
992 S_SPAWNFIRE1,
993 S_SPAWNFIRE2,
994 S_SPAWNFIRE3,
995 S_SPAWNFIRE4,
996 S_SPAWNFIRE5,
997 S_SPAWNFIRE6,
998 S_SPAWNFIRE7,
999 S_SPAWNFIRE8,
1000 S_BRAINEXPLODE1,
1001 S_BRAINEXPLODE2,
1002 S_BRAINEXPLODE3,
1003 S_ARM1,
1004 S_ARM1A,
1005 S_ARM2,
1006 S_ARM2A,
1007 S_BAR1,
1008 S_BAR2,
1009 S_BEXP,
1010 S_BEXP2,
1011 S_BEXP3,
1012 S_BEXP4,
1013 S_BEXP5,
1014 S_BBAR1,
1015 S_BBAR2,
1016 S_BBAR3,
1017 S_BON1,
1018 S_BON1A,
1019 S_BON1B,
1020 S_BON1C,
1021 S_BON1D,
1022 S_BON1E,
1023 S_BON2,
1024 S_BON2A,
1025 S_BON2B,
1026 S_BON2C,
1027 S_BON2D,
1028 S_BON2E,
1029 S_BKEY,
1030 S_BKEY2,
1031 S_RKEY,
1032 S_RKEY2,
1033 S_YKEY,
1034 S_YKEY2,
1035 S_BSKULL,
1036 S_BSKULL2,
1037 S_RSKULL,
1038 S_RSKULL2,
1039 S_YSKULL,
1040 S_YSKULL2,
1041 S_STIM,
1042 S_MEDI,
1043 S_SOUL,
1044 S_SOUL2,
1045 S_SOUL3,
1046 S_SOUL4,
1047 S_SOUL5,
1048 S_SOUL6,
1049 S_PINV,
1050 S_PINV2,
1051 S_PINV3,
1052 S_PINV4,
1053 S_PSTR,
1054 S_PINS,
1055 S_PINS2,
1056 S_PINS3,
1057 S_PINS4,
1058 S_MEGA,
1059 S_MEGA2,
1060 S_MEGA3,
1061 S_MEGA4,
1062 S_SUIT,
1063 S_PMAP,
1064 S_PMAP2,
1065 S_PMAP3,
1066 S_PMAP4,
1067 S_PMAP5,
1068 S_PMAP6,
1069 S_PVIS,
1070 S_PVIS2,
1071 S_CLIP,
1072 S_AMMO,
1073 S_ROCK,
1074 S_BROK,
1075 S_CELL,
1076 S_CELP,
1077 S_SHEL,
1078 S_SBOX,
1079 S_BPAK,
1080 S_BFUG,
1081 S_MGUN,
1082 S_CSAW,
1083 S_LAUN,
1084 S_PLAS,
1085 S_SHOT,
1086 S_SHOT2,
1087 S_COLU,
1088 S_STALAG,
1089 S_BLOODYTWITCH,
1090 S_BLOODYTWITCH2,
1091 S_BLOODYTWITCH3,
1092 S_BLOODYTWITCH4,
1093 S_DEADTORSO,
1094 S_DEADBOTTOM,
1095 S_HEADSONSTICK,
1096 S_GIBS,
1097 S_HEADONASTICK,
1098 S_HEADCANDLES,
1099 S_HEADCANDLES2,
1100 S_DEADSTICK,
1101 S_LIVESTICK,
1102 S_LIVESTICK2,
1103 S_MEAT2,
1104 S_MEAT3,
1105 S_MEAT4,
1106 S_MEAT5,
1107 S_STALAGTITE,
1108 S_TALLGRNCOL,
1109 S_SHRTGRNCOL,
1110 S_TALLREDCOL,
1111 S_SHRTREDCOL,
1112 S_CANDLESTIK,
1113 S_CANDELABRA,
1114 S_SKULLCOL,
1115 S_TORCHTREE,
1116 S_BIGTREE,
1117 S_TECHPILLAR,
1118 S_EVILEYE,
1119 S_EVILEYE2,
1120 S_EVILEYE3,
1121 S_EVILEYE4,
1122 S_FLOATSKULL,
1123 S_FLOATSKULL2,
1124 S_FLOATSKULL3,
1125 S_HEARTCOL,
1126 S_HEARTCOL2,
1127 S_BLUETORCH,
1128 S_BLUETORCH2,
1129 S_BLUETORCH3,
1130 S_BLUETORCH4,
1131 S_GREENTORCH,
1132 S_GREENTORCH2,
1133 S_GREENTORCH3,
1134 S_GREENTORCH4,
1135 S_REDTORCH,
1136 S_REDTORCH2,
1137 S_REDTORCH3,
1138 S_REDTORCH4,
1139 S_BTORCHSHRT,
1140 S_BTORCHSHRT2,
1141 S_BTORCHSHRT3,
1142 S_BTORCHSHRT4,
1143 S_GTORCHSHRT,
1144 S_GTORCHSHRT2,
1145 S_GTORCHSHRT3,
1146 S_GTORCHSHRT4,
1147 S_RTORCHSHRT,
1148 S_RTORCHSHRT2,
1149 S_RTORCHSHRT3,
1150 S_RTORCHSHRT4,
1151 S_HANGNOGUTS,
1152 S_HANGBNOBRAIN,
1153 S_HANGTLOOKDN,
1154 S_HANGTSKULL,
1155 S_HANGTLOOKUP,
1156 S_HANGTNOBRAIN,
1157 S_COLONGIBS,
1158 S_SMALLPOOL,
1159 S_BRAINSTEM,
1160 S_TECHLAMP,
1161 S_TECHLAMP2,
1162 S_TECHLAMP3,
1163 S_TECHLAMP4,
1164 S_TECH2LAMP,
1165 S_TECH2LAMP2,
1166 S_TECH2LAMP3,
1167 S_TECH2LAMP4,
1168 S_TNT1, /* add state for invisible sprite phares 3/8/98 */
1169
1170 S_GRENADE, /* killough 8/9/98: grenade launcher */
1171 S_DETONATE, /* killough 8/9/98: detonation of objects */
1172 S_DETONATE2,
1173 S_DETONATE3,
1174
1175 // always count dog states, even if dogs are disabled
1176 S_DOGS_STND, /* killough 7/19/98: Marine's best friend :) */
1177 S_DOGS_STND2,
1178 S_DOGS_RUN1,
1179 S_DOGS_RUN2,
1180 S_DOGS_RUN3,
1181 S_DOGS_RUN4,
1182 S_DOGS_RUN5,
1183 S_DOGS_RUN6,
1184 S_DOGS_RUN7,
1185 S_DOGS_RUN8,
1186 S_DOGS_ATK1,
1187 S_DOGS_ATK2,
1188 S_DOGS_ATK3,
1189 S_DOGS_PAIN,
1190 S_DOGS_PAIN2,
1191 S_DOGS_DIE1,
1192 S_DOGS_DIE2,
1193 S_DOGS_DIE3,
1194 S_DOGS_DIE4,
1195 S_DOGS_DIE5,
1196 S_DOGS_DIE6,
1197 S_DOGS_RAISE1,
1198 S_DOGS_RAISE2,
1199 S_DOGS_RAISE3,
1200 S_DOGS_RAISE4,
1201 S_DOGS_RAISE5,
1202 S_DOGS_RAISE6,
1203
1204 // add dummy beta bfg / lost soul frames for dehacked compatibility
1205 // fixes bug #1576151 (part 2)
1206 S_OLDBFG1, // killough 7/11/98: the old BFG's 43 firing frames
1207 S_OLDBFG42 = S_OLDBFG1+41,
1208 S_OLDBFG43,
1209
1210 S_PLS1BALL, // killough 7/19/98: first plasma fireball in the beta
1211 S_PLS1BALL2,
1212 S_PLS1EXP,
1213 S_PLS1EXP2,
1214 S_PLS1EXP3,
1215 S_PLS1EXP4,
1216 S_PLS1EXP5,
1217
1218 S_PLS2BALL, // killough 7/19/98: second plasma fireball in the beta
1219 S_PLS2BALL2,
1220 S_PLS2BALLX1,
1221 S_PLS2BALLX2,
1222 S_PLS2BALLX3,
1223 S_BON3, // killough 7/11/98: evil sceptre in beta version
1224 S_BON4, // killough 7/11/98: unholy bible in beta version
1225
1226 // killough 10/98: beta lost souls were different from their modern cousins
1227 S_BSKUL_STND,
1228 S_BSKUL_RUN1,
1229 S_BSKUL_RUN2,
1230 S_BSKUL_RUN3,
1231 S_BSKUL_RUN4,
1232 S_BSKUL_ATK1,
1233 S_BSKUL_ATK2,
1234 S_BSKUL_ATK3,
1235 S_BSKUL_PAIN1,
1236 S_BSKUL_PAIN2,
1237 S_BSKUL_PAIN3,
1238 S_BSKUL_DIE1,
1239 S_BSKUL_DIE2,
1240 S_BSKUL_DIE3,
1241 S_BSKUL_DIE4,
1242 S_BSKUL_DIE5,
1243 S_BSKUL_DIE6,
1244 S_BSKUL_DIE7,
1245 S_BSKUL_DIE8,
1246
1247 S_MUSHROOM, /* killough 10/98: mushroom explosion effect */
1248
1249 NUMSTATES /* Counter of how many there are */
1250
1251} statenum_t;
1252
1253/********************************************************************
1254 * Definition of the state (frames) structure *
1255 ********************************************************************/
1256
1257typedef struct
1258{
1259 spritenum_t sprite; /* sprite number to show */
1260 long frame; /* which frame/subframe of the sprite is shown */
1261 long tics; /* number of gametics this frame should last */
1262 actionf_t action; /* code pointer to function for action if any */
1263 statenum_t nextstate; /* linked list pointer to next state or zero */
1264 long misc1, misc2; /* apparently never used in DOOM */
1265} state_t;
1266
1267/* these are in info.c */
1268extern state_t states[NUMSTATES];
1269extern const char *sprnames[]; /* 1/17/98 killough - CPhipps - const */
1270
1271/********************************************************************
1272 * Thing enumeration -- must match info.c *
1273 ********************************************************************
1274 * Note that many of these are generically named for the ornamentals
1275 */
1276
1277typedef enum {
1278 MT_PLAYER,
1279 MT_POSSESSED,
1280 MT_SHOTGUY,
1281 MT_VILE,
1282 MT_FIRE,
1283 MT_UNDEAD,
1284 MT_TRACER,
1285 MT_SMOKE,
1286 MT_FATSO,
1287 MT_FATSHOT,
1288 MT_CHAINGUY,
1289 MT_TROOP,
1290 MT_SERGEANT,
1291 MT_SHADOWS,
1292 MT_HEAD,
1293 MT_BRUISER,
1294 MT_BRUISERSHOT,
1295 MT_KNIGHT,
1296 MT_SKULL,
1297 MT_SPIDER,
1298 MT_BABY,
1299 MT_CYBORG,
1300 MT_PAIN,
1301 MT_WOLFSS,
1302 MT_KEEN,
1303 MT_BOSSBRAIN,
1304 MT_BOSSSPIT,
1305 MT_BOSSTARGET,
1306 MT_SPAWNSHOT,
1307 MT_SPAWNFIRE,
1308 MT_BARREL,
1309 MT_TROOPSHOT,
1310 MT_HEADSHOT,
1311 MT_ROCKET,
1312 MT_PLASMA,
1313 MT_BFG,
1314 MT_ARACHPLAZ,
1315 MT_PUFF,
1316 MT_BLOOD,
1317 MT_TFOG,
1318 MT_IFOG,
1319 MT_TELEPORTMAN,
1320 MT_EXTRABFG,
1321 MT_MISC0,
1322 MT_MISC1,
1323 MT_MISC2,
1324 MT_MISC3,
1325 MT_MISC4,
1326 MT_MISC5,
1327 MT_MISC6,
1328 MT_MISC7,
1329 MT_MISC8,
1330 MT_MISC9,
1331 MT_MISC10,
1332 MT_MISC11,
1333 MT_MISC12,
1334 MT_INV,
1335 MT_MISC13,
1336 MT_INS,
1337 MT_MISC14,
1338 MT_MISC15,
1339 MT_MISC16,
1340 MT_MEGA,
1341 MT_CLIP,
1342 MT_MISC17,
1343 MT_MISC18,
1344 MT_MISC19,
1345 MT_MISC20,
1346 MT_MISC21,
1347 MT_MISC22,
1348 MT_MISC23,
1349 MT_MISC24,
1350 MT_MISC25,
1351 MT_CHAINGUN,
1352 MT_MISC26,
1353 MT_MISC27,
1354 MT_MISC28,
1355 MT_SHOTGUN,
1356 MT_SUPERSHOTGUN,
1357 MT_MISC29,
1358 MT_MISC30,
1359 MT_MISC31,
1360 MT_MISC32,
1361 MT_MISC33,
1362 MT_MISC34,
1363 MT_MISC35,
1364 MT_MISC36,
1365 MT_MISC37,
1366 MT_MISC38,
1367 MT_MISC39,
1368 MT_MISC40,
1369 MT_MISC41,
1370 MT_MISC42,
1371 MT_MISC43,
1372 MT_MISC44,
1373 MT_MISC45,
1374 MT_MISC46,
1375 MT_MISC47,
1376 MT_MISC48,
1377 MT_MISC49,
1378 MT_MISC50,
1379 MT_MISC51,
1380 MT_MISC52,
1381 MT_MISC53,
1382 MT_MISC54,
1383 MT_MISC55,
1384 MT_MISC56,
1385 MT_MISC57,
1386 MT_MISC58,
1387 MT_MISC59,
1388 MT_MISC60,
1389 MT_MISC61,
1390 MT_MISC62,
1391 MT_MISC63,
1392 MT_MISC64,
1393 MT_MISC65,
1394 MT_MISC66,
1395 MT_MISC67,
1396 MT_MISC68,
1397 MT_MISC69,
1398 MT_MISC70,
1399 MT_MISC71,
1400 MT_MISC72,
1401 MT_MISC73,
1402 MT_MISC74,
1403 MT_MISC75,
1404 MT_MISC76,
1405 MT_MISC77,
1406 MT_MISC78,
1407 MT_MISC79,
1408 MT_MISC80,
1409 MT_MISC81,
1410 MT_MISC82,
1411 MT_MISC83,
1412 MT_MISC84,
1413 MT_MISC85,
1414 MT_MISC86,
1415 MT_PUSH, /* controls push source - phares */
1416 MT_PULL, /* controls pull source - phares 3/20/98 */
1417
1418#ifdef DOGS
1419 MT_DOGS, /* killough 7/19/98: Marine's best friend */
1420#endif
1421
1422 /* proff 11/22/98: Andy Baker's stealth monsters (next 12)
1423 * cph - moved below the MBF stuff, no need to displace them */
1424 MT_STEALTHBABY,
1425 MT_STEALTHVILE,
1426 MT_STEALTHBRUISER,
1427 MT_STEALTHHEAD,
1428 MT_STEALTHCHAINGUY,
1429 MT_STEALTHSERGEANT,
1430 MT_STEALTHKNIGHT,
1431 MT_STEALTHIMP,
1432 MT_STEALTHFATSO,
1433 MT_STEALTHUNDEAD,
1434 MT_STEALTHSHOTGUY,
1435 MT_STEALTHZOMBIE,
1436
1437 NUMMOBJTYPES // Counter of how many there are
1438} mobjtype_t;
1439
1440/********************************************************************
1441 * Definition of the Thing structure
1442 ********************************************************************/
1443/* Note that these are only indices to the state, sound, etc. arrays
1444 * and not actual pointers. Most can be set to zero if the action or
1445 * sound doesn't apply (like lamps generally don't attack or whistle).
1446 */
1447
1448typedef struct
1449{
1450 int doomednum; /* Thing number used in id's editor, and now
1451 probably by every other editor too */
1452 int spawnstate; /* The state (frame) index when this Thing is
1453 first created */
1454 int spawnhealth; /* The initial hit points for this Thing */
1455 int seestate; /* The state when it sees you or wakes up */
1456 int seesound; /* The sound it makes when waking */
1457 int reactiontime; /* How many tics it waits after it wakes up
1458 before it will start to attack, in normal
1459 skills (halved for nightmare) */
1460 int attacksound; /* The sound it makes when it attacks */
1461 int painstate; /* The state to indicate pain */
1462 int painchance; /* A number that is checked against a random
1463 number 0-255 to see if the Thing is supposed
1464 to go to its painstate or not. Note this
1465 has absolutely nothing to do with the chance
1466 it will get hurt, just the chance of it
1467 reacting visibly. */
1468 int painsound; /* The sound it emits when it feels pain */
1469 int meleestate; /* Melee==close attack */
1470 int missilestate; /* What states to use when it's in the air, if
1471 in fact it is ever used as a missile */
1472 int deathstate; /* What state begins the death sequence */
1473 int xdeathstate; /* What state begins the horrible death sequence
1474 like when a rocket takes out a trooper */
1475 int deathsound; /* The death sound. See also A_Scream() in
1476 p_enemy.c for some tweaking that goes on
1477 for certain monsters */
1478 int speed; /* How fast it moves. Too fast and it can miss
1479 collision logic. */
1480 int radius; /* An often incorrect radius */
1481 int height; /* An often incorrect height, used only to see
1482 if a monster can enter a sector */
1483 int mass; /* How much an impact will move it. Cacodemons
1484 seem to retreat when shot because they have
1485 very little mass and are moved by impact */
1486 int damage; /* If this is a missile, how much does it hurt? */
1487 int activesound; /* What sound it makes wandering around, once
1488 in a while. Chance is 3/256 it will. */
1489 uint_64_t flags; /* Bit masks for lots of things. See p_mobj.h */
1490 int raisestate; /* The first state for an Archvile or respawn
1491 resurrection. Zero means it won't come
1492 back to life. */
1493} mobjinfo_t;
1494
1495/* See p_mobj_h for addition more technical info */
1496extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
1497
1498#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Provides a logical console output routine that allows what is
31 * output to console normally and when output is redirected to
32 * be controlled..
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39#ifdef _WIN32
40#define WIN32_LEAN_AND_MEAN
41#include <windows.h>
42#endif
43#ifdef _MSC_VER
44#include <io.h>
45#endif
46#include <stdio.h>
47#include <stdlib.h>
48#include <stdarg.h>
49#ifdef HAVE_UNISTD_H
50#include <unistd.h>
51#endif
52#include "doomtype.h"
53#include "lprintf.h"
54#include "i_main.h"
55#include "m_argv.h"
56
57int cons_error_mask = -1-LO_INFO; /* all but LO_INFO when redir'd */
58int cons_output_mask = -1; /* all output enabled */
59
60/* cphipps - enlarged message buffer and made non-static
61 * We still have to be careful here, this function can be called after exit
62 */
63#define MAX_MESSAGE_SIZE 2048
64
65#ifdef _WIN32
66// Variables for the console
67HWND con_hWnd=0;
68HFONT OemFont;
69LONG OemWidth, OemHeight;
70int ConWidth,ConHeight;
71char szConName[] = "PrBoomConWinClass";
72char Lines[(80+2)*25+1];
73char *Last = NULL;
74boolean console_inited=FALSE;
75static boolean should_exit = 0;
76
77static CALLBACK ConWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
78{
79 PAINTSTRUCT paint;
80 HDC dc;
81
82 switch (iMsg) {
83 case WM_KEYDOWN:
84 if (wParam == VK_ESCAPE)
85 should_exit = 1;
86 break;
87 case WM_CLOSE:
88 return 1;
89 break;
90 case WM_PAINT:
91 if (dc = BeginPaint (con_hWnd, &paint))
92 {
93 if (Last)
94 {
95 char *row;
96 int line, last;
97
98 line = paint.rcPaint.top / OemHeight;
99 last = paint.rcPaint.bottom / OemHeight;
100 for (row = Lines + (line*(80+2)); line < last; line++)
101 {
102 if (row[1]>0)
103 TextOut (dc, 0, line * OemHeight, &row[2], row[1]);
104 row += 80 + 2;
105 }
106 }
107 EndPaint (con_hWnd, &paint);
108 }
109 return 0;
110 break;
111 default:
112 break;
113 }
114 return(DefWindowProc(hwnd,iMsg,wParam,lParam));
115}
116
117static void I_PrintStr (int xp, const char *cp, int count, BOOL scroll) {
118 RECT rect;
119 HDC conDC;
120
121 if ((!con_hWnd) || (!console_inited))
122 return;
123 if (count)
124 {
125 conDC=GetDC(con_hWnd);
126 TextOut (conDC, xp * OemWidth, ConHeight - OemHeight, cp, count);
127 ReleaseDC(con_hWnd,conDC);
128 }
129 if (scroll) {
130 rect.left = 0;
131 rect.top = 0;
132 rect.right = ConWidth;
133 rect.bottom = ConHeight;
134 ScrollWindowEx (con_hWnd, 0, -OemHeight, NULL, &rect, NULL, NULL, SW_ERASE|SW_INVALIDATE);
135 UpdateWindow (con_hWnd);
136 }
137}
138
139static int I_ConPrintString (const char *outline)
140{
141 const char *cp, *newcp;
142 static int xp = 0;
143 int newxp;
144 BOOL scroll;
145
146 if (!console_inited)
147 return 0;
148 cp = outline;
149 while (*cp) {
150 for (newcp = cp, newxp = xp;
151 *newcp != '\n' && *newcp != '\0' && newxp < 80;
152 newcp++) {
153 if (*newcp == '\x08') {
154 newxp--;
155 break;
156 }
157 else if (*newcp == '\t') {
158 newxp = ((newxp + 8) / 8) * 8;
159 break;
160 }
161 else
162 newxp++;
163 }
164
165 if (*cp) {
166 const char *poop;
167 int x;
168
169 for (x = xp, poop = cp; poop < newcp; poop++, x++) {
170 Last[x+2] = ((*poop) < 32) ? 32 : (*poop);
171 }
172
173 if (*newcp == '\t')
174 for (x = xp; x < newxp; x++)
175 Last[x+2] = ' ';
176
177 if (Last[1] < xp + (newcp - cp))
178 Last[1] = xp + (newcp - cp);
179
180 if (*newcp == '\n' || xp == 80) {
181 if (*newcp != '\n') {
182 Last[0] = 1;
183 }
184 memmove (Lines, Lines + (80 + 2), (80 + 2) * (25 - 1));
185 Last[0] = 0;
186 Last[1] = 0;
187 newxp = 0;
188 scroll = TRUE;
189 } else {
190 scroll = FALSE;
191 }
192 I_PrintStr (xp, cp, newcp - cp, scroll);
193
194 xp = newxp;
195
196 if ((*newcp == '\n') || (*newcp == '\x08') || (*newcp == '\t'))
197 cp = newcp + 1;
198 else
199 cp = newcp;
200 }
201 }
202
203 return strlen (outline);
204}
205
206void I_ConTextAttr(unsigned char a)
207{
208 int r,g,b,col;
209 HDC conDC;
210
211 if (!console_inited)
212 return;
213 conDC=GetDC(con_hWnd);
214 r=0; g=0; b=0;
215 if (a & FOREGROUND_INTENSITY) col=255;
216 else col=128;
217 if (a & FOREGROUND_RED) r=col;
218 if (a & FOREGROUND_GREEN) g=col;
219 if (a & FOREGROUND_BLUE) b=col;
220 SetTextColor(conDC, PALETTERGB(r,g,b));
221 r=0; g=0; b=0;
222 if (a & BACKGROUND_INTENSITY) col=255;
223 else col=128;
224 if (a & BACKGROUND_RED) r=col;
225 if (a & BACKGROUND_GREEN) g=col;
226 if (a & BACKGROUND_BLUE) b=col;
227 SetBkColor(conDC, PALETTERGB(r,g,b));
228 ReleaseDC(con_hWnd,conDC);
229}
230
231void I_UpdateConsole(void)
232{
233 MSG msg;
234
235 UpdateWindow(con_hWnd);
236 while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
237 {
238 TranslateMessage(&msg);
239 DispatchMessage(&msg);
240 }
241 if (should_exit)
242 exit(0);
243}
244
245static void Init_Console(void)
246{
247 memset(Lines,0,25*(80+2)+1);
248 Last = Lines + (25 - 1) * (80 + 2);
249 console_inited=TRUE;
250}
251
252int Init_ConsoleWin(void)
253{
254 HDC conDC;
255 WNDCLASS wndclass;
256 TEXTMETRIC metrics;
257 RECT cRect;
258 int width,height;
259 int scr_width,scr_height;
260 HINSTANCE hInstance;
261 char titlebuffer[2048];
262
263 if (con_hWnd)
264 return TRUE;
265 hInstance = GetModuleHandle(NULL);
266 Init_Console();
267 /* Register the frame class */
268 wndclass.style = CS_OWNDC;
269 wndclass.lpfnWndProc = (WNDPROC)ConWndProc;
270 wndclass.cbClsExtra = 0;
271 wndclass.cbWndExtra = 0;
272 wndclass.hInstance = hInstance;
273 wndclass.hIcon = LoadIcon (hInstance, IDI_WINLOGO);
274 wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);
275 wndclass.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH);
276 wndclass.lpszMenuName = szConName;
277 wndclass.lpszClassName = szConName;
278
279 if (!RegisterClass(&wndclass))
280 return FALSE;
281
282 width=100;
283 height=100;
284 strcpy(titlebuffer,PACKAGE);
285 strcat(titlebuffer," ");
286 strcat(titlebuffer,VERSION);
287 strcat(titlebuffer," console");
288 con_hWnd = CreateWindow(szConName, titlebuffer,
289 WS_CAPTION | WS_POPUP,
290 0, 0, width, height,
291 NULL, NULL, hInstance, NULL);
292 conDC=GetDC(con_hWnd);
293 OemFont = GetStockObject(OEM_FIXED_FONT);
294 SelectObject(conDC, OemFont);
295 GetTextMetrics(conDC, &metrics);
296 OemWidth = metrics.tmAveCharWidth;
297 OemHeight = metrics.tmHeight;
298 GetClientRect(con_hWnd, &cRect);
299 width += (OemWidth * 80) - cRect.right;
300 height += (OemHeight * 25) - cRect.bottom;
301 // proff 11/09/98: Added code for centering console
302 scr_width = GetSystemMetrics(SM_CXFULLSCREEN);
303 scr_height = GetSystemMetrics(SM_CYFULLSCREEN);
304 MoveWindow(con_hWnd, (scr_width-width)/2, (scr_height-height)/2, width, height, TRUE);
305 GetClientRect(con_hWnd, &cRect);
306 ConWidth = cRect.right;
307 ConHeight = cRect.bottom;
308 SetTextColor(conDC, RGB(192,192,192));
309 SetBkColor(conDC, RGB(0,0,0));
310 SetBkMode(conDC, OPAQUE);
311 ReleaseDC(con_hWnd,conDC);
312 ShowWindow(con_hWnd, SW_SHOW);
313 UpdateWindow(con_hWnd);
314 return TRUE;
315}
316
317void Done_ConsoleWin(void)
318{
319 if (con_hWnd)
320 DestroyWindow(con_hWnd);
321 UnregisterClass(szConName,GetModuleHandle(NULL));
322 con_hWnd=0;
323}
324#endif
325
326int lprintf(OutputLevels pri, const char *s, ...)
327{
328 int r=0;
329 char msg[MAX_MESSAGE_SIZE];
330 int lvl=pri;
331
332 va_list v;
333 va_start(v,s);
334#ifdef HAVE_VSNPRINTF
335 vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */
336#else
337 vsprintf(msg,s,v);
338#endif
339 va_end(v);
340
341 if (lvl&cons_output_mask) /* mask output as specified */
342 {
343 r=fprintf(stdout,"%s",msg);
344#ifdef _WIN32
345 I_ConPrintString(msg);
346#endif
347 }
348 if (!isatty(1) && lvl&cons_error_mask) /* if stdout redirected */
349 r=fprintf(stderr,"%s",msg); /* select output at console */
350
351 return r;
352}
353
354/*
355 * I_Error
356 *
357 * cphipps - moved out of i_* headers, to minimise source files that depend on
358 * the low-level headers. All this does is print the error, then call the
359 * low-level safe exit function.
360 * killough 3/20/98: add const
361 */
362
363void I_Error(const char *error, ...)
364{
365 char errmsg[MAX_MESSAGE_SIZE];
366 va_list argptr;
367 va_start(argptr,error);
368#ifdef HAVE_VSNPRINTF
369 vsnprintf(errmsg,sizeof(errmsg),error,argptr);
370#else
371 vsprintf(errmsg,error,argptr);
372#endif
373 va_end(argptr);
374 lprintf(LO_ERROR, "%s\n", errmsg);
375#ifdef _MSC_VER
376 if (!M_CheckParm ("-nodraw")) {
377 //Init_ConsoleWin();
378 MessageBox(con_hWnd,errmsg,"PrBoom",MB_OK | MB_TASKMODAL | MB_TOPMOST);
379 }
380#endif
381 I_SafeExit(-1);
382}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Declarations etc. for logical console output
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __LPRINTF__
35#define __LPRINTF__
36
37typedef enum /* Logical output levels */
38{
39 LO_INFO=1, /* One of these is used in each physical output */
40 LO_CONFIRM=2, /* call. Which are output, or echoed to console */
41 LO_WARN=4, /* if output redirected is determined by the */
42 LO_ERROR=8, /* global masks: cons_output_mask,cons_error_mask. */
43 LO_FATAL=16,
44 LO_DEBUG=32,
45 LO_ALWAYS=64,
46} OutputLevels;
47
48#ifndef __GNUC__
49#define __attribute__(x)
50#endif
51
52extern int lprintf(OutputLevels pri, const char *fmt, ...) __attribute__((format(printf,2,3)));
53extern int cons_output_mask;
54extern int cons_error_mask;
55
56/* killough 3/20/98: add const
57 * killough 4/25/98: add gcc attributes
58 * cphipps 01/11- moved from i_system.h */
59void I_Error(const char *error, ...) __attribute__((format(printf,1,2)));
60
61#ifdef _WIN32
62void I_ConTextAttr(unsigned char a);
63void I_UpdateConsole(void);
64int Init_ConsoleWin(void);
65void Done_ConsoleWin(void);
66#endif
67
68#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Some argument handling.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include <string.h>
35// CPhipps - include the correct header
36#include "doomtype.h"
37#include "m_argv.h"
38
39int myargc;
40const char * const * myargv; // CPhipps - not sure if ANSI C allows you to
41// modify contents of argv, but I can't imagine it does.
42
43//
44// M_CheckParm
45// Checks for the given parameter
46// in the program's command line arguments.
47// Returns the argument number (1 to argc-1)
48// or 0 if not present
49//
50
51int M_CheckParm(const char *check)
52{
53 signed int i = myargc;
54 while (--i>0)
55 if (!strcasecmp(check, myargv[i]))
56 return i;
57 return 0;
58}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Argument handling.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __M_ARGV__
36#define __M_ARGV__
37
38/*
39 * MISC
40 */
41extern int myargc;
42extern const char * const * myargv; /* CPhipps - const * const * */
43
44/* Returns the position of the given parameter in the arg list (0 if not found). */
45int M_CheckParm(const char *check);
46
47#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Main loop menu stuff.
31 * Random number LUT.
32 * Default Config File.
33 * PCX Screenshots.
34 *
35 *-----------------------------------------------------------------------------*/
36
37#ifdef __GNUG__
38#pragma implementation "m_bbox.h"
39#endif
40#include "m_bbox.h"
41
42void M_ClearBox (fixed_t *box)
43{
44 box[BOXTOP] = box[BOXRIGHT] = INT_MIN;
45 box[BOXBOTTOM] = box[BOXLEFT] = INT_MAX;
46}
47
48void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y)
49 {
50 if (x<box[BOXLEFT])
51 box[BOXLEFT] = x;
52 else if (x>box[BOXRIGHT])
53 box[BOXRIGHT] = x;
54 if (y<box[BOXBOTTOM])
55 box[BOXBOTTOM] = y;
56 else if (y>box[BOXTOP])
57 box[BOXTOP] = y;
58 }
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Simple bounding box datatype and functions.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __M_BBOX__
36#define __M_BBOX__
37
38#include <limits.h>
39#include "m_fixed.h"
40
41/* Bounding box coordinate storage. */
42enum
43{
44 BOXTOP,
45 BOXBOTTOM,
46 BOXLEFT,
47 BOXRIGHT
48}; /* bbox coordinates */
49
50/* Bounding box functions. */
51
52void M_ClearBox(fixed_t* box);
53
54void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y);
55
56#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Cheat sequence checking.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "g_game.h"
36#include "r_data.h"
37#include "p_inter.h"
38#include "p_tick.h"
39#include "m_cheat.h"
40#include "m_argv.h"
41#include "s_sound.h"
42#include "sounds.h"
43#include "dstrings.h"
44#include "r_main.h"
45#include "p_map.h"
46#include "d_deh.h" // Ty 03/27/98 - externalized strings
47/* cph 2006/07/23 - needs direct access to thinkercap */
48#include "p_tick.h"
49
50#define plyr (players+consoleplayer) /* the console player */
51
52//-----------------------------------------------------------------------------
53//
54// CHEAT SEQUENCE PACKAGE
55//
56//-----------------------------------------------------------------------------
57
58static void cheat_mus();
59static void cheat_choppers();
60static void cheat_god();
61static void cheat_fa();
62static void cheat_k();
63static void cheat_kfa();
64static void cheat_noclip();
65static void cheat_pw();
66static void cheat_behold();
67static void cheat_clev();
68static void cheat_mypos();
69static void cheat_rate();
70static void cheat_comp();
71static void cheat_friction();
72static void cheat_pushers();
73static void cheat_tnttran();
74static void cheat_massacre();
75static void cheat_ddt();
76static void cheat_hom();
77static void cheat_fast();
78static void cheat_tntkey();
79static void cheat_tntkeyx();
80static void cheat_tntkeyxx();
81static void cheat_tntweap();
82static void cheat_tntweapx();
83static void cheat_tntammo();
84static void cheat_tntammox();
85static void cheat_smart();
86static void cheat_pitch();
87static void cheat_megaarmour();
88static void cheat_health();
89
90//-----------------------------------------------------------------------------
91//
92// List of cheat codes, functions, and special argument indicators.
93//
94// The first argument is the cheat code.
95//
96// The second argument is its DEH name, or NULL if it's not supported by -deh.
97//
98// The third argument is a combination of the bitmasks:
99// {always, not_dm, not_coop, not_net, not_menu, not_demo, not_deh},
100// which excludes the cheat during certain modes of play.
101//
102// The fourth argument is the handler function.
103//
104// The fifth argument is passed to the handler function if it's non-negative;
105// if negative, then its negative indicates the number of extra characters
106// expected after the cheat code, which are passed to the handler function
107// via a pointer to a buffer (after folding any letters to lowercase).
108//
109//-----------------------------------------------------------------------------
110
111struct cheat_s cheat[] = {
112 {"idmus", "Change music", always,
113 cheat_mus, -2},
114
115 {"idchoppers", "Chainsaw", not_net | not_demo,
116 cheat_choppers },
117
118 {"iddqd", "God mode", not_net | not_demo,
119 cheat_god },
120
121#if 0
122 {"idk", NULL, not_net | not_demo | not_deh,
123 cheat_k }, // The most controversial cheat code in Doom history!!!
124#endif
125
126 {"idkfa", "Ammo & Keys", not_net | not_demo,
127 cheat_kfa },
128
129 {"idfa", "Ammo", not_net | not_demo,
130 cheat_fa },
131
132 {"idspispopd", "No Clipping 1", not_net | not_demo,
133 cheat_noclip },
134
135 {"idclip", "No Clipping 2", not_net | not_demo,
136 cheat_noclip },
137
138 {"idbeholdh", "Invincibility", not_net | not_demo,
139 cheat_health },
140
141 {"idbeholdm", "Invincibility", not_net | not_demo,
142 cheat_megaarmour },
143
144 {"idbeholdv", "Invincibility", not_net | not_demo,
145 cheat_pw, pw_invulnerability },
146
147 {"idbeholds", "Berserk", not_net | not_demo,
148 cheat_pw, pw_strength },
149
150 {"idbeholdi", "Invisibility", not_net | not_demo,
151 cheat_pw, pw_invisibility },
152
153 {"idbeholdr", "Radiation Suit", not_net | not_demo,
154 cheat_pw, pw_ironfeet },
155
156 {"idbeholda", "Auto-map", not_dm,
157 cheat_pw, pw_allmap },
158
159 {"idbeholdl", "Lite-Amp Goggles", not_dm,
160 cheat_pw, pw_infrared },
161
162 {"idbehold", "BEHOLD menu", not_dm,
163 cheat_behold },
164
165 {"idclev", "Level Warp", not_net | not_demo | not_menu,
166 cheat_clev, -2},
167
168 {"idmypos", "Player Position", not_dm,
169 cheat_mypos },
170
171 {"idrate", "Frame rate", 0,
172 cheat_rate },
173
174 {"tntcomp", NULL, not_net | not_demo,
175 cheat_comp }, // phares
176
177 {"tntem", NULL, not_net | not_demo,
178 cheat_massacre }, // jff 2/01/98 kill all monsters
179
180 {"iddt", "Map cheat", not_dm,
181 cheat_ddt }, // killough 2/07/98: moved from am_map.c
182
183 {"tnthom", NULL, always,
184 cheat_hom }, // killough 2/07/98: HOM autodetector
185
186 {"tntkey", NULL, not_net | not_demo,
187 cheat_tntkey }, // killough 2/16/98: generalized key cheats
188
189 {"tntkeyr", NULL, not_net | not_demo,
190 cheat_tntkeyx },
191
192 {"tntkeyy", NULL, not_net | not_demo,
193 cheat_tntkeyx },
194
195 {"tntkeyb", NULL, not_net | not_demo,
196 cheat_tntkeyx },
197
198 {"tntkeyrc", NULL, not_net | not_demo,
199 cheat_tntkeyxx, it_redcard },
200
201 {"tntkeyyc", NULL, not_net | not_demo,
202 cheat_tntkeyxx, it_yellowcard },
203
204 {"tntkeybc", NULL, not_net | not_demo,
205 cheat_tntkeyxx, it_bluecard },
206
207 {"tntkeyrs", NULL, not_net | not_demo,
208 cheat_tntkeyxx, it_redskull },
209
210 {"tntkeyys", NULL, not_net | not_demo,
211 cheat_tntkeyxx, it_yellowskull},
212
213 {"tntkeybs", NULL, not_net | not_demo,
214 cheat_tntkeyxx, it_blueskull }, // killough 2/16/98: end generalized keys
215
216 {"tntka", NULL, not_net | not_demo,
217 cheat_k }, // Ty 04/11/98 - Added TNTKA
218
219 {"tntweap", NULL, not_net | not_demo,
220 cheat_tntweap }, // killough 2/16/98: generalized weapon cheats
221
222 {"tntweap", NULL, not_net | not_demo,
223 cheat_tntweapx, -1},
224
225 {"tntammo", NULL, not_net | not_demo,
226 cheat_tntammo },
227
228 {"tntammo", NULL, not_net | not_demo,
229 cheat_tntammox, -1}, // killough 2/16/98: end generalized weapons
230
231 {"tnttran", NULL, always,
232 cheat_tnttran }, // invoke translucency // phares
233
234 {"tntsmart", NULL, not_net | not_demo,
235 cheat_smart}, // killough 2/21/98: smart monster toggle
236
237 {"tntpitch", NULL, always,
238 cheat_pitch}, // killough 2/21/98: pitched sound toggle
239
240 // killough 2/21/98: reduce RSI injury by adding simpler alias sequences:
241 {"tntran", NULL, always,
242 cheat_tnttran }, // killough 2/21/98: same as tnttran
243
244 {"tntamo", NULL, not_net | not_demo,
245 cheat_tntammo }, // killough 2/21/98: same as tntammo
246
247 {"tntamo", NULL, not_net | not_demo,
248 cheat_tntammox, -1}, // killough 2/21/98: same as tntammo
249
250 {"tntfast", NULL, not_net | not_demo,
251 cheat_fast }, // killough 3/6/98: -fast toggle
252
253 {"tntice", NULL, not_net | not_demo,
254 cheat_friction }, // phares 3/10/98: toggle variable friction effects
255
256 {"tntpush", NULL, not_net | not_demo,
257 cheat_pushers }, // phares 3/10/98: toggle pushers
258
259 {NULL} // end-of-list marker
260};
261
262//-----------------------------------------------------------------------------
263
264static void cheat_mus(buf)
265char buf[3];
266{
267 int musnum;
268
269 //jff 3/20/98 note: this cheat allowed in netgame/demorecord
270
271 //jff 3/17/98 avoid musnum being negative and crashing
272 if (!isdigit(buf[0]) || !isdigit(buf[1]))
273 return;
274
275 plyr->message = s_STSTR_MUS; // Ty 03/27/98 - externalized
276
277 if (gamemode == commercial)
278 {
279 musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1;
280
281 //jff 4/11/98 prevent IDMUS00 in DOOMII and IDMUS36 or greater
282 if (musnum < mus_runnin || ((buf[0]-'0')*10 + buf[1]-'0') > 35)
283 plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized
284 else
285 {
286 S_ChangeMusic(musnum, 1);
287 idmusnum = musnum; //jff 3/17/98 remember idmus number for restore
288 }
289 }
290 else
291 {
292 musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1');
293
294 //jff 4/11/98 prevent IDMUS0x IDMUSx0 in DOOMI and greater than introa
295 if (buf[0] < '1' || buf[1] < '1' || ((buf[0]-'1')*9 + buf[1]-'1') > 31)
296 plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized
297 else
298 {
299 S_ChangeMusic(musnum, 1);
300 idmusnum = musnum; //jff 3/17/98 remember idmus number for restore
301 }
302 }
303}
304
305// 'choppers' invulnerability & chainsaw
306static void cheat_choppers()
307{
308 plyr->weaponowned[wp_chainsaw] = true;
309 plyr->powers[pw_invulnerability] = true;
310 plyr->message = s_STSTR_CHOPPERS; // Ty 03/27/98 - externalized
311}
312
313static void cheat_god()
314{ // 'dqd' cheat for toggleable god mode
315 plyr->cheats ^= CF_GODMODE;
316 if (plyr->cheats & CF_GODMODE)
317 {
318 if (plyr->mo)
319 plyr->mo->health = god_health; // Ty 03/09/98 - deh
320
321 plyr->health = god_health;
322 plyr->message = s_STSTR_DQDON; // Ty 03/27/98 - externalized
323 }
324 else
325 plyr->message = s_STSTR_DQDOFF; // Ty 03/27/98 - externalized
326}
327
328// CPhipps - new health and armour cheat codes
329static void cheat_health()
330{
331 if (!(plyr->cheats & CF_GODMODE)) {
332 if (plyr->mo)
333 plyr->mo->health = mega_health;
334 plyr->health = mega_health;
335 plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized
336 }
337}
338
339static void cheat_megaarmour()
340{
341 plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh
342 plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh
343 plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized
344}
345
346static void cheat_fa()
347{
348 int i;
349
350 if (!plyr->backpack)
351 {
352 for (i=0 ; i<NUMAMMO ; i++)
353 plyr->maxammo[i] *= 2;
354 plyr->backpack = true;
355 }
356
357 plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh
358 plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh
359
360 // You can't own weapons that aren't in the game // phares 02/27/98
361 for (i=0;i<NUMWEAPONS;i++)
362 if (!(((i == wp_plasma || i == wp_bfg) && gamemode == shareware) ||
363 (i == wp_supershotgun && gamemode != commercial)))
364 plyr->weaponowned[i] = true;
365
366 for (i=0;i<NUMAMMO;i++)
367 if (i!=am_cell || gamemode!=shareware)
368 plyr->ammo[i] = plyr->maxammo[i];
369
370 plyr->message = s_STSTR_FAADDED;
371}
372
373static void cheat_k()
374{
375 int i;
376 for (i=0;i<NUMCARDS;i++)
377 if (!plyr->cards[i]) // only print message if at least one key added
378 { // however, caller may overwrite message anyway
379 plyr->cards[i] = true;
380 plyr->message = "Keys Added";
381 }
382}
383
384static void cheat_kfa()
385{
386 cheat_k();
387 cheat_fa();
388 plyr->message = STSTR_KFAADDED;
389}
390
391static void cheat_noclip()
392{
393 // Simplified, accepting both "noclip" and "idspispopd".
394 // no clipping mode cheat
395
396 plyr->message = (plyr->cheats ^= CF_NOCLIP) & CF_NOCLIP ?
397 s_STSTR_NCON : s_STSTR_NCOFF; // Ty 03/27/98 - externalized
398}
399
400// 'behold?' power-up cheats (modified for infinite duration -- killough)
401static void cheat_pw(int pw)
402{
403 if (plyr->powers[pw])
404 plyr->powers[pw] = pw!=pw_strength && pw!=pw_allmap; // killough
405 else
406 {
407 P_GivePower(plyr, pw);
408 if (pw != pw_strength)
409 plyr->powers[pw] = -1; // infinite duration -- killough
410 }
411 plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized
412}
413
414// 'behold' power-up menu
415static void cheat_behold()
416{
417 plyr->message = s_STSTR_BEHOLD; // Ty 03/27/98 - externalized
418}
419
420// 'clev' change-level cheat
421static void cheat_clev(char buf[3])
422{
423 int epsd, map;
424
425 if (gamemode == commercial)
426 {
427 epsd = 1; //jff was 0, but espd is 1-based
428 map = (buf[0] - '0')*10 + buf[1] - '0';
429 }
430 else
431 {
432 epsd = buf[0] - '0';
433 map = buf[1] - '0';
434 }
435
436 // Catch invalid maps.
437 if (epsd < 1 || map < 1 || // Ohmygod - this is not going to work.
438 (gamemode == retail && (epsd > 4 || map > 9 )) ||
439 (gamemode == registered && (epsd > 3 || map > 9 )) ||
440 (gamemode == shareware && (epsd > 1 || map > 9 )) ||
441 (gamemode == commercial && (epsd > 1 || map > 32 )) ) //jff no 33 and 34
442 return; //8/14/98 allowed
443
444 // So be it.
445
446 idmusnum = -1; //jff 3/17/98 revert to normal level music on IDCLEV
447
448 plyr->message = s_STSTR_CLEV; // Ty 03/27/98 - externalized
449
450 G_DeferedInitNew(gameskill, epsd, map);
451}
452
453// 'mypos' for player position
454// killough 2/7/98: simplified using dprintf and made output more user-friendly
455static void cheat_mypos()
456{
457 doom_printf("Position (%d,%d,%d)\tAngle %-.0f",
458 players[consoleplayer].mo->x >> FRACBITS,
459 players[consoleplayer].mo->y >> FRACBITS,
460 players[consoleplayer].mo->z >> FRACBITS,
461 players[consoleplayer].mo->angle * (90.0/ANG90));
462}
463
464// cph - cheat to toggle frame rate/rendering stats display
465static void cheat_rate()
466{
467 rendering_stats ^= 1;
468}
469
470// compatibility cheat
471
472static void cheat_comp()
473{
474 // CPhipps - modified for new compatibility system
475 compatibility_level++; compatibility_level %= MAX_COMPATIBILITY_LEVEL;
476 // must call G_Compatibility after changing compatibility_level
477 // (fixes sf bug number 1558738)
478 G_Compatibility();
479 doom_printf("New compatibility level:\n%s",
480 comp_lev_str[compatibility_level]);
481}
482
483// variable friction cheat
484static void cheat_friction()
485{
486 plyr->message = // Ty 03/27/98 - *not* externalized
487 (variable_friction = !variable_friction) ? "Variable Friction enabled" :
488 "Variable Friction disabled";
489}
490
491
492// Pusher cheat
493// phares 3/10/98
494static void cheat_pushers()
495{
496 plyr->message = // Ty 03/27/98 - *not* externalized
497 (allow_pushers = !allow_pushers) ? "Pushers enabled" : "Pushers disabled";
498}
499
500// translucency cheat
501static void cheat_tnttran()
502{
503 plyr->message = // Ty 03/27/98 - *not* externalized
504 (general_translucency = !general_translucency) ? "Translucency enabled" :
505 "Translucency disabled";
506
507 // killough 3/1/98, 4/11/98: cache translucency map on a demand basis
508 if (general_translucency && !main_tranmap)
509 R_InitTranMap(0);
510}
511
512static void cheat_massacre() // jff 2/01/98 kill all monsters
513{
514 // jff 02/01/98 'em' cheat - kill all monsters
515 // partially taken from Chi's .46 port
516 //
517 // killough 2/7/98: cleaned up code and changed to use dprintf;
518 // fixed lost soul bug (LSs left behind when PEs are killed)
519
520 int killcount=0;
521 thinker_t *currentthinker = NULL;
522 extern void A_PainDie(mobj_t *);
523
524 // killough 7/20/98: kill friendly monsters only if no others to kill
525 uint_64_t mask = MF_FRIEND;
526 P_MapStart();
527 do
528 while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL)
529 if (currentthinker->function == P_MobjThinker &&
530 !(((mobj_t *) currentthinker)->flags & mask) && // killough 7/20/98
531 (((mobj_t *) currentthinker)->flags & MF_COUNTKILL ||
532 ((mobj_t *) currentthinker)->type == MT_SKULL))
533 { // killough 3/6/98: kill even if PE is dead
534 if (((mobj_t *) currentthinker)->health > 0)
535 {
536 killcount++;
537 P_DamageMobj((mobj_t *)currentthinker, NULL, NULL, 10000);
538 }
539 if (((mobj_t *) currentthinker)->type == MT_PAIN)
540 {
541 A_PainDie((mobj_t *) currentthinker); // killough 2/8/98
542 P_SetMobjState ((mobj_t *) currentthinker, S_PAIN_DIE6);
543 }
544 }
545 while (!killcount && mask ? mask=0, 1 : 0); // killough 7/20/98
546 P_MapEnd();
547 // killough 3/22/98: make more intelligent about plural
548 // Ty 03/27/98 - string(s) *not* externalized
549 doom_printf("%d Monster%s Killed", killcount, killcount==1 ? "" : "s");
550}
551
552// killough 2/7/98: move iddt cheat from am_map.c to here
553// killough 3/26/98: emulate Doom better
554static void cheat_ddt()
555{
556 extern int ddt_cheating;
557 if (automapmode & am_active)
558 ddt_cheating = (ddt_cheating+1) % 3;
559}
560
561// killough 2/7/98: HOM autodetection
562static void cheat_hom()
563{
564 extern int autodetect_hom; // Ty 03/27/98 - *not* externalized
565 plyr->message = (autodetect_hom = !autodetect_hom) ? "HOM Detection On" :
566 "HOM Detection Off";
567}
568
569// killough 3/6/98: -fast parameter toggle
570static void cheat_fast()
571{
572 plyr->message = (fastparm = !fastparm) ? "Fast Monsters On" :
573 "Fast Monsters Off"; // Ty 03/27/98 - *not* externalized
574 G_SetFastParms(fastparm); // killough 4/10/98: set -fast parameter correctly
575}
576
577// killough 2/16/98: keycard/skullkey cheat functions
578static void cheat_tntkey()
579{
580 plyr->message = "Red, Yellow, Blue"; // Ty 03/27/98 - *not* externalized
581}
582
583static void cheat_tntkeyx()
584{
585 plyr->message = "Card, Skull"; // Ty 03/27/98 - *not* externalized
586}
587
588static void cheat_tntkeyxx(int key)
589{
590 plyr->message = (plyr->cards[key] = !plyr->cards[key]) ?
591 "Key Added" : "Key Removed"; // Ty 03/27/98 - *not* externalized
592}
593
594// killough 2/16/98: generalized weapon cheats
595
596static void cheat_tntweap()
597{ // Ty 03/27/98 - *not* externalized
598 plyr->message = gamemode==commercial ? // killough 2/28/98
599 "Weapon number 1-9" : "Weapon number 1-8";
600}
601
602static void cheat_tntweapx(buf)
603char buf[3];
604{
605 int w = *buf - '1';
606
607 if ((w==wp_supershotgun && gamemode!=commercial) || // killough 2/28/98
608 ((w==wp_bfg || w==wp_plasma) && gamemode==shareware))
609 return;
610
611 if (w==wp_fist) // make '1' apply beserker strength toggle
612 cheat_pw(pw_strength);
613 else
614 if (w >= 0 && w < NUMWEAPONS) {
615 if ((plyr->weaponowned[w] = !plyr->weaponowned[w]))
616 plyr->message = "Weapon Added"; // Ty 03/27/98 - *not* externalized
617 else
618 {
619 plyr->message = "Weapon Removed"; // Ty 03/27/98 - *not* externalized
620 if (w==plyr->readyweapon) // maybe switch if weapon removed
621 plyr->pendingweapon = P_SwitchWeapon(plyr);
622 }
623 }
624}
625
626// killough 2/16/98: generalized ammo cheats
627static void cheat_tntammo()
628{
629 plyr->message = "Ammo 1-4, Backpack"; // Ty 03/27/98 - *not* externalized
630}
631
632static void cheat_tntammox(buf)
633char buf[1];
634{
635 int a = *buf - '1';
636 if (*buf == 'b') // Ty 03/27/98 - strings *not* externalized
637 if ((plyr->backpack = !plyr->backpack))
638 for (plyr->message = "Backpack Added", a=0 ; a<NUMAMMO ; a++)
639 plyr->maxammo[a] <<= 1;
640 else
641 for (plyr->message = "Backpack Removed", a=0 ; a<NUMAMMO ; a++)
642 {
643 if (plyr->ammo[a] > (plyr->maxammo[a] >>= 1))
644 plyr->ammo[a] = plyr->maxammo[a];
645 }
646 else
647 if (a>=0 && a<NUMAMMO) // Ty 03/27/98 - *not* externalized
648 { // killough 5/5/98: switch plasma and rockets for now -- KLUDGE
649 a = a==am_cell ? am_misl : a==am_misl ? am_cell : a; // HACK
650 plyr->message = (plyr->ammo[a] = !plyr->ammo[a]) ?
651 plyr->ammo[a] = plyr->maxammo[a], "Ammo Added" : "Ammo Removed";
652 }
653}
654
655static void cheat_smart()
656{
657 plyr->message = (monsters_remember = !monsters_remember) ?
658 "Smart Monsters Enabled" : "Smart Monsters Disabled";
659}
660
661static void cheat_pitch()
662{
663 plyr->message=(pitched_sounds = !pitched_sounds) ? "Pitch Effects Enabled" :
664 "Pitch Effects Disabled";
665}
666
667//-----------------------------------------------------------------------------
668// 2/7/98: Cheat detection rewritten by Lee Killough, to avoid
669// scrambling and to use a more general table-driven approach.
670//-----------------------------------------------------------------------------
671
672#define CHEAT_ARGS_MAX 8 /* Maximum number of args at end of cheats */
673
674boolean M_FindCheats(int key)
675{
676 static uint_64_t sr;
677 static char argbuf[CHEAT_ARGS_MAX+1], *arg;
678 static int init, argsleft, cht;
679 int i, ret, matchedbefore;
680
681 // If we are expecting arguments to a cheat
682 // (e.g. idclev), put them in the arg buffer
683
684 if (argsleft)
685 {
686 *arg++ = tolower(key); // store key in arg buffer
687 if (!--argsleft) // if last key in arg list,
688 cheat[cht].func(argbuf); // process the arg buffer
689 return 1; // affirmative response
690 }
691
692 key = tolower(key) - 'a';
693 if (key < 0 || key >= 32) // ignore most non-alpha cheat letters
694 {
695 sr = 0; // clear shift register
696 return 0;
697 }
698
699 if (!init) // initialize aux entries of table
700 {
701 init = 1;
702 for (i=0;cheat[i].cheat;i++)
703 {
704 uint_64_t c=0, m=0;
705 const char *p;
706
707 for (p=cheat[i].cheat; *p; p++)
708 {
709 unsigned key = tolower(*p)-'a'; // convert to 0-31
710 if (key >= 32) // ignore most non-alpha cheat letters
711 continue;
712 c = (c<<5) + key; // shift key into code
713 m = (m<<5) + 31; // shift 1's into mask
714 }
715 cheat[i].code = c; // code for this cheat key
716 cheat[i].mask = m; // mask for this cheat key
717 }
718 }
719
720 sr = (sr<<5) + key; // shift this key into shift register
721
722 for (matchedbefore = ret = i = 0; cheat[i].cheat; i++)
723 if ((sr & cheat[i].mask) == cheat[i].code && // if match found
724 !(cheat[i].when & not_dm && deathmatch) && // and if cheat allowed
725 !(cheat[i].when & not_coop && netgame && !deathmatch) &&
726 !(cheat[i].when & not_demo && (demorecording || demoplayback)) &&
727 !(cheat[i].when & not_menu && menuactive) &&
728 !(cheat[i].when & not_deh && M_CheckParm("-deh"))) {
729 if (cheat[i].arg < 0) // if additional args are required
730 {
731 cht = i; // remember this cheat code
732 arg = argbuf; // point to start of arg buffer
733 argsleft = -cheat[i].arg; // number of args expected
734 ret = 1; // responder has eaten key
735 }
736 else
737 if (!matchedbefore) // allow only one cheat at a time
738 {
739 matchedbefore = ret = 1; // responder has eaten key
740 cheat[i].func(cheat[i].arg); // call cheat handler
741 }
742 }
743 return ret;
744}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Cheat code checking.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __M_CHEAT__
35#define __M_CHEAT__
36
37/* killough 4/16/98: Cheat table structure */
38
39extern struct cheat_s {
40 const char * cheat;
41 const char *const deh_cheat;
42 enum {
43 always = 0,
44 not_dm = 1,
45 not_coop = 2,
46 not_demo = 4,
47 not_menu = 8,
48 not_deh = 16,
49 not_net = not_dm | not_coop
50 } const when;
51 void (*const func)();
52 const int arg;
53 uint_64_t code, mask;
54} cheat[];
55
56boolean M_FindCheats(int key);
57
58#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Fixed point arithemtics, implementation.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __M_FIXED__
35#define __M_FIXED__
36
37#include "config.h"
38#include "doomtype.h"
39
40/*
41 * Fixed point, 32bit as 16.16.
42 */
43
44#define FRACBITS 16
45#define FRACUNIT (1<<FRACBITS)
46
47typedef int fixed_t;
48
49/*
50 * Absolute Value
51 *
52 * killough 5/10/98: In djgpp, use inlined assembly for performance
53 * killough 9/05/98: better code seems to be gotten from using inlined C
54 */
55
56inline static const int D_abs(int x)
57{
58 fixed_t _t = (x),_s;
59 _s = _t >> (8*sizeof _t-1);
60 return (_t^_s)-_s;
61}
62/*
63 * Fixed Point Multiplication
64 */
65
66/* CPhipps - made __inline__ to inline, as specified in the gcc docs
67 * Also made const */
68
69inline static CONSTFUNC fixed_t FixedMul(fixed_t a, fixed_t b)
70{
71 return (fixed_t)((int_64_t) a*b >> FRACBITS);
72}
73/*
74 * Fixed Point Division
75 */
76
77/* CPhipps - made __inline__ to inline, as specified in the gcc docs
78 * Also made const */
79
80inline static CONSTFUNC fixed_t FixedDiv(fixed_t a, fixed_t b)
81{
82 return ((unsigned)D_abs(a)>>14) >= (unsigned)D_abs(b) ? ((a^b)>>31) ^ INT_MAX :
83 (fixed_t)(((int_64_t) a << FRACBITS) / b);
84}
85
86
87/* CPhipps -
88 * FixedMod - returns a % b, guaranteeing 0<=a<b
89 * (notice that the C standard for % does not guarantee this)
90 */
91
92inline static CONSTFUNC fixed_t FixedMod(fixed_t a, fixed_t b)
93{
94 if (b & (b-1)) {
95 fixed_t r = a % b;
96 return ((r<0) ? r+b : r);
97 } else
98 return (a & (b-1));
99}
100
101#endif
diff --git a/src/m_menu.c b/src/m_menu.c
new file mode 100644
index 0000000..16afd60
--- /dev/null
+++ b/src/m_menu.c
@@ -0,0 +1,5559 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * DOOM selection menu, options, episode etc. (aka Big Font menus)
31 * Sliders and icons. Kinda widget stuff.
32 * Setup Menus.
33 * Extended HELP screens.
34 * Dynamic HELP screen.
35 *
36 *-----------------------------------------------------------------------------*/
37
38#include <stdio.h>
39#include <fcntl.h>
40
41#include "doomdef.h"
42#include "doomstat.h"
43#include "dstrings.h"
44#include "d_main.h"
45#include "v_video.h"
46#include "w_wad.h"
47#include "r_main.h"
48#include "hu_stuff.h"
49#include "g_game.h"
50#include "s_sound.h"
51#include "sounds.h"
52#include "m_menu.h"
53#include "d_deh.h"
54#include "m_misc.h"
55#include "lprintf.h"
56#include "am_map.h"
57#include "i_main.h"
58#include "i_system.h"
59#include "i_video.h"
60#include "i_sound.h"
61#include "r_demo.h"
62#include "r_fps.h"
63
64extern patchnum_t hu_font[HU_FONTSIZE];
65extern boolean message_dontfuckwithme;
66
67extern boolean chat_on; // in heads-up code
68
69//
70// defaulted values
71//
72
73int mouseSensitivity_horiz; // has default // killough
74int mouseSensitivity_vert; // has default
75
76int showMessages; // Show messages has default, 0 = off, 1 = on
77
78int hide_setup=1; // killough 5/15/98
79
80// Blocky mode, has default, 0 = high, 1 = normal
81//int detailLevel; obsolete -- killough
82int screenblocks; // has default
83
84int screenSize; // temp for screenblocks (0-9)
85
86int quickSaveSlot; // -1 = no quicksave slot picked!
87
88int messageToPrint; // 1 = message to be printed
89
90// CPhipps - static const
91static const char* messageString; // ...and here is the message string!
92
93// message x & y
94int messx;
95int messy;
96int messageLastMenuActive;
97
98boolean messageNeedsInput; // timed message = no input from user
99
100void (*messageRoutine)(int response);
101
102#define SAVESTRINGSIZE 24
103
104/* killough 8/15/98: when changes are allowed to sync-critical variables */
105static int allow_changes(void)
106{
107 return !(demoplayback || demorecording || netgame);
108}
109
110static void M_UpdateCurrent(default_t* def)
111{
112 /* cph - requires rewrite of m_misc.c */
113 if (def->current) {
114 if (allow_changes()) /* killough 8/15/98 */
115 *def->current = *def->location.pi;
116 else if (*def->current != *def->location.pi)
117 warn_about_changes(S_LEVWARN); /* killough 8/15/98 */
118 }
119}
120
121int warning_about_changes, print_warning_about_changes;
122
123/* cphipps - M_DrawBackground renamed and moved to v_video.c */
124#define M_DrawBackground V_DrawBackground
125
126// we are going to be entering a savegame string
127
128int saveStringEnter;
129int saveSlot; // which slot to save in
130int saveCharIndex; // which char we're editing
131// old save description before edit
132char saveOldString[SAVESTRINGSIZE];
133
134boolean inhelpscreens; // indicates we are in or just left a help screen
135
136boolean menuactive; // The menus are up
137
138#define SKULLXOFF -32
139#define LINEHEIGHT 16
140
141char savegamestrings[10][SAVESTRINGSIZE];
142
143//
144// MENU TYPEDEFS
145//
146
147typedef struct
148{
149 short status; // 0 = no cursor here, 1 = ok, 2 = arrows ok
150 char name[10];
151
152 // choice = menu item #.
153 // if status = 2,
154 // choice=0:leftarrow,1:rightarrow
155 void (*routine)(int choice);
156 char alphaKey; // hotkey in menu
157} menuitem_t;
158
159typedef struct menu_s
160{
161 short numitems; // # of menu items
162 struct menu_s* prevMenu; // previous menu
163 menuitem_t* menuitems; // menu items
164 void (*routine)(); // draw routine
165 short x;
166 short y; // x,y of menu
167 short lastOn; // last item user was on in menu
168} menu_t;
169
170short itemOn; // menu item skull is on (for Big Font menus)
171short skullAnimCounter; // skull animation counter
172short whichSkull; // which skull to draw (he blinks)
173
174// graphic name of skulls
175
176const char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
177
178menu_t* currentMenu; // current menudef
179
180// phares 3/30/98
181// externs added for setup menus
182
183extern int mousebfire;
184extern int mousebstrafe;
185extern int mousebforward;
186// proff 08/17/98: Added backward to mousebuttons
187extern int mousebbackward;
188extern int joybfire;
189extern int joybstrafe;
190extern int joybuse;
191extern int joybspeed;
192int mapcolor_me; // cph
193
194extern int map_point_coordinates; // killough 10/98
195
196extern char* chat_macros[]; // chat macros
197extern const char* shiftxform;
198extern default_t defaults[];
199extern int numdefaults;
200
201// end of externs added for setup menus
202
203//
204// PROTOTYPES
205//
206void M_NewGame(int choice);
207void M_Episode(int choice);
208void M_ChooseSkill(int choice);
209void M_LoadGame(int choice);
210void M_SaveGame(int choice);
211void M_Options(int choice);
212void M_EndGame(int choice);
213void M_ReadThis(int choice);
214void M_ReadThis2(int choice);
215void M_QuitDOOM(int choice);
216
217void M_ChangeMessages(int choice);
218void M_ChangeSensitivity(int choice);
219void M_SfxVol(int choice);
220void M_MusicVol(int choice);
221/* void M_ChangeDetail(int choice); unused -- killough */
222void M_SizeDisplay(int choice);
223void M_StartGame(int choice);
224void M_Sound(int choice);
225
226void M_Mouse(int choice, int *sens); /* killough */
227void M_MouseVert(int choice);
228void M_MouseHoriz(int choice);
229void M_DrawMouse(void);
230
231void M_FinishReadThis(int choice);
232void M_FinishHelp(int choice); // killough 10/98
233void M_LoadSelect(int choice);
234void M_SaveSelect(int choice);
235void M_ReadSaveStrings(void);
236void M_QuickSave(void);
237void M_QuickLoad(void);
238
239void M_DrawMainMenu(void);
240void M_DrawReadThis1(void);
241void M_DrawReadThis2(void);
242void M_DrawNewGame(void);
243void M_DrawEpisode(void);
244void M_DrawOptions(void);
245void M_DrawSound(void);
246void M_DrawLoad(void);
247void M_DrawSave(void);
248void M_DrawSetup(void); // phares 3/21/98
249void M_DrawHelp (void); // phares 5/04/98
250
251void M_DrawSaveLoadBorder(int x,int y);
252void M_SetupNextMenu(menu_t *menudef);
253void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
254void M_DrawEmptyCell(menu_t *menu,int item);
255void M_DrawSelCell(menu_t *menu,int item);
256void M_WriteText(int x, int y, const char *string);
257int M_StringWidth(const char *string);
258int M_StringHeight(const char *string);
259void M_StartMessage(const char *string,void *routine,boolean input);
260void M_StopMessage(void);
261void M_ClearMenus (void);
262
263// phares 3/30/98
264// prototypes added to support Setup Menus and Extended HELP screens
265
266int M_GetKeyString(int,int);
267void M_Setup(int choice);
268void M_KeyBindings(int choice);
269void M_Weapons(int);
270void M_StatusBar(int);
271void M_Automap(int);
272void M_Enemy(int);
273void M_Messages(int);
274void M_ChatStrings(int);
275void M_InitExtendedHelp(void);
276void M_ExtHelpNextScreen(int);
277void M_ExtHelp(int);
278static int M_GetPixelWidth(const char*);
279void M_DrawKeybnd(void);
280void M_DrawWeapons(void);
281static void M_DrawMenuString(int,int,int);
282static void M_DrawStringCentered(int,int,int,const char*);
283void M_DrawStatusHUD(void);
284void M_DrawExtHelp(void);
285void M_DrawAutoMap(void);
286void M_DrawEnemy(void);
287void M_DrawMessages(void);
288void M_DrawChatStrings(void);
289void M_Compat(int); // killough 10/98
290void M_ChangeDemoSmoothTurns(void);
291void M_General(int); // killough 10/98
292void M_DrawCompat(void); // killough 10/98
293void M_DrawGeneral(void); // killough 10/98
294void M_FullScreen(void); // nathanh 01/01
295
296menu_t NewDef; // phares 5/04/98
297
298// end of prototypes added to support Setup Menus and Extended HELP screens
299
300/////////////////////////////////////////////////////////////////////////////
301//
302// DOOM MENUS
303//
304
305/////////////////////////////
306//
307// MAIN MENU
308//
309
310// main_e provides numerical values for which Big Font screen you're on
311
312enum
313{
314 newgame = 0,
315 loadgame,
316 savegame,
317 options,
318 readthis,
319 quitdoom,
320 main_end
321} main_e;
322
323//
324// MainMenu is the definition of what the main menu Screen should look
325// like. Each entry shows that the cursor can land on each item (1), the
326// built-in graphic lump (i.e. "M_NGAME") that should be displayed,
327// the program which takes over when an item is selected, and the hotkey
328// associated with the item.
329//
330
331menuitem_t MainMenu[]=
332{
333 {1,"M_NGAME", M_NewGame, 'n'},
334 {1,"M_OPTION",M_Options, 'o'},
335 {1,"M_LOADG", M_LoadGame,'l'},
336 {1,"M_SAVEG", M_SaveGame,'s'},
337 // Another hickup with Special edition.
338 {1,"M_RDTHIS",M_ReadThis,'r'},
339 {1,"M_QUITG", M_QuitDOOM,'q'}
340};
341
342menu_t MainDef =
343{
344 main_end, // number of menu items
345 NULL, // previous menu screen
346 MainMenu, // table that defines menu items
347 M_DrawMainMenu, // drawing routine
348 97,64, // initial cursor position
349 0 // last menu item the user was on
350};
351
352//
353// M_DrawMainMenu
354//
355
356void M_DrawMainMenu(void)
357{
358 // CPhipps - patch drawing updated
359 V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH);
360}
361
362/////////////////////////////
363//
364// Read This! MENU 1 & 2
365//
366
367// There are no menu items on the Read This! screens, so read_e just
368// provides a placeholder to maintain structure.
369
370enum
371{
372 rdthsempty1,
373 read1_end
374} read_e;
375
376enum
377{
378 rdthsempty2,
379 read2_end
380} read_e2;
381
382enum // killough 10/98
383{
384 helpempty,
385 help_end
386} help_e;
387
388
389// The definitions of the Read This! screens
390
391menuitem_t ReadMenu1[] =
392{
393 {1,"",M_ReadThis2,0}
394};
395
396menuitem_t ReadMenu2[]=
397{
398 {1,"",M_FinishReadThis,0}
399};
400
401menuitem_t HelpMenu[]= // killough 10/98
402{
403 {1,"",M_FinishHelp,0}
404};
405
406menu_t ReadDef1 =
407{
408 read1_end,
409 &MainDef,
410 ReadMenu1,
411 M_DrawReadThis1,
412 330,175,
413 //280,185, // killough 2/21/98: fix help screens
414 0
415};
416
417menu_t ReadDef2 =
418{
419 read2_end,
420 &ReadDef1,
421 ReadMenu2,
422 M_DrawReadThis2,
423 330,175,
424 0
425};
426
427menu_t HelpDef = // killough 10/98
428{
429 help_end,
430 &HelpDef,
431 HelpMenu,
432 M_DrawHelp,
433 330,175,
434 0
435};
436
437//
438// M_ReadThis
439//
440
441void M_ReadThis(int choice)
442{
443 M_SetupNextMenu(&ReadDef1);
444}
445
446void M_ReadThis2(int choice)
447{
448 M_SetupNextMenu(&ReadDef2);
449}
450
451void M_FinishReadThis(int choice)
452{
453 M_SetupNextMenu(&MainDef);
454}
455
456void M_FinishHelp(int choice) // killough 10/98
457{
458 M_SetupNextMenu(&MainDef);
459}
460
461//
462// Read This Menus
463// Had a "quick hack to fix romero bug"
464//
465// killough 10/98: updated with new screens
466
467void M_DrawReadThis1(void)
468{
469 inhelpscreens = true;
470 if (gamemode == shareware)
471 V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH);
472 else
473 M_DrawCredits();
474}
475
476//
477// Read This Menus - optional second page.
478//
479// killough 10/98: updated with new screens
480
481void M_DrawReadThis2(void)
482{
483 inhelpscreens = true;
484 if (gamemode == shareware)
485 M_DrawCredits();
486 else
487 V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH);
488}
489
490/////////////////////////////
491//
492// EPISODE SELECT
493//
494
495//
496// episodes_e provides numbers for the episode menu items. The default is
497// 4, to accomodate Ultimate Doom. If the user is running anything else,
498// this is accounted for in the code.
499//
500
501enum
502{
503 ep1,
504 ep2,
505 ep3,
506 ep4,
507 ep_end
508} episodes_e;
509
510// The definitions of the Episodes menu
511
512menuitem_t EpisodeMenu[]=
513{
514 {1,"M_EPI1", M_Episode,'k'},
515 {1,"M_EPI2", M_Episode,'t'},
516 {1,"M_EPI3", M_Episode,'i'},
517 {1,"M_EPI4", M_Episode,'t'}
518};
519
520menu_t EpiDef =
521{
522 ep_end, // # of menu items
523 &MainDef, // previous menu
524 EpisodeMenu, // menuitem_t ->
525 M_DrawEpisode, // drawing routine ->
526 48,63, // x,y
527 ep1 // lastOn
528};
529
530//
531// M_Episode
532//
533int epi;
534
535void M_DrawEpisode(void)
536{
537 // CPhipps - patch drawing updated
538 V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH);
539}
540
541void M_Episode(int choice)
542{
543 if ( (gamemode == shareware) && choice) {
544 M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized
545 M_SetupNextMenu(&ReadDef1);
546 return;
547 }
548
549 // Yet another hack...
550 if ( (gamemode == registered) && (choice > 2))
551 {
552 lprintf( LO_WARN,
553 "M_Episode: 4th episode requires UltimateDOOM\n");
554 choice = 0;
555 }
556
557 epi = choice;
558 M_SetupNextMenu(&NewDef);
559}
560
561/////////////////////////////
562//
563// NEW GAME
564//
565
566// numerical values for the New Game menu items
567
568enum
569{
570 killthings,
571 toorough,
572 hurtme,
573 violence,
574 nightmare,
575 newg_end
576} newgame_e;
577
578// The definitions of the New Game menu
579
580menuitem_t NewGameMenu[]=
581{
582 {1,"M_JKILL", M_ChooseSkill, 'i'},
583 {1,"M_ROUGH", M_ChooseSkill, 'h'},
584 {1,"M_HURT", M_ChooseSkill, 'h'},
585 {1,"M_ULTRA", M_ChooseSkill, 'u'},
586 {1,"M_NMARE", M_ChooseSkill, 'n'}
587};
588
589menu_t NewDef =
590{
591 newg_end, // # of menu items
592 &EpiDef, // previous menu
593 NewGameMenu, // menuitem_t ->
594 M_DrawNewGame, // drawing routine ->
595 48,63, // x,y
596 hurtme // lastOn
597};
598
599//
600// M_NewGame
601//
602
603void M_DrawNewGame(void)
604{
605 // CPhipps - patch drawing updated
606 V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH);
607 V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH);
608}
609
610/* cph - make `New Game' restart the level in a netgame */
611static void M_RestartLevelResponse(int ch)
612{
613 if (ch != 'y')
614 return;
615
616 if (demorecording)
617 exit(0);
618
619 currentMenu->lastOn = itemOn;
620 M_ClearMenus ();
621 G_RestartLevel ();
622}
623
624void M_NewGame(int choice)
625{
626 if (netgame && !demoplayback) {
627 if (compatibility_level < lxdoom_1_compatibility)
628 M_StartMessage(s_NEWGAME,NULL,false); // Ty 03/27/98 - externalized
629 else // CPhipps - query restarting the level
630 M_StartMessage(s_RESTARTLEVEL,M_RestartLevelResponse,true);
631 return;
632 }
633
634 if (demorecording) { /* killough 5/26/98: exclude during demo recordings */
635 M_StartMessage("you can't start a new game\n"
636 "while recording a demo!\n\n"PRESSKEY,
637 NULL, false); // killough 5/26/98: not externalized
638 return;
639 }
640
641 if ( gamemode == commercial )
642 M_SetupNextMenu(&NewDef);
643 else
644 M_SetupNextMenu(&EpiDef);
645}
646
647// CPhipps - static
648static void M_VerifyNightmare(int ch)
649{
650 if (ch != 'y')
651 return;
652
653 G_DeferedInitNew(nightmare,epi+1,1);
654 M_ClearMenus ();
655}
656
657void M_ChooseSkill(int choice)
658{
659 if (choice == nightmare)
660 { // Ty 03/27/98 - externalized
661 M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true);
662 return;
663 }
664
665 G_DeferedInitNew(choice,epi+1,1);
666 M_ClearMenus ();
667}
668
669/////////////////////////////
670//
671// LOAD GAME MENU
672//
673
674// numerical values for the Load Game slots
675
676enum
677{
678 load1,
679 load2,
680 load3,
681 load4,
682 load5,
683 load6,
684 load7, //jff 3/15/98 extend number of slots
685 load8,
686 load_end
687} load_e;
688
689// The definitions of the Load Game screen
690
691menuitem_t LoadMenue[]=
692{
693 {1,"", M_LoadSelect,'1'},
694 {1,"", M_LoadSelect,'2'},
695 {1,"", M_LoadSelect,'3'},
696 {1,"", M_LoadSelect,'4'},
697 {1,"", M_LoadSelect,'5'},
698 {1,"", M_LoadSelect,'6'},
699 {1,"", M_LoadSelect,'7'}, //jff 3/15/98 extend number of slots
700 {1,"", M_LoadSelect,'8'},
701};
702
703menu_t LoadDef =
704{
705 load_end,
706 &MainDef,
707 LoadMenue,
708 M_DrawLoad,
709 80,34, //jff 3/15/98 move menu up
710 0
711};
712
713#define LOADGRAPHIC_Y 8
714
715//
716// M_LoadGame & Cie.
717//
718
719void M_DrawLoad(void)
720{
721 int i;
722
723 //jff 3/15/98 use symbolic load position
724 // CPhipps - patch drawing updated
725 V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH);
726 for (i = 0 ; i < load_end ; i++) {
727 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
728 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
729 }
730}
731
732//
733// Draw border for the savegame description
734//
735
736void M_DrawSaveLoadBorder(int x,int y)
737{
738 int i;
739
740 V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH);
741
742 for (i = 0 ; i < 24 ; i++)
743 {
744 V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH);
745 x += 8;
746 }
747
748 V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH);
749}
750
751//
752// User wants to load this game
753//
754
755void M_LoadSelect(int choice)
756{
757 // CPhipps - Modified so savegame filename is worked out only internal
758 // to g_game.c, this only passes the slot.
759
760 G_LoadGame(choice, false); // killough 3/16/98, 5/15/98: add slot, cmd
761
762 M_ClearMenus ();
763}
764
765//
766// killough 5/15/98: add forced loadgames
767//
768
769static void M_VerifyForcedLoadGame(int ch)
770{
771 if (ch=='y')
772 G_ForcedLoadGame();
773 free((char*)messageString); // free the message strdup()'ed below
774 M_ClearMenus();
775}
776
777void M_ForcedLoadGame(const char *msg)
778{
779 M_StartMessage(strdup(msg), M_VerifyForcedLoadGame, true); // free()'d above
780}
781
782//
783// Selected from DOOM menu
784//
785
786void M_LoadGame (int choice)
787{
788 /* killough 5/26/98: exclude during demo recordings
789 * cph - unless a new demo */
790 if (demorecording && (compatibility_level < prboom_2_compatibility))
791 {
792 M_StartMessage("you can't load a game\n"
793 "while recording an old demo!\n\n"PRESSKEY,
794 NULL, false); // killough 5/26/98: not externalized
795 return;
796 }
797
798 M_SetupNextMenu(&LoadDef);
799 M_ReadSaveStrings();
800}
801
802/////////////////////////////
803//
804// SAVE GAME MENU
805//
806
807// The definitions of the Save Game screen
808
809menuitem_t SaveMenu[]=
810{
811 {1,"", M_SaveSelect,'1'},
812 {1,"", M_SaveSelect,'2'},
813 {1,"", M_SaveSelect,'3'},
814 {1,"", M_SaveSelect,'4'},
815 {1,"", M_SaveSelect,'5'},
816 {1,"", M_SaveSelect,'6'},
817 {1,"", M_SaveSelect,'7'}, //jff 3/15/98 extend number of slots
818 {1,"", M_SaveSelect,'8'},
819};
820
821menu_t SaveDef =
822{
823 load_end, // same number of slots as the Load Game screen
824 &MainDef,
825 SaveMenu,
826 M_DrawSave,
827 80,34, //jff 3/15/98 move menu up
828 0
829};
830
831//
832// M_ReadSaveStrings
833// read the strings from the savegame files
834//
835void M_ReadSaveStrings(void)
836{
837 int i;
838
839 for (i = 0 ; i < load_end ; i++) {
840 char name[PATH_MAX+1]; // killough 3/22/98
841 FILE *fp; // killough 11/98: change to use stdio
842
843 /* killough 3/22/98
844 * cph - add not-demoplayback parameter */
845 G_SaveGameName(name,sizeof(name),i,false);
846 fp = fopen(name,"rb");
847 if (!fp) { // Ty 03/27/98 - externalized:
848 strcpy(&savegamestrings[i][0],s_EMPTYSTRING);
849 LoadMenue[i].status = 0;
850 continue;
851 }
852 fread(&savegamestrings[i], SAVESTRINGSIZE, 1, fp);
853 fclose(fp);
854 LoadMenue[i].status = 1;
855 }
856}
857
858//
859// M_SaveGame & Cie.
860//
861void M_DrawSave(void)
862{
863 int i;
864
865 //jff 3/15/98 use symbolic load position
866 // CPhipps - patch drawing updated
867 V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH);
868 for (i = 0 ; i < load_end ; i++)
869 {
870 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
871 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
872 }
873
874 if (saveStringEnter)
875 {
876 i = M_StringWidth(savegamestrings[saveSlot]);
877 M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
878 }
879}
880
881//
882// M_Responder calls this when user is finished
883//
884static void M_DoSave(int slot)
885{
886 G_SaveGame (slot,savegamestrings[slot]);
887 M_ClearMenus ();
888
889 // PICK QUICKSAVE SLOT YET?
890 if (quickSaveSlot == -2)
891 quickSaveSlot = slot;
892}
893
894//
895// User wants to save. Start string input for M_Responder
896//
897void M_SaveSelect(int choice)
898{
899 // we are going to be intercepting all chars
900 saveStringEnter = 1;
901
902 saveSlot = choice;
903 strcpy(saveOldString,savegamestrings[choice]);
904 if (!strcmp(savegamestrings[choice],s_EMPTYSTRING)) // Ty 03/27/98 - externalized
905 savegamestrings[choice][0] = 0;
906 saveCharIndex = strlen(savegamestrings[choice]);
907}
908
909//
910// Selected from DOOM menu
911//
912void M_SaveGame (int choice)
913{
914 // killough 10/6/98: allow savegames during single-player demo playback
915 if (!usergame && (!demoplayback || netgame))
916 {
917 M_StartMessage(s_SAVEDEAD,NULL,false); // Ty 03/27/98 - externalized
918 return;
919 }
920
921 if (gamestate != GS_LEVEL)
922 return;
923
924 M_SetupNextMenu(&SaveDef);
925 M_ReadSaveStrings();
926}
927
928/////////////////////////////
929//
930// OPTIONS MENU
931//
932
933// numerical values for the Options menu items
934
935enum
936{
937 general, // killough 10/98
938 // killough 4/6/98: move setup to be a sub-menu of OPTIONs
939 setup, // phares 3/21/98
940 endgame,
941 messages,
942 /* detail, obsolete -- killough */
943 scrnsize,
944 option_empty1,
945 mousesens,
946 /* option_empty2, submenu now -- killough */
947 soundvol,
948 opt_end
949} options_e;
950
951// The definitions of the Options menu
952
953menuitem_t OptionsMenu[]=
954{
955 // killough 4/6/98: move setup to be a sub-menu of OPTIONs
956 {1,"M_GENERL", M_General, 'g'}, // killough 10/98
957 {1,"M_SETUP", M_Setup, 's'}, // phares 3/21/98
958 {1,"M_ENDGAM", M_EndGame,'e'},
959 {1,"M_MESSG", M_ChangeMessages,'m'},
960 /* {1,"M_DETAIL", M_ChangeDetail,'g'}, unused -- killough */
961 {2,"M_SCRNSZ", M_SizeDisplay,'s'},
962 {-1,"",0},
963 {1,"M_MSENS", M_ChangeSensitivity,'m'},
964 /* {-1,"",0}, replaced with submenu -- killough */
965 {1,"M_SVOL", M_Sound,'s'}
966};
967
968menu_t OptionsDef =
969{
970 opt_end,
971 &MainDef,
972 OptionsMenu,
973 M_DrawOptions,
974 60,37,
975 0
976};
977
978//
979// M_Options
980//
981char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"};
982char msgNames[2][9] = {"M_MSGOFF","M_MSGON"};
983
984
985void M_DrawOptions(void)
986{
987 // CPhipps - patch drawing updated
988 // proff/nicolas 09/20/98 -- changed for hi-res
989 V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH);
990
991 V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0,
992 msgNames[showMessages], CR_DEFAULT, VPT_STRETCH);
993
994 M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
995 9,screenSize);
996}
997
998void M_Options(int choice)
999{
1000 M_SetupNextMenu(&OptionsDef);
1001}
1002
1003/////////////////////////////
1004//
1005// M_QuitDOOM
1006//
1007int quitsounds[8] =
1008{
1009 sfx_pldeth,
1010 sfx_dmpain,
1011 sfx_popain,
1012 sfx_slop,
1013 sfx_telept,
1014 sfx_posit1,
1015 sfx_posit3,
1016 sfx_sgtatk
1017};
1018
1019int quitsounds2[8] =
1020{
1021 sfx_vilact,
1022 sfx_getpow,
1023 sfx_boscub,
1024 sfx_slop,
1025 sfx_skeswg,
1026 sfx_kntdth,
1027 sfx_bspact,
1028 sfx_sgtatk
1029};
1030
1031static void M_QuitResponse(int ch)
1032{
1033 if (ch != 'y')
1034 return;
1035 if ((!netgame || demoplayback) // killough 12/98
1036 && !nosfxparm && snd_card) // avoid delay if no sound card
1037 {
1038 int i;
1039
1040 if (gamemode == commercial)
1041 S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
1042 else
1043 S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
1044
1045 // wait till all sounds stopped or 3 seconds are over
1046 i = 30;
1047 while (i>0) {
1048 I_uSleep(100000); // CPhipps - don't thrash cpu in this loop
1049 if (!I_AnySoundStillPlaying())
1050 break;
1051 i--;
1052 }
1053 }
1054 exit(0); // killough
1055}
1056
1057void M_QuitDOOM(int choice)
1058{
1059 static char endstring[160];
1060
1061 // We pick index 0 which is language sensitive,
1062 // or one at random, between 1 and maximum number.
1063 // Ty 03/27/98 - externalized DOSY as a string s_DOSY that's in the sprintf
1064 if (language != english)
1065 sprintf(endstring,"%s\n\n%s",s_DOSY, endmsg[0] );
1066 else // killough 1/18/98: fix endgame message calculation:
1067 sprintf(endstring,"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY);
1068
1069 M_StartMessage(endstring,M_QuitResponse,true);
1070}
1071
1072/////////////////////////////
1073//
1074// SOUND VOLUME MENU
1075//
1076
1077// numerical values for the Sound Volume menu items
1078// The 'empty' slots are where the sliding scales appear.
1079
1080enum
1081{
1082 sfx_vol,
1083 sfx_empty1,
1084 music_vol,
1085 sfx_empty2,
1086 sound_end
1087} sound_e;
1088
1089// The definitions of the Sound Volume menu
1090
1091menuitem_t SoundMenu[]=
1092{
1093 {2,"M_SFXVOL",M_SfxVol,'s'},
1094 {-1,"",0},
1095 {2,"M_MUSVOL",M_MusicVol,'m'},
1096 {-1,"",0}
1097};
1098
1099menu_t SoundDef =
1100{
1101 sound_end,
1102 &OptionsDef,
1103 SoundMenu,
1104 M_DrawSound,
1105 80,64,
1106 0
1107};
1108
1109//
1110// Change Sfx & Music volumes
1111//
1112
1113void M_DrawSound(void)
1114{
1115 // CPhipps - patch drawing updated
1116 V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH);
1117
1118 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),16,snd_SfxVolume);
1119
1120 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),16,snd_MusicVolume);
1121}
1122
1123void M_Sound(int choice)
1124{
1125 M_SetupNextMenu(&SoundDef);
1126}
1127
1128void M_SfxVol(int choice)
1129{
1130 switch(choice)
1131 {
1132 case 0:
1133 if (snd_SfxVolume)
1134 snd_SfxVolume--;
1135 break;
1136 case 1:
1137 if (snd_SfxVolume < 15)
1138 snd_SfxVolume++;
1139 break;
1140 }
1141
1142 S_SetSfxVolume(snd_SfxVolume /* *8 */);
1143}
1144
1145void M_MusicVol(int choice)
1146{
1147 switch(choice)
1148 {
1149 case 0:
1150 if (snd_MusicVolume)
1151 snd_MusicVolume--;
1152 break;
1153 case 1:
1154 if (snd_MusicVolume < 15)
1155 snd_MusicVolume++;
1156 break;
1157 }
1158
1159 S_SetMusicVolume(snd_MusicVolume /* *8 */);
1160}
1161
1162/////////////////////////////
1163//
1164// MOUSE SENSITIVITY MENU -- killough
1165//
1166
1167// numerical values for the Mouse Sensitivity menu items
1168// The 'empty' slots are where the sliding scales appear.
1169
1170enum
1171{
1172 mouse_horiz,
1173 mouse_empty1,
1174 mouse_vert,
1175 mouse_empty2,
1176 mouse_end
1177} mouse_e;
1178
1179// The definitions of the Mouse Sensitivity menu
1180
1181menuitem_t MouseMenu[]=
1182{
1183 {2,"M_HORSEN",M_MouseHoriz,'h'},
1184 {-1,"",0},
1185 {2,"M_VERSEN",M_MouseVert,'v'},
1186 {-1,"",0}
1187};
1188
1189menu_t MouseDef =
1190{
1191 mouse_end,
1192 &OptionsDef,
1193 MouseMenu,
1194 M_DrawMouse,
1195 60,64,
1196 0
1197};
1198
1199
1200// I'm using a scale of 100 since I don't know what's normal -- killough.
1201
1202#define MOUSE_SENS_MAX 100
1203
1204//
1205// Change Mouse Sensitivities -- killough
1206//
1207
1208void M_DrawMouse(void)
1209{
1210 int mhmx,mvmx; /* jff 4/3/98 clamp drawn position 99max mead */
1211
1212 // CPhipps - patch drawing updated
1213 V_DrawNamePatch(60, 38, 0, "M_MSENS", CR_DEFAULT, VPT_STRETCH);
1214
1215 //jff 4/3/98 clamp horizontal sensitivity display
1216 mhmx = mouseSensitivity_horiz>99? 99 : mouseSensitivity_horiz; /*mead*/
1217 M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_horiz+1),100,mhmx);
1218 //jff 4/3/98 clamp vertical sensitivity display
1219 mvmx = mouseSensitivity_vert>99? 99 : mouseSensitivity_vert; /*mead*/
1220 M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_vert+1),100,mvmx);
1221}
1222
1223void M_ChangeSensitivity(int choice)
1224{
1225 M_SetupNextMenu(&MouseDef); // killough
1226
1227 // switch(choice)
1228 // {
1229 // case 0:
1230 // if (mouseSensitivity)
1231 // mouseSensitivity--;
1232 // break;
1233 // case 1:
1234 // if (mouseSensitivity < 9)
1235 // mouseSensitivity++;
1236 // break;
1237 // }
1238}
1239
1240void M_MouseHoriz(int choice)
1241{
1242 M_Mouse(choice, &mouseSensitivity_horiz);
1243}
1244
1245void M_MouseVert(int choice)
1246{
1247 M_Mouse(choice, &mouseSensitivity_vert);
1248}
1249
1250void M_Mouse(int choice, int *sens)
1251{
1252 switch(choice)
1253 {
1254 case 0:
1255 if (*sens)
1256 --*sens;
1257 break;
1258 case 1:
1259 if (*sens < 99)
1260 ++*sens; /*mead*/
1261 break;
1262 }
1263}
1264
1265/////////////////////////////
1266//
1267// M_QuickSave
1268//
1269
1270char tempstring[80];
1271
1272static void M_QuickSaveResponse(int ch)
1273{
1274 if (ch == 'y') {
1275 M_DoSave(quickSaveSlot);
1276 S_StartSound(NULL,sfx_swtchx);
1277 }
1278}
1279
1280void M_QuickSave(void)
1281{
1282 if (!usergame && (!demoplayback || netgame)) { /* killough 10/98 */
1283 S_StartSound(NULL,sfx_oof);
1284 return;
1285 }
1286
1287 if (gamestate != GS_LEVEL)
1288 return;
1289
1290 if (quickSaveSlot < 0) {
1291 M_StartControlPanel();
1292 M_ReadSaveStrings();
1293 M_SetupNextMenu(&SaveDef);
1294 quickSaveSlot = -2; // means to pick a slot now
1295 return;
1296 }
1297 sprintf(tempstring,s_QSPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized
1298 M_StartMessage(tempstring,M_QuickSaveResponse,true);
1299}
1300
1301/////////////////////////////
1302//
1303// M_QuickLoad
1304//
1305
1306static void M_QuickLoadResponse(int ch)
1307{
1308 if (ch == 'y') {
1309 M_LoadSelect(quickSaveSlot);
1310 S_StartSound(NULL,sfx_swtchx);
1311 }
1312}
1313
1314void M_QuickLoad(void)
1315{
1316 // cph - removed restriction against quickload in a netgame
1317
1318 if (demorecording) { // killough 5/26/98: exclude during demo recordings
1319 M_StartMessage("you can't quickload\n"
1320 "while recording a demo!\n\n"PRESSKEY,
1321 NULL, false); // killough 5/26/98: not externalized
1322 return;
1323 }
1324
1325 if (quickSaveSlot < 0) {
1326 M_StartMessage(s_QSAVESPOT,NULL,false); // Ty 03/27/98 - externalized
1327 return;
1328 }
1329 sprintf(tempstring,s_QLPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized
1330 M_StartMessage(tempstring,M_QuickLoadResponse,true);
1331}
1332
1333/////////////////////////////
1334//
1335// M_EndGame
1336//
1337
1338static void M_EndGameResponse(int ch)
1339{
1340 if (ch != 'y')
1341 return;
1342
1343 // killough 5/26/98: make endgame quit if recording or playing back demo
1344 if (demorecording || singledemo)
1345 G_CheckDemoStatus();
1346
1347 currentMenu->lastOn = itemOn;
1348 M_ClearMenus ();
1349 D_StartTitle ();
1350}
1351
1352void M_EndGame(int choice)
1353{
1354 if (netgame)
1355 {
1356 M_StartMessage(s_NETEND,NULL,false); // Ty 03/27/98 - externalized
1357 return;
1358 }
1359 M_StartMessage(s_ENDGAME,M_EndGameResponse,true); // Ty 03/27/98 - externalized
1360}
1361
1362/////////////////////////////
1363//
1364// Toggle messages on/off
1365//
1366
1367void M_ChangeMessages(int choice)
1368{
1369 // warning: unused parameter `int choice'
1370 choice = 0;
1371 showMessages = 1 - showMessages;
1372
1373 if (!showMessages)
1374 players[consoleplayer].message = s_MSGOFF; // Ty 03/27/98 - externalized
1375 else
1376 players[consoleplayer].message = s_MSGON ; // Ty 03/27/98 - externalized
1377
1378 message_dontfuckwithme = true;
1379}
1380
1381/////////////////////////////
1382//
1383// CHANGE DISPLAY SIZE
1384//
1385// jff 2/23/98 restored to pre-HUD state
1386// hud_active controlled soley by F5=key_detail (key_hud)
1387// hud_displayed is toggled by + or = in fullscreen
1388// hud_displayed is cleared by -
1389
1390void M_SizeDisplay(int choice)
1391{
1392 switch(choice) {
1393 case 0:
1394 if (screenSize > 0) {
1395 screenblocks--;
1396 screenSize--;
1397 hud_displayed = 0;
1398 }
1399 break;
1400 case 1:
1401 if (screenSize < 8) {
1402 screenblocks++;
1403 screenSize++;
1404 }
1405 else
1406 hud_displayed = !hud_displayed;
1407 break;
1408 }
1409 R_SetViewSize (screenblocks /*, detailLevel obsolete -- killough */);
1410}
1411
1412//
1413// End of Original Menus
1414//
1415/////////////////////////////////////////////////////////////////////////////
1416
1417/////////////////////////////////////////////////////////////////////////////
1418//
1419// SETUP MENU (phares)
1420//
1421// We've added a set of Setup Screens from which you can configure a number
1422// of variables w/o having to restart the game. There are 7 screens:
1423//
1424// Key Bindings
1425// Weapons
1426// Status Bar / HUD
1427// Automap
1428// Enemies
1429// Messages
1430// Chat Strings
1431//
1432// killough 10/98: added Compatibility and General menus
1433//
1434
1435/////////////////////////////
1436//
1437// booleans for setup screens
1438// these tell you what state the setup screens are in, and whether any of
1439// the overlay screens (automap colors, reset button message) should be
1440// displayed
1441
1442boolean setup_active = false; // in one of the setup screens
1443boolean set_keybnd_active = false; // in key binding setup screens
1444boolean set_weapon_active = false; // in weapons setup screen
1445boolean set_status_active = false; // in status bar/hud setup screen
1446boolean set_auto_active = false; // in automap setup screen
1447boolean set_enemy_active = false; // in enemies setup screen
1448boolean set_mess_active = false; // in messages setup screen
1449boolean set_chat_active = false; // in chat string setup screen
1450boolean setup_select = false; // changing an item
1451boolean setup_gather = false; // gathering keys for value
1452boolean colorbox_active = false; // color palette being shown
1453boolean default_verify = false; // verify reset defaults decision
1454boolean set_general_active = false;
1455boolean set_compat_active = false;
1456
1457/////////////////////////////
1458//
1459// set_menu_itemon is an index that starts at zero, and tells you which
1460// item on the current screen the cursor is sitting on.
1461//
1462// current_setup_menu is a pointer to the current setup menu table.
1463
1464static int set_menu_itemon; // which setup item is selected? // phares 3/98
1465setup_menu_t* current_setup_menu; // points to current setup menu table
1466
1467/////////////////////////////
1468//
1469// The menu_buffer is used to construct strings for display on the screen.
1470
1471static char menu_buffer[64];
1472
1473/////////////////////////////
1474//
1475// The setup_e enum is used to provide a unique number for each group of Setup
1476// Screens.
1477
1478enum
1479{
1480 set_compat,
1481 set_key_bindings,
1482 set_weapons,
1483 set_statbar,
1484 set_automap,
1485 set_enemy,
1486 set_messages,
1487 set_chatstrings,
1488 set_setup_end
1489} setup_e;
1490
1491int setup_screen; // the current setup screen. takes values from setup_e
1492
1493/////////////////////////////
1494//
1495// SetupMenu is the definition of what the main Setup Screen should look
1496// like. Each entry shows that the cursor can land on each item (1), the
1497// built-in graphic lump (i.e. "M_KEYBND") that should be displayed,
1498// the program which takes over when an item is selected, and the hotkey
1499// associated with the item.
1500
1501menuitem_t SetupMenu[]=
1502{
1503 {1,"M_COMPAT",M_Compat, 'p'},
1504 {1,"M_KEYBND",M_KeyBindings,'k'},
1505 {1,"M_WEAP" ,M_Weapons, 'w'},
1506 {1,"M_STAT" ,M_StatusBar, 's'},
1507 {1,"M_AUTO" ,M_Automap, 'a'},
1508 {1,"M_ENEM" ,M_Enemy, 'e'},
1509 {1,"M_MESS" ,M_Messages, 'm'},
1510 {1,"M_CHAT" ,M_ChatStrings,'c'},
1511};
1512
1513/////////////////////////////
1514//
1515// M_DoNothing does just that: nothing. Just a placeholder.
1516
1517static void M_DoNothing(int choice)
1518{
1519}
1520
1521/////////////////////////////
1522//
1523// Items needed to satisfy the 'Big Font' menu structures:
1524//
1525// the generic_setup_e enum mimics the 'Big Font' menu structures, but
1526// means nothing to the Setup Menus.
1527
1528enum
1529{
1530 generic_setupempty1,
1531 generic_setup_end
1532} generic_setup_e;
1533
1534// Generic_Setup is a do-nothing definition that the mainstream Menu code
1535// can understand, while the Setup Menu code is working. Another placeholder.
1536
1537menuitem_t Generic_Setup[] =
1538{
1539 {1,"",M_DoNothing,0}
1540};
1541
1542/////////////////////////////
1543//
1544// SetupDef is the menu definition that the mainstream Menu code understands.
1545// This is used by M_Setup (below) to define what is drawn and what is done
1546// with the main Setup screen.
1547
1548menu_t SetupDef =
1549{
1550 set_setup_end, // number of Setup Menu items (Key Bindings, etc.)
1551 &OptionsDef, // menu to return to when BACKSPACE is hit on this menu
1552 SetupMenu, // definition of items to show on the Setup Screen
1553 M_DrawSetup, // program that draws the Setup Screen
1554 59,37, // x,y position of the skull (modified when the skull is
1555 // drawn). The skull is parked on the upper-left corner
1556 // of the Setup screens, since it isn't needed as a cursor
1557 0 // last item the user was on for this menu
1558};
1559
1560/////////////////////////////
1561//
1562// Here are the definitions of the individual Setup Menu screens. They
1563// follow the format of the 'Big Font' menu structures. See the comments
1564// for SetupDef (above) to help understand what each of these says.
1565
1566menu_t KeybndDef =
1567{
1568 generic_setup_end,
1569 &SetupDef,
1570 Generic_Setup,
1571 M_DrawKeybnd,
1572 34,5, // skull drawn here
1573 0
1574};
1575
1576menu_t WeaponDef =
1577{
1578 generic_setup_end,
1579 &SetupDef,
1580 Generic_Setup,
1581 M_DrawWeapons,
1582 34,5, // skull drawn here
1583 0
1584};
1585
1586menu_t StatusHUDDef =
1587{
1588 generic_setup_end,
1589 &SetupDef,
1590 Generic_Setup,
1591 M_DrawStatusHUD,
1592 34,5, // skull drawn here
1593 0
1594};
1595
1596menu_t AutoMapDef =
1597{
1598 generic_setup_end,
1599 &SetupDef,
1600 Generic_Setup,
1601 M_DrawAutoMap,
1602 34,5, // skull drawn here
1603 0
1604};
1605
1606menu_t EnemyDef = // phares 4/08/98
1607{
1608 generic_setup_end,
1609 &SetupDef,
1610 Generic_Setup,
1611 M_DrawEnemy,
1612 34,5, // skull drawn here
1613 0
1614};
1615
1616menu_t MessageDef = // phares 4/08/98
1617{
1618 generic_setup_end,
1619 &SetupDef,
1620 Generic_Setup,
1621 M_DrawMessages,
1622 34,5, // skull drawn here
1623 0
1624};
1625
1626menu_t ChatStrDef = // phares 4/10/98
1627{
1628 generic_setup_end,
1629 &SetupDef,
1630 Generic_Setup,
1631 M_DrawChatStrings,
1632 34,5, // skull drawn here
1633 0
1634};
1635
1636menu_t GeneralDef = // killough 10/98
1637{
1638 generic_setup_end,
1639 &OptionsDef,
1640 Generic_Setup,
1641 M_DrawGeneral,
1642 34,5, // skull drawn here
1643 0
1644};
1645
1646menu_t CompatDef = // killough 10/98
1647{
1648 generic_setup_end,
1649 &SetupDef,
1650 Generic_Setup,
1651 M_DrawCompat,
1652 34,5, // skull drawn here
1653 0
1654};
1655
1656/////////////////////////////
1657//
1658// Draws the Title for the main Setup screen
1659
1660void M_DrawSetup(void)
1661{
1662 // CPhipps - patch drawing updated
1663 V_DrawNamePatch(124, 15, 0, "M_SETUP", CR_DEFAULT, VPT_STRETCH);
1664}
1665
1666/////////////////////////////
1667//
1668// Uses the SetupDef structure to draw the menu items for the main
1669// Setup screen
1670
1671void M_Setup(int choice)
1672{
1673 M_SetupNextMenu(&SetupDef);
1674}
1675
1676/////////////////////////////
1677//
1678// Data that's used by the Setup screen code
1679//
1680// Establish the message colors to be used
1681
1682#define CR_TITLE CR_GOLD
1683#define CR_SET CR_GREEN
1684#define CR_ITEM CR_RED
1685#define CR_HILITE CR_ORANGE
1686#define CR_SELECT CR_GRAY
1687
1688// Data used by the Automap color selection code
1689
1690#define CHIP_SIZE 7 // size of color block for colored items
1691
1692#define COLORPALXORIG ((320 - 16*(CHIP_SIZE+1))/2)
1693#define COLORPALYORIG ((200 - 16*(CHIP_SIZE+1))/2)
1694
1695#define PAL_BLACK 0
1696#define PAL_WHITE 4
1697
1698// Data used by the Chat String editing code
1699
1700#define CHAT_STRING_BFR_SIZE 128
1701
1702// chat strings must fit in this screen space
1703// killough 10/98: reduced, for more general uses
1704#define MAXCHATWIDTH 272
1705
1706int chat_index;
1707char* chat_string_buffer; // points to new chat strings while editing
1708
1709/////////////////////////////
1710//
1711// phares 4/17/98:
1712// Added 'Reset to Defaults' Button to Setup Menu screens
1713// This is a small button that sits in the upper-right-hand corner of
1714// the first screen for each group. It blinks when selected, thus the
1715// two patches, which it toggles back and forth.
1716
1717char ResetButtonName[2][8] = {"M_BUTT1","M_BUTT2"};
1718
1719/////////////////////////////
1720//
1721// phares 4/18/98:
1722// Consolidate Item drawing code
1723//
1724// M_DrawItem draws the description of the provided item (the left-hand
1725// part). A different color is used for the text depending on whether the
1726// item is selected or not, or whether it's about to change.
1727
1728// CPhipps - static, hanging else removed, const parameter
1729static void M_DrawItem(const setup_menu_t* s)
1730{
1731 int x = s->m_x;
1732 int y = s->m_y;
1733 int flags = s->m_flags;
1734 if (flags & S_RESET)
1735
1736 // This item is the reset button
1737 // Draw the 'off' version if this isn't the current menu item
1738 // Draw the blinking version in tune with the blinking skull otherwise
1739
1740 // proff/nicolas 09/20/98 -- changed for hi-res
1741 // CPhipps - Patch drawing updated, reformatted
1742
1743 V_DrawNamePatch(x, y, 0, ResetButtonName[(flags & (S_HILITE|S_SELECT)) ? whichSkull : 0],
1744 CR_DEFAULT, VPT_STRETCH);
1745
1746 else { // Draw the item string
1747 char *p, *t;
1748 int w = 0;
1749 int color =
1750 flags & S_SELECT ? CR_SELECT :
1751 flags & S_HILITE ? CR_HILITE :
1752 flags & (S_TITLE|S_NEXT|S_PREV) ? CR_TITLE : CR_ITEM; // killough 10/98
1753
1754 /* killough 10/98:
1755 * Enhance to support multiline text separated by newlines.
1756 * This supports multiline items on horizontally-crowded menus.
1757 */
1758
1759 for (p = t = strdup(s->m_text); (p = strtok(p,"\n")); y += 8, p = NULL)
1760 { /* killough 10/98: support left-justification: */
1761 strcpy(menu_buffer,p);
1762 if (!(flags & S_LEFTJUST))
1763 w = M_GetPixelWidth(menu_buffer) + 4;
1764 M_DrawMenuString(x - w, y ,color);
1765 }
1766 free(t);
1767 }
1768}
1769
1770// If a number item is being changed, allow up to N keystrokes to 'gather'
1771// the value. Gather_count tells you how many you have so far. The legality
1772// of what is gathered is determined by the low/high settings for the item.
1773
1774#define MAXGATHER 5
1775int gather_count;
1776char gather_buffer[MAXGATHER+1]; // killough 10/98: make input character-based
1777
1778/////////////////////////////
1779//
1780// phares 4/18/98:
1781// Consolidate Item Setting drawing code
1782//
1783// M_DrawSetting draws the setting of the provided item (the right-hand
1784// part. It determines the text color based on whether the item is
1785// selected or being changed. Then, depending on the type of item, it
1786// displays the appropriate setting value: yes/no, a key binding, a number,
1787// a paint chip, etc.
1788
1789static void M_DrawSetting(const setup_menu_t* s)
1790{
1791 int x = s->m_x, y = s->m_y, flags = s->m_flags, color;
1792
1793 // Determine color of the text. This may or may not be used later,
1794 // depending on whether the item is a text string or not.
1795
1796 color = flags & S_SELECT ? CR_SELECT : flags & S_HILITE ? CR_HILITE : CR_SET;
1797
1798 // Is the item a YES/NO item?
1799
1800 if (flags & S_YESNO) {
1801 strcpy(menu_buffer,*s->var.def->location.pi ? "YES" : "NO");
1802 M_DrawMenuString(x,y,color);
1803 return;
1804 }
1805
1806 // Is the item a simple number?
1807
1808 if (flags & S_NUM) {
1809 // killough 10/98: We must draw differently for items being gathered.
1810 if (flags & (S_HILITE|S_SELECT) && setup_gather) {
1811 gather_buffer[gather_count] = 0;
1812 strcpy(menu_buffer, gather_buffer);
1813 }
1814 else
1815 sprintf(menu_buffer,"%d",*s->var.def->location.pi);
1816 M_DrawMenuString(x,y,color);
1817 return;
1818 }
1819
1820 // Is the item a key binding?
1821
1822 if (flags & S_KEY) { // Key Binding
1823 int *key = s->var.m_key;
1824
1825 // Draw the key bound to the action
1826
1827 if (key) {
1828 M_GetKeyString(*key,0); // string to display
1829 if (key == &key_use) {
1830 // For the 'use' key, you have to build the string
1831
1832 if (s->m_mouse)
1833 sprintf(menu_buffer+strlen(menu_buffer), "/DBL-CLK MB%d",*s->m_mouse+1);
1834 if (s->m_joy)
1835 sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",*s->m_joy+1);
1836 }
1837 else if (key == &key_up || key == &key_speed ||
1838 key == &key_fire || key == &key_strafe)
1839 {
1840 if (s->m_mouse)
1841 sprintf(menu_buffer+strlen(menu_buffer), "/MB%d",
1842 *s->m_mouse+1);
1843 if (s->m_joy)
1844 sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",
1845 *s->m_joy+1);
1846 }
1847 M_DrawMenuString(x,y,color);
1848 }
1849 return;
1850 }
1851
1852 // Is the item a weapon number?
1853 // OR, Is the item a colored text string from the Automap?
1854 //
1855 // killough 10/98: removed special code, since the rest of the engine
1856 // already takes care of it, and this code prevented the user from setting
1857 // their overall weapons preferences while playing Doom 1.
1858 //
1859 // killough 11/98: consolidated weapons code with color range code
1860
1861 if (flags & (S_WEAP|S_CRITEM)) // weapon number or color range
1862 {
1863 sprintf(menu_buffer,"%d", *s->var.def->location.pi);
1864 M_DrawMenuString(x,y, flags & S_CRITEM ? *s->var.def->location.pi : color);
1865 return;
1866 }
1867
1868 // Is the item a paint chip?
1869
1870 if (flags & S_COLOR) // Automap paint chip
1871 {
1872 int ch;
1873
1874 ch = *s->var.def->location.pi;
1875 // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch
1876 // draw the paint chip
1877 V_FillRect(0, x*SCREENWIDTH/320, (y-1)*SCREENHEIGHT/200,
1878 8*SCREENWIDTH/320, 8*SCREENHEIGHT/200,
1879 PAL_BLACK);
1880 V_FillRect(0, (x+1)*SCREENWIDTH/320, y*SCREENHEIGHT/200,
1881 6*SCREENWIDTH/320, 6*SCREENHEIGHT/200,
1882 (byte)ch);
1883
1884 if (!ch) // don't show this item in automap mode
1885 V_DrawNamePatch(x+1,y,0,"M_PALNO", CR_DEFAULT, VPT_STRETCH);
1886 return;
1887 }
1888
1889 // Is the item a chat string?
1890 // killough 10/98: or a filename?
1891
1892 if (flags & S_STRING) {
1893 /* cph - cast to char* as it's really a Z_Strdup'd string (see m_misc.h) */
1894 char *text = (char*)*s->var.def->location.ppsz;
1895
1896 // Are we editing this string? If so, display a cursor under
1897 // the correct character.
1898
1899 if (setup_select && (s->m_flags & (S_HILITE|S_SELECT))) {
1900 int cursor_start, char_width;
1901 char c[2];
1902
1903 // If the string is too wide for the screen, trim it back,
1904 // one char at a time until it fits. This should only occur
1905 // while you're editing the string.
1906
1907 while (M_GetPixelWidth(text) >= MAXCHATWIDTH) {
1908 int len = strlen(text);
1909 text[--len] = 0;
1910 if (chat_index > len)
1911 chat_index--;
1912 }
1913
1914 // Find the distance from the beginning of the string to
1915 // where the cursor should be drawn, plus the width of
1916 // the char the cursor is under..
1917
1918 *c = text[chat_index]; // hold temporarily
1919 c[1] = 0;
1920 char_width = M_GetPixelWidth(c);
1921 if (char_width == 1)
1922 char_width = 7; // default for end of line
1923 text[chat_index] = 0; // NULL to get cursor position
1924 cursor_start = M_GetPixelWidth(text);
1925 text[chat_index] = *c; // replace stored char
1926
1927 // Now draw the cursor
1928 // proff 12/6/98: Drawing of cursor changed for hi-res
1929 V_FillRect(0, ((x+cursor_start-1)*SCREENWIDTH)/320, (y*SCREENHEIGHT)/200,
1930 (char_width*SCREENWIDTH)/320, 9*SCREENHEIGHT/200, PAL_WHITE);
1931 }
1932
1933 // Draw the setting for the item
1934
1935 strcpy(menu_buffer,text);
1936 M_DrawMenuString(x,y,color);
1937 return;
1938 }
1939
1940 // Is the item a selection of choices?
1941
1942 if (flags & S_CHOICE) {
1943 if (s->var.def->type == def_int) {
1944 if (s->selectstrings == NULL) {
1945 sprintf(menu_buffer,"%d",*s->var.def->location.pi);
1946 } else {
1947 strcpy(menu_buffer,s->selectstrings[*s->var.def->location.pi]);
1948 }
1949 }
1950
1951 if (s->var.def->type == def_str) {
1952 sprintf(menu_buffer,"%s", *s->var.def->location.ppsz);
1953 }
1954
1955 M_DrawMenuString(x,y,color);
1956 return;
1957 }
1958}
1959
1960/////////////////////////////
1961//
1962// M_DrawScreenItems takes the data for each menu item and gives it to
1963// the drawing routines above.
1964
1965// CPhipps - static, const parameter, formatting
1966static void M_DrawScreenItems(const setup_menu_t* src)
1967{
1968 if (print_warning_about_changes > 0) { /* killough 8/15/98: print warning */
1969 if (warning_about_changes & S_BADVAL) {
1970 strcpy(menu_buffer, "Value out of Range");
1971 M_DrawMenuString(100,176,CR_RED);
1972 } else if (warning_about_changes & S_PRGWARN) {
1973 strcpy(menu_buffer, "Warning: Program must be restarted to see changes");
1974 M_DrawMenuString(3, 176, CR_RED);
1975 } else if (warning_about_changes & S_BADVID) {
1976 strcpy(menu_buffer, "Video mode not supported");
1977 M_DrawMenuString(80,176,CR_RED);
1978 } else {
1979 strcpy(menu_buffer, "Warning: Changes are pending until next game");
1980 M_DrawMenuString(18,184,CR_RED);
1981 }
1982 }
1983
1984 while (!(src->m_flags & S_END)) {
1985
1986 // See if we're to draw the item description (left-hand part)
1987
1988 if (src->m_flags & S_SHOWDESC)
1989 M_DrawItem(src);
1990
1991 // See if we're to draw the setting (right-hand part)
1992
1993 if (src->m_flags & S_SHOWSET)
1994 M_DrawSetting(src);
1995 src++;
1996 }
1997}
1998
1999/////////////////////////////
2000//
2001// Data used to draw the "are you sure?" dialogue box when resetting
2002// to defaults.
2003
2004#define VERIFYBOXXORG 66
2005#define VERIFYBOXYORG 88
2006#define PAL_GRAY1 91
2007#define PAL_GRAY2 98
2008#define PAL_GRAY3 105
2009
2010// And the routine to draw it.
2011
2012static void M_DrawDefVerify(void)
2013{
2014 // proff 12/6/98: Drawing of verify box changed for hi-res, it now uses a patch
2015 V_DrawNamePatch(VERIFYBOXXORG,VERIFYBOXYORG,0,"M_VBOX",CR_DEFAULT,VPT_STRETCH);
2016 // The blinking messages is keyed off of the blinking of the
2017 // cursor skull.
2018
2019 if (whichSkull) { // blink the text
2020 strcpy(menu_buffer,"Reset to defaults? (Y or N)");
2021 M_DrawMenuString(VERIFYBOXXORG+8,VERIFYBOXYORG+8,CR_RED);
2022 }
2023}
2024
2025
2026/////////////////////////////
2027//
2028// phares 4/18/98:
2029// M_DrawInstructions writes the instruction text just below the screen title
2030//
2031// cph 2006/08/06 - go back to the Boom version, and then clean up by using
2032// M_DrawStringCentered (much better than all those magic 'x' valies!)
2033
2034static void M_DrawInstructions(void)
2035{
2036 int flags = current_setup_menu[set_menu_itemon].m_flags;
2037
2038 // There are different instruction messages depending on whether you
2039 // are changing an item or just sitting on it.
2040
2041 if (setup_select) {
2042 switch (flags & (S_KEY | S_YESNO | S_WEAP | S_NUM | S_COLOR | S_CRITEM | S_CHAT | S_RESET | S_FILE | S_CHOICE)) {
2043 case S_KEY:
2044 // See if a joystick or mouse button setting is allowed for
2045 // this item.
2046 if (current_setup_menu[set_menu_itemon].m_mouse || current_setup_menu[set_menu_itemon].m_joy)
2047 M_DrawStringCentered(160, 20, CR_SELECT, "Press key or button for this action");
2048 else
2049 M_DrawStringCentered(160, 20, CR_SELECT, "Press key for this action");
2050 break;
2051
2052 case S_YESNO:
2053 M_DrawStringCentered(160, 20, CR_SELECT, "Press ENTER key to toggle");
2054 break;
2055 case S_WEAP:
2056 M_DrawStringCentered(160, 20, CR_SELECT, "Enter weapon number");
2057 break;
2058 case S_NUM:
2059 M_DrawStringCentered(160, 20, CR_SELECT, "Enter value. Press ENTER when finished.");
2060 break;
2061 case S_COLOR:
2062 M_DrawStringCentered(160, 20, CR_SELECT, "Select color and press enter");
2063 break;
2064 case S_CRITEM:
2065 M_DrawStringCentered(160, 20, CR_SELECT, "Enter value");
2066 break;
2067 case S_CHAT:
2068 M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit chat string and Press ENTER");
2069 break;
2070 case S_FILE:
2071 M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit filename and Press ENTER");
2072 break;
2073 case S_CHOICE:
2074 M_DrawStringCentered(160, 20, CR_SELECT, "Press left or right to choose");
2075 break;
2076 case S_RESET:
2077 break;
2078#ifdef SIMPLECHECKS
2079 default:
2080 lprintf(LO_WARN,"Unrecognised menu item type %d", flags);
2081#endif
2082 }
2083 } else {
2084 if (flags & S_RESET)
2085 M_DrawStringCentered(160, 20, CR_HILITE, "Press ENTER key to reset to defaults");
2086 else
2087 M_DrawStringCentered(160, 20, CR_HILITE, "Press Enter to Change");
2088 }
2089}
2090
2091
2092/////////////////////////////
2093//
2094// The Key Binding Screen tables.
2095
2096#define KB_X 160
2097#define KB_PREV 57
2098#define KB_NEXT 310
2099#define KB_Y 31
2100
2101// phares 4/16/98:
2102// X,Y position of reset button. This is the same for every screen, and is
2103// only defined once here.
2104
2105#define X_BUTTON 301
2106#define Y_BUTTON 3
2107
2108// Definitions of the (in this case) four key binding screens.
2109
2110setup_menu_t keys_settings1[];
2111setup_menu_t keys_settings2[];
2112setup_menu_t keys_settings3[];
2113setup_menu_t keys_settings4[];
2114
2115// The table which gets you from one screen table to the next.
2116
2117setup_menu_t* keys_settings[] =
2118{
2119 keys_settings1,
2120 keys_settings2,
2121 keys_settings3,
2122 keys_settings4,
2123 NULL
2124};
2125
2126int mult_screens_index; // the index of the current screen in a set
2127
2128// Here's an example from this first screen, with explanations.
2129//
2130// {
2131// "STRAFE", // The description of the item ('strafe' key)
2132// S_KEY, // This is a key binding item
2133// m_scrn, // It belongs to the m_scrn group. Its key cannot be
2134// // bound to two items in this group.
2135// KB_X, // The X offset of the start of the right-hand side
2136// KB_Y+ 8*8, // The Y offset of the start of the right-hand side.
2137// // Always given in multiples off a baseline.
2138// &key_strafe, // The variable that holds the key value bound to this
2139// OR a string that holds the config variable name.
2140// OR a pointer to another setup_menu
2141// &mousebstrafe, // The variable that holds the mouse button bound to
2142 // this. If zero, no mouse button can be bound here.
2143// &joybstrafe, // The variable that holds the joystick button bound to
2144 // this. If zero, no mouse button can be bound here.
2145// }
2146
2147// The first Key Binding screen table.
2148// Note that the Y values are ascending. If you need to add something to
2149// this table, (well, this one's not a good example, because it's full)
2150// you need to make sure the Y values still make sense so everything gets
2151// displayed.
2152//
2153// Note also that the first screen of each set has a line for the reset
2154// button. If there is more than one screen in a set, the others don't get
2155// the reset button.
2156//
2157// Note also that this screen has a "NEXT ->" line. This acts like an
2158// item, in that 'activating' it moves you along to the next screen. If
2159// there's a "<- PREV" item on a screen, it behaves similarly, moving you
2160// to the previous screen. If you leave these off, you can't move from
2161// screen to screen.
2162
2163setup_menu_t keys_settings1[] = // Key Binding screen strings
2164{
2165 {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2166 {"FORWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+1*8,{&key_up},&mousebforward},
2167 {"BACKWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+2*8,{&key_down}},
2168 {"TURN LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+3*8,{&key_left}},
2169 {"TURN RIGHT" ,S_KEY ,m_scrn,KB_X,KB_Y+4*8,{&key_right}},
2170 {"RUN" ,S_KEY ,m_scrn,KB_X,KB_Y+5*8,{&key_speed},0,&joybspeed},
2171 {"STRAFE LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+6*8,{&key_strafeleft}},
2172 {"STRAFE RIGHT",S_KEY ,m_scrn,KB_X,KB_Y+7*8,{&key_straferight}},
2173 {"STRAFE" ,S_KEY ,m_scrn,KB_X,KB_Y+8*8,{&key_strafe},&mousebstrafe,&joybstrafe},
2174 {"AUTORUN" ,S_KEY ,m_scrn,KB_X,KB_Y+9*8,{&key_autorun}},
2175 {"180 TURN" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_reverse}},
2176 {"USE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_use},&mousebforward,&joybuse},
2177
2178 {"MENUS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
2179 {"NEXT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+13*8,{&key_menu_down}},
2180 {"PREV ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+14*8,{&key_menu_up}},
2181 {"LEFT" ,S_KEY ,m_menu,KB_X,KB_Y+15*8,{&key_menu_left}},
2182 {"RIGHT" ,S_KEY ,m_menu,KB_X,KB_Y+16*8,{&key_menu_right}},
2183 {"BACKSPACE" ,S_KEY ,m_menu,KB_X,KB_Y+17*8,{&key_menu_backspace}},
2184 {"SELECT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+18*8,{&key_menu_enter}},
2185 {"EXIT" ,S_KEY ,m_menu,KB_X,KB_Y+19*8,{&key_menu_escape}},
2186
2187 // Button for resetting to defaults
2188 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2189
2190 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings2}},
2191
2192 // Final entry
2193 {0,S_SKIP|S_END,m_null}
2194
2195};
2196
2197setup_menu_t keys_settings2[] = // Key Binding screen strings
2198{
2199 {"SCREEN" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2200
2201 // phares 4/13/98:
2202 // key_help and key_escape can no longer be rebound. This keeps the
2203 // player from getting themselves in a bind where they can't remember how
2204 // to get to the menus, and can't remember how to get to the help screen
2205 // to give them a clue as to how to get to the menus. :)
2206
2207 // Also, the keys assigned to these functions cannot be bound to other
2208 // functions. Introduce an S_KEEP flag to show that you cannot swap this
2209 // key with other keys in the same 'group'. (m_scrn, etc.)
2210
2211 {"HELP" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_help}},
2212 {"MENU" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_escape}},
2213 // killough 10/98: hotkey for entering setup menu:
2214 {"SETUP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_setup}},
2215 {"PAUSE" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_pause}},
2216 {"AUTOMAP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_map}},
2217 {"VOLUME" ,S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_soundvolume}},
2218 {"HUD" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_hud}},
2219 {"MESSAGES" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_messages}},
2220 {"GAMMA FIX" ,S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_gamma}},
2221 {"SPY" ,S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_spy}},
2222 {"LARGER VIEW" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_zoomin}},
2223 {"SMALLER VIEW",S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_zoomout}},
2224 {"SCREENSHOT" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_screenshot}},
2225 {"GAME" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
2226 {"SAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_savegame}},
2227 {"LOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&key_loadgame}},
2228 {"QUICKSAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&key_quicksave}},
2229 {"QUICKLOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&key_quickload}},
2230 {"END GAME" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&key_endgame}},
2231 {"QUIT" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_quit}},
2232 {"<- PREV", S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings1}},
2233 {"NEXT ->", S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings3}},
2234
2235 // Final entry
2236
2237 {0,S_SKIP|S_END,m_null}
2238};
2239
2240setup_menu_t keys_settings3[] = // Key Binding screen strings
2241{
2242 {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2243 {"FIST" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_weapon1}},
2244 {"PISTOL" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_weapon2}},
2245 {"SHOTGUN" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_weapon3}},
2246 {"CHAINGUN",S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_weapon4}},
2247 {"ROCKET" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_weapon5}},
2248 {"PLASMA" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_weapon6}},
2249 {"BFG", S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_weapon7}},
2250 {"CHAINSAW",S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_weapon8}},
2251 {"SSG" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_weapon9}},
2252 {"BEST" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_weapontoggle}},
2253 {"FIRE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_fire},&mousebfire,&joybfire},
2254
2255 {"<- PREV",S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings2}},
2256 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings4}},
2257
2258 // Final entry
2259
2260 {0,S_SKIP|S_END,m_null}
2261
2262};
2263
2264setup_menu_t keys_settings4[] = // Key Binding screen strings
2265{
2266 {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2267 {"FOLLOW" ,S_KEY ,m_map ,KB_X,KB_Y+ 1*8,{&key_map_follow}},
2268 {"ZOOM IN" ,S_KEY ,m_map ,KB_X,KB_Y+ 2*8,{&key_map_zoomin}},
2269 {"ZOOM OUT" ,S_KEY ,m_map ,KB_X,KB_Y+ 3*8,{&key_map_zoomout}},
2270 {"SHIFT UP" ,S_KEY ,m_map ,KB_X,KB_Y+ 4*8,{&key_map_up}},
2271 {"SHIFT DOWN" ,S_KEY ,m_map ,KB_X,KB_Y+ 5*8,{&key_map_down}},
2272 {"SHIFT LEFT" ,S_KEY ,m_map ,KB_X,KB_Y+ 6*8,{&key_map_left}},
2273 {"SHIFT RIGHT",S_KEY ,m_map ,KB_X,KB_Y+ 7*8,{&key_map_right}},
2274 {"MARK PLACE" ,S_KEY ,m_map ,KB_X,KB_Y+ 8*8,{&key_map_mark}},
2275 {"CLEAR MARKS",S_KEY ,m_map ,KB_X,KB_Y+ 9*8,{&key_map_clear}},
2276 {"FULL/ZOOM" ,S_KEY ,m_map ,KB_X,KB_Y+10*8,{&key_map_gobig}},
2277 {"GRID" ,S_KEY ,m_map ,KB_X,KB_Y+11*8,{&key_map_grid}},
2278
2279 {"CHATTING" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
2280 {"BEGIN CHAT" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_chat}},
2281 {"PLAYER 1" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&destination_keys[0]}},
2282 {"PLAYER 2" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&destination_keys[1]}},
2283 {"PLAYER 3" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&destination_keys[2]}},
2284 {"PLAYER 4" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&destination_keys[3]}},
2285 {"BACKSPACE" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_backspace}},
2286 {"ENTER" ,S_KEY ,m_scrn,KB_X,KB_Y+19*8,{&key_enter}},
2287
2288 {"<- PREV" ,S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings3}},
2289
2290 // Final entry
2291
2292 {0,S_SKIP|S_END,m_null}
2293
2294};
2295
2296// Setting up for the Key Binding screen. Turn on flags, set pointers,
2297// locate the first item on the screen where the cursor is allowed to
2298// land.
2299
2300void M_KeyBindings(int choice)
2301{
2302 M_SetupNextMenu(&KeybndDef);
2303
2304 setup_active = true;
2305 setup_screen = ss_keys;
2306 set_keybnd_active = true;
2307 setup_select = false;
2308 default_verify = false;
2309 setup_gather = false;
2310 mult_screens_index = 0;
2311 current_setup_menu = keys_settings[0];
2312 set_menu_itemon = 0;
2313 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2314 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2315}
2316
2317// The drawing part of the Key Bindings Setup initialization. Draw the
2318// background, title, instruction line, and items.
2319
2320void M_DrawKeybnd(void)
2321
2322{
2323 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2324
2325 // Set up the Key Binding screen
2326
2327 M_DrawBackground("FLOOR4_6", 0); // Draw background
2328 // proff/nicolas 09/20/98 -- changed for hi-res
2329 V_DrawNamePatch(84, 2, 0, "M_KEYBND", CR_DEFAULT, VPT_STRETCH);
2330 M_DrawInstructions();
2331 M_DrawScreenItems(current_setup_menu);
2332
2333 // If the Reset Button has been selected, an "Are you sure?" message
2334 // is overlayed across everything else.
2335
2336 if (default_verify)
2337 M_DrawDefVerify();
2338}
2339
2340/////////////////////////////
2341//
2342// The Weapon Screen tables.
2343
2344#define WP_X 203
2345#define WP_Y 33
2346
2347// There's only one weapon settings screen (for now). But since we're
2348// trying to fit a common description for screens, it gets a setup_menu_t,
2349// which only has one screen definition in it.
2350//
2351// Note that this screen has no PREV or NEXT items, since there are no
2352// neighboring screens.
2353
2354enum { // killough 10/98: enum for y-offset info
2355 weap_recoil,
2356 weap_bobbing,
2357 weap_bfg,
2358 weap_stub1,
2359 weap_pref1,
2360 weap_pref2,
2361 weap_pref3,
2362 weap_pref4,
2363 weap_pref5,
2364 weap_pref6,
2365 weap_pref7,
2366 weap_pref8,
2367 weap_pref9,
2368 weap_stub2,
2369 weap_toggle,
2370 weap_toggle2,
2371};
2372
2373setup_menu_t weap_settings1[];
2374
2375setup_menu_t* weap_settings[] =
2376{
2377 weap_settings1,
2378 NULL
2379};
2380
2381setup_menu_t weap_settings1[] = // Weapons Settings screen
2382{
2383 {"ENABLE RECOIL", S_YESNO,m_null,WP_X, WP_Y+ weap_recoil*8, {"weapon_recoil"}},
2384 {"ENABLE BOBBING",S_YESNO,m_null,WP_X, WP_Y+weap_bobbing*8, {"player_bobbing"}},
2385
2386 {"1ST CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref1*8, {"weapon_choice_1"}},
2387 {"2nd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref2*8, {"weapon_choice_2"}},
2388 {"3rd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref3*8, {"weapon_choice_3"}},
2389 {"4th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref4*8, {"weapon_choice_4"}},
2390 {"5th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref5*8, {"weapon_choice_5"}},
2391 {"6th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref6*8, {"weapon_choice_6"}},
2392 {"7th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref7*8, {"weapon_choice_7"}},
2393 {"8th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref8*8, {"weapon_choice_8"}},
2394 {"9th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref9*8, {"weapon_choice_9"}},
2395
2396 {"Enable Fist/Chainsaw\n& SG/SSG toggle", S_YESNO, m_null, WP_X,
2397 WP_Y+ weap_toggle*8, {"doom_weapon_toggles"}},
2398
2399 // Button for resetting to defaults
2400 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2401
2402 // Final entry
2403 {0,S_SKIP|S_END,m_null}
2404
2405};
2406
2407// Setting up for the Weapons screen. Turn on flags, set pointers,
2408// locate the first item on the screen where the cursor is allowed to
2409// land.
2410
2411void M_Weapons(int choice)
2412{
2413 M_SetupNextMenu(&WeaponDef);
2414
2415 setup_active = true;
2416 setup_screen = ss_weap;
2417 set_weapon_active = true;
2418 setup_select = false;
2419 default_verify = false;
2420 setup_gather = false;
2421 mult_screens_index = 0;
2422 current_setup_menu = weap_settings[0];
2423 set_menu_itemon = 0;
2424 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2425 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2426}
2427
2428
2429// The drawing part of the Weapons Setup initialization. Draw the
2430// background, title, instruction line, and items.
2431
2432void M_DrawWeapons(void)
2433{
2434 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2435
2436 M_DrawBackground("FLOOR4_6", 0); // Draw background
2437 // proff/nicolas 09/20/98 -- changed for hi-res
2438 V_DrawNamePatch(109, 2, 0, "M_WEAP", CR_DEFAULT, VPT_STRETCH);
2439 M_DrawInstructions();
2440 M_DrawScreenItems(current_setup_menu);
2441
2442 // If the Reset Button has been selected, an "Are you sure?" message
2443 // is overlayed across everything else.
2444
2445 if (default_verify)
2446 M_DrawDefVerify();
2447}
2448
2449/////////////////////////////
2450//
2451// The Status Bar / HUD tables.
2452
2453#define ST_X 203
2454#define ST_Y 31
2455
2456// Screen table definitions
2457
2458setup_menu_t stat_settings1[];
2459
2460setup_menu_t* stat_settings[] =
2461{
2462 stat_settings1,
2463 NULL
2464};
2465
2466setup_menu_t stat_settings1[] = // Status Bar and HUD Settings screen
2467{
2468 {"STATUS BAR" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 1*8 },
2469
2470 {"USE RED NUMBERS" ,S_YESNO, m_null,ST_X,ST_Y+ 2*8, {"sts_always_red"}},
2471 {"GRAY %" ,S_YESNO, m_null,ST_X,ST_Y+ 3*8, {"sts_pct_always_gray"}},
2472 {"SINGLE KEY DISPLAY",S_YESNO, m_null,ST_X,ST_Y+ 4*8, {"sts_traditional_keys"}},
2473
2474 {"HEADS-UP DISPLAY" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 6*8},
2475
2476 {"HIDE SECRETS" ,S_YESNO ,m_null,ST_X,ST_Y+ 7*8, {"hud_nosecrets"}},
2477 {"HEALTH LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+ 8*8, {"health_red"}},
2478 {"HEALTH OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+ 9*8, {"health_yellow"}},
2479 {"HEALTH GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+10*8, {"health_green"}},
2480 {"ARMOR LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+11*8, {"armor_red"}},
2481 {"ARMOR OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+12*8, {"armor_yellow"}},
2482 {"ARMOR GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+13*8, {"armor_green"}},
2483 {"AMMO LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+14*8, {"ammo_red"}},
2484 {"AMMO OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+15*8, {"ammo_yellow"}},
2485
2486 // Button for resetting to defaults
2487 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2488
2489 // Final entry
2490 {0,S_SKIP|S_END,m_null}
2491};
2492
2493// Setting up for the Status Bar / HUD screen. Turn on flags, set pointers,
2494// locate the first item on the screen where the cursor is allowed to
2495// land.
2496
2497void M_StatusBar(int choice)
2498{
2499 M_SetupNextMenu(&StatusHUDDef);
2500
2501 setup_active = true;
2502 setup_screen = ss_stat;
2503 set_status_active = true;
2504 setup_select = false;
2505 default_verify = false;
2506 setup_gather = false;
2507 mult_screens_index = 0;
2508 current_setup_menu = stat_settings[0];
2509 set_menu_itemon = 0;
2510 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2511 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2512}
2513
2514
2515// The drawing part of the Status Bar / HUD Setup initialization. Draw the
2516// background, title, instruction line, and items.
2517
2518void M_DrawStatusHUD(void)
2519
2520{
2521 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2522
2523 M_DrawBackground("FLOOR4_6", 0); // Draw background
2524 // proff/nicolas 09/20/98 -- changed for hi-res
2525 V_DrawNamePatch(59, 2, 0, "M_STAT", CR_DEFAULT, VPT_STRETCH);
2526 M_DrawInstructions();
2527 M_DrawScreenItems(current_setup_menu);
2528
2529 // If the Reset Button has been selected, an "Are you sure?" message
2530 // is overlayed across everything else.
2531
2532 if (default_verify)
2533 M_DrawDefVerify();
2534}
2535
2536
2537/////////////////////////////
2538//
2539// The Automap tables.
2540
2541#define AU_X 250
2542#define AU_Y 31
2543#define AU_PREV KB_PREV
2544#define AU_NEXT KB_NEXT
2545
2546setup_menu_t auto_settings1[];
2547setup_menu_t auto_settings2[];
2548
2549setup_menu_t* auto_settings[] =
2550{
2551 auto_settings1,
2552 auto_settings2,
2553 NULL
2554};
2555
2556setup_menu_t auto_settings1[] = // 1st AutoMap Settings screen
2557{
2558 {"background", S_COLOR, m_null, AU_X, AU_Y, {"mapcolor_back"}},
2559 {"grid lines", S_COLOR, m_null, AU_X, AU_Y + 1*8, {"mapcolor_grid"}},
2560 {"normal 1s wall", S_COLOR, m_null,AU_X,AU_Y+ 2*8, {"mapcolor_wall"}},
2561 {"line at floor height change", S_COLOR, m_null, AU_X, AU_Y+ 3*8, {"mapcolor_fchg"}},
2562 {"line at ceiling height change" ,S_COLOR,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_cchg"}},
2563 {"line at sector with floor = ceiling",S_COLOR,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_clsd"}},
2564 {"red key" ,S_COLOR,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_rkey"}},
2565 {"blue key" ,S_COLOR,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_bkey"}},
2566 {"yellow key" ,S_COLOR,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_ykey"}},
2567 {"red door" ,S_COLOR,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_rdor"}},
2568 {"blue door" ,S_COLOR,m_null,AU_X,AU_Y+10*8, {"mapcolor_bdor"}},
2569 {"yellow door" ,S_COLOR,m_null,AU_X,AU_Y+11*8, {"mapcolor_ydor"}},
2570
2571 {"AUTOMAP LEVEL TITLE COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+13*8, {"hudcolor_titl"}},
2572 {"AUTOMAP COORDINATES COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+14*8, {"hudcolor_xyco"}},
2573
2574 {"Show Secrets only after entering",S_YESNO,m_null,AU_X,AU_Y+15*8, {"map_secret_after"}},
2575
2576 {"Show coordinates of automap pointer",S_YESNO,m_null,AU_X,AU_Y+16*8, {"map_point_coord"}}, // killough 10/98
2577
2578 // Button for resetting to defaults
2579 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2580
2581 {"NEXT ->",S_SKIP|S_NEXT,m_null,AU_NEXT,AU_Y+20*8, {auto_settings2}},
2582
2583 // Final entry
2584 {0,S_SKIP|S_END,m_null}
2585
2586};
2587
2588setup_menu_t auto_settings2[] = // 2nd AutoMap Settings screen
2589{
2590 {"teleporter line" ,S_COLOR ,m_null,AU_X,AU_Y, {"mapcolor_tele"}},
2591 {"secret sector boundary" ,S_COLOR ,m_null,AU_X,AU_Y+ 1*8, {"mapcolor_secr"}},
2592 //jff 4/23/98 add exit line to automap
2593 {"exit line" ,S_COLOR ,m_null,AU_X,AU_Y+ 2*8, {"mapcolor_exit"}},
2594 {"computer map unseen line" ,S_COLOR ,m_null,AU_X,AU_Y+ 3*8, {"mapcolor_unsn"}},
2595 {"line w/no floor/ceiling changes",S_COLOR ,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_flat"}},
2596 {"general sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_sprt"}},
2597 {"countable enemy sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_enemy"}}, // cph 2006/06/30
2598 {"countable item sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_item"}}, // mead 3/4/2003
2599 {"crosshair" ,S_COLOR ,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_hair"}},
2600 {"single player arrow" ,S_COLOR ,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_sngl"}},
2601 {"your colour in multiplayer" ,S_COLOR ,m_null,AU_X,AU_Y+10*8, {"mapcolor_me"}},
2602
2603 {"friends" ,S_COLOR ,m_null,AU_X,AU_Y+12*8, {"mapcolor_frnd"}}, // killough 8/8/98
2604
2605 {"<- PREV",S_SKIP|S_PREV,m_null,AU_PREV,AU_Y+20*8, {auto_settings1}},
2606
2607 // Final entry
2608
2609 {0,S_SKIP|S_END,m_null}
2610
2611};
2612
2613
2614// Setting up for the Automap screen. Turn on flags, set pointers,
2615// locate the first item on the screen where the cursor is allowed to
2616// land.
2617
2618void M_Automap(int choice)
2619{
2620 M_SetupNextMenu(&AutoMapDef);
2621
2622 setup_active = true;
2623 setup_screen = ss_auto;
2624 set_auto_active = true;
2625 setup_select = false;
2626 colorbox_active = false;
2627 default_verify = false;
2628 setup_gather = false;
2629 set_menu_itemon = 0;
2630 mult_screens_index = 0;
2631 current_setup_menu = auto_settings[0];
2632 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2633 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2634}
2635
2636// Data used by the color palette that is displayed for the player to
2637// select colors.
2638
2639int color_palette_x; // X position of the cursor on the color palette
2640int color_palette_y; // Y position of the cursor on the color palette
2641byte palette_background[16*(CHIP_SIZE+1)+8];
2642
2643// M_DrawColPal() draws the color palette when the user needs to select a
2644// color.
2645
2646// phares 4/1/98: now uses a single lump for the palette instead of
2647// building the image out of individual paint chips.
2648
2649static void M_DrawColPal(void)
2650{
2651 int cpx, cpy;
2652
2653 // Draw a background, border, and paint chips
2654
2655 // proff/nicolas 09/20/98 -- changed for hi-res
2656 // CPhipps - patch drawing updated
2657 V_DrawNamePatch(COLORPALXORIG-5, COLORPALYORIG-5, 0, "M_COLORS", CR_DEFAULT, VPT_STRETCH);
2658
2659 // Draw the cursor around the paint chip
2660 // (cpx,cpy) is the upper left-hand corner of the paint chip
2661
2662 cpx = COLORPALXORIG+color_palette_x*(CHIP_SIZE+1)-1;
2663 cpy = COLORPALYORIG+color_palette_y*(CHIP_SIZE+1)-1;
2664 // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch
2665 V_DrawNamePatch(cpx,cpy,0,"M_PALSEL",CR_DEFAULT,VPT_STRETCH); // PROFF_GL_FIX
2666}
2667
2668// The drawing part of the Automap Setup initialization. Draw the
2669// background, title, instruction line, and items.
2670
2671void M_DrawAutoMap(void)
2672
2673{
2674 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2675
2676 M_DrawBackground("FLOOR4_6", 0); // Draw background
2677 // CPhipps - patch drawing updated
2678 V_DrawNamePatch(109, 2, 0, "M_AUTO", CR_DEFAULT, VPT_STRETCH);
2679 M_DrawInstructions();
2680 M_DrawScreenItems(current_setup_menu);
2681
2682 // If a color is being selected, need to show color paint chips
2683
2684 if (colorbox_active)
2685 M_DrawColPal();
2686
2687 // If the Reset Button has been selected, an "Are you sure?" message
2688 // is overlayed across everything else.
2689
2690 else if (default_verify)
2691 M_DrawDefVerify();
2692}
2693
2694
2695/////////////////////////////
2696//
2697// The Enemies table.
2698
2699#define E_X 250
2700#define E_Y 31
2701
2702setup_menu_t enem_settings1[];
2703
2704setup_menu_t* enem_settings[] =
2705{
2706 enem_settings1,
2707 NULL
2708};
2709
2710enum {
2711 enem_infighting,
2712
2713 enem_remember = 1,
2714
2715 enem_backing,
2716 enem_monkeys,
2717 enem_avoid_hazards,
2718 enem_friction,
2719 enem_help_friends,
2720
2721#ifdef DOGS
2722 enem_helpers,
2723#endif
2724
2725 enem_distfriend,
2726
2727#ifdef DOGS
2728 enem_dog_jumping,
2729#endif
2730
2731 enem_end
2732};
2733
2734setup_menu_t enem_settings1[] = // Enemy Settings screen
2735{
2736 // killough 7/19/98
2737 {"Monster Infighting When Provoked",S_YESNO,m_null,E_X,E_Y+ enem_infighting*8, {"monster_infighting"}},
2738
2739 {"Remember Previous Enemy",S_YESNO,m_null,E_X,E_Y+ enem_remember*8, {"monsters_remember"}},
2740
2741 // killough 9/8/98
2742 {"Monster Backing Out",S_YESNO,m_null,E_X,E_Y+ enem_backing*8, {"monster_backing"}},
2743
2744 {"Climb Steep Stairs", S_YESNO,m_null,E_X,E_Y+enem_monkeys*8, {"monkeys"}},
2745
2746 // killough 9/9/98
2747 {"Intelligently Avoid Hazards",S_YESNO,m_null,E_X,E_Y+ enem_avoid_hazards*8, {"monster_avoid_hazards"}},
2748
2749 // killough 10/98
2750 {"Affected by Friction",S_YESNO,m_null,E_X,E_Y+ enem_friction*8, {"monster_friction"}},
2751
2752 {"Rescue Dying Friends",S_YESNO,m_null,E_X,E_Y+ enem_help_friends*8, {"help_friends"}},
2753
2754#ifdef DOGS
2755 // killough 7/19/98
2756 {"Number Of Single-Player Helper Dogs",S_NUM|S_LEVWARN,m_null,E_X,E_Y+ enem_helpers*8, {"player_helpers"}},
2757
2758 // killough 8/8/98
2759 {"Distance Friends Stay Away",S_NUM,m_null,E_X,E_Y+ enem_distfriend*8, {"friend_distance"}},
2760
2761 {"Allow dogs to jump down",S_YESNO,m_null,E_X,E_Y+ enem_dog_jumping*8, {"dog_jumping"}},
2762#endif
2763
2764 // Button for resetting to defaults
2765 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2766
2767 // Final entry
2768 {0,S_SKIP|S_END,m_null}
2769
2770};
2771
2772/////////////////////////////
2773
2774// Setting up for the Enemies screen. Turn on flags, set pointers,
2775// locate the first item on the screen where the cursor is allowed to
2776// land.
2777
2778void M_Enemy(int choice)
2779{
2780 M_SetupNextMenu(&EnemyDef);
2781
2782 setup_active = true;
2783 setup_screen = ss_enem;
2784 set_enemy_active = true;
2785 setup_select = false;
2786 default_verify = false;
2787 setup_gather = false;
2788 mult_screens_index = 0;
2789 current_setup_menu = enem_settings[0];
2790 set_menu_itemon = 0;
2791 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2792 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2793}
2794
2795// The drawing part of the Enemies Setup initialization. Draw the
2796// background, title, instruction line, and items.
2797
2798void M_DrawEnemy(void)
2799
2800{
2801 inhelpscreens = true;
2802
2803 M_DrawBackground("FLOOR4_6", 0); // Draw background
2804 // proff/nicolas 09/20/98 -- changed for hi-res
2805 V_DrawNamePatch(114, 2, 0, "M_ENEM", CR_DEFAULT, VPT_STRETCH);
2806 M_DrawInstructions();
2807 M_DrawScreenItems(current_setup_menu);
2808
2809 // If the Reset Button has been selected, an "Are you sure?" message
2810 // is overlayed across everything else.
2811
2812 if (default_verify)
2813 M_DrawDefVerify();
2814}
2815
2816
2817/////////////////////////////
2818//
2819// The General table.
2820// killough 10/10/98
2821
2822extern int usejoystick, usemouse, default_mus_card, default_snd_card;
2823extern int detect_voices, realtic_clock_rate, tran_filter_pct;
2824
2825setup_menu_t gen_settings1[], gen_settings2[], gen_settings3[];
2826
2827setup_menu_t* gen_settings[] =
2828{
2829 gen_settings1,
2830 gen_settings2,
2831 gen_settings3,
2832 NULL
2833};
2834
2835enum {
2836 general_trans,
2837 general_transpct,
2838 general_fullscreen,
2839 general_videomode,
2840// general_pcx,
2841// general_diskicon,
2842 general_uncapped,
2843};
2844
2845enum {
2846 general_gl_texfilter,
2847 general_gl_texformat,
2848 general_flooroffset,
2849};
2850
2851enum {
2852// general_sndcard,
2853// general_muscard,
2854// general_detvoices,
2855 general_sndchan,
2856 general_pitch
2857};
2858
2859#define G_X 250
2860#define G_YA 44
2861#define G_YA2 (G_YA+9*8)
2862#define G_YA3 (G_YA2+5*8)
2863#define GF_X 76
2864
2865static const char *videomodes[] = {"8bit","15bit","16bit",
2866 "32bit","OpenGL", NULL};
2867
2868static const char *gltexfilters[] = {"GL_NEAREST","GL_LINEAR",
2869 "GL_LINEAR_MIPMAP_LINEAR",
2870 NULL};
2871
2872static const char *gltexformats[] = {"GL_RGBA","GL_RGB5_A1",
2873 "GL_RGBA4", NULL};
2874
2875setup_menu_t gen_settings1[] = { // General Settings screen1
2876
2877 {"Video" ,S_SKIP|S_TITLE, m_null, G_X, G_YA - 12},
2878
2879 {"Enable Translucency", S_YESNO, m_null, G_X,
2880 G_YA + general_trans*8, {"translucency"}, 0, 0, M_Trans},
2881
2882 {"Translucency filter percentage", S_NUM, m_null, G_X,
2883 G_YA + general_transpct*8, {"tran_filter_pct"}, 0, 0, M_Trans},
2884
2885 {"Fullscreen Video mode", S_YESNO|S_PRGWARN, m_null, G_X,
2886 G_YA + general_fullscreen*8, {"use_fullscreen"}, 0, 0, NULL},
2887
2888 {"Video mode", S_CHOICE|S_PRGWARN, m_null, G_X,
2889 G_YA + general_videomode*8, {"videomode"}, 0, 0, NULL, videomodes},
2890
2891 {"Uncapped Framerate", S_YESNO, m_null, G_X,
2892 G_YA + general_uncapped*8, {"uncapped_framerate"}},
2893
2894#ifdef GL_DOOM
2895 {"OpenGL", S_SKIP|S_TITLE, m_null, G_X, G_YA2 - 12},
2896
2897 {"Texture filter", S_CHOICE|S_PRGWARN, m_null, G_X,
2898 G_YA2 + general_gl_texfilter*8, {"gl_tex_filter_string"}, 0, 0, NULL, gltexfilters},
2899
2900 {"Texture format", S_CHOICE|S_PRGWARN, m_null, G_X,
2901 G_YA2 + general_gl_texformat*8, {"gl_tex_format_string"}, 0, 0, NULL, gltexformats},
2902
2903 {"Item out of Floor offset", S_NUM, m_null, G_X,
2904 G_YA2 + general_flooroffset*8, {"gl_sprite_offset"}},
2905#endif
2906
2907#if 0
2908 {"PCX instead of BMP for screenshots", S_YESNO, m_null, G_X,
2909 G_YA + general_pcx*8, {"screenshot_pcx"}},
2910#endif
2911
2912#if 0 // MBF
2913 {"Flash Icon During Disk IO", S_YESNO, m_null, G_X,
2914 G_YA + general_diskicon*8, {"disk_icon"}},
2915#endif
2916
2917 {"Sound & Music", S_SKIP|S_TITLE, m_null, G_X, G_YA3 - 12},
2918#if 0 // MBF
2919 {"Sound Card", S_NUM|S_PRGWARN, m_null, G_X,
2920 G_YA2 + general_sndcard*8, {"sound_card"}},
2921
2922 {"Music Card", S_NUM|S_PRGWARN, m_null, G_X,
2923 G_YA2 + general_muscard*8, {"music_card"}},
2924
2925 {"Autodetect Number of Voices", S_YESNO|S_PRGWARN, m_null, G_X,
2926 G_YA2 + general_detvoices*8, {"detect_voices"}},
2927#endif
2928
2929 {"Number of Sound Channels", S_NUM|S_PRGWARN, m_null, G_X,
2930 G_YA3 + general_sndchan*8, {"snd_channels"}},
2931
2932 {"Enable v1.1 Pitch Effects", S_YESNO, m_null, G_X,
2933 G_YA3 + general_pitch*8, {"pitched_sounds"}},
2934
2935 // Button for resetting to defaults
2936 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2937
2938 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings2}},
2939
2940 // Final entry
2941 {0,S_SKIP|S_END,m_null}
2942};
2943
2944enum {
2945 general_mouse,
2946 general_joy,
2947 general_leds
2948};
2949
2950enum {
2951 general_wad1,
2952 general_wad2,
2953 general_deh1,
2954 general_deh2
2955};
2956
2957enum {
2958 general_corpse,
2959 general_realtic,
2960 general_smooth,
2961 general_smoothfactor,
2962 general_defskill,
2963};
2964
2965#define G_YB 44
2966#define G_YB1 (G_YB+44)
2967#define G_YB2 (G_YB1+52)
2968
2969static const char *gen_skillstrings[] = {
2970 // Dummy first option because defaultskill is 1-based
2971 "", "ITYTD", "HNTR", "HMP", "UV", "NM", NULL
2972};
2973
2974setup_menu_t gen_settings2[] = { // General Settings screen2
2975
2976 {"Input Devices" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12},
2977
2978 {"Enable Mouse", S_YESNO, m_null, G_X,
2979 G_YB + general_mouse*8, {"use_mouse"}},
2980
2981 {"Enable Joystick", S_YESNO, m_null, G_X,
2982 G_YB + general_joy*8, {"use_joystick"}},
2983
2984 {"Files Preloaded at Game Startup",S_SKIP|S_TITLE, m_null, G_X,
2985 G_YB1 - 12},
2986
2987 {"WAD # 1", S_FILE, m_null, GF_X, G_YB1 + general_wad1*8, {"wadfile_1"}},
2988
2989 {"WAD #2", S_FILE, m_null, GF_X, G_YB1 + general_wad2*8, {"wadfile_2"}},
2990
2991 {"DEH/BEX # 1", S_FILE, m_null, GF_X, G_YB1 + general_deh1*8, {"dehfile_1"}},
2992
2993 {"DEH/BEX #2", S_FILE, m_null, GF_X, G_YB1 + general_deh2*8, {"dehfile_2"}},
2994
2995 {"Miscellaneous" ,S_SKIP|S_TITLE, m_null, G_X, G_YB2 - 12},
2996
2997 {"Maximum number of player corpses", S_NUM|S_PRGWARN, m_null, G_X,
2998 G_YB2 + general_corpse*8, {"max_player_corpse"}},
2999
3000 {"Game speed, percentage of normal", S_NUM|S_PRGWARN, m_null, G_X,
3001 G_YB2 + general_realtic*8, {"realtic_clock_rate"}},
3002
3003 {"Smooth Demo Playback", S_YESNO, m_null, G_X,
3004 G_YB2 + general_smooth*8, {"demo_smoothturns"}, 0, 0, M_ChangeDemoSmoothTurns},
3005
3006 {"Smooth Demo Playback Factor", S_NUM, m_null, G_X,
3007 G_YB2 + general_smoothfactor*8, {"demo_smoothturnsfactor"}, 0, 0, M_ChangeDemoSmoothTurns},
3008
3009 {"Default skill level", S_CHOICE, m_null, G_X,
3010 G_YB2 + general_defskill*8, {"default_skill"}, 0, 0, NULL, gen_skillstrings},
3011
3012 {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings1}},
3013
3014 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings3}},
3015
3016 // Final entry
3017
3018 {0,S_SKIP|S_END,m_null}
3019};
3020
3021enum {
3022 general_filterwall,
3023 general_filterfloor,
3024 general_filtersprite,
3025 general_filterpatch,
3026 general_filterz,
3027 general_filter_threshold,
3028 general_spriteedges,
3029 general_patchedges,
3030 general_hom,
3031};
3032
3033#define G_YC 44
3034
3035static const char *renderfilters[] = {"none", "point", "linear", "rounded"};
3036static const char *edgetypes[] = {"jagged", "sloped"};
3037
3038setup_menu_t gen_settings3[] = { // General Settings screen2
3039
3040 {"Renderer settings" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12},
3041
3042 {"Filter for walls", S_CHOICE, m_null, G_X,
3043 G_YC + general_filterwall*8, {"filter_wall"}, 0, 0, NULL, renderfilters},
3044
3045 {"Filter for floors/ceilings", S_CHOICE, m_null, G_X,
3046 G_YC + general_filterfloor*8, {"filter_floor"}, 0, 0, NULL, renderfilters},
3047
3048 {"Filter for sprites", S_CHOICE, m_null, G_X,
3049 G_YC + general_filtersprite*8, {"filter_sprite"}, 0, 0, NULL, renderfilters},
3050
3051 {"Filter for patches", S_CHOICE, m_null, G_X,
3052 G_YC + general_filterpatch*8, {"filter_patch"}, 0, 0, NULL, renderfilters},
3053
3054 {"Filter for lighting", S_CHOICE, m_null, G_X,
3055 G_YC + general_filterz*8, {"filter_z"}, 0, 0, NULL, renderfilters},
3056
3057 {"Drawing of sprite edges", S_CHOICE, m_null, G_X,
3058 G_YC + general_spriteedges*8, {"sprite_edges"}, 0, 0, NULL, edgetypes},
3059
3060 {"Drawing of patch edges", S_CHOICE, m_null, G_X,
3061 G_YC + general_patchedges*8, {"patch_edges"}, 0, 0, NULL, edgetypes},
3062
3063 {"Flashing HOM indicator", S_YESNO, m_null, G_X,
3064 G_YC + general_hom*8, {"flashing_hom"}},
3065
3066 {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings2}},
3067
3068 // Final entry
3069
3070 {0,S_SKIP|S_END,m_null}
3071};
3072
3073void M_Trans(void) // To reset translucency after setting it in menu
3074{
3075 general_translucency = default_translucency; //e6y: Fix for "translucency won't change until you restart the engine"
3076
3077 if (general_translucency)
3078 R_InitTranMap(0);
3079}
3080
3081void M_FullScreen(void) // To (un)set fullscreen video after menu changes
3082{
3083 I_UpdateVideoMode();
3084 V_SetPalette(0);
3085}
3086
3087void M_ChangeDemoSmoothTurns(void)
3088{
3089 if (demo_smoothturns)
3090 gen_settings2[12].m_flags &= ~(S_SKIP|S_SELECT);
3091 else
3092 gen_settings2[12].m_flags |= (S_SKIP|S_SELECT);
3093
3094 R_SmoothPlaying_Reset(NULL);
3095}
3096
3097// Setting up for the General screen. Turn on flags, set pointers,
3098// locate the first item on the screen where the cursor is allowed to
3099// land.
3100
3101void M_General(int choice)
3102{
3103 M_SetupNextMenu(&GeneralDef);
3104
3105 setup_active = true;
3106 setup_screen = ss_gen;
3107 set_general_active = true;
3108 setup_select = false;
3109 default_verify = false;
3110 setup_gather = false;
3111 mult_screens_index = 0;
3112 current_setup_menu = gen_settings[0];
3113 set_menu_itemon = 0;
3114 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3115 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3116}
3117
3118// The drawing part of the General Setup initialization. Draw the
3119// background, title, instruction line, and items.
3120
3121void M_DrawGeneral(void)
3122{
3123 inhelpscreens = true;
3124
3125 M_DrawBackground("FLOOR4_6", 0); // Draw background
3126 // proff/nicolas 09/20/98 -- changed for hi-res
3127 V_DrawNamePatch(114, 2, 0, "M_GENERL", CR_DEFAULT, VPT_STRETCH);
3128 M_DrawInstructions();
3129 M_DrawScreenItems(current_setup_menu);
3130
3131 // If the Reset Button has been selected, an "Are you sure?" message
3132 // is overlayed across everything else.
3133
3134 if (default_verify)
3135 M_DrawDefVerify();
3136}
3137
3138/////////////////////////////
3139//
3140// The Compatibility table.
3141// killough 10/10/98
3142
3143#define C_X 284
3144#define C_Y 32
3145#define COMP_SPC 12
3146#define C_NEXTPREV 131
3147
3148setup_menu_t comp_settings1[], comp_settings2[], comp_settings3[];
3149
3150setup_menu_t* comp_settings[] =
3151{
3152 comp_settings1,
3153 comp_settings2,
3154 comp_settings3,
3155 NULL
3156};
3157
3158enum
3159{
3160 compat_telefrag,
3161 compat_dropoff,
3162 compat_falloff,
3163 compat_staylift,
3164 compat_doorstuck,
3165 compat_pursuit,
3166 compat_vile,
3167 compat_pain,
3168 compat_skull,
3169 compat_blazing,
3170 compat_doorlight = 0,
3171 compat_god,
3172 compat_infcheat,
3173 compat_zombie,
3174 compat_skymap,
3175 compat_stairs,
3176 compat_floors,
3177 compat_moveblock,
3178 compat_model,
3179 compat_zerotags,
3180 compat_666 = 0,
3181 compat_soul,
3182 compat_maskedanim,
3183};
3184
3185setup_menu_t comp_settings1[] = // Compatibility Settings screen #1
3186{
3187 {"Any monster can telefrag on MAP30", S_YESNO, m_null, C_X,
3188 C_Y + compat_telefrag * COMP_SPC, {"comp_telefrag"}},
3189
3190 {"Some objects never hang over tall ledges", S_YESNO, m_null, C_X,
3191 C_Y + compat_dropoff * COMP_SPC, {"comp_dropoff"}},
3192
3193 {"Objects don't fall under their own weight", S_YESNO, m_null, C_X,
3194 C_Y + compat_falloff * COMP_SPC, {"comp_falloff"}},
3195
3196 {"Monsters randomly walk off of moving lifts", S_YESNO, m_null, C_X,
3197 C_Y + compat_staylift * COMP_SPC, {"comp_staylift"}},
3198
3199 {"Monsters get stuck on doortracks", S_YESNO, m_null, C_X,
3200 C_Y + compat_doorstuck * COMP_SPC, {"comp_doorstuck"}},
3201
3202 {"Monsters don't give up pursuit of targets", S_YESNO, m_null, C_X,
3203 C_Y + compat_pursuit * COMP_SPC, {"comp_pursuit"}},
3204
3205 {"Arch-Vile resurrects invincible ghosts", S_YESNO, m_null, C_X,
3206 C_Y + compat_vile * COMP_SPC, {"comp_vile"}},
3207
3208 {"Pain Elementals limited to 21 lost souls", S_YESNO, m_null, C_X,
3209 C_Y + compat_pain * COMP_SPC, {"comp_pain"}},
3210
3211 {"Lost souls get stuck behind walls", S_YESNO, m_null, C_X,
3212 C_Y + compat_skull * COMP_SPC, {"comp_skull"}},
3213
3214 {"Blazing doors make double closing sounds", S_YESNO, m_null, C_X,
3215 C_Y + compat_blazing * COMP_SPC, {"comp_blazing"}},
3216
3217 // Button for resetting to defaults
3218 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
3219
3220 {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings2}},
3221
3222 // Final entry
3223 {0,S_SKIP|S_END,m_null}
3224};
3225
3226setup_menu_t comp_settings2[] = // Compatibility Settings screen #2
3227{
3228 {"Tagged doors don't trigger special lighting", S_YESNO, m_null, C_X,
3229 C_Y + compat_doorlight * COMP_SPC, {"comp_doorlight"}},
3230
3231 {"God mode isn't absolute", S_YESNO, m_null, C_X,
3232 C_Y + compat_god * COMP_SPC, {"comp_god"}},
3233
3234 {"Powerup cheats are not infinite duration", S_YESNO, m_null, C_X,
3235 C_Y + compat_infcheat * COMP_SPC, {"comp_infcheat"}},
3236
3237 {"Zombie players can exit levels", S_YESNO, m_null, C_X,
3238 C_Y + compat_zombie * COMP_SPC, {"comp_zombie"}},
3239
3240 {"Sky is unaffected by invulnerability", S_YESNO, m_null, C_X,
3241 C_Y + compat_skymap * COMP_SPC, {"comp_skymap"}},
3242
3243 {"Use exactly Doom's stairbuilding method", S_YESNO, m_null, C_X,
3244 C_Y + compat_stairs * COMP_SPC, {"comp_stairs"}},
3245
3246 {"Use exactly Doom's floor motion behavior", S_YESNO, m_null, C_X,
3247 C_Y + compat_floors * COMP_SPC, {"comp_floors"}},
3248
3249 {"Use exactly Doom's movement clipping code", S_YESNO, m_null, C_X,
3250 C_Y + compat_moveblock * COMP_SPC, {"comp_moveblock"}},
3251
3252 {"Use exactly Doom's linedef trigger model", S_YESNO, m_null, C_X,
3253 C_Y + compat_model * COMP_SPC, {"comp_model"}},
3254
3255 {"Linedef effects work with sector tag = 0", S_YESNO, m_null, C_X,
3256 C_Y + compat_zerotags * COMP_SPC, {"comp_zerotags"}},
3257
3258 {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings1}},
3259
3260 {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings3}},
3261
3262 // Final entry
3263
3264 {0,S_SKIP|S_END,m_null}
3265};
3266
3267setup_menu_t comp_settings3[] = // Compatibility Settings screen #2
3268{
3269 {"All boss types can trigger tag 666 at ExM8", S_YESNO, m_null, C_X,
3270 C_Y + compat_666 * COMP_SPC, {"comp_666"}},
3271
3272 {"Lost souls don't bounce off flat surfaces", S_YESNO, m_null, C_X,
3273 C_Y + compat_soul * COMP_SPC, {"comp_soul"}},
3274
3275 {"2S middle textures do not animate", S_YESNO, m_null, C_X,
3276 C_Y + compat_maskedanim * COMP_SPC, {"comp_maskedanim"}},
3277
3278 {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings2}},
3279
3280 // Final entry
3281
3282 {0,S_SKIP|S_END,m_null}
3283};
3284
3285// Setting up for the Compatibility screen. Turn on flags, set pointers,
3286// locate the first item on the screen where the cursor is allowed to
3287// land.
3288
3289void M_Compat(int choice)
3290{
3291 M_SetupNextMenu(&CompatDef);
3292
3293 setup_active = true;
3294 setup_screen = ss_comp;
3295 set_general_active = true;
3296 setup_select = false;
3297 default_verify = false;
3298 setup_gather = false;
3299 mult_screens_index = 0;
3300 current_setup_menu = comp_settings[0];
3301 set_menu_itemon = 0;
3302 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3303 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3304}
3305
3306// The drawing part of the Compatibility Setup initialization. Draw the
3307// background, title, instruction line, and items.
3308
3309void M_DrawCompat(void)
3310{
3311 inhelpscreens = true;
3312
3313 M_DrawBackground("FLOOR4_6", 0); // Draw background
3314 V_DrawNamePatch(52,2,0,"M_COMPAT", CR_DEFAULT, VPT_STRETCH);
3315 M_DrawInstructions();
3316 M_DrawScreenItems(current_setup_menu);
3317
3318 // If the Reset Button has been selected, an "Are you sure?" message
3319 // is overlayed across everything else.
3320
3321 if (default_verify)
3322 M_DrawDefVerify();
3323}
3324
3325/////////////////////////////
3326//
3327// The Messages table.
3328
3329#define M_X 230
3330#define M_Y 39
3331
3332// killough 11/98: enumerated
3333
3334enum {
3335 mess_color_play,
3336 mess_timer,
3337 mess_color_chat,
3338 mess_chat_timer,
3339 mess_color_review,
3340 mess_timed,
3341 mess_hud_timer,
3342 mess_lines,
3343 mess_scrollup,
3344 mess_background,
3345};
3346
3347setup_menu_t mess_settings1[];
3348
3349setup_menu_t* mess_settings[] =
3350{
3351 mess_settings1,
3352 NULL
3353};
3354
3355setup_menu_t mess_settings1[] = // Messages screen
3356{
3357 {"Message Color During Play", S_CRITEM, m_null, M_X,
3358 M_Y + mess_color_play*8, {"hudcolor_mesg"}},
3359
3360#if 0
3361 {"Message Duration During Play (ms)", S_NUM, m_null, M_X,
3362 M_Y + mess_timer*8, {"message_timer"}},
3363#endif
3364
3365 {"Chat Message Color", S_CRITEM, m_null, M_X,
3366 M_Y + mess_color_chat*8, {"hudcolor_chat"}},
3367
3368#if 0
3369 {"Chat Message Duration (ms)", S_NUM, m_null, M_X,
3370 M_Y + mess_chat_timer*8, {"chat_msg_timer"}},
3371#endif
3372
3373 {"Message Review Color", S_CRITEM, m_null, M_X,
3374 M_Y + mess_color_review*8, {"hudcolor_list"}},
3375
3376#if 0
3377 {"Message Listing Review is Temporary", S_YESNO, m_null, M_X,
3378 M_Y + mess_timed*8, {"hud_msg_timed"}},
3379
3380 {"Message Review Duration (ms)", S_NUM, m_null, M_X,
3381 M_Y + mess_hud_timer*8, {"hud_msg_timer"}},
3382#endif
3383
3384 {"Number of Review Message Lines", S_NUM, m_null, M_X,
3385 M_Y + mess_lines*8, {"hud_msg_lines"}},
3386
3387#if 0
3388 {"Message Listing Scrolls Upwards", S_YESNO, m_null, M_X,
3389 M_Y + mess_scrollup*8, {"hud_msg_scrollup"}},
3390#endif
3391
3392 {"Message Background", S_YESNO, m_null, M_X,
3393 M_Y + mess_background*8, {"hud_list_bgon"}},
3394
3395 // Button for resetting to defaults
3396 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
3397
3398 // Final entry
3399
3400 {0,S_SKIP|S_END,m_null}
3401};
3402
3403
3404// Setting up for the Messages screen. Turn on flags, set pointers,
3405// locate the first item on the screen where the cursor is allowed to
3406// land.
3407
3408void M_Messages(int choice)
3409{
3410 M_SetupNextMenu(&MessageDef);
3411
3412 setup_active = true;
3413 setup_screen = ss_mess;
3414 set_mess_active = true;
3415 setup_select = false;
3416 default_verify = false;
3417 setup_gather = false;
3418 mult_screens_index = 0;
3419 current_setup_menu = mess_settings[0];
3420 set_menu_itemon = 0;
3421 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3422 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3423}
3424
3425
3426// The drawing part of the Messages Setup initialization. Draw the
3427// background, title, instruction line, and items.
3428
3429void M_DrawMessages(void)
3430
3431{
3432 inhelpscreens = true;
3433 M_DrawBackground("FLOOR4_6", 0); // Draw background
3434 // CPhipps - patch drawing updated
3435 V_DrawNamePatch(103, 2, 0, "M_MESS", CR_DEFAULT, VPT_STRETCH);
3436 M_DrawInstructions();
3437 M_DrawScreenItems(current_setup_menu);
3438 if (default_verify)
3439 M_DrawDefVerify();
3440}
3441
3442
3443/////////////////////////////
3444//
3445// The Chat Strings table.
3446
3447#define CS_X 20
3448#define CS_Y (31+8)
3449
3450setup_menu_t chat_settings1[];
3451
3452setup_menu_t* chat_settings[] =
3453{
3454 chat_settings1,
3455 NULL
3456};
3457
3458setup_menu_t chat_settings1[] = // Chat Strings screen
3459{
3460 {"1",S_CHAT,m_null,CS_X,CS_Y+ 1*8, {"chatmacro1"}},
3461 {"2",S_CHAT,m_null,CS_X,CS_Y+ 2*8, {"chatmacro2"}},
3462 {"3",S_CHAT,m_null,CS_X,CS_Y+ 3*8, {"chatmacro3"}},
3463 {"4",S_CHAT,m_null,CS_X,CS_Y+ 4*8, {"chatmacro4"}},
3464 {"5",S_CHAT,m_null,CS_X,CS_Y+ 5*8, {"chatmacro5"}},
3465 {"6",S_CHAT,m_null,CS_X,CS_Y+ 6*8, {"chatmacro6"}},
3466 {"7",S_CHAT,m_null,CS_X,CS_Y+ 7*8, {"chatmacro7"}},
3467 {"8",S_CHAT,m_null,CS_X,CS_Y+ 8*8, {"chatmacro8"}},
3468 {"9",S_CHAT,m_null,CS_X,CS_Y+ 9*8, {"chatmacro9"}},
3469 {"0",S_CHAT,m_null,CS_X,CS_Y+10*8, {"chatmacro0"}},
3470
3471 // Button for resetting to defaults
3472 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
3473
3474 // Final entry
3475 {0,S_SKIP|S_END,m_null}
3476
3477};
3478
3479// Setting up for the Chat Strings screen. Turn on flags, set pointers,
3480// locate the first item on the screen where the cursor is allowed to
3481// land.
3482
3483void M_ChatStrings(int choice)
3484{
3485 M_SetupNextMenu(&ChatStrDef);
3486 setup_active = true;
3487 setup_screen = ss_chat;
3488 set_chat_active = true;
3489 setup_select = false;
3490 default_verify = false;
3491 setup_gather = false;
3492 mult_screens_index = 0;
3493 current_setup_menu = chat_settings[0];
3494 set_menu_itemon = 0;
3495 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3496 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3497}
3498
3499// The drawing part of the Chat Strings Setup initialization. Draw the
3500// background, title, instruction line, and items.
3501
3502void M_DrawChatStrings(void)
3503
3504{
3505 inhelpscreens = true;
3506 M_DrawBackground("FLOOR4_6", 0); // Draw background
3507 // CPhipps - patch drawing updated
3508 V_DrawNamePatch(83, 2, 0, "M_CHAT", CR_DEFAULT, VPT_STRETCH);
3509 M_DrawInstructions();
3510 M_DrawScreenItems(current_setup_menu);
3511
3512 // If the Reset Button has been selected, an "Are you sure?" message
3513 // is overlayed across everything else.
3514
3515 if (default_verify)
3516 M_DrawDefVerify();
3517}
3518
3519/////////////////////////////
3520//
3521// General routines used by the Setup screens.
3522//
3523
3524static boolean shiftdown = false; // phares 4/10/98: SHIFT key down or not
3525
3526// phares 4/17/98:
3527// M_SelectDone() gets called when you have finished entering your
3528// Setup Menu item change.
3529
3530static void M_SelectDone(setup_menu_t* ptr)
3531{
3532 ptr->m_flags &= ~S_SELECT;
3533 ptr->m_flags |= S_HILITE;
3534 S_StartSound(NULL,sfx_itemup);
3535 setup_select = false;
3536 colorbox_active = false;
3537 if (print_warning_about_changes) // killough 8/15/98
3538 print_warning_about_changes--;
3539}
3540
3541// phares 4/21/98:
3542// Array of setup screens used by M_ResetDefaults()
3543
3544static setup_menu_t **setup_screens[] =
3545{
3546 keys_settings,
3547 weap_settings,
3548 stat_settings,
3549 auto_settings,
3550 enem_settings,
3551 mess_settings,
3552 chat_settings,
3553 gen_settings, // killough 10/98
3554 comp_settings,
3555};
3556
3557// phares 4/19/98:
3558// M_ResetDefaults() resets all values for a setup screen to default values
3559//
3560// killough 10/98: rewritten to fix bugs and warn about pending changes
3561
3562static void M_ResetDefaults(void)
3563{
3564 int i; //e6y
3565
3566 default_t *dp;
3567 int warn = 0;
3568
3569 // Look through the defaults table and reset every variable that
3570 // belongs to the group we're interested in.
3571 //
3572 // killough: However, only reset variables whose field in the
3573 // current setup screen is the same as in the defaults table.
3574 // i.e. only reset variables really in the current setup screen.
3575
3576 // e6y
3577 // Fixed crash while trying to read data past array end
3578 // All previous versions of prboom worked only by a lucky accident
3579 // old code: for (dp = defaults; dp->name; dp++)
3580 for (i = 0; i < numdefaults ; i++)
3581 {
3582 dp = &defaults[i];
3583
3584 if (dp->setupscreen == setup_screen)
3585 {
3586 setup_menu_t **l, *p;
3587 for (l = setup_screens[setup_screen-1]; *l; l++)
3588 for (p = *l; !(p->m_flags & S_END); p++)
3589 if (p->m_flags & S_HASDEFPTR ? p->var.def == dp :
3590 p->var.m_key == dp->location.pi ||
3591 p->m_mouse == dp->location.pi ||
3592 p->m_joy == dp->location.pi)
3593 {
3594 if (IS_STRING(*dp))
3595 free((char*)*dp->location.ppsz),
3596 *dp->location.ppsz = strdup(dp->defaultvalue.psz);
3597 else
3598 *dp->location.pi = dp->defaultvalue.i;
3599
3600#if 0
3601 if (p->m_flags & (S_LEVWARN | S_PRGWARN))
3602 warn |= p->m_flags & (S_LEVWARN | S_PRGWARN);
3603 else
3604 if (dp->current)
3605 if (allow_changes())
3606 *dp->current = *dp->location.pi;
3607 else
3608 warn |= S_LEVWARN;
3609#endif
3610 if (p->action)
3611 p->action();
3612
3613 goto end;
3614 }
3615 end:;
3616 }
3617 }
3618
3619 if (warn)
3620 warn_about_changes(warn);
3621}
3622
3623//
3624// M_InitDefaults()
3625//
3626// killough 11/98:
3627//
3628// This function converts all setup menu entries consisting of cfg
3629// variable names, into pointers to the corresponding default[]
3630// array entry. var.name becomes converted to var.def.
3631//
3632
3633static void M_InitDefaults(void)
3634{
3635 setup_menu_t *const *p, *t;
3636 default_t *dp;
3637 int i;
3638 for (i = 0; i < ss_max-1; i++)
3639 for (p = setup_screens[i]; *p; p++)
3640 for (t = *p; !(t->m_flags & S_END); t++)
3641 if (t->m_flags & S_HASDEFPTR) {
3642 if (!(dp = M_LookupDefault(t->var.name)))
3643 I_Error("M_InitDefaults: Couldn't find config variable %s", t->var.name);
3644 else
3645 (t->var.def = dp)->setup_menu = t;
3646 }
3647}
3648
3649//
3650// End of Setup Screens.
3651//
3652/////////////////////////////////////////////////////////////////////////////
3653
3654/////////////////////////////////////////////////////////////////////////////
3655//
3656// Start of Extended HELP screens // phares 3/30/98
3657//
3658// The wad designer can define a set of extended HELP screens for their own
3659// information display. These screens should be 320x200 graphic lumps
3660// defined in a separate wad. They should be named "HELP01" through "HELP99".
3661// "HELP01" is shown after the regular BOOM Dynamic HELP screen, and ENTER
3662// and BACKSPACE keys move the player through the HELP set.
3663//
3664// Rather than define a set of menu definitions for each of the possible
3665// HELP screens, one definition is used, and is altered on the fly
3666// depending on what HELPnn lumps the game finds.
3667
3668// phares 3/30/98:
3669// Extended Help Screen variables
3670
3671int extended_help_count; // number of user-defined help screens found
3672int extended_help_index; // index of current extended help screen
3673
3674menuitem_t ExtHelpMenu[] =
3675{
3676 {1,"",M_ExtHelpNextScreen,0}
3677};
3678
3679menu_t ExtHelpDef =
3680{
3681 1, // # of menu items
3682 &ReadDef1, // previous menu
3683 ExtHelpMenu, // menuitem_t ->
3684 M_DrawExtHelp, // drawing routine ->
3685 330,181, // x,y
3686 0 // lastOn
3687};
3688
3689// M_ExtHelpNextScreen establishes the number of the next HELP screen in
3690// the series.
3691
3692void M_ExtHelpNextScreen(int choice)
3693{
3694 choice = 0;
3695 if (++extended_help_index > extended_help_count)
3696 {
3697
3698 // when finished with extended help screens, return to Main Menu
3699
3700 extended_help_index = 1;
3701 M_SetupNextMenu(&MainDef);
3702 }
3703}
3704
3705// phares 3/30/98:
3706// Routine to look for HELPnn screens and create a menu
3707// definition structure that defines extended help screens.
3708
3709void M_InitExtendedHelp(void)
3710
3711{
3712 int index,i;
3713 char namebfr[] = { "HELPnn"} ;
3714
3715 extended_help_count = 0;
3716 for (index = 1 ; index < 100 ; index++) {
3717 namebfr[4] = index/10 + 0x30;
3718 namebfr[5] = index%10 + 0x30;
3719 i = W_CheckNumForName(namebfr);
3720 if (i == -1) {
3721 if (extended_help_count) {
3722 if (gamemode == commercial) {
3723 ExtHelpDef.prevMenu = &ReadDef1; /* previous menu */
3724 ReadMenu1[0].routine = M_ExtHelp;
3725 } else {
3726 ExtHelpDef.prevMenu = &ReadDef2; /* previous menu */
3727 ReadMenu2[0].routine = M_ExtHelp;
3728 }
3729 }
3730 return;
3731 }
3732 extended_help_count++;
3733 }
3734
3735}
3736
3737// Initialization for the extended HELP screens.
3738
3739void M_ExtHelp(int choice)
3740{
3741 choice = 0;
3742 extended_help_index = 1; // Start with first extended help screen
3743 M_SetupNextMenu(&ExtHelpDef);
3744}
3745
3746// Initialize the drawing part of the extended HELP screens.
3747
3748void M_DrawExtHelp(void)
3749{
3750 char namebfr[10] = { "HELPnn" }; // CPhipps - make it local & writable
3751
3752 inhelpscreens = true; // killough 5/1/98
3753 namebfr[4] = extended_help_index/10 + 0x30;
3754 namebfr[5] = extended_help_index%10 + 0x30;
3755 // CPhipps - patch drawing updated
3756 V_DrawNamePatch(0, 0, 0, namebfr, CR_DEFAULT, VPT_STRETCH);
3757}
3758
3759//
3760// End of Extended HELP screens // phares 3/30/98
3761//
3762////////////////////////////////////////////////////////////////////////////
3763
3764////////////////////////////////////////////////////////////////////////////
3765//
3766// Dynamic HELP screen // phares 3/2/98
3767//
3768// Rather than providing the static HELP screens from DOOM and its versions,
3769// BOOM provides the player with a dynamic HELP screen that displays the
3770// current settings of major key bindings.
3771//
3772// The Dynamic HELP screen is defined in a manner similar to that used for
3773// the Setup Screens above.
3774//
3775// M_GetKeyString finds the correct string to represent the key binding
3776// for the current item being drawn.
3777
3778int M_GetKeyString(int c,int offset)
3779{
3780 const char* s;
3781
3782 if (c >= 33 && c <= 126) {
3783
3784 // The '=', ',', and '.' keys originally meant the shifted
3785 // versions of those keys, but w/o having to shift them in
3786 // the game. Any actions that are mapped to these keys will
3787 // still mean their shifted versions. Could be changed later
3788 // if someone can come up with a better way to deal with them.
3789
3790 if (c == '=') // probably means the '+' key?
3791 c = '+';
3792 else if (c == ',') // probably means the '<' key?
3793 c = '<';
3794 else if (c == '.') // probably means the '>' key?
3795 c = '>';
3796 menu_buffer[offset++] = c; // Just insert the ascii key
3797 menu_buffer[offset] = 0;
3798
3799 } else {
3800
3801 // Retrieve 4-letter (max) string representing the key
3802
3803 // cph - Keypad keys, general code reorganisation to
3804 // make this smaller and neater.
3805 if ((0x100 <= c) && (c < 0x200)) {
3806 if (c == KEYD_KEYPADENTER)
3807 s = "PADE";
3808 else {
3809 strcpy(&menu_buffer[offset], "PAD");
3810 offset+=4;
3811 menu_buffer[offset-1] = c & 0xff;
3812 menu_buffer[offset] = 0;
3813 }
3814 } else if ((KEYD_F1 <= c) && (c < KEYD_F10)) {
3815 menu_buffer[offset++] = 'F';
3816 menu_buffer[offset++] = '1' + c - KEYD_F1;
3817 menu_buffer[offset] = 0;
3818 } else {
3819 switch(c) {
3820 case KEYD_TAB: s = "TAB"; break;
3821 case KEYD_ENTER: s = "ENTR"; break;
3822 case KEYD_ESCAPE: s = "ESC"; break;
3823 case KEYD_SPACEBAR: s = "SPAC"; break;
3824 case KEYD_BACKSPACE: s = "BACK"; break;
3825 case KEYD_RCTRL: s = "CTRL"; break;
3826 case KEYD_LEFTARROW: s = "LARR"; break;
3827 case KEYD_UPARROW: s = "UARR"; break;
3828 case KEYD_RIGHTARROW: s = "RARR"; break;
3829 case KEYD_DOWNARROW: s = "DARR"; break;
3830 case KEYD_RSHIFT: s = "SHFT"; break;
3831 case KEYD_RALT: s = "ALT"; break;
3832 case KEYD_CAPSLOCK: s = "CAPS"; break;
3833 case KEYD_SCROLLLOCK: s = "SCRL"; break;
3834 case KEYD_HOME: s = "HOME"; break;
3835 case KEYD_PAGEUP: s = "PGUP"; break;
3836 case KEYD_END: s = "END"; break;
3837 case KEYD_PAGEDOWN: s = "PGDN"; break;
3838 case KEYD_INSERT: s = "INST"; break;
3839 case KEYD_DEL: s = "DEL"; break;
3840 case KEYD_F10: s = "F10"; break;
3841 case KEYD_F11: s = "F11"; break;
3842 case KEYD_F12: s = "F12"; break;
3843 case KEYD_PAUSE: s = "PAUS"; break;
3844 default: s = "JUNK"; break;
3845 }
3846
3847 if (s) { // cph - Slight code change
3848 strcpy(&menu_buffer[offset],s); // string to display
3849 offset += strlen(s);
3850 }
3851 }
3852 }
3853 return offset;
3854}
3855
3856//
3857// The Dynamic HELP screen table.
3858
3859#define KT_X1 283
3860#define KT_X2 172
3861#define KT_X3 87
3862
3863#define KT_Y1 2
3864#define KT_Y2 118
3865#define KT_Y3 102
3866
3867setup_menu_t helpstrings[] = // HELP screen strings
3868{
3869 {"SCREEN" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y1},
3870 {"HELP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 1*8,{&key_help}},
3871 {"MENU" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 2*8,{&key_escape}},
3872 {"SETUP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 3*8,{&key_setup}},
3873 {"PAUSE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 4*8,{&key_pause}},
3874 {"AUTOMAP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 5*8,{&key_map}},
3875 {"SOUND VOLUME",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 6*8,{&key_soundvolume}},
3876 {"HUD" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 7*8,{&key_hud}},
3877 {"MESSAGES" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 8*8,{&key_messages}},
3878 {"GAMMA FIX" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 9*8,{&key_gamma}},
3879 {"SPY" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+10*8,{&key_spy}},
3880 {"LARGER VIEW" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+11*8,{&key_zoomin}},
3881 {"SMALLER VIEW",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+12*8,{&key_zoomout}},
3882 {"SCREENSHOT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+13*8,{&key_screenshot}},
3883
3884 {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y2},
3885 {"FOLLOW MODE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 1*8,{&key_map_follow}},
3886 {"ZOOM IN" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 2*8,{&key_map_zoomin}},
3887 {"ZOOM OUT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 3*8,{&key_map_zoomout}},
3888 {"MARK PLACE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 4*8,{&key_map_mark}},
3889 {"CLEAR MARKS" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 5*8,{&key_map_clear}},
3890 {"FULL/ZOOM" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 6*8,{&key_map_gobig}},
3891 {"GRID" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 7*8,{&key_map_grid}},
3892
3893 {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y1},
3894 {"FIST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 1*8,{&key_weapon1}},
3895 {"PISTOL" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 2*8,{&key_weapon2}},
3896 {"SHOTGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 3*8,{&key_weapon3}},
3897 {"CHAINGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 4*8,{&key_weapon4}},
3898 {"ROCKET" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 5*8,{&key_weapon5}},
3899 {"PLASMA" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 6*8,{&key_weapon6}},
3900 {"BFG 9000" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 7*8,{&key_weapon7}},
3901 {"CHAINSAW" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 8*8,{&key_weapon8}},
3902 {"SSG" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 9*8,{&key_weapon9}},
3903 {"BEST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+10*8,{&key_weapontoggle}},
3904 {"FIRE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+11*8,{&key_fire},&mousebfire,&joybfire},
3905
3906 {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y3},
3907 {"FORWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 1*8,{&key_up},&mousebforward},
3908 {"BACKWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 2*8,{&key_down}},
3909 {"TURN LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 3*8,{&key_left}},
3910 {"TURN RIGHT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 4*8,{&key_right}},
3911 {"RUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 5*8,{&key_speed},0,&joybspeed},
3912 {"STRAFE LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 6*8,{&key_strafeleft}},
3913 {"STRAFE RIGHT",S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 7*8,{&key_straferight}},
3914 {"STRAFE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 8*8,{&key_strafe},&mousebstrafe,&joybstrafe},
3915 {"AUTORUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 9*8,{&key_autorun}},
3916 {"180 TURN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+10*8,{&key_reverse}},
3917 {"USE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+11*8,{&key_use},&mousebforward,&joybuse},
3918
3919 {"GAME" ,S_SKIP|S_TITLE,m_null,KT_X2,KT_Y1},
3920 {"SAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 1*8,{&key_savegame}},
3921 {"LOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 2*8,{&key_loadgame}},
3922 {"QUICKSAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 3*8,{&key_quicksave}},
3923 {"END GAME" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 4*8,{&key_endgame}},
3924 {"QUICKLOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 5*8,{&key_quickload}},
3925 {"QUIT" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 6*8,{&key_quit}},
3926
3927 // Final entry
3928
3929 {0,S_SKIP|S_END,m_null}
3930};
3931
3932#define SPACEWIDTH 4
3933
3934/* cph 2006/08/06
3935 * M_DrawString() is the old M_DrawMenuString, except that it is not tied to
3936 * menu_buffer - no reason to force all the callers to write into one array! */
3937
3938static void M_DrawString(int cx, int cy, int color, const char* ch)
3939{
3940 int w;
3941 int c;
3942
3943 while (*ch) {
3944 c = *ch++; // get next char
3945 c = toupper(c) - HU_FONTSTART;
3946 if (c < 0 || c> HU_FONTSIZE)
3947 {
3948 cx += SPACEWIDTH; // space
3949 continue;
3950 }
3951 w = hu_font[c].width;
3952 if (cx + w > 320)
3953 break;
3954
3955 // V_DrawpatchTranslated() will draw the string in the
3956 // desired color, colrngs[color]
3957
3958 // CPhipps - patch drawing updated
3959 V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, color, VPT_STRETCH | VPT_TRANS);
3960 // The screen is cramped, so trim one unit from each
3961 // character so they butt up against each other.
3962 cx += w - 1;
3963 }
3964}
3965
3966// M_DrawMenuString() draws the string in menu_buffer[]
3967
3968static void M_DrawMenuString(int cx, int cy, int color)
3969{
3970 M_DrawString(cx, cy, color, menu_buffer);
3971}
3972
3973// M_GetPixelWidth() returns the number of pixels in the width of
3974// the string, NOT the number of chars in the string.
3975
3976static int M_GetPixelWidth(const char* ch)
3977{
3978 int len = 0;
3979 int c;
3980
3981 while (*ch) {
3982 c = *ch++; // pick up next char
3983 c = toupper(c) - HU_FONTSTART;
3984 if (c < 0 || c > HU_FONTSIZE)
3985 {
3986 len += SPACEWIDTH; // space
3987 continue;
3988 }
3989 len += hu_font[c].width;
3990 len--; // adjust so everything fits
3991 }
3992 len++; // replace what you took away on the last char only
3993 return len;
3994}
3995
3996static void M_DrawStringCentered(int cx, int cy, int color, const char* ch)
3997{
3998 M_DrawString(cx - M_GetPixelWidth(ch)/2, cy, color, ch);
3999}
4000
4001//
4002// M_DrawHelp
4003//
4004// This displays the help screen
4005
4006void M_DrawHelp (void)
4007{
4008 inhelpscreens = true; // killough 10/98
4009 M_DrawBackground("FLOOR4_6", 0);
4010
4011 M_DrawScreenItems(helpstrings);
4012}
4013
4014//
4015// End of Dynamic HELP screen // phares 3/2/98
4016//
4017////////////////////////////////////////////////////////////////////////////
4018
4019enum {
4020 prog,
4021 prog_stub,
4022 prog_stub1,
4023 prog_stub2,
4024 adcr
4025};
4026
4027enum {
4028 cr_prog=0,
4029 cr_adcr=2,
4030};
4031
4032#define CR_S 9
4033#define CR_X 20
4034#define CR_X2 50
4035#define CR_Y 32
4036#define CR_SH 9
4037
4038setup_menu_t cred_settings[]={
4039
4040 {"Programmers",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*prog + CR_SH*cr_prog},
4041 {"Florian 'Proff' Schulze",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+1) + CR_SH*cr_prog},
4042 {"Colin Phipps",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+2) + CR_SH*cr_prog},
4043 {"Neil Stevens",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+3) + CR_SH*cr_prog},
4044 {"Andrey Budko",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+4) + CR_SH*cr_prog},
4045
4046 {"Additional Credit To",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*adcr + CR_SH*cr_adcr},
4047 {"id Software for DOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+1)+CR_SH*cr_adcr},
4048 {"TeamTNT for BOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+2)+CR_SH*cr_adcr},
4049 {"Lee Killough for MBF",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+3)+CR_SH*cr_adcr},
4050 {"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},
4051 {"Randy Heit for ZDOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+5)+CR_SH*cr_adcr},
4052 {"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},
4053 {"Jess Haas for lSDLDoom",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+7) + CR_SH*cr_adcr},
4054 {"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},
4055
4056 {0,S_SKIP|S_END,m_null}
4057};
4058
4059void M_DrawCredits(void) // killough 10/98: credit screen
4060{
4061 inhelpscreens = true;
4062 M_DrawBackground(gamemode==shareware ? "CEIL5_1" : "MFLR8_4", 0);
4063 V_DrawNamePatch(115,9,0, "PRBOOM",CR_GOLD, VPT_TRANS | VPT_STRETCH);
4064 M_DrawScreenItems(cred_settings);
4065}
4066
4067static int M_IndexInChoices(const char *str, const char **choices) {
4068 int i = 0;
4069
4070 while (*choices != NULL) {
4071 if (!strcmp(str, *choices))
4072 return i;
4073 i++;
4074 choices++;
4075 }
4076 return 0;
4077}
4078
4079/////////////////////////////////////////////////////////////////////////////
4080//
4081// M_Responder
4082//
4083// Examines incoming keystrokes and button pushes and determines some
4084// action based on the state of the system.
4085//
4086
4087boolean M_Responder (event_t* ev) {
4088 int ch;
4089 int i;
4090 static int joywait = 0;
4091 static int mousewait = 0;
4092 static int mousey = 0;
4093 static int lasty = 0;
4094 static int mousex = 0;
4095 static int lastx = 0;
4096
4097 ch = -1; // will be changed to a legit char if we're going to use it here
4098
4099 // Process joystick input
4100
4101 if (ev->type == ev_joystick && joywait < I_GetTime()) {
4102 if (ev->data3 == -1)
4103 {
4104 ch = key_menu_up; // phares 3/7/98
4105 joywait = I_GetTime() + 5;
4106 }
4107 else if (ev->data3 == 1)
4108 {
4109 ch = key_menu_down; // phares 3/7/98
4110 joywait = I_GetTime() + 5;
4111 }
4112
4113 if (ev->data2 == -1)
4114 {
4115 ch = key_menu_left; // phares 3/7/98
4116 joywait = I_GetTime() + 2;
4117 }
4118 else if (ev->data2 == 1)
4119 {
4120 ch = key_menu_right; // phares 3/7/98
4121 joywait = I_GetTime() + 2;
4122 }
4123
4124 if (ev->data1&1)
4125 {
4126 ch = key_menu_enter; // phares 3/7/98
4127 joywait = I_GetTime() + 5;
4128 }
4129
4130 if (ev->data1&2)
4131 {
4132 ch = key_menu_backspace; // phares 3/7/98
4133 joywait = I_GetTime() + 5;
4134 }
4135
4136 // phares 4/4/98:
4137 // Handle joystick buttons 3 and 4, and allow them to pass down
4138 // to where key binding can eat them.
4139
4140 if (setup_active && set_keybnd_active) {
4141 if (ev->data1&4) {
4142 ch = 0; // meaningless, just to get you past the check for -1
4143 joywait = I_GetTime() + 5;
4144 }
4145 if (ev->data1&8) {
4146 ch = 0; // meaningless, just to get you past the check for -1
4147 joywait = I_GetTime() + 5;
4148 }
4149 }
4150
4151 } else {
4152 // Mouse input processing removed
4153
4154 // Process keyboard input
4155
4156 if (ev->type == ev_keydown)
4157 {
4158 ch = ev->data1; // phares 4/11/98:
4159 if (ch == KEYD_RSHIFT) // For chat string processing, need
4160 shiftdown = true; // to know when shift key is up or
4161 } // down so you can get at the !,#,
4162 else if (ev->type == ev_keyup) // etc. keys. Keydowns are allowed
4163 if (ev->data1 == KEYD_RSHIFT) // past this point, but keyups aren't
4164 shiftdown = false; // so we need to note the difference
4165 } // here using the 'shiftdown' boolean.
4166
4167 if (ch == -1)
4168 return false; // we can't use the event here
4169
4170 // Save Game string input
4171
4172 if (saveStringEnter) {
4173 if (ch == key_menu_backspace) // phares 3/7/98
4174 {
4175 if (saveCharIndex > 0)
4176 {
4177 saveCharIndex--;
4178 savegamestrings[saveSlot][saveCharIndex] = 0;
4179 }
4180 }
4181
4182 else if (ch == key_menu_escape) // phares 3/7/98
4183 {
4184 saveStringEnter = 0;
4185 strcpy(&savegamestrings[saveSlot][0],saveOldString);
4186 }
4187
4188 else if (ch == key_menu_enter) // phares 3/7/98
4189 {
4190 saveStringEnter = 0;
4191 if (savegamestrings[saveSlot][0])
4192 M_DoSave(saveSlot);
4193 }
4194
4195 else
4196 {
4197 ch = toupper(ch);
4198 if (ch >= 32 && ch <= 127 &&
4199 saveCharIndex < SAVESTRINGSIZE-1 &&
4200 M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8)
4201 {
4202 savegamestrings[saveSlot][saveCharIndex++] = ch;
4203 savegamestrings[saveSlot][saveCharIndex] = 0;
4204 }
4205 }
4206 return true;
4207 }
4208
4209 // Take care of any messages that need input
4210
4211 if (messageToPrint) {
4212 if (messageNeedsInput == true &&
4213 !(ch == ' ' || ch == 'n' || ch == 'y' || ch == key_escape)) // phares
4214 return false;
4215
4216 menuactive = messageLastMenuActive;
4217 messageToPrint = 0;
4218 if (messageRoutine)
4219 messageRoutine(ch);
4220
4221 menuactive = false;
4222 S_StartSound(NULL,sfx_swtchx);
4223 return true;
4224 }
4225
4226 /* killough 2/22/98: add support for screenshot key:
4227 * cph 2001/02/04: no need for this to be a gameaction, just do it
4228 */
4229 if (ch == key_screenshot)
4230 {
4231 M_ScreenShot ();
4232 // Don't eat the keypress in this case. See sf bug #1843280.
4233 }
4234
4235 // If there is no active menu displayed...
4236
4237 if (!menuactive) { // phares
4238 if (ch == key_autorun) // Autorun // V
4239 {
4240 autorun = !autorun;
4241 return true;
4242 }
4243
4244 if (ch == key_help) // Help key
4245 {
4246 M_StartControlPanel ();
4247
4248 currentMenu = &HelpDef; // killough 10/98: new help screen
4249
4250 itemOn = 0;
4251 S_StartSound(NULL,sfx_swtchn);
4252 return true;
4253 }
4254
4255 if (ch == key_savegame) // Save Game
4256 {
4257 M_StartControlPanel();
4258 S_StartSound(NULL,sfx_swtchn);
4259 M_SaveGame(0);
4260 return true;
4261 }
4262
4263 if (ch == key_loadgame) // Load Game
4264 {
4265 M_StartControlPanel();
4266 S_StartSound(NULL,sfx_swtchn);
4267 M_LoadGame(0);
4268 return true;
4269 }
4270
4271 if (ch == key_soundvolume) // Sound Volume
4272 {
4273 M_StartControlPanel ();
4274 currentMenu = &SoundDef;
4275 itemOn = sfx_vol;
4276 S_StartSound(NULL,sfx_swtchn);
4277 return true;
4278 }
4279
4280 if (ch == key_quicksave) // Quicksave
4281 {
4282 S_StartSound(NULL,sfx_swtchn);
4283 M_QuickSave();
4284 return true;
4285 }
4286
4287 if (ch == key_endgame) // End game
4288 {
4289 S_StartSound(NULL,sfx_swtchn);
4290 M_EndGame(0);
4291 return true;
4292 }
4293
4294 if (ch == key_messages) // Toggle messages
4295 {
4296 M_ChangeMessages(0);
4297 S_StartSound(NULL,sfx_swtchn);
4298 return true;
4299 }
4300
4301 if (ch == key_quickload) // Quickload
4302 {
4303 S_StartSound(NULL,sfx_swtchn);
4304 M_QuickLoad();
4305 return true;
4306 }
4307
4308 if (ch == key_quit) // Quit DOOM
4309 {
4310 S_StartSound(NULL,sfx_swtchn);
4311 M_QuitDOOM(0);
4312 return true;
4313 }
4314
4315 if (ch == key_gamma) // gamma toggle
4316 {
4317 usegamma++;
4318 if (usegamma > 4)
4319 usegamma = 0;
4320 players[consoleplayer].message =
4321 usegamma == 0 ? s_GAMMALVL0 :
4322 usegamma == 1 ? s_GAMMALVL1 :
4323 usegamma == 2 ? s_GAMMALVL2 :
4324 usegamma == 3 ? s_GAMMALVL3 :
4325 s_GAMMALVL4;
4326 V_SetPalette(0);
4327 return true;
4328 }
4329
4330
4331 if (ch == key_zoomout) // zoom out
4332 {
4333 if ((automapmode & am_active) || chat_on)
4334 return false;
4335 M_SizeDisplay(0);
4336 S_StartSound(NULL,sfx_stnmov);
4337 return true;
4338 }
4339
4340 if (ch == key_zoomin) // zoom in
4341 { // jff 2/23/98
4342 if ((automapmode & am_active) || chat_on) // allow
4343 return false; // key_hud==key_zoomin
4344 M_SizeDisplay(1); // ^
4345 S_StartSound(NULL,sfx_stnmov); // |
4346 return true; // phares
4347 }
4348
4349 if (ch == key_hud) // heads-up mode
4350 {
4351 if ((automapmode & am_active) || chat_on) // jff 2/22/98
4352 return false; // HUD mode control
4353 if (screenSize<8) // function on default F5
4354 while (screenSize<8 || !hud_displayed) // make hud visible
4355 M_SizeDisplay(1); // when configuring it
4356 else
4357 {
4358 hud_displayed = 1; //jff 3/3/98 turn hud on
4359 hud_active = (hud_active+1)%3; // cycle hud_active
4360 if (!hud_active) //jff 3/4/98 add distributed
4361 {
4362 hud_distributed = !hud_distributed; // to cycle
4363 HU_MoveHud(); //jff 3/9/98 move it now to avoid glitch
4364 }
4365 }
4366 return true;
4367 }
4368
4369 /* killough 10/98: allow key shortcut into Setup menu */
4370 if (ch == key_setup) {
4371 M_StartControlPanel();
4372 S_StartSound(NULL,sfx_swtchn);
4373 M_SetupNextMenu(&SetupDef);
4374 return true;
4375 }
4376 }
4377 // Pop-up Main menu?
4378
4379 if (!menuactive)
4380 {
4381 if (ch == key_escape) // phares
4382 {
4383 M_StartControlPanel ();
4384 S_StartSound(NULL,sfx_swtchn);
4385 return true;
4386 }
4387 return false;
4388 }
4389
4390 // phares 3/26/98 - 4/11/98:
4391 // Setup screen key processing
4392
4393 if (setup_active) {
4394 setup_menu_t* ptr1= current_setup_menu + set_menu_itemon;
4395 setup_menu_t* ptr2 = NULL;
4396
4397 // phares 4/19/98:
4398 // Catch the response to the 'reset to default?' verification
4399 // screen
4400
4401 if (default_verify)
4402 {
4403 if (toupper(ch) == 'Y') {
4404 M_ResetDefaults();
4405 default_verify = false;
4406 M_SelectDone(ptr1);
4407 }
4408 else if (toupper(ch) == 'N') {
4409 default_verify = false;
4410 M_SelectDone(ptr1);
4411 }
4412 return true;
4413 }
4414
4415 // Common processing for some items
4416
4417 if (setup_select) { // changing an entry
4418 if (ch == key_menu_escape) // Exit key = no change
4419 {
4420 M_SelectDone(ptr1); // phares 4/17/98
4421 setup_gather = false; // finished gathering keys, if any
4422 return true;
4423 }
4424
4425 if (ptr1->m_flags & S_YESNO) // yes or no setting?
4426 {
4427 if (ch == key_menu_enter) {
4428 *ptr1->var.def->location.pi = !*ptr1->var.def->location.pi; // killough 8/15/98
4429
4430 // phares 4/14/98:
4431 // If not in demoplayback, demorecording, or netgame,
4432 // and there's a second variable in var2, set that
4433 // as well
4434
4435 // killough 8/15/98: add warning messages
4436
4437 if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
4438 warn_about_changes(ptr1->m_flags & // killough 10/98
4439 (S_LEVWARN | S_PRGWARN));
4440 else
4441 M_UpdateCurrent(ptr1->var.def);
4442
4443 if (ptr1->action) // killough 10/98
4444 ptr1->action();
4445 }
4446 M_SelectDone(ptr1); // phares 4/17/98
4447 return true;
4448 }
4449
4450 if (ptr1->m_flags & S_CRITEM)
4451 {
4452 if (ch != key_menu_enter)
4453 {
4454 ch -= 0x30; // out of ascii
4455 if (ch < 0 || ch > 9)
4456 return true; // ignore
4457 *ptr1->var.def->location.pi = ch;
4458 }
4459 if (ptr1->action) // killough 10/98
4460 ptr1->action();
4461 M_SelectDone(ptr1); // phares 4/17/98
4462 return true;
4463 }
4464
4465 if (ptr1->m_flags & S_NUM) // number?
4466 {
4467 if (setup_gather) { // gathering keys for a value?
4468 /* killough 10/98: Allow negatives, and use a more
4469 * friendly input method (e.g. don't clear value early,
4470 * allow backspace, and return to original value if bad
4471 * value is entered).
4472 */
4473 if (ch == key_menu_enter) {
4474 if (gather_count) { // Any input?
4475 int value;
4476
4477 gather_buffer[gather_count] = 0;
4478 value = atoi(gather_buffer); // Integer value
4479
4480 if ((ptr1->var.def->minvalue != UL &&
4481 value < ptr1->var.def->minvalue) ||
4482 (ptr1->var.def->maxvalue != UL &&
4483 value > ptr1->var.def->maxvalue))
4484 warn_about_changes(S_BADVAL);
4485 else {
4486 *ptr1->var.def->location.pi = value;
4487
4488 /* killough 8/9/98: fix numeric vars
4489 * killough 8/15/98: add warning message
4490 */
4491 if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
4492 warn_about_changes(ptr1->m_flags &
4493 (S_LEVWARN | S_PRGWARN));
4494 else
4495 M_UpdateCurrent(ptr1->var.def);
4496
4497 if (ptr1->action) // killough 10/98
4498 ptr1->action();
4499 }
4500 }
4501 M_SelectDone(ptr1); // phares 4/17/98
4502 setup_gather = false; // finished gathering keys
4503 return true;
4504 }
4505
4506 if (ch == key_menu_backspace && gather_count) {
4507 gather_count--;
4508 return true;
4509 }
4510
4511 if (gather_count >= MAXGATHER)
4512 return true;
4513
4514 if (!isdigit(ch) && ch != '-')
4515 return true; // ignore
4516
4517 /* killough 10/98: character-based numerical input */
4518 gather_buffer[gather_count++] = ch;
4519 }
4520 return true;
4521 }
4522
4523 if (ptr1->m_flags & S_CHOICE) // selection of choices?
4524 {
4525 if (ch == key_menu_left) {
4526 if (ptr1->var.def->type == def_int) {
4527 int value = *ptr1->var.def->location.pi;
4528
4529 value = value - 1;
4530 if ((ptr1->var.def->minvalue != UL &&
4531 value < ptr1->var.def->minvalue))
4532 value = ptr1->var.def->minvalue;
4533 if ((ptr1->var.def->maxvalue != UL &&
4534 value > ptr1->var.def->maxvalue))
4535 value = ptr1->var.def->maxvalue;
4536 if (*ptr1->var.def->location.pi != value)
4537 S_StartSound(NULL,sfx_pstop);
4538 *ptr1->var.def->location.pi = value;
4539 }
4540 if (ptr1->var.def->type == def_str) {
4541 int old_value, value;
4542
4543 old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz,
4544 ptr1->selectstrings);
4545 value = old_value - 1;
4546 if (value < 0)
4547 value = 0;
4548 if (old_value != value)
4549 S_StartSound(NULL,sfx_pstop);
4550 *ptr1->var.def->location.ppsz = ptr1->selectstrings[value];
4551 }
4552 }
4553 if (ch == key_menu_right) {
4554 if (ptr1->var.def->type == def_int) {
4555 int value = *ptr1->var.def->location.pi;
4556
4557 value = value + 1;
4558 if ((ptr1->var.def->minvalue != UL &&
4559 value < ptr1->var.def->minvalue))
4560 value = ptr1->var.def->minvalue;
4561 if ((ptr1->var.def->maxvalue != UL &&
4562 value > ptr1->var.def->maxvalue))
4563 value = ptr1->var.def->maxvalue;
4564 if (*ptr1->var.def->location.pi != value)
4565 S_StartSound(NULL,sfx_pstop);
4566 *ptr1->var.def->location.pi = value;
4567 }
4568 if (ptr1->var.def->type == def_str) {
4569 int old_value, value;
4570
4571 old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz,
4572 ptr1->selectstrings);
4573 value = old_value + 1;
4574 if (ptr1->selectstrings[value] == NULL)
4575 value = old_value;
4576 if (old_value != value)
4577 S_StartSound(NULL,sfx_pstop);
4578 *ptr1->var.def->location.ppsz = ptr1->selectstrings[value];
4579 }
4580 }
4581 if (ch == key_menu_enter) {
4582 // phares 4/14/98:
4583 // If not in demoplayback, demorecording, or netgame,
4584 // and there's a second variable in var2, set that
4585 // as well
4586
4587 // killough 8/15/98: add warning messages
4588
4589 if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
4590 warn_about_changes(ptr1->m_flags & // killough 10/98
4591 (S_LEVWARN | S_PRGWARN));
4592 else
4593 M_UpdateCurrent(ptr1->var.def);
4594
4595 if (ptr1->action) // killough 10/98
4596 ptr1->action();
4597 M_SelectDone(ptr1); // phares 4/17/98
4598 }
4599 return true;
4600 }
4601
4602 }
4603
4604 // Key Bindings
4605
4606 if (set_keybnd_active) // on a key binding setup screen
4607 if (setup_select) // incoming key or button gets bound
4608 {
4609 if (ev->type == ev_joystick)
4610 {
4611 int oldbutton,group;
4612 boolean search = true;
4613
4614 if (!ptr1->m_joy)
4615 return true; // not a legal action here (yet)
4616
4617 // see if the button is already bound elsewhere. if so, you
4618 // have to swap bindings so the action where it's currently
4619 // bound doesn't go dead. Since there is more than one
4620 // keybinding screen, you have to search all of them for
4621 // any duplicates. You're only interested in the items
4622 // that belong to the same group as the one you're changing.
4623
4624 oldbutton = *ptr1->m_joy;
4625 group = ptr1->m_group;
4626 if (ev->data1 & 1)
4627 ch = 0;
4628 else if (ev->data1 & 2)
4629 ch = 1;
4630 else if (ev->data1 & 4)
4631 ch = 2;
4632 else if (ev->data1 & 8)
4633 ch = 3;
4634 else
4635 return true;
4636 for (i = 0 ; keys_settings[i] && search ; i++)
4637 for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
4638 if (ptr2->m_group == group && ptr1 != ptr2)
4639 if (ptr2->m_flags & S_KEY && ptr2->m_joy)
4640 if (*ptr2->m_joy == ch)
4641 {
4642 *ptr2->m_joy = oldbutton;
4643 search = false;
4644 break;
4645 }
4646 *ptr1->m_joy = ch;
4647 }
4648 else if (ev->type == ev_mouse)
4649 {
4650 int i,oldbutton,group;
4651 boolean search = true;
4652
4653 if (!ptr1->m_mouse)
4654 return true; // not a legal action here (yet)
4655
4656 // see if the button is already bound elsewhere. if so, you
4657 // have to swap bindings so the action where it's currently
4658 // bound doesn't go dead. Since there is more than one
4659 // keybinding screen, you have to search all of them for
4660 // any duplicates. You're only interested in the items
4661 // that belong to the same group as the one you're changing.
4662
4663 oldbutton = *ptr1->m_mouse;
4664 group = ptr1->m_group;
4665 if (ev->data1 & 1)
4666 ch = 0;
4667 else if (ev->data1 & 2)
4668 ch = 1;
4669 else if (ev->data1 & 4)
4670 ch = 2;
4671 else
4672 return true;
4673 for (i = 0 ; keys_settings[i] && search ; i++)
4674 for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
4675 if (ptr2->m_group == group && ptr1 != ptr2)
4676 if (ptr2->m_flags & S_KEY && ptr2->m_mouse)
4677 if (*ptr2->m_mouse == ch)
4678 {
4679 *ptr2->m_mouse = oldbutton;
4680 search = false;
4681 break;
4682 }
4683 *ptr1->m_mouse = ch;
4684 }
4685 else // keyboard key
4686 {
4687 int i,oldkey,group;
4688 boolean search = true;
4689
4690 // see if 'ch' is already bound elsewhere. if so, you have
4691 // to swap bindings so the action where it's currently
4692 // bound doesn't go dead. Since there is more than one
4693 // keybinding screen, you have to search all of them for
4694 // any duplicates. You're only interested in the items
4695 // that belong to the same group as the one you're changing.
4696
4697 // if you find that you're trying to swap with an action
4698 // that has S_KEEP set, you can't bind ch; it's already
4699 // bound to that S_KEEP action, and that action has to
4700 // keep that key.
4701
4702 oldkey = *ptr1->var.m_key;
4703 group = ptr1->m_group;
4704 for (i = 0 ; keys_settings[i] && search ; i++)
4705 for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
4706 if (ptr2->m_flags & (S_KEY|S_KEEP) &&
4707 ptr2->m_group == group &&
4708 ptr1 != ptr2)
4709 if (*ptr2->var.m_key == ch)
4710 {
4711 if (ptr2->m_flags & S_KEEP)
4712 return true; // can't have it!
4713 *ptr2->var.m_key = oldkey;
4714 search = false;
4715 break;
4716 }
4717 *ptr1->var.m_key = ch;
4718 }
4719
4720 M_SelectDone(ptr1); // phares 4/17/98
4721 return true;
4722 }
4723
4724 // Weapons
4725
4726 if (set_weapon_active) // on the weapons setup screen
4727 if (setup_select) // changing an entry
4728 {
4729 if (ch != key_menu_enter)
4730 {
4731 ch -= '0'; // out of ascii
4732 if (ch < 1 || ch > 9)
4733 return true; // ignore
4734
4735 // Plasma and BFG don't exist in shareware
4736 // killough 10/98: allow it anyway, since this
4737 // isn't the game itself, just setting preferences
4738
4739 // see if 'ch' is already assigned elsewhere. if so,
4740 // you have to swap assignments.
4741
4742 // killough 11/98: simplified
4743
4744 for (i = 0; (ptr2 = weap_settings[i]); i++)
4745 for (; !(ptr2->m_flags & S_END); ptr2++)
4746 if (ptr2->m_flags & S_WEAP &&
4747 *ptr2->var.def->location.pi == ch && ptr1 != ptr2)
4748 {
4749 *ptr2->var.def->location.pi = *ptr1->var.def->location.pi;
4750 goto end;
4751 }
4752 end:
4753 *ptr1->var.def->location.pi = ch;
4754 }
4755
4756 M_SelectDone(ptr1); // phares 4/17/98
4757 return true;
4758 }
4759
4760 // Automap
4761
4762 if (set_auto_active) // on the automap setup screen
4763 if (setup_select) // incoming key
4764 {
4765 if (ch == key_menu_down)
4766 {
4767 if (++color_palette_y == 16)
4768 color_palette_y = 0;
4769 S_StartSound(NULL,sfx_itemup);
4770 return true;
4771 }
4772
4773 if (ch == key_menu_up)
4774 {
4775 if (--color_palette_y < 0)
4776 color_palette_y = 15;
4777 S_StartSound(NULL,sfx_itemup);
4778 return true;
4779 }
4780
4781 if (ch == key_menu_left)
4782 {
4783 if (--color_palette_x < 0)
4784 color_palette_x = 15;
4785 S_StartSound(NULL,sfx_itemup);
4786 return true;
4787 }
4788
4789 if (ch == key_menu_right)
4790 {
4791 if (++color_palette_x == 16)
4792 color_palette_x = 0;
4793 S_StartSound(NULL,sfx_itemup);
4794 return true;
4795 }
4796
4797 if (ch == key_menu_enter)
4798 {
4799 *ptr1->var.def->location.pi = color_palette_x + 16*color_palette_y;
4800 M_SelectDone(ptr1); // phares 4/17/98
4801 colorbox_active = false;
4802 return true;
4803 }
4804 }
4805
4806 // killough 10/98: consolidate handling into one place:
4807 if (setup_select &&
4808 set_enemy_active | set_general_active | set_chat_active |
4809 set_mess_active | set_status_active | set_compat_active)
4810 {
4811 if (ptr1->m_flags & S_STRING) // creating/editing a string?
4812 {
4813 if (ch == key_menu_backspace) // backspace and DEL
4814 {
4815 if (chat_string_buffer[chat_index] == 0)
4816 {
4817 if (chat_index > 0)
4818 chat_string_buffer[--chat_index] = 0;
4819 }
4820 // shift the remainder of the text one char left
4821 else
4822 strcpy(&chat_string_buffer[chat_index],
4823 &chat_string_buffer[chat_index+1]);
4824 }
4825 else if (ch == key_menu_left) // move cursor left
4826 {
4827 if (chat_index > 0)
4828 chat_index--;
4829 }
4830 else if (ch == key_menu_right) // move cursor right
4831 {
4832 if (chat_string_buffer[chat_index] != 0)
4833 chat_index++;
4834 }
4835 else if ((ch == key_menu_enter) ||
4836 (ch == key_menu_escape))
4837 {
4838 *ptr1->var.def->location.ppsz = chat_string_buffer;
4839 M_SelectDone(ptr1); // phares 4/17/98
4840 }
4841
4842 // Adding a char to the text. Has to be a printable
4843 // char, and you can't overrun the buffer. If the
4844 // chat string gets larger than what the screen can hold,
4845 // it is dealt with when the string is drawn (above).
4846
4847 else if ((ch >= 32) && (ch <= 126))
4848 if ((chat_index+1) < CHAT_STRING_BFR_SIZE)
4849 {
4850 if (shiftdown)
4851 ch = shiftxform[ch];
4852 if (chat_string_buffer[chat_index] == 0)
4853 {
4854 chat_string_buffer[chat_index++] = ch;
4855 chat_string_buffer[chat_index] = 0;
4856 }
4857 else
4858 chat_string_buffer[chat_index++] = ch;
4859 }
4860 return true;
4861 }
4862
4863 M_SelectDone(ptr1); // phares 4/17/98
4864 return true;
4865 }
4866
4867 // Not changing any items on the Setup screens. See if we're
4868 // navigating the Setup menus or selecting an item to change.
4869
4870 if (ch == key_menu_down)
4871 {
4872 ptr1->m_flags &= ~S_HILITE; // phares 4/17/98
4873 do
4874 if (ptr1->m_flags & S_END)
4875 {
4876 set_menu_itemon = 0;
4877 ptr1 = current_setup_menu;
4878 }
4879 else
4880 {
4881 set_menu_itemon++;
4882 ptr1++;
4883 }
4884 while (ptr1->m_flags & S_SKIP);
4885 M_SelectDone(ptr1); // phares 4/17/98
4886 return true;
4887 }
4888
4889 if (ch == key_menu_up)
4890 {
4891 ptr1->m_flags &= ~S_HILITE; // phares 4/17/98
4892 do
4893 {
4894 if (set_menu_itemon == 0)
4895 do
4896 set_menu_itemon++;
4897 while(!((current_setup_menu + set_menu_itemon)->m_flags & S_END));
4898 set_menu_itemon--;
4899 }
4900 while((current_setup_menu + set_menu_itemon)->m_flags & S_SKIP);
4901 M_SelectDone(current_setup_menu + set_menu_itemon); // phares 4/17/98
4902 return true;
4903 }
4904
4905 if (ch == key_menu_enter)
4906 {
4907 int flags = ptr1->m_flags;
4908
4909 // You've selected an item to change. Highlight it, post a new
4910 // message about what to do, and get ready to process the
4911 // change.
4912 //
4913 // killough 10/98: use friendlier char-based input buffer
4914
4915 if (flags & S_NUM)
4916 {
4917 setup_gather = true;
4918 print_warning_about_changes = false;
4919 gather_count = 0;
4920 }
4921 else if (flags & S_COLOR)
4922 {
4923 int color = *ptr1->var.def->location.pi;
4924
4925 if (color < 0 || color > 255) // range check the value
4926 color = 0; // 'no show' if invalid
4927
4928 color_palette_x = *ptr1->var.def->location.pi & 15;
4929 color_palette_y = *ptr1->var.def->location.pi >> 4;
4930 colorbox_active = true;
4931 }
4932 else if (flags & S_STRING)
4933 {
4934 // copy chat string into working buffer; trim if needed.
4935 // free the old chat string memory and replace it with
4936 // the (possibly larger) new memory for editing purposes
4937 //
4938 // killough 10/98: fix bugs, simplify
4939
4940 chat_string_buffer = malloc(CHAT_STRING_BFR_SIZE);
4941 strncpy(chat_string_buffer,
4942 *ptr1->var.def->location.ppsz, CHAT_STRING_BFR_SIZE);
4943
4944 // guarantee null delimiter
4945 chat_string_buffer[CHAT_STRING_BFR_SIZE-1] = 0;
4946
4947 // set chat table pointer to working buffer
4948 // and free old string's memory.
4949
4950 free((char*)*ptr1->var.def->location.ppsz);
4951 *ptr1->var.def->location.ppsz = chat_string_buffer;
4952 chat_index = 0; // current cursor position in chat_string_buffer
4953 }
4954 else if (flags & S_RESET)
4955 default_verify = true;
4956
4957 ptr1->m_flags |= S_SELECT;
4958 setup_select = true;
4959 S_StartSound(NULL,sfx_itemup);
4960 return true;
4961 }
4962
4963 if ((ch == key_menu_escape) || (ch == key_menu_backspace))
4964 {
4965 if (ch == key_menu_escape) // Clear all menus
4966 M_ClearMenus();
4967 else // key_menu_backspace = return to Setup Menu
4968 if (currentMenu->prevMenu)
4969 {
4970 currentMenu = currentMenu->prevMenu;
4971 itemOn = currentMenu->lastOn;
4972 S_StartSound(NULL,sfx_swtchn);
4973 }
4974 ptr1->m_flags &= ~(S_HILITE|S_SELECT);// phares 4/19/98
4975 setup_active = false;
4976 set_keybnd_active = false;
4977 set_weapon_active = false;
4978 set_status_active = false;
4979 set_auto_active = false;
4980 set_enemy_active = false;
4981 set_mess_active = false;
4982 set_chat_active = false;
4983 colorbox_active = false;
4984 default_verify = false; // phares 4/19/98
4985 set_general_active = false; // killough 10/98
4986 set_compat_active = false; // killough 10/98
4987 HU_Start(); // catch any message changes // phares 4/19/98
4988 S_StartSound(NULL,sfx_swtchx);
4989 return true;
4990 }
4991
4992 // Some setup screens may have multiple screens.
4993 // When there are multiple screens, m_prev and m_next items need to
4994 // be placed on the appropriate screen tables so the user can
4995 // move among the screens using the left and right arrow keys.
4996 // The m_var1 field contains a pointer to the appropriate screen
4997 // to move to.
4998
4999 if (ch == key_menu_left)
5000 {
5001 ptr2 = ptr1;
5002 do
5003 {
5004 ptr2++;
5005 if (ptr2->m_flags & S_PREV)
5006 {
5007 ptr1->m_flags &= ~S_HILITE;
5008 mult_screens_index--;
5009 current_setup_menu = ptr2->var.menu;
5010 set_menu_itemon = 0;
5011 print_warning_about_changes = false; // killough 10/98
5012 while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP);
5013 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
5014 S_StartSound(NULL,sfx_pstop); // killough 10/98
5015 return true;
5016 }
5017 }
5018 while (!(ptr2->m_flags & S_END));
5019 }
5020
5021 if (ch == key_menu_right)
5022 {
5023 ptr2 = ptr1;
5024 do
5025 {
5026 ptr2++;
5027 if (ptr2->m_flags & S_NEXT)
5028 {
5029 ptr1->m_flags &= ~S_HILITE;
5030 mult_screens_index++;
5031 current_setup_menu = ptr2->var.menu;
5032 set_menu_itemon = 0;
5033 print_warning_about_changes = false; // killough 10/98
5034 while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP);
5035 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
5036 S_StartSound(NULL,sfx_pstop); // killough 10/98
5037 return true;
5038 }
5039 }
5040 while (!(ptr2->m_flags & S_END));
5041 }
5042
5043 } // End of Setup Screen processing
5044
5045 // From here on, these navigation keys are used on the BIG FONT menus
5046 // like the Main Menu.
5047
5048 if (ch == key_menu_down) // phares 3/7/98
5049 {
5050 do
5051 {
5052 if (itemOn+1 > currentMenu->numitems-1)
5053 itemOn = 0;
5054 else
5055 itemOn++;
5056 S_StartSound(NULL,sfx_pstop);
5057 }
5058 while(currentMenu->menuitems[itemOn].status==-1);
5059 return true;
5060 }
5061
5062 if (ch == key_menu_up) // phares 3/7/98
5063 {
5064 do
5065 {
5066 if (!itemOn)
5067 itemOn = currentMenu->numitems-1;
5068 else
5069 itemOn--;
5070 S_StartSound(NULL,sfx_pstop);
5071 }
5072 while(currentMenu->menuitems[itemOn].status==-1);
5073 return true;
5074 }
5075
5076 if (ch == key_menu_left) // phares 3/7/98
5077 {
5078 if (currentMenu->menuitems[itemOn].routine &&
5079 currentMenu->menuitems[itemOn].status == 2)
5080 {
5081 S_StartSound(NULL,sfx_stnmov);
5082 currentMenu->menuitems[itemOn].routine(0);
5083 }
5084 return true;
5085 }
5086
5087 if (ch == key_menu_right) // phares 3/7/98
5088 {
5089 if (currentMenu->menuitems[itemOn].routine &&
5090 currentMenu->menuitems[itemOn].status == 2)
5091 {
5092 S_StartSound(NULL,sfx_stnmov);
5093 currentMenu->menuitems[itemOn].routine(1);
5094 }
5095 return true;
5096 }
5097
5098 if (ch == key_menu_enter) // phares 3/7/98
5099 {
5100 if (currentMenu->menuitems[itemOn].routine &&
5101 currentMenu->menuitems[itemOn].status)
5102 {
5103 currentMenu->lastOn = itemOn;
5104 if (currentMenu->menuitems[itemOn].status == 2)
5105 {
5106 currentMenu->menuitems[itemOn].routine(1); // right arrow
5107 S_StartSound(NULL,sfx_stnmov);
5108 }
5109 else
5110 {
5111 currentMenu->menuitems[itemOn].routine(itemOn);
5112 S_StartSound(NULL,sfx_pistol);
5113 }
5114 }
5115 //jff 3/24/98 remember last skill selected
5116 // killough 10/98 moved to skill-specific functions
5117 return true;
5118 }
5119
5120 if (ch == key_menu_escape) // phares 3/7/98
5121 {
5122 currentMenu->lastOn = itemOn;
5123 M_ClearMenus ();
5124 S_StartSound(NULL,sfx_swtchx);
5125 return true;
5126 }
5127
5128 if (ch == key_menu_backspace) // phares 3/7/98
5129 {
5130 currentMenu->lastOn = itemOn;
5131
5132 // phares 3/30/98:
5133 // add checks to see if you're in the extended help screens
5134 // if so, stay with the same menu definition, but bump the
5135 // index back one. if the index bumps back far enough ( == 0)
5136 // then you can return to the Read_Thisn menu definitions
5137
5138 if (currentMenu->prevMenu)
5139 {
5140 if (currentMenu == &ExtHelpDef)
5141 {
5142 if (--extended_help_index == 0)
5143 {
5144 currentMenu = currentMenu->prevMenu;
5145 extended_help_index = 1; // reset
5146 }
5147 }
5148 else
5149 currentMenu = currentMenu->prevMenu;
5150 itemOn = currentMenu->lastOn;
5151 S_StartSound(NULL,sfx_swtchn);
5152 }
5153 return true;
5154 }
5155
5156 else
5157 {
5158 for (i = itemOn+1;i < currentMenu->numitems;i++)
5159 if (currentMenu->menuitems[i].alphaKey == ch)
5160 {
5161 itemOn = i;
5162 S_StartSound(NULL,sfx_pstop);
5163 return true;
5164 }
5165 for (i = 0;i <= itemOn;i++)
5166 if (currentMenu->menuitems[i].alphaKey == ch)
5167 {
5168 itemOn = i;
5169 S_StartSound(NULL,sfx_pstop);
5170 return true;
5171 }
5172 }
5173 return false;
5174}
5175
5176//
5177// End of M_Responder
5178//
5179/////////////////////////////////////////////////////////////////////////////
5180
5181/////////////////////////////////////////////////////////////////////////////
5182//
5183// General Routines
5184//
5185// This displays the Main menu and gets the menu screens rolling.
5186// Plus a variety of routines that control the Big Font menu display.
5187// Plus some initialization for game-dependant situations.
5188
5189void M_StartControlPanel (void)
5190{
5191 // intro might call this repeatedly
5192
5193 if (menuactive)
5194 return;
5195
5196 //jff 3/24/98 make default skill menu choice follow -skill or defaultskill
5197 //from command line or config file
5198 //
5199 // killough 10/98:
5200 // Fix to make "always floating" with menu selections, and to always follow
5201 // defaultskill, instead of -skill.
5202
5203 NewDef.lastOn = defaultskill - 1;
5204
5205 default_verify = 0; // killough 10/98
5206 menuactive = 1;
5207 currentMenu = &MainDef; // JDC
5208 itemOn = currentMenu->lastOn; // JDC
5209 print_warning_about_changes = false; // killough 11/98
5210}
5211
5212//
5213// M_Drawer
5214// Called after the view has been rendered,
5215// but before it has been blitted.
5216//
5217// killough 9/29/98: Significantly reformatted source
5218//
5219
5220void M_Drawer (void)
5221{
5222 inhelpscreens = false;
5223
5224 // Horiz. & Vertically center string and print it.
5225 // killough 9/29/98: simplified code, removed 40-character width limit
5226 if (messageToPrint)
5227 {
5228 /* cph - strdup string to writable memory */
5229 char *ms = strdup(messageString);
5230 char *p = ms;
5231
5232 int y = 100 - M_StringHeight(messageString)/2;
5233 while (*p)
5234 {
5235 char *string = p, c;
5236 while ((c = *p) && *p != '\n')
5237 p++;
5238 *p = 0;
5239 M_WriteText(160 - M_StringWidth(string)/2, y, string);
5240 y += hu_font[0].height;
5241 if ((*p = c))
5242 p++;
5243 }
5244 free(ms);
5245 }
5246 else
5247 if (menuactive)
5248 {
5249 int x,y,max,i;
5250
5251 if (currentMenu->routine)
5252 currentMenu->routine(); // call Draw routine
5253
5254 // DRAW MENU
5255
5256 x = currentMenu->x;
5257 y = currentMenu->y;
5258 max = currentMenu->numitems;
5259
5260 for (i=0;i<max;i++)
5261 {
5262 if (currentMenu->menuitems[i].name[0])
5263 V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name,
5264 CR_DEFAULT, VPT_STRETCH);
5265 y += LINEHEIGHT;
5266 }
5267
5268 // DRAW SKULL
5269
5270 // CPhipps - patch drawing updated
5271 V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0,
5272 skullName[whichSkull], CR_DEFAULT, VPT_STRETCH);
5273 }
5274}
5275
5276//
5277// M_ClearMenus
5278//
5279// Called when leaving the menu screens for the real world
5280
5281void M_ClearMenus (void)
5282{
5283 menuactive = 0;
5284 print_warning_about_changes = 0; // killough 8/15/98
5285 default_verify = 0; // killough 10/98
5286
5287 // if (!netgame && usergame && paused)
5288 // sendpause = true;
5289}
5290
5291//
5292// M_SetupNextMenu
5293//
5294void M_SetupNextMenu(menu_t *menudef)
5295{
5296 currentMenu = menudef;
5297 itemOn = currentMenu->lastOn;
5298}
5299
5300/////////////////////////////
5301//
5302// M_Ticker
5303//
5304void M_Ticker (void)
5305{
5306 if (--skullAnimCounter <= 0)
5307 {
5308 whichSkull ^= 1;
5309 skullAnimCounter = 8;
5310 }
5311}
5312
5313/////////////////////////////
5314//
5315// Message Routines
5316//
5317
5318void M_StartMessage (const char* string,void* routine,boolean input)
5319{
5320 messageLastMenuActive = menuactive;
5321 messageToPrint = 1;
5322 messageString = string;
5323 messageRoutine = routine;
5324 messageNeedsInput = input;
5325 menuactive = true;
5326 return;
5327}
5328
5329void M_StopMessage(void)
5330{
5331 menuactive = messageLastMenuActive;
5332 messageToPrint = 0;
5333}
5334
5335/////////////////////////////
5336//
5337// Thermometer Routines
5338//
5339
5340//
5341// M_DrawThermo draws the thermometer graphic for Mouse Sensitivity,
5342// Sound Volume, etc.
5343//
5344// proff/nicolas 09/20/98 -- changed for hi-res
5345// CPhipps - patch drawing updated
5346//
5347void M_DrawThermo(int x,int y,int thermWidth,int thermDot )
5348 {
5349 int xx;
5350 int i;
5351 /*
5352 * Modification By Barry Mead to allow the Thermometer to have vastly
5353 * larger ranges. (the thermWidth parameter can now have a value as
5354 * large as 200. Modified 1-9-2000 Originally I used it to make
5355 * the sensitivity range for the mouse better. It could however also
5356 * be used to improve the dynamic range of music and sound affect
5357 * volume controls for example.
5358 */
5359 int horizScaler; //Used to allow more thermo range for mouse sensitivity.
5360 thermWidth = (thermWidth > 200) ? 200 : thermWidth; //Clamp to 200 max
5361 horizScaler = (thermWidth > 23) ? (200 / thermWidth) : 8; //Dynamic range
5362 xx = x;
5363 V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH);
5364 xx += 8;
5365 for (i=0;i<thermWidth;i++)
5366 {
5367 V_DrawNamePatch(xx, y, 0, "M_THERMM", CR_DEFAULT, VPT_STRETCH);
5368 xx += horizScaler;
5369 }
5370
5371 xx += (8 - horizScaler); /* make the right end look even */
5372
5373 V_DrawNamePatch(xx, y, 0, "M_THERMR", CR_DEFAULT, VPT_STRETCH);
5374 V_DrawNamePatch((x+8)+thermDot*horizScaler,y,0,"M_THERMO",CR_DEFAULT,VPT_STRETCH);
5375 }
5376
5377//
5378// Draw an empty cell in the thermometer
5379//
5380
5381void M_DrawEmptyCell (menu_t* menu,int item)
5382{
5383 // CPhipps - patch drawing updated
5384 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
5385 "M_CELL1", CR_DEFAULT, VPT_STRETCH);
5386}
5387
5388//
5389// Draw a full cell in the thermometer
5390//
5391
5392void M_DrawSelCell (menu_t* menu,int item)
5393{
5394 // CPhipps - patch drawing updated
5395 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
5396 "M_CELL2", CR_DEFAULT, VPT_STRETCH);
5397}
5398
5399/////////////////////////////
5400//
5401// String-drawing Routines
5402//
5403
5404//
5405// Find string width from hu_font chars
5406//
5407
5408int M_StringWidth(const char* string)
5409{
5410 int i, c, w = 0;
5411 for (i = 0;(size_t)i < strlen(string);i++)
5412 w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ?
5413 4 : hu_font[c].width;
5414 return w;
5415}
5416
5417//
5418// Find string height from hu_font chars
5419//
5420
5421int M_StringHeight(const char* string)
5422{
5423 int i, h, height = h = hu_font[0].height;
5424 for (i = 0;string[i];i++) // killough 1/31/98
5425 if (string[i] == '\n')
5426 h += height;
5427 return h;
5428}
5429
5430//
5431// Write a string using the hu_font
5432//
5433void M_WriteText (int x,int y,const char* string)
5434{
5435 int w;
5436 const char* ch;
5437 int c;
5438 int cx;
5439 int cy;
5440
5441 ch = string;
5442 cx = x;
5443 cy = y;
5444
5445 while(1) {
5446 c = *ch++;
5447 if (!c)
5448 break;
5449 if (c == '\n') {
5450 cx = x;
5451 cy += 12;
5452 continue;
5453 }
5454
5455 c = toupper(c) - HU_FONTSTART;
5456 if (c < 0 || c>= HU_FONTSIZE) {
5457 cx += 4;
5458 continue;
5459 }
5460
5461 w = hu_font[c].width;
5462 if (cx+w > SCREENWIDTH)
5463 break;
5464 // proff/nicolas 09/20/98 -- changed for hi-res
5465 // CPhipps - patch drawing updated
5466 V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
5467 cx+=w;
5468 }
5469}
5470
5471/////////////////////////////
5472//
5473// Initialization Routines to take care of one-time setup
5474//
5475
5476// phares 4/08/98:
5477// M_InitHelpScreen() clears the weapons from the HELP
5478// screen that don't exist in this version of the game.
5479
5480void M_InitHelpScreen(void)
5481{
5482 setup_menu_t* src;
5483
5484 src = helpstrings;
5485 while (!(src->m_flags & S_END)) {
5486
5487 if ((strncmp(src->m_text,"PLASMA",6) == 0) && (gamemode == shareware))
5488 src->m_flags = S_SKIP; // Don't show setting or item
5489 if ((strncmp(src->m_text,"BFG",3) == 0) && (gamemode == shareware))
5490 src->m_flags = S_SKIP; // Don't show setting or item
5491 if ((strncmp(src->m_text,"SSG",3) == 0) && (gamemode != commercial))
5492 src->m_flags = S_SKIP; // Don't show setting or item
5493 src++;
5494 }
5495}
5496
5497//
5498// M_Init
5499//
5500void M_Init(void)
5501{
5502 M_InitDefaults(); // killough 11/98
5503 currentMenu = &MainDef;
5504 menuactive = 0;
5505 itemOn = currentMenu->lastOn;
5506 whichSkull = 0;
5507 skullAnimCounter = 10;
5508 screenSize = screenblocks - 3;
5509 messageToPrint = 0;
5510 messageString = NULL;
5511 messageLastMenuActive = menuactive;
5512 quickSaveSlot = -1;
5513
5514 // Here we could catch other version dependencies,
5515 // like HELP1/2, and four episodes.
5516
5517 switch(gamemode)
5518 {
5519 case commercial:
5520 // This is used because DOOM 2 had only one HELP
5521 // page. I use CREDIT as second page now, but
5522 // kept this hack for educational purposes.
5523 MainMenu[readthis] = MainMenu[quitdoom];
5524 MainDef.numitems--;
5525 MainDef.y += 8;
5526 NewDef.prevMenu = &MainDef;
5527 ReadDef1.routine = M_DrawReadThis1;
5528 ReadDef1.x = 330;
5529 ReadDef1.y = 165;
5530 ReadMenu1[0].routine = M_FinishReadThis;
5531 break;
5532 case registered:
5533 // Episode 2 and 3 are handled,
5534 // branching to an ad screen.
5535
5536 // killough 2/21/98: Fix registered Doom help screen
5537 // killough 10/98: moved to second screen, moved up to the top
5538 ReadDef2.y = 15;
5539
5540 case shareware:
5541 // We need to remove the fourth episode.
5542 EpiDef.numitems--;
5543 break;
5544 case retail:
5545 // We are fine.
5546 default:
5547 break;
5548 }
5549
5550 M_InitHelpScreen(); // init the help screen // phares 4/08/98
5551 M_InitExtendedHelp(); // init extended help screens // phares 3/30/98
5552
5553 M_ChangeDemoSmoothTurns();
5554}
5555
5556//
5557// End of General Routines
5558//
5559/////////////////////////////////////////////////////////////////////////////
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Menu widget stuff, episode selection and such.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __M_MENU__
35#define __M_MENU__
36
37#include "d_event.h"
38
39//
40// MENUS
41//
42// Called by main loop,
43// saves config file and calls I_Quit when user exits.
44// Even when the menu is not displayed,
45// this can resize the view and change game parameters.
46// Does all the real work of the menu interaction.
47
48boolean M_Responder (event_t *ev);
49
50// Called by main loop,
51// only used for menu (skull cursor) animation.
52
53void M_Ticker (void);
54
55// Called by main loop,
56// draws the menus directly into the screen buffer.
57
58void M_Drawer (void);
59
60// Called by D_DoomMain,
61// loads the config file.
62
63void M_Init (void);
64
65// Called by intro code to force menu up upon a keypress,
66// does nothing if menu is already up.
67
68void M_StartControlPanel (void);
69
70void M_ForcedLoadGame(const char *msg); // killough 5/15/98: forced loadgames
71
72void M_Trans(void); // killough 11/98: reset translucency
73
74void M_ResetMenu(void); // killough 11/98: reset main menu ordering
75
76void M_DrawCredits(void); // killough 11/98
77
78/* killough 8/15/98: warn about changes not being committed until next game */
79#define warn_about_changes(x) (warning_about_changes=(x), \
80 print_warning_about_changes = 2)
81
82extern int warning_about_changes, print_warning_about_changes;
83
84/****************************
85 *
86 * The following #defines are for the m_flags field of each item on every
87 * Setup Screen. They can be OR'ed together where appropriate
88 */
89
90#define S_HILITE 0x1 // Cursor is sitting on this item
91#define S_SELECT 0x2 // We're changing this item
92#define S_TITLE 0x4 // Title item
93#define S_YESNO 0x8 // Yes or No item
94#define S_CRITEM 0x10 // Message color
95#define S_COLOR 0x20 // Automap color
96#define S_CHAT 0x40 // Chat String
97#define S_RESET 0x80 // Reset to Defaults Button
98#define S_PREV 0x100 // Previous menu exists
99#define S_NEXT 0x200 // Next menu exists
100#define S_KEY 0x400 // Key Binding
101#define S_WEAP 0x800 // Weapon #
102#define S_NUM 0x1000 // Numerical item
103#define S_SKIP 0x2000 // Cursor can't land here
104#define S_KEEP 0x4000 // Don't swap key out
105#define S_END 0x8000 // Last item in list (dummy)
106#define S_LEVWARN 0x10000// killough 8/30/98: Always warn about pending change
107#define S_PRGWARN 0x20000// killough 10/98: Warn about change until next run
108#define S_BADVAL 0x40000// killough 10/98: Warn about bad value
109#define S_FILE 0x80000// killough 10/98: Filenames
110#define S_LEFTJUST 0x100000 // killough 10/98: items which are left-justified
111#define S_CREDIT 0x200000 // killough 10/98: credit
112#define S_BADVID 0x400000 // killough 12/98: video mode change error
113#define S_CHOICE 0x800000 // this item has several values
114
115/* S_SHOWDESC = the set of items whose description should be displayed
116 * S_SHOWSET = the set of items whose setting should be displayed
117 * S_STRING = the set of items whose settings are strings -- killough 10/98:
118 * S_HASDEFPTR = the set of items whose var field points to default array
119 */
120
121#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)
122
123#define S_SHOWSET (S_YESNO|S_CRITEM|S_COLOR|S_CHAT|S_KEY|S_WEAP|S_NUM|S_FILE|S_CHOICE)
124
125#define S_STRING (S_CHAT|S_FILE)
126
127#define S_HASDEFPTR (S_STRING|S_YESNO|S_NUM|S_WEAP|S_COLOR|S_CRITEM|S_CHOICE)
128
129/****************************
130 *
131 * The setup_group enum is used to show which 'groups' keys fall into so
132 * that you can bind a key differently in each 'group'.
133 */
134
135typedef enum {
136 m_null, // Has no meaning; not applicable
137 m_scrn, // A key can not be assigned to more than one action
138 m_map, // in the same group. A key can be assigned to one
139 m_menu, // action in one group, and another action in another.
140} setup_group;
141
142/****************************
143 *
144 * phares 4/17/98:
145 * State definition for each item.
146 * This is the definition of the structure for each setup item. Not all
147 * fields are used by all items.
148 *
149 * A setup screen is defined by an array of these items specific to
150 * that screen.
151 *
152 * killough 11/98:
153 *
154 * Restructured to allow simpler table entries,
155 * and to Xref with defaults[] array in m_misc.c.
156 * Moved from m_menu.c to m_menu.h so that m_misc.c can use it.
157 */
158
159typedef struct setup_menu_s
160{
161 const char *m_text; /* text to display */
162 int m_flags; /* phares 4/17/98: flag bits S_* (defined above) */
163 setup_group m_group; /* Group */
164 short m_x; /* screen x position (left is 0) */
165 short m_y; /* screen y position (top is 0) */
166
167 union /* killough 11/98: The first field is a union of several types */
168 {
169 const void *var; /* generic variable */
170 int *m_key; /* key value, or 0 if not shown */
171 const char *name; /* name */
172 struct default_s *def; /* default[] table entry */
173 struct setup_menu_s *menu; /* next or prev menu */
174 } var;
175
176 int *m_mouse; /* mouse button value, or 0 if not shown */
177 int *m_joy; /* joystick button value, or 0 if not shown */
178 void (*action)(void); /* killough 10/98: function to call after changing */
179 const char **selectstrings; /* list of strings for choice value */
180} setup_menu_t;
181
182#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Main loop menu stuff.
31 * Default Config File.
32 * PCX Screenshots.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40#include <stdio.h>
41#include <errno.h>
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
45#ifdef _MSC_VER
46#include <io.h>
47#endif
48#include <fcntl.h>
49#include <sys/stat.h>
50
51#include "doomstat.h"
52#include "m_argv.h"
53#include "g_game.h"
54#include "m_menu.h"
55#include "am_map.h"
56#include "w_wad.h"
57#include "i_system.h"
58#include "i_sound.h"
59#include "i_video.h"
60#include "v_video.h"
61#include "hu_stuff.h"
62#include "st_stuff.h"
63#include "dstrings.h"
64#include "m_misc.h"
65#include "s_sound.h"
66#include "sounds.h"
67#include "i_joy.h"
68#include "lprintf.h"
69#include "d_main.h"
70#include "r_draw.h"
71#include "r_demo.h"
72#include "r_fps.h"
73
74/* cph - disk icon not implemented */
75static inline void I_BeginRead(void) {}
76static inline void I_EndRead(void) {}
77
78/*
79 * M_WriteFile
80 *
81 * killough 9/98: rewritten to use stdio and to flash disk icon
82 */
83
84boolean M_WriteFile(char const *name, void *source, int length)
85{
86 FILE *fp;
87
88 errno = 0;
89
90 if (!(fp = fopen(name, "wb"))) // Try opening file
91 return 0; // Could not open file for writing
92
93 I_BeginRead(); // Disk icon on
94 length = fwrite(source, 1, length, fp) == (size_t)length; // Write data
95 fclose(fp);
96 I_EndRead(); // Disk icon off
97
98 if (!length) // Remove partially written file
99 remove(name);
100
101 return length;
102}
103
104/*
105 * M_ReadFile
106 *
107 * killough 9/98: rewritten to use stdio and to flash disk icon
108 */
109
110int M_ReadFile(char const *name, byte **buffer)
111{
112 FILE *fp;
113
114 if ((fp = fopen(name, "rb")))
115 {
116 size_t length;
117
118 I_BeginRead();
119 fseek(fp, 0, SEEK_END);
120 length = ftell(fp);
121 fseek(fp, 0, SEEK_SET);
122 *buffer = Z_Malloc(length, PU_STATIC, 0);
123 if (fread(*buffer, 1, length, fp) == length)
124 {
125 fclose(fp);
126 I_EndRead();
127 return length;
128 }
129 fclose(fp);
130 }
131
132 /* cph 2002/08/10 - this used to return 0 on error, but that's ambiguous,
133 * because we could have a legit 0-length file. So make it -1. */
134 return -1;
135}
136
137//
138// DEFAULTS
139//
140
141int usemouse;
142boolean precache = true; /* if true, load all graphics at start */
143
144extern int mousebfire;
145extern int mousebstrafe;
146extern int mousebforward;
147
148extern int viewwidth;
149extern int viewheight;
150#ifdef GL_DOOM
151extern int gl_nearclip;
152extern int gl_colorbuffer_bits;
153extern int gl_depthbuffer_bits;
154extern char *gl_tex_filter_string;
155extern char *gl_tex_format_string;
156extern int gl_drawskys;
157extern int gl_sortsprites;
158extern int gl_use_paletted_texture;
159extern int gl_use_shared_texture_palette;
160extern int gl_sprite_offset;
161#endif
162
163extern int realtic_clock_rate; // killough 4/13/98: adjustable timer
164extern int tran_filter_pct; // killough 2/21/98
165
166extern int screenblocks;
167extern int showMessages;
168
169#ifndef DJGPP
170int mus_pause_opt; // 0 = kill music, 1 = pause, 2 = continue
171#endif
172
173extern const char* chat_macros[];
174
175extern int endoom_mode;
176
177extern const char* S_music_files[]; // cournia
178
179/* cph - Some MBF stuff parked here for now
180 * killough 10/98
181 */
182int map_point_coordinates;
183
184default_t defaults[] =
185{
186 {"Misc settings",{NULL},{0},UL,UL,def_none,ss_none},
187 {"default_compatibility_level",{(int*)&default_compatibility_level},
188 {-1},-1,MAX_COMPATIBILITY_LEVEL-1,
189 def_int,ss_none}, // compatibility level" - CPhipps
190 {"realtic_clock_rate",{&realtic_clock_rate},{100},0,UL,
191 def_int,ss_none}, // percentage of normal speed (35 fps) realtic clock runs at
192 {"max_player_corpse", {&bodyquesize}, {32},-1,UL, // killough 2/8/98
193 def_int,ss_none}, // number of dead bodies in view supported (-1 = no limit)
194 {"flashing_hom",{&flashing_hom},{0},0,1,
195 def_bool,ss_none}, // killough 10/98 - enable flashing HOM indicator
196 {"demo_insurance",{&default_demo_insurance},{2},0,2, // killough 3/31/98
197 def_int,ss_none}, // 1=take special steps ensuring demo sync, 2=only during recordings
198 {"endoom_mode", {&endoom_mode},{5},0,7, // CPhipps - endoom flags
199 def_hex, ss_none}, // 0, +1 for colours, +2 for non-ascii chars, +4 for skip-last-line
200 {"level_precache",{(int*)&precache},{0},0,1,
201 def_bool,ss_none}, // precache level data?
202 {"demo_smoothturns", {&demo_smoothturns}, {0},0,1,
203 def_bool,ss_stat},
204 {"demo_smoothturnsfactor", {&demo_smoothturnsfactor}, {6},1,SMOOTH_PLAYING_MAXFACTOR,
205 def_int,ss_stat},
206
207 {"Files",{NULL},{0},UL,UL,def_none,ss_none},
208 /* cph - MBF-like wad/deh/bex autoload code */
209 {"wadfile_1",{NULL,&wad_files[0]},{0,""},UL,UL,def_str,ss_none},
210 {"wadfile_2",{NULL,&wad_files[1]},{0,""},UL,UL,def_str,ss_none},
211 {"dehfile_1",{NULL,&deh_files[0]},{0,""},UL,UL,def_str,ss_none},
212 {"dehfile_2",{NULL,&deh_files[1]},{0,""},UL,UL,def_str,ss_none},
213
214 {"Game settings",{NULL},{0},UL,UL,def_none,ss_none},
215 {"default_skill",{&defaultskill},{3},1,5, // jff 3/24/98 allow default skill setting
216 def_int,ss_none}, // selects default skill 1=TYTD 2=NTR 3=HMP 4=UV 5=NM
217 {"weapon_recoil",{&default_weapon_recoil},{0},0,1,
218 def_bool,ss_weap, &weapon_recoil},
219 /* killough 10/98 - toggle between SG/SSG and Fist/Chainsaw */
220 {"doom_weapon_toggles",{&doom_weapon_toggles}, {1}, 0, 1,
221 def_bool, ss_weap },
222 {"player_bobbing",{&default_player_bobbing},{1},0,1, // phares 2/25/98
223 def_bool,ss_weap, &player_bobbing},
224 {"monsters_remember",{&default_monsters_remember},{1},0,1, // killough 3/1/98
225 def_bool,ss_enem, &monsters_remember},
226 /* MBF AI enhancement options */
227 {"monster_infighting",{&default_monster_infighting}, {1}, 0, 1,
228 def_bool, ss_enem, &monster_infighting},
229 {"monster_backing",{&default_monster_backing}, {0}, 0, 1,
230 def_bool, ss_enem, &monster_backing},
231 {"monster_avoid_hazards",{&default_monster_avoid_hazards}, {1}, 0, 1,
232 def_bool, ss_enem, &monster_avoid_hazards},
233 {"monkeys",{&default_monkeys}, {0}, 0, 1,
234 def_bool, ss_enem, &monkeys},
235 {"monster_friction",{&default_monster_friction}, {1}, 0, 1,
236 def_bool, ss_enem, &monster_friction},
237 {"help_friends",{&default_help_friends}, {1}, 0, 1,
238 def_bool, ss_enem, &help_friends},
239 {"allow_pushers",{&default_allow_pushers},{1},0,1,
240 def_bool,ss_weap, &allow_pushers},
241 {"variable_friction",{&default_variable_friction},{1},0,1,
242 def_bool,ss_weap, &variable_friction},
243#ifdef DOGS
244 {"player_helpers",{&default_dogs}, {0}, 0, 3,
245 def_bool, ss_enem },
246 {"friend_distance",{&default_distfriend}, {128}, 0, 999,
247 def_int, ss_enem, &distfriend},
248 {"dog_jumping",{&default_dog_jumping}, {1}, 0, 1,
249 def_bool, ss_enem, &dog_jumping},
250#endif
251 /* End of MBF AI extras */
252
253 {"sts_always_red",{&sts_always_red},{1},0,1, // no color changes on status bar
254 def_bool,ss_stat},
255 {"sts_pct_always_gray",{&sts_pct_always_gray},{0},0,1, // 2/23/98 chg default
256 def_bool,ss_stat}, // makes percent signs on status bar always gray
257 {"sts_traditional_keys",{&sts_traditional_keys},{0},0,1, // killough 2/28/98
258 def_bool,ss_stat}, // disables doubled card and skull key display on status bar
259 {"show_messages",{&showMessages},{1},0,1,
260 def_bool,ss_none}, // enables message display
261 {"autorun",{&autorun},{0},0,1, // killough 3/6/98: preserve autorun across games
262 def_bool,ss_none},
263
264 {"Compatibility settings",{NULL},{0},UL,UL,def_none,ss_none},
265 {"comp_zombie",{&default_comp[comp_zombie]},{0},0,1,def_bool,ss_comp,&comp[comp_zombie]},
266 {"comp_infcheat",{&default_comp[comp_infcheat]},{0},0,1,def_bool,ss_comp,&comp[comp_infcheat]},
267 {"comp_stairs",{&default_comp[comp_stairs]},{0},0,1,def_bool,ss_comp,&comp[comp_stairs]},
268 {"comp_telefrag",{&default_comp[comp_telefrag]},{0},0,1,def_bool,ss_comp,&comp[comp_telefrag]},
269 {"comp_dropoff",{&default_comp[comp_dropoff]},{0},0,1,def_bool,ss_comp,&comp[comp_dropoff]},
270 {"comp_falloff",{&default_comp[comp_falloff]},{0},0,1,def_bool,ss_comp,&comp[comp_falloff]},
271 {"comp_staylift",{&default_comp[comp_staylift]},{0},0,1,def_bool,ss_comp,&comp[comp_staylift]},
272 {"comp_doorstuck",{&default_comp[comp_doorstuck]},{0},0,1,def_bool,ss_comp,&comp[comp_doorstuck]},
273 {"comp_pursuit",{&default_comp[comp_pursuit]},{0},0,1,def_bool,ss_comp,&comp[comp_pursuit]},
274 {"comp_vile",{&default_comp[comp_vile]},{0},0,1,def_bool,ss_comp,&comp[comp_vile]},
275 {"comp_pain",{&default_comp[comp_pain]},{0},0,1,def_bool,ss_comp,&comp[comp_pain]},
276 {"comp_skull",{&default_comp[comp_skull]},{0},0,1,def_bool,ss_comp,&comp[comp_skull]},
277 {"comp_blazing",{&default_comp[comp_blazing]},{0},0,1,def_bool,ss_comp,&comp[comp_blazing]},
278 {"comp_doorlight",{&default_comp[comp_doorlight]},{0},0,1,def_bool,ss_comp,&comp[comp_doorlight]},
279 {"comp_god",{&default_comp[comp_god]},{0},0,1,def_bool,ss_comp,&comp[comp_god]},
280 {"comp_skymap",{&default_comp[comp_skymap]},{0},0,1,def_bool,ss_comp,&comp[comp_skymap]},
281 {"comp_floors",{&default_comp[comp_floors]},{0},0,1,def_bool,ss_comp,&comp[comp_floors]},
282 {"comp_model",{&default_comp[comp_model]},{0},0,1,def_bool,ss_comp,&comp[comp_model]},
283 {"comp_zerotags",{&default_comp[comp_zerotags]},{0},0,1,def_bool,ss_comp,&comp[comp_zerotags]},
284 {"comp_moveblock",{&default_comp[comp_moveblock]},{0},0,1,def_bool,ss_comp,&comp[comp_moveblock]},
285 {"comp_sound",{&default_comp[comp_sound]},{0},0,1,def_bool,ss_comp,&comp[comp_sound]},
286 {"comp_666",{&default_comp[comp_666]},{0},0,1,def_bool,ss_comp,&comp[comp_666]},
287 {"comp_soul",{&default_comp[comp_soul]},{0},0,1,def_bool,ss_comp,&comp[comp_soul]},
288 {"comp_maskedanim",{&default_comp[comp_maskedanim]},{0},0,1,def_bool,ss_comp,&comp[comp_maskedanim]},
289
290 {"Sound settings",{NULL},{0},UL,UL,def_none,ss_none},
291 {"sound_card",{&snd_card},{-1},-1,7, // jff 1/18/98 allow Allegro drivers
292 def_int,ss_none}, // select sounds driver (DOS), -1 is autodetect, 0 is none; in Linux, non-zero enables sound
293 {"music_card",{&mus_card},{-1},-1,9, // to be set, -1 = autodetect
294 def_int,ss_none}, // select music driver (DOS), -1 is autodetect, 0 is none"; in Linux, non-zero enables music
295 {"pitched_sounds",{&pitched_sounds},{0},0,1, // killough 2/21/98
296 def_bool,ss_none}, // enables variable pitch in sound effects (from id's original code)
297 {"samplerate",{&snd_samplerate},{22050},11025,48000, def_int,ss_none},
298 {"sfx_volume",{&snd_SfxVolume},{8},0,15, def_int,ss_none},
299 {"music_volume",{&snd_MusicVolume},{8},0,15, def_int,ss_none},
300 {"mus_pause_opt",{&mus_pause_opt},{2},0,2, // CPhipps - music pausing
301 def_int, ss_none}, // 0 = kill music when paused, 1 = pause music, 2 = let music continue
302 {"snd_channels",{&default_numChannels},{8},1,32,
303 def_int,ss_none}, // number of audio events simultaneously // killough
304
305 {"Video settings",{NULL},{0},UL,UL,def_none,ss_none},
306#ifdef GL_DOOM
307 #ifdef _MSC_VER
308 {"videomode",{NULL, &default_videomode},{0,"gl"},UL,UL,def_str,ss_none},
309 #else
310 {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none},
311 #endif
312#else
313 {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none},
314#endif
315 /* 640x480 default resolution */
316 {"screen_width",{&desired_screenwidth},{640}, 320, MAX_SCREENWIDTH,
317 def_int,ss_none},
318 {"screen_height",{&desired_screenheight},{480},200,MAX_SCREENHEIGHT,
319 def_int,ss_none},
320 {"use_fullscreen",{&use_fullscreen},{1},0,1, /* proff 21/05/2000 */
321 def_bool,ss_none},
322#ifndef DISABLE_DOUBLEBUFFER
323 {"use_doublebuffer",{&use_doublebuffer},{1},0,1, // proff 2001-7-4
324 def_bool,ss_none}, // enable doublebuffer to avoid display tearing (fullscreen)
325#endif
326 {"translucency",{&default_translucency},{1},0,1, // phares
327 def_bool,ss_none}, // enables translucency
328 {"tran_filter_pct",{&tran_filter_pct},{66},0,100, // killough 2/21/98
329 def_int,ss_none}, // set percentage of foreground/background translucency mix
330 {"screenblocks",{&screenblocks},{10},3,11, // killough 2/21/98: default to 10
331 def_int,ss_none},
332 {"usegamma",{&usegamma},{3},0,4, //jff 3/6/98 fix erroneous upper limit in range
333 def_int,ss_none}, // gamma correction level // killough 1/18/98
334 {"uncapped_framerate", {&movement_smooth}, {0},0,1,
335 def_bool,ss_stat},
336 {"filter_wall",{(int*)&drawvars.filterwall},{RDRAW_FILTER_POINT},
337 RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
338 {"filter_floor",{(int*)&drawvars.filterfloor},{RDRAW_FILTER_POINT},
339 RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
340 {"filter_sprite",{(int*)&drawvars.filtersprite},{RDRAW_FILTER_POINT},
341 RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
342 {"filter_z",{(int*)&drawvars.filterz},{RDRAW_FILTER_POINT},
343 RDRAW_FILTER_POINT, RDRAW_FILTER_LINEAR, def_int,ss_none},
344 {"filter_patch",{(int*)&drawvars.filterpatch},{RDRAW_FILTER_POINT},
345 RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
346 {"filter_threshold",{(int*)&drawvars.mag_threshold},{49152},
347 0, UL, def_int,ss_none},
348 {"sprite_edges",{(int*)&drawvars.sprite_edges},{RDRAW_MASKEDCOLUMNEDGE_SQUARE},
349 RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none},
350 {"patch_edges",{(int*)&drawvars.patch_edges},{RDRAW_MASKEDCOLUMNEDGE_SQUARE},
351 RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none},
352
353#ifdef GL_DOOM
354 {"OpenGL settings",{NULL},{0},UL,UL,def_none,ss_none},
355 {"gl_nearclip",{&gl_nearclip},{5},0,UL,
356 def_int,ss_none}, /* near clipping plane pos */
357 {"gl_colorbuffer_bits",{&gl_colorbuffer_bits},{16},16,32,
358 def_int,ss_none},
359 {"gl_depthbuffer_bits",{&gl_depthbuffer_bits},{16},16,32,
360 def_int,ss_none},
361 {"gl_tex_filter_string", {NULL,&gl_tex_filter_string}, {0,"GL_LINEAR"},UL,UL,
362 def_str,ss_none},
363 {"gl_tex_format_string", {NULL,&gl_tex_format_string}, {0,"GL_RGB5_A1"},UL,UL,
364 def_str,ss_none},
365 {"gl_drawskys",{&gl_drawskys},{1},0,1,
366 def_bool,ss_none},
367 {"gl_sortsprites",{&gl_sortsprites},{1},0,1,
368 def_bool,ss_none},
369 {"gl_use_paletted_texture",{&gl_use_paletted_texture},{0},0,1,
370 def_bool,ss_none},
371 {"gl_use_shared_texture_palette",{&gl_use_shared_texture_palette},{0},0,1,
372 def_bool,ss_none},
373#ifdef GL_DOOM
374 {"gl_sprite_offset",{&gl_sprite_offset},{0}, 0, 5,
375 def_int,ss_none}, // amount to bring items out of floor (GL) Mead 8/13/03
376#endif
377#endif
378
379 {"Mouse settings",{NULL},{0},UL,UL,def_none,ss_none},
380 {"use_mouse",{&usemouse},{1},0,1,
381 def_bool,ss_none}, // enables use of mouse with DOOM
382 //jff 4/3/98 allow unlimited sensitivity
383 {"mouse_sensitivity_horiz",{&mouseSensitivity_horiz},{10},0,UL,
384 def_int,ss_none}, /* adjust horizontal (x) mouse sensitivity killough/mead */
385 //jff 4/3/98 allow unlimited sensitivity
386 {"mouse_sensitivity_vert",{&mouseSensitivity_vert},{10},0,UL,
387 def_int,ss_none}, /* adjust vertical (y) mouse sensitivity killough/mead */
388 //jff 3/8/98 allow -1 in mouse bindings to disable mouse function
389 {"mouseb_fire",{&mousebfire},{0},-1,MAX_MOUSEB,
390 def_int,ss_keys}, // mouse button number to use for fire
391 {"mouseb_strafe",{&mousebstrafe},{1},-1,MAX_MOUSEB,
392 def_int,ss_keys}, // mouse button number to use for strafing
393 {"mouseb_forward",{&mousebforward},{2},-1,MAX_MOUSEB,
394 def_int,ss_keys}, // mouse button number to use for forward motion
395 //jff 3/8/98 end of lower range change for -1 allowed in mouse binding
396
397// For key bindings, the values stored in the key_* variables // phares
398// are the internal Doom Codes. The values stored in the default.cfg
399// file are the keyboard codes.
400// CPhipps - now they're the doom codes, so default.cfg can be portable
401
402 {"Key bindings",{NULL},{0},UL,UL,def_none,ss_none},
403 {"key_right", {&key_right}, {KEYD_RIGHTARROW},
404 0,MAX_KEY,def_key,ss_keys}, // key to turn right
405 {"key_left", {&key_left}, {KEYD_LEFTARROW} ,
406 0,MAX_KEY,def_key,ss_keys}, // key to turn left
407 {"key_up", {&key_up}, {KEYD_UPARROW} ,
408 0,MAX_KEY,def_key,ss_keys}, // key to move forward
409 {"key_down", {&key_down}, {KEYD_DOWNARROW},
410 0,MAX_KEY,def_key,ss_keys}, // key to move backward
411 {"key_menu_right", {&key_menu_right}, {KEYD_RIGHTARROW},// phares 3/7/98
412 0,MAX_KEY,def_key,ss_keys}, // key to move right in a menu // |
413 {"key_menu_left", {&key_menu_left}, {KEYD_LEFTARROW} ,// V
414 0,MAX_KEY,def_key,ss_keys}, // key to move left in a menu
415 {"key_menu_up", {&key_menu_up}, {KEYD_UPARROW} ,
416 0,MAX_KEY,def_key,ss_keys}, // key to move up in a menu
417 {"key_menu_down", {&key_menu_down}, {KEYD_DOWNARROW} ,
418 0,MAX_KEY,def_key,ss_keys}, // key to move down in a menu
419 {"key_menu_backspace",{&key_menu_backspace},{KEYD_BACKSPACE} ,
420 0,MAX_KEY,def_key,ss_keys}, // delete key in a menu
421 {"key_menu_escape", {&key_menu_escape}, {KEYD_ESCAPE} ,
422 0,MAX_KEY,def_key,ss_keys}, // key to leave a menu , // phares 3/7/98
423 {"key_menu_enter", {&key_menu_enter}, {KEYD_ENTER} ,
424 0,MAX_KEY,def_key,ss_keys}, // key to select from menu
425 {"key_strafeleft", {&key_strafeleft}, {','} ,
426 0,MAX_KEY,def_key,ss_keys}, // key to strafe left
427 {"key_straferight", {&key_straferight}, {'.'} ,
428 0,MAX_KEY,def_key,ss_keys}, // key to strafe right
429
430 {"key_fire", {&key_fire}, {KEYD_RCTRL} ,
431 0,MAX_KEY,def_key,ss_keys}, // duh
432 {"key_use", {&key_use}, {' '} ,
433 0,MAX_KEY,def_key,ss_keys}, // key to open a door, use a switch
434 {"key_strafe", {&key_strafe}, {KEYD_RALT} ,
435 0,MAX_KEY,def_key,ss_keys}, // key to use with arrows to strafe
436 {"key_speed", {&key_speed}, {KEYD_RSHIFT} ,
437 0,MAX_KEY,def_key,ss_keys}, // key to run
438
439 {"key_savegame", {&key_savegame}, {KEYD_F2} ,
440 0,MAX_KEY,def_key,ss_keys}, // key to save current game
441 {"key_loadgame", {&key_loadgame}, {KEYD_F3} ,
442 0,MAX_KEY,def_key,ss_keys}, // key to restore from saved games
443 {"key_soundvolume", {&key_soundvolume}, {KEYD_F4} ,
444 0,MAX_KEY,def_key,ss_keys}, // key to bring up sound controls
445 {"key_hud", {&key_hud}, {KEYD_F5} ,
446 0,MAX_KEY,def_key,ss_keys}, // key to adjust HUD
447 {"key_quicksave", {&key_quicksave}, {KEYD_F6} ,
448 0,MAX_KEY,def_key,ss_keys}, // key to to quicksave
449 {"key_endgame", {&key_endgame}, {KEYD_F7} ,
450 0,MAX_KEY,def_key,ss_keys}, // key to end the game
451 {"key_messages", {&key_messages}, {KEYD_F8} ,
452 0,MAX_KEY,def_key,ss_keys}, // key to toggle message enable
453 {"key_quickload", {&key_quickload}, {KEYD_F9} ,
454 0,MAX_KEY,def_key,ss_keys}, // key to load from quicksave
455 {"key_quit", {&key_quit}, {KEYD_F10} ,
456 0,MAX_KEY,def_key,ss_keys}, // key to quit game
457 {"key_gamma", {&key_gamma}, {KEYD_F11} ,
458 0,MAX_KEY,def_key,ss_keys}, // key to adjust gamma correction
459 {"key_spy", {&key_spy}, {KEYD_F12} ,
460 0,MAX_KEY,def_key,ss_keys}, // key to view from another coop player's view
461 {"key_pause", {&key_pause}, {KEYD_PAUSE} ,
462 0,MAX_KEY,def_key,ss_keys}, // key to pause the game
463 {"key_autorun", {&key_autorun}, {KEYD_CAPSLOCK} ,
464 0,MAX_KEY,def_key,ss_keys}, // key to toggle always run mode
465 {"key_chat", {&key_chat}, {'t'} ,
466 0,MAX_KEY,def_key,ss_keys}, // key to enter a chat message
467 {"key_backspace", {&key_backspace}, {KEYD_BACKSPACE} ,
468 0,MAX_KEY,def_key,ss_keys}, // backspace key
469 {"key_enter", {&key_enter}, {KEYD_ENTER} ,
470 0,MAX_KEY,def_key,ss_keys}, // key to select from menu or see last message
471 {"key_map", {&key_map}, {KEYD_TAB} ,
472 0,MAX_KEY,def_key,ss_keys}, // key to toggle automap display
473 {"key_map_right", {&key_map_right}, {KEYD_RIGHTARROW},// phares 3/7/98
474 0,MAX_KEY,def_key,ss_keys}, // key to shift automap right // |
475 {"key_map_left", {&key_map_left}, {KEYD_LEFTARROW} ,// V
476 0,MAX_KEY,def_key,ss_keys}, // key to shift automap left
477 {"key_map_up", {&key_map_up}, {KEYD_UPARROW} ,
478 0,MAX_KEY,def_key,ss_keys}, // key to shift automap up
479 {"key_map_down", {&key_map_down}, {KEYD_DOWNARROW} ,
480 0,MAX_KEY,def_key,ss_keys}, // key to shift automap down
481 {"key_map_zoomin", {&key_map_zoomin}, {'='} ,
482 0,MAX_KEY,def_key,ss_keys}, // key to enlarge automap
483 {"key_map_zoomout", {&key_map_zoomout}, {'-'} ,
484 0,MAX_KEY,def_key,ss_keys}, // key to reduce automap
485 {"key_map_gobig", {&key_map_gobig}, {'0'} ,
486 0,MAX_KEY,def_key,ss_keys}, // key to get max zoom for automap
487 {"key_map_follow", {&key_map_follow}, {'f'} ,
488 0,MAX_KEY,def_key,ss_keys}, // key to toggle follow mode
489 {"key_map_mark", {&key_map_mark}, {'m'} ,
490 0,MAX_KEY,def_key,ss_keys}, // key to drop a marker on automap
491 {"key_map_clear", {&key_map_clear}, {'c'} ,
492 0,MAX_KEY,def_key,ss_keys}, // key to clear all markers on automap
493 {"key_map_grid", {&key_map_grid}, {'g'} ,
494 0,MAX_KEY,def_key,ss_keys}, // key to toggle grid display over automap
495 {"key_map_rotate", {&key_map_rotate}, {'r'} ,
496 0,MAX_KEY,def_key,ss_keys}, // key to toggle rotating the automap to match the player's orientation
497 {"key_map_overlay", {&key_map_overlay}, {'o'} ,
498 0,MAX_KEY,def_key,ss_keys}, // key to toggle overlaying the automap on the rendered display
499 {"key_reverse", {&key_reverse}, {'/'} ,
500 0,MAX_KEY,def_key,ss_keys}, // key to spin 180 instantly
501 {"key_zoomin", {&key_zoomin}, {'='} ,
502 0,MAX_KEY,def_key,ss_keys}, // key to enlarge display
503 {"key_zoomout", {&key_zoomout}, {'-'} ,
504 0,MAX_KEY,def_key,ss_keys}, // key to reduce display
505 {"key_chatplayer1", {&destination_keys[0]}, {'g'} ,
506 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 1
507 // killough 11/98: fix 'i'/'b' reversal
508 {"key_chatplayer2", {&destination_keys[1]}, {'i'} ,
509 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 2
510 {"key_chatplayer3", {&destination_keys[2]}, {'b'} ,
511 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 3
512 {"key_chatplayer4", {&destination_keys[3]}, {'r'} ,
513 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 4
514 {"key_weapontoggle",{&key_weapontoggle}, {'0'} ,
515 0,MAX_KEY,def_key,ss_keys}, // key to toggle between two most preferred weapons with ammo
516 {"key_weapon1", {&key_weapon1}, {'1'} ,
517 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 1 (fist/chainsaw)
518 {"key_weapon2", {&key_weapon2}, {'2'} ,
519 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 2 (pistol)
520 {"key_weapon3", {&key_weapon3}, {'3'} ,
521 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 3 (supershotgun/shotgun)
522 {"key_weapon4", {&key_weapon4}, {'4'} ,
523 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 4 (chaingun)
524 {"key_weapon5", {&key_weapon5}, {'5'} ,
525 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 5 (rocket launcher)
526 {"key_weapon6", {&key_weapon6}, {'6'} ,
527 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 6 (plasma rifle)
528 {"key_weapon7", {&key_weapon7}, {'7'} ,
529 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 7 (bfg9000) // ^
530 {"key_weapon8", {&key_weapon8}, {'8'} ,
531 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 8 (chainsaw) // |
532 {"key_weapon9", {&key_weapon9}, {'9'} ,
533 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 9 (supershotgun) // phares
534
535 // killough 2/22/98: screenshot key
536 {"key_screenshot", {&key_screenshot}, {'*'} ,
537 0,MAX_KEY,def_key,ss_keys}, // key to take a screenshot
538
539 {"Joystick settings",{NULL},{0},UL,UL,def_none,ss_none},
540 {"use_joystick",{&usejoystick},{0},0,2,
541 def_int,ss_none}, // number of joystick to use (0 for none)
542 {"joy_left",{&joyleft},{0}, UL,UL,def_int,ss_none},
543 {"joy_right",{&joyright},{0},UL,UL,def_int,ss_none},
544 {"joy_up", {&joyup}, {0}, UL,UL,def_int,ss_none},
545 {"joy_down",{&joydown},{0}, UL,UL,def_int,ss_none},
546 {"joyb_fire",{&joybfire},{0},0,UL,
547 def_int,ss_keys}, // joystick button number to use for fire
548 {"joyb_strafe",{&joybstrafe},{1},0,UL,
549 def_int,ss_keys}, // joystick button number to use for strafing
550 {"joyb_speed",{&joybspeed},{2},0,UL,
551 def_int,ss_keys}, // joystick button number to use for running
552 {"joyb_use",{&joybuse},{3},0,UL,
553 def_int,ss_keys}, // joystick button number to use for use/open
554
555 {"Chat macros",{NULL},{0},UL,UL,def_none,ss_none},
556 {"chatmacro0", {0,&chat_macros[0]}, {0,HUSTR_CHATMACRO0},UL,UL,
557 def_str,ss_chat}, // chat string associated with 0 key
558 {"chatmacro1", {0,&chat_macros[1]}, {0,HUSTR_CHATMACRO1},UL,UL,
559 def_str,ss_chat}, // chat string associated with 1 key
560 {"chatmacro2", {0,&chat_macros[2]}, {0,HUSTR_CHATMACRO2},UL,UL,
561 def_str,ss_chat}, // chat string associated with 2 key
562 {"chatmacro3", {0,&chat_macros[3]}, {0,HUSTR_CHATMACRO3},UL,UL,
563 def_str,ss_chat}, // chat string associated with 3 key
564 {"chatmacro4", {0,&chat_macros[4]}, {0,HUSTR_CHATMACRO4},UL,UL,
565 def_str,ss_chat}, // chat string associated with 4 key
566 {"chatmacro5", {0,&chat_macros[5]}, {0,HUSTR_CHATMACRO5},UL,UL,
567 def_str,ss_chat}, // chat string associated with 5 key
568 {"chatmacro6", {0,&chat_macros[6]}, {0,HUSTR_CHATMACRO6},UL,UL,
569 def_str,ss_chat}, // chat string associated with 6 key
570 {"chatmacro7", {0,&chat_macros[7]}, {0,HUSTR_CHATMACRO7},UL,UL,
571 def_str,ss_chat}, // chat string associated with 7 key
572 {"chatmacro8", {0,&chat_macros[8]}, {0,HUSTR_CHATMACRO8},UL,UL,
573 def_str,ss_chat}, // chat string associated with 8 key
574 {"chatmacro9", {0,&chat_macros[9]}, {0,HUSTR_CHATMACRO9},UL,UL,
575 def_str,ss_chat}, // chat string associated with 9 key
576
577 {"Automap settings",{NULL},{0},UL,UL,def_none,ss_none},
578 //jff 1/7/98 defaults for automap colors
579 //jff 4/3/98 remove -1 in lower range, 0 now disables new map features
580 {"mapcolor_back", {&mapcolor_back}, {247},0,255, // black //jff 4/6/98 new black
581 def_colour,ss_auto}, // color used as background for automap
582 {"mapcolor_grid", {&mapcolor_grid}, {104},0,255, // dk gray
583 def_colour,ss_auto}, // color used for automap grid lines
584 {"mapcolor_wall", {&mapcolor_wall}, {23},0,255, // red-brown
585 def_colour,ss_auto}, // color used for one side walls on automap
586 {"mapcolor_fchg", {&mapcolor_fchg}, {55},0,255, // lt brown
587 def_colour,ss_auto}, // color used for lines floor height changes across
588 {"mapcolor_cchg", {&mapcolor_cchg}, {215},0,255, // orange
589 def_colour,ss_auto}, // color used for lines ceiling height changes across
590 {"mapcolor_clsd", {&mapcolor_clsd}, {208},0,255, // white
591 def_colour,ss_auto}, // color used for lines denoting closed doors, objects
592 {"mapcolor_rkey", {&mapcolor_rkey}, {175},0,255, // red
593 def_colour,ss_auto}, // color used for red key sprites
594 {"mapcolor_bkey", {&mapcolor_bkey}, {204},0,255, // blue
595 def_colour,ss_auto}, // color used for blue key sprites
596 {"mapcolor_ykey", {&mapcolor_ykey}, {231},0,255, // yellow
597 def_colour,ss_auto}, // color used for yellow key sprites
598 {"mapcolor_rdor", {&mapcolor_rdor}, {175},0,255, // red
599 def_colour,ss_auto}, // color used for closed red doors
600 {"mapcolor_bdor", {&mapcolor_bdor}, {204},0,255, // blue
601 def_colour,ss_auto}, // color used for closed blue doors
602 {"mapcolor_ydor", {&mapcolor_ydor}, {231},0,255, // yellow
603 def_colour,ss_auto}, // color used for closed yellow doors
604 {"mapcolor_tele", {&mapcolor_tele}, {119},0,255, // dk green
605 def_colour,ss_auto}, // color used for teleporter lines
606 {"mapcolor_secr", {&mapcolor_secr}, {252},0,255, // purple
607 def_colour,ss_auto}, // color used for lines around secret sectors
608 {"mapcolor_exit", {&mapcolor_exit}, {0},0,255, // none
609 def_colour,ss_auto}, // color used for exit lines
610 {"mapcolor_unsn", {&mapcolor_unsn}, {104},0,255, // dk gray
611 def_colour,ss_auto}, // color used for lines not seen without computer map
612 {"mapcolor_flat", {&mapcolor_flat}, {88},0,255, // lt gray
613 def_colour,ss_auto}, // color used for lines with no height changes
614 {"mapcolor_sprt", {&mapcolor_sprt}, {112},0,255, // green
615 def_colour,ss_auto}, // color used as things
616 {"mapcolor_item", {&mapcolor_item}, {231},0,255, // yellow
617 def_colour,ss_auto}, // color used for counted items
618 {"mapcolor_hair", {&mapcolor_hair}, {208},0,255, // white
619 def_colour,ss_auto}, // color used for dot crosshair denoting center of map
620 {"mapcolor_sngl", {&mapcolor_sngl}, {208},0,255, // white
621 def_colour,ss_auto}, // color used for the single player arrow
622 {"mapcolor_me", {&mapcolor_me}, {112},0,255, // green
623 def_colour,ss_auto}, // your (player) colour
624 {"mapcolor_enemy", {&mapcolor_enemy}, {177},0,255,
625 def_colour,ss_auto},
626 {"mapcolor_frnd", {&mapcolor_frnd}, {112},0,255,
627 def_colour,ss_auto},
628 //jff 3/9/98 add option to not show secrets til after found
629 {"map_secret_after", {&map_secret_after}, {0},0,1, // show secret after gotten
630 def_bool,ss_auto}, // prevents showing secret sectors till after entered
631 {"map_point_coord", {&map_point_coordinates}, {0},0,1,
632 def_bool,ss_auto},
633 //jff 1/7/98 end additions for automap
634 {"automapmode", {(int*)&automapmode}, {0}, 0, 31, // CPhipps - remember automap mode
635 def_hex,ss_none}, // automap mode
636
637 {"Heads-up display settings",{NULL},{0},UL,UL,def_none,ss_none},
638 //jff 2/16/98 defaults for color ranges in hud and status
639 {"hudcolor_titl", {&hudcolor_titl}, {5},0,9, // gold range
640 def_int,ss_auto}, // color range used for automap level title
641 {"hudcolor_xyco", {&hudcolor_xyco}, {3},0,9, // green range
642 def_int,ss_auto}, // color range used for automap coordinates
643 {"hudcolor_mesg", {&hudcolor_mesg}, {6},0,9, // red range
644 def_int,ss_mess}, // color range used for messages during play
645 {"hudcolor_chat", {&hudcolor_chat}, {5},0,9, // gold range
646 def_int,ss_mess}, // color range used for chat messages and entry
647 {"hudcolor_list", {&hudcolor_list}, {5},0,9, // gold range //jff 2/26/98
648 def_int,ss_mess}, // color range used for message review
649 {"hud_msg_lines", {&hud_msg_lines}, {1},1,16, // 1 line scrolling window
650 def_int,ss_mess}, // number of messages in review display (1=disable)
651 {"hud_list_bgon", {&hud_list_bgon}, {0},0,1, // solid window bg ena //jff 2/26/98
652 def_bool,ss_mess}, // enables background window behind message review
653 {"hud_distributed",{&hud_distributed},{0},0,1, // hud broken up into 3 displays //jff 3/4/98
654 def_bool,ss_none}, // splits HUD into three 2 line displays
655
656 {"health_red", {&health_red} , {25},0,200, // below is red
657 def_int,ss_stat}, // amount of health for red to yellow transition
658 {"health_yellow", {&health_yellow}, {50},0,200, // below is yellow
659 def_int,ss_stat}, // amount of health for yellow to green transition
660 {"health_green", {&health_green} , {100},0,200,// below is green, above blue
661 def_int,ss_stat}, // amount of health for green to blue transition
662 {"armor_red", {&armor_red} , {25},0,200, // below is red
663 def_int,ss_stat}, // amount of armor for red to yellow transition
664 {"armor_yellow", {&armor_yellow} , {50},0,200, // below is yellow
665 def_int,ss_stat}, // amount of armor for yellow to green transition
666 {"armor_green", {&armor_green} , {100},0,200,// below is green, above blue
667 def_int,ss_stat}, // amount of armor for green to blue transition
668 {"ammo_red", {&ammo_red} , {25},0,100, // below 25% is red
669 def_int,ss_stat}, // percent of ammo for red to yellow transition
670 {"ammo_yellow", {&ammo_yellow} , {50},0,100, // below 50% is yellow, above green
671 def_int,ss_stat}, // percent of ammo for yellow to green transition
672
673 //jff 2/16/98 HUD and status feature controls
674 {"hud_active", {&hud_active}, {2},0,2, // 0=off, 1=small, 2=full
675 def_int,ss_none}, // 0 for HUD off, 1 for HUD small, 2 for full HUD
676 //jff 2/23/98
677 {"hud_displayed", {&hud_displayed}, {0},0,1, // whether hud is displayed
678 def_bool,ss_none}, // enables display of HUD
679 {"hud_nosecrets", {&hud_nosecrets}, {0},0,1, // no secrets/items/kills HUD line
680 def_bool,ss_stat}, // disables display of kills/items/secrets on HUD
681
682 {"Weapon preferences",{NULL},{0},UL,UL,def_none,ss_none},
683 // killough 2/8/98: weapon preferences set by user:
684 {"weapon_choice_1", {&weapon_preferences[0][0]}, {6}, 0,9,
685 def_int,ss_weap}, // first choice for weapon (best)
686 {"weapon_choice_2", {&weapon_preferences[0][1]}, {9}, 0,9,
687 def_int,ss_weap}, // second choice for weapon
688 {"weapon_choice_3", {&weapon_preferences[0][2]}, {4}, 0,9,
689 def_int,ss_weap}, // third choice for weapon
690 {"weapon_choice_4", {&weapon_preferences[0][3]}, {3}, 0,9,
691 def_int,ss_weap}, // fourth choice for weapon
692 {"weapon_choice_5", {&weapon_preferences[0][4]}, {2}, 0,9,
693 def_int,ss_weap}, // fifth choice for weapon
694 {"weapon_choice_6", {&weapon_preferences[0][5]}, {8}, 0,9,
695 def_int,ss_weap}, // sixth choice for weapon
696 {"weapon_choice_7", {&weapon_preferences[0][6]}, {5}, 0,9,
697 def_int,ss_weap}, // seventh choice for weapon
698 {"weapon_choice_8", {&weapon_preferences[0][7]}, {7}, 0,9,
699 def_int,ss_weap}, // eighth choice for weapon
700 {"weapon_choice_9", {&weapon_preferences[0][8]}, {1}, 0,9,
701 def_int,ss_weap}, // ninth choice for weapon (worst)
702
703 // cournia - support for arbitrary music file (defaults are mp3)
704 {"Music", {NULL},{0},UL,UL,def_none,ss_none},
705 {"mus_e1m1", {0,&S_music_files[mus_e1m1]}, {0,"e1m1.mp3"},UL,UL,
706 def_str,ss_none},
707 {"mus_e1m2", {0,&S_music_files[mus_e1m2]}, {0,"e1m2.mp3"},UL,UL,
708 def_str,ss_none},
709 {"mus_e1m3", {0,&S_music_files[mus_e1m3]}, {0,"e1m3.mp3"},UL,UL,
710 def_str,ss_none},
711 {"mus_e1m4", {0,&S_music_files[mus_e1m4]}, {0,"e1m4.mp3"},UL,UL,
712 def_str,ss_none},
713 {"mus_e1m5", {0,&S_music_files[mus_e1m5]}, {0,"e1m5.mp3"},UL,UL,
714 def_str,ss_none},
715 {"mus_e1m6", {0,&S_music_files[mus_e1m6]}, {0,"e1m6.mp3"},UL,UL,
716 def_str,ss_none},
717 {"mus_e1m7", {0,&S_music_files[mus_e1m7]}, {0,"e1m7.mp3"},UL,UL,
718 def_str,ss_none},
719 {"mus_e1m8", {0,&S_music_files[mus_e1m8]}, {0,"e1m8.mp3"},UL,UL,
720 def_str,ss_none},
721 {"mus_e1m9", {0,&S_music_files[mus_e1m9]}, {0,"e1m9.mp3"},UL,UL,
722 def_str,ss_none},
723 {"mus_e2m1", {0,&S_music_files[mus_e2m1]}, {0,"e2m1.mp3"},UL,UL,
724 def_str,ss_none},
725 {"mus_e2m2", {0,&S_music_files[mus_e2m2]}, {0,"e2m2.mp3"},UL,UL,
726 def_str,ss_none},
727 {"mus_e2m3", {0,&S_music_files[mus_e2m3]}, {0,"e2m3.mp3"},UL,UL,
728 def_str,ss_none},
729 {"mus_e2m4", {0,&S_music_files[mus_e2m4]}, {0,"e2m4.mp3"},UL,UL,
730 def_str,ss_none},
731 {"mus_e2m5", {0,&S_music_files[mus_e2m5]}, {0,"e1m7.mp3"},UL,UL,
732 def_str,ss_none},
733 {"mus_e2m6", {0,&S_music_files[mus_e2m6]}, {0,"e2m6.mp3"},UL,UL,
734 def_str,ss_none},
735 {"mus_e2m7", {0,&S_music_files[mus_e2m7]}, {0,"e2m7.mp3"},UL,UL,
736 def_str,ss_none},
737 {"mus_e2m8", {0,&S_music_files[mus_e2m8]}, {0,"e2m8.mp3"},UL,UL,
738 def_str,ss_none},
739 {"mus_e2m9", {0,&S_music_files[mus_e2m9]}, {0,"e3m1.mp3"},UL,UL,
740 def_str,ss_none},
741 {"mus_e3m1", {0,&S_music_files[mus_e3m1]}, {0,"e3m1.mp3"},UL,UL,
742 def_str,ss_none},
743 {"mus_e3m2", {0,&S_music_files[mus_e3m2]}, {0,"e3m2.mp3"},UL,UL,
744 def_str,ss_none},
745 {"mus_e3m3", {0,&S_music_files[mus_e3m3]}, {0,"e3m3.mp3"},UL,UL,
746 def_str,ss_none},
747 {"mus_e3m4", {0,&S_music_files[mus_e3m4]}, {0,"e1m8.mp3"},UL,UL,
748 def_str,ss_none},
749 {"mus_e3m5", {0,&S_music_files[mus_e3m5]}, {0,"e1m7.mp3"},UL,UL,
750 def_str,ss_none},
751 {"mus_e3m6", {0,&S_music_files[mus_e3m6]}, {0,"e1m6.mp3"},UL,UL,
752 def_str,ss_none},
753 {"mus_e3m7", {0,&S_music_files[mus_e3m7]}, {0,"e2m7.mp3"},UL,UL,
754 def_str,ss_none},
755 {"mus_e3m8", {0,&S_music_files[mus_e3m8]}, {0,"e3m8.mp3"},UL,UL,
756 def_str,ss_none},
757 {"mus_e3m9", {0,&S_music_files[mus_e3m9]}, {0,"e1m9.mp3"},UL,UL,
758 def_str,ss_none},
759 {"mus_inter", {0,&S_music_files[mus_inter]}, {0,"e2m3.mp3"},UL,UL,
760 def_str,ss_none},
761 {"mus_intro", {0,&S_music_files[mus_intro]}, {0,"intro.mp3"},UL,UL,
762 def_str,ss_none},
763 {"mus_bunny", {0,&S_music_files[mus_bunny]}, {0,"bunny.mp3"},UL,UL,
764 def_str,ss_none},
765 {"mus_victor", {0,&S_music_files[mus_victor]}, {0,"victor.mp3"},UL,UL,
766 def_str,ss_none},
767 {"mus_introa", {0,&S_music_files[mus_introa]}, {0,"intro.mp3"},UL,UL,
768 def_str,ss_none},
769 {"mus_runnin", {0,&S_music_files[mus_runnin]}, {0,"runnin.mp3"},UL,UL,
770 def_str,ss_none},
771 {"mus_stalks", {0,&S_music_files[mus_stalks]}, {0,"stalks.mp3"},UL,UL,
772 def_str,ss_none},
773 {"mus_countd", {0,&S_music_files[mus_countd]}, {0,"countd.mp3"},UL,UL,
774 def_str,ss_none},
775 {"mus_betwee", {0,&S_music_files[mus_betwee]}, {0,"betwee.mp3"},UL,UL,
776 def_str,ss_none},
777 {"mus_doom", {0,&S_music_files[mus_doom]}, {0,"doom.mp3"},UL,UL,
778 def_str,ss_none},
779 {"mus_the_da", {0,&S_music_files[mus_the_da]}, {0,"the_da.mp3"},UL,UL,
780 def_str,ss_none},
781 {"mus_shawn", {0,&S_music_files[mus_shawn]}, {0,"shawn.mp3"},UL,UL,
782 def_str,ss_none},
783 {"mus_ddtblu", {0,&S_music_files[mus_ddtblu]}, {0,"ddtblu.mp3"},UL,UL,
784 def_str,ss_none},
785 {"mus_in_cit", {0,&S_music_files[mus_in_cit]}, {0,"in_cit.mp3"},UL,UL,
786 def_str,ss_none},
787 {"mus_dead", {0,&S_music_files[mus_dead]}, {0,"dead.mp3"},UL,UL,
788 def_str,ss_none},
789 {"mus_stlks2", {0,&S_music_files[mus_stlks2]}, {0,"stalks.mp3"},UL,UL,
790 def_str,ss_none},
791 {"mus_theda2", {0,&S_music_files[mus_theda2]}, {0,"the_da.mp3"},UL,UL,
792 def_str,ss_none},
793 {"mus_doom2", {0,&S_music_files[mus_doom2]}, {0,"doom.mp3"},UL,UL,
794 def_str,ss_none},
795 {"mus_ddtbl2", {0,&S_music_files[mus_ddtbl2]}, {0,"ddtblu.mp3"},UL,UL,
796 def_str,ss_none},
797 {"mus_runni2", {0,&S_music_files[mus_runni2]}, {0,"runnin.mp3"},UL,UL,
798 def_str,ss_none},
799 {"mus_dead2", {0,&S_music_files[mus_dead2]}, {0,"dead.mp3"},UL,UL,
800 def_str,ss_none},
801 {"mus_stlks3", {0,&S_music_files[mus_stlks3]}, {0,"stalks.mp3"},UL,UL,
802 def_str,ss_none},
803 {"mus_romero", {0,&S_music_files[mus_romero]}, {0,"romero.mp3"},UL,UL,
804 def_str,ss_none},
805 {"mus_shawn2", {0,&S_music_files[mus_shawn2]}, {0,"shawn.mp3"},UL,UL,
806 def_str,ss_none},
807 {"mus_messag", {0,&S_music_files[mus_messag]}, {0,"messag.mp3"},UL,UL,
808 def_str,ss_none},
809 {"mus_count2", {0,&S_music_files[mus_count2]}, {0,"countd.mp3"},UL,UL,
810 def_str,ss_none},
811 {"mus_ddtbl3", {0,&S_music_files[mus_ddtbl3]}, {0,"ddtblu.mp3"},UL,UL,
812 def_str,ss_none},
813 {"mus_ampie", {0,&S_music_files[mus_ampie]}, {0,"ampie.mp3"},UL,UL,
814 def_str,ss_none},
815 {"mus_theda3", {0,&S_music_files[mus_theda3]}, {0,"the_da.mp3"},UL,UL,
816 def_str,ss_none},
817 {"mus_adrian", {0,&S_music_files[mus_adrian]}, {0,"adrian.mp3"},UL,UL,
818 def_str,ss_none},
819 {"mus_messg2", {0,&S_music_files[mus_messg2]}, {0,"messag.mp3"},UL,UL,
820 def_str,ss_none},
821 {"mus_romer2", {0,&S_music_files[mus_romer2]}, {0,"romero.mp3"},UL,UL,
822 def_str,ss_none},
823 {"mus_tense", {0,&S_music_files[mus_tense]}, {0,"tense.mp3"},UL,UL,
824 def_str,ss_none},
825 {"mus_shawn3", {0,&S_music_files[mus_shawn3]}, {0,"shawn.mp3"},UL,UL,
826 def_str,ss_none},
827 {"mus_openin", {0,&S_music_files[mus_openin]}, {0,"openin.mp3"},UL,UL,
828 def_str,ss_none},
829 {"mus_evil", {0,&S_music_files[mus_evil]}, {0,"evil.mp3"},UL,UL,
830 def_str,ss_none},
831 {"mus_ultima", {0,&S_music_files[mus_ultima]}, {0,"ultima.mp3"},UL,UL,
832 def_str,ss_none},
833 {"mus_read_m", {0,&S_music_files[mus_read_m]}, {0,"read_m.mp3"},UL,UL,
834 def_str,ss_none},
835 {"mus_dm2ttl", {0,&S_music_files[mus_dm2ttl]}, {0,"dm2ttl.mp3"},UL,UL,
836 def_str,ss_none},
837 {"mus_dm2int", {0,&S_music_files[mus_dm2int]}, {0,"dm2int.mp3"},UL,UL,
838 def_str,ss_none},
839};
840
841int numdefaults;
842static const char* defaultfile; // CPhipps - static, const
843
844//
845// M_SaveDefaults
846//
847
848void M_SaveDefaults (void)
849 {
850 int i;
851 FILE* f;
852
853 f = fopen (defaultfile, "w");
854 if (!f)
855 return; // can't write the file, but don't complain
856
857 // 3/3/98 explain format of file
858
859 fprintf(f,"# Doom config file\n");
860 fprintf(f,"# Format:\n");
861 fprintf(f,"# variable value\n");
862
863 for (i = 0 ; i < numdefaults ; i++) {
864 if (defaults[i].type == def_none) {
865 // CPhipps - pure headers
866 fprintf(f, "\n# %s\n", defaults[i].name);
867 } else
868 // CPhipps - modified for new default_t form
869 if (!IS_STRING(defaults[i])) //jff 4/10/98 kill super-hack on pointer value
870 {
871 // CPhipps - remove keycode hack
872 // killough 3/6/98: use spaces instead of tabs for uniform justification
873 if (defaults[i].type == def_hex)
874 fprintf (f,"%-25s 0x%x\n",defaults[i].name,*(defaults[i].location.pi));
875 else
876 fprintf (f,"%-25s %5i\n",defaults[i].name,*(defaults[i].location.pi));
877 }
878 else
879 {
880 fprintf (f,"%-25s \"%s\"\n",defaults[i].name,*(defaults[i].location.ppsz));
881 }
882 }
883
884 fclose (f);
885 }
886
887/*
888 * M_LookupDefault
889 *
890 * cph - mimic MBF function for now. Yes it's crap.
891 */
892
893struct default_s *M_LookupDefault(const char *name)
894{
895 int i;
896 for (i = 0 ; i < numdefaults ; i++)
897 if ((defaults[i].type != def_none) && !strcmp(name, defaults[i].name))
898 return &defaults[i];
899 I_Error("M_LookupDefault: %s not found",name);
900 return NULL;
901}
902
903//
904// M_LoadDefaults
905//
906
907#define NUMCHATSTRINGS 10 // phares 4/13/98
908
909void M_LoadDefaults (void)
910{
911 int i;
912 int len;
913 FILE* f;
914 char def[80];
915 char strparm[100];
916 char* newstring = NULL; // killough
917 int parm;
918 boolean isstring;
919
920 // set everything to base values
921
922 numdefaults = sizeof(defaults)/sizeof(defaults[0]);
923 for (i = 0 ; i < numdefaults ; i++) {
924 if (defaults[i].location.ppsz)
925 *defaults[i].location.ppsz = strdup(defaults[i].defaultvalue.psz);
926 if (defaults[i].location.pi)
927 *defaults[i].location.pi = defaults[i].defaultvalue.i;
928 }
929
930 // check for a custom default file
931
932 i = M_CheckParm ("-config");
933 if (i && i < myargc-1)
934 defaultfile = myargv[i+1];
935 else {
936 const char* exedir = I_DoomExeDir();
937 defaultfile = malloc(PATH_MAX+1);
938 /* get config file from same directory as executable */
939#ifdef HAVE_SNPRINTF
940 snprintf((char *)defaultfile, PATH_MAX,
941#else
942 sprintf ((char *)defaultfile,
943#endif
944 "%s%s%sboom.cfg", exedir, HasTrailingSlash(exedir) ? "" : "/",
945#if ((defined GL_DOOM) && (defined _MSC_VER))
946 "gl");
947#else
948 "pr");
949#endif
950 }
951
952 lprintf (LO_CONFIRM, " default file: %s\n",defaultfile);
953
954 // read the file in, overriding any set defaults
955
956 f = fopen (defaultfile, "r");
957 if (f)
958 {
959 while (!feof(f))
960 {
961 isstring = false;
962 if (fscanf (f, "%79s %[^\n]\n", def, strparm) == 2)
963 {
964
965 //jff 3/3/98 skip lines not starting with an alphanum
966
967 if (!isalnum(def[0]))
968 continue;
969
970 if (strparm[0] == '"') {
971 // get a string default
972
973 isstring = true;
974 len = strlen(strparm);
975 newstring = (char *) malloc(len);
976 strparm[len-1] = 0; // clears trailing double-quote mark
977 strcpy(newstring, strparm+1); // clears leading double-quote mark
978 } else if ((strparm[0] == '0') && (strparm[1] == 'x')) {
979 // CPhipps - allow ints to be specified in hex
980 sscanf(strparm+2, "%x", &parm);
981 } else {
982 sscanf(strparm, "%i", &parm);
983 // Keycode hack removed
984 }
985
986 for (i = 0 ; i < numdefaults ; i++)
987 if ((defaults[i].type != def_none) && !strcmp(def, defaults[i].name))
988 {
989 // CPhipps - safety check
990 if (isstring != IS_STRING(defaults[i])) {
991 lprintf(LO_WARN, "M_LoadDefaults: Type mismatch reading %s\n", defaults[i].name);
992 continue;
993 }
994 if (!isstring)
995 {
996
997 //jff 3/4/98 range check numeric parameters
998
999 if ((defaults[i].minvalue==UL || defaults[i].minvalue<=parm) &&
1000 (defaults[i].maxvalue==UL || defaults[i].maxvalue>=parm))
1001 *(defaults[i].location.pi) = parm;
1002 }
1003 else
1004 {
1005 free((char*)*(defaults[i].location.ppsz)); /* phares 4/13/98 */
1006 *(defaults[i].location.ppsz) = newstring;
1007 }
1008 break;
1009 }
1010 }
1011 }
1012
1013 fclose (f);
1014 }
1015 //jff 3/4/98 redundant range checks for hud deleted here
1016 /* proff 2001/7/1 - added prboom.wad as last entry so it's always loaded and
1017 doesn't overlap with the cfg settings */
1018 wad_files[MAXLOADFILES-1]="prboom.wad";
1019}
1020
1021
1022//
1023// SCREEN SHOTS
1024//
1025
1026//
1027// M_ScreenShot
1028//
1029// Modified by Lee Killough so that any number of shots can be taken,
1030// the code is faster, and no annoying "screenshot" message appears.
1031
1032// CPhipps - modified to use its own buffer for the image
1033// - checks for the case where no file can be created (doesn't occur on POSIX systems, would on DOS)
1034// - track errors better
1035// - split into 2 functions
1036
1037//
1038// M_DoScreenShot
1039// Takes a screenshot into the names file
1040
1041void M_DoScreenShot (const char* fname)
1042{
1043 if (I_ScreenShot(fname) != 0)
1044 doom_printf("M_ScreenShot: Error writing screenshot\n");
1045}
1046
1047#ifndef SCREENSHOT_DIR
1048#define SCREENSHOT_DIR "."
1049#endif
1050
1051#ifdef HAVE_LIBPNG
1052#define SCREENSHOT_EXT ".png"
1053#else
1054#define SCREENSHOT_EXT ".bmp"
1055#endif
1056
1057void M_ScreenShot(void)
1058{
1059 static int shot;
1060 char lbmname[PATH_MAX + 1];
1061 int startshot;
1062
1063 if (!access(SCREENSHOT_DIR,2))
1064 {
1065 startshot = shot; // CPhipps - prevent infinite loop
1066
1067 do {
1068 sprintf(lbmname,"%s/doom%02d" SCREENSHOT_EXT, SCREENSHOT_DIR, shot++);
1069 } while (!access(lbmname,0) && (shot != startshot) && (shot < 10000));
1070
1071 if (access(lbmname,0))
1072 {
1073 S_StartSound(NULL,gamemode==commercial ? sfx_radio : sfx_tink);
1074 M_DoScreenShot(lbmname); // cph
1075 return;
1076 }
1077 }
1078
1079 doom_printf ("M_ScreenShot: Couldn't create screenshot");
1080 return;
1081}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * External non-system-specific stuff, like storing config settings,
31 * simple file handling, and saving screnshots.
32 *
33 *-----------------------------------------------------------------------------*/
34
35
36#ifndef __M_MISC__
37#define __M_MISC__
38
39
40#include "doomtype.h"
41//
42// MISC
43//
44
45boolean M_WriteFile (char const* name,void* source,int length);
46
47int M_ReadFile (char const* name,byte** buffer);
48
49void M_ScreenShot (void);
50void M_DoScreenShot (const char*); // cph
51
52void M_LoadDefaults (void);
53
54void M_SaveDefaults (void);
55
56struct default_s *M_LookupDefault(const char *name); /* killough 11/98 */
57
58// phares 4/21/98:
59// Moved from m_misc.c so m_menu.c could see it.
60
61// CPhipps - struct to hold a value in a config file
62// Cannot be a union, as it must be initialised
63typedef struct default_s
64{
65 const char* name;
66 /* cph -
67 * The location struct holds the pointer to the variable holding the
68 * setting. For int's we do nothing special.
69 * For strings, the string is actually stored on our heap with Z_Strdup()
70 * BUT we don't want the rest of the program to be able to modify them,
71 * so we declare it const. It's not really const though, and m_misc.c and
72 * m_menu.c cast it back when they need to change it. Possibly this is
73 * more trouble than it's worth.
74 */
75 struct {
76 int* pi;
77 const char** ppsz;
78 } location;
79 struct {
80 int i;
81 const char* psz;
82 } defaultvalue; // CPhipps - default value
83 // Limits (for an int)
84 int minvalue; // jff 3/3/98 minimum allowed value
85 int maxvalue; // jff 3/3/98 maximum allowed value
86 enum {
87 def_none, // Dummy entry
88 def_str, // A string
89 def_int, // Integer
90 def_hex, // Integer (write in hex)
91 def_bool = def_int, // Boolean
92 def_key = def_hex, // Key code (byte)
93 def_mouseb = def_int,// Mouse button
94 def_colour = def_hex // Colour (256 colour palette entry)
95 } type; // CPhipps - type of entry
96 int setupscreen; // phares 4/19/98: setup screen where this appears
97 int *current; /* cph - MBF-like pointer to current value */
98 // cph - removed the help strings from the config file
99 // const char* help; // jff 3/3/98 description of parameter
100 // CPhipps - remove unused "lousy hack" code
101 struct setup_menu_s *setup_menu; /* Xref to setup menu item, if any */
102} default_t;
103
104#define IS_STRING(dv) ((dv).type == def_str)
105// CPhipps - What is the max. key code that X will send us?
106#define MAX_KEY 65536
107#define MAX_MOUSEB 2
108
109#define UL (-123456789) /* magic number for no min or max for parameter */
110
111#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Random number LUT.
31 *
32 * 1/19/98 killough: Rewrote random number generator for better randomness,
33 * while at the same time maintaining demo sync and backward compatibility.
34 *
35 * 2/16/98 killough: Made each RNG local to each control-equivalent block,
36 * to reduce the chances of demo sync problems.
37 *
38 *-----------------------------------------------------------------------------*/
39
40
41#include "doomstat.h"
42#include "m_random.h"
43#include "lprintf.h"
44
45//
46// M_Random
47// Returns a 0-255 number
48//
49static const unsigned char rndtable[256] = { // 1/19/98 killough -- made const
50 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 ,
51 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 ,
52 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 ,
53 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 ,
54 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 ,
55 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 ,
56 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 ,
57 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 ,
58 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 ,
59 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 ,
60 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 ,
61 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 ,
62 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 ,
63 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 ,
64 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 ,
65 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 ,
66 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 ,
67 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 ,
68 120, 163, 236, 249
69};
70
71rng_t rng; // the random number state
72
73unsigned long rngseed = 1993; // killough 3/26/98: The seed
74
75int (P_Random)(pr_class_t pr_class
76#ifdef INSTRUMENTED
77 , const char *file, int line
78#endif
79)
80{
81 // killough 2/16/98: We always update both sets of random number
82 // generators, to ensure repeatability if the demo_compatibility
83 // flag is changed while the program is running. Changing the
84 // demo_compatibility flag does not change the sequences generated,
85 // only which one is selected from.
86 //
87 // All of this RNG stuff is tricky as far as demo sync goes --
88 // it's like playing with explosives :) Lee
89
90#ifdef INSTRUMENTED
91 //lprintf(LO_DEBUG, "%.10d: %.10d - %s:%.5d\n", gametic, pr_class, file, line);
92#endif
93
94 int compat = pr_class == pr_misc ?
95 (rng.prndindex = (rng.prndindex + 1) & 255) :
96 (rng. rndindex = (rng. rndindex + 1) & 255) ;
97
98 unsigned long boom;
99
100 // killough 3/31/98:
101 // If demo sync insurance is not requested, use
102 // much more unstable method by putting everything
103 // except pr_misc into pr_all_in_one
104
105 if (pr_class != pr_misc && !demo_insurance) // killough 3/31/98
106 pr_class = pr_all_in_one;
107
108 boom = rng.seed[pr_class];
109
110 // killough 3/26/98: add pr_class*2 to addend
111
112 rng.seed[pr_class] = boom * 1664525ul + 221297ul + pr_class*2;
113
114 if (demo_compatibility)
115 return rndtable[compat];
116
117 boom >>= 20;
118
119 /* killough 3/30/98: use gametic-levelstarttic to shuffle RNG
120 * killough 3/31/98: but only if demo insurance requested,
121 * since it's unnecessary for random shuffling otherwise
122 * killough 9/29/98: but use basetic now instead of levelstarttic
123 * cph - DEMOSYNC - this change makes MBF demos work,
124 * but does it break Boom ones?
125 */
126
127 if (demo_insurance)
128 boom += (gametic-basetic)*7;
129
130 return boom & 255;
131}
132
133// Initialize all the seeds
134//
135// This initialization method is critical to maintaining demo sync.
136// Each seed is initialized according to its class, so if new classes
137// are added they must be added to end of pr_class_t list. killough
138//
139
140void M_ClearRandom (void)
141{
142 int i;
143 unsigned long seed = rngseed*2+1; // add 3/26/98: add rngseed
144 for (i=0; i<NUMPRCLASS; i++) // go through each pr_class and set
145 rng.seed[i] = seed *= 69069ul; // each starting seed differently
146 rng.prndindex = rng.rndindex = 0; // clear two compatibility indices
147}
diff --git a/src/m_random.h b/src/m_random.h
new file mode 100644
index 0000000..aa63532
--- /dev/null
+++ b/src/m_random.h
@@ -0,0 +1,154 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Functions to return random numbers.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __M_RANDOM__
36#define __M_RANDOM__
37
38#include "doomtype.h"
39
40// killough 1/19/98: rewritten to use to use a better random number generator
41// in the new engine, although the old one is available for compatibility.
42
43// killough 2/16/98:
44//
45// Make every random number generator local to each control-equivalent block.
46// Critical for demo sync. Changing the order of this list breaks all previous
47// versions' demos. The random number generators are made local to reduce the
48// chances of sync problems. In Doom, if a single random number generator call
49// was off, it would mess up all random number generators. This reduces the
50// chances of it happening by making each RNG local to a control flow block.
51//
52// Notes to developers: if you want to reduce your demo sync hassles, follow
53// this rule: for each call to P_Random you add, add a new class to the enum
54// type below for each block of code which calls P_Random. If two calls to
55// P_Random are not in "control-equivalent blocks", i.e. there are any cases
56// where one is executed, and the other is not, put them in separate classes.
57//
58// Keep all current entries in this list the same, and in the order
59// indicated by the #'s, because they're critical for preserving demo
60// sync. Do not remove entries simply because they become unused later.
61
62typedef enum {
63 pr_skullfly, // #1
64 pr_damage, // #2
65 pr_crush, // #3
66 pr_genlift, // #4
67 pr_killtics, // #5
68 pr_damagemobj, // #6
69 pr_painchance, // #7
70 pr_lights, // #8
71 pr_explode, // #9
72 pr_respawn, // #10
73 pr_lastlook, // #11
74 pr_spawnthing, // #12
75 pr_spawnpuff, // #13
76 pr_spawnblood, // #14
77 pr_missile, // #15
78 pr_shadow, // #16
79 pr_plats, // #17
80 pr_punch, // #18
81 pr_punchangle, // #19
82 pr_saw, // #20
83 pr_plasma, // #21
84 pr_gunshot, // #22
85 pr_misfire, // #23
86 pr_shotgun, // #24
87 pr_bfg, // #25
88 pr_slimehurt, // #26
89 pr_dmspawn, // #27
90 pr_missrange, // #28
91 pr_trywalk, // #29
92 pr_newchase, // #30
93 pr_newchasedir, // #31
94 pr_see, // #32
95 pr_facetarget, // #33
96 pr_posattack, // #34
97 pr_sposattack, // #35
98 pr_cposattack, // #36
99 pr_spidrefire, // #37
100 pr_troopattack, // #38
101 pr_sargattack, // #39
102 pr_headattack, // #40
103 pr_bruisattack, // #41
104 pr_tracer, // #42
105 pr_skelfist, // #43
106 pr_scream, // #44
107 pr_brainscream, // #45
108 pr_cposrefire, // #46
109 pr_brainexp, // #47
110 pr_spawnfly, // #48
111 pr_misc, // #49
112 pr_all_in_one, // #50
113 /* CPhipps - new entries from MBF, mostly unused for now */
114 pr_opendoor, // #51
115 pr_targetsearch, // #52
116 pr_friends, // #53
117 pr_threshold, // #54
118 pr_skiptarget, // #55
119 pr_enemystrafe, // #56
120 pr_avoidcrush, // #57
121 pr_stayonlift, // #58
122 pr_helpfriend, // #59
123 pr_dropoff, // #60
124 pr_randomjump, // #61
125 pr_defect, // #62 // Start new entries -- add new entries below
126
127 // End of new entries
128 NUMPRCLASS // MUST be last item in list
129} pr_class_t;
130
131// The random number generator's state.
132typedef struct {
133 unsigned long seed[NUMPRCLASS]; // Each block's random seed
134 int rndindex, prndindex; // For compatibility support
135} rng_t;
136
137extern rng_t rng; // The rng's state
138
139extern unsigned long rngseed; // The starting seed (not part of state)
140
141// As M_Random, but used by the play simulation.
142int P_Random(pr_class_t DA(const char *, int));
143
144#ifdef INSTRUMENTED
145#define P_Random(a) (P_Random) (a, __FILE__,__LINE__)
146#endif
147
148// Returns a number from 0 to 255,
149#define M_Random() P_Random(pr_misc)
150
151// Fix randoms for demos.
152void M_ClearRandom(void);
153
154#endif
diff --git a/src/m_swap.h b/src/m_swap.h
new file mode 100644
index 0000000..df86460
--- /dev/null
+++ b/src/m_swap.h
@@ -0,0 +1,134 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Endianess handling, swapping 16bit and 32bit.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __M_SWAP__
36#define __M_SWAP__
37
38#ifdef __GNUG__
39#pragma interface
40#endif
41
42/* CPhipps - now the endianness handling, converting input or output to/from
43 * the machine's endianness to that wanted for this type of I/O
44 *
45 * To find our own endianness, use config.h
46 */
47
48#ifdef HAVE_CONFIG_H
49#include "config.h"
50#endif
51
52/* Endianess handling. */
53
54/* cph - First the macros to do the actual byte swapping */
55
56/* leban
57 * rather than continue the confusing tradition of redefining the
58 * stardard macro, we now present the doom_ntoh and doom_hton macros....
59 * might as well use the xdoom macros.
60 */
61
62/* Try to use superfast macros on systems that support them */
63#ifdef HAVE_ASM_BYTEORDER_H
64#include <asm/byteorder.h>
65#ifdef __arch__swab16
66#define doom_swap_s (signed short)__arch__swab16
67#endif
68#ifdef __arch__swab32
69#define doom_swap_l (signed long)__arch__swab32
70#endif
71#endif /* HAVE_ASM_BYTEORDER_H */
72
73#ifdef HAVE_LIBKERN_OSBYTEORDER_H
74#include <libkern/OSByteOrder.h>
75
76#define doom_swap_s (short)OSSwapInt16
77#define doom_swap_l (long)OSSwapInt32
78#endif
79
80#ifndef doom_swap_l
81#define doom_swap_l(x) \
82 ((long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
83 (((unsigned long int)(x) & 0x0000ff00U) << 8) | \
84 (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
85 (((unsigned long int)(x) & 0xff000000U) >> 24)))
86#endif
87
88#ifndef doom_swap_s
89#define doom_swap_s(x) \
90 ((short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
91 (((unsigned short int)(x) & 0xff00) >> 8)))
92#endif
93
94/* Macros are named doom_XtoYT, where
95 * X is thing to convert from, Y is thing to convert to, chosen from
96 * n for network, h for host (i.e our machine's), w for WAD (Doom data files)
97 * and T is the type, l or s for long or short
98 *
99 * CPhipps - all WADs and network packets will be little endian for now
100 * Use separate macros so network could be converted to big-endian later.
101 */
102
103#ifdef WORDS_BIGENDIAN
104
105#define doom_wtohl(x) doom_swap_l(x)
106#define doom_htowl(x) doom_swap_l(x)
107#define doom_wtohs(x) doom_swap_s(x)
108#define doom_htows(x) doom_swap_s(x)
109
110#define doom_ntohl(x) doom_swap_l(x)
111#define doom_htonl(x) doom_swap_l(x)
112#define doom_ntohs(x) doom_swap_s(x)
113#define doom_htons(x) doom_swap_s(x)
114
115#else
116
117#define doom_wtohl(x) (long int)(x)
118#define doom_htowl(x) (long int)(x)
119#define doom_wtohs(x) (short int)(x)
120#define doom_htows(x) (short int)(x)
121
122#define doom_ntohl(x) (long int)(x)
123#define doom_htonl(x) (long int)(x)
124#define doom_ntohs(x) (short int)(x)
125#define doom_htons(x) (short int)(x)
126
127#endif
128
129/* CPhipps - Boom's old LONG and SHORT endianness macros are for WAD stuff */
130
131#define LONG(x) doom_wtohl(x)
132#define SHORT(x) doom_htows(x)
133
134#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 @@
1/*
2 * This code implements the MD5 message-digest algorithm.
3 * The algorithm is due to Ron Rivest. This code was
4 * written by Colin Plumb in 1993, no copyright is claimed.
5 * This code is in the public domain; do with it what you wish.
6 *
7 * Equivalent code is available from RSA Data Security, Inc.
8 * This code has been tested against that, and is equivalent,
9 * except that you don't need to include two pages of legalese
10 * with every copy.
11 *
12 * To compute the message digest of a chunk of bytes, declare an
13 * MD5Context structure, pass it to MD5Init, call MD5Update as
14 * needed on buffers full of bytes, and then call MD5Final, which
15 * will fill a supplied 16-byte array with the digest.
16 *
17 * Changed so as no longer to depend on Colin Plumb's `usual.h' header
18 * definitions; now uses stuff from dpkg's config.h.
19 * - Ian Jackson <ian@chiark.greenend.org.uk>.
20 * Still in the public domain.
21 */
22#include "config.h"
23
24#include <string.h> /* for memcpy() */
25#include <sys/types.h> /* for stupid systems */
26
27#include "md5.h"
28
29#ifdef WORDS_BIGENDIAN
30void
31byteSwap(UWORD32 *buf, unsigned words)
32{
33 md5byte *p = (md5byte *)buf;
34
35 do {
36 *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
37 ((unsigned)p[1] << 8 | p[0]);
38 p += 4;
39 } while (--words);
40}
41#else
42#define byteSwap(buf,words)
43#endif
44
45/*
46 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
47 * initialization constants.
48 */
49void
50MD5Init(struct MD5Context *ctx)
51{
52 ctx->buf[0] = 0x67452301;
53 ctx->buf[1] = 0xefcdab89;
54 ctx->buf[2] = 0x98badcfe;
55 ctx->buf[3] = 0x10325476;
56
57 ctx->bytes[0] = 0;
58 ctx->bytes[1] = 0;
59}
60
61/*
62 * Update context to reflect the concatenation of another buffer full
63 * of bytes.
64 */
65void
66MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
67{
68 UWORD32 t;
69
70 /* Update byte count */
71
72 t = ctx->bytes[0];
73 if ((ctx->bytes[0] = t + len) < t)
74 ctx->bytes[1]++; /* Carry from low to high */
75
76 t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
77 if (t > len) {
78 memcpy((md5byte *)ctx->in + 64 - t, buf, len);
79 return;
80 }
81 /* First chunk is an odd size */
82 memcpy((md5byte *)ctx->in + 64 - t, buf, t);
83 byteSwap(ctx->in, 16);
84 MD5Transform(ctx->buf, ctx->in);
85 buf += t;
86 len -= t;
87
88 /* Process data in 64-byte chunks */
89 while (len >= 64) {
90 memcpy(ctx->in, buf, 64);
91 byteSwap(ctx->in, 16);
92 MD5Transform(ctx->buf, ctx->in);
93 buf += 64;
94 len -= 64;
95 }
96
97 /* Handle any remaining bytes of data. */
98 memcpy(ctx->in, buf, len);
99}
100
101/*
102 * Final wrapup - pad to 64-byte boundary with the bit pattern
103 * 1 0* (64-bit count of bits processed, MSB-first)
104 */
105void
106MD5Final(md5byte digest[16], struct MD5Context *ctx)
107{
108 int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
109 md5byte *p = (md5byte *)ctx->in + count;
110
111 /* Set the first char of padding to 0x80. There is always room. */
112 *p++ = 0x80;
113
114 /* Bytes of padding needed to make 56 bytes (-8..55) */
115 count = 56 - 1 - count;
116
117 if (count < 0) { /* Padding forces an extra block */
118 memset(p, 0, count + 8);
119 byteSwap(ctx->in, 16);
120 MD5Transform(ctx->buf, ctx->in);
121 p = (md5byte *)ctx->in;
122 count = 56;
123 }
124 memset(p, 0, count);
125 byteSwap(ctx->in, 14);
126
127 /* Append length in bits and transform */
128 ctx->in[14] = ctx->bytes[0] << 3;
129 ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
130 MD5Transform(ctx->buf, ctx->in);
131
132 byteSwap(ctx->buf, 4);
133 memcpy(digest, ctx->buf, 16);
134 memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
135}
136
137#ifndef ASM_MD5
138
139/* The four core functions - F1 is optimized somewhat */
140
141/* #define F1(x, y, z) (x & y | ~x & z) */
142#define F1(x, y, z) (z ^ (x & (y ^ z)))
143#define F2(x, y, z) F1(z, x, y)
144#define F3(x, y, z) (x ^ y ^ z)
145#define F4(x, y, z) (y ^ (x | ~z))
146
147/* This is the central step in the MD5 algorithm. */
148#define MD5STEP(f,w,x,y,z,in,s) \
149 (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
150
151/*
152 * The core of the MD5 algorithm, this alters an existing MD5 hash to
153 * reflect the addition of 16 longwords of new data. MD5Update blocks
154 * the data and converts bytes into longwords for this routine.
155 */
156void
157MD5Transform(UWORD32 buf[4], UWORD32 const in[16])
158{
159 register UWORD32 a, b, c, d;
160
161 a = buf[0];
162 b = buf[1];
163 c = buf[2];
164 d = buf[3];
165
166 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
167 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
168 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
169 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
170 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
171 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
172 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
173 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
174 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
175 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
176 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
177 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
178 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
179 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
180 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
181 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
182
183 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
184 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
185 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
186 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
187 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
188 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
189 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
190 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
191 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
192 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
193 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
194 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
195 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
196 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
197 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
198 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
199
200 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
201 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
202 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
203 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
204 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
205 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
206 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
207 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
208 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
209 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
210 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
211 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
212 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
213 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
214 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
215 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
216
217 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
218 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
219 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
220 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
221 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
222 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
223 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
224 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
225 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
226 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
227 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
228 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
229 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
230 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
231 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
232 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
233
234 buf[0] += a;
235 buf[1] += b;
236 buf[2] += c;
237 buf[3] += d;
238}
239
240#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 @@
1/*
2 * This is the header file for the MD5 message-digest algorithm.
3 * The algorithm is due to Ron Rivest. This code was
4 * written by Colin Plumb in 1993, no copyright is claimed.
5 * This code is in the public domain; do with it what you wish.
6 *
7 * Equivalent code is available from RSA Data Security, Inc.
8 * This code has been tested against that, and is equivalent,
9 * except that you don't need to include two pages of legalese
10 * with every copy.
11 *
12 * To compute the message digest of a chunk of bytes, declare an
13 * MD5Context structure, pass it to MD5Init, call MD5Update as
14 * needed on buffers full of bytes, and then call MD5Final, which
15 * will fill a supplied 16-byte array with the digest.
16 *
17 * Changed so as no longer to depend on Colin Plumb's `usual.h'
18 * header definitions; now uses stuff from dpkg's config.h
19 * - Ian Jackson <ian@chiark.greenend.org.uk>.
20 * Still in the public domain.
21 */
22
23#ifndef MD5_H
24#define MD5_H
25
26#ifdef _MSC_VER
27#define WIN32_LEAN_AND_MEAN
28#include <windows.h>
29#define UWORD32 DWORD
30#else
31#include <inttypes.h>
32#define UWORD32 uint32_t
33#endif
34#define md5byte unsigned char
35
36struct MD5Context {
37 UWORD32 buf[4];
38 UWORD32 bytes[2];
39 UWORD32 in[16];
40};
41
42void MD5Init(struct MD5Context *context);
43void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
44void MD5Final(unsigned char digest[16], struct MD5Context *context);
45void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
46
47#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * This file supports conversion of MUS format music in memory
31 * to MIDI format 1 music in memory.
32 *
33 * The primary routine, mmus2mid, converts a block of memory in MUS format
34 * to an Allegro MIDI structure. This supports playing MUS lumps in a wad
35 * file with BOOM.
36 *
37 * Another routine, Midi2MIDI, converts a block of memory in MIDI format 1 to
38 * an Allegro MIDI structure. This supports playing MIDI lumps in a wad
39 * file with BOOM.
40 *
41 * For testing purposes, and to make a utility if desired, if the symbol
42 * STANDALONE is defined by uncommenting the definition below, a main
43 * routine is compiled that will convert a possibly wildcarded set of MUS
44 * files to a similarly named set of MIDI files.
45 *
46 * Much of the code here is thanks to S. Bacquet's source for QMUS2MID.C
47 *
48 *-----------------------------------------------------------------------------
49 */
50
51
52#include <ctype.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <sys/types.h>
57#include <sys/stat.h>
58#include <stdlib.h>
59#ifdef MSDOS /* proff: I don't use allegro in windows */
60#include <allegro.h>
61#endif /* !MSDOS */
62#include "mmus2mid.h"
63#include "lprintf.h" // jff 08/03/98 - declaration of lprintf
64
65//#define STANDALONE /* uncomment this to make MMUS2MID.EXE */
66#ifndef STANDALONE
67#include "m_swap.h"
68#include "z_zone.h"
69#endif
70
71// some macros to decode mus event bit fields
72
73#define last(e) ((UBYTE)((e) & 0x80))
74#define event_type(e) ((UBYTE)(((e) & 0x7F) >> 4))
75#define channel(e) ((UBYTE)((e) & 0x0F))
76
77// event types
78
79typedef enum
80{
81 RELEASE_NOTE,
82 PLAY_NOTE,
83 BEND_NOTE,
84 SYS_EVENT,
85 CNTL_CHANGE,
86 UNKNOWN_EVENT1,
87 SCORE_END,
88 UNKNOWN_EVENT2,
89} mus_event_t;
90
91// MUS format header structure
92
93typedef struct
94{
95 char ID[4]; // identifier "MUS"0x1A
96 UWORD ScoreLength; // length of music portion
97 UWORD ScoreStart; // offset of music portion
98 UWORD channels; // count of primary channels
99 UWORD SecChannels; // count of secondary channels
100 UWORD InstrCnt; // number of instruments
101} PACKEDATTR MUSheader;
102
103// to keep track of information in a MIDI track
104
105typedef struct Track
106{
107 char velocity;
108 long deltaT;
109 UBYTE lastEvt;
110 long alloced;
111} TrackInfo;
112
113// array of info about tracks
114
115static TrackInfo track[MIDI_TRACKS];
116
117// initial track size allocation
118#define TRACKBUFFERSIZE 1024
119
120// lookup table MUS -> MID controls
121static UBYTE MUS2MIDcontrol[15] =
122{
123 0, // Program change - not a MIDI control change
124 0x00, // Bank select
125 0x01, // Modulation pot
126 0x07, // Volume
127 0x0A, // Pan pot
128 0x0B, // Expression pot
129 0x5B, // Reverb depth
130 0x5D, // Chorus depth
131 0x40, // Sustain pedal
132 0x43, // Soft pedal
133 0x78, // All sounds off
134 0x7B, // All notes off
135 0x7E, // Mono
136 0x7F, // Poly
137 0x79 // Reset all controllers
138};
139
140// some strings of bytes used in the midi format
141
142static UBYTE midikey[] =
143{0x00,0xff,0x59,0x02,0x00,0x00}; // C major
144static UBYTE miditempo[] =
145{0x00,0xff,0x51,0x03,0x09,0xa3,0x1a}; // uS/qnote
146static UBYTE midihdr[] =
147{'M','T','h','d',0,0,0,6,0,1,0,0,0,0}; // header (length 6, format 1)
148static UBYTE trackhdr[] =
149{'M','T','r','k'}; // track header
150
151// static routine prototypes
152
153static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte);
154static int TWriteVarLen(MIDI *mididata, int MIDItrack, register ULONG value);
155static ULONG ReadTime(const UBYTE **musptrp);
156static int FirstChannelAvailable(int MUS2MIDchannel[]);
157static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel,
158 UBYTE MIDItrack,int nocomp);
159
160//
161// TWriteByte()
162//
163// write one byte to the selected MIDItrack, update current position
164// if track allocation exceeded, double it
165// if track not allocated, initially allocate TRACKBUFFERSIZE bytes
166//
167// Passed pointer to Allegro MIDI structure, number of the MIDI track being
168// written, and the byte to write.
169//
170// Returns 0 on success, MEMALLOC if a memory allocation error occurs
171//
172static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte)
173{
174 ULONG pos ;
175
176 pos = mididata->track[MIDItrack].len;
177 if (pos >= (ULONG)track[MIDItrack].alloced)
178 {
179 track[MIDItrack].alloced = // double allocation
180 track[MIDItrack].alloced? // or set initial TRACKBUFFERSIZE
181 2*track[MIDItrack].alloced :
182 TRACKBUFFERSIZE;
183
184 if (!(mididata->track[MIDItrack].data = // attempt to reallocate
185 realloc(mididata->track[MIDItrack].data,
186 track[MIDItrack].alloced)))
187 return MEMALLOC;
188 }
189 mididata->track[MIDItrack].data[pos] = byte;
190 mididata->track[MIDItrack].len++;
191 return 0;
192}
193
194//
195// TWriteVarLen()
196//
197// write the ULONG value to tracknum-th track, in midi format, which is
198// big endian, 7 bits per byte, with all bytes but the last flagged by
199// bit 8 being set, allowing the length to vary.
200//
201// Passed the Allegro MIDI structure, the track number to write,
202// and the ULONG value to encode in midi format there
203//
204// Returns 0 if sucessful, MEMALLOC if a memory allocation error occurs
205//
206static int TWriteVarLen(MIDI *mididata, int tracknum, register ULONG value)
207{
208 register ULONG buffer;
209
210 buffer = value & 0x7f;
211 while ((value >>= 7)) // terminates because value unsigned
212 {
213 buffer <<= 8; // note first value shifted in has bit 8 clear
214 buffer |= 0x80; // all succeeding values do not
215 buffer += (value & 0x7f);
216 }
217 while (1) // write bytes out in opposite order
218 {
219 if (TWriteByte(mididata, tracknum, (UBYTE)(buffer&0xff))) // insure buffer masked
220 return MEMALLOC;
221
222 if (buffer & 0x80)
223 buffer >>= 8;
224 else // terminate on the byte with bit 8 clear
225 break;
226 }
227 return 0;
228}
229
230//
231// ReadTime()
232//
233// Read a time value from the MUS buffer, advancing the position in it
234//
235// A time value is a variable length sequence of 8 bit bytes, with all
236// but the last having bit 8 set.
237//
238// Passed a pointer to the pointer to the MUS buffer
239// Returns the integer unsigned long time value there and advances the pointer
240//
241static ULONG ReadTime(const UBYTE **musptrp)
242{
243 register ULONG timeval = 0;
244 int byte;
245
246 do // shift each byte read up in the result until a byte with bit 8 clear
247 {
248 byte = *(*musptrp)++;
249 timeval = (timeval << 7) + (byte & 0x7F);
250 }
251 while(byte & 0x80);
252
253 return timeval;
254}
255
256//
257// FirstChannelAvailable()
258//
259// Return the next unassigned MIDI channel number
260//
261// The assignment for MUS channel 15 is not counted in the caculation, that
262// being percussion and always assigned to MIDI channel 9 (base 0).
263//
264// Passed the array of MIDI channels assigned to MUS channels
265// Returns the maximum channel number unassigned unless that is 9 in which
266// case 10 is returned.
267//
268// killough 10/7/98: changed char parameter, return values to int
269
270static int FirstChannelAvailable(int MUS2MIDchannel[])
271{
272 int i ;
273 int max = -1 ;
274
275 // find the largest MIDI channel assigned so far
276 for (i = 0; i < 15; i++)
277 if (MUS2MIDchannel[i] > max)
278 max = MUS2MIDchannel[i];
279
280 return (max == 8 ? 10 : max+1); // skip MIDI channel 9 (percussion)
281}
282
283//
284// MidiEvent()
285//
286// Constructs a MIDI event code, and writes it to the current MIDI track
287// unless its the same as the last event code and compressio is enabled
288// in which case nothing is written.
289//
290// Passed the Allegro MIDI structure, the midi event code, the current
291// MIDI channel number, the current MIDI track number, and whether compression
292// (running status) is enabled.
293//
294// Returns the new event code if successful, 0 if a memory allocation error
295//
296static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel,
297 UBYTE MIDItrack,int nocomp)
298{
299 UBYTE newevent;
300
301 newevent = midicode | MIDIchannel;
302 if ((newevent != track[MIDItrack].lastEvt) || nocomp)
303 {
304 if (TWriteByte(mididata,MIDItrack, newevent))
305 return 0; // indicates MEMALLOC error
306 track[MIDItrack].lastEvt = newevent;
307 }
308 return newevent;
309}
310
311//
312// mmus2mid()
313//
314// Convert a memory buffer contain MUS data to an Allegro MIDI structure
315// with specified time division and compression.
316//
317// Passed a pointer to the buffer containing MUS data, a pointer to the
318// Allegro MIDI structure, the divisions, and a flag whether to compress.
319//
320// Returns 0 if successful, otherwise an error code (see mmus2mid.h).
321//
322int mmus2mid(const UBYTE *mus, MIDI *mididata, UWORD division, int nocomp)
323{
324 UWORD TrackCnt = 0;
325 UBYTE evt, MUSchannel, MIDIchannel, MIDItrack=0, NewEvent;
326 int i, event, data;
327 const UBYTE *musptr;
328 size_t muslen;
329 static MUSheader MUSh;
330 UBYTE MIDIchan2track[MIDI_TRACKS]; // killough 10/7/98: fix too small array
331 int MUS2MIDchannel[MIDI_TRACKS]; // killough 10/7/98: fix too small array
332
333 // copy the MUS header from the MUS buffer to the MUSh header structure
334
335 memcpy(&MUSh,mus,sizeof(MUSheader));
336 MUSh.ScoreLength = doom_wtohs(MUSh.ScoreLength);
337 MUSh.ScoreStart = doom_wtohs(MUSh.ScoreStart);
338 MUSh.channels = doom_wtohs(MUSh.channels);
339 MUSh.SecChannels = doom_wtohs(MUSh.SecChannels);
340 MUSh.InstrCnt = doom_wtohs(MUSh.InstrCnt);
341
342 // check some things and set length of MUS buffer from internal data
343
344 if (!(muslen = MUSh.ScoreLength + MUSh.ScoreStart))
345 return MUSDATAMT; // MUS file empty
346
347 if (MUSh.channels > 15) // MUSchannels + drum channel > 16
348 return TOOMCHAN ;
349
350 musptr = mus+MUSh.ScoreStart; // init musptr to start of score
351
352 for (i = 0; i < MIDI_TRACKS; i++) // init the track structure's tracks
353 {
354 MUS2MIDchannel[i] = -1; // flag for channel not used yet
355 track[i].velocity = 64;
356 track[i].deltaT = 0;
357 track[i].lastEvt = 0;
358 //free(mididata->track[i].data);//jff 3/5/98 remove old allocations
359 mididata->track[i].data=NULL;
360 track[i].alloced = 0;
361 mididata->track[i].len = 0;
362 }
363
364 if (!division)
365 division = 70;
366
367 // allocate the first track which is a special tempo/key track
368 // note multiple tracks means midi format 1
369
370 // set the divisions (ticks per quarter note)
371 mididata->divisions = division;
372
373 // allocate for midi tempo/key track, allow for end of track
374 if (!(mididata->track[0].data =
375 realloc(mididata->track[0].data,sizeof(midikey)+sizeof(miditempo)+4)))
376 return MEMALLOC;
377
378 // key C major
379 memcpy(mididata->track[0].data,midikey,sizeof(midikey));
380 // tempo uS/qnote
381 memcpy(mididata->track[0].data+sizeof(midikey),miditempo,sizeof(miditempo));
382 mididata->track[0].len = sizeof(midikey)+sizeof(miditempo);
383
384 TrackCnt++; // music tracks start at 1
385
386 // process the MUS events in the MUS buffer
387
388 do
389 {
390 // get a mus event, decode its type and channel fields
391
392 event = *musptr++;
393 if ((evt = event_type(event)) == SCORE_END) //jff 1/23/98 use symbol
394 break; // if end of score event, leave
395 MUSchannel = channel(event);
396
397 // if this channel not initialized, do so
398
399 if (MUS2MIDchannel[MUSchannel] == -1)
400 {
401 // set MIDIchannel and MIDItrack
402
403 MIDIchannel = MUS2MIDchannel[MUSchannel] =
404 (MUSchannel == 15 ? 9 : FirstChannelAvailable(MUS2MIDchannel));
405 MIDItrack = MIDIchan2track[MIDIchannel] = (UBYTE)TrackCnt++;
406 }
407 else // channel already allocated as a track, use those values
408 {
409 MIDIchannel = MUS2MIDchannel[MUSchannel];
410 MIDItrack = MIDIchan2track[MIDIchannel];
411 }
412
413 if (TWriteVarLen(mididata, MIDItrack, track[MIDItrack].deltaT))
414 return MEMALLOC;
415 track[MIDItrack].deltaT = 0;
416
417 switch(evt)
418 {
419 case RELEASE_NOTE:
420 // killough 10/7/98: Fix noise problems by not allowing compression
421 if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,1)))
422 return MEMALLOC;
423
424 data = *musptr++;
425 if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F)))
426 return MEMALLOC;
427 if (TWriteByte(mididata, MIDItrack, 0))
428 return MEMALLOC;
429 break;
430
431 case PLAY_NOTE:
432 if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,nocomp)))
433 return MEMALLOC;
434
435 data = *musptr++;
436 if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F)))
437 return MEMALLOC;
438 if( data & 0x80 )
439 track[MIDItrack].velocity = (*musptr++) & 0x7f;
440 if (TWriteByte(mididata, MIDItrack, track[MIDItrack].velocity))
441 return MEMALLOC;
442 break;
443
444 case BEND_NOTE:
445 if (!(NewEvent=MidiEvent(mididata,0xE0,MIDIchannel,MIDItrack,nocomp)))
446 return MEMALLOC;
447
448 data = *musptr++;
449 if (TWriteByte(mididata, MIDItrack, (UBYTE)((data & 1) << 6)))
450 return MEMALLOC;
451 if (TWriteByte(mididata, MIDItrack, (UBYTE)(data >> 1)))
452 return MEMALLOC;
453 break;
454
455 case SYS_EVENT:
456 if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
457 return MEMALLOC;
458
459 data = *musptr++;
460 if (data<10 || data>14)
461 return BADSYSEVT;
462
463 if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
464 return MEMALLOC;
465 if (data == 12)
466 {
467 if (TWriteByte(mididata, MIDItrack, (UBYTE)(MUSh.channels+1)))
468 return MEMALLOC;
469 }
470 else
471 if (TWriteByte(mididata, MIDItrack, 0))
472 return MEMALLOC;
473 break;
474
475 case CNTL_CHANGE:
476 data = *musptr++;
477 if (data>9)
478 return BADCTLCHG;
479
480 if (data)
481 {
482 if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
483 return MEMALLOC;
484
485 if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
486 return MEMALLOC;
487 }
488 else
489 {
490 if (!(NewEvent=MidiEvent(mididata,0xC0,MIDIchannel,MIDItrack,nocomp)))
491 return MEMALLOC;
492 }
493 data = *musptr++;
494 if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F)))
495 return MEMALLOC;
496 break;
497
498 case UNKNOWN_EVENT1: // mus events 5 and 7
499 case UNKNOWN_EVENT2: // meaning not known
500 return BADMUSCTL;
501
502 case SCORE_END:
503 break;
504
505 default:
506 return BADMUSCTL; // exit with error
507 }
508 if (last(event))
509 {
510 ULONG DeltaTime = ReadTime(&musptr); // killough 10/7/98: make local
511 for (i = 0;i < MIDI_TRACKS; i++) //jff 3/13/98 update all tracks
512 track[i].deltaT += DeltaTime; //whether allocated yet or not
513 }
514
515 }
516 while ((evt != SCORE_END) && ((size_t)(musptr-mus) < muslen));
517
518 if (evt!=SCORE_END)
519 return MUSDATACOR;
520
521 // Now add an end of track to each mididata track, correct allocation
522
523 for (i = 0; i < MIDI_TRACKS; i++)
524 if (mididata->track[i].len)
525 { // killough 10/7/98: simplify code
526 if (TWriteByte(mididata, i, 0x00) || // midi end of track code
527 TWriteByte(mididata, i, 0xFF) ||
528 TWriteByte(mididata, i, 0x2F) ||
529 TWriteByte(mididata, i, 0x00))
530 return MEMALLOC;
531
532 // jff 1/23/98 fix failure to set data NULL, len 0 for unused tracks
533 // shorten allocation to proper length (important for Allegro)
534 if (!(mididata->track[i].data =
535 realloc(mididata->track[i].data,mididata->track[i].len)))
536 return MEMALLOC;
537 }
538 else
539 {
540 free(mididata->track[i].data);
541 mididata->track[i].data = NULL;
542 }
543
544 return 0;
545}
546
547void free_mididata(MIDI *mid)
548{
549 int i;
550
551 for (i = 0; i < MIDI_TRACKS; i++)
552 if (mid->track[i].data)
553 free(mid->track[i].data);
554}
555
556//
557// ReadLength()
558//
559// Reads the length of a chunk in a midi buffer, advancing the pointer
560// 4 bytes, bigendian
561//
562// Passed a pointer to the pointer to a MIDI buffer
563// Returns the chunk length at the pointer position
564//
565static size_t ReadLength(UBYTE **mid)
566{
567 UBYTE *midptr = *mid;
568
569 size_t length = (*midptr++)<<24;
570 length += (*midptr++)<<16;
571 length += (*midptr++)<<8;
572 length += *midptr++;
573 *mid = midptr;
574 return length;
575}
576
577//
578// MidiToMIDI()
579//
580// Convert an in-memory copy of a MIDI format 0 or 1 file to
581// an Allegro MIDI structure, that is valid or has been zeroed
582//
583// Passed a pointer to a memory buffer with MIDI format music in it and a
584// pointer to an Allegro MIDI structure.
585//
586// Returns 0 if successful, BADMIDHDR if the buffer is not MIDI format
587//
588int MidiToMIDI(UBYTE *mid,MIDI *mididata)
589{
590 int i;
591 int ntracks;
592
593 // read the midi header
594
595 if (memcmp(mid,midihdr,4))
596 return BADMIDHDR;
597
598 mididata->divisions = (mid[12]<<8)+mid[13];
599 ntracks = (mid[10]<<8)+mid[11];
600
601 if (ntracks>=MIDI_TRACKS)
602 return BADMIDHDR;
603
604 mid += 4;
605 { // killough 10/7/98: fix mid from being modified twice before sequence pt.
606 size_t t = ReadLength(&mid); // seek past header
607 mid += t;
608 }
609
610 // now read each track
611
612 for (i=0;i<ntracks;i++)
613 {
614 while (memcmp(mid,trackhdr,4)) // simply skip non-track data
615 {
616 mid += 4;
617 {
618 size_t t = ReadLength(&mid); // seek past header
619 mid += t; // killough 10/7/98: prevent mid undefined behavior
620 }
621 }
622 mid += 4;
623 mididata->track[i].len = ReadLength(&mid); // get length, move mid past it
624
625 // read a track
626 mididata->track[i].data = realloc(mididata->track[i].data,mididata->track[i].len);
627 memcpy(mididata->track[i].data,mid,mididata->track[i].len);
628 mid += mididata->track[i].len;
629 }
630 for (;i<MIDI_TRACKS;i++)
631 if (mididata->track[i].len)
632 {
633 free(mididata->track[i].data);
634 mididata->track[i].data = NULL;
635 mididata->track[i].len = 0;
636 }
637 return 0;
638}
639
640//#ifdef STANDALONE /* this code unused by BOOM provided for future portability */
641// /* it also provides a MUS to MID file converter*/
642// proff: I moved this down, because I need MIDItoMidi
643
644static void FreeTracks(MIDI *mididata);
645static void TWriteLength(UBYTE **midiptr,ULONG length);
646
647//
648// FreeTracks()
649//
650// Free all track allocations in the MIDI structure
651//
652// Passed a pointer to an Allegro MIDI structure
653// Returns nothing
654//
655static void FreeTracks(MIDI *mididata)
656{
657 int i;
658
659 for (i=0; i<MIDI_TRACKS; i++)
660 {
661 free(mididata->track[i].data);
662 mididata->track[i].data = NULL;
663 mididata->track[i].len = 0;
664 }
665}
666
667//
668// TWriteLength()
669//
670// Write the length of a MIDI chunk to a midi buffer. The length is four
671// bytes and is written byte-reversed for bigendian. The pointer to the
672// midi buffer is advanced.
673//
674// Passed a pointer to the pointer to a midi buffer, and the length to write
675// Returns nothing
676//
677static void TWriteLength(UBYTE **midiptr,ULONG length)
678{
679// proff: Added typecast to avoid warning
680 *(*midiptr)++ = (unsigned char)((length>>24)&0xff);
681 *(*midiptr)++ = (unsigned char)((length>>16)&0xff);
682 *(*midiptr)++ = (unsigned char)((length>>8)&0xff);
683 *(*midiptr)++ = (unsigned char)((length)&0xff);
684}
685
686//
687// MIDIToMidi()
688//
689// This routine converts an Allegro MIDI structure to a midi 1 format file
690// in memory. It is used to support memory MUS -> MIDI conversion
691//
692// Passed a pointer to an Allegro MIDI structure, a pointer to a pointer to
693// a buffer containing midi data, and a pointer to a length return.
694// Returns 0 if successful, MEMALLOC if a memory allocation error occurs
695//
696int MIDIToMidi(MIDI *mididata,UBYTE **mid,int *midlen)
697{
698 size_t total;
699 int i,ntrks;
700 UBYTE *midiptr;
701
702 // calculate how long the mid buffer must be, and allocate
703
704 total = sizeof(midihdr);
705 for (i=0,ntrks=0;i<MIDI_TRACKS;i++)
706 if (mididata->track[i].len)
707 {
708 total += 8 + mididata->track[i].len; // Track hdr + track length
709 ntrks++;
710 }
711 if ((*mid = malloc(total))==NULL)
712 return MEMALLOC;
713
714
715 // fill in number of tracks and bigendian divisions (ticks/qnote)
716
717 midihdr[10] = 0;
718 midihdr[11] = (UBYTE)ntrks; // set number of tracks in header
719 midihdr[12] = (mididata->divisions>>8) & 0x7f;
720 midihdr[13] = (mididata->divisions) & 0xff;
721
722 // write the midi header
723
724 midiptr = *mid;
725 memcpy(midiptr,midihdr,sizeof(midihdr));
726 midiptr += sizeof(midihdr);
727
728 // write the tracks
729
730 for (i=0;i<MIDI_TRACKS;i++)
731 {
732 if (mididata->track[i].len)
733 {
734 memcpy(midiptr,trackhdr,sizeof(trackhdr)); // header
735 midiptr += sizeof(trackhdr);
736 TWriteLength(&midiptr,mididata->track[i].len); // track length
737 // data
738 memcpy(midiptr,mididata->track[i].data,mididata->track[i].len);
739 midiptr += mididata->track[i].len;
740 }
741 }
742
743 // return length information
744
745 *midlen = midiptr - *mid;
746
747 return 0;
748}
749
750#ifdef STANDALONE /* this code unused by BOOM provided for future portability */
751 /* it also provides a MUS to MID file converter*/
752// proff: I moved this down, because I need MIDItoMidi
753
754//
755// main()
756//
757// Main routine that will convert a globbed set of MUS files to the
758// correspondingly named MID files using mmus2mid(). Only compiled
759// if the STANDALONE symbol is defined.
760//
761// Passed the command line arguments, returns 0 if successful
762//
763int main(int argc,char **argv)
764{
765 FILE *musst,*midst;
766 char musfile[FILENAME_MAX],midfile[FILENAME_MAX];
767 MUSheader MUSh;
768 UBYTE *mus,*mid;
769 static MIDI mididata;
770 int err,midlen;
771 char *p,*q;
772 int i;
773
774 if (argc<2)
775 {
776 //jff 8/3/98 use logical output routine
777 lprintf(LO_INFO,"Usage: MMUS2MID musfile[.MUS]\n");
778 lprintf(LO_INFO,"writes musfile.MID as output\n");
779 lprintf(LO_INFO,"musfile may contain wildcards\n");
780 exit(1);
781 }
782
783 for (i=1;i<argc;i++)
784 {
785 strcpy(musfile,argv[i]);
786 p = strrchr(musfile,'.');
787 q = strrchr(musfile,'\\');
788 if (p && (!q || q<p)) *p='\0';
789 strcpy(midfile,musfile);
790 strcat(musfile,".MUS");
791 strcat(midfile,".MID");
792
793 musst = fopen(musfile,"rb");
794 if (musst)
795 {
796 fread(&MUSh,sizeof(MUSheader),1,musst);
797 mus = malloc(MUSh.ScoreLength+MUSh.ScoreStart);
798 if (mus)
799 {
800 fseek(musst,0,SEEK_SET);
801 if (!fread(mus,MUSh.ScoreLength+MUSh.ScoreStart,1,musst))
802 {
803 //jff 8/3/98 use logical output routine
804 lprintf(LO_FATAL,"Error reading MUS file\n");
805 free(mus);
806 exit(1);
807 }
808 fclose(musst);
809 }
810 else
811 {
812 //jff 8/3/98 use logical output routine
813 lprintf(LO_FATAL,"Out of memory\n");
814 free(mus);
815 exit(1);
816 }
817
818 err = mmus2mid(mus,&mididata,89,1);
819 if (err)
820 {
821 //jff 8/3/98 use logical output routine
822 lprintf(LO_FATAL,"Error converting MUS file to MIDI: %d\n",err);
823 exit(1);
824 }
825 free(mus);
826
827 MIDIToMidi(&mididata,&mid,&midlen);
828
829 midst = fopen(midfile,"wb");
830 if (midst)
831 {
832 if (!fwrite(mid,midlen,1,midst))
833 {
834 //jff 8/3/98 use logical output routine
835 lprintf(LO_FATAL,"Error writing MIDI file\n");
836 FreeTracks(&mididata);
837 free(mid);
838 exit(1);
839 }
840 fclose(midst);
841 }
842 else
843 {
844 //jff 8/3/98 use logical output routine
845 lprintf(LO_FATAL,"Can't open MIDI file for output: %s\n", midfile);
846 FreeTracks(&mididata);
847 free(mid);
848 exit(1);
849 }
850 }
851 else
852 {
853 //jff 8/3/98 use logical output routine
854 lprintf(LO_FATAL,"Can't open MUS file for input: %s\n", midfile);
855 exit(1);
856 }
857
858 //jff 8/3/98 use logical output routine
859 lprintf(LO_CONFIRM,"MUS file %s converted to MIDI file %s\n",musfile,midfile);
860 FreeTracks(&mididata);
861 free(mid);
862 }
863 exit(0);
864}
865
866#endif
diff --git a/src/mmus2mid.h b/src/mmus2mid.h
new file mode 100644
index 0000000..55d5803
--- /dev/null
+++ b/src/mmus2mid.h
@@ -0,0 +1,76 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * mmus2mid.c supports conversion of MUS format music in memory
31 * to MIDI format 1 music in memory.
32 */
33
34#if !defined( MMUS2MID_H )
35#define MMUS2MID_H
36
37// error codes
38
39typedef enum
40{
41 MUSDATACOR, // MUS data corrupt
42 TOOMCHAN, // Too many channels
43 MEMALLOC, // Memory allocation error
44 MUSDATAMT, // MUS file empty
45 BADMUSCTL, // MUS event 5 or 7 found
46 BADSYSEVT, // MUS system event not in 10-14 range
47 BADCTLCHG, // MUS control change larger than 9
48 TRACKOVF, // MIDI track exceeds allocation
49 BADMIDHDR, // bad midi header detected
50} error_code_t;
51
52// some names for integers of various sizes, all unsigned
53typedef unsigned char UBYTE; // a one-byte int
54typedef unsigned short UWORD; // a two-byte int
55// proff: changed from unsigned int to unsigned long to avoid warning
56typedef unsigned long ULONG; // a four-byte int (assumes int 4 bytes)
57
58#ifndef MSDOS /* proff: This is from allegro.h */
59#define MIDI_TRACKS 32
60
61typedef struct MIDI /* a midi file */
62{
63 int divisions; /* number of ticks per quarter note */
64 struct {
65 unsigned char *data; /* MIDI message stream */
66 int len; /* length of the track data */
67 } track[MIDI_TRACKS];
68} MIDI;
69#endif /* !MSDOS */
70
71extern int mmus2mid(const UBYTE *mus,MIDI *mid, UWORD division, int nocomp);
72extern void free_mididata(MIDI *mid);
73extern int MIDIToMidi(MIDI *mididata,UBYTE **mid,int *midlen);
74extern int MidiToMIDI(UBYTE *mid,MIDI *mididata);
75
76#endif
diff --git a/src/p_ceilng.c b/src/p_ceilng.c
new file mode 100644
index 0000000..7b45ba5
--- /dev/null
+++ b/src/p_ceilng.c
@@ -0,0 +1,467 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Ceiling aninmation (lowering, crushing, raising)
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "r_main.h"
36#include "p_spec.h"
37#include "p_tick.h"
38#include "s_sound.h"
39#include "sounds.h"
40
41// the list of ceilings moving currently, including crushers
42ceilinglist_t *activeceilings;
43
44/////////////////////////////////////////////////////////////////
45//
46// Ceiling action routine and linedef type handler
47//
48/////////////////////////////////////////////////////////////////
49
50//
51// T_MoveCeiling
52//
53// Action routine that moves ceilings. Called once per tick.
54//
55// Passed a ceiling_t structure that contains all the info about the move.
56// see P_SPEC.H for fields. No return.
57//
58// jff 02/08/98 all cases with labels beginning with gen added to support
59// generalized line type behaviors.
60//
61void T_MoveCeiling (ceiling_t* ceiling)
62{
63 result_e res;
64
65 switch(ceiling->direction)
66 {
67 case 0:
68 // If ceiling in stasis, do nothing
69 break;
70
71 case 1:
72 // Ceiling is moving up
73 res = T_MovePlane
74 (
75 ceiling->sector,
76 ceiling->speed,
77 ceiling->topheight,
78 false,
79 1,
80 ceiling->direction
81 );
82
83 // if not a silent crusher, make moving sound
84 if (!(leveltime&7))
85 {
86 switch(ceiling->type)
87 {
88 case silentCrushAndRaise:
89 case genSilentCrusher:
90 break;
91 default:
92 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov);
93 break;
94 }
95 }
96
97 // handle reaching destination height
98 if (res == pastdest)
99 {
100 switch(ceiling->type)
101 {
102 // plain movers are just removed
103 case raiseToHighest:
104 case genCeiling:
105 P_RemoveActiveCeiling(ceiling);
106 break;
107
108 // movers with texture change, change the texture then get removed
109 case genCeilingChgT:
110 case genCeilingChg0:
111 ceiling->sector->special = ceiling->newspecial;
112 //jff 3/14/98 transfer old special field as well
113 ceiling->sector->oldspecial = ceiling->oldspecial;
114 case genCeilingChg:
115 ceiling->sector->ceilingpic = ceiling->texture;
116 P_RemoveActiveCeiling(ceiling);
117 break;
118
119 // crushers reverse direction at the top
120 case silentCrushAndRaise:
121 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
122 case genSilentCrusher:
123 case genCrusher:
124 case fastCrushAndRaise:
125 case crushAndRaise:
126 ceiling->direction = -1;
127 break;
128
129 default:
130 break;
131 }
132 }
133 break;
134
135 case -1:
136 // Ceiling moving down
137 res = T_MovePlane
138 (
139 ceiling->sector,
140 ceiling->speed,
141 ceiling->bottomheight,
142 ceiling->crush,
143 1,
144 ceiling->direction
145 );
146
147 // if not silent crusher type make moving sound
148 if (!(leveltime&7))
149 {
150 switch(ceiling->type)
151 {
152 case silentCrushAndRaise:
153 case genSilentCrusher:
154 break;
155 default:
156 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov);
157 }
158 }
159
160 // handle reaching destination height
161 if (res == pastdest)
162 {
163 switch(ceiling->type)
164 {
165 // 02/09/98 jff change slow crushers' speed back to normal
166 // start back up
167 case genSilentCrusher:
168 case genCrusher:
169 if (ceiling->oldspeed<CEILSPEED*3)
170 ceiling->speed = ceiling->oldspeed;
171 ceiling->direction = 1; //jff 2/22/98 make it go back up!
172 break;
173
174 // make platform stop at bottom of all crusher strokes
175 // except generalized ones, reset speed, start back up
176 case silentCrushAndRaise:
177 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
178 case crushAndRaise:
179 ceiling->speed = CEILSPEED;
180 case fastCrushAndRaise:
181 ceiling->direction = 1;
182 break;
183
184 // in the case of ceiling mover/changer, change the texture
185 // then remove the active ceiling
186 case genCeilingChgT:
187 case genCeilingChg0:
188 ceiling->sector->special = ceiling->newspecial;
189 //jff add to fix bug in special transfers from changes
190 ceiling->sector->oldspecial = ceiling->oldspecial;
191 case genCeilingChg:
192 ceiling->sector->ceilingpic = ceiling->texture;
193 P_RemoveActiveCeiling(ceiling);
194 break;
195
196 // all other case, just remove the active ceiling
197 case lowerAndCrush:
198 case lowerToFloor:
199 case lowerToLowest:
200 case lowerToMaxFloor:
201 case genCeiling:
202 P_RemoveActiveCeiling(ceiling);
203 break;
204
205 default:
206 break;
207 }
208 }
209 else // ( res != pastdest )
210 {
211 // handle the crusher encountering an obstacle
212 if (res == crushed)
213 {
214 switch(ceiling->type)
215 {
216 //jff 02/08/98 slow down slow crushers on obstacle
217 case genCrusher:
218 case genSilentCrusher:
219 if (ceiling->oldspeed < CEILSPEED*3)
220 ceiling->speed = CEILSPEED / 8;
221 break;
222 case silentCrushAndRaise:
223 case crushAndRaise:
224 case lowerAndCrush:
225 ceiling->speed = CEILSPEED / 8;
226 break;
227
228 default:
229 break;
230 }
231 }
232 }
233 break;
234 }
235}
236
237
238//
239// EV_DoCeiling
240//
241// Move a ceiling up/down or start a crusher
242//
243// Passed the linedef activating the function and the type of function desired
244// returns true if a thinker started
245//
246int EV_DoCeiling
247( line_t* line,
248 ceiling_e type )
249{
250 int secnum;
251 int rtn;
252 sector_t* sec;
253 ceiling_t* ceiling;
254
255 secnum = -1;
256 rtn = 0;
257
258 // Reactivate in-stasis ceilings...for certain types.
259 // This restarts a crusher after it has been stopped
260 switch(type)
261 {
262 case fastCrushAndRaise:
263 case silentCrushAndRaise:
264 case crushAndRaise:
265 //jff 4/5/98 return if activated
266 rtn = P_ActivateInStasisCeiling(line);
267 default:
268 break;
269 }
270
271 // affects all sectors with the same tag as the linedef
272 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
273 {
274 sec = &sectors[secnum];
275
276 // if ceiling already moving, don't start a second function on it
277 if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
278 continue;
279
280 // create a new ceiling thinker
281 rtn = 1;
282 ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
283 memset(ceiling, 0, sizeof(*ceiling));
284 P_AddThinker (&ceiling->thinker);
285 sec->ceilingdata = ceiling; //jff 2/22/98
286 ceiling->thinker.function = T_MoveCeiling;
287 ceiling->sector = sec;
288 ceiling->crush = false;
289
290 // setup ceiling structure according to type of function
291 switch(type)
292 {
293 case fastCrushAndRaise:
294 ceiling->crush = true;
295 ceiling->topheight = sec->ceilingheight;
296 ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
297 ceiling->direction = -1;
298 ceiling->speed = CEILSPEED * 2;
299 break;
300
301 case silentCrushAndRaise:
302 case crushAndRaise:
303 ceiling->crush = true;
304 ceiling->topheight = sec->ceilingheight;
305 case lowerAndCrush:
306 case lowerToFloor:
307 ceiling->bottomheight = sec->floorheight;
308 if (type != lowerToFloor)
309 ceiling->bottomheight += 8*FRACUNIT;
310 ceiling->direction = -1;
311 ceiling->speed = CEILSPEED;
312 break;
313
314 case raiseToHighest:
315 ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
316 ceiling->direction = 1;
317 ceiling->speed = CEILSPEED;
318 break;
319
320 case lowerToLowest:
321 ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec);
322 ceiling->direction = -1;
323 ceiling->speed = CEILSPEED;
324 break;
325
326 case lowerToMaxFloor:
327 ceiling->bottomheight = P_FindHighestFloorSurrounding(sec);
328 ceiling->direction = -1;
329 ceiling->speed = CEILSPEED;
330 break;
331
332 default:
333 break;
334 }
335
336 // add the ceiling to the active list
337 ceiling->tag = sec->tag;
338 ceiling->type = type;
339 P_AddActiveCeiling(ceiling);
340 }
341 return rtn;
342}
343
344//////////////////////////////////////////////////////////////////////
345//
346// Active ceiling list primitives
347//
348/////////////////////////////////////////////////////////////////////
349
350// jff 2/22/98 - modified Lee's plat code to work for ceilings
351//
352// The following were all rewritten by Lee Killough
353// to use the new structure which places no limits
354// on active ceilings. It also avoids spending as much
355// time searching for active ceilings. Previously a
356// fixed-size array was used, with NULL indicating
357// empty entries, while now a doubly-linked list
358// is used.
359
360//
361// P_ActivateInStasisCeiling()
362//
363// Reactivates all stopped crushers with the right tag
364//
365// Passed the line reactivating the crusher
366// Returns true if a ceiling reactivated
367//
368//jff 4/5/98 return if activated
369int P_ActivateInStasisCeiling(line_t *line)
370{
371 ceilinglist_t *cl;
372 int rtn=0;
373
374 for (cl=activeceilings; cl; cl=cl->next)
375 {
376 ceiling_t *ceiling = cl->ceiling;
377 if (ceiling->tag == line->tag && ceiling->direction == 0)
378 {
379 ceiling->direction = ceiling->olddirection;
380 ceiling->thinker.function = T_MoveCeiling;
381 //jff 4/5/98 return if activated
382 rtn=1;
383 }
384 }
385 return rtn;
386}
387
388//
389// EV_CeilingCrushStop()
390//
391// Stops all active ceilings with the right tag
392//
393// Passed the linedef stopping the ceilings
394// Returns true if a ceiling put in stasis
395//
396int EV_CeilingCrushStop(line_t* line)
397{
398 int rtn=0;
399
400 ceilinglist_t *cl;
401 for (cl=activeceilings; cl; cl=cl->next)
402 {
403 ceiling_t *ceiling = cl->ceiling;
404 if (ceiling->direction != 0 && ceiling->tag == line->tag)
405 {
406 ceiling->olddirection = ceiling->direction;
407 ceiling->direction = 0;
408 ceiling->thinker.function = NULL;
409 rtn=1;
410 }
411 }
412 return rtn;
413}
414
415//
416// P_AddActiveCeiling()
417//
418// Adds a ceiling to the head of the list of active ceilings
419//
420// Passed the ceiling motion structure
421// Returns nothing
422//
423void P_AddActiveCeiling(ceiling_t* ceiling)
424{
425 ceilinglist_t *list = malloc(sizeof *list);
426 list->ceiling = ceiling;
427 ceiling->list = list;
428 if ((list->next = activeceilings))
429 list->next->prev = &list->next;
430 list->prev = &activeceilings;
431 activeceilings = list;
432}
433
434//
435// P_RemoveActiveCeiling()
436//
437// Removes a ceiling from the list of active ceilings
438//
439// Passed the ceiling motion structure
440// Returns nothing
441//
442void P_RemoveActiveCeiling(ceiling_t* ceiling)
443{
444 ceilinglist_t *list = ceiling->list;
445 ceiling->sector->ceilingdata = NULL; //jff 2/22/98
446 P_RemoveThinker(&ceiling->thinker);
447 if ((*list->prev = list->next))
448 list->next->prev = list->prev;
449 free(list);
450}
451
452//
453// P_RemoveAllActiveCeilings()
454//
455// Removes all ceilings from the active ceiling list
456//
457// Passed nothing, returns nothing
458//
459void P_RemoveAllActiveCeilings(void)
460{
461 while (activeceilings)
462 {
463 ceilinglist_t *next = activeceilings->next;
464 free(activeceilings);
465 activeceilings = next;
466 }
467}
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 @@
1#include <stdio.h>
2#include <string.h>
3#include <errno.h>
4#include <stdlib.h> /* exit(), atexit() */
5
6#include "p_checksum.h"
7#include "md5.h"
8#include "doomstat.h" /* players{,ingame} */
9#include "lprintf.h"
10
11/* forward decls */
12static void p_checksum_cleanup(void);
13void checksum_gamestate(int tic);
14
15/* vars */
16static void p_checksum_nop(int tic){} /* do nothing */
17void (*P_Checksum)(int) = p_checksum_nop;
18
19/*
20 * P_RecordChecksum
21 * sets up the file and function pointers to write out checksum data
22 */
23static FILE *outfile = NULL;
24static struct MD5Context md5global;
25
26void P_RecordChecksum(const char *file) {
27 size_t fnsize;
28
29 fnsize = strlen(file);
30
31 /* special case: write to stdout */
32 if(0 == strncmp("-",file,MIN(1,fnsize)))
33 outfile = stdout;
34 else {
35 outfile = fopen(file,"wb");
36 if(NULL == outfile) {
37 I_Error("cannot open %s for writing checksum:\n%s\n",
38 file, strerror(errno));
39 }
40 atexit(p_checksum_cleanup);
41 }
42
43 MD5Init(&md5global);
44
45 P_Checksum = checksum_gamestate;
46}
47
48void P_ChecksumFinal(void) {
49 int i;
50 unsigned char digest[16];
51
52 if (!outfile)
53 return;
54
55 MD5Final(digest, &md5global);
56 fprintf(outfile, "final: ");
57 for (i=0; i<16; i++)
58 fprintf(outfile,"%x", digest[i]);
59 fprintf(outfile, "\n");
60 MD5Init(&md5global);
61}
62
63static void p_checksum_cleanup(void) {
64 if (outfile && (outfile != stdout))
65 fclose(outfile);
66}
67
68/*
69 * runs on each tic when recording checksums
70 */
71void checksum_gamestate(int tic) {
72 int i;
73 struct MD5Context md5ctx;
74 unsigned char digest[16];
75 char buffer[2048];
76
77 fprintf(outfile,"%6d, ", tic);
78
79 /* based on "ArchivePlayers" */
80 MD5Init(&md5ctx);
81 for (i=0 ; i<MAXPLAYERS ; i++) {
82 if (!playeringame[i]) continue;
83
84#ifdef HAVE_SNPRINTF
85 snprintf (buffer, sizeof(buffer), "%d", players[i].health);
86#else
87 sprintf (buffer, "%d", players[i].health);
88#endif
89 buffer[sizeof(buffer)-1] = 0;
90
91 MD5Update(&md5ctx, (md5byte const *)&buffer, strlen(buffer));
92 }
93 MD5Final(digest, &md5ctx);
94 for (i=0; i<16; i++) {
95 MD5Update(&md5global, (md5byte const *)&digest[i], sizeof(digest[i]));
96 fprintf(outfile,"%x", digest[i]);
97 }
98
99 fprintf(outfile,"\n");
100}
diff --git a/src/p_checksum.h b/src/p_checksum.h
new file mode 100644
index 0000000..8bce768
--- /dev/null
+++ b/src/p_checksum.h
@@ -0,0 +1,4 @@
1extern void (*P_Checksum)(int);
2extern void P_ChecksumFinal(void);
3void P_RecordChecksum(const char *file);
4//void P_VerifyChecksum(const char *file);
diff --git a/src/p_doors.c b/src/p_doors.c
new file mode 100644
index 0000000..ba9561c
--- /dev/null
+++ b/src/p_doors.c
@@ -0,0 +1,711 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Door animation code (opening/closing)
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "p_spec.h"
36#include "p_tick.h"
37#include "s_sound.h"
38#include "sounds.h"
39#include "r_main.h"
40#include "dstrings.h"
41#include "d_deh.h" // Ty 03/27/98 - externalized
42#include "lprintf.h"
43
44///////////////////////////////////////////////////////////////
45//
46// Door action routines, called once per tick
47//
48///////////////////////////////////////////////////////////////
49
50//
51// T_VerticalDoor
52//
53// Passed a door structure containing all info about the door.
54// See P_SPEC.H for fields.
55// Returns nothing.
56//
57// jff 02/08/98 all cases with labels beginning with gen added to support
58// generalized line type behaviors.
59
60void T_VerticalDoor (vldoor_t* door)
61{
62 result_e res;
63
64 // Is the door waiting, going up, or going down?
65 switch(door->direction)
66 {
67 case 0:
68 // Door is waiting
69 if (!--door->topcountdown) // downcount and check
70 {
71 switch(door->type)
72 {
73 case blazeRaise:
74 case genBlazeRaise:
75 door->direction = -1; // time to go back down
76 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls);
77 break;
78
79 case normal:
80 case genRaise:
81 door->direction = -1; // time to go back down
82 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls);
83 break;
84
85 case close30ThenOpen:
86 case genCdO:
87 door->direction = 1; // time to go back up
88 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn);
89 break;
90
91 case genBlazeCdO:
92 door->direction = 1; // time to go back up
93 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn);
94 break;
95
96 default:
97 break;
98 }
99 }
100 break;
101
102 case 2:
103 // Special case for sector type door that opens in 5 mins
104 if (!--door->topcountdown) // 5 minutes up?
105 {
106 switch(door->type)
107 {
108 case raiseIn5Mins:
109 door->direction = 1; // time to raise then
110 door->type = normal; // door acts just like normal 1 DR door now
111 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn);
112 break;
113
114 default:
115 break;
116 }
117 }
118 break;
119
120 case -1:
121 // Door is moving down
122 res = T_MovePlane
123 (
124 door->sector,
125 door->speed,
126 door->sector->floorheight,
127 false,
128 1,
129 door->direction
130 );
131
132 /* killough 10/98: implement gradual lighting effects */
133 // e6y: "Tagged doors don't trigger special lighting" handled wrong
134 // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943
135 // Old code: if (door->lighttag && door->topheight - door->sector->floorheight)
136 if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level >= mbf_compatibility)
137 EV_LightTurnOnPartway(door->line,
138 FixedDiv(door->sector->ceilingheight -
139 door->sector->floorheight,
140 door->topheight -
141 door->sector->floorheight));
142
143 // handle door reaching bottom
144 if (res == pastdest)
145 {
146 switch(door->type)
147 {
148 // regular open and close doors are all done, remove them
149 case blazeRaise:
150 case blazeClose:
151 case genBlazeRaise:
152 case genBlazeClose:
153 door->sector->ceilingdata = NULL; //jff 2/22/98
154 P_RemoveThinker (&door->thinker); // unlink and free
155 // killough 4/15/98: remove double-closing sound of blazing doors
156 if (comp[comp_blazing])
157 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls);
158 break;
159
160 case normal:
161 case close:
162 case genRaise:
163 case genClose:
164 door->sector->ceilingdata = NULL; //jff 2/22/98
165 P_RemoveThinker (&door->thinker); // unlink and free
166 break;
167
168 // close then open doors start waiting
169 case close30ThenOpen:
170 door->direction = 0;
171 door->topcountdown = TICRATE*30;
172 break;
173
174 case genCdO:
175 case genBlazeCdO:
176 door->direction = 0;
177 door->topcountdown = door->topwait; // jff 5/8/98 insert delay
178 break;
179
180 default:
181 break;
182 }
183 // e6y: "Tagged doors don't trigger special lighting" handled wrong
184 // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943
185 if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level < mbf_compatibility)
186 EV_LightTurnOnPartway(door->line,0);
187 }
188 /* jff 1/31/98 turn lighting off in tagged sectors of manual doors
189 * killough 10/98: replaced with gradual lighting code
190 */
191 else if (res == crushed) // handle door meeting obstruction on way down
192 {
193 switch(door->type)
194 {
195 case genClose:
196 case genBlazeClose:
197 case blazeClose:
198 case close: // Close types do not bounce, merely wait
199 break;
200
201 case blazeRaise:
202 case genBlazeRaise:
203 door->direction = 1;
204 if (!comp[comp_blazing]) {
205 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn);
206 break;
207 }
208
209 default: // other types bounce off the obstruction
210 door->direction = 1;
211 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn);
212 break;
213 }
214 }
215 break;
216
217 case 1:
218 // Door is moving up
219 res = T_MovePlane
220 (
221 door->sector,
222 door->speed,
223 door->topheight,
224 false,
225 1,
226 door->direction
227 );
228
229 /* killough 10/98: implement gradual lighting effects */
230 // e6y: "Tagged doors don't trigger special lighting" handled wrong
231 // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943
232 // Old code: if (door->lighttag && door->topheight - door->sector->floorheight)
233 if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level >= mbf_compatibility)
234 EV_LightTurnOnPartway(door->line,
235 FixedDiv(door->sector->ceilingheight -
236 door->sector->floorheight,
237 door->topheight -
238 door->sector->floorheight));
239
240 // handle door reaching the top
241 if (res == pastdest)
242 {
243 switch(door->type)
244 {
245 case blazeRaise: // regular open/close doors start waiting
246 case normal:
247 case genRaise:
248 case genBlazeRaise:
249 door->direction = 0; // wait at top with delay
250 door->topcountdown = door->topwait;
251 break;
252
253 case close30ThenOpen: // close and close/open doors are done
254 case blazeOpen:
255 case open:
256 case genBlazeOpen:
257 case genOpen:
258 case genCdO:
259 case genBlazeCdO:
260 door->sector->ceilingdata = NULL; //jff 2/22/98
261 P_RemoveThinker (&door->thinker); // unlink and free
262 break;
263
264 default:
265 break;
266 }
267
268 /* jff 1/31/98 turn lighting on in tagged sectors of manual doors
269 * killough 10/98: replaced with gradual lighting code */
270 // e6y: "Tagged doors don't trigger special lighting" handled wrong
271 // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943
272 if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level < mbf_compatibility)
273 EV_LightTurnOnPartway(door->line,FRACUNIT);
274 }
275 break;
276 }
277}
278
279///////////////////////////////////////////////////////////////
280//
281// Door linedef handlers
282//
283///////////////////////////////////////////////////////////////
284
285//
286// EV_DoLockedDoor
287//
288// Handle opening a tagged locked door
289//
290// Passed the line activating the door, the type of door,
291// and the thing that activated the line
292// Returns true if a thinker created
293//
294int EV_DoLockedDoor
295( line_t* line,
296 vldoor_e type,
297 mobj_t* thing )
298{
299 player_t* p;
300
301 // only players can open locked doors
302 p = thing->player;
303 if (!p)
304 return 0;
305
306 // check type of linedef, and if key is possessed to open it
307 switch(line->special)
308 {
309 case 99: // Blue Lock
310 case 133:
311 if (!p->cards[it_bluecard] && !p->cards[it_blueskull])
312 {
313 p->message = s_PD_BLUEO; // Ty 03/27/98 - externalized
314 S_StartSound(p->mo,sfx_oof); // killough 3/20/98
315 return 0;
316 }
317 break;
318
319 case 134: // Red Lock
320 case 135:
321 if (!p->cards[it_redcard] && !p->cards[it_redskull])
322 {
323 p->message = s_PD_REDO; // Ty 03/27/98 - externalized
324 S_StartSound(p->mo,sfx_oof); // killough 3/20/98
325 return 0;
326 }
327 break;
328
329 case 136: // Yellow Lock
330 case 137:
331 if (!p->cards[it_yellowcard] && !p->cards[it_yellowskull])
332 {
333 p->message = s_PD_YELLOWO; // Ty 03/27/98 - externalized
334 S_StartSound(p->mo,sfx_oof); // killough 3/20/98
335 return 0;
336 }
337 break;
338 }
339
340 // got the key, so open the door
341 return EV_DoDoor(line,type);
342}
343
344
345//
346// EV_DoDoor
347//
348// Handle opening a tagged door
349//
350// Passed the line activating the door and the type of door
351// Returns true if a thinker created
352//
353int EV_DoDoor
354( line_t* line,
355 vldoor_e type )
356{
357 int secnum,rtn;
358 sector_t* sec;
359 vldoor_t* door;
360
361 secnum = -1;
362 rtn = 0;
363
364 // open all doors with the same tag as the activating line
365 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
366 {
367 sec = &sectors[secnum];
368 // if the ceiling already moving, don't start the door action
369 if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
370 continue;
371
372 // new door thinker
373 rtn = 1;
374 door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
375 memset(door, 0, sizeof(*door));
376 P_AddThinker (&door->thinker);
377 sec->ceilingdata = door; //jff 2/22/98
378
379 door->thinker.function = T_VerticalDoor;
380 door->sector = sec;
381 door->type = type;
382 door->topwait = VDOORWAIT;
383 door->speed = VDOORSPEED;
384 door->line = line; // jff 1/31/98 remember line that triggered us
385 door->lighttag = 0; /* killough 10/98: no light effects with tagged doors */
386
387 // setup door parameters according to type of door
388 switch(type)
389 {
390 case blazeClose:
391 door->topheight = P_FindLowestCeilingSurrounding(sec);
392 door->topheight -= 4*FRACUNIT;
393 door->direction = -1;
394 door->speed = VDOORSPEED * 4;
395 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls);
396 break;
397
398 case close:
399 door->topheight = P_FindLowestCeilingSurrounding(sec);
400 door->topheight -= 4*FRACUNIT;
401 door->direction = -1;
402 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls);
403 break;
404
405 case close30ThenOpen:
406 door->topheight = sec->ceilingheight;
407 door->direction = -1;
408 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls);
409 break;
410
411 case blazeRaise:
412 case blazeOpen:
413 door->direction = 1;
414 door->topheight = P_FindLowestCeilingSurrounding(sec);
415 door->topheight -= 4*FRACUNIT;
416 door->speed = VDOORSPEED * 4;
417 if (door->topheight != sec->ceilingheight)
418 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn);
419 break;
420
421 case normal:
422 case open:
423 door->direction = 1;
424 door->topheight = P_FindLowestCeilingSurrounding(sec);
425 door->topheight -= 4*FRACUNIT;
426 if (door->topheight != sec->ceilingheight)
427 S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn);
428 break;
429
430 default:
431 break;
432 }
433 }
434 return rtn;
435}
436
437
438//
439// EV_VerticalDoor
440//
441// Handle opening a door manually, no tag value
442//
443// Passed the line activating the door and the thing activating it
444// Returns true if a thinker created
445//
446// jff 2/12/98 added int return value, fixed all returns
447//
448int EV_VerticalDoor
449( line_t* line,
450 mobj_t* thing )
451{
452 player_t* player;
453 int secnum;
454 sector_t* sec;
455 vldoor_t* door;
456
457 // Check for locks
458 player = thing->player;
459
460 switch(line->special)
461 {
462 case 26: // Blue Lock
463 case 32:
464 if ( !player )
465 return 0;
466 if (!player->cards[it_bluecard] && !player->cards[it_blueskull])
467 {
468 player->message = s_PD_BLUEK; // Ty 03/27/98 - externalized
469 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
470 return 0;
471 }
472 break;
473
474 case 27: // Yellow Lock
475 case 34:
476 if ( !player )
477 return 0;
478 if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull])
479 {
480 player->message = s_PD_YELLOWK; // Ty 03/27/98 - externalized
481 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
482 return 0;
483 }
484 break;
485
486 case 28: // Red Lock
487 case 33:
488 if ( !player )
489 return 0;
490 if (!player->cards[it_redcard] && !player->cards[it_redskull])
491 {
492 player->message = s_PD_REDK; // Ty 03/27/98 - externalized
493 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
494 return 0;
495 }
496 break;
497
498 default:
499 break;
500 }
501
502 // if the wrong side of door is pushed, give oof sound
503 if (line->sidenum[1]==NO_INDEX) // killough
504 {
505 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
506 return 0;
507 }
508
509 // get the sector on the second side of activating linedef
510 sec = sides[line->sidenum[1]].sector;
511 secnum = sec-sectors;
512
513 /* if door already has a thinker, use it
514 * cph 2001/04/05 -
515 * Ok, this is a disaster area. We're assuming that sec->ceilingdata
516 * is a vldoor_t! What if this door is controlled by both DR lines
517 * and by switches? I don't know how to fix that.
518 * Secondly, original Doom didn't distinguish floor/lighting/ceiling
519 * actions, so we need to do the same in demo compatibility mode.
520 */
521 door = sec->ceilingdata;
522 if (demo_compatibility) {
523 if (!door) door = sec->floordata;
524 if (!door) door = sec->lightingdata;
525 }
526 /* 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) */
527 if (door &&
528 ((compatibility_level == prboom_4_compatibility) ||
529 (line->special == 1) || (line->special == 117) || (line->special == 26) || (line->special == 27) || (line->special == 28)
530 )
531 ) {
532 /* For old demos we have to emulate the old buggy behavior and
533 * mess up non-T_VerticalDoor actions.
534 */
535 if (compatibility_level < prboom_4_compatibility ||
536 door->thinker.function == T_VerticalDoor) {
537 /* cph - we are writing outval to door->direction iff it is non-zero */
538 signed int outval = 0;
539
540 /* An already moving repeatable door which is being re-pressed, or a
541 * monster is trying to open a closing door - so change direction
542 * DEMOSYNC: we only read door->direction now if it really is a door.
543 */
544 if (door->thinker.function == T_VerticalDoor && door->direction == -1) {
545 outval = 1; /* go back up */
546 } else if (player) {
547 outval = -1; /* go back down */
548 }
549
550 /* Write this to the thinker. In demo compatibility mode, we might be
551 * overwriting a field of a non-vldoor_t thinker - we need to add any
552 * other thinker types here if any demos depend on specific fields
553 * being corrupted by this.
554 */
555 if (outval) {
556 if (door->thinker.function == T_VerticalDoor) {
557 door->direction = outval;
558 } else if (door->thinker.function == T_PlatRaise) {
559 plat_t* p = (plat_t*)door;
560 p->wait = outval;
561 } else {
562 lprintf(LO_DEBUG, "EV_VerticalDoor: unknown thinker.function in thinker corruption emulation");
563 }
564
565 return 1;
566 }
567 }
568 /* Either we're in prboom >=v2.3 and it's not a door, or it's a door but
569 * we're a monster and don't want to shut it; exit with no action.
570 */
571 return 0;
572 }
573
574 // emit proper sound
575 switch(line->special)
576 {
577 case 117: // blazing door raise
578 case 118: // blazing door open
579 S_StartSound((mobj_t *)&sec->soundorg,sfx_bdopn);
580 break;
581
582 default: // normal or locked door sound
583 S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn);
584 break;
585 }
586
587 // new door thinker
588 door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
589 memset(door, 0, sizeof(*door));
590 P_AddThinker (&door->thinker);
591 sec->ceilingdata = door; //jff 2/22/98
592 door->thinker.function = T_VerticalDoor;
593 door->sector = sec;
594 door->direction = 1;
595 door->speed = VDOORSPEED;
596 door->topwait = VDOORWAIT;
597 door->line = line; // jff 1/31/98 remember line that triggered us
598
599 /* killough 10/98: use gradual lighting changes if nonzero tag given */
600 door->lighttag = comp[comp_doorlight] ? 0 : line->tag;
601
602 // set the type of door from the activating linedef type
603 switch(line->special)
604 {
605 case 1:
606 case 26:
607 case 27:
608 case 28:
609 door->type = normal;
610 break;
611
612 case 31:
613 case 32:
614 case 33:
615 case 34:
616 door->type = open;
617 line->special = 0;
618 break;
619
620 case 117: // blazing door raise
621 door->type = blazeRaise;
622 door->speed = VDOORSPEED*4;
623 break;
624 case 118: // blazing door open
625 door->type = blazeOpen;
626 line->special = 0;
627 door->speed = VDOORSPEED*4;
628 break;
629
630 default:
631 door->lighttag = 0; // killough 10/98
632 break;
633 }
634
635 // find the top and bottom of the movement range
636 door->topheight = P_FindLowestCeilingSurrounding(sec);
637 door->topheight -= 4*FRACUNIT;
638 return 1;
639}
640
641
642///////////////////////////////////////////////////////////////
643//
644// Sector type door spawners
645//
646///////////////////////////////////////////////////////////////
647
648//
649// P_SpawnDoorCloseIn30()
650//
651// Spawn a door that closes after 30 seconds (called at level init)
652//
653// Passed the sector of the door, whose type specified the door action
654// Returns nothing
655//
656void P_SpawnDoorCloseIn30 (sector_t* sec)
657{
658 vldoor_t* door;
659
660 door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0);
661
662 memset(door, 0, sizeof(*door));
663 P_AddThinker (&door->thinker);
664
665 sec->ceilingdata = door; //jff 2/22/98
666 sec->special = 0;
667
668 door->thinker.function = T_VerticalDoor;
669 door->sector = sec;
670 door->direction = 0;
671 door->type = normal;
672 door->speed = VDOORSPEED;
673 door->topcountdown = 30 * 35;
674 door->line = NULL; // jff 1/31/98 remember line that triggered us
675 door->lighttag = 0; /* killough 10/98: no lighting changes */
676}
677
678//
679// P_SpawnDoorRaiseIn5Mins()
680//
681// Spawn a door that opens after 5 minutes (called at level init)
682//
683// Passed the sector of the door, whose type specified the door action
684// Returns nothing
685//
686void P_SpawnDoorRaiseIn5Mins
687( sector_t* sec,
688 int secnum )
689{
690 vldoor_t* door;
691
692 door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0);
693
694 memset(door, 0, sizeof(*door));
695 P_AddThinker (&door->thinker);
696
697 sec->ceilingdata = door; //jff 2/22/98
698 sec->special = 0;
699
700 door->thinker.function = T_VerticalDoor;
701 door->sector = sec;
702 door->direction = 2;
703 door->type = raiseIn5Mins;
704 door->speed = VDOORSPEED;
705 door->topheight = P_FindLowestCeilingSurrounding(sec);
706 door->topheight -= 4*FRACUNIT;
707 door->topwait = VDOORWAIT;
708 door->topcountdown = 5 * 60 * 35;
709 door->line = NULL; // jff 1/31/98 remember line that triggered us
710 door->lighttag = 0; /* killough 10/98: no lighting changes */
711}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000,2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Enemy thinking, AI.
31 * Action Pointer Functions
32 * that are associated with states/frames.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#include "doomstat.h"
37#include "m_random.h"
38#include "r_main.h"
39#include "p_maputl.h"
40#include "p_map.h"
41#include "p_setup.h"
42#include "p_spec.h"
43#include "s_sound.h"
44#include "sounds.h"
45#include "p_inter.h"
46#include "g_game.h"
47#include "p_enemy.h"
48#include "p_tick.h"
49#include "m_bbox.h"
50#include "lprintf.h"
51
52static mobj_t *current_actor;
53
54typedef enum {
55 DI_EAST,
56 DI_NORTHEAST,
57 DI_NORTH,
58 DI_NORTHWEST,
59 DI_WEST,
60 DI_SOUTHWEST,
61 DI_SOUTH,
62 DI_SOUTHEAST,
63 DI_NODIR,
64 NUMDIRS
65} dirtype_t;
66
67static void P_NewChaseDir(mobj_t *actor);
68void P_ZBumpCheck(mobj_t *); // phares
69
70//
71// ENEMY THINKING
72// Enemies are allways spawned
73// with targetplayer = -1, threshold = 0
74// Most monsters are spawned unaware of all players,
75// but some can be made preaware
76//
77
78//
79// Called by P_NoiseAlert.
80// Recursively traverse adjacent sectors,
81// sound blocking lines cut off traversal.
82//
83// killough 5/5/98: reformatted, cleaned up
84
85static void P_RecursiveSound(sector_t *sec, int soundblocks,
86 mobj_t *soundtarget)
87{
88 int i;
89
90 // wake up all monsters in this sector
91 if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1)
92 return; // already flooded
93
94 sec->validcount = validcount;
95 sec->soundtraversed = soundblocks+1;
96 P_SetTarget(&sec->soundtarget, soundtarget);
97
98 for (i=0; i<sec->linecount; i++)
99 {
100 sector_t *other;
101 line_t *check = sec->lines[i];
102
103 if (!(check->flags & ML_TWOSIDED))
104 continue;
105
106 P_LineOpening(check);
107
108 if (openrange <= 0)
109 continue; // closed door
110
111 other=sides[check->sidenum[sides[check->sidenum[0]].sector==sec]].sector;
112
113 if (!(check->flags & ML_SOUNDBLOCK))
114 P_RecursiveSound(other, soundblocks, soundtarget);
115 else
116 if (!soundblocks)
117 P_RecursiveSound(other, 1, soundtarget);
118 }
119}
120
121//
122// P_NoiseAlert
123// If a monster yells at a player,
124// it will alert other monsters to the player.
125//
126void P_NoiseAlert(mobj_t *target, mobj_t *emitter)
127{
128 validcount++;
129 P_RecursiveSound(emitter->subsector->sector, 0, target);
130}
131
132//
133// P_CheckMeleeRange
134//
135
136static boolean P_CheckMeleeRange(mobj_t *actor)
137{
138 mobj_t *pl = actor->target;
139
140 return // killough 7/18/98: friendly monsters don't attack other friends
141 pl && !(actor->flags & pl->flags & MF_FRIEND) &&
142 (P_AproxDistance(pl->x-actor->x, pl->y-actor->y) <
143 MELEERANGE - 20*FRACUNIT + pl->info->radius) &&
144 P_CheckSight(actor, actor->target);
145}
146
147//
148// P_HitFriend()
149//
150// killough 12/98
151// This function tries to prevent shooting at friends
152
153static boolean P_HitFriend(mobj_t *actor)
154{
155 return actor->flags & MF_FRIEND && actor->target &&
156 (P_AimLineAttack(actor,
157 R_PointToAngle2(actor->x, actor->y,
158 actor->target->x, actor->target->y),
159 P_AproxDistance(actor->x-actor->target->x,
160 actor->y-actor->target->y), 0),
161 linetarget) && linetarget != actor->target &&
162 !((linetarget->flags ^ actor->flags) & MF_FRIEND);
163}
164
165//
166// P_CheckMissileRange
167//
168static boolean P_CheckMissileRange(mobj_t *actor)
169{
170 fixed_t dist;
171
172 if (!P_CheckSight(actor, actor->target))
173 return false;
174
175 if (actor->flags & MF_JUSTHIT)
176 { // the target just hit the enemy, so fight back!
177 actor->flags &= ~MF_JUSTHIT;
178
179 /* killough 7/18/98: no friendly fire at corpses
180 * killough 11/98: prevent too much infighting among friends
181 * cph - yikes, talk about fitting everything on one line... */
182
183 return
184 !(actor->flags & MF_FRIEND) ||
185 (actor->target->health > 0 &&
186 (!(actor->target->flags & MF_FRIEND) ||
187 (actor->target->player ?
188 monster_infighting || P_Random(pr_defect) >128 :
189 !(actor->target->flags & MF_JUSTHIT) && P_Random(pr_defect) >128)));
190 }
191
192 /* killough 7/18/98: friendly monsters don't attack other friendly
193 * monsters or players (except when attacked, and then only once)
194 */
195 if (actor->flags & actor->target->flags & MF_FRIEND)
196 return false;
197
198 if (actor->reactiontime)
199 return false; // do not attack yet
200
201 // OPTIMIZE: get this from a global checksight
202 dist = P_AproxDistance ( actor->x-actor->target->x,
203 actor->y-actor->target->y) - 64*FRACUNIT;
204
205 if (!actor->info->meleestate)
206 dist -= 128*FRACUNIT; // no melee attack, so fire more
207
208 dist >>= FRACBITS;
209
210 if (actor->type == MT_VILE)
211 if (dist > 14*64)
212 return false; // too far away
213
214
215 if (actor->type == MT_UNDEAD)
216 {
217 if (dist < 196)
218 return false; // close for fist attack
219 dist >>= 1;
220 }
221
222 if (actor->type == MT_CYBORG ||
223 actor->type == MT_SPIDER ||
224 actor->type == MT_SKULL)
225 dist >>= 1;
226
227 if (dist > 200)
228 dist = 200;
229
230 if (actor->type == MT_CYBORG && dist > 160)
231 dist = 160;
232
233 if (P_Random(pr_missrange) < dist)
234 return false;
235
236 if (P_HitFriend(actor))
237 return false;
238
239 return true;
240}
241
242/*
243 * P_IsOnLift
244 *
245 * killough 9/9/98:
246 *
247 * Returns true if the object is on a lift. Used for AI,
248 * since it may indicate the need for crowded conditions,
249 * or that a monster should stay on the lift for a while
250 * while it goes up or down.
251 */
252
253static boolean P_IsOnLift(const mobj_t *actor)
254{
255 const sector_t *sec = actor->subsector->sector;
256 line_t line;
257 int l;
258
259 // Short-circuit: it's on a lift which is active.
260 if (sec->floordata && ((thinker_t *) sec->floordata)->function==T_PlatRaise)
261 return true;
262
263 // Check to see if it's in a sector which can be activated as a lift.
264 if ((line.tag = sec->tag))
265 for (l = -1; (l = P_FindLineFromLineTag(&line, l)) >= 0;)
266 switch (lines[l].special)
267 {
268 case 10: case 14: case 15: case 20: case 21: case 22:
269 case 47: case 53: case 62: case 66: case 67: case 68:
270 case 87: case 88: case 95: case 120: case 121: case 122:
271 case 123: case 143: case 162: case 163: case 181: case 182:
272 case 144: case 148: case 149: case 211: case 227: case 228:
273 case 231: case 232: case 235: case 236:
274 return true;
275 }
276
277 return false;
278}
279
280/*
281 * P_IsUnderDamage
282 *
283 * killough 9/9/98:
284 *
285 * Returns nonzero if the object is under damage based on
286 * their current position. Returns 1 if the damage is moderate,
287 * -1 if it is serious. Used for AI.
288 */
289
290static int P_IsUnderDamage(mobj_t *actor)
291{
292 const struct msecnode_s *seclist;
293 const ceiling_t *cl; // Crushing ceiling
294 int dir = 0;
295 for (seclist=actor->touching_sectorlist; seclist; seclist=seclist->m_tnext)
296 if ((cl = seclist->m_sector->ceilingdata) &&
297 cl->thinker.function == T_MoveCeiling)
298 dir |= cl->direction;
299 return dir;
300}
301
302//
303// P_Move
304// Move in the current direction,
305// returns false if the move is blocked.
306//
307
308static fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
309static fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
310
311// 1/11/98 killough: Limit removed on special lines crossed
312extern line_t **spechit; // New code -- killough
313extern int numspechit;
314
315static boolean P_Move(mobj_t *actor, boolean dropoff) /* killough 9/12/98 */
316{
317 fixed_t tryx, tryy, deltax, deltay, origx, origy;
318 boolean try_ok;
319 int movefactor = ORIG_FRICTION_FACTOR; // killough 10/98
320 int friction = ORIG_FRICTION;
321 int speed;
322
323 if (actor->movedir == DI_NODIR)
324 return false;
325
326#ifdef RANGECHECK
327 if ((unsigned)actor->movedir >= 8)
328 I_Error ("P_Move: Weird actor->movedir!");
329#endif
330
331 // killough 10/98: make monsters get affected by ice and sludge too:
332
333 if (monster_friction)
334 movefactor = P_GetMoveFactor(actor, &friction);
335
336 speed = actor->info->speed;
337
338 if (friction < ORIG_FRICTION && // sludge
339 !(speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2)
340 * speed) / ORIG_FRICTION_FACTOR))
341 speed = 1; // always give the monster a little bit of speed
342
343 tryx = (origx = actor->x) + (deltax = speed * xspeed[actor->movedir]);
344 tryy = (origy = actor->y) + (deltay = speed * yspeed[actor->movedir]);
345
346 try_ok = P_TryMove(actor, tryx, tryy, dropoff);
347
348 // killough 10/98:
349 // Let normal momentum carry them, instead of steptoeing them across ice.
350
351 if (try_ok && friction > ORIG_FRICTION)
352 {
353 actor->x = origx;
354 actor->y = origy;
355 movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4;
356 actor->momx += FixedMul(deltax, movefactor);
357 actor->momy += FixedMul(deltay, movefactor);
358 }
359
360 if (!try_ok)
361 { // open any specials
362 int good;
363
364 if (actor->flags & MF_FLOAT && floatok)
365 {
366 if (actor->z < tmfloorz) // must adjust height
367 actor->z += FLOATSPEED;
368 else
369 actor->z -= FLOATSPEED;
370
371 actor->flags |= MF_INFLOAT;
372
373 return true;
374 }
375
376 if (!numspechit)
377 return false;
378
379 actor->movedir = DI_NODIR;
380
381 /* if the special is not a door that can be opened, return false
382 *
383 * killough 8/9/98: this is what caused monsters to get stuck in
384 * doortracks, because it thought that the monster freed itself
385 * by opening a door, even if it was moving towards the doortrack,
386 * and not the door itself.
387 *
388 * killough 9/9/98: If a line blocking the monster is activated,
389 * return true 90% of the time. If a line blocking the monster is
390 * not activated, but some other line is, return false 90% of the
391 * time. A bit of randomness is needed to ensure it's free from
392 * lockups, but for most cases, it returns the correct result.
393 *
394 * Do NOT simply return false 1/4th of the time (causes monsters to
395 * back out when they shouldn't, and creates secondary stickiness).
396 */
397
398 for (good = false; numspechit--; )
399 if (P_UseSpecialLine(actor, spechit[numspechit], 0))
400 good |= spechit[numspechit] == blockline ? 1 : 2;
401
402 /* cph - compatibility maze here
403 * Boom v2.01 and orig. Doom return "good"
404 * Boom v2.02 and LxDoom return good && (P_Random(pr_trywalk)&3)
405 * MBF plays even more games
406 */
407 if (!good || comp[comp_doorstuck]) return good;
408 if (!mbf_features)
409 return (P_Random(pr_trywalk)&3); /* jff 8/13/98 */
410 else /* finally, MBF code */
411 return ((P_Random(pr_opendoor) >= 230) ^ (good & 1));
412 }
413 else
414 actor->flags &= ~MF_INFLOAT;
415
416 /* killough 11/98: fall more slowly, under gravity, if felldown==true */
417 if (!(actor->flags & MF_FLOAT) &&
418 (!felldown || !mbf_features))
419 actor->z = actor->floorz;
420
421 return true;
422}
423
424/*
425 * P_SmartMove
426 *
427 * killough 9/12/98: Same as P_Move, except smarter
428 */
429
430static boolean P_SmartMove(mobj_t *actor)
431{
432 mobj_t *target = actor->target;
433 int on_lift, dropoff = false, under_damage;
434
435 /* killough 9/12/98: Stay on a lift if target is on one */
436 on_lift = !comp[comp_staylift]
437 && target && target->health > 0
438 && target->subsector->sector->tag==actor->subsector->sector->tag &&
439 P_IsOnLift(actor);
440
441 under_damage = monster_avoid_hazards && P_IsUnderDamage(actor);
442
443 // killough 10/98: allow dogs to drop off of taller ledges sometimes.
444 // dropoff==1 means always allow it, dropoff==2 means only up to 128 high,
445 // and only if the target is immediately on the other side of the line.
446
447#ifdef DOGS
448 // haleyjd: allow all friends of HelperType to also jump down
449
450 if ((actor->type == MT_DOGS || (actor->type == (HelperThing-1) && actor->flags&MF_FRIEND))
451 && target && dog_jumping &&
452 !((target->flags ^ actor->flags) & MF_FRIEND) &&
453 P_AproxDistance(actor->x - target->x,
454 actor->y - target->y) < FRACUNIT*144 &&
455 P_Random(pr_dropoff) < 235)
456 dropoff = 2;
457#endif
458
459 if (!P_Move(actor, dropoff))
460 return false;
461
462 // killough 9/9/98: avoid crushing ceilings or other damaging areas
463 if (
464 (on_lift && P_Random(pr_stayonlift) < 230 && // Stay on lift
465 !P_IsOnLift(actor))
466 ||
467 (monster_avoid_hazards && !under_damage && // Get away from damage
468 (under_damage = P_IsUnderDamage(actor)) &&
469 (under_damage < 0 || P_Random(pr_avoidcrush) < 200))
470 )
471 actor->movedir = DI_NODIR; // avoid the area (most of the time anyway)
472
473 return true;
474}
475
476//
477// TryWalk
478// Attempts to move actor on
479// in its current (ob->moveangle) direction.
480// If blocked by either a wall or an actor
481// returns FALSE
482// If move is either clear or blocked only by a door,
483// returns TRUE and sets...
484// If a door is in the way,
485// an OpenDoor call is made to start it opening.
486//
487
488static boolean P_TryWalk(mobj_t *actor)
489{
490 if (!P_SmartMove(actor))
491 return false;
492 actor->movecount = P_Random(pr_trywalk)&15;
493 return true;
494}
495
496//
497// P_DoNewChaseDir
498//
499// killough 9/8/98:
500//
501// Most of P_NewChaseDir(), except for what
502// determines the new direction to take
503//
504
505static void P_DoNewChaseDir(mobj_t *actor, fixed_t deltax, fixed_t deltay)
506{
507 dirtype_t xdir, ydir, tdir;
508 dirtype_t olddir = actor->movedir;
509 dirtype_t turnaround = olddir;
510
511 if (turnaround != DI_NODIR) // find reverse direction
512 turnaround ^= 4;
513
514 xdir =
515 deltax > 10*FRACUNIT ? DI_EAST :
516 deltax < -10*FRACUNIT ? DI_WEST : DI_NODIR;
517
518 ydir =
519 deltay < -10*FRACUNIT ? DI_SOUTH :
520 deltay > 10*FRACUNIT ? DI_NORTH : DI_NODIR;
521
522 // try direct route
523 if (xdir != DI_NODIR && ydir != DI_NODIR && turnaround !=
524 (actor->movedir = deltay < 0 ? deltax > 0 ? DI_SOUTHEAST : DI_SOUTHWEST :
525 deltax > 0 ? DI_NORTHEAST : DI_NORTHWEST) && P_TryWalk(actor))
526 return;
527
528 // try other directions
529 if (P_Random(pr_newchase) > 200 || D_abs(deltay)>D_abs(deltax))
530 tdir = xdir, xdir = ydir, ydir = tdir;
531
532 if ((xdir == turnaround ? xdir = DI_NODIR : xdir) != DI_NODIR &&
533 (actor->movedir = xdir, P_TryWalk(actor)))
534 return; // either moved forward or attacked
535
536 if ((ydir == turnaround ? ydir = DI_NODIR : ydir) != DI_NODIR &&
537 (actor->movedir = ydir, P_TryWalk(actor)))
538 return;
539
540 // there is no direct path to the player, so pick another direction.
541 if (olddir != DI_NODIR && (actor->movedir = olddir, P_TryWalk(actor)))
542 return;
543
544 // randomly determine direction of search
545 if (P_Random(pr_newchasedir) & 1)
546 {
547 for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
548 if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor)))
549 return;
550 }
551 else
552 for (tdir = DI_SOUTHEAST; tdir != DI_EAST-1; tdir--)
553 if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor)))
554 return;
555
556 if ((actor->movedir = turnaround) != DI_NODIR && !P_TryWalk(actor))
557 actor->movedir = DI_NODIR;
558}
559
560//
561// killough 11/98:
562//
563// Monsters try to move away from tall dropoffs.
564//
565// In Doom, they were never allowed to hang over dropoffs,
566// and would remain stuck if involuntarily forced over one.
567// This logic, combined with p_map.c (P_TryMove), allows
568// monsters to free themselves without making them tend to
569// hang over dropoffs.
570
571static fixed_t dropoff_deltax, dropoff_deltay, floorz;
572
573static boolean PIT_AvoidDropoff(line_t *line)
574{
575 if (line->backsector && // Ignore one-sided linedefs
576 tmbbox[BOXRIGHT] > line->bbox[BOXLEFT] &&
577 tmbbox[BOXLEFT] < line->bbox[BOXRIGHT] &&
578 tmbbox[BOXTOP] > line->bbox[BOXBOTTOM] && // Linedef must be contacted
579 tmbbox[BOXBOTTOM] < line->bbox[BOXTOP] &&
580 P_BoxOnLineSide(tmbbox, line) == -1)
581 {
582 fixed_t front = line->frontsector->floorheight;
583 fixed_t back = line->backsector->floorheight;
584 angle_t angle;
585
586 // The monster must contact one of the two floors,
587 // and the other must be a tall dropoff (more than 24).
588
589 if (back == floorz && front < floorz - FRACUNIT*24)
590 angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff
591 else
592 if (front == floorz && back < floorz - FRACUNIT*24)
593 angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff
594 else
595 return true;
596
597 // Move away from dropoff at a standard speed.
598 // Multiple contacted linedefs are cumulative (e.g. hanging over corner)
599 dropoff_deltax -= finesine[angle >> ANGLETOFINESHIFT]*32;
600 dropoff_deltay += finecosine[angle >> ANGLETOFINESHIFT]*32;
601 }
602 return true;
603}
604
605//
606// Driver for above
607//
608
609static fixed_t P_AvoidDropoff(mobj_t *actor)
610{
611 int yh=((tmbbox[BOXTOP] = actor->y+actor->radius)-bmaporgy)>>MAPBLOCKSHIFT;
612 int yl=((tmbbox[BOXBOTTOM]= actor->y-actor->radius)-bmaporgy)>>MAPBLOCKSHIFT;
613 int xh=((tmbbox[BOXRIGHT] = actor->x+actor->radius)-bmaporgx)>>MAPBLOCKSHIFT;
614 int xl=((tmbbox[BOXLEFT] = actor->x-actor->radius)-bmaporgx)>>MAPBLOCKSHIFT;
615 int bx, by;
616
617 floorz = actor->z; // remember floor height
618
619 dropoff_deltax = dropoff_deltay = 0;
620
621 // check lines
622
623 validcount++;
624 for (bx=xl ; bx<=xh ; bx++)
625 for (by=yl ; by<=yh ; by++)
626 P_BlockLinesIterator(bx, by, PIT_AvoidDropoff); // all contacted lines
627
628 return dropoff_deltax | dropoff_deltay; // Non-zero if movement prescribed
629}
630
631//
632// P_NewChaseDir
633//
634// killough 9/8/98: Split into two functions
635//
636
637static void P_NewChaseDir(mobj_t *actor)
638{
639 mobj_t *target = actor->target;
640 fixed_t deltax = target->x - actor->x;
641 fixed_t deltay = target->y - actor->y;
642
643 // killough 8/8/98: sometimes move away from target, keeping distance
644 //
645 // 1) Stay a certain distance away from a friend, to avoid being in their way
646 // 2) Take advantage over an enemy without missiles, by keeping distance
647
648 actor->strafecount = 0;
649
650 if (mbf_features) {
651 if (actor->floorz - actor->dropoffz > FRACUNIT*24 &&
652 actor->z <= actor->floorz &&
653 !(actor->flags & (MF_DROPOFF|MF_FLOAT)) &&
654 !comp[comp_dropoff] &&
655 P_AvoidDropoff(actor)) /* Move away from dropoff */
656 {
657 P_DoNewChaseDir(actor, dropoff_deltax, dropoff_deltay);
658
659 // If moving away from dropoff, set movecount to 1 so that
660 // small steps are taken to get monster away from dropoff.
661
662 actor->movecount = 1;
663 return;
664 }
665 else
666 {
667 fixed_t dist = P_AproxDistance(deltax, deltay);
668
669 // Move away from friends when too close, except
670 // in certain situations (e.g. a crowded lift)
671
672 if (actor->flags & target->flags & MF_FRIEND &&
673 distfriend << FRACBITS > dist &&
674 !P_IsOnLift(target) && !P_IsUnderDamage(actor))
675 {
676 deltax = -deltax, deltay = -deltay;
677 } else
678 if (target->health > 0 && (actor->flags ^ target->flags) & MF_FRIEND)
679 { // Live enemy target
680 if (monster_backing &&
681 actor->info->missilestate && actor->type != MT_SKULL &&
682 ((!target->info->missilestate && dist < MELEERANGE*2) ||
683 (target->player && dist < MELEERANGE*3 &&
684 (target->player->readyweapon == wp_fist ||
685 target->player->readyweapon == wp_chainsaw))))
686 { // Back away from melee attacker
687 actor->strafecount = P_Random(pr_enemystrafe) & 15;
688 deltax = -deltax, deltay = -deltay;
689 }
690 }
691 }
692 }
693
694 P_DoNewChaseDir(actor, deltax, deltay);
695
696 // If strafing, set movecount to strafecount so that old Doom
697 // logic still works the same, except in the strafing part
698
699 if (actor->strafecount)
700 actor->movecount = actor->strafecount;
701}
702
703//
704// P_IsVisible
705//
706// killough 9/9/98: whether a target is visible to a monster
707//
708
709static boolean P_IsVisible(mobj_t *actor, mobj_t *mo, boolean allaround)
710{
711 if (!allaround)
712 {
713 angle_t an = R_PointToAngle2(actor->x, actor->y,
714 mo->x, mo->y) - actor->angle;
715 if (an > ANG90 && an < ANG270 &&
716 P_AproxDistance(mo->x-actor->x, mo->y-actor->y) > MELEERANGE)
717 return false;
718 }
719 return P_CheckSight(actor, mo);
720}
721
722//
723// PIT_FindTarget
724//
725// killough 9/5/98
726//
727// Finds monster targets for other monsters
728//
729
730static int current_allaround;
731
732static boolean PIT_FindTarget(mobj_t *mo)
733{
734 mobj_t *actor = current_actor;
735
736 if (!((mo->flags ^ actor->flags) & MF_FRIEND && // Invalid target
737 mo->health > 0 && (mo->flags & MF_COUNTKILL || mo->type == MT_SKULL)))
738 return true;
739
740 // If the monster is already engaged in a one-on-one attack
741 // with a healthy friend, don't attack around 60% the time
742 {
743 const mobj_t *targ = mo->target;
744 if (targ && targ->target == mo &&
745 P_Random(pr_skiptarget) > 100 &&
746 (targ->flags ^ mo->flags) & MF_FRIEND &&
747 targ->health*2 >= targ->info->spawnhealth)
748 return true;
749 }
750
751 if (!P_IsVisible(actor, mo, current_allaround))
752 return true;
753
754 P_SetTarget(&actor->lastenemy, actor->target); // Remember previous target
755 P_SetTarget(&actor->target, mo); // Found target
756
757 // Move the selected monster to the end of its associated
758 // list, so that it gets searched last next time.
759
760 {
761 thinker_t *cap = &thinkerclasscap[mo->flags & MF_FRIEND ?
762 th_friends : th_enemies];
763 (mo->thinker.cprev->cnext = mo->thinker.cnext)->cprev = mo->thinker.cprev;
764 (mo->thinker.cprev = cap->cprev)->cnext = &mo->thinker;
765 (mo->thinker.cnext = cap)->cprev = &mo->thinker;
766 }
767
768 return false;
769}
770
771//
772// P_LookForPlayers
773// If allaround is false, only look 180 degrees in front.
774// Returns true if a player is targeted.
775//
776
777static boolean P_LookForPlayers(mobj_t *actor, boolean allaround)
778{
779 player_t *player;
780 int stop, stopc, c;
781
782 if (actor->flags & MF_FRIEND)
783 { // killough 9/9/98: friendly monsters go about players differently
784 int anyone;
785
786#if 0
787 if (!allaround) // If you want friendly monsters not to awaken unprovoked
788 return false;
789#endif
790
791 // Go back to a player, no matter whether it's visible or not
792 for (anyone=0; anyone<=1; anyone++)
793 for (c=0; c<MAXPLAYERS; c++)
794 if (playeringame[c] && players[c].playerstate==PST_LIVE &&
795 (anyone || P_IsVisible(actor, players[c].mo, allaround)))
796 {
797 P_SetTarget(&actor->target, players[c].mo);
798
799 // killough 12/98:
800 // get out of refiring loop, to avoid hitting player accidentally
801
802 if (actor->info->missilestate)
803 {
804 P_SetMobjState(actor, actor->info->seestate);
805 actor->flags &= ~MF_JUSTHIT;
806 }
807
808 return true;
809 }
810
811 return false;
812 }
813
814 // Change mask of 3 to (MAXPLAYERS-1) -- killough 2/15/98:
815 stop = (actor->lastlook-1)&(MAXPLAYERS-1);
816
817 c = 0;
818
819 stopc = !mbf_features &&
820 !demo_compatibility && monsters_remember ?
821 MAXPLAYERS : 2; // killough 9/9/98
822
823 for (;; actor->lastlook = (actor->lastlook+1)&(MAXPLAYERS-1))
824 {
825 if (!playeringame[actor->lastlook])
826 continue;
827
828 // killough 2/15/98, 9/9/98:
829 if (c++ == stopc || actor->lastlook == stop) // done looking
830 {
831 // e6y
832 // Fixed Boom incompatibilities. The following code was missed.
833 // There are no more desyncs on Donce's demos on horror.wad
834
835 // Use last known enemy if no players sighted -- killough 2/15/98:
836 if (!mbf_features && !demo_compatibility && monsters_remember)
837 {
838 if (actor->lastenemy && actor->lastenemy->health > 0)
839 {
840 actor->target = actor->lastenemy;
841 actor->lastenemy = NULL;
842 return true;
843 }
844 }
845
846 return false;
847 }
848
849 player = &players[actor->lastlook];
850
851 if (player->health <= 0)
852 continue; // dead
853
854 if (!P_IsVisible(actor, player->mo, allaround))
855 continue;
856
857 P_SetTarget(&actor->target, player->mo);
858
859 /* killough 9/9/98: give monsters a threshold towards getting players
860 * (we don't want it to be too easy for a player with dogs :)
861 */
862 if (!comp[comp_pursuit])
863 actor->threshold = 60;
864
865 return true;
866 }
867}
868
869//
870// Friendly monsters, by Lee Killough 7/18/98
871//
872// Friendly monsters go after other monsters first, but
873// also return to owner if they cannot find any targets.
874// A marine's best friend :) killough 7/18/98, 9/98
875//
876
877static boolean P_LookForMonsters(mobj_t *actor, boolean allaround)
878{
879 thinker_t *cap, *th;
880
881 if (demo_compatibility)
882 return false;
883
884 if (actor->lastenemy && actor->lastenemy->health > 0 && monsters_remember &&
885 !(actor->lastenemy->flags & actor->flags & MF_FRIEND)) // not friends
886 {
887 P_SetTarget(&actor->target, actor->lastenemy);
888 P_SetTarget(&actor->lastenemy, NULL);
889 return true;
890 }
891
892 /* Old demos do not support monster-seeking bots */
893 if (!mbf_features)
894 return false;
895
896 // Search the threaded list corresponding to this object's potential targets
897 cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_enemies : th_friends];
898
899 // Search for new enemy
900
901 if (cap->cnext != cap) // Empty list? bail out early
902 {
903 int x = (actor->x - bmaporgx)>>MAPBLOCKSHIFT;
904 int y = (actor->y - bmaporgy)>>MAPBLOCKSHIFT;
905 int d;
906
907 current_actor = actor;
908 current_allaround = allaround;
909
910 // Search first in the immediate vicinity.
911
912 if (!P_BlockThingsIterator(x, y, PIT_FindTarget))
913 return true;
914
915 for (d=1; d<5; d++)
916 {
917 int i = 1 - d;
918 do
919 if (!P_BlockThingsIterator(x+i, y-d, PIT_FindTarget) ||
920 !P_BlockThingsIterator(x+i, y+d, PIT_FindTarget))
921 return true;
922 while (++i < d);
923 do
924 if (!P_BlockThingsIterator(x-d, y+i, PIT_FindTarget) ||
925 !P_BlockThingsIterator(x+d, y+i, PIT_FindTarget))
926 return true;
927 while (--i + d >= 0);
928 }
929
930 { // Random number of monsters, to prevent patterns from forming
931 int n = (P_Random(pr_friends) & 31) + 15;
932
933 for (th = cap->cnext; th != cap; th = th->cnext)
934 if (--n < 0)
935 {
936 // Only a subset of the monsters were searched. Move all of
937 // the ones which were searched so far, to the end of the list.
938
939 (cap->cnext->cprev = cap->cprev)->cnext = cap->cnext;
940 (cap->cprev = th->cprev)->cnext = cap;
941 (th->cprev = cap)->cnext = th;
942 break;
943 }
944 else
945 if (!PIT_FindTarget((mobj_t *) th)) // If target sighted
946 return true;
947 }
948 }
949
950 return false; // No monster found
951}
952
953//
954// P_LookForTargets
955//
956// killough 9/5/98: look for targets to go after, depending on kind of monster
957//
958
959static boolean P_LookForTargets(mobj_t *actor, int allaround)
960{
961 return actor->flags & MF_FRIEND ?
962 P_LookForMonsters(actor, allaround) || P_LookForPlayers (actor, allaround):
963 P_LookForPlayers (actor, allaround) || P_LookForMonsters(actor, allaround);
964}
965
966//
967// P_HelpFriend
968//
969// killough 9/8/98: Help friends in danger of dying
970//
971
972static boolean P_HelpFriend(mobj_t *actor)
973{
974 thinker_t *cap, *th;
975
976 // If less than 33% health, self-preservation rules
977 if (actor->health*3 < actor->info->spawnhealth)
978 return false;
979
980 current_actor = actor;
981 current_allaround = true;
982
983 // Possibly help a friend under 50% health
984 cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_friends : th_enemies];
985
986 for (th = cap->cnext; th != cap; th = th->cnext)
987 if (((mobj_t *) th)->health*2 >= ((mobj_t *) th)->info->spawnhealth)
988 {
989 if (P_Random(pr_helpfriend) < 180)
990 break;
991 }
992 else
993 if (((mobj_t *) th)->flags & MF_JUSTHIT &&
994 ((mobj_t *) th)->target &&
995 ((mobj_t *) th)->target != actor->target &&
996 !PIT_FindTarget(((mobj_t *) th)->target))
997 {
998 // Ignore any attacking monsters, while searching for friend
999 actor->threshold = BASETHRESHOLD;
1000 return true;
1001 }
1002
1003 return false;
1004}
1005
1006//
1007// A_KeenDie
1008// DOOM II special, map 32.
1009// Uses special tag 666.
1010//
1011void A_KeenDie(mobj_t* mo)
1012{
1013 thinker_t *th;
1014 line_t junk;
1015
1016 A_Fall(mo);
1017
1018 // scan the remaining thinkers to see if all Keens are dead
1019
1020 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
1021 if (th->function == P_MobjThinker)
1022 {
1023 mobj_t *mo2 = (mobj_t *) th;
1024 if (mo2 != mo && mo2->type == mo->type && mo2->health > 0)
1025 return; // other Keen not dead
1026 }
1027
1028 junk.tag = 666;
1029 EV_DoDoor(&junk,open);
1030}
1031
1032
1033//
1034// ACTION ROUTINES
1035//
1036
1037//
1038// A_Look
1039// Stay in state until a player is sighted.
1040//
1041
1042void A_Look(mobj_t *actor)
1043{
1044 mobj_t *targ = actor->subsector->sector->soundtarget;
1045 actor->threshold = 0; // any shot will wake up
1046
1047 /* killough 7/18/98:
1048 * Friendly monsters go after other monsters first, but
1049 * also return to player, without attacking them, if they
1050 * cannot find any targets. A marine's best friend :)
1051 */
1052 actor->pursuecount = 0;
1053
1054 if (!(actor->flags & MF_FRIEND && P_LookForTargets(actor, false)) &&
1055 !((targ = actor->subsector->sector->soundtarget) &&
1056 targ->flags & MF_SHOOTABLE &&
1057 (P_SetTarget(&actor->target, targ),
1058 !(actor->flags & MF_AMBUSH) || P_CheckSight(actor, targ))) &&
1059 (actor->flags & MF_FRIEND || !P_LookForTargets(actor, false)))
1060 return;
1061
1062 // go into chase state
1063
1064 if (actor->info->seesound)
1065 {
1066 int sound;
1067 switch (actor->info->seesound)
1068 {
1069 case sfx_posit1:
1070 case sfx_posit2:
1071 case sfx_posit3:
1072 sound = sfx_posit1+P_Random(pr_see)%3;
1073 break;
1074
1075 case sfx_bgsit1:
1076 case sfx_bgsit2:
1077 sound = sfx_bgsit1+P_Random(pr_see)%2;
1078 break;
1079
1080 default:
1081 sound = actor->info->seesound;
1082 break;
1083 }
1084 if (actor->type==MT_SPIDER || actor->type == MT_CYBORG)
1085 S_StartSound(NULL, sound); // full volume
1086 else
1087 S_StartSound(actor, sound);
1088 }
1089 P_SetMobjState(actor, actor->info->seestate);
1090}
1091
1092//
1093// A_KeepChasing
1094//
1095// killough 10/98:
1096// Allows monsters to continue movement while attacking
1097//
1098
1099static void A_KeepChasing(mobj_t *actor)
1100{
1101 if (actor->movecount)
1102 {
1103 actor->movecount--;
1104 if (actor->strafecount)
1105 actor->strafecount--;
1106 P_SmartMove(actor);
1107 }
1108}
1109
1110//
1111// A_Chase
1112// Actor has a melee attack,
1113// so it tries to close as fast as possible
1114//
1115
1116void A_Chase(mobj_t *actor)
1117{
1118 if (actor->reactiontime)
1119 actor->reactiontime--;
1120
1121 if (actor->threshold) { /* modify target threshold */
1122 if (!actor->target || actor->target->health <= 0)
1123 actor->threshold = 0;
1124 else
1125 actor->threshold--;
1126 }
1127
1128 /* turn towards movement direction if not there yet
1129 * killough 9/7/98: keep facing towards target if strafing or backing out
1130 */
1131
1132 if (actor->strafecount)
1133 A_FaceTarget(actor);
1134 else if (actor->movedir < 8)
1135 {
1136 int delta = (actor->angle &= (7<<29)) - (actor->movedir << 29);
1137 if (delta > 0)
1138 actor->angle -= ANG90/2;
1139 else
1140 if (delta < 0)
1141 actor->angle += ANG90/2;
1142 }
1143
1144 if (!actor->target || !(actor->target->flags&MF_SHOOTABLE))
1145 {
1146 if (!P_LookForTargets(actor,true)) // look for a new target
1147 P_SetMobjState(actor, actor->info->spawnstate); // no new target
1148 return;
1149 }
1150
1151 // do not attack twice in a row
1152 if (actor->flags & MF_JUSTATTACKED)
1153 {
1154 actor->flags &= ~MF_JUSTATTACKED;
1155 if (gameskill != sk_nightmare && !fastparm)
1156 P_NewChaseDir(actor);
1157 return;
1158 }
1159
1160 // check for melee attack
1161 if (actor->info->meleestate && P_CheckMeleeRange(actor))
1162 {
1163 if (actor->info->attacksound)
1164 S_StartSound(actor, actor->info->attacksound);
1165 P_SetMobjState(actor, actor->info->meleestate);
1166 /* killough 8/98: remember an attack
1167 * cph - DEMOSYNC? */
1168 if (!actor->info->missilestate)
1169 actor->flags |= MF_JUSTHIT;
1170 return;
1171 }
1172
1173 // check for missile attack
1174 if (actor->info->missilestate)
1175 if (!(gameskill < sk_nightmare && !fastparm && actor->movecount))
1176 if (P_CheckMissileRange(actor))
1177 {
1178 P_SetMobjState(actor, actor->info->missilestate);
1179 actor->flags |= MF_JUSTATTACKED;
1180 return;
1181 }
1182
1183 if (!actor->threshold) {
1184 if (!mbf_features)
1185 { /* killough 9/9/98: for backward demo compatibility */
1186 if (netgame && !P_CheckSight(actor, actor->target) &&
1187 P_LookForPlayers(actor, true))
1188 return;
1189 }
1190 /* killough 7/18/98, 9/9/98: new monster AI */
1191 else if (help_friends && P_HelpFriend(actor))
1192 return; /* killough 9/8/98: Help friends in need */
1193 /* Look for new targets if current one is bad or is out of view */
1194 else if (actor->pursuecount)
1195 actor->pursuecount--;
1196 else {
1197 /* Our pursuit time has expired. We're going to think about
1198 * changing targets */
1199 actor->pursuecount = BASETHRESHOLD;
1200
1201 /* Unless (we have a live target
1202 * and it's not friendly
1203 * and we can see it)
1204 * try to find a new one; return if sucessful */
1205
1206 if (!(actor->target && actor->target->health > 0 &&
1207 ((comp[comp_pursuit] && !netgame) ||
1208 (((actor->target->flags ^ actor->flags) & MF_FRIEND ||
1209 (!(actor->flags & MF_FRIEND) && monster_infighting)) &&
1210 P_CheckSight(actor, actor->target))))
1211 && P_LookForTargets(actor, true))
1212 return;
1213
1214 /* (Current target was good, or no new target was found.)
1215 *
1216 * If monster is a missile-less friend, give up pursuit and
1217 * return to player, if no attacks have occurred recently.
1218 */
1219
1220 if (!actor->info->missilestate && actor->flags & MF_FRIEND) {
1221 if (actor->flags & MF_JUSTHIT) /* if recent action, */
1222 actor->flags &= ~MF_JUSTHIT; /* keep fighting */
1223 else if (P_LookForPlayers(actor, true)) /* else return to player */
1224 return;
1225 }
1226 }
1227 }
1228
1229 if (actor->strafecount)
1230 actor->strafecount--;
1231
1232 // chase towards player
1233 if (--actor->movecount<0 || !P_SmartMove(actor))
1234 P_NewChaseDir(actor);
1235
1236 // make active sound
1237 if (actor->info->activesound && P_Random(pr_see)<3)
1238 S_StartSound(actor, actor->info->activesound);
1239}
1240
1241//
1242// A_FaceTarget
1243//
1244void A_FaceTarget(mobj_t *actor)
1245{
1246 if (!actor->target)
1247 return;
1248 actor->flags &= ~MF_AMBUSH;
1249 actor->angle = R_PointToAngle2(actor->x, actor->y,
1250 actor->target->x, actor->target->y);
1251 if (actor->target->flags & MF_SHADOW)
1252 { // killough 5/5/98: remove dependence on order of evaluation:
1253 int t = P_Random(pr_facetarget);
1254 actor->angle += (t-P_Random(pr_facetarget))<<21;
1255 }
1256}
1257
1258//
1259// A_PosAttack
1260//
1261
1262void A_PosAttack(mobj_t *actor)
1263{
1264 int angle, damage, slope, t;
1265
1266 if (!actor->target)
1267 return;
1268 A_FaceTarget(actor);
1269 angle = actor->angle;
1270 slope = P_AimLineAttack(actor, angle, MISSILERANGE, 0); /* killough 8/2/98 */
1271 S_StartSound(actor, sfx_pistol);
1272
1273 // killough 5/5/98: remove dependence on order of evaluation:
1274 t = P_Random(pr_posattack);
1275 angle += (t - P_Random(pr_posattack))<<20;
1276 damage = (P_Random(pr_posattack)%5 + 1)*3;
1277 P_LineAttack(actor, angle, MISSILERANGE, slope, damage);
1278}
1279
1280void A_SPosAttack(mobj_t* actor)
1281{
1282 int i, bangle, slope;
1283
1284 if (!actor->target)
1285 return;
1286 S_StartSound(actor, sfx_shotgn);
1287 A_FaceTarget(actor);
1288 bangle = actor->angle;
1289 slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */
1290 for (i=0; i<3; i++)
1291 { // killough 5/5/98: remove dependence on order of evaluation:
1292 int t = P_Random(pr_sposattack);
1293 int angle = bangle + ((t - P_Random(pr_sposattack))<<20);
1294 int damage = ((P_Random(pr_sposattack)%5)+1)*3;
1295 P_LineAttack(actor, angle, MISSILERANGE, slope, damage);
1296 }
1297}
1298
1299void A_CPosAttack(mobj_t *actor)
1300{
1301 int angle, bangle, damage, slope, t;
1302
1303 if (!actor->target)
1304 return;
1305 S_StartSound(actor, sfx_shotgn);
1306 A_FaceTarget(actor);
1307 bangle = actor->angle;
1308 slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */
1309
1310 // killough 5/5/98: remove dependence on order of evaluation:
1311 t = P_Random(pr_cposattack);
1312 angle = bangle + ((t - P_Random(pr_cposattack))<<20);
1313 damage = ((P_Random(pr_cposattack)%5)+1)*3;
1314 P_LineAttack(actor, angle, MISSILERANGE, slope, damage);
1315}
1316
1317void A_CPosRefire(mobj_t *actor)
1318{
1319 // keep firing unless target got out of sight
1320 A_FaceTarget(actor);
1321
1322 /* killough 12/98: Stop firing if a friend has gotten in the way */
1323 if (P_HitFriend(actor))
1324 goto stop;
1325
1326 /* killough 11/98: prevent refiring on friends continuously */
1327 if (P_Random(pr_cposrefire) < 40) {
1328 if (actor->target && actor->flags & actor->target->flags & MF_FRIEND)
1329 goto stop;
1330 else
1331 return;
1332 }
1333
1334 if (!actor->target || actor->target->health <= 0
1335 || !P_CheckSight(actor, actor->target))
1336stop: P_SetMobjState(actor, actor->info->seestate);
1337}
1338
1339void A_SpidRefire(mobj_t* actor)
1340{
1341 // keep firing unless target got out of sight
1342 A_FaceTarget(actor);
1343
1344 /* killough 12/98: Stop firing if a friend has gotten in the way */
1345 if (P_HitFriend(actor))
1346 goto stop;
1347
1348 if (P_Random(pr_spidrefire) < 10)
1349 return;
1350
1351 // killough 11/98: prevent refiring on friends continuously
1352 if (!actor->target || actor->target->health <= 0
1353 || actor->flags & actor->target->flags & MF_FRIEND
1354 || !P_CheckSight(actor, actor->target))
1355 stop: P_SetMobjState(actor, actor->info->seestate);
1356}
1357
1358void A_BspiAttack(mobj_t *actor)
1359{
1360 if (!actor->target)
1361 return;
1362 A_FaceTarget(actor);
1363 P_SpawnMissile(actor, actor->target, MT_ARACHPLAZ); // launch a missile
1364}
1365
1366//
1367// A_TroopAttack
1368//
1369
1370void A_TroopAttack(mobj_t *actor)
1371{
1372 if (!actor->target)
1373 return;
1374 A_FaceTarget(actor);
1375 if (P_CheckMeleeRange(actor))
1376 {
1377 int damage;
1378 S_StartSound(actor, sfx_claw);
1379 damage = (P_Random(pr_troopattack)%8+1)*3;
1380 P_DamageMobj(actor->target, actor, actor, damage);
1381 return;
1382 }
1383 P_SpawnMissile(actor, actor->target, MT_TROOPSHOT); // launch a missile
1384}
1385
1386void A_SargAttack(mobj_t *actor)
1387{
1388 if (!actor->target)
1389 return;
1390 A_FaceTarget(actor);
1391 if (P_CheckMeleeRange(actor))
1392 {
1393 int damage = ((P_Random(pr_sargattack)%10)+1)*4;
1394 P_DamageMobj(actor->target, actor, actor, damage);
1395 }
1396}
1397
1398void A_HeadAttack(mobj_t *actor)
1399{
1400 if (!actor->target)
1401 return;
1402 A_FaceTarget (actor);
1403 if (P_CheckMeleeRange(actor))
1404 {
1405 int damage = (P_Random(pr_headattack)%6+1)*10;
1406 P_DamageMobj(actor->target, actor, actor, damage);
1407 return;
1408 }
1409 P_SpawnMissile(actor, actor->target, MT_HEADSHOT); // launch a missile
1410}
1411
1412void A_CyberAttack(mobj_t *actor)
1413{
1414 if (!actor->target)
1415 return;
1416 A_FaceTarget(actor);
1417 P_SpawnMissile(actor, actor->target, MT_ROCKET);
1418}
1419
1420void A_BruisAttack(mobj_t *actor)
1421{
1422 if (!actor->target)
1423 return;
1424 if (P_CheckMeleeRange(actor))
1425 {
1426 int damage;
1427 S_StartSound(actor, sfx_claw);
1428 damage = (P_Random(pr_bruisattack)%8+1)*10;
1429 P_DamageMobj(actor->target, actor, actor, damage);
1430 return;
1431 }
1432 P_SpawnMissile(actor, actor->target, MT_BRUISERSHOT); // launch a missile
1433}
1434
1435//
1436// A_SkelMissile
1437//
1438
1439void A_SkelMissile(mobj_t *actor)
1440{
1441 mobj_t *mo;
1442
1443 if (!actor->target)
1444 return;
1445
1446 A_FaceTarget (actor);
1447 actor->z += 16*FRACUNIT; // so missile spawns higher
1448 mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
1449 actor->z -= 16*FRACUNIT; // back to normal
1450
1451 mo->x += mo->momx;
1452 mo->y += mo->momy;
1453 P_SetTarget(&mo->tracer, actor->target);
1454}
1455
1456int TRACEANGLE = 0xc000000;
1457
1458void A_Tracer(mobj_t *actor)
1459{
1460 angle_t exact;
1461 fixed_t dist;
1462 fixed_t slope;
1463 mobj_t *dest;
1464 mobj_t *th;
1465
1466 /* killough 1/18/98: this is why some missiles do not have smoke
1467 * and some do. Also, internal demos start at random gametics, thus
1468 * the bug in which revenants cause internal demos to go out of sync.
1469 *
1470 * killough 3/6/98: fix revenant internal demo bug by subtracting
1471 * levelstarttic from gametic.
1472 *
1473 * killough 9/29/98: use new "basetic" so that demos stay in sync
1474 * during pauses and menu activations, while retaining old demo sync.
1475 *
1476 * leveltime would have been better to use to start with in Doom, but
1477 * since old demos were recorded using gametic, we must stick with it,
1478 * and improvise around it (using leveltime causes desync across levels).
1479 */
1480
1481 if ((gametic-basetic) & 3)
1482 return;
1483
1484 // spawn a puff of smoke behind the rocket
1485 P_SpawnPuff(actor->x, actor->y, actor->z);
1486
1487 th = P_SpawnMobj (actor->x-actor->momx,
1488 actor->y-actor->momy,
1489 actor->z, MT_SMOKE);
1490
1491 th->momz = FRACUNIT;
1492 th->tics -= P_Random(pr_tracer) & 3;
1493 if (th->tics < 1)
1494 th->tics = 1;
1495
1496 // adjust direction
1497 dest = actor->tracer;
1498
1499 if (!dest || dest->health <= 0)
1500 return;
1501
1502 // change angle
1503 exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y);
1504
1505 if (exact != actor->angle) {
1506 if (exact - actor->angle > 0x80000000)
1507 {
1508 actor->angle -= TRACEANGLE;
1509 if (exact - actor->angle < 0x80000000)
1510 actor->angle = exact;
1511 }
1512 else
1513 {
1514 actor->angle += TRACEANGLE;
1515 if (exact - actor->angle > 0x80000000)
1516 actor->angle = exact;
1517 }
1518 }
1519
1520 exact = actor->angle>>ANGLETOFINESHIFT;
1521 actor->momx = FixedMul(actor->info->speed, finecosine[exact]);
1522 actor->momy = FixedMul(actor->info->speed, finesine[exact]);
1523
1524 // change slope
1525 dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
1526
1527 dist = dist / actor->info->speed;
1528
1529 if (dist < 1)
1530 dist = 1;
1531
1532 slope = (dest->z+40*FRACUNIT - actor->z) / dist;
1533
1534 if (slope < actor->momz)
1535 actor->momz -= FRACUNIT/8;
1536 else
1537 actor->momz += FRACUNIT/8;
1538}
1539
1540void A_SkelWhoosh(mobj_t *actor)
1541{
1542 if (!actor->target)
1543 return;
1544 A_FaceTarget(actor);
1545 S_StartSound(actor,sfx_skeswg);
1546}
1547
1548void A_SkelFist(mobj_t *actor)
1549{
1550 if (!actor->target)
1551 return;
1552 A_FaceTarget(actor);
1553 if (P_CheckMeleeRange(actor))
1554 {
1555 int damage = ((P_Random(pr_skelfist)%10)+1)*6;
1556 S_StartSound(actor, sfx_skepch);
1557 P_DamageMobj(actor->target, actor, actor, damage);
1558 }
1559}
1560
1561//
1562// PIT_VileCheck
1563// Detect a corpse that could be raised.
1564//
1565
1566mobj_t* corpsehit;
1567mobj_t* vileobj;
1568fixed_t viletryx;
1569fixed_t viletryy;
1570
1571static boolean PIT_VileCheck(mobj_t *thing)
1572{
1573 int maxdist;
1574 boolean check;
1575
1576 if (!(thing->flags & MF_CORPSE) )
1577 return true; // not a monster
1578
1579 if (thing->tics != -1)
1580 return true; // not lying still yet
1581
1582 if (thing->info->raisestate == S_NULL)
1583 return true; // monster doesn't have a raise state
1584
1585 maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
1586
1587 if (D_abs(thing->x-viletryx) > maxdist || D_abs(thing->y-viletryy) > maxdist)
1588 return true; // not actually touching
1589
1590// Check to see if the radius and height are zero. If they are // phares
1591// then this is a crushed monster that has been turned into a // |
1592// gib. One of the options may be to ignore this guy. // V
1593
1594// Option 1: the original, buggy method, -> ghost (compatibility)
1595// Option 2: ressurect the monster, but not as a ghost
1596// Option 3: ignore the gib
1597
1598// if (Option3) // ^
1599// if ((thing->height == 0) && (thing->radius == 0)) // |
1600// return true; // phares
1601
1602 corpsehit = thing;
1603 corpsehit->momx = corpsehit->momy = 0;
1604 if (comp[comp_vile]) // phares
1605 { // |
1606 corpsehit->height <<= 2; // V
1607 check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y);
1608 corpsehit->height >>= 2;
1609 }
1610 else
1611 {
1612 int height,radius;
1613
1614 height = corpsehit->height; // save temporarily
1615 radius = corpsehit->radius; // save temporarily
1616 corpsehit->height = corpsehit->info->height;
1617 corpsehit->radius = corpsehit->info->radius;
1618 corpsehit->flags |= MF_SOLID;
1619 check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y);
1620 corpsehit->height = height; // restore
1621 corpsehit->radius = radius; // restore // ^
1622 corpsehit->flags &= ~MF_SOLID;
1623 } // |
1624 // phares
1625 if (!check)
1626 return true; // doesn't fit here
1627 return false; // got one, so stop checking
1628}
1629
1630//
1631// A_VileChase
1632// Check for ressurecting a body
1633//
1634
1635void A_VileChase(mobj_t* actor)
1636{
1637 int xl, xh;
1638 int yl, yh;
1639 int bx, by;
1640
1641 if (actor->movedir != DI_NODIR)
1642 {
1643 // check for corpses to raise
1644 viletryx =
1645 actor->x + actor->info->speed*xspeed[actor->movedir];
1646 viletryy =
1647 actor->y + actor->info->speed*yspeed[actor->movedir];
1648
1649 xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1650 xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1651 yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1652 yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1653
1654 vileobj = actor;
1655 for (bx=xl ; bx<=xh ; bx++)
1656 {
1657 for (by=yl ; by<=yh ; by++)
1658 {
1659 // Call PIT_VileCheck to check
1660 // whether object is a corpse
1661 // that canbe raised.
1662 if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
1663 {
1664 mobjinfo_t *info;
1665
1666 // got one!
1667 mobj_t* temp = actor->target;
1668 actor->target = corpsehit;
1669 A_FaceTarget(actor);
1670 actor->target = temp;
1671
1672 P_SetMobjState(actor, S_VILE_HEAL1);
1673 S_StartSound(corpsehit, sfx_slop);
1674 info = corpsehit->info;
1675
1676 P_SetMobjState(corpsehit,info->raisestate);
1677
1678 if (comp[comp_vile]) // phares
1679 corpsehit->height <<= 2; // |
1680 else // V
1681 {
1682 corpsehit->height = info->height; // fix Ghost bug
1683 corpsehit->radius = info->radius; // fix Ghost bug
1684 } // phares
1685
1686 /* killough 7/18/98:
1687 * friendliness is transferred from AV to raised corpse
1688 */
1689 corpsehit->flags =
1690 (info->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND);
1691
1692 if (!((corpsehit->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
1693 totallive++;
1694
1695 corpsehit->health = info->spawnhealth;
1696 P_SetTarget(&corpsehit->target, NULL); // killough 11/98
1697
1698 if (mbf_features)
1699 { /* kilough 9/9/98 */
1700 P_SetTarget(&corpsehit->lastenemy, NULL);
1701 corpsehit->flags &= ~MF_JUSTHIT;
1702 }
1703
1704 /* killough 8/29/98: add to appropriate thread */
1705 P_UpdateThinker(&corpsehit->thinker);
1706
1707 return;
1708 }
1709 }
1710 }
1711 }
1712 A_Chase(actor); // Return to normal attack.
1713}
1714
1715//
1716// A_VileStart
1717//
1718
1719void A_VileStart(mobj_t *actor)
1720{
1721 S_StartSound(actor, sfx_vilatk);
1722}
1723
1724//
1725// A_Fire
1726// Keep fire in front of player unless out of sight
1727//
1728
1729void A_StartFire(mobj_t *actor)
1730{
1731 S_StartSound(actor,sfx_flamst);
1732 A_Fire(actor);
1733}
1734
1735void A_FireCrackle(mobj_t* actor)
1736{
1737 S_StartSound(actor,sfx_flame);
1738 A_Fire(actor);
1739}
1740
1741void A_Fire(mobj_t *actor)
1742{
1743 unsigned an;
1744 mobj_t *dest = actor->tracer;
1745
1746 if (!dest)
1747 return;
1748
1749 // don't move it if the vile lost sight
1750 if (!P_CheckSight(actor->target, dest) )
1751 return;
1752
1753 an = dest->angle >> ANGLETOFINESHIFT;
1754
1755 P_UnsetThingPosition(actor);
1756 actor->x = dest->x + FixedMul(24*FRACUNIT, finecosine[an]);
1757 actor->y = dest->y + FixedMul(24*FRACUNIT, finesine[an]);
1758 actor->z = dest->z;
1759 P_SetThingPosition(actor);
1760}
1761
1762//
1763// A_VileTarget
1764// Spawn the hellfire
1765//
1766
1767void A_VileTarget(mobj_t *actor)
1768{
1769 mobj_t *fog;
1770
1771 if (!actor->target)
1772 return;
1773
1774 A_FaceTarget(actor);
1775
1776 // killough 12/98: fix Vile fog coordinates // CPhipps - compatibility optioned
1777 fog = P_SpawnMobj(actor->target->x,
1778 (compatibility_level < lxdoom_1_compatibility) ? actor->target->x : actor->target->y,
1779 actor->target->z,MT_FIRE);
1780
1781 P_SetTarget(&actor->tracer, fog);
1782 P_SetTarget(&fog->target, actor);
1783 P_SetTarget(&fog->tracer, actor->target);
1784 A_Fire(fog);
1785}
1786
1787//
1788// A_VileAttack
1789//
1790
1791void A_VileAttack(mobj_t *actor)
1792{
1793 mobj_t *fire;
1794 int an;
1795
1796 if (!actor->target)
1797 return;
1798
1799 A_FaceTarget(actor);
1800
1801 if (!P_CheckSight(actor, actor->target))
1802 return;
1803
1804 S_StartSound(actor, sfx_barexp);
1805 P_DamageMobj(actor->target, actor, actor, 20);
1806 actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
1807
1808 an = actor->angle >> ANGLETOFINESHIFT;
1809
1810 fire = actor->tracer;
1811
1812 if (!fire)
1813 return;
1814
1815 // move the fire between the vile and the player
1816 fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
1817 fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
1818 P_RadiusAttack(fire, actor, 70);
1819}
1820
1821//
1822// Mancubus attack,
1823// firing three missiles (bruisers)
1824// in three different directions?
1825// Doesn't look like it.
1826//
1827
1828#define FATSPREAD (ANG90/8)
1829
1830void A_FatRaise(mobj_t *actor)
1831{
1832 A_FaceTarget(actor);
1833 S_StartSound(actor, sfx_manatk);
1834}
1835
1836void A_FatAttack1(mobj_t *actor)
1837{
1838 mobj_t *mo;
1839 int an;
1840
1841 if (!actor->target)
1842 return;
1843
1844 A_FaceTarget(actor);
1845
1846 // Change direction to ...
1847 actor->angle += FATSPREAD;
1848
1849 P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1850
1851 mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1852 mo->angle += FATSPREAD;
1853 an = mo->angle >> ANGLETOFINESHIFT;
1854 mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1855 mo->momy = FixedMul(mo->info->speed, finesine[an]);
1856}
1857
1858void A_FatAttack2(mobj_t *actor)
1859{
1860 mobj_t *mo;
1861 int an;
1862
1863 if (!actor->target)
1864 return;
1865
1866 A_FaceTarget(actor);
1867 // Now here choose opposite deviation.
1868 actor->angle -= FATSPREAD;
1869 P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1870
1871 mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1872 mo->angle -= FATSPREAD*2;
1873 an = mo->angle >> ANGLETOFINESHIFT;
1874 mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1875 mo->momy = FixedMul(mo->info->speed, finesine[an]);
1876}
1877
1878void A_FatAttack3(mobj_t *actor)
1879{
1880 mobj_t *mo;
1881 int an;
1882
1883 if (!actor->target)
1884 return;
1885
1886 A_FaceTarget(actor);
1887
1888 mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1889 mo->angle -= FATSPREAD/2;
1890 an = mo->angle >> ANGLETOFINESHIFT;
1891 mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1892 mo->momy = FixedMul(mo->info->speed, finesine[an]);
1893
1894 mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1895 mo->angle += FATSPREAD/2;
1896 an = mo->angle >> ANGLETOFINESHIFT;
1897 mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1898 mo->momy = FixedMul(mo->info->speed, finesine[an]);
1899}
1900
1901
1902//
1903// SkullAttack
1904// Fly at the player like a missile.
1905//
1906#define SKULLSPEED (20*FRACUNIT)
1907
1908void A_SkullAttack(mobj_t *actor)
1909{
1910 mobj_t *dest;
1911 angle_t an;
1912 int dist;
1913
1914 if (!actor->target)
1915 return;
1916
1917 dest = actor->target;
1918 actor->flags |= MF_SKULLFLY;
1919
1920 S_StartSound(actor, actor->info->attacksound);
1921 A_FaceTarget(actor);
1922 an = actor->angle >> ANGLETOFINESHIFT;
1923 actor->momx = FixedMul(SKULLSPEED, finecosine[an]);
1924 actor->momy = FixedMul(SKULLSPEED, finesine[an]);
1925 dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
1926 dist = dist / SKULLSPEED;
1927
1928 if (dist < 1)
1929 dist = 1;
1930 actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
1931}
1932
1933//
1934// A_PainShootSkull
1935// Spawn a lost soul and launch it at the target
1936//
1937
1938static void A_PainShootSkull(mobj_t *actor, angle_t angle)
1939{
1940 fixed_t x,y,z;
1941 mobj_t *newmobj;
1942 angle_t an;
1943 int prestep;
1944
1945// The original code checked for 20 skulls on the level, // phares
1946// and wouldn't spit another one if there were. If not in // phares
1947// compatibility mode, we remove the limit. // phares
1948 // phares
1949 if (comp[comp_pain]) /* killough 10/98: compatibility-optioned */
1950 {
1951 // count total number of skulls currently on the level
1952 int count = 0;
1953 thinker_t *currentthinker = NULL;
1954 while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL)
1955 if ((currentthinker->function == P_MobjThinker)
1956 && ((mobj_t *)currentthinker)->type == MT_SKULL)
1957 count++;
1958 if (count > 20) // phares
1959 return; // phares
1960 }
1961
1962 // okay, there's room for another one
1963
1964 an = angle >> ANGLETOFINESHIFT;
1965
1966 prestep = 4*FRACUNIT + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
1967
1968 x = actor->x + FixedMul(prestep, finecosine[an]);
1969 y = actor->y + FixedMul(prestep, finesine[an]);
1970 z = actor->z + 8*FRACUNIT;
1971
1972 if (comp[comp_skull]) /* killough 10/98: compatibility-optioned */
1973 newmobj = P_SpawnMobj(x, y, z, MT_SKULL); // phares
1974 else // V
1975 {
1976 // Check whether the Lost Soul is being fired through a 1-sided
1977 // wall or an impassible line, or a "monsters can't cross" line.
1978 // If it is, then we don't allow the spawn. This is a bug fix, but
1979 // it should be considered an enhancement, since it may disturb
1980 // existing demos, so don't do it in compatibility mode.
1981
1982 if (Check_Sides(actor,x,y))
1983 return;
1984
1985 newmobj = P_SpawnMobj(x, y, z, MT_SKULL);
1986
1987 // Check to see if the new Lost Soul's z value is above the
1988 // ceiling of its new sector, or below the floor. If so, kill it.
1989
1990 if ((newmobj->z >
1991 (newmobj->subsector->sector->ceilingheight - newmobj->height)) ||
1992 (newmobj->z < newmobj->subsector->sector->floorheight))
1993 {
1994 // kill it immediately
1995 P_DamageMobj(newmobj,actor,actor,10000);
1996 return; // ^
1997 } // |
1998 } // phares
1999
2000 /* killough 7/20/98: PEs shoot lost souls with the same friendliness */
2001 newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND);
2002
2003 /* killough 8/29/98: add to appropriate thread */
2004 P_UpdateThinker(&newmobj->thinker);
2005
2006 // Check for movements.
2007 // killough 3/15/98: don't jump over dropoffs:
2008
2009 if (!P_TryMove(newmobj, newmobj->x, newmobj->y, false))
2010 {
2011 // kill it immediately
2012 P_DamageMobj(newmobj, actor, actor, 10000);
2013 return;
2014 }
2015
2016 P_SetTarget(&newmobj->target, actor->target);
2017 A_SkullAttack(newmobj);
2018}
2019
2020//
2021// A_PainAttack
2022// Spawn a lost soul and launch it at the target
2023//
2024
2025void A_PainAttack(mobj_t *actor)
2026{
2027 if (!actor->target)
2028 return;
2029 A_FaceTarget(actor);
2030 A_PainShootSkull(actor, actor->angle);
2031}
2032
2033void A_PainDie(mobj_t *actor)
2034{
2035 A_Fall(actor);
2036 A_PainShootSkull(actor, actor->angle+ANG90);
2037 A_PainShootSkull(actor, actor->angle+ANG180);
2038 A_PainShootSkull(actor, actor->angle+ANG270);
2039}
2040
2041void A_Scream(mobj_t *actor)
2042{
2043 int sound;
2044
2045 switch (actor->info->deathsound)
2046 {
2047 case 0:
2048 return;
2049
2050 case sfx_podth1:
2051 case sfx_podth2:
2052 case sfx_podth3:
2053 sound = sfx_podth1 + P_Random(pr_scream)%3;
2054 break;
2055
2056 case sfx_bgdth1:
2057 case sfx_bgdth2:
2058 sound = sfx_bgdth1 + P_Random(pr_scream)%2;
2059 break;
2060
2061 default:
2062 sound = actor->info->deathsound;
2063 break;
2064 }
2065
2066 // Check for bosses.
2067 if (actor->type==MT_SPIDER || actor->type == MT_CYBORG)
2068 S_StartSound(NULL, sound); // full volume
2069 else
2070 S_StartSound(actor, sound);
2071}
2072
2073void A_XScream(mobj_t *actor)
2074{
2075 S_StartSound(actor, sfx_slop);
2076}
2077
2078void A_Pain(mobj_t *actor)
2079{
2080 if (actor->info->painsound)
2081 S_StartSound(actor, actor->info->painsound);
2082}
2083
2084void A_Fall(mobj_t *actor)
2085{
2086 // actor is on ground, it can be walked over
2087 actor->flags &= ~MF_SOLID;
2088}
2089
2090//
2091// A_Explode
2092//
2093void A_Explode(mobj_t *thingy)
2094{
2095 P_RadiusAttack( thingy, thingy->target, 128 );
2096}
2097
2098//
2099// A_BossDeath
2100// Possibly trigger special effects
2101// if on first boss level
2102//
2103
2104void A_BossDeath(mobj_t *mo)
2105{
2106 thinker_t *th;
2107 line_t junk;
2108 int i;
2109
2110 if (gamemode == commercial)
2111 {
2112 if (gamemap != 7)
2113 return;
2114
2115 if ((mo->type != MT_FATSO)
2116 && (mo->type != MT_BABY))
2117 return;
2118 }
2119 else
2120 {
2121 // e6y
2122 // Additional check of gameepisode is necessary, because
2123 // there is no right or wrong solution for E4M6 in original EXEs,
2124 // there's nothing to emulate.
2125 if (comp[comp_666] && gameepisode < 4)
2126 {
2127 // e6y
2128 // Only following checks are present in doom2.exe ver. 1.666 and 1.9
2129 // instead of separate checks for each episode in doomult.exe, plutonia.exe and tnt.exe
2130 // There is no more desync on doom.wad\episode3.lmp
2131 // http://www.doomworld.com/idgames/index.php?id=6909
2132 if (gamemap != 8)
2133 return;
2134 if (mo->type == MT_BRUISER && gameepisode != 1)
2135 return;
2136 }
2137 else
2138 {
2139 switch(gameepisode)
2140 {
2141 case 1:
2142 if (gamemap != 8)
2143 return;
2144
2145 if (mo->type != MT_BRUISER)
2146 return;
2147 break;
2148
2149 case 2:
2150 if (gamemap != 8)
2151 return;
2152
2153 if (mo->type != MT_CYBORG)
2154 return;
2155 break;
2156
2157 case 3:
2158 if (gamemap != 8)
2159 return;
2160
2161 if (mo->type != MT_SPIDER)
2162 return;
2163
2164 break;
2165
2166 case 4:
2167 switch(gamemap)
2168 {
2169 case 6:
2170 if (mo->type != MT_CYBORG)
2171 return;
2172 break;
2173
2174 case 8:
2175 if (mo->type != MT_SPIDER)
2176 return;
2177 break;
2178
2179 default:
2180 return;
2181 break;
2182 }
2183 break;
2184
2185 default:
2186 if (gamemap != 8)
2187 return;
2188 break;
2189 }
2190 }
2191
2192 }
2193
2194 // make sure there is a player alive for victory
2195 for (i=0; i<MAXPLAYERS; i++)
2196 if (playeringame[i] && players[i].health > 0)
2197 break;
2198
2199 if (i==MAXPLAYERS)
2200 return; // no one left alive, so do not end game
2201
2202 // scan the remaining thinkers to see
2203 // if all bosses are dead
2204 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
2205 if (th->function == P_MobjThinker)
2206 {
2207 mobj_t *mo2 = (mobj_t *) th;
2208 if (mo2 != mo && mo2->type == mo->type && mo2->health > 0)
2209 return; // other boss not dead
2210 }
2211
2212 // victory!
2213 if ( gamemode == commercial)
2214 {
2215 if (gamemap == 7)
2216 {
2217 if (mo->type == MT_FATSO)
2218 {
2219 junk.tag = 666;
2220 EV_DoFloor(&junk,lowerFloorToLowest);
2221 return;
2222 }
2223
2224 if (mo->type == MT_BABY)
2225 {
2226 junk.tag = 667;
2227 EV_DoFloor(&junk,raiseToTexture);
2228 return;
2229 }
2230 }
2231 }
2232 else
2233 {
2234 switch(gameepisode)
2235 {
2236 case 1:
2237 junk.tag = 666;
2238 EV_DoFloor(&junk, lowerFloorToLowest);
2239 return;
2240 break;
2241
2242 case 4:
2243 switch(gamemap)
2244 {
2245 case 6:
2246 junk.tag = 666;
2247 EV_DoDoor(&junk, blazeOpen);
2248 return;
2249 break;
2250
2251 case 8:
2252 junk.tag = 666;
2253 EV_DoFloor(&junk, lowerFloorToLowest);
2254 return;
2255 break;
2256 }
2257 }
2258 }
2259 G_ExitLevel();
2260}
2261
2262
2263void A_Hoof (mobj_t* mo)
2264{
2265 S_StartSound(mo, sfx_hoof);
2266 A_Chase(mo);
2267}
2268
2269void A_Metal(mobj_t *mo)
2270{
2271 S_StartSound(mo, sfx_metal);
2272 A_Chase(mo);
2273}
2274
2275void A_BabyMetal(mobj_t *mo)
2276{
2277 S_StartSound(mo, sfx_bspwlk);
2278 A_Chase(mo);
2279}
2280
2281void A_OpenShotgun2(player_t *player, pspdef_t *psp)
2282{
2283 S_StartSound(player->mo, sfx_dbopn);
2284}
2285
2286void A_LoadShotgun2(player_t *player, pspdef_t *psp)
2287{
2288 S_StartSound(player->mo, sfx_dbload);
2289}
2290
2291void A_CloseShotgun2(player_t *player, pspdef_t *psp)
2292{
2293 S_StartSound(player->mo, sfx_dbcls);
2294 A_ReFire(player,psp);
2295}
2296
2297// killough 2/7/98: Remove limit on icon landings:
2298mobj_t **braintargets;
2299int numbraintargets_alloc;
2300int numbraintargets;
2301
2302struct brain_s brain; // killough 3/26/98: global state of boss brain
2303
2304// killough 3/26/98: initialize icon landings at level startup,
2305// rather than at boss wakeup, to prevent savegame-related crashes
2306
2307void P_SpawnBrainTargets(void) // killough 3/26/98: renamed old function
2308{
2309 thinker_t *thinker;
2310
2311 // find all the target spots
2312 numbraintargets = 0;
2313 brain.targeton = 0;
2314 brain.easy = 0; // killough 3/26/98: always init easy to 0
2315
2316 for (thinker = thinkercap.next ;
2317 thinker != &thinkercap ;
2318 thinker = thinker->next)
2319 if (thinker->function == P_MobjThinker)
2320 {
2321 mobj_t *m = (mobj_t *) thinker;
2322
2323 if (m->type == MT_BOSSTARGET )
2324 { // killough 2/7/98: remove limit on icon landings:
2325 if (numbraintargets >= numbraintargets_alloc)
2326 braintargets = realloc(braintargets,
2327 (numbraintargets_alloc = numbraintargets_alloc ?
2328 numbraintargets_alloc*2 : 32) *sizeof *braintargets);
2329 braintargets[numbraintargets++] = m;
2330 }
2331 }
2332}
2333
2334void A_BrainAwake(mobj_t *mo)
2335{
2336 S_StartSound(NULL,sfx_bossit); // killough 3/26/98: only generates sound now
2337}
2338
2339void A_BrainPain(mobj_t *mo)
2340{
2341 S_StartSound(NULL,sfx_bospn);
2342}
2343
2344void A_BrainScream(mobj_t *mo)
2345{
2346 int x;
2347 for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
2348 {
2349 int y = mo->y - 320*FRACUNIT;
2350 int z = 128 + P_Random(pr_brainscream)*2*FRACUNIT;
2351 mobj_t *th = P_SpawnMobj (x,y,z, MT_ROCKET);
2352 th->momz = P_Random(pr_brainscream)*512;
2353 P_SetMobjState(th, S_BRAINEXPLODE1);
2354 th->tics -= P_Random(pr_brainscream)&7;
2355 if (th->tics < 1)
2356 th->tics = 1;
2357 }
2358 S_StartSound(NULL,sfx_bosdth);
2359}
2360
2361void A_BrainExplode(mobj_t *mo)
2362{ // killough 5/5/98: remove dependence on order of evaluation:
2363 int t = P_Random(pr_brainexp);
2364 int x = mo->x + (t - P_Random(pr_brainexp))*2048;
2365 int y = mo->y;
2366 int z = 128 + P_Random(pr_brainexp)*2*FRACUNIT;
2367 mobj_t *th = P_SpawnMobj(x,y,z, MT_ROCKET);
2368 th->momz = P_Random(pr_brainexp)*512;
2369 P_SetMobjState(th, S_BRAINEXPLODE1);
2370 th->tics -= P_Random(pr_brainexp)&7;
2371 if (th->tics < 1)
2372 th->tics = 1;
2373}
2374
2375void A_BrainDie(mobj_t *mo)
2376{
2377 G_ExitLevel();
2378}
2379
2380void A_BrainSpit(mobj_t *mo)
2381{
2382 mobj_t *targ, *newmobj;
2383
2384 if (!numbraintargets) // killough 4/1/98: ignore if no targets
2385 return;
2386
2387 brain.easy ^= 1; // killough 3/26/98: use brain struct
2388 if (gameskill <= sk_easy && !brain.easy)
2389 return;
2390
2391 // shoot a cube at current target
2392 targ = braintargets[brain.targeton++]; // killough 3/26/98:
2393 brain.targeton %= numbraintargets; // Use brain struct for targets
2394
2395 // spawn brain missile
2396 newmobj = P_SpawnMissile(mo, targ, MT_SPAWNSHOT);
2397 P_SetTarget(&newmobj->target, targ);
2398 newmobj->reactiontime = (short)(((targ->y-mo->y)/newmobj->momy)/newmobj->state->tics);
2399
2400 // killough 7/18/98: brain friendliness is transferred
2401 newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2402
2403 // killough 8/29/98: add to appropriate thread
2404 P_UpdateThinker(&newmobj->thinker);
2405
2406 S_StartSound(NULL, sfx_bospit);
2407}
2408
2409// travelling cube sound
2410void A_SpawnSound(mobj_t *mo)
2411{
2412 S_StartSound(mo,sfx_boscub);
2413 A_SpawnFly(mo);
2414}
2415
2416void A_SpawnFly(mobj_t *mo)
2417{
2418 mobj_t *newmobj;
2419 mobj_t *fog;
2420 mobj_t *targ;
2421 int r;
2422 mobjtype_t type;
2423
2424 if (--mo->reactiontime)
2425 return; // still flying
2426
2427 targ = mo->target;
2428
2429 // First spawn teleport fog.
2430 fog = P_SpawnMobj(targ->x, targ->y, targ->z, MT_SPAWNFIRE);
2431 S_StartSound(fog, sfx_telept);
2432
2433 // Randomly select monster to spawn.
2434 r = P_Random(pr_spawnfly);
2435
2436 // Probability distribution (kind of :), decreasing likelihood.
2437 if ( r<50 )
2438 type = MT_TROOP;
2439 else if (r<90)
2440 type = MT_SERGEANT;
2441 else if (r<120)
2442 type = MT_SHADOWS;
2443 else if (r<130)
2444 type = MT_PAIN;
2445 else if (r<160)
2446 type = MT_HEAD;
2447 else if (r<162)
2448 type = MT_VILE;
2449 else if (r<172)
2450 type = MT_UNDEAD;
2451 else if (r<192)
2452 type = MT_BABY;
2453 else if (r<222)
2454 type = MT_FATSO;
2455 else if (r<246)
2456 type = MT_KNIGHT;
2457 else
2458 type = MT_BRUISER;
2459
2460 newmobj = P_SpawnMobj(targ->x, targ->y, targ->z, type);
2461
2462 /* killough 7/18/98: brain friendliness is transferred */
2463 newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2464
2465 /* killough 8/29/98: add to appropriate thread */
2466 P_UpdateThinker(&newmobj->thinker);
2467
2468 if (P_LookForTargets(newmobj,true)) /* killough 9/4/98 */
2469 P_SetMobjState(newmobj, newmobj->info->seestate);
2470
2471 // telefrag anything in this spot
2472 P_TeleportMove(newmobj, newmobj->x, newmobj->y, true); /* killough 8/9/98 */
2473
2474 // remove self (i.e., cube).
2475 P_RemoveMobj(mo);
2476}
2477
2478void A_PlayerScream(mobj_t *mo)
2479{
2480 int sound = sfx_pldeth; // Default death sound.
2481 if (gamemode != shareware && mo->health < -50)
2482 sound = sfx_pdiehi; // IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING
2483 S_StartSound(mo, sound);
2484}
2485
2486/* cph - MBF-added codepointer functions */
2487
2488// killough 11/98: kill an object
2489void A_Die(mobj_t *actor)
2490{
2491 P_DamageMobj(actor, NULL, NULL, actor->health);
2492}
2493
2494//
2495// A_Detonate
2496// killough 8/9/98: same as A_Explode, except that the damage is variable
2497//
2498
2499void A_Detonate(mobj_t *mo)
2500{
2501 P_RadiusAttack(mo, mo->target, mo->info->damage);
2502}
2503
2504//
2505// killough 9/98: a mushroom explosion effect, sorta :)
2506// Original idea: Linguica
2507//
2508
2509void A_Mushroom(mobj_t *actor)
2510{
2511 int i, j, n = actor->info->damage;
2512
2513 A_Explode(actor); // First make normal explosion
2514
2515 // Now launch mushroom cloud
2516 for (i = -n; i <= n; i += 8)
2517 for (j = -n; j <= n; j += 8)
2518 {
2519 mobj_t target = *actor, *mo;
2520 target.x += i << FRACBITS; // Aim in many directions from source
2521 target.y += j << FRACBITS;
2522 target.z += P_AproxDistance(i,j) << (FRACBITS+2); // Aim up fairly high
2523 mo = P_SpawnMissile(actor, &target, MT_FATSHOT); // Launch fireball
2524 mo->momx >>= 1;
2525 mo->momy >>= 1; // Slow it down a bit
2526 mo->momz >>= 1;
2527 mo->flags &= ~MF_NOGRAVITY; // Make debris fall under gravity
2528 }
2529}
2530
2531//
2532// killough 11/98
2533//
2534// The following were inspired by Len Pitre
2535//
2536// A small set of highly-sought-after code pointers
2537//
2538
2539void A_Spawn(mobj_t *mo)
2540{
2541 if (mo->state->misc1)
2542 {
2543 /* mobj_t *newmobj = */
2544 P_SpawnMobj(mo->x, mo->y, (mo->state->misc2 << FRACBITS) + mo->z,
2545 mo->state->misc1 - 1);
2546 /* CPhipps - no friendlyness (yet)
2547 newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2548 */
2549 }
2550}
2551
2552void A_Turn(mobj_t *mo)
2553{
2554 mo->angle += (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360);
2555}
2556
2557void A_Face(mobj_t *mo)
2558{
2559 mo->angle = (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360);
2560}
2561
2562void A_Scratch(mobj_t *mo)
2563{
2564 mo->target && (A_FaceTarget(mo), P_CheckMeleeRange(mo)) ?
2565 mo->state->misc2 ? S_StartSound(mo, mo->state->misc2) : (void) 0,
2566 P_DamageMobj(mo->target, mo, mo, mo->state->misc1) : (void) 0;
2567}
2568
2569void A_PlaySound(mobj_t *mo)
2570{
2571 S_StartSound(mo->state->misc2 ? NULL : mo, mo->state->misc1);
2572}
2573
2574void A_RandomJump(mobj_t *mo)
2575{
2576 if (P_Random(pr_randomjump) < mo->state->misc2)
2577 P_SetMobjState(mo, mo->state->misc1);
2578}
2579
2580//
2581// This allows linedef effects to be activated inside deh frames.
2582//
2583
2584void A_LineEffect(mobj_t *mo)
2585{
2586 static line_t junk;
2587 player_t player;
2588 player_t *oldplayer;
2589 junk = *lines;
2590 oldplayer = mo->player;
2591 mo->player = &player;
2592 player.health = 100;
2593 junk.special = (short)mo->state->misc1;
2594 if (!junk.special)
2595 return;
2596 junk.tag = (short)mo->state->misc2;
2597 if (!P_UseSpecialLine(mo, &junk, 0))
2598 P_CrossSpecialLine(&junk, 0, mo);
2599 mo->state->misc1 = junk.special;
2600 mo->player = oldplayer;
2601}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Enemy thinking, AI.
31 * Action Pointer Functions
32 * that are associated with states/frames.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifndef __P_ENEMY__
37#define __P_ENEMY__
38
39#include "p_mobj.h"
40
41void P_NoiseAlert (mobj_t *target, mobj_t *emmiter);
42void P_SpawnBrainTargets(void); /* killough 3/26/98: spawn icon landings */
43
44extern struct brain_s { /* killough 3/26/98: global state of boss brain */
45 int easy, targeton;
46} brain;
47
48// ********************************************************************
49// Function addresses or Code Pointers
50// ********************************************************************
51// These function addresses are the Code Pointers that have been
52// modified for years by Dehacked enthusiasts. The new BEX format
53// allows more extensive changes (see d_deh.c)
54
55// Doesn't work with g++, needs actionf_p1
56void A_Explode();
57void A_Pain();
58void A_PlayerScream();
59void A_Fall();
60void A_XScream();
61void A_Look();
62void A_Chase();
63void A_FaceTarget();
64void A_PosAttack();
65void A_Scream();
66void A_SPosAttack();
67void A_VileChase();
68void A_VileStart();
69void A_VileTarget();
70void A_VileAttack();
71void A_StartFire();
72void A_Fire();
73void A_FireCrackle();
74void A_Tracer();
75void A_SkelWhoosh();
76void A_SkelFist();
77void A_SkelMissile();
78void A_FatRaise();
79void A_FatAttack1();
80void A_FatAttack2();
81void A_FatAttack3();
82void A_BossDeath();
83void A_CPosAttack();
84void A_CPosRefire();
85void A_TroopAttack();
86void A_SargAttack();
87void A_HeadAttack();
88void A_BruisAttack();
89void A_SkullAttack();
90void A_Metal();
91void A_SpidRefire();
92void A_BabyMetal();
93void A_BspiAttack();
94void A_Hoof();
95void A_CyberAttack();
96void A_PainAttack();
97void A_PainDie();
98void A_KeenDie();
99void A_BrainPain();
100void A_BrainScream();
101void A_BrainDie();
102void A_BrainAwake();
103void A_BrainSpit();
104void A_SpawnSound();
105void A_SpawnFly();
106void A_BrainExplode();
107void A_Die();
108void A_Detonate(); /* killough 8/9/98: detonate a bomb or other device */
109void A_Mushroom(); /* killough 10/98: mushroom effect */
110void A_Spawn(); // killough 11/98
111void A_Turn(); // killough 11/98
112void A_Face(); // killough 11/98
113void A_Scratch(); // killough 11/98
114void A_PlaySound(); // killough 11/98
115void A_RandomJump(); // killough 11/98
116void A_LineEffect(); // killough 11/98
117
118#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * General plane mover and floor mover action routines
31 * Floor motion, pure changer types, raising stairs. donuts, elevators
32 *
33 *-----------------------------------------------------------------------------*/
34
35#include "doomstat.h"
36#include "r_main.h"
37#include "p_map.h"
38#include "p_spec.h"
39#include "p_tick.h"
40#include "s_sound.h"
41#include "sounds.h"
42
43///////////////////////////////////////////////////////////////////////
44//
45// Plane (floor or ceiling), Floor motion and Elevator action routines
46//
47///////////////////////////////////////////////////////////////////////
48
49//
50// T_MovePlane()
51//
52// Move a plane (floor or ceiling) and check for crushing. Called
53// every tick by all actions that move floors or ceilings.
54//
55// Passed the sector to move a plane in, the speed to move it at,
56// the dest height it is to achieve, whether it crushes obstacles,
57// whether it moves a floor or ceiling, and the direction up or down
58// to move.
59//
60// Returns a result_e:
61// ok - plane moved normally, has not achieved destination yet
62// pastdest - plane moved normally and is now at destination height
63// crushed - plane encountered an obstacle, is holding until removed
64//
65result_e T_MovePlane
66( sector_t* sector,
67 fixed_t speed,
68 fixed_t dest,
69 boolean crush,
70 int floorOrCeiling,
71 int direction )
72{
73 boolean flag;
74 fixed_t lastpos;
75 fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings
76 // from moving thru each other
77
78 switch(floorOrCeiling)
79 {
80 case 0:
81 // Moving a floor
82 switch(direction)
83 {
84 case -1:
85 // Moving a floor down
86 if (sector->floorheight - speed < dest)
87 {
88 lastpos = sector->floorheight;
89 sector->floorheight = dest;
90 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
91 if (flag == true)
92 {
93 sector->floorheight =lastpos;
94 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
95 }
96 return pastdest;
97 }
98 else
99 {
100 lastpos = sector->floorheight;
101 sector->floorheight -= speed;
102 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
103 /* cph - make more compatible with original Doom, by
104 * reintroducing this code. This means floors can't lower
105 * if objects are stuck in the ceiling */
106 if ((flag == true) && comp[comp_floors]) {
107 sector->floorheight = lastpos;
108 P_ChangeSector(sector,crush);
109 return crushed;
110 }
111 }
112 break;
113
114 case 1:
115 // Moving a floor up
116 // jff 02/04/98 keep floor from moving thru ceilings
117 // jff 2/22/98 weaken check to demo_compatibility
118 destheight = (comp[comp_floors] || dest<sector->ceilingheight)?
119 dest : sector->ceilingheight;
120 if (sector->floorheight + speed > destheight)
121 {
122 lastpos = sector->floorheight;
123 sector->floorheight = destheight;
124 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
125 if (flag == true)
126 {
127 sector->floorheight = lastpos;
128 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
129 }
130 return pastdest;
131 }
132 else
133 {
134 // crushing is possible
135 lastpos = sector->floorheight;
136 sector->floorheight += speed;
137 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
138 if (flag == true)
139 {
140 /* jff 1/25/98 fix floor crusher */
141 if (comp[comp_floors]) {
142 if (crush == true)
143 return crushed;
144 }
145 sector->floorheight = lastpos;
146 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
147 return crushed;
148 }
149 }
150 break;
151 }
152 break;
153
154 case 1:
155 // moving a ceiling
156 switch(direction)
157 {
158 case -1:
159 // moving a ceiling down
160 // jff 02/04/98 keep ceiling from moving thru floors
161 // jff 2/22/98 weaken check to demo_compatibility
162 destheight = (comp[comp_floors] || dest>sector->floorheight)?
163 dest : sector->floorheight;
164 if (sector->ceilingheight - speed < destheight)
165 {
166 lastpos = sector->ceilingheight;
167 sector->ceilingheight = destheight;
168 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
169
170 if (flag == true)
171 {
172 sector->ceilingheight = lastpos;
173 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
174 }
175 return pastdest;
176 }
177 else
178 {
179 // crushing is possible
180 lastpos = sector->ceilingheight;
181 sector->ceilingheight -= speed;
182 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
183
184 if (flag == true)
185 {
186 if (crush == true)
187 return crushed;
188 sector->ceilingheight = lastpos;
189 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
190 return crushed;
191 }
192 }
193 break;
194
195 case 1:
196 // moving a ceiling up
197 if (sector->ceilingheight + speed > dest)
198 {
199 lastpos = sector->ceilingheight;
200 sector->ceilingheight = dest;
201 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
202 if (flag == true)
203 {
204 sector->ceilingheight = lastpos;
205 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
206 }
207 return pastdest;
208 }
209 else
210 {
211 lastpos = sector->ceilingheight;
212 sector->ceilingheight += speed;
213 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
214 }
215 break;
216 }
217 break;
218 }
219 return ok;
220}
221
222//
223// T_MoveFloor()
224//
225// Move a floor to it's destination (up or down).
226// Called once per tick for each moving floor.
227//
228// Passed a floormove_t structure that contains all pertinent info about the
229// move. See P_SPEC.H for fields.
230// No return.
231//
232// jff 02/08/98 all cases with labels beginning with gen added to support
233// generalized line type behaviors.
234
235void T_MoveFloor(floormove_t* floor)
236{
237 result_e res;
238
239 res = T_MovePlane // move the floor
240 (
241 floor->sector,
242 floor->speed,
243 floor->floordestheight,
244 floor->crush,
245 0,
246 floor->direction
247 );
248
249 if (!(leveltime&7)) // make the floormove sound
250 S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_stnmov);
251
252 if (res == pastdest) // if destination height is reached
253 {
254 if (floor->direction == 1) // going up
255 {
256 switch(floor->type) // handle texture/type changes
257 {
258 case donutRaise:
259 floor->sector->special = floor->newspecial;
260 floor->sector->floorpic = floor->texture;
261 break;
262 case genFloorChgT:
263 case genFloorChg0:
264 floor->sector->special = floor->newspecial;
265 //jff add to fix bug in special transfers from changes
266 floor->sector->oldspecial = floor->oldspecial;
267 //fall thru
268 case genFloorChg:
269 floor->sector->floorpic = floor->texture;
270 break;
271 default:
272 break;
273 }
274 }
275 else if (floor->direction == -1) // going down
276 {
277 switch(floor->type) // handle texture/type changes
278 {
279 case lowerAndChange:
280 floor->sector->special = floor->newspecial;
281 //jff add to fix bug in special transfers from changes
282 floor->sector->oldspecial = floor->oldspecial;
283 floor->sector->floorpic = floor->texture;
284 break;
285 case genFloorChgT:
286 case genFloorChg0:
287 floor->sector->special = floor->newspecial;
288 //jff add to fix bug in special transfers from changes
289 floor->sector->oldspecial = floor->oldspecial;
290 //fall thru
291 case genFloorChg:
292 floor->sector->floorpic = floor->texture;
293 break;
294 default:
295 break;
296 }
297 }
298
299 floor->sector->floordata = NULL; //jff 2/22/98
300 P_RemoveThinker(&floor->thinker);//remove this floor from list of movers
301
302 //jff 2/26/98 implement stair retrigger lockout while still building
303 // note this only applies to the retriggerable generalized stairs
304
305 if (floor->sector->stairlock==-2) // if this sector is stairlocked
306 {
307 sector_t *sec = floor->sector;
308 sec->stairlock=-1; // thinker done, promote lock to -1
309
310 while (sec->prevsec!=-1 && sectors[sec->prevsec].stairlock!=-2)
311 sec = &sectors[sec->prevsec]; // search for a non-done thinker
312 if (sec->prevsec==-1) // if all thinkers previous are done
313 {
314 sec = floor->sector; // search forward
315 while (sec->nextsec!=-1 && sectors[sec->nextsec].stairlock!=-2)
316 sec = &sectors[sec->nextsec];
317 if (sec->nextsec==-1) // if all thinkers ahead are done too
318 {
319 while (sec->prevsec!=-1) // clear all locks
320 {
321 sec->stairlock = 0;
322 sec = &sectors[sec->prevsec];
323 }
324 sec->stairlock = 0;
325 }
326 }
327 }
328
329 // make floor stop sound
330 S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop);
331 }
332}
333
334//
335// T_MoveElevator()
336//
337// Move an elevator to it's destination (up or down)
338// Called once per tick for each moving floor.
339//
340// Passed an elevator_t structure that contains all pertinent info about the
341// move. See P_SPEC.H for fields.
342// No return.
343//
344// jff 02/22/98 added to support parallel floor/ceiling motion
345//
346void T_MoveElevator(elevator_t* elevator)
347{
348 result_e res;
349
350 if (elevator->direction<0) // moving down
351 {
352 res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
353 (
354 elevator->sector,
355 elevator->speed,
356 elevator->ceilingdestheight,
357 0,
358 1, // move floor
359 elevator->direction
360 );
361 if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked
362 T_MovePlane
363 (
364 elevator->sector,
365 elevator->speed,
366 elevator->floordestheight,
367 0,
368 0, // move ceiling
369 elevator->direction
370 );
371 }
372 else // up
373 {
374 res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
375 (
376 elevator->sector,
377 elevator->speed,
378 elevator->floordestheight,
379 0,
380 0, // move ceiling
381 elevator->direction
382 );
383 if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked
384 T_MovePlane
385 (
386 elevator->sector,
387 elevator->speed,
388 elevator->ceilingdestheight,
389 0,
390 1, // move floor
391 elevator->direction
392 );
393 }
394
395 // make floor move sound
396 if (!(leveltime&7))
397 S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_stnmov);
398
399 if (res == pastdest) // if destination height acheived
400 {
401 elevator->sector->floordata = NULL; //jff 2/22/98
402 elevator->sector->ceilingdata = NULL; //jff 2/22/98
403 P_RemoveThinker(&elevator->thinker); // remove elevator from actives
404
405 // make floor stop sound
406 S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_pstop);
407 }
408}
409
410///////////////////////////////////////////////////////////////////////
411//
412// Floor motion linedef handlers
413//
414///////////////////////////////////////////////////////////////////////
415
416//
417// EV_DoFloor()
418//
419// Handle regular and extended floor types
420//
421// Passed the line that activated the floor and the type of floor motion
422// Returns true if a thinker was created.
423//
424int EV_DoFloor
425( line_t* line,
426 floor_e floortype )
427{
428 int secnum;
429 int rtn;
430 int i;
431 sector_t* sec;
432 floormove_t* floor;
433
434 secnum = -1;
435 rtn = 0;
436 // move all floors with the same tag as the linedef
437 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
438 {
439 sec = &sectors[secnum];
440
441 // Don't start a second thinker on the same floor
442 if (P_SectorActive(floor_special,sec)) //jff 2/23/98
443 continue;
444
445 // new floor thinker
446 rtn = 1;
447 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
448 memset(floor, 0, sizeof(*floor));
449 P_AddThinker (&floor->thinker);
450 sec->floordata = floor; //jff 2/22/98
451 floor->thinker.function = T_MoveFloor;
452 floor->type = floortype;
453 floor->crush = false;
454
455 // setup the thinker according to the linedef type
456 switch(floortype)
457 {
458 case lowerFloor:
459 floor->direction = -1;
460 floor->sector = sec;
461 floor->speed = FLOORSPEED;
462 floor->floordestheight = P_FindHighestFloorSurrounding(sec);
463 break;
464
465 //jff 02/03/30 support lowering floor by 24 absolute
466 case lowerFloor24:
467 floor->direction = -1;
468 floor->sector = sec;
469 floor->speed = FLOORSPEED;
470 floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
471 break;
472
473 //jff 02/03/30 support lowering floor by 32 absolute (fast)
474 case lowerFloor32Turbo:
475 floor->direction = -1;
476 floor->sector = sec;
477 floor->speed = FLOORSPEED*4;
478 floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT;
479 break;
480
481 case lowerFloorToLowest:
482 floor->direction = -1;
483 floor->sector = sec;
484 floor->speed = FLOORSPEED;
485 floor->floordestheight = P_FindLowestFloorSurrounding(sec);
486 break;
487
488 //jff 02/03/30 support lowering floor to next lowest floor
489 case lowerFloorToNearest:
490 floor->direction = -1;
491 floor->sector = sec;
492 floor->speed = FLOORSPEED;
493 floor->floordestheight =
494 P_FindNextLowestFloor(sec,floor->sector->floorheight);
495 break;
496
497 case turboLower:
498 floor->direction = -1;
499 floor->sector = sec;
500 floor->speed = FLOORSPEED * 4;
501 floor->floordestheight = P_FindHighestFloorSurrounding(sec);
502 if (floor->floordestheight != sec->floorheight)
503 floor->floordestheight += 8*FRACUNIT;
504 break;
505
506 case raiseFloorCrush:
507 floor->crush = true;
508 case raiseFloor:
509 floor->direction = 1;
510 floor->sector = sec;
511 floor->speed = FLOORSPEED;
512 floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
513 if (floor->floordestheight > sec->ceilingheight)
514 floor->floordestheight = sec->ceilingheight;
515 floor->floordestheight -= (8*FRACUNIT)*(floortype == raiseFloorCrush);
516 break;
517
518 case raiseFloorTurbo:
519 floor->direction = 1;
520 floor->sector = sec;
521 floor->speed = FLOORSPEED*4;
522 floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight);
523 break;
524
525 case raiseFloorToNearest:
526 floor->direction = 1;
527 floor->sector = sec;
528 floor->speed = FLOORSPEED;
529 floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight);
530 break;
531
532 case raiseFloor24:
533 floor->direction = 1;
534 floor->sector = sec;
535 floor->speed = FLOORSPEED;
536 floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
537 break;
538
539 // jff 2/03/30 support straight raise by 32 (fast)
540 case raiseFloor32Turbo:
541 floor->direction = 1;
542 floor->sector = sec;
543 floor->speed = FLOORSPEED*4;
544 floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT;
545 break;
546
547 case raiseFloor512:
548 floor->direction = 1;
549 floor->sector = sec;
550 floor->speed = FLOORSPEED;
551 floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT;
552 break;
553
554 case raiseFloor24AndChange:
555 floor->direction = 1;
556 floor->sector = sec;
557 floor->speed = FLOORSPEED;
558 floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
559 sec->floorpic = line->frontsector->floorpic;
560 sec->special = line->frontsector->special;
561 //jff 3/14/98 transfer both old and new special
562 sec->oldspecial = line->frontsector->oldspecial;
563 break;
564
565 case raiseToTexture:
566 {
567 int minsize = INT_MAX;
568 side_t* side;
569
570 /* jff 3/13/98 no ovf */
571 if (!comp[comp_model]) minsize = 32000<<FRACBITS;
572 floor->direction = 1;
573 floor->sector = sec;
574 floor->speed = FLOORSPEED;
575 for (i = 0; i < sec->linecount; i++)
576 {
577 if (twoSided (secnum, i) )
578 {
579 side = getSide(secnum,i,0);
580 // jff 8/14/98 don't scan texture 0, its not real
581 if (side->bottomtexture > 0 ||
582 (comp[comp_model] && !side->bottomtexture))
583 if (textureheight[side->bottomtexture] < minsize)
584 minsize = textureheight[side->bottomtexture];
585 side = getSide(secnum,i,1);
586 // jff 8/14/98 don't scan texture 0, its not real
587 if (side->bottomtexture > 0 ||
588 (comp[comp_model] && !side->bottomtexture))
589 if (textureheight[side->bottomtexture] < minsize)
590 minsize = textureheight[side->bottomtexture];
591 }
592 }
593 if (comp[comp_model])
594 floor->floordestheight = floor->sector->floorheight + minsize;
595 else
596 {
597 floor->floordestheight =
598 (floor->sector->floorheight>>FRACBITS) + (minsize>>FRACBITS);
599 if (floor->floordestheight>32000)
600 floor->floordestheight = 32000; //jff 3/13/98 do not
601 floor->floordestheight<<=FRACBITS; // allow height overflow
602 }
603 }
604 break;
605
606 case lowerAndChange:
607 floor->direction = -1;
608 floor->sector = sec;
609 floor->speed = FLOORSPEED;
610 floor->floordestheight = P_FindLowestFloorSurrounding(sec);
611 floor->texture = sec->floorpic;
612
613 // jff 1/24/98 make sure floor->newspecial gets initialized
614 // in case no surrounding sector is at floordestheight
615 // --> should not affect compatibility <--
616 floor->newspecial = sec->special;
617 //jff 3/14/98 transfer both old and new special
618 floor->oldspecial = sec->oldspecial;
619
620 //jff 5/23/98 use model subroutine to unify fixes and handling
621 sec = P_FindModelFloorSector(floor->floordestheight,sec-sectors);
622 if (sec)
623 {
624 floor->texture = sec->floorpic;
625 floor->newspecial = sec->special;
626 //jff 3/14/98 transfer both old and new special
627 floor->oldspecial = sec->oldspecial;
628 }
629 break;
630 default:
631 break;
632 }
633 }
634 return rtn;
635}
636
637//
638// EV_DoChange()
639//
640// Handle pure change types. These change floor texture and sector type
641// by trigger or numeric model without moving the floor.
642//
643// The linedef causing the change and the type of change is passed
644// Returns true if any sector changes
645//
646// jff 3/15/98 added to better support generalized sector types
647//
648int EV_DoChange
649( line_t* line,
650 change_e changetype )
651{
652 int secnum;
653 int rtn;
654 sector_t* sec;
655 sector_t* secm;
656
657 secnum = -1;
658 rtn = 0;
659 // change all sectors with the same tag as the linedef
660 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
661 {
662 sec = &sectors[secnum];
663
664 rtn = 1;
665
666 // handle trigger or numeric change type
667 switch(changetype)
668 {
669 case trigChangeOnly:
670 sec->floorpic = line->frontsector->floorpic;
671 sec->special = line->frontsector->special;
672 sec->oldspecial = line->frontsector->oldspecial;
673 break;
674 case numChangeOnly:
675 secm = P_FindModelFloorSector(sec->floorheight,secnum);
676 if (secm) // if no model, no change
677 {
678 sec->floorpic = secm->floorpic;
679 sec->special = secm->special;
680 sec->oldspecial = secm->oldspecial;
681 }
682 break;
683 default:
684 break;
685 }
686 }
687 return rtn;
688}
689
690/*
691 * EV_BuildStairs()
692 *
693 * Handles staircase building. A sequence of sectors chosen by algorithm
694 * rise at a speed indicated to a height that increases by the stepsize
695 * each step.
696 *
697 * Passed the linedef triggering the stairs and the type of stair rise
698 * Returns true if any thinkers are created
699 *
700 * cph 2001/09/21 - compatibility nightmares again
701 * There are three different ways this function has, during its history, stepped
702 * through all the stairs to be triggered by the single switch
703 * - original Doom used a linear P_FindSectorFromLineTag, but failed to preserve
704 * the index of the previous sector found, so instead it would restart its
705 * linear search from the last sector of the previous staircase
706 * - MBF/PrBoom with comp_stairs fail to emulate this, because their
707 * P_FindSectorFromLineTag is a chained hash table implementation. Instead they
708 * start following the hash chain from the last sector of the previous
709 * staircase, which will (probably) have the wrong tag, so they miss any further
710 * stairs
711 * - Boom fixed the bug, and MBF/PrBoom without comp_stairs work right
712 */
713static inline int P_FindSectorFromLineTagWithLowerBound
714(line_t* l, int start, int min)
715{
716 /* Emulate original Doom's linear lower-bounded P_FindSectorFromLineTag
717 * as needed */
718 do {
719 start = P_FindSectorFromLineTag(l,start);
720 } while (start >= 0 && start <= min);
721 return start;
722}
723
724int EV_BuildStairs
725( line_t* line,
726 stair_e type )
727{
728 /* cph 2001/09/22 - cleaned up this function to save my sanity. A separate
729 * outer loop index makes the logic much cleared, and local variables moved
730 * into the inner blocks helps too */
731 int ssec = -1;
732 int minssec = -1;
733 int rtn = 0;
734
735 // start a stair at each sector tagged the same as the linedef
736 while ((ssec = P_FindSectorFromLineTagWithLowerBound(line,ssec,minssec)) >= 0)
737 {
738 int secnum = ssec;
739 sector_t* sec = &sectors[secnum];
740
741 // don't start a stair if the first step's floor is already moving
742 if (!P_SectorActive(floor_special,sec)) { //jff 2/22/98
743 floormove_t* floor;
744 int texture, height;
745 fixed_t stairsize;
746 fixed_t speed;
747 int ok;
748
749 // create new floor thinker for first step
750 rtn = 1;
751 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
752 memset(floor, 0, sizeof(*floor));
753 P_AddThinker (&floor->thinker);
754 sec->floordata = floor;
755 floor->thinker.function = T_MoveFloor;
756 floor->direction = 1;
757 floor->sector = sec;
758 floor->type = buildStair; //jff 3/31/98 do not leave uninited
759
760 // set up the speed and stepsize according to the stairs type
761 switch(type)
762 {
763 default: // killough -- prevent compiler warning
764 case build8:
765 speed = FLOORSPEED/4;
766 stairsize = 8*FRACUNIT;
767 if (!demo_compatibility)
768 floor->crush = false; //jff 2/27/98 fix uninitialized crush field
769 break;
770 case turbo16:
771 speed = FLOORSPEED*4;
772 stairsize = 16*FRACUNIT;
773 if (!demo_compatibility)
774 floor->crush = true; //jff 2/27/98 fix uninitialized crush field
775 break;
776 }
777 floor->speed = speed;
778 height = sec->floorheight + stairsize;
779 floor->floordestheight = height;
780
781 texture = sec->floorpic;
782
783 // Find next sector to raise
784 // 1. Find 2-sided line with same sector side[0] (lowest numbered)
785 // 2. Other side is the next sector to raise
786 // 3. Unless already moving, or different texture, then stop building
787 do
788 {
789 int i;
790 ok = 0;
791
792 for (i = 0;i < sec->linecount;i++)
793 {
794 sector_t* tsec = (sec->lines[i])->frontsector;
795 int newsecnum;
796 if ( !((sec->lines[i])->flags & ML_TWOSIDED) )
797 continue;
798
799 newsecnum = tsec-sectors;
800
801 if (secnum != newsecnum)
802 continue;
803
804 tsec = (sec->lines[i])->backsector;
805 if (!tsec) continue; //jff 5/7/98 if no backside, continue
806 newsecnum = tsec - sectors;
807
808 // if sector's floor is different texture, look for another
809 if (tsec->floorpic != texture)
810 continue;
811
812 /* jff 6/19/98 prevent double stepsize
813 * killough 10/98: intentionally left this way [MBF comment]
814 * cph 2001/02/06: stair bug fix should be controlled by comp_stairs,
815 * except if we're emulating MBF which perversly reverted the fix
816 */
817 if (comp[comp_stairs] || (compatibility_level == mbf_compatibility))
818 height += stairsize; // jff 6/28/98 change demo compatibility
819
820 // if sector's floor already moving, look for another
821 if (P_SectorActive(floor_special,tsec)) //jff 2/22/98
822 continue;
823
824 /* cph - see comment above - do this iff we didn't do so above */
825 if (!comp[comp_stairs] && (compatibility_level != mbf_compatibility))
826 height += stairsize;
827
828 sec = tsec;
829 secnum = newsecnum;
830
831 // create and initialize a thinker for the next step
832 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
833 memset(floor, 0, sizeof(*floor));
834 P_AddThinker (&floor->thinker);
835
836 sec->floordata = floor; //jff 2/22/98
837 floor->thinker.function = T_MoveFloor;
838 floor->direction = 1;
839 floor->sector = sec;
840 floor->speed = speed;
841 floor->floordestheight = height;
842 floor->type = buildStair; //jff 3/31/98 do not leave uninited
843 //jff 2/27/98 fix uninitialized crush field
844 if (!demo_compatibility)
845 floor->crush = type==build8? false : true;
846 ok = 1;
847 break;
848 }
849 } while(ok); // continue until no next step is found
850
851 }
852 /* killough 10/98: compatibility option */
853 if (comp[comp_stairs]) {
854 /* cph 2001/09/22 - emulate buggy MBF comp_stairs for demos, with logic
855 * reversed since we now have a separate outer loop index.
856 * DEMOSYNC - what about boom_compatibility_compatibility?
857 */
858 if ((compatibility_level >= mbf_compatibility) && (compatibility_level <
859 prboom_3_compatibility)) ssec = secnum; /* Trash outer loop index */
860 else {
861 /* cph 2001/09/22 - now the correct comp_stairs - Doom used a linear
862 * search from the last secnum, so we set that as a minimum value and do
863 * a fresh tag search
864 */
865 ssec = -1; minssec = secnum;
866 }
867 }
868 }
869 return rtn;
870}
871
872//
873// EV_DoDonut()
874//
875// Handle donut function: lower pillar, raise surrounding pool, both to height,
876// texture and type of the sector surrounding the pool.
877//
878// Passed the linedef that triggered the donut
879// Returns whether a thinker was created
880//
881int EV_DoDonut(line_t* line)
882{
883 sector_t* s1;
884 sector_t* s2;
885 sector_t* s3;
886 int secnum;
887 int rtn;
888 int i;
889 floormove_t* floor;
890
891 secnum = -1;
892 rtn = 0;
893 // do function on all sectors with same tag as linedef
894 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
895 {
896 s1 = &sectors[secnum]; // s1 is pillar's sector
897
898 // do not start the donut if the pillar is already moving
899 if (P_SectorActive(floor_special,s1)) //jff 2/22/98
900 continue;
901
902 s2 = getNextSector(s1->lines[0],s1); // s2 is pool's sector
903 if (!s2) continue; // note lowest numbered line around
904 // pillar must be two-sided
905
906 /* do not start the donut if the pool is already moving
907 * cph - DEMOSYNC - was !compatibility */
908 if (!comp[comp_floors] && P_SectorActive(floor_special,s2))
909 continue; //jff 5/7/98
910
911 // find a two sided line around the pool whose other side isn't the pillar
912 for (i = 0;i < s2->linecount;i++)
913 {
914 //jff 3/29/98 use true two-sidedness, not the flag
915 // killough 4/5/98: changed demo_compatibility to compatibility
916 if (comp[comp_model])
917 {
918 if ((!s2->lines[i]->flags & ML_TWOSIDED) ||
919 (s2->lines[i]->backsector == s1))
920 continue;
921 }
922 else if (!s2->lines[i]->backsector || s2->lines[i]->backsector == s1)
923 continue;
924
925 rtn = 1; //jff 1/26/98 no donut action - no switch change on return
926
927 s3 = s2->lines[i]->backsector; // s3 is model sector for changes
928
929 // Spawn rising slime
930 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
931 memset(floor, 0, sizeof(*floor));
932 P_AddThinker (&floor->thinker);
933 s2->floordata = floor; //jff 2/22/98
934 floor->thinker.function = T_MoveFloor;
935 floor->type = donutRaise;
936 floor->crush = false;
937 floor->direction = 1;
938 floor->sector = s2;
939 floor->speed = FLOORSPEED / 2;
940 floor->texture = s3->floorpic;
941 floor->newspecial = 0;
942 floor->floordestheight = s3->floorheight;
943
944 // Spawn lowering donut-hole pillar
945 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
946 memset(floor, 0, sizeof(*floor));
947 P_AddThinker (&floor->thinker);
948 s1->floordata = floor; //jff 2/22/98
949 floor->thinker.function = T_MoveFloor;
950 floor->type = lowerFloor;
951 floor->crush = false;
952 floor->direction = -1;
953 floor->sector = s1;
954 floor->speed = FLOORSPEED / 2;
955 floor->floordestheight = s3->floorheight;
956 break;
957 }
958 }
959 return rtn;
960}
961
962//
963// EV_DoElevator
964//
965// Handle elevator linedef types
966//
967// Passed the linedef that triggered the elevator and the elevator action
968//
969// jff 2/22/98 new type to move floor and ceiling in parallel
970//
971int EV_DoElevator
972( line_t* line,
973 elevator_e elevtype )
974{
975 int secnum;
976 int rtn;
977 sector_t* sec;
978 elevator_t* elevator;
979
980 secnum = -1;
981 rtn = 0;
982 // act on all sectors with the same tag as the triggering linedef
983 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
984 {
985 sec = &sectors[secnum];
986
987 // If either floor or ceiling is already activated, skip it
988 if (sec->floordata || sec->ceilingdata) //jff 2/22/98
989 continue;
990
991 // create and initialize new elevator thinker
992 rtn = 1;
993 elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0);
994 memset(elevator, 0, sizeof(*elevator));
995 P_AddThinker (&elevator->thinker);
996 sec->floordata = elevator; //jff 2/22/98
997 sec->ceilingdata = elevator; //jff 2/22/98
998 elevator->thinker.function = T_MoveElevator;
999 elevator->type = elevtype;
1000
1001 // set up the fields according to the type of elevator action
1002 switch(elevtype)
1003 {
1004 // elevator down to next floor
1005 case elevateDown:
1006 elevator->direction = -1;
1007 elevator->sector = sec;
1008 elevator->speed = ELEVATORSPEED;
1009 elevator->floordestheight =
1010 P_FindNextLowestFloor(sec,sec->floorheight);
1011 elevator->ceilingdestheight =
1012 elevator->floordestheight + sec->ceilingheight - sec->floorheight;
1013 break;
1014
1015 // elevator up to next floor
1016 case elevateUp:
1017 elevator->direction = 1;
1018 elevator->sector = sec;
1019 elevator->speed = ELEVATORSPEED;
1020 elevator->floordestheight =
1021 P_FindNextHighestFloor(sec,sec->floorheight);
1022 elevator->ceilingdestheight =
1023 elevator->floordestheight + sec->ceilingheight - sec->floorheight;
1024 break;
1025
1026 // elevator to floor height of activating switch's front sector
1027 case elevateCurrent:
1028 elevator->sector = sec;
1029 elevator->speed = ELEVATORSPEED;
1030 elevator->floordestheight = line->frontsector->floorheight;
1031 elevator->ceilingdestheight =
1032 elevator->floordestheight + sec->ceilingheight - sec->floorheight;
1033 elevator->direction =
1034 elevator->floordestheight>sec->floorheight? 1 : -1;
1035 break;
1036
1037 default:
1038 break;
1039 }
1040 }
1041 return rtn;
1042}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Generalized linedef type handlers
31 * Floors, Ceilings, Doors, Locked Doors, Lifts, Stairs, Crushers
32 *
33 *-----------------------------------------------------------------------------*/
34
35#include "doomstat.h" //jff 6/19/98 for demo_compatibility
36#include "r_main.h"
37#include "p_spec.h"
38#include "p_tick.h"
39#include "m_random.h"
40#include "s_sound.h"
41#include "sounds.h"
42
43//////////////////////////////////////////////////////////
44//
45// Generalized Linedef Type handlers
46//
47//////////////////////////////////////////////////////////
48
49//
50// EV_DoGenFloor()
51//
52// Handle generalized floor types
53//
54// Passed the line activating the generalized floor function
55// Returns true if a thinker is created
56//
57// jff 02/04/98 Added this routine (and file) to handle generalized
58// floor movers using bit fields in the line special type.
59//
60int EV_DoGenFloor
61( line_t* line )
62{
63 int secnum;
64 int rtn;
65 boolean manual;
66 sector_t* sec;
67 floormove_t* floor;
68 unsigned value = (unsigned)line->special - GenFloorBase;
69
70 // parse the bit fields in the line's special type
71
72 int Crsh = (value & FloorCrush) >> FloorCrushShift;
73 int ChgT = (value & FloorChange) >> FloorChangeShift;
74 int Targ = (value & FloorTarget) >> FloorTargetShift;
75 int Dirn = (value & FloorDirection) >> FloorDirectionShift;
76 int ChgM = (value & FloorModel) >> FloorModelShift;
77 int Sped = (value & FloorSpeed) >> FloorSpeedShift;
78 int Trig = (value & TriggerType) >> TriggerTypeShift;
79
80 rtn = 0;
81
82 // check if a manual trigger, if so do just the sector on the backside
83 manual = false;
84 if (Trig==PushOnce || Trig==PushMany)
85 {
86 if (!(sec = line->backsector))
87 return rtn;
88 secnum = sec-sectors;
89 manual = true;
90 goto manual_floor;
91 }
92
93 secnum = -1;
94 // if not manual do all sectors tagged the same as the line
95 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
96 {
97 sec = &sectors[secnum];
98
99manual_floor:
100 // Do not start another function if floor already moving
101 if (P_SectorActive(floor_special,sec))
102 {
103 if (!manual)
104 continue;
105 else
106 return rtn;
107 }
108
109 // new floor thinker
110 rtn = 1;
111 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
112 memset(floor, 0, sizeof(*floor));
113 P_AddThinker (&floor->thinker);
114 sec->floordata = floor;
115 floor->thinker.function = T_MoveFloor;
116 floor->crush = Crsh;
117 floor->direction = Dirn? 1 : -1;
118 floor->sector = sec;
119 floor->texture = sec->floorpic;
120 floor->newspecial = sec->special;
121 //jff 3/14/98 transfer old special field too
122 floor->oldspecial = sec->oldspecial;
123 floor->type = genFloor;
124
125 // set the speed of motion
126 switch (Sped)
127 {
128 case SpeedSlow:
129 floor->speed = FLOORSPEED;
130 break;
131 case SpeedNormal:
132 floor->speed = FLOORSPEED*2;
133 break;
134 case SpeedFast:
135 floor->speed = FLOORSPEED*4;
136 break;
137 case SpeedTurbo:
138 floor->speed = FLOORSPEED*8;
139 break;
140 default:
141 break;
142 }
143
144 // set the destination height
145 switch(Targ)
146 {
147 case FtoHnF:
148 floor->floordestheight = P_FindHighestFloorSurrounding(sec);
149 break;
150 case FtoLnF:
151 floor->floordestheight = P_FindLowestFloorSurrounding(sec);
152 break;
153 case FtoNnF:
154 floor->floordestheight = Dirn?
155 P_FindNextHighestFloor(sec,sec->floorheight) :
156 P_FindNextLowestFloor(sec,sec->floorheight);
157 break;
158 case FtoLnC:
159 floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
160 break;
161 case FtoC:
162 floor->floordestheight = sec->ceilingheight;
163 break;
164 case FbyST:
165 floor->floordestheight = (floor->sector->floorheight>>FRACBITS) +
166 floor->direction * (P_FindShortestTextureAround(secnum)>>FRACBITS);
167 if (floor->floordestheight>32000) //jff 3/13/98 prevent overflow
168 floor->floordestheight=32000; // wraparound in floor height
169 if (floor->floordestheight<-32000)
170 floor->floordestheight=-32000;
171 floor->floordestheight<<=FRACBITS;
172 break;
173 case Fby24:
174 floor->floordestheight = floor->sector->floorheight +
175 floor->direction * 24*FRACUNIT;
176 break;
177 case Fby32:
178 floor->floordestheight = floor->sector->floorheight +
179 floor->direction * 32*FRACUNIT;
180 break;
181 default:
182 break;
183 }
184
185 // set texture/type change properties
186 if (ChgT) // if a texture change is indicated
187 {
188 if (ChgM) // if a numeric model change
189 {
190 sector_t *sec;
191
192 //jff 5/23/98 find model with ceiling at target height if target
193 //is a ceiling type
194 sec = (Targ==FtoLnC || Targ==FtoC)?
195 P_FindModelCeilingSector(floor->floordestheight,secnum) :
196 P_FindModelFloorSector(floor->floordestheight,secnum);
197 if (sec)
198 {
199 floor->texture = sec->floorpic;
200 switch(ChgT)
201 {
202 case FChgZero: // zero type
203 floor->newspecial = 0;
204 //jff 3/14/98 change old field too
205 floor->oldspecial = 0;
206 floor->type = genFloorChg0;
207 break;
208 case FChgTyp: // copy type
209 floor->newspecial = sec->special;
210 //jff 3/14/98 change old field too
211 floor->oldspecial = sec->oldspecial;
212 floor->type = genFloorChgT;
213 break;
214 case FChgTxt: // leave type be
215 floor->type = genFloorChg;
216 break;
217 default:
218 break;
219 }
220 }
221 }
222 else // else if a trigger model change
223 {
224 floor->texture = line->frontsector->floorpic;
225 switch (ChgT)
226 {
227 case FChgZero: // zero type
228 floor->newspecial = 0;
229 //jff 3/14/98 change old field too
230 floor->oldspecial = 0;
231 floor->type = genFloorChg0;
232 break;
233 case FChgTyp: // copy type
234 floor->newspecial = line->frontsector->special;
235 //jff 3/14/98 change old field too
236 floor->oldspecial = line->frontsector->oldspecial;
237 floor->type = genFloorChgT;
238 break;
239 case FChgTxt: // leave type be
240 floor->type = genFloorChg;
241 default:
242 break;
243 }
244 }
245 }
246 if (manual) return rtn;
247 }
248 return rtn;
249}
250
251
252//
253// EV_DoGenCeiling()
254//
255// Handle generalized ceiling types
256//
257// Passed the linedef activating the ceiling function
258// Returns true if a thinker created
259//
260// jff 02/04/98 Added this routine (and file) to handle generalized
261// floor movers using bit fields in the line special type.
262//
263int EV_DoGenCeiling
264( line_t* line )
265{
266 int secnum;
267 int rtn;
268 boolean manual;
269 fixed_t targheight;
270 sector_t* sec;
271 ceiling_t* ceiling;
272 unsigned value = (unsigned)line->special - GenCeilingBase;
273
274 // parse the bit fields in the line's special type
275
276 int Crsh = (value & CeilingCrush) >> CeilingCrushShift;
277 int ChgT = (value & CeilingChange) >> CeilingChangeShift;
278 int Targ = (value & CeilingTarget) >> CeilingTargetShift;
279 int Dirn = (value & CeilingDirection) >> CeilingDirectionShift;
280 int ChgM = (value & CeilingModel) >> CeilingModelShift;
281 int Sped = (value & CeilingSpeed) >> CeilingSpeedShift;
282 int Trig = (value & TriggerType) >> TriggerTypeShift;
283
284 rtn = 0;
285
286 // check if a manual trigger, if so do just the sector on the backside
287 manual = false;
288 if (Trig==PushOnce || Trig==PushMany)
289 {
290 if (!(sec = line->backsector))
291 return rtn;
292 secnum = sec-sectors;
293 manual = true;
294 goto manual_ceiling;
295 }
296
297 secnum = -1;
298 // if not manual do all sectors tagged the same as the line
299 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
300 {
301 sec = &sectors[secnum];
302
303manual_ceiling:
304 // Do not start another function if ceiling already moving
305 if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
306 {
307 if (!manual)
308 continue;
309 else
310 return rtn;
311 }
312
313 // new ceiling thinker
314 rtn = 1;
315 ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
316 memset(ceiling, 0, sizeof(*ceiling));
317 P_AddThinker (&ceiling->thinker);
318 sec->ceilingdata = ceiling; //jff 2/22/98
319 ceiling->thinker.function = T_MoveCeiling;
320 ceiling->crush = Crsh;
321 ceiling->direction = Dirn? 1 : -1;
322 ceiling->sector = sec;
323 ceiling->texture = sec->ceilingpic;
324 ceiling->newspecial = sec->special;
325 //jff 3/14/98 change old field too
326 ceiling->oldspecial = sec->oldspecial;
327 ceiling->tag = sec->tag;
328 ceiling->type = genCeiling;
329
330 // set speed of motion
331 switch (Sped)
332 {
333 case SpeedSlow:
334 ceiling->speed = CEILSPEED;
335 break;
336 case SpeedNormal:
337 ceiling->speed = CEILSPEED*2;
338 break;
339 case SpeedFast:
340 ceiling->speed = CEILSPEED*4;
341 break;
342 case SpeedTurbo:
343 ceiling->speed = CEILSPEED*8;
344 break;
345 default:
346 break;
347 }
348
349 // set destination target height
350 targheight = sec->ceilingheight;
351 switch(Targ)
352 {
353 case CtoHnC:
354 targheight = P_FindHighestCeilingSurrounding(sec);
355 break;
356 case CtoLnC:
357 targheight = P_FindLowestCeilingSurrounding(sec);
358 break;
359 case CtoNnC:
360 targheight = Dirn?
361 P_FindNextHighestCeiling(sec,sec->ceilingheight) :
362 P_FindNextLowestCeiling(sec,sec->ceilingheight);
363 break;
364 case CtoHnF:
365 targheight = P_FindHighestFloorSurrounding(sec);
366 break;
367 case CtoF:
368 targheight = sec->floorheight;
369 break;
370 case CbyST:
371 targheight = (ceiling->sector->ceilingheight>>FRACBITS) +
372 ceiling->direction * (P_FindShortestUpperAround(secnum)>>FRACBITS);
373 if (targheight>32000) //jff 3/13/98 prevent overflow
374 targheight=32000; // wraparound in ceiling height
375 if (targheight<-32000)
376 targheight=-32000;
377 targheight<<=FRACBITS;
378 break;
379 case Cby24:
380 targheight = ceiling->sector->ceilingheight +
381 ceiling->direction * 24*FRACUNIT;
382 break;
383 case Cby32:
384 targheight = ceiling->sector->ceilingheight +
385 ceiling->direction * 32*FRACUNIT;
386 break;
387 default:
388 break;
389 }
390 if (Dirn) ceiling->topheight = targheight;
391 else ceiling->bottomheight = targheight;
392
393 // set texture/type change properties
394 if (ChgT) // if a texture change is indicated
395 {
396 if (ChgM) // if a numeric model change
397 {
398 sector_t *sec;
399
400 //jff 5/23/98 find model with floor at target height if target
401 //is a floor type
402 sec = (Targ==CtoHnF || Targ==CtoF)?
403 P_FindModelFloorSector(targheight,secnum) :
404 P_FindModelCeilingSector(targheight,secnum);
405 if (sec)
406 {
407 ceiling->texture = sec->ceilingpic;
408 switch (ChgT)
409 {
410 case CChgZero: // type is zeroed
411 ceiling->newspecial = 0;
412 //jff 3/14/98 change old field too
413 ceiling->oldspecial = 0;
414 ceiling->type = genCeilingChg0;
415 break;
416 case CChgTyp: // type is copied
417 ceiling->newspecial = sec->special;
418 //jff 3/14/98 change old field too
419 ceiling->oldspecial = sec->oldspecial;
420 ceiling->type = genCeilingChgT;
421 break;
422 case CChgTxt: // type is left alone
423 ceiling->type = genCeilingChg;
424 break;
425 default:
426 break;
427 }
428 }
429 }
430 else // else if a trigger model change
431 {
432 ceiling->texture = line->frontsector->ceilingpic;
433 switch (ChgT)
434 {
435 case CChgZero: // type is zeroed
436 ceiling->newspecial = 0;
437 //jff 3/14/98 change old field too
438 ceiling->oldspecial = 0;
439 ceiling->type = genCeilingChg0;
440 break;
441 case CChgTyp: // type is copied
442 ceiling->newspecial = line->frontsector->special;
443 //jff 3/14/98 change old field too
444 ceiling->oldspecial = line->frontsector->oldspecial;
445 ceiling->type = genCeilingChgT;
446 break;
447 case CChgTxt: // type is left alone
448 ceiling->type = genCeilingChg;
449 break;
450 default:
451 break;
452 }
453 }
454 }
455 P_AddActiveCeiling(ceiling); // add this ceiling to the active list
456 if (manual) return rtn;
457 }
458 return rtn;
459}
460
461//
462// EV_DoGenLift()
463//
464// Handle generalized lift types
465//
466// Passed the linedef activating the lift
467// Returns true if a thinker is created
468//
469int EV_DoGenLift
470( line_t* line )
471{
472 plat_t* plat;
473 int secnum;
474 int rtn;
475 boolean manual;
476 sector_t* sec;
477 unsigned value = (unsigned)line->special - GenLiftBase;
478
479 // parse the bit fields in the line's special type
480
481 int Targ = (value & LiftTarget) >> LiftTargetShift;
482 int Dely = (value & LiftDelay) >> LiftDelayShift;
483 int Sped = (value & LiftSpeed) >> LiftSpeedShift;
484 int Trig = (value & TriggerType) >> TriggerTypeShift;
485
486 secnum = -1;
487 rtn = 0;
488
489 // Activate all <type> plats that are in_stasis
490
491 if (Targ==LnF2HnF)
492 P_ActivateInStasis(line->tag);
493
494 // check if a manual trigger, if so do just the sector on the backside
495 manual = false;
496 if (Trig==PushOnce || Trig==PushMany)
497 {
498 if (!(sec = line->backsector))
499 return rtn;
500 secnum = sec-sectors;
501 manual = true;
502 goto manual_lift;
503 }
504
505 // if not manual do all sectors tagged the same as the line
506 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
507 {
508 sec = &sectors[secnum];
509
510manual_lift:
511 // Do not start another function if floor already moving
512 if (P_SectorActive(floor_special,sec))
513 {
514 if (!manual)
515 continue;
516 else
517 return rtn;
518 }
519
520 // Setup the plat thinker
521 rtn = 1;
522 plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0);
523 memset(plat, 0, sizeof(*plat));
524 P_AddThinker(&plat->thinker);
525
526 plat->sector = sec;
527 plat->sector->floordata = plat;
528 plat->thinker.function = T_PlatRaise;
529 plat->crush = false;
530 plat->tag = line->tag;
531
532 plat->type = genLift;
533 plat->high = sec->floorheight;
534 plat->status = down;
535
536 // setup the target destination height
537 switch(Targ)
538 {
539 case F2LnF:
540 plat->low = P_FindLowestFloorSurrounding(sec);
541 if (plat->low > sec->floorheight)
542 plat->low = sec->floorheight;
543 break;
544 case F2NnF:
545 plat->low = P_FindNextLowestFloor(sec,sec->floorheight);
546 break;
547 case F2LnC:
548 plat->low = P_FindLowestCeilingSurrounding(sec);
549 if (plat->low > sec->floorheight)
550 plat->low = sec->floorheight;
551 break;
552 case LnF2HnF:
553 plat->type = genPerpetual;
554 plat->low = P_FindLowestFloorSurrounding(sec);
555 if (plat->low > sec->floorheight)
556 plat->low = sec->floorheight;
557 plat->high = P_FindHighestFloorSurrounding(sec);
558 if (plat->high < sec->floorheight)
559 plat->high = sec->floorheight;
560 plat->status = P_Random(pr_genlift)&1;
561 break;
562 default:
563 break;
564 }
565
566 // setup the speed of motion
567 switch(Sped)
568 {
569 case SpeedSlow:
570 plat->speed = PLATSPEED * 2;
571 break;
572 case SpeedNormal:
573 plat->speed = PLATSPEED * 4;
574 break;
575 case SpeedFast:
576 plat->speed = PLATSPEED * 8;
577 break;
578 case SpeedTurbo:
579 plat->speed = PLATSPEED * 16;
580 break;
581 default:
582 break;
583 }
584
585 // setup the delay time before the floor returns
586 switch(Dely)
587 {
588 case 0:
589 plat->wait = 1*35;
590 break;
591 case 1:
592 plat->wait = PLATWAIT*35;
593 break;
594 case 2:
595 plat->wait = 5*35;
596 break;
597 case 3:
598 plat->wait = 10*35;
599 break;
600 }
601
602 S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
603 P_AddActivePlat(plat); // add this plat to the list of active plats
604
605 if (manual)
606 return rtn;
607 }
608 return rtn;
609}
610
611//
612// EV_DoGenStairs()
613//
614// Handle generalized stair building
615//
616// Passed the linedef activating the stairs
617// Returns true if a thinker is created
618//
619int EV_DoGenStairs
620( line_t* line )
621{
622 int secnum;
623 int osecnum; //jff 3/4/98 preserve loop index
624 int height;
625 int i;
626 int newsecnum;
627 int texture;
628 int ok;
629 int rtn;
630 boolean manual;
631
632 sector_t* sec;
633 sector_t* tsec;
634
635 floormove_t* floor;
636
637 fixed_t stairsize;
638 fixed_t speed;
639
640 unsigned value = (unsigned)line->special - GenStairsBase;
641
642 // parse the bit fields in the line's special type
643
644 int Igno = (value & StairIgnore) >> StairIgnoreShift;
645 int Dirn = (value & StairDirection) >> StairDirectionShift;
646 int Step = (value & StairStep) >> StairStepShift;
647 int Sped = (value & StairSpeed) >> StairSpeedShift;
648 int Trig = (value & TriggerType) >> TriggerTypeShift;
649
650 rtn = 0;
651
652 // check if a manual trigger, if so do just the sector on the backside
653 manual = false;
654 if (Trig==PushOnce || Trig==PushMany)
655 {
656 if (!(sec = line->backsector))
657 return rtn;
658 secnum = sec-sectors;
659 manual = true;
660 goto manual_stair;
661 }
662
663 secnum = -1;
664 // if not manual do all sectors tagged the same as the line
665 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
666 {
667 sec = &sectors[secnum];
668
669manual_stair:
670 //Do not start another function if floor already moving
671 //jff 2/26/98 add special lockout condition to wait for entire
672 //staircase to build before retriggering
673 if (P_SectorActive(floor_special,sec) || sec->stairlock)
674 {
675 if (!manual)
676 continue;
677 else
678 return rtn;
679 }
680
681 // new floor thinker
682 rtn = 1;
683 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
684 memset(floor, 0, sizeof(*floor));
685 P_AddThinker (&floor->thinker);
686 sec->floordata = floor;
687 floor->thinker.function = T_MoveFloor;
688 floor->direction = Dirn? 1 : -1;
689 floor->sector = sec;
690
691 // setup speed of stair building
692 switch(Sped)
693 {
694 default:
695 case SpeedSlow:
696 floor->speed = FLOORSPEED/4;
697 break;
698 case SpeedNormal:
699 floor->speed = FLOORSPEED/2;
700 break;
701 case SpeedFast:
702 floor->speed = FLOORSPEED*2;
703 break;
704 case SpeedTurbo:
705 floor->speed = FLOORSPEED*4;
706 break;
707 }
708
709 // setup stepsize for stairs
710 switch(Step)
711 {
712 default:
713 case 0:
714 stairsize = 4*FRACUNIT;
715 break;
716 case 1:
717 stairsize = 8*FRACUNIT;
718 break;
719 case 2:
720 stairsize = 16*FRACUNIT;
721 break;
722 case 3:
723 stairsize = 24*FRACUNIT;
724 break;
725 }
726
727 speed = floor->speed;
728 height = sec->floorheight + floor->direction * stairsize;
729 floor->floordestheight = height;
730 texture = sec->floorpic;
731 floor->crush = false;
732 floor->type = genBuildStair; // jff 3/31/98 do not leave uninited
733
734 sec->stairlock = -2; // jff 2/26/98 set up lock on current sector
735 sec->nextsec = -1;
736 sec->prevsec = -1;
737
738 osecnum = secnum; //jff 3/4/98 preserve loop index
739 // Find next sector to raise
740 // 1. Find 2-sided line with same sector side[0]
741 // 2. Other side is the next sector to raise
742 do
743 {
744 ok = 0;
745 for (i = 0;i < sec->linecount;i++)
746 {
747 if ( !((sec->lines[i])->backsector) )
748 continue;
749
750 tsec = (sec->lines[i])->frontsector;
751 newsecnum = tsec-sectors;
752
753 if (secnum != newsecnum)
754 continue;
755
756 tsec = (sec->lines[i])->backsector;
757 newsecnum = tsec - sectors;
758
759 if (!Igno && tsec->floorpic != texture)
760 continue;
761
762 /* jff 6/19/98 prevent double stepsize */
763 if (compatibility_level < boom_202_compatibility)
764 height += floor->direction * stairsize;
765
766 //jff 2/26/98 special lockout condition for retriggering
767 if (P_SectorActive(floor_special,tsec) || tsec->stairlock)
768 continue;
769
770 /* jff 6/19/98 increase height AFTER continue */
771 if (compatibility_level >= boom_202_compatibility)
772 height += floor->direction * stairsize;
773
774 // jff 2/26/98
775 // link the stair chain in both directions
776 // lock the stair sector until building complete
777 sec->nextsec = newsecnum; // link step to next
778 tsec->prevsec = secnum; // link next back
779 tsec->nextsec = -1; // set next forward link as end
780 tsec->stairlock = -2; // lock the step
781
782 sec = tsec;
783 secnum = newsecnum;
784 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
785
786 memset(floor, 0, sizeof(*floor));
787 P_AddThinker (&floor->thinker);
788
789 sec->floordata = floor;
790 floor->thinker.function = T_MoveFloor;
791 floor->direction = Dirn? 1 : -1;
792 floor->sector = sec;
793 floor->speed = speed;
794 floor->floordestheight = height;
795 floor->crush = false;
796 floor->type = genBuildStair; // jff 3/31/98 do not leave uninited
797
798 ok = 1;
799 break;
800 }
801 } while(ok);
802 if (manual)
803 return rtn;
804 secnum = osecnum; //jff 3/4/98 restore old loop index
805 }
806 // retriggerable generalized stairs build up or down alternately
807 if (rtn)
808 line->special ^= StairDirection; // alternate dir on succ activations
809 return rtn;
810}
811
812//
813// EV_DoGenCrusher()
814//
815// Handle generalized crusher types
816//
817// Passed the linedef activating the crusher
818// Returns true if a thinker created
819//
820int EV_DoGenCrusher
821( line_t* line )
822{
823 int secnum;
824 int rtn;
825 boolean manual;
826 sector_t* sec;
827 ceiling_t* ceiling;
828 unsigned value = (unsigned)line->special - GenCrusherBase;
829
830 // parse the bit fields in the line's special type
831
832 int Slnt = (value & CrusherSilent) >> CrusherSilentShift;
833 int Sped = (value & CrusherSpeed) >> CrusherSpeedShift;
834 int Trig = (value & TriggerType) >> TriggerTypeShift;
835
836 //jff 2/22/98 Reactivate in-stasis ceilings...for certain types.
837 //jff 4/5/98 return if activated
838 rtn = P_ActivateInStasisCeiling(line);
839
840 // check if a manual trigger, if so do just the sector on the backside
841 manual = false;
842 if (Trig==PushOnce || Trig==PushMany)
843 {
844 if (!(sec = line->backsector))
845 return rtn;
846 secnum = sec-sectors;
847 manual = true;
848 goto manual_crusher;
849 }
850
851 secnum = -1;
852 // if not manual do all sectors tagged the same as the line
853 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
854 {
855 sec = &sectors[secnum];
856
857manual_crusher:
858 // Do not start another function if ceiling already moving
859 if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
860 {
861 if (!manual)
862 continue;
863 else
864 return rtn;
865 }
866
867 // new ceiling thinker
868 rtn = 1;
869 ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
870 memset(ceiling, 0, sizeof(*ceiling));
871 P_AddThinker (&ceiling->thinker);
872 sec->ceilingdata = ceiling; //jff 2/22/98
873 ceiling->thinker.function = T_MoveCeiling;
874 ceiling->crush = true;
875 ceiling->direction = -1;
876 ceiling->sector = sec;
877 ceiling->texture = sec->ceilingpic;
878 ceiling->newspecial = sec->special;
879 ceiling->tag = sec->tag;
880 ceiling->type = Slnt? genSilentCrusher : genCrusher;
881 ceiling->topheight = sec->ceilingheight;
882 ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
883
884 // setup ceiling motion speed
885 switch (Sped)
886 {
887 case SpeedSlow:
888 ceiling->speed = CEILSPEED;
889 break;
890 case SpeedNormal:
891 ceiling->speed = CEILSPEED*2;
892 break;
893 case SpeedFast:
894 ceiling->speed = CEILSPEED*4;
895 break;
896 case SpeedTurbo:
897 ceiling->speed = CEILSPEED*8;
898 break;
899 default:
900 break;
901 }
902 ceiling->oldspeed=ceiling->speed;
903
904 P_AddActiveCeiling(ceiling); // add to list of active ceilings
905 if (manual) return rtn;
906 }
907 return rtn;
908}
909
910//
911// EV_DoGenLockedDoor()
912//
913// Handle generalized locked door types
914//
915// Passed the linedef activating the generalized locked door
916// Returns true if a thinker created
917//
918int EV_DoGenLockedDoor
919( line_t* line )
920{
921 int secnum,rtn;
922 sector_t* sec;
923 vldoor_t* door;
924 boolean manual;
925 unsigned value = (unsigned)line->special - GenLockedBase;
926
927 // parse the bit fields in the line's special type
928
929 int Kind = (value & LockedKind) >> LockedKindShift;
930 int Sped = (value & LockedSpeed) >> LockedSpeedShift;
931 int Trig = (value & TriggerType) >> TriggerTypeShift;
932
933 rtn = 0;
934
935 // check if a manual trigger, if so do just the sector on the backside
936 manual = false;
937 if (Trig==PushOnce || Trig==PushMany)
938 {
939 if (!(sec = line->backsector))
940 return rtn;
941 secnum = sec-sectors;
942 manual = true;
943 goto manual_locked;
944 }
945
946 secnum = -1;
947 rtn = 0;
948
949 // if not manual do all sectors tagged the same as the line
950 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
951 {
952 sec = &sectors[secnum];
953manual_locked:
954 // Do not start another function if ceiling already moving
955 if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
956 {
957 if (!manual)
958 continue;
959 else
960 return rtn;
961 }
962
963 // new door thinker
964 rtn = 1;
965 door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
966 memset(door, 0, sizeof(*door));
967 P_AddThinker (&door->thinker);
968 sec->ceilingdata = door; //jff 2/22/98
969
970 door->thinker.function = T_VerticalDoor;
971 door->sector = sec;
972 door->topwait = VDOORWAIT;
973 door->line = line;
974 door->topheight = P_FindLowestCeilingSurrounding(sec);
975 door->topheight -= 4*FRACUNIT;
976 door->direction = 1;
977
978 /* killough 10/98: implement gradual lighting */
979 door->lighttag = !comp[comp_doorlight] &&
980 (line->special&6) == 6 &&
981 line->special > GenLockedBase ? line->tag : 0;
982
983 // setup speed of door motion
984 switch(Sped)
985 {
986 default:
987 case SpeedSlow:
988 door->type = Kind? genOpen : genRaise;
989 door->speed = VDOORSPEED;
990 break;
991 case SpeedNormal:
992 door->type = Kind? genOpen : genRaise;
993 door->speed = VDOORSPEED*2;
994 break;
995 case SpeedFast:
996 door->type = Kind? genBlazeOpen : genBlazeRaise;
997 door->speed = VDOORSPEED*4;
998 break;
999 case SpeedTurbo:
1000 door->type = Kind? genBlazeOpen : genBlazeRaise;
1001 door->speed = VDOORSPEED*8;
1002
1003 break;
1004 }
1005
1006 // killough 4/15/98: fix generalized door opening sounds
1007 // (previously they always had the blazing door close sound)
1008
1009 S_StartSound((mobj_t *)&door->sector->soundorg, // killough 4/15/98
1010 door->speed >= VDOORSPEED*4 ? sfx_bdopn : sfx_doropn);
1011
1012 if (manual)
1013 return rtn;
1014 }
1015 return rtn;
1016}
1017
1018//
1019// EV_DoGenDoor()
1020//
1021// Handle generalized door types
1022//
1023// Passed the linedef activating the generalized door
1024// Returns true if a thinker created
1025//
1026int EV_DoGenDoor
1027( line_t* line )
1028{
1029 int secnum,rtn;
1030 sector_t* sec;
1031 boolean manual;
1032 vldoor_t* door;
1033 unsigned value = (unsigned)line->special - GenDoorBase;
1034
1035 // parse the bit fields in the line's special type
1036
1037 int Dely = (value & DoorDelay) >> DoorDelayShift;
1038 int Kind = (value & DoorKind) >> DoorKindShift;
1039 int Sped = (value & DoorSpeed) >> DoorSpeedShift;
1040 int Trig = (value & TriggerType) >> TriggerTypeShift;
1041
1042 rtn = 0;
1043
1044 // check if a manual trigger, if so do just the sector on the backside
1045 manual = false;
1046 if (Trig==PushOnce || Trig==PushMany)
1047 {
1048 if (!(sec = line->backsector))
1049 return rtn;
1050 secnum = sec-sectors;
1051 manual = true;
1052 goto manual_door;
1053 }
1054
1055
1056 secnum = -1;
1057 rtn = 0;
1058
1059 // if not manual do all sectors tagged the same as the line
1060 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
1061 {
1062 sec = &sectors[secnum];
1063manual_door:
1064 // Do not start another function if ceiling already moving
1065 if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
1066 {
1067 if (!manual)
1068 continue;
1069 else
1070 return rtn;
1071 }
1072
1073 // new door thinker
1074 rtn = 1;
1075 door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
1076 memset(door, 0, sizeof(*door));
1077 P_AddThinker (&door->thinker);
1078 sec->ceilingdata = door; //jff 2/22/98
1079
1080 door->thinker.function = T_VerticalDoor;
1081 door->sector = sec;
1082 // setup delay for door remaining open/closed
1083 switch(Dely)
1084 {
1085 default:
1086 case 0:
1087 door->topwait = 35;
1088 break;
1089 case 1:
1090 door->topwait = VDOORWAIT;
1091 break;
1092 case 2:
1093 door->topwait = 2*VDOORWAIT;
1094 break;
1095 case 3:
1096 door->topwait = 7*VDOORWAIT;
1097 break;
1098 }
1099
1100 // setup speed of door motion
1101 switch(Sped)
1102 {
1103 default:
1104 case SpeedSlow:
1105 door->speed = VDOORSPEED;
1106 break;
1107 case SpeedNormal:
1108 door->speed = VDOORSPEED*2;
1109 break;
1110 case SpeedFast:
1111 door->speed = VDOORSPEED*4;
1112 break;
1113 case SpeedTurbo:
1114 door->speed = VDOORSPEED*8;
1115 break;
1116 }
1117 door->line = line; // jff 1/31/98 remember line that triggered us
1118
1119 /* killough 10/98: implement gradual lighting */
1120 door->lighttag = !comp[comp_doorlight] &&
1121 (line->special&6) == 6 &&
1122 line->special > GenLockedBase ? line->tag : 0;
1123
1124 // set kind of door, whether it opens then close, opens, closes etc.
1125 // assign target heights accordingly
1126 switch(Kind)
1127 {
1128 case OdCDoor:
1129 door->direction = 1;
1130 door->topheight = P_FindLowestCeilingSurrounding(sec);
1131 door->topheight -= 4*FRACUNIT;
1132 if (door->topheight != sec->ceilingheight)
1133 S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn);
1134 door->type = Sped>=SpeedFast? genBlazeRaise : genRaise;
1135 break;
1136 case ODoor:
1137 door->direction = 1;
1138 door->topheight = P_FindLowestCeilingSurrounding(sec);
1139 door->topheight -= 4*FRACUNIT;
1140 if (door->topheight != sec->ceilingheight)
1141 S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn);
1142 door->type = Sped>=SpeedFast? genBlazeOpen : genOpen;
1143 break;
1144 case CdODoor:
1145 door->topheight = sec->ceilingheight;
1146 door->direction = -1;
1147 S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls);
1148 door->type = Sped>=SpeedFast? genBlazeCdO : genCdO;
1149 break;
1150 case CDoor:
1151 door->topheight = P_FindLowestCeilingSurrounding(sec);
1152 door->topheight -= 4*FRACUNIT;
1153 door->direction = -1;
1154 S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls);
1155 door->type = Sped>=SpeedFast? genBlazeClose : genClose;
1156 break;
1157 default:
1158 break;
1159 }
1160 if (manual)
1161 return rtn;
1162 }
1163 return rtn;
1164}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Handling interactions (i.e., collisions).
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "dstrings.h"
36#include "m_random.h"
37#include "am_map.h"
38#include "r_main.h"
39#include "s_sound.h"
40#include "sounds.h"
41#include "d_deh.h" // Ty 03/22/98 - externalized strings
42#include "p_tick.h"
43#include "lprintf.h"
44
45#include "p_inter.h"
46#include "p_enemy.h"
47
48#ifdef __GNUG__
49#pragma implementation "p_inter.h"
50#endif
51#include "p_inter.h"
52
53#define BONUSADD 6
54
55// Ty 03/07/98 - add deh externals
56// Maximums and such were hardcoded values. Need to externalize those for
57// dehacked support (and future flexibility). Most var names came from the key
58// strings used in dehacked.
59
60int initial_health = 100;
61int initial_bullets = 50;
62int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module
63int max_armor = 200;
64int green_armor_class = 1; // these are involved with armortype below
65int blue_armor_class = 2;
66int max_soul = 200;
67int soul_health = 100;
68int mega_health = 200;
69int god_health = 100; // these are used in cheats (see st_stuff.c)
70int idfa_armor = 200;
71int idfa_armor_class = 2;
72// not actually used due to pairing of cheat_k and cheat_fa
73int idkfa_armor = 200;
74int idkfa_armor_class = 2;
75
76int bfgcells = 40; // used in p_pspr.c
77int monsters_infight = 0; // e6y: Dehacked support - monsters infight
78// Ty 03/07/98 - end deh externals
79
80// a weapon is found with two clip loads,
81// a big item has five clip loads
82int maxammo[NUMAMMO] = {200, 50, 300, 50};
83int clipammo[NUMAMMO] = { 10, 4, 20, 1};
84
85//
86// GET STUFF
87//
88
89//
90// P_GiveAmmo
91// Num is the number of clip loads,
92// not the individual count (0= 1/2 clip).
93// Returns false if the ammo can't be picked up at all
94//
95
96static boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num)
97{
98 int oldammo;
99
100 if (ammo == am_noammo)
101 return false;
102
103#ifdef RANGECHECK
104 if (ammo < 0 || ammo > NUMAMMO)
105 I_Error ("P_GiveAmmo: bad type %i", ammo);
106#endif
107
108 if ( player->ammo[ammo] == player->maxammo[ammo] )
109 return false;
110
111 if (num)
112 num *= clipammo[ammo];
113 else
114 num = clipammo[ammo]/2;
115
116 // give double ammo in trainer mode, you'll need in nightmare
117 if (gameskill == sk_baby || gameskill == sk_nightmare)
118 num <<= 1;
119
120 oldammo = player->ammo[ammo];
121 player->ammo[ammo] += num;
122
123 if (player->ammo[ammo] > player->maxammo[ammo])
124 player->ammo[ammo] = player->maxammo[ammo];
125
126 // If non zero ammo, don't change up weapons, player was lower on purpose.
127 if (oldammo)
128 return true;
129
130 // We were down to zero, so select a new weapon.
131 // Preferences are not user selectable.
132
133 switch (ammo)
134 {
135 case am_clip:
136 if (player->readyweapon == wp_fist) {
137 if (player->weaponowned[wp_chaingun])
138 player->pendingweapon = wp_chaingun;
139 else
140 player->pendingweapon = wp_pistol;
141 }
142 break;
143
144 case am_shell:
145 if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
146 if (player->weaponowned[wp_shotgun])
147 player->pendingweapon = wp_shotgun;
148 break;
149
150 case am_cell:
151 if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
152 if (player->weaponowned[wp_plasma])
153 player->pendingweapon = wp_plasma;
154 break;
155
156 case am_misl:
157 if (player->readyweapon == wp_fist)
158 if (player->weaponowned[wp_missile])
159 player->pendingweapon = wp_missile;
160 default:
161 break;
162 }
163 return true;
164}
165
166//
167// P_GiveWeapon
168// The weapon name may have a MF_DROPPED flag ored in.
169//
170
171static boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped)
172{
173 boolean gaveammo;
174 boolean gaveweapon;
175
176 if (netgame && deathmatch!=2 && !dropped)
177 {
178 // leave placed weapons forever on net games
179 if (player->weaponowned[weapon])
180 return false;
181
182 player->bonuscount += BONUSADD;
183 player->weaponowned[weapon] = true;
184
185 P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2);
186
187 player->pendingweapon = weapon;
188 /* cph 20028/10 - for old-school DM addicts, allow old behavior
189 * where only consoleplayer's pickup sounds are heard */
190 // displayplayer, not consoleplayer, for viewing multiplayer demos
191 if (!comp[comp_sound] || player == &players[displayplayer])
192 S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98
193 return false;
194 }
195
196 if (weaponinfo[weapon].ammo != am_noammo)
197 {
198 // give one clip with a dropped weapon,
199 // two clips with a found weapon
200 gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2);
201 }
202 else
203 gaveammo = false;
204
205 if (player->weaponowned[weapon])
206 gaveweapon = false;
207 else
208 {
209 gaveweapon = true;
210 player->weaponowned[weapon] = true;
211 player->pendingweapon = weapon;
212 }
213 return gaveweapon || gaveammo;
214}
215
216//
217// P_GiveBody
218// Returns false if the body isn't needed at all
219//
220
221static boolean P_GiveBody(player_t *player, int num)
222{
223 if (player->health >= maxhealth)
224 return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth
225 player->health += num;
226 if (player->health > maxhealth)
227 player->health = maxhealth;
228 player->mo->health = player->health;
229 return true;
230}
231
232//
233// P_GiveArmor
234// Returns false if the armor is worse
235// than the current armor.
236//
237
238static boolean P_GiveArmor(player_t *player, int armortype)
239{
240 int hits = armortype*100;
241 if (player->armorpoints >= hits)
242 return false; // don't pick up
243 player->armortype = armortype;
244 player->armorpoints = hits;
245 return true;
246}
247
248//
249// P_GiveCard
250//
251
252static void P_GiveCard(player_t *player, card_t card)
253{
254 if (player->cards[card])
255 return;
256 player->bonuscount = BONUSADD;
257 player->cards[card] = 1;
258}
259
260//
261// P_GivePower
262//
263// Rewritten by Lee Killough
264//
265
266boolean P_GivePower(player_t *player, int power)
267{
268 static const int tics[NUMPOWERS] = {
269 INVULNTICS, 1 /* strength */, INVISTICS,
270 IRONTICS, 1 /* allmap */, INFRATICS,
271 };
272
273 switch (power)
274 {
275 case pw_invisibility:
276 player->mo->flags |= MF_SHADOW;
277 break;
278 case pw_allmap:
279 if (player->powers[pw_allmap])
280 return false;
281 break;
282 case pw_strength:
283 P_GiveBody(player,100);
284 break;
285 }
286
287 // Unless player has infinite duration cheat, set duration (killough)
288
289 if (player->powers[power] >= 0)
290 player->powers[power] = tics[power];
291 return true;
292}
293
294//
295// P_TouchSpecialThing
296//
297
298void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
299{
300 player_t *player;
301 int i;
302 int sound;
303 fixed_t delta = special->z - toucher->z;
304
305 if (delta > toucher->height || delta < -8*FRACUNIT)
306 return; // out of reach
307
308 sound = sfx_itemup;
309 player = toucher->player;
310
311 // Dead thing touching.
312 // Can happen with a sliding player corpse.
313 if (toucher->health <= 0)
314 return;
315
316 // Identify by sprite.
317 switch (special->sprite)
318 {
319 // armor
320 case SPR_ARM1:
321 if (!P_GiveArmor (player, green_armor_class))
322 return;
323 player->message = s_GOTARMOR; // Ty 03/22/98 - externalized
324 break;
325
326 case SPR_ARM2:
327 if (!P_GiveArmor (player, blue_armor_class))
328 return;
329 player->message = s_GOTMEGA; // Ty 03/22/98 - externalized
330 break;
331
332 // bonus items
333 case SPR_BON1:
334 player->health++; // can go over 100%
335 if (player->health > (maxhealth * 2))
336 player->health = (maxhealth * 2);
337 player->mo->health = player->health;
338 player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized
339 break;
340
341 case SPR_BON2:
342 player->armorpoints++; // can go over 100%
343 if (player->armorpoints > max_armor)
344 player->armorpoints = max_armor;
345 if (!player->armortype)
346 player->armortype = green_armor_class;
347 player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized
348 break;
349
350 case SPR_SOUL:
351 player->health += soul_health;
352 if (player->health > max_soul)
353 player->health = max_soul;
354 player->mo->health = player->health;
355 player->message = s_GOTSUPER; // Ty 03/22/98 - externalized
356 sound = sfx_getpow;
357 break;
358
359 case SPR_MEGA:
360 if (gamemode != commercial)
361 return;
362 player->health = mega_health;
363 player->mo->health = player->health;
364 P_GiveArmor (player,blue_armor_class);
365 player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized
366 sound = sfx_getpow;
367 break;
368
369 // cards
370 // leave cards for everyone
371 case SPR_BKEY:
372 if (!player->cards[it_bluecard])
373 player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized
374 P_GiveCard (player, it_bluecard);
375 if (!netgame)
376 break;
377 return;
378
379 case SPR_YKEY:
380 if (!player->cards[it_yellowcard])
381 player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized
382 P_GiveCard (player, it_yellowcard);
383 if (!netgame)
384 break;
385 return;
386
387 case SPR_RKEY:
388 if (!player->cards[it_redcard])
389 player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized
390 P_GiveCard (player, it_redcard);
391 if (!netgame)
392 break;
393 return;
394
395 case SPR_BSKU:
396 if (!player->cards[it_blueskull])
397 player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized
398 P_GiveCard (player, it_blueskull);
399 if (!netgame)
400 break;
401 return;
402
403 case SPR_YSKU:
404 if (!player->cards[it_yellowskull])
405 player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized
406 P_GiveCard (player, it_yellowskull);
407 if (!netgame)
408 break;
409 return;
410
411 case SPR_RSKU:
412 if (!player->cards[it_redskull])
413 player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized
414 P_GiveCard (player, it_redskull);
415 if (!netgame)
416 break;
417 return;
418
419 // medikits, heals
420 case SPR_STIM:
421 if (!P_GiveBody (player, 10))
422 return;
423 player->message = s_GOTSTIM; // Ty 03/22/98 - externalized
424 break;
425
426 case SPR_MEDI:
427 if (!P_GiveBody (player, 25))
428 return;
429
430 if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug
431 player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized
432 else
433 player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized
434 break;
435
436
437 // power ups
438 case SPR_PINV:
439 if (!P_GivePower (player, pw_invulnerability))
440 return;
441 player->message = s_GOTINVUL; // Ty 03/22/98 - externalized
442 sound = sfx_getpow;
443 break;
444
445 case SPR_PSTR:
446 if (!P_GivePower (player, pw_strength))
447 return;
448 player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized
449 if (player->readyweapon != wp_fist)
450 player->pendingweapon = wp_fist;
451 sound = sfx_getpow;
452 break;
453
454 case SPR_PINS:
455 if (!P_GivePower (player, pw_invisibility))
456 return;
457 player->message = s_GOTINVIS; // Ty 03/22/98 - externalized
458 sound = sfx_getpow;
459 break;
460
461 case SPR_SUIT:
462 if (!P_GivePower (player, pw_ironfeet))
463 return;
464 player->message = s_GOTSUIT; // Ty 03/22/98 - externalized
465 sound = sfx_getpow;
466 break;
467
468 case SPR_PMAP:
469 if (!P_GivePower (player, pw_allmap))
470 return;
471 player->message = s_GOTMAP; // Ty 03/22/98 - externalized
472 sound = sfx_getpow;
473 break;
474
475 case SPR_PVIS:
476 if (!P_GivePower (player, pw_infrared))
477 return;
478 player->message = s_GOTVISOR; // Ty 03/22/98 - externalized
479 sound = sfx_getpow;
480 break;
481
482 // ammo
483 case SPR_CLIP:
484 if (special->flags & MF_DROPPED)
485 {
486 if (!P_GiveAmmo (player,am_clip,0))
487 return;
488 }
489 else
490 {
491 if (!P_GiveAmmo (player,am_clip,1))
492 return;
493 }
494 player->message = s_GOTCLIP; // Ty 03/22/98 - externalized
495 break;
496
497 case SPR_AMMO:
498 if (!P_GiveAmmo (player, am_clip,5))
499 return;
500 player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized
501 break;
502
503 case SPR_ROCK:
504 if (!P_GiveAmmo (player, am_misl,1))
505 return;
506 player->message = s_GOTROCKET; // Ty 03/22/98 - externalized
507 break;
508
509 case SPR_BROK:
510 if (!P_GiveAmmo (player, am_misl,5))
511 return;
512 player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized
513 break;
514
515 case SPR_CELL:
516 if (!P_GiveAmmo (player, am_cell,1))
517 return;
518 player->message = s_GOTCELL; // Ty 03/22/98 - externalized
519 break;
520
521 case SPR_CELP:
522 if (!P_GiveAmmo (player, am_cell,5))
523 return;
524 player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized
525 break;
526
527 case SPR_SHEL:
528 if (!P_GiveAmmo (player, am_shell,1))
529 return;
530 player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized
531 break;
532
533 case SPR_SBOX:
534 if (!P_GiveAmmo (player, am_shell,5))
535 return;
536 player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized
537 break;
538
539 case SPR_BPAK:
540 if (!player->backpack)
541 {
542 for (i=0 ; i<NUMAMMO ; i++)
543 player->maxammo[i] *= 2;
544 player->backpack = true;
545 }
546 for (i=0 ; i<NUMAMMO ; i++)
547 P_GiveAmmo (player, i, 1);
548 player->message = s_GOTBACKPACK; // Ty 03/22/98 - externalized
549 break;
550
551 // weapons
552 case SPR_BFUG:
553 if (!P_GiveWeapon (player, wp_bfg, false) )
554 return;
555 player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized
556 sound = sfx_wpnup;
557 break;
558
559 case SPR_MGUN:
560 if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) )
561 return;
562 player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized
563 sound = sfx_wpnup;
564 break;
565
566 case SPR_CSAW:
567 if (!P_GiveWeapon (player, wp_chainsaw, false) )
568 return;
569 player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized
570 sound = sfx_wpnup;
571 break;
572
573 case SPR_LAUN:
574 if (!P_GiveWeapon (player, wp_missile, false) )
575 return;
576 player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized
577 sound = sfx_wpnup;
578 break;
579
580 case SPR_PLAS:
581 if (!P_GiveWeapon (player, wp_plasma, false) )
582 return;
583 player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized
584 sound = sfx_wpnup;
585 break;
586
587 case SPR_SHOT:
588 if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) )
589 return;
590 player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized
591 sound = sfx_wpnup;
592 break;
593
594 case SPR_SGN2:
595 if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0))
596 return;
597 player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized
598 sound = sfx_wpnup;
599 break;
600
601 default:
602 I_Error ("P_SpecialThing: Unknown gettable thing");
603 }
604
605 if (special->flags & MF_COUNTITEM)
606 player->itemcount++;
607 P_RemoveMobj (special);
608 player->bonuscount += BONUSADD;
609
610 /* cph 20028/10 - for old-school DM addicts, allow old behavior
611 * where only consoleplayer's pickup sounds are heard */
612 // displayplayer, not consoleplayer, for viewing multiplayer demos
613 if (!comp[comp_sound] || player == &players[displayplayer])
614 S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98
615}
616
617//
618// KillMobj
619//
620// killough 11/98: make static
621static void P_KillMobj(mobj_t *source, mobj_t *target)
622{
623 mobjtype_t item;
624 mobj_t *mo;
625
626 target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
627
628 if (target->type != MT_SKULL)
629 target->flags &= ~MF_NOGRAVITY;
630
631 target->flags |= MF_CORPSE|MF_DROPOFF;
632 target->height >>= 2;
633
634 if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
635 totallive--;
636
637 if (source && source->player)
638 {
639 // count for intermission
640 if (target->flags & MF_COUNTKILL)
641 source->player->killcount++;
642 if (target->player)
643 source->player->frags[target->player-players]++;
644 }
645 else
646 if (target->flags & MF_COUNTKILL) { /* Add to kills tally */
647 if ((compatibility_level < lxdoom_1_compatibility) || !netgame) {
648 if (!netgame)
649 // count all monster deaths,
650 // even those caused by other monsters
651 players[0].killcount++;
652 } else
653 if (!deathmatch) {
654 // try and find a player to give the kill to, otherwise give the
655 // kill to a random player. this fixes the missing monsters bug
656 // in coop - rain
657 // CPhipps - not a bug as such, but certainly an inconsistency.
658 if (target->lastenemy && target->lastenemy->health > 0
659 && target->lastenemy->player) // Fighting a player
660 target->lastenemy->player->killcount++;
661 else {
662 // cph - randomely choose a player in the game to be credited
663 // and do it uniformly between the active players
664 unsigned int activeplayers = 0, player, i;
665
666 for (player = 0; player<MAXPLAYERS; player++)
667 if (playeringame[player])
668 activeplayers++;
669
670 if (activeplayers) {
671 player = P_Random(pr_friends) % activeplayers;
672
673 for (i=0; i<MAXPLAYERS; i++)
674 if (playeringame[i])
675 if (!player--)
676 players[i].killcount++;
677 }
678 }
679 }
680 }
681
682 if (target->player)
683 {
684 // count environment kills against you
685 if (!source)
686 target->player->frags[target->player-players]++;
687
688 target->flags &= ~MF_SOLID;
689 target->player->playerstate = PST_DEAD;
690 P_DropWeapon (target->player);
691
692 if (target->player == &players[consoleplayer] && (automapmode & am_active))
693 AM_Stop(); // don't die in auto map; switch view prior to dying
694 }
695
696 if (target->health < -target->info->spawnhealth && target->info->xdeathstate)
697 P_SetMobjState (target, target->info->xdeathstate);
698 else
699 P_SetMobjState (target, target->info->deathstate);
700
701 target->tics -= P_Random(pr_killtics)&3;
702
703 if (target->tics < 1)
704 target->tics = 1;
705
706 // Drop stuff.
707 // This determines the kind of object spawned
708 // during the death frame of a thing.
709
710 switch (target->type)
711 {
712 case MT_WOLFSS:
713 case MT_POSSESSED:
714 item = MT_CLIP;
715 break;
716
717 case MT_SHOTGUY:
718 item = MT_SHOTGUN;
719 break;
720
721 case MT_CHAINGUY:
722 item = MT_CHAINGUN;
723 break;
724
725 default:
726 return;
727 }
728
729 mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
730 mo->flags |= MF_DROPPED; // special versions of items
731}
732
733//
734// P_DamageMobj
735// Damages both enemies and players
736// "inflictor" is the thing that caused the damage
737// creature or missile, can be NULL (slime, etc)
738// "source" is the thing to target after taking damage
739// creature or NULL
740// Source and inflictor are the same for melee attacks.
741// Source can be NULL for slime, barrel explosions
742// and other environmental stuff.
743//
744
745void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage)
746{
747 player_t *player;
748 boolean justhit = false; /* killough 11/98 */
749
750 /* killough 8/31/98: allow bouncers to take damage */
751 if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES)))
752 return; // shouldn't happen...
753
754 if (target->health <= 0)
755 return;
756
757 if (target->flags & MF_SKULLFLY)
758 target->momx = target->momy = target->momz = 0;
759
760 player = target->player;
761 if (player && gameskill == sk_baby)
762 damage >>= 1; // take half damage in trainer mode
763
764 // Some close combat weapons should not
765 // inflict thrust and push the victim out of reach,
766 // thus kick away unless using the chainsaw.
767
768 if (inflictor && !(target->flags & MF_NOCLIP) &&
769 (!source || !source->player ||
770 source->player->readyweapon != wp_chainsaw))
771 {
772 unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y,
773 target->x, target->y);
774
775 fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
776
777 // make fall forwards sometimes
778 if ( damage < 40 && damage > target->health
779 && target->z - inflictor->z > 64*FRACUNIT
780 && P_Random(pr_damagemobj) & 1)
781 {
782 ang += ANG180;
783 thrust *= 4;
784 }
785
786 ang >>= ANGLETOFINESHIFT;
787 target->momx += FixedMul (thrust, finecosine[ang]);
788 target->momy += FixedMul (thrust, finesine[ang]);
789
790 /* killough 11/98: thrust objects hanging off ledges */
791 if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR)
792 target->gear = 0;
793 }
794
795 // player specific
796 if (player)
797 {
798 // end of game hell hack
799 if (target->subsector->sector->special == 11 && damage >= target->health)
800 damage = target->health - 1;
801
802 // Below certain threshold,
803 // ignore damage in GOD mode, or with INVUL power.
804 // killough 3/26/98: make god mode 100% god mode in non-compat mode
805
806 if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) &&
807 (player->cheats&CF_GODMODE || player->powers[pw_invulnerability]))
808 return;
809
810 if (player->armortype)
811 {
812 int saved = player->armortype == 1 ? damage/3 : damage/2;
813 if (player->armorpoints <= saved)
814 {
815 // armor is used up
816 saved = player->armorpoints;
817 player->armortype = 0;
818 }
819 player->armorpoints -= saved;
820 damage -= saved;
821 }
822
823 player->health -= damage; // mirror mobj health here for Dave
824 if (player->health < 0)
825 player->health = 0;
826
827 player->attacker = source;
828 player->damagecount += damage; // add damage after armor / invuln
829
830 if (player->damagecount > 100)
831 player->damagecount = 100; // teleport stomp does 10k points...
832 }
833
834 // do the damage
835 target->health -= damage;
836 if (target->health <= 0)
837 {
838 P_KillMobj (source, target);
839 return;
840 }
841
842 // killough 9/7/98: keep track of targets so that friends can help friends
843 if (mbf_features)
844 {
845 /* If target is a player, set player's target to source,
846 * so that a friend can tell who's hurting a player
847 */
848 if (player)
849 P_SetTarget(&target->target, source);
850
851 /* killough 9/8/98:
852 * If target's health is less than 50%, move it to the front of its list.
853 * This will slightly increase the chances that enemies will choose to
854 * "finish it off", but its main purpose is to alert friends of danger.
855 */
856 if (target->health*2 < target->info->spawnhealth)
857 {
858 thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ?
859 th_friends : th_enemies];
860 (target->thinker.cprev->cnext = target->thinker.cnext)->cprev =
861 target->thinker.cprev;
862 (target->thinker.cnext = cap->cnext)->cprev = &target->thinker;
863 (target->thinker.cprev = cap)->cnext = &target->thinker;
864 }
865 }
866
867 if (P_Random (pr_painchance) < target->info->painchance &&
868 !(target->flags & MF_SKULLFLY)) { //killough 11/98: see below
869 if (mbf_features)
870 justhit = true;
871 else
872 target->flags |= MF_JUSTHIT; // fight back!
873
874 P_SetMobjState(target, target->info->painstate);
875 }
876
877 target->reactiontime = 0; // we're awake now...
878
879 /* killough 9/9/98: cleaned up, made more consistent: */
880
881 if (source && source != target && source->type != MT_VILE &&
882 (!target->threshold || target->type == MT_VILE) &&
883 ((source->flags ^ target->flags) & MF_FRIEND ||
884 monster_infighting ||
885 !mbf_features))
886 {
887 /* if not intent on another player, chase after this one
888 *
889 * killough 2/15/98: remember last enemy, to prevent
890 * sleeping early; 2/21/98: Place priority on players
891 * killough 9/9/98: cleaned up, made more consistent:
892 */
893
894 if (!target->lastenemy || target->lastenemy->health <= 0 ||
895 (!mbf_features ?
896 !target->lastenemy->player :
897 !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) &&
898 target->target != source)) // remember last enemy - killough
899 P_SetTarget(&target->lastenemy, target->target);
900
901 P_SetTarget(&target->target, source); // killough 11/98
902 target->threshold = BASETHRESHOLD;
903 if (target->state == &states[target->info->spawnstate]
904 && target->info->seestate != S_NULL)
905 P_SetMobjState (target, target->info->seestate);
906 }
907
908 /* killough 11/98: Don't attack a friend, unless hit by that friend.
909 * cph 2006/04/01 - implicitly this is only if mbf_features */
910 if (justhit && (target->target == source || !target->target ||
911 !(target->flags & target->target->flags & MF_FRIEND)))
912 target->flags |= MF_JUSTHIT; // fight back!
913}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Thing events, and dehacked specified numbers controlling them.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __P_INTER__
35#define __P_INTER__
36
37#include "d_player.h"
38#include "p_mobj.h"
39
40#ifdef __GNUG__
41#pragma interface
42#endif
43
44/* Ty 03/09/98 Moved to an int in p_inter.c for deh and externalization */
45#define MAXHEALTH maxhealth
46
47/* follow a player exlusively for 3 seconds */
48#define BASETHRESHOLD (100)
49
50boolean P_GivePower(player_t *, int);
51void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher);
52void P_DamageMobj(mobj_t *target,mobj_t *inflictor,mobj_t *source,int damage);
53
54/* killough 5/2/98: moved from d_deh.c, g_game.c, m_misc.c, others: */
55
56extern int god_health; /* Ty 03/09/98 - deh support, see also p_inter.c */
57extern int idfa_armor;
58extern int idfa_armor_class;
59extern int idkfa_armor;
60extern int idkfa_armor_class; /* Ty - end */
61/* Ty 03/13/98 - externalized initial settings for respawned player */
62extern int initial_health;
63extern int initial_bullets;
64extern int maxhealth;
65extern int max_armor;
66extern int green_armor_class;
67extern int blue_armor_class;
68extern int max_soul;
69extern int soul_health;
70extern int mega_health;
71extern int bfgcells;
72extern int monsters_infight; // e6y: Dehacked support - monsters infight
73extern int maxammo[], clipammo[];
74
75#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Action routines for lighting thinkers
31 * Spawn sector based lighting effects.
32 * Handle lighting linedef types
33 *
34 *-----------------------------------------------------------------------------*/
35
36#include "doomstat.h" //jff 5/18/98
37#include "doomdef.h"
38#include "m_random.h"
39#include "r_main.h"
40#include "p_spec.h"
41#include "p_tick.h"
42
43//////////////////////////////////////////////////////////
44//
45// Lighting action routines, called once per tick
46//
47//////////////////////////////////////////////////////////
48
49//
50// T_FireFlicker()
51//
52// Firelight flicker action routine, called once per tick
53//
54// Passed a fireflicker_t structure containing light levels and timing
55// Returns nothing
56//
57void T_FireFlicker (fireflicker_t* flick)
58{
59 int amount;
60
61 if (--flick->count)
62 return;
63
64 amount = (P_Random(pr_lights)&3)*16;
65
66 if (flick->sector->lightlevel - amount < flick->minlight)
67 flick->sector->lightlevel = flick->minlight;
68 else
69 flick->sector->lightlevel = flick->maxlight - amount;
70
71 flick->count = 4;
72}
73
74//
75// T_LightFlash()
76//
77// Broken light flashing action routine, called once per tick
78//
79// Passed a lightflash_t structure containing light levels and timing
80// Returns nothing
81//
82void T_LightFlash (lightflash_t* flash)
83{
84 if (--flash->count)
85 return;
86
87 if (flash->sector->lightlevel == flash->maxlight)
88 {
89 flash-> sector->lightlevel = flash->minlight;
90 flash->count = (P_Random(pr_lights)&flash->mintime)+1;
91 }
92 else
93 {
94 flash-> sector->lightlevel = flash->maxlight;
95 flash->count = (P_Random(pr_lights)&flash->maxtime)+1;
96 }
97
98}
99
100//
101// T_StrobeFlash()
102//
103// Strobe light flashing action routine, called once per tick
104//
105// Passed a strobe_t structure containing light levels and timing
106// Returns nothing
107//
108void T_StrobeFlash (strobe_t* flash)
109{
110 if (--flash->count)
111 return;
112
113 if (flash->sector->lightlevel == flash->minlight)
114 {
115 flash-> sector->lightlevel = flash->maxlight;
116 flash->count = flash->brighttime;
117 }
118 else
119 {
120 flash-> sector->lightlevel = flash->minlight;
121 flash->count =flash->darktime;
122 }
123}
124
125//
126// T_Glow()
127//
128// Glowing light action routine, called once per tick
129//
130// Passed a glow_t structure containing light levels and timing
131// Returns nothing
132//
133
134void T_Glow(glow_t* g)
135{
136 switch(g->direction)
137 {
138 case -1:
139 // light dims
140 g->sector->lightlevel -= GLOWSPEED;
141 if (g->sector->lightlevel <= g->minlight)
142 {
143 g->sector->lightlevel += GLOWSPEED;
144 g->direction = 1;
145 }
146 break;
147
148 case 1:
149 // light brightens
150 g->sector->lightlevel += GLOWSPEED;
151 if (g->sector->lightlevel >= g->maxlight)
152 {
153 g->sector->lightlevel -= GLOWSPEED;
154 g->direction = -1;
155 }
156 break;
157 }
158}
159
160//////////////////////////////////////////////////////////
161//
162// Sector lighting type spawners
163//
164// After the map has been loaded, each sector is scanned
165// for specials that spawn thinkers
166//
167//////////////////////////////////////////////////////////
168
169//
170// P_SpawnFireFlicker()
171//
172// Spawns a fire flicker lighting thinker
173//
174// Passed the sector that spawned the thinker
175// Returns nothing
176//
177void P_SpawnFireFlicker (sector_t* sector)
178{
179 fireflicker_t* flick;
180
181 // Note that we are resetting sector attributes.
182 // Nothing special about it during gameplay.
183 sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
184
185 flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0);
186
187 memset(flick, 0, sizeof(*flick));
188 P_AddThinker (&flick->thinker);
189
190 flick->thinker.function = T_FireFlicker;
191 flick->sector = sector;
192 flick->maxlight = sector->lightlevel;
193 flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel)+16;
194 flick->count = 4;
195}
196
197//
198// P_SpawnLightFlash()
199//
200// Spawns a broken light flash lighting thinker
201//
202// Passed the sector that spawned the thinker
203// Returns nothing
204//
205void P_SpawnLightFlash (sector_t* sector)
206{
207 lightflash_t* flash;
208
209 // nothing special about it during gameplay
210 sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
211
212 flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);
213
214 memset(flash, 0, sizeof(*flash));
215 P_AddThinker (&flash->thinker);
216
217 flash->thinker.function = T_LightFlash;
218 flash->sector = sector;
219 flash->maxlight = sector->lightlevel;
220
221 flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
222 flash->maxtime = 64;
223 flash->mintime = 7;
224 flash->count = (P_Random(pr_lights)&flash->maxtime)+1;
225}
226
227//
228// P_SpawnStrobeFlash
229//
230// Spawns a blinking light thinker
231//
232// Passed the sector that spawned the thinker, speed of blinking
233// and whether blinking is to by syncrhonous with other sectors
234//
235// Returns nothing
236//
237void P_SpawnStrobeFlash
238( sector_t* sector,
239 int fastOrSlow,
240 int inSync )
241{
242 strobe_t* flash;
243
244 flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);
245
246 memset(flash, 0, sizeof(*flash));
247 P_AddThinker (&flash->thinker);
248
249 flash->sector = sector;
250 flash->darktime = fastOrSlow;
251 flash->brighttime = STROBEBRIGHT;
252 flash->thinker.function = T_StrobeFlash;
253 flash->maxlight = sector->lightlevel;
254 flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
255
256 if (flash->minlight == flash->maxlight)
257 flash->minlight = 0;
258
259 // nothing special about it during gameplay
260 sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
261
262 if (!inSync)
263 flash->count = (P_Random(pr_lights)&7)+1;
264 else
265 flash->count = 1;
266}
267
268//
269// P_SpawnGlowingLight()
270//
271// Spawns a glowing light (smooth oscillation from min to max) thinker
272//
273// Passed the sector that spawned the thinker
274// Returns nothing
275//
276void P_SpawnGlowingLight(sector_t* sector)
277{
278 glow_t* g;
279
280 g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0);
281
282 memset(g, 0, sizeof(*g));
283 P_AddThinker(&g->thinker);
284
285 g->sector = sector;
286 g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
287 g->maxlight = sector->lightlevel;
288 g->thinker.function = T_Glow;
289 g->direction = -1;
290
291 sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
292}
293
294//////////////////////////////////////////////////////////
295//
296// Linedef lighting function handlers
297//
298//////////////////////////////////////////////////////////
299
300//
301// EV_StartLightStrobing()
302//
303// Start strobing lights (usually from a trigger)
304//
305// Passed the line that activated the strobing
306// Returns true
307//
308// jff 2/12/98 added int return value, fixed return
309//
310int EV_StartLightStrobing(line_t* line)
311{
312 int secnum;
313 sector_t* sec;
314
315 secnum = -1;
316 // start lights strobing in all sectors tagged same as line
317 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
318 {
319 sec = &sectors[secnum];
320 // if already doing a lighting function, don't start a second
321 if (P_SectorActive(lighting_special,sec)) //jff 2/22/98
322 continue;
323
324 P_SpawnStrobeFlash (sec,SLOWDARK, 0);
325 }
326 return 1;
327}
328
329//
330// EV_TurnTagLightsOff()
331//
332// Turn line's tagged sector's lights to min adjacent neighbor level
333//
334// Passed the line that activated the lights being turned off
335// Returns true
336//
337// jff 2/12/98 added int return value, fixed return
338//
339int EV_TurnTagLightsOff(line_t* line)
340{
341 int j;
342
343 // search sectors for those with same tag as activating line
344
345 // killough 10/98: replaced inefficient search with fast search
346 for (j = -1; (j = P_FindSectorFromLineTag(line,j)) >= 0;)
347 {
348 sector_t *sector = sectors + j, *tsec;
349 int i, min = sector->lightlevel;
350 // find min neighbor light level
351 for (i = 0;i < sector->linecount; i++)
352 if ((tsec = getNextSector(sector->lines[i], sector)) &&
353 tsec->lightlevel < min)
354 min = tsec->lightlevel;
355 sector->lightlevel = min;
356 }
357 return 1;
358}
359
360//
361// EV_LightTurnOn()
362//
363// Turn sectors tagged to line lights on to specified or max neighbor level
364//
365// Passed the activating line, and a level to set the light to
366// If level passed is 0, the maximum neighbor lighting is used
367// Returns true
368//
369// jff 2/12/98 added int return value, fixed return
370//
371int EV_LightTurnOn(line_t *line, int bright)
372{
373 int i;
374
375 // search all sectors for ones with same tag as activating line
376
377 // killough 10/98: replace inefficient search with fast search
378 for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;)
379 {
380 sector_t *temp, *sector = sectors+i;
381 int j, tbright = bright; //jff 5/17/98 search for maximum PER sector
382
383 // bright = 0 means to search for highest light level surrounding sector
384
385 if (!bright)
386 for (j = 0;j < sector->linecount; j++)
387 if ((temp = getNextSector(sector->lines[j],sector)) &&
388 temp->lightlevel > tbright)
389 tbright = temp->lightlevel;
390
391 sector->lightlevel = tbright;
392
393 //jff 5/17/98 unless compatibility optioned
394 //then maximum near ANY tagged sector
395 if (comp[comp_model])
396 bright = tbright;
397 }
398 return 1;
399}
400
401/* killough 10/98:
402 *
403 * EV_LightTurnOnPartway()
404 *
405 * Turn sectors tagged to line lights on to specified or max neighbor level
406 *
407 * Passed the activating line, and a light level fraction between 0 and 1.
408 * Sets the light to min on 0, max on 1, and interpolates in-between.
409 * Used for doors with gradual lighting effects.
410 *
411 * Returns true
412 */
413
414int EV_LightTurnOnPartway(line_t *line, fixed_t level)
415{
416 int i;
417
418 if (level < 0) // clip at extremes
419 level = 0;
420 if (level > FRACUNIT)
421 level = FRACUNIT;
422
423 // search all sectors for ones with same tag as activating line
424 for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;)
425 {
426 sector_t *temp, *sector = sectors+i;
427 int j, bright = 0, min = sector->lightlevel;
428
429 for (j = 0; j < sector->linecount; j++)
430 if ((temp = getNextSector(sector->lines[j],sector)))
431 {
432 if (temp->lightlevel > bright)
433 bright = temp->lightlevel;
434 if (temp->lightlevel < min)
435 min = temp->lightlevel;
436 }
437
438 sector->lightlevel = // Set level in-between extremes
439 (level * bright + (FRACUNIT-level) * min) >> FRACBITS;
440 }
441 return 1;
442}
443
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2004 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Movement, collision handling.
31 * Shooting and aiming.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#include "doomstat.h"
36#include "r_main.h"
37#include "p_mobj.h"
38#include "p_maputl.h"
39#include "p_map.h"
40#include "p_setup.h"
41#include "p_spec.h"
42#include "s_sound.h"
43#include "sounds.h"
44#include "p_inter.h"
45#include "m_random.h"
46#include "m_bbox.h"
47#include "lprintf.h"
48
49static mobj_t *tmthing;
50static fixed_t tmx;
51static fixed_t tmy;
52static int pe_x; // Pain Elemental position for Lost Soul checks // phares
53static int pe_y; // Pain Elemental position for Lost Soul checks // phares
54static int ls_x; // Lost Soul position for Lost Soul checks // phares
55static int ls_y; // Lost Soul position for Lost Soul checks // phares
56
57// If "floatok" true, move would be ok
58// if within "tmfloorz - tmceilingz".
59
60boolean floatok;
61
62/* killough 11/98: if "felldown" true, object was pushed down ledge */
63boolean felldown;
64
65// The tm* items are used to hold information globally, usually for
66// line or object intersection checking
67
68fixed_t tmbbox[4]; // bounding box for line intersection checks
69fixed_t tmfloorz; // floor you'd hit if free to fall
70fixed_t tmceilingz; // ceiling of sector you're in
71fixed_t tmdropoffz; // dropoff on other side of line you're crossing
72
73// keep track of the line that lowers the ceiling,
74// so missiles don't explode against sky hack walls
75
76line_t *ceilingline;
77line_t *blockline; /* killough 8/11/98: blocking linedef */
78line_t *floorline; /* killough 8/1/98: Highest touched floor */
79static int tmunstuck; /* killough 8/1/98: whether to allow unsticking */
80
81// keep track of special lines as they are hit,
82// but don't process them until the move is proven valid
83
84// 1/11/98 killough: removed limit on special lines crossed
85line_t **spechit; // new code -- killough
86static int spechit_max; // killough
87
88int numspechit;
89
90// Temporary holder for thing_sectorlist threads
91msecnode_t* sector_list = NULL; // phares 3/16/98
92
93//
94// TELEPORT MOVE
95//
96
97//
98// PIT_StompThing
99//
100
101static boolean telefrag; /* killough 8/9/98: whether to telefrag at exit */
102
103boolean PIT_StompThing (mobj_t* thing)
104 {
105 fixed_t blockdist;
106
107 // phares 9/10/98: moved this self-check to start of routine
108
109 // don't clip against self
110
111 if (thing == tmthing)
112 return true;
113
114 if (!(thing->flags & MF_SHOOTABLE)) // Can't shoot it? Can't stomp it!
115 return true;
116
117 blockdist = thing->radius + tmthing->radius;
118
119 if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist)
120 return true; // didn't hit it
121
122 // monsters don't stomp things except on boss level
123 if (!telefrag) // killough 8/9/98: make consistent across all levels
124 return false;
125
126 P_DamageMobj (thing, tmthing, tmthing, 10000); // Stomp!
127
128 return true;
129 }
130
131
132/*
133 * killough 8/28/98:
134 *
135 * P_GetFriction()
136 *
137 * Returns the friction associated with a particular mobj.
138 */
139
140int P_GetFriction(const mobj_t *mo, int *frictionfactor)
141{
142 int friction = ORIG_FRICTION;
143 int movefactor = ORIG_FRICTION_FACTOR;
144 const msecnode_t *m;
145 const sector_t *sec;
146
147 /* Assign the friction value to objects on the floor, non-floating,
148 * and clipped. Normally the object's friction value is kept at
149 * ORIG_FRICTION and this thinker changes it for icy or muddy floors.
150 *
151 * When the object is straddling sectors with the same
152 * floorheight that have different frictions, use the lowest
153 * friction value (muddy has precedence over icy).
154 */
155
156 if (!(mo->flags & (MF_NOCLIP|MF_NOGRAVITY))
157 && (mbf_features || (mo->player && !compatibility)) &&
158 variable_friction)
159 for (m = mo->touching_sectorlist; m; m = m->m_tnext)
160 if ((sec = m->m_sector)->special & FRICTION_MASK &&
161 (sec->friction < friction || friction == ORIG_FRICTION) &&
162 (mo->z <= sec->floorheight ||
163 (sec->heightsec != -1 &&
164 mo->z <= sectors[sec->heightsec].floorheight &&
165 mbf_features)))
166 friction = sec->friction, movefactor = sec->movefactor;
167
168 if (frictionfactor)
169 *frictionfactor = movefactor;
170
171 return friction;
172}
173
174/* phares 3/19/98
175 * P_GetMoveFactor() returns the value by which the x,y
176 * movements are multiplied to add to player movement.
177 *
178 * killough 8/28/98: rewritten
179 */
180
181int P_GetMoveFactor(const mobj_t *mo, int *frictionp)
182{
183 int movefactor, friction;
184
185 //e6y
186 if (!mbf_features)
187 {
188 int momentum;
189
190 movefactor = ORIG_FRICTION_FACTOR;
191
192 if (!compatibility && variable_friction &&
193 !(mo->flags & (MF_NOGRAVITY | MF_NOCLIP)))
194 {
195 friction = mo->friction;
196 if (friction == ORIG_FRICTION) // normal floor
197 ;
198 else if (friction > ORIG_FRICTION) // ice
199 {
200 movefactor = mo->movefactor;
201 ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset
202 }
203 else // sludge
204 {
205
206 // phares 3/11/98: you start off slowly, then increase as
207 // you get better footing
208
209 momentum = (P_AproxDistance(mo->momx,mo->momy));
210 movefactor = mo->movefactor;
211 if (momentum > MORE_FRICTION_MOMENTUM<<2)
212 movefactor <<= 3;
213
214 else if (momentum > MORE_FRICTION_MOMENTUM<<1)
215 movefactor <<= 2;
216
217 else if (momentum > MORE_FRICTION_MOMENTUM)
218 movefactor <<= 1;
219
220 ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset
221 }
222 } // ^
223
224 return(movefactor); // |
225 }
226
227 // If the floor is icy or muddy, it's harder to get moving. This is where
228 // the different friction factors are applied to 'trying to move'. In
229 // p_mobj.c, the friction factors are applied as you coast and slow down.
230
231 if ((friction = P_GetFriction(mo, &movefactor)) < ORIG_FRICTION)
232 {
233 // phares 3/11/98: you start off slowly, then increase as
234 // you get better footing
235
236 int momentum = P_AproxDistance(mo->momx,mo->momy);
237
238 if (momentum > MORE_FRICTION_MOMENTUM<<2)
239 movefactor <<= 3;
240 else if (momentum > MORE_FRICTION_MOMENTUM<<1)
241 movefactor <<= 2;
242 else if (momentum > MORE_FRICTION_MOMENTUM)
243 movefactor <<= 1;
244 }
245
246 if (frictionp)
247 *frictionp = friction;
248
249 return movefactor;
250}
251
252//
253// P_TeleportMove
254//
255
256boolean P_TeleportMove (mobj_t* thing,fixed_t x,fixed_t y, boolean boss)
257 {
258 int xl;
259 int xh;
260 int yl;
261 int yh;
262 int bx;
263 int by;
264
265 subsector_t* newsubsec;
266
267 /* killough 8/9/98: make telefragging more consistent, preserve compatibility */
268 telefrag = thing->player ||
269 (!comp[comp_telefrag] ? boss : (gamemap==30));
270
271 // kill anything occupying the position
272
273 tmthing = thing;
274
275 tmx = x;
276 tmy = y;
277
278 tmbbox[BOXTOP] = y + tmthing->radius;
279 tmbbox[BOXBOTTOM] = y - tmthing->radius;
280 tmbbox[BOXRIGHT] = x + tmthing->radius;
281 tmbbox[BOXLEFT] = x - tmthing->radius;
282
283 newsubsec = R_PointInSubsector (x,y);
284 ceilingline = NULL;
285
286 // The base floor/ceiling is from the subsector
287 // that contains the point.
288 // Any contacted lines the step closer together
289 // will adjust them.
290
291 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
292 tmceilingz = newsubsec->sector->ceilingheight;
293
294 validcount++;
295 numspechit = 0;
296
297 // stomp on any things contacted
298
299 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
300 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
301 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
302 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
303
304 for (bx=xl ; bx<=xh ; bx++)
305 for (by=yl ; by<=yh ; by++)
306 if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
307 return false;
308
309 // the move is ok,
310 // so unlink from the old position & link into the new position
311
312 P_UnsetThingPosition (thing);
313
314 thing->floorz = tmfloorz;
315 thing->ceilingz = tmceilingz;
316 thing->dropoffz = tmdropoffz; // killough 11/98
317
318 thing->x = x;
319 thing->y = y;
320
321 P_SetThingPosition (thing);
322
323 thing->PrevX = x;
324 thing->PrevY = y;
325 thing->PrevZ = thing->floorz;
326
327 return true;
328 }
329
330
331//
332// MOVEMENT ITERATOR FUNCTIONS
333//
334
335// e6y: Spechits overrun emulation code
336static void SpechitOverrun(line_t *ld);
337
338// // phares
339// PIT_CrossLine // |
340// Checks to see if a PE->LS trajectory line crosses a blocking // V
341// line. Returns false if it does.
342//
343// tmbbox holds the bounding box of the trajectory. If that box
344// does not touch the bounding box of the line in question,
345// then the trajectory is not blocked. If the PE is on one side
346// of the line and the LS is on the other side, then the
347// trajectory is blocked.
348//
349// Currently this assumes an infinite line, which is not quite
350// correct. A more correct solution would be to check for an
351// intersection of the trajectory and the line, but that takes
352// longer and probably really isn't worth the effort.
353//
354
355static // killough 3/26/98: make static
356boolean PIT_CrossLine (line_t* ld)
357 {
358 if (!(ld->flags & ML_TWOSIDED) ||
359 (ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS)))
360 if (!(tmbbox[BOXLEFT] > ld->bbox[BOXRIGHT] ||
361 tmbbox[BOXRIGHT] < ld->bbox[BOXLEFT] ||
362 tmbbox[BOXTOP] < ld->bbox[BOXBOTTOM] ||
363 tmbbox[BOXBOTTOM] > ld->bbox[BOXTOP]))
364 if (P_PointOnLineSide(pe_x,pe_y,ld) != P_PointOnLineSide(ls_x,ls_y,ld))
365 return(false); // line blocks trajectory // ^
366 return(true); // line doesn't block trajectory // |
367 } // phares
368
369
370/* killough 8/1/98: used to test intersection between thing and line
371 * assuming NO movement occurs -- used to avoid sticky situations.
372 */
373
374static int untouched(line_t *ld)
375{
376 fixed_t x, y, tmbbox[4];
377 return
378 (tmbbox[BOXRIGHT] = (x=tmthing->x)+tmthing->radius) <= ld->bbox[BOXLEFT] ||
379 (tmbbox[BOXLEFT] = x-tmthing->radius) >= ld->bbox[BOXRIGHT] ||
380 (tmbbox[BOXTOP] = (y=tmthing->y)+tmthing->radius) <= ld->bbox[BOXBOTTOM] ||
381 (tmbbox[BOXBOTTOM] = y-tmthing->radius) >= ld->bbox[BOXTOP] ||
382 P_BoxOnLineSide(tmbbox, ld) != -1;
383}
384
385//
386// PIT_CheckLine
387// Adjusts tmfloorz and tmceilingz as lines are contacted
388//
389
390static // killough 3/26/98: make static
391boolean PIT_CheckLine (line_t* ld)
392{
393 if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
394 || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
395 || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
396 || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
397 return true; // didn't hit it
398
399 if (P_BoxOnLineSide(tmbbox, ld) != -1)
400 return true; // didn't hit it
401
402 // A line has been hit
403
404 // The moving thing's destination position will cross the given line.
405 // If this should not be allowed, return false.
406 // If the line is special, keep track of it
407 // to process later if the move is proven ok.
408 // NOTE: specials are NOT sorted by order,
409 // so two special lines that are only 8 pixels apart
410 // could be crossed in either order.
411
412 // killough 7/24/98: allow player to move out of 1s wall, to prevent sticking
413 if (!ld->backsector) // one sided line
414 {
415 blockline = ld;
416 return tmunstuck && !untouched(ld) &&
417 FixedMul(tmx-tmthing->x,ld->dy) > FixedMul(tmy-tmthing->y,ld->dx);
418 }
419
420 // killough 8/10/98: allow bouncing objects to pass through as missiles
421 if (!(tmthing->flags & (MF_MISSILE | MF_BOUNCES)))
422 {
423 if (ld->flags & ML_BLOCKING) // explicitly blocking everything
424 return tmunstuck && !untouched(ld); // killough 8/1/98: allow escape
425
426 // killough 8/9/98: monster-blockers don't affect friends
427 if (!(tmthing->flags & MF_FRIEND || tmthing->player)
428 && ld->flags & ML_BLOCKMONSTERS)
429 return false; // block monsters only
430 }
431
432 // set openrange, opentop, openbottom
433 // these define a 'window' from one sector to another across this line
434
435 P_LineOpening (ld);
436
437 // adjust floor & ceiling heights
438
439 if (opentop < tmceilingz)
440 {
441 tmceilingz = opentop;
442 ceilingline = ld;
443 blockline = ld;
444 }
445
446 if (openbottom > tmfloorz)
447 {
448 tmfloorz = openbottom;
449 floorline = ld; // killough 8/1/98: remember floor linedef
450 blockline = ld;
451 }
452
453 if (lowfloor < tmdropoffz)
454 tmdropoffz = lowfloor;
455
456 // if contacted a special line, add it to the list
457
458 if (ld->special)
459 {
460 // 1/11/98 killough: remove limit on lines hit, by array doubling
461 if (numspechit >= spechit_max) {
462 spechit_max = spechit_max ? spechit_max*2 : 8;
463 spechit = realloc(spechit,sizeof *spechit*spechit_max); // killough
464 }
465 spechit[numspechit++] = ld;
466 // e6y: Spechits overrun emulation code
467 if (numspechit >= 8 && demo_compatibility)
468 SpechitOverrun(ld);
469 }
470
471 return true;
472}
473
474//
475// PIT_CheckThing
476//
477
478static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static
479{
480 fixed_t blockdist;
481 int damage;
482
483 // killough 11/98: add touchy things
484 if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE|MF_TOUCHY)))
485 return true;
486
487 blockdist = thing->radius + tmthing->radius;
488
489 if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist)
490 return true; // didn't hit it
491
492 // killough 11/98:
493 //
494 // This test has less information content (it's almost always false), so it
495 // should not be moved up to first, as it adds more overhead than it removes.
496
497 // don't clip against self
498
499 if (thing == tmthing)
500 return true;
501
502 /* killough 11/98:
503 *
504 * TOUCHY flag, for mines or other objects which die on contact with solids.
505 * If a solid object of a different type comes in contact with a touchy
506 * thing, and the touchy thing is not the sole one moving relative to fixed
507 * surroundings such as walls, then the touchy thing dies immediately.
508 */
509
510 if (thing->flags & MF_TOUCHY && // touchy object
511 tmthing->flags & MF_SOLID && // solid object touches it
512 thing->health > 0 && // touchy object is alive
513 (thing->intflags & MIF_ARMED || // Thing is an armed mine
514 sentient(thing)) && // ... or a sentient thing
515 (thing->type != tmthing->type || // only different species
516 thing->type == MT_PLAYER) && // ... or different players
517 thing->z + thing->height >= tmthing->z && // touches vertically
518 tmthing->z + tmthing->height >= thing->z &&
519 (thing->type ^ MT_PAIN) | // PEs and lost souls
520 (tmthing->type ^ MT_SKULL) && // are considered same
521 (thing->type ^ MT_SKULL) | // (but Barons & Knights
522 (tmthing->type ^ MT_PAIN)) // are intentionally not)
523 {
524 P_DamageMobj(thing, NULL, NULL, thing->health); // kill object
525 return true;
526 }
527
528 // check for skulls slamming into things
529
530 if (tmthing->flags & MF_SKULLFLY)
531 {
532 // A flying skull is smacking something.
533 // Determine damage amount, and the skull comes to a dead stop.
534
535 int damage = ((P_Random(pr_skullfly)%8)+1)*tmthing->info->damage;
536
537 P_DamageMobj (thing, tmthing, tmthing, damage);
538
539 tmthing->flags &= ~MF_SKULLFLY;
540 tmthing->momx = tmthing->momy = tmthing->momz = 0;
541
542 P_SetMobjState (tmthing, tmthing->info->spawnstate);
543
544 return false; // stop moving
545 }
546
547 // missiles can hit other things
548 // killough 8/10/98: bouncing non-solid things can hit other things too
549
550 if (tmthing->flags & MF_MISSILE || (tmthing->flags & MF_BOUNCES &&
551 !(tmthing->flags & MF_SOLID)))
552 {
553 // see if it went over / under
554
555 if (tmthing->z > thing->z + thing->height)
556 return true; // overhead
557
558 if (tmthing->z+tmthing->height < thing->z)
559 return true; // underneath
560
561 if (tmthing->target && (tmthing->target->type == thing->type ||
562 (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
563 (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT)))
564 {
565 if (thing == tmthing->target)
566 return true; // Don't hit same species as originator.
567 else
568 // e6y: Dehacked support - monsters infight
569 if (thing->type != MT_PLAYER && !monsters_infight) // Explode, but do no damage.
570 return false; // Let players missile other players.
571 }
572
573 // killough 8/10/98: if moving thing is not a missile, no damage
574 // is inflicted, and momentum is reduced if object hit is solid.
575
576 if (!(tmthing->flags & MF_MISSILE)) {
577 if (!(thing->flags & MF_SOLID)) {
578 return true;
579 } else {
580 tmthing->momx = -tmthing->momx;
581 tmthing->momy = -tmthing->momy;
582 if (!(tmthing->flags & MF_NOGRAVITY))
583 {
584 tmthing->momx >>= 2;
585 tmthing->momy >>= 2;
586 }
587 return false;
588 }
589 }
590
591 if (!(thing->flags & MF_SHOOTABLE))
592 return !(thing->flags & MF_SOLID); // didn't do any damage
593
594 // damage / explode
595
596 damage = ((P_Random(pr_damage)%8)+1)*tmthing->info->damage;
597 P_DamageMobj (thing, tmthing, tmthing->target, damage);
598
599 // don't traverse any more
600 return false;
601 }
602
603 // check for special pickup
604
605 if (thing->flags & MF_SPECIAL)
606 {
607 uint_64_t solid = thing->flags & MF_SOLID;
608 if (tmthing->flags & MF_PICKUP)
609 P_TouchSpecialThing(thing, tmthing); // can remove thing
610 return !solid;
611 }
612
613 // killough 3/16/98: Allow non-solid moving objects to move through solid
614 // ones, by allowing the moving thing (tmthing) to move if it's non-solid,
615 // despite another solid thing being in the way.
616 // killough 4/11/98: Treat no-clipping things as not blocking
617 // ...but not in demo_compatibility mode
618
619 return !(thing->flags & MF_SOLID)
620 || (!demo_compatibility
621 && (thing->flags & MF_NOCLIP || !(tmthing->flags & MF_SOLID)));
622
623 // return !(thing->flags & MF_SOLID); // old code -- killough
624}
625
626// This routine checks for Lost Souls trying to be spawned // phares
627// across 1-sided lines, impassible lines, or "monsters can't // |
628// cross" lines. Draw an imaginary line between the PE // V
629// and the new Lost Soul spawn spot. If that line crosses
630// a 'blocking' line, then disallow the spawn. Only search
631// lines in the blocks of the blockmap where the bounding box
632// of the trajectory line resides. Then check bounding box
633// of the trajectory vs. the bounding box of each blocking
634// line to see if the trajectory and the blocking line cross.
635// Then check the PE and LS to see if they're on different
636// sides of the blocking line. If so, return true, otherwise
637// false.
638
639boolean Check_Sides(mobj_t* actor, int x, int y)
640 {
641 int bx,by,xl,xh,yl,yh;
642
643 pe_x = actor->x;
644 pe_y = actor->y;
645 ls_x = x;
646 ls_y = y;
647
648 // Here is the bounding box of the trajectory
649
650 tmbbox[BOXLEFT] = pe_x < x ? pe_x : x;
651 tmbbox[BOXRIGHT] = pe_x > x ? pe_x : x;
652 tmbbox[BOXTOP] = pe_y > y ? pe_y : y;
653 tmbbox[BOXBOTTOM] = pe_y < y ? pe_y : y;
654
655 // Determine which blocks to look in for blocking lines
656
657 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
658 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
659 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
660 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
661
662 // xl->xh, yl->yh determine the mapblock set to search
663
664 validcount++; // prevents checking same line twice
665 for (bx = xl ; bx <= xh ; bx++)
666 for (by = yl ; by <= yh ; by++)
667 if (!P_BlockLinesIterator(bx,by,PIT_CrossLine))
668 return true; // ^
669 return(false); // |
670 } // phares
671
672//
673// MOVEMENT CLIPPING
674//
675
676//
677// P_CheckPosition
678// This is purely informative, nothing is modified
679// (except things picked up).
680//
681// in:
682// a mobj_t (can be valid or invalid)
683// a position to be checked
684// (doesn't need to be related to the mobj_t->x,y)
685//
686// during:
687// special things are touched if MF_PICKUP
688// early out on solid lines?
689//
690// out:
691// newsubsec
692// floorz
693// ceilingz
694// tmdropoffz
695// the lowest point contacted
696// (monsters won't move to a dropoff)
697// speciallines[]
698// numspeciallines
699//
700
701boolean P_CheckPosition (mobj_t* thing,fixed_t x,fixed_t y)
702 {
703 int xl;
704 int xh;
705 int yl;
706 int yh;
707 int bx;
708 int by;
709 subsector_t* newsubsec;
710
711 tmthing = thing;
712
713 tmx = x;
714 tmy = y;
715
716 tmbbox[BOXTOP] = y + tmthing->radius;
717 tmbbox[BOXBOTTOM] = y - tmthing->radius;
718 tmbbox[BOXRIGHT] = x + tmthing->radius;
719 tmbbox[BOXLEFT] = x - tmthing->radius;
720
721 newsubsec = R_PointInSubsector (x,y);
722 floorline = blockline = ceilingline = NULL; // killough 8/1/98
723
724 // Whether object can get out of a sticky situation:
725 tmunstuck = thing->player && /* only players */
726 thing->player->mo == thing && /* not voodoo dolls */
727 mbf_features; /* not under old demos */
728
729 // The base floor / ceiling is from the subsector
730 // that contains the point.
731 // Any contacted lines the step closer together
732 // will adjust them.
733
734 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
735 tmceilingz = newsubsec->sector->ceilingheight;
736 validcount++;
737 numspechit = 0;
738
739 if ( tmthing->flags & MF_NOCLIP )
740 return true;
741
742 // Check things first, possibly picking things up.
743 // The bounding box is extended by MAXRADIUS
744 // because mobj_ts are grouped into mapblocks
745 // based on their origin point, and can overlap
746 // into adjacent blocks by up to MAXRADIUS units.
747
748 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
749 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
750 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
751 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
752
753
754 for (bx=xl ; bx<=xh ; bx++)
755 for (by=yl ; by<=yh ; by++)
756 if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
757 return false;
758
759 // check lines
760
761 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
762 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
763 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
764 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
765
766 for (bx=xl ; bx<=xh ; bx++)
767 for (by=yl ; by<=yh ; by++)
768 if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
769 return false; // doesn't fit
770
771 return true;
772 }
773
774
775//
776// P_TryMove
777// Attempt to move to a new position,
778// crossing special lines unless MF_TELEPORT is set.
779//
780boolean P_TryMove(mobj_t* thing,fixed_t x,fixed_t y,
781 boolean dropoff) // killough 3/15/98: allow dropoff as option
782 {
783 fixed_t oldx;
784 fixed_t oldy;
785
786 felldown = floatok = false; // killough 11/98
787
788 if (!P_CheckPosition (thing, x, y))
789 return false; // solid wall or thing
790
791 if ( !(thing->flags & MF_NOCLIP) )
792 {
793 // killough 7/26/98: reformatted slightly
794 // killough 8/1/98: Possibly allow escape if otherwise stuck
795
796 if (tmceilingz - tmfloorz < thing->height || // doesn't fit
797 // mobj must lower to fit
798 (floatok = true, !(thing->flags & MF_TELEPORT) &&
799 tmceilingz - thing->z < thing->height) ||
800 // too big a step up
801 (!(thing->flags & MF_TELEPORT) &&
802 tmfloorz - thing->z > 24*FRACUNIT))
803 return tmunstuck
804 && !(ceilingline && untouched(ceilingline))
805 && !( floorline && untouched( floorline));
806
807 /* killough 3/15/98: Allow certain objects to drop off
808 * killough 7/24/98, 8/1/98:
809 * Prevent monsters from getting stuck hanging off ledges
810 * killough 10/98: Allow dropoffs in controlled circumstances
811 * killough 11/98: Improve symmetry of clipping on stairs
812 */
813
814 if (!(thing->flags & (MF_DROPOFF|MF_FLOAT))) {
815 if (comp[comp_dropoff])
816 {
817 if ((compatibility || !dropoff
818 // fix demosync bug in mbf compatibility mode
819 || (mbf_features && compatibility_level <= prboom_2_compatibility))
820 && (tmfloorz - tmdropoffz > 24*FRACUNIT))
821 return false; // don't stand over a dropoff
822 }
823 else
824 if (!dropoff || (dropoff==2 && // large jump down (e.g. dogs)
825 (tmfloorz-tmdropoffz > 128*FRACUNIT ||
826 !thing->target || thing->target->z >tmdropoffz)))
827 {
828 if (!monkeys || !mbf_features ?
829 tmfloorz - tmdropoffz > 24*FRACUNIT :
830 thing->floorz - tmfloorz > 24*FRACUNIT ||
831 thing->dropoffz - tmdropoffz > 24*FRACUNIT)
832 return false;
833 }
834 else { /* dropoff allowed -- check for whether it fell more than 24 */
835 felldown = !(thing->flags & MF_NOGRAVITY) &&
836 thing->z - tmfloorz > 24*FRACUNIT;
837 }
838 }
839
840 if (thing->flags & MF_BOUNCES && // killough 8/13/98
841 !(thing->flags & (MF_MISSILE|MF_NOGRAVITY)) &&
842 !sentient(thing) && tmfloorz - thing->z > 16*FRACUNIT)
843 return false; // too big a step up for bouncers under gravity
844
845 // killough 11/98: prevent falling objects from going up too many steps
846 if (thing->intflags & MIF_FALLING && tmfloorz - thing->z >
847 FixedMul(thing->momx,thing->momx)+FixedMul(thing->momy,thing->momy))
848 return false;
849 }
850
851 // the move is ok,
852 // so unlink from the old position and link into the new position
853
854 P_UnsetThingPosition (thing);
855
856 oldx = thing->x;
857 oldy = thing->y;
858 thing->floorz = tmfloorz;
859 thing->ceilingz = tmceilingz;
860 thing->dropoffz = tmdropoffz; // killough 11/98: keep track of dropoffs
861 thing->x = x;
862 thing->y = y;
863
864 P_SetThingPosition (thing);
865
866 // if any special lines were hit, do the effect
867
868 if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
869 while (numspechit--)
870 if (spechit[numspechit]->special) // see if the line was crossed
871 {
872 int oldside;
873 if ((oldside = P_PointOnLineSide(oldx, oldy, spechit[numspechit])) !=
874 P_PointOnLineSide(thing->x, thing->y, spechit[numspechit]))
875 P_CrossSpecialLine(spechit[numspechit], oldside, thing);
876 }
877
878 return true;
879 }
880
881/*
882 * killough 9/12/98:
883 *
884 * Apply "torque" to objects hanging off of ledges, so that they
885 * fall off. It's not really torque, since Doom has no concept of
886 * rotation, but it's a convincing effect which avoids anomalies
887 * such as lifeless objects hanging more than halfway off of ledges,
888 * and allows objects to roll off of the edges of moving lifts, or
889 * to slide up and then back down stairs, or to fall into a ditch.
890 * If more than one linedef is contacted, the effects are cumulative,
891 * so balancing is possible.
892 */
893
894static boolean PIT_ApplyTorque(line_t *ld)
895{
896 if (ld->backsector && // If thing touches two-sided pivot linedef
897 tmbbox[BOXRIGHT] > ld->bbox[BOXLEFT] &&
898 tmbbox[BOXLEFT] < ld->bbox[BOXRIGHT] &&
899 tmbbox[BOXTOP] > ld->bbox[BOXBOTTOM] &&
900 tmbbox[BOXBOTTOM] < ld->bbox[BOXTOP] &&
901 P_BoxOnLineSide(tmbbox, ld) == -1)
902 {
903 mobj_t *mo = tmthing;
904
905 fixed_t dist = // lever arm
906 + (ld->dx >> FRACBITS) * (mo->y >> FRACBITS)
907 - (ld->dy >> FRACBITS) * (mo->x >> FRACBITS)
908 - (ld->dx >> FRACBITS) * (ld->v1->y >> FRACBITS)
909 + (ld->dy >> FRACBITS) * (ld->v1->x >> FRACBITS);
910
911 if (dist < 0 ? // dropoff direction
912 ld->frontsector->floorheight < mo->z &&
913 ld->backsector->floorheight >= mo->z :
914 ld->backsector->floorheight < mo->z &&
915 ld->frontsector->floorheight >= mo->z)
916 {
917 /* At this point, we know that the object straddles a two-sided
918 * linedef, and that the object's center of mass is above-ground.
919 */
920
921 fixed_t x = D_abs(ld->dx), y = D_abs(ld->dy);
922
923 if (y > x)
924 {
925 fixed_t t = x;
926 x = y;
927 y = t;
928 }
929
930 y = finesine[(tantoangle[FixedDiv(y,x)>>DBITS] +
931 ANG90) >> ANGLETOFINESHIFT];
932
933 /* Momentum is proportional to distance between the
934 * object's center of mass and the pivot linedef.
935 *
936 * It is scaled by 2^(OVERDRIVE - gear). When gear is
937 * increased, the momentum gradually decreases to 0 for
938 * the same amount of pseudotorque, so that oscillations
939 * are prevented, yet it has a chance to reach equilibrium.
940 */
941 dist = FixedDiv(FixedMul(dist, (mo->gear < OVERDRIVE) ?
942 y << -(mo->gear - OVERDRIVE) :
943 y >> +(mo->gear - OVERDRIVE)), x);
944
945 /* Apply momentum away from the pivot linedef. */
946
947 x = FixedMul(ld->dy, dist);
948 y = FixedMul(ld->dx, dist);
949
950 /* Avoid moving too fast all of a sudden (step into "overdrive") */
951
952 dist = FixedMul(x,x) + FixedMul(y,y);
953
954 while (dist > FRACUNIT*4 && mo->gear < MAXGEAR)
955 ++mo->gear, x >>= 1, y >>= 1, dist >>= 1;
956
957 mo->momx -= x;
958 mo->momy += y;
959 }
960 }
961 return true;
962}
963
964/*
965 * killough 9/12/98
966 *
967 * Applies "torque" to objects, based on all contacted linedefs
968 */
969
970void P_ApplyTorque(mobj_t *mo)
971{
972 int xl = ((tmbbox[BOXLEFT] =
973 mo->x - mo->radius) - bmaporgx) >> MAPBLOCKSHIFT;
974 int xh = ((tmbbox[BOXRIGHT] =
975 mo->x + mo->radius) - bmaporgx) >> MAPBLOCKSHIFT;
976 int yl = ((tmbbox[BOXBOTTOM] =
977 mo->y - mo->radius) - bmaporgy) >> MAPBLOCKSHIFT;
978 int yh = ((tmbbox[BOXTOP] =
979 mo->y + mo->radius) - bmaporgy) >> MAPBLOCKSHIFT;
980 int bx,by,flags = mo->intflags; //Remember the current state, for gear-change
981
982 tmthing = mo;
983 validcount++; /* prevents checking same line twice */
984
985 for (bx = xl ; bx <= xh ; bx++)
986 for (by = yl ; by <= yh ; by++)
987 P_BlockLinesIterator(bx, by, PIT_ApplyTorque);
988
989 /* If any momentum, mark object as 'falling' using engine-internal flags */
990 if (mo->momx | mo->momy)
991 mo->intflags |= MIF_FALLING;
992 else // Clear the engine-internal flag indicating falling object.
993 mo->intflags &= ~MIF_FALLING;
994
995 /* If the object has been moving, step up the gear.
996 * This helps reach equilibrium and avoid oscillations.
997 *
998 * Doom has no concept of potential energy, much less
999 * of rotation, so we have to creatively simulate these
1000 * systems somehow :)
1001 */
1002
1003 if (!((mo->intflags | flags) & MIF_FALLING)) // If not falling for a while,
1004 mo->gear = 0; // Reset it to full strength
1005 else
1006 if (mo->gear < MAXGEAR) // Else if not at max gear,
1007 mo->gear++; // move up a gear
1008}
1009
1010//
1011// P_ThingHeightClip
1012// Takes a valid thing and adjusts the thing->floorz,
1013// thing->ceilingz, and possibly thing->z.
1014// This is called for all nearby monsters
1015// whenever a sector changes height.
1016// If the thing doesn't fit,
1017// the z will be set to the lowest value
1018// and false will be returned.
1019//
1020
1021boolean P_ThingHeightClip (mobj_t* thing)
1022{
1023 boolean onfloor;
1024
1025 onfloor = (thing->z == thing->floorz);
1026
1027 P_CheckPosition (thing, thing->x, thing->y);
1028
1029 /* what about stranding a monster partially off an edge?
1030 * killough 11/98: Answer: see below (upset balance if hanging off ledge)
1031 */
1032
1033 thing->floorz = tmfloorz;
1034 thing->ceilingz = tmceilingz;
1035 thing->dropoffz = tmdropoffz; /* killough 11/98: remember dropoffs */
1036
1037 if (onfloor)
1038 {
1039
1040 // walking monsters rise and fall with the floor
1041
1042 thing->z = thing->floorz;
1043
1044 /* killough 11/98: Possibly upset balance of objects hanging off ledges */
1045 if (thing->intflags & MIF_FALLING && thing->gear >= MAXGEAR)
1046 thing->gear = 0;
1047 }
1048 else
1049 {
1050
1051 // don't adjust a floating monster unless forced to
1052
1053 if (thing->z+thing->height > thing->ceilingz)
1054 thing->z = thing->ceilingz - thing->height;
1055 }
1056
1057 return thing->ceilingz - thing->floorz >= thing->height;
1058}
1059
1060
1061//
1062// SLIDE MOVE
1063// Allows the player to slide along any angled walls.
1064//
1065
1066/* killough 8/2/98: make variables static */
1067static fixed_t bestslidefrac;
1068static line_t* bestslideline;
1069static mobj_t* slidemo;
1070static fixed_t tmxmove;
1071static fixed_t tmymove;
1072
1073
1074//
1075// P_HitSlideLine
1076// Adjusts the xmove / ymove
1077// so that the next move will slide along the wall.
1078// If the floor is icy, then you can bounce off a wall. // phares
1079//
1080
1081void P_HitSlideLine (line_t* ld)
1082 {
1083 int side;
1084 angle_t lineangle;
1085 angle_t moveangle;
1086 angle_t deltaangle;
1087 fixed_t movelen;
1088 fixed_t newlen;
1089 boolean icyfloor; // is floor icy? // phares
1090 // |
1091 // Under icy conditions, if the angle of approach to the wall // V
1092 // is more than 45 degrees, then you'll bounce and lose half
1093 // your momentum. If less than 45 degrees, you'll slide along
1094 // the wall. 45 is arbitrary and is believable.
1095
1096 // Check for the special cases of horz or vert walls.
1097
1098 /* killough 10/98: only bounce if hit hard (prevents wobbling)
1099 * cph - DEMOSYNC - should only affect players in Boom demos? */
1100
1101 //e6y
1102 if (mbf_features)
1103 {
1104 icyfloor =
1105 P_AproxDistance(tmxmove, tmymove) > 4*FRACUNIT &&
1106 variable_friction && // killough 8/28/98: calc friction on demand
1107 slidemo->z <= slidemo->floorz &&
1108 P_GetFriction(slidemo, NULL) > ORIG_FRICTION;
1109 }
1110 else
1111 {
1112 extern boolean onground;
1113 icyfloor = !compatibility &&
1114 variable_friction &&
1115 slidemo->player &&
1116 onground &&
1117 slidemo->friction > ORIG_FRICTION;
1118 }
1119
1120 if (ld->slopetype == ST_HORIZONTAL)
1121 {
1122 if (icyfloor && (D_abs(tmymove) > D_abs(tmxmove)))
1123 {
1124 tmxmove /= 2; // absorb half the momentum
1125 tmymove = -tmymove/2;
1126 S_StartSound(slidemo,sfx_oof); // oooff!
1127 }
1128 else
1129 tmymove = 0; // no more movement in the Y direction
1130 return;
1131 }
1132
1133 if (ld->slopetype == ST_VERTICAL)
1134 {
1135 if (icyfloor && (D_abs(tmxmove) > D_abs(tmymove)))
1136 {
1137 tmxmove = -tmxmove/2; // absorb half the momentum
1138 tmymove /= 2;
1139 S_StartSound(slidemo,sfx_oof); // oooff! // ^
1140 } // |
1141 else // phares
1142 tmxmove = 0; // no more movement in the X direction
1143 return;
1144 }
1145
1146 // The wall is angled. Bounce if the angle of approach is // phares
1147 // less than 45 degrees. // phares
1148
1149 side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
1150
1151 lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
1152 if (side == 1)
1153 lineangle += ANG180;
1154 moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
1155
1156 // killough 3/2/98:
1157 // The moveangle+=10 breaks v1.9 demo compatibility in
1158 // some demos, so it needs demo_compatibility switch.
1159
1160 if (!demo_compatibility)
1161 moveangle += 10; // prevents sudden path reversal due to // phares
1162 // rounding error // |
1163 deltaangle = moveangle-lineangle; // V
1164 movelen = P_AproxDistance (tmxmove, tmymove);
1165 if (icyfloor && (deltaangle > ANG45) && (deltaangle < ANG90+ANG45))
1166 {
1167 moveangle = lineangle - deltaangle;
1168 movelen /= 2; // absorb
1169 S_StartSound(slidemo,sfx_oof); // oooff!
1170 moveangle >>= ANGLETOFINESHIFT;
1171 tmxmove = FixedMul (movelen, finecosine[moveangle]);
1172 tmymove = FixedMul (movelen, finesine[moveangle]);
1173 } // ^
1174 else // |
1175 { // phares
1176 if (deltaangle > ANG180)
1177 deltaangle += ANG180;
1178
1179 // I_Error ("SlideLine: ang>ANG180");
1180
1181 lineangle >>= ANGLETOFINESHIFT;
1182 deltaangle >>= ANGLETOFINESHIFT;
1183 newlen = FixedMul (movelen, finecosine[deltaangle]);
1184 tmxmove = FixedMul (newlen, finecosine[lineangle]);
1185 tmymove = FixedMul (newlen, finesine[lineangle]);
1186 } // phares
1187 }
1188
1189
1190//
1191// PTR_SlideTraverse
1192//
1193
1194boolean PTR_SlideTraverse (intercept_t* in)
1195 {
1196 line_t* li;
1197
1198 if (!in->isaline)
1199 I_Error ("PTR_SlideTraverse: not a line?");
1200
1201 li = in->d.line;
1202
1203 if ( ! (li->flags & ML_TWOSIDED) )
1204 {
1205 if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
1206 return true; // don't hit the back side
1207 goto isblocking;
1208 }
1209
1210 // set openrange, opentop, openbottom.
1211 // These define a 'window' from one sector to another across a line
1212
1213 P_LineOpening (li);
1214
1215 if (openrange < slidemo->height)
1216 goto isblocking; // doesn't fit
1217
1218 if (opentop - slidemo->z < slidemo->height)
1219 goto isblocking; // mobj is too high
1220
1221 if (openbottom - slidemo->z > 24*FRACUNIT )
1222 goto isblocking; // too big a step up
1223
1224 // this line doesn't block movement
1225
1226 return true;
1227
1228 // the line does block movement,
1229 // see if it is closer than best so far
1230
1231isblocking:
1232
1233 if (in->frac < bestslidefrac)
1234 {
1235 bestslidefrac = in->frac;
1236 bestslideline = li;
1237 }
1238
1239 return false; // stop
1240 }
1241
1242
1243//
1244// P_SlideMove
1245// The momx / momy move is bad, so try to slide
1246// along a wall.
1247// Find the first line hit, move flush to it,
1248// and slide along it
1249//
1250// This is a kludgy mess.
1251//
1252// killough 11/98: reformatted
1253
1254void P_SlideMove(mobj_t *mo)
1255{
1256 int hitcount = 3;
1257
1258 slidemo = mo; // the object that's sliding
1259
1260 do
1261 {
1262 fixed_t leadx, leady, trailx, traily;
1263
1264 if (!--hitcount)
1265 goto stairstep; // don't loop forever
1266
1267 // trace along the three leading corners
1268
1269 if (mo->momx > 0)
1270 leadx = mo->x + mo->radius, trailx = mo->x - mo->radius;
1271 else
1272 leadx = mo->x - mo->radius, trailx = mo->x + mo->radius;
1273
1274 if (mo->momy > 0)
1275 leady = mo->y + mo->radius, traily = mo->y - mo->radius;
1276 else
1277 leady = mo->y - mo->radius, traily = mo->y + mo->radius;
1278
1279 bestslidefrac = FRACUNIT+1;
1280
1281 P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy,
1282 PT_ADDLINES, PTR_SlideTraverse);
1283 P_PathTraverse(trailx, leady, trailx+mo->momx, leady+mo->momy,
1284 PT_ADDLINES, PTR_SlideTraverse);
1285 P_PathTraverse(leadx, traily, leadx+mo->momx, traily+mo->momy,
1286 PT_ADDLINES, PTR_SlideTraverse);
1287
1288 // move up to the wall
1289
1290 if (bestslidefrac == FRACUNIT+1)
1291 {
1292 // the move must have hit the middle, so stairstep
1293
1294 stairstep:
1295
1296 /* killough 3/15/98: Allow objects to drop off ledges
1297 *
1298 * phares 5/4/98: kill momentum if you can't move at all
1299 * This eliminates player bobbing if pressed against a wall
1300 * while on ice.
1301 *
1302 * killough 10/98: keep buggy code around for old Boom demos
1303 *
1304 * cph 2000/09//23: buggy code was only in Boom v2.01
1305 */
1306
1307 if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true))
1308 if (!P_TryMove(mo, mo->x + mo->momx, mo->y, true))
1309 if (compatibility_level == boom_201_compatibility)
1310 mo->momx = mo->momy = 0;
1311
1312 break;
1313 }
1314
1315 // fudge a bit to make sure it doesn't hit
1316
1317 if ((bestslidefrac -= 0x800) > 0)
1318 {
1319 fixed_t newx = FixedMul(mo->momx, bestslidefrac);
1320 fixed_t newy = FixedMul(mo->momy, bestslidefrac);
1321
1322 // killough 3/15/98: Allow objects to drop off ledges
1323
1324 if (!P_TryMove(mo, mo->x+newx, mo->y+newy, true))
1325 goto stairstep;
1326 }
1327
1328 // Now continue along the wall.
1329 // First calculate remainder.
1330
1331 bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
1332
1333 if (bestslidefrac > FRACUNIT)
1334 bestslidefrac = FRACUNIT;
1335
1336 if (bestslidefrac <= 0)
1337 break;
1338
1339 tmxmove = FixedMul(mo->momx, bestslidefrac);
1340 tmymove = FixedMul(mo->momy, bestslidefrac);
1341
1342 P_HitSlideLine(bestslideline); // clip the moves
1343
1344 mo->momx = tmxmove;
1345 mo->momy = tmymove;
1346
1347 /* killough 10/98: affect the bobbing the same way (but not voodoo dolls)
1348 * cph - DEMOSYNC? */
1349 if (mo->player && mo->player->mo == mo)
1350 {
1351 if (D_abs(mo->player->momx) > D_abs(tmxmove))
1352 mo->player->momx = tmxmove;
1353 if (D_abs(mo->player->momy) > D_abs(tmymove))
1354 mo->player->momy = tmymove;
1355 }
1356 } // killough 3/15/98: Allow objects to drop off ledges:
1357 while (!P_TryMove(mo, mo->x+tmxmove, mo->y+tmymove, true));
1358}
1359
1360//
1361// P_LineAttack
1362//
1363mobj_t* linetarget; // who got hit (or NULL)
1364static mobj_t* shootthing;
1365
1366/* killough 8/2/98: for more intelligent autoaiming */
1367static uint_64_t aim_flags_mask;
1368
1369// Height if not aiming up or down
1370fixed_t shootz;
1371
1372int la_damage;
1373fixed_t attackrange;
1374
1375static fixed_t aimslope;
1376
1377// slopes to top and bottom of target
1378// killough 4/20/98: make static instead of using ones in p_sight.c
1379
1380static fixed_t topslope;
1381static fixed_t bottomslope;
1382
1383
1384//
1385// PTR_AimTraverse
1386// Sets linetaget and aimslope when a target is aimed at.
1387//
1388boolean PTR_AimTraverse (intercept_t* in)
1389 {
1390 line_t* li;
1391 mobj_t* th;
1392 fixed_t slope;
1393 fixed_t thingtopslope;
1394 fixed_t thingbottomslope;
1395 fixed_t dist;
1396
1397 if (in->isaline)
1398 {
1399 li = in->d.line;
1400
1401 if ( !(li->flags & ML_TWOSIDED) )
1402 return false; // stop
1403
1404 // Crosses a two sided line.
1405 // A two sided line will restrict
1406 // the possible target ranges.
1407
1408 P_LineOpening (li);
1409
1410 if (openbottom >= opentop)
1411 return false; // stop
1412
1413 dist = FixedMul (attackrange, in->frac);
1414
1415 if (li->frontsector->floorheight != li->backsector->floorheight)
1416 {
1417 slope = FixedDiv (openbottom - shootz , dist);
1418 if (slope > bottomslope)
1419 bottomslope = slope;
1420 }
1421
1422 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
1423 {
1424 slope = FixedDiv (opentop - shootz , dist);
1425 if (slope < topslope)
1426 topslope = slope;
1427 }
1428
1429 if (topslope <= bottomslope)
1430 return false; // stop
1431
1432 return true; // shot continues
1433 }
1434
1435 // shoot a thing
1436
1437 th = in->d.thing;
1438 if (th == shootthing)
1439 return true; // can't shoot self
1440
1441 if (!(th->flags&MF_SHOOTABLE))
1442 return true; // corpse or something
1443
1444 /* killough 7/19/98, 8/2/98:
1445 * friends don't aim at friends (except players), at least not first
1446 */
1447 if (th->flags & shootthing->flags & aim_flags_mask && !th->player)
1448 return true;
1449
1450 // check angles to see if the thing can be aimed at
1451
1452 dist = FixedMul (attackrange, in->frac);
1453 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1454
1455 if (thingtopslope < bottomslope)
1456 return true; // shot over the thing
1457
1458 thingbottomslope = FixedDiv (th->z - shootz, dist);
1459
1460 if (thingbottomslope > topslope)
1461 return true; // shot under the thing
1462
1463 // this thing can be hit!
1464
1465 if (thingtopslope > topslope)
1466 thingtopslope = topslope;
1467
1468 if (thingbottomslope < bottomslope)
1469 thingbottomslope = bottomslope;
1470
1471 aimslope = (thingtopslope+thingbottomslope)/2;
1472 linetarget = th;
1473
1474 return false; // don't go any farther
1475 }
1476
1477
1478//
1479// PTR_ShootTraverse
1480//
1481boolean PTR_ShootTraverse (intercept_t* in)
1482 {
1483 fixed_t x;
1484 fixed_t y;
1485 fixed_t z;
1486 fixed_t frac;
1487
1488 mobj_t* th;
1489
1490 fixed_t slope;
1491 fixed_t dist;
1492 fixed_t thingtopslope;
1493 fixed_t thingbottomslope;
1494
1495 if (in->isaline)
1496 {
1497 line_t *li = in->d.line;
1498
1499 if (li->special)
1500 P_ShootSpecialLine (shootthing, li);
1501
1502 if (li->flags & ML_TWOSIDED)
1503 { // crosses a two sided (really 2s) line
1504 P_LineOpening (li);
1505 dist = FixedMul(attackrange, in->frac);
1506
1507 // killough 11/98: simplify
1508
1509 if ((li->frontsector->floorheight==li->backsector->floorheight ||
1510 (slope = FixedDiv(openbottom - shootz , dist)) <= aimslope) &&
1511 (li->frontsector->ceilingheight==li->backsector->ceilingheight ||
1512 (slope = FixedDiv (opentop - shootz , dist)) >= aimslope))
1513 return true; // shot continues
1514 }
1515
1516 // hit line
1517 // position a bit closer
1518
1519 frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
1520 x = trace.x + FixedMul (trace.dx, frac);
1521 y = trace.y + FixedMul (trace.dy, frac);
1522 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
1523
1524 if (li->frontsector->ceilingpic == skyflatnum)
1525 {
1526 // don't shoot the sky!
1527
1528 if (z > li->frontsector->ceilingheight)
1529 return false;
1530
1531 // it's a sky hack wall
1532
1533 if (li->backsector && li->backsector->ceilingpic == skyflatnum)
1534
1535 // fix bullet-eaters -- killough:
1536 // WARNING: Almost all demos will lose sync without this
1537 // demo_compatibility flag check!!! killough 1/18/98
1538 if (demo_compatibility || li->backsector->ceilingheight < z)
1539 return false;
1540 }
1541
1542 // Spawn bullet puffs.
1543
1544 P_SpawnPuff (x,y,z);
1545
1546 // don't go any farther
1547
1548 return false;
1549 }
1550
1551 // shoot a thing
1552
1553 th = in->d.thing;
1554 if (th == shootthing)
1555 return true; // can't shoot self
1556
1557 if (!(th->flags&MF_SHOOTABLE))
1558 return true; // corpse or something
1559
1560 // check angles to see if the thing can be aimed at
1561
1562 dist = FixedMul (attackrange, in->frac);
1563 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1564
1565 if (thingtopslope < aimslope)
1566 return true; // shot over the thing
1567
1568 thingbottomslope = FixedDiv (th->z - shootz, dist);
1569
1570 if (thingbottomslope > aimslope)
1571 return true; // shot under the thing
1572
1573 // hit thing
1574 // position a bit closer
1575
1576 frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
1577
1578 x = trace.x + FixedMul (trace.dx, frac);
1579 y = trace.y + FixedMul (trace.dy, frac);
1580 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
1581
1582 // Spawn bullet puffs or blod spots,
1583 // depending on target type.
1584 if (in->d.thing->flags & MF_NOBLOOD)
1585 P_SpawnPuff (x,y,z);
1586 else
1587 P_SpawnBlood (x,y,z, la_damage);
1588
1589 if (la_damage)
1590 P_DamageMobj (th, shootthing, shootthing, la_damage);
1591
1592 // don't go any farther
1593 return false;
1594 }
1595
1596
1597//
1598// P_AimLineAttack
1599//
1600fixed_t P_AimLineAttack(mobj_t* t1,angle_t angle,fixed_t distance, uint_64_t mask)
1601 {
1602 fixed_t x2;
1603 fixed_t y2;
1604
1605 angle >>= ANGLETOFINESHIFT;
1606 shootthing = t1;
1607
1608 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1609 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1610 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1611
1612 // can't shoot outside view angles
1613
1614 topslope = 100*FRACUNIT/160;
1615 bottomslope = -100*FRACUNIT/160;
1616
1617 attackrange = distance;
1618 linetarget = NULL;
1619
1620 /* killough 8/2/98: prevent friends from aiming at friends */
1621 aim_flags_mask = mask;
1622
1623 P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_AimTraverse);
1624
1625 if (linetarget)
1626 return aimslope;
1627
1628 return 0;
1629 }
1630
1631
1632//
1633// P_LineAttack
1634// If damage == 0, it is just a test trace
1635// that will leave linetarget set.
1636//
1637
1638void P_LineAttack
1639(mobj_t* t1,
1640 angle_t angle,
1641 fixed_t distance,
1642 fixed_t slope,
1643 int damage)
1644 {
1645 fixed_t x2;
1646 fixed_t y2;
1647
1648 angle >>= ANGLETOFINESHIFT;
1649 shootthing = t1;
1650 la_damage = damage;
1651 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1652 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1653 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1654 attackrange = distance;
1655 aimslope = slope;
1656
1657 P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_ShootTraverse);
1658 }
1659
1660
1661//
1662// USE LINES
1663//
1664
1665mobj_t* usething;
1666
1667boolean PTR_UseTraverse (intercept_t* in)
1668 {
1669 int side;
1670
1671 if (!in->d.line->special)
1672 {
1673 P_LineOpening (in->d.line);
1674 if (openrange <= 0)
1675 {
1676 S_StartSound (usething, sfx_noway);
1677
1678 // can't use through a wall
1679 return false;
1680 }
1681
1682 // not a special line, but keep checking
1683
1684 return true;
1685 }
1686
1687 side = 0;
1688 if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
1689 side = 1;
1690
1691 // return false; // don't use back side
1692
1693 P_UseSpecialLine (usething, in->d.line, side);
1694
1695 //WAS can't use for than one special line in a row
1696 //jff 3/21/98 NOW multiple use allowed with enabling line flag
1697
1698 return (!demo_compatibility && (in->d.line->flags&ML_PASSUSE))?
1699 true : false;
1700}
1701
1702// Returns false if a "oof" sound should be made because of a blocking
1703// linedef. Makes 2s middles which are impassable, as well as 2s uppers
1704// and lowers which block the player, cause the sound effect when the
1705// player tries to activate them. Specials are excluded, although it is
1706// assumed that all special linedefs within reach have been considered
1707// and rejected already (see P_UseLines).
1708//
1709// by Lee Killough
1710//
1711
1712boolean PTR_NoWayTraverse(intercept_t* in)
1713 {
1714 line_t *ld = in->d.line;
1715 // This linedef
1716 return ld->special || !( // Ignore specials
1717 ld->flags & ML_BLOCKING || ( // Always blocking
1718 P_LineOpening(ld), // Find openings
1719 openrange <= 0 || // No opening
1720 openbottom > usething->z+24*FRACUNIT || // Too high it blocks
1721 opentop < usething->z+usething->height // Too low it blocks
1722 )
1723 );
1724 }
1725
1726//
1727// P_UseLines
1728// Looks for special lines in front of the player to activate.
1729//
1730void P_UseLines (player_t* player)
1731 {
1732 int angle;
1733 fixed_t x1;
1734 fixed_t y1;
1735 fixed_t x2;
1736 fixed_t y2;
1737
1738 usething = player->mo;
1739
1740 angle = player->mo->angle >> ANGLETOFINESHIFT;
1741
1742 x1 = player->mo->x;
1743 y1 = player->mo->y;
1744 x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
1745 y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
1746
1747 // old code:
1748 //
1749 // P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
1750 //
1751 // This added test makes the "oof" sound work on 2s lines -- killough:
1752
1753 if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ))
1754 if (!comp[comp_sound] && !P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse ))
1755 S_StartSound (usething, sfx_noway);
1756 }
1757
1758
1759//
1760// RADIUS ATTACK
1761//
1762
1763static mobj_t *bombsource, *bombspot;
1764static int bombdamage;
1765
1766
1767//
1768// PIT_RadiusAttack
1769// "bombsource" is the creature
1770// that caused the explosion at "bombspot".
1771//
1772
1773boolean PIT_RadiusAttack (mobj_t* thing)
1774 {
1775 fixed_t dx;
1776 fixed_t dy;
1777 fixed_t dist;
1778
1779 /* killough 8/20/98: allow bouncers to take damage
1780 * (missile bouncers are already excluded with MF_NOBLOCKMAP)
1781 */
1782
1783 if (!(thing->flags & (MF_SHOOTABLE | MF_BOUNCES)))
1784 return true;
1785
1786 // Boss spider and cyborg
1787 // take no damage from concussion.
1788
1789 // killough 8/10/98: allow grenades to hurt anyone, unless
1790 // fired by Cyberdemons, in which case it won't hurt Cybers.
1791
1792 if (bombspot->flags & MF_BOUNCES ?
1793 thing->type == MT_CYBORG && bombsource->type == MT_CYBORG :
1794 thing->type == MT_CYBORG || thing->type == MT_SPIDER)
1795 return true;
1796
1797 dx = D_abs(thing->x - bombspot->x);
1798 dy = D_abs(thing->y - bombspot->y);
1799
1800 dist = dx>dy ? dx : dy;
1801 dist = (dist - thing->radius) >> FRACBITS;
1802
1803 if (dist < 0)
1804 dist = 0;
1805
1806 if (dist >= bombdamage)
1807 return true; // out of range
1808
1809 if ( P_CheckSight (thing, bombspot) )
1810 {
1811 // must be in direct path
1812 P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
1813 }
1814
1815 return true;
1816 }
1817
1818
1819//
1820// P_RadiusAttack
1821// Source is the creature that caused the explosion at spot.
1822//
1823void P_RadiusAttack(mobj_t* spot,mobj_t* source,int damage)
1824 {
1825 int x;
1826 int y;
1827
1828 int xl;
1829 int xh;
1830 int yl;
1831 int yh;
1832
1833 fixed_t dist;
1834
1835 dist = (damage+MAXRADIUS)<<FRACBITS;
1836 yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
1837 yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
1838 xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
1839 xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
1840 bombspot = spot;
1841 bombsource = source;
1842 bombdamage = damage;
1843
1844 for (y=yl ; y<=yh ; y++)
1845 for (x=xl ; x<=xh ; x++)
1846 P_BlockThingsIterator (x, y, PIT_RadiusAttack );
1847 }
1848
1849
1850
1851//
1852// SECTOR HEIGHT CHANGING
1853// After modifying a sectors floor or ceiling height,
1854// call this routine to adjust the positions
1855// of all things that touch the sector.
1856//
1857// If anything doesn't fit anymore, true will be returned.
1858// If crunch is true, they will take damage
1859// as they are being crushed.
1860// If Crunch is false, you should set the sector height back
1861// the way it was and call P_ChangeSector again
1862// to undo the changes.
1863//
1864
1865static boolean crushchange, nofit;
1866
1867//
1868// PIT_ChangeSector
1869//
1870
1871boolean PIT_ChangeSector (mobj_t* thing)
1872 {
1873 mobj_t* mo;
1874
1875 if (P_ThingHeightClip (thing))
1876 return true; // keep checking
1877
1878 // crunch bodies to giblets
1879
1880 if (thing->health <= 0)
1881 {
1882 P_SetMobjState (thing, S_GIBS);
1883
1884 thing->flags &= ~MF_SOLID;
1885 thing->height = 0;
1886 thing->radius = 0;
1887 return true; // keep checking
1888 }
1889
1890 // crunch dropped items
1891
1892 if (thing->flags & MF_DROPPED)
1893 {
1894 P_RemoveMobj (thing);
1895
1896 // keep checking
1897 return true;
1898 }
1899
1900 /* killough 11/98: kill touchy things immediately */
1901 if (thing->flags & MF_TOUCHY &&
1902 (thing->intflags & MIF_ARMED || sentient(thing)))
1903 {
1904 P_DamageMobj(thing, NULL, NULL, thing->health); // kill object
1905 return true; // keep checking
1906 }
1907
1908 if (! (thing->flags & MF_SHOOTABLE) )
1909 {
1910 // assume it is bloody gibs or something
1911 return true;
1912 }
1913
1914 nofit = true;
1915
1916 if (crushchange && !(leveltime&3)) {
1917 int t;
1918 P_DamageMobj(thing,NULL,NULL,10);
1919
1920 // spray blood in a random direction
1921 mo = P_SpawnMobj (thing->x,
1922 thing->y,
1923 thing->z + thing->height/2, MT_BLOOD);
1924
1925 /* killough 8/10/98: remove dependence on order of evaluation */
1926 t = P_Random(pr_crush);
1927 mo->momx = (t - P_Random (pr_crush))<<12;
1928 t = P_Random(pr_crush);
1929 mo->momy = (t - P_Random (pr_crush))<<12;
1930 }
1931
1932 // keep checking (crush other things)
1933 return true;
1934 }
1935
1936
1937//
1938// P_ChangeSector
1939//
1940boolean P_ChangeSector(sector_t* sector,boolean crunch)
1941 {
1942 int x;
1943 int y;
1944
1945 nofit = false;
1946 crushchange = crunch;
1947
1948 // ARRGGHHH!!!!
1949 // This is horrendously slow!!!
1950 // killough 3/14/98
1951
1952 // re-check heights for all things near the moving sector
1953
1954 for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
1955 for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
1956 P_BlockThingsIterator (x, y, PIT_ChangeSector);
1957
1958 return nofit;
1959 }
1960
1961//
1962// P_CheckSector
1963// jff 3/19/98 added to just check monsters on the periphery
1964// of a moving sector instead of all in bounding box of the
1965// sector. Both more accurate and faster.
1966//
1967
1968boolean P_CheckSector(sector_t* sector,boolean crunch)
1969 {
1970 msecnode_t *n;
1971
1972 if (comp[comp_floors]) /* use the old routine for old demos though */
1973 return P_ChangeSector(sector,crunch);
1974
1975 nofit = false;
1976 crushchange = crunch;
1977
1978 // killough 4/4/98: scan list front-to-back until empty or exhausted,
1979 // restarting from beginning after each thing is processed. Avoids
1980 // crashes, and is sure to examine all things in the sector, and only
1981 // the things which are in the sector, until a steady-state is reached.
1982 // Things can arbitrarily be inserted and removed and it won't mess up.
1983 //
1984 // killough 4/7/98: simplified to avoid using complicated counter
1985
1986 // Mark all things invalid
1987
1988 for (n=sector->touching_thinglist; n; n=n->m_snext)
1989 n->visited = false;
1990
1991 do
1992 for (n=sector->touching_thinglist; n; n=n->m_snext) // go through list
1993 if (!n->visited) // unprocessed thing found
1994 {
1995 n->visited = true; // mark thing as processed
1996 if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these
1997 PIT_ChangeSector(n->m_thing); // process it
1998 break; // exit and start over
1999 }
2000 while (n); // repeat from scratch until all things left are marked valid
2001
2002 return nofit;
2003 }
2004
2005
2006// CPhipps -
2007// Use block memory allocator here
2008
2009#include "z_bmalloc.h"
2010
2011IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(secnodezone, sizeof(msecnode_t), PU_LEVEL, 32, "SecNodes");
2012
2013inline static msecnode_t* P_GetSecnode(void)
2014{
2015 return (msecnode_t*)Z_BMalloc(&secnodezone);
2016}
2017
2018// P_PutSecnode() returns a node to the freelist.
2019
2020inline static void P_PutSecnode(msecnode_t* node)
2021{
2022 Z_BFree(&secnodezone, node);
2023}
2024
2025// phares 3/16/98
2026//
2027// P_AddSecnode() searches the current list to see if this sector is
2028// already there. If not, it adds a sector node at the head of the list of
2029// sectors this object appears in. This is called when creating a list of
2030// nodes that will get linked in later. Returns a pointer to the new node.
2031
2032msecnode_t* P_AddSecnode(sector_t* s, mobj_t* thing, msecnode_t* nextnode)
2033 {
2034 msecnode_t* node;
2035
2036 node = nextnode;
2037 while (node)
2038 {
2039 if (node->m_sector == s) // Already have a node for this sector?
2040 {
2041 node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
2042 return(nextnode);
2043 }
2044 node = node->m_tnext;
2045 }
2046
2047 // Couldn't find an existing node for this sector. Add one at the head
2048 // of the list.
2049
2050 node = P_GetSecnode();
2051
2052 // killough 4/4/98, 4/7/98: mark new nodes unvisited.
2053 node->visited = 0;
2054
2055 node->m_sector = s; // sector
2056 node->m_thing = thing; // mobj
2057 node->m_tprev = NULL; // prev node on Thing thread
2058 node->m_tnext = nextnode; // next node on Thing thread
2059 if (nextnode)
2060 nextnode->m_tprev = node; // set back link on Thing
2061
2062 // Add new node at head of sector thread starting at s->touching_thinglist
2063
2064 node->m_sprev = NULL; // prev node on sector thread
2065 node->m_snext = s->touching_thinglist; // next node on sector thread
2066 if (s->touching_thinglist)
2067 node->m_snext->m_sprev = node;
2068 s->touching_thinglist = node;
2069 return(node);
2070 }
2071
2072
2073// P_DelSecnode() deletes a sector node from the list of
2074// sectors this object appears in. Returns a pointer to the next node
2075// on the linked list, or NULL.
2076
2077msecnode_t* P_DelSecnode(msecnode_t* node)
2078 {
2079 msecnode_t* tp; // prev node on thing thread
2080 msecnode_t* tn; // next node on thing thread
2081 msecnode_t* sp; // prev node on sector thread
2082 msecnode_t* sn; // next node on sector thread
2083
2084 if (node)
2085 {
2086
2087 // Unlink from the Thing thread. The Thing thread begins at
2088 // sector_list and not from mobj_t->touching_sectorlist.
2089
2090 tp = node->m_tprev;
2091 tn = node->m_tnext;
2092 if (tp)
2093 tp->m_tnext = tn;
2094 if (tn)
2095 tn->m_tprev = tp;
2096
2097 // Unlink from the sector thread. This thread begins at
2098 // sector_t->touching_thinglist.
2099
2100 sp = node->m_sprev;
2101 sn = node->m_snext;
2102 if (sp)
2103 sp->m_snext = sn;
2104 else
2105 node->m_sector->touching_thinglist = sn;
2106 if (sn)
2107 sn->m_sprev = sp;
2108
2109 // Return this node to the freelist
2110
2111 P_PutSecnode(node);
2112 return(tn);
2113 }
2114 return(NULL);
2115 } // phares 3/13/98
2116
2117// Delete an entire sector list
2118
2119void P_DelSeclist(msecnode_t* node)
2120
2121 {
2122 while (node)
2123 node = P_DelSecnode(node);
2124 }
2125
2126
2127// phares 3/14/98
2128//
2129// PIT_GetSectors
2130// Locates all the sectors the object is in by looking at the lines that
2131// cross through it. You have already decided that the object is allowed
2132// at this location, so don't bother with checking impassable or
2133// blocking lines.
2134
2135boolean PIT_GetSectors(line_t* ld)
2136 {
2137 if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] ||
2138 tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] ||
2139 tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] ||
2140 tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
2141 return true;
2142
2143 if (P_BoxOnLineSide(tmbbox, ld) != -1)
2144 return true;
2145
2146 // This line crosses through the object.
2147
2148 // Collect the sector(s) from the line and add to the
2149 // sector_list you're examining. If the Thing ends up being
2150 // allowed to move to this position, then the sector_list
2151 // will be attached to the Thing's mobj_t at touching_sectorlist.
2152
2153 sector_list = P_AddSecnode(ld->frontsector,tmthing,sector_list);
2154
2155 /* Don't assume all lines are 2-sided, since some Things
2156 * like MT_TFOG are allowed regardless of whether their radius takes
2157 * them beyond an impassable linedef.
2158 *
2159 * killough 3/27/98, 4/4/98:
2160 * Use sidedefs instead of 2s flag to determine two-sidedness.
2161 * killough 8/1/98: avoid duplicate if same sector on both sides
2162 * cph - DEMOSYNC? */
2163
2164 if (ld->backsector && ld->backsector != ld->frontsector)
2165 sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list);
2166
2167 return true;
2168 }
2169
2170
2171// phares 3/14/98
2172//
2173// P_CreateSecNodeList alters/creates the sector_list that shows what sectors
2174// the object resides in.
2175
2176void P_CreateSecNodeList(mobj_t* thing,fixed_t x,fixed_t y)
2177{
2178 int xl;
2179 int xh;
2180 int yl;
2181 int yh;
2182 int bx;
2183 int by;
2184 msecnode_t* node;
2185 mobj_t* saved_tmthing = tmthing; /* cph - see comment at func end */
2186 fixed_t saved_tmx = tmx, saved_tmy = tmy; /* ditto */
2187
2188 // First, clear out the existing m_thing fields. As each node is
2189 // added or verified as needed, m_thing will be set properly. When
2190 // finished, delete all nodes where m_thing is still NULL. These
2191 // represent the sectors the Thing has vacated.
2192
2193 node = sector_list;
2194 while (node)
2195 {
2196 node->m_thing = NULL;
2197 node = node->m_tnext;
2198 }
2199
2200 tmthing = thing;
2201
2202 tmx = x;
2203 tmy = y;
2204
2205 tmbbox[BOXTOP] = y + tmthing->radius;
2206 tmbbox[BOXBOTTOM] = y - tmthing->radius;
2207 tmbbox[BOXRIGHT] = x + tmthing->radius;
2208 tmbbox[BOXLEFT] = x - tmthing->radius;
2209
2210 validcount++; // used to make sure we only process a line once
2211
2212 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
2213 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
2214 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
2215 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
2216
2217 for (bx=xl ; bx<=xh ; bx++)
2218 for (by=yl ; by<=yh ; by++)
2219 P_BlockLinesIterator(bx,by,PIT_GetSectors);
2220
2221 // Add the sector of the (x,y) point to sector_list.
2222
2223 sector_list = P_AddSecnode(thing->subsector->sector,thing,sector_list);
2224
2225 // Now delete any nodes that won't be used. These are the ones where
2226 // m_thing is still NULL.
2227
2228 node = sector_list;
2229 while (node)
2230 {
2231 if (node->m_thing == NULL)
2232 {
2233 if (node == sector_list)
2234 sector_list = node->m_tnext;
2235 node = P_DelSecnode(node);
2236 }
2237 else
2238 node = node->m_tnext;
2239 }
2240
2241 /* cph -
2242 * This is the strife we get into for using global variables. tmthing
2243 * is being used by several different functions calling
2244 * P_BlockThingIterator, including functions that can be called *from*
2245 * P_BlockThingIterator. Using a global tmthing is not reentrant.
2246 * OTOH for Boom/MBF demos we have to preserve the buggy behavior.
2247 * Fun. We restore its previous value unless we're in a Boom/MBF demo.
2248 */
2249 if ((compatibility_level < boom_compatibility_compatibility) ||
2250 (compatibility_level >= prboom_3_compatibility))
2251 tmthing = saved_tmthing;
2252 /* And, duh, the same for tmx/y - cph 2002/09/22
2253 * And for tmbbox - cph 2003/08/10 */
2254 if ((compatibility_level < boom_compatibility_compatibility) /* ||
2255 (compatibility_level >= prboom_4_compatibility) */) {
2256 tmx = saved_tmx, tmy = saved_tmy;
2257 if (tmthing) {
2258 tmbbox[BOXTOP] = tmy + tmthing->radius;
2259 tmbbox[BOXBOTTOM] = tmy - tmthing->radius;
2260 tmbbox[BOXRIGHT] = tmx + tmthing->radius;
2261 tmbbox[BOXLEFT] = tmx - tmthing->radius;
2262 }
2263 }
2264}
2265
2266/* cphipps 2004/08/30 -
2267 * 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. */
2268void P_MapStart(void) {
2269 if (tmthing) I_Error("P_MapStart: tmthing set!");
2270}
2271void P_MapEnd(void) {
2272 tmthing = NULL;
2273}
2274
2275// e6y
2276// Code to emulate the behavior of Vanilla Doom when encountering an overrun
2277// of the spechit array.
2278// No more desyncs on compet-n\hr.wad\hr18*.lmp, all strain.wad\map07 demos etc.
2279// http://www.doomworld.com/vb/showthread.php?s=&threadid=35214
2280static void SpechitOverrun(line_t *ld)
2281{
2282 //int addr = 0x01C09C98 + (ld - lines) * 0x3E;
2283 int addr = 0x00C09C98 + (ld - lines) * 0x3E;
2284
2285 if (compatibility_level == dosdoom_compatibility || compatibility_level == tasdoom_compatibility)
2286 {
2287 // e6y
2288 // There are no more desyncs in the following dosdoom demos:
2289 // flsofdth.wad\fod3uv.lmp - http://www.doomworld.com/sda/flsofdth.htm
2290 // hr.wad\hf181430.lmp - http://www.doomworld.com/tas/hf181430.zip
2291 // hr.wad\hr181329.lmp - http://www.doomworld.com/tas/hr181329.zip
2292 // icarus.wad\ic09uv.lmp - http://competn.doom2.net/pub/sda/i-o/icuvlmps.zip
2293
2294 switch(numspechit)
2295 {
2296 case 8: break; /* strange cph's code */
2297 case 9:
2298 tmfloorz = addr;
2299 break;
2300 case 10:
2301 tmceilingz = addr;
2302 break;
2303
2304 default:
2305 lprintf(LO_ERROR, "SpechitOverrun: Warning: unable to emulate"
2306 " an overrun where numspechit=%i\n",
2307 numspechit);
2308 break;
2309 }
2310 }
2311 else
2312 {
2313 switch(numspechit)
2314 {
2315 case 8: break; /* numspechit, not significant it seems - cph */
2316 case 9:
2317 case 10:
2318 case 11:
2319 case 12:
2320 tmbbox[numspechit-9] = addr;
2321 break;
2322 case 13:
2323 nofit = addr;
2324 break;
2325 case 14:
2326 crushchange = addr;
2327 break;
2328 default:
2329 lprintf(LO_ERROR, "SpechitOverrun: Warning: unable to emulate"
2330 " an overrun where numspechit=%i\n",
2331 numspechit);
2332 break;
2333 }
2334 }
2335}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Map functions
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __P_MAP__
35#define __P_MAP__
36
37#include "r_defs.h"
38#include "d_player.h"
39
40#define USERANGE (64*FRACUNIT)
41#define MELEERANGE (64*FRACUNIT)
42#define MISSILERANGE (32*64*FRACUNIT)
43
44// MAXRADIUS is for precalculated sector block boxes the spider demon
45// is larger, but we do not have any moving sectors nearby
46#define MAXRADIUS (32*FRACUNIT)
47
48// killough 3/15/98: add fourth argument to P_TryMove
49boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean dropoff);
50
51// killough 8/9/98: extra argument for telefragging
52boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y,boolean boss);
53void P_SlideMove(mobj_t *mo);
54boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
55void P_UseLines(player_t *player);
56
57// killough 8/2/98: add 'mask' argument to prevent friends autoaiming at others
58fixed_t P_AimLineAttack(mobj_t *t1,angle_t angle,fixed_t distance, uint_64_t mask);
59
60void P_LineAttack(mobj_t *t1, angle_t angle, fixed_t distance,
61 fixed_t slope, int damage );
62void P_RadiusAttack(mobj_t *spot, mobj_t *source, int damage);
63boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
64
65//jff 3/19/98 P_CheckSector(): new routine to replace P_ChangeSector()
66boolean P_ChangeSector(sector_t* sector,boolean crunch);
67boolean P_CheckSector(sector_t *sector, boolean crunch);
68void P_DelSeclist(msecnode_t*); // phares 3/16/98
69void P_CreateSecNodeList(mobj_t*,fixed_t,fixed_t); // phares 3/14/98
70boolean Check_Sides(mobj_t *, int, int); // phares
71
72int P_GetMoveFactor(const mobj_t *mo, int *friction); // killough 8/28/98
73int P_GetFriction(const mobj_t *mo, int *factor); // killough 8/28/98
74void P_ApplyTorque(mobj_t *mo); // killough 9/12/98
75
76/* cphipps 2004/08/30 */
77void P_MapStart(void);
78void P_MapEnd(void);
79
80// If "floatok" true, move would be ok if within "tmfloorz - tmceilingz".
81extern boolean floatok;
82extern boolean felldown; // killough 11/98: indicates object pushed off ledge
83extern fixed_t tmfloorz;
84extern fixed_t tmceilingz;
85extern line_t *ceilingline;
86extern line_t *floorline; // killough 8/23/98
87extern mobj_t *linetarget; // who got hit (or NULL)
88extern msecnode_t *sector_list; // phares 3/16/98
89extern fixed_t tmbbox[4]; // phares 3/20/98
90extern line_t *blockline; // killough 8/11/98
91
92#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Movement/collision utility functions,
31 * as used by function in p_map.c.
32 * BLOCKMAP Iterator functions,
33 * and some PIT_* functions to use for iteration.
34 *
35 *-----------------------------------------------------------------------------*/
36
37#include "doomstat.h"
38#include "m_bbox.h"
39#include "r_main.h"
40#include "p_maputl.h"
41#include "p_map.h"
42#include "p_setup.h"
43
44//
45// P_AproxDistance
46// Gives an estimation of distance (not exact)
47//
48
49fixed_t CONSTFUNC P_AproxDistance(fixed_t dx, fixed_t dy)
50{
51 dx = D_abs(dx);
52 dy = D_abs(dy);
53 if (dx < dy)
54 return dx+dy-(dx>>1);
55 return dx+dy-(dy>>1);
56}
57
58//
59// P_PointOnLineSide
60// Returns 0 or 1
61//
62// killough 5/3/98: reformatted, cleaned up
63
64int PUREFUNC P_PointOnLineSide(fixed_t x, fixed_t y, const line_t *line)
65{
66 return
67 !line->dx ? x <= line->v1->x ? line->dy > 0 : line->dy < 0 :
68 !line->dy ? y <= line->v1->y ? line->dx < 0 : line->dx > 0 :
69 FixedMul(y-line->v1->y, line->dx>>FRACBITS) >=
70 FixedMul(line->dy>>FRACBITS, x-line->v1->x);
71}
72
73//
74// P_BoxOnLineSide
75// Considers the line to be infinite
76// Returns side 0 or 1, -1 if box crosses the line.
77//
78// killough 5/3/98: reformatted, cleaned up
79
80int PUREFUNC P_BoxOnLineSide(const fixed_t *tmbox, const line_t *ld)
81{
82 switch (ld->slopetype)
83 {
84 int p;
85 default: // shut up compiler warnings -- killough
86 case ST_HORIZONTAL:
87 return
88 (tmbox[BOXBOTTOM] > ld->v1->y) == (p = tmbox[BOXTOP] > ld->v1->y) ?
89 p ^ (ld->dx < 0) : -1;
90 case ST_VERTICAL:
91 return
92 (tmbox[BOXLEFT] < ld->v1->x) == (p = tmbox[BOXRIGHT] < ld->v1->x) ?
93 p ^ (ld->dy < 0) : -1;
94 case ST_POSITIVE:
95 return
96 P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld) ==
97 (p = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld)) ? p : -1;
98 case ST_NEGATIVE:
99 return
100 (P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld)) ==
101 (p = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld)) ? p : -1;
102 }
103}
104
105//
106// P_PointOnDivlineSide
107// Returns 0 or 1.
108//
109// killough 5/3/98: reformatted, cleaned up
110
111static int PUREFUNC P_PointOnDivlineSide(fixed_t x, fixed_t y, const divline_t *line)
112{
113 return
114 !line->dx ? x <= line->x ? line->dy > 0 : line->dy < 0 :
115 !line->dy ? y <= line->y ? line->dx < 0 : line->dx > 0 :
116 (line->dy^line->dx^(x -= line->x)^(y -= line->y)) < 0 ? (line->dy^x) < 0 :
117 FixedMul(y>>8, line->dx>>8) >= FixedMul(line->dy>>8, x>>8);
118}
119
120//
121// P_MakeDivline
122//
123
124static void P_MakeDivline(const line_t *li, divline_t *dl)
125{
126 dl->x = li->v1->x;
127 dl->y = li->v1->y;
128 dl->dx = li->dx;
129 dl->dy = li->dy;
130}
131
132//
133// P_InterceptVector
134// Returns the fractional intercept point
135// along the first divline.
136// This is only called by the addthings
137// and addlines traversers.
138//
139
140/* cph - this is killough's 4/19/98 version of P_InterceptVector and
141 * P_InterceptVector2 (which were interchangeable). We still use this
142 * in compatibility mode. */
143fixed_t PUREFUNC P_InterceptVector2(const divline_t *v2, const divline_t *v1)
144{
145 fixed_t den;
146 return (den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy)) ?
147 FixedDiv(FixedMul((v1->x - v2->x)>>8, v1->dy) +
148 FixedMul((v2->y - v1->y)>>8, v1->dx), den) : 0;
149}
150
151fixed_t PUREFUNC P_InterceptVector(const divline_t *v2, const divline_t *v1)
152{
153 if (compatibility_level < prboom_4_compatibility)
154 return P_InterceptVector2(v2, v1);
155 else {
156 /* cph - This was introduced at prboom_4_compatibility - no precision/overflow problems */
157 int_64_t den = (int_64_t)v1->dy * v2->dx - (int_64_t)v1->dx * v2->dy;
158 den >>= 16;
159 if (!den)
160 return 0;
161 return (fixed_t)(((int_64_t)(v1->x - v2->x) * v1->dy - (int_64_t)(v1->y - v2->y) * v1->dx) / den);
162 }
163}
164
165//
166// P_LineOpening
167// Sets opentop and openbottom to the window
168// through a two sided line.
169// OPTIMIZE: keep this precalculated
170//
171
172fixed_t opentop;
173fixed_t openbottom;
174fixed_t openrange;
175fixed_t lowfloor;
176
177// moved front and back outside P-LineOpening and changed // phares 3/7/98
178// them to these so we can pick up the new friction value
179// in PIT_CheckLine()
180sector_t *openfrontsector; // made global // phares
181sector_t *openbacksector; // made global
182
183void P_LineOpening(const line_t *linedef)
184{
185 if (linedef->sidenum[1] == NO_INDEX) // single sided line
186 {
187 openrange = 0;
188 return;
189 }
190
191 openfrontsector = linedef->frontsector;
192 openbacksector = linedef->backsector;
193
194 if (openfrontsector->ceilingheight < openbacksector->ceilingheight)
195 opentop = openfrontsector->ceilingheight;
196 else
197 opentop = openbacksector->ceilingheight;
198
199 if (openfrontsector->floorheight > openbacksector->floorheight)
200 {
201 openbottom = openfrontsector->floorheight;
202 lowfloor = openbacksector->floorheight;
203 }
204 else
205 {
206 openbottom = openbacksector->floorheight;
207 lowfloor = openfrontsector->floorheight;
208 }
209 openrange = opentop - openbottom;
210}
211
212//
213// THING POSITION SETTING
214//
215
216//
217// P_UnsetThingPosition
218// Unlinks a thing from block map and sectors.
219// On each position change, BLOCKMAP and other
220// lookups maintaining lists ot things inside
221// these structures need to be updated.
222//
223
224void P_UnsetThingPosition (mobj_t *thing)
225{
226 if (!(thing->flags & MF_NOSECTOR))
227 {
228 /* invisible things don't need to be in sector list
229 * unlink from subsector
230 *
231 * killough 8/11/98: simpler scheme using pointers-to-pointers for prev
232 * pointers, allows head node pointers to be treated like everything else
233 */
234
235 mobj_t **sprev = thing->sprev;
236 mobj_t *snext = thing->snext;
237 if ((*sprev = snext)) // unlink from sector list
238 snext->sprev = sprev;
239
240 // phares 3/14/98
241 //
242 // Save the sector list pointed to by touching_sectorlist.
243 // In P_SetThingPosition, we'll keep any nodes that represent
244 // sectors the Thing still touches. We'll add new ones then, and
245 // delete any nodes for sectors the Thing has vacated. Then we'll
246 // put it back into touching_sectorlist. It's done this way to
247 // avoid a lot of deleting/creating for nodes, when most of the
248 // time you just get back what you deleted anyway.
249 //
250 // If this Thing is being removed entirely, then the calling
251 // routine will clear out the nodes in sector_list.
252
253 sector_list = thing->touching_sectorlist;
254 thing->touching_sectorlist = NULL; //to be restored by P_SetThingPosition
255 }
256
257 if (!(thing->flags & MF_NOBLOCKMAP))
258 {
259 /* inert things don't need to be in blockmap
260 *
261 * killough 8/11/98: simpler scheme using pointers-to-pointers for prev
262 * pointers, allows head node pointers to be treated like everything else
263 *
264 * Also more robust, since it doesn't depend on current position for
265 * unlinking. Old method required computing head node based on position
266 * at time of unlinking, assuming it was the same position as during
267 * linking.
268 */
269
270 mobj_t *bnext, **bprev = thing->bprev;
271 if (bprev && (*bprev = bnext = thing->bnext)) // unlink from block map
272 bnext->bprev = bprev;
273 }
274}
275
276//
277// P_SetThingPosition
278// Links a thing into both a block and a subsector
279// based on it's x y.
280// Sets thing->subsector properly
281//
282// killough 5/3/98: reformatted, cleaned up
283
284void P_SetThingPosition(mobj_t *thing)
285{ // link into subsector
286 subsector_t *ss = thing->subsector = R_PointInSubsector(thing->x, thing->y);
287 if (!(thing->flags & MF_NOSECTOR))
288 {
289 // invisible things don't go into the sector links
290
291 // killough 8/11/98: simpler scheme using pointer-to-pointer prev
292 // pointers, allows head nodes to be treated like everything else
293
294 mobj_t **link = &ss->sector->thinglist;
295 mobj_t *snext = *link;
296 if ((thing->snext = snext))
297 snext->sprev = &thing->snext;
298 thing->sprev = link;
299 *link = thing;
300
301 // phares 3/16/98
302 //
303 // If sector_list isn't NULL, it has a collection of sector
304 // nodes that were just removed from this Thing.
305
306 // Collect the sectors the object will live in by looking at
307 // the existing sector_list and adding new nodes and deleting
308 // obsolete ones.
309
310 // When a node is deleted, its sector links (the links starting
311 // at sector_t->touching_thinglist) are broken. When a node is
312 // added, new sector links are created.
313
314 P_CreateSecNodeList(thing,thing->x,thing->y);
315 thing->touching_sectorlist = sector_list; // Attach to Thing's mobj_t
316 sector_list = NULL; // clear for next time
317 }
318
319 // link into blockmap
320 if (!(thing->flags & MF_NOBLOCKMAP))
321 {
322 // inert things don't need to be in blockmap
323 int blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
324 int blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
325 if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight)
326 {
327 // killough 8/11/98: simpler scheme using pointer-to-pointer prev
328 // pointers, allows head nodes to be treated like everything else
329
330 mobj_t **link = &blocklinks[blocky*bmapwidth+blockx];
331 mobj_t *bnext = *link;
332 if ((thing->bnext = bnext))
333 bnext->bprev = &thing->bnext;
334 thing->bprev = link;
335 *link = thing;
336 }
337 else // thing is off the map
338 thing->bnext = NULL, thing->bprev = NULL;
339 }
340}
341
342//
343// BLOCK MAP ITERATORS
344// For each line/thing in the given mapblock,
345// call the passed PIT_* function.
346// If the function returns false,
347// exit with false without checking anything else.
348//
349
350//
351// P_BlockLinesIterator
352// The validcount flags are used to avoid checking lines
353// that are marked in multiple mapblocks,
354// so increment validcount before the first call
355// to P_BlockLinesIterator, then make one or more calls
356// to it.
357//
358// killough 5/3/98: reformatted, cleaned up
359
360boolean P_BlockLinesIterator(int x, int y, boolean func(line_t*))
361{
362 int offset;
363 const long *list; // killough 3/1/98: for removal of blockmap limit
364
365 if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
366 return true;
367 offset = y*bmapwidth+x;
368 offset = *(blockmap+offset);
369 list = blockmaplump+offset; // original was reading // phares
370 // delmiting 0 as linedef 0 // phares
371
372 // killough 1/31/98: for compatibility we need to use the old method.
373 // Most demos go out of sync, and maybe other problems happen, if we
374 // don't consider linedef 0. For safety this should be qualified.
375
376 if (!demo_compatibility) // killough 2/22/98: demo_compatibility check
377 list++; // skip 0 starting delimiter // phares
378 for ( ; *list != -1 ; list++) // phares
379 {
380 line_t *ld = &lines[*list];
381 if (ld->validcount == validcount)
382 continue; // line has already been checked
383 ld->validcount = validcount;
384 if (!func(ld))
385 return false;
386 }
387 return true; // everything was checked
388}
389
390//
391// P_BlockThingsIterator
392//
393// killough 5/3/98: reformatted, cleaned up
394
395boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t*))
396{
397 mobj_t *mobj;
398 if (!(x<0 || y<0 || x>=bmapwidth || y>=bmapheight))
399 for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext)
400 if (!func(mobj))
401 return false;
402 return true;
403}
404
405//
406// INTERCEPT ROUTINES
407//
408
409// 1/11/98 killough: Intercept limit removed
410static intercept_t *intercepts, *intercept_p;
411
412// Check for limit and double size if necessary -- killough
413static void check_intercept(void)
414{
415 static size_t num_intercepts;
416 size_t offset = intercept_p - intercepts;
417 if (offset >= num_intercepts)
418 {
419 num_intercepts = num_intercepts ? num_intercepts*2 : 128;
420 intercepts = realloc(intercepts, sizeof(*intercepts)*num_intercepts);
421 intercept_p = intercepts + offset;
422 }
423}
424
425divline_t trace;
426
427// PIT_AddLineIntercepts.
428// Looks for lines in the given block
429// that intercept the given trace
430// to add to the intercepts list.
431//
432// A line is crossed if its endpoints
433// are on opposite sides of the trace.
434//
435// killough 5/3/98: reformatted, cleaned up
436
437boolean PIT_AddLineIntercepts(line_t *ld)
438{
439 int s1;
440 int s2;
441 fixed_t frac;
442 divline_t dl;
443
444 // avoid precision problems with two routines
445 if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 ||
446 trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
447 {
448 s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
449 s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
450 }
451 else
452 {
453 s1 = P_PointOnLineSide (trace.x, trace.y, ld);
454 s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld);
455 }
456
457 if (s1 == s2)
458 return true; // line isn't crossed
459
460 // hit the line
461 P_MakeDivline(ld, &dl);
462 frac = P_InterceptVector(&trace, &dl);
463
464 if (frac < 0)
465 return true; // behind source
466
467 check_intercept(); // killough
468
469 intercept_p->frac = frac;
470 intercept_p->isaline = true;
471 intercept_p->d.line = ld;
472 intercept_p++;
473
474 return true; // continue
475}
476
477//
478// PIT_AddThingIntercepts
479//
480// killough 5/3/98: reformatted, cleaned up
481
482boolean PIT_AddThingIntercepts(mobj_t *thing)
483{
484 fixed_t x1, y1;
485 fixed_t x2, y2;
486 int s1, s2;
487 divline_t dl;
488 fixed_t frac;
489
490 // check a corner to corner crossection for hit
491 if ((trace.dx ^ trace.dy) > 0)
492 {
493 x1 = thing->x - thing->radius;
494 y1 = thing->y + thing->radius;
495 x2 = thing->x + thing->radius;
496 y2 = thing->y - thing->radius;
497 }
498 else
499 {
500 x1 = thing->x - thing->radius;
501 y1 = thing->y - thing->radius;
502 x2 = thing->x + thing->radius;
503 y2 = thing->y + thing->radius;
504 }
505
506 s1 = P_PointOnDivlineSide (x1, y1, &trace);
507 s2 = P_PointOnDivlineSide (x2, y2, &trace);
508
509 if (s1 == s2)
510 return true; // line isn't crossed
511
512 dl.x = x1;
513 dl.y = y1;
514 dl.dx = x2-x1;
515 dl.dy = y2-y1;
516
517 frac = P_InterceptVector (&trace, &dl);
518
519 if (frac < 0)
520 return true; // behind source
521
522 check_intercept(); // killough
523
524 intercept_p->frac = frac;
525 intercept_p->isaline = false;
526 intercept_p->d.thing = thing;
527 intercept_p++;
528
529 return true; // keep going
530}
531
532//
533// P_TraverseIntercepts
534// Returns true if the traverser function returns true
535// for all lines.
536//
537// killough 5/3/98: reformatted, cleaned up
538
539boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac)
540{
541 intercept_t *in = NULL;
542 int count = intercept_p - intercepts;
543 while (count--)
544 {
545 fixed_t dist = INT_MAX;
546 intercept_t *scan;
547 for (scan = intercepts; scan < intercept_p; scan++)
548 if (scan->frac < dist)
549 dist = (in=scan)->frac;
550 if (dist > maxfrac)
551 return true; // checked everything in range
552 if (!func(in))
553 return false; // don't bother going farther
554 in->frac = INT_MAX;
555 }
556 return true; // everything was traversed
557}
558
559//
560// P_PathTraverse
561// Traces a line from x1,y1 to x2,y2,
562// calling the traverser function for each.
563// Returns true if the traverser function returns true
564// for all lines.
565//
566// killough 5/3/98: reformatted, cleaned up
567
568boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
569 int flags, boolean trav(intercept_t *))
570{
571 fixed_t xt1, yt1;
572 fixed_t xt2, yt2;
573 fixed_t xstep, ystep;
574 fixed_t partial;
575 fixed_t xintercept, yintercept;
576 int mapx, mapy;
577 int mapxstep, mapystep;
578 int count;
579
580 validcount++;
581 intercept_p = intercepts;
582
583 if (!((x1-bmaporgx)&(MAPBLOCKSIZE-1)))
584 x1 += FRACUNIT; // don't side exactly on a line
585
586 if (!((y1-bmaporgy)&(MAPBLOCKSIZE-1)))
587 y1 += FRACUNIT; // don't side exactly on a line
588
589 trace.x = x1;
590 trace.y = y1;
591 trace.dx = x2 - x1;
592 trace.dy = y2 - y1;
593
594 x1 -= bmaporgx;
595 y1 -= bmaporgy;
596 xt1 = x1>>MAPBLOCKSHIFT;
597 yt1 = y1>>MAPBLOCKSHIFT;
598
599 x2 -= bmaporgx;
600 y2 -= bmaporgy;
601 xt2 = x2>>MAPBLOCKSHIFT;
602 yt2 = y2>>MAPBLOCKSHIFT;
603
604 if (xt2 > xt1)
605 {
606 mapxstep = 1;
607 partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
608 ystep = FixedDiv (y2-y1,D_abs(x2-x1));
609 }
610 else
611 if (xt2 < xt1)
612 {
613 mapxstep = -1;
614 partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
615 ystep = FixedDiv (y2-y1,D_abs(x2-x1));
616 }
617 else
618 {
619 mapxstep = 0;
620 partial = FRACUNIT;
621 ystep = 256*FRACUNIT;
622 }
623
624 yintercept = (y1>>MAPBTOFRAC) + FixedMul(partial, ystep);
625
626 if (yt2 > yt1)
627 {
628 mapystep = 1;
629 partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
630 xstep = FixedDiv (x2-x1,D_abs(y2-y1));
631 }
632 else
633 if (yt2 < yt1)
634 {
635 mapystep = -1;
636 partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
637 xstep = FixedDiv (x2-x1,D_abs(y2-y1));
638 }
639 else
640 {
641 mapystep = 0;
642 partial = FRACUNIT;
643 xstep = 256*FRACUNIT;
644 }
645
646 xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
647
648 // Step through map blocks.
649 // Count is present to prevent a round off error
650 // from skipping the break.
651
652 mapx = xt1;
653 mapy = yt1;
654
655 for (count = 0; count < 64; count++)
656 {
657 if (flags & PT_ADDLINES)
658 if (!P_BlockLinesIterator(mapx, mapy,PIT_AddLineIntercepts))
659 return false; // early out
660
661 if (flags & PT_ADDTHINGS)
662 if (!P_BlockThingsIterator(mapx, mapy,PIT_AddThingIntercepts))
663 return false; // early out
664
665 if (mapx == xt2 && mapy == yt2)
666 break;
667
668 if ((yintercept >> FRACBITS) == mapy)
669 {
670 yintercept += ystep;
671 mapx += mapxstep;
672 }
673 else
674 if ((xintercept >> FRACBITS) == mapx)
675 {
676 xintercept += xstep;
677 mapy += mapystep;
678 }
679 }
680
681 // go through the sorted list
682 return P_TraverseIntercepts(trav, FRACUNIT);
683}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Map utility functions
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __P_MAPUTL__
35#define __P_MAPUTL__
36
37#include "r_defs.h"
38
39/* mapblocks are used to check movement against lines and things */
40#define MAPBLOCKUNITS 128
41#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT)
42#define MAPBLOCKSHIFT (FRACBITS+7)
43#define MAPBMASK (MAPBLOCKSIZE-1)
44#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS)
45
46#define PT_ADDLINES 1
47#define PT_ADDTHINGS 2
48#define PT_EARLYOUT 4
49
50typedef struct {
51 fixed_t x;
52 fixed_t y;
53 fixed_t dx;
54 fixed_t dy;
55} divline_t;
56
57typedef struct {
58 fixed_t frac; /* along trace line */
59 boolean isaline;
60 union {
61 mobj_t* thing;
62 line_t* line;
63 } d;
64} intercept_t;
65
66typedef boolean (*traverser_t)(intercept_t *in);
67
68fixed_t CONSTFUNC P_AproxDistance (fixed_t dx, fixed_t dy);
69int PUREFUNC P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line);
70int PUREFUNC P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld);
71fixed_t PUREFUNC P_InterceptVector (const divline_t *v2, const divline_t *v1);
72/* cph - old compatibility version below */
73fixed_t PUREFUNC P_InterceptVector2(const divline_t *v2, const divline_t *v1);
74
75void P_LineOpening (const line_t *linedef);
76void P_UnsetThingPosition(mobj_t *thing);
77void P_SetThingPosition(mobj_t *thing);
78boolean P_BlockLinesIterator (int x, int y, boolean func(line_t *));
79boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t *));
80boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
81 int flags, boolean trav(intercept_t *));
82
83extern fixed_t opentop;
84extern fixed_t openbottom;
85extern fixed_t openrange;
86extern fixed_t lowfloor;
87extern divline_t trace;
88
89#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2004 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Moving object handling. Spawn functions.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomdef.h"
35#include "doomstat.h"
36#include "m_random.h"
37#include "r_main.h"
38#include "p_maputl.h"
39#include "p_map.h"
40#include "p_tick.h"
41#include "sounds.h"
42#include "st_stuff.h"
43#include "hu_stuff.h"
44#include "s_sound.h"
45#include "info.h"
46#include "g_game.h"
47#include "p_inter.h"
48#include "lprintf.h"
49#include "r_demo.h"
50
51//
52// P_SetMobjState
53// Returns true if the mobj is still present.
54//
55
56boolean P_SetMobjState(mobj_t* mobj,statenum_t state)
57 {
58 state_t* st;
59
60 // killough 4/9/98: remember states seen, to detect cycles:
61
62 static statenum_t seenstate_tab[NUMSTATES]; // fast transition table
63 statenum_t *seenstate = seenstate_tab; // pointer to table
64 static int recursion; // detects recursion
65 statenum_t i = state; // initial state
66 boolean ret = true; // return value
67 statenum_t tempstate[NUMSTATES]; // for use with recursion
68
69 if (recursion++) // if recursion detected,
70 memset(seenstate=tempstate,0,sizeof tempstate); // clear state table
71
72 do
73 {
74 if (state == S_NULL)
75 {
76 mobj->state = (state_t *) S_NULL;
77 P_RemoveMobj (mobj);
78 ret = false;
79 break; // killough 4/9/98
80 }
81
82 st = &states[state];
83 mobj->state = st;
84 mobj->tics = st->tics;
85 mobj->sprite = st->sprite;
86 mobj->frame = st->frame;
87
88 // Modified handling.
89 // Call action functions when the state is set
90
91 if (st->action)
92 st->action(mobj);
93
94 seenstate[state] = 1 + st->nextstate; // killough 4/9/98
95
96 state = st->nextstate;
97 } while (!mobj->tics && !seenstate[state]); // killough 4/9/98
98
99 if (ret && !mobj->tics) // killough 4/9/98: detect state cycles
100 doom_printf("Warning: State Cycle Detected");
101
102 if (!--recursion)
103 for (;(state=seenstate[i]);i=state-1)
104 seenstate[i] = 0; // killough 4/9/98: erase memory of states
105
106 return ret;
107 }
108
109
110//
111// P_ExplodeMissile
112//
113
114void P_ExplodeMissile (mobj_t* mo)
115 {
116 mo->momx = mo->momy = mo->momz = 0;
117
118 P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
119
120 mo->tics -= P_Random(pr_explode)&3;
121
122 if (mo->tics < 1)
123 mo->tics = 1;
124
125 mo->flags &= ~MF_MISSILE;
126
127 if (mo->info->deathsound)
128 S_StartSound (mo, mo->info->deathsound);
129 }
130
131
132//
133// P_XYMovement
134//
135// Attempts to move something if it has momentum.
136//
137
138static void P_XYMovement (mobj_t* mo)
139 {
140 player_t *player;
141 fixed_t xmove, ymove;
142
143 //e6y
144 fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice
145
146#if 0
147 fixed_t ptryx;
148 fixed_t ptryy;
149 fixed_t xmove;
150 fixed_t ymove;
151 fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice
152 // when up against walls
153#endif
154 if (!(mo->momx | mo->momy)) // Any momentum?
155 {
156 if (mo->flags & MF_SKULLFLY)
157 {
158
159 // the skull slammed into something
160
161 mo->flags &= ~MF_SKULLFLY;
162 mo->momz = 0;
163
164 P_SetMobjState (mo, mo->info->spawnstate);
165 }
166 return;
167 }
168
169 player = mo->player;
170
171 if (mo->momx > MAXMOVE)
172 mo->momx = MAXMOVE;
173 else if (mo->momx < -MAXMOVE)
174 mo->momx = -MAXMOVE;
175
176 if (mo->momy > MAXMOVE)
177 mo->momy = MAXMOVE;
178 else if (mo->momy < -MAXMOVE)
179 mo->momy = -MAXMOVE;
180
181 xmove = mo->momx;
182 ymove = mo->momy;
183
184 oldx = mo->x; // phares 9/10/98: new code to reduce bobbing/momentum
185 oldy = mo->y; // when on ice & up against wall. These will be compared
186 // to your x,y values later to see if you were able to move
187
188 do
189 {
190 fixed_t ptryx, ptryy;
191 // killough 8/9/98: fix bug in original Doom source:
192 // Large negative displacements were never considered.
193 // This explains the tendency for Mancubus fireballs
194 // to pass through walls.
195 // CPhipps - compatibility optioned
196
197 if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2 ||
198 (!comp[comp_moveblock]
199 && (xmove < -MAXMOVE/2 || ymove < -MAXMOVE/2)))
200 {
201 ptryx = mo->x + xmove/2;
202 ptryy = mo->y + ymove/2;
203 xmove >>= 1;
204 ymove >>= 1;
205 }
206 else
207 {
208 ptryx = mo->x + xmove;
209 ptryy = mo->y + ymove;
210 xmove = ymove = 0;
211 }
212
213 // killough 3/15/98: Allow objects to drop off
214
215 if (!P_TryMove (mo, ptryx, ptryy, true))
216 {
217 // blocked move
218
219 // killough 8/11/98: bouncing off walls
220 // killough 10/98:
221 // Add ability for objects other than players to bounce on ice
222
223 if (!(mo->flags & MF_MISSILE) &&
224 mbf_features &&
225 (mo->flags & MF_BOUNCES ||
226 (!player && blockline &&
227 variable_friction && mo->z <= mo->floorz &&
228 P_GetFriction(mo, NULL) > ORIG_FRICTION)))
229 {
230 if (blockline)
231 {
232 fixed_t r = ((blockline->dx >> FRACBITS) * mo->momx +
233 (blockline->dy >> FRACBITS) * mo->momy) /
234 ((blockline->dx >> FRACBITS)*(blockline->dx >> FRACBITS)+
235 (blockline->dy >> FRACBITS)*(blockline->dy >> FRACBITS));
236 fixed_t x = FixedMul(r, blockline->dx);
237 fixed_t y = FixedMul(r, blockline->dy);
238
239 // reflect momentum away from wall
240
241 mo->momx = x*2 - mo->momx;
242 mo->momy = y*2 - mo->momy;
243
244 // if under gravity, slow down in
245 // direction perpendicular to wall.
246
247 if (!(mo->flags & MF_NOGRAVITY))
248 {
249 mo->momx = (mo->momx + x)/2;
250 mo->momy = (mo->momy + y)/2;
251 }
252 }
253 else
254 mo->momx = mo->momy = 0;
255 }
256 else
257 if (player) // try to slide along it
258 P_SlideMove (mo);
259 else
260 if (mo->flags & MF_MISSILE)
261 {
262 // explode a missile
263
264 if (ceilingline &&
265 ceilingline->backsector &&
266 ceilingline->backsector->ceilingpic == skyflatnum)
267 if (demo_compatibility || // killough
268 mo->z > ceilingline->backsector->ceilingheight)
269 {
270 // Hack to prevent missiles exploding
271 // against the sky.
272 // Does not handle sky floors.
273
274 P_RemoveMobj (mo);
275 return;
276 }
277 P_ExplodeMissile (mo);
278 }
279 else // whatever else it is, it is now standing still in (x,y)
280 mo->momx = mo->momy = 0;
281 }
282 } while (xmove || ymove);
283
284 // slow down
285
286#if 0 /* killough 10/98: this is unused code (except maybe in .deh files?) */
287 if (player && player->cheats & CF_NOMOMENTUM)
288 {
289 // debug option for no sliding at all
290 mo->momx = mo->momy = 0;
291 player->momx = player->momy = 0; /* killough 10/98 */
292 return;
293 }
294#endif
295
296 /* no friction for missiles or skulls ever, no friction when airborne */
297 if (mo->flags & (MF_MISSILE | MF_SKULLFLY) || mo->z > mo->floorz)
298 return;
299
300 /* killough 8/11/98: add bouncers
301 * killough 9/15/98: add objects falling off ledges
302 * killough 11/98: only include bouncers hanging off ledges
303 */
304 if (((mo->flags & MF_BOUNCES && mo->z > mo->dropoffz) ||
305 mo->flags & MF_CORPSE || mo->intflags & MIF_FALLING) &&
306 (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 ||
307 mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) &&
308 mo->floorz != mo->subsector->sector->floorheight)
309 return; // do not stop sliding if halfway off a step with some momentum
310
311 // killough 11/98:
312 // Stop voodoo dolls that have come to rest, despite any
313 // moving corresponding player, except in old demos:
314
315 if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED &&
316 mo->momy > -STOPSPEED && mo->momy < STOPSPEED &&
317 (!player || !(player->cmd.forwardmove | player->cmd.sidemove) ||
318 (player->mo != mo && compatibility_level >= lxdoom_1_compatibility)))
319 {
320 // if in a walking frame, stop moving
321
322 // killough 10/98:
323 // Don't affect main player when voodoo dolls stop, except in old demos:
324
325// if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4)
326// P_SetMobjState (player->mo, S_PLAY);
327 if (player && (unsigned)(player->mo->state - states - S_PLAY_RUN1) < 4
328 && (player->mo == mo || compatibility_level >= lxdoom_1_compatibility))
329 P_SetMobjState(player->mo, S_PLAY);
330
331 mo->momx = mo->momy = 0;
332
333 /* killough 10/98: kill any bobbing momentum too (except in voodoo dolls)
334 * cph - DEMOSYNC - needs compatibility check?
335 */
336 if (player && player->mo == mo)
337 player->momx = player->momy = 0;
338 }
339 else
340 {
341 /* phares 3/17/98
342 *
343 * Friction will have been adjusted by friction thinkers for
344 * icy or muddy floors. Otherwise it was never touched and
345 * remained set at ORIG_FRICTION
346 *
347 * killough 8/28/98: removed inefficient thinker algorithm,
348 * instead using touching_sectorlist in P_GetFriction() to
349 * determine friction (and thus only when it is needed).
350 *
351 * killough 10/98: changed to work with new bobbing method.
352 * Reducing player momentum is no longer needed to reduce
353 * bobbing, so ice works much better now.
354 *
355 * cph - DEMOSYNC - need old code for Boom demos?
356 */
357
358 //e6y
359 if (compatibility_level <= boom_201_compatibility)
360 {
361 // phares 3/17/98
362 // Friction will have been adjusted by friction thinkers for icy
363 // or muddy floors. Otherwise it was never touched and
364 // remained set at ORIG_FRICTION
365 mo->momx = FixedMul(mo->momx,mo->friction);
366 mo->momy = FixedMul(mo->momy,mo->friction);
367 mo->friction = ORIG_FRICTION; // reset to normal for next tic
368 }
369 else if (compatibility_level <= lxdoom_1_compatibility)
370 {
371 // phares 9/10/98: reduce bobbing/momentum when on ice & up against wall
372
373 if ((oldx == mo->x) && (oldy == mo->y)) // Did you go anywhere?
374 { // No. Use original friction. This allows you to not bob so much
375 // if you're on ice, but keeps enough momentum around to break free
376 // when you're mildly stuck in a wall.
377 mo->momx = FixedMul(mo->momx,ORIG_FRICTION);
378 mo->momy = FixedMul(mo->momy,ORIG_FRICTION);
379 }
380 else
381 { // Yes. Use stored friction.
382 mo->momx = FixedMul(mo->momx,mo->friction);
383 mo->momy = FixedMul(mo->momy,mo->friction);
384 }
385 mo->friction = ORIG_FRICTION; // reset to normal for next tic
386 }
387 else
388 {
389
390 fixed_t friction = P_GetFriction(mo, NULL);
391
392 mo->momx = FixedMul(mo->momx, friction);
393 mo->momy = FixedMul(mo->momy, friction);
394
395 /* killough 10/98: Always decrease player bobbing by ORIG_FRICTION.
396 * This prevents problems with bobbing on ice, where it was not being
397 * reduced fast enough, leading to all sorts of kludges being developed.
398 */
399
400 if (player && player->mo == mo) /* Not voodoo dolls */
401 {
402 player->momx = FixedMul(player->momx, ORIG_FRICTION);
403 player->momy = FixedMul(player->momy, ORIG_FRICTION);
404 }
405
406 }
407
408 }
409 }
410
411
412//
413// P_ZMovement
414//
415// Attempt vertical movement.
416
417static void P_ZMovement (mobj_t* mo)
418{
419 /* killough 7/11/98:
420 * BFG fireballs bounced on floors and ceilings in Pre-Beta Doom
421 * killough 8/9/98: added support for non-missile objects bouncing
422 * (e.g. grenade, mine, pipebomb)
423 */
424
425 if (mo->flags & MF_BOUNCES && mo->momz) {
426 mo->z += mo->momz;
427 if (mo->z <= mo->floorz) { /* bounce off floors */
428 mo->z = mo->floorz;
429 if (mo->momz < 0) {
430 mo->momz = -mo->momz;
431 if (!(mo->flags & MF_NOGRAVITY)) { /* bounce back with decay */
432 mo->momz = mo->flags & MF_FLOAT ? // floaters fall slowly
433 mo->flags & MF_DROPOFF ? // DROPOFF indicates rate
434 FixedMul(mo->momz, (fixed_t)(FRACUNIT*.85)) :
435 FixedMul(mo->momz, (fixed_t)(FRACUNIT*.70)) :
436 FixedMul(mo->momz, (fixed_t)(FRACUNIT*.45)) ;
437
438 /* Bring it to rest below a certain speed */
439 if (D_abs(mo->momz) <= mo->info->mass*(GRAVITY*4/256))
440 mo->momz = 0;
441 }
442
443 /* killough 11/98: touchy objects explode on impact */
444 if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED
445 && mo->health > 0)
446 P_DamageMobj(mo, NULL, NULL, mo->health);
447 else if (mo->flags & MF_FLOAT && sentient(mo))
448 goto floater;
449 return;
450 }
451 } else if (mo->z >= mo->ceilingz - mo->height) {
452 /* bounce off ceilings */
453 mo->z = mo->ceilingz - mo->height;
454 if (mo->momz > 0) {
455 if (mo->subsector->sector->ceilingpic != skyflatnum)
456 mo->momz = -mo->momz; /* always bounce off non-sky ceiling */
457 else if (mo->flags & MF_MISSILE)
458 P_RemoveMobj(mo); /* missiles don't bounce off skies */
459 else if (mo->flags & MF_NOGRAVITY)
460 mo->momz = -mo->momz; // bounce unless under gravity
461
462 if (mo->flags & MF_FLOAT && sentient(mo))
463 goto floater;
464
465 return;
466 }
467 } else {
468 if (!(mo->flags & MF_NOGRAVITY)) /* free-fall under gravity */
469 mo->momz -= mo->info->mass*(GRAVITY/256);
470
471 if (mo->flags & MF_FLOAT && sentient(mo)) goto floater;
472 return;
473 }
474
475 /* came to a stop */
476 mo->momz = 0;
477
478 if (mo->flags & MF_MISSILE) {
479 if (ceilingline &&
480 ceilingline->backsector &&
481 ceilingline->backsector->ceilingpic == skyflatnum &&
482 mo->z > ceilingline->backsector->ceilingheight)
483 P_RemoveMobj(mo); /* don't explode on skies */
484 else
485 P_ExplodeMissile(mo);
486 }
487
488 if (mo->flags & MF_FLOAT && sentient(mo)) goto floater;
489 return;
490 }
491
492 /* killough 8/9/98: end bouncing object code */
493
494 // check for smooth step up
495
496 if (mo->player &&
497 mo->player->mo == mo && // killough 5/12/98: exclude voodoo dolls
498 mo->z < mo->floorz)
499 {
500 mo->player->viewheight -= mo->floorz-mo->z;
501 mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3;
502 }
503
504 // adjust altitude
505
506 mo->z += mo->momz;
507
508floater:
509 if ((mo->flags & MF_FLOAT) && mo->target)
510
511 // float down towards target if too close
512
513 if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) &&
514 mo->target) /* killough 11/98: simplify */
515 {
516 fixed_t delta;
517 if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) <
518 D_abs(delta = mo->target->z + (mo->height>>1) - mo->z)*3)
519 mo->z += delta < 0 ? -FLOATSPEED : FLOATSPEED;
520 }
521
522 // clip movement
523
524 if (mo->z <= mo->floorz)
525 {
526 // hit the floor
527
528 /* Note (id):
529 * somebody left this after the setting momz to 0,
530 * kinda useless there.
531 * cph - This was the a bug in the linuxdoom-1.10 source which
532 * caused it not to sync Doom 2 v1.9 demos. Someone
533 * added the above comment and moved up the following code. So
534 * demos would desync in close lost soul fights.
535 * cph - revised 2001/04/15 -
536 * This was a bug in the Doom/Doom 2 source; the following code
537 * is meant to make charging lost souls bounce off of floors, but it
538 * was incorrectly placed after momz was set to 0.
539 * However, this bug was fixed in Doom95, Final/Ultimate Doom, and
540 * the v1.10 source release (which is one reason why it failed to sync
541 * some Doom2 v1.9 demos)
542 * I've added a comp_soul compatibility option to make this behavior
543 * selectable for PrBoom v2.3+. For older demos, we do this here only
544 * if we're in a compatibility level above Doom 2 v1.9 (in which case we
545 * mimic the bug and do it further down instead)
546 */
547
548 if (mo->flags & MF_SKULLFLY &&
549 (!comp[comp_soul] ||
550 (compatibility_level > doom2_19_compatibility &&
551 compatibility_level < prboom_4_compatibility)
552 ))
553 mo->momz = -mo->momz; // the skull slammed into something
554
555 if (mo->momz < 0)
556 {
557 /* killough 11/98: touchy objects explode on impact */
558 if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED && mo->health > 0)
559 P_DamageMobj(mo, NULL, NULL, mo->health);
560 else
561 if (mo->player && /* killough 5/12/98: exclude voodoo dolls */
562 mo->player->mo == mo && mo->momz < -GRAVITY*8)
563 {
564 // Squat down.
565 // Decrease viewheight for a moment
566 // after hitting the ground (hard),
567 // and utter appropriate sound.
568
569 mo->player->deltaviewheight = mo->momz>>3;
570 if (mo->health > 0) /* cph - prevent "oof" when dead */
571 S_StartSound (mo, sfx_oof);
572 }
573 mo->momz = 0;
574 }
575 mo->z = mo->floorz;
576
577 /* cph 2001/04/15 -
578 * This is the buggy lost-soul bouncing code referenced above.
579 * We've already set momz = 0 normally by this point, so it's useless.
580 * However we might still have upward momentum, in which case this will
581 * incorrectly reverse it, so we might still need this for demo sync
582 */
583 if (mo->flags & MF_SKULLFLY &&
584 compatibility_level <= doom2_19_compatibility)
585 mo->momz = -mo->momz; // the skull slammed into something
586
587 if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) )
588 {
589 P_ExplodeMissile (mo);
590 return;
591 }
592 }
593 else // still above the floor // phares
594 if (!(mo->flags & MF_NOGRAVITY))
595 {
596 if (!mo->momz)
597 mo->momz = -GRAVITY;
598 mo->momz -= GRAVITY;
599 }
600
601 if (mo->z + mo->height > mo->ceilingz)
602 {
603 /* cph 2001/04/15 -
604 * Lost souls were meant to bounce off of ceilings;
605 * new comp_soul compatibility option added
606 */
607 if (!comp[comp_soul] && mo->flags & MF_SKULLFLY)
608 mo->momz = -mo->momz; // the skull slammed into something
609
610 // hit the ceiling
611
612 if (mo->momz > 0)
613 mo->momz = 0;
614
615 mo->z = mo->ceilingz - mo->height;
616
617 /* cph 2001/04/15 -
618 * We might have hit a ceiling but had downward momentum (e.g. ceiling is
619 * lowering on us), so for old demos we must still do the buggy
620 * momentum reversal here
621 */
622 if (comp[comp_soul] && mo->flags & MF_SKULLFLY)
623 mo->momz = -mo->momz; // the skull slammed into something
624
625 if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) )
626 {
627 P_ExplodeMissile (mo);
628 return;
629 }
630 }
631 }
632
633//
634// P_NightmareRespawn
635//
636
637static void P_NightmareRespawn(mobj_t* mobj)
638 {
639 fixed_t x;
640 fixed_t y;
641 fixed_t z;
642 subsector_t* ss;
643 mobj_t* mo;
644 mapthing_t* mthing;
645
646 x = mobj->spawnpoint.x << FRACBITS;
647 y = mobj->spawnpoint.y << FRACBITS;
648
649 /* haleyjd: stupid nightmare respawning bug fix
650 *
651 * 08/09/00: compatibility added, time to ramble :)
652 * This fixes the notorious nightmare respawning bug that causes monsters
653 * that didn't spawn at level startup to respawn at the point (0,0)
654 * regardless of that point's nature. SMMU and Eternity need this for
655 * script-spawned things like Halif Swordsmythe, as well.
656 *
657 * cph - copied from eternity, except comp_respawnfix becomes comp_respawn
658 * and the logic is reversed (i.e. like the rest of comp_ it *disables*
659 * the fix)
660 */
661 if(!comp[comp_respawn] && !x && !y)
662 {
663 // spawnpoint was zeroed out, so use point of death instead
664 x = mobj->x;
665 y = mobj->y;
666 }
667
668 // something is occupying its position?
669
670 if (!P_CheckPosition (mobj, x, y) )
671 return; // no respwan
672
673 // spawn a teleport fog at old spot
674 // because of removal of the body?
675
676 mo = P_SpawnMobj (mobj->x,
677 mobj->y,
678 mobj->subsector->sector->floorheight,
679 MT_TFOG);
680
681 // initiate teleport sound
682
683 S_StartSound (mo, sfx_telept);
684
685 // spawn a teleport fog at the new spot
686
687 ss = R_PointInSubsector (x,y);
688
689 mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG);
690
691 S_StartSound (mo, sfx_telept);
692
693 // spawn the new monster
694
695 mthing = &mobj->spawnpoint;
696 if (mobj->info->flags & MF_SPAWNCEILING)
697 z = ONCEILINGZ;
698 else
699 z = ONFLOORZ;
700
701 // inherit attributes from deceased one
702
703 mo = P_SpawnMobj (x,y,z, mobj->type);
704 mo->spawnpoint = mobj->spawnpoint;
705 mo->angle = ANG45 * (mthing->angle/45);
706
707 if (mthing->options & MTF_AMBUSH)
708 mo->flags |= MF_AMBUSH;
709
710 /* killough 11/98: transfer friendliness from deceased */
711 mo->flags = (mo->flags & ~MF_FRIEND) | (mobj->flags & MF_FRIEND);
712
713 mo->reactiontime = 18;
714
715 // remove the old monster,
716
717 P_RemoveMobj (mobj);
718 }
719
720
721//
722// P_MobjThinker
723//
724
725void P_MobjThinker (mobj_t* mobj)
726 {
727 // killough 11/98:
728 // removed old code which looked at target references
729 // (we use pointer reference counting now)
730
731 mobj->PrevX = mobj->x;
732 mobj->PrevY = mobj->y;
733 mobj->PrevZ = mobj->z;
734
735 // momentum movement
736 if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY)
737 {
738 P_XYMovement(mobj);
739 if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed
740 return; // killough - mobj was removed
741 }
742
743 if (mobj->z != mobj->floorz || mobj->momz)
744 {
745 P_ZMovement(mobj);
746 if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed
747 return; // killough - mobj was removed
748 }
749 else
750 if (!(mobj->momx | mobj->momy) && !sentient(mobj))
751 { // non-sentient objects at rest
752 mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest
753
754 // killough 9/12/98: objects fall off ledges if they are hanging off
755 // slightly push off of ledge if hanging more than halfway off
756
757 if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff
758 !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall
759 !comp[comp_falloff]) // Not in old demos
760 P_ApplyTorque(mobj); // Apply torque
761 else
762 mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque
763 }
764
765 // cycle through states,
766 // calling action functions at transitions
767
768 if (mobj->tics != -1)
769 {
770 mobj->tics--;
771
772 // you can cycle through multiple states in a tic
773
774 if (!mobj->tics)
775 if (!P_SetMobjState (mobj, mobj->state->nextstate) )
776 return; // freed itself
777 }
778 else
779 {
780
781 // check for nightmare respawn
782
783 if (! (mobj->flags & MF_COUNTKILL) )
784 return;
785
786 if (!respawnmonsters)
787 return;
788
789 mobj->movecount++;
790
791 if (mobj->movecount < 12*35)
792 return;
793
794 if (leveltime & 31)
795 return;
796
797 if (P_Random (pr_respawn) > 4)
798 return;
799
800 P_NightmareRespawn (mobj);
801 }
802
803 }
804
805
806//
807// P_SpawnMobj
808//
809mobj_t* P_SpawnMobj(fixed_t x,fixed_t y,fixed_t z,mobjtype_t type)
810 {
811 mobj_t* mobj;
812 state_t* st;
813 mobjinfo_t* info;
814
815 mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
816 memset (mobj, 0, sizeof (*mobj));
817 info = &mobjinfo[type];
818 mobj->type = type;
819 mobj->info = info;
820 mobj->x = x;
821 mobj->y = y;
822 mobj->radius = info->radius;
823 mobj->height = info->height; // phares
824 mobj->flags = info->flags;
825
826 /* killough 8/23/98: no friends, bouncers, or touchy things in old demos */
827 if (!mbf_features)
828 mobj->flags &= ~(MF_BOUNCES | MF_FRIEND | MF_TOUCHY);
829 else
830 if (type == MT_PLAYER) // Except in old demos, players
831 mobj->flags |= MF_FRIEND; // are always friends.
832
833 mobj->health = info->spawnhealth;
834
835 if (gameskill != sk_nightmare)
836 mobj->reactiontime = info->reactiontime;
837
838 mobj->lastlook = P_Random (pr_lastlook) % MAXPLAYERS;
839
840 // do not set the state with P_SetMobjState,
841 // because action routines can not be called yet
842
843 st = &states[info->spawnstate];
844
845 mobj->state = st;
846 mobj->tics = st->tics;
847 mobj->sprite = st->sprite;
848 mobj->frame = st->frame;
849 mobj->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98
850
851 // set subsector and/or block links
852
853 P_SetThingPosition (mobj);
854
855 mobj->dropoffz = /* killough 11/98: for tracking dropoffs */
856 mobj->floorz = mobj->subsector->sector->floorheight;
857 mobj->ceilingz = mobj->subsector->sector->ceilingheight;
858
859 mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ?
860 mobj->ceilingz - mobj->height : z;
861
862 mobj->PrevX = mobj->x;
863 mobj->PrevY = mobj->y;
864 mobj->PrevZ = mobj->z;
865
866 mobj->thinker.function = P_MobjThinker;
867
868 //e6y
869 mobj->friction = ORIG_FRICTION; // phares 3/17/98
870
871 mobj->target = mobj->tracer = mobj->lastenemy = NULL;
872 P_AddThinker (&mobj->thinker);
873 if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
874 totallive++;
875 return mobj;
876 }
877
878
879static mapthing_t itemrespawnque[ITEMQUESIZE];
880static int itemrespawntime[ITEMQUESIZE];
881int iquehead;
882int iquetail;
883
884
885//
886// P_RemoveMobj
887//
888
889void P_RemoveMobj (mobj_t* mobj)
890{
891 if ((mobj->flags & MF_SPECIAL)
892 && !(mobj->flags & MF_DROPPED)
893 && (mobj->type != MT_INV)
894 && (mobj->type != MT_INS))
895 {
896 itemrespawnque[iquehead] = mobj->spawnpoint;
897 itemrespawntime[iquehead] = leveltime;
898 iquehead = (iquehead+1)&(ITEMQUESIZE-1);
899
900 // lose one off the end?
901
902 if (iquehead == iquetail)
903 iquetail = (iquetail+1)&(ITEMQUESIZE-1);
904 }
905
906 // unlink from sector and block lists
907
908 P_UnsetThingPosition (mobj);
909
910 // Delete all nodes on the current sector_list phares 3/16/98
911
912 if (sector_list)
913 {
914 P_DelSeclist(sector_list);
915 sector_list = NULL;
916 }
917
918 // stop any playing sound
919
920 S_StopSound (mobj);
921
922 // killough 11/98:
923 //
924 // Remove any references to other mobjs.
925 //
926 // Older demos might depend on the fields being left alone, however,
927 // if multiple thinkers reference each other indirectly before the
928 // end of the current tic.
929 // CPhipps - only leave dead references in old demos; I hope lxdoom_1 level
930 // demos are rare and don't rely on this. I hope.
931
932 if ((compatibility_level >= lxdoom_1_compatibility) ||
933 (!demorecording && !demoplayback)) {
934 P_SetTarget(&mobj->target, NULL);
935 P_SetTarget(&mobj->tracer, NULL);
936 P_SetTarget(&mobj->lastenemy, NULL);
937 }
938 // free block
939
940 P_RemoveThinker (&mobj->thinker);
941}
942
943
944/*
945 * P_FindDoomedNum
946 *
947 * Finds a mobj type with a matching doomednum
948 *
949 * killough 8/24/98: rewrote to use hashing
950 */
951
952static PUREFUNC int P_FindDoomedNum(unsigned type)
953{
954 static struct { int first, next; } *hash;
955 register int i;
956
957 if (!hash)
958 {
959 hash = Z_Malloc(sizeof *hash * NUMMOBJTYPES, PU_CACHE, (void **) &hash);
960 for (i=0; i<NUMMOBJTYPES; i++)
961 hash[i].first = NUMMOBJTYPES;
962 for (i=0; i<NUMMOBJTYPES; i++)
963 if (mobjinfo[i].doomednum != -1)
964 {
965 unsigned h = (unsigned) mobjinfo[i].doomednum % NUMMOBJTYPES;
966 hash[i].next = hash[h].first;
967 hash[h].first = i;
968 }
969 }
970
971 i = hash[type % NUMMOBJTYPES].first;
972 while ((i < NUMMOBJTYPES) && ((unsigned)mobjinfo[i].doomednum != type))
973 i = hash[i].next;
974 return i;
975}
976
977//
978// P_RespawnSpecials
979//
980
981void P_RespawnSpecials (void)
982 {
983 fixed_t x;
984 fixed_t y;
985 fixed_t z;
986 subsector_t* ss;
987 mobj_t* mo;
988 mapthing_t* mthing;
989 int i;
990
991 // only respawn items in deathmatch
992
993 if (deathmatch != 2)
994 return;
995
996 // nothing left to respawn?
997
998 if (iquehead == iquetail)
999 return;
1000
1001 // wait at least 30 seconds
1002
1003 if (leveltime - itemrespawntime[iquetail] < 30*35)
1004 return;
1005
1006 mthing = &itemrespawnque[iquetail];
1007
1008 x = mthing->x << FRACBITS;
1009 y = mthing->y << FRACBITS;
1010
1011 // spawn a teleport fog at the new spot
1012
1013 ss = R_PointInSubsector (x,y);
1014 mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG);
1015 S_StartSound (mo, sfx_itmbk);
1016
1017 // find which type to spawn
1018
1019 /* killough 8/23/98: use table for faster lookup */
1020 i = P_FindDoomedNum(mthing->type);
1021
1022 // spawn it
1023
1024 if (mobjinfo[i].flags & MF_SPAWNCEILING)
1025 z = ONCEILINGZ;
1026 else
1027 z = ONFLOORZ;
1028
1029 mo = P_SpawnMobj (x,y,z, i);
1030 mo->spawnpoint = *mthing;
1031 mo->angle = ANG45 * (mthing->angle/45);
1032
1033 // pull it from the queue
1034
1035 iquetail = (iquetail+1)&(ITEMQUESIZE-1);
1036 }
1037
1038//
1039// P_SpawnPlayer
1040// Called when a player is spawned on the level.
1041// Most of the player structure stays unchanged
1042// between levels.
1043//
1044
1045extern byte playernumtotrans[MAXPLAYERS];
1046
1047void P_SpawnPlayer (int n, const mapthing_t* mthing)
1048 {
1049 player_t* p;
1050 fixed_t x;
1051 fixed_t y;
1052 fixed_t z;
1053 mobj_t* mobj;
1054 int i;
1055
1056 // not playing?
1057
1058 if (!playeringame[n])
1059 return;
1060
1061 p = &players[n];
1062
1063 if (p->playerstate == PST_REBORN)
1064 G_PlayerReborn (mthing->type-1);
1065
1066 /* cph 2001/08/14 - use the options field of memorised player starts to
1067 * indicate whether the start really exists in the level.
1068 */
1069 if (!mthing->options)
1070 I_Error("P_SpawnPlayer: attempt to spawn player at unavailable start point");
1071
1072 x = mthing->x << FRACBITS;
1073 y = mthing->y << FRACBITS;
1074 z = ONFLOORZ;
1075 mobj = P_SpawnMobj (x,y,z, MT_PLAYER);
1076
1077 // set color translations for player sprites
1078
1079 mobj->flags |= playernumtotrans[n]<<MF_TRANSSHIFT;
1080
1081 mobj->angle = ANG45 * (mthing->angle/45);
1082 mobj->player = p;
1083 mobj->health = p->health;
1084
1085 p->mo = mobj;
1086 p->playerstate = PST_LIVE;
1087 p->refire = 0;
1088 p->message = NULL;
1089 p->damagecount = 0;
1090 p->bonuscount = 0;
1091 p->extralight = 0;
1092 p->fixedcolormap = 0;
1093 p->viewheight = VIEWHEIGHT;
1094
1095 p->momx = p->momy = 0; // killough 10/98: initialize bobbing to 0.
1096
1097 // setup gun psprite
1098
1099 P_SetupPsprites (p);
1100
1101 // give all cards in death match mode
1102
1103 if (deathmatch)
1104 for (i = 0 ; i < NUMCARDS ; i++)
1105 p->cards[i] = true;
1106
1107 if (mthing->type-1 == consoleplayer)
1108 {
1109 ST_Start(); // wake up the status bar
1110 HU_Start(); // wake up the heads up text
1111 }
1112 R_SmoothPlaying_Reset(p); // e6y
1113 }
1114
1115/*
1116 * P_IsDoomnumAllowed()
1117 * Based on code taken from P_LoadThings() in src/p_setup.c Return TRUE
1118 * if the thing in question is expected to be available in the gamemode used.
1119 */
1120
1121boolean P_IsDoomnumAllowed(int doomnum)
1122{
1123 // Do not spawn cool, new monsters if !commercial
1124 if (gamemode != commercial)
1125 switch(doomnum)
1126 {
1127 case 64: // Archvile
1128 case 65: // Former Human Commando
1129 case 66: // Revenant
1130 case 67: // Mancubus
1131 case 68: // Arachnotron
1132 case 69: // Hell Knight
1133 case 71: // Pain Elemental
1134 case 84: // Wolf SS
1135 case 88: // Boss Brain
1136 case 89: // Boss Shooter
1137 return false;
1138 }
1139
1140 return true;
1141}
1142
1143//
1144// P_SpawnMapThing
1145// The fields of the mapthing should
1146// already be in host byte order.
1147//
1148
1149void P_SpawnMapThing (const mapthing_t* mthing)
1150 {
1151 int i;
1152 //int bit;
1153 mobj_t* mobj;
1154 fixed_t x;
1155 fixed_t y;
1156 fixed_t z;
1157 int options = mthing->options; /* cph 2001/07/07 - make writable copy */
1158
1159 // killough 2/26/98: Ignore type-0 things as NOPs
1160 // phares 5/14/98: Ignore Player 5-8 starts (for now)
1161
1162 switch(mthing->type)
1163 {
1164 case 0:
1165 case DEN_PLAYER5:
1166 case DEN_PLAYER6:
1167 case DEN_PLAYER7:
1168 case DEN_PLAYER8:
1169 return;
1170 }
1171
1172 // killough 11/98: clear flags unused by Doom
1173 //
1174 // We clear the flags unused in Doom if we see flag mask 256 set, since
1175 // it is reserved to be 0 under the new scheme. A 1 in this reserved bit
1176 // indicates it's a Doom wad made by a Doom editor which puts 1's in
1177 // bits that weren't used in Doom (such as HellMaker wads). So we should
1178 // then simply ignore all upper bits.
1179
1180 if (demo_compatibility ||
1181 (compatibility_level >= lxdoom_1_compatibility &&
1182 options & MTF_RESERVED)) {
1183 if (!demo_compatibility) // cph - Add warning about bad thing flags
1184 lprintf(LO_WARN, "P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n",
1185 options, mthing->type);
1186 options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE;
1187 }
1188
1189 // count deathmatch start positions
1190
1191 // doom2.exe has at most 10 deathmatch starts
1192 if (mthing->type == 11)
1193 {
1194 if (!(!compatibility || deathmatch_p-deathmatchstarts < 10)) {
1195 return;
1196 } else {
1197 // 1/11/98 killough -- new code removes limit on deathmatch starts:
1198
1199 size_t offset = deathmatch_p - deathmatchstarts;
1200
1201 if (offset >= num_deathmatchstarts)
1202 {
1203 num_deathmatchstarts = num_deathmatchstarts ?
1204 num_deathmatchstarts*2 : 16;
1205 deathmatchstarts = realloc(deathmatchstarts,
1206 num_deathmatchstarts *
1207 sizeof(*deathmatchstarts));
1208 deathmatch_p = deathmatchstarts + offset;
1209 }
1210 memcpy(deathmatch_p++, mthing, sizeof(*mthing));
1211 (deathmatch_p-1)->options = 1;
1212 return;
1213 }
1214 }
1215
1216 // check for players specially
1217
1218 if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes
1219 {
1220#ifdef DOGS
1221 // killough 7/19/98: Marine's best friend :)
1222 if (!netgame && mthing->type > 1 && mthing->type <= dogs+1 &&
1223 !players[mthing->type-1].secretcount)
1224 { // use secretcount to avoid multiple dogs in case of multiple starts
1225 players[mthing->type-1].secretcount = 1;
1226
1227 // killough 10/98: force it to be a friend
1228 options |= MTF_FRIEND;
1229 if(HelperThing != -1) // haleyjd 9/22/99: deh substitution
1230 {
1231 int type = HelperThing - 1;
1232 if(type >= 0 && type < NUMMOBJTYPES)
1233 {
1234 i = type;
1235 }
1236 else
1237 {
1238 doom_printf("Invalid value %i for helper, ignored.", HelperThing);
1239 i = MT_DOGS;
1240 }
1241 }
1242 else {
1243 i = MT_DOGS;
1244 }
1245 goto spawnit;
1246 }
1247#endif
1248
1249 // save spots for respawning in coop games
1250 playerstarts[mthing->type-1] = *mthing;
1251 /* cph 2006/07/24 - use the otherwise-unused options field to flag that
1252 * this start is present (so we know which elements of the array are filled
1253 * in, in effect). Also note that the call below to P_SpawnPlayer must use
1254 * the playerstarts version with this field set */
1255 playerstarts[mthing->type-1].options = 1;
1256
1257 if (!deathmatch)
1258 P_SpawnPlayer (mthing->type-1, &playerstarts[mthing->type-1]);
1259 return;
1260 }
1261
1262 // check for apropriate skill level
1263
1264 /* jff "not single" thing flag */
1265 if (!netgame && options & MTF_NOTSINGLE)
1266 return;
1267
1268 //jff 3/30/98 implement "not deathmatch" thing flag
1269
1270 if (netgame && deathmatch && options & MTF_NOTDM)
1271 return;
1272
1273 //jff 3/30/98 implement "not cooperative" thing flag
1274
1275 if (netgame && !deathmatch && options & MTF_NOTCOOP)
1276 return;
1277
1278 // killough 11/98: simplify
1279 if (gameskill == sk_baby || gameskill == sk_easy ?
1280 !(options & MTF_EASY) :
1281 gameskill == sk_hard || gameskill == sk_nightmare ?
1282 !(options & MTF_HARD) : !(options & MTF_NORMAL))
1283 return;
1284
1285 // find which type to spawn
1286
1287 // killough 8/23/98: use table for faster lookup
1288 i = P_FindDoomedNum(mthing->type);
1289
1290 // phares 5/16/98:
1291 // Do not abort because of an unknown thing. Ignore it, but post a
1292 // warning message for the player.
1293
1294 if (i == NUMMOBJTYPES)
1295 {
1296 doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y);
1297 return;
1298 }
1299
1300 // don't spawn keycards and players in deathmatch
1301
1302 if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
1303 return;
1304
1305 // don't spawn any monsters if -nomonsters
1306
1307 if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL)))
1308 return;
1309
1310 // spawn it
1311#ifdef DOGS
1312spawnit:
1313#endif
1314
1315 x = mthing->x << FRACBITS;
1316 y = mthing->y << FRACBITS;
1317
1318 if (mobjinfo[i].flags & MF_SPAWNCEILING)
1319 z = ONCEILINGZ;
1320 else
1321 z = ONFLOORZ;
1322
1323 mobj = P_SpawnMobj (x,y,z, i);
1324 mobj->spawnpoint = *mthing;
1325
1326 if (mobj->tics > 0)
1327 mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics);
1328
1329 if (!(mobj->flags & MF_FRIEND) &&
1330 options & MTF_FRIEND &&
1331 mbf_features)
1332 {
1333 mobj->flags |= MF_FRIEND; // killough 10/98:
1334 P_UpdateThinker(&mobj->thinker); // transfer friendliness flag
1335 }
1336
1337 /* killough 7/20/98: exclude friends */
1338 if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
1339 totalkills++;
1340
1341 if (mobj->flags & MF_COUNTITEM)
1342 totalitems++;
1343
1344 mobj->angle = ANG45 * (mthing->angle/45);
1345 if (options & MTF_AMBUSH)
1346 mobj->flags |= MF_AMBUSH;
1347 }
1348
1349
1350//
1351// GAME SPAWN FUNCTIONS
1352//
1353
1354//
1355// P_SpawnPuff
1356//
1357
1358extern fixed_t attackrange;
1359
1360void P_SpawnPuff(fixed_t x,fixed_t y,fixed_t z)
1361 {
1362 mobj_t* th;
1363 // killough 5/5/98: remove dependence on order of evaluation:
1364 int t = P_Random(pr_spawnpuff);
1365 z += (t - P_Random(pr_spawnpuff))<<10;
1366
1367 th = P_SpawnMobj (x,y,z, MT_PUFF);
1368 th->momz = FRACUNIT;
1369 th->tics -= P_Random(pr_spawnpuff)&3;
1370
1371 if (th->tics < 1)
1372 th->tics = 1;
1373
1374 // don't make punches spark on the wall
1375
1376 if (attackrange == MELEERANGE)
1377 P_SetMobjState (th, S_PUFF3);
1378 }
1379
1380
1381//
1382// P_SpawnBlood
1383//
1384void P_SpawnBlood(fixed_t x,fixed_t y,fixed_t z,int damage)
1385 {
1386 mobj_t* th;
1387 // killough 5/5/98: remove dependence on order of evaluation:
1388 int t = P_Random(pr_spawnblood);
1389 z += (t - P_Random(pr_spawnblood))<<10;
1390 th = P_SpawnMobj(x,y,z, MT_BLOOD);
1391 th->momz = FRACUNIT*2;
1392 th->tics -= P_Random(pr_spawnblood)&3;
1393
1394 if (th->tics < 1)
1395 th->tics = 1;
1396
1397 if (damage <= 12 && damage >= 9)
1398 P_SetMobjState (th,S_BLOOD2);
1399 else if (damage < 9)
1400 P_SetMobjState (th,S_BLOOD3);
1401 }
1402
1403
1404//
1405// P_CheckMissileSpawn
1406// Moves the missile forward a bit
1407// and possibly explodes it right there.
1408//
1409
1410void P_CheckMissileSpawn (mobj_t* th)
1411 {
1412 th->tics -= P_Random(pr_missile)&3;
1413 if (th->tics < 1)
1414 th->tics = 1;
1415
1416 // move a little forward so an angle can
1417 // be computed if it immediately explodes
1418
1419 th->x += (th->momx>>1);
1420 th->y += (th->momy>>1);
1421 th->z += (th->momz>>1);
1422
1423 // killough 8/12/98: for non-missile objects (e.g. grenades)
1424 if (!(th->flags & MF_MISSILE) && mbf_features)
1425 return;
1426
1427 // killough 3/15/98: no dropoff (really = don't care for missiles)
1428
1429 if (!P_TryMove (th, th->x, th->y, false))
1430 P_ExplodeMissile (th);
1431 }
1432
1433
1434//
1435// P_SpawnMissile
1436//
1437
1438mobj_t* P_SpawnMissile(mobj_t* source,mobj_t* dest,mobjtype_t type)
1439 {
1440 mobj_t* th;
1441 angle_t an;
1442 int dist;
1443
1444 th = P_SpawnMobj (source->x,source->y,source->z + 4*8*FRACUNIT,type);
1445
1446 if (th->info->seesound)
1447 S_StartSound (th, th->info->seesound);
1448
1449 P_SetTarget(&th->target, source); // where it came from
1450 an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);
1451
1452 // fuzzy player
1453
1454 if (dest->flags & MF_SHADOW)
1455 { // killough 5/5/98: remove dependence on order of evaluation:
1456 int t = P_Random(pr_shadow);
1457 an += (t - P_Random(pr_shadow))<<20;
1458 }
1459
1460 th->angle = an;
1461 an >>= ANGLETOFINESHIFT;
1462 th->momx = FixedMul (th->info->speed, finecosine[an]);
1463 th->momy = FixedMul (th->info->speed, finesine[an]);
1464
1465 dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
1466 dist = dist / th->info->speed;
1467
1468 if (dist < 1)
1469 dist = 1;
1470
1471 th->momz = (dest->z - source->z) / dist;
1472 P_CheckMissileSpawn (th);
1473
1474 return th;
1475 }
1476
1477
1478//
1479// P_SpawnPlayerMissile
1480// Tries to aim at a nearby monster
1481//
1482
1483void P_SpawnPlayerMissile(mobj_t* source,mobjtype_t type)
1484{
1485 mobj_t *th;
1486 fixed_t x, y, z, slope = 0;
1487
1488 // see which target is to be aimed at
1489
1490 angle_t an = source->angle;
1491
1492 // killough 7/19/98: autoaiming was not in original beta
1493 {
1494 // killough 8/2/98: prefer autoaiming at enemies
1495 uint_64_t mask = mbf_features ? MF_FRIEND : 0;
1496
1497 do
1498 {
1499 slope = P_AimLineAttack(source, an, 16*64*FRACUNIT, mask);
1500 if (!linetarget)
1501 slope = P_AimLineAttack(source, an += 1<<26, 16*64*FRACUNIT, mask);
1502 if (!linetarget)
1503 slope = P_AimLineAttack(source, an -= 2<<26, 16*64*FRACUNIT, mask);
1504 if (!linetarget)
1505 an = source->angle, slope = 0;
1506 }
1507 while (mask && (mask=0, !linetarget)); // killough 8/2/98
1508 }
1509
1510 x = source->x;
1511 y = source->y;
1512 z = source->z + 4*8*FRACUNIT;
1513
1514 th = P_SpawnMobj (x,y,z, type);
1515
1516 if (th->info->seesound)
1517 S_StartSound (th, th->info->seesound);
1518
1519 P_SetTarget(&th->target, source);
1520 th->angle = an;
1521 th->momx = FixedMul(th->info->speed,finecosine[an>>ANGLETOFINESHIFT]);
1522 th->momy = FixedMul(th->info->speed,finesine[an>>ANGLETOFINESHIFT]);
1523 th->momz = FixedMul(th->info->speed,slope);
1524
1525 P_CheckMissileSpawn(th);
1526 }
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Map Objects, MObj, definition and handling.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __P_MOBJ__
35#define __P_MOBJ__
36
37// Basics.
38#include "tables.h"
39#include "m_fixed.h"
40
41// We need the thinker_t stuff.
42#include "d_think.h"
43
44// We need the WAD data structure for Map things,
45// from the THINGS lump.
46#include "doomdata.h"
47
48// States are tied to finite states are
49// tied to animation frames.
50// Needs precompiled tables/data structures.
51#include "info.h"
52
53//
54// NOTES: mobj_t
55//
56// mobj_ts are used to tell the refresh where to draw an image,
57// tell the world simulation when objects are contacted,
58// and tell the sound driver how to position a sound.
59//
60// The refresh uses the next and prev links to follow
61// lists of things in sectors as they are being drawn.
62// The sprite, frame, and angle elements determine which patch_t
63// is used to draw the sprite if it is visible.
64// The sprite and frame values are allmost allways set
65// from state_t structures.
66// The statescr.exe utility generates the states.h and states.c
67// files that contain the sprite/frame numbers from the
68// statescr.txt source file.
69// The xyz origin point represents a point at the bottom middle
70// of the sprite (between the feet of a biped).
71// This is the default origin position for patch_ts grabbed
72// with lumpy.exe.
73// A walking creature will have its z equal to the floor
74// it is standing on.
75//
76// The sound code uses the x,y, and subsector fields
77// to do stereo positioning of any sound effited by the mobj_t.
78//
79// The play simulation uses the blocklinks, x,y,z, radius, height
80// to determine when mobj_ts are touching each other,
81// touching lines in the map, or hit by trace lines (gunshots,
82// lines of sight, etc).
83// The mobj_t->flags element has various bit flags
84// used by the simulation.
85//
86// Every mobj_t is linked into a single sector
87// based on its origin coordinates.
88// The subsector_t is found with R_PointInSubsector(x,y),
89// and the sector_t can be found with subsector->sector.
90// The sector links are only used by the rendering code,
91// the play simulation does not care about them at all.
92//
93// Any mobj_t that needs to be acted upon by something else
94// in the play world (block movement, be shot, etc) will also
95// need to be linked into the blockmap.
96// If the thing has the MF_NOBLOCK flag set, it will not use
97// the block links. It can still interact with other things,
98// but only as the instigator (missiles will run into other
99// things, but nothing can run into a missile).
100// Each block in the grid is 128*128 units, and knows about
101// every line_t that it contains a piece of, and every
102// interactable mobj_t that has its origin contained.
103//
104// A valid mobj_t is a mobj_t that has the proper subsector_t
105// filled in for its xy coordinates and is linked into the
106// sector from which the subsector was made, or has the
107// MF_NOSECTOR flag set (the subsector_t needs to be valid
108// even if MF_NOSECTOR is set), and is linked into a blockmap
109// block or has the MF_NOBLOCKMAP flag set.
110// Links should only be modified by the P_[Un]SetThingPosition()
111// functions.
112// Do not change the MF_NO? flags while a thing is valid.
113//
114// Any questions?
115//
116
117//
118// Misc. mobj flags
119//
120
121// Call P_SpecialThing when touched.
122#define MF_SPECIAL (uint_64_t)(0x0000000000000001)
123// Blocks.
124#define MF_SOLID (uint_64_t)(0x0000000000000002)
125// Can be hit.
126#define MF_SHOOTABLE (uint_64_t)(0x0000000000000004)
127// Don't use the sector links (invisible but touchable).
128#define MF_NOSECTOR (uint_64_t)(0x0000000000000008)
129// Don't use the blocklinks (inert but displayable)
130#define MF_NOBLOCKMAP (uint_64_t)(0x0000000000000010)
131
132// Not to be activated by sound, deaf monster.
133#define MF_AMBUSH (uint_64_t)(0x0000000000000020)
134// Will try to attack right back.
135#define MF_JUSTHIT (uint_64_t)(0x0000000000000040)
136// Will take at least one step before attacking.
137#define MF_JUSTATTACKED (uint_64_t)(0x0000000000000080)
138// On level spawning (initial position),
139// hang from ceiling instead of stand on floor.
140#define MF_SPAWNCEILING (uint_64_t)(0x0000000000000100)
141// Don't apply gravity (every tic),
142// that is, object will float, keeping current height
143// or changing it actively.
144#define MF_NOGRAVITY (uint_64_t)(0x0000000000000200)
145
146// Movement flags.
147// This allows jumps from high places.
148#define MF_DROPOFF (uint_64_t)(0x0000000000000400)
149// For players, will pick up items.
150#define MF_PICKUP (uint_64_t)(0x0000000000000800)
151// Player cheat. ???
152#define MF_NOCLIP (uint_64_t)(0x0000000000001000)
153// Player: keep info about sliding along walls.
154#define MF_SLIDE (uint_64_t)(0x0000000000002000)
155// Allow moves to any height, no gravity.
156// For active floaters, e.g. cacodemons, pain elementals.
157#define MF_FLOAT (uint_64_t)(0x0000000000004000)
158// Don't cross lines
159// ??? or look at heights on teleport.
160#define MF_TELEPORT (uint_64_t)(0x0000000000008000)
161// Don't hit same species, explode on block.
162// Player missiles as well as fireballs of various kinds.
163#define MF_MISSILE (uint_64_t)(0x0000000000010000)
164// Dropped by a demon, not level spawned.
165// E.g. ammo clips dropped by dying former humans.
166#define MF_DROPPED (uint_64_t)(0x0000000000020000)
167// Use fuzzy draw (shadow demons or spectres),
168// temporary player invisibility powerup.
169#define MF_SHADOW (uint_64_t)(0x0000000000040000)
170// Flag: don't bleed when shot (use puff),
171// barrels and shootable furniture shall not bleed.
172#define MF_NOBLOOD (uint_64_t)(0x0000000000080000)
173// Don't stop moving halfway off a step,
174// that is, have dead bodies slide down all the way.
175#define MF_CORPSE (uint_64_t)(0x0000000000100000)
176// Floating to a height for a move, ???
177// don't auto float to target's height.
178#define MF_INFLOAT (uint_64_t)(0x0000000000200000)
179
180// On kill, count this enemy object
181// towards intermission kill total.
182// Happy gathering.
183#define MF_COUNTKILL (uint_64_t)(0x0000000000400000)
184
185// On picking up, count this item object
186// towards intermission item total.
187#define MF_COUNTITEM (uint_64_t)(0x0000000000800000)
188
189// Special handling: skull in flight.
190// Neither a cacodemon nor a missile.
191#define MF_SKULLFLY (uint_64_t)(0x0000000001000000)
192
193// Don't spawn this object
194// in death match mode (e.g. key cards).
195#define MF_NOTDMATCH (uint_64_t)(0x0000000002000000)
196
197// Player sprites in multiplayer modes are modified
198// using an internal color lookup table for re-indexing.
199// If 0x4 0x8 or 0xc,
200// use a translation table for player colormaps
201#define MF_TRANSLATION (uint_64_t)(0x000000000c000000)
202#define MF_TRANSLATION1 (uint_64_t)(0x0000000004000000)
203#define MF_TRANSLATION2 (uint_64_t)(0x0000000008000000)
204// Hmm ???.
205#define MF_TRANSSHIFT 26
206
207#define MF_UNUSED2 (uint_64_t)(0x0000000010000000)
208#define MF_UNUSED3 (uint_64_t)(0x0000000020000000)
209
210 // Translucent sprite? // phares
211#define MF_TRANSLUCENT (uint_64_t)(0x0000000040000000)
212
213// this is free LONGLONG(0x0000000100000000)
214
215// these are greater than an int. That's why the flags below are now uint_64_t
216
217#define MF_TOUCHY LONGLONG(0x0000000100000000)
218#define MF_BOUNCES LONGLONG(0x0000000200000000)
219#define MF_FRIEND LONGLONG(0x0000000400000000)
220
221// killough 9/15/98: Same, but internal flags, not intended for .deh
222// (some degree of opaqueness is good, to avoid compatibility woes)
223
224enum {
225 MIF_FALLING = 1, // Object is falling
226 MIF_ARMED = 2, // Object is armed (for MF_TOUCHY objects)
227};
228
229// Map Object definition.
230//
231//
232// killough 2/20/98:
233//
234// WARNING: Special steps must be taken in p_saveg.c if C pointers are added to
235// this mobj_s struct, or else savegames will crash when loaded. See p_saveg.c.
236// Do not add "struct mobj_s *fooptr" without adding code to p_saveg.c to
237// convert the pointers to ordinals and back for savegames. This was the whole
238// reason behind monsters going to sleep when loading savegames (the "target"
239// pointer was simply nullified after loading, to prevent Doom from crashing),
240// and the whole reason behind loadgames crashing on savegames of AV attacks.
241//
242
243// killough 9/8/98: changed some fields to shorts,
244// for better memory usage (if only for cache).
245/* cph 2006/08/28 - move Prev[XYZ] fields to the end of the struct. Add any
246 * other new fields to the end, and make sure you don't break savegames! */
247
248typedef struct mobj_s
249{
250 // List: thinker links.
251 thinker_t thinker;
252
253 // Info for drawing: position.
254 fixed_t x;
255 fixed_t y;
256 fixed_t z;
257
258 // More list: links in sector (if needed)
259 struct mobj_s* snext;
260 struct mobj_s** sprev; // killough 8/10/98: change to ptr-to-ptr
261
262 //More drawing info: to determine current sprite.
263 angle_t angle; // orientation
264 spritenum_t sprite; // used to find patch_t and flip value
265 int frame; // might be ORed with FF_FULLBRIGHT
266
267 // Interaction info, by BLOCKMAP.
268 // Links in blocks (if needed).
269 struct mobj_s* bnext;
270 struct mobj_s** bprev; // killough 8/11/98: change to ptr-to-ptr
271
272 struct subsector_s* subsector;
273
274 // The closest interval over all contacted Sectors.
275 fixed_t floorz;
276 fixed_t ceilingz;
277
278 // killough 11/98: the lowest floor over all contacted Sectors.
279 fixed_t dropoffz;
280
281 // For movement checking.
282 fixed_t radius;
283 fixed_t height;
284
285 // Momentums, used to update position.
286 fixed_t momx;
287 fixed_t momy;
288 fixed_t momz;
289
290 // If == validcount, already checked.
291 int validcount;
292
293 mobjtype_t type;
294 mobjinfo_t* info; // &mobjinfo[mobj->type]
295
296 int tics; // state tic counter
297 state_t* state;
298 uint_64_t flags;
299 int intflags; // killough 9/15/98: internal flags
300 int health;
301
302 // Movement direction, movement generation (zig-zagging).
303 short movedir; // 0-7
304 short movecount; // when 0, select a new dir
305 short strafecount; // killough 9/8/98: monster strafing
306
307 // Thing being chased/attacked (or NULL),
308 // also the originator for missiles.
309 struct mobj_s* target;
310
311 // Reaction time: if non 0, don't attack yet.
312 // Used by player to freeze a bit after teleporting.
313 short reactiontime;
314
315 // If >0, the current target will be chased no
316 // matter what (even if shot by another object)
317 short threshold;
318
319 // killough 9/9/98: How long a monster pursues a target.
320 short pursuecount;
321
322 short gear; // killough 11/98: used in torque simulation
323
324 // Additional info record for player avatars only.
325 // Only valid if type == MT_PLAYER
326 struct player_s* player;
327
328 // Player number last looked for.
329 short lastlook;
330
331 // For nightmare respawn.
332 mapthing_t spawnpoint;
333
334 // Thing being chased/attacked for tracers.
335 struct mobj_s* tracer;
336
337 // new field: last known enemy -- killough 2/15/98
338 struct mobj_s* lastenemy;
339
340 // killough 8/2/98: friction properties part of sectors,
341 // not objects -- removed friction properties from here
342 // e6y: restored friction properties here
343 // Friction values for the sector the object is in
344 int friction; // phares 3/17/98
345 int movefactor;
346
347 // a linked list of sectors where this object appears
348 struct msecnode_s* touching_sectorlist; // phares 3/14/98
349
350 fixed_t PrevX;
351 fixed_t PrevY;
352 fixed_t PrevZ;
353
354 fixed_t pad; // cph - needed so I can get the size unambiguously on amd64
355
356 // SEE WARNING ABOVE ABOUT POINTER FIELDS!!!
357} mobj_t;
358
359// External declarations (fomerly in p_local.h) -- killough 5/2/98
360
361#define VIEWHEIGHT (41*FRACUNIT)
362
363#define GRAVITY FRACUNIT
364#define MAXMOVE (30*FRACUNIT)
365
366#define ONFLOORZ INT_MIN
367#define ONCEILINGZ INT_MAX
368
369// Time interval for item respawning.
370#define ITEMQUESIZE 128
371
372#define FLOATSPEED (FRACUNIT*4)
373#define STOPSPEED (FRACUNIT/16)
374
375// killough 11/98:
376// For torque simulation:
377
378#define OVERDRIVE 6
379#define MAXGEAR (OVERDRIVE+16)
380
381// killough 11/98:
382// Whether an object is "sentient" or not. Used for environmental influences.
383#define sentient(mobj) ((mobj)->health > 0 && (mobj)->info->seestate)
384
385extern int iquehead;
386extern int iquetail;
387
388void P_RespawnSpecials(void);
389mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
390void P_RemoveMobj(mobj_t *th);
391boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
392void P_MobjThinker(mobj_t *mobj);
393void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z);
394void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage);
395mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type);
396void P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type);
397boolean P_IsDoomnumAllowed(int doomnum);
398void P_SpawnMapThing (const mapthing_t* mthing);
399void P_SpawnPlayer(int n, const mapthing_t *mthing);
400void P_CheckMissileSpawn(mobj_t*); // killough 8/2/98
401void P_ExplodeMissile(mobj_t*); // killough
402#endif
403
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Plats (i.e. elevator platforms) code, raising/lowering.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "m_random.h"
36#include "r_main.h"
37#include "p_spec.h"
38#include "p_tick.h"
39#include "s_sound.h"
40#include "sounds.h"
41
42platlist_t *activeplats; // killough 2/14/98: made global again
43
44//
45// T_PlatRaise()
46//
47// Action routine to move a plat up and down
48//
49// Passed a plat structure containing all pertinent information about the move
50// No return
51//
52// jff 02/08/98 all cases with labels beginning with gen added to support
53// generalized line type behaviors.
54
55void T_PlatRaise(plat_t* plat)
56{
57 result_e res;
58
59 // handle plat moving, up, down, waiting, or in stasis,
60 switch(plat->status)
61 {
62 case up: // plat moving up
63 res = T_MovePlane(plat->sector,plat->speed,plat->high,plat->crush,0,1);
64
65 // if a pure raise type, make the plat moving sound
66 if (plat->type == raiseAndChange
67 || plat->type == raiseToNearestAndChange)
68 {
69 if (!(leveltime&7))
70 S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_stnmov);
71 }
72
73 // if encountered an obstacle, and not a crush type, reverse direction
74 if (res == crushed && (!plat->crush))
75 {
76 plat->count = plat->wait;
77 plat->status = down;
78 S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart);
79 }
80 else // else handle reaching end of up stroke
81 {
82 if (res == pastdest) // end of stroke
83 {
84 // if not an instant toggle type, wait, make plat stop sound
85 if (plat->type!=toggleUpDn)
86 {
87 plat->count = plat->wait;
88 plat->status = waiting;
89 S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop);
90 }
91 else // else go into stasis awaiting next toggle activation
92 {
93 plat->oldstatus = plat->status;//jff 3/14/98 after action wait
94 plat->status = in_stasis; //for reactivation of toggle
95 }
96
97 // lift types and pure raise types are done at end of up stroke
98 // only the perpetual type waits then goes back up
99 switch(plat->type)
100 {
101 case blazeDWUS:
102 case downWaitUpStay:
103 case raiseAndChange:
104 case raiseToNearestAndChange:
105 case genLift:
106 P_RemoveActivePlat(plat); // killough
107 default:
108 break;
109 }
110 }
111 }
112 break;
113
114 case down: // plat moving down
115 res = T_MovePlane(plat->sector,plat->speed,plat->low,false,0,-1);
116
117 // handle reaching end of down stroke
118 if (res == pastdest)
119 {
120 // if not an instant toggle, start waiting, make plat stop sound
121 if (plat->type!=toggleUpDn) //jff 3/14/98 toggle up down
122 { // is silent, instant, no waiting
123 plat->count = plat->wait;
124 plat->status = waiting;
125 S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstop);
126 }
127 else // instant toggles go into stasis awaiting next activation
128 {
129 plat->oldstatus = plat->status;//jff 3/14/98 after action wait
130 plat->status = in_stasis; //for reactivation of toggle
131 }
132
133 //jff 1/26/98 remove the plat if it bounced so it can be tried again
134 //only affects plats that raise and bounce
135 //killough 1/31/98: relax compatibility to demo_compatibility
136
137 // remove the plat if its a pure raise type
138 if (!comp[comp_floors])
139 {
140 switch(plat->type)
141 {
142 case raiseAndChange:
143 case raiseToNearestAndChange:
144 P_RemoveActivePlat(plat);
145 default:
146 break;
147 }
148 }
149 }
150 break;
151
152 case waiting: // plat is waiting
153 if (!--plat->count) // downcount and check for delay elapsed
154 {
155 if (plat->sector->floorheight == plat->low)
156 plat->status = up; // if at bottom, start up
157 else
158 plat->status = down; // if at top, start down
159
160 // make plat start sound
161 S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstart);
162 }
163 break; //jff 1/27/98 don't pickup code added later to in_stasis
164
165 case in_stasis: // do nothing if in stasis
166 break;
167 }
168}
169
170
171//
172// EV_DoPlat
173//
174// Handle Plat linedef types
175//
176// Passed the linedef that activated the plat, the type of plat action,
177// and for some plat types, an amount to raise
178// Returns true if a thinker is started, or restarted from stasis
179//
180int EV_DoPlat
181( line_t* line,
182 plattype_e type,
183 int amount )
184{
185 plat_t* plat;
186 int secnum;
187 int rtn;
188 sector_t* sec;
189
190 secnum = -1;
191 rtn = 0;
192
193
194 // Activate all <type> plats that are in_stasis
195 switch(type)
196 {
197 case perpetualRaise:
198 P_ActivateInStasis(line->tag);
199 break;
200
201 case toggleUpDn:
202 P_ActivateInStasis(line->tag);
203 rtn=1;
204 break;
205
206 default:
207 break;
208 }
209
210 // act on all sectors tagged the same as the activating linedef
211 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
212 {
213 sec = &sectors[secnum];
214
215 // don't start a second floor function if already moving
216 if (P_SectorActive(floor_special,sec)) //jff 2/23/98 multiple thinkers
217 continue;
218
219 // Create a thinker
220 rtn = 1;
221 plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0);
222 memset(plat, 0, sizeof(*plat));
223 P_AddThinker(&plat->thinker);
224
225 plat->type = type;
226 plat->sector = sec;
227 plat->sector->floordata = plat; //jff 2/23/98 multiple thinkers
228 plat->thinker.function = T_PlatRaise;
229 plat->crush = false;
230 plat->tag = line->tag;
231
232 //jff 1/26/98 Avoid raise plat bouncing a head off a ceiling and then
233 //going down forever -- default low to plat height when triggered
234 plat->low = sec->floorheight;
235
236 // set up plat according to type
237 switch(type)
238 {
239 case raiseToNearestAndChange:
240 plat->speed = PLATSPEED/2;
241 sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
242 plat->high = P_FindNextHighestFloor(sec,sec->floorheight);
243 plat->wait = 0;
244 plat->status = up;
245 sec->special = 0;
246 //jff 3/14/98 clear old field as well
247 sec->oldspecial = 0;
248
249 S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov);
250 break;
251
252 case raiseAndChange:
253 plat->speed = PLATSPEED/2;
254 sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
255 plat->high = sec->floorheight + amount*FRACUNIT;
256 plat->wait = 0;
257 plat->status = up;
258
259 S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov);
260 break;
261
262 case downWaitUpStay:
263 plat->speed = PLATSPEED * 4;
264 plat->low = P_FindLowestFloorSurrounding(sec);
265
266 if (plat->low > sec->floorheight)
267 plat->low = sec->floorheight;
268
269 plat->high = sec->floorheight;
270 plat->wait = 35*PLATWAIT;
271 plat->status = down;
272 S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
273 break;
274
275 case blazeDWUS:
276 plat->speed = PLATSPEED * 8;
277 plat->low = P_FindLowestFloorSurrounding(sec);
278
279 if (plat->low > sec->floorheight)
280 plat->low = sec->floorheight;
281
282 plat->high = sec->floorheight;
283 plat->wait = 35*PLATWAIT;
284 plat->status = down;
285 S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
286 break;
287
288 case perpetualRaise:
289 plat->speed = PLATSPEED;
290 plat->low = P_FindLowestFloorSurrounding(sec);
291
292 if (plat->low > sec->floorheight)
293 plat->low = sec->floorheight;
294
295 plat->high = P_FindHighestFloorSurrounding(sec);
296
297 if (plat->high < sec->floorheight)
298 plat->high = sec->floorheight;
299
300 plat->wait = 35*PLATWAIT;
301 plat->status = P_Random(pr_plats)&1;
302
303 S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
304 break;
305
306 case toggleUpDn: //jff 3/14/98 add new type to support instant toggle
307 plat->speed = PLATSPEED; //not used
308 plat->wait = 35*PLATWAIT; //not used
309 plat->crush = true; //jff 3/14/98 crush anything in the way
310
311 // set up toggling between ceiling, floor inclusive
312 plat->low = sec->ceilingheight;
313 plat->high = sec->floorheight;
314 plat->status = down;
315 break;
316
317 default:
318 break;
319 }
320 P_AddActivePlat(plat); // add plat to list of active plats
321 }
322 return rtn;
323}
324
325// The following were all rewritten by Lee Killough
326// to use the new structure which places no limits
327// on active plats. It also avoids spending as much
328// time searching for active plats. Previously a
329// fixed-size array was used, with NULL indicating
330// empty entries, while now a doubly-linked list
331// is used.
332
333//
334// P_ActivateInStasis()
335//
336// Activate a plat that has been put in stasis
337// (stopped perpetual floor, instant floor/ceil toggle)
338//
339// Passed the tag of the plat that should be reactivated
340// Returns nothing
341//
342void P_ActivateInStasis(int tag)
343{
344 platlist_t *pl;
345 for (pl=activeplats; pl; pl=pl->next) // search the active plats
346 {
347 plat_t *plat = pl->plat; // for one in stasis with right tag
348 if (plat->tag == tag && plat->status == in_stasis)
349 {
350 if (plat->type==toggleUpDn) //jff 3/14/98 reactivate toggle type
351 plat->status = plat->oldstatus==up? down : up;
352 else
353 plat->status = plat->oldstatus;
354 plat->thinker.function = T_PlatRaise;
355 }
356 }
357}
358
359//
360// EV_StopPlat()
361//
362// Handler for "stop perpetual floor" linedef type
363//
364// Passed the linedef that stopped the plat
365// Returns true if a plat was put in stasis
366//
367// jff 2/12/98 added int return value, fixed return
368//
369int EV_StopPlat(line_t* line)
370{
371 platlist_t *pl;
372 for (pl=activeplats; pl; pl=pl->next) // search the active plats
373 {
374 plat_t *plat = pl->plat; // for one with the tag not in stasis
375 if (plat->status != in_stasis && plat->tag == line->tag)
376 {
377 plat->oldstatus = plat->status; // put it in stasis
378 plat->status = in_stasis;
379 plat->thinker.function = NULL;
380 }
381 }
382 return 1;
383}
384
385//
386// P_AddActivePlat()
387//
388// Add a plat to the head of the active plat list
389//
390// Passed a pointer to the plat to add
391// Returns nothing
392//
393void P_AddActivePlat(plat_t* plat)
394{
395 platlist_t *list = malloc(sizeof *list);
396 list->plat = plat;
397 plat->list = list;
398 if ((list->next = activeplats))
399 list->next->prev = &list->next;
400 list->prev = &activeplats;
401 activeplats = list;
402}
403
404//
405// P_RemoveActivePlat()
406//
407// Remove a plat from the active plat list
408//
409// Passed a pointer to the plat to remove
410// Returns nothing
411//
412void P_RemoveActivePlat(plat_t* plat)
413{
414 platlist_t *list = plat->list;
415 plat->sector->floordata = NULL; //jff 2/23/98 multiple thinkers
416 P_RemoveThinker(&plat->thinker);
417 if ((*list->prev = list->next))
418 list->next->prev = list->prev;
419 free(list);
420}
421
422//
423// P_RemoveAllActivePlats()
424//
425// Remove all plats from the active plat list
426//
427// Passed nothing, returns nothing
428//
429void P_RemoveAllActivePlats(void)
430{
431 while (activeplats)
432 {
433 platlist_t *next = activeplats->next;
434 free(activeplats);
435 activeplats = next;
436 }
437}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Weapon sprite animation, weapon objects.
31 * Action functions for weapons.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#include "doomstat.h"
36#include "r_main.h"
37#include "p_map.h"
38#include "p_inter.h"
39#include "p_pspr.h"
40#include "p_enemy.h"
41#include "m_random.h"
42#include "s_sound.h"
43#include "sounds.h"
44#include "d_event.h"
45#include "r_demo.h"
46
47#define LOWERSPEED (FRACUNIT*6)
48#define RAISESPEED (FRACUNIT*6)
49#define WEAPONBOTTOM (FRACUNIT*128)
50#define WEAPONTOP (FRACUNIT*32)
51
52#define BFGCELLS bfgcells /* Ty 03/09/98 externalized in p_inter.c */
53
54extern void P_Thrust(player_t *, angle_t, fixed_t);
55
56// The following array holds the recoil values // phares
57
58static const int recoil_values[] = { // phares
59 10, // wp_fist
60 10, // wp_pistol
61 30, // wp_shotgun
62 10, // wp_chaingun
63 100,// wp_missile
64 20, // wp_plasma
65 100,// wp_bfg
66 0, // wp_chainsaw
67 80 // wp_supershotgun
68};
69
70//
71// P_SetPsprite
72//
73
74static void P_SetPsprite(player_t *player, int position, statenum_t stnum)
75{
76 pspdef_t *psp = &player->psprites[position];
77
78 do
79 {
80 state_t *state;
81
82 if (!stnum)
83 {
84 // object removed itself
85 psp->state = NULL;
86 break;
87 }
88
89 state = &states[stnum];
90 psp->state = state;
91 psp->tics = state->tics; // could be 0
92
93 if (state->misc1)
94 {
95 // coordinate set
96 psp->sx = state->misc1 << FRACBITS;
97 psp->sy = state->misc2 << FRACBITS;
98 }
99
100 // Call action routine.
101 // Modified handling.
102 if (state->action)
103 {
104 state->action(player, psp);
105 if (!psp->state)
106 break;
107 }
108 stnum = psp->state->nextstate;
109 }
110 while (!psp->tics); // an initial state of 0 could cycle through
111}
112
113//
114// P_BringUpWeapon
115// Starts bringing the pending weapon up
116// from the bottom of the screen.
117// Uses player
118//
119
120static void P_BringUpWeapon(player_t *player)
121{
122 statenum_t newstate;
123
124 if (player->pendingweapon == wp_nochange)
125 player->pendingweapon = player->readyweapon;
126
127 if (player->pendingweapon == wp_chainsaw)
128 S_StartSound (player->mo, sfx_sawup);
129
130 newstate = weaponinfo[player->pendingweapon].upstate;
131
132 player->pendingweapon = wp_nochange;
133 // killough 12/98: prevent pistol from starting visibly at bottom of screen:
134 player->psprites[ps_weapon].sy =
135 mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM;
136
137 P_SetPsprite(player, ps_weapon, newstate);
138}
139
140// The first set is where the weapon preferences from // killough,
141// default.cfg are stored. These values represent the keys used // phares
142// in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These // |
143// are NOT the wp_* constants. // V
144
145int weapon_preferences[2][NUMWEAPONS+1] = {
146 {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // !compatibility preferences
147 {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // compatibility preferences
148};
149
150// P_SwitchWeapon checks current ammo levels and gives you the
151// most preferred weapon with ammo. It will not pick the currently
152// raised weapon. When called from P_CheckAmmo this won't matter,
153// because the raised weapon has no ammo anyway. When called from
154// G_BuildTiccmd you want to toggle to a different weapon regardless.
155
156int P_SwitchWeapon(player_t *player)
157{
158 int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98
159 int currentweapon = player->readyweapon;
160 int newweapon = currentweapon;
161 int i = NUMWEAPONS+1; // killough 5/2/98
162
163 // killough 2/8/98: follow preferences and fix BFG/SSG bugs
164
165 do
166 switch (*prefer++)
167 {
168 case 1:
169 if (!player->powers[pw_strength]) // allow chainsaw override
170 break;
171 case 0:
172 newweapon = wp_fist;
173 break;
174 case 2:
175 if (player->ammo[am_clip])
176 newweapon = wp_pistol;
177 break;
178 case 3:
179 if (player->weaponowned[wp_shotgun] && player->ammo[am_shell])
180 newweapon = wp_shotgun;
181 break;
182 case 4:
183 if (player->weaponowned[wp_chaingun] && player->ammo[am_clip])
184 newweapon = wp_chaingun;
185 break;
186 case 5:
187 if (player->weaponowned[wp_missile] && player->ammo[am_misl])
188 newweapon = wp_missile;
189 break;
190 case 6:
191 if (player->weaponowned[wp_plasma] && player->ammo[am_cell] &&
192 gamemode != shareware)
193 newweapon = wp_plasma;
194 break;
195 case 7:
196 if (player->weaponowned[wp_bfg] && gamemode != shareware &&
197 player->ammo[am_cell] >= (demo_compatibility ? 41 : 40))
198 newweapon = wp_bfg;
199 break;
200 case 8:
201 if (player->weaponowned[wp_chainsaw])
202 newweapon = wp_chainsaw;
203 break;
204 case 9:
205 if (player->weaponowned[wp_supershotgun] && gamemode == commercial &&
206 player->ammo[am_shell] >= (demo_compatibility ? 3 : 2))
207 newweapon = wp_supershotgun;
208 break;
209 }
210 while (newweapon==currentweapon && --i); // killough 5/2/98
211 return newweapon;
212}
213
214// killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2.
215int P_WeaponPreferred(int w1, int w2)
216{
217 return
218 (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 ||
219 (weapon_preferences[0][1] != w2 && (weapon_preferences[0][1] == w1 ||
220 (weapon_preferences[0][2] != w2 && (weapon_preferences[0][2] == w1 ||
221 (weapon_preferences[0][3] != w2 && (weapon_preferences[0][3] == w1 ||
222 (weapon_preferences[0][4] != w2 && (weapon_preferences[0][4] == w1 ||
223 (weapon_preferences[0][5] != w2 && (weapon_preferences[0][5] == w1 ||
224 (weapon_preferences[0][6] != w2 && (weapon_preferences[0][6] == w1 ||
225 (weapon_preferences[0][7] != w2 && (weapon_preferences[0][7] == w1
226 ))))))))))))))));
227}
228
229//
230// P_CheckAmmo
231// Returns true if there is enough ammo to shoot.
232// If not, selects the next weapon to use.
233// (only in demo_compatibility mode -- killough 3/22/98)
234//
235
236boolean P_CheckAmmo(player_t *player)
237{
238 ammotype_t ammo = weaponinfo[player->readyweapon].ammo;
239 int count = 1; // Regular
240
241 if (player->readyweapon == wp_bfg) // Minimal amount for one shot varies.
242 count = BFGCELLS;
243 else
244 if (player->readyweapon == wp_supershotgun) // Double barrel.
245 count = 2;
246
247 // Some do not need ammunition anyway.
248 // Return if current ammunition sufficient.
249
250 if (ammo == am_noammo || player->ammo[ammo] >= count)
251 return true;
252
253 // Out of ammo, pick a weapon to change to.
254 //
255 // killough 3/22/98: for old demos we do the switch here and now;
256 // for Boom games we cannot do this, and have different player
257 // preferences across demos or networks, so we have to use the
258 // G_BuildTiccmd() interface instead of making the switch here.
259
260 if (demo_compatibility)
261 {
262 player->pendingweapon = P_SwitchWeapon(player); // phares
263 // Now set appropriate weapon overlay.
264 P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate);
265 }
266
267 return false;
268}
269
270//
271// P_FireWeapon.
272//
273
274static void P_FireWeapon(player_t *player)
275{
276 statenum_t newstate;
277
278 if (!P_CheckAmmo(player))
279 return;
280
281 P_SetMobjState(player->mo, S_PLAY_ATK1);
282 newstate = weaponinfo[player->readyweapon].atkstate;
283 P_SetPsprite(player, ps_weapon, newstate);
284 P_NoiseAlert(player->mo, player->mo);
285}
286
287//
288// P_DropWeapon
289// Player died, so put the weapon away.
290//
291
292void P_DropWeapon(player_t *player)
293{
294 P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate);
295}
296
297//
298// A_WeaponReady
299// The player can fire the weapon
300// or change to another weapon at this time.
301// Follows after getting weapon up,
302// or after previous attack/fire sequence.
303//
304
305void A_WeaponReady(player_t *player, pspdef_t *psp)
306{
307 // get out of attack state
308 if (player->mo->state == &states[S_PLAY_ATK1]
309 || player->mo->state == &states[S_PLAY_ATK2] )
310 P_SetMobjState(player->mo, S_PLAY);
311
312 if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW])
313 S_StartSound(player->mo, sfx_sawidl);
314
315 // check for change
316 // if player is dead, put the weapon away
317
318 if (player->pendingweapon != wp_nochange || !player->health)
319 {
320 // change weapon (pending weapon should already be validated)
321 statenum_t newstate = weaponinfo[player->readyweapon].downstate;
322 P_SetPsprite(player, ps_weapon, newstate);
323 return;
324 }
325
326 // check for fire
327 // the missile launcher and bfg do not auto fire
328
329 if (player->cmd.buttons & BT_ATTACK)
330 {
331 if (!player->attackdown || (player->readyweapon != wp_missile &&
332 player->readyweapon != wp_bfg))
333 {
334 player->attackdown = true;
335 P_FireWeapon(player);
336 return;
337 }
338 }
339 else
340 player->attackdown = false;
341
342 // bob the weapon based on movement speed
343 {
344 int angle = (128*leveltime) & FINEMASK;
345 psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
346 angle &= FINEANGLES/2-1;
347 psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
348 }
349}
350
351//
352// A_ReFire
353// The player can re-fire the weapon
354// without lowering it entirely.
355//
356
357void A_ReFire(player_t *player, pspdef_t *psp)
358{
359 // check for fire
360 // (if a weaponchange is pending, let it go through instead)
361
362 if ( (player->cmd.buttons & BT_ATTACK)
363 && player->pendingweapon == wp_nochange && player->health)
364 {
365 player->refire++;
366 P_FireWeapon(player);
367 }
368 else
369 {
370 player->refire = 0;
371 P_CheckAmmo(player);
372 }
373}
374
375void A_CheckReload(player_t *player, pspdef_t *psp)
376{
377 if (!P_CheckAmmo(player) && compatibility_level >= prboom_4_compatibility) {
378 /* cph 2002/08/08 - In old Doom, P_CheckAmmo would start the weapon lowering
379 * immediately. This was lost in Boom when the weapon switching logic was
380 * rewritten. But we must tell Doom that we don't need to complete the
381 * reload frames for the weapon here. G_BuildTiccmd will set ->pendingweapon
382 * for us later on. */
383 P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate);
384 }
385}
386
387//
388// A_Lower
389// Lowers current weapon,
390// and changes weapon at bottom.
391//
392
393void A_Lower(player_t *player, pspdef_t *psp)
394{
395 psp->sy += LOWERSPEED;
396
397 // Is already down.
398 if (psp->sy < WEAPONBOTTOM)
399 return;
400
401 // Player is dead.
402 if (player->playerstate == PST_DEAD)
403 {
404 psp->sy = WEAPONBOTTOM;
405 return; // don't bring weapon back up
406 }
407
408 // The old weapon has been lowered off the screen,
409 // so change the weapon and start raising it
410
411 if (!player->health)
412 { // Player is dead, so keep the weapon off screen.
413 P_SetPsprite(player, ps_weapon, S_NULL);
414 return;
415 }
416
417 player->readyweapon = player->pendingweapon;
418
419 P_BringUpWeapon(player);
420}
421
422//
423// A_Raise
424//
425
426void A_Raise(player_t *player, pspdef_t *psp)
427{
428 statenum_t newstate;
429
430 psp->sy -= RAISESPEED;
431
432 if (psp->sy > WEAPONTOP)
433 return;
434
435 psp->sy = WEAPONTOP;
436
437 // The weapon has been raised all the way,
438 // so change to the ready state.
439
440 newstate = weaponinfo[player->readyweapon].readystate;
441
442 P_SetPsprite(player, ps_weapon, newstate);
443}
444
445
446// Weapons now recoil, amount depending on the weapon. // phares
447// // |
448// The P_SetPsprite call in each of the weapon firing routines // V
449// was moved here so the recoil could be synched with the
450// muzzle flash, rather than the pressing of the trigger.
451// The BFG delay caused this to be necessary.
452
453static void A_FireSomething(player_t* player,int adder)
454{
455 P_SetPsprite(player, ps_flash,
456 weaponinfo[player->readyweapon].flashstate+adder);
457
458 // killough 3/27/98: prevent recoil in no-clipping mode
459 if (!(player->mo->flags & MF_NOCLIP))
460 if (!compatibility && weapon_recoil)
461 P_Thrust(player,
462 ANG180+player->mo->angle, // ^
463 2048*recoil_values[player->readyweapon]); // |
464} // phares
465
466//
467// A_GunFlash
468//
469
470void A_GunFlash(player_t *player, pspdef_t *psp)
471{
472 P_SetMobjState(player->mo, S_PLAY_ATK2);
473
474 A_FireSomething(player,0); // phares
475}
476
477//
478// WEAPON ATTACKS
479//
480
481//
482// A_Punch
483//
484
485void A_Punch(player_t *player, pspdef_t *psp)
486{
487 angle_t angle;
488 int t, slope, damage = (P_Random(pr_punch)%10+1)<<1;
489
490 if (player->powers[pw_strength])
491 damage *= 10;
492
493 angle = player->mo->angle;
494
495 // killough 5/5/98: remove dependence on order of evaluation:
496 t = P_Random(pr_punchangle);
497 angle += (t - P_Random(pr_punchangle))<<18;
498
499 /* killough 8/2/98: make autoaiming prefer enemies */
500 if (!mbf_features ||
501 (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND),
502 !linetarget))
503 slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0);
504
505 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
506
507 if (!linetarget)
508 return;
509
510 S_StartSound(player->mo, sfx_punch);
511
512 // turn to face target
513
514 player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y,
515 linetarget->x, linetarget->y);
516 R_SmoothPlaying_Reset(player); // e6y
517}
518
519//
520// A_Saw
521//
522
523void A_Saw(player_t *player, pspdef_t *psp)
524{
525 int slope, damage = 2*(P_Random(pr_saw)%10+1);
526 angle_t angle = player->mo->angle;
527 // killough 5/5/98: remove dependence on order of evaluation:
528 int t = P_Random(pr_saw);
529 angle += (t - P_Random(pr_saw))<<18;
530
531 /* Use meleerange + 1 so that the puff doesn't skip the flash
532 * killough 8/2/98: make autoaiming prefer enemies */
533 if (!mbf_features ||
534 (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND),
535 !linetarget))
536 slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0);
537
538 P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage);
539
540 if (!linetarget)
541 {
542 S_StartSound(player->mo, sfx_sawful);
543 return;
544 }
545
546 S_StartSound(player->mo, sfx_sawhit);
547
548 // turn to face target
549 angle = R_PointToAngle2(player->mo->x, player->mo->y,
550 linetarget->x, linetarget->y);
551
552 if (angle - player->mo->angle > ANG180) {
553 if (angle - player->mo->angle < -ANG90/20)
554 player->mo->angle = angle + ANG90/21;
555 else
556 player->mo->angle -= ANG90/20;
557 } else {
558 if (angle - player->mo->angle > ANG90/20)
559 player->mo->angle = angle - ANG90/21;
560 else
561 player->mo->angle += ANG90/20;
562 }
563
564 player->mo->flags |= MF_JUSTATTACKED;
565 R_SmoothPlaying_Reset(player); // e6y
566}
567
568//
569// A_FireMissile
570//
571
572void A_FireMissile(player_t *player, pspdef_t *psp)
573{
574 player->ammo[weaponinfo[player->readyweapon].ammo]--;
575 P_SpawnPlayerMissile(player->mo, MT_ROCKET);
576}
577
578//
579// A_FireBFG
580//
581
582void A_FireBFG(player_t *player, pspdef_t *psp)
583{
584 player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
585 P_SpawnPlayerMissile(player->mo, MT_BFG);
586}
587
588//
589// A_FirePlasma
590//
591
592void A_FirePlasma(player_t *player, pspdef_t *psp)
593{
594 player->ammo[weaponinfo[player->readyweapon].ammo]--;
595
596 A_FireSomething(player,P_Random(pr_plasma)&1); // phares
597 P_SpawnPlayerMissile(player->mo, MT_PLASMA);
598}
599
600//
601// P_BulletSlope
602// Sets a slope so a near miss is at aproximately
603// the height of the intended target
604//
605
606static fixed_t bulletslope;
607
608static void P_BulletSlope(mobj_t *mo)
609{
610 angle_t an = mo->angle; // see which target is to be aimed at
611
612 /* killough 8/2/98: make autoaiming prefer enemies */
613 uint_64_t mask = mbf_features ? MF_FRIEND : 0;
614
615 do
616 {
617 bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask);
618 if (!linetarget)
619 bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask);
620 if (!linetarget)
621 bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask);
622 }
623 while (mask && (mask=0, !linetarget)); /* killough 8/2/98 */
624}
625
626//
627// P_GunShot
628//
629
630static void P_GunShot(mobj_t *mo, boolean accurate)
631{
632 int damage = 5*(P_Random(pr_gunshot)%3+1);
633 angle_t angle = mo->angle;
634
635 if (!accurate)
636 { // killough 5/5/98: remove dependence on order of evaluation:
637 int t = P_Random(pr_misfire);
638 angle += (t - P_Random(pr_misfire))<<18;
639 }
640
641 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
642}
643
644//
645// A_FirePistol
646//
647
648void A_FirePistol(player_t *player, pspdef_t *psp)
649{
650 S_StartSound(player->mo, sfx_pistol);
651
652 P_SetMobjState(player->mo, S_PLAY_ATK2);
653 player->ammo[weaponinfo[player->readyweapon].ammo]--;
654
655 A_FireSomething(player,0); // phares
656 P_BulletSlope(player->mo);
657 P_GunShot(player->mo, !player->refire);
658}
659
660//
661// A_FireShotgun
662//
663
664void A_FireShotgun(player_t *player, pspdef_t *psp)
665{
666 int i;
667
668 S_StartSound(player->mo, sfx_shotgn);
669 P_SetMobjState(player->mo, S_PLAY_ATK2);
670
671 player->ammo[weaponinfo[player->readyweapon].ammo]--;
672
673 A_FireSomething(player,0); // phares
674
675 P_BulletSlope(player->mo);
676
677 for (i=0; i<7; i++)
678 P_GunShot(player->mo, false);
679}
680
681//
682// A_FireShotgun2
683//
684
685void A_FireShotgun2(player_t *player, pspdef_t *psp)
686{
687 int i;
688
689 S_StartSound(player->mo, sfx_dshtgn);
690 P_SetMobjState(player->mo, S_PLAY_ATK2);
691 player->ammo[weaponinfo[player->readyweapon].ammo] -= 2;
692
693 A_FireSomething(player,0); // phares
694
695 P_BulletSlope(player->mo);
696
697 for (i=0; i<20; i++)
698 {
699 int damage = 5*(P_Random(pr_shotgun)%3+1);
700 angle_t angle = player->mo->angle;
701 // killough 5/5/98: remove dependence on order of evaluation:
702 int t = P_Random(pr_shotgun);
703 angle += (t - P_Random(pr_shotgun))<<19;
704 t = P_Random(pr_shotgun);
705 P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope +
706 ((t - P_Random(pr_shotgun))<<5), damage);
707 }
708}
709
710//
711// A_FireCGun
712//
713
714void A_FireCGun(player_t *player, pspdef_t *psp)
715{
716 if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound])
717 S_StartSound(player->mo, sfx_pistol);
718
719 if (!player->ammo[weaponinfo[player->readyweapon].ammo])
720 return;
721
722 P_SetMobjState(player->mo, S_PLAY_ATK2);
723 player->ammo[weaponinfo[player->readyweapon].ammo]--;
724
725 A_FireSomething(player,psp->state - &states[S_CHAIN1]); // phares
726
727 P_BulletSlope(player->mo);
728
729 P_GunShot(player->mo, !player->refire);
730}
731
732void A_Light0(player_t *player, pspdef_t *psp)
733{
734 player->extralight = 0;
735}
736
737void A_Light1 (player_t *player, pspdef_t *psp)
738{
739 player->extralight = 1;
740}
741
742void A_Light2 (player_t *player, pspdef_t *psp)
743{
744 player->extralight = 2;
745}
746
747//
748// A_BFGSpray
749// Spawn a BFG explosion on every monster in view
750//
751
752void A_BFGSpray(mobj_t *mo)
753{
754 int i;
755
756 for (i=0 ; i<40 ; i++) // offset angles from its attack angle
757 {
758 int j, damage;
759 angle_t an = mo->angle - ANG90/2 + ANG90/40*i;
760
761 // mo->target is the originator (player) of the missile
762
763 // killough 8/2/98: make autoaiming prefer enemies
764 if (!mbf_features ||
765 (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND),
766 !linetarget))
767 P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0);
768
769 if (!linetarget)
770 continue;
771
772 P_SpawnMobj(linetarget->x, linetarget->y,
773 linetarget->z + (linetarget->height>>2), MT_EXTRABFG);
774
775 for (damage=j=0; j<15; j++)
776 damage += (P_Random(pr_bfg)&7) + 1;
777
778 P_DamageMobj(linetarget, mo->target, mo->target, damage);
779 }
780}
781
782//
783// A_BFGsound
784//
785
786void A_BFGsound(player_t *player, pspdef_t *psp)
787{
788 S_StartSound(player->mo, sfx_bfg);
789}
790
791//
792// P_SetupPsprites
793// Called at start of level for each player.
794//
795
796void P_SetupPsprites(player_t *player)
797{
798 int i;
799
800 // remove all psprites
801 for (i=0; i<NUMPSPRITES; i++)
802 player->psprites[i].state = NULL;
803
804 // spawn the gun
805 player->pendingweapon = player->readyweapon;
806 P_BringUpWeapon(player);
807}
808
809//
810// P_MovePsprites
811// Called every tic by player thinking routine.
812//
813
814void P_MovePsprites(player_t *player)
815{
816 pspdef_t *psp = player->psprites;
817 int i;
818
819 // a null state means not active
820 // drop tic count and possibly change state
821 // a -1 tic count never changes
822
823 for (i=0; i<NUMPSPRITES; i++, psp++)
824 if (psp->state && psp->tics != -1 && !--psp->tics)
825 P_SetPsprite(player, i, psp->state->nextstate);
826
827 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
828 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
829}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Sprite animation.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __P_PSPR__
35#define __P_PSPR__
36
37/* Basic data types.
38 * Needs fixed point, and BAM angles. */
39
40#include "m_fixed.h"
41#include "tables.h"
42
43/* Needs to include the precompiled sprite animation tables.
44 *
45 * Header generated by multigen utility.
46 * This includes all the data for thing animation,
47 * i.e. the Thing Atrributes table and the Frame Sequence table.
48 */
49
50#include "info.h"
51
52#ifdef __GNUG__
53#pragma interface
54#endif
55
56/*
57 * Frame flags:
58 * handles maximum brightness (torches, muzzle flare, light sources)
59 */
60
61#define FF_FULLBRIGHT 0x8000 /* flag in thing->frame */
62#define FF_FRAMEMASK 0x7fff
63
64/*
65 * Overlay psprites are scaled shapes
66 * drawn directly on the view screen,
67 * coordinates are given for a 320*200 view screen.
68 */
69
70typedef enum
71{
72 ps_weapon,
73 ps_flash,
74 NUMPSPRITES
75} psprnum_t;
76
77typedef struct
78{
79 state_t *state; /* a NULL state means not active */
80 int tics;
81 fixed_t sx;
82 fixed_t sy;
83} pspdef_t;
84
85extern int weapon_preferences[2][NUMWEAPONS+1]; /* killough 5/2/98 */
86int P_WeaponPreferred(int w1, int w2);
87
88struct player_s;
89int P_SwitchWeapon(struct player_s *player);
90boolean P_CheckAmmo(struct player_s *player);
91void P_SetupPsprites(struct player_s *curplayer);
92void P_MovePsprites(struct player_s *curplayer);
93void P_DropWeapon(struct player_s *player);
94
95void A_Light0();
96void A_WeaponReady();
97void A_Lower();
98void A_Raise();
99void A_Punch();
100void A_ReFire();
101void A_FirePistol();
102void A_Light1();
103void A_FireShotgun();
104void A_Light2();
105void A_FireShotgun2();
106void A_CheckReload();
107void A_OpenShotgun2();
108void A_LoadShotgun2();
109void A_CloseShotgun2();
110void A_FireCGun();
111void A_GunFlash();
112void A_FireMissile();
113void A_Saw();
114void A_FirePlasma();
115void A_BFGsound();
116void A_FireBFG();
117void A_BFGSpray();
118
119#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Archiving: SaveGame I/O.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "r_main.h"
36#include "p_maputl.h"
37#include "p_spec.h"
38#include "p_tick.h"
39#include "p_saveg.h"
40#include "m_random.h"
41#include "am_map.h"
42#include "p_enemy.h"
43#include "lprintf.h"
44
45byte *save_p;
46
47// Pads save_p to a 4-byte boundary
48// so that the load/save works on SGI&Gecko.
49#define PADSAVEP() do { save_p += (4 - ((int) save_p & 3)) & 3; } while (0)
50//
51// P_ArchivePlayers
52//
53void P_ArchivePlayers (void)
54{
55 int i;
56
57 CheckSaveGame(sizeof(player_t) * MAXPLAYERS); // killough
58 for (i=0 ; i<MAXPLAYERS ; i++)
59 if (playeringame[i])
60 {
61 int j;
62 player_t *dest;
63
64 PADSAVEP();
65 dest = (player_t *) save_p;
66 memcpy(dest, &players[i], sizeof(player_t));
67 save_p += sizeof(player_t);
68 for (j=0; j<NUMPSPRITES; j++)
69 if (dest->psprites[j].state)
70 dest->psprites[j].state =
71 (state_t *)(dest->psprites[j].state-states);
72 }
73}
74
75//
76// P_UnArchivePlayers
77//
78void P_UnArchivePlayers (void)
79{
80 int i;
81
82 for (i=0 ; i<MAXPLAYERS ; i++)
83 if (playeringame[i])
84 {
85 int j;
86
87 PADSAVEP();
88
89 memcpy(&players[i], save_p, sizeof(player_t));
90 save_p += sizeof(player_t);
91
92 // will be set when unarc thinker
93 players[i].mo = NULL;
94 players[i].message = NULL;
95 players[i].attacker = NULL;
96
97 for (j=0 ; j<NUMPSPRITES ; j++)
98 if (players[i]. psprites[j].state)
99 players[i]. psprites[j].state =
100 &states[ (int)players[i].psprites[j].state ];
101 }
102}
103
104
105//
106// P_ArchiveWorld
107//
108void P_ArchiveWorld (void)
109{
110 int i;
111 const sector_t *sec;
112 const line_t *li;
113 const side_t *si;
114 short *put;
115
116 // killough 3/22/98: fix bug caused by hoisting save_p too early
117 // killough 10/98: adjust size for changes below
118 size_t size =
119 (sizeof(short)*5 + sizeof sec->floorheight + sizeof sec->ceilingheight)
120 * numsectors + sizeof(short)*3*numlines + 4;
121
122 for (i=0; i<numlines; i++)
123 {
124 if (lines[i].sidenum[0] != NO_INDEX)
125 size +=
126 sizeof(short)*3 + sizeof si->textureoffset + sizeof si->rowoffset;
127 if (lines[i].sidenum[1] != NO_INDEX)
128 size +=
129 sizeof(short)*3 + sizeof si->textureoffset + sizeof si->rowoffset;
130 }
131
132 CheckSaveGame(size); // killough
133
134 PADSAVEP(); // killough 3/22/98
135
136 put = (short *)save_p;
137
138 // do sectors
139 for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
140 {
141 // killough 10/98: save full floor & ceiling heights, including fraction
142 memcpy(put, &sec->floorheight, sizeof sec->floorheight);
143 put = (void *)((char *) put + sizeof sec->floorheight);
144 memcpy(put, &sec->ceilingheight, sizeof sec->ceilingheight);
145 put = (void *)((char *) put + sizeof sec->ceilingheight);
146
147 *put++ = sec->floorpic;
148 *put++ = sec->ceilingpic;
149 *put++ = sec->lightlevel;
150 *put++ = sec->special; // needed? yes -- transfer types
151 *put++ = sec->tag; // needed? need them -- killough
152 }
153
154 // do lines
155 for (i=0, li = lines ; i<numlines ; i++,li++)
156 {
157 int j;
158
159 *put++ = li->flags;
160 *put++ = li->special;
161 *put++ = li->tag;
162
163 for (j=0; j<2; j++)
164 if (li->sidenum[j] != NO_INDEX)
165 {
166 si = &sides[li->sidenum[j]];
167
168 // killough 10/98: save full sidedef offsets,
169 // preserving fractional scroll offsets
170
171 memcpy(put, &si->textureoffset, sizeof si->textureoffset);
172 put = (void *)((char *) put + sizeof si->textureoffset);
173 memcpy(put, &si->rowoffset, sizeof si->rowoffset);
174 put = (void *)((char *) put + sizeof si->rowoffset);
175
176 *put++ = si->toptexture;
177 *put++ = si->bottomtexture;
178 *put++ = si->midtexture;
179 }
180 }
181 save_p = (byte *) put;
182}
183
184
185
186//
187// P_UnArchiveWorld
188//
189void P_UnArchiveWorld (void)
190{
191 int i;
192 sector_t *sec;
193 line_t *li;
194 const short *get;
195
196 PADSAVEP(); // killough 3/22/98
197
198 get = (short *) save_p;
199
200 // do sectors
201 for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
202 {
203 // killough 10/98: load full floor & ceiling heights, including fractions
204
205 memcpy(&sec->floorheight, get, sizeof sec->floorheight);
206 get = (void *)((char *) get + sizeof sec->floorheight);
207 memcpy(&sec->ceilingheight, get, sizeof sec->ceilingheight);
208 get = (void *)((char *) get + sizeof sec->ceilingheight);
209
210 sec->floorpic = *get++;
211 sec->ceilingpic = *get++;
212 sec->lightlevel = *get++;
213 sec->special = *get++;
214 sec->tag = *get++;
215 sec->ceilingdata = 0; //jff 2/22/98 now three thinker fields, not two
216 sec->floordata = 0;
217 sec->lightingdata = 0;
218 sec->soundtarget = 0;
219 }
220
221 // do lines
222 for (i=0, li = lines ; i<numlines ; i++,li++)
223 {
224 int j;
225
226 li->flags = *get++;
227 li->special = *get++;
228 li->tag = *get++;
229 for (j=0 ; j<2 ; j++)
230 if (li->sidenum[j] != NO_INDEX)
231 {
232 side_t *si = &sides[li->sidenum[j]];
233
234 // killough 10/98: load full sidedef offsets, including fractions
235
236 memcpy(&si->textureoffset, get, sizeof si->textureoffset);
237 get = (void *)((char *) get + sizeof si->textureoffset);
238 memcpy(&si->rowoffset, get, sizeof si->rowoffset);
239 get = (void *)((char *) get + sizeof si->rowoffset);
240
241 si->toptexture = *get++;
242 si->bottomtexture = *get++;
243 si->midtexture = *get++;
244 }
245 }
246 save_p = (byte *) get;
247}
248
249//
250// Thinkers
251//
252
253typedef enum {
254 tc_end,
255 tc_mobj
256} thinkerclass_t;
257
258// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the
259// thinker indices could be used by the code that saves sector info.
260
261static int number_of_thinkers;
262
263void P_ThinkerToIndex(void)
264 {
265 thinker_t *th;
266
267 // killough 2/14/98:
268 // count the number of thinkers, and mark each one with its index, using
269 // the prev field as a placeholder, since it can be restored later.
270
271 number_of_thinkers = 0;
272 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
273 if (th->function == P_MobjThinker)
274 th->prev = (thinker_t *) ++number_of_thinkers;
275 }
276
277// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the
278// thinker indices could be used by the code that saves sector info.
279
280void P_IndexToThinker(void)
281 {
282 // killough 2/14/98: restore prev pointers
283 thinker_t *th;
284 thinker_t *prev = &thinkercap;
285
286 for (th = thinkercap.next ; th != &thinkercap ; prev=th, th=th->next)
287 th->prev = prev;
288 }
289
290//
291// P_ArchiveThinkers
292//
293// 2/14/98 killough: substantially modified to fix savegame bugs
294
295void P_ArchiveThinkers (void)
296{
297 thinker_t *th;
298
299 CheckSaveGame(sizeof brain); // killough 3/26/98: Save boss brain state
300 memcpy(save_p, &brain, sizeof brain);
301 save_p += sizeof brain;
302
303 /* check that enough room is available in savegame buffer
304 * - killough 2/14/98
305 * cph - use number_of_thinkers saved by P_ThinkerToIndex above
306 * size per object is sizeof(mobj_t) - 2*sizeof(void*) - 4*sizeof(fixed_t) plus
307 * padded type (4) plus 5*sizeof(void*), i.e. sizeof(mobj_t) + 4 +
308 * 3*sizeof(void*)
309 * cph - +1 for the tc_end
310 */
311 CheckSaveGame(number_of_thinkers*(sizeof(mobj_t)-3*sizeof(fixed_t)+4+3*sizeof(void*)) +1);
312
313 // save off the current thinkers
314 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
315 if (th->function == P_MobjThinker)
316 {
317 mobj_t *mobj;
318
319 *save_p++ = tc_mobj;
320 PADSAVEP();
321 mobj = (mobj_t *)save_p;
322 /* cph 2006/07/30 -
323 * The end of mobj_t changed from
324 * boolean invisible;
325 * mobj_t* lastenemy;
326 * mobj_t* above_monster;
327 * mobj_t* below_monster;
328 * void* touching_sectorlist;
329 * to
330 * mobj_t* lastenemy;
331 * void* touching_sectorlist;
332 * fixed_t PrevX, PrevY, PrevZ, padding;
333 * at prboom 2.4.4. There is code here to preserve the savegame format.
334 *
335 * touching_sectorlist is reconstructed anyway, so we now leave off the
336 * last 2 words of mobj_t, write 5 words of 0 and then write lastenemy
337 * into the second of these.
338 */
339 memcpy (mobj, th, sizeof(*mobj) - 2*sizeof(void*));
340 save_p += sizeof(*mobj) - 2*sizeof(void*) - 4*sizeof(fixed_t);
341 memset (save_p, 0, 5*sizeof(void*));
342 mobj->state = (state_t *)(mobj->state - states);
343
344 // killough 2/14/98: convert pointers into indices.
345 // Fixes many savegame problems, by properly saving
346 // target and tracer fields. Note: we store NULL if
347 // the thinker pointed to by these fields is not a
348 // mobj thinker.
349
350 if (mobj->target)
351 mobj->target = mobj->target->thinker.function ==
352 P_MobjThinker ?
353 (mobj_t *) mobj->target->thinker.prev : NULL;
354
355 if (mobj->tracer)
356 mobj->tracer = mobj->tracer->thinker.function ==
357 P_MobjThinker ?
358 (mobj_t *) mobj->tracer->thinker.prev : NULL;
359
360 // killough 2/14/98: new field: save last known enemy. Prevents
361 // monsters from going to sleep after killing monsters and not
362 // seeing player anymore.
363
364 if (((mobj_t*)th)->lastenemy && ((mobj_t*)th)->lastenemy->thinker.function == P_MobjThinker) {
365 memcpy (save_p + sizeof(void*), &(((mobj_t*)th)->lastenemy->thinker.prev), sizeof(void*));
366 }
367
368 // killough 2/14/98: end changes
369
370 save_p += 5*sizeof(void*);
371
372 if (mobj->player)
373 mobj->player = (player_t *)((mobj->player-players) + 1);
374 }
375
376 // add a terminating marker
377 *save_p++ = tc_end;
378
379 // killough 9/14/98: save soundtargets
380 {
381 int i;
382 CheckSaveGame(numsectors * sizeof(mobj_t *)); // killough 9/14/98
383 for (i = 0; i < numsectors; i++)
384 {
385 mobj_t *target = sectors[i].soundtarget;
386 // Fix crash on reload when a soundtarget points to a removed corpse
387 // (prboom bug #1590350)
388 if (target && target->thinker.function == P_MobjThinker)
389 target = (mobj_t *) target->thinker.prev;
390 else
391 target = NULL;
392 memcpy(save_p, &target, sizeof target);
393 save_p += sizeof target;
394 }
395 }
396}
397
398/*
399 * killough 11/98
400 *
401 * Same as P_SetTarget() in p_tick.c, except that the target is nullified
402 * first, so that no old target's reference count is decreased (when loading
403 * savegames, old targets are indices, not really pointers to targets).
404 */
405
406static void P_SetNewTarget(mobj_t **mop, mobj_t *targ)
407{
408 *mop = NULL;
409 P_SetTarget(mop, targ);
410}
411
412//
413// P_UnArchiveThinkers
414//
415// 2/14/98 killough: substantially modified to fix savegame bugs
416//
417
418// savegame file stores ints in the corresponding * field; this function
419// safely casts them back to int.
420static int P_GetMobj(mobj_t* mi, size_t s)
421{
422 size_t i = (size_t)mi;
423 if (i >= s) I_Error("Corrupt savegame");
424 return i;
425}
426
427void P_UnArchiveThinkers (void)
428{
429 thinker_t *th;
430 mobj_t **mobj_p; // killough 2/14/98: Translation table
431 size_t size; // killough 2/14/98: size of or index into table
432
433 totallive = 0;
434 // killough 3/26/98: Load boss brain state
435 memcpy(&brain, save_p, sizeof brain);
436 save_p += sizeof brain;
437
438 // remove all the current thinkers
439 for (th = thinkercap.next; th != &thinkercap; )
440 {
441 thinker_t *next = th->next;
442 if (th->function == P_MobjThinker)
443 P_RemoveMobj ((mobj_t *) th);
444 else
445 Z_Free (th);
446 th = next;
447 }
448 P_InitThinkers ();
449
450 // killough 2/14/98: count number of thinkers by skipping through them
451 {
452 byte *sp = save_p; // save pointer and skip header
453 for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98
454 { // skip all entries, adding up count
455 PADSAVEP();
456 /* cph 2006/07/30 - see comment below for change in layout of mobj_t */
457 save_p += sizeof(mobj_t)+3*sizeof(void*)-4*sizeof(fixed_t);
458 }
459
460 if (*--save_p != tc_end)
461 I_Error ("P_UnArchiveThinkers: Unknown tclass %i in savegame", *save_p);
462
463 // first table entry special: 0 maps to NULL
464 *(mobj_p = malloc(size * sizeof *mobj_p)) = 0; // table of pointers
465 save_p = sp; // restore save pointer
466 }
467
468 // read in saved thinkers
469 for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98
470 {
471 mobj_t *mobj = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL);
472
473 // killough 2/14/98 -- insert pointers to thinkers into table, in order:
474 mobj_p[size] = mobj;
475
476 PADSAVEP();
477 /* cph 2006/07/30 -
478 * The end of mobj_t changed from
479 * boolean invisible;
480 * mobj_t* lastenemy;
481 * mobj_t* above_monster;
482 * mobj_t* below_monster;
483 * void* touching_sectorlist;
484 * to
485 * mobj_t* lastenemy;
486 * void* touching_sectorlist;
487 * fixed_t PrevX, PrevY, PrevZ;
488 * at prboom 2.4.4. There is code here to preserve the savegame format.
489 *
490 * touching_sectorlist is reconstructed anyway, so we now read in all
491 * but the last 5 words from the savegame (filling all but the last 2
492 * fields of our current mobj_t. We then pull lastenemy from the 2nd of
493 * the 5 leftover words, and skip the others.
494 */
495 memcpy (mobj, save_p, sizeof(mobj_t)-2*sizeof(void*)-4*sizeof(fixed_t));
496 save_p += sizeof(mobj_t)-sizeof(void*)-4*sizeof(fixed_t);
497 memcpy (&(mobj->lastenemy), save_p, sizeof(void*));
498 save_p += 4*sizeof(void*);
499 mobj->state = states + (int) mobj->state;
500
501 if (mobj->player)
502 (mobj->player = &players[(int) mobj->player - 1]) -> mo = mobj;
503
504 P_SetThingPosition (mobj);
505 mobj->info = &mobjinfo[mobj->type];
506
507 // killough 2/28/98:
508 // Fix for falling down into a wall after savegame loaded:
509 // mobj->floorz = mobj->subsector->sector->floorheight;
510 // mobj->ceilingz = mobj->subsector->sector->ceilingheight;
511
512 mobj->thinker.function = P_MobjThinker;
513 P_AddThinker (&mobj->thinker);
514
515 if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL | MF_CORPSE)))
516 totallive++;
517 }
518
519 // killough 2/14/98: adjust target and tracer fields, plus
520 // lastenemy field, to correctly point to mobj thinkers.
521 // NULL entries automatically handled by first table entry.
522 //
523 // killough 11/98: use P_SetNewTarget() to set fields
524
525 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
526 {
527 P_SetNewTarget(&((mobj_t *) th)->target,
528 mobj_p[P_GetMobj(((mobj_t *)th)->target,size)]);
529
530 P_SetNewTarget(&((mobj_t *) th)->tracer,
531 mobj_p[P_GetMobj(((mobj_t *)th)->tracer,size)]);
532
533 P_SetNewTarget(&((mobj_t *) th)->lastenemy,
534 mobj_p[P_GetMobj(((mobj_t *)th)->lastenemy,size)]);
535 }
536
537 { // killough 9/14/98: restore soundtargets
538 int i;
539 for (i = 0; i < numsectors; i++)
540 {
541 mobj_t *target;
542 memcpy(&target, save_p, sizeof target);
543 save_p += sizeof target;
544 // Must verify soundtarget. See P_ArchiveThinkers.
545 P_SetNewTarget(&sectors[i].soundtarget, mobj_p[P_GetMobj(target,size)]);
546 }
547 }
548
549 free(mobj_p); // free translation table
550
551 // killough 3/26/98: Spawn icon landings:
552 if (gamemode == commercial)
553 P_SpawnBrainTargets();
554}
555
556//
557// P_ArchiveSpecials
558//
559enum {
560 tc_ceiling,
561 tc_door,
562 tc_floor,
563 tc_plat,
564 tc_flash,
565 tc_strobe,
566 tc_glow,
567 tc_elevator, //jff 2/22/98 new elevator type thinker
568 tc_scroll, // killough 3/7/98: new scroll effect thinker
569 tc_pusher, // phares 3/22/98: new push/pull effect thinker
570 tc_flicker, // killough 10/4/98
571 tc_endspecials
572} specials_e;
573
574//
575// Things to handle:
576//
577// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list
578// T_VerticalDoor, (vldoor_t: sector_t * swizzle),
579// T_MoveFloor, (floormove_t: sector_t * swizzle),
580// T_LightFlash, (lightflash_t: sector_t * swizzle),
581// T_StrobeFlash, (strobe_t: sector_t *),
582// T_Glow, (glow_t: sector_t *),
583// T_PlatRaise, (plat_t: sector_t *), - active list
584// T_MoveElevator, (plat_t: sector_t *), - active list // jff 2/22/98
585// T_Scroll // killough 3/7/98
586// T_Pusher // phares 3/22/98
587// T_FireFlicker // killough 10/4/98
588//
589
590void P_ArchiveSpecials (void)
591{
592 thinker_t *th;
593 size_t size = 0; // killough
594
595 // save off the current thinkers (memory size calculation -- killough)
596
597 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
598 if (!th->function)
599 {
600 platlist_t *pl;
601 ceilinglist_t *cl; //jff 2/22/98 need this for ceilings too now
602 for (pl=activeplats; pl; pl=pl->next)
603 if (pl->plat == (plat_t *) th) // killough 2/14/98
604 {
605 size += 4+sizeof(plat_t);
606 goto end;
607 }
608 for (cl=activeceilings; cl; cl=cl->next) // search for activeceiling
609 if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98
610 {
611 size += 4+sizeof(ceiling_t);
612 goto end;
613 }
614 end:;
615 }
616 else
617 size +=
618 th->function==T_MoveCeiling ? 4+sizeof(ceiling_t) :
619 th->function==T_VerticalDoor ? 4+sizeof(vldoor_t) :
620 th->function==T_MoveFloor ? 4+sizeof(floormove_t):
621 th->function==T_PlatRaise ? 4+sizeof(plat_t) :
622 th->function==T_LightFlash ? 4+sizeof(lightflash_t):
623 th->function==T_StrobeFlash ? 4+sizeof(strobe_t) :
624 th->function==T_Glow ? 4+sizeof(glow_t) :
625 th->function==T_MoveElevator ? 4+sizeof(elevator_t):
626 th->function==T_Scroll ? 4+sizeof(scroll_t) :
627 th->function==T_Pusher ? 4+sizeof(pusher_t) :
628 th->function==T_FireFlicker? 4+sizeof(fireflicker_t) :
629 0;
630
631 CheckSaveGame(size + 1); // killough; cph: +1 for the tc_endspecials
632
633 // save off the current thinkers
634 for (th=thinkercap.next; th!=&thinkercap; th=th->next)
635 {
636 if (!th->function)
637 {
638 platlist_t *pl;
639 ceilinglist_t *cl; //jff 2/22/98 add iter variable for ceilings
640
641 // killough 2/8/98: fix plat original height bug.
642 // Since acv==NULL, this could be a plat in stasis.
643 // so check the active plats list, and save this
644 // plat (jff: or ceiling) even if it is in stasis.
645
646 for (pl=activeplats; pl; pl=pl->next)
647 if (pl->plat == (plat_t *) th) // killough 2/14/98
648 goto plat;
649
650 for (cl=activeceilings; cl; cl=cl->next)
651 if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98
652 goto ceiling;
653
654 continue;
655 }
656
657 if (th->function == T_MoveCeiling)
658 {
659 ceiling_t *ceiling;
660 ceiling: // killough 2/14/98
661 *save_p++ = tc_ceiling;
662 PADSAVEP();
663 ceiling = (ceiling_t *)save_p;
664 memcpy (ceiling, th, sizeof(*ceiling));
665 save_p += sizeof(*ceiling);
666 ceiling->sector = (sector_t *)(ceiling->sector - sectors);
667 continue;
668 }
669
670 if (th->function == T_VerticalDoor)
671 {
672 vldoor_t *door;
673 *save_p++ = tc_door;
674 PADSAVEP();
675 door = (vldoor_t *) save_p;
676 memcpy (door, th, sizeof *door);
677 save_p += sizeof(*door);
678 door->sector = (sector_t *)(door->sector - sectors);
679 //jff 1/31/98 archive line remembered by door as well
680 door->line = (line_t *) (door->line ? door->line-lines : -1);
681 continue;
682 }
683
684 if (th->function == T_MoveFloor)
685 {
686 floormove_t *floor;
687 *save_p++ = tc_floor;
688 PADSAVEP();
689 floor = (floormove_t *)save_p;
690 memcpy (floor, th, sizeof(*floor));
691 save_p += sizeof(*floor);
692 floor->sector = (sector_t *)(floor->sector - sectors);
693 continue;
694 }
695
696 if (th->function == T_PlatRaise)
697 {
698 plat_t *plat;
699 plat: // killough 2/14/98: added fix for original plat height above
700 *save_p++ = tc_plat;
701 PADSAVEP();
702 plat = (plat_t *)save_p;
703 memcpy (plat, th, sizeof(*plat));
704 save_p += sizeof(*plat);
705 plat->sector = (sector_t *)(plat->sector - sectors);
706 continue;
707 }
708
709 if (th->function == T_LightFlash)
710 {
711 lightflash_t *flash;
712 *save_p++ = tc_flash;
713 PADSAVEP();
714 flash = (lightflash_t *)save_p;
715 memcpy (flash, th, sizeof(*flash));
716 save_p += sizeof(*flash);
717 flash->sector = (sector_t *)(flash->sector - sectors);
718 continue;
719 }
720
721 if (th->function == T_StrobeFlash)
722 {
723 strobe_t *strobe;
724 *save_p++ = tc_strobe;
725 PADSAVEP();
726 strobe = (strobe_t *)save_p;
727 memcpy (strobe, th, sizeof(*strobe));
728 save_p += sizeof(*strobe);
729 strobe->sector = (sector_t *)(strobe->sector - sectors);
730 continue;
731 }
732
733 if (th->function == T_Glow)
734 {
735 glow_t *glow;
736 *save_p++ = tc_glow;
737 PADSAVEP();
738 glow = (glow_t *)save_p;
739 memcpy (glow, th, sizeof(*glow));
740 save_p += sizeof(*glow);
741 glow->sector = (sector_t *)(glow->sector - sectors);
742 continue;
743 }
744
745 // killough 10/4/98: save flickers
746 if (th->function == T_FireFlicker)
747 {
748 fireflicker_t *flicker;
749 *save_p++ = tc_flicker;
750 PADSAVEP();
751 flicker = (fireflicker_t *)save_p;
752 memcpy (flicker, th, sizeof(*flicker));
753 save_p += sizeof(*flicker);
754 flicker->sector = (sector_t *)(flicker->sector - sectors);
755 continue;
756 }
757
758 //jff 2/22/98 new case for elevators
759 if (th->function == T_MoveElevator)
760 {
761 elevator_t *elevator; //jff 2/22/98
762 *save_p++ = tc_elevator;
763 PADSAVEP();
764 elevator = (elevator_t *)save_p;
765 memcpy (elevator, th, sizeof(*elevator));
766 save_p += sizeof(*elevator);
767 elevator->sector = (sector_t *)(elevator->sector - sectors);
768 continue;
769 }
770
771 // killough 3/7/98: Scroll effect thinkers
772 if (th->function == T_Scroll)
773 {
774 *save_p++ = tc_scroll;
775 memcpy (save_p, th, sizeof(scroll_t));
776 save_p += sizeof(scroll_t);
777 continue;
778 }
779
780 // phares 3/22/98: Push/Pull effect thinkers
781
782 if (th->function == T_Pusher)
783 {
784 *save_p++ = tc_pusher;
785 memcpy (save_p, th, sizeof(pusher_t));
786 save_p += sizeof(pusher_t);
787 continue;
788 }
789 }
790
791 // add a terminating marker
792 *save_p++ = tc_endspecials;
793}
794
795
796//
797// P_UnArchiveSpecials
798//
799void P_UnArchiveSpecials (void)
800{
801 byte tclass;
802
803 // read in saved thinkers
804 while ((tclass = *save_p++) != tc_endspecials) // killough 2/14/98
805 switch (tclass)
806 {
807 case tc_ceiling:
808 PADSAVEP();
809 {
810 ceiling_t *ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL);
811 memcpy (ceiling, save_p, sizeof(*ceiling));
812 save_p += sizeof(*ceiling);
813 ceiling->sector = &sectors[(int)ceiling->sector];
814 ceiling->sector->ceilingdata = ceiling; //jff 2/22/98
815
816 if (ceiling->thinker.function)
817 ceiling->thinker.function = T_MoveCeiling;
818
819 P_AddThinker (&ceiling->thinker);
820 P_AddActiveCeiling(ceiling);
821 break;
822 }
823
824 case tc_door:
825 PADSAVEP();
826 {
827 vldoor_t *door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL);
828 memcpy (door, save_p, sizeof(*door));
829 save_p += sizeof(*door);
830 door->sector = &sectors[(int)door->sector];
831
832 //jff 1/31/98 unarchive line remembered by door as well
833 door->line = (int)door->line!=-1? &lines[(int)door->line] : NULL;
834
835 door->sector->ceilingdata = door; //jff 2/22/98
836 door->thinker.function = T_VerticalDoor;
837 P_AddThinker (&door->thinker);
838 break;
839 }
840
841 case tc_floor:
842 PADSAVEP();
843 {
844 floormove_t *floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
845 memcpy (floor, save_p, sizeof(*floor));
846 save_p += sizeof(*floor);
847 floor->sector = &sectors[(int)floor->sector];
848 floor->sector->floordata = floor; //jff 2/22/98
849 floor->thinker.function = T_MoveFloor;
850 P_AddThinker (&floor->thinker);
851 break;
852 }
853
854 case tc_plat:
855 PADSAVEP();
856 {
857 plat_t *plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
858 memcpy (plat, save_p, sizeof(*plat));
859 save_p += sizeof(*plat);
860 plat->sector = &sectors[(int)plat->sector];
861 plat->sector->floordata = plat; //jff 2/22/98
862
863 if (plat->thinker.function)
864 plat->thinker.function = T_PlatRaise;
865
866 P_AddThinker (&plat->thinker);
867 P_AddActivePlat(plat);
868 break;
869 }
870
871 case tc_flash:
872 PADSAVEP();
873 {
874 lightflash_t *flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
875 memcpy (flash, save_p, sizeof(*flash));
876 save_p += sizeof(*flash);
877 flash->sector = &sectors[(int)flash->sector];
878 flash->thinker.function = T_LightFlash;
879 P_AddThinker (&flash->thinker);
880 break;
881 }
882
883 case tc_strobe:
884 PADSAVEP();
885 {
886 strobe_t *strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
887 memcpy (strobe, save_p, sizeof(*strobe));
888 save_p += sizeof(*strobe);
889 strobe->sector = &sectors[(int)strobe->sector];
890 strobe->thinker.function = T_StrobeFlash;
891 P_AddThinker (&strobe->thinker);
892 break;
893 }
894
895 case tc_glow:
896 PADSAVEP();
897 {
898 glow_t *glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
899 memcpy (glow, save_p, sizeof(*glow));
900 save_p += sizeof(*glow);
901 glow->sector = &sectors[(int)glow->sector];
902 glow->thinker.function = T_Glow;
903 P_AddThinker (&glow->thinker);
904 break;
905 }
906
907 case tc_flicker: // killough 10/4/98
908 PADSAVEP();
909 {
910 fireflicker_t *flicker = Z_Malloc (sizeof(*flicker), PU_LEVEL, NULL);
911 memcpy (flicker, save_p, sizeof(*flicker));
912 save_p += sizeof(*flicker);
913 flicker->sector = &sectors[(int)flicker->sector];
914 flicker->thinker.function = T_FireFlicker;
915 P_AddThinker (&flicker->thinker);
916 break;
917 }
918
919 //jff 2/22/98 new case for elevators
920 case tc_elevator:
921 PADSAVEP();
922 {
923 elevator_t *elevator = Z_Malloc (sizeof(*elevator), PU_LEVEL, NULL);
924 memcpy (elevator, save_p, sizeof(*elevator));
925 save_p += sizeof(*elevator);
926 elevator->sector = &sectors[(int)elevator->sector];
927 elevator->sector->floordata = elevator; //jff 2/22/98
928 elevator->sector->ceilingdata = elevator; //jff 2/22/98
929 elevator->thinker.function = T_MoveElevator;
930 P_AddThinker (&elevator->thinker);
931 break;
932 }
933
934 case tc_scroll: // killough 3/7/98: scroll effect thinkers
935 {
936 scroll_t *scroll = Z_Malloc (sizeof(scroll_t), PU_LEVEL, NULL);
937 memcpy (scroll, save_p, sizeof(scroll_t));
938 save_p += sizeof(scroll_t);
939 scroll->thinker.function = T_Scroll;
940 P_AddThinker(&scroll->thinker);
941 break;
942 }
943
944 case tc_pusher: // phares 3/22/98: new Push/Pull effect thinkers
945 {
946 pusher_t *pusher = Z_Malloc (sizeof(pusher_t), PU_LEVEL, NULL);
947 memcpy (pusher, save_p, sizeof(pusher_t));
948 save_p += sizeof(pusher_t);
949 pusher->thinker.function = T_Pusher;
950 pusher->source = P_GetPushThing(pusher->affectee);
951 P_AddThinker(&pusher->thinker);
952 break;
953 }
954
955 default:
956 I_Error("P_UnarchiveSpecials: Unknown tclass %i in savegame", tclass);
957 }
958}
959
960// killough 2/16/98: save/restore random number generator state information
961
962void P_ArchiveRNG(void)
963{
964 CheckSaveGame(sizeof rng);
965 memcpy(save_p, &rng, sizeof rng);
966 save_p += sizeof rng;
967}
968
969void P_UnArchiveRNG(void)
970{
971 memcpy(&rng, save_p, sizeof rng);
972 save_p += sizeof rng;
973}
974
975// killough 2/22/98: Save/restore automap state
976// killough 2/22/98: Save/restore automap state
977void P_ArchiveMap(void)
978{
979 int zero = 0, one = 1;
980 CheckSaveGame(2 * sizeof zero + sizeof markpointnum +
981 markpointnum * sizeof *markpoints +
982 sizeof automapmode + sizeof one);
983
984 memcpy(save_p, &automapmode, sizeof automapmode);
985 save_p += sizeof automapmode;
986 memcpy(save_p, &one, sizeof one); // CPhipps - used to be viewactive, now
987 save_p += sizeof one; // that's worked out locally by D_Display
988 memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be followplayer
989 save_p += sizeof zero; // that is now part of automapmode
990 memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be automap_grid, ditto
991 save_p += sizeof zero;
992 memcpy(save_p, &markpointnum, sizeof markpointnum);
993 save_p += sizeof markpointnum;
994
995 if (markpointnum)
996 {
997 memcpy(save_p, markpoints, sizeof *markpoints * markpointnum);
998 save_p += markpointnum * sizeof *markpoints;
999 }
1000}
1001
1002void P_UnArchiveMap(void)
1003{
1004 int unused;
1005 memcpy(&automapmode, save_p, sizeof automapmode);
1006 save_p += sizeof automapmode;
1007 memcpy(&unused, save_p, sizeof unused);
1008 save_p += sizeof unused;
1009 memcpy(&unused, save_p, sizeof unused);
1010 save_p += sizeof unused;
1011 memcpy(&unused, save_p, sizeof unused);
1012 save_p += sizeof unused;
1013
1014 if (automapmode & am_active)
1015 AM_Start();
1016
1017 memcpy(&markpointnum, save_p, sizeof markpointnum);
1018 save_p += sizeof markpointnum;
1019
1020 if (markpointnum)
1021 {
1022 while (markpointnum >= markpointnum_max)
1023 markpoints = realloc(markpoints, sizeof *markpoints *
1024 (markpointnum_max = markpointnum_max ? markpointnum_max*2 : 16));
1025 memcpy(markpoints, save_p, markpointnum * sizeof *markpoints);
1026 save_p += markpointnum * sizeof *markpoints;
1027 }
1028}
1029
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Savegame I/O, archiving, persistence.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __P_SAVEG__
35#define __P_SAVEG__
36
37#ifdef __GNUG__
38#pragma interface
39#endif
40
41/* Persistent storage/archiving.
42 * These are the load / save game routines. */
43void P_ArchivePlayers(void);
44void P_UnArchivePlayers(void);
45void P_ArchiveWorld(void);
46void P_UnArchiveWorld(void);
47void P_ArchiveThinkers(void);
48void P_UnArchiveThinkers(void);
49void P_ArchiveSpecials(void);
50void P_UnArchiveSpecials(void);
51void P_ThinkerToIndex(void); /* phares 9/13/98: save soundtarget in savegame */
52void P_IndexToThinker(void); /* phares 9/13/98: save soundtarget in savegame */
53
54/* 1/18/98 killough: add RNG info to savegame */
55void P_ArchiveRNG(void);
56void P_UnArchiveRNG(void);
57
58/* 2/21/98 killough: add automap info to savegame */
59void P_ArchiveMap(void);
60void P_UnArchiveMap(void);
61
62extern byte *save_p;
63void CheckSaveGame(size_t,const char*, int); /* killough */
64#define CheckSaveGame(a) (CheckSaveGame)(a, __FILE__, __LINE__)
65
66#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Do all the WAD I/O, get map description,
31 * set up initial state and misc. LUTs.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#include <math.h>
36
37#include "doomstat.h"
38#include "m_bbox.h"
39#include "m_argv.h"
40#include "g_game.h"
41#include "w_wad.h"
42#include "r_main.h"
43#include "r_things.h"
44#include "p_maputl.h"
45#include "p_map.h"
46#include "p_setup.h"
47#include "p_spec.h"
48#include "p_tick.h"
49#include "p_enemy.h"
50#include "s_sound.h"
51#include "lprintf.h" //jff 10/6/98 for debug outputs
52#include "v_video.h"
53#include "r_demo.h"
54#include "r_fps.h"
55
56//
57// MAP related Lookup tables.
58// Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
59//
60
61int numvertexes;
62vertex_t *vertexes;
63
64int numsegs;
65seg_t *segs;
66
67int numsectors;
68sector_t *sectors;
69
70int numsubsectors;
71subsector_t *subsectors;
72
73int numnodes;
74node_t *nodes;
75
76int numlines;
77line_t *lines;
78
79int numsides;
80side_t *sides;
81
82
83////////////////////////////////////////////////////////////////////////////////////////////
84// figgi 08/21/00 -- constants and globals for glBsp support
85#define gNd2 0x32644E67 // figgi -- suppport for new GL_VERT format v2.0
86#define gNd3 0x33644E67
87#define gNd4 0x34644E67
88#define gNd5 0x35644E67
89#define ZNOD 0x444F4E5A
90#define ZGLN 0x4E4C475A
91#define GL_VERT_OFFSET 4
92
93int firstglvertex = 0;
94int nodesVersion = 0;
95boolean forceOldBsp = false;
96
97// figgi 08/21/00 -- glSegs
98typedef struct
99{
100 unsigned short v1; // start vertex (16 bit)
101 unsigned short v2; // end vertex (16 bit)
102 unsigned short linedef; // linedef, or -1 for minisegs
103 short side; // side on linedef: 0 for right, 1 for left
104 unsigned short partner; // corresponding partner seg, or -1 on one-sided walls
105} glseg_t;
106
107// fixed 32 bit gl_vert format v2.0+ (glBsp 1.91)
108typedef struct
109{
110 fixed_t x,y;
111} mapglvertex_t;
112
113enum
114{
115 ML_GL_LABEL=0, // A separator name, GL_ExMx or GL_MAPxx
116 ML_GL_VERTS, // Extra Vertices
117 ML_GL_SEGS, // Segs, from linedefs & minisegs
118 ML_GL_SSECT, // SubSectors, list of segs
119 ML_GL_NODES // GL BSP nodes
120};
121////////////////////////////////////////////////////////////////////////////////////////////
122
123
124// BLOCKMAP
125// Created from axis aligned bounding box
126// of the map, a rectangular array of
127// blocks of size ...
128// Used to speed up collision detection
129// by spatial subdivision in 2D.
130//
131// Blockmap size.
132
133int bmapwidth, bmapheight; // size in mapblocks
134
135// killough 3/1/98: remove blockmap limit internally:
136long *blockmap; // was short -- killough
137
138// offsets in blockmap are from here
139long *blockmaplump; // was short -- killough
140
141fixed_t bmaporgx, bmaporgy; // origin of block map
142
143mobj_t **blocklinks; // for thing chains
144
145//
146// REJECT
147// For fast sight rejection.
148// Speeds up enemy AI by skipping detailed
149// LineOf Sight calculation.
150// Without the special effect, this could
151// be used as a PVS lookup as well.
152//
153
154static int rejectlump = -1;// cph - store reject lump num if cached
155const byte *rejectmatrix; // cph - const*
156
157// Maintain single and multi player starting spots.
158
159// 1/11/98 killough: Remove limit on deathmatch starts
160mapthing_t *deathmatchstarts; // killough
161size_t num_deathmatchstarts; // killough
162
163mapthing_t *deathmatch_p;
164mapthing_t playerstarts[MAXPLAYERS];
165
166//
167// P_CheckForZDoomNodes
168//
169
170static boolean P_CheckForZDoomNodes(int lumpnum, int gl_lumpnum)
171{
172 const void *data;
173
174 data = W_CacheLumpNum(lumpnum + ML_NODES);
175 if (*(const int *)data == ZNOD)
176 I_Error("P_CheckForZDoomNodes: ZDoom nodes not supported yet");
177
178 data = W_CacheLumpNum(lumpnum + ML_SSECTORS);
179 if (*(const int *)data == ZGLN)
180 I_Error("P_CheckForZDoomNodes: ZDoom GL nodes not supported yet");
181
182 return false;
183}
184
185//
186// P_GetNodesVersion
187//
188
189static void P_GetNodesVersion(int lumpnum, int gl_lumpnum)
190{
191 const void *data;
192
193 data = W_CacheLumpNum(gl_lumpnum+ML_GL_VERTS);
194 if ( (gl_lumpnum > lumpnum) && (forceOldBsp == false) && (compatibility_level >= prboom_2_compatibility) ) {
195 if (*(const int *)data == gNd2) {
196 data = W_CacheLumpNum(gl_lumpnum+ML_GL_SEGS);
197 if (*(const int *)data == gNd3) {
198 nodesVersion = gNd3;
199 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 3 nodes\n");
200 I_Error("P_GetNodesVersion: version 3 nodes not supported\n");
201 } else {
202 nodesVersion = gNd2;
203 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 2 nodes\n");
204 }
205 }
206 if (*(const int *)data == gNd4) {
207 nodesVersion = gNd4;
208 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 4 nodes\n");
209 I_Error("P_GetNodesVersion: version 4 nodes not supported\n");
210 }
211 if (*(const int *)data == gNd5) {
212 nodesVersion = gNd5;
213 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 5 nodes\n");
214 I_Error("P_GetNodesVersion: version 5 nodes not supported\n");
215 }
216 } else {
217 nodesVersion = 0;
218 lprintf(LO_DEBUG,"P_GetNodesVersion: using normal BSP nodes\n");
219 if (P_CheckForZDoomNodes(lumpnum, gl_lumpnum))
220 I_Error("P_GetNodesVersion: ZDoom nodes not supported yet");
221 }
222}
223
224//
225// P_LoadVertexes
226//
227// killough 5/3/98: reformatted, cleaned up
228//
229static void P_LoadVertexes (int lump)
230{
231 const mapvertex_t *data; // cph - const
232 int i;
233
234 // Determine number of lumps:
235 // total lump length / vertex record length.
236 numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t);
237
238 // Allocate zone memory for buffer.
239 vertexes = Z_Malloc(numvertexes*sizeof(vertex_t),PU_LEVEL,0);
240
241 // Load data into cache.
242 // cph 2006/07/29 - cast to mapvertex_t here, making the loop below much neater
243 data = (const mapvertex_t *)W_CacheLumpNum(lump);
244
245 // Copy and convert vertex coordinates,
246 // internal representation as fixed.
247 for (i=0; i<numvertexes; i++)
248 {
249 vertexes[i].x = SHORT(data[i].x)<<FRACBITS;
250 vertexes[i].y = SHORT(data[i].y)<<FRACBITS;
251 }
252
253 // Free buffer memory.
254 W_UnlockLumpNum(lump);
255}
256
257/*******************************************
258 * Name : P_LoadVertexes2 *
259 * modified : 09/18/00, adapted for PrBoom *
260 * author : figgi *
261 * what : support for gl nodes *
262 *******************************************/
263
264// figgi -- FIXME: Automap showes wrong zoom boundaries when starting game
265// when P_LoadVertexes2 is used with classic BSP nodes.
266
267static void P_LoadVertexes2(int lump, int gllump)
268{
269 const byte *gldata;
270 int i;
271 const mapvertex_t* ml;
272
273 firstglvertex = W_LumpLength(lump) / sizeof(mapvertex_t);
274 numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t);
275
276 if (gllump >= 0) // check for glVertices
277 {
278 gldata = W_CacheLumpNum(gllump);
279
280 if (nodesVersion == gNd2) // 32 bit GL_VERT format (16.16 fixed)
281 {
282 const mapglvertex_t* mgl;
283
284 numvertexes += (W_LumpLength(gllump) - GL_VERT_OFFSET)/sizeof(mapglvertex_t);
285 vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);
286 mgl = (const mapglvertex_t *) (gldata + GL_VERT_OFFSET);
287
288 for (i = firstglvertex; i < numvertexes; i++)
289 {
290 vertexes[i].x = mgl->x;
291 vertexes[i].y = mgl->y;
292 mgl++;
293 }
294 }
295 else
296 {
297 numvertexes += W_LumpLength(gllump)/sizeof(mapvertex_t);
298 vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);
299 ml = (const mapvertex_t *)gldata;
300
301 for (i = firstglvertex; i < numvertexes; i++)
302 {
303 vertexes[i].x = SHORT(ml->x)<<FRACBITS;
304 vertexes[i].y = SHORT(ml->y)<<FRACBITS;
305 ml++;
306 }
307 }
308 W_UnlockLumpNum(gllump);
309 }
310
311 ml = (const mapvertex_t*) W_CacheLumpNum(lump);
312
313 for (i=0; i < firstglvertex; i++)
314 {
315 vertexes[i].x = SHORT(ml->x)<<FRACBITS;
316 vertexes[i].y = SHORT(ml->y)<<FRACBITS;
317 ml++;
318 }
319 W_UnlockLumpNum(lump);
320}
321
322
323/*******************************************
324 * created : 08/13/00 *
325 * modified : 09/18/00, adapted for PrBoom *
326 * author : figgi *
327 * what : basic functions needed for *
328 * computing gl nodes *
329 *******************************************/
330
331static int checkGLVertex(int num)
332{
333 if (num & 0x8000)
334 num = (num&0x7FFF)+firstglvertex;
335 return num;
336}
337
338
339static float GetDistance(int dx, int dy)
340{
341 float fx = (float)(dx)/FRACUNIT, fy = (float)(dy)/FRACUNIT;
342 return (float)sqrt(fx*fx + fy*fy);
343}
344
345
346static int GetOffset(vertex_t *v1, vertex_t *v2)
347{
348 float a, b;
349 int r;
350 a = (float)(v1->x - v2->x) / (float)FRACUNIT;
351 b = (float)(v1->y - v2->y) / (float)FRACUNIT;
352 r = (int)(sqrt(a*a+b*b) * (float)FRACUNIT);
353 return r;
354}
355
356
357
358//
359// P_LoadSegs
360//
361// killough 5/3/98: reformatted, cleaned up
362
363static void P_LoadSegs (int lump)
364{
365 int i;
366 const mapseg_t *data; // cph - const
367
368 numsegs = W_LumpLength(lump) / sizeof(mapseg_t);
369 segs = Z_Calloc(numsegs,sizeof(seg_t),PU_LEVEL,0);
370 data = (const mapseg_t *)W_CacheLumpNum(lump); // cph - wad lump handling updated
371
372 if ((!data) || (!numsegs))
373 I_Error("P_LoadSegs: no segs in level");
374
375 for (i=0; i<numsegs; i++)
376 {
377 seg_t *li = segs+i;
378 const mapseg_t *ml = data + i;
379 unsigned short v1, v2;
380
381 int side, linedef;
382 line_t *ldef;
383
384 li->iSegID = i; // proff 11/05/2000: needed for OpenGL
385
386 v1 = (unsigned short)SHORT(ml->v1);
387 v2 = (unsigned short)SHORT(ml->v2);
388 li->v1 = &vertexes[v1];
389 li->v2 = &vertexes[v2];
390
391 li->miniseg = false; // figgi -- there are no minisegs in classic BSP nodes
392 li->length = GetDistance(li->v2->x - li->v1->x, li->v2->y - li->v1->y);
393 li->angle = (SHORT(ml->angle))<<16;
394 li->offset =(SHORT(ml->offset))<<16;
395 linedef = (unsigned short)SHORT(ml->linedef);
396 ldef = &lines[linedef];
397 li->linedef = ldef;
398 side = SHORT(ml->side);
399 li->sidedef = &sides[ldef->sidenum[side]];
400
401 /* cph 2006/09/30 - our frontsector can be the second side of the
402 * linedef, so must check for NO_INDEX in case we are incorrectly
403 * referencing the back of a 1S line */
404 if (ldef->sidenum[side] != NO_INDEX)
405 li->frontsector = sides[ldef->sidenum[side]].sector;
406 else {
407 li->frontsector = 0;
408 lprintf(LO_WARN, "P_LoadSegs: front of seg %i has no sidedef\n", i);
409 }
410
411 if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=NO_INDEX)
412 li->backsector = sides[ldef->sidenum[side^1]].sector;
413 else
414 li->backsector = 0;
415 }
416
417 W_UnlockLumpNum(lump); // cph - release the data
418}
419
420
421
422/*******************************************
423 * Name : P_LoadGLSegs *
424 * created : 08/13/00 *
425 * modified : 09/18/00, adapted for PrBoom *
426 * author : figgi *
427 * what : support for gl nodes *
428 *******************************************/
429static void P_LoadGLSegs(int lump)
430{
431 int i;
432 const glseg_t *ml;
433 line_t *ldef;
434
435 numsegs = W_LumpLength(lump) / sizeof(glseg_t);
436 segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0);
437 memset(segs, 0, numsegs * sizeof(seg_t));
438 ml = (const glseg_t*)W_CacheLumpNum(lump);
439
440 if ((!ml) || (!numsegs))
441 I_Error("P_LoadGLSegs: no glsegs in level");
442
443 for(i = 0; i < numsegs; i++)
444 { // check for gl-vertices
445 segs[i].v1 = &vertexes[checkGLVertex(SHORT(ml->v1))];
446 segs[i].v2 = &vertexes[checkGLVertex(SHORT(ml->v2))];
447 segs[i].iSegID = i;
448
449 if(ml->linedef != (unsigned short)-1) // skip minisegs
450 {
451 ldef = &lines[ml->linedef];
452 segs[i].linedef = ldef;
453 segs[i].miniseg = false;
454 segs[i].angle = R_PointToAngle2(segs[i].v1->x,segs[i].v1->y,segs[i].v2->x,segs[i].v2->y);
455
456 segs[i].sidedef = &sides[ldef->sidenum[ml->side]];
457 segs[i].length = GetDistance(segs[i].v2->x - segs[i].v1->x, segs[i].v2->y - segs[i].v1->y);
458 segs[i].frontsector = sides[ldef->sidenum[ml->side]].sector;
459 if (ldef->flags & ML_TWOSIDED)
460 segs[i].backsector = sides[ldef->sidenum[ml->side^1]].sector;
461 else
462 segs[i].backsector = 0;
463
464 if (ml->side)
465 segs[i].offset = GetOffset(segs[i].v1, ldef->v2);
466 else
467 segs[i].offset = GetOffset(segs[i].v1, ldef->v1);
468 }
469 else
470 {
471 segs[i].miniseg = true;
472 segs[i].angle = 0;
473 segs[i].offset = 0;
474 segs[i].length = 0;
475 segs[i].linedef = NULL;
476 segs[i].sidedef = NULL;
477 segs[i].frontsector = NULL;
478 segs[i].backsector = NULL;
479 }
480 ml++;
481 }
482 W_UnlockLumpNum(lump);
483}
484
485//
486// P_LoadSubsectors
487//
488// killough 5/3/98: reformatted, cleaned up
489
490static void P_LoadSubsectors (int lump)
491{
492 /* cph 2006/07/29 - make data a const mapsubsector_t *, so the loop below is simpler & gives no constness warnings */
493 const mapsubsector_t *data;
494 int i;
495
496 numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
497 subsectors = Z_Calloc(numsubsectors,sizeof(subsector_t),PU_LEVEL,0);
498 data = (const mapsubsector_t *)W_CacheLumpNum(lump);
499
500 if ((!data) || (!numsubsectors))
501 I_Error("P_LoadSubsectors: no subsectors in level");
502
503 for (i=0; i<numsubsectors; i++)
504 {
505 subsectors[i].numlines = (unsigned short)SHORT(data[i].numsegs );
506 subsectors[i].firstline = (unsigned short)SHORT(data[i].firstseg);
507 }
508
509 W_UnlockLumpNum(lump); // cph - release the data
510}
511
512//
513// P_LoadSectors
514//
515// killough 5/3/98: reformatted, cleaned up
516
517static void P_LoadSectors (int lump)
518{
519 const byte *data; // cph - const*
520 int i;
521
522 numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
523 sectors = Z_Calloc (numsectors,sizeof(sector_t),PU_LEVEL,0);
524 data = W_CacheLumpNum (lump); // cph - wad lump handling updated
525
526 for (i=0; i<numsectors; i++)
527 {
528 sector_t *ss = sectors + i;
529 const mapsector_t *ms = (const mapsector_t *) data + i;
530
531 ss->iSectorID=i; // proff 04/05/2000: needed for OpenGL
532 ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
533 ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
534 ss->floorpic = R_FlatNumForName(ms->floorpic);
535 ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
536 ss->lightlevel = SHORT(ms->lightlevel);
537 ss->special = SHORT(ms->special);
538 ss->oldspecial = SHORT(ms->special);
539 ss->tag = SHORT(ms->tag);
540 ss->thinglist = NULL;
541 ss->touching_thinglist = NULL; // phares 3/14/98
542
543 ss->nextsec = -1; //jff 2/26/98 add fields to support locking out
544 ss->prevsec = -1; // stair retriggering until build completes
545
546 // killough 3/7/98:
547 ss->floor_xoffs = 0;
548 ss->floor_yoffs = 0; // floor and ceiling flats offsets
549 ss->ceiling_xoffs = 0;
550 ss->ceiling_yoffs = 0;
551 ss->heightsec = -1; // sector used to get floor and ceiling height
552 ss->floorlightsec = -1; // sector used to get floor lighting
553 // killough 3/7/98: end changes
554
555 // killough 4/11/98 sector used to get ceiling lighting:
556 ss->ceilinglightsec = -1;
557
558 // killough 4/4/98: colormaps:
559 ss->bottommap = ss->midmap = ss->topmap = 0;
560
561 // killough 10/98: sky textures coming from sidedefs:
562 ss->sky = 0;
563 }
564
565 W_UnlockLumpNum(lump); // cph - release the data
566}
567
568
569//
570// P_LoadNodes
571//
572// killough 5/3/98: reformatted, cleaned up
573
574static void P_LoadNodes (int lump)
575{
576 const byte *data; // cph - const*
577 int i;
578
579 numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
580 nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
581 data = W_CacheLumpNum (lump); // cph - wad lump handling updated
582
583 if ((!data) || (!numnodes))
584 {
585 // allow trivial maps
586 if (numsubsectors == 1)
587 lprintf(LO_INFO,
588 "P_LoadNodes: trivial map (no nodes, one subsector)\n");
589 else
590 I_Error("P_LoadNodes: no nodes in level");
591 }
592
593 for (i=0; i<numnodes; i++)
594 {
595 node_t *no = nodes + i;
596 const mapnode_t *mn = (const mapnode_t *) data + i;
597 int j;
598
599 no->x = SHORT(mn->x)<<FRACBITS;
600 no->y = SHORT(mn->y)<<FRACBITS;
601 no->dx = SHORT(mn->dx)<<FRACBITS;
602 no->dy = SHORT(mn->dy)<<FRACBITS;
603
604 for (j=0 ; j<2 ; j++)
605 {
606 int k;
607 no->children[j] = SHORT(mn->children[j]);
608 for (k=0 ; k<4 ; k++)
609 no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
610 }
611 }
612
613 W_UnlockLumpNum(lump); // cph - release the data
614}
615
616
617/*
618 * P_LoadThings
619 *
620 * killough 5/3/98: reformatted, cleaned up
621 * cph 2001/07/07 - don't write into the lump cache, especially non-idepotent
622 * changes like byte order reversals. Take a copy to edit.
623 */
624
625static void P_LoadThings (int lump)
626{
627 int i, numthings = W_LumpLength (lump) / sizeof(mapthing_t);
628 const mapthing_t *data = W_CacheLumpNum (lump);
629
630 if ((!data) || (!numthings))
631 I_Error("P_LoadThings: no things in level");
632
633 for (i=0; i<numthings; i++)
634 {
635 mapthing_t mt = data[i];
636
637 mt.x = SHORT(mt.x);
638 mt.y = SHORT(mt.y);
639 mt.angle = SHORT(mt.angle);
640 mt.type = SHORT(mt.type);
641 mt.options = SHORT(mt.options);
642
643 if (!P_IsDoomnumAllowed(mt.type))
644 continue;
645
646 // Do spawn all other stuff.
647 P_SpawnMapThing(&mt);
648 }
649
650 W_UnlockLumpNum(lump); // cph - release the data
651}
652
653//
654// P_LoadLineDefs
655// Also counts secret lines for intermissions.
656// ^^^
657// ??? killough ???
658// Does this mean secrets used to be linedef-based, rather than sector-based?
659//
660// killough 4/4/98: split into two functions, to allow sidedef overloading
661//
662// killough 5/3/98: reformatted, cleaned up
663
664static void P_LoadLineDefs (int lump)
665{
666 const byte *data; // cph - const*
667 int i;
668
669 numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
670 lines = Z_Calloc (numlines,sizeof(line_t),PU_LEVEL,0);
671 data = W_CacheLumpNum (lump); // cph - wad lump handling updated
672
673 for (i=0; i<numlines; i++)
674 {
675 const maplinedef_t *mld = (const maplinedef_t *) data + i;
676 line_t *ld = lines+i;
677 vertex_t *v1, *v2;
678
679 ld->flags = (unsigned short)SHORT(mld->flags);
680 ld->special = SHORT(mld->special);
681 ld->tag = SHORT(mld->tag);
682 v1 = ld->v1 = &vertexes[(unsigned short)SHORT(mld->v1)];
683 v2 = ld->v2 = &vertexes[(unsigned short)SHORT(mld->v2)];
684 ld->dx = v2->x - v1->x;
685 ld->dy = v2->y - v1->y;
686
687 ld->tranlump = -1; // killough 4/11/98: no translucency by default
688
689 ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL :
690 FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE;
691
692 if (v1->x < v2->x)
693 {
694 ld->bbox[BOXLEFT] = v1->x;
695 ld->bbox[BOXRIGHT] = v2->x;
696 }
697 else
698 {
699 ld->bbox[BOXLEFT] = v2->x;
700 ld->bbox[BOXRIGHT] = v1->x;
701 }
702 if (v1->y < v2->y)
703 {
704 ld->bbox[BOXBOTTOM] = v1->y;
705 ld->bbox[BOXTOP] = v2->y;
706 }
707 else
708 {
709 ld->bbox[BOXBOTTOM] = v2->y;
710 ld->bbox[BOXTOP] = v1->y;
711 }
712
713 /* calculate sound origin of line to be its midpoint */
714 //e6y: fix sound origin for large levels
715 // no need for comp_sound test, these are only used when comp_sound = 0
716 ld->soundorg.x = ld->bbox[BOXLEFT] / 2 + ld->bbox[BOXRIGHT] / 2;
717 ld->soundorg.y = ld->bbox[BOXTOP] / 2 + ld->bbox[BOXBOTTOM] / 2;
718
719 ld->iLineID=i; // proff 04/05/2000: needed for OpenGL
720 ld->sidenum[0] = SHORT(mld->sidenum[0]);
721 ld->sidenum[1] = SHORT(mld->sidenum[1]);
722
723 {
724 /* cph 2006/09/30 - fix sidedef errors right away.
725 * cph 2002/07/20 - these errors are fatal if not fixed, so apply them
726 * in compatibility mode - a desync is better than a crash! */
727 int j;
728
729 for (j=0; j < 2; j++)
730 {
731 if (ld->sidenum[j] != NO_INDEX && ld->sidenum[j] >= numsides) {
732 ld->sidenum[j] = NO_INDEX;
733 lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has out-of-range sidedef number\n",numlines-i-1);
734 }
735 }
736
737 // killough 11/98: fix common wad errors (missing sidedefs):
738
739 if (ld->sidenum[0] == NO_INDEX) {
740 ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side
741 // cph - print a warning about the bug
742 lprintf(LO_WARN, "P_LoadLineDefs: linedef %d missing first sidedef\n",numlines-i-1);
743 }
744
745 if ((ld->sidenum[1] == NO_INDEX) && (ld->flags & ML_TWOSIDED)) {
746 ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side
747 // cph - print a warning about the bug
748 lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has two-sided flag set, but no second sidedef\n",numlines-i-1);
749 }
750 }
751
752 // killough 4/4/98: support special sidedef interpretation below
753 if (ld->sidenum[0] != NO_INDEX && ld->special)
754 sides[*ld->sidenum].special = ld->special;
755 }
756
757 W_UnlockLumpNum(lump); // cph - release the lump
758}
759
760// killough 4/4/98: delay using sidedefs until they are loaded
761// killough 5/3/98: reformatted, cleaned up
762
763static void P_LoadLineDefs2(int lump)
764{
765 int i = numlines;
766 register line_t *ld = lines;
767 for (;i--;ld++)
768 {
769 ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be NO_INDEX here
770 ld->backsector = ld->sidenum[1]!=NO_INDEX ? sides[ld->sidenum[1]].sector : 0;
771 switch (ld->special)
772 { // killough 4/11/98: handle special types
773 int lump, j;
774
775 case 260: // killough 4/11/98: translucent 2s textures
776 lump = sides[*ld->sidenum].special; // translucency from sidedef
777 if (!ld->tag) // if tag==0,
778 ld->tranlump = lump; // affect this linedef only
779 else
780 for (j=0;j<numlines;j++) // if tag!=0,
781 if (lines[j].tag == ld->tag) // affect all matching linedefs
782 lines[j].tranlump = lump;
783 break;
784 }
785 }
786}
787
788//
789// P_LoadSideDefs
790//
791// killough 4/4/98: split into two functions
792
793static void P_LoadSideDefs (int lump)
794{
795 numsides = W_LumpLength(lump) / sizeof(mapsidedef_t);
796 sides = Z_Calloc(numsides,sizeof(side_t),PU_LEVEL,0);
797}
798
799// killough 4/4/98: delay using texture names until
800// after linedefs are loaded, to allow overloading.
801// killough 5/3/98: reformatted, cleaned up
802
803static void P_LoadSideDefs2(int lump)
804{
805 const byte *data = W_CacheLumpNum(lump); // cph - const*, wad lump handling updated
806 int i;
807
808 for (i=0; i<numsides; i++)
809 {
810 register const mapsidedef_t *msd = (const mapsidedef_t *) data + i;
811 register side_t *sd = sides + i;
812 register sector_t *sec;
813
814 sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
815 sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
816
817 { /* cph 2006/09/30 - catch out-of-range sector numbers; use sector 0 instead */
818 unsigned short sector_num = SHORT(msd->sector);
819 if (sector_num >= numsectors) {
820 lprintf(LO_WARN,"P_LoadSideDefs2: sidedef %i has out-of-range sector num %u\n", i, sector_num);
821 sector_num = 0;
822 }
823 sd->sector = sec = &sectors[sector_num];
824 }
825
826 // killough 4/4/98: allow sidedef texture names to be overloaded
827 // killough 4/11/98: refined to allow colormaps to work as wall
828 // textures if invalid as colormaps but valid as textures.
829 switch (sd->special)
830 {
831 case 242: // variable colormap via 242 linedef
832 sd->bottomtexture =
833 (sec->bottommap = R_ColormapNumForName(msd->bottomtexture)) < 0 ?
834 sec->bottommap = 0, R_TextureNumForName(msd->bottomtexture): 0 ;
835 sd->midtexture =
836 (sec->midmap = R_ColormapNumForName(msd->midtexture)) < 0 ?
837 sec->midmap = 0, R_TextureNumForName(msd->midtexture) : 0 ;
838 sd->toptexture =
839 (sec->topmap = R_ColormapNumForName(msd->toptexture)) < 0 ?
840 sec->topmap = 0, R_TextureNumForName(msd->toptexture) : 0 ;
841 break;
842
843 case 260: // killough 4/11/98: apply translucency to 2s normal texture
844 sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ?
845 (sd->special = W_CheckNumForName(msd->midtexture)) < 0 ||
846 W_LumpLength(sd->special) != 65536 ?
847 sd->special=0, R_TextureNumForName(msd->midtexture) :
848 (sd->special++, 0) : (sd->special=0);
849 sd->toptexture = R_TextureNumForName(msd->toptexture);
850 sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
851 break;
852
853 default: // normal cases
854 sd->midtexture = R_SafeTextureNumForName(msd->midtexture, i);
855 sd->toptexture = R_SafeTextureNumForName(msd->toptexture, i);
856 sd->bottomtexture = R_SafeTextureNumForName(msd->bottomtexture, i);
857 break;
858 }
859 }
860
861 W_UnlockLumpNum(lump); // cph - release the lump
862}
863
864//
865// jff 10/6/98
866// New code added to speed up calculation of internal blockmap
867// Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows
868//
869
870#define blkshift 7 /* places to shift rel position for cell num */
871#define blkmask ((1<<blkshift)-1)/* mask for rel position within cell */
872#define blkmargin 0 /* size guardband around map used */
873 // jff 10/8/98 use guardband>0
874 // jff 10/12/98 0 ok with + 1 in rows,cols
875
876typedef struct linelist_t // type used to list lines in each block
877{
878 long num;
879 struct linelist_t *next;
880} linelist_t;
881
882//
883// Subroutine to add a line number to a block list
884// It simply returns if the line is already in the block
885//
886
887static void AddBlockLine
888(
889 linelist_t **lists,
890 int *count,
891 int *done,
892 int blockno,
893 long lineno
894)
895{
896 linelist_t *l;
897
898 if (done[blockno])
899 return;
900
901 l = malloc(sizeof(linelist_t));
902 l->num = lineno;
903 l->next = lists[blockno];
904 lists[blockno] = l;
905 count[blockno]++;
906 done[blockno] = 1;
907}
908
909//
910// Actually construct the blockmap lump from the level data
911//
912// This finds the intersection of each linedef with the column and
913// row lines at the left and bottom of each blockmap cell. It then
914// adds the line to all block lists touching the intersection.
915//
916
917static void P_CreateBlockMap(void)
918{
919 int xorg,yorg; // blockmap origin (lower left)
920 int nrows,ncols; // blockmap dimensions
921 linelist_t **blocklists=NULL; // array of pointers to lists of lines
922 int *blockcount=NULL; // array of counters of line lists
923 int *blockdone=NULL; // array keeping track of blocks/line
924 int NBlocks; // number of cells = nrows*ncols
925 long linetotal=0; // total length of all blocklists
926 int i,j;
927 int map_minx=INT_MAX; // init for map limits search
928 int map_miny=INT_MAX;
929 int map_maxx=INT_MIN;
930 int map_maxy=INT_MIN;
931
932 // scan for map limits, which the blockmap must enclose
933
934 for (i=0;i<numvertexes;i++)
935 {
936 fixed_t t;
937
938 if ((t=vertexes[i].x) < map_minx)
939 map_minx = t;
940 else if (t > map_maxx)
941 map_maxx = t;
942 if ((t=vertexes[i].y) < map_miny)
943 map_miny = t;
944 else if (t > map_maxy)
945 map_maxy = t;
946 }
947 map_minx >>= FRACBITS; // work in map coords, not fixed_t
948 map_maxx >>= FRACBITS;
949 map_miny >>= FRACBITS;
950 map_maxy >>= FRACBITS;
951
952 // set up blockmap area to enclose level plus margin
953
954 xorg = map_minx-blkmargin;
955 yorg = map_miny-blkmargin;
956 ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift; //jff 10/12/98
957 nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift; //+1 needed for
958 NBlocks = ncols*nrows; //map exactly 1 cell
959
960 // create the array of pointers on NBlocks to blocklists
961 // also create an array of linelist counts on NBlocks
962 // finally make an array in which we can mark blocks done per line
963
964 // CPhipps - calloc's
965 blocklists = calloc(NBlocks,sizeof(linelist_t *));
966 blockcount = calloc(NBlocks,sizeof(int));
967 blockdone = malloc(NBlocks*sizeof(int));
968
969 // initialize each blocklist, and enter the trailing -1 in all blocklists
970 // note the linked list of lines grows backwards
971
972 for (i=0;i<NBlocks;i++)
973 {
974 blocklists[i] = malloc(sizeof(linelist_t));
975 blocklists[i]->num = -1;
976 blocklists[i]->next = NULL;
977 blockcount[i]++;
978 }
979
980 // For each linedef in the wad, determine all blockmap blocks it touches,
981 // and add the linedef number to the blocklists for those blocks
982
983 for (i=0;i<numlines;i++)
984 {
985 int x1 = lines[i].v1->x>>FRACBITS; // lines[i] map coords
986 int y1 = lines[i].v1->y>>FRACBITS;
987 int x2 = lines[i].v2->x>>FRACBITS;
988 int y2 = lines[i].v2->y>>FRACBITS;
989 int dx = x2-x1;
990 int dy = y2-y1;
991 int vert = !dx; // lines[i] slopetype
992 int horiz = !dy;
993 int spos = (dx^dy) > 0;
994 int sneg = (dx^dy) < 0;
995 int bx,by; // block cell coords
996 int minx = x1>x2? x2 : x1; // extremal lines[i] coords
997 int maxx = x1>x2? x1 : x2;
998 int miny = y1>y2? y2 : y1;
999 int maxy = y1>y2? y1 : y2;
1000
1001 // no blocks done for this linedef yet
1002
1003 memset(blockdone,0,NBlocks*sizeof(int));
1004
1005 // The line always belongs to the blocks containing its endpoints
1006
1007 bx = (x1-xorg)>>blkshift;
1008 by = (y1-yorg)>>blkshift;
1009 AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i);
1010 bx = (x2-xorg)>>blkshift;
1011 by = (y2-yorg)>>blkshift;
1012 AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i);
1013
1014
1015 // For each column, see where the line along its left edge, which
1016 // it contains, intersects the Linedef i. Add i to each corresponding
1017 // blocklist.
1018
1019 if (!vert) // don't interesect vertical lines with columns
1020 {
1021 for (j=0;j<ncols;j++)
1022 {
1023 // intersection of Linedef with x=xorg+(j<<blkshift)
1024 // (y-y1)*dx = dy*(x-x1)
1025 // y = dy*(x-x1)+y1*dx;
1026
1027 int x = xorg+(j<<blkshift); // (x,y) is intersection
1028 int y = (dy*(x-x1))/dx+y1;
1029 int yb = (y-yorg)>>blkshift; // block row number
1030 int yp = (y-yorg)&blkmask; // y position within block
1031
1032 if (yb<0 || yb>nrows-1) // outside blockmap, continue
1033 continue;
1034
1035 if (x<minx || x>maxx) // line doesn't touch column
1036 continue;
1037
1038 // The cell that contains the intersection point is always added
1039
1040 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i);
1041
1042 // if the intersection is at a corner it depends on the slope
1043 // (and whether the line extends past the intersection) which
1044 // blocks are hit
1045
1046 if (yp==0) // intersection at a corner
1047 {
1048 if (sneg) // \ - blocks x,y-, x-,y
1049 {
1050 if (yb>0 && miny<y)
1051 AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j,i);
1052 if (j>0 && minx<x)
1053 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1054 }
1055 else if (spos) // / - block x-,y-
1056 {
1057 if (yb>0 && j>0 && minx<x)
1058 AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j-1,i);
1059 }
1060 else if (horiz) // - - block x-,y
1061 {
1062 if (j>0 && minx<x)
1063 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1064 }
1065 }
1066 else if (j>0 && minx<x) // else not at corner: x-,y
1067 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1068 }
1069 }
1070
1071 // For each row, see where the line along its bottom edge, which
1072 // it contains, intersects the Linedef i. Add i to all the corresponding
1073 // blocklists.
1074
1075 if (!horiz)
1076 {
1077 for (j=0;j<nrows;j++)
1078 {
1079 // intersection of Linedef with y=yorg+(j<<blkshift)
1080 // (x,y) on Linedef i satisfies: (y-y1)*dx = dy*(x-x1)
1081 // x = dx*(y-y1)/dy+x1;
1082
1083 int y = yorg+(j<<blkshift); // (x,y) is intersection
1084 int x = (dx*(y-y1))/dy+x1;
1085 int xb = (x-xorg)>>blkshift; // block column number
1086 int xp = (x-xorg)&blkmask; // x position within block
1087
1088 if (xb<0 || xb>ncols-1) // outside blockmap, continue
1089 continue;
1090
1091 if (y<miny || y>maxy) // line doesn't touch row
1092 continue;
1093
1094 // The cell that contains the intersection point is always added
1095
1096 AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb,i);
1097
1098 // if the intersection is at a corner it depends on the slope
1099 // (and whether the line extends past the intersection) which
1100 // blocks are hit
1101
1102 if (xp==0) // intersection at a corner
1103 {
1104 if (sneg) // \ - blocks x,y-, x-,y
1105 {
1106 if (j>0 && miny<y)
1107 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
1108 if (xb>0 && minx<x)
1109 AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb-1,i);
1110 }
1111 else if (vert) // | - block x,y-
1112 {
1113 if (j>0 && miny<y)
1114 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
1115 }
1116 else if (spos) // / - block x-,y-
1117 {
1118 if (xb>0 && j>0 && miny<y)
1119 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb-1,i);
1120 }
1121 }
1122 else if (j>0 && miny<y) // else not on a corner: x,y-
1123 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
1124 }
1125 }
1126 }
1127
1128 // Add initial 0 to all blocklists
1129 // count the total number of lines (and 0's and -1's)
1130
1131 memset(blockdone,0,NBlocks*sizeof(int));
1132 for (i=0,linetotal=0;i<NBlocks;i++)
1133 {
1134 AddBlockLine(blocklists,blockcount,blockdone,i,0);
1135 linetotal += blockcount[i];
1136 }
1137
1138 // Create the blockmap lump
1139
1140 blockmaplump = Z_Malloc(sizeof(*blockmaplump) * (4+NBlocks+linetotal),
1141 PU_LEVEL, 0);
1142 // blockmap header
1143
1144 blockmaplump[0] = bmaporgx = xorg << FRACBITS;
1145 blockmaplump[1] = bmaporgy = yorg << FRACBITS;
1146 blockmaplump[2] = bmapwidth = ncols;
1147 blockmaplump[3] = bmapheight = nrows;
1148
1149 // offsets to lists and block lists
1150
1151 for (i=0;i<NBlocks;i++)
1152 {
1153 linelist_t *bl = blocklists[i];
1154 long offs = blockmaplump[4+i] = // set offset to block's list
1155 (i? blockmaplump[4+i-1] : 4+NBlocks) + (i? blockcount[i-1] : 0);
1156
1157 // add the lines in each block's list to the blockmaplump
1158 // delete each list node as we go
1159
1160 while (bl)
1161 {
1162 linelist_t *tmp = bl->next;
1163 blockmaplump[offs++] = bl->num;
1164 free(bl);
1165 bl = tmp;
1166 }
1167 }
1168
1169 // free all temporary storage
1170
1171 free (blocklists);
1172 free (blockcount);
1173 free (blockdone);
1174}
1175
1176// jff 10/6/98
1177// End new code added to speed up calculation of internal blockmap
1178
1179//
1180// P_LoadBlockMap
1181//
1182// killough 3/1/98: substantially modified to work
1183// towards removing blockmap limit (a wad limitation)
1184//
1185// killough 3/30/98: Rewritten to remove blockmap limit,
1186// though current algorithm is brute-force and unoptimal.
1187//
1188
1189static void P_LoadBlockMap (int lump)
1190{
1191 long count;
1192
1193 if (M_CheckParm("-blockmap") || W_LumpLength(lump)<8 || (count = W_LumpLength(lump)/2) >= 0x10000) //e6y
1194 P_CreateBlockMap();
1195 else
1196 {
1197 long i;
1198 // cph - const*, wad lump handling updated
1199 const short *wadblockmaplump = W_CacheLumpNum(lump);
1200 blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0);
1201
1202 // killough 3/1/98: Expand wad blockmap into larger internal one,
1203 // by treating all offsets except -1 as unsigned and zero-extending
1204 // them. This potentially doubles the size of blockmaps allowed,
1205 // because Doom originally considered the offsets as always signed.
1206
1207 blockmaplump[0] = SHORT(wadblockmaplump[0]);
1208 blockmaplump[1] = SHORT(wadblockmaplump[1]);
1209 blockmaplump[2] = (long)(SHORT(wadblockmaplump[2])) & 0xffff;
1210 blockmaplump[3] = (long)(SHORT(wadblockmaplump[3])) & 0xffff;
1211
1212 for (i=4 ; i<count ; i++)
1213 {
1214 short t = SHORT(wadblockmaplump[i]); // killough 3/1/98
1215 blockmaplump[i] = t == -1 ? -1l : (long) t & 0xffff;
1216 }
1217
1218 W_UnlockLumpNum(lump); // cph - unlock the lump
1219
1220 bmaporgx = blockmaplump[0]<<FRACBITS;
1221 bmaporgy = blockmaplump[1]<<FRACBITS;
1222 bmapwidth = blockmaplump[2];
1223 bmapheight = blockmaplump[3];
1224 }
1225
1226 // clear out mobj chains - CPhipps - use calloc
1227 blocklinks = Z_Calloc (bmapwidth*bmapheight,sizeof(*blocklinks),PU_LEVEL,0);
1228 blockmap = blockmaplump+4;
1229}
1230
1231//
1232// P_LoadReject - load the reject table, padding it if it is too short
1233// totallines must be the number returned by P_GroupLines()
1234// an underflow will be padded with zeroes, or a doom.exe z_zone header
1235//
1236// this function incorporates e6y's RejectOverrunAddInt code:
1237// e6y: REJECT overrun emulation code
1238// It's emulated successfully if the size of overflow no more than 16 bytes.
1239// No more desync on teeth-32.wad\teeth-32.lmp.
1240// http://www.doomworld.com/vb/showthread.php?s=&threadid=35214
1241
1242static void P_LoadReject(int lumpnum, int totallines)
1243{
1244 unsigned int length, required;
1245 byte *newreject;
1246
1247 // dump any old cached reject lump, then cache the new one
1248 if (rejectlump != -1)
1249 W_UnlockLumpNum(rejectlump);
1250 rejectlump = lumpnum + ML_REJECT;
1251 rejectmatrix = W_CacheLumpNum(rejectlump);
1252
1253 required = (numsectors * numsectors + 7) / 8;
1254 length = W_LumpLength(rejectlump);
1255
1256 if (length >= required)
1257 return; // nothing to do
1258
1259 // allocate a new block and copy the reject table into it; zero the rest
1260 // PU_LEVEL => will be freed on level exit
1261 newreject = Z_Malloc(required, PU_LEVEL, NULL);
1262 rejectmatrix = (const byte *)memmove(newreject, rejectmatrix, length);
1263 memset(newreject + length, 0, required - length);
1264 // unlock the original lump, it is no longer needed
1265 W_UnlockLumpNum(rejectlump);
1266 rejectlump = -1;
1267
1268 if (demo_compatibility)
1269 {
1270 // merged in RejectOverrunAddInt(), and the 4 calls to it, here
1271 unsigned int rejectpad[4] = {
1272 0, // size, will be filled in using totallines
1273 0, // part of the header of a doom.exe z_zone block
1274 50, // DOOM_CONST_PU_LEVEL
1275 0x1d4a11 // DOOM_CONST_ZONEID
1276 };
1277 unsigned int i, pad = 0, *src = rejectpad;
1278 byte *dest = newreject + length;
1279
1280 rejectpad[0] = ((totallines*4+3)&~3)+24; // doom.exe zone header size
1281
1282 // copy at most 16 bytes from rejectpad
1283 // emulating a 32-bit, little-endian architecture (can't memmove)
1284 for (i = 0; i < required - length && i < 16; i++) { // 16 hard-coded
1285 if (!(i&3)) // get the next 4 bytes to copy when i=0,4,8,12
1286 pad = *src++;
1287 *dest++ = pad & 0xff; // store lowest-significant byte
1288 pad >>= 8; // rotate the next byte down
1289 }
1290 }
1291 lprintf(LO_WARN, "P_LoadReject: REJECT too short (%u<%u) - padded\n",
1292 length, required);
1293}
1294
1295//
1296// P_GroupLines
1297// Builds sector line lists and subsector sector numbers.
1298// Finds block bounding boxes for sectors.
1299//
1300// killough 5/3/98: reformatted, cleaned up
1301// cph 18/8/99: rewritten to avoid O(numlines * numsectors) section
1302// It makes things more complicated, but saves seconds on big levels
1303// figgi 09/18/00 -- adapted for gl-nodes
1304
1305// cph - convenient sub-function
1306static void P_AddLineToSector(line_t* li, sector_t* sector)
1307{
1308 fixed_t *bbox = (void*)sector->blockbox;
1309
1310 sector->lines[sector->linecount++] = li;
1311 M_AddToBox (bbox, li->v1->x, li->v1->y);
1312 M_AddToBox (bbox, li->v2->x, li->v2->y);
1313}
1314
1315// modified to return totallines (needed by P_LoadReject)
1316static int P_GroupLines (void)
1317{
1318 register line_t *li;
1319 register sector_t *sector;
1320 int i,j, total = numlines;
1321
1322 // figgi
1323 for (i=0 ; i<numsubsectors ; i++)
1324 {
1325 seg_t *seg = &segs[subsectors[i].firstline];
1326 subsectors[i].sector = NULL;
1327 for(j=0; j<subsectors[i].numlines; j++)
1328 {
1329 if(seg->sidedef)
1330 {
1331 subsectors[i].sector = seg->sidedef->sector;
1332 break;
1333 }
1334 seg++;
1335 }
1336 if(subsectors[i].sector == NULL)
1337 I_Error("P_GroupLines: Subsector a part of no sector!\n");
1338 }
1339
1340 // count number of lines in each sector
1341 for (i=0,li=lines; i<numlines; i++, li++)
1342 {
1343 li->frontsector->linecount++;
1344 if (li->backsector && li->backsector != li->frontsector)
1345 {
1346 li->backsector->linecount++;
1347 total++;
1348 }
1349 }
1350
1351 { // allocate line tables for each sector
1352 line_t **linebuffer = Z_Malloc(total*sizeof(line_t *), PU_LEVEL, 0);
1353
1354 // e6y: REJECT overrun emulation code
1355 // moved to P_LoadReject
1356
1357 for (i=0, sector = sectors; i<numsectors; i++, sector++)
1358 {
1359 sector->lines = linebuffer;
1360 linebuffer += sector->linecount;
1361 sector->linecount = 0;
1362 M_ClearBox(sector->blockbox);
1363 }
1364 }
1365
1366 // Enter those lines
1367 for (i=0,li=lines; i<numlines; i++, li++)
1368 {
1369 P_AddLineToSector(li, li->frontsector);
1370 if (li->backsector && li->backsector != li->frontsector)
1371 P_AddLineToSector(li, li->backsector);
1372 }
1373
1374 for (i=0, sector = sectors; i<numsectors; i++, sector++)
1375 {
1376 fixed_t *bbox = (void*)sector->blockbox; // cph - For convenience, so
1377 // I can sue the old code unchanged
1378 int block;
1379
1380 // set the degenmobj_t to the middle of the bounding box
1381 if (comp[comp_sound])
1382 {
1383 sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
1384 sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
1385 }
1386 else
1387 {
1388 //e6y: fix sound origin for large levels
1389 sector->soundorg.x = bbox[BOXRIGHT]/2+bbox[BOXLEFT]/2;
1390 sector->soundorg.y = bbox[BOXTOP]/2+bbox[BOXBOTTOM]/2;
1391 }
1392
1393 // adjust bounding box to map blocks
1394 block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
1395 block = block >= bmapheight ? bmapheight-1 : block;
1396 sector->blockbox[BOXTOP]=block;
1397
1398 block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
1399 block = block < 0 ? 0 : block;
1400 sector->blockbox[BOXBOTTOM]=block;
1401
1402 block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
1403 block = block >= bmapwidth ? bmapwidth-1 : block;
1404 sector->blockbox[BOXRIGHT]=block;
1405
1406 block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
1407 block = block < 0 ? 0 : block;
1408 sector->blockbox[BOXLEFT]=block;
1409 }
1410
1411 return total; // this value is needed by the reject overrun emulation code
1412}
1413
1414//
1415// killough 10/98
1416//
1417// Remove slime trails.
1418//
1419// Slime trails are inherent to Doom's coordinate system -- i.e. there is
1420// nothing that a node builder can do to prevent slime trails ALL of the time,
1421// because it's a product of the integer coodinate system, and just because
1422// two lines pass through exact integer coordinates, doesn't necessarily mean
1423// that they will intersect at integer coordinates. Thus we must allow for
1424// fractional coordinates if we are to be able to split segs with node lines,
1425// as a node builder must do when creating a BSP tree.
1426//
1427// A wad file does not allow fractional coordinates, so node builders are out
1428// of luck except that they can try to limit the number of splits (they might
1429// also be able to detect the degree of roundoff error and try to avoid splits
1430// with a high degree of roundoff error). But we can use fractional coordinates
1431// here, inside the engine. It's like the difference between square inches and
1432// square miles, in terms of granularity.
1433//
1434// For each vertex of every seg, check to see whether it's also a vertex of
1435// the linedef associated with the seg (i.e, it's an endpoint). If it's not
1436// an endpoint, and it wasn't already moved, move the vertex towards the
1437// linedef by projecting it using the law of cosines. Formula:
1438//
1439// 2 2 2 2
1440// dx x0 + dy x1 + dx dy (y0 - y1) dy y0 + dx y1 + dx dy (x0 - x1)
1441// {---------------------------------, ---------------------------------}
1442// 2 2 2 2
1443// dx + dy dx + dy
1444//
1445// (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the
1446// reference linedef.
1447//
1448// Segs corresponding to orthogonal linedefs (exactly vertical or horizontal
1449// linedefs), which comprise at least half of all linedefs in most wads, don't
1450// need to be considered, because they almost never contribute to slime trails
1451// (because then any roundoff error is parallel to the linedef, which doesn't
1452// cause slime). Skipping simple orthogonal lines lets the code finish quicker.
1453//
1454// Please note: This section of code is not interchangable with TeamTNT's
1455// code which attempts to fix the same problem.
1456//
1457// Firelines (TM) is a Rezistered Trademark of MBF Productions
1458//
1459
1460static void P_RemoveSlimeTrails(void) // killough 10/98
1461{
1462 byte *hit = calloc(1, numvertexes); // Hitlist for vertices
1463 int i;
1464 for (i=0; i<numsegs; i++) // Go through each seg
1465 {
1466 const line_t *l;
1467
1468 if (segs[i].miniseg == true) //figgi -- skip minisegs
1469 return;
1470
1471 l = segs[i].linedef; // The parent linedef
1472 if (l->dx && l->dy) // We can ignore orthogonal lines
1473 {
1474 vertex_t *v = segs[i].v1;
1475 do
1476 if (!hit[v - vertexes]) // If we haven't processed vertex
1477 {
1478 hit[v - vertexes] = 1; // Mark this vertex as processed
1479 if (v != l->v1 && v != l->v2) // Exclude endpoints of linedefs
1480 { // Project the vertex back onto the parent linedef
1481 int_64_t dx2 = (l->dx >> FRACBITS) * (l->dx >> FRACBITS);
1482 int_64_t dy2 = (l->dy >> FRACBITS) * (l->dy >> FRACBITS);
1483 int_64_t dxy = (l->dx >> FRACBITS) * (l->dy >> FRACBITS);
1484 int_64_t s = dx2 + dy2;
1485 int x0 = v->x, y0 = v->y, x1 = l->v1->x, y1 = l->v1->y;
1486 v->x = (int)((dx2 * x0 + dy2 * x1 + dxy * (y0 - y1)) / s);
1487 v->y = (int)((dy2 * y0 + dx2 * y1 + dxy * (x0 - x1)) / s);
1488 }
1489 } // Obsfucated C contest entry: :)
1490 while ((v != segs[i].v2) && (v = segs[i].v2));
1491 }
1492 }
1493 free(hit);
1494}
1495
1496//
1497// P_SetupLevel
1498//
1499// killough 5/3/98: reformatted, cleaned up
1500
1501void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
1502{
1503 int i;
1504 char lumpname[9];
1505 int lumpnum;
1506
1507 char gl_lumpname[9];
1508 int gl_lumpnum;
1509
1510 R_StopAllInterpolations();
1511
1512 totallive = totalkills = totalitems = totalsecret = wminfo.maxfrags = 0;
1513 wminfo.partime = 180;
1514
1515 for (i=0; i<MAXPLAYERS; i++)
1516 players[i].killcount = players[i].secretcount = players[i].itemcount = 0;
1517
1518 // Initial height of PointOfView will be set by player think.
1519 players[consoleplayer].viewz = 1;
1520
1521 // Make sure all sounds are stopped before Z_FreeTags.
1522 S_Start();
1523
1524 Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
1525 if (rejectlump != -1) { // cph - unlock the reject table
1526 W_UnlockLumpNum(rejectlump);
1527 rejectlump = -1;
1528 }
1529
1530#ifdef GL_DOOM
1531// proff 11/99: clean the memory from textures etc.
1532 gld_CleanMemory();
1533#endif
1534
1535 P_InitThinkers();
1536
1537 // if working with a devlopment map, reload it
1538 // W_Reload (); killough 1/31/98: W_Reload obsolete
1539
1540 // find map name
1541 if (gamemode == commercial)
1542 {
1543 sprintf(lumpname, "map%02d", map); // killough 1/24/98: simplify
1544 sprintf(gl_lumpname, "gl_map%02d", map); // figgi
1545 }
1546 else
1547 {
1548 sprintf(lumpname, "E%dM%d", episode, map); // killough 1/24/98: simplify
1549 sprintf(gl_lumpname, "GL_E%iM%i", episode, map); // figgi
1550 }
1551
1552 lumpnum = W_GetNumForName(lumpname);
1553 gl_lumpnum = W_CheckNumForName(gl_lumpname); // figgi
1554
1555 leveltime = 0; totallive = 0;
1556
1557 // note: most of this ordering is important
1558
1559 // killough 3/1/98: P_LoadBlockMap call moved down to below
1560 // killough 4/4/98: split load of sidedefs into two parts,
1561 // to allow texture names to be used in special linedefs
1562
1563 // refuse to load Hexen-format maps, avoid segfaults
1564 if ((i = lumpnum + ML_BLOCKMAP + 1) < numlumps
1565 && !strncasecmp(lumpinfo[i].name, "BEHAVIOR", 8))
1566 I_Error("P_SetupLevel: %s: Hexen format not supported", lumpname);
1567
1568#if 1
1569 // figgi 10/19/00 -- check for gl lumps and load them
1570 P_GetNodesVersion(lumpnum,gl_lumpnum);
1571
1572 if (nodesVersion > 0)
1573 P_LoadVertexes2 (lumpnum+ML_VERTEXES,gl_lumpnum+ML_GL_VERTS);
1574 else
1575 P_LoadVertexes (lumpnum+ML_VERTEXES);
1576 P_LoadSectors (lumpnum+ML_SECTORS);
1577 P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
1578 P_LoadLineDefs (lumpnum+ML_LINEDEFS);
1579 P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS);
1580 P_LoadLineDefs2 (lumpnum+ML_LINEDEFS);
1581 P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
1582
1583 if (nodesVersion > 0)
1584 {
1585 P_LoadSubsectors(gl_lumpnum + ML_GL_SSECT);
1586 P_LoadNodes(gl_lumpnum + ML_GL_NODES);
1587 P_LoadGLSegs(gl_lumpnum + ML_GL_SEGS);
1588 }
1589 else
1590 {
1591 P_LoadSubsectors(lumpnum + ML_SSECTORS);
1592 P_LoadNodes(lumpnum + ML_NODES);
1593 P_LoadSegs(lumpnum + ML_SEGS);
1594 }
1595
1596#else
1597
1598 P_LoadVertexes (lumpnum+ML_VERTEXES);
1599 P_LoadSectors (lumpnum+ML_SECTORS);
1600 P_LoadSideDefs (lumpnum+ML_SIDEDEFS); // killough 4/4/98
1601 P_LoadLineDefs (lumpnum+ML_LINEDEFS); // |
1602 P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); // |
1603 P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); // killough 4/4/98
1604 P_LoadBlockMap (lumpnum+ML_BLOCKMAP); // killough 3/1/98
1605 P_LoadSubsectors(lumpnum+ML_SSECTORS);
1606 P_LoadNodes (lumpnum+ML_NODES);
1607 P_LoadSegs (lumpnum+ML_SEGS);
1608
1609#endif
1610
1611 // reject loading and underflow padding separated out into new function
1612 // P_GroupLines modified to return a number the underflow padding needs
1613 P_LoadReject(lumpnum, P_GroupLines());
1614
1615 // e6y
1616 // Correction of desync on dv04-423.lmp/dv.wad
1617 // http://www.doomworld.com/vb/showthread.php?s=&postid=627257#post627257
1618 if (compatibility_level>=lxdoom_1_compatibility || M_CheckParm("-force_remove_slime_trails") > 0)
1619 P_RemoveSlimeTrails(); // killough 10/98: remove slime trails from wad
1620
1621 // Note: you don't need to clear player queue slots --
1622 // a much simpler fix is in g_game.c -- killough 10/98
1623
1624 bodyqueslot = 0;
1625
1626 /* cph - reset all multiplayer starts */
1627 memset(playerstarts,0,sizeof(playerstarts));
1628 deathmatch_p = deathmatchstarts;
1629 for (i = 0; i < MAXPLAYERS; i++)
1630 players[i].mo = NULL;
1631
1632 P_MapStart();
1633
1634 P_LoadThings(lumpnum+ML_THINGS);
1635
1636 // if deathmatch, randomly spawn the active players
1637 if (deathmatch)
1638 {
1639 for (i=0; i<MAXPLAYERS; i++)
1640 if (playeringame[i])
1641 {
1642 players[i].mo = NULL; // not needed? - done before P_LoadThings
1643 G_DeathMatchSpawnPlayer(i);
1644 }
1645 }
1646 else // if !deathmatch, check all necessary player starts actually exist
1647 {
1648 for (i=0; i<MAXPLAYERS; i++)
1649 if (playeringame[i] && !players[i].mo)
1650 I_Error("P_SetupLevel: missing player %d start\n", i+1);
1651 }
1652
1653 // killough 3/26/98: Spawn icon landings:
1654 if (gamemode==commercial)
1655 P_SpawnBrainTargets();
1656
1657 // clear special respawning que
1658 iquehead = iquetail = 0;
1659
1660 // set up world state
1661 P_SpawnSpecials();
1662
1663 P_MapEnd();
1664
1665 // preload graphics
1666 if (precache)
1667 R_PrecacheLevel();
1668
1669#ifdef GL_DOOM
1670 if (V_GetMode() == VID_MODEGL)
1671 {
1672 // proff 11/99: calculate all OpenGL specific tables etc.
1673 gld_PreprocessLevel();
1674 }
1675#endif
1676
1677 R_SmoothPlaying_Reset(NULL); // e6y
1678}
1679
1680//
1681// P_Init
1682//
1683void P_Init (void)
1684{
1685 P_InitSwitchList();
1686 P_InitPicAnims();
1687 R_InitSprites(sprnames);
1688}
diff --git a/src/p_setup.h b/src/p_setup.h
new file mode 100644
index 0000000..847c5cb
--- /dev/null
+++ b/src/p_setup.h
@@ -0,0 +1,57 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Setup a game, startup stuff.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __P_SETUP__
35#define __P_SETUP__
36
37#include "p_mobj.h"
38
39#ifdef __GNUG__
40#pragma interface
41#endif
42
43void P_SetupLevel(int episode, int map, int playermask, skill_t skill);
44void P_Init(void); /* Called by startup code. */
45
46extern const byte *rejectmatrix; /* for fast sight rejection - cph - const* */
47
48/* killough 3/1/98: change blockmap from "short" to "long" offsets: */
49extern long *blockmaplump; /* offsets in blockmap are from here */
50extern long *blockmap;
51extern int bmapwidth;
52extern int bmapheight; /* in mapblocks */
53extern fixed_t bmaporgx;
54extern fixed_t bmaporgy; /* origin of block map */
55extern mobj_t **blocklinks; /* for thing chains */
56
57#endif
diff --git a/src/p_sight.c b/src/p_sight.c
new file mode 100644
index 0000000..d5d5756
--- /dev/null
+++ b/src/p_sight.c
@@ -0,0 +1,338 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * LineOfSight/Visibility checks, uses REJECT Lookup Table.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "r_main.h"
36#include "p_map.h"
37#include "p_maputl.h"
38#include "p_setup.h"
39#include "m_bbox.h"
40#include "lprintf.h"
41
42//
43// P_CheckSight
44//
45// killough 4/19/98:
46// Convert LOS info to struct for reentrancy and efficiency of data locality
47
48typedef struct {
49 fixed_t sightzstart, t2x, t2y; // eye z of looker
50 divline_t strace; // from t1 to t2
51 fixed_t topslope, bottomslope; // slopes to top and bottom of target
52 fixed_t bbox[4];
53 fixed_t maxz,minz; // cph - z optimisations for 2sided lines
54} los_t;
55
56static los_t los; // cph - made static
57
58//
59// P_DivlineSide
60// Returns side 0 (front), 1 (back), or 2 (on).
61//
62// killough 4/19/98: made static, cleaned up
63
64inline static int P_DivlineSide(fixed_t x, fixed_t y, const divline_t *node)
65{
66 fixed_t left, right;
67 return
68 !node->dx ? x == node->x ? 2 : x <= node->x ? node->dy > 0 : node->dy < 0 :
69 !node->dy ? ( compatibility_level < prboom_4_compatibility ? x : y) == node->y ? 2 : y <= node->y ? node->dx < 0 : node->dx > 0 :
70 (right = ((y - node->y) >> FRACBITS) * (node->dx >> FRACBITS)) <
71 (left = ((x - node->x) >> FRACBITS) * (node->dy >> FRACBITS)) ? 0 :
72 right == left ? 2 : 1;
73}
74
75//
76// P_CrossSubsector
77// Returns true
78// if strace crosses the given subsector successfully.
79//
80// killough 4/19/98: made static and cleaned up
81
82static boolean P_CrossSubsector(int num)
83{
84 seg_t *seg = segs + subsectors[num].firstline;
85 int count;
86 fixed_t opentop = 0, openbottom = 0;
87 const sector_t *front = NULL, *back = NULL;
88
89#ifdef RANGECHECK
90 if (num >= numsubsectors)
91 I_Error("P_CrossSubsector: ss %i with numss = %i", num, numsubsectors);
92#endif
93
94 for (count = subsectors[num].numlines; --count >= 0; seg++) { // check lines
95 line_t *line = seg->linedef;
96 divline_t divl;
97
98 if(!line) // figgi -- skip minisegs
99 continue;
100
101 // allready checked other side?
102 if (line->validcount == validcount)
103 continue;
104
105 line->validcount = validcount;
106
107 /* OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test
108 * cph - this is causing demo desyncs on original Doom demos.
109 * Who knows why. Exclude test for those.
110 */
111 if (!demo_compatibility)
112 if (line->bbox[BOXLEFT ] > los.bbox[BOXRIGHT ] ||
113 line->bbox[BOXRIGHT ] < los.bbox[BOXLEFT ] ||
114 line->bbox[BOXBOTTOM] > los.bbox[BOXTOP ] ||
115 line->bbox[BOXTOP] < los.bbox[BOXBOTTOM])
116 continue;
117
118 // cph - do what we can before forced to check intersection
119 if (line->flags & ML_TWOSIDED) {
120
121 // no wall to block sight with?
122 if ((front = seg->frontsector)->floorheight ==
123 (back = seg->backsector)->floorheight &&
124 front->ceilingheight == back->ceilingheight)
125 continue;
126
127 // possible occluder
128 // because of ceiling height differences
129 opentop = front->ceilingheight < back->ceilingheight ?
130 front->ceilingheight : back->ceilingheight ;
131
132 // because of floor height differences
133 openbottom = front->floorheight > back->floorheight ?
134 front->floorheight : back->floorheight ;
135
136 // cph - reject if does not intrude in the z-space of the possible LOS
137 if ((opentop >= los.maxz) && (openbottom <= los.minz))
138 continue;
139 }
140
141 { // Forget this line if it doesn't cross the line of sight
142 const vertex_t *v1,*v2;
143
144 v1 = line->v1;
145 v2 = line->v2;
146
147 if (P_DivlineSide(v1->x, v1->y, &los.strace) ==
148 P_DivlineSide(v2->x, v2->y, &los.strace))
149 continue;
150
151 divl.dx = v2->x - (divl.x = v1->x);
152 divl.dy = v2->y - (divl.y = v1->y);
153
154 // line isn't crossed?
155 if (P_DivlineSide(los.strace.x, los.strace.y, &divl) ==
156 P_DivlineSide(los.t2x, los.t2y, &divl))
157 continue;
158 }
159
160 // cph - if bottom >= top or top < minz or bottom > maxz then it must be
161 // solid wrt this LOS
162 if (!(line->flags & ML_TWOSIDED) || (openbottom >= opentop) ||
163 (opentop < los.minz) || (openbottom > los.maxz))
164 return false;
165
166 { // crosses a two sided line
167 /* cph 2006/07/15 - oops, we missed this in 2.4.0 & .1;
168 * use P_InterceptVector2 for those compat levels only. */
169 fixed_t frac = (compatibility_level == prboom_5_compatibility || compatibility_level == prboom_6_compatibility) ?
170 P_InterceptVector2(&los.strace, &divl) :
171 P_InterceptVector(&los.strace, &divl);
172
173 if (front->floorheight != back->floorheight) {
174 fixed_t slope = FixedDiv(openbottom - los.sightzstart , frac);
175 if (slope > los.bottomslope)
176 los.bottomslope = slope;
177 }
178
179 if (front->ceilingheight != back->ceilingheight)
180 {
181 fixed_t slope = FixedDiv(opentop - los.sightzstart , frac);
182 if (slope < los.topslope)
183 los.topslope = slope;
184 }
185
186 if (los.topslope <= los.bottomslope)
187 return false; // stop
188 }
189 }
190 // passed the subsector ok
191 return true;
192}
193
194//
195// P_CrossBSPNode
196// Returns true
197// if strace crosses the given node successfully.
198//
199// killough 4/20/98: rewritten to remove tail recursion, clean up, and optimize
200// cph - Made to use R_PointOnSide instead of P_DivlineSide, since the latter
201// could return 2 which was ambigous, and the former is
202// better optimised; also removes two casts :-)
203
204static boolean P_CrossBSPNode_LxDoom(int bspnum)
205{
206 while (!(bspnum & NF_SUBSECTOR))
207 {
208 register const node_t *bsp = nodes + bspnum;
209 int side,side2;
210 side = R_PointOnSide(los.strace.x, los.strace.y, bsp);
211 side2 = R_PointOnSide(los.t2x, los.t2y, bsp);
212 if (side == side2)
213 bspnum = bsp->children[side]; // doesn't touch the other side
214 else // the partition plane is crossed here
215 if (!P_CrossBSPNode_LxDoom(bsp->children[side]))
216 return 0; // cross the starting side
217 else
218 bspnum = bsp->children[side^1]; // cross the ending side
219 }
220 return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
221}
222
223static boolean P_CrossBSPNode_PrBoom(int bspnum)
224{
225 while (!(bspnum & NF_SUBSECTOR))
226 {
227 register const node_t *bsp = nodes + bspnum;
228 int side,side2;
229 side = P_DivlineSide(los.strace.x,los.strace.y,(const divline_t *)bsp)&1;
230 side2= P_DivlineSide(los.t2x, los.t2y, (const divline_t *) bsp);
231 if (side == side2)
232 bspnum = bsp->children[side]; // doesn't touch the other side
233 else // the partition plane is crossed here
234 if (!P_CrossBSPNode_PrBoom(bsp->children[side]))
235 return 0; // cross the starting side
236 else
237 bspnum = bsp->children[side^1]; // cross the ending side
238 }
239 return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
240}
241
242/* proff - Moved the compatibility check outside the functions
243 * this gives a slight speedup
244 */
245static boolean P_CrossBSPNode(int bspnum)
246{
247 /* cph - LxDoom used some R_* funcs here */
248 if (compatibility_level == lxdoom_1_compatibility)
249 return P_CrossBSPNode_LxDoom(bspnum);
250 else
251 return P_CrossBSPNode_PrBoom(bspnum);
252}
253
254//
255// P_CheckSight
256// Returns true
257// if a straight line between t1 and t2 is unobstructed.
258// Uses REJECT.
259//
260// killough 4/20/98: cleaned up, made to use new LOS struct
261
262boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
263{
264 const sector_t *s1 = t1->subsector->sector;
265 const sector_t *s2 = t2->subsector->sector;
266 int pnum = (s1-sectors)*numsectors + (s2-sectors);
267
268 // First check for trivial rejection.
269 // Determine subsector entries in REJECT table.
270 //
271 // Check in REJECT table.
272
273 if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
274 return false;
275
276 // killough 4/19/98: make fake floors and ceilings block monster view
277
278 if ((s1->heightsec != -1 &&
279 ((t1->z + t1->height <= sectors[s1->heightsec].floorheight &&
280 t2->z >= sectors[s1->heightsec].floorheight) ||
281 (t1->z >= sectors[s1->heightsec].ceilingheight &&
282 t2->z + t1->height <= sectors[s1->heightsec].ceilingheight)))
283 ||
284 (s2->heightsec != -1 &&
285 ((t2->z + t2->height <= sectors[s2->heightsec].floorheight &&
286 t1->z >= sectors[s2->heightsec].floorheight) ||
287 (t2->z >= sectors[s2->heightsec].ceilingheight &&
288 t1->z + t2->height <= sectors[s2->heightsec].ceilingheight))))
289 return false;
290
291 /* killough 11/98: shortcut for melee situations
292 * same subsector? obviously visible
293 * cph - compatibility optioned for demo sync, cf HR06-UV.LMP */
294 if ((t1->subsector == t2->subsector) &&
295 (compatibility_level >= mbf_compatibility))
296 return true;
297
298 // An unobstructed LOS is possible.
299 // Now look from eyes of t1 to any part of t2.
300
301 validcount++;
302
303 los.topslope = (los.bottomslope = t2->z - (los.sightzstart =
304 t1->z + t1->height -
305 (t1->height>>2))) + t2->height;
306 los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x);
307 los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y);
308
309 if (t1->x > t2->x)
310 los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x;
311 else
312 los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x;
313
314 if (t1->y > t2->y)
315 los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y;
316 else
317 los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y;
318
319 /* cph - calculate min and max z of the potential line of sight
320 * For old demos, we disable this optimisation by setting them to
321 * the extremes */
322 switch (compatibility_level) {
323 case lxdoom_1_compatibility:
324 if (los.sightzstart < t2->z) {
325 los.maxz = t2->z + t2->height; los.minz = los.sightzstart;
326 } else if (los.sightzstart > t2->z + t2->height) {
327 los.maxz = los.sightzstart; los.minz = t2->z;
328 } else {
329 los.maxz = t2->z + t2->height; los.minz = t2->z;
330 }
331 break;
332 default:
333 los.maxz = INT_MAX; los.minz = INT_MIN;
334 }
335
336 // the head node is the last node output
337 return P_CrossBSPNode(numnodes-1);
338}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * -Loads and initializes texture and flat animation sequences
31 * -Implements utility functions for all linedef/sector special handlers
32 * -Dispatches walkover and gun line triggers
33 * -Initializes and implements special sector types
34 * -Implements donut linedef triggers
35 * -Initializes and implements BOOM linedef triggers for
36 * Scrollers/Conveyors
37 * Friction
38 * Wind/Current
39 *
40 *-----------------------------------------------------------------------------*/
41
42#include "doomstat.h"
43#include "p_spec.h"
44#include "p_tick.h"
45#include "p_setup.h"
46#include "m_random.h"
47#include "d_englsh.h"
48#include "m_argv.h"
49#include "w_wad.h"
50#include "r_main.h"
51#include "p_maputl.h"
52#include "p_map.h"
53#include "g_game.h"
54#include "p_inter.h"
55#include "s_sound.h"
56#include "sounds.h"
57#include "m_bbox.h" // phares 3/20/98
58#include "d_deh.h"
59#include "r_plane.h"
60#include "lprintf.h"
61
62//
63// Animating textures and planes
64// There is another anim_t used in wi_stuff, unrelated.
65//
66typedef struct
67{
68 boolean istexture;
69 int picnum;
70 int basepic;
71 int numpics;
72 int speed;
73
74} anim_t;
75
76//
77// source animation definition
78//
79//
80#ifdef _MSC_VER // proff: This is the same as __attribute__ ((packed)) in GNUC
81#pragma pack(push)
82#pragma pack(1)
83#endif //_MSC_VER
84
85#if defined(__MWERKS__)
86#pragma options align=packed
87#endif
88
89typedef struct
90{
91 signed char istexture; //jff 3/23/98 make char for comparison // cph - make signed
92 char endname[9]; // if false, it is a flat
93 char startname[9];
94 int speed;
95} PACKEDATTR animdef_t; //jff 3/23/98 pack to read from memory
96
97#if defined(__MWERKS__)
98#pragma options align=reset
99#endif
100
101#ifdef _MSC_VER
102#pragma pack(pop)
103#endif //_MSC_VER
104
105#define MAXANIMS 32 // no longer a strict limit -- killough
106
107static anim_t* lastanim;
108static anim_t* anims; // new structure w/o limits -- killough
109static size_t maxanims;
110
111// killough 3/7/98: Initialize generalized scrolling
112static void P_SpawnScrollers(void);
113
114static void P_SpawnFriction(void); // phares 3/16/98
115static void P_SpawnPushers(void); // phares 3/20/98
116
117//
118// P_InitPicAnims
119//
120// Load the table of animation definitions, checking for existence of
121// the start and end of each frame. If the start doesn't exist the sequence
122// is skipped, if the last doesn't exist, BOOM exits.
123//
124// Wall/Flat animation sequences, defined by name of first and last frame,
125// The full animation sequence is given using all lumps between the start
126// and end entry, in the order found in the WAD file.
127//
128// This routine modified to read its data from a predefined lump or
129// PWAD lump called ANIMATED rather than a static table in this module to
130// allow wad designers to insert or modify animation sequences.
131//
132// Lump format is an array of byte packed animdef_t structures, terminated
133// by a structure with istexture == -1. The lump can be generated from a
134// text source file using SWANTBLS.EXE, distributed with the BOOM utils.
135// The standard list of switches and animations is contained in the example
136// source text file DEFSWANI.DAT also in the BOOM util distribution.
137//
138//
139void P_InitPicAnims (void)
140{
141 int i;
142 const animdef_t *animdefs; //jff 3/23/98 pointer to animation lump
143 int lump = W_GetNumForName("ANIMATED"); // cph - new wad lump handling
144 // Init animation
145
146 //jff 3/23/98 read from predefined or wad lump instead of table
147 animdefs = (const animdef_t *)W_CacheLumpNum(lump);
148
149 lastanim = anims;
150 for (i=0 ; animdefs[i].istexture != -1 ; i++)
151 {
152 // 1/11/98 killough -- removed limit by array-doubling
153 if (lastanim >= anims + maxanims)
154 {
155 size_t newmax = maxanims ? maxanims*2 : MAXANIMS;
156 anims = realloc(anims, newmax*sizeof(*anims)); // killough
157 lastanim = anims + maxanims;
158 maxanims = newmax;
159 }
160
161 if (animdefs[i].istexture)
162 {
163 // different episode ?
164 if (R_CheckTextureNumForName(animdefs[i].startname) == -1)
165 continue;
166
167 lastanim->picnum = R_TextureNumForName (animdefs[i].endname);
168 lastanim->basepic = R_TextureNumForName (animdefs[i].startname);
169 }
170 else
171 {
172 if ((W_CheckNumForName)(animdefs[i].startname, ns_flats) == -1) // killough 4/17/98
173 continue;
174
175 lastanim->picnum = R_FlatNumForName (animdefs[i].endname);
176 lastanim->basepic = R_FlatNumForName (animdefs[i].startname);
177 }
178
179 lastanim->istexture = animdefs[i].istexture;
180 lastanim->numpics = lastanim->picnum - lastanim->basepic + 1;
181
182 if (lastanim->numpics < 2)
183 I_Error ("P_InitPicAnims: bad cycle from %s to %s",
184 animdefs[i].startname,
185 animdefs[i].endname);
186
187 lastanim->speed = LONG(animdefs[i].speed); // killough 5/5/98: add LONG()
188 lastanim++;
189 }
190 W_UnlockLumpNum(lump);
191}
192
193///////////////////////////////////////////////////////////////
194//
195// Linedef and Sector Special Implementation Utility Functions
196//
197///////////////////////////////////////////////////////////////
198
199//
200// getSide()
201//
202// Will return a side_t*
203// given the number of the current sector,
204// the line number, and the side (0/1) that you want.
205//
206// Note: if side=1 is specified, it must exist or results undefined
207//
208side_t* getSide
209( int currentSector,
210 int line,
211 int side )
212{
213 return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
214}
215
216
217//
218// getSector()
219//
220// Will return a sector_t*
221// given the number of the current sector,
222// the line number and the side (0/1) that you want.
223//
224// Note: if side=1 is specified, it must exist or results undefined
225//
226sector_t* getSector
227( int currentSector,
228 int line,
229 int side )
230{
231 return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
232}
233
234
235//
236// twoSided()
237//
238// Given the sector number and the line number,
239// it will tell you whether the line is two-sided or not.
240//
241// modified to return actual two-sidedness rather than presence
242// of 2S flag unless compatibility optioned
243//
244int twoSided
245( int sector,
246 int line )
247{
248 //jff 1/26/98 return what is actually needed, whether the line
249 //has two sidedefs, rather than whether the 2S flag is set
250
251 return comp[comp_model] ?
252 (sectors[sector].lines[line])->flags & ML_TWOSIDED
253 :
254 (sectors[sector].lines[line])->sidenum[1] != NO_INDEX;
255}
256
257
258//
259// getNextSector()
260//
261// Return sector_t * of sector next to current across line.
262//
263// Note: returns NULL if not two-sided line, or both sides refer to sector
264//
265sector_t* getNextSector
266( line_t* line,
267 sector_t* sec )
268{
269 //jff 1/26/98 check unneeded since line->backsector already
270 //returns NULL if the line is not two sided, and does so from
271 //the actual two-sidedness of the line, rather than its 2S flag
272
273 if (comp[comp_model])
274 {
275 if (!(line->flags & ML_TWOSIDED))
276 return NULL;
277 }
278
279 if (line->frontsector == sec) {
280 if (comp[comp_model] || line->backsector!=sec)
281 return line->backsector; //jff 5/3/98 don't retn sec unless compatibility
282 else // fixes an intra-sector line breaking functions
283 return NULL; // like floor->highest floor
284 }
285 return line->frontsector;
286}
287
288
289//
290// P_FindLowestFloorSurrounding()
291//
292// Returns the fixed point value of the lowest floor height
293// in the sector passed or its surrounding sectors.
294//
295fixed_t P_FindLowestFloorSurrounding(sector_t* sec)
296{
297 int i;
298 line_t* check;
299 sector_t* other;
300 fixed_t floor = sec->floorheight;
301
302 for (i=0 ;i < sec->linecount ; i++)
303 {
304 check = sec->lines[i];
305 other = getNextSector(check,sec);
306
307 if (!other)
308 continue;
309
310 if (other->floorheight < floor)
311 floor = other->floorheight;
312 }
313 return floor;
314}
315
316
317//
318// P_FindHighestFloorSurrounding()
319//
320// Passed a sector, returns the fixed point value of the largest
321// floor height in the surrounding sectors, not including that passed
322//
323// NOTE: if no surrounding sector exists -32000*FRACUINT is returned
324// if compatibility then -500*FRACUNIT is the smallest return possible
325//
326fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
327{
328 int i;
329 line_t* check;
330 sector_t* other;
331 fixed_t floor = -500*FRACUNIT;
332
333 //jff 1/26/98 Fix initial value for floor to not act differently
334 //in sections of wad that are below -500 units
335 if (!comp[comp_model]) /* jff 3/12/98 avoid ovf */
336 floor = -32000*FRACUNIT; // in height calculations
337
338 for (i=0 ;i < sec->linecount ; i++)
339 {
340 check = sec->lines[i];
341 other = getNextSector(check,sec);
342
343 if (!other)
344 continue;
345
346 if (other->floorheight > floor)
347 floor = other->floorheight;
348 }
349 return floor;
350}
351
352
353//
354// P_FindNextHighestFloor()
355//
356// Passed a sector and a floor height, returns the fixed point value
357// of the smallest floor height in a surrounding sector larger than
358// the floor height passed. If no such height exists the floorheight
359// passed is returned.
360//
361// Rewritten by Lee Killough to avoid fixed array and to be faster
362//
363fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight)
364{
365 sector_t *other;
366 int i;
367
368 for (i=0 ;i < sec->linecount ; i++)
369 if ((other = getNextSector(sec->lines[i],sec)) &&
370 other->floorheight > currentheight)
371 {
372 int height = other->floorheight;
373 while (++i < sec->linecount)
374 if ((other = getNextSector(sec->lines[i],sec)) &&
375 other->floorheight < height &&
376 other->floorheight > currentheight)
377 height = other->floorheight;
378 return height;
379 }
380 /* cph - my guess at doom v1.2 - 1.4beta compatibility here.
381 * If there are no higher neighbouring sectors, Heretic just returned
382 * heightlist[0] (local variable), i.e. noise off the stack. 0 is right for
383 * RETURN01 E1M2, so let's take that. */
384 return (compatibility_level < doom_1666_compatibility ? 0 : currentheight);
385}
386
387
388//
389// P_FindNextLowestFloor()
390//
391// Passed a sector and a floor height, returns the fixed point value
392// of the largest floor height in a surrounding sector smaller than
393// the floor height passed. If no such height exists the floorheight
394// passed is returned.
395//
396// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
397//
398fixed_t P_FindNextLowestFloor(sector_t *sec, int currentheight)
399{
400 sector_t *other;
401 int i;
402
403 for (i=0 ;i < sec->linecount ; i++)
404 if ((other = getNextSector(sec->lines[i],sec)) &&
405 other->floorheight < currentheight)
406 {
407 int height = other->floorheight;
408 while (++i < sec->linecount)
409 if ((other = getNextSector(sec->lines[i],sec)) &&
410 other->floorheight > height &&
411 other->floorheight < currentheight)
412 height = other->floorheight;
413 return height;
414 }
415 return currentheight;
416}
417
418
419//
420// P_FindNextLowestCeiling()
421//
422// Passed a sector and a ceiling height, returns the fixed point value
423// of the largest ceiling height in a surrounding sector smaller than
424// the ceiling height passed. If no such height exists the ceiling height
425// passed is returned.
426//
427// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
428//
429fixed_t P_FindNextLowestCeiling(sector_t *sec, int currentheight)
430{
431 sector_t *other;
432 int i;
433
434 for (i=0 ;i < sec->linecount ; i++)
435 if ((other = getNextSector(sec->lines[i],sec)) &&
436 other->ceilingheight < currentheight)
437 {
438 int height = other->ceilingheight;
439 while (++i < sec->linecount)
440 if ((other = getNextSector(sec->lines[i],sec)) &&
441 other->ceilingheight > height &&
442 other->ceilingheight < currentheight)
443 height = other->ceilingheight;
444 return height;
445 }
446 return currentheight;
447}
448
449
450//
451// P_FindNextHighestCeiling()
452//
453// Passed a sector and a ceiling height, returns the fixed point value
454// of the smallest ceiling height in a surrounding sector larger than
455// the ceiling height passed. If no such height exists the ceiling height
456// passed is returned.
457//
458// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
459//
460fixed_t P_FindNextHighestCeiling(sector_t *sec, int currentheight)
461{
462 sector_t *other;
463 int i;
464
465 for (i=0 ;i < sec->linecount ; i++)
466 if ((other = getNextSector(sec->lines[i],sec)) &&
467 other->ceilingheight > currentheight)
468 {
469 int height = other->ceilingheight;
470 while (++i < sec->linecount)
471 if ((other = getNextSector(sec->lines[i],sec)) &&
472 other->ceilingheight < height &&
473 other->ceilingheight > currentheight)
474 height = other->ceilingheight;
475 return height;
476 }
477 return currentheight;
478}
479
480
481//
482// P_FindLowestCeilingSurrounding()
483//
484// Passed a sector, returns the fixed point value of the smallest
485// ceiling height in the surrounding sectors, not including that passed
486//
487// NOTE: if no surrounding sector exists 32000*FRACUINT is returned
488// but if compatibility then INT_MAX is the return
489//
490fixed_t P_FindLowestCeilingSurrounding(sector_t* sec)
491{
492 int i;
493 line_t* check;
494 sector_t* other;
495 fixed_t height = INT_MAX;
496
497 /* jff 3/12/98 avoid ovf in height calculations */
498 if (!comp[comp_model]) height = 32000*FRACUNIT;
499
500 for (i=0 ;i < sec->linecount ; i++)
501 {
502 check = sec->lines[i];
503 other = getNextSector(check,sec);
504
505 if (!other)
506 continue;
507
508 if (other->ceilingheight < height)
509 height = other->ceilingheight;
510 }
511 return height;
512}
513
514
515//
516// P_FindHighestCeilingSurrounding()
517//
518// Passed a sector, returns the fixed point value of the largest
519// ceiling height in the surrounding sectors, not including that passed
520//
521// NOTE: if no surrounding sector exists -32000*FRACUINT is returned
522// but if compatibility then 0 is the smallest return possible
523//
524fixed_t P_FindHighestCeilingSurrounding(sector_t* sec)
525{
526 int i;
527 line_t* check;
528 sector_t* other;
529 fixed_t height = 0;
530
531 /* jff 1/26/98 Fix initial value for floor to not act differently
532 * in sections of wad that are below 0 units
533 * jff 3/12/98 avoid ovf in height calculations */
534 if (!comp[comp_model]) height = -32000*FRACUNIT;
535
536 for (i=0 ;i < sec->linecount ; i++)
537 {
538 check = sec->lines[i];
539 other = getNextSector(check,sec);
540
541 if (!other)
542 continue;
543
544 if (other->ceilingheight > height)
545 height = other->ceilingheight;
546 }
547 return height;
548}
549
550
551//
552// P_FindShortestTextureAround()
553//
554// Passed a sector number, returns the shortest lower texture on a
555// linedef bounding the sector.
556//
557// Note: If no lower texture exists 32000*FRACUNIT is returned.
558// but if compatibility then INT_MAX is returned
559//
560// jff 02/03/98 Add routine to find shortest lower texture
561//
562fixed_t P_FindShortestTextureAround(int secnum)
563{
564 int minsize = INT_MAX;
565 side_t* side;
566 int i;
567 sector_t *sec = &sectors[secnum];
568
569 if (!comp[comp_model])
570 minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow in height calcs
571
572 for (i = 0; i < sec->linecount; i++)
573 {
574 if (twoSided(secnum, i))
575 {
576 side = getSide(secnum,i,0);
577 if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder
578 if (textureheight[side->bottomtexture] < minsize)
579 minsize = textureheight[side->bottomtexture];
580 side = getSide(secnum,i,1);
581 if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder
582 if (textureheight[side->bottomtexture] < minsize)
583 minsize = textureheight[side->bottomtexture];
584 }
585 }
586 return minsize;
587}
588
589
590//
591// P_FindShortestUpperAround()
592//
593// Passed a sector number, returns the shortest upper texture on a
594// linedef bounding the sector.
595//
596// Note: If no upper texture exists 32000*FRACUNIT is returned.
597// but if compatibility then INT_MAX is returned
598//
599// jff 03/20/98 Add routine to find shortest upper texture
600//
601fixed_t P_FindShortestUpperAround(int secnum)
602{
603 int minsize = INT_MAX;
604 side_t* side;
605 int i;
606 sector_t *sec = &sectors[secnum];
607
608 if (!comp[comp_model])
609 minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow
610 // in height calcs
611 for (i = 0; i < sec->linecount; i++)
612 {
613 if (twoSided(secnum, i))
614 {
615 side = getSide(secnum,i,0);
616 if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder
617 if (textureheight[side->toptexture] < minsize)
618 minsize = textureheight[side->toptexture];
619 side = getSide(secnum,i,1);
620 if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder
621 if (textureheight[side->toptexture] < minsize)
622 minsize = textureheight[side->toptexture];
623 }
624 }
625 return minsize;
626}
627
628
629//
630// P_FindModelFloorSector()
631//
632// Passed a floor height and a sector number, return a pointer to a
633// a sector with that floor height across the lowest numbered two sided
634// line surrounding the sector.
635//
636// Note: If no sector at that height bounds the sector passed, return NULL
637//
638// jff 02/03/98 Add routine to find numeric model floor
639// around a sector specified by sector number
640// jff 3/14/98 change first parameter to plain height to allow call
641// from routine not using floormove_t
642//
643sector_t *P_FindModelFloorSector(fixed_t floordestheight,int secnum)
644{
645 int i;
646 sector_t *sec=NULL;
647 int linecount;
648
649 sec = &sectors[secnum]; //jff 3/2/98 woops! better do this
650 //jff 5/23/98 don't disturb sec->linecount while searching
651 // but allow early exit in old demos
652 linecount = sec->linecount;
653 for (i = 0; i < (demo_compatibility && sec->linecount<linecount?
654 sec->linecount : linecount); i++)
655 {
656 if ( twoSided(secnum, i) )
657 {
658 if (getSide(secnum,i,0)->sector-sectors == secnum)
659 sec = getSector(secnum,i,1);
660 else
661 sec = getSector(secnum,i,0);
662
663 if (sec->floorheight == floordestheight)
664 return sec;
665 }
666 }
667 return NULL;
668}
669
670
671//
672// P_FindModelCeilingSector()
673//
674// Passed a ceiling height and a sector number, return a pointer to a
675// a sector with that ceiling height across the lowest numbered two sided
676// line surrounding the sector.
677//
678// Note: If no sector at that height bounds the sector passed, return NULL
679//
680// jff 02/03/98 Add routine to find numeric model ceiling
681// around a sector specified by sector number
682// used only from generalized ceiling types
683// jff 3/14/98 change first parameter to plain height to allow call
684// from routine not using ceiling_t
685//
686sector_t *P_FindModelCeilingSector(fixed_t ceildestheight,int secnum)
687{
688 int i;
689 sector_t *sec=NULL;
690 int linecount;
691
692 sec = &sectors[secnum]; //jff 3/2/98 woops! better do this
693 //jff 5/23/98 don't disturb sec->linecount while searching
694 // but allow early exit in old demos
695 linecount = sec->linecount;
696 for (i = 0; i < (demo_compatibility && sec->linecount<linecount?
697 sec->linecount : linecount); i++)
698 {
699 if ( twoSided(secnum, i) )
700 {
701 if (getSide(secnum,i,0)->sector-sectors == secnum)
702 sec = getSector(secnum,i,1);
703 else
704 sec = getSector(secnum,i,0);
705
706 if (sec->ceilingheight == ceildestheight)
707 return sec;
708 }
709 }
710 return NULL;
711}
712
713//
714// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
715//
716
717// Find the next sector with the same tag as a linedef.
718// Rewritten by Lee Killough to use chained hashing to improve speed
719
720int P_FindSectorFromLineTag(const line_t *line, int start)
721{
722 start = start >= 0 ? sectors[start].nexttag :
723 sectors[(unsigned) line->tag % (unsigned) numsectors].firsttag;
724 while (start >= 0 && sectors[start].tag != line->tag)
725 start = sectors[start].nexttag;
726 return start;
727}
728
729// killough 4/16/98: Same thing, only for linedefs
730
731int P_FindLineFromLineTag(const line_t *line, int start)
732{
733 start = start >= 0 ? lines[start].nexttag :
734 lines[(unsigned) line->tag % (unsigned) numlines].firsttag;
735 while (start >= 0 && lines[start].tag != line->tag)
736 start = lines[start].nexttag;
737 return start;
738}
739
740// Hash the sector tags across the sectors and linedefs.
741static void P_InitTagLists(void)
742{
743 register int i;
744
745 for (i=numsectors; --i>=0; ) // Initially make all slots empty.
746 sectors[i].firsttag = -1;
747 for (i=numsectors; --i>=0; ) // Proceed from last to first sector
748 { // so that lower sectors appear first
749 int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func
750 sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain
751 sectors[j].firsttag = i;
752 }
753
754 // killough 4/17/98: same thing, only for linedefs
755
756 for (i=numlines; --i>=0; ) // Initially make all slots empty.
757 lines[i].firsttag = -1;
758 for (i=numlines; --i>=0; ) // Proceed from last to first linedef
759 { // so that lower linedefs appear first
760 int j = (unsigned) lines[i].tag % (unsigned) numlines; // Hash func
761 lines[i].nexttag = lines[j].firsttag; // Prepend linedef to chain
762 lines[j].firsttag = i;
763 }
764}
765
766//
767// P_FindMinSurroundingLight()
768//
769// Passed a sector and a light level, returns the smallest light level
770// in a surrounding sector less than that passed. If no smaller light
771// level exists, the light level passed is returned.
772//
773int P_FindMinSurroundingLight
774( sector_t* sector,
775 int max )
776{
777 int i;
778 int min;
779 line_t* line;
780 sector_t* check;
781
782 min = max;
783 for (i=0 ; i < sector->linecount ; i++)
784 {
785 line = sector->lines[i];
786 check = getNextSector(line,sector);
787
788 if (!check)
789 continue;
790
791 if (check->lightlevel < min)
792 min = check->lightlevel;
793 }
794 return min;
795}
796
797
798//
799// P_CanUnlockGenDoor()
800//
801// Passed a generalized locked door linedef and a player, returns whether
802// the player has the keys necessary to unlock that door.
803//
804// Note: The linedef passed MUST be a generalized locked door type
805// or results are undefined.
806//
807// jff 02/05/98 routine added to test for unlockability of
808// generalized locked doors
809//
810boolean P_CanUnlockGenDoor
811( line_t* line,
812 player_t* player)
813{
814 // does this line special distinguish between skulls and keys?
815 int skulliscard = (line->special & LockedNKeys)>>LockedNKeysShift;
816
817 // determine for each case of lock type if player's keys are adequate
818 switch((line->special & LockedKey)>>LockedKeyShift)
819 {
820 case AnyKey:
821 if
822 (
823 !player->cards[it_redcard] &&
824 !player->cards[it_redskull] &&
825 !player->cards[it_bluecard] &&
826 !player->cards[it_blueskull] &&
827 !player->cards[it_yellowcard] &&
828 !player->cards[it_yellowskull]
829 )
830 {
831 player->message = s_PD_ANY; // Ty 03/27/98 - externalized
832 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
833 return false;
834 }
835 break;
836 case RCard:
837 if
838 (
839 !player->cards[it_redcard] &&
840 (!skulliscard || !player->cards[it_redskull])
841 )
842 {
843 player->message = skulliscard? s_PD_REDK : s_PD_REDC; // Ty 03/27/98 - externalized
844 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
845 return false;
846 }
847 break;
848 case BCard:
849 if
850 (
851 !player->cards[it_bluecard] &&
852 (!skulliscard || !player->cards[it_blueskull])
853 )
854 {
855 player->message = skulliscard? s_PD_BLUEK : s_PD_BLUEC; // Ty 03/27/98 - externalized
856 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
857 return false;
858 }
859 break;
860 case YCard:
861 if
862 (
863 !player->cards[it_yellowcard] &&
864 (!skulliscard || !player->cards[it_yellowskull])
865 )
866 {
867 player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWC; // Ty 03/27/98 - externalized
868 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
869 return false;
870 }
871 break;
872 case RSkull:
873 if
874 (
875 !player->cards[it_redskull] &&
876 (!skulliscard || !player->cards[it_redcard])
877 )
878 {
879 player->message = skulliscard? s_PD_REDK : s_PD_REDS; // Ty 03/27/98 - externalized
880 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
881 return false;
882 }
883 break;
884 case BSkull:
885 if
886 (
887 !player->cards[it_blueskull] &&
888 (!skulliscard || !player->cards[it_bluecard])
889 )
890 {
891 player->message = skulliscard? s_PD_BLUEK : s_PD_BLUES; // Ty 03/27/98 - externalized
892 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
893 return false;
894 }
895 break;
896 case YSkull:
897 if
898 (
899 !player->cards[it_yellowskull] &&
900 (!skulliscard || !player->cards[it_yellowcard])
901 )
902 {
903 player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWS; // Ty 03/27/98 - externalized
904 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
905 return false;
906 }
907 break;
908 case AllKeys:
909 if
910 (
911 !skulliscard &&
912 (
913 !player->cards[it_redcard] ||
914 !player->cards[it_redskull] ||
915 !player->cards[it_bluecard] ||
916 !player->cards[it_blueskull] ||
917 !player->cards[it_yellowcard] ||
918 !player->cards[it_yellowskull]
919 )
920 )
921 {
922 player->message = s_PD_ALL6; // Ty 03/27/98 - externalized
923 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
924 return false;
925 }
926 if
927 (
928 skulliscard &&
929 (
930 (!player->cards[it_redcard] &&
931 !player->cards[it_redskull]) ||
932 (!player->cards[it_bluecard] &&
933 !player->cards[it_blueskull]) ||
934 (!player->cards[it_yellowcard] &&
935 !player->cards[it_yellowskull])
936 )
937 )
938 {
939 player->message = s_PD_ALL3; // Ty 03/27/98 - externalized
940 S_StartSound(player->mo,sfx_oof); // killough 3/20/98
941 return false;
942 }
943 break;
944 }
945 return true;
946}
947
948
949//
950// P_SectorActive()
951//
952// Passed a linedef special class (floor, ceiling, lighting) and a sector
953// returns whether the sector is already busy with a linedef special of the
954// same class. If old demo compatibility true, all linedef special classes
955// are the same.
956//
957// jff 2/23/98 added to prevent old demos from
958// succeeding in starting multiple specials on one sector
959//
960boolean PUREFUNC P_SectorActive(special_e t, const sector_t *sec)
961{
962 if (demo_compatibility) // return whether any thinker is active
963 return sec->floordata != NULL || sec->ceilingdata != NULL || sec->lightingdata != NULL;
964 else
965 switch (t) // return whether thinker of same type is active
966 {
967 case floor_special:
968 return sec->floordata != NULL;
969 case ceiling_special:
970 return sec->ceilingdata != NULL;
971 case lighting_special:
972 return sec->lightingdata != NULL;
973 }
974 return true; // don't know which special, must be active, shouldn't be here
975}
976
977
978//
979// P_CheckTag()
980//
981// Passed a line, returns true if the tag is non-zero or the line special
982// allows no tag without harm. If compatibility, all linedef specials are
983// allowed to have zero tag.
984//
985// Note: Only line specials activated by walkover, pushing, or shooting are
986// checked by this routine.
987//
988// jff 2/27/98 Added to check for zero tag allowed for regular special types
989//
990int P_CheckTag(line_t *line)
991{
992 /* tag not zero, allowed, or
993 * killough 11/98: compatibility option */
994 if (comp[comp_zerotags] || line->tag)
995 return 1;
996
997 switch(line->special)
998 {
999 case 1: // Manual door specials
1000 case 26:
1001 case 27:
1002 case 28:
1003 case 31:
1004 case 32:
1005 case 33:
1006 case 34:
1007 case 117:
1008 case 118:
1009
1010 case 139: // Lighting specials
1011 case 170:
1012 case 79:
1013 case 35:
1014 case 138:
1015 case 171:
1016 case 81:
1017 case 13:
1018 case 192:
1019 case 169:
1020 case 80:
1021 case 12:
1022 case 194:
1023 case 173:
1024 case 157:
1025 case 104:
1026 case 193:
1027 case 172:
1028 case 156:
1029 case 17:
1030
1031 case 195: // Thing teleporters
1032 case 174:
1033 case 97:
1034 case 39:
1035 case 126:
1036 case 125:
1037 case 210:
1038 case 209:
1039 case 208:
1040 case 207:
1041
1042 case 11: // Exits
1043 case 52:
1044 case 197:
1045 case 51:
1046 case 124:
1047 case 198:
1048
1049 case 48: // Scrolling walls
1050 case 85:
1051 return 1; // zero tag allowed
1052
1053 default:
1054 break;
1055 }
1056 return 0; // zero tag not allowed
1057}
1058
1059
1060//
1061// P_IsSecret()
1062//
1063// Passed a sector, returns if the sector secret type is still active, i.e.
1064// secret type is set and the secret has not yet been obtained.
1065//
1066// jff 3/14/98 added to simplify checks for whether sector is secret
1067// in automap and other places
1068//
1069boolean PUREFUNC P_IsSecret(const sector_t *sec)
1070{
1071 return (sec->special==9 || (sec->special&SECRET_MASK));
1072}
1073
1074
1075//
1076// P_WasSecret()
1077//
1078// Passed a sector, returns if the sector secret type is was active, i.e.
1079// secret type was set and the secret has been obtained already.
1080//
1081// jff 3/14/98 added to simplify checks for whether sector is secret
1082// in automap and other places
1083//
1084boolean PUREFUNC P_WasSecret(const sector_t *sec)
1085{
1086 return (sec->oldspecial==9 || (sec->oldspecial&SECRET_MASK));
1087}
1088
1089
1090//////////////////////////////////////////////////////////////////////////
1091//
1092// Events
1093//
1094// Events are operations triggered by using, crossing,
1095// or shooting special lines, or by timed thinkers.
1096//
1097/////////////////////////////////////////////////////////////////////////
1098
1099//
1100// P_CrossSpecialLine - Walkover Trigger Dispatcher
1101//
1102// Called every time a thing origin is about
1103// to cross a line with a non 0 special, whether a walkover type or not.
1104//
1105// jff 02/12/98 all W1 lines were fixed to check the result from the EV_
1106// function before clearing the special. This avoids losing the function
1107// of the line, should the sector already be active when the line is
1108// crossed. Change is qualified by demo_compatibility.
1109//
1110// CPhipps - take a line_t pointer instead of a line number, as in MBF
1111void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing)
1112{
1113 int ok;
1114
1115 // Things that should never trigger lines
1116 if (!thing->player)
1117 {
1118 // Things that should NOT trigger specials...
1119 switch(thing->type)
1120 {
1121 case MT_ROCKET:
1122 case MT_PLASMA:
1123 case MT_BFG:
1124 case MT_TROOPSHOT:
1125 case MT_HEADSHOT:
1126 case MT_BRUISERSHOT:
1127 return;
1128 break;
1129
1130 default: break;
1131 }
1132 }
1133
1134 //jff 02/04/98 add check here for generalized lindef types
1135 if (!demo_compatibility) // generalized types not recognized if old demo
1136 {
1137 // pointer to line function is NULL by default, set non-null if
1138 // line special is walkover generalized linedef type
1139 int (*linefunc)(line_t *line)=NULL;
1140
1141 // check each range of generalized linedefs
1142 if ((unsigned)line->special >= GenEnd)
1143 {
1144 // Out of range for GenFloors
1145 }
1146 else if ((unsigned)line->special >= GenFloorBase)
1147 {
1148 if (!thing->player)
1149 if ((line->special & FloorChange) || !(line->special & FloorModel))
1150 return; // FloorModel is "Allow Monsters" if FloorChange is 0
1151 if (!line->tag) //jff 2/27/98 all walk generalized types require tag
1152 return;
1153 linefunc = EV_DoGenFloor;
1154 }
1155 else if ((unsigned)line->special >= GenCeilingBase)
1156 {
1157 if (!thing->player)
1158 if ((line->special & CeilingChange) || !(line->special & CeilingModel))
1159 return; // CeilingModel is "Allow Monsters" if CeilingChange is 0
1160 if (!line->tag) //jff 2/27/98 all walk generalized types require tag
1161 return;
1162 linefunc = EV_DoGenCeiling;
1163 }
1164 else if ((unsigned)line->special >= GenDoorBase)
1165 {
1166 if (!thing->player)
1167 {
1168 if (!(line->special & DoorMonster))
1169 return; // monsters disallowed from this door
1170 if (line->flags & ML_SECRET) // they can't open secret doors either
1171 return;
1172 }
1173 if (!line->tag) //3/2/98 move outside the monster check
1174 return;
1175 linefunc = EV_DoGenDoor;
1176 }
1177 else if ((unsigned)line->special >= GenLockedBase)
1178 {
1179 if (!thing->player)
1180 return; // monsters disallowed from unlocking doors
1181 if (((line->special&TriggerType)==WalkOnce) || ((line->special&TriggerType)==WalkMany))
1182 { //jff 4/1/98 check for being a walk type before reporting door type
1183 if (!P_CanUnlockGenDoor(line,thing->player))
1184 return;
1185 }
1186 else
1187 return;
1188 linefunc = EV_DoGenLockedDoor;
1189 }
1190 else if ((unsigned)line->special >= GenLiftBase)
1191 {
1192 if (!thing->player)
1193 if (!(line->special & LiftMonster))
1194 return; // monsters disallowed
1195 if (!line->tag) //jff 2/27/98 all walk generalized types require tag
1196 return;
1197 linefunc = EV_DoGenLift;
1198 }
1199 else if ((unsigned)line->special >= GenStairsBase)
1200 {
1201 if (!thing->player)
1202 if (!(line->special & StairMonster))
1203 return; // monsters disallowed
1204 if (!line->tag) //jff 2/27/98 all walk generalized types require tag
1205 return;
1206 linefunc = EV_DoGenStairs;
1207 }
1208
1209 if (linefunc) // if it was a valid generalized type
1210 switch((line->special & TriggerType) >> TriggerTypeShift)
1211 {
1212 case WalkOnce:
1213 if (linefunc(line))
1214 line->special = 0; // clear special if a walk once type
1215 return;
1216 case WalkMany:
1217 linefunc(line);
1218 return;
1219 default: // if not a walk type, do nothing here
1220 return;
1221 }
1222 }
1223
1224 if (!thing->player)
1225 {
1226 ok = 0;
1227 switch(line->special)
1228 {
1229 case 39: // teleport trigger
1230 case 97: // teleport retrigger
1231 case 125: // teleport monsteronly trigger
1232 case 126: // teleport monsteronly retrigger
1233 case 4: // raise door
1234 case 10: // plat down-wait-up-stay trigger
1235 case 88: // plat down-wait-up-stay retrigger
1236 //jff 3/5/98 add ability of monsters etc. to use teleporters
1237 case 208: //silent thing teleporters
1238 case 207:
1239 case 243: //silent line-line teleporter
1240 case 244: //jff 3/6/98 make fit within DCK's 256 linedef types
1241 case 262: //jff 4/14/98 add monster only
1242 case 263: //jff 4/14/98 silent thing,line,line rev types
1243 case 264: //jff 4/14/98 plus player/monster silent line
1244 case 265: // reversed types
1245 case 266:
1246 case 267:
1247 case 268:
1248 case 269:
1249 ok = 1;
1250 break;
1251 }
1252 if (!ok)
1253 return;
1254 }
1255
1256 if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types
1257 return;
1258
1259 // Dispatch on the line special value to the line's action routine
1260 // If a once only function, and successful, clear the line special
1261
1262 switch (line->special)
1263 {
1264 // Regular walk once triggers
1265
1266 case 2:
1267 // Open Door
1268 if (EV_DoDoor(line,open) || demo_compatibility)
1269 line->special = 0;
1270 break;
1271
1272 case 3:
1273 // Close Door
1274 if (EV_DoDoor(line,close) || demo_compatibility)
1275 line->special = 0;
1276 break;
1277
1278 case 4:
1279 // Raise Door
1280 if (EV_DoDoor(line,normal) || demo_compatibility)
1281 line->special = 0;
1282 break;
1283
1284 case 5:
1285 // Raise Floor
1286 if (EV_DoFloor(line,raiseFloor) || demo_compatibility)
1287 line->special = 0;
1288 break;
1289
1290 case 6:
1291 // Fast Ceiling Crush & Raise
1292 if (EV_DoCeiling(line,fastCrushAndRaise) || demo_compatibility)
1293 line->special = 0;
1294 break;
1295
1296 case 8:
1297 // Build Stairs
1298 if (EV_BuildStairs(line,build8) || demo_compatibility)
1299 line->special = 0;
1300 break;
1301
1302 case 10:
1303 // PlatDownWaitUp
1304 if (EV_DoPlat(line,downWaitUpStay,0) || demo_compatibility)
1305 line->special = 0;
1306 break;
1307
1308 case 12:
1309 // Light Turn On - brightest near
1310 if (EV_LightTurnOn(line,0) || demo_compatibility)
1311 line->special = 0;
1312 break;
1313
1314 case 13:
1315 // Light Turn On 255
1316 if (EV_LightTurnOn(line,255) || demo_compatibility)
1317 line->special = 0;
1318 break;
1319
1320 case 16:
1321 // Close Door 30
1322 if (EV_DoDoor(line,close30ThenOpen) || demo_compatibility)
1323 line->special = 0;
1324 break;
1325
1326 case 17:
1327 // Start Light Strobing
1328 if (EV_StartLightStrobing(line) || demo_compatibility)
1329 line->special = 0;
1330 break;
1331
1332 case 19:
1333 // Lower Floor
1334 if (EV_DoFloor(line,lowerFloor) || demo_compatibility)
1335 line->special = 0;
1336 break;
1337
1338 case 22:
1339 // Raise floor to nearest height and change texture
1340 if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility)
1341 line->special = 0;
1342 break;
1343
1344 case 25:
1345 // Ceiling Crush and Raise
1346 if (EV_DoCeiling(line,crushAndRaise) || demo_compatibility)
1347 line->special = 0;
1348 break;
1349
1350 case 30:
1351 // Raise floor to shortest texture height
1352 // on either side of lines.
1353 if (EV_DoFloor(line,raiseToTexture) || demo_compatibility)
1354 line->special = 0;
1355 break;
1356
1357 case 35:
1358 // Lights Very Dark
1359 if (EV_LightTurnOn(line,35) || demo_compatibility)
1360 line->special = 0;
1361 break;
1362
1363 case 36:
1364 // Lower Floor (TURBO)
1365 if (EV_DoFloor(line,turboLower) || demo_compatibility)
1366 line->special = 0;
1367 break;
1368
1369 case 37:
1370 // LowerAndChange
1371 if (EV_DoFloor(line,lowerAndChange) || demo_compatibility)
1372 line->special = 0;
1373 break;
1374
1375 case 38:
1376 // Lower Floor To Lowest
1377 if (EV_DoFloor(line, lowerFloorToLowest) || demo_compatibility)
1378 line->special = 0;
1379 break;
1380
1381 case 39:
1382 // TELEPORT! //jff 02/09/98 fix using up with wrong side crossing
1383 if (EV_Teleport(line, side, thing) || demo_compatibility)
1384 line->special = 0;
1385 break;
1386
1387 case 40:
1388 // RaiseCeilingLowerFloor
1389 if (demo_compatibility)
1390 {
1391 EV_DoCeiling( line, raiseToHighest );
1392 EV_DoFloor( line, lowerFloorToLowest ); //jff 02/12/98 doesn't work
1393 line->special = 0;
1394 }
1395 else
1396 if (EV_DoCeiling(line, raiseToHighest))
1397 line->special = 0;
1398 break;
1399
1400 case 44:
1401 // Ceiling Crush
1402 if (EV_DoCeiling(line, lowerAndCrush) || demo_compatibility)
1403 line->special = 0;
1404 break;
1405
1406 case 52:
1407 // EXIT!
1408 // killough 10/98: prevent zombies from exiting levels
1409 if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie]))
1410 G_ExitLevel ();
1411 break;
1412
1413 case 53:
1414 // Perpetual Platform Raise
1415 if (EV_DoPlat(line,perpetualRaise,0) || demo_compatibility)
1416 line->special = 0;
1417 break;
1418
1419 case 54:
1420 // Platform Stop
1421 if (EV_StopPlat(line) || demo_compatibility)
1422 line->special = 0;
1423 break;
1424
1425 case 56:
1426 // Raise Floor Crush
1427 if (EV_DoFloor(line,raiseFloorCrush) || demo_compatibility)
1428 line->special = 0;
1429 break;
1430
1431 case 57:
1432 // Ceiling Crush Stop
1433 if (EV_CeilingCrushStop(line) || demo_compatibility)
1434 line->special = 0;
1435 break;
1436
1437 case 58:
1438 // Raise Floor 24
1439 if (EV_DoFloor(line,raiseFloor24) || demo_compatibility)
1440 line->special = 0;
1441 break;
1442
1443 case 59:
1444 // Raise Floor 24 And Change
1445 if (EV_DoFloor(line,raiseFloor24AndChange) || demo_compatibility)
1446 line->special = 0;
1447 break;
1448
1449 case 100:
1450 // Build Stairs Turbo 16
1451 if (EV_BuildStairs(line,turbo16) || demo_compatibility)
1452 line->special = 0;
1453 break;
1454
1455 case 104:
1456 // Turn lights off in sector(tag)
1457 if (EV_TurnTagLightsOff(line) || demo_compatibility)
1458 line->special = 0;
1459 break;
1460
1461 case 108:
1462 // Blazing Door Raise (faster than TURBO!)
1463 if (EV_DoDoor(line,blazeRaise) || demo_compatibility)
1464 line->special = 0;
1465 break;
1466
1467 case 109:
1468 // Blazing Door Open (faster than TURBO!)
1469 if (EV_DoDoor (line,blazeOpen) || demo_compatibility)
1470 line->special = 0;
1471 break;
1472
1473 case 110:
1474 // Blazing Door Close (faster than TURBO!)
1475 if (EV_DoDoor (line,blazeClose) || demo_compatibility)
1476 line->special = 0;
1477 break;
1478
1479 case 119:
1480 // Raise floor to nearest surr. floor
1481 if (EV_DoFloor(line,raiseFloorToNearest) || demo_compatibility)
1482 line->special = 0;
1483 break;
1484
1485 case 121:
1486 // Blazing PlatDownWaitUpStay
1487 if (EV_DoPlat(line,blazeDWUS,0) || demo_compatibility)
1488 line->special = 0;
1489 break;
1490
1491 case 124:
1492 // Secret EXIT
1493 // killough 10/98: prevent zombies from exiting levels
1494 // CPhipps - change for lxdoom's compatibility handling
1495 if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie]))
1496 G_SecretExitLevel ();
1497 break;
1498
1499 case 125:
1500 // TELEPORT MonsterONLY
1501 if (!thing->player &&
1502 (EV_Teleport(line, side, thing) || demo_compatibility))
1503 line->special = 0;
1504 break;
1505
1506 case 130:
1507 // Raise Floor Turbo
1508 if (EV_DoFloor(line,raiseFloorTurbo) || demo_compatibility)
1509 line->special = 0;
1510 break;
1511
1512 case 141:
1513 // Silent Ceiling Crush & Raise
1514 if (EV_DoCeiling(line,silentCrushAndRaise) || demo_compatibility)
1515 line->special = 0;
1516 break;
1517
1518 // Regular walk many retriggerable
1519
1520 case 72:
1521 // Ceiling Crush
1522 EV_DoCeiling( line, lowerAndCrush );
1523 break;
1524
1525 case 73:
1526 // Ceiling Crush and Raise
1527 EV_DoCeiling(line,crushAndRaise);
1528 break;
1529
1530 case 74:
1531 // Ceiling Crush Stop
1532 EV_CeilingCrushStop(line);
1533 break;
1534
1535 case 75:
1536 // Close Door
1537 EV_DoDoor(line,close);
1538 break;
1539
1540 case 76:
1541 // Close Door 30
1542 EV_DoDoor(line,close30ThenOpen);
1543 break;
1544
1545 case 77:
1546 // Fast Ceiling Crush & Raise
1547 EV_DoCeiling(line,fastCrushAndRaise);
1548 break;
1549
1550 case 79:
1551 // Lights Very Dark
1552 EV_LightTurnOn(line,35);
1553 break;
1554
1555 case 80:
1556 // Light Turn On - brightest near
1557 EV_LightTurnOn(line,0);
1558 break;
1559
1560 case 81:
1561 // Light Turn On 255
1562 EV_LightTurnOn(line,255);
1563 break;
1564
1565 case 82:
1566 // Lower Floor To Lowest
1567 EV_DoFloor( line, lowerFloorToLowest );
1568 break;
1569
1570 case 83:
1571 // Lower Floor
1572 EV_DoFloor(line,lowerFloor);
1573 break;
1574
1575 case 84:
1576 // LowerAndChange
1577 EV_DoFloor(line,lowerAndChange);
1578 break;
1579
1580 case 86:
1581 // Open Door
1582 EV_DoDoor(line,open);
1583 break;
1584
1585 case 87:
1586 // Perpetual Platform Raise
1587 EV_DoPlat(line,perpetualRaise,0);
1588 break;
1589
1590 case 88:
1591 // PlatDownWaitUp
1592 EV_DoPlat(line,downWaitUpStay,0);
1593 break;
1594
1595 case 89:
1596 // Platform Stop
1597 EV_StopPlat(line);
1598 break;
1599
1600 case 90:
1601 // Raise Door
1602 EV_DoDoor(line,normal);
1603 break;
1604
1605 case 91:
1606 // Raise Floor
1607 EV_DoFloor(line,raiseFloor);
1608 break;
1609
1610 case 92:
1611 // Raise Floor 24
1612 EV_DoFloor(line,raiseFloor24);
1613 break;
1614
1615 case 93:
1616 // Raise Floor 24 And Change
1617 EV_DoFloor(line,raiseFloor24AndChange);
1618 break;
1619
1620 case 94:
1621 // Raise Floor Crush
1622 EV_DoFloor(line,raiseFloorCrush);
1623 break;
1624
1625 case 95:
1626 // Raise floor to nearest height
1627 // and change texture.
1628 EV_DoPlat(line,raiseToNearestAndChange,0);
1629 break;
1630
1631 case 96:
1632 // Raise floor to shortest texture height
1633 // on either side of lines.
1634 EV_DoFloor(line,raiseToTexture);
1635 break;
1636
1637 case 97:
1638 // TELEPORT!
1639 EV_Teleport( line, side, thing );
1640 break;
1641
1642 case 98:
1643 // Lower Floor (TURBO)
1644 EV_DoFloor(line,turboLower);
1645 break;
1646
1647 case 105:
1648 // Blazing Door Raise (faster than TURBO!)
1649 EV_DoDoor (line,blazeRaise);
1650 break;
1651
1652 case 106:
1653 // Blazing Door Open (faster than TURBO!)
1654 EV_DoDoor (line,blazeOpen);
1655 break;
1656
1657 case 107:
1658 // Blazing Door Close (faster than TURBO!)
1659 EV_DoDoor (line,blazeClose);
1660 break;
1661
1662 case 120:
1663 // Blazing PlatDownWaitUpStay.
1664 EV_DoPlat(line,blazeDWUS,0);
1665 break;
1666
1667 case 126:
1668 // TELEPORT MonsterONLY.
1669 if (!thing->player)
1670 EV_Teleport( line, side, thing );
1671 break;
1672
1673 case 128:
1674 // Raise To Nearest Floor
1675 EV_DoFloor(line,raiseFloorToNearest);
1676 break;
1677
1678 case 129:
1679 // Raise Floor Turbo
1680 EV_DoFloor(line,raiseFloorTurbo);
1681 break;
1682
1683 // Extended walk triggers
1684
1685 // jff 1/29/98 added new linedef types to fill all functions out so that
1686 // all have varieties SR, S1, WR, W1
1687
1688 // killough 1/31/98: "factor out" compatibility test, by
1689 // adding inner switch qualified by compatibility flag.
1690 // relax test to demo_compatibility
1691
1692 // killough 2/16/98: Fix problems with W1 types being cleared too early
1693
1694 default:
1695 if (!demo_compatibility)
1696 switch (line->special)
1697 {
1698 // Extended walk once triggers
1699
1700 case 142:
1701 // Raise Floor 512
1702 // 142 W1 EV_DoFloor(raiseFloor512)
1703 if (EV_DoFloor(line,raiseFloor512))
1704 line->special = 0;
1705 break;
1706
1707 case 143:
1708 // Raise Floor 24 and change
1709 // 143 W1 EV_DoPlat(raiseAndChange,24)
1710 if (EV_DoPlat(line,raiseAndChange,24))
1711 line->special = 0;
1712 break;
1713
1714 case 144:
1715 // Raise Floor 32 and change
1716 // 144 W1 EV_DoPlat(raiseAndChange,32)
1717 if (EV_DoPlat(line,raiseAndChange,32))
1718 line->special = 0;
1719 break;
1720
1721 case 145:
1722 // Lower Ceiling to Floor
1723 // 145 W1 EV_DoCeiling(lowerToFloor)
1724 if (EV_DoCeiling( line, lowerToFloor ))
1725 line->special = 0;
1726 break;
1727
1728 case 146:
1729 // Lower Pillar, Raise Donut
1730 // 146 W1 EV_DoDonut()
1731 if (EV_DoDonut(line))
1732 line->special = 0;
1733 break;
1734
1735 case 199:
1736 // Lower ceiling to lowest surrounding ceiling
1737 // 199 W1 EV_DoCeiling(lowerToLowest)
1738 if (EV_DoCeiling(line,lowerToLowest))
1739 line->special = 0;
1740 break;
1741
1742 case 200:
1743 // Lower ceiling to highest surrounding floor
1744 // 200 W1 EV_DoCeiling(lowerToMaxFloor)
1745 if (EV_DoCeiling(line,lowerToMaxFloor))
1746 line->special = 0;
1747 break;
1748
1749 case 207:
1750 // killough 2/16/98: W1 silent teleporter (normal kind)
1751 if (EV_SilentTeleport(line, side, thing))
1752 line->special = 0;
1753 break;
1754
1755 //jff 3/16/98 renumber 215->153
1756 case 153: //jff 3/15/98 create texture change no motion type
1757 // Texture/Type Change Only (Trig)
1758 // 153 W1 Change Texture/Type Only
1759 if (EV_DoChange(line,trigChangeOnly))
1760 line->special = 0;
1761 break;
1762
1763 case 239: //jff 3/15/98 create texture change no motion type
1764 // Texture/Type Change Only (Numeric)
1765 // 239 W1 Change Texture/Type Only
1766 if (EV_DoChange(line,numChangeOnly))
1767 line->special = 0;
1768 break;
1769
1770 case 219:
1771 // Lower floor to next lower neighbor
1772 // 219 W1 Lower Floor Next Lower Neighbor
1773 if (EV_DoFloor(line,lowerFloorToNearest))
1774 line->special = 0;
1775 break;
1776
1777 case 227:
1778 // Raise elevator next floor
1779 // 227 W1 Raise Elevator next floor
1780 if (EV_DoElevator(line,elevateUp))
1781 line->special = 0;
1782 break;
1783
1784 case 231:
1785 // Lower elevator next floor
1786 // 231 W1 Lower Elevator next floor
1787 if (EV_DoElevator(line,elevateDown))
1788 line->special = 0;
1789 break;
1790
1791 case 235:
1792 // Elevator to current floor
1793 // 235 W1 Elevator to current floor
1794 if (EV_DoElevator(line,elevateCurrent))
1795 line->special = 0;
1796 break;
1797
1798 case 243: //jff 3/6/98 make fit within DCK's 256 linedef types
1799 // killough 2/16/98: W1 silent teleporter (linedef-linedef kind)
1800 if (EV_SilentLineTeleport(line, side, thing, false))
1801 line->special = 0;
1802 break;
1803
1804 case 262: //jff 4/14/98 add silent line-line reversed
1805 if (EV_SilentLineTeleport(line, side, thing, true))
1806 line->special = 0;
1807 break;
1808
1809 case 264: //jff 4/14/98 add monster-only silent line-line reversed
1810 if (!thing->player &&
1811 EV_SilentLineTeleport(line, side, thing, true))
1812 line->special = 0;
1813 break;
1814
1815 case 266: //jff 4/14/98 add monster-only silent line-line
1816 if (!thing->player &&
1817 EV_SilentLineTeleport(line, side, thing, false))
1818 line->special = 0;
1819 break;
1820
1821 case 268: //jff 4/14/98 add monster-only silent
1822 if (!thing->player && EV_SilentTeleport(line, side, thing))
1823 line->special = 0;
1824 break;
1825
1826 //jff 1/29/98 end of added W1 linedef types
1827
1828 // Extended walk many retriggerable
1829
1830 //jff 1/29/98 added new linedef types to fill all functions
1831 //out so that all have varieties SR, S1, WR, W1
1832
1833 case 147:
1834 // Raise Floor 512
1835 // 147 WR EV_DoFloor(raiseFloor512)
1836 EV_DoFloor(line,raiseFloor512);
1837 break;
1838
1839 case 148:
1840 // Raise Floor 24 and Change
1841 // 148 WR EV_DoPlat(raiseAndChange,24)
1842 EV_DoPlat(line,raiseAndChange,24);
1843 break;
1844
1845 case 149:
1846 // Raise Floor 32 and Change
1847 // 149 WR EV_DoPlat(raiseAndChange,32)
1848 EV_DoPlat(line,raiseAndChange,32);
1849 break;
1850
1851 case 150:
1852 // Start slow silent crusher
1853 // 150 WR EV_DoCeiling(silentCrushAndRaise)
1854 EV_DoCeiling(line,silentCrushAndRaise);
1855 break;
1856
1857 case 151:
1858 // RaiseCeilingLowerFloor
1859 // 151 WR EV_DoCeiling(raiseToHighest),
1860 // EV_DoFloor(lowerFloortoLowest)
1861 EV_DoCeiling( line, raiseToHighest );
1862 EV_DoFloor( line, lowerFloorToLowest );
1863 break;
1864
1865 case 152:
1866 // Lower Ceiling to Floor
1867 // 152 WR EV_DoCeiling(lowerToFloor)
1868 EV_DoCeiling( line, lowerToFloor );
1869 break;
1870
1871 //jff 3/16/98 renumber 153->256
1872 case 256:
1873 // Build stairs, step 8
1874 // 256 WR EV_BuildStairs(build8)
1875 EV_BuildStairs(line,build8);
1876 break;
1877
1878 //jff 3/16/98 renumber 154->257
1879 case 257:
1880 // Build stairs, step 16
1881 // 257 WR EV_BuildStairs(turbo16)
1882 EV_BuildStairs(line,turbo16);
1883 break;
1884
1885 case 155:
1886 // Lower Pillar, Raise Donut
1887 // 155 WR EV_DoDonut()
1888 EV_DoDonut(line);
1889 break;
1890
1891 case 156:
1892 // Start lights strobing
1893 // 156 WR Lights EV_StartLightStrobing()
1894 EV_StartLightStrobing(line);
1895 break;
1896
1897 case 157:
1898 // Lights to dimmest near
1899 // 157 WR Lights EV_TurnTagLightsOff()
1900 EV_TurnTagLightsOff(line);
1901 break;
1902
1903 case 201:
1904 // Lower ceiling to lowest surrounding ceiling
1905 // 201 WR EV_DoCeiling(lowerToLowest)
1906 EV_DoCeiling(line,lowerToLowest);
1907 break;
1908
1909 case 202:
1910 // Lower ceiling to highest surrounding floor
1911 // 202 WR EV_DoCeiling(lowerToMaxFloor)
1912 EV_DoCeiling(line,lowerToMaxFloor);
1913 break;
1914
1915 case 208:
1916 // killough 2/16/98: WR silent teleporter (normal kind)
1917 EV_SilentTeleport(line, side, thing);
1918 break;
1919
1920 case 212: //jff 3/14/98 create instant toggle floor type
1921 // Toggle floor between C and F instantly
1922 // 212 WR Instant Toggle Floor
1923 EV_DoPlat(line,toggleUpDn,0);
1924 break;
1925
1926 //jff 3/16/98 renumber 216->154
1927 case 154: //jff 3/15/98 create texture change no motion type
1928 // Texture/Type Change Only (Trigger)
1929 // 154 WR Change Texture/Type Only
1930 EV_DoChange(line,trigChangeOnly);
1931 break;
1932
1933 case 240: //jff 3/15/98 create texture change no motion type
1934 // Texture/Type Change Only (Numeric)
1935 // 240 WR Change Texture/Type Only
1936 EV_DoChange(line,numChangeOnly);
1937 break;
1938
1939 case 220:
1940 // Lower floor to next lower neighbor
1941 // 220 WR Lower Floor Next Lower Neighbor
1942 EV_DoFloor(line,lowerFloorToNearest);
1943 break;
1944
1945 case 228:
1946 // Raise elevator next floor
1947 // 228 WR Raise Elevator next floor
1948 EV_DoElevator(line,elevateUp);
1949 break;
1950
1951 case 232:
1952 // Lower elevator next floor
1953 // 232 WR Lower Elevator next floor
1954 EV_DoElevator(line,elevateDown);
1955 break;
1956
1957 case 236:
1958 // Elevator to current floor
1959 // 236 WR Elevator to current floor
1960 EV_DoElevator(line,elevateCurrent);
1961 break;
1962
1963 case 244: //jff 3/6/98 make fit within DCK's 256 linedef types
1964 // killough 2/16/98: WR silent teleporter (linedef-linedef kind)
1965 EV_SilentLineTeleport(line, side, thing, false);
1966 break;
1967
1968 case 263: //jff 4/14/98 add silent line-line reversed
1969 EV_SilentLineTeleport(line, side, thing, true);
1970 break;
1971
1972 case 265: //jff 4/14/98 add monster-only silent line-line reversed
1973 if (!thing->player)
1974 EV_SilentLineTeleport(line, side, thing, true);
1975 break;
1976
1977 case 267: //jff 4/14/98 add monster-only silent line-line
1978 if (!thing->player)
1979 EV_SilentLineTeleport(line, side, thing, false);
1980 break;
1981
1982 case 269: //jff 4/14/98 add monster-only silent
1983 if (!thing->player)
1984 EV_SilentTeleport(line, side, thing);
1985 break;
1986
1987 //jff 1/29/98 end of added WR linedef types
1988 }
1989 break;
1990 }
1991}
1992
1993//
1994// P_ShootSpecialLine - Gun trigger special dispatcher
1995//
1996// Called when a thing shoots a special line with bullet, shell, saw, or fist.
1997//
1998// jff 02/12/98 all G1 lines were fixed to check the result from the EV_
1999// function before clearing the special. This avoids losing the function
2000// of the line, should the sector already be in motion when the line is
2001// impacted. Change is qualified by demo_compatibility.
2002//
2003void P_ShootSpecialLine
2004( mobj_t* thing,
2005 line_t* line )
2006{
2007 //jff 02/04/98 add check here for generalized linedef
2008 if (!demo_compatibility)
2009 {
2010 // pointer to line function is NULL by default, set non-null if
2011 // line special is gun triggered generalized linedef type
2012 int (*linefunc)(line_t *line)=NULL;
2013
2014 // check each range of generalized linedefs
2015 if ((unsigned)line->special >= GenEnd)
2016 {
2017 // Out of range for GenFloors
2018 }
2019 else if ((unsigned)line->special >= GenFloorBase)
2020 {
2021 if (!thing->player)
2022 if ((line->special & FloorChange) || !(line->special & FloorModel))
2023 return; // FloorModel is "Allow Monsters" if FloorChange is 0
2024 if (!line->tag) //jff 2/27/98 all gun generalized types require tag
2025 return;
2026
2027 linefunc = EV_DoGenFloor;
2028 }
2029 else if ((unsigned)line->special >= GenCeilingBase)
2030 {
2031 if (!thing->player)
2032 if ((line->special & CeilingChange) || !(line->special & CeilingModel))
2033 return; // CeilingModel is "Allow Monsters" if CeilingChange is 0
2034 if (!line->tag) //jff 2/27/98 all gun generalized types require tag
2035 return;
2036 linefunc = EV_DoGenCeiling;
2037 }
2038 else if ((unsigned)line->special >= GenDoorBase)
2039 {
2040 if (!thing->player)
2041 {
2042 if (!(line->special & DoorMonster))
2043 return; // monsters disallowed from this door
2044 if (line->flags & ML_SECRET) // they can't open secret doors either
2045 return;
2046 }
2047 if (!line->tag) //jff 3/2/98 all gun generalized types require tag
2048 return;
2049 linefunc = EV_DoGenDoor;
2050 }
2051 else if ((unsigned)line->special >= GenLockedBase)
2052 {
2053 if (!thing->player)
2054 return; // monsters disallowed from unlocking doors
2055 if (((line->special&TriggerType)==GunOnce) || ((line->special&TriggerType)==GunMany))
2056 { //jff 4/1/98 check for being a gun type before reporting door type
2057 if (!P_CanUnlockGenDoor(line,thing->player))
2058 return;
2059 }
2060 else
2061 return;
2062 if (!line->tag) //jff 2/27/98 all gun generalized types require tag
2063 return;
2064
2065 linefunc = EV_DoGenLockedDoor;
2066 }
2067 else if ((unsigned)line->special >= GenLiftBase)
2068 {
2069 if (!thing->player)
2070 if (!(line->special & LiftMonster))
2071 return; // monsters disallowed
2072 linefunc = EV_DoGenLift;
2073 }
2074 else if ((unsigned)line->special >= GenStairsBase)
2075 {
2076 if (!thing->player)
2077 if (!(line->special & StairMonster))
2078 return; // monsters disallowed
2079 if (!line->tag) //jff 2/27/98 all gun generalized types require tag
2080 return;
2081 linefunc = EV_DoGenStairs;
2082 }
2083 else if ((unsigned)line->special >= GenCrusherBase)
2084 {
2085 if (!thing->player)
2086 if (!(line->special & StairMonster))
2087 return; // monsters disallowed
2088 if (!line->tag) //jff 2/27/98 all gun generalized types require tag
2089 return;
2090 linefunc = EV_DoGenCrusher;
2091 }
2092
2093 if (linefunc)
2094 switch((line->special & TriggerType) >> TriggerTypeShift)
2095 {
2096 case GunOnce:
2097 if (linefunc(line))
2098 P_ChangeSwitchTexture(line,0);
2099 return;
2100 case GunMany:
2101 if (linefunc(line))
2102 P_ChangeSwitchTexture(line,1);
2103 return;
2104 default: // if not a gun type, do nothing here
2105 return;
2106 }
2107 }
2108
2109 // Impacts that other things can activate.
2110 if (!thing->player)
2111 {
2112 int ok = 0;
2113 switch(line->special)
2114 {
2115 case 46:
2116 // 46 GR Open door on impact weapon is monster activatable
2117 ok = 1;
2118 break;
2119 }
2120 if (!ok)
2121 return;
2122 }
2123
2124 if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types
2125 return;
2126
2127 switch(line->special)
2128 {
2129 case 24:
2130 // 24 G1 raise floor to highest adjacent
2131 if (EV_DoFloor(line,raiseFloor) || demo_compatibility)
2132 P_ChangeSwitchTexture(line,0);
2133 break;
2134
2135 case 46:
2136 // 46 GR open door, stay open
2137 EV_DoDoor(line,open);
2138 P_ChangeSwitchTexture(line,1);
2139 break;
2140
2141 case 47:
2142 // 47 G1 raise floor to nearest and change texture and type
2143 if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility)
2144 P_ChangeSwitchTexture(line,0);
2145 break;
2146
2147 //jff 1/30/98 added new gun linedefs here
2148 // killough 1/31/98: added demo_compatibility check, added inner switch
2149
2150 default:
2151 if (!demo_compatibility)
2152 switch (line->special)
2153 {
2154 case 197:
2155 // Exit to next level
2156 // killough 10/98: prevent zombies from exiting levels
2157 if(thing->player && thing->player->health<=0 && !comp[comp_zombie])
2158 break;
2159 P_ChangeSwitchTexture(line,0);
2160 G_ExitLevel();
2161 break;
2162
2163 case 198:
2164 // Exit to secret level
2165 // killough 10/98: prevent zombies from exiting levels
2166 if(thing->player && thing->player->health<=0 && !comp[comp_zombie])
2167 break;
2168 P_ChangeSwitchTexture(line,0);
2169 G_SecretExitLevel();
2170 break;
2171 //jff end addition of new gun linedefs
2172 }
2173 break;
2174 }
2175}
2176
2177
2178//
2179// P_PlayerInSpecialSector()
2180//
2181// Called every tick frame
2182// that the player origin is in a special sector
2183//
2184// Changed to ignore sector types the engine does not recognize
2185//
2186void P_PlayerInSpecialSector (player_t* player)
2187{
2188 sector_t* sector;
2189
2190 sector = player->mo->subsector->sector;
2191
2192 // Falling, not all the way down yet?
2193 // Sector specials don't apply in mid-air
2194 if (player->mo->z != sector->floorheight)
2195 return;
2196
2197 // Has hit ground.
2198 //jff add if to handle old vs generalized types
2199 if (sector->special<32) // regular sector specials
2200 {
2201 switch (sector->special)
2202 {
2203 case 5:
2204 // 5/10 unit damage per 31 ticks
2205 if (!player->powers[pw_ironfeet])
2206 if (!(leveltime&0x1f))
2207 P_DamageMobj (player->mo, NULL, NULL, 10);
2208 break;
2209
2210 case 7:
2211 // 2/5 unit damage per 31 ticks
2212 if (!player->powers[pw_ironfeet])
2213 if (!(leveltime&0x1f))
2214 P_DamageMobj (player->mo, NULL, NULL, 5);
2215 break;
2216
2217 case 16:
2218 // 10/20 unit damage per 31 ticks
2219 case 4:
2220 // 10/20 unit damage plus blinking light (light already spawned)
2221 if (!player->powers[pw_ironfeet]
2222 || (P_Random(pr_slimehurt)<5) ) // even with suit, take damage
2223 {
2224 if (!(leveltime&0x1f))
2225 P_DamageMobj (player->mo, NULL, NULL, 20);
2226 }
2227 break;
2228
2229 case 9:
2230 // Tally player in secret sector, clear secret special
2231 player->secretcount++;
2232 sector->special = 0;
2233 break;
2234
2235 case 11:
2236 // Exit on health < 11, take 10/20 damage per 31 ticks
2237 if (comp[comp_god]) /* killough 2/21/98: add compatibility switch */
2238 player->cheats &= ~CF_GODMODE; // on godmode cheat clearing
2239 // does not affect invulnerability
2240 if (!(leveltime&0x1f))
2241 P_DamageMobj (player->mo, NULL, NULL, 20);
2242
2243 if (player->health <= 10)
2244 G_ExitLevel();
2245 break;
2246
2247 default:
2248 //jff 1/24/98 Don't exit as DOOM2 did, just ignore
2249 break;
2250 };
2251 }
2252 else //jff 3/14/98 handle extended sector types for secrets and damage
2253 {
2254 switch ((sector->special&DAMAGE_MASK)>>DAMAGE_SHIFT)
2255 {
2256 case 0: // no damage
2257 break;
2258 case 1: // 2/5 damage per 31 ticks
2259 if (!player->powers[pw_ironfeet])
2260 if (!(leveltime&0x1f))
2261 P_DamageMobj (player->mo, NULL, NULL, 5);
2262 break;
2263 case 2: // 5/10 damage per 31 ticks
2264 if (!player->powers[pw_ironfeet])
2265 if (!(leveltime&0x1f))
2266 P_DamageMobj (player->mo, NULL, NULL, 10);
2267 break;
2268 case 3: // 10/20 damage per 31 ticks
2269 if (!player->powers[pw_ironfeet]
2270 || (P_Random(pr_slimehurt)<5)) // take damage even with suit
2271 {
2272 if (!(leveltime&0x1f))
2273 P_DamageMobj (player->mo, NULL, NULL, 20);
2274 }
2275 break;
2276 }
2277 if (sector->special&SECRET_MASK)
2278 {
2279 player->secretcount++;
2280 sector->special &= ~SECRET_MASK;
2281 if (sector->special<32) // if all extended bits clear,
2282 sector->special=0; // sector is not special anymore
2283 }
2284
2285 // phares 3/19/98:
2286 //
2287 // If FRICTION_MASK or PUSH_MASK is set, we don't care at this
2288 // point, since the code to deal with those situations is
2289 // handled by Thinkers.
2290
2291 }
2292}
2293
2294//
2295// P_UpdateSpecials()
2296//
2297// Check level timer, frag counter,
2298// animate flats, scroll walls,
2299// change button textures
2300//
2301// Reads and modifies globals:
2302// levelTimer, levelTimeCount,
2303// levelFragLimit, levelFragLimitCount
2304//
2305
2306static boolean levelTimer;
2307static int levelTimeCount;
2308boolean levelFragLimit; // Ty 03/18/98 Added -frags support
2309int levelFragLimitCount; // Ty 03/18/98 Added -frags support
2310
2311void P_UpdateSpecials (void)
2312{
2313 anim_t* anim;
2314 int pic;
2315 int i;
2316
2317 // Downcount level timer, exit level if elapsed
2318 if (levelTimer == true)
2319 {
2320 levelTimeCount--;
2321 if (!levelTimeCount)
2322 G_ExitLevel();
2323 }
2324
2325 // Check frag counters, if frag limit reached, exit level // Ty 03/18/98
2326 // Seems like the total frags should be kept in a simple
2327 // array somewhere, but until they are...
2328 if (levelFragLimit == true) // we used -frags so compare count
2329 {
2330 int k,m,fragcount,exitflag=false;
2331 for (k=0;k<MAXPLAYERS;k++)
2332 {
2333 if (!playeringame[k]) continue;
2334 fragcount = 0;
2335 for (m=0;m<MAXPLAYERS;m++)
2336 {
2337 if (!playeringame[m]) continue;
2338 fragcount += (m!=k)? players[k].frags[m] : -players[k].frags[m];
2339 }
2340 if (fragcount >= levelFragLimitCount) exitflag = true;
2341 if (exitflag == true) break; // skip out of the loop--we're done
2342 }
2343 if (exitflag == true)
2344 G_ExitLevel();
2345 }
2346
2347 // Animate flats and textures globally
2348 for (anim = anims ; anim < lastanim ; anim++)
2349 {
2350 for (i=anim->basepic ; i<anim->basepic+anim->numpics ; i++)
2351 {
2352 pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics );
2353 if (anim->istexture)
2354 texturetranslation[i] = pic;
2355 else
2356 flattranslation[i] = pic;
2357 }
2358 }
2359
2360 // Check buttons (retriggerable switches) and change texture on timeout
2361 for (i = 0; i < MAXBUTTONS; i++)
2362 if (buttonlist[i].btimer)
2363 {
2364 buttonlist[i].btimer--;
2365 if (!buttonlist[i].btimer)
2366 {
2367 switch(buttonlist[i].where)
2368 {
2369 case top:
2370 sides[buttonlist[i].line->sidenum[0]].toptexture =
2371 buttonlist[i].btexture;
2372 break;
2373
2374 case middle:
2375 sides[buttonlist[i].line->sidenum[0]].midtexture =
2376 buttonlist[i].btexture;
2377 break;
2378
2379 case bottom:
2380 sides[buttonlist[i].line->sidenum[0]].bottomtexture =
2381 buttonlist[i].btexture;
2382 break;
2383 }
2384 {
2385 /* don't take the address of the switch's sound origin,
2386 * unless in a compatibility mode. */
2387 mobj_t *so = (mobj_t *)buttonlist[i].soundorg;
2388 if (comp[comp_sound] || compatibility_level < prboom_6_compatibility)
2389 /* since the buttonlist array is usually zeroed out,
2390 * button popouts generally appear to come from (0,0) */
2391 so = (mobj_t *)&buttonlist[i].soundorg;
2392 S_StartSound(so, sfx_swtchn);
2393 }
2394 memset(&buttonlist[i],0,sizeof(button_t));
2395 }
2396 }
2397}
2398
2399//////////////////////////////////////////////////////////////////////
2400//
2401// Sector and Line special thinker spawning at level startup
2402//
2403//////////////////////////////////////////////////////////////////////
2404
2405//
2406// P_SpawnSpecials
2407// After the map has been loaded,
2408// scan for specials that spawn thinkers
2409//
2410
2411// Parses command line parameters.
2412void P_SpawnSpecials (void)
2413{
2414 sector_t* sector;
2415 int i;
2416 int episode;
2417
2418 episode = 1;
2419 if (W_CheckNumForName("texture2") >= 0)
2420 episode = 2;
2421
2422 // See if -timer needs to be used.
2423 levelTimer = false;
2424
2425 i = M_CheckParm("-avg"); // Austin Virtual Gaming 20 min timer on DM play
2426 if (i && deathmatch)
2427 {
2428 levelTimer = true;
2429 levelTimeCount = 20 * 60 * TICRATE;
2430 }
2431
2432 i = M_CheckParm("-timer"); // user defined timer on game play
2433 if (i && deathmatch)
2434 {
2435 int time;
2436 time = atoi(myargv[i+1]) * 60 * TICRATE;
2437 levelTimer = true;
2438 levelTimeCount = time;
2439 }
2440
2441 // See if -frags has been used
2442 levelFragLimit = false;
2443 i = M_CheckParm("-frags"); // Ty 03/18/98 Added -frags support
2444 if (i && deathmatch)
2445 {
2446 int frags;
2447 frags = atoi(myargv[i+1]);
2448 if (frags <= 0) frags = 10; // default 10 if no count provided
2449 levelFragLimit = true;
2450 levelFragLimitCount = frags;
2451 }
2452
2453
2454 // Init special sectors.
2455 sector = sectors;
2456 for (i=0 ; i<numsectors ; i++, sector++)
2457 {
2458 if (!sector->special)
2459 continue;
2460
2461 if (sector->special&SECRET_MASK) //jff 3/15/98 count extended
2462 totalsecret++; // secret sectors too
2463
2464 switch (sector->special&31)
2465 {
2466 case 1:
2467 // random off
2468 P_SpawnLightFlash (sector);
2469 break;
2470
2471 case 2:
2472 // strobe fast
2473 P_SpawnStrobeFlash(sector,FASTDARK,0);
2474 break;
2475
2476 case 3:
2477 // strobe slow
2478 P_SpawnStrobeFlash(sector,SLOWDARK,0);
2479 break;
2480
2481 case 4:
2482 // strobe fast/death slime
2483 P_SpawnStrobeFlash(sector,FASTDARK,0);
2484 sector->special |= 3<<DAMAGE_SHIFT; //jff 3/14/98 put damage bits in
2485 break;
2486
2487 case 8:
2488 // glowing light
2489 P_SpawnGlowingLight(sector);
2490 break;
2491 case 9:
2492 // secret sector
2493 if (sector->special<32) //jff 3/14/98 bits don't count unless not
2494 totalsecret++; // a generalized sector type
2495 break;
2496
2497 case 10:
2498 // door close in 30 seconds
2499 P_SpawnDoorCloseIn30 (sector);
2500 break;
2501
2502 case 12:
2503 // sync strobe slow
2504 P_SpawnStrobeFlash (sector, SLOWDARK, 1);
2505 break;
2506
2507 case 13:
2508 // sync strobe fast
2509 P_SpawnStrobeFlash (sector, FASTDARK, 1);
2510 break;
2511
2512 case 14:
2513 // door raise in 5 minutes
2514 P_SpawnDoorRaiseIn5Mins (sector, i);
2515 break;
2516
2517 case 17:
2518 // fire flickering
2519 P_SpawnFireFlicker(sector);
2520 break;
2521 }
2522 }
2523
2524 P_RemoveAllActiveCeilings(); // jff 2/22/98 use killough's scheme
2525
2526 P_RemoveAllActivePlats(); // killough
2527
2528 for (i = 0;i < MAXBUTTONS;i++)
2529 memset(&buttonlist[i],0,sizeof(button_t));
2530
2531 // P_InitTagLists() must be called before P_FindSectorFromLineTag()
2532 // or P_FindLineFromLineTag() can be called.
2533
2534 P_InitTagLists(); // killough 1/30/98: Create xref tables for tags
2535
2536 P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers
2537
2538 P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs
2539
2540 P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs
2541
2542 for (i=0; i<numlines; i++)
2543 switch (lines[i].special)
2544 {
2545 int s, sec;
2546
2547 // killough 3/7/98:
2548 // support for drawn heights coming from different sector
2549 case 242:
2550 sec = sides[*lines[i].sidenum].sector-sectors;
2551 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2552 sectors[s].heightsec = sec;
2553 break;
2554
2555 // killough 3/16/98: Add support for setting
2556 // floor lighting independently (e.g. lava)
2557 case 213:
2558 sec = sides[*lines[i].sidenum].sector-sectors;
2559 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2560 sectors[s].floorlightsec = sec;
2561 break;
2562
2563 // killough 4/11/98: Add support for setting
2564 // ceiling lighting independently
2565 case 261:
2566 sec = sides[*lines[i].sidenum].sector-sectors;
2567 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2568 sectors[s].ceilinglightsec = sec;
2569 break;
2570
2571 // killough 10/98:
2572 //
2573 // Support for sky textures being transferred from sidedefs.
2574 // Allows scrolling and other effects (but if scrolling is
2575 // used, then the same sector tag needs to be used for the
2576 // sky sector, the sky-transfer linedef, and the scroll-effect
2577 // linedef). Still requires user to use F_SKY1 for the floor
2578 // or ceiling texture, to distinguish floor and ceiling sky.
2579
2580 case 271: // Regular sky
2581 case 272: // Same, only flipped
2582 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2583 sectors[s].sky = i | PL_SKYFLAT;
2584 break;
2585 }
2586}
2587
2588// killough 2/28/98:
2589//
2590// This function, with the help of r_plane.c and r_bsp.c, supports generalized
2591// scrolling floors and walls, with optional mobj-carrying properties, e.g.
2592// conveyor belts, rivers, etc. A linedef with a special type affects all
2593// tagged sectors the same way, by creating scrolling and/or object-carrying
2594// properties. Multiple linedefs may be used on the same sector and are
2595// cumulative, although the special case of scrolling a floor and carrying
2596// things on it, requires only one linedef. The linedef's direction determines
2597// the scrolling direction, and the linedef's length determines the scrolling
2598// speed. This was designed so that an edge around the sector could be used to
2599// control the direction of the sector's scrolling, which is usually what is
2600// desired.
2601//
2602// Process the active scrollers.
2603//
2604// This is the main scrolling code
2605// killough 3/7/98
2606
2607void T_Scroll(scroll_t *s)
2608{
2609 fixed_t dx = s->dx, dy = s->dy;
2610
2611 if (s->control != -1)
2612 { // compute scroll amounts based on a sector's height changes
2613 fixed_t height = sectors[s->control].floorheight +
2614 sectors[s->control].ceilingheight;
2615 fixed_t delta = height - s->last_height;
2616 s->last_height = height;
2617 dx = FixedMul(dx, delta);
2618 dy = FixedMul(dy, delta);
2619 }
2620
2621 // killough 3/14/98: Add acceleration
2622 if (s->accel)
2623 {
2624 s->vdx = dx += s->vdx;
2625 s->vdy = dy += s->vdy;
2626 }
2627
2628 if (!(dx | dy)) // no-op if both (x,y) offsets 0
2629 return;
2630
2631 switch (s->type)
2632 {
2633 side_t *side;
2634 sector_t *sec;
2635 fixed_t height, waterheight; // killough 4/4/98: add waterheight
2636 msecnode_t *node;
2637 mobj_t *thing;
2638
2639 case sc_side: // killough 3/7/98: Scroll wall texture
2640 side = sides + s->affectee;
2641 side->textureoffset += dx;
2642 side->rowoffset += dy;
2643 break;
2644
2645 case sc_floor: // killough 3/7/98: Scroll floor texture
2646 sec = sectors + s->affectee;
2647 sec->floor_xoffs += dx;
2648 sec->floor_yoffs += dy;
2649 break;
2650
2651 case sc_ceiling: // killough 3/7/98: Scroll ceiling texture
2652 sec = sectors + s->affectee;
2653 sec->ceiling_xoffs += dx;
2654 sec->ceiling_yoffs += dy;
2655 break;
2656
2657 case sc_carry:
2658
2659 // killough 3/7/98: Carry things on floor
2660 // killough 3/20/98: use new sector list which reflects true members
2661 // killough 3/27/98: fix carrier bug
2662 // killough 4/4/98: Underwater, carry things even w/o gravity
2663
2664 sec = sectors + s->affectee;
2665 height = sec->floorheight;
2666 waterheight = sec->heightsec != -1 &&
2667 sectors[sec->heightsec].floorheight > height ?
2668 sectors[sec->heightsec].floorheight : INT_MIN;
2669
2670 for (node = sec->touching_thinglist; node; node = node->m_snext)
2671 if (!((thing = node->m_thing)->flags & MF_NOCLIP) &&
2672 (!(thing->flags & MF_NOGRAVITY || thing->z > height) ||
2673 thing->z < waterheight))
2674 {
2675 // Move objects only if on floor or underwater,
2676 // non-floating, and clipped.
2677 thing->momx += dx;
2678 thing->momy += dy;
2679 }
2680 break;
2681
2682 case sc_carry_ceiling: // to be added later
2683 break;
2684 }
2685}
2686
2687//
2688// Add_Scroller()
2689//
2690// Add a generalized scroller to the thinker list.
2691//
2692// type: the enumerated type of scrolling: floor, ceiling, floor carrier,
2693// wall, floor carrier & scroller
2694//
2695// (dx,dy): the direction and speed of the scrolling or its acceleration
2696//
2697// control: the sector whose heights control this scroller's effect
2698// remotely, or -1 if no control sector
2699//
2700// affectee: the index of the affected object (sector or sidedef)
2701//
2702// accel: non-zero if this is an accelerative effect
2703//
2704
2705static void Add_Scroller(int type, fixed_t dx, fixed_t dy,
2706 int control, int affectee, int accel)
2707{
2708 scroll_t *s = Z_Malloc(sizeof *s, PU_LEVSPEC, 0);
2709 s->thinker.function = T_Scroll;
2710 s->type = type;
2711 s->dx = dx;
2712 s->dy = dy;
2713 s->accel = accel;
2714 s->vdx = s->vdy = 0;
2715 if ((s->control = control) != -1)
2716 s->last_height =
2717 sectors[control].floorheight + sectors[control].ceilingheight;
2718 s->affectee = affectee;
2719 P_AddThinker(&s->thinker);
2720}
2721
2722// Adds wall scroller. Scroll amount is rotated with respect to wall's
2723// linedef first, so that scrolling towards the wall in a perpendicular
2724// direction is translated into vertical motion, while scrolling along
2725// the wall in a parallel direction is translated into horizontal motion.
2726//
2727// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff
2728//
2729// killough 10/98:
2730// fix scrolling aliasing problems, caused by long linedefs causing overflowing
2731
2732static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l,
2733 int control, int accel)
2734{
2735 fixed_t x = D_abs(l->dx), y = D_abs(l->dy), d;
2736 if (y > x)
2737 d = x, x = y, y = d;
2738 d = FixedDiv(x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90)
2739 >> ANGLETOFINESHIFT]);
2740
2741 // CPhipps - Import scroller calc overflow fix, compatibility optioned
2742 if (compatibility_level >= lxdoom_1_compatibility) {
2743 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:
2744 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
2745 } else {
2746 x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d);
2747 y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d);
2748 }
2749 Add_Scroller(sc_side, x, y, control, *l->sidenum, accel);
2750}
2751
2752// Amount (dx,dy) vector linedef is shifted right to get scroll amount
2753#define SCROLL_SHIFT 5
2754
2755// Factor to scale scrolling effect into mobj-carrying properties = 3/32.
2756// (This is so scrolling floors and objects on them can move at same speed.)
2757#define CARRYFACTOR ((fixed_t)(FRACUNIT*.09375))
2758
2759// Initialize the scrollers
2760static void P_SpawnScrollers(void)
2761{
2762 int i;
2763 line_t *l = lines;
2764
2765 for (i=0;i<numlines;i++,l++)
2766 {
2767 fixed_t dx = l->dx >> SCROLL_SHIFT; // direction and speed of scrolling
2768 fixed_t dy = l->dy >> SCROLL_SHIFT;
2769 int control = -1, accel = 0; // no control sector or acceleration
2770 int special = l->special;
2771
2772 // killough 3/7/98: Types 245-249 are same as 250-254 except that the
2773 // first side's sector's heights cause scrolling when they change, and
2774 // this linedef controls the direction and speed of the scrolling. The
2775 // most complicated linedef since donuts, but powerful :)
2776 //
2777 // killough 3/15/98: Add acceleration. Types 214-218 are the same but
2778 // are accelerative.
2779
2780 if (special >= 245 && special <= 249) // displacement scrollers
2781 {
2782 special += 250-245;
2783 control = sides[*l->sidenum].sector - sectors;
2784 }
2785 else
2786 if (special >= 214 && special <= 218) // accelerative scrollers
2787 {
2788 accel = 1;
2789 special += 250-214;
2790 control = sides[*l->sidenum].sector - sectors;
2791 }
2792
2793 switch (special)
2794 {
2795 register int s;
2796
2797 case 250: // scroll effect ceiling
2798 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2799 Add_Scroller(sc_ceiling, -dx, dy, control, s, accel);
2800 break;
2801
2802 case 251: // scroll effect floor
2803 case 253: // scroll and carry objects on floor
2804 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2805 Add_Scroller(sc_floor, -dx, dy, control, s, accel);
2806 if (special != 253)
2807 break;
2808
2809 case 252: // carry objects on floor
2810 dx = FixedMul(dx,CARRYFACTOR);
2811 dy = FixedMul(dy,CARRYFACTOR);
2812 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2813 Add_Scroller(sc_carry, dx, dy, control, s, accel);
2814 break;
2815
2816 // killough 3/1/98: scroll wall according to linedef
2817 // (same direction and speed as scrolling floors)
2818 case 254:
2819 for (s=-1; (s = P_FindLineFromLineTag(l,s)) >= 0;)
2820 if (s != i)
2821 Add_WallScroller(dx, dy, lines+s, control, accel);
2822 break;
2823
2824 case 255: // killough 3/2/98: scroll according to sidedef offsets
2825 s = lines[i].sidenum[0];
2826 Add_Scroller(sc_side, -sides[s].textureoffset,
2827 sides[s].rowoffset, -1, s, accel);
2828 break;
2829
2830 case 48: // scroll first side
2831 Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel);
2832 break;
2833
2834 case 85: // jff 1/30/98 2-way scroll
2835 Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel);
2836 break;
2837 }
2838 }
2839}
2840
2841// e6y
2842// restored boom's friction code
2843
2844/////////////////////////////
2845//
2846// Add a friction thinker to the thinker list
2847//
2848// Add_Friction adds a new friction thinker to the list of active thinkers.
2849//
2850
2851static void Add_Friction(int friction, int movefactor, int affectee)
2852 {
2853 friction_t *f = Z_Malloc(sizeof *f, PU_LEVSPEC, 0);
2854
2855 f->thinker.function/*.acp1*/ = /*(actionf_p1) */T_Friction;
2856 f->friction = friction;
2857 f->movefactor = movefactor;
2858 f->affectee = affectee;
2859 P_AddThinker(&f->thinker);
2860 }
2861
2862/////////////////////////////
2863//
2864// This is where abnormal friction is applied to objects in the sectors.
2865// A friction thinker has been spawned for each sector where less or
2866// more friction should be applied. The amount applied is proportional to
2867// the length of the controlling linedef.
2868
2869void T_Friction(friction_t *f)
2870 {
2871 sector_t *sec;
2872 mobj_t *thing;
2873 msecnode_t* node;
2874
2875 if (compatibility || !variable_friction)
2876 return;
2877
2878 sec = sectors + f->affectee;
2879
2880 // Be sure the special sector type is still turned on. If so, proceed.
2881 // Else, bail out; the sector type has been changed on us.
2882
2883 if (!(sec->special & FRICTION_MASK))
2884 return;
2885
2886 // Assign the friction value to players on the floor, non-floating,
2887 // and clipped. Normally the object's friction value is kept at
2888 // ORIG_FRICTION and this thinker changes it for icy or muddy floors.
2889
2890 // In Phase II, you can apply friction to Things other than players.
2891
2892 // When the object is straddling sectors with the same
2893 // floorheight that have different frictions, use the lowest
2894 // friction value (muddy has precedence over icy).
2895
2896 node = sec->touching_thinglist; // things touching this sector
2897 while (node)
2898 {
2899 thing = node->m_thing;
2900 if (thing->player &&
2901 !(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) &&
2902 thing->z <= sec->floorheight)
2903 {
2904 if ((thing->friction == ORIG_FRICTION) || // normal friction?
2905 (f->friction < thing->friction))
2906 {
2907 thing->friction = f->friction;
2908 thing->movefactor = f->movefactor;
2909 }
2910 }
2911 node = node->m_snext;
2912 }
2913 }
2914
2915
2916// killough 3/7/98 -- end generalized scroll effects
2917
2918////////////////////////////////////////////////////////////////////////////
2919//
2920// FRICTION EFFECTS
2921//
2922// phares 3/12/98: Start of friction effects
2923//
2924// As the player moves, friction is applied by decreasing the x and y
2925// momentum values on each tic. By varying the percentage of decrease,
2926// we can simulate muddy or icy conditions. In mud, the player slows
2927// down faster. In ice, the player slows down more slowly.
2928//
2929// The amount of friction change is controlled by the length of a linedef
2930// with type 223. A length < 100 gives you mud. A length > 100 gives you ice.
2931//
2932// Also, each sector where these effects are to take place is given a
2933// new special type _______. Changing the type value at runtime allows
2934// these effects to be turned on or off.
2935//
2936// Sector boundaries present problems. The player should experience these
2937// friction changes only when his feet are touching the sector floor. At
2938// sector boundaries where floor height changes, the player can find
2939// himself still 'in' one sector, but with his feet at the floor level
2940// of the next sector (steps up or down). To handle this, Thinkers are used
2941// in icy/muddy sectors. These thinkers examine each object that is touching
2942// their sectors, looking for players whose feet are at the same level as
2943// their floors. Players satisfying this condition are given new friction
2944// values that are applied by the player movement code later.
2945//
2946// killough 8/28/98:
2947//
2948// Completely redid code, which did not need thinkers, and which put a heavy
2949// drag on CPU. Friction is now a property of sectors, NOT objects inside
2950// them. All objects, not just players, are affected by it, if they touch
2951// the sector's floor. Code simpler and faster, only calling on friction
2952// calculations when an object needs friction considered, instead of doing
2953// friction calculations on every sector during every tic.
2954//
2955// Although this -might- ruin Boom demo sync involving friction, it's the only
2956// way, short of code explosion, to fix the original design bug. Fixing the
2957// design bug in Boom's original friction code, while maintaining demo sync
2958// under every conceivable circumstance, would double or triple code size, and
2959// would require maintenance of buggy legacy code which is only useful for old
2960// demos. Doom demos, which are more important IMO, are not affected by this
2961// change.
2962//
2963/////////////////////////////
2964//
2965// Initialize the sectors where friction is increased or decreased
2966
2967static void P_SpawnFriction(void)
2968{
2969 int i;
2970 line_t *l = lines;
2971
2972 // killough 8/28/98: initialize all sectors to normal friction first
2973 for (i = 0; i < numsectors; i++)
2974 {
2975 sectors[i].friction = ORIG_FRICTION;
2976 sectors[i].movefactor = ORIG_FRICTION_FACTOR;
2977 }
2978
2979 for (i = 0 ; i < numlines ; i++,l++)
2980 if (l->special == 223)
2981 {
2982 int length = P_AproxDistance(l->dx,l->dy)>>FRACBITS;
2983 int friction = (0x1EB8*length)/0x80 + 0xD000;
2984 int movefactor, s;
2985
2986 // The following check might seem odd. At the time of movement,
2987 // the move distance is multiplied by 'friction/0x10000', so a
2988 // higher friction value actually means 'less friction'.
2989
2990 if (friction > ORIG_FRICTION) // ice
2991 movefactor = ((0x10092 - friction)*(0x70))/0x158;
2992 else
2993 movefactor = ((friction - 0xDB34)*(0xA))/0x80;
2994
2995 if (mbf_features)
2996 { // killough 8/28/98: prevent odd situations
2997 if (friction > FRACUNIT)
2998 friction = FRACUNIT;
2999 if (friction < 0)
3000 friction = 0;
3001 if (movefactor < 32)
3002 movefactor = 32;
3003 }
3004
3005 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3006 {
3007 // killough 8/28/98:
3008 //
3009 // Instead of spawning thinkers, which are slow and expensive,
3010 // modify the sector's own friction values. Friction should be
3011 // a property of sectors, not objects which reside inside them.
3012 // Original code scanned every object in every friction sector
3013 // on every tic, adjusting its friction, putting unnecessary
3014 // drag on CPU. New code adjusts friction of sector only once
3015 // at level startup, and then uses this friction value.
3016
3017 //e6y: boom's friction code for boom compatibility
3018 if (!demo_compatibility && !mbf_features)
3019 Add_Friction(friction,movefactor,s);
3020
3021 sectors[s].friction = friction;
3022 sectors[s].movefactor = movefactor;
3023 }
3024 }
3025}
3026
3027//
3028// phares 3/12/98: End of friction effects
3029//
3030////////////////////////////////////////////////////////////////////////////
3031
3032////////////////////////////////////////////////////////////////////////////
3033//
3034// PUSH/PULL EFFECT
3035//
3036// phares 3/20/98: Start of push/pull effects
3037//
3038// This is where push/pull effects are applied to objects in the sectors.
3039//
3040// There are four kinds of push effects
3041//
3042// 1) Pushing Away
3043//
3044// Pushes you away from a point source defined by the location of an
3045// MT_PUSH Thing. The force decreases linearly with distance from the
3046// source. This force crosses sector boundaries and is felt w/in a circle
3047// whose center is at the MT_PUSH. The force is felt only if the point
3048// MT_PUSH can see the target object.
3049//
3050// 2) Pulling toward
3051//
3052// Same as Pushing Away except you're pulled toward an MT_PULL point
3053// source. This force crosses sector boundaries and is felt w/in a circle
3054// whose center is at the MT_PULL. The force is felt only if the point
3055// MT_PULL can see the target object.
3056//
3057// 3) Wind
3058//
3059// Pushes you in a constant direction. Full force above ground, half
3060// force on the ground, nothing if you're below it (water).
3061//
3062// 4) Current
3063//
3064// Pushes you in a constant direction. No force above ground, full
3065// force if on the ground or below it (water).
3066//
3067// The magnitude of the force is controlled by the length of a controlling
3068// linedef. The force vector for types 3 & 4 is determined by the angle
3069// of the linedef, and is constant.
3070//
3071// For each sector where these effects occur, the sector special type has
3072// to have the PUSH_MASK bit set. If this bit is turned off by a switch
3073// at run-time, the effect will not occur. The controlling sector for
3074// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing.
3075
3076
3077#define PUSH_FACTOR 7
3078
3079/////////////////////////////
3080//
3081// Add a push thinker to the thinker list
3082
3083static void Add_Pusher(int type, int x_mag, int y_mag, mobj_t* source, int affectee)
3084 {
3085 pusher_t *p = Z_Malloc(sizeof *p, PU_LEVSPEC, 0);
3086
3087 p->thinker.function = T_Pusher;
3088 p->source = source;
3089 p->type = type;
3090 p->x_mag = x_mag>>FRACBITS;
3091 p->y_mag = y_mag>>FRACBITS;
3092 p->magnitude = P_AproxDistance(p->x_mag,p->y_mag);
3093 if (source) // point source exist?
3094 {
3095 p->radius = (p->magnitude)<<(FRACBITS+1); // where force goes to zero
3096 p->x = p->source->x;
3097 p->y = p->source->y;
3098 }
3099 p->affectee = affectee;
3100 P_AddThinker(&p->thinker);
3101 }
3102
3103/////////////////////////////
3104//
3105// PIT_PushThing determines the angle and magnitude of the effect.
3106// The object's x and y momentum values are changed.
3107//
3108// tmpusher belongs to the point source (MT_PUSH/MT_PULL).
3109//
3110// killough 10/98: allow to affect things besides players
3111
3112pusher_t* tmpusher; // pusher structure for blockmap searches
3113
3114static boolean PIT_PushThing(mobj_t* thing)
3115{
3116 /* killough 10/98: made more general */
3117 if (!mbf_features ?
3118 thing->player && !(thing->flags & (MF_NOCLIP | MF_NOGRAVITY)) :
3119 (sentient(thing) || thing->flags & MF_SHOOTABLE) &&
3120 !(thing->flags & MF_NOCLIP))
3121 {
3122 angle_t pushangle;
3123 fixed_t speed;
3124 fixed_t sx = tmpusher->x;
3125 fixed_t sy = tmpusher->y;
3126
3127 speed = (tmpusher->magnitude -
3128 ((P_AproxDistance(thing->x - sx,thing->y - sy)
3129 >>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1);
3130
3131 // killough 10/98: make magnitude decrease with square
3132 // of distance, making it more in line with real nature,
3133 // so long as it's still in range with original formula.
3134 //
3135 // Removes angular distortion, and makes effort required
3136 // to stay close to source, grow increasingly hard as you
3137 // get closer, as expected. Still, it doesn't consider z :(
3138
3139 if (speed > 0 && mbf_features)
3140 {
3141 int x = (thing->x-sx) >> FRACBITS;
3142 int y = (thing->y-sy) >> FRACBITS;
3143 speed = (int)(((uint_64_t) tmpusher->magnitude << 23) / (x*x+y*y+1));
3144 }
3145
3146 // If speed <= 0, you're outside the effective radius. You also have
3147 // to be able to see the push/pull source point.
3148
3149 if (speed > 0 && P_CheckSight(thing,tmpusher->source))
3150 {
3151 pushangle = R_PointToAngle2(thing->x,thing->y,sx,sy);
3152 if (tmpusher->source->type == MT_PUSH)
3153 pushangle += ANG180; // away
3154 pushangle >>= ANGLETOFINESHIFT;
3155 thing->momx += FixedMul(speed,finecosine[pushangle]);
3156 thing->momy += FixedMul(speed,finesine[pushangle]);
3157 }
3158 }
3159 return true;
3160}
3161
3162/////////////////////////////
3163//
3164// T_Pusher looks for all objects that are inside the radius of
3165// the effect.
3166//
3167
3168void T_Pusher(pusher_t *p)
3169 {
3170 sector_t *sec;
3171 mobj_t *thing;
3172 msecnode_t* node;
3173 int xspeed,yspeed;
3174 int xl,xh,yl,yh,bx,by;
3175 int radius;
3176 int ht = 0;
3177
3178 if (!allow_pushers)
3179 return;
3180
3181 sec = sectors + p->affectee;
3182
3183 // Be sure the special sector type is still turned on. If so, proceed.
3184 // Else, bail out; the sector type has been changed on us.
3185
3186 if (!(sec->special & PUSH_MASK))
3187 return;
3188
3189 // For constant pushers (wind/current) there are 3 situations:
3190 //
3191 // 1) Affected Thing is above the floor.
3192 //
3193 // Apply the full force if wind, no force if current.
3194 //
3195 // 2) Affected Thing is on the ground.
3196 //
3197 // Apply half force if wind, full force if current.
3198 //
3199 // 3) Affected Thing is below the ground (underwater effect).
3200 //
3201 // Apply no force if wind, full force if current.
3202
3203 if (p->type == p_push)
3204 {
3205
3206 // Seek out all pushable things within the force radius of this
3207 // point pusher. Crosses sectors, so use blockmap.
3208
3209 tmpusher = p; // MT_PUSH/MT_PULL point source
3210 radius = p->radius; // where force goes to zero
3211 tmbbox[BOXTOP] = p->y + radius;
3212 tmbbox[BOXBOTTOM] = p->y - radius;
3213 tmbbox[BOXRIGHT] = p->x + radius;
3214 tmbbox[BOXLEFT] = p->x - radius;
3215
3216 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
3217 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
3218 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
3219 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
3220 for (bx=xl ; bx<=xh ; bx++)
3221 for (by=yl ; by<=yh ; by++)
3222 P_BlockThingsIterator(bx,by,PIT_PushThing);
3223 return;
3224 }
3225
3226 // constant pushers p_wind and p_current
3227
3228 if (sec->heightsec != -1) // special water sector?
3229 ht = sectors[sec->heightsec].floorheight;
3230 node = sec->touching_thinglist; // things touching this sector
3231 for ( ; node ; node = node->m_snext)
3232 {
3233 thing = node->m_thing;
3234 if (!thing->player || (thing->flags & (MF_NOGRAVITY | MF_NOCLIP)))
3235 continue;
3236 if (p->type == p_wind)
3237 {
3238 if (sec->heightsec == -1) // NOT special water sector
3239 if (thing->z > thing->floorz) // above ground
3240 {
3241 xspeed = p->x_mag; // full force
3242 yspeed = p->y_mag;
3243 }
3244 else // on ground
3245 {
3246 xspeed = (p->x_mag)>>1; // half force
3247 yspeed = (p->y_mag)>>1;
3248 }
3249 else // special water sector
3250 {
3251 if (thing->z > ht) // above ground
3252 {
3253 xspeed = p->x_mag; // full force
3254 yspeed = p->y_mag;
3255 }
3256 else if (thing->player->viewz < ht) // underwater
3257 xspeed = yspeed = 0; // no force
3258 else // wading in water
3259 {
3260 xspeed = (p->x_mag)>>1; // half force
3261 yspeed = (p->y_mag)>>1;
3262 }
3263 }
3264 }
3265 else // p_current
3266 {
3267 if (sec->heightsec == -1) // NOT special water sector
3268 if (thing->z > sec->floorheight) // above ground
3269 xspeed = yspeed = 0; // no force
3270 else // on ground
3271 {
3272 xspeed = p->x_mag; // full force
3273 yspeed = p->y_mag;
3274 }
3275 else // special water sector
3276 if (thing->z > ht) // above ground
3277 xspeed = yspeed = 0; // no force
3278 else // underwater
3279 {
3280 xspeed = p->x_mag; // full force
3281 yspeed = p->y_mag;
3282 }
3283 }
3284 thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR);
3285 thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR);
3286 }
3287 }
3288
3289/////////////////////////////
3290//
3291// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing,
3292// NULL otherwise.
3293
3294mobj_t* P_GetPushThing(int s)
3295 {
3296 mobj_t* thing;
3297 sector_t* sec;
3298
3299 sec = sectors + s;
3300 thing = sec->thinglist;
3301 while (thing)
3302 {
3303 switch(thing->type)
3304 {
3305 case MT_PUSH:
3306 case MT_PULL:
3307 return thing;
3308 default:
3309 break;
3310 }
3311 thing = thing->snext;
3312 }
3313 return NULL;
3314 }
3315
3316/////////////////////////////
3317//
3318// Initialize the sectors where pushers are present
3319//
3320
3321static void P_SpawnPushers(void)
3322 {
3323 int i;
3324 line_t *l = lines;
3325 register int s;
3326 mobj_t* thing;
3327
3328 for (i = 0 ; i < numlines ; i++,l++)
3329 switch(l->special)
3330 {
3331 case 224: // wind
3332 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3333 Add_Pusher(p_wind,l->dx,l->dy,NULL,s);
3334 break;
3335 case 225: // current
3336 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3337 Add_Pusher(p_current,l->dx,l->dy,NULL,s);
3338 break;
3339 case 226: // push/pull
3340 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3341 {
3342 thing = P_GetPushThing(s);
3343 if (thing) // No MT_P* means no effect
3344 Add_Pusher(p_push,l->dx,l->dy,thing,s);
3345 }
3346 break;
3347 }
3348 }
3349
3350//
3351// phares 3/20/98: End of Pusher effects
3352//
3353////////////////////////////////////////////////////////////////////////////
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: definitions, declarations and prototypes for specials
30 *
31 *-----------------------------------------------------------------------------*/
32
33#ifndef __P_SPEC__
34#define __P_SPEC__
35
36#include "r_defs.h"
37#include "d_player.h"
38
39// Define values for map objects
40#define MO_TELEPORTMAN 14
41
42// p_floor
43
44#define ELEVATORSPEED (FRACUNIT*4)
45#define FLOORSPEED FRACUNIT
46
47// p_ceilng
48
49#define CEILSPEED FRACUNIT
50#define CEILWAIT 150
51
52// p_doors
53
54#define VDOORSPEED (FRACUNIT*2)
55#define VDOORWAIT 150
56
57// p_plats
58
59#define PLATWAIT 3
60#define PLATSPEED FRACUNIT
61
62// p_switch
63
64// 4 players, 4 buttons each at once, max.
65// killough 2/14/98: redefine in terms of MAXPLAYERS
66#define MAXBUTTONS (MAXPLAYERS*4)
67
68// 1 second, in ticks.
69#define BUTTONTIME TICRATE
70
71// p_lights
72
73#define GLOWSPEED 8
74#define STROBEBRIGHT 5
75#define FASTDARK 15
76#define SLOWDARK 35
77
78//jff 3/14/98 add bits and shifts for generalized sector types
79
80#define DAMAGE_MASK 0x60
81#define DAMAGE_SHIFT 5
82#define SECRET_MASK 0x80
83#define SECRET_SHIFT 7
84#define FRICTION_MASK 0x100
85#define FRICTION_SHIFT 8
86#define PUSH_MASK 0x200
87#define PUSH_SHIFT 9
88
89//jff 02/04/98 Define masks, shifts, for fields in
90// generalized linedef types
91
92#define GenEnd 0x8000
93#define GenFloorBase 0x6000
94#define GenCeilingBase 0x4000
95#define GenDoorBase 0x3c00
96#define GenLockedBase 0x3800
97#define GenLiftBase 0x3400
98#define GenStairsBase 0x3000
99#define GenCrusherBase 0x2F80
100
101#define TriggerType 0x0007
102#define TriggerTypeShift 0
103
104// define masks and shifts for the floor type fields
105
106#define FloorCrush 0x1000
107#define FloorChange 0x0c00
108#define FloorTarget 0x0380
109#define FloorDirection 0x0040
110#define FloorModel 0x0020
111#define FloorSpeed 0x0018
112
113#define FloorCrushShift 12
114#define FloorChangeShift 10
115#define FloorTargetShift 7
116#define FloorDirectionShift 6
117#define FloorModelShift 5
118#define FloorSpeedShift 3
119
120// define masks and shifts for the ceiling type fields
121
122#define CeilingCrush 0x1000
123#define CeilingChange 0x0c00
124#define CeilingTarget 0x0380
125#define CeilingDirection 0x0040
126#define CeilingModel 0x0020
127#define CeilingSpeed 0x0018
128
129#define CeilingCrushShift 12
130#define CeilingChangeShift 10
131#define CeilingTargetShift 7
132#define CeilingDirectionShift 6
133#define CeilingModelShift 5
134#define CeilingSpeedShift 3
135
136// define masks and shifts for the lift type fields
137
138#define LiftTarget 0x0300
139#define LiftDelay 0x00c0
140#define LiftMonster 0x0020
141#define LiftSpeed 0x0018
142
143#define LiftTargetShift 8
144#define LiftDelayShift 6
145#define LiftMonsterShift 5
146#define LiftSpeedShift 3
147
148// define masks and shifts for the stairs type fields
149
150#define StairIgnore 0x0200
151#define StairDirection 0x0100
152#define StairStep 0x00c0
153#define StairMonster 0x0020
154#define StairSpeed 0x0018
155
156#define StairIgnoreShift 9
157#define StairDirectionShift 8
158#define StairStepShift 6
159#define StairMonsterShift 5
160#define StairSpeedShift 3
161
162// define masks and shifts for the crusher type fields
163
164#define CrusherSilent 0x0040
165#define CrusherMonster 0x0020
166#define CrusherSpeed 0x0018
167
168#define CrusherSilentShift 6
169#define CrusherMonsterShift 5
170#define CrusherSpeedShift 3
171
172// define masks and shifts for the door type fields
173
174#define DoorDelay 0x0300
175#define DoorMonster 0x0080
176#define DoorKind 0x0060
177#define DoorSpeed 0x0018
178
179#define DoorDelayShift 8
180#define DoorMonsterShift 7
181#define DoorKindShift 5
182#define DoorSpeedShift 3
183
184// define masks and shifts for the locked door type fields
185
186#define LockedNKeys 0x0200
187#define LockedKey 0x01c0
188#define LockedKind 0x0020
189#define LockedSpeed 0x0018
190
191#define LockedNKeysShift 9
192#define LockedKeyShift 6
193#define LockedKindShift 5
194#define LockedSpeedShift 3
195
196// define names for the TriggerType field of the general linedefs
197
198typedef enum
199{
200 WalkOnce,
201 WalkMany,
202 SwitchOnce,
203 SwitchMany,
204 GunOnce,
205 GunMany,
206 PushOnce,
207 PushMany,
208} triggertype_e;
209
210// define names for the Speed field of the general linedefs
211
212typedef enum
213{
214 SpeedSlow,
215 SpeedNormal,
216 SpeedFast,
217 SpeedTurbo,
218} motionspeed_e;
219
220// define names for the Target field of the general floor
221
222typedef enum
223{
224 FtoHnF,
225 FtoLnF,
226 FtoNnF,
227 FtoLnC,
228 FtoC,
229 FbyST,
230 Fby24,
231 Fby32,
232} floortarget_e;
233
234// define names for the Changer Type field of the general floor
235
236typedef enum
237{
238 FNoChg,
239 FChgZero,
240 FChgTxt,
241 FChgTyp,
242} floorchange_e;
243
244// define names for the Change Model field of the general floor
245
246typedef enum
247{
248 FTriggerModel,
249 FNumericModel,
250} floormodel_t;
251
252// define names for the Target field of the general ceiling
253
254typedef enum
255{
256 CtoHnC,
257 CtoLnC,
258 CtoNnC,
259 CtoHnF,
260 CtoF,
261 CbyST,
262 Cby24,
263 Cby32,
264} ceilingtarget_e;
265
266// define names for the Changer Type field of the general ceiling
267
268typedef enum
269{
270 CNoChg,
271 CChgZero,
272 CChgTxt,
273 CChgTyp,
274} ceilingchange_e;
275
276// define names for the Change Model field of the general ceiling
277
278typedef enum
279{
280 CTriggerModel,
281 CNumericModel,
282} ceilingmodel_t;
283
284// define names for the Target field of the general lift
285
286typedef enum
287{
288 F2LnF,
289 F2NnF,
290 F2LnC,
291 LnF2HnF,
292} lifttarget_e;
293
294// define names for the door Kind field of the general ceiling
295
296typedef enum
297{
298 OdCDoor,
299 ODoor,
300 CdODoor,
301 CDoor,
302} doorkind_e;
303
304// define names for the locked door Kind field of the general ceiling
305
306typedef enum
307{
308 AnyKey,
309 RCard,
310 BCard,
311 YCard,
312 RSkull,
313 BSkull,
314 YSkull,
315 AllKeys,
316} keykind_e;
317
318//////////////////////////////////////////////////////////////////
319//
320// enums for classes of linedef triggers
321//
322//////////////////////////////////////////////////////////////////
323
324//jff 2/23/98 identify the special classes that can share sectors
325
326typedef enum
327{
328 floor_special,
329 ceiling_special,
330 lighting_special,
331} special_e;
332
333//jff 3/15/98 pure texture/type change for better generalized support
334typedef enum
335{
336 trigChangeOnly,
337 numChangeOnly,
338} change_e;
339
340// p_plats
341
342typedef enum
343{
344 up,
345 down,
346 waiting,
347 in_stasis
348} plat_e;
349
350typedef enum
351{
352 perpetualRaise,
353 downWaitUpStay,
354 raiseAndChange,
355 raiseToNearestAndChange,
356 blazeDWUS,
357 genLift, //jff added to support generalized Plat types
358 genPerpetual,
359 toggleUpDn, //jff 3/14/98 added to support instant toggle type
360
361} plattype_e;
362
363// p_doors
364
365typedef enum
366{
367 normal,
368 close30ThenOpen,
369 close,
370 open,
371 raiseIn5Mins,
372 blazeRaise,
373 blazeOpen,
374 blazeClose,
375
376 //jff 02/05/98 add generalize door types
377 genRaise,
378 genBlazeRaise,
379 genOpen,
380 genBlazeOpen,
381 genClose,
382 genBlazeClose,
383 genCdO,
384 genBlazeCdO,
385} vldoor_e;
386
387// p_ceilng
388
389typedef enum
390{
391 lowerToFloor,
392 raiseToHighest,
393 lowerToLowest,
394 lowerToMaxFloor,
395 lowerAndCrush,
396 crushAndRaise,
397 fastCrushAndRaise,
398 silentCrushAndRaise,
399
400 //jff 02/04/98 add types for generalized ceiling mover
401 genCeiling,
402 genCeilingChg,
403 genCeilingChg0,
404 genCeilingChgT,
405
406 //jff 02/05/98 add types for generalized ceiling mover
407 genCrusher,
408 genSilentCrusher,
409
410} ceiling_e;
411
412// p_floor
413
414typedef enum
415{
416 // lower floor to highest surrounding floor
417 lowerFloor,
418
419 // lower floor to lowest surrounding floor
420 lowerFloorToLowest,
421
422 // lower floor to highest surrounding floor VERY FAST
423 turboLower,
424
425 // raise floor to lowest surrounding CEILING
426 raiseFloor,
427
428 // raise floor to next highest surrounding floor
429 raiseFloorToNearest,
430
431 //jff 02/03/98 lower floor to next lowest neighbor
432 lowerFloorToNearest,
433
434 //jff 02/03/98 lower floor 24 absolute
435 lowerFloor24,
436
437 //jff 02/03/98 lower floor 32 absolute
438 lowerFloor32Turbo,
439
440 // raise floor to shortest height texture around it
441 raiseToTexture,
442
443 // lower floor to lowest surrounding floor
444 // and change floorpic
445 lowerAndChange,
446
447 raiseFloor24,
448
449 //jff 02/03/98 raise floor 32 absolute
450 raiseFloor32Turbo,
451
452 raiseFloor24AndChange,
453 raiseFloorCrush,
454
455 // raise to next highest floor, turbo-speed
456 raiseFloorTurbo,
457 donutRaise,
458 raiseFloor512,
459
460 //jff 02/04/98 add types for generalized floor mover
461 genFloor,
462 genFloorChg,
463 genFloorChg0,
464 genFloorChgT,
465
466 //new types for stair builders
467 buildStair,
468 genBuildStair,
469} floor_e;
470
471typedef enum
472{
473 build8, // slowly build by 8
474 turbo16 // quickly build by 16
475
476} stair_e;
477
478typedef enum
479{
480 elevateUp,
481 elevateDown,
482 elevateCurrent,
483} elevator_e;
484
485//////////////////////////////////////////////////////////////////
486//
487// general enums
488//
489//////////////////////////////////////////////////////////////////
490
491// texture type enum
492typedef enum
493{
494 top,
495 middle,
496 bottom
497
498} bwhere_e;
499
500// crush check returns
501typedef enum
502{
503 ok,
504 crushed,
505 pastdest
506} result_e;
507
508//////////////////////////////////////////////////////////////////
509//
510// linedef and sector special data types
511//
512//////////////////////////////////////////////////////////////////
513
514// p_switch
515
516// switch animation structure type
517
518#if defined(__MWERKS__)
519#pragma options align=packed
520#endif
521
522typedef struct
523{
524 char name1[9];
525 char name2[9];
526 short episode;
527} PACKEDATTR switchlist_t; //jff 3/23/98 pack to read from memory
528
529#if defined(__MWERKS__)
530#pragma options align=reset
531#endif
532
533typedef struct
534{
535 line_t* line;
536 bwhere_e where;
537 int btexture;
538 int btimer;
539 mobj_t* soundorg;
540
541} button_t;
542
543// p_lights
544
545typedef struct
546{
547 thinker_t thinker;
548 sector_t* sector;
549 int count;
550 int maxlight;
551 int minlight;
552
553} fireflicker_t;
554
555typedef struct
556{
557 thinker_t thinker;
558 sector_t* sector;
559 int count;
560 int maxlight;
561 int minlight;
562 int maxtime;
563 int mintime;
564
565} lightflash_t;
566
567typedef struct
568{
569 thinker_t thinker;
570 sector_t* sector;
571 int count;
572 int minlight;
573 int maxlight;
574 int darktime;
575 int brighttime;
576
577} strobe_t;
578
579typedef struct
580{
581 thinker_t thinker;
582 sector_t* sector;
583 int minlight;
584 int maxlight;
585 int direction;
586
587} glow_t;
588
589// p_plats
590
591typedef struct
592{
593 thinker_t thinker;
594 sector_t* sector;
595 fixed_t speed;
596 fixed_t low;
597 fixed_t high;
598 int wait;
599 int count;
600 plat_e status;
601 plat_e oldstatus;
602 boolean crush;
603 int tag;
604 plattype_e type;
605
606 struct platlist *list; // killough
607} plat_t;
608
609// New limit-free plat structure -- killough
610
611typedef struct platlist {
612 plat_t *plat;
613 struct platlist *next,**prev;
614} platlist_t;
615
616// p_ceilng
617
618typedef struct
619{
620 thinker_t thinker;
621 vldoor_e type;
622 sector_t* sector;
623 fixed_t topheight;
624 fixed_t speed;
625
626 // 1 = up, 0 = waiting at top, -1 = down
627 int direction;
628
629 // tics to wait at the top
630 int topwait;
631 // (keep in case a door going down is reset)
632 // when it reaches 0, start going down
633 int topcountdown;
634
635 //jff 1/31/98 keep track of line door is triggered by
636 line_t *line;
637
638 /* killough 10/98: sector tag for gradual lighting effects */
639 int lighttag;
640} vldoor_t;
641
642// p_doors
643
644typedef struct
645{
646 thinker_t thinker;
647 ceiling_e type;
648 sector_t* sector;
649 fixed_t bottomheight;
650 fixed_t topheight;
651 fixed_t speed;
652 fixed_t oldspeed;
653 boolean crush;
654
655 //jff 02/04/98 add these to support ceiling changers
656 int newspecial;
657 int oldspecial; //jff 3/14/98 add to fix bug in change transfers
658 short texture;
659
660 // 1 = up, 0 = waiting, -1 = down
661 int direction;
662
663 // ID
664 int tag;
665 int olddirection;
666 struct ceilinglist *list; // jff 2/22/98 copied from killough's plats
667} ceiling_t;
668
669typedef struct ceilinglist {
670 ceiling_t *ceiling;
671 struct ceilinglist *next,**prev;
672} ceilinglist_t;
673
674// p_floor
675
676typedef struct
677{
678 thinker_t thinker;
679 floor_e type;
680 boolean crush;
681 sector_t* sector;
682 int direction;
683 int newspecial;
684 int oldspecial; //jff 3/14/98 add to fix bug in change transfers
685 short texture;
686 fixed_t floordestheight;
687 fixed_t speed;
688
689} floormove_t;
690
691typedef struct
692{
693 thinker_t thinker;
694 elevator_e type;
695 sector_t* sector;
696 int direction;
697 fixed_t floordestheight;
698 fixed_t ceilingdestheight;
699 fixed_t speed;
700} elevator_t;
701
702// p_spec
703
704// killough 3/7/98: Add generalized scroll effects
705
706typedef struct {
707 thinker_t thinker; // Thinker structure for scrolling
708 fixed_t dx, dy; // (dx,dy) scroll speeds
709 int affectee; // Number of affected sidedef, sector, tag, or whatever
710 int control; // Control sector (-1 if none) used to control scrolling
711 fixed_t last_height; // Last known height of control sector
712 fixed_t vdx, vdy; // Accumulated velocity if accelerative
713 int accel; // Whether it's accelerative
714 enum
715 {
716 sc_side,
717 sc_floor,
718 sc_ceiling,
719 sc_carry,
720 sc_carry_ceiling, // killough 4/11/98: carry objects hanging on ceilings
721 } type; // Type of scroll effect
722} scroll_t;
723
724// phares 3/12/98: added new model of friction for ice/sludge effects
725
726typedef struct {
727 thinker_t thinker; // Thinker structure for friction
728 int friction; // friction value (E800 = normal)
729 int movefactor; // inertia factor when adding to momentum
730 int affectee; // Number of affected sector
731} friction_t;
732
733// phares 3/20/98: added new model of Pushers for push/pull effects
734
735typedef struct {
736 thinker_t thinker; // Thinker structure for Pusher
737 enum
738 {
739 p_push,
740 p_pull,
741 p_wind,
742 p_current,
743 } type;
744 mobj_t* source; // Point source if point pusher
745 int x_mag; // X Strength
746 int y_mag; // Y Strength
747 int magnitude; // Vector strength for point pusher
748 int radius; // Effective radius for point pusher
749 int x; // X of point source if point pusher
750 int y; // Y of point source if point pusher
751 int affectee; // Number of affected sector
752} pusher_t;
753
754//////////////////////////////////////////////////////////////////
755//
756// external data declarations
757//
758//////////////////////////////////////////////////////////////////
759
760// list of retriggerable buttons active
761extern button_t buttonlist[MAXBUTTONS];
762
763extern platlist_t *activeplats; // killough 2/14/98
764
765extern ceilinglist_t *activeceilings; // jff 2/22/98
766
767////////////////////////////////////////////////////////////////
768//
769// Linedef and sector special utility function prototypes
770//
771////////////////////////////////////////////////////////////////
772
773int twoSided
774( int sector,
775 int line );
776
777sector_t* getSector
778( int currentSector,
779 int line,
780 int side );
781
782side_t* getSide
783( int currentSector,
784 int line,
785 int side );
786
787fixed_t P_FindLowestFloorSurrounding
788( sector_t* sec );
789
790fixed_t P_FindHighestFloorSurrounding
791( sector_t* sec );
792
793fixed_t P_FindNextHighestFloor
794( sector_t* sec,
795 int currentheight );
796
797fixed_t P_FindNextLowestFloor
798( sector_t* sec,
799 int currentheight );
800
801fixed_t P_FindLowestCeilingSurrounding
802( sector_t* sec ); // jff 2/04/98
803
804fixed_t P_FindHighestCeilingSurrounding
805( sector_t* sec ); // jff 2/04/98
806
807fixed_t P_FindNextLowestCeiling
808( sector_t *sec,
809 int currentheight ); // jff 2/04/98
810
811fixed_t P_FindNextHighestCeiling
812( sector_t *sec,
813 int currentheight ); // jff 2/04/98
814
815fixed_t P_FindShortestTextureAround
816( int secnum ); // jff 2/04/98
817
818fixed_t P_FindShortestUpperAround
819( int secnum ); // jff 2/04/98
820
821sector_t* P_FindModelFloorSector
822( fixed_t floordestheight,
823 int secnum ); //jff 02/04/98
824
825sector_t* P_FindModelCeilingSector
826( fixed_t ceildestheight,
827 int secnum ); //jff 02/04/98
828
829int P_FindSectorFromLineTag
830( const line_t *line,
831 int start ); // killough 4/17/98
832
833int P_FindLineFromLineTag
834( const line_t *line,
835 int start ); // killough 4/17/98
836
837int P_FindMinSurroundingLight
838( sector_t* sector,
839 int max );
840
841sector_t* getNextSector
842( line_t* line,
843 sector_t* sec );
844
845int P_CheckTag
846(line_t *line); // jff 2/27/98
847
848boolean P_CanUnlockGenDoor
849( line_t* line,
850 player_t* player);
851
852boolean PUREFUNC P_SectorActive
853( special_e t,
854 const sector_t* s );
855
856boolean PUREFUNC P_IsSecret
857( const sector_t *sec );
858
859boolean PUREFUNC P_WasSecret
860( const sector_t *sec );
861
862void P_ChangeSwitchTexture
863( line_t* line,
864 int useAgain );
865
866////////////////////////////////////////////////////////////////
867//
868// Linedef and sector special action function prototypes
869//
870////////////////////////////////////////////////////////////////
871
872// p_lights
873
874void T_LightFlash
875( lightflash_t* flash );
876
877void T_StrobeFlash
878( strobe_t* flash );
879
880// jff 8/8/98 add missing thinker for flicker
881void T_FireFlicker
882( fireflicker_t* flick );
883
884void T_Glow
885( glow_t* g );
886
887// p_plats
888
889void T_PlatRaise
890( plat_t* plat );
891
892// p_doors
893
894void T_VerticalDoor
895( vldoor_t* door );
896
897// p_ceilng
898
899void T_MoveCeiling
900( ceiling_t* ceiling );
901
902// p_floor
903
904result_e T_MovePlane
905( sector_t* sector,
906 fixed_t speed,
907 fixed_t dest,
908 boolean crush,
909 int floorOrCeiling,
910 int direction );
911
912void T_MoveFloor
913( floormove_t* floor );
914
915void T_MoveElevator
916( elevator_t* elevator );
917
918// p_spec
919
920void T_Scroll
921( scroll_t * ); // killough 3/7/98: scroll effect thinker
922
923void T_Friction
924( friction_t * ); // phares 3/12/98: friction thinker
925
926void T_Pusher
927( pusher_t * ); // phares 3/20/98: Push thinker
928
929////////////////////////////////////////////////////////////////
930//
931// Linedef and sector special handler prototypes
932//
933////////////////////////////////////////////////////////////////
934
935// p_telept
936
937int EV_Teleport
938( line_t* line,
939 int side,
940 mobj_t* thing );
941
942// killough 2/14/98: Add silent teleporter
943int EV_SilentTeleport
944( line_t* line,
945 int side,
946 mobj_t* thing );
947
948// killough 1/31/98: Add silent line teleporter
949int EV_SilentLineTeleport
950( line_t* line,
951 int side,
952 mobj_t* thing,
953 boolean reverse);
954
955// p_floor
956
957int
958EV_DoElevator
959( line_t* line,
960 elevator_e type );
961
962int EV_BuildStairs
963( line_t* line,
964 stair_e type );
965
966int EV_DoFloor
967( line_t* line,
968 floor_e floortype );
969
970// p_ceilng
971
972int EV_DoCeiling
973( line_t* line,
974 ceiling_e type );
975
976int EV_CeilingCrushStop
977( line_t* line );
978
979// p_doors
980
981int EV_VerticalDoor
982( line_t* line,
983 mobj_t* thing );
984
985int EV_DoDoor
986( line_t* line,
987 vldoor_e type );
988
989int EV_DoLockedDoor
990( line_t* line,
991 vldoor_e type,
992 mobj_t* thing );
993
994// p_lights
995
996int EV_StartLightStrobing
997( line_t* line );
998
999int EV_TurnTagLightsOff
1000( line_t* line );
1001
1002int EV_LightTurnOn
1003( line_t* line,
1004 int bright );
1005
1006int EV_LightTurnOnPartway(line_t* line, fixed_t level); // killough 10/10/98
1007
1008// p_floor
1009
1010int EV_DoChange
1011( line_t* line,
1012 change_e changetype );
1013
1014int EV_DoDonut
1015( line_t* line );
1016
1017// p_plats
1018
1019int EV_DoPlat
1020( line_t* line,
1021 plattype_e type,
1022 int amount );
1023
1024int EV_StopPlat
1025( line_t* line );
1026
1027// p_genlin
1028
1029int EV_DoGenFloor
1030( line_t* line );
1031
1032int EV_DoGenCeiling
1033( line_t* line );
1034
1035int EV_DoGenLift
1036( line_t* line );
1037
1038int EV_DoGenStairs
1039( line_t* line );
1040
1041int EV_DoGenCrusher
1042( line_t* line );
1043
1044int EV_DoGenDoor
1045( line_t* line );
1046
1047int EV_DoGenLockedDoor
1048( line_t* line );
1049
1050////////////////////////////////////////////////////////////////
1051//
1052// Linedef and sector special thinker spawning
1053//
1054////////////////////////////////////////////////////////////////
1055
1056// at game start
1057void P_InitPicAnims
1058( void );
1059
1060void P_InitSwitchList
1061( void );
1062
1063// at map load
1064void P_SpawnSpecials
1065( void );
1066
1067// every tic
1068void P_UpdateSpecials
1069( void );
1070
1071// when needed
1072boolean P_UseSpecialLine
1073( mobj_t* thing,
1074 line_t* line,
1075 int side );
1076
1077void P_ShootSpecialLine
1078( mobj_t* thing,
1079 line_t* line );
1080
1081void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing);
1082
1083void P_PlayerInSpecialSector
1084( player_t* player );
1085
1086// p_lights
1087
1088void P_SpawnFireFlicker
1089( sector_t* sector );
1090
1091void P_SpawnLightFlash
1092( sector_t* sector );
1093
1094void P_SpawnStrobeFlash
1095( sector_t* sector,
1096 int fastOrSlow,
1097 int inSync );
1098
1099void P_SpawnGlowingLight
1100( sector_t* sector );
1101
1102// p_plats
1103
1104void P_AddActivePlat
1105( plat_t* plat );
1106
1107void P_RemoveActivePlat
1108( plat_t* plat );
1109
1110void P_RemoveAllActivePlats
1111( void ); // killough
1112
1113void P_ActivateInStasis
1114( int tag );
1115
1116// p_doors
1117
1118void P_SpawnDoorCloseIn30
1119( sector_t* sec );
1120
1121void P_SpawnDoorRaiseIn5Mins
1122( sector_t* sec,
1123 int secnum );
1124
1125// p_ceilng
1126
1127void P_RemoveActiveCeiling
1128( ceiling_t* ceiling ); //jff 2/22/98
1129
1130void P_RemoveAllActiveCeilings
1131( void ); //jff 2/22/98
1132
1133void P_AddActiveCeiling
1134( ceiling_t* c );
1135
1136int P_ActivateInStasisCeiling
1137( line_t* line );
1138
1139mobj_t* P_GetPushThing(int); // phares 3/23/98
1140
1141#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Switches, buttons. Two-state animation. Exits.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "w_wad.h"
36#include "r_main.h"
37#include "p_spec.h"
38#include "g_game.h"
39#include "s_sound.h"
40#include "sounds.h"
41#include "lprintf.h"
42
43// killough 2/8/98: Remove switch limit
44
45static int *switchlist; // killough
46static int max_numswitches; // killough
47static int numswitches; // killough
48
49button_t buttonlist[MAXBUTTONS];
50
51//
52// P_InitSwitchList()
53//
54// Only called at game initialization in order to list the set of switches
55// and buttons known to the engine. This enables their texture to change
56// when activated, and in the case of buttons, change back after a timeout.
57//
58// This routine modified to read its data from a predefined lump or
59// PWAD lump called SWITCHES rather than a static table in this module to
60// allow wad designers to insert or modify switches.
61//
62// Lump format is an array of byte packed switchlist_t structures, terminated
63// by a structure with episode == -0. The lump can be generated from a
64// text source file using SWANTBLS.EXE, distributed with the BOOM utils.
65// The standard list of switches and animations is contained in the example
66// source text file DEFSWANI.DAT also in the BOOM util distribution.
67//
68// Rewritten by Lee Killough to remove limit 2/8/98
69//
70void P_InitSwitchList(void)
71{
72 int i, index = 0;
73 int episode = (gamemode == registered || gamemode==retail) ?
74 2 : gamemode == commercial ? 3 : 1;
75 const switchlist_t *alphSwitchList; //jff 3/23/98 pointer to switch table
76 int lump = W_GetNumForName("SWITCHES"); // cph - new wad lump handling
77
78 //jff 3/23/98 read the switch table from a predefined lump
79 alphSwitchList = (const switchlist_t *)W_CacheLumpNum(lump);
80
81 for (i=0;;i++)
82 {
83 if (index+1 >= max_numswitches)
84 switchlist = realloc(switchlist, sizeof *switchlist *
85 (max_numswitches = max_numswitches ? max_numswitches*2 : 8));
86 if (SHORT(alphSwitchList[i].episode) <= episode) //jff 5/11/98 endianess
87 {
88 int texture1, texture2;
89
90 if (!SHORT(alphSwitchList[i].episode))
91 break;
92
93 // Ignore switches referencing unknown texture names, instead of exiting.
94 // Warn if either one is missing, but only add if both are valid.
95 texture1 = R_CheckTextureNumForName(alphSwitchList[i].name1);
96 if (texture1 == -1)
97 lprintf(LO_WARN, "P_InitSwitchList: unknown texture %s\n",
98 alphSwitchList[i].name1);
99 texture2 = R_CheckTextureNumForName(alphSwitchList[i].name2);
100 if (texture2 == -1)
101 lprintf(LO_WARN, "P_InitSwitchList: unknown texture %s\n",
102 alphSwitchList[i].name2);
103 if (texture1 != -1 && texture2 != -1) {
104 switchlist[index++] = texture1;
105 switchlist[index++] = texture2;
106 }
107 }
108 }
109
110 numswitches = index/2;
111 switchlist[index] = -1;
112 W_UnlockLumpNum(lump);
113}
114
115//
116// P_StartButton()
117//
118// Start a button (retriggerable switch) counting down till it turns off.
119//
120// Passed the linedef the button is on, which texture on the sidedef contains
121// the button, the texture number of the button, and the time the button is
122// to remain active in gametics.
123// No return.
124//
125static void P_StartButton
126( line_t* line,
127 bwhere_e w,
128 int texture,
129 int time )
130{
131 int i;
132
133 // See if button is already pressed
134 for (i = 0;i < MAXBUTTONS;i++)
135 if (buttonlist[i].btimer && buttonlist[i].line == line)
136 return;
137
138 for (i = 0;i < MAXBUTTONS;i++)
139 if (!buttonlist[i].btimer) // use first unused element of list
140 {
141 buttonlist[i].line = line;
142 buttonlist[i].where = w;
143 buttonlist[i].btexture = texture;
144 buttonlist[i].btimer = time;
145 /* use sound origin of line itself - no need to compatibility-wrap
146 * as the popout code gets it wrong whatever its value */
147 buttonlist[i].soundorg = (mobj_t *)&line->soundorg;
148 return;
149 }
150
151 I_Error("P_StartButton: no button slots left!");
152}
153
154//
155// P_ChangeSwitchTexture()
156//
157// Function that changes switch wall texture on activation.
158//
159// Passed the line which the switch is on, and whether its retriggerable.
160// If not retriggerable, this function clears the line special to insure that
161//
162// No return
163//
164void P_ChangeSwitchTexture
165( line_t* line,
166 int useAgain )
167{
168 /* Rearranged a bit to avoid too much code duplication */
169 mobj_t *soundorg;
170 int i, sound;
171 short *texture, *ttop, *tmid, *tbot;
172 bwhere_e position;
173
174 ttop = &sides[line->sidenum[0]].toptexture;
175 tmid = &sides[line->sidenum[0]].midtexture;
176 tbot = &sides[line->sidenum[0]].bottomtexture;
177
178 sound = sfx_swtchn;
179 /* use the sound origin of the linedef (its midpoint)
180 * unless in a compatibility mode */
181 soundorg = (mobj_t *)&line->soundorg;
182 if (comp[comp_sound] || compatibility_level < prboom_6_compatibility) {
183 /* usually NULL, unless there is another button already pressed in,
184 * in which case it's the sound origin of that button press... */
185 soundorg = buttonlist->soundorg;
186 } else {
187 // EXIT SWITCH?
188 /* don't do this unless you're in a compatibility mode */
189 // proff - this works as advertised, but I don't like the sound
190 // if (line->special == 11 || line->special == 51) // exit or secret exit
191 // sound = sfx_swtchx;
192 }
193
194 /* don't zero line->special until after exit switch test */
195 if (!useAgain)
196 line->special = 0;
197
198 /* search for a texture to change */
199 texture = NULL; position = 0;
200 for (i = 0;i < numswitches*2;i++) { /* this could be more efficient... */
201 if (switchlist[i] == *ttop) {
202 texture = ttop; position = top; break;
203 } else if (switchlist[i] == *tmid) {
204 texture = tmid; position = middle; break;
205 } else if (switchlist[i] == *tbot) {
206 texture = tbot; position = bottom; break;
207 }
208 }
209 if (texture == NULL)
210 return; /* no switch texture was found to change */
211 *texture = switchlist[i^1];
212
213 S_StartSound(soundorg, sound);
214
215 if (useAgain)
216 P_StartButton(line, position, switchlist[i], BUTTONTIME);
217}
218
219
220//
221// P_UseSpecialLine
222//
223//
224// Called when a thing uses (pushes) a special line.
225// Only the front sides of lines are usable.
226// Dispatches to the appropriate linedef function handler.
227//
228// Passed the thing using the line, the line being used, and the side used
229// Returns true if a thinker was created
230//
231boolean
232P_UseSpecialLine
233( mobj_t* thing,
234 line_t* line,
235 int side )
236{
237
238 // e6y
239 // b.m. side test was broken in boom201
240 if ((demoplayback ? (demover != 201) : (compatibility_level != boom_201_compatibility)))
241 if (side) //jff 6/1/98 fix inadvertent deletion of side test
242 return false;
243
244 //jff 02/04/98 add check here for generalized floor/ceil mover
245 if (!demo_compatibility)
246 {
247 // pointer to line function is NULL by default, set non-null if
248 // line special is push or switch generalized linedef type
249 int (*linefunc)(line_t *line)=NULL;
250
251 // check each range of generalized linedefs
252 if ((unsigned)line->special >= GenEnd)
253 {
254 // Out of range for GenFloors
255 }
256 else if ((unsigned)line->special >= GenFloorBase)
257 {
258 if (!thing->player)
259 if ((line->special & FloorChange) || !(line->special & FloorModel))
260 return false; // FloorModel is "Allow Monsters" if FloorChange is 0
261 if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual
262 return false; // generalized types require tag
263 linefunc = EV_DoGenFloor;
264 }
265 else if ((unsigned)line->special >= GenCeilingBase)
266 {
267 if (!thing->player)
268 if ((line->special & CeilingChange) || !(line->special & CeilingModel))
269 return false; // CeilingModel is "Allow Monsters" if CeilingChange is 0
270 if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual
271 return false; // generalized types require tag
272 linefunc = EV_DoGenCeiling;
273 }
274 else if ((unsigned)line->special >= GenDoorBase)
275 {
276 if (!thing->player)
277 {
278 if (!(line->special & DoorMonster))
279 return false; // monsters disallowed from this door
280 if (line->flags & ML_SECRET) // they can't open secret doors either
281 return false;
282 }
283 if (!line->tag && ((line->special&6)!=6)) //jff 3/2/98 all non-manual
284 return false; // generalized types require tag
285 linefunc = EV_DoGenDoor;
286 }
287 else if ((unsigned)line->special >= GenLockedBase)
288 {
289 if (!thing->player)
290 return false; // monsters disallowed from unlocking doors
291 if (!P_CanUnlockGenDoor(line,thing->player))
292 return false;
293 if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual
294 return false; // generalized types require tag
295
296 linefunc = EV_DoGenLockedDoor;
297 }
298 else if ((unsigned)line->special >= GenLiftBase)
299 {
300 if (!thing->player)
301 if (!(line->special & LiftMonster))
302 return false; // monsters disallowed
303 if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual
304 return false; // generalized types require tag
305 linefunc = EV_DoGenLift;
306 }
307 else if ((unsigned)line->special >= GenStairsBase)
308 {
309 if (!thing->player)
310 if (!(line->special & StairMonster))
311 return false; // monsters disallowed
312 if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual
313 return false; // generalized types require tag
314 linefunc = EV_DoGenStairs;
315 }
316 else if ((unsigned)line->special >= GenCrusherBase)
317 {
318 if (!thing->player)
319 if (!(line->special & CrusherMonster))
320 return false; // monsters disallowed
321 if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual
322 return false; // generalized types require tag
323 linefunc = EV_DoGenCrusher;
324 }
325
326 if (linefunc)
327 switch((line->special & TriggerType) >> TriggerTypeShift)
328 {
329 case PushOnce:
330 if (!side)
331 if (linefunc(line))
332 line->special = 0;
333 return true;
334 case PushMany:
335 if (!side)
336 linefunc(line);
337 return true;
338 case SwitchOnce:
339 if (linefunc(line))
340 P_ChangeSwitchTexture(line,0);
341 return true;
342 case SwitchMany:
343 if (linefunc(line))
344 P_ChangeSwitchTexture(line,1);
345 return true;
346 default: // if not a switch/push type, do nothing here
347 return false;
348 }
349 }
350
351 // Switches that other things can activate.
352 if (!thing->player)
353 {
354 // never open secret doors
355 if (line->flags & ML_SECRET)
356 return false;
357
358 switch(line->special)
359 {
360 case 1: // MANUAL DOOR RAISE
361 case 32: // MANUAL BLUE
362 case 33: // MANUAL RED
363 case 34: // MANUAL YELLOW
364 //jff 3/5/98 add ability to use teleporters for monsters
365 case 195: // switch teleporters
366 case 174:
367 case 210: // silent switch teleporters
368 case 209:
369 break;
370
371 default:
372 return false;
373 break;
374 }
375 }
376
377 if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types
378 return false;
379
380 // Dispatch to handler according to linedef type
381 switch (line->special)
382 {
383 // Manual doors, push type with no tag
384 case 1: // Vertical Door
385 case 26: // Blue Door/Locked
386 case 27: // Yellow Door /Locked
387 case 28: // Red Door /Locked
388
389 case 31: // Manual door open
390 case 32: // Blue locked door open
391 case 33: // Red locked door open
392 case 34: // Yellow locked door open
393
394 case 117: // Blazing door raise
395 case 118: // Blazing door open
396 EV_VerticalDoor (line, thing);
397 break;
398
399 // Switches (non-retriggerable)
400 case 7:
401 // Build Stairs
402 if (EV_BuildStairs(line,build8))
403 P_ChangeSwitchTexture(line,0);
404 break;
405
406 case 9:
407 // Change Donut
408 if (EV_DoDonut(line))
409 P_ChangeSwitchTexture(line,0);
410 break;
411
412 case 11:
413 /* Exit level
414 * killough 10/98: prevent zombies from exiting levels
415 */
416 if (thing->player && thing->player->health <= 0 && !comp[comp_zombie])
417 {
418 S_StartSound(thing, sfx_noway);
419 return false;
420 }
421
422 P_ChangeSwitchTexture(line,0);
423 G_ExitLevel ();
424 break;
425
426 case 14:
427 // Raise Floor 32 and change texture
428 if (EV_DoPlat(line,raiseAndChange,32))
429 P_ChangeSwitchTexture(line,0);
430 break;
431
432 case 15:
433 // Raise Floor 24 and change texture
434 if (EV_DoPlat(line,raiseAndChange,24))
435 P_ChangeSwitchTexture(line,0);
436 break;
437
438 case 18:
439 // Raise Floor to next highest floor
440 if (EV_DoFloor(line, raiseFloorToNearest))
441 P_ChangeSwitchTexture(line,0);
442 break;
443
444 case 20:
445 // Raise Plat next highest floor and change texture
446 if (EV_DoPlat(line,raiseToNearestAndChange,0))
447 P_ChangeSwitchTexture(line,0);
448 break;
449
450 case 21:
451 // PlatDownWaitUpStay
452 if (EV_DoPlat(line,downWaitUpStay,0))
453 P_ChangeSwitchTexture(line,0);
454 break;
455
456 case 23:
457 // Lower Floor to Lowest
458 if (EV_DoFloor(line,lowerFloorToLowest))
459 P_ChangeSwitchTexture(line,0);
460 break;
461
462 case 29:
463 // Raise Door
464 if (EV_DoDoor(line,normal))
465 P_ChangeSwitchTexture(line,0);
466 break;
467
468 case 41:
469 // Lower Ceiling to Floor
470 if (EV_DoCeiling(line,lowerToFloor))
471 P_ChangeSwitchTexture(line,0);
472 break;
473
474 case 71:
475 // Turbo Lower Floor
476 if (EV_DoFloor(line,turboLower))
477 P_ChangeSwitchTexture(line,0);
478 break;
479
480 case 49:
481 // Ceiling Crush And Raise
482 if (EV_DoCeiling(line,crushAndRaise))
483 P_ChangeSwitchTexture(line,0);
484 break;
485
486 case 50:
487 // Close Door
488 if (EV_DoDoor(line,close))
489 P_ChangeSwitchTexture(line,0);
490 break;
491
492 case 51:
493 /* Secret EXIT
494 * killough 10/98: prevent zombies from exiting levels
495 */
496 if (thing->player && thing->player->health <= 0 && !comp[comp_zombie])
497 {
498 S_StartSound(thing, sfx_noway);
499 return false;
500 }
501
502 P_ChangeSwitchTexture(line,0);
503 G_SecretExitLevel ();
504 break;
505
506 case 55:
507 // Raise Floor Crush
508 if (EV_DoFloor(line,raiseFloorCrush))
509 P_ChangeSwitchTexture(line,0);
510 break;
511
512 case 101:
513 // Raise Floor
514 if (EV_DoFloor(line,raiseFloor))
515 P_ChangeSwitchTexture(line,0);
516 break;
517
518 case 102:
519 // Lower Floor to Surrounding floor height
520 if (EV_DoFloor(line,lowerFloor))
521 P_ChangeSwitchTexture(line,0);
522 break;
523
524 case 103:
525 // Open Door
526 if (EV_DoDoor(line,open))
527 P_ChangeSwitchTexture(line,0);
528 break;
529
530 case 111:
531 // Blazing Door Raise (faster than TURBO!)
532 if (EV_DoDoor (line,blazeRaise))
533 P_ChangeSwitchTexture(line,0);
534 break;
535
536 case 112:
537 // Blazing Door Open (faster than TURBO!)
538 if (EV_DoDoor (line,blazeOpen))
539 P_ChangeSwitchTexture(line,0);
540 break;
541
542 case 113:
543 // Blazing Door Close (faster than TURBO!)
544 if (EV_DoDoor (line,blazeClose))
545 P_ChangeSwitchTexture(line,0);
546 break;
547
548 case 122:
549 // Blazing PlatDownWaitUpStay
550 if (EV_DoPlat(line,blazeDWUS,0))
551 P_ChangeSwitchTexture(line,0);
552 break;
553
554 case 127:
555 // Build Stairs Turbo 16
556 if (EV_BuildStairs(line,turbo16))
557 P_ChangeSwitchTexture(line,0);
558 break;
559
560 case 131:
561 // Raise Floor Turbo
562 if (EV_DoFloor(line,raiseFloorTurbo))
563 P_ChangeSwitchTexture(line,0);
564 break;
565
566 case 133:
567 // BlzOpenDoor BLUE
568 case 135:
569 // BlzOpenDoor RED
570 case 137:
571 // BlzOpenDoor YELLOW
572 if (EV_DoLockedDoor (line,blazeOpen,thing))
573 P_ChangeSwitchTexture(line,0);
574 break;
575
576 case 140:
577 // Raise Floor 512
578 if (EV_DoFloor(line,raiseFloor512))
579 P_ChangeSwitchTexture(line,0);
580 break;
581
582 // killough 1/31/98: factored out compatibility check;
583 // added inner switch, relaxed check to demo_compatibility
584
585 default:
586 if (!demo_compatibility)
587 switch (line->special)
588 {
589 //jff 1/29/98 added linedef types to fill all functions out so that
590 // all possess SR, S1, WR, W1 types
591
592 case 158:
593 // Raise Floor to shortest lower texture
594 // 158 S1 EV_DoFloor(raiseToTexture), CSW(0)
595 if (EV_DoFloor(line,raiseToTexture))
596 P_ChangeSwitchTexture(line,0);
597 break;
598
599 case 159:
600 // Raise Floor to shortest lower texture
601 // 159 S1 EV_DoFloor(lowerAndChange)
602 if (EV_DoFloor(line,lowerAndChange))
603 P_ChangeSwitchTexture(line,0);
604 break;
605
606 case 160:
607 // Raise Floor 24 and change
608 // 160 S1 EV_DoFloor(raiseFloor24AndChange)
609 if (EV_DoFloor(line,raiseFloor24AndChange))
610 P_ChangeSwitchTexture(line,0);
611 break;
612
613 case 161:
614 // Raise Floor 24
615 // 161 S1 EV_DoFloor(raiseFloor24)
616 if (EV_DoFloor(line,raiseFloor24))
617 P_ChangeSwitchTexture(line,0);
618 break;
619
620 case 162:
621 // Moving floor min n to max n
622 // 162 S1 EV_DoPlat(perpetualRaise,0)
623 if (EV_DoPlat(line,perpetualRaise,0))
624 P_ChangeSwitchTexture(line,0);
625 break;
626
627 case 163:
628 // Stop Moving floor
629 // 163 S1 EV_DoPlat(perpetualRaise,0)
630 EV_StopPlat(line);
631 P_ChangeSwitchTexture(line,0);
632 break;
633
634 case 164:
635 // Start fast crusher
636 // 164 S1 EV_DoCeiling(fastCrushAndRaise)
637 if (EV_DoCeiling(line,fastCrushAndRaise))
638 P_ChangeSwitchTexture(line,0);
639 break;
640
641 case 165:
642 // Start slow silent crusher
643 // 165 S1 EV_DoCeiling(silentCrushAndRaise)
644 if (EV_DoCeiling(line,silentCrushAndRaise))
645 P_ChangeSwitchTexture(line,0);
646 break;
647
648 case 166:
649 // Raise ceiling, Lower floor
650 // 166 S1 EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest)
651 if (EV_DoCeiling(line, raiseToHighest) ||
652 EV_DoFloor(line, lowerFloorToLowest))
653 P_ChangeSwitchTexture(line,0);
654 break;
655
656 case 167:
657 // Lower floor and Crush
658 // 167 S1 EV_DoCeiling(lowerAndCrush)
659 if (EV_DoCeiling(line, lowerAndCrush))
660 P_ChangeSwitchTexture(line,0);
661 break;
662
663 case 168:
664 // Stop crusher
665 // 168 S1 EV_CeilingCrushStop()
666 if (EV_CeilingCrushStop(line))
667 P_ChangeSwitchTexture(line,0);
668 break;
669
670 case 169:
671 // Lights to brightest neighbor sector
672 // 169 S1 EV_LightTurnOn(0)
673 EV_LightTurnOn(line,0);
674 P_ChangeSwitchTexture(line,0);
675 break;
676
677 case 170:
678 // Lights to near dark
679 // 170 S1 EV_LightTurnOn(35)
680 EV_LightTurnOn(line,35);
681 P_ChangeSwitchTexture(line,0);
682 break;
683
684 case 171:
685 // Lights on full
686 // 171 S1 EV_LightTurnOn(255)
687 EV_LightTurnOn(line,255);
688 P_ChangeSwitchTexture(line,0);
689 break;
690
691 case 172:
692 // Start Lights Strobing
693 // 172 S1 EV_StartLightStrobing()
694 EV_StartLightStrobing(line);
695 P_ChangeSwitchTexture(line,0);
696 break;
697
698 case 173:
699 // Lights to Dimmest Near
700 // 173 S1 EV_TurnTagLightsOff()
701 EV_TurnTagLightsOff(line);
702 P_ChangeSwitchTexture(line,0);
703 break;
704
705 case 174:
706 // Teleport
707 // 174 S1 EV_Teleport(side,thing)
708 if (EV_Teleport(line,side,thing))
709 P_ChangeSwitchTexture(line,0);
710 break;
711
712 case 175:
713 // Close Door, Open in 30 secs
714 // 175 S1 EV_DoDoor(close30ThenOpen)
715 if (EV_DoDoor(line,close30ThenOpen))
716 P_ChangeSwitchTexture(line,0);
717 break;
718
719 case 189: //jff 3/15/98 create texture change no motion type
720 // Texture Change Only (Trigger)
721 // 189 S1 Change Texture/Type Only
722 if (EV_DoChange(line,trigChangeOnly))
723 P_ChangeSwitchTexture(line,0);
724 break;
725
726 case 203:
727 // Lower ceiling to lowest surrounding ceiling
728 // 203 S1 EV_DoCeiling(lowerToLowest)
729 if (EV_DoCeiling(line,lowerToLowest))
730 P_ChangeSwitchTexture(line,0);
731 break;
732
733 case 204:
734 // Lower ceiling to highest surrounding floor
735 // 204 S1 EV_DoCeiling(lowerToMaxFloor)
736 if (EV_DoCeiling(line,lowerToMaxFloor))
737 P_ChangeSwitchTexture(line,0);
738 break;
739
740 case 209:
741 // killough 1/31/98: silent teleporter
742 //jff 209 S1 SilentTeleport
743 if (EV_SilentTeleport(line, side, thing))
744 P_ChangeSwitchTexture(line,0);
745 break;
746
747 case 241: //jff 3/15/98 create texture change no motion type
748 // Texture Change Only (Numeric)
749 // 241 S1 Change Texture/Type Only
750 if (EV_DoChange(line,numChangeOnly))
751 P_ChangeSwitchTexture(line,0);
752 break;
753
754 case 221:
755 // Lower floor to next lowest floor
756 // 221 S1 Lower Floor To Nearest Floor
757 if (EV_DoFloor(line,lowerFloorToNearest))
758 P_ChangeSwitchTexture(line,0);
759 break;
760
761 case 229:
762 // Raise elevator next floor
763 // 229 S1 Raise Elevator next floor
764 if (EV_DoElevator(line,elevateUp))
765 P_ChangeSwitchTexture(line,0);
766 break;
767
768 case 233:
769 // Lower elevator next floor
770 // 233 S1 Lower Elevator next floor
771 if (EV_DoElevator(line,elevateDown))
772 P_ChangeSwitchTexture(line,0);
773 break;
774
775 case 237:
776 // Elevator to current floor
777 // 237 S1 Elevator to current floor
778 if (EV_DoElevator(line,elevateCurrent))
779 P_ChangeSwitchTexture(line,0);
780 break;
781
782
783 // jff 1/29/98 end of added S1 linedef types
784
785 //jff 1/29/98 added linedef types to fill all functions out so that
786 // all possess SR, S1, WR, W1 types
787
788 case 78: //jff 3/15/98 create texture change no motion type
789 // Texture Change Only (Numeric)
790 // 78 SR Change Texture/Type Only
791 if (EV_DoChange(line,numChangeOnly))
792 P_ChangeSwitchTexture(line,1);
793 break;
794
795 case 176:
796 // Raise Floor to shortest lower texture
797 // 176 SR EV_DoFloor(raiseToTexture), CSW(1)
798 if (EV_DoFloor(line,raiseToTexture))
799 P_ChangeSwitchTexture(line,1);
800 break;
801
802 case 177:
803 // Raise Floor to shortest lower texture
804 // 177 SR EV_DoFloor(lowerAndChange)
805 if (EV_DoFloor(line,lowerAndChange))
806 P_ChangeSwitchTexture(line,1);
807 break;
808
809 case 178:
810 // Raise Floor 512
811 // 178 SR EV_DoFloor(raiseFloor512)
812 if (EV_DoFloor(line,raiseFloor512))
813 P_ChangeSwitchTexture(line,1);
814 break;
815
816 case 179:
817 // Raise Floor 24 and change
818 // 179 SR EV_DoFloor(raiseFloor24AndChange)
819 if (EV_DoFloor(line,raiseFloor24AndChange))
820 P_ChangeSwitchTexture(line,1);
821 break;
822
823 case 180:
824 // Raise Floor 24
825 // 180 SR EV_DoFloor(raiseFloor24)
826 if (EV_DoFloor(line,raiseFloor24))
827 P_ChangeSwitchTexture(line,1);
828 break;
829
830 case 181:
831 // Moving floor min n to max n
832 // 181 SR EV_DoPlat(perpetualRaise,0)
833
834 EV_DoPlat(line,perpetualRaise,0);
835 P_ChangeSwitchTexture(line,1);
836 break;
837
838 case 182:
839 // Stop Moving floor
840 // 182 SR EV_DoPlat(perpetualRaise,0)
841 EV_StopPlat(line);
842 P_ChangeSwitchTexture(line,1);
843 break;
844
845 case 183:
846 // Start fast crusher
847 // 183 SR EV_DoCeiling(fastCrushAndRaise)
848 if (EV_DoCeiling(line,fastCrushAndRaise))
849 P_ChangeSwitchTexture(line,1);
850 break;
851
852 case 184:
853 // Start slow crusher
854 // 184 SR EV_DoCeiling(crushAndRaise)
855 if (EV_DoCeiling(line,crushAndRaise))
856 P_ChangeSwitchTexture(line,1);
857 break;
858
859 case 185:
860 // Start slow silent crusher
861 // 185 SR EV_DoCeiling(silentCrushAndRaise)
862 if (EV_DoCeiling(line,silentCrushAndRaise))
863 P_ChangeSwitchTexture(line,1);
864 break;
865
866 case 186:
867 // Raise ceiling, Lower floor
868 // 186 SR EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest)
869 if (EV_DoCeiling(line, raiseToHighest) ||
870 EV_DoFloor(line, lowerFloorToLowest))
871 P_ChangeSwitchTexture(line,1);
872 break;
873
874 case 187:
875 // Lower floor and Crush
876 // 187 SR EV_DoCeiling(lowerAndCrush)
877 if (EV_DoCeiling(line, lowerAndCrush))
878 P_ChangeSwitchTexture(line,1);
879 break;
880
881 case 188:
882 // Stop crusher
883 // 188 SR EV_CeilingCrushStop()
884 if (EV_CeilingCrushStop(line))
885 P_ChangeSwitchTexture(line,1);
886 break;
887
888 case 190: //jff 3/15/98 create texture change no motion type
889 // Texture Change Only (Trigger)
890 // 190 SR Change Texture/Type Only
891 if (EV_DoChange(line,trigChangeOnly))
892 P_ChangeSwitchTexture(line,1);
893 break;
894
895 case 191:
896 // Lower Pillar, Raise Donut
897 // 191 SR EV_DoDonut()
898 if (EV_DoDonut(line))
899 P_ChangeSwitchTexture(line,1);
900 break;
901
902 case 192:
903 // Lights to brightest neighbor sector
904 // 192 SR EV_LightTurnOn(0)
905 EV_LightTurnOn(line,0);
906 P_ChangeSwitchTexture(line,1);
907 break;
908
909 case 193:
910 // Start Lights Strobing
911 // 193 SR EV_StartLightStrobing()
912 EV_StartLightStrobing(line);
913 P_ChangeSwitchTexture(line,1);
914 break;
915
916 case 194:
917 // Lights to Dimmest Near
918 // 194 SR EV_TurnTagLightsOff()
919 EV_TurnTagLightsOff(line);
920 P_ChangeSwitchTexture(line,1);
921 break;
922
923 case 195:
924 // Teleport
925 // 195 SR EV_Teleport(side,thing)
926 if (EV_Teleport(line,side,thing))
927 P_ChangeSwitchTexture(line,1);
928 break;
929
930 case 196:
931 // Close Door, Open in 30 secs
932 // 196 SR EV_DoDoor(close30ThenOpen)
933 if (EV_DoDoor(line,close30ThenOpen))
934 P_ChangeSwitchTexture(line,1);
935 break;
936
937 case 205:
938 // Lower ceiling to lowest surrounding ceiling
939 // 205 SR EV_DoCeiling(lowerToLowest)
940 if (EV_DoCeiling(line,lowerToLowest))
941 P_ChangeSwitchTexture(line,1);
942 break;
943
944 case 206:
945 // Lower ceiling to highest surrounding floor
946 // 206 SR EV_DoCeiling(lowerToMaxFloor)
947 if (EV_DoCeiling(line,lowerToMaxFloor))
948 P_ChangeSwitchTexture(line,1);
949 break;
950
951 case 210:
952 // killough 1/31/98: silent teleporter
953 //jff 210 SR SilentTeleport
954 if (EV_SilentTeleport(line, side, thing))
955 P_ChangeSwitchTexture(line,1);
956 break;
957
958 case 211: //jff 3/14/98 create instant toggle floor type
959 // Toggle Floor Between C and F Instantly
960 // 211 SR Toggle Floor Instant
961 if (EV_DoPlat(line,toggleUpDn,0))
962 P_ChangeSwitchTexture(line,1);
963 break;
964
965 case 222:
966 // Lower floor to next lowest floor
967 // 222 SR Lower Floor To Nearest Floor
968 if (EV_DoFloor(line,lowerFloorToNearest))
969 P_ChangeSwitchTexture(line,1);
970 break;
971
972 case 230:
973 // Raise elevator next floor
974 // 230 SR Raise Elevator next floor
975 if (EV_DoElevator(line,elevateUp))
976 P_ChangeSwitchTexture(line,1);
977 break;
978
979 case 234:
980 // Lower elevator next floor
981 // 234 SR Lower Elevator next floor
982 if (EV_DoElevator(line,elevateDown))
983 P_ChangeSwitchTexture(line,1);
984 break;
985
986 case 238:
987 // Elevator to current floor
988 // 238 SR Elevator to current floor
989 if (EV_DoElevator(line,elevateCurrent))
990 P_ChangeSwitchTexture(line,1);
991 break;
992
993 case 258:
994 // Build stairs, step 8
995 // 258 SR EV_BuildStairs(build8)
996 if (EV_BuildStairs(line,build8))
997 P_ChangeSwitchTexture(line,1);
998 break;
999
1000 case 259:
1001 // Build stairs, step 16
1002 // 259 SR EV_BuildStairs(turbo16)
1003 if (EV_BuildStairs(line,turbo16))
1004 P_ChangeSwitchTexture(line,1);
1005 break;
1006
1007 // 1/29/98 jff end of added SR linedef types
1008
1009 }
1010 break;
1011
1012 // Buttons (retriggerable switches)
1013 case 42:
1014 // Close Door
1015 if (EV_DoDoor(line,close))
1016 P_ChangeSwitchTexture(line,1);
1017 break;
1018
1019 case 43:
1020 // Lower Ceiling to Floor
1021 if (EV_DoCeiling(line,lowerToFloor))
1022 P_ChangeSwitchTexture(line,1);
1023 break;
1024
1025 case 45:
1026 // Lower Floor to Surrounding floor height
1027 if (EV_DoFloor(line,lowerFloor))
1028 P_ChangeSwitchTexture(line,1);
1029 break;
1030
1031 case 60:
1032 // Lower Floor to Lowest
1033 if (EV_DoFloor(line,lowerFloorToLowest))
1034 P_ChangeSwitchTexture(line,1);
1035 break;
1036
1037 case 61:
1038 // Open Door
1039 if (EV_DoDoor(line,open))
1040 P_ChangeSwitchTexture(line,1);
1041 break;
1042
1043 case 62:
1044 // PlatDownWaitUpStay
1045 if (EV_DoPlat(line,downWaitUpStay,1))
1046 P_ChangeSwitchTexture(line,1);
1047 break;
1048
1049 case 63:
1050 // Raise Door
1051 if (EV_DoDoor(line,normal))
1052 P_ChangeSwitchTexture(line,1);
1053 break;
1054
1055 case 64:
1056 // Raise Floor to ceiling
1057 if (EV_DoFloor(line,raiseFloor))
1058 P_ChangeSwitchTexture(line,1);
1059 break;
1060
1061 case 66:
1062 // Raise Floor 24 and change texture
1063 if (EV_DoPlat(line,raiseAndChange,24))
1064 P_ChangeSwitchTexture(line,1);
1065 break;
1066
1067 case 67:
1068 // Raise Floor 32 and change texture
1069 if (EV_DoPlat(line,raiseAndChange,32))
1070 P_ChangeSwitchTexture(line,1);
1071 break;
1072
1073 case 65:
1074 // Raise Floor Crush
1075 if (EV_DoFloor(line,raiseFloorCrush))
1076 P_ChangeSwitchTexture(line,1);
1077 break;
1078
1079 case 68:
1080 // Raise Plat to next highest floor and change texture
1081 if (EV_DoPlat(line,raiseToNearestAndChange,0))
1082 P_ChangeSwitchTexture(line,1);
1083 break;
1084
1085 case 69:
1086 // Raise Floor to next highest floor
1087 if (EV_DoFloor(line, raiseFloorToNearest))
1088 P_ChangeSwitchTexture(line,1);
1089 break;
1090
1091 case 70:
1092 // Turbo Lower Floor
1093 if (EV_DoFloor(line,turboLower))
1094 P_ChangeSwitchTexture(line,1);
1095 break;
1096
1097 case 114:
1098 // Blazing Door Raise (faster than TURBO!)
1099 if (EV_DoDoor (line,blazeRaise))
1100 P_ChangeSwitchTexture(line,1);
1101 break;
1102
1103 case 115:
1104 // Blazing Door Open (faster than TURBO!)
1105 if (EV_DoDoor (line,blazeOpen))
1106 P_ChangeSwitchTexture(line,1);
1107 break;
1108
1109 case 116:
1110 // Blazing Door Close (faster than TURBO!)
1111 if (EV_DoDoor (line,blazeClose))
1112 P_ChangeSwitchTexture(line,1);
1113 break;
1114
1115 case 123:
1116 // Blazing PlatDownWaitUpStay
1117 if (EV_DoPlat(line,blazeDWUS,0))
1118 P_ChangeSwitchTexture(line,1);
1119 break;
1120
1121 case 132:
1122 // Raise Floor Turbo
1123 if (EV_DoFloor(line,raiseFloorTurbo))
1124 P_ChangeSwitchTexture(line,1);
1125 break;
1126
1127 case 99:
1128 // BlzOpenDoor BLUE
1129 case 134:
1130 // BlzOpenDoor RED
1131 case 136:
1132 // BlzOpenDoor YELLOW
1133 if (EV_DoLockedDoor (line,blazeOpen,thing))
1134 P_ChangeSwitchTexture(line,1);
1135 break;
1136
1137 case 138:
1138 // Light Turn On
1139 EV_LightTurnOn(line,255);
1140 P_ChangeSwitchTexture(line,1);
1141 break;
1142
1143 case 139:
1144 // Light Turn Off
1145 EV_LightTurnOn(line,35);
1146 P_ChangeSwitchTexture(line,1);
1147 break;
1148 }
1149 return true;
1150}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Teleportation.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomdef.h"
35#include "doomstat.h"
36#include "p_spec.h"
37#include "p_maputl.h"
38#include "p_map.h"
39#include "r_main.h"
40#include "p_tick.h"
41#include "s_sound.h"
42#include "sounds.h"
43#include "p_user.h"
44#include "r_demo.h"
45
46static mobj_t* P_TeleportDestination(line_t* line)
47{
48 int i;
49 for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) {
50 register thinker_t* th = NULL;
51 while ((th = P_NextThinker(th,th_misc)) != NULL)
52 if (th->function == P_MobjThinker) {
53 register mobj_t* m = (mobj_t*)th;
54 if (m->type == MT_TELEPORTMAN &&
55 m->subsector->sector-sectors == i)
56 return m;
57 }
58 }
59 return NULL;
60}
61//
62// TELEPORTATION
63//
64// killough 5/3/98: reformatted, cleaned up
65
66int EV_Teleport(line_t *line, int side, mobj_t *thing)
67{
68 mobj_t *m;
69
70 // don't teleport missiles
71 // Don't teleport if hit back of line,
72 // so you can get out of teleporter.
73 if (side || thing->flags & MF_MISSILE)
74 return 0;
75
76 // killough 1/31/98: improve performance by using
77 // P_FindSectorFromLineTag instead of simple linear search.
78
79 if ((m = P_TeleportDestination(line)) != NULL)
80 {
81 fixed_t oldx = thing->x, oldy = thing->y, oldz = thing->z;
82 player_t *player = thing->player;
83
84 // killough 5/12/98: exclude voodoo dolls:
85 if (player && player->mo != thing)
86 player = NULL;
87
88 if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */
89 return 0;
90
91 if (compatibility_level != finaldoom_compatibility)
92 thing->z = thing->floorz;
93
94 if (player)
95 player->viewz = thing->z + player->viewheight;
96
97 // spawn teleport fog and emit sound at source
98 S_StartSound(P_SpawnMobj(oldx, oldy, oldz, MT_TFOG), sfx_telept);
99
100 // spawn teleport fog and emit sound at destination
101 S_StartSound(P_SpawnMobj(m->x +
102 20*finecosine[m->angle>>ANGLETOFINESHIFT],
103 m->y +
104 20*finesine[m->angle>>ANGLETOFINESHIFT],
105 thing->z, MT_TFOG),
106 sfx_telept);
107
108 /* don't move for a bit
109 * cph - DEMOSYNC - BOOM had (player) here? */
110 if (thing->player)
111 thing->reactiontime = 18;
112
113 thing->angle = m->angle;
114
115 thing->momx = thing->momy = thing->momz = 0;
116
117 /* killough 10/98: kill all bobbing momentum too */
118 if (player)
119 player->momx = player->momy = 0;
120
121 // e6y
122 if (player && player->mo == thing)
123 R_ResetAfterTeleport(player);
124
125 return 1;
126 }
127 return 0;
128}
129
130//
131// Silent TELEPORTATION, by Lee Killough
132// Primarily for rooms-over-rooms etc.
133//
134
135int EV_SilentTeleport(line_t *line, int side, mobj_t *thing)
136{
137 mobj_t *m;
138
139 // don't teleport missiles
140 // Don't teleport if hit back of line,
141 // so you can get out of teleporter.
142
143 if (side || thing->flags & MF_MISSILE)
144 return 0;
145
146 if ((m = P_TeleportDestination(line)) != NULL)
147 {
148 // Height of thing above ground, in case of mid-air teleports:
149 fixed_t z = thing->z - thing->floorz;
150
151 // Get the angle between the exit thing and source linedef.
152 // Rotate 90 degrees, so that walking perpendicularly across
153 // teleporter linedef causes thing to exit in the direction
154 // indicated by the exit thing.
155 angle_t angle =
156 R_PointToAngle2(0, 0, line->dx, line->dy) - m->angle + ANG90;
157
158 // Sine, cosine of angle adjustment
159 fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
160 fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
161
162 // Momentum of thing crossing teleporter linedef
163 fixed_t momx = thing->momx;
164 fixed_t momy = thing->momy;
165
166 // Whether this is a player, and if so, a pointer to its player_t
167 player_t *player = thing->player;
168
169 // Attempt to teleport, aborting if blocked
170 if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */
171 return 0;
172
173 // Rotate thing according to difference in angles
174 thing->angle += angle;
175
176 // Adjust z position to be same height above ground as before
177 thing->z = z + thing->floorz;
178
179 // Rotate thing's momentum to come out of exit just like it entered
180 thing->momx = FixedMul(momx, c) - FixedMul(momy, s);
181 thing->momy = FixedMul(momy, c) + FixedMul(momx, s);
182
183 // Adjust player's view, in case there has been a height change
184 // Voodoo dolls are excluded by making sure player->mo == thing.
185 if (player && player->mo == thing)
186 {
187 // Save the current deltaviewheight, used in stepping
188 fixed_t deltaviewheight = player->deltaviewheight;
189
190 // Clear deltaviewheight, since we don't want any changes
191 player->deltaviewheight = 0;
192
193 // Set player's view according to the newly set parameters
194 P_CalcHeight(player);
195
196 // Reset the delta to have the same dynamics as before
197 player->deltaviewheight = deltaviewheight;
198 }
199
200 // e6y
201 if (player && player->mo == thing)
202 R_ResetAfterTeleport(player);
203
204 return 1;
205 }
206 return 0;
207}
208
209//
210// Silent linedef-based TELEPORTATION, by Lee Killough
211// Primarily for rooms-over-rooms etc.
212// This is the complete player-preserving kind of teleporter.
213// It has advantages over the teleporter with thing exits.
214//
215
216// maximum fixed_t units to move object to avoid hiccups
217#define FUDGEFACTOR 10
218
219int EV_SilentLineTeleport(line_t *line, int side, mobj_t *thing,
220 boolean reverse)
221{
222 int i;
223 line_t *l;
224
225 if (side || thing->flags & MF_MISSILE)
226 return 0;
227
228 for (i = -1; (i = P_FindLineFromLineTag(line, i)) >= 0;)
229 if ((l=lines+i) != line && l->backsector)
230 {
231 // Get the thing's position along the source linedef
232 fixed_t pos = D_abs(line->dx) > D_abs(line->dy) ?
233 FixedDiv(thing->x - line->v1->x, line->dx) :
234 FixedDiv(thing->y - line->v1->y, line->dy) ;
235
236 // Get the angle between the two linedefs, for rotating
237 // orientation and momentum. Rotate 180 degrees, and flip
238 // the position across the exit linedef, if reversed.
239 angle_t angle = (reverse ? pos = FRACUNIT-pos, 0 : ANG180) +
240 R_PointToAngle2(0, 0, l->dx, l->dy) -
241 R_PointToAngle2(0, 0, line->dx, line->dy);
242
243 // Interpolate position across the exit linedef
244 fixed_t x = l->v2->x - FixedMul(pos, l->dx);
245 fixed_t y = l->v2->y - FixedMul(pos, l->dy);
246
247 // Sine, cosine of angle adjustment
248 fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
249 fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
250
251 // Maximum distance thing can be moved away from interpolated
252 // exit, to ensure that it is on the correct side of exit linedef
253 int fudge = FUDGEFACTOR;
254
255 // Whether this is a player, and if so, a pointer to its player_t.
256 // Voodoo dolls are excluded by making sure thing->player->mo==thing.
257 player_t *player = thing->player && thing->player->mo == thing ?
258 thing->player : NULL;
259
260 // Whether walking towards first side of exit linedef steps down
261 int stepdown =
262 l->frontsector->floorheight < l->backsector->floorheight;
263
264 // Height of thing above ground
265 fixed_t z = thing->z - thing->floorz;
266
267 // Side to exit the linedef on positionally.
268 //
269 // Notes:
270 //
271 // This flag concerns exit position, not momentum. Due to
272 // roundoff error, the thing can land on either the left or
273 // the right side of the exit linedef, and steps must be
274 // taken to make sure it does not end up on the wrong side.
275 //
276 // Exit momentum is always towards side 1 in a reversed
277 // teleporter, and always towards side 0 otherwise.
278 //
279 // Exiting positionally on side 1 is always safe, as far
280 // as avoiding oscillations and stuck-in-wall problems,
281 // but may not be optimum for non-reversed teleporters.
282 //
283 // Exiting on side 0 can cause oscillations if momentum
284 // is towards side 1, as it is with reversed teleporters.
285 //
286 // Exiting on side 1 slightly improves player viewing
287 // when going down a step on a non-reversed teleporter.
288
289 int side = reverse || (player && stepdown);
290
291 // Make sure we are on correct side of exit linedef.
292 while (P_PointOnLineSide(x, y, l) != side && --fudge>=0)
293 if (D_abs(l->dx) > D_abs(l->dy))
294 y -= l->dx < 0 != side ? -1 : 1;
295 else
296 x += l->dy < 0 != side ? -1 : 1;
297
298 // Attempt to teleport, aborting if blocked
299 if (!P_TeleportMove(thing, x, y, false)) /* killough 8/9/98 */
300 return 0;
301
302 // e6y
303 if (player && player->mo == thing)
304 R_ResetAfterTeleport(player);
305
306 // Adjust z position to be same height above ground as before.
307 // Ground level at the exit is measured as the higher of the
308 // two floor heights at the exit linedef.
309 thing->z = z + sides[l->sidenum[stepdown]].sector->floorheight;
310
311 // Rotate thing's orientation according to difference in linedef angles
312 thing->angle += angle;
313
314 // Momentum of thing crossing teleporter linedef
315 x = thing->momx;
316 y = thing->momy;
317
318 // Rotate thing's momentum to come out of exit just like it entered
319 thing->momx = FixedMul(x, c) - FixedMul(y, s);
320 thing->momy = FixedMul(y, c) + FixedMul(x, s);
321
322 // Adjust a player's view, in case there has been a height change
323 if (player)
324 {
325 // Save the current deltaviewheight, used in stepping
326 fixed_t deltaviewheight = player->deltaviewheight;
327
328 // Clear deltaviewheight, since we don't want any changes now
329 player->deltaviewheight = 0;
330
331 // Set player's view according to the newly set parameters
332 P_CalcHeight(player);
333
334 // Reset the delta to have the same dynamics as before
335 player->deltaviewheight = deltaviewheight;
336 }
337
338 // e6y
339 if (player && player->mo == thing)
340 R_ResetAfterTeleport(player);
341
342 return 1;
343 }
344 return 0;
345}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000,2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Thinker, Ticker.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "p_user.h"
36#include "p_spec.h"
37#include "p_tick.h"
38#include "p_map.h"
39#include "r_fps.h"
40
41int leveltime;
42
43static boolean newthinkerpresent;
44
45//
46// THINKERS
47// All thinkers should be allocated by Z_Malloc
48// so they can be operated on uniformly.
49// The actual structures will vary in size,
50// but the first element must be thinker_t.
51//
52
53// killough 8/29/98: we maintain several separate threads, each containing
54// a special class of thinkers, to allow more efficient searches.
55thinker_t thinkerclasscap[th_all+1];
56
57//
58// P_InitThinkers
59//
60
61void P_InitThinkers(void)
62{
63 int i;
64
65 for (i=0; i<NUMTHCLASS; i++) // killough 8/29/98: initialize threaded lists
66 thinkerclasscap[i].cprev = thinkerclasscap[i].cnext = &thinkerclasscap[i];
67
68 thinkercap.prev = thinkercap.next = &thinkercap;
69}
70
71//
72// killough 8/29/98:
73//
74// We maintain separate threads of friends and enemies, to permit more
75// efficient searches.
76//
77
78void P_UpdateThinker(thinker_t *thinker)
79{
80 register thinker_t *th;
81 // find the class the thinker belongs to
82
83 int class =
84 thinker->function == P_RemoveThinkerDelayed ? th_delete :
85 thinker->function == P_MobjThinker &&
86 ((mobj_t *) thinker)->health > 0 &&
87 (((mobj_t *) thinker)->flags & MF_COUNTKILL ||
88 ((mobj_t *) thinker)->type == MT_SKULL) ?
89 ((mobj_t *) thinker)->flags & MF_FRIEND ?
90 th_friends : th_enemies : th_misc;
91
92 {
93 /* Remove from current thread, if in one */
94 if ((th = thinker->cnext)!= NULL)
95 (th->cprev = thinker->cprev)->cnext = th;
96 }
97
98 // Add to appropriate thread
99 th = &thinkerclasscap[class];
100 th->cprev->cnext = thinker;
101 thinker->cnext = th;
102 thinker->cprev = th->cprev;
103 th->cprev = thinker;
104}
105
106//
107// P_AddThinker
108// Adds a new thinker at the end of the list.
109//
110
111void P_AddThinker(thinker_t* thinker)
112{
113 thinkercap.prev->next = thinker;
114 thinker->next = &thinkercap;
115 thinker->prev = thinkercap.prev;
116 thinkercap.prev = thinker;
117
118 thinker->references = 0; // killough 11/98: init reference counter to 0
119
120 // killough 8/29/98: set sentinel pointers, and then add to appropriate list
121 thinker->cnext = thinker->cprev = NULL;
122 P_UpdateThinker(thinker);
123 newthinkerpresent = true;
124}
125
126//
127// killough 11/98:
128//
129// Make currentthinker external, so that P_RemoveThinkerDelayed
130// can adjust currentthinker when thinkers self-remove.
131
132static thinker_t *currentthinker;
133
134//
135// P_RemoveThinkerDelayed()
136//
137// Called automatically as part of the thinker loop in P_RunThinkers(),
138// on nodes which are pending deletion.
139//
140// If this thinker has no more pointers referencing it indirectly,
141// remove it, and set currentthinker to one node preceeding it, so
142// that the next step in P_RunThinkers() will get its successor.
143//
144
145void P_RemoveThinkerDelayed(thinker_t *thinker)
146{
147 if (!thinker->references)
148 {
149 { /* Remove from main thinker list */
150 thinker_t *next = thinker->next;
151 /* Note that currentthinker is guaranteed to point to us,
152 * and since we're freeing our memory, we had better change that. So
153 * point it to thinker->prev, so the iterator will correctly move on to
154 * thinker->prev->next = thinker->next */
155 (next->prev = currentthinker = thinker->prev)->next = next;
156 }
157 {
158 /* Remove from current thinker class list */
159 thinker_t *th = thinker->cnext;
160 (th->cprev = thinker->cprev)->cnext = th;
161 }
162 Z_Free(thinker);
163 }
164}
165
166//
167// P_RemoveThinker
168//
169// Deallocation is lazy -- it will not actually be freed
170// until its thinking turn comes up.
171//
172// killough 4/25/98:
173//
174// Instead of marking the function with -1 value cast to a function pointer,
175// set the function to P_RemoveThinkerDelayed(), so that later, it will be
176// removed automatically as part of the thinker process.
177//
178
179void P_RemoveThinker(thinker_t *thinker)
180{
181 R_StopInterpolationIfNeeded(thinker);
182 thinker->function = P_RemoveThinkerDelayed;
183
184 P_UpdateThinker(thinker);
185}
186
187/* cph 2002/01/13 - iterator for thinker list
188 * WARNING: Do not modify thinkers between calls to this functin
189 */
190thinker_t* P_NextThinker(thinker_t* th, th_class cl)
191{
192 thinker_t* top = &thinkerclasscap[cl];
193 if (!th) th = top;
194 th = cl == th_all ? th->next : th->cnext;
195 return th == top ? NULL : th;
196}
197
198/*
199 * P_SetTarget
200 *
201 * This function is used to keep track of pointer references to mobj thinkers.
202 * In Doom, objects such as lost souls could sometimes be removed despite
203 * their still being referenced. In Boom, 'target' mobj fields were tested
204 * during each gametic, and any objects pointed to by them would be prevented
205 * from being removed. But this was incomplete, and was slow (every mobj was
206 * checked during every gametic). Now, we keep a count of the number of
207 * references, and delay removal until the count is 0.
208 */
209
210void P_SetTarget(mobj_t **mop, mobj_t *targ)
211{
212 if (*mop) // If there was a target already, decrease its refcount
213 (*mop)->thinker.references--;
214 if ((*mop = targ)) // Set new target and if non-NULL, increase its counter
215 targ->thinker.references++;
216}
217
218//
219// P_RunThinkers
220//
221// killough 4/25/98:
222//
223// Fix deallocator to stop using "next" pointer after node has been freed
224// (a Doom bug).
225//
226// Process each thinker. For thinkers which are marked deleted, we must
227// load the "next" pointer prior to freeing the node. In Doom, the "next"
228// pointer was loaded AFTER the thinker was freed, which could have caused
229// crashes.
230//
231// But if we are not deleting the thinker, we should reload the "next"
232// pointer after calling the function, in case additional thinkers are
233// added at the end of the list.
234//
235// killough 11/98:
236//
237// Rewritten to delete nodes implicitly, by making currentthinker
238// external and using P_RemoveThinkerDelayed() implicitly.
239//
240
241static void P_RunThinkers (void)
242{
243 for (currentthinker = thinkercap.next;
244 currentthinker != &thinkercap;
245 currentthinker = currentthinker->next)
246 {
247 if (newthinkerpresent)
248 R_ActivateThinkerInterpolations(currentthinker);
249 if (currentthinker->function)
250 currentthinker->function(currentthinker);
251 }
252 newthinkerpresent = false;
253}
254
255//
256// P_Ticker
257//
258
259void P_Ticker (void)
260{
261 int i;
262
263 /* pause if in menu and at least one tic has been run
264 *
265 * killough 9/29/98: note that this ties in with basetic,
266 * since G_Ticker does the pausing during recording or
267 * playback, and compenates by incrementing basetic.
268 *
269 * All of this complicated mess is used to preserve demo sync.
270 */
271
272 if (paused || (menuactive && !demoplayback && !netgame &&
273 players[consoleplayer].viewz != 1))
274 return;
275
276 R_UpdateInterpolations ();
277
278 P_MapStart();
279 // not if this is an intermission screen
280 if(gamestate==GS_LEVEL)
281 for (i=0; i<MAXPLAYERS; i++)
282 if (playeringame[i])
283 P_PlayerThink(&players[i]);
284
285 P_RunThinkers();
286 P_UpdateSpecials();
287 P_RespawnSpecials();
288 P_MapEnd();
289 leveltime++; // for par times
290}
291
diff --git a/src/p_tick.h b/src/p_tick.h
new file mode 100644
index 0000000..22c9d97
--- /dev/null
+++ b/src/p_tick.h
@@ -0,0 +1,75 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000,2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Core thinker processing prototypes.
31 *-----------------------------------------------------------------------------*/
32
33#ifndef __P_TICK__
34#define __P_TICK__
35
36#include "d_think.h"
37
38#ifdef __GNUG__
39#pragma interface
40#endif
41
42/* Called by C_Ticker, can call G_PlayerExited.
43 * Carries out all thinking of monsters and players. */
44
45void P_Ticker(void);
46
47void P_InitThinkers(void);
48void P_AddThinker(thinker_t *thinker);
49void P_RemoveThinker(thinker_t *thinker);
50void P_RemoveThinkerDelayed(thinker_t *thinker); // killough 4/25/98
51
52void P_UpdateThinker(thinker_t *thinker); // killough 8/29/98
53
54void P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98
55
56/* killough 8/29/98: threads of thinkers, for more efficient searches
57 * cph 2002/01/13: for consistency with the main thinker list, keep objects
58 * pending deletion on a class list too
59 */
60typedef enum {
61 th_delete,
62 th_misc,
63 th_friends,
64 th_enemies,
65 NUMTHCLASS,
66 th_all = NUMTHCLASS, /* For P_NextThinker, indicates "any class" */
67} th_class;
68
69extern thinker_t thinkerclasscap[];
70#define thinkercap thinkerclasscap[th_all]
71
72/* cph 2002/01/13 - iterator for thinker lists */
73thinker_t* P_NextThinker(thinker_t*,th_class);
74
75#endif
diff --git a/src/p_user.c b/src/p_user.c
new file mode 100644
index 0000000..d280e55
--- /dev/null
+++ b/src/p_user.c
@@ -0,0 +1,452 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Player related stuff.
31 * Bobbing POV/weapon, movement.
32 * Pending weapon.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#include "doomstat.h"
37#include "d_event.h"
38#include "r_main.h"
39#include "p_map.h"
40#include "p_spec.h"
41#include "p_user.h"
42#include "r_demo.h"
43#include "r_fps.h"
44
45// Index of the special effects (INVUL inverse) map.
46
47#define INVERSECOLORMAP 32
48
49//
50// Movement.
51//
52
53// 16 pixels of bob
54
55#define MAXBOB 0x100000
56
57boolean onground; // whether player is on ground or in air
58
59//
60// P_Thrust
61// Moves the given origin along a given angle.
62//
63
64void P_Thrust(player_t* player,angle_t angle,fixed_t move)
65 {
66 angle >>= ANGLETOFINESHIFT;
67 player->mo->momx += FixedMul(move,finecosine[angle]);
68 player->mo->momy += FixedMul(move,finesine[angle]);
69 }
70
71
72/*
73 * P_Bob
74 * Same as P_Thrust, but only affects bobbing.
75 *
76 * killough 10/98: We apply thrust separately between the real physical player
77 * and the part which affects bobbing. This way, bobbing only comes from player
78 * motion, nothing external, avoiding many problems, e.g. bobbing should not
79 * occur on conveyors, unless the player walks on one, and bobbing should be
80 * reduced at a regular rate, even on ice (where the player coasts).
81 */
82
83static void P_Bob(player_t *player, angle_t angle, fixed_t move)
84{
85 //e6y
86 if (!mbf_features)
87 return;
88
89 player->momx += FixedMul(move,finecosine[angle >>= ANGLETOFINESHIFT]);
90 player->momy += FixedMul(move,finesine[angle]);
91}
92
93//
94// P_CalcHeight
95// Calculate the walking / running height adjustment
96//
97
98void P_CalcHeight (player_t* player)
99 {
100 int angle;
101 fixed_t bob;
102
103 // Regular movement bobbing
104 // (needs to be calculated for gun swing
105 // even if not on ground)
106 // OPTIMIZE: tablify angle
107 // Note: a LUT allows for effects
108 // like a ramp with low health.
109
110
111 /* killough 10/98: Make bobbing depend only on player-applied motion.
112 *
113 * Note: don't reduce bobbing here if on ice: if you reduce bobbing here,
114 * it causes bobbing jerkiness when the player moves from ice to non-ice,
115 * and vice-versa.
116 */
117 player->bob = !mbf_features ?
118 (FixedMul (player->mo->momx, player->mo->momx)
119 + FixedMul (player->mo->momy,player->mo->momy))>>2 :
120 player_bobbing ? (FixedMul(player->momx,player->momx) +
121 FixedMul(player->momy,player->momy))>>2 : 0;
122
123 //e6y
124 if (compatibility_level >= boom_202_compatibility &&
125 compatibility_level <= lxdoom_1_compatibility &&
126 player->mo->friction > ORIG_FRICTION) // ice?
127 {
128 if (player->bob > (MAXBOB>>2))
129 player->bob = MAXBOB>>2;
130 }
131 else
132
133 if (player->bob > MAXBOB)
134 player->bob = MAXBOB;
135
136 if (!onground || player->cheats & CF_NOMOMENTUM)
137 {
138 player->viewz = player->mo->z + VIEWHEIGHT;
139
140 if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
141 player->viewz = player->mo->ceilingz-4*FRACUNIT;
142
143// The following line was in the Id source and appears // phares 2/25/98
144// to be a bug. player->viewz is checked in a similar
145// manner at a different exit below.
146
147// player->viewz = player->mo->z + player->viewheight;
148 return;
149 }
150
151 angle = (FINEANGLES/20*leveltime)&FINEMASK;
152 bob = FixedMul(player->bob/2,finesine[angle]);
153
154 // move viewheight
155
156 if (player->playerstate == PST_LIVE)
157 {
158 player->viewheight += player->deltaviewheight;
159
160 if (player->viewheight > VIEWHEIGHT)
161 {
162 player->viewheight = VIEWHEIGHT;
163 player->deltaviewheight = 0;
164 }
165
166 if (player->viewheight < VIEWHEIGHT/2)
167 {
168 player->viewheight = VIEWHEIGHT/2;
169 if (player->deltaviewheight <= 0)
170 player->deltaviewheight = 1;
171 }
172
173 if (player->deltaviewheight)
174 {
175 player->deltaviewheight += FRACUNIT/4;
176 if (!player->deltaviewheight)
177 player->deltaviewheight = 1;
178 }
179 }
180
181 player->viewz = player->mo->z + player->viewheight + bob;
182
183 if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
184 player->viewz = player->mo->ceilingz-4*FRACUNIT;
185 }
186
187
188//
189// P_MovePlayer
190//
191// Adds momentum if the player is not in the air
192//
193// killough 10/98: simplified
194
195void P_MovePlayer (player_t* player)
196{
197 ticcmd_t *cmd = &player->cmd;
198 mobj_t *mo = player->mo;
199
200 mo->angle += cmd->angleturn << 16;
201 onground = mo->z <= mo->floorz;
202
203 // e6y
204 if (demo_smoothturns && player == &players[displayplayer])
205 R_SmoothPlaying_Add(cmd->angleturn << 16);
206
207 // killough 10/98:
208 //
209 // We must apply thrust to the player and bobbing separately, to avoid
210 // anomalies. The thrust applied to bobbing is always the same strength on
211 // ice, because the player still "works just as hard" to move, while the
212 // thrust applied to the movement varies with 'movefactor'.
213
214 //e6y
215 if ((!demo_compatibility && !mbf_features) || (cmd->forwardmove | cmd->sidemove)) // killough 10/98
216 {
217 if (onground || mo->flags & MF_BOUNCES) // killough 8/9/98
218 {
219 int friction, movefactor = P_GetMoveFactor(mo, &friction);
220
221 // killough 11/98:
222 // On sludge, make bobbing depend on efficiency.
223 // On ice, make it depend on effort.
224
225 int bobfactor =
226 friction < ORIG_FRICTION ? movefactor : ORIG_FRICTION_FACTOR;
227
228 if (cmd->forwardmove)
229 {
230 P_Bob(player,mo->angle,cmd->forwardmove*bobfactor);
231 P_Thrust(player,mo->angle,cmd->forwardmove*movefactor);
232 }
233
234 if (cmd->sidemove)
235 {
236 P_Bob(player,mo->angle-ANG90,cmd->sidemove*bobfactor);
237 P_Thrust(player,mo->angle-ANG90,cmd->sidemove*movefactor);
238 }
239 }
240 if (mo->state == states+S_PLAY)
241 P_SetMobjState(mo,S_PLAY_RUN1);
242 }
243}
244
245#define ANG5 (ANG90/18)
246
247//
248// P_DeathThink
249// Fall on your face when dying.
250// Decrease POV height to floor height.
251//
252
253void P_DeathThink (player_t* player)
254 {
255 angle_t angle;
256 angle_t delta;
257
258 P_MovePsprites (player);
259
260 // fall to the ground
261
262 if (player->viewheight > 6*FRACUNIT)
263 player->viewheight -= FRACUNIT;
264
265 if (player->viewheight < 6*FRACUNIT)
266 player->viewheight = 6*FRACUNIT;
267
268 player->deltaviewheight = 0;
269 onground = (player->mo->z <= player->mo->floorz);
270 P_CalcHeight (player);
271
272 if (player->attacker && player->attacker != player->mo)
273 {
274 angle = R_PointToAngle2 (player->mo->x,
275 player->mo->y,
276 player->attacker->x,
277 player->attacker->y);
278
279 delta = angle - player->mo->angle;
280
281 if (delta < ANG5 || delta > (unsigned)-ANG5)
282 {
283 // Looking at killer,
284 // so fade damage flash down.
285
286 player->mo->angle = angle;
287
288 if (player->damagecount)
289 player->damagecount--;
290 }
291 else if (delta < ANG180)
292 player->mo->angle += ANG5;
293 else
294 player->mo->angle -= ANG5;
295 }
296 else if (player->damagecount)
297 player->damagecount--;
298
299 if (player->cmd.buttons & BT_USE)
300 player->playerstate = PST_REBORN;
301 R_SmoothPlaying_Reset(player); // e6y
302 }
303
304
305//
306// P_PlayerThink
307//
308
309void P_PlayerThink (player_t* player)
310 {
311 ticcmd_t* cmd;
312 weapontype_t newweapon;
313
314 if (movement_smooth && players && &players[displayplayer] == player)
315 {
316 original_view_vars.viewx = player->mo->x;
317 original_view_vars.viewy = player->mo->y;
318 original_view_vars.viewz = player->viewz;
319 original_view_vars.viewangle = R_SmoothPlaying_Get(player->mo->angle) + viewangleoffset;
320 }
321
322 // killough 2/8/98, 3/21/98:
323 if (player->cheats & CF_NOCLIP)
324 player->mo->flags |= MF_NOCLIP;
325 else
326 player->mo->flags &= ~MF_NOCLIP;
327
328 // chain saw run forward
329
330 cmd = &player->cmd;
331 if (player->mo->flags & MF_JUSTATTACKED)
332 {
333 cmd->angleturn = 0;
334 cmd->forwardmove = 0xc800/512;
335 cmd->sidemove = 0;
336 player->mo->flags &= ~MF_JUSTATTACKED;
337 }
338
339 if (player->playerstate == PST_DEAD)
340 {
341 P_DeathThink (player);
342 return;
343 }
344
345 // Move around.
346 // Reactiontime is used to prevent movement
347 // for a bit after a teleport.
348
349 if (player->mo->reactiontime)
350 player->mo->reactiontime--;
351 else
352 P_MovePlayer (player);
353
354 P_CalcHeight (player); // Determines view height and bobbing
355
356 // Determine if there's anything about the sector you're in that's
357 // going to affect you, like painful floors.
358
359 if (player->mo->subsector->sector->special)
360 P_PlayerInSpecialSector (player);
361
362 // Check for weapon change.
363
364 if (cmd->buttons & BT_CHANGE)
365 {
366 // The actual changing of the weapon is done
367 // when the weapon psprite can do it
368 // (read: not in the middle of an attack).
369
370 newweapon = (cmd->buttons & BT_WEAPONMASK)>>BT_WEAPONSHIFT;
371
372 // killough 3/22/98: For demo compatibility we must perform the fist
373 // and SSG weapons switches here, rather than in G_BuildTiccmd(). For
374 // other games which rely on user preferences, we must use the latter.
375
376 if (demo_compatibility)
377 { // compatibility mode -- required for old demos -- killough
378 if (newweapon == wp_fist && player->weaponowned[wp_chainsaw] &&
379 (player->readyweapon != wp_chainsaw ||
380 !player->powers[pw_strength]))
381 newweapon = wp_chainsaw;
382 if (gamemode == commercial &&
383 newweapon == wp_shotgun &&
384 player->weaponowned[wp_supershotgun] &&
385 player->readyweapon != wp_supershotgun)
386 newweapon = wp_supershotgun;
387 }
388
389 // killough 2/8/98, 3/22/98 -- end of weapon selection changes
390
391 if (player->weaponowned[newweapon] && newweapon != player->readyweapon)
392
393 // Do not go to plasma or BFG in shareware,
394 // even if cheated.
395
396 if ((newweapon != wp_plasma && newweapon != wp_bfg)
397 || (gamemode != shareware) )
398 player->pendingweapon = newweapon;
399 }
400
401 // check for use
402
403 if (cmd->buttons & BT_USE)
404 {
405 if (!player->usedown)
406 {
407 P_UseLines (player);
408 player->usedown = true;
409 }
410 }
411 else
412 player->usedown = false;
413
414 // cycle psprites
415
416 P_MovePsprites (player);
417
418 // Counters, time dependent power ups.
419
420 // Strength counts up to diminish fade.
421
422 if (player->powers[pw_strength])
423 player->powers[pw_strength]++;
424
425 // killough 1/98: Make idbeholdx toggle:
426
427 if (player->powers[pw_invulnerability] > 0) // killough
428 player->powers[pw_invulnerability]--;
429
430 if (player->powers[pw_invisibility] > 0) // killough
431 if (! --player->powers[pw_invisibility] )
432 player->mo->flags &= ~MF_SHADOW;
433
434 if (player->powers[pw_infrared] > 0) // killough
435 player->powers[pw_infrared]--;
436
437 if (player->powers[pw_ironfeet] > 0) // killough
438 player->powers[pw_ironfeet]--;
439
440 if (player->damagecount)
441 player->damagecount--;
442
443 if (player->bonuscount)
444 player->bonuscount--;
445
446 // Handling colormaps.
447 // killough 3/20/98: reformat to terse C syntax
448
449 player->fixedcolormap = player->powers[pw_invulnerability] > 4*32 ||
450 player->powers[pw_invulnerability] & 8 ? INVERSECOLORMAP :
451 player->powers[pw_infrared] > 4*32 || player->powers[pw_infrared] & 8;
452 }
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Player related stuff.
31 * Bobbing POV/weapon, movement.
32 * Pending weapon.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifndef __P_USER__
37#define __P_USER__
38
39#include "d_player.h"
40
41void P_PlayerThink(player_t *player);
42void P_CalcHeight(player_t *player);
43void P_DeathThink(player_t *player);
44void P_MovePlayer(player_t *player);
45void P_Thrust(player_t *player, angle_t angle, fixed_t move);
46
47#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Doom Network protocol packet definitions.
31 *-----------------------------------------------------------------------------*/
32
33#include "doomtype.h"
34#include "d_ticcmd.h"
35#include "m_swap.h"
36
37enum packet_type_e {
38 PKT_INIT, // initial packet to server
39 PKT_SETUP, // game information packet
40 PKT_GO, // game has started
41 PKT_TICC, // tics from client
42 PKT_TICS, // tics from server
43 PKT_RETRANS, // Request for retransmission
44 PKT_EXTRA, // Extra info packet
45 PKT_QUIT, // Player quit game
46 PKT_DOWN, // Server downed
47 PKT_WAD, // Wad file request
48 PKT_BACKOFF, // Request for client back-off
49};
50
51typedef struct {
52 byte checksum; // Simple checksum of the entire packet
53 byte type; /* Type of packet */
54 byte reserved[2]; /* Was random in prboom <=2.2.4, now 0 */
55 unsigned tic; // Timestamp
56} PACKEDATTR packet_header_t;
57
58static inline void packet_set(packet_header_t* p, enum packet_type_e t, unsigned long tic)
59{ p->tic = doom_htonl(tic); p->type = t; p->reserved[0] = 0; p->reserved[1] = 0; }
60
61#ifndef GAME_OPTIONS_SIZE
62// From g_game.h
63#define GAME_OPTIONS_SIZE 64
64#endif
65
66struct setup_packet_s {
67 byte players, yourplayer, skill, episode, level, deathmatch, complevel, ticdup, extratic;
68 byte game_options[GAME_OPTIONS_SIZE];
69 byte numwads;
70 byte wadnames[1]; // Actually longer
71};
72
73/* cph - convert network byte stream to usable ticcmd_t and visa-versa
74 * - the functions are functionally identical apart from parameters
75 * - the void* param can be unaligned. By using void* as the parameter
76 * it means gcc won't assume alignment so won't make false assumptions
77 * when optimising. So I'm told.
78 */
79inline static void RawToTic(ticcmd_t* dst, const void* src)
80{
81 memcpy(dst,src,sizeof *dst);
82 dst->angleturn = doom_ntohs(dst->angleturn);
83 dst->consistancy = doom_ntohs(dst->consistancy);
84}
85
86inline static void TicToRaw(void* dst, const ticcmd_t* src)
87{
88 /* We have to make a copy of the source struct, then do byte swaps,
89 * and fnially copy to the destination (can't do the swaps in the
90 * destination, because it might not be aligned).
91 */
92 ticcmd_t tmp = *src;
93 tmp.angleturn = doom_ntohs(tmp.angleturn);
94 tmp.consistancy = doom_ntohs(tmp.consistancy);
95 memcpy(dst,&tmp,sizeof tmp);
96}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * BSP traversal, handling of LineSegs for rendering.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "m_bbox.h"
36#include "r_main.h"
37#include "r_segs.h"
38#include "r_plane.h"
39#include "r_things.h"
40#include "r_bsp.h" // cph - sanity checking
41#include "v_video.h"
42#include "lprintf.h"
43
44seg_t *curline;
45side_t *sidedef;
46line_t *linedef;
47sector_t *frontsector;
48sector_t *backsector;
49drawseg_t *ds_p;
50
51// killough 4/7/98: indicates doors closed wrt automap bugfix:
52// cph - replaced by linedef rendering flags - int doorclosed;
53
54// killough: New code which removes 2s linedef limit
55drawseg_t *drawsegs;
56unsigned maxdrawsegs;
57// drawseg_t drawsegs[MAXDRAWSEGS]; // old code -- killough
58
59//
60// R_ClearDrawSegs
61//
62
63void R_ClearDrawSegs(void)
64{
65 ds_p = drawsegs;
66}
67
68// CPhipps -
69// Instead of clipsegs, let's try using an array with one entry for each column,
70// indicating whether it's blocked by a solid wall yet or not.
71
72byte solidcol[MAX_SCREENWIDTH];
73
74// CPhipps -
75// R_ClipWallSegment
76//
77// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those
78// columns which aren't solid, and updates the solidcol[] array appropriately
79
80static void R_ClipWallSegment(int first, int last, boolean solid)
81{
82 byte *p;
83 while (first < last) {
84 if (solidcol[first]) {
85 if (!(p = memchr(solidcol+first, 0, last-first))) return; // All solid
86 first = p - solidcol;
87 } else {
88 int to;
89 if (!(p = memchr(solidcol+first, 1, last-first))) to = last;
90 else to = p - solidcol;
91 R_StoreWallRange(first, to-1);
92 if (solid) {
93 memset(solidcol+first,1,to-first);
94 }
95 first = to;
96 }
97 }
98}
99
100//
101// R_ClearClipSegs
102//
103
104void R_ClearClipSegs (void)
105{
106 memset(solidcol, 0, SCREENWIDTH);
107}
108
109// killough 1/18/98 -- This function is used to fix the automap bug which
110// showed lines behind closed doors simply because the door had a dropoff.
111//
112// cph - converted to R_RecalcLineFlags. This recalculates all the flags for
113// a line, including closure and texture tiling.
114
115static void R_RecalcLineFlags(void)
116{
117 linedef->r_validcount = gametic;
118
119 /* First decide if the line is closed, normal, or invisible */
120 if (!(linedef->flags & ML_TWOSIDED)
121 || backsector->ceilingheight <= frontsector->floorheight
122 || backsector->floorheight >= frontsector->ceilingheight
123 || (
124 // if door is closed because back is shut:
125 backsector->ceilingheight <= backsector->floorheight
126
127 // preserve a kind of transparent door/lift special effect:
128 && (backsector->ceilingheight >= frontsector->ceilingheight ||
129 curline->sidedef->toptexture)
130
131 && (backsector->floorheight <= frontsector->floorheight ||
132 curline->sidedef->bottomtexture)
133
134 // properly render skies (consider door "open" if both ceilings are sky):
135 && (backsector->ceilingpic !=skyflatnum ||
136 frontsector->ceilingpic!=skyflatnum)
137 )
138 )
139 linedef->r_flags = RF_CLOSED;
140 else {
141 // Reject empty lines used for triggers
142 // and special events.
143 // Identical floor and ceiling on both sides,
144 // identical light levels on both sides,
145 // and no middle texture.
146 // CPhipps - recode for speed, not certain if this is portable though
147 if (backsector->ceilingheight != frontsector->ceilingheight
148 || backsector->floorheight != frontsector->floorheight
149 || curline->sidedef->midtexture
150 || memcmp(&backsector->floor_xoffs, &frontsector->floor_xoffs,
151 sizeof(frontsector->floor_xoffs) + sizeof(frontsector->floor_yoffs) +
152 sizeof(frontsector->ceiling_xoffs) + sizeof(frontsector->ceiling_yoffs) +
153 sizeof(frontsector->ceilingpic) + sizeof(frontsector->floorpic) +
154 sizeof(frontsector->lightlevel) + sizeof(frontsector->floorlightsec) +
155 sizeof(frontsector->ceilinglightsec))) {
156 linedef->r_flags = 0; return;
157 } else
158 linedef->r_flags = RF_IGNORE;
159 }
160
161 /* cph - I'm too lazy to try and work with offsets in this */
162 if (curline->sidedef->rowoffset) return;
163
164 /* Now decide on texture tiling */
165 if (linedef->flags & ML_TWOSIDED) {
166 int c;
167
168 /* Does top texture need tiling */
169 if ((c = frontsector->ceilingheight - backsector->ceilingheight) > 0 &&
170 (textureheight[texturetranslation[curline->sidedef->toptexture]] > c))
171 linedef->r_flags |= RF_TOP_TILE;
172
173 /* Does bottom texture need tiling */
174 if ((c = frontsector->floorheight - backsector->floorheight) > 0 &&
175 (textureheight[texturetranslation[curline->sidedef->bottomtexture]] > c))
176 linedef->r_flags |= RF_BOT_TILE;
177 } else {
178 int c;
179 /* Does middle texture need tiling */
180 if ((c = frontsector->ceilingheight - frontsector->floorheight) > 0 &&
181 (textureheight[texturetranslation[curline->sidedef->midtexture]] > c))
182 linedef->r_flags |= RF_MID_TILE;
183 }
184}
185
186//
187// killough 3/7/98: Hack floor/ceiling heights for deep water etc.
188//
189// If player's view height is underneath fake floor, lower the
190// drawn ceiling to be just under the floor height, and replace
191// the drawn floor and ceiling textures, and light level, with
192// the control sector's.
193//
194// Similar for ceiling, only reflected.
195//
196// killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter
197//
198
199sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec,
200 int *floorlightlevel, int *ceilinglightlevel,
201 boolean back)
202{
203 if (floorlightlevel)
204 *floorlightlevel = sec->floorlightsec == -1 ?
205 sec->lightlevel : sectors[sec->floorlightsec].lightlevel;
206
207 if (ceilinglightlevel)
208 *ceilinglightlevel = sec->ceilinglightsec == -1 ? // killough 4/11/98
209 sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel;
210
211 if (sec->heightsec != -1)
212 {
213 const sector_t *s = &sectors[sec->heightsec];
214 int heightsec = viewplayer->mo->subsector->sector->heightsec;
215 int underwater = heightsec!=-1 && viewz<=sectors[heightsec].floorheight;
216
217 // Replace sector being drawn, with a copy to be hacked
218 *tempsec = *sec;
219
220 // Replace floor and ceiling height with other sector's heights.
221 tempsec->floorheight = s->floorheight;
222 tempsec->ceilingheight = s->ceilingheight;
223
224 // killough 11/98: prevent sudden light changes from non-water sectors:
225 if (underwater && (tempsec-> floorheight = sec->floorheight,
226 tempsec->ceilingheight = s->floorheight-1, !back))
227 { // head-below-floor hack
228 tempsec->floorpic = s->floorpic;
229 tempsec->floor_xoffs = s->floor_xoffs;
230 tempsec->floor_yoffs = s->floor_yoffs;
231
232 if (underwater) {
233 if (s->ceilingpic == skyflatnum) {
234 tempsec->floorheight = tempsec->ceilingheight+1;
235 tempsec->ceilingpic = tempsec->floorpic;
236 tempsec->ceiling_xoffs = tempsec->floor_xoffs;
237 tempsec->ceiling_yoffs = tempsec->floor_yoffs;
238 } else {
239 tempsec->ceilingpic = s->ceilingpic;
240 tempsec->ceiling_xoffs = s->ceiling_xoffs;
241 tempsec->ceiling_yoffs = s->ceiling_yoffs;
242 }
243 }
244
245 tempsec->lightlevel = s->lightlevel;
246
247 if (floorlightlevel)
248 *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel :
249 sectors[s->floorlightsec].lightlevel; // killough 3/16/98
250
251 if (ceilinglightlevel)
252 *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel :
253 sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98
254 }
255 else
256 if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight &&
257 sec->ceilingheight > s->ceilingheight)
258 { // Above-ceiling hack
259 tempsec->ceilingheight = s->ceilingheight;
260 tempsec->floorheight = s->ceilingheight + 1;
261
262 tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic;
263 tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs;
264 tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs;
265
266 if (s->floorpic != skyflatnum)
267 {
268 tempsec->ceilingheight = sec->ceilingheight;
269 tempsec->floorpic = s->floorpic;
270 tempsec->floor_xoffs = s->floor_xoffs;
271 tempsec->floor_yoffs = s->floor_yoffs;
272 }
273
274 tempsec->lightlevel = s->lightlevel;
275
276 if (floorlightlevel)
277 *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel :
278 sectors[s->floorlightsec].lightlevel; // killough 3/16/98
279
280 if (ceilinglightlevel)
281 *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel :
282 sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98
283 }
284 sec = tempsec; // Use other sector
285 }
286 return sec;
287}
288
289//
290// R_AddLine
291// Clips the given segment
292// and adds any visible pieces to the line list.
293//
294
295static void R_AddLine (seg_t *line)
296{
297 int x1;
298 int x2;
299 angle_t angle1;
300 angle_t angle2;
301 angle_t span;
302 angle_t tspan;
303 static sector_t tempsec; // killough 3/8/98: ceiling/water hack
304
305 curline = line;
306
307 angle1 = R_PointToAngle (line->v1->x, line->v1->y);
308 angle2 = R_PointToAngle (line->v2->x, line->v2->y);
309
310 // Clip to view edges.
311 span = angle1 - angle2;
312
313 // Back side, i.e. backface culling
314 if (span >= ANG180)
315 return;
316
317 // Global angle needed by segcalc.
318 rw_angle1 = angle1;
319 angle1 -= viewangle;
320 angle2 -= viewangle;
321
322 tspan = angle1 + clipangle;
323 if (tspan > 2*clipangle)
324 {
325 tspan -= 2*clipangle;
326
327 // Totally off the left edge?
328 if (tspan >= span)
329 return;
330
331 angle1 = clipangle;
332 }
333
334 tspan = clipangle - angle2;
335 if (tspan > 2*clipangle)
336 {
337 tspan -= 2*clipangle;
338
339 // Totally off the left edge?
340 if (tspan >= span)
341 return;
342 angle2 = 0-clipangle;
343 }
344
345 // The seg is in the view range,
346 // but not necessarily visible.
347
348 angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
349 angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
350
351 // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur:
352 x1 = viewangletox[angle1];
353 x2 = viewangletox[angle2];
354
355#ifdef GL_DOOM
356 // proff 11/99: we have to add these segs to avoid gaps in OpenGL
357 if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness
358 {
359 if (V_GetMode() == VID_MODEGL)
360 {
361 if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM
362 {
363 unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a
364 unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough
365 drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs));
366 //ds_p = drawsegs+maxdrawsegs;
367 ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a
368 maxdrawsegs = newmax;
369 }
370 ds_p->curline = curline;
371 ds_p++;
372 gld_AddWall(curline);
373 return;
374 }
375 else
376 return;
377 }
378#else
379 // Does not cross a pixel?
380 if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness
381 return;
382#endif
383
384 backsector = line->backsector;
385
386 // Single sided line?
387 if (backsector)
388 // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
389 backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true);
390
391 /* cph - roll up linedef properties in flags */
392 if ((linedef = curline->linedef)->r_validcount != gametic)
393 R_RecalcLineFlags();
394
395 if (linedef->r_flags & RF_IGNORE)
396 {
397 return;
398 }
399 else
400 R_ClipWallSegment (x1, x2, linedef->r_flags & RF_CLOSED);
401}
402
403//
404// R_CheckBBox
405// Checks BSP node/subtree bounding box.
406// Returns true
407// if some part of the bbox might be visible.
408//
409
410static const int checkcoord[12][4] = // killough -- static const
411{
412 {3,0,2,1},
413 {3,0,2,0},
414 {3,1,2,0},
415 {0},
416 {2,0,2,1},
417 {0,0,0,0},
418 {3,1,3,0},
419 {0},
420 {2,0,3,1},
421 {2,1,3,1},
422 {2,1,3,0}
423};
424
425// killough 1/28/98: static // CPhipps - const parameter, reformatted
426static boolean R_CheckBBox(const fixed_t *bspcoord)
427{
428 angle_t angle1, angle2;
429
430 {
431 int boxpos;
432 const int* check;
433
434 // Find the corners of the box
435 // that define the edges from current viewpoint.
436 boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) +
437 (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8);
438
439 if (boxpos == 5)
440 return true;
441
442 check = checkcoord[boxpos];
443 angle1 = R_PointToAngle (bspcoord[check[0]], bspcoord[check[1]]) - viewangle;
444 angle2 = R_PointToAngle (bspcoord[check[2]], bspcoord[check[3]]) - viewangle;
445 }
446
447 // cph - replaced old code, which was unclear and badly commented
448 // Much more efficient code now
449 if ((signed)angle1 < (signed)angle2) { /* it's "behind" us */
450 /* Either angle1 or angle2 is behind us, so it doesn't matter if we
451 * change it to the corect sign
452 */
453 if ((angle1 >= ANG180) && (angle1 < ANG270))
454 angle1 = INT_MAX; /* which is ANG180-1 */
455 else
456 angle2 = INT_MIN;
457 }
458
459 if ((signed)angle2 >= (signed)clipangle) return false; // Both off left edge
460 if ((signed)angle1 <= -(signed)clipangle) return false; // Both off right edge
461 if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; // Clip at left edge
462 if ((signed)angle2 <= -(signed)clipangle) angle2 = 0-clipangle; // Clip at right edge
463
464 // Find the first clippost
465 // that touches the source post
466 // (adjacent pixels are touching).
467 angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
468 angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
469 {
470 int sx1 = viewangletox[angle1];
471 int sx2 = viewangletox[angle2];
472 // const cliprange_t *start;
473
474 // Does not cross a pixel.
475 if (sx1 == sx2)
476 return false;
477
478 if (!memchr(solidcol+sx1, 0, sx2-sx1)) return false;
479 // All columns it covers are already solidly covered
480 }
481
482 return true;
483}
484
485//
486// R_Subsector
487// Determine floor/ceiling planes.
488// Add sprites of things in sector.
489// Draw one or more line segments.
490//
491// killough 1/31/98 -- made static, polished
492
493static void R_Subsector(int num)
494{
495 int count;
496 seg_t *line;
497 subsector_t *sub;
498 sector_t tempsec; // killough 3/7/98: deep water hack
499 int floorlightlevel; // killough 3/16/98: set floor lightlevel
500 int ceilinglightlevel; // killough 4/11/98
501#ifdef GL_DOOM
502 visplane_t dummyfloorplane;
503 visplane_t dummyceilingplane;
504#endif
505
506#ifdef RANGECHECK
507 if (num>=numsubsectors)
508 I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors);
509#endif
510
511 sub = &subsectors[num];
512 frontsector = sub->sector;
513 count = sub->numlines;
514 line = &segs[sub->firstline];
515
516 // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
517 frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
518 &ceilinglightlevel, false); // killough 4/11/98
519
520 // killough 3/7/98: Add (x,y) offsets to flats, add deep water check
521 // killough 3/16/98: add floorlightlevel
522 // killough 10/98: add support for skies transferred from sidedefs
523
524 floorplane = frontsector->floorheight < viewz || // killough 3/7/98
525 (frontsector->heightsec != -1 &&
526 sectors[frontsector->heightsec].ceilingpic == skyflatnum) ?
527 R_FindPlane(frontsector->floorheight,
528 frontsector->floorpic == skyflatnum && // kilough 10/98
529 frontsector->sky & PL_SKYFLAT ? frontsector->sky :
530 frontsector->floorpic,
531 floorlightlevel, // killough 3/16/98
532 frontsector->floor_xoffs, // killough 3/7/98
533 frontsector->floor_yoffs
534 ) : NULL;
535
536 ceilingplane = frontsector->ceilingheight > viewz ||
537 frontsector->ceilingpic == skyflatnum ||
538 (frontsector->heightsec != -1 &&
539 sectors[frontsector->heightsec].floorpic == skyflatnum) ?
540 R_FindPlane(frontsector->ceilingheight, // killough 3/8/98
541 frontsector->ceilingpic == skyflatnum && // kilough 10/98
542 frontsector->sky & PL_SKYFLAT ? frontsector->sky :
543 frontsector->ceilingpic,
544 ceilinglightlevel, // killough 4/11/98
545 frontsector->ceiling_xoffs, // killough 3/7/98
546 frontsector->ceiling_yoffs
547 ) : NULL;
548#ifdef GL_DOOM
549 // check if the sector is faked
550 if ((frontsector==sub->sector) && (V_GetMode() == VID_MODEGL))
551 {
552 // if the sector has bottomtextures, then the floorheight will be set to the
553 // highest surounding floorheight
554 if ((frontsector->no_bottomtextures) || (!floorplane))
555 {
556 int i=frontsector->linecount;
557
558 dummyfloorplane.height=INT_MIN;
559 while (i--)
560 {
561 line_t *tmpline=frontsector->lines[i];
562 if (tmpline->backsector)
563 if (tmpline->backsector != frontsector)
564 if (tmpline->backsector->floorheight>dummyfloorplane.height)
565 {
566 dummyfloorplane.height=tmpline->backsector->floorheight;
567 dummyfloorplane.lightlevel=tmpline->backsector->lightlevel;
568 }
569 if (tmpline->frontsector)
570 if (tmpline->frontsector != frontsector)
571 if (tmpline->frontsector->floorheight>dummyfloorplane.height)
572 {
573 dummyfloorplane.height=tmpline->frontsector->floorheight;
574 dummyfloorplane.lightlevel=tmpline->frontsector->lightlevel;
575 }
576 }
577 if (dummyfloorplane.height!=INT_MIN)
578 floorplane=&dummyfloorplane;
579 }
580 // the same for ceilings. they will be set to the lowest ceilingheight
581 if ((frontsector->no_toptextures) || (!ceilingplane))
582 {
583 int i=frontsector->linecount;
584
585 dummyceilingplane.height=INT_MAX;
586 while (i--)
587 {
588 line_t *tmpline=frontsector->lines[i];
589 if (tmpline->backsector)
590 if (tmpline->backsector != frontsector)
591 if (tmpline->backsector->ceilingheight<dummyceilingplane.height)
592 {
593 dummyceilingplane.height=tmpline->backsector->ceilingheight;
594 dummyceilingplane.lightlevel=tmpline->backsector->lightlevel;
595 }
596 if (tmpline->frontsector)
597 if (tmpline->frontsector != frontsector)
598 if (tmpline->frontsector->ceilingheight<dummyceilingplane.height)
599 {
600 dummyceilingplane.height=tmpline->frontsector->ceilingheight;
601 dummyceilingplane.lightlevel=tmpline->frontsector->lightlevel;
602 }
603 }
604 if (dummyceilingplane.height!=INT_MAX)
605 ceilingplane=&dummyceilingplane;
606 }
607 }
608#endif
609
610 // killough 9/18/98: Fix underwater slowdown, by passing real sector
611 // instead of fake one. Improve sprite lighting by basing sprite
612 // lightlevels on floor & ceiling lightlevels in the surrounding area.
613 //
614 // 10/98 killough:
615 //
616 // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!!
617 // That is part of the 242 effect!!! If you simply pass sub->sector to
618 // the old code you will not get correct lighting for underwater sprites!!!
619 // Either you must pass the fake sector and handle validcount here, on the
620 // real sector, or you must account for the lighting in some other way,
621 // like passing it as an argument.
622
623 R_AddSprites(sub, (floorlightlevel+ceilinglightlevel)/2);
624 while (count--)
625 {
626 if (line->miniseg == false)
627 R_AddLine (line);
628 line++;
629 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 */
630 }
631#ifdef GL_DOOM
632 if (V_GetMode() == VID_MODEGL)
633 gld_AddPlane(num, floorplane, ceilingplane);
634#endif
635}
636
637//
638// RenderBSPNode
639// Renders all subsectors below a given node,
640// traversing subtree recursively.
641// Just call with BSP root.
642//
643// killough 5/2/98: reformatted, removed tail recursion
644
645void R_RenderBSPNode(int bspnum)
646{
647 while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
648 {
649 const node_t *bsp = &nodes[bspnum];
650
651 // Decide which side the view point is on.
652 int side = R_PointOnSide(viewx, viewy, bsp);
653 // Recursively divide front space.
654 R_RenderBSPNode(bsp->children[side]);
655
656 // Possibly divide back space.
657
658 if (!R_CheckBBox(bsp->bbox[side^1]))
659 return;
660
661 bspnum = bsp->children[side^1];
662 }
663 R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
664}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Refresh module, BSP traversal and handling.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_BSP__
35#define __R_BSP__
36
37#ifdef __GNUG__
38#pragma interface
39#endif
40
41extern seg_t *curline;
42extern side_t *sidedef;
43extern line_t *linedef;
44extern sector_t *frontsector;
45extern sector_t *backsector;
46
47/* old code -- killough:
48 * extern drawseg_t drawsegs[MAXDRAWSEGS];
49 * new code -- killough: */
50extern drawseg_t *drawsegs;
51extern unsigned maxdrawsegs;
52
53extern byte solidcol[MAX_SCREENWIDTH];
54
55extern drawseg_t *ds_p;
56
57void R_ClearClipSegs(void);
58void R_ClearDrawSegs(void);
59void R_RenderBSPNode(int bspnum);
60
61/* killough 4/13/98: fake floors/ceilings for deep water / fake ceilings: */
62sector_t *R_FakeFlat(sector_t *, sector_t *, int *, int *, boolean);
63
64#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Preparation of data for rendering,
31 * generation of lookups, caching, retrieval by name.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#include "doomstat.h"
36#include "w_wad.h"
37#include "r_draw.h"
38#include "r_main.h"
39#include "r_sky.h"
40#include "i_system.h"
41#include "r_bsp.h"
42#include "r_things.h"
43#include "p_tick.h"
44#include "lprintf.h" // jff 08/03/98 - declaration of lprintf
45#include "p_tick.h"
46
47//
48// Graphics.
49// DOOM graphics for walls and sprites
50// is stored in vertical runs of opaque pixels (posts).
51// A column is composed of zero or more posts,
52// a patch or sprite is composed of zero or more columns.
53//
54
55//
56// Texture definition.
57// Each texture is composed of one or more patches,
58// with patches being lumps stored in the WAD.
59// The lumps are referenced by number, and patched
60// into the rectangular texture space using origin
61// and possibly other attributes.
62//
63
64typedef struct
65{
66 short originx;
67 short originy;
68 short patch;
69 short stepdir; // unused in Doom but might be used in Phase 2 Boom
70 short colormap; // unused in Doom but might be used in Phase 2 Boom
71} PACKEDATTR mappatch_t;
72
73
74typedef struct
75{
76 char name[8];
77 char pad2[4]; // unused
78 short width;
79 short height;
80 char pad[4]; // unused in Doom but might be used in Boom Phase 2
81 short patchcount;
82 mappatch_t patches[1];
83} PACKEDATTR maptexture_t;
84
85// A maptexturedef_t describes a rectangular texture, which is composed
86// of one or more mappatch_t structures that arrange graphic patches.
87
88// killough 4/17/98: make firstcolormaplump,lastcolormaplump external
89int firstcolormaplump, lastcolormaplump; // killough 4/17/98
90
91int firstflat, lastflat, numflats;
92int firstspritelump, lastspritelump, numspritelumps;
93int numtextures;
94texture_t **textures; // proff - 04/05/2000 removed static for OpenGL
95fixed_t *textureheight; //needed for texture pegging (and TFE fix - killough)
96int *flattranslation; // for global animation
97int *texturetranslation;
98
99//
100// R_GetTextureColumn
101//
102
103const byte *R_GetTextureColumn(const rpatch_t *texpatch, int col) {
104 while (col < 0)
105 col += texpatch->width;
106 col &= texpatch->widthmask;
107
108 return texpatch->columns[col].pixels;
109}
110
111//
112// R_InitTextures
113// Initializes the texture list
114// with the textures from the world map.
115//
116
117static void R_InitTextures (void)
118{
119 const maptexture_t *mtexture;
120 texture_t *texture;
121 const mappatch_t *mpatch;
122 texpatch_t *patch;
123 int i, j;
124 int maptex_lump[2] = {-1, -1};
125 const int *maptex;
126 const int *maptex1, *maptex2;
127 char name[9];
128 int names_lump; // cph - new wad lump handling
129 const char *names; // cph -
130 const char *name_p;// const*'s
131 int *patchlookup;
132 int totalwidth;
133 int nummappatches;
134 int offset;
135 int maxoff, maxoff2;
136 int numtextures1, numtextures2;
137 const int *directory;
138 int errors = 0;
139
140 // Load the patch names from pnames.lmp.
141 name[8] = 0;
142 names = W_CacheLumpNum(names_lump = W_GetNumForName("PNAMES"));
143 nummappatches = LONG(*((const int *)names));
144 name_p = names+4;
145 patchlookup = malloc(nummappatches*sizeof(*patchlookup)); // killough
146
147 for (i=0 ; i<nummappatches ; i++)
148 {
149 strncpy (name,name_p+i*8, 8);
150 patchlookup[i] = W_CheckNumForName(name);
151 if (patchlookup[i] == -1)
152 {
153 // killough 4/17/98:
154 // Some wads use sprites as wall patches, so repeat check and
155 // look for sprites this time, but only if there were no wall
156 // patches found. This is the same as allowing for both, except
157 // that wall patches always win over sprites, even when they
158 // appear first in a wad. This is a kludgy solution to the wad
159 // lump namespace problem.
160
161 patchlookup[i] = (W_CheckNumForName)(name, ns_sprites);
162
163 if (patchlookup[i] == -1 && devparm)
164 //jff 8/3/98 use logical output routine
165 lprintf(LO_WARN,"\nWarning: patch %.8s, index %d does not exist",name,i);
166 }
167 }
168 W_UnlockLumpNum(names_lump); // cph - release the lump
169
170 // Load the map texture definitions from textures.lmp.
171 // The data is contained in one or two lumps,
172 // TEXTURE1 for shareware, plus TEXTURE2 for commercial.
173
174 maptex = maptex1 = W_CacheLumpNum(maptex_lump[0] = W_GetNumForName("TEXTURE1"));
175 numtextures1 = LONG(*maptex);
176 maxoff = W_LumpLength(maptex_lump[0]);
177 directory = maptex+1;
178
179 if (W_CheckNumForName("TEXTURE2") != -1)
180 {
181 maptex2 = W_CacheLumpNum(maptex_lump[1] = W_GetNumForName("TEXTURE2"));
182 numtextures2 = LONG(*maptex2);
183 maxoff2 = W_LumpLength(maptex_lump[1]);
184 }
185 else
186 {
187 maptex2 = NULL;
188 numtextures2 = 0;
189 maxoff2 = 0;
190 }
191 numtextures = numtextures1 + numtextures2;
192
193 // killough 4/9/98: make column offsets 32-bit;
194 // clean up malloc-ing to use sizeof
195
196 textures = Z_Malloc(numtextures*sizeof*textures, PU_STATIC, 0);
197 textureheight = Z_Malloc(numtextures*sizeof*textureheight, PU_STATIC, 0);
198
199 totalwidth = 0;
200
201 for (i=0 ; i<numtextures ; i++, directory++)
202 {
203 if (i == numtextures1)
204 {
205 // Start looking in second texture file.
206 maptex = maptex2;
207 maxoff = maxoff2;
208 directory = maptex+1;
209 }
210
211 offset = LONG(*directory);
212
213 if (offset > maxoff)
214 I_Error("R_InitTextures: Bad texture directory");
215
216 mtexture = (const maptexture_t *) ( (const byte *)maptex + offset);
217
218 texture = textures[i] =
219 Z_Malloc(sizeof(texture_t) +
220 sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1),
221 PU_STATIC, 0);
222
223 texture->width = SHORT(mtexture->width);
224 texture->height = SHORT(mtexture->height);
225 texture->patchcount = SHORT(mtexture->patchcount);
226
227 /* Mattias Engdegård emailed me of the following explenation of
228 * why memcpy doesnt work on some systems:
229 * "I suppose it is the mad unaligned allocation
230 * going on (and which gcc in some way manages to cope with
231 * through the __attribute__ ((packed))), and which it forgets
232 * when optimizing memcpy (to a single word move) since it appears
233 * to be aligned. Technically a gcc bug, but I can't blame it when
234 * it's stressed with that amount of
235 * non-standard nonsense."
236 * So in short the unaligned struct confuses gcc's optimizer so
237 * i took the memcpy out alltogether to avoid future problems-Jess
238 */
239 /* The above was #ifndef SPARC, but i got a mail from
240 * Putera Joseph F NPRI <PuteraJF@Npt.NUWC.Navy.Mil> containing:
241 * I had to use the memcpy function on a sparc machine. The
242 * other one would give me a core dump.
243 * cph - I find it hard to believe that sparc memcpy is broken,
244 * but I don't believe the pointers to memcpy have to be aligned
245 * either. Use fast memcpy on other machines anyway.
246 */
247/*
248 proff - I took this out, because Oli Kraus (olikraus@yahoo.com) told
249 me the memcpy produced a buserror. Since this function isn't time-
250 critical I'm using the for loop now.
251*/
252/*
253#ifndef GCC
254 memcpy(texture->name, mtexture->name, sizeof(texture->name));
255#else
256*/
257 {
258 int j;
259 for(j=0;j<sizeof(texture->name);j++)
260 texture->name[j]=mtexture->name[j];
261 }
262/* #endif */
263
264 mpatch = mtexture->patches;
265 patch = texture->patches;
266
267 for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++)
268 {
269 patch->originx = SHORT(mpatch->originx);
270 patch->originy = SHORT(mpatch->originy);
271 patch->patch = patchlookup[SHORT(mpatch->patch)];
272 if (patch->patch == -1)
273 {
274 //jff 8/3/98 use logical output routine
275 lprintf(LO_ERROR,"\nR_InitTextures: Missing patch %d in texture %.8s",
276 SHORT(mpatch->patch), texture->name); // killough 4/17/98
277 ++errors;
278 }
279 }
280
281 for (j=1; j*2 <= texture->width; j<<=1)
282 ;
283 texture->widthmask = j-1;
284 textureheight[i] = texture->height<<FRACBITS;
285
286 totalwidth += texture->width;
287 }
288
289 free(patchlookup); // killough
290
291 for (i=0; i<2; i++) // cph - release the TEXTUREx lumps
292 if (maptex_lump[i] != -1)
293 W_UnlockLumpNum(maptex_lump[i]);
294
295 if (errors)
296 I_Error("R_InitTextures: %d errors", errors);
297
298 // Precalculate whatever possible.
299 if (devparm) // cph - If in development mode, generate now so all errors are found at once
300 for (i=0 ; i<numtextures ; i++)
301 {
302 // proff - This is for the new renderer now
303 R_CacheTextureCompositePatchNum(i);
304 R_UnlockTextureCompositePatchNum(i);
305 }
306
307 if (errors)
308 I_Error("R_InitTextures: %d errors", errors);
309
310 // Create translation table for global animation.
311 // killough 4/9/98: make column offsets 32-bit;
312 // clean up malloc-ing to use sizeof
313
314 texturetranslation =
315 Z_Malloc((numtextures+1)*sizeof*texturetranslation, PU_STATIC, 0);
316
317 for (i=0 ; i<numtextures ; i++)
318 texturetranslation[i] = i;
319
320 // killough 1/31/98: Initialize texture hash table
321 for (i = 0; i<numtextures; i++)
322 textures[i]->index = -1;
323 while (--i >= 0)
324 {
325 int j = W_LumpNameHash(textures[i]->name) % (unsigned) numtextures;
326 textures[i]->next = textures[j]->index; // Prepend to chain
327 textures[j]->index = i;
328 }
329}
330
331//
332// R_InitFlats
333//
334static void R_InitFlats(void)
335{
336 int i;
337
338 firstflat = W_GetNumForName("F_START") + 1;
339 lastflat = W_GetNumForName("F_END") - 1;
340 numflats = lastflat - firstflat + 1;
341
342 // Create translation table for global animation.
343 // killough 4/9/98: make column offsets 32-bit;
344 // clean up malloc-ing to use sizeof
345
346 flattranslation =
347 Z_Malloc((numflats+1)*sizeof(*flattranslation), PU_STATIC, 0);
348
349 for (i=0 ; i<numflats ; i++)
350 flattranslation[i] = i;
351}
352
353//
354// R_InitSpriteLumps
355// Finds the width and hoffset of all sprites in the wad,
356// so the sprite does not need to be cached completely
357// just for having the header info ready during rendering.
358//
359static void R_InitSpriteLumps(void)
360{
361 firstspritelump = W_GetNumForName("S_START") + 1;
362 lastspritelump = W_GetNumForName("S_END") - 1;
363 numspritelumps = lastspritelump - firstspritelump + 1;
364}
365
366//
367// R_InitColormaps
368//
369// killough 3/20/98: rewritten to allow dynamic colormaps
370// and to remove unnecessary 256-byte alignment
371//
372// killough 4/4/98: Add support for C_START/C_END markers
373//
374
375static void R_InitColormaps(void)
376{
377 int i;
378 firstcolormaplump = W_GetNumForName("C_START");
379 lastcolormaplump = W_GetNumForName("C_END");
380 numcolormaps = lastcolormaplump - firstcolormaplump;
381 colormaps = Z_Malloc(sizeof(*colormaps) * numcolormaps, PU_STATIC, 0);
382 colormaps[0] = (const lighttable_t *)W_CacheLumpName("COLORMAP");
383 for (i=1; i<numcolormaps; i++)
384 colormaps[i] = (const lighttable_t *)W_CacheLumpNum(i+firstcolormaplump);
385 // cph - always lock
386}
387
388// killough 4/4/98: get colormap number from name
389// killough 4/11/98: changed to return -1 for illegal names
390// killough 4/17/98: changed to use ns_colormaps tag
391
392int R_ColormapNumForName(const char *name)
393{
394 register int i = 0;
395 if (strncasecmp(name,"COLORMAP",8)) // COLORMAP predefined to return 0
396 if ((i = (W_CheckNumForName)(name, ns_colormaps)) != -1)
397 i -= firstcolormaplump;
398 return i;
399}
400
401/*
402 * R_ColourMap
403 *
404 * cph 2001/11/17 - unify colour maping logic in a single place;
405 * obsoletes old c_scalelight stuff
406 */
407
408static inline int between(int l,int u,int x)
409{ return (l > x ? l : x > u ? u : x); }
410
411const lighttable_t* R_ColourMap(int lightlevel, fixed_t spryscale)
412{
413 if (fixedcolormap) return fixedcolormap;
414 else {
415 if (curline)
416 if (curline->v1->y == curline->v2->y)
417 lightlevel -= 1 << LIGHTSEGSHIFT;
418 else
419 if (curline->v1->x == curline->v2->x)
420 lightlevel += 1 << LIGHTSEGSHIFT;
421
422 lightlevel += extralight << LIGHTSEGSHIFT;
423
424 /* cph 2001/11/17 -
425 * Work out what colour map to use, remembering to clamp it to the number of
426 * colour maps we actually have. This formula is basically the one from the
427 * original source, just brought into one place. The main difference is it
428 * throws away less precision in the lightlevel half, so it supports 32
429 * light levels in WADs compared to Doom's 16.
430 *
431 * Note we can make it more accurate if we want - we should keep all the
432 * precision until the final step, so slight scale differences can count
433 * against slight light level variations.
434 */
435 return fullcolormap + between(0,NUMCOLORMAPS-1,
436 ((256-lightlevel)*2*NUMCOLORMAPS/256) - 4
437 - (FixedMul(spryscale,pspriteiscale)/2 >> LIGHTSCALESHIFT)
438 )*256;
439 }
440}
441
442//
443// R_InitTranMap
444//
445// Initialize translucency filter map
446//
447// By Lee Killough 2/21/98
448//
449
450int tran_filter_pct = 66; // filter percent
451
452#define TSC 12 /* number of fixed point digits in filter percent */
453
454void R_InitTranMap(int progress)
455{
456 int lump = W_CheckNumForName("TRANMAP");
457
458 // If a tranlucency filter map lump is present, use it
459
460 if (lump != -1) // Set a pointer to the translucency filter maps.
461 main_tranmap = W_CacheLumpNum(lump); // killough 4/11/98
462 else if (W_CheckNumForName("PLAYPAL")!=-1) // can be called before WAD loaded
463 { // Compose a default transparent filter map based on PLAYPAL.
464 const byte *playpal = W_CacheLumpName("PLAYPAL");
465 byte *my_tranmap;
466
467 char fname[PATH_MAX+1];
468 struct {
469 unsigned char pct;
470 unsigned char playpal[256];
471 } cache;
472 FILE *cachefp = fopen(strcat(strcpy(fname, I_DoomExeDir()), "/tranmap.dat"),"rb");
473
474 main_tranmap = my_tranmap = Z_Malloc(256*256, PU_STATIC, 0); // killough 4/11/98
475
476 // Use cached translucency filter if it's available
477
478 if (!cachefp ||
479 fread(&cache, 1, sizeof cache, cachefp) != sizeof cache ||
480 cache.pct != tran_filter_pct ||
481 memcmp(cache.playpal, playpal, sizeof cache.playpal) ||
482 fread(my_tranmap, 256, 256, cachefp) != 256 ) // killough 4/11/98
483 {
484 long pal[3][256], tot[256], pal_w1[3][256];
485 long w1 = ((unsigned long) tran_filter_pct<<TSC)/100;
486 long w2 = (1l<<TSC)-w1;
487
488 if (progress)
489 lprintf(LO_INFO, "Tranmap build [ ]\x08\x08\x08\x08\x08\x08\x08\x08\x08");
490
491 // First, convert playpal into long int type, and transpose array,
492 // for fast inner-loop calculations. Precompute tot array.
493
494 {
495 register int i = 255;
496 register const unsigned char *p = playpal+255*3;
497 do
498 {
499 register long t,d;
500 pal_w1[0][i] = (pal[0][i] = t = p[0]) * w1;
501 d = t*t;
502 pal_w1[1][i] = (pal[1][i] = t = p[1]) * w1;
503 d += t*t;
504 pal_w1[2][i] = (pal[2][i] = t = p[2]) * w1;
505 d += t*t;
506 p -= 3;
507 tot[i] = d << (TSC-1);
508 }
509 while (--i>=0);
510 }
511
512 // Next, compute all entries using minimum arithmetic.
513
514 {
515 int i,j;
516 byte *tp = my_tranmap;
517 for (i=0;i<256;i++)
518 {
519 long r1 = pal[0][i] * w2;
520 long g1 = pal[1][i] * w2;
521 long b1 = pal[2][i] * w2;
522 if (!(i & 31) && progress)
523 //jff 8/3/98 use logical output routine
524 lprintf(LO_INFO,".");
525 for (j=0;j<256;j++,tp++)
526 {
527 register int color = 255;
528 register long err;
529 long r = pal_w1[0][j] + r1;
530 long g = pal_w1[1][j] + g1;
531 long b = pal_w1[2][j] + b1;
532 long best = LONG_MAX;
533 do
534 if ((err = tot[color] - pal[0][color]*r
535 - pal[1][color]*g - pal[2][color]*b) < best)
536 best = err, *tp = color;
537 while (--color >= 0);
538 }
539 }
540 }
541 if ((cachefp = fopen(fname,"wb")) != NULL) // write out the cached translucency map
542 {
543 cache.pct = tran_filter_pct;
544 memcpy(cache.playpal, playpal, 256);
545 fseek(cachefp, 0, SEEK_SET);
546 fwrite(&cache, 1, sizeof cache, cachefp);
547 fwrite(main_tranmap, 256, 256, cachefp);
548 // CPhipps - leave close for a few lines...
549 }
550 }
551
552 if (cachefp) // killough 11/98: fix filehandle leak
553 fclose(cachefp);
554
555 W_UnlockLumpName("PLAYPAL");
556 }
557}
558
559//
560// R_InitData
561// Locates all the lumps
562// that will be used by all views
563// Must be called after W_Init.
564//
565
566void R_InitData(void)
567{
568 lprintf(LO_INFO, "Textures ");
569 R_InitTextures();
570 lprintf(LO_INFO, "Flats ");
571 R_InitFlats();
572 lprintf(LO_INFO, "Sprites ");
573 R_InitSpriteLumps();
574 if (default_translucency) // killough 3/1/98
575 R_InitTranMap(1); // killough 2/21/98, 3/6/98
576 R_InitColormaps(); // killough 3/20/98
577}
578
579//
580// R_FlatNumForName
581// Retrieval, get a flat number for a flat name.
582//
583// killough 4/17/98: changed to use ns_flats namespace
584//
585
586int R_FlatNumForName(const char *name) // killough -- const added
587{
588 int i = (W_CheckNumForName)(name, ns_flats);
589 if (i == -1)
590 I_Error("R_FlatNumForName: %.8s not found", name);
591 return i - firstflat;
592}
593
594//
595// R_CheckTextureNumForName
596// Check whether texture is available.
597// Filter out NoTexture indicator.
598//
599// Rewritten by Lee Killough to use hash table for fast lookup. Considerably
600// reduces the time needed to start new levels. See w_wad.c for comments on
601// the hashing algorithm, which is also used for lump searches.
602//
603// killough 1/21/98, 1/31/98
604//
605
606int PUREFUNC R_CheckTextureNumForName(const char *name)
607{
608 int i = NO_TEXTURE;
609 if (*name != '-') // "NoTexture" marker.
610 {
611 i = textures[W_LumpNameHash(name) % (unsigned) numtextures]->index;
612 while (i >= 0 && strncasecmp(textures[i]->name,name,8))
613 i = textures[i]->next;
614 }
615 return i;
616}
617
618//
619// R_TextureNumForName
620// Calls R_CheckTextureNumForName,
621// aborts with error message.
622//
623
624int PUREFUNC R_TextureNumForName(const char *name) // const added -- killough
625{
626 int i = R_CheckTextureNumForName(name);
627 if (i == -1)
628 I_Error("R_TextureNumForName: %.8s not found", name);
629 return i;
630}
631
632//
633// R_SafeTextureNumForName
634// Calls R_CheckTextureNumForName, and changes any error to NO_TEXTURE
635int PUREFUNC R_SafeTextureNumForName(const char *name, int snum)
636{
637 int i = R_CheckTextureNumForName(name);
638 if (i == -1) {
639 i = NO_TEXTURE; // e6y - return "no texture"
640 lprintf(LO_DEBUG,"bad texture '%s' in sidedef %d\n",name,snum);
641 }
642 return i;
643}
644
645//
646// R_PrecacheLevel
647// Preloads all relevant graphics for the level.
648//
649// Totally rewritten by Lee Killough to use less memory,
650// to avoid using alloca(), and to improve performance.
651// cph - new wad lump handling, calls cache functions but acquires no locks
652
653static inline void precache_lump(int l)
654{
655 W_CacheLumpNum(l); W_UnlockLumpNum(l);
656}
657
658void R_PrecacheLevel(void)
659{
660 register int i;
661 register byte *hitlist;
662
663 if (demoplayback)
664 return;
665
666 {
667 size_t size = numflats > numsprites ? numflats : numsprites;
668 hitlist = malloc((size_t)numtextures > size ? numtextures : size);
669 }
670
671 // Precache flats.
672
673 memset(hitlist, 0, numflats);
674
675 for (i = numsectors; --i >= 0; )
676 hitlist[sectors[i].floorpic] = hitlist[sectors[i].ceilingpic] = 1;
677
678 for (i = numflats; --i >= 0; )
679 if (hitlist[i])
680 precache_lump(firstflat + i);
681
682 // Precache textures.
683
684 memset(hitlist, 0, numtextures);
685
686 for (i = numsides; --i >= 0;)
687 hitlist[sides[i].bottomtexture] =
688 hitlist[sides[i].toptexture] =
689 hitlist[sides[i].midtexture] = 1;
690
691 // Sky texture is always present.
692 // Note that F_SKY1 is the name used to
693 // indicate a sky floor/ceiling as a flat,
694 // while the sky texture is stored like
695 // a wall texture, with an episode dependend
696 // name.
697
698 hitlist[skytexture] = 1;
699
700 for (i = numtextures; --i >= 0; )
701 if (hitlist[i])
702 {
703 texture_t *texture = textures[i];
704 int j = texture->patchcount;
705 while (--j >= 0)
706 precache_lump(texture->patches[j].patch);
707 }
708
709 // Precache sprites.
710 memset(hitlist, 0, numsprites);
711
712 {
713 thinker_t *th = NULL;
714 while ((th = P_NextThinker(th,th_all)) != NULL)
715 if (th->function == P_MobjThinker)
716 hitlist[((mobj_t *)th)->sprite] = 1;
717 }
718
719 for (i=numsprites; --i >= 0;)
720 if (hitlist[i])
721 {
722 int j = sprites[i].numframes;
723 while (--j >= 0)
724 {
725 short *sflump = sprites[i].spriteframes[j].lump;
726 int k = 7;
727 do
728 precache_lump(firstspritelump + sflump[k]);
729 while (--k >= 0);
730 }
731 }
732 free(hitlist);
733}
734
735// Proff - Added for OpenGL
736void R_SetPatchNum(patchnum_t *patchnum, const char *name)
737{
738 const rpatch_t *patch = R_CachePatchName(name);
739 patchnum->width = patch->width;
740 patchnum->height = patch->height;
741 patchnum->leftoffset = patch->leftoffset;
742 patchnum->topoffset = patch->topoffset;
743 patchnum->lumpnum = W_GetNumForName(name);
744 R_UnlockPatchName(name);
745}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Refresh module, data I/O, caching, retrieval of graphics
31 * by name.
32 *
33 *-----------------------------------------------------------------------------*/
34
35
36#ifndef __R_DATA__
37#define __R_DATA__
38
39#include "r_defs.h"
40#include "r_state.h"
41#include "r_patch.h"
42
43#ifdef __GNUG__
44#pragma interface
45#endif
46
47// A single patch from a texture definition, basically
48// a rectangular area within the texture rectangle.
49typedef struct
50{
51 int originx, originy; // Block origin, which has already accounted
52 int patch; // for the internal origin of the patch.
53} texpatch_t;
54
55//
56// Texture definition.
57// A DOOM wall texture is a list of patches
58// which are to be combined in a predefined order.
59//
60
61typedef struct
62{
63 char name[8]; // Keep name for switch changing, etc.
64 int next, index; // killough 1/31/98: used in hashing algorithm
65 // CPhipps - moved arrays with per-texture entries to elements here
66 unsigned widthmask;
67 // CPhipps - end of additions
68 short width, height;
69 short patchcount; // All the patches[patchcount] are drawn
70 texpatch_t patches[1]; // back-to-front into the cached texture.
71} texture_t;
72
73extern int numtextures;
74extern texture_t **textures;
75
76
77const byte *R_GetTextureColumn(const rpatch_t *texpatch, int col);
78
79
80// I/O, setting up the stuff.
81void R_InitData (void);
82void R_PrecacheLevel (void);
83
84
85// Retrieval.
86// Floor/ceiling opaque texture tiles,
87// lookup by name. For animation?
88int R_FlatNumForName (const char* name); // killough -- const added
89
90
91// R_*TextureNumForName returns the texture number for the texture name, or NO_TEXTURE if
92// there is no texture (i.e. "-") specified.
93/* cph 2006/07/23 - defined value for no-texture marker (texture "-" in the WAD file) */
94#define NO_TEXTURE 0
95int PUREFUNC R_TextureNumForName (const char *name); // killough -- const added; cph - now PUREFUNC
96int PUREFUNC R_SafeTextureNumForName (const char *name, int snum);
97int PUREFUNC R_CheckTextureNumForName (const char *name);
98
99void R_InitTranMap(int); // killough 3/6/98: translucency initialization
100int R_ColormapNumForName(const char *name); // killough 4/4/98
101/* cph 2001/11/17 - new func to do lighting calcs and get suitable colour map */
102const lighttable_t* R_ColourMap(int lightlevel, fixed_t spryscale);
103
104extern const byte *main_tranmap, *tranmap;
105
106/* Proff - Added for OpenGL - cph - const char* param */
107void R_SetPatchNum(patchnum_t *patchnum, const char *name);
108
109#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Refresh/rendering module, shared data struct definitions.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_DEFS__
35#define __R_DEFS__
36
37// Screenwidth.
38#include "doomdef.h"
39
40// Some more or less basic data types
41// we depend on.
42#include "m_fixed.h"
43
44// We rely on the thinker data struct
45// to handle sound origins in sectors.
46#include "d_think.h"
47
48// SECTORS do store MObjs anyway.
49#include "p_mobj.h"
50
51#ifdef __GNUG__
52#pragma interface
53#endif
54
55// Silhouette, needed for clipping Segs (mainly)
56// and sprites representing things.
57#define SIL_NONE 0
58#define SIL_BOTTOM 1
59#define SIL_TOP 2
60#define SIL_BOTH 3
61
62#define MAXDRAWSEGS 256
63
64//
65// INTERNAL MAP TYPES
66// used by play and refresh
67//
68
69//
70// Your plain vanilla vertex.
71// Note: transformed values not buffered locally,
72// like some DOOM-alikes ("wt", "WebView") do.
73//
74typedef struct
75{
76 fixed_t x, y;
77} vertex_t;
78
79// Each sector has a degenmobj_t in its center for sound origin purposes.
80typedef struct
81{
82 thinker_t thinker; // not used for anything
83 fixed_t x, y, z;
84} degenmobj_t;
85
86//
87// The SECTORS record, at runtime.
88// Stores things/mobjs.
89//
90
91typedef struct
92{
93 int iSectorID; // proff 04/05/2000: needed for OpenGL and used in debugmode by the HUD to draw sectornum
94 boolean no_toptextures;
95 boolean no_bottomtextures;
96 fixed_t floorheight;
97 fixed_t ceilingheight;
98 int nexttag,firsttag; // killough 1/30/98: improves searches for tags.
99 int soundtraversed; // 0 = untraversed, 1,2 = sndlines-1
100 mobj_t *soundtarget; // thing that made a sound (or null)
101 int blockbox[4]; // mapblock bounding box for height changes
102 degenmobj_t soundorg; // origin for any sounds played by the sector
103 int validcount; // if == validcount, already checked
104 mobj_t *thinglist; // list of mobjs in sector
105
106 /* killough 8/28/98: friction is a sector property, not an mobj property.
107 * these fields used to be in mobj_t, but presented performance problems
108 * when processed as mobj properties. Fix is to make them sector properties.
109 */
110 int friction,movefactor;
111
112 // thinker_t for reversable actions
113 void *floordata; // jff 2/22/98 make thinkers on
114 void *ceilingdata; // floors, ceilings, lighting,
115 void *lightingdata; // independent of one another
116
117 // jff 2/26/98 lockout machinery for stairbuilding
118 int stairlock; // -2 on first locked -1 after thinker done 0 normally
119 int prevsec; // -1 or number of sector for previous step
120 int nextsec; // -1 or number of next step sector
121
122 // killough 3/7/98: support flat heights drawn at another sector's heights
123 int heightsec; // other sector, or -1 if no other sector
124
125 int bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps
126
127 // list of mobjs that are at least partially in the sector
128 // thinglist is a subset of touching_thinglist
129 struct msecnode_s *touching_thinglist; // phares 3/14/98
130
131 int linecount;
132 struct line_s **lines;
133
134 // killough 10/98: support skies coming from sidedefs. Allows scrolling
135 // skies and other effects. No "level info" kind of lump is needed,
136 // because you can use an arbitrary number of skies per level with this
137 // method. This field only applies when skyflatnum is used for floorpic
138 // or ceilingpic, because the rest of Doom needs to know which is sky
139 // and which isn't, etc.
140
141 int sky;
142
143 // killough 3/7/98: floor and ceiling texture offsets
144 fixed_t floor_xoffs, floor_yoffs;
145 fixed_t ceiling_xoffs, ceiling_yoffs;
146
147 // killough 4/11/98: support for lightlevels coming from another sector
148 int floorlightsec, ceilinglightsec;
149
150 short floorpic;
151 short ceilingpic;
152 short lightlevel;
153 short special;
154 short oldspecial; //jff 2/16/98 remembers if sector WAS secret (automap)
155 short tag;
156} sector_t;
157
158//
159// The SideDef.
160//
161
162typedef struct
163{
164 fixed_t textureoffset; // add this to the calculated texture column
165 fixed_t rowoffset; // add this to the calculated texture top
166 short toptexture; // Texture indices. We do not maintain names here.
167 short bottomtexture;
168 short midtexture;
169 sector_t* sector; // Sector the SideDef is facing.
170
171 // killough 4/4/98, 4/11/98: highest referencing special linedef's type,
172 // or lump number of special effect. Allows texture names to be overloaded
173 // for other functions.
174
175 int special;
176
177} side_t;
178
179//
180// Move clipping aid for LineDefs.
181//
182typedef enum
183{
184 ST_HORIZONTAL,
185 ST_VERTICAL,
186 ST_POSITIVE,
187 ST_NEGATIVE
188} slopetype_t;
189
190typedef struct line_s
191{
192 int iLineID; // proff 04/05/2000: needed for OpenGL
193 vertex_t *v1, *v2; // Vertices, from v1 to v2.
194 fixed_t dx, dy; // Precalculated v2 - v1 for side checking.
195 unsigned short flags; // Animation related.
196 short special;
197 short tag;
198 unsigned short sidenum[2]; // Visual appearance: SideDefs.
199 fixed_t bbox[4]; // A bounding box, for the linedef's extent
200 slopetype_t slopetype; // To aid move clipping.
201 sector_t *frontsector; // Front and back sector.
202 sector_t *backsector;
203 int validcount; // if == validcount, already checked
204 void *specialdata; // thinker_t for reversable actions
205 int tranlump; // killough 4/11/98: translucency filter, -1 == none
206 int firsttag,nexttag; // killough 4/17/98: improves searches for tags.
207 int r_validcount; // cph: if == gametic, r_flags already done
208 enum { // cph:
209 RF_TOP_TILE = 1, // Upper texture needs tiling
210 RF_MID_TILE = 2, // Mid texture needs tiling
211 RF_BOT_TILE = 4, // Lower texture needs tiling
212 RF_IGNORE = 8, // Renderer can skip this line
213 RF_CLOSED =16, // Line blocks view
214 } r_flags;
215 degenmobj_t soundorg; // sound origin for switches/buttons
216} line_t;
217
218
219// phares 3/14/98
220//
221// Sector list node showing all sectors an object appears in.
222//
223// There are two threads that flow through these nodes. The first thread
224// starts at touching_thinglist in a sector_t and flows through the m_snext
225// links to find all mobjs that are entirely or partially in the sector.
226// The second thread starts at touching_sectorlist in an mobj_t and flows
227// through the m_tnext links to find all sectors a thing touches. This is
228// useful when applying friction or push effects to sectors. These effects
229// can be done as thinkers that act upon all objects touching their sectors.
230// As an mobj moves through the world, these nodes are created and
231// destroyed, with the links changed appropriately.
232//
233// For the links, NULL means top or end of list.
234
235typedef struct msecnode_s
236{
237 sector_t *m_sector; // a sector containing this object
238 struct mobj_s *m_thing; // this object
239 struct msecnode_s *m_tprev; // prev msecnode_t for this thing
240 struct msecnode_s *m_tnext; // next msecnode_t for this thing
241 struct msecnode_s *m_sprev; // prev msecnode_t for this sector
242 struct msecnode_s *m_snext; // next msecnode_t for this sector
243 boolean visited; // killough 4/4/98, 4/7/98: used in search algorithms
244} msecnode_t;
245
246//
247// The LineSeg.
248//
249typedef struct
250{
251 vertex_t *v1, *v2;
252 fixed_t offset;
253 angle_t angle;
254 side_t* sidedef;
255 line_t* linedef;
256
257 int iSegID; // proff 11/05/2000: needed for OpenGL
258 // figgi -- needed for glnodes
259 float length;
260 boolean miniseg;
261
262
263 // Sector references.
264 // Could be retrieved from linedef, too
265 // (but that would be slower -- killough)
266 // backsector is NULL for one sided lines
267
268 sector_t *frontsector, *backsector;
269} seg_t;
270
271
272//
273// A SubSector.
274// References a Sector.
275// Basically, this is a list of LineSegs,
276// indicating the visible walls that define
277// (all or some) sides of a convex BSP leaf.
278//
279
280typedef struct subsector_s
281{
282 sector_t *sector;
283 unsigned short numlines, firstline;
284} subsector_t;
285
286
287//
288// BSP node.
289//
290typedef struct
291{
292 fixed_t x, y, dx, dy; // Partition line.
293 fixed_t bbox[2][4]; // Bounding box for each child.
294 unsigned short children[2]; // If NF_SUBSECTOR its a subsector.
295} node_t;
296
297//
298// OTHER TYPES
299//
300
301// This could be wider for >8 bit display.
302// Indeed, true color support is posibble
303// precalculating 24bpp lightmap/colormap LUT.
304// from darkening PLAYPAL to all black.
305// Could use even more than 32 levels.
306
307typedef byte lighttable_t;
308
309//
310// Masked 2s linedefs
311//
312
313typedef struct drawseg_s
314{
315 seg_t *curline;
316 int x1, x2;
317 fixed_t scale1, scale2, scalestep;
318 int silhouette; // 0=none, 1=bottom, 2=top, 3=both
319 fixed_t bsilheight; // do not clip sprites above this
320 fixed_t tsilheight; // do not clip sprites below this
321
322 // Added for filtering (fractional texture u coord) support - POPE
323 fixed_t rw_offset, rw_distance, rw_centerangle;
324
325 // Pointers to lists for sprite clipping,
326 // all three adjusted so [x1] is first value.
327
328 int *sprtopclip, *sprbottomclip, *maskedtexturecol; // dropoff overflow
329} drawseg_t;
330
331// proff: Added for OpenGL
332typedef struct
333{
334 int width,height;
335 int leftoffset,topoffset;
336 int lumpnum;
337} patchnum_t;
338
339//
340// A vissprite_t is a thing that will be drawn during a refresh.
341// i.e. a sprite object that is partly visible.
342//
343
344typedef struct vissprite_s
345{
346 mobj_t *thing;
347 boolean flip;
348 int x1, x2;
349 fixed_t gx, gy; // for line side calculation
350 fixed_t gz, gzt; // global bottom / top for silhouette clipping
351 fixed_t startfrac; // horizontal position of x1
352 fixed_t scale;
353 fixed_t xiscale; // negative if flipped
354 fixed_t texturemid;
355 int patch;
356 uint_64_t mobjflags;
357
358 // for color translation and shadow draw, maxbright frames as well
359 const lighttable_t *colormap;
360
361 // killough 3/27/98: height sector for underwater/fake ceiling support
362 int heightsec;
363
364 boolean isplayersprite;
365} vissprite_t;
366
367//
368// Sprites are patches with a special naming convention
369// so they can be recognized by R_InitSprites.
370// The base name is NNNNFx or NNNNFxFx, with
371// x indicating the rotation, x = 0, 1-7.
372// The sprite and frame specified by a thing_t
373// is range checked at run time.
374// A sprite is a patch_t that is assumed to represent
375// a three dimensional object and may have multiple
376// rotations pre drawn.
377// Horizontal flipping is used to save space,
378// thus NNNNF2F5 defines a mirrored patch.
379// Some sprites will only have one picture used
380// for all views: NNNNF0
381//
382
383typedef struct
384{
385 // If false use 0 for any position.
386 // Note: as eight entries are available,
387 // we might as well insert the same name eight times.
388 boolean rotate;
389
390 // Lump to use for view angles 0-7.
391 short lump[8];
392
393 // Flip bit (1 = flip) to use for view angles 0-7.
394 byte flip[8];
395
396} spriteframe_t;
397
398//
399// A sprite definition:
400// a number of animation frames.
401//
402
403typedef struct
404{
405 int numframes;
406 spriteframe_t *spriteframes;
407} spritedef_t;
408
409//
410// Now what is a visplane, anyway?
411//
412// Go to http://classicgaming.com/doom/editing/ to find out -- killough
413//
414
415typedef struct visplane
416{
417 struct visplane *next; // Next visplane in hash chain -- killough
418 int picnum, lightlevel, minx, maxx;
419 fixed_t height;
420 fixed_t xoffs, yoffs; // killough 2/28/98: Support scrolling flats
421 unsigned int pad1; // leave pads for [minx-1]/[maxx+1]
422 unsigned int top[MAX_SCREENWIDTH];
423 unsigned int pad2, pad3; // killough 2/8/98, 4/25/98
424 unsigned int bottom[MAX_SCREENWIDTH];
425 unsigned int pad4; // dropoff overflow
426} visplane_t;
427
428#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Demo stuff
31 *
32 *---------------------------------------------------------------------
33 */
34
35#include "doomstat.h"
36#include "r_demo.h"
37#include "r_fps.h"
38
39int demo_smoothturns = false;
40int demo_smoothturnsfactor = 6;
41
42static int smooth_playing_turns[SMOOTH_PLAYING_MAXFACTOR];
43static int_64_t smooth_playing_sum;
44static int smooth_playing_index;
45static angle_t smooth_playing_angle;
46
47void R_SmoothPlaying_Reset(player_t *player)
48{
49 if (demo_smoothturns && demoplayback && players)
50 {
51 if (!player)
52 player = &players[displayplayer];
53
54 if (player==&players[displayplayer])
55 {
56 smooth_playing_angle = players[displayplayer].mo->angle;
57 memset(smooth_playing_turns, 0, sizeof(smooth_playing_turns[0]) * SMOOTH_PLAYING_MAXFACTOR);
58 smooth_playing_sum = 0;
59 smooth_playing_index = 0;
60 }
61 }
62}
63
64void R_SmoothPlaying_Add(int delta)
65{
66 if (demo_smoothturns && demoplayback)
67 {
68 smooth_playing_sum -= smooth_playing_turns[smooth_playing_index];
69 smooth_playing_turns[smooth_playing_index] = delta;
70 smooth_playing_index = (smooth_playing_index + 1)%(demo_smoothturnsfactor);
71 smooth_playing_sum += delta;
72 smooth_playing_angle += (int)(smooth_playing_sum/(demo_smoothturnsfactor));
73 }
74}
75
76angle_t R_SmoothPlaying_Get(angle_t defangle)
77{
78 if (demo_smoothturns && demoplayback)
79 return smooth_playing_angle;
80 else
81 return defangle;
82}
83
84void R_ResetAfterTeleport(player_t *player)
85{
86 R_ResetViewInterpolation();
87 R_SmoothPlaying_Reset(player);
88}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Demo stuff
31 *
32 *---------------------------------------------------------------------
33 */
34
35#include "doomstat.h"
36
37#define SMOOTH_PLAYING_MAXFACTOR 16
38
39extern int demo_smoothturns;
40extern int demo_smoothturnsfactor;
41
42void R_SmoothPlaying_Reset(player_t *player);
43void R_SmoothPlaying_Add(int delta);
44angle_t R_SmoothPlaying_Get(angle_t defangle);
45void 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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * The actual span/column drawing functions.
31 * Here find the main potential for optimization,
32 * e.g. inline assembly, different algorithms.
33 *
34 *-----------------------------------------------------------------------------*/
35
36#include "doomstat.h"
37#include "w_wad.h"
38#include "r_main.h"
39#include "r_draw.h"
40#include "r_filter.h"
41#include "v_video.h"
42#include "st_stuff.h"
43#include "g_game.h"
44#include "am_map.h"
45#include "lprintf.h"
46
47//
48// All drawing to the view buffer is accomplished in this file.
49// The other refresh files only know about ccordinates,
50// not the architecture of the frame buffer.
51// Conveniently, the frame buffer is a linear one,
52// and we need only the base address,
53// and the total size == width*height*depth/8.,
54//
55
56byte *viewimage;
57int viewwidth;
58int scaledviewwidth;
59int viewheight;
60int viewwindowx;
61int viewwindowy;
62
63// Color tables for different players,
64// translate a limited part to another
65// (color ramps used for suit colors).
66//
67
68// CPhipps - made const*'s
69const byte *tranmap; // translucency filter maps 256x256 // phares
70const byte *main_tranmap; // killough 4/11/98
71
72//
73// R_DrawColumn
74// Source is the top of the column to scale.
75//
76
77// SoM: OPTIMIZE for ANYRES
78typedef enum
79{
80 COL_NONE,
81 COL_OPAQUE,
82 COL_TRANS,
83 COL_FLEXTRANS,
84 COL_FUZZ,
85 COL_FLEXADD
86} columntype_e;
87
88static int temp_x = 0;
89static int tempyl[4], tempyh[4];
90static byte byte_tempbuf[MAX_SCREENHEIGHT * 4];
91static unsigned short short_tempbuf[MAX_SCREENHEIGHT * 4];
92static unsigned int int_tempbuf[MAX_SCREENHEIGHT * 4];
93static int startx = 0;
94static int temptype = COL_NONE;
95static int commontop, commonbot;
96static const byte *temptranmap = NULL;
97// SoM 7-28-04: Fix the fuzz problem.
98static const byte *tempfuzzmap;
99
100//
101// Spectre/Invisibility.
102//
103
104#define FUZZTABLE 50
105// proff 08/17/98: Changed for high-res
106//#define FUZZOFF (SCREENWIDTH)
107#define FUZZOFF 1
108
109static const int fuzzoffset_org[FUZZTABLE] = {
110 FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
111 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
112 FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,
113 FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
114 FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,
115 FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,
116 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
117};
118
119static int fuzzoffset[FUZZTABLE];
120
121static int fuzzpos = 0;
122
123// render pipelines
124#define RDC_STANDARD 1
125#define RDC_TRANSLUCENT 2
126#define RDC_TRANSLATED 4
127#define RDC_FUZZ 8
128// no color mapping
129#define RDC_NOCOLMAP 16
130// filter modes
131#define RDC_DITHERZ 32
132#define RDC_BILINEAR 64
133#define RDC_ROUNDED 128
134
135draw_vars_t drawvars = {
136 NULL, // byte_topleft
137 NULL, // short_topleft
138 NULL, // int_topleft
139 0, // byte_pitch
140 0, // short_pitch
141 0, // int_pitch
142 RDRAW_FILTER_POINT, // filterwall
143 RDRAW_FILTER_POINT, // filterfloor
144 RDRAW_FILTER_POINT, // filtersprite
145 RDRAW_FILTER_POINT, // filterz
146 RDRAW_FILTER_POINT, // filterpatch
147
148 RDRAW_MASKEDCOLUMNEDGE_SQUARE, // sprite_edges
149 RDRAW_MASKEDCOLUMNEDGE_SQUARE, // patch_edges
150
151 // 49152 = FRACUNIT * 0.75
152 // 81920 = FRACUNIT * 1.25
153 49152 // mag_threshold
154};
155
156//
157// Error functions that will abort if R_FlushColumns tries to flush
158// columns without a column type.
159//
160
161static void R_FlushWholeError(void)
162{
163 I_Error("R_FlushWholeColumns called without being initialized.\n");
164}
165
166static void R_FlushHTError(void)
167{
168 I_Error("R_FlushHTColumns called without being initialized.\n");
169}
170
171static void R_QuadFlushError(void)
172{
173 I_Error("R_FlushQuadColumn called without being initialized.\n");
174}
175
176static void (*R_FlushWholeColumns)(void) = R_FlushWholeError;
177static void (*R_FlushHTColumns)(void) = R_FlushHTError;
178static void (*R_FlushQuadColumn)(void) = R_QuadFlushError;
179
180static void R_FlushColumns(void)
181{
182 if(temp_x != 4 || commontop >= commonbot)
183 R_FlushWholeColumns();
184 else
185 {
186 R_FlushHTColumns();
187 R_FlushQuadColumn();
188 }
189 temp_x = 0;
190}
191
192//
193// R_ResetColumnBuffer
194//
195// haleyjd 09/13/04: new function to call from main rendering loop
196// which gets rid of the unnecessary reset of various variables during
197// column drawing.
198//
199void R_ResetColumnBuffer(void)
200{
201 // haleyjd 10/06/05: this must not be done if temp_x == 0!
202 if(temp_x)
203 R_FlushColumns();
204 temptype = COL_NONE;
205 R_FlushWholeColumns = R_FlushWholeError;
206 R_FlushHTColumns = R_FlushHTError;
207 R_FlushQuadColumn = R_QuadFlushError;
208}
209
210#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD
211#define R_DRAWCOLUMN_PIPELINE_BITS 8
212#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8
213#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8
214#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8
215#include "r_drawflush.inl"
216
217#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT
218#define R_DRAWCOLUMN_PIPELINE_BITS 8
219#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL8
220#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL8
221#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL8
222#include "r_drawflush.inl"
223
224#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ
225#define R_DRAWCOLUMN_PIPELINE_BITS 8
226#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz8
227#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz8
228#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz8
229#include "r_drawflush.inl"
230
231#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD
232#define R_DRAWCOLUMN_PIPELINE_BITS 15
233#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15
234#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15
235#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15
236#include "r_drawflush.inl"
237
238#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT
239#define R_DRAWCOLUMN_PIPELINE_BITS 15
240#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL15
241#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL15
242#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL15
243#include "r_drawflush.inl"
244
245#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ
246#define R_DRAWCOLUMN_PIPELINE_BITS 15
247#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz15
248#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz15
249#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz15
250#include "r_drawflush.inl"
251
252#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD
253#define R_DRAWCOLUMN_PIPELINE_BITS 16
254#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16
255#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16
256#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16
257#include "r_drawflush.inl"
258
259#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT
260#define R_DRAWCOLUMN_PIPELINE_BITS 16
261#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL16
262#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL16
263#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL16
264#include "r_drawflush.inl"
265
266#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ
267#define R_DRAWCOLUMN_PIPELINE_BITS 16
268#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz16
269#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz16
270#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz16
271#include "r_drawflush.inl"
272
273#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD
274#define R_DRAWCOLUMN_PIPELINE_BITS 32
275#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32
276#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32
277#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32
278#include "r_drawflush.inl"
279
280#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT
281#define R_DRAWCOLUMN_PIPELINE_BITS 32
282#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL32
283#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL32
284#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL32
285#include "r_drawflush.inl"
286
287#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ
288#define R_DRAWCOLUMN_PIPELINE_BITS 32
289#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz32
290#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz32
291#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz32
292#include "r_drawflush.inl"
293
294//
295// R_DrawColumn
296//
297
298//
299// A column is a vertical slice/span from a wall texture that,
300// given the DOOM style restrictions on the view orientation,
301// will always have constant z depth.
302// Thus a special case loop for very fast rendering can
303// be used. It has also been used with Wolfenstein 3D.
304//
305
306byte *translationtables;
307
308#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_STANDARD
309#define R_DRAWCOLUMN_PIPELINE_BASE RDC_STANDARD
310
311#define R_DRAWCOLUMN_PIPELINE_BITS 8
312#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn8 ## postfix
313#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8
314#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8
315#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8
316#include "r_drawcolpipeline.inl"
317
318#define R_DRAWCOLUMN_PIPELINE_BITS 15
319#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn15 ## postfix
320#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15
321#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15
322#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15
323#include "r_drawcolpipeline.inl"
324
325#define R_DRAWCOLUMN_PIPELINE_BITS 16
326#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn16 ## postfix
327#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16
328#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16
329#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16
330#include "r_drawcolpipeline.inl"
331
332#define R_DRAWCOLUMN_PIPELINE_BITS 32
333#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn32 ## postfix
334#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32
335#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32
336#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32
337#include "r_drawcolpipeline.inl"
338
339#undef R_DRAWCOLUMN_PIPELINE_BASE
340#undef R_DRAWCOLUMN_PIPELINE_TYPE
341
342// Here is the version of R_DrawColumn that deals with translucent // phares
343// textures and sprites. It's identical to R_DrawColumn except // |
344// for the spot where the color index is stuffed into *dest. At // V
345// that point, the existing color index and the new color index
346// are mapped through the TRANMAP lump filters to get a new color
347// index whose RGB values are the average of the existing and new
348// colors.
349//
350// Since we're concerned about performance, the 'translucent or
351// opaque' decision is made outside this routine, not down where the
352// actual code differences are.
353
354#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_TRANSLUCENT
355#define R_DRAWCOLUMN_PIPELINE_BASE RDC_TRANSLUCENT
356
357#define R_DRAWCOLUMN_PIPELINE_BITS 8
358#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn8 ## postfix
359#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL8
360#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL8
361#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL8
362#include "r_drawcolpipeline.inl"
363
364#define R_DRAWCOLUMN_PIPELINE_BITS 15
365#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn15 ## postfix
366#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL15
367#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL15
368#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL15
369#include "r_drawcolpipeline.inl"
370
371#define R_DRAWCOLUMN_PIPELINE_BITS 16
372#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn16 ## postfix
373#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL16
374#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL16
375#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL16
376#include "r_drawcolpipeline.inl"
377
378#define R_DRAWCOLUMN_PIPELINE_BITS 32
379#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn32 ## postfix
380#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL32
381#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL32
382#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL32
383#include "r_drawcolpipeline.inl"
384
385#undef R_DRAWCOLUMN_PIPELINE_BASE
386#undef R_DRAWCOLUMN_PIPELINE_TYPE
387
388//
389// R_DrawTranslatedColumn
390// Used to draw player sprites
391// with the green colorramp mapped to others.
392// Could be used with different translation
393// tables, e.g. the lighter colored version
394// of the BaronOfHell, the HellKnight, uses
395// identical sprites, kinda brightened up.
396//
397
398#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_TRANSLATED
399#define R_DRAWCOLUMN_PIPELINE_BASE RDC_TRANSLATED
400
401#define R_DRAWCOLUMN_PIPELINE_BITS 8
402#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn8 ## postfix
403#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8
404#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8
405#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8
406#include "r_drawcolpipeline.inl"
407
408#define R_DRAWCOLUMN_PIPELINE_BITS 15
409#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn15 ## postfix
410#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15
411#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15
412#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15
413#include "r_drawcolpipeline.inl"
414
415#define R_DRAWCOLUMN_PIPELINE_BITS 16
416#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn16 ## postfix
417#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16
418#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16
419#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16
420#include "r_drawcolpipeline.inl"
421
422#define R_DRAWCOLUMN_PIPELINE_BITS 32
423#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn32 ## postfix
424#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32
425#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32
426#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32
427#include "r_drawcolpipeline.inl"
428
429#undef R_DRAWCOLUMN_PIPELINE_BASE
430#undef R_DRAWCOLUMN_PIPELINE_TYPE
431
432//
433// Framebuffer postprocessing.
434// Creates a fuzzy image by copying pixels
435// from adjacent ones to left and right.
436// Used with an all black colormap, this
437// could create the SHADOW effect,
438// i.e. spectres and invisible players.
439//
440
441#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_FUZZ
442#define R_DRAWCOLUMN_PIPELINE_BASE RDC_FUZZ
443
444#define R_DRAWCOLUMN_PIPELINE_BITS 8
445#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn8 ## postfix
446#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz8
447#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz8
448#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz8
449#include "r_drawcolpipeline.inl"
450
451#define R_DRAWCOLUMN_PIPELINE_BITS 15
452#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn15 ## postfix
453#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz15
454#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz15
455#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz15
456#include "r_drawcolpipeline.inl"
457
458#define R_DRAWCOLUMN_PIPELINE_BITS 16
459#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn16 ## postfix
460#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz16
461#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz16
462#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz16
463#include "r_drawcolpipeline.inl"
464
465#define R_DRAWCOLUMN_PIPELINE_BITS 32
466#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn32 ## postfix
467#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz32
468#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz32
469#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz32
470#include "r_drawcolpipeline.inl"
471
472#undef R_DRAWCOLUMN_PIPELINE_BASE
473#undef R_DRAWCOLUMN_PIPELINE_TYPE
474
475static R_DrawColumn_f drawcolumnfuncs[VID_MODEMAX][RDRAW_FILTER_MAXFILTERS][RDRAW_FILTER_MAXFILTERS][RDC_PIPELINE_MAXPIPELINES] = {
476 {
477 {
478 {NULL, NULL, NULL, NULL,},
479 {R_DrawColumn8_PointUV,
480 R_DrawTLColumn8_PointUV,
481 R_DrawTranslatedColumn8_PointUV,
482 R_DrawFuzzColumn8_PointUV,},
483 {R_DrawColumn8_LinearUV,
484 R_DrawTLColumn8_LinearUV,
485 R_DrawTranslatedColumn8_LinearUV,
486 R_DrawFuzzColumn8_LinearUV,},
487 {R_DrawColumn8_RoundedUV,
488 R_DrawTLColumn8_RoundedUV,
489 R_DrawTranslatedColumn8_RoundedUV,
490 R_DrawFuzzColumn8_RoundedUV,},
491 },
492 {
493 {NULL, NULL, NULL, NULL,},
494 {R_DrawColumn8_PointUV_PointZ,
495 R_DrawTLColumn8_PointUV_PointZ,
496 R_DrawTranslatedColumn8_PointUV_PointZ,
497 R_DrawFuzzColumn8_PointUV_PointZ,},
498 {R_DrawColumn8_LinearUV_PointZ,
499 R_DrawTLColumn8_LinearUV_PointZ,
500 R_DrawTranslatedColumn8_LinearUV_PointZ,
501 R_DrawFuzzColumn8_LinearUV_PointZ,},
502 {R_DrawColumn8_RoundedUV_PointZ,
503 R_DrawTLColumn8_RoundedUV_PointZ,
504 R_DrawTranslatedColumn8_RoundedUV_PointZ,
505 R_DrawFuzzColumn8_RoundedUV_PointZ,},
506 },
507 {
508 {NULL, NULL, NULL, NULL,},
509 {R_DrawColumn8_PointUV_LinearZ,
510 R_DrawTLColumn8_PointUV_LinearZ,
511 R_DrawTranslatedColumn8_PointUV_LinearZ,
512 R_DrawFuzzColumn8_PointUV_LinearZ,},
513 {R_DrawColumn8_LinearUV_LinearZ,
514 R_DrawTLColumn8_LinearUV_LinearZ,
515 R_DrawTranslatedColumn8_LinearUV_LinearZ,
516 R_DrawFuzzColumn8_LinearUV_LinearZ,},
517 {R_DrawColumn8_RoundedUV_LinearZ,
518 R_DrawTLColumn8_RoundedUV_LinearZ,
519 R_DrawTranslatedColumn8_RoundedUV_LinearZ,
520 R_DrawFuzzColumn8_RoundedUV_LinearZ,},
521 },
522 },
523 {
524 {
525 {NULL, NULL, NULL, NULL,},
526 {R_DrawColumn15_PointUV,
527 R_DrawTLColumn15_PointUV,
528 R_DrawTranslatedColumn15_PointUV,
529 R_DrawFuzzColumn15_PointUV,},
530 {R_DrawColumn15_LinearUV,
531 R_DrawTLColumn15_LinearUV,
532 R_DrawTranslatedColumn15_LinearUV,
533 R_DrawFuzzColumn15_LinearUV,},
534 {R_DrawColumn15_RoundedUV,
535 R_DrawTLColumn15_RoundedUV,
536 R_DrawTranslatedColumn15_RoundedUV,
537 R_DrawFuzzColumn15_RoundedUV,},
538 },
539 {
540 {NULL, NULL, NULL, NULL,},
541 {R_DrawColumn15_PointUV_PointZ,
542 R_DrawTLColumn15_PointUV_PointZ,
543 R_DrawTranslatedColumn15_PointUV_PointZ,
544 R_DrawFuzzColumn15_PointUV_PointZ,},
545 {R_DrawColumn15_LinearUV_PointZ,
546 R_DrawTLColumn15_LinearUV_PointZ,
547 R_DrawTranslatedColumn15_LinearUV_PointZ,
548 R_DrawFuzzColumn15_LinearUV_PointZ,},
549 {R_DrawColumn15_RoundedUV_PointZ,
550 R_DrawTLColumn15_RoundedUV_PointZ,
551 R_DrawTranslatedColumn15_RoundedUV_PointZ,
552 R_DrawFuzzColumn15_RoundedUV_PointZ,},
553 },
554 {
555 {NULL, NULL, NULL, NULL,},
556 {R_DrawColumn15_PointUV_LinearZ,
557 R_DrawTLColumn15_PointUV_LinearZ,
558 R_DrawTranslatedColumn15_PointUV_LinearZ,
559 R_DrawFuzzColumn15_PointUV_LinearZ,},
560 {R_DrawColumn15_LinearUV_LinearZ,
561 R_DrawTLColumn15_LinearUV_LinearZ,
562 R_DrawTranslatedColumn15_LinearUV_LinearZ,
563 R_DrawFuzzColumn15_LinearUV_LinearZ,},
564 {R_DrawColumn15_RoundedUV_LinearZ,
565 R_DrawTLColumn15_RoundedUV_LinearZ,
566 R_DrawTranslatedColumn15_RoundedUV_LinearZ,
567 R_DrawFuzzColumn15_RoundedUV_LinearZ,},
568 },
569 },
570 {
571 {
572 {NULL, NULL, NULL, NULL,},
573 {R_DrawColumn16_PointUV,
574 R_DrawTLColumn16_PointUV,
575 R_DrawTranslatedColumn16_PointUV,
576 R_DrawFuzzColumn16_PointUV,},
577 {R_DrawColumn16_LinearUV,
578 R_DrawTLColumn16_LinearUV,
579 R_DrawTranslatedColumn16_LinearUV,
580 R_DrawFuzzColumn16_LinearUV,},
581 {R_DrawColumn16_RoundedUV,
582 R_DrawTLColumn16_RoundedUV,
583 R_DrawTranslatedColumn16_RoundedUV,
584 R_DrawFuzzColumn16_RoundedUV,},
585 },
586 {
587 {NULL, NULL, NULL, NULL,},
588 {R_DrawColumn16_PointUV_PointZ,
589 R_DrawTLColumn16_PointUV_PointZ,
590 R_DrawTranslatedColumn16_PointUV_PointZ,
591 R_DrawFuzzColumn16_PointUV_PointZ,},
592 {R_DrawColumn16_LinearUV_PointZ,
593 R_DrawTLColumn16_LinearUV_PointZ,
594 R_DrawTranslatedColumn16_LinearUV_PointZ,
595 R_DrawFuzzColumn16_LinearUV_PointZ,},
596 {R_DrawColumn16_RoundedUV_PointZ,
597 R_DrawTLColumn16_RoundedUV_PointZ,
598 R_DrawTranslatedColumn16_RoundedUV_PointZ,
599 R_DrawFuzzColumn16_RoundedUV_PointZ,},
600 },
601 {
602 {NULL, NULL, NULL, NULL,},
603 {R_DrawColumn16_PointUV_LinearZ,
604 R_DrawTLColumn16_PointUV_LinearZ,
605 R_DrawTranslatedColumn16_PointUV_LinearZ,
606 R_DrawFuzzColumn16_PointUV_LinearZ,},
607 {R_DrawColumn16_LinearUV_LinearZ,
608 R_DrawTLColumn16_LinearUV_LinearZ,
609 R_DrawTranslatedColumn16_LinearUV_LinearZ,
610 R_DrawFuzzColumn16_LinearUV_LinearZ,},
611 {R_DrawColumn16_RoundedUV_LinearZ,
612 R_DrawTLColumn16_RoundedUV_LinearZ,
613 R_DrawTranslatedColumn16_RoundedUV_LinearZ,
614 R_DrawFuzzColumn16_RoundedUV_LinearZ,},
615 },
616 },
617 {
618 {
619 {NULL, NULL, NULL, NULL,},
620 {R_DrawColumn32_PointUV,
621 R_DrawTLColumn32_PointUV,
622 R_DrawTranslatedColumn32_PointUV,
623 R_DrawFuzzColumn32_PointUV,},
624 {R_DrawColumn32_LinearUV,
625 R_DrawTLColumn32_LinearUV,
626 R_DrawTranslatedColumn32_LinearUV,
627 R_DrawFuzzColumn32_LinearUV,},
628 {R_DrawColumn32_RoundedUV,
629 R_DrawTLColumn32_RoundedUV,
630 R_DrawTranslatedColumn32_RoundedUV,
631 R_DrawFuzzColumn32_RoundedUV,},
632 },
633 {
634 {NULL, NULL, NULL, NULL,},
635 {R_DrawColumn32_PointUV_PointZ,
636 R_DrawTLColumn32_PointUV_PointZ,
637 R_DrawTranslatedColumn32_PointUV_PointZ,
638 R_DrawFuzzColumn32_PointUV_PointZ,},
639 {R_DrawColumn32_LinearUV_PointZ,
640 R_DrawTLColumn32_LinearUV_PointZ,
641 R_DrawTranslatedColumn32_LinearUV_PointZ,
642 R_DrawFuzzColumn32_LinearUV_PointZ,},
643 {R_DrawColumn32_RoundedUV_PointZ,
644 R_DrawTLColumn32_RoundedUV_PointZ,
645 R_DrawTranslatedColumn32_RoundedUV_PointZ,
646 R_DrawFuzzColumn32_RoundedUV_PointZ,},
647 },
648 {
649 {NULL, NULL, NULL, NULL,},
650 {R_DrawColumn32_PointUV_LinearZ,
651 R_DrawTLColumn32_PointUV_LinearZ,
652 R_DrawTranslatedColumn32_PointUV_LinearZ,
653 R_DrawFuzzColumn32_PointUV_LinearZ,},
654 {R_DrawColumn32_LinearUV_LinearZ,
655 R_DrawTLColumn32_LinearUV_LinearZ,
656 R_DrawTranslatedColumn32_LinearUV_LinearZ,
657 R_DrawFuzzColumn32_LinearUV_LinearZ,},
658 {R_DrawColumn32_RoundedUV_LinearZ,
659 R_DrawTLColumn32_RoundedUV_LinearZ,
660 R_DrawTranslatedColumn32_RoundedUV_LinearZ,
661 R_DrawFuzzColumn32_RoundedUV_LinearZ,},
662 },
663 },
664};
665
666R_DrawColumn_f R_GetDrawColumnFunc(enum column_pipeline_e type,
667 enum draw_filter_type_e filter,
668 enum draw_filter_type_e filterz) {
669 R_DrawColumn_f result = drawcolumnfuncs[V_GetMode()][filterz][filter][type];
670 if (result == NULL)
671 I_Error("R_GetDrawColumnFunc: undefined function (%d, %d, %d)",
672 type, filter, filterz);
673 return result;
674}
675
676void R_SetDefaultDrawColumnVars(draw_column_vars_t *dcvars) {
677 dcvars->x = dcvars->yl = dcvars->yh = dcvars->z = 0;
678 dcvars->iscale = dcvars->texturemid = dcvars->texheight = dcvars->texu = 0;
679 dcvars->source = dcvars->prevsource = dcvars->nextsource = NULL;
680 dcvars->colormap = dcvars->nextcolormap = colormaps[0];
681 dcvars->translation = NULL;
682 dcvars->edgeslope = dcvars->drawingmasked = 0;
683 dcvars->edgetype = drawvars.sprite_edges;
684}
685
686//
687// R_InitTranslationTables
688// Creates the translation tables to map
689// the green color ramp to gray, brown, red.
690// Assumes a given structure of the PLAYPAL.
691// Could be read from a lump instead.
692//
693
694byte playernumtotrans[MAXPLAYERS];
695extern lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ];
696
697void R_InitTranslationTables (void)
698{
699 int i, j;
700#define MAXTRANS 3
701 byte transtocolour[MAXTRANS];
702
703 // killough 5/2/98:
704 // Remove dependency of colormaps aligned on 256-byte boundary
705
706 if (translationtables == NULL) // CPhipps - allow multiple calls
707 translationtables = Z_Malloc(256*MAXTRANS, PU_STATIC, 0);
708
709 for (i=0; i<MAXTRANS; i++) transtocolour[i] = 255;
710
711 for (i=0; i<MAXPLAYERS; i++) {
712 byte wantcolour = mapcolor_plyr[i];
713 playernumtotrans[i] = 0;
714 if (wantcolour != 0x70) // Not green, would like translation
715 for (j=0; j<MAXTRANS; j++)
716 if (transtocolour[j] == 255) {
717 transtocolour[j] = wantcolour; playernumtotrans[i] = j+1; break;
718 }
719 }
720
721 // translate just the 16 green colors
722 for (i=0; i<256; i++)
723 if (i >= 0x70 && i<= 0x7f)
724 {
725 // CPhipps - configurable player colours
726 translationtables[i] = colormaps[0][((i&0xf)<<9) + transtocolour[0]];
727 translationtables[i+256] = colormaps[0][((i&0xf)<<9) + transtocolour[1]];
728 translationtables[i+512] = colormaps[0][((i&0xf)<<9) + transtocolour[2]];
729 }
730 else // Keep all other colors as is.
731 translationtables[i]=translationtables[i+256]=translationtables[i+512]=i;
732}
733
734//
735// R_DrawSpan
736// With DOOM style restrictions on view orientation,
737// the floors and ceilings consist of horizontal slices
738// or spans with constant z depth.
739// However, rotation around the world z axis is possible,
740// thus this mapping, while simpler and faster than
741// perspective correct texture mapping, has to traverse
742// the texture at an angle in all but a few cases.
743// In consequence, flats are not stored by column (like walls),
744// and the inner loop has to step in texture space u and v.
745//
746
747#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_PointUV_PointZ
748#define R_DRAWSPAN_PIPELINE_BITS 8
749#define R_DRAWSPAN_PIPELINE (RDC_STANDARD)
750#include "r_drawspan.inl"
751
752#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_PointUV_LinearZ
753#define R_DRAWSPAN_PIPELINE_BITS 8
754#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ)
755#include "r_drawspan.inl"
756
757#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_LinearUV_PointZ
758#define R_DRAWSPAN_PIPELINE_BITS 8
759#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR)
760#include "r_drawspan.inl"
761
762#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_LinearUV_LinearZ
763#define R_DRAWSPAN_PIPELINE_BITS 8
764#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ)
765#include "r_drawspan.inl"
766
767#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_RoundedUV_PointZ
768#define R_DRAWSPAN_PIPELINE_BITS 8
769#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED)
770#include "r_drawspan.inl"
771
772#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_RoundedUV_LinearZ
773#define R_DRAWSPAN_PIPELINE_BITS 8
774#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ)
775#include "r_drawspan.inl"
776
777#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_PointUV_PointZ
778#define R_DRAWSPAN_PIPELINE_BITS 15
779#define R_DRAWSPAN_PIPELINE (RDC_STANDARD)
780#include "r_drawspan.inl"
781
782#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_PointUV_LinearZ
783#define R_DRAWSPAN_PIPELINE_BITS 15
784#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ)
785#include "r_drawspan.inl"
786
787#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_LinearUV_PointZ
788#define R_DRAWSPAN_PIPELINE_BITS 15
789#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR)
790#include "r_drawspan.inl"
791
792#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_LinearUV_LinearZ
793#define R_DRAWSPAN_PIPELINE_BITS 15
794#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ)
795#include "r_drawspan.inl"
796
797#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_RoundedUV_PointZ
798#define R_DRAWSPAN_PIPELINE_BITS 15
799#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED)
800#include "r_drawspan.inl"
801
802#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_RoundedUV_LinearZ
803#define R_DRAWSPAN_PIPELINE_BITS 15
804#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ)
805#include "r_drawspan.inl"
806
807#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_PointUV_PointZ
808#define R_DRAWSPAN_PIPELINE_BITS 16
809#define R_DRAWSPAN_PIPELINE (RDC_STANDARD)
810#include "r_drawspan.inl"
811
812#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_PointUV_LinearZ
813#define R_DRAWSPAN_PIPELINE_BITS 16
814#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ)
815#include "r_drawspan.inl"
816
817#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_LinearUV_PointZ
818#define R_DRAWSPAN_PIPELINE_BITS 16
819#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR)
820#include "r_drawspan.inl"
821
822#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_LinearUV_LinearZ
823#define R_DRAWSPAN_PIPELINE_BITS 16
824#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ)
825#include "r_drawspan.inl"
826
827#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_RoundedUV_PointZ
828#define R_DRAWSPAN_PIPELINE_BITS 16
829#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED)
830#include "r_drawspan.inl"
831
832#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_RoundedUV_LinearZ
833#define R_DRAWSPAN_PIPELINE_BITS 16
834#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ)
835#include "r_drawspan.inl"
836
837#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_PointUV_PointZ
838#define R_DRAWSPAN_PIPELINE_BITS 32
839#define R_DRAWSPAN_PIPELINE (RDC_STANDARD)
840#include "r_drawspan.inl"
841
842#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_PointUV_LinearZ
843#define R_DRAWSPAN_PIPELINE_BITS 32
844#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ)
845#include "r_drawspan.inl"
846
847#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_LinearUV_PointZ
848#define R_DRAWSPAN_PIPELINE_BITS 32
849#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR)
850#include "r_drawspan.inl"
851
852#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_LinearUV_LinearZ
853#define R_DRAWSPAN_PIPELINE_BITS 32
854#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ)
855#include "r_drawspan.inl"
856
857#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_RoundedUV_PointZ
858#define R_DRAWSPAN_PIPELINE_BITS 32
859#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED)
860#include "r_drawspan.inl"
861
862#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_RoundedUV_LinearZ
863#define R_DRAWSPAN_PIPELINE_BITS 32
864#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ)
865#include "r_drawspan.inl"
866
867static R_DrawSpan_f drawspanfuncs[VID_MODEMAX][RDRAW_FILTER_MAXFILTERS][RDRAW_FILTER_MAXFILTERS] = {
868 {
869 {
870 NULL,
871 NULL,
872 NULL,
873 NULL,
874 },
875 {
876 NULL,
877 R_DrawSpan8_PointUV_PointZ,
878 R_DrawSpan8_LinearUV_PointZ,
879 R_DrawSpan8_RoundedUV_PointZ,
880 },
881 {
882 NULL,
883 R_DrawSpan8_PointUV_LinearZ,
884 R_DrawSpan8_LinearUV_LinearZ,
885 R_DrawSpan8_RoundedUV_LinearZ,
886 },
887 {
888 NULL,
889 NULL,
890 NULL,
891 NULL,
892 },
893 },
894 {
895 {
896 NULL,
897 NULL,
898 NULL,
899 NULL,
900 },
901 {
902 NULL,
903 R_DrawSpan15_PointUV_PointZ,
904 R_DrawSpan15_LinearUV_PointZ,
905 R_DrawSpan15_RoundedUV_PointZ,
906 },
907 {
908 NULL,
909 R_DrawSpan15_PointUV_LinearZ,
910 R_DrawSpan15_LinearUV_LinearZ,
911 R_DrawSpan15_RoundedUV_LinearZ,
912 },
913 {
914 NULL,
915 NULL,
916 NULL,
917 NULL,
918 },
919 },
920 {
921 {
922 NULL,
923 NULL,
924 NULL,
925 NULL,
926 },
927 {
928 NULL,
929 R_DrawSpan16_PointUV_PointZ,
930 R_DrawSpan16_LinearUV_PointZ,
931 R_DrawSpan16_RoundedUV_PointZ,
932 },
933 {
934 NULL,
935 R_DrawSpan16_PointUV_LinearZ,
936 R_DrawSpan16_LinearUV_LinearZ,
937 R_DrawSpan16_RoundedUV_LinearZ,
938 },
939 {
940 NULL,
941 NULL,
942 NULL,
943 NULL,
944 },
945 },
946 {
947 {
948 NULL,
949 NULL,
950 NULL,
951 NULL,
952 },
953 {
954 NULL,
955 R_DrawSpan32_PointUV_PointZ,
956 R_DrawSpan32_LinearUV_PointZ,
957 R_DrawSpan32_RoundedUV_PointZ,
958 },
959 {
960 NULL,
961 R_DrawSpan32_PointUV_LinearZ,
962 R_DrawSpan32_LinearUV_LinearZ,
963 R_DrawSpan32_RoundedUV_LinearZ,
964 },
965 {
966 NULL,
967 NULL,
968 NULL,
969 NULL,
970 },
971 },
972};
973
974R_DrawSpan_f R_GetDrawSpanFunc(enum draw_filter_type_e filter,
975 enum draw_filter_type_e filterz) {
976 R_DrawSpan_f result = drawspanfuncs[V_GetMode()][filterz][filter];
977 if (result == NULL)
978 I_Error("R_GetDrawSpanFunc: undefined function (%d, %d)",
979 filter, filterz);
980 return result;
981}
982
983void R_DrawSpan(draw_span_vars_t *dsvars) {
984 R_GetDrawSpanFunc(drawvars.filterfloor, drawvars.filterz)(dsvars);
985}
986
987//
988// R_InitBuffer
989// Creats lookup tables that avoid
990// multiplies and other hazzles
991// for getting the framebuffer address
992// of a pixel to draw.
993//
994
995void R_InitBuffer(int width, int height)
996{
997 int i=0;
998 // Handle resize,
999 // e.g. smaller view windows
1000 // with border and/or status bar.
1001
1002 viewwindowx = (SCREENWIDTH-width) >> 1;
1003
1004 // Same with base row offset.
1005
1006 viewwindowy = width==SCREENWIDTH ? 0 : (SCREENHEIGHT-(ST_SCALED_HEIGHT-1)-height)>>1;
1007
1008 drawvars.byte_topleft = screens[0].data + viewwindowy*screens[0].byte_pitch + viewwindowx;
1009 drawvars.short_topleft = (unsigned short *)(screens[0].data) + viewwindowy*screens[0].short_pitch + viewwindowx;
1010 drawvars.int_topleft = (unsigned int *)(screens[0].data) + viewwindowy*screens[0].int_pitch + viewwindowx;
1011 drawvars.byte_pitch = screens[0].byte_pitch;
1012 drawvars.short_pitch = screens[0].short_pitch;
1013 drawvars.int_pitch = screens[0].int_pitch;
1014
1015 if (V_GetMode() == VID_MODE8) {
1016 for (i=0; i<FUZZTABLE; i++)
1017 fuzzoffset[i] = fuzzoffset_org[i]*screens[0].byte_pitch;
1018 } else if ((V_GetMode() == VID_MODE15) || (V_GetMode() == VID_MODE16)) {
1019 for (i=0; i<FUZZTABLE; i++)
1020 fuzzoffset[i] = fuzzoffset_org[i]*screens[0].short_pitch;
1021 } else if (V_GetMode() == VID_MODE32) {
1022 for (i=0; i<FUZZTABLE; i++)
1023 fuzzoffset[i] = fuzzoffset_org[i]*screens[0].int_pitch;
1024 }
1025}
1026
1027//
1028// R_FillBackScreen
1029// Fills the back screen with a pattern
1030// for variable screen sizes
1031// Also draws a beveled edge.
1032//
1033// CPhipps - patch drawing updated
1034
1035void R_FillBackScreen (void)
1036{
1037 int x,y;
1038
1039 if (scaledviewwidth == SCREENWIDTH)
1040 return;
1041
1042 V_DrawBackground(gamemode == commercial ? "GRNROCK" : "FLOOR7_2", 1);
1043
1044 for (x=0; x<scaledviewwidth; x+=8)
1045 V_DrawNamePatch(viewwindowx+x,viewwindowy-8,1,"brdr_t", CR_DEFAULT, VPT_NONE);
1046
1047 for (x=0; x<scaledviewwidth; x+=8)
1048 V_DrawNamePatch(viewwindowx+x,viewwindowy+viewheight,1,"brdr_b", CR_DEFAULT, VPT_NONE);
1049
1050 for (y=0; y<viewheight; y+=8)
1051 V_DrawNamePatch(viewwindowx-8,viewwindowy+y,1,"brdr_l", CR_DEFAULT, VPT_NONE);
1052
1053 for (y=0; y<viewheight; y+=8)
1054 V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy+y,1,"brdr_r", CR_DEFAULT, VPT_NONE);
1055
1056 // Draw beveled edge.
1057 V_DrawNamePatch(viewwindowx-8,viewwindowy-8,1,"brdr_tl", CR_DEFAULT, VPT_NONE);
1058
1059 V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy-8,1,"brdr_tr", CR_DEFAULT, VPT_NONE);
1060
1061 V_DrawNamePatch(viewwindowx-8,viewwindowy+viewheight,1,"brdr_bl", CR_DEFAULT, VPT_NONE);
1062
1063 V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy+viewheight,1,"brdr_br", CR_DEFAULT, VPT_NONE);
1064}
1065
1066//
1067// Copy a screen buffer.
1068//
1069
1070void R_VideoErase(int x, int y, int count)
1071{
1072 if (V_GetMode() != VID_MODEGL)
1073 memcpy(screens[0].data+y*screens[0].byte_pitch+x*V_GetPixelDepth(),
1074 screens[1].data+y*screens[1].byte_pitch+x*V_GetPixelDepth(),
1075 count*V_GetPixelDepth()); // LFB copy.
1076}
1077
1078//
1079// R_DrawViewBorder
1080// Draws the border around the view
1081// for different size windows?
1082//
1083
1084void R_DrawViewBorder(void)
1085{
1086 int top, side, i;
1087
1088 if (V_GetMode() == VID_MODEGL) {
1089 // proff 11/99: we don't have a backscreen in OpenGL from where we can copy this
1090 R_FillBackScreen();
1091 return;
1092 }
1093
1094 if ((SCREENHEIGHT != viewheight) ||
1095 ((automapmode & am_active) && ! (automapmode & am_overlay)))
1096 {
1097 // erase left and right of statusbar
1098 side= ( SCREENWIDTH - ST_SCALED_WIDTH ) / 2;
1099
1100 if (side > 0) {
1101 for (i = (SCREENHEIGHT - ST_SCALED_HEIGHT); i < SCREENHEIGHT; i++)
1102 {
1103 R_VideoErase (0, i, side);
1104 R_VideoErase (ST_SCALED_WIDTH+side, i, side);
1105 }
1106 }
1107 }
1108
1109 if ( viewheight >= ( SCREENHEIGHT - ST_SCALED_HEIGHT ))
1110 return; // if high-res, don´t go any further!
1111
1112 top = ((SCREENHEIGHT-ST_SCALED_HEIGHT)-viewheight)/2;
1113 side = (SCREENWIDTH-scaledviewwidth)/2;
1114
1115 // copy top
1116 for (i = 0; i < top; i++)
1117 R_VideoErase (0, i, SCREENWIDTH);
1118
1119 // copy sides
1120 for (i = top; i < (top+viewheight); i++) {
1121 R_VideoErase (0, i, side);
1122 R_VideoErase (viewwidth+side, i, side);
1123 }
1124
1125 // copy bottom
1126 for (i = top+viewheight; i < (SCREENHEIGHT - ST_SCALED_HEIGHT); i++)
1127 R_VideoErase (0, i, SCREENWIDTH);
1128}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * System specific interface stuff.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_DRAW__
35#define __R_DRAW__
36
37#include "r_defs.h"
38
39#ifdef __GNUG__
40#pragma interface
41#endif
42
43enum column_pipeline_e {
44 RDC_PIPELINE_STANDARD,
45 RDC_PIPELINE_TRANSLUCENT,
46 RDC_PIPELINE_TRANSLATED,
47 RDC_PIPELINE_FUZZ,
48 RDC_PIPELINE_MAXPIPELINES,
49};
50
51// Used to specify what kind of filering you want
52enum draw_filter_type_e {
53 RDRAW_FILTER_NONE,
54 RDRAW_FILTER_POINT,
55 RDRAW_FILTER_LINEAR,
56 RDRAW_FILTER_ROUNDED,
57 RDRAW_FILTER_MAXFILTERS
58};
59
60// Used to specify what kind of column edge rendering to use on masked
61// columns. SQUARE = standard, SLOPED = slope the column edge up or down
62// based on neighboring columns
63enum sloped_edge_type_e {
64 RDRAW_MASKEDCOLUMNEDGE_SQUARE,
65 RDRAW_MASKEDCOLUMNEDGE_SLOPED
66};
67
68// Packaged into a struct - POPE
69typedef struct {
70 int x;
71 int yl;
72 int yh;
73 fixed_t z; // the current column z coord
74 fixed_t iscale;
75 fixed_t texturemid;
76 int texheight; // killough
77 fixed_t texu; // the current column u coord
78 const byte *source; // first pixel in a column
79 const byte *prevsource; // first pixel in previous column
80 const byte *nextsource; // first pixel in next column
81 const lighttable_t *colormap;
82 const lighttable_t *nextcolormap;
83 const byte *translation;
84 int edgeslope; // OR'ed RDRAW_EDGESLOPE_*
85 // 1 if R_DrawColumn* is currently drawing a masked column, otherwise 0
86 int drawingmasked;
87 enum sloped_edge_type_e edgetype;
88} draw_column_vars_t;
89
90void R_SetDefaultDrawColumnVars(draw_column_vars_t *dcvars);
91
92void R_VideoErase(int x, int y, int count);
93
94typedef struct {
95 int y;
96 int x1;
97 int x2;
98 fixed_t z; // the current span z coord
99 fixed_t xfrac;
100 fixed_t yfrac;
101 fixed_t xstep;
102 fixed_t ystep;
103 const byte *source; // start of a 64*64 tile image
104 const lighttable_t *colormap;
105 const lighttable_t *nextcolormap;
106} draw_span_vars_t;
107
108typedef struct {
109 byte *byte_topleft;
110 unsigned short *short_topleft;
111 unsigned int *int_topleft;
112 int byte_pitch;
113 int short_pitch;
114 int int_pitch;
115
116 enum draw_filter_type_e filterwall;
117 enum draw_filter_type_e filterfloor;
118 enum draw_filter_type_e filtersprite;
119 enum draw_filter_type_e filterz;
120 enum draw_filter_type_e filterpatch;
121
122 enum sloped_edge_type_e sprite_edges;
123 enum sloped_edge_type_e patch_edges;
124
125 // Used to specify an early-out magnification threshold for filtering.
126 // If a texture is being minified (dcvars.iscale > rdraw_magThresh), then it
127 // drops back to point filtering.
128 fixed_t mag_threshold;
129} draw_vars_t;
130
131extern draw_vars_t drawvars;
132
133extern byte playernumtotrans[MAXPLAYERS]; // CPhipps - what translation table for what player
134extern byte *translationtables;
135
136typedef void (*R_DrawColumn_f)(draw_column_vars_t *dcvars);
137R_DrawColumn_f R_GetDrawColumnFunc(enum column_pipeline_e type,
138 enum draw_filter_type_e filter,
139 enum draw_filter_type_e filterz);
140
141// Span blitting for rows, floor/ceiling. No Spectre effect needed.
142typedef void (*R_DrawSpan_f)(draw_span_vars_t *dsvars);
143R_DrawSpan_f R_GetDrawSpanFunc(enum draw_filter_type_e filter,
144 enum draw_filter_type_e filterz);
145void R_DrawSpan(draw_span_vars_t *dsvars);
146
147void R_InitBuffer(int width, int height);
148
149// Initialize color translation tables, for player rendering etc.
150void R_InitTranslationTables(void);
151
152// Rendering function.
153void R_FillBackScreen(void);
154
155// If the view size is not full screen, draws a border around it.
156void R_DrawViewBorder(void);
157
158// haleyjd 09/13/04: new function to call from main rendering loop
159// which gets rid of the unnecessary reset of various variables during
160// column drawing.
161void R_ResetColumnBuffer(void);
162
163#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 @@
1
2// no color mapping
3#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV)
4#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_NOCOLMAP)
5#include "r_drawcolumn.inl"
6
7// simple depth color mapping
8#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV_PointZ)
9#define R_DRAWCOLUMN_PIPELINE R_DRAWCOLUMN_PIPELINE_BASE
10#include "r_drawcolumn.inl"
11
12// z-dither
13#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV_LinearZ)
14#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_DITHERZ)
15#include "r_drawcolumn.inl"
16
17// bilinear with no color mapping
18#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV)
19#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR | RDC_NOCOLMAP)
20#include "r_drawcolumn.inl"
21
22// bilinear with simple depth color mapping
23#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV_PointZ)
24#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR)
25#include "r_drawcolumn.inl"
26
27// bilinear + z-dither
28#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV_LinearZ)
29#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR | RDC_DITHERZ)
30#include "r_drawcolumn.inl"
31
32// rounded with no color mapping
33#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV)
34#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED | RDC_NOCOLMAP)
35#include "r_drawcolumn.inl"
36
37// rounded with simple depth color mapping
38#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV_PointZ)
39#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED)
40#include "r_drawcolumn.inl"
41
42// rounded + z-dither
43#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV_LinearZ)
44#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED | RDC_DITHERZ)
45#include "r_drawcolumn.inl"
46
47#undef R_FLUSHWHOLE_FUNCNAME
48#undef R_FLUSHHEADTAIL_FUNCNAME
49#undef R_FLUSHQUAD_FUNCNAME
50#undef R_DRAWCOLUMN_FUNCNAME_COMPOSITE
51#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 *-----------------------------------------------------------------------------*/
30
31
32#if (R_DRAWCOLUMN_PIPELINE_BITS == 8)
33#define SCREENTYPE byte
34#define TEMPBUF byte_tempbuf
35#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15)
36#define SCREENTYPE unsigned short
37#define TEMPBUF short_tempbuf
38#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16)
39#define SCREENTYPE unsigned short
40#define TEMPBUF short_tempbuf
41#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32)
42#define SCREENTYPE unsigned int
43#define TEMPBUF int_tempbuf
44#endif
45
46#define GETDESTCOLOR8(col) (col)
47#define GETDESTCOLOR15(col) (col)
48#define GETDESTCOLOR16(col) (col)
49#define GETDESTCOLOR32(col) (col)
50
51#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLATED)
52#define GETCOL8_MAPPED(col) (translation[(col)])
53#else
54#define GETCOL8_MAPPED(col) (col)
55#endif
56
57#if (R_DRAWCOLUMN_PIPELINE & RDC_NOCOLMAP)
58 #define GETCOL8_DEPTH(col) GETCOL8_MAPPED(col)
59#else
60 #if (R_DRAWCOLUMN_PIPELINE & RDC_DITHERZ)
61 #define GETCOL8_DEPTH(col) (dither_colormaps[filter_getDitheredPixelLevel(x, y, fracz)][GETCOL8_MAPPED(col)])
62 #else
63 #define GETCOL8_DEPTH(col) colormap[GETCOL8_MAPPED(col)]
64 #endif
65#endif
66
67#if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR)
68 #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(filter_getDitheredForColumn(x,y,frac,nextfrac))
69 #define GETCOL15(frac, nextfrac) filter_getFilteredForColumn15(GETCOL8_DEPTH,frac,nextfrac)
70 #define GETCOL16(frac, nextfrac) filter_getFilteredForColumn16(GETCOL8_DEPTH,frac,nextfrac)
71 #define GETCOL32(frac, nextfrac) filter_getFilteredForColumn32(GETCOL8_DEPTH,frac,nextfrac)
72#elif (R_DRAWCOLUMN_PIPELINE & RDC_ROUNDED)
73 #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac))
74 #define GETCOL15(frac, nextfrac) VID_PAL15(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK)
75 #define GETCOL16(frac, nextfrac) VID_PAL16(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK)
76 #define GETCOL32(frac, nextfrac) VID_PAL32(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK)
77#else
78 #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(source[(frac)>>FRACBITS])
79 #define GETCOL15(frac, nextfrac) VID_PAL15(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK)
80 #define GETCOL16(frac, nextfrac) VID_PAL16(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK)
81 #define GETCOL32(frac, nextfrac) VID_PAL32(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK)
82#endif
83
84#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED|RDC_DITHERZ))
85 #define INCY(y) (y++)
86#else
87 #define INCY(y)
88#endif
89
90#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
91#define COLTYPE (COL_TRANS)
92#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
93#define COLTYPE (COL_FUZZ)
94#else
95#define COLTYPE (COL_OPAQUE)
96#endif
97
98#if (R_DRAWCOLUMN_PIPELINE_BITS == 8)
99 #define GETCOL(frac, nextfrac) GETCOL8(frac, nextfrac)
100 #define GETDESTCOLOR(col) GETDESTCOLOR8(col)
101#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15)
102 #define GETCOL(frac, nextfrac) GETCOL15(frac, nextfrac)
103 #define GETDESTCOLOR(col) GETDESTCOLOR15(col)
104#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16)
105 #define GETCOL(frac, nextfrac) GETCOL16(frac, nextfrac)
106 #define GETDESTCOLOR(col) GETDESTCOLOR16(col)
107#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32)
108 #define GETCOL(frac, nextfrac) GETCOL32(frac, nextfrac)
109 #define GETDESTCOLOR(col) GETDESTCOLOR32(col)
110#endif
111
112static void R_DRAWCOLUMN_FUNCNAME(draw_column_vars_t *dcvars)
113{
114 int count;
115 SCREENTYPE *dest; // killough
116 fixed_t frac;
117 const fixed_t fracstep = dcvars->iscale;
118#if ((R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) && (R_DRAWCOLUMN_PIPELINE_BITS != 8))
119 const fixed_t slope_texu = (dcvars->source == dcvars->nextsource) ? 0 : dcvars->texu & 0xffff;
120#else
121 const fixed_t slope_texu = dcvars->texu;
122#endif
123
124 // drop back to point filtering if we're minifying
125#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED))
126 if (dcvars->iscale > drawvars.mag_threshold) {
127 R_GetDrawColumnFunc(R_DRAWCOLUMN_PIPELINE_TYPE,
128 RDRAW_FILTER_POINT,
129 drawvars.filterz)(dcvars);
130 return;
131 }
132#endif
133
134#if (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
135 // Adjust borders. Low...
136 if (!dcvars->yl)
137 dcvars->yl = 1;
138
139 // .. and high.
140 if (dcvars->yh == viewheight-1)
141 dcvars->yh = viewheight - 2;
142#endif
143
144 // leban 1/17/99:
145 // removed the + 1 here, adjusted the if test, and added an increment
146 // later. this helps a compiler pipeline a bit better. the x86
147 // assembler also does this.
148
149 count = dcvars->yh - dcvars->yl;
150
151 // leban 1/17/99:
152 // this case isn't executed too often. depending on how many instructions
153 // there are between here and the second if test below, this case could
154 // be moved down and might save instructions overall. since there are
155 // probably different wads that favor one way or the other, i'll leave
156 // this alone for now.
157 if (count < 0) // Zero length, column does not exceed a pixel.
158 return;
159
160#ifdef RANGECHECK
161 if (dcvars->x >= SCREENWIDTH
162 || dcvars->yl < 0
163 || dcvars->yh >= SCREENHEIGHT)
164 I_Error("R_DrawColumn: %i to %i at %i", dcvars->yl, dcvars->yh, dcvars->x);
165#endif
166
167 // Determine scaling, which is the only mapping to be done.
168 #if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR)
169 frac = dcvars->texturemid - (FRACUNIT>>1) + (dcvars->yl-centery)*fracstep;
170 #else
171 frac = dcvars->texturemid + (dcvars->yl-centery)*fracstep;
172 #endif
173
174 if (dcvars->drawingmasked && dcvars->edgetype == RDRAW_MASKEDCOLUMNEDGE_SLOPED) {
175 // slope the top and bottom column edge based on the fractional u coordinate
176 // and dcvars->edgeslope, which were set in R_DrawMaskedColumn
177 // in r_things.c
178 if (dcvars->yl != 0) {
179 if (dcvars->edgeslope & RDRAW_EDGESLOPE_TOP_UP) {
180 // [/#]
181 int shift = ((0xffff-(slope_texu & 0xffff))/dcvars->iscale);
182 dcvars->yl += shift;
183 count -= shift;
184 frac += 0xffff-(slope_texu & 0xffff);
185 }
186 else if (dcvars->edgeslope & RDRAW_EDGESLOPE_TOP_DOWN) {
187 // [#\]
188 int shift = ((slope_texu & 0xffff)/dcvars->iscale);
189 dcvars->yl += shift;
190 count -= shift;
191 frac += slope_texu & 0xffff;
192 }
193 }
194 if (dcvars->yh != viewheight-1) {
195 if (dcvars->edgeslope & RDRAW_EDGESLOPE_BOT_UP) {
196 // [#/]
197 int shift = ((0xffff-(slope_texu & 0xffff))/dcvars->iscale);
198 dcvars->yh -= shift;
199 count -= shift;
200 }
201 else if (dcvars->edgeslope & RDRAW_EDGESLOPE_BOT_DOWN) {
202 // [\#]
203 int shift = ((slope_texu & 0xffff)/dcvars->iscale);
204 dcvars->yh -= shift;
205 count -= shift;
206 }
207 }
208 if (count <= 0) return;
209 }
210
211 // Framebuffer destination address.
212 // SoM: MAGIC
213 {
214 // haleyjd: reordered predicates
215 if(temp_x == 4 ||
216 (temp_x && (temptype != COLTYPE || temp_x + startx != dcvars->x)))
217 R_FlushColumns();
218
219 if(!temp_x)
220 {
221 startx = dcvars->x;
222 tempyl[0] = commontop = dcvars->yl;
223 tempyh[0] = commonbot = dcvars->yh;
224 temptype = COLTYPE;
225#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
226 temptranmap = tranmap;
227#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
228 tempfuzzmap = fullcolormap; // SoM 7-28-04: Fix the fuzz problem.
229#endif
230 R_FlushWholeColumns = R_FLUSHWHOLE_FUNCNAME;
231 R_FlushHTColumns = R_FLUSHHEADTAIL_FUNCNAME;
232 R_FlushQuadColumn = R_FLUSHQUAD_FUNCNAME;
233 dest = &TEMPBUF[dcvars->yl << 2];
234 } else {
235 tempyl[temp_x] = dcvars->yl;
236 tempyh[temp_x] = dcvars->yh;
237
238 if(dcvars->yl > commontop)
239 commontop = dcvars->yl;
240 if(dcvars->yh < commonbot)
241 commonbot = dcvars->yh;
242
243 dest = &TEMPBUF[(dcvars->yl << 2) + temp_x];
244 }
245 temp_x += 1;
246 }
247
248// do nothing else when drawin fuzz columns
249#if (!(R_DRAWCOLUMN_PIPELINE & RDC_FUZZ))
250 {
251 const byte *source = dcvars->source;
252 const lighttable_t *colormap = dcvars->colormap;
253 const byte *translation = dcvars->translation;
254#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED|RDC_DITHERZ))
255 int y = dcvars->yl;
256 const int x = dcvars->x;
257#endif
258#if (R_DRAWCOLUMN_PIPELINE & RDC_DITHERZ)
259 const int fracz = (dcvars->z >> 6) & 255;
260 const byte *dither_colormaps[2] = { dcvars->colormap, dcvars->nextcolormap };
261#endif
262#if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR)
263 #if (R_DRAWCOLUMN_PIPELINE_BITS == 8)
264 const int yl = dcvars->yl;
265 const byte *dither_sources[2] = { dcvars->source, dcvars->nextsource };
266 const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : (dcvars->texu>>8) & 0xff;
267 #else
268 const byte *nextsource = dcvars->nextsource;
269 const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : dcvars->texu & 0xffff;
270 #endif
271#endif
272#if (R_DRAWCOLUMN_PIPELINE & RDC_ROUNDED)
273 const byte *prevsource = dcvars->prevsource;
274 const byte *nextsource = dcvars->nextsource;
275 const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : (dcvars->texu>>8) & 0xff;
276#endif
277
278 count++;
279
280 // Inner loop that does the actual texture mapping,
281 // e.g. a DDA-lile scaling.
282 // This is as fast as it gets. (Yeah, right!!! -- killough)
283 //
284 // killough 2/1/98: more performance tuning
285
286 if (dcvars->texheight == 128) {
287 #define FIXEDT_128MASK ((127<<FRACBITS)|0xffff)
288 while(count--) {
289 *dest = GETDESTCOLOR(GETCOL(frac & FIXEDT_128MASK, (frac+FRACUNIT) & FIXEDT_128MASK));
290 INCY(y);
291 dest += 4;
292 frac += fracstep;
293 }
294 } else if (dcvars->texheight == 0) {
295 /* cph - another special case */
296 while (count--) {
297 *dest = GETDESTCOLOR(GETCOL(frac, (frac+FRACUNIT)));
298 INCY(y);
299 dest += 4;
300 frac += fracstep;
301 }
302 } else {
303 unsigned heightmask = dcvars->texheight-1; // CPhipps - specify type
304 if (! (dcvars->texheight & heightmask) ) { // power of 2 -- killough
305 fixed_t fixedt_heightmask = (heightmask<<FRACBITS)|0xffff;
306 while ((count-=2)>=0) { // texture height is a power of 2 -- killough
307 *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask));
308 INCY(y);
309 dest += 4;
310 frac += fracstep;
311 *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask));
312 INCY(y);
313 dest += 4;
314 frac += fracstep;
315 }
316 if (count & 1)
317 *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask));
318 INCY(y);
319 } else {
320 fixed_t nextfrac = 0;
321
322 heightmask++;
323 heightmask <<= FRACBITS;
324
325 if (frac < 0)
326 while ((frac += heightmask) < 0);
327 else
328 while (frac >= (int)heightmask)
329 frac -= heightmask;
330
331#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED))
332 nextfrac = frac + FRACUNIT;
333 while (nextfrac >= (int)heightmask)
334 nextfrac -= heightmask;
335#endif
336
337#define INCFRAC(f) if ((f += fracstep) >= (int)heightmask) f -= heightmask;
338
339 while (count--) {
340 // Re-map color indices from wall texture column
341 // using a lighting/special effects LUT.
342
343 // heightmask is the Tutti-Frutti fix -- killough
344
345 *dest = GETDESTCOLOR(GETCOL(frac, nextfrac));
346 INCY(y);
347 dest += 4;
348 INCFRAC(frac);
349#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED))
350 INCFRAC(nextfrac);
351#endif
352 }
353 }
354 }
355 }
356#endif // (!(R_DRAWCOLUMN_PIPELINE & RDC_FUZZ))
357}
358
359#undef GETDESTCOLOR32
360#undef GETDESTCOLOR16
361#undef GETDESTCOLOR15
362#undef GETDESTCOLOR8
363#undef GETDESTCOLOR
364#undef GETCOL8_MAPPED
365#undef GETCOL8_DEPTH
366#undef GETCOL32
367#undef GETCOL16
368#undef GETCOL15
369#undef GETCOL8
370#undef GETCOL
371#undef INCY
372#undef INCFRAC
373#undef COLTYPE
374#undef TEMPBUF
375#undef SCREENTYPE
376
377#undef R_DRAWCOLUMN_FUNCNAME
378#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 *-----------------------------------------------------------------------------*/
30
31#if (R_DRAWCOLUMN_PIPELINE_BITS == 8)
32#define SCREENTYPE byte
33#define TOPLEFT byte_topleft
34#define PITCH byte_pitch
35#define TEMPBUF byte_tempbuf
36#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15)
37#define SCREENTYPE unsigned short
38#define TOPLEFT short_topleft
39#define PITCH short_pitch
40#define TEMPBUF short_tempbuf
41#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16)
42#define SCREENTYPE unsigned short
43#define TOPLEFT short_topleft
44#define PITCH short_pitch
45#define TEMPBUF short_tempbuf
46#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32)
47#define SCREENTYPE unsigned int
48#define TOPLEFT int_topleft
49#define PITCH int_pitch
50#define TEMPBUF int_tempbuf
51#endif
52
53#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
54#define GETDESTCOLOR8(col1, col2) (temptranmap[((col1)<<8)+(col2)])
55#define GETDESTCOLOR15(col1, col2) (GETBLENDED15_3268((col1), (col2)))
56#define GETDESTCOLOR16(col1, col2) (GETBLENDED16_3268((col1), (col2)))
57#define GETDESTCOLOR32(col1, col2) (GETBLENDED32_3268((col1), (col2)))
58#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
59#define GETDESTCOLOR8(col) (tempfuzzmap[6*256+(col)])
60#define GETDESTCOLOR15(col) GETBLENDED15_9406(col, 0)
61#define GETDESTCOLOR16(col) GETBLENDED16_9406(col, 0)
62#define GETDESTCOLOR32(col) GETBLENDED32_9406(col, 0)
63#else
64#define GETDESTCOLOR8(col) (col)
65#define GETDESTCOLOR15(col) (col)
66#define GETDESTCOLOR16(col) (col)
67#define GETDESTCOLOR32(col) (col)
68#endif
69
70#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
71 #if (R_DRAWCOLUMN_PIPELINE_BITS == 8)
72 #define GETDESTCOLOR(col1, col2) GETDESTCOLOR8(col1, col2)
73 #elif (R_DRAWCOLUMN_PIPELINE_BITS == 15)
74 #define GETDESTCOLOR(col1, col2) GETDESTCOLOR15(col1, col2)
75 #elif (R_DRAWCOLUMN_PIPELINE_BITS == 16)
76 #define GETDESTCOLOR(col1, col2) GETDESTCOLOR16(col1, col2)
77 #elif (R_DRAWCOLUMN_PIPELINE_BITS == 32)
78 #define GETDESTCOLOR(col1, col2) GETDESTCOLOR32(col1, col2)
79 #endif
80#else
81 #if (R_DRAWCOLUMN_PIPELINE_BITS == 8)
82 #define GETDESTCOLOR(col) GETDESTCOLOR8(col)
83 #elif (R_DRAWCOLUMN_PIPELINE_BITS == 15)
84 #define GETDESTCOLOR(col) GETDESTCOLOR15(col)
85 #elif (R_DRAWCOLUMN_PIPELINE_BITS == 16)
86 #define GETDESTCOLOR(col) GETDESTCOLOR16(col)
87 #elif (R_DRAWCOLUMN_PIPELINE_BITS == 32)
88 #define GETDESTCOLOR(col) GETDESTCOLOR32(col)
89 #endif
90#endif
91
92//
93// R_FlushWholeOpaque
94//
95// Flushes the entire columns in the buffer, one at a time.
96// This is used when a quad flush isn't possible.
97// Opaque version -- no remapping whatsoever.
98//
99static void R_FLUSHWHOLE_FUNCNAME(void)
100{
101 SCREENTYPE *source;
102 SCREENTYPE *dest;
103 int count, yl;
104
105 while(--temp_x >= 0)
106 {
107 yl = tempyl[temp_x];
108 source = &TEMPBUF[temp_x + (yl << 2)];
109 dest = drawvars.TOPLEFT + yl*drawvars.PITCH + startx + temp_x;
110 count = tempyh[temp_x] - yl + 1;
111
112 while(--count >= 0)
113 {
114#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
115 *dest = GETDESTCOLOR(*dest, *source);
116#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
117 // SoM 7-28-04: Fix the fuzz problem.
118 *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]);
119
120 // Clamp table lookup index.
121 if(++fuzzpos == FUZZTABLE)
122 fuzzpos = 0;
123#else
124 *dest = *source;
125#endif
126
127 source += 4;
128 dest += drawvars.PITCH;
129 }
130 }
131}
132
133//
134// R_FlushHTOpaque
135//
136// Flushes the head and tail of columns in the buffer in
137// preparation for a quad flush.
138// Opaque version -- no remapping whatsoever.
139//
140static void R_FLUSHHEADTAIL_FUNCNAME(void)
141{
142 SCREENTYPE *source;
143 SCREENTYPE *dest;
144 int count, colnum = 0;
145 int yl, yh;
146
147 while(colnum < 4)
148 {
149 yl = tempyl[colnum];
150 yh = tempyh[colnum];
151
152 // flush column head
153 if(yl < commontop)
154 {
155 source = &TEMPBUF[colnum + (yl << 2)];
156 dest = drawvars.TOPLEFT + yl*drawvars.PITCH + startx + colnum;
157 count = commontop - yl;
158
159 while(--count >= 0)
160 {
161#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
162 // haleyjd 09/11/04: use temptranmap here
163 *dest = GETDESTCOLOR(*dest, *source);
164#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
165 // SoM 7-28-04: Fix the fuzz problem.
166 *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]);
167
168 // Clamp table lookup index.
169 if(++fuzzpos == FUZZTABLE)
170 fuzzpos = 0;
171#else
172 *dest = *source;
173#endif
174
175 source += 4;
176 dest += drawvars.PITCH;
177 }
178 }
179
180 // flush column tail
181 if(yh > commonbot)
182 {
183 source = &TEMPBUF[colnum + ((commonbot + 1) << 2)];
184 dest = drawvars.TOPLEFT + (commonbot + 1)*drawvars.PITCH + startx + colnum;
185 count = yh - commonbot;
186
187 while(--count >= 0)
188 {
189#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
190 // haleyjd 09/11/04: use temptranmap here
191 *dest = GETDESTCOLOR(*dest, *source);
192#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
193 // SoM 7-28-04: Fix the fuzz problem.
194 *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]);
195
196 // Clamp table lookup index.
197 if(++fuzzpos == FUZZTABLE)
198 fuzzpos = 0;
199#else
200 *dest = *source;
201#endif
202
203 source += 4;
204 dest += drawvars.PITCH;
205 }
206 }
207 ++colnum;
208 }
209}
210
211static void R_FLUSHQUAD_FUNCNAME(void)
212{
213 SCREENTYPE *source = &TEMPBUF[commontop << 2];
214 SCREENTYPE *dest = drawvars.TOPLEFT + commontop*drawvars.PITCH + startx;
215 int count;
216#if (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
217 int fuzz1, fuzz2, fuzz3, fuzz4;
218
219 fuzz1 = fuzzpos;
220 fuzz2 = (fuzz1 + tempyl[1]) % FUZZTABLE;
221 fuzz3 = (fuzz2 + tempyl[2]) % FUZZTABLE;
222 fuzz4 = (fuzz3 + tempyl[3]) % FUZZTABLE;
223#endif
224
225 count = commonbot - commontop + 1;
226
227#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT)
228 while(--count >= 0)
229 {
230 dest[0] = GETDESTCOLOR(dest[0], source[0]);
231 dest[1] = GETDESTCOLOR(dest[1], source[1]);
232 dest[2] = GETDESTCOLOR(dest[2], source[2]);
233 dest[3] = GETDESTCOLOR(dest[3], source[3]);
234 source += 4 * sizeof(byte);
235 dest += drawvars.PITCH * sizeof(byte);
236 }
237#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)
238 while(--count >= 0)
239 {
240 dest[0] = GETDESTCOLOR(dest[0 + fuzzoffset[fuzz1]]);
241 dest[1] = GETDESTCOLOR(dest[1 + fuzzoffset[fuzz2]]);
242 dest[2] = GETDESTCOLOR(dest[2 + fuzzoffset[fuzz3]]);
243 dest[3] = GETDESTCOLOR(dest[3 + fuzzoffset[fuzz4]]);
244 fuzz1 = (fuzz1 + 1) % FUZZTABLE;
245 fuzz2 = (fuzz2 + 1) % FUZZTABLE;
246 fuzz3 = (fuzz3 + 1) % FUZZTABLE;
247 fuzz4 = (fuzz4 + 1) % FUZZTABLE;
248 source += 4 * sizeof(byte);
249 dest += drawvars.PITCH * sizeof(byte);
250 }
251#else
252 #if (R_DRAWCOLUMN_PIPELINE_BITS == 8)
253 if ((sizeof(int) == 4) && (((int)source % 4) == 0) && (((int)dest % 4) == 0)) {
254 while(--count >= 0)
255 {
256 *(int *)dest = *(int *)source;
257 source += 4 * sizeof(byte);
258 dest += drawvars.PITCH * sizeof(byte);
259 }
260 } else {
261 while(--count >= 0)
262 {
263 dest[0] = source[0];
264 dest[1] = source[1];
265 dest[2] = source[2];
266 dest[3] = source[3];
267 source += 4 * sizeof(byte);
268 dest += drawvars.PITCH * sizeof(byte);
269 }
270 }
271 #else
272 while(--count >= 0)
273 {
274 dest[0] = source[0];
275 dest[1] = source[1];
276 dest[2] = source[2];
277 dest[3] = source[3];
278 source += 4;
279 dest += drawvars.PITCH;
280 }
281 #endif
282#endif
283}
284
285#undef GETDESTCOLOR32
286#undef GETDESTCOLOR16
287#undef GETDESTCOLOR15
288#undef GETDESTCOLOR8
289#undef GETDESTCOLOR
290
291#undef TEMPBUF
292#undef PITCH
293#undef TOPLEFT
294#undef SCREENTYPE
295
296#undef R_DRAWCOLUMN_PIPELINE_BITS
297#undef R_DRAWCOLUMN_PIPELINE
298#undef R_FLUSHWHOLE_FUNCNAME
299#undef R_FLUSHHEADTAIL_FUNCNAME
300#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 *-----------------------------------------------------------------------------*/
30
31//
32// R_DrawSpan
33//
34
35#if (R_DRAWSPAN_PIPELINE_BITS == 8)
36#define SCREENTYPE byte
37#define TOPLEFT byte_topleft
38#define PITCH byte_pitch
39#elif (R_DRAWSPAN_PIPELINE_BITS == 15)
40#define SCREENTYPE unsigned short
41#define TOPLEFT short_topleft
42#define PITCH short_pitch
43#elif (R_DRAWSPAN_PIPELINE_BITS == 16)
44#define SCREENTYPE unsigned short
45#define TOPLEFT short_topleft
46#define PITCH short_pitch
47#elif (R_DRAWSPAN_PIPELINE_BITS == 32)
48#define SCREENTYPE unsigned int
49#define TOPLEFT int_topleft
50#define PITCH int_pitch
51#endif
52
53#if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ)
54 #define GETDEPTHMAP(col) dither_colormaps[filter_getDitheredPixelLevel(x1, y, fracz)][(col)]
55#else
56 #define GETDEPTHMAP(col) colormap[(col)]
57#endif
58
59#if (R_DRAWSPAN_PIPELINE_BITS == 8)
60 #define GETCOL_POINT(col) GETDEPTHMAP(col)
61 #define GETCOL_LINEAR(col) GETDEPTHMAP(col)
62#elif (R_DRAWSPAN_PIPELINE_BITS == 15)
63 #define GETCOL_POINT(col) VID_PAL15(GETDEPTHMAP(col), VID_COLORWEIGHTMASK)
64 #define GETCOL_LINEAR(col) filter_getFilteredForSpan15(GETDEPTHMAP, xfrac, yfrac)
65#elif (R_DRAWSPAN_PIPELINE_BITS == 16)
66 #define GETCOL_POINT(col) VID_PAL16(GETDEPTHMAP(col), VID_COLORWEIGHTMASK)
67 #define GETCOL_LINEAR(col) filter_getFilteredForSpan16(GETDEPTHMAP, xfrac, yfrac)
68#elif (R_DRAWSPAN_PIPELINE_BITS == 32)
69 #define GETCOL_POINT(col) VID_PAL32(GETDEPTHMAP(col), VID_COLORWEIGHTMASK)
70 #define GETCOL_LINEAR(col) filter_getFilteredForSpan32(GETDEPTHMAP, xfrac, yfrac)
71#endif
72
73#if (R_DRAWSPAN_PIPELINE & RDC_BILINEAR)
74 #define GETCOL(col) GETCOL_LINEAR(col)
75#else
76 #define GETCOL(col) GETCOL_POINT(col)
77#endif
78
79static void R_DRAWSPAN_FUNCNAME(draw_span_vars_t *dsvars)
80{
81#if (R_DRAWSPAN_PIPELINE & (RDC_ROUNDED|RDC_BILINEAR))
82 // drop back to point filtering if we're minifying
83 // 49152 = FRACUNIT * 0.75
84 if ((D_abs(dsvars->xstep) > drawvars.mag_threshold)
85 || (D_abs(dsvars->ystep) > drawvars.mag_threshold))
86 {
87 R_GetDrawSpanFunc(RDRAW_FILTER_POINT,
88 drawvars.filterz)(dsvars);
89 return;
90 }
91#endif
92 {
93 unsigned count = dsvars->x2 - dsvars->x1 + 1;
94 fixed_t xfrac = dsvars->xfrac;
95 fixed_t yfrac = dsvars->yfrac;
96 const fixed_t xstep = dsvars->xstep;
97 const fixed_t ystep = dsvars->ystep;
98 const byte *source = dsvars->source;
99 const byte *colormap = dsvars->colormap;
100 SCREENTYPE *dest = drawvars.TOPLEFT + dsvars->y*drawvars.PITCH + dsvars->x1;
101#if (R_DRAWSPAN_PIPELINE & (RDC_DITHERZ|RDC_BILINEAR))
102 const int y = dsvars->y;
103 int x1 = dsvars->x1;
104#endif
105#if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ)
106 const int fracz = (dsvars->z >> 12) & 255;
107 const byte *dither_colormaps[2] = { dsvars->colormap, dsvars->nextcolormap };
108#endif
109
110 while (count) {
111#if ((R_DRAWSPAN_PIPELINE_BITS != 8) && (R_DRAWSPAN_PIPELINE & RDC_BILINEAR))
112 // truecolor bilinear filtered
113 *dest++ = GETCOL(0);
114 xfrac += xstep;
115 yfrac += ystep;
116 count--;
117 #if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ)
118 x1--;
119 #endif
120#elif (R_DRAWSPAN_PIPELINE & RDC_ROUNDED)
121 *dest++ = GETCOL(filter_getRoundedForSpan(xfrac, yfrac));
122 xfrac += xstep;
123 yfrac += ystep;
124 count--;
125 #if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ)
126 x1--;
127 #endif
128#else
129 #if (R_DRAWSPAN_PIPELINE & RDC_BILINEAR)
130 // 8 bit bilinear
131 const fixed_t xtemp = ((xfrac >> 16) + (filter_getDitheredPixelLevel(x1, y, ((xfrac>>8)&0xff)))) & 63;
132 const fixed_t ytemp = ((yfrac >> 10) + 64*(filter_getDitheredPixelLevel(x1, y, ((yfrac>>8)&0xff)))) & 4032;
133 #else
134 const fixed_t xtemp = (xfrac >> 16) & 63;
135 const fixed_t ytemp = (yfrac >> 10) & 4032;
136 #endif
137 const fixed_t spot = xtemp | ytemp;
138 xfrac += xstep;
139 yfrac += ystep;
140 *dest++ = GETCOL(source[spot]);
141 count--;
142 #if (R_DRAWSPAN_PIPELINE & (RDC_DITHERZ|RDC_BILINEAR))
143 x1--;
144 #endif
145#endif
146 }
147 }
148}
149
150#undef GETDEPTHMAP
151#undef GETCOL_LINEAR
152#undef GETCOL_POINT
153#undef GETCOL
154#undef PITCH
155#undef TOPLEFT
156#undef SCREENTYPE
157
158#undef R_DRAWSPAN_PIPELINE_BITS
159#undef R_DRAWSPAN_PIPELINE
160#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 *-----------------------------------------------------------------------------*/
30
31#include "doomtype.h"
32#include "r_filter.h"
33
34#define DMR 16
35byte filter_ditherMatrix[DITHER_DIM][DITHER_DIM] = {
36 0*DMR, 14*DMR, 3*DMR, 13*DMR, 11*DMR, 5*DMR, 8*DMR, 6*DMR,
37 12*DMR, 2*DMR, 15*DMR, 1*DMR, 7*DMR, 9*DMR, 4*DMR, 10*DMR
38};
39
40byte filter_roundedUVMap[FILTER_UVDIM*FILTER_UVDIM];
41byte filter_roundedRowMap[4*16];
42
43void R_FilterInit(void) {
44 int i,j,s,t;
45
46 // scale2x takes the following source:
47 // A B C
48 // D E F
49 // G H I
50 //
51 // and doubles the size of E to produce:
52 // E0 E1
53 // E2 E3
54 //
55 // E0 = D == B && B != F && D != H ? D : E;
56 // E1 = B == F && B != D && F != H ? F : E;
57 // E2 = D == H && D != B && H != F ? D : E;
58 // E3 = H == F && D != H && B != F ? F : E;
59 //
60 // to make this comparison regimen faster, we encode source color
61 // equivalency into a single byte with the getCode() macro
62 //
63 // #define getCode(b,f,h,d) ( (b == f)<<0 | (f == h)<<1 | (h == d)<<2 | (d == b)<<3 )
64
65 // encode the scale2x conditionals into a lookup code
66 for (i=0; i<16; i++) {
67 // E0 = D == B && B != F && D != H ? D : E; // 10-0 => 1000 or 1010 => 8 or A
68 filter_roundedRowMap[0*16+i] = (i == 0x8 || i == 0xA) ? 0 : 1;
69 // E1 = B == F && B != D && F != H ? F : E; // 0-01 => 0101 or 0001 => 5 or 1
70 filter_roundedRowMap[1*16+i] = (i == 0x5 || i == 0x1) ? 2 : 1;
71 // E2 = D == H && D != B && H != F ? D : E; // 010- => 0101 or 0100 => 5 or 4
72 filter_roundedRowMap[2*16+i] = (i == 0x4 || i == 0x5) ? 0 : 1;
73 // E3 = H == F && D != H && B != F ? F : E; // -010 => 1010 or 0010 => A or 2
74 filter_roundedRowMap[3*16+i] = (i == 0xA || i == 0x2) ? 2 : 1;
75 }
76
77 // fill the uvMap. this will return:
78 // 0/\1
79 // /4 \
80 // \ /
81 // 2\/3
82 // .. based on the uv coordinates
83 for (i=0; i<FILTER_UVDIM; i++) {
84 for (j=0; j<FILTER_UVDIM; j++) {
85 s = (FILTER_UVDIM/2) - i;
86 t = (FILTER_UVDIM/2) - j;
87 if (s>=0 && t>=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (s+t > FILTER_UVDIM/2) ? 0 : 4;
88 else if (s>=0 && t<=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (s-t > FILTER_UVDIM/2) ? 2 : 4;
89 else if (s<=0 && t>=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (-s+t > FILTER_UVDIM/2) ? 1 : 4;
90 else if (s<=0 && t<=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (-s-t > FILTER_UVDIM/2) ? 3 : 4;
91 else filter_roundedUVMap[i*FILTER_UVDIM+j] = 4;
92 }
93 }
94}
95
96byte *filter_getScale2xQuadColors(byte e, byte b, byte f, byte h, byte d) {
97 // A B C
98 // D E F
99 // G H I
100 // perform the Scale2x algorithm (quickly) to get the new quad to represent E
101 static byte quad[5];
102 static byte rowColors[3];
103 int code;
104
105 rowColors[0] = d;
106 rowColors[1] = e;
107 rowColors[2] = f;
108
109 #define getCode(b,f,h,d) ( (b == f)<<0 | (f == h)<<1 | (h == d)<<2 | (d == b)<<3 )
110
111 code = getCode(b,f,h,d);
112 quad[0] = rowColors[filter_roundedRowMap[0*16+code]];
113 quad[1] = rowColors[filter_roundedRowMap[1*16+code]];
114 quad[2] = rowColors[filter_roundedRowMap[2*16+code]];
115 quad[3] = rowColors[filter_roundedRowMap[3*16+code]];
116 quad[4] = e;
117
118 return quad;
119}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 *-----------------------------------------------------------------------------*/
30
31#ifndef R_FILTER_H
32#define R_FILTER_H
33
34#define DITHER_DIM 4
35
36extern byte filter_ditherMatrix[DITHER_DIM][DITHER_DIM];
37#define FILTER_UVBITS 6
38#define FILTER_UVDIM (1<<FILTER_UVBITS)
39extern byte filter_roundedUVMap[FILTER_UVDIM*FILTER_UVDIM];
40extern byte filter_roundedRowMap[4*16];
41
42void R_FilterInit(void);
43
44// Use the dither matrix to determine whether a pixel is on or off based
45// on the overall intensity we're trying to simulate
46#define filter_getDitheredPixelLevel(x, y, intensity) \
47 ((filter_ditherMatrix[(y)&(DITHER_DIM-1)][(x)&(DITHER_DIM-1)] < (intensity)) ? 1 : 0)
48
49// Choose current pixel or next pixel down based on dither of the fractional
50// texture V coord. texV is not a true fractional texture coord, so it
51// has to be converted using ((texV) - dcvars.yl) >> 8), which was empirically
52// derived. the "-dcvars.yl" is apparently required to offset some minor
53// shaking in coordinate y-axis and prevents dithering seams
54#define FILTER_GETV(x,y,texV,nextRowTexV) \
55 (filter_getDitheredPixelLevel(x, y, (((texV) - yl) >> 8)&0xff) ? ((nextRowTexV)>>FRACBITS) : ((texV)>>FRACBITS))
56
57// Choose current column or next column to the right based on dither of the
58// fractional texture U coord
59#define filter_getDitheredForColumn(x, y, texV, nextRowTexV) \
60 dither_sources[(filter_getDitheredPixelLevel(x, y, filter_fracu))][FILTER_GETV(x,y,texV,nextRowTexV)]
61
62#define filter_getRoundedForColumn(texV, nextRowTexV) \
63 filter_getScale2xQuadColors( \
64 source[ ((texV)>>FRACBITS) ], \
65 source[ (MAX(0, ((texV)>>FRACBITS)-1)) ], \
66 nextsource[ ((texV)>>FRACBITS) ], \
67 source[ ((nextRowTexV)>>FRACBITS) ], \
68 prevsource[ ((texV)>>FRACBITS) ] \
69 ) \
70 [ filter_roundedUVMap[ \
71 ((filter_fracu>>(8-FILTER_UVBITS))<<FILTER_UVBITS) + \
72 ((((texV)>>8) & 0xff)>>(8-FILTER_UVBITS)) \
73 ] ]
74
75#define filter_getRoundedForSpan(texU, texV) \
76 filter_getScale2xQuadColors( \
77 source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0) ], \
78 source[ (((texU)>>16)&0x3f) | ((((texV)-FRACUNIT)>>10)&0xfc0) ], \
79 source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0) ], \
80 source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0) ], \
81 source[ ((((texU)-FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0) ] \
82 ) \
83 [ filter_roundedUVMap[ \
84 (((((texU)>>8) & 0xff)>>(8-FILTER_UVBITS))<<FILTER_UVBITS) + \
85 ((((texV)>>8) & 0xff)>>(8-FILTER_UVBITS)) \
86 ] ]
87
88byte *filter_getScale2xQuadColors(byte e, byte b, byte f, byte h, byte d);
89
90// This is the horrendous macro version of the function commented out of
91// r_filter.c. It does a bilinear blend on the four source texels for a
92// given u and v
93#define filter_getFilteredForColumn32(depthmap, texV, nextRowTexV) ( \
94 VID_PAL32( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \
95 VID_PAL32( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \
96 VID_PAL32( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \
97 VID_PAL32( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ))
98
99// The 16 bit method of the filtering doesn't really maintain enough
100// accuracy for discerning viewers, but the alternative requires converting
101// from 32 bit, which is slow and requires both the intPalette and the
102// shortPalette to be in memory at the same time.
103#define filter_getFilteredForColumn16(depthmap, texV, nextRowTexV) ( \
104 VID_PAL16( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \
105 VID_PAL16( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \
106 VID_PAL16( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \
107 VID_PAL16( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ))
108
109#define filter_getFilteredForColumn15(depthmap, texV, nextRowTexV) ( \
110 VID_PAL15( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \
111 VID_PAL15( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \
112 VID_PAL15( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \
113 VID_PAL15( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ))
114
115// Same as for column but wrapping at 64
116#define filter_getFilteredForSpan32(depthmap, texU, texV) ( \
117 VID_PAL32( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \
118 VID_PAL32( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \
119 VID_PAL32( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \
120 VID_PAL32( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)))
121
122// Use 16 bit addition here since it's a little faster and the defects from
123// such low-accuracy blending are less visible on spans
124#define filter_getFilteredForSpan16(depthmap, texU, texV) ( \
125 VID_PAL16( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \
126 VID_PAL16( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \
127 VID_PAL16( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \
128 VID_PAL16( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)))
129
130#define filter_getFilteredForSpan15(depthmap, texU, texV) ( \
131 VID_PAL15( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \
132 VID_PAL15( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \
133 VID_PAL15( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \
134 VID_PAL15( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)))
135
136// do red and blue at once for slight speedup
137
138#define GETBLENDED15_5050(col1, col2) \
139 ((((col1&0x7c1f)+(col2&0x7c1f))>>1)&0x7c1f) | \
140 ((((col1&0x03e0)+(col2&0x03e0))>>1)&0x03e0)
141
142#define GETBLENDED16_5050(col1, col2) \
143 ((((col1&0xf81f)+(col2&0xf81f))>>1)&0xf81f) | \
144 ((((col1&0x07e0)+(col2&0x07e0))>>1)&0x07e0)
145
146#define GETBLENDED32_5050(col1, col2) \
147 ((((col1&0xff00ff)+(col2&0xff00ff))>>1)&0xff00ff) | \
148 ((((col1&0x00ff00)+(col2&0x00ff00))>>1)&0x00ff00)
149
150#define GETBLENDED15_3268(col1, col2) \
151 ((((col1&0x7c1f)*5+(col2&0x7c1f)*11)>>4)&0x7c1f) | \
152 ((((col1&0x03e0)*5+(col2&0x03e0)*11)>>4)&0x03e0)
153
154#define GETBLENDED16_3268(col1, col2) \
155 ((((col1&0xf81f)*5+(col2&0xf81f)*11)>>4)&0xf81f) | \
156 ((((col1&0x07e0)*5+(col2&0x07e0)*11)>>4)&0x07e0)
157
158#define GETBLENDED32_3268(col1, col2) \
159 ((((col1&0xff00ff)*5+(col2&0xff00ff)*11)>>4)&0xff00ff) | \
160 ((((col1&0x00ff00)*5+(col2&0x00ff00)*11)>>4)&0x00ff00)
161
162#define GETBLENDED15_9406(col1, col2) \
163 ((((col1&0x7c1f)*15+(col2&0x7c1f))>>4)&0x7c1f) | \
164 ((((col1&0x03e0)*15+(col2&0x03e0))>>4)&0x03e0)
165
166#define GETBLENDED16_9406(col1, col2) \
167 ((((col1&0xf81f)*15+(col2&0xf81f))>>4)&0xf81f) | \
168 ((((col1&0x07e0)*15+(col2&0x07e0))>>4)&0x07e0)
169
170#define GETBLENDED32_9406(col1, col2) \
171 ((((col1&0xff00ff)*15+(col2&0xff00ff))>>4)&0xff00ff) | \
172 ((((col1&0x00ff00)*15+(col2&0x00ff00))>>4)&0x00ff00)
173
174#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Uncapped framerate stuff
31 *
32 *---------------------------------------------------------------------
33 */
34
35#include "doomstat.h"
36#include "r_defs.h"
37#include "r_state.h"
38#include "p_spec.h"
39#include "r_demo.h"
40#include "r_fps.h"
41
42int movement_smooth = false;
43
44typedef enum
45{
46 INTERP_SectorFloor,
47 INTERP_SectorCeiling,
48 INTERP_Vertex,
49 INTERP_WallPanning,
50 INTERP_FloorPanning,
51 INTERP_CeilingPanning
52} interpolation_type_e;
53
54typedef struct
55{
56 interpolation_type_e type;
57 void *address;
58} interpolation_t;
59
60static int numinterpolations = 0;
61
62tic_vars_t tic_vars;
63
64view_vars_t original_view_vars;
65
66extern int realtic_clock_rate;
67void D_Display(void);
68
69void R_InitInterpolation(void)
70{
71 tic_vars.msec = realtic_clock_rate * TICRATE / 100000.0f;
72}
73
74typedef fixed_t fixed2_t[2];
75static fixed2_t *oldipos;
76static fixed2_t *bakipos;
77static interpolation_t *curipos;
78
79static boolean NoInterpolateView;
80static boolean didInterp;
81boolean WasRenderedInTryRunTics;
82
83void R_InterpolateView (player_t *player, fixed_t frac)
84{
85 if (movement_smooth)
86 {
87 if (NoInterpolateView)
88 {
89 NoInterpolateView = false;
90 original_view_vars.viewx = player->mo->x;
91 original_view_vars.viewy = player->mo->y;
92 original_view_vars.viewz = player->viewz;
93
94 original_view_vars.viewangle = player->mo->angle + viewangleoffset;
95 }
96
97 viewx = original_view_vars.viewx + FixedMul (frac, player->mo->x - original_view_vars.viewx);
98 viewy = original_view_vars.viewy + FixedMul (frac, player->mo->y - original_view_vars.viewy);
99 viewz = original_view_vars.viewz + FixedMul (frac, player->viewz - original_view_vars.viewz);
100
101 viewangle = original_view_vars.viewangle + FixedMul (frac, R_SmoothPlaying_Get(player->mo->angle) + viewangleoffset - original_view_vars.viewangle);
102 }
103 else
104 {
105 viewx = player->mo->x;
106 viewy = player->mo->y;
107 viewz = player->viewz;
108 viewangle = R_SmoothPlaying_Get(player->mo->angle);
109 }
110}
111
112void R_ResetViewInterpolation ()
113{
114 NoInterpolateView = true;
115}
116
117static void R_CopyInterpToOld (int i)
118{
119 switch (curipos[i].type)
120 {
121 case INTERP_SectorFloor:
122 oldipos[i][0] = ((sector_t*)curipos[i].address)->floorheight;
123 break;
124 case INTERP_SectorCeiling:
125 oldipos[i][0] = ((sector_t*)curipos[i].address)->ceilingheight;
126 break;
127 case INTERP_Vertex:
128 oldipos[i][0] = ((vertex_t*)curipos[i].address)->x;
129 oldipos[i][1] = ((vertex_t*)curipos[i].address)->y;
130 break;
131 case INTERP_WallPanning:
132 oldipos[i][0] = ((side_t*)curipos[i].address)->rowoffset;
133 oldipos[i][1] = ((side_t*)curipos[i].address)->textureoffset;
134 break;
135 case INTERP_FloorPanning:
136 oldipos[i][0] = ((sector_t*)curipos[i].address)->floor_xoffs;
137 oldipos[i][1] = ((sector_t*)curipos[i].address)->floor_yoffs;
138 break;
139 case INTERP_CeilingPanning:
140 oldipos[i][0] = ((sector_t*)curipos[i].address)->ceiling_xoffs;
141 oldipos[i][1] = ((sector_t*)curipos[i].address)->ceiling_yoffs;
142 break;
143 }
144}
145
146static void R_CopyBakToInterp (int i)
147{
148 switch (curipos[i].type)
149 {
150 case INTERP_SectorFloor:
151 ((sector_t*)curipos[i].address)->floorheight = bakipos[i][0];
152 break;
153 case INTERP_SectorCeiling:
154 ((sector_t*)curipos[i].address)->ceilingheight = bakipos[i][0];
155 break;
156 case INTERP_Vertex:
157 ((vertex_t*)curipos[i].address)->x = bakipos[i][0];
158 ((vertex_t*)curipos[i].address)->y = bakipos[i][1];
159 break;
160 case INTERP_WallPanning:
161 ((side_t*)curipos[i].address)->rowoffset = bakipos[i][0];
162 ((side_t*)curipos[i].address)->textureoffset = bakipos[i][1];
163 break;
164 case INTERP_FloorPanning:
165 ((sector_t*)curipos[i].address)->floor_xoffs = bakipos[i][0];
166 ((sector_t*)curipos[i].address)->floor_yoffs = bakipos[i][1];
167 break;
168 case INTERP_CeilingPanning:
169 ((sector_t*)curipos[i].address)->ceiling_xoffs = bakipos[i][0];
170 ((sector_t*)curipos[i].address)->ceiling_yoffs = bakipos[i][1];
171 break;
172 }
173}
174
175static void R_DoAnInterpolation (int i, fixed_t smoothratio)
176{
177 fixed_t pos;
178 fixed_t *adr1 = NULL;
179 fixed_t *adr2 = NULL;
180
181 switch (curipos[i].type)
182 {
183 case INTERP_SectorFloor:
184 adr1 = &((sector_t*)curipos[i].address)->floorheight;
185 break;
186 case INTERP_SectorCeiling:
187 adr1 = &((sector_t*)curipos[i].address)->ceilingheight;
188 break;
189 case INTERP_Vertex:
190 adr1 = &((vertex_t*)curipos[i].address)->x;
191//// adr2 = &((vertex_t*)curipos[i].Address)->y;
192 break;
193 case INTERP_WallPanning:
194 adr1 = &((side_t*)curipos[i].address)->rowoffset;
195 adr2 = &((side_t*)curipos[i].address)->textureoffset;
196 break;
197 case INTERP_FloorPanning:
198 adr1 = &((sector_t*)curipos[i].address)->floor_xoffs;
199 adr2 = &((sector_t*)curipos[i].address)->floor_yoffs;
200 break;
201 case INTERP_CeilingPanning:
202 adr1 = &((sector_t*)curipos[i].address)->ceiling_xoffs;
203 adr2 = &((sector_t*)curipos[i].address)->ceiling_yoffs;
204 break;
205
206 default:
207 return;
208 }
209
210 if (adr1)
211 {
212 pos = bakipos[i][0] = *adr1;
213 *adr1 = oldipos[i][0] + FixedMul (pos - oldipos[i][0], smoothratio);
214 }
215
216 if (adr2)
217 {
218 pos = bakipos[i][1] = *adr2;
219 *adr2 = oldipos[i][1] + FixedMul (pos - oldipos[i][1], smoothratio);
220 }
221}
222
223void R_UpdateInterpolations()
224{
225 int i;
226 if (!movement_smooth)
227 return;
228 for (i = numinterpolations-1; i >= 0; --i)
229 R_CopyInterpToOld (i);
230}
231
232int interpolations_max = 0;
233
234static void R_SetInterpolation(interpolation_type_e type, void *posptr)
235{
236 int i;
237 if (!movement_smooth)
238 return;
239
240 if (numinterpolations >= interpolations_max) {
241 interpolations_max = interpolations_max ? interpolations_max * 2 : 256;
242
243 oldipos = (fixed2_t*)realloc(oldipos, sizeof(*oldipos) * interpolations_max);
244 bakipos = (fixed2_t*)realloc(bakipos, sizeof(*bakipos) * interpolations_max);
245 curipos = (interpolation_t*)realloc(curipos, sizeof(*curipos) * interpolations_max);
246 }
247
248 for(i = numinterpolations-1; i >= 0; i--)
249 if (curipos[i].address == posptr && curipos[i].type == type)
250 return;
251
252 curipos[numinterpolations].address = posptr;
253 curipos[numinterpolations].type = type;
254 R_CopyInterpToOld (numinterpolations);
255 numinterpolations++;
256}
257
258static void R_StopInterpolation(interpolation_type_e type, void *posptr)
259{
260 int i;
261
262 if (!movement_smooth)
263 return;
264
265 for(i=numinterpolations-1; i>= 0; --i)
266 {
267 if (curipos[i].address == posptr && curipos[i].type == type)
268 {
269 numinterpolations--;
270 oldipos[i][0] = oldipos[numinterpolations][0];
271 oldipos[i][1] = oldipos[numinterpolations][1];
272 bakipos[i][0] = bakipos[numinterpolations][0];
273 bakipos[i][1] = bakipos[numinterpolations][1];
274 curipos[i] = curipos[numinterpolations];
275 break;
276 }
277 }
278}
279
280void R_StopAllInterpolations(void)
281{
282 int i;
283
284 if (!movement_smooth)
285 return;
286
287 for(i=numinterpolations-1; i>= 0; --i)
288 {
289 numinterpolations--;
290 oldipos[i][0] = oldipos[numinterpolations][0];
291 oldipos[i][1] = oldipos[numinterpolations][1];
292 bakipos[i][0] = bakipos[numinterpolations][0];
293 bakipos[i][1] = bakipos[numinterpolations][1];
294 curipos[i] = curipos[numinterpolations];
295 }
296}
297
298void R_DoInterpolations(fixed_t smoothratio)
299{
300 int i;
301 if (!movement_smooth)
302 return;
303
304 if (smoothratio == FRACUNIT)
305 {
306 didInterp = false;
307 return;
308 }
309
310 didInterp = true;
311
312 for (i = numinterpolations-1; i >= 0; --i)
313 {
314 R_DoAnInterpolation (i, smoothratio);
315 }
316}
317
318void R_RestoreInterpolations()
319{
320 int i;
321
322 if (!movement_smooth)
323 return;
324
325 if (didInterp)
326 {
327 didInterp = false;
328 for (i = numinterpolations-1; i >= 0; --i)
329 {
330 R_CopyBakToInterp (i);
331 }
332 }
333}
334
335void R_ActivateSectorInterpolations()
336{
337 int i;
338 sector_t *sec;
339
340 if (!movement_smooth)
341 return;
342
343 for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
344 {
345 if (sec->floordata)
346 R_SetInterpolation (INTERP_SectorFloor, sec);
347 if (sec->ceilingdata)
348 R_SetInterpolation (INTERP_SectorCeiling, sec);
349 }
350}
351
352static void R_InterpolationGetData(thinker_t *th,
353 interpolation_type_e *type1, interpolation_type_e *type2,
354 void **posptr1, void **posptr2)
355{
356 *posptr1 = NULL;
357 *posptr2 = NULL;
358
359 if (th->function == T_MoveFloor)
360 {
361 *type1 = INTERP_SectorFloor;
362 *posptr1 = ((floormove_t *)th)->sector;
363 }
364 else
365 if (th->function == T_PlatRaise)
366 {
367 *type1 = INTERP_SectorFloor;
368 *posptr1 = ((plat_t *)th)->sector;
369 }
370 else
371 if (th->function == T_MoveCeiling)
372 {
373 *type1 = INTERP_SectorCeiling;
374 *posptr1 = ((ceiling_t *)th)->sector;
375 }
376 else
377 if (th->function == T_VerticalDoor)
378 {
379 *type1 = INTERP_SectorCeiling;
380 *posptr1 = ((vldoor_t *)th)->sector;
381 }
382 else
383 if (th->function == T_MoveElevator)
384 {
385 *type1 = INTERP_SectorFloor;
386 *posptr1 = ((elevator_t *)th)->sector;
387 *type2 = INTERP_SectorCeiling;
388 *posptr2 = ((elevator_t *)th)->sector;
389 }
390 else
391 if (th->function == T_Scroll)
392 {
393 switch (((scroll_t *)th)->type)
394 {
395 case sc_side:
396 *type1 = INTERP_WallPanning;
397 *posptr1 = sides + ((scroll_t *)th)->affectee;
398 break;
399 case sc_floor:
400 *type1 = INTERP_FloorPanning;
401 *posptr1 = sectors + ((scroll_t *)th)->affectee;
402 break;
403 case sc_ceiling:
404 *type1 = INTERP_CeilingPanning;
405 *posptr1 = sectors + ((scroll_t *)th)->affectee;
406 break;
407 default: ;
408 }
409 }
410}
411
412void R_ActivateThinkerInterpolations(thinker_t *th)
413{
414 void *posptr1;
415 void *posptr2;
416 interpolation_type_e type1, type2;
417
418 if (!movement_smooth)
419 return;
420
421 R_InterpolationGetData(th, &type1, &type2, &posptr1, &posptr2);
422
423 if(posptr1)
424 {
425 R_SetInterpolation (type1, posptr1);
426
427 if(posptr2)
428 R_SetInterpolation (type2, posptr2);
429 }
430}
431
432void R_StopInterpolationIfNeeded(thinker_t *th)
433{
434 void *posptr1;
435 void *posptr2;
436 interpolation_type_e type1, type2;
437
438 if (!movement_smooth)
439 return;
440
441 R_InterpolationGetData(th, &type1, &type2, &posptr1, &posptr2);
442
443 if(posptr1)
444 {
445 R_StopInterpolation (type1, posptr1);
446 if(posptr2)
447 R_StopInterpolation (type2, posptr2);
448 }
449}
450
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Uncapped framerate stuff
31 *
32 *---------------------------------------------------------------------
33 */
34
35#ifndef __R_FPS__
36#define __R_FPS__
37
38#include "doomstat.h"
39
40extern int movement_smooth;
41
42typedef struct {
43 fixed_t viewx;
44 fixed_t viewy;
45 fixed_t viewz;
46 angle_t viewangle;
47 angle_t viewpitch;
48} view_vars_t;
49
50extern view_vars_t original_view_vars;
51
52typedef struct {
53 unsigned int start;
54 unsigned int next;
55 unsigned int step;
56 fixed_t frac;
57 float msec;
58} tic_vars_t;
59
60extern tic_vars_t tic_vars;
61
62void R_InitInterpolation(void);
63void R_InterpolateView (player_t *player, fixed_t frac);
64
65extern boolean WasRenderedInTryRunTics;
66
67void R_ResetViewInterpolation ();
68void R_UpdateInterpolations();
69void R_StopAllInterpolations(void);
70void R_DoInterpolations(fixed_t smoothratio);
71void R_RestoreInterpolations();
72void R_ActivateSectorInterpolations();
73void R_ActivateThinkerInterpolations(thinker_t *th);
74void R_StopInterpolationIfNeeded(thinker_t *th);
75
76#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Rendering main loop and setup functions,
31 * utility functions (BSP, geometry, trigonometry).
32 * See tables.c, too.
33 *
34 *-----------------------------------------------------------------------------*/
35
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40#ifdef USE_SDL
41#include "SDL.h"
42#endif
43#include "doomstat.h"
44#include "d_net.h"
45#include "w_wad.h"
46#include "r_main.h"
47#include "r_things.h"
48#include "r_plane.h"
49#include "r_bsp.h"
50#include "r_draw.h"
51#include "m_bbox.h"
52#include "r_sky.h"
53#include "v_video.h"
54#include "lprintf.h"
55#include "st_stuff.h"
56#include "i_main.h"
57#include "i_system.h"
58#include "g_game.h"
59#include "r_demo.h"
60#include "r_fps.h"
61
62// Fineangles in the SCREENWIDTH wide window.
63#define FIELDOFVIEW 2048
64
65// killough: viewangleoffset is a legacy from the pre-v1.2 days, when Doom
66// had Left/Mid/Right viewing. +/-ANG90 offsets were placed here on each
67// node, by d_net.c, to set up a L/M/R session.
68
69int viewangleoffset;
70int validcount = 1; // increment every time a check is made
71const lighttable_t *fixedcolormap;
72int centerx, centery;
73fixed_t centerxfrac, centeryfrac;
74fixed_t viewheightfrac; //e6y: for correct clipping of things
75fixed_t projection;
76// proff 11/06/98: Added for high-res
77fixed_t projectiony;
78fixed_t viewx, viewy, viewz;
79angle_t viewangle;
80fixed_t viewcos, viewsin;
81player_t *viewplayer;
82extern lighttable_t **walllights;
83
84static mobj_t *oviewer;
85
86//
87// precalculated math tables
88//
89
90angle_t clipangle;
91
92// The viewangletox[viewangle + FINEANGLES/4] lookup
93// maps the visible view angles to screen X coordinates,
94// flattening the arc to a flat projection plane.
95// There will be many angles mapped to the same X.
96
97int viewangletox[FINEANGLES/2];
98
99// The xtoviewangleangle[] table maps a screen pixel
100// to the lowest viewangle that maps back to x ranges
101// from clipangle to -clipangle.
102
103angle_t xtoviewangle[MAX_SCREENWIDTH+1]; // killough 2/8/98
104
105// killough 3/20/98: Support dynamic colormaps, e.g. deep water
106// killough 4/4/98: support dynamic number of them as well
107
108int numcolormaps;
109const lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ];
110const lighttable_t *(*zlight)[MAXLIGHTZ];
111const lighttable_t *fullcolormap;
112const lighttable_t **colormaps;
113
114// killough 3/20/98, 4/4/98: end dynamic colormaps
115
116int extralight; // bumped light from gun blasts
117
118//
119// R_PointOnSide
120// Traverse BSP (sub) tree,
121// check point against partition plane.
122// Returns side 0 (front) or 1 (back).
123//
124// killough 5/2/98: reformatted
125//
126
127PUREFUNC int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node)
128{
129 if (!node->dx)
130 return x <= node->x ? node->dy > 0 : node->dy < 0;
131
132 if (!node->dy)
133 return y <= node->y ? node->dx < 0 : node->dx > 0;
134
135 x -= node->x;
136 y -= node->y;
137
138 // Try to quickly decide by looking at sign bits.
139 if ((node->dy ^ node->dx ^ x ^ y) < 0)
140 return (node->dy ^ x) < 0; // (left is negative)
141 return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x);
142}
143
144// killough 5/2/98: reformatted
145
146PUREFUNC int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line)
147{
148 fixed_t lx = line->v1->x;
149 fixed_t ly = line->v1->y;
150 fixed_t ldx = line->v2->x - lx;
151 fixed_t ldy = line->v2->y - ly;
152
153 if (!ldx)
154 return x <= lx ? ldy > 0 : ldy < 0;
155
156 if (!ldy)
157 return y <= ly ? ldx < 0 : ldx > 0;
158
159 x -= lx;
160 y -= ly;
161
162 // Try to quickly decide by looking at sign bits.
163 if ((ldy ^ ldx ^ x ^ y) < 0)
164 return (ldy ^ x) < 0; // (left is negative)
165 return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x);
166}
167
168//
169// R_PointToAngle
170// To get a global angle from cartesian coordinates,
171// the coordinates are flipped until they are in
172// the first octant of the coordinate system, then
173// the y (<=x) is scaled and divided by x to get a
174// tangent (slope) value which is looked up in the
175// tantoangle[] table. The +1 size of tantoangle[]
176// is to handle the case when x==y without additional
177// checking.
178//
179// killough 5/2/98: reformatted, cleaned up
180
181#include <math.h>
182
183angle_t R_PointToAngle(fixed_t x, fixed_t y)
184{
185 static fixed_t oldx, oldy;
186 static angle_t oldresult;
187
188 x -= viewx; y -= viewy;
189
190 if ( /* !render_precise && */
191 // e6y: here is where "slime trails" can SOMETIMES occur
192#ifdef GL_DOOM
193 (V_GetMode() != VID_MODEGL) &&
194#endif
195 (x < INT_MAX/4 && x > -INT_MAX/4 && y < INT_MAX/4 && y > -INT_MAX/4)
196 )
197 {
198 // old R_PointToAngle
199 return (x || y) ?
200 x >= 0 ?
201 y >= 0 ?
202 (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0
203 ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1
204 x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8
205 ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7
206 y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3
207 ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2
208 (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4
209 ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5
210 0;
211 }
212
213 // R_PointToAngleEx merged into R_PointToAngle
214 // e6y: The precision of the code above is abysmal so use the CRT atan2 function instead!
215 if (oldx != x || oldy != y)
216 {
217 oldx = x;
218 oldy = y;
219 oldresult = (int)(atan2(y, x) * ANG180/M_PI);
220 }
221 return oldresult;
222}
223
224angle_t R_PointToAngle2(fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y)
225{
226 return (y -= viewy, (x -= viewx) || y) ?
227 x >= 0 ?
228 y >= 0 ?
229 (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0
230 ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1
231 x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8
232 ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7
233 y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3
234 ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2
235 (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4
236 ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5
237 0;
238}
239
240//
241// R_InitTextureMapping
242//
243// killough 5/2/98: reformatted
244
245static void R_InitTextureMapping (void)
246{
247 register int i,x;
248 fixed_t focallength;
249
250 // Use tangent table to generate viewangletox:
251 // viewangletox will give the next greatest x
252 // after the view angle.
253 //
254 // Calc focallength
255 // so FIELDOFVIEW angles covers SCREENWIDTH.
256
257 focallength = FixedDiv(centerxfrac, finetangent[FINEANGLES/4+FIELDOFVIEW/2]);
258
259 for (i=0 ; i<FINEANGLES/2 ; i++)
260 {
261 int t;
262 if (finetangent[i] > FRACUNIT*2)
263 t = -1;
264 else
265 if (finetangent[i] < -FRACUNIT*2)
266 t = viewwidth+1;
267 else
268 {
269 t = FixedMul(finetangent[i], focallength);
270 t = (centerxfrac - t + FRACUNIT-1) >> FRACBITS;
271 if (t < -1)
272 t = -1;
273 else
274 if (t > viewwidth+1)
275 t = viewwidth+1;
276 }
277 viewangletox[i] = t;
278 }
279
280 // Scan viewangletox[] to generate xtoviewangle[]:
281 // xtoviewangle will give the smallest view angle
282 // that maps to x.
283
284 for (x=0; x<=viewwidth; x++)
285 {
286 for (i=0; viewangletox[i] > x; i++)
287 ;
288 xtoviewangle[x] = (i<<ANGLETOFINESHIFT)-ANG90;
289 }
290
291 // Take out the fencepost cases from viewangletox.
292 for (i=0; i<FINEANGLES/2; i++)
293 if (viewangletox[i] == -1)
294 viewangletox[i] = 0;
295 else
296 if (viewangletox[i] == viewwidth+1)
297 viewangletox[i] = viewwidth;
298
299 clipangle = xtoviewangle[0];
300}
301
302//
303// R_InitLightTables
304//
305
306#define DISTMAP 2
307
308static void R_InitLightTables (void)
309{
310 int i;
311
312 // killough 4/4/98: dynamic colormaps
313 c_zlight = malloc(sizeof(*c_zlight) * numcolormaps);
314
315 // Calculate the light levels to use
316 // for each level / distance combination.
317 for (i=0; i< LIGHTLEVELS; i++)
318 {
319 int j, startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
320 for (j=0; j<MAXLIGHTZ; j++)
321 {
322 // CPhipps - use 320 here instead of SCREENWIDTH, otherwise hires is
323 // brighter than normal res
324 int scale = FixedDiv ((320/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
325 int t, level = startmap - (scale >>= LIGHTSCALESHIFT)/DISTMAP;
326
327 if (level < 0)
328 level = 0;
329 else
330 if (level >= NUMCOLORMAPS)
331 level = NUMCOLORMAPS-1;
332
333 // killough 3/20/98: Initialize multiple colormaps
334 level *= 256;
335 for (t=0; t<numcolormaps; t++) // killough 4/4/98
336 c_zlight[t][i][j] = colormaps[t] + level;
337 }
338 }
339}
340
341//
342// R_SetViewSize
343// Do not really change anything here,
344// because it might be in the middle of a refresh.
345// The change will take effect next refresh.
346//
347
348boolean setsizeneeded;
349int setblocks;
350
351void R_SetViewSize(int blocks)
352{
353 setsizeneeded = true;
354 setblocks = blocks;
355}
356
357//
358// R_ExecuteSetViewSize
359//
360
361void R_ExecuteSetViewSize (void)
362{
363 int i;
364
365 setsizeneeded = false;
366
367 if (setblocks == 11)
368 {
369 scaledviewwidth = SCREENWIDTH;
370 viewheight = SCREENHEIGHT;
371 }
372// proff 09/24/98: Added for high-res
373 else if (setblocks == 10)
374 {
375 scaledviewwidth = SCREENWIDTH;
376 viewheight = SCREENHEIGHT-ST_SCALED_HEIGHT;
377 }
378 else
379 {
380// proff 08/17/98: Changed for high-res
381 scaledviewwidth = setblocks*SCREENWIDTH/10;
382 viewheight = (setblocks*(SCREENHEIGHT-ST_SCALED_HEIGHT)/10) & ~7;
383 }
384
385 viewwidth = scaledviewwidth;
386
387 viewheightfrac = viewheight<<FRACBITS;//e6y
388
389 centery = viewheight/2;
390 centerx = viewwidth/2;
391 centerxfrac = centerx<<FRACBITS;
392 centeryfrac = centery<<FRACBITS;
393 projection = centerxfrac;
394// proff 11/06/98: Added for high-res
395 projectiony = ((SCREENHEIGHT * centerx * 320) / 200) / SCREENWIDTH * FRACUNIT;
396
397 R_InitBuffer (scaledviewwidth, viewheight);
398
399 R_InitTextureMapping();
400
401 // psprite scales
402// proff 08/17/98: Changed for high-res
403 pspritescale = FRACUNIT*viewwidth/320;
404 pspriteiscale = FRACUNIT*320/viewwidth;
405// proff 11/06/98: Added for high-res
406 pspriteyscale = (((SCREENHEIGHT*viewwidth)/SCREENWIDTH) << FRACBITS) / 200;
407
408 // thing clipping
409 for (i=0 ; i<viewwidth ; i++)
410 screenheightarray[i] = viewheight;
411
412 // planes
413 for (i=0 ; i<viewheight ; i++)
414 { // killough 5/2/98: reformatted
415 fixed_t dy = D_abs(((i-viewheight/2)<<FRACBITS)+FRACUNIT/2);
416// proff 08/17/98: Changed for high-res
417 yslope[i] = FixedDiv(projectiony, dy);
418 }
419
420 for (i=0 ; i<viewwidth ; i++)
421 {
422 fixed_t cosadj = D_abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
423 distscale[i] = FixedDiv(FRACUNIT,cosadj);
424 }
425
426}
427
428//
429// R_Init
430//
431
432extern int screenblocks;
433
434void R_Init (void)
435{
436 // CPhipps - R_DrawColumn isn't constant anymore, so must
437 // initialise in code
438 // current column draw function
439 lprintf(LO_INFO, "\nR_LoadTrigTables: ");
440 R_LoadTrigTables();
441 lprintf(LO_INFO, "\nR_InitData: ");
442 R_InitData();
443 R_SetViewSize(screenblocks);
444 lprintf(LO_INFO, "\nR_Init: R_InitPlanes ");
445 R_InitPlanes();
446 lprintf(LO_INFO, "R_InitLightTables ");
447 R_InitLightTables();
448 lprintf(LO_INFO, "R_InitSkyMap ");
449 R_InitSkyMap();
450 lprintf(LO_INFO, "R_InitTranslationsTables ");
451 R_InitTranslationTables();
452 lprintf(LO_INFO, "R_InitPatches ");
453 R_InitPatches();
454}
455
456//
457// R_PointInSubsector
458//
459// killough 5/2/98: reformatted, cleaned up
460
461subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
462{
463 int nodenum = numnodes-1;
464
465 // special case for trivial maps (single subsector, no nodes)
466 if (numnodes == 0)
467 return subsectors;
468
469 while (!(nodenum & NF_SUBSECTOR))
470 nodenum = nodes[nodenum].children[R_PointOnSide(x, y, nodes+nodenum)];
471 return &subsectors[nodenum & ~NF_SUBSECTOR];
472}
473
474//
475// R_SetupFrame
476//
477
478static void R_SetupFrame (player_t *player)
479{
480 int cm;
481 boolean NoInterpolate = paused || (menuactive && !demoplayback);
482
483 viewplayer = player;
484
485 if (player->mo != oviewer || NoInterpolate)
486 {
487 R_ResetViewInterpolation ();
488 oviewer = player->mo;
489 }
490 tic_vars.frac = I_GetTimeFrac ();
491 if (NoInterpolate)
492 tic_vars.frac = FRACUNIT;
493 R_InterpolateView (player, tic_vars.frac);
494
495 extralight = player->extralight;
496
497 viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
498 viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
499
500 R_DoInterpolations(tic_vars.frac);
501
502 // killough 3/20/98, 4/4/98: select colormap based on player status
503
504 if (player->mo->subsector->sector->heightsec != -1)
505 {
506 const sector_t *s = player->mo->subsector->sector->heightsec + sectors;
507 cm = viewz < s->floorheight ? s->bottommap : viewz > s->ceilingheight ?
508 s->topmap : s->midmap;
509 if (cm < 0 || cm > numcolormaps)
510 cm = 0;
511 }
512 else
513 cm = 0;
514
515 fullcolormap = colormaps[cm];
516 zlight = c_zlight[cm];
517
518 if (player->fixedcolormap)
519 {
520 fixedcolormap = fullcolormap // killough 3/20/98: use fullcolormap
521 + player->fixedcolormap*256*sizeof(lighttable_t);
522 }
523 else
524 fixedcolormap = 0;
525
526 validcount++;
527}
528
529int autodetect_hom = 0; // killough 2/7/98: HOM autodetection flag
530
531//
532// R_ShowStats
533//
534int rendered_visplanes, rendered_segs, rendered_vissprites;
535boolean rendering_stats;
536
537static void R_ShowStats(void)
538{
539//e6y
540#if USE_SDL
541 static unsigned int FPS_SavedTick = 0, FPS_FrameCount = 0;
542 unsigned int tick = SDL_GetTicks();
543 FPS_FrameCount++;
544 if(tick >= FPS_SavedTick + 1000)
545 {
546 doom_printf((V_GetMode() == VID_MODEGL)
547 ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d"
548 :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d",
549 1000 * FPS_FrameCount / (tick - FPS_SavedTick), rendered_segs,
550 rendered_visplanes, rendered_vissprites);
551 FPS_SavedTick = tick;
552 FPS_FrameCount = 0;
553 }
554#else
555
556#define KEEPTIMES 10
557 static int keeptime[KEEPTIMES], showtime;
558 int now = I_GetTime();
559
560 if (now - showtime > 35) {
561 doom_printf((V_GetMode() == VID_MODEGL)
562 ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d"
563 :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d",
564 (35*KEEPTIMES)/(now - keeptime[0]), rendered_segs,
565 rendered_visplanes, rendered_vissprites);
566 showtime = now;
567 }
568 memmove(keeptime, keeptime+1, sizeof(keeptime[0]) * (KEEPTIMES-1));
569 keeptime[KEEPTIMES-1] = now;
570
571#endif //e6y
572}
573
574//
575// R_RenderView
576//
577void R_RenderPlayerView (player_t* player)
578{
579 R_SetupFrame (player);
580
581 // Clear buffers.
582 R_ClearClipSegs ();
583 R_ClearDrawSegs ();
584 R_ClearPlanes ();
585 R_ClearSprites ();
586
587 rendered_segs = rendered_visplanes = 0;
588 if (V_GetMode() == VID_MODEGL)
589 {
590#ifdef GL_DOOM
591 // proff 11/99: clear buffers
592 gld_InitDrawScene();
593 // proff 11/99: switch to perspective mode
594 gld_StartDrawScene();
595#endif
596 } else {
597 if (autodetect_hom)
598 { // killough 2/10/98: add flashing red HOM indicators
599 unsigned char color=(gametic % 20) < 9 ? 0xb0 : 0;
600 V_FillRect(0, viewwindowx, viewwindowy, viewwidth, viewheight, color);
601 R_DrawViewBorder();
602 }
603 }
604
605 // check for new console commands.
606#ifdef HAVE_NET
607 NetUpdate ();
608#endif
609
610 // The head node is the last node output.
611 R_RenderBSPNode (numnodes-1);
612 R_ResetColumnBuffer();
613
614 // Check for new console commands.
615#ifdef HAVE_NET
616 NetUpdate ();
617#endif
618
619 if (V_GetMode() != VID_MODEGL)
620 R_DrawPlanes ();
621
622 // Check for new console commands.
623#ifdef HAVE_NET
624 NetUpdate ();
625#endif
626
627 if (V_GetMode() != VID_MODEGL) {
628 R_DrawMasked ();
629 R_ResetColumnBuffer();
630 }
631
632 // Check for new console commands.
633#ifdef HAVE_NET
634 NetUpdate ();
635#endif
636
637 if (V_GetMode() == VID_MODEGL) {
638#ifdef GL_DOOM
639 // proff 11/99: draw the scene
640 gld_DrawScene(player);
641 // proff 11/99: finishing off
642 gld_EndDrawScene();
643#endif
644 }
645
646 if (rendering_stats) R_ShowStats();
647
648 R_RestoreInterpolations();
649}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Renderer main interface.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_MAIN__
35#define __R_MAIN__
36
37#include "d_player.h"
38#include "r_data.h"
39
40#ifdef __GNUG__
41#pragma interface
42#endif
43
44//
45// POV related.
46//
47
48extern fixed_t viewcos;
49extern fixed_t viewsin;
50extern int viewwidth;
51extern int viewheight;
52extern int viewwindowx;
53extern int viewwindowy;
54extern int centerx;
55extern int centery;
56extern fixed_t centerxfrac;
57extern fixed_t centeryfrac;
58extern fixed_t viewheightfrac; //e6y: for correct clipping of things
59extern fixed_t projection;
60// proff 11/06/98: Added for high-res
61extern fixed_t projectiony;
62extern int validcount;
63
64//
65// Rendering stats
66//
67
68extern int rendered_visplanes, rendered_segs, rendered_vissprites;
69extern boolean rendering_stats;
70
71//
72// Lighting LUT.
73// Used for z-depth cuing per column/row,
74// and other lighting effects (sector ambient, flash).
75//
76
77// Lighting constants.
78
79#define LIGHTLEVELS 16
80#define LIGHTSEGSHIFT 4
81#define MAXLIGHTSCALE 48
82#define LIGHTSCALESHIFT 12
83#define MAXLIGHTZ 128
84#define LIGHTZSHIFT 20
85
86// killough 3/20/98: Allow colormaps to be dynamic (e.g. underwater)
87extern const lighttable_t *(*zlight)[MAXLIGHTZ];
88extern const lighttable_t *fullcolormap;
89extern int numcolormaps; // killough 4/4/98: dynamic number of maps
90extern const lighttable_t **colormaps;
91// killough 3/20/98, 4/4/98: end dynamic colormaps
92
93extern int extralight;
94extern const lighttable_t *fixedcolormap;
95
96// Number of diminishing brightness levels.
97// There a 0-31, i.e. 32 LUT in the COLORMAP lump.
98
99#define NUMCOLORMAPS 32
100
101//
102// Utility functions.
103//
104
105PUREFUNC int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node);
106PUREFUNC int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line);
107angle_t R_PointToAngle(fixed_t x, fixed_t y);
108angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
109subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
110
111//
112// REFRESH - the actual rendering functions.
113//
114
115void R_RenderPlayerView(player_t *player); // Called by G_Drawer.
116void R_Init(void); // Called by startup code.
117void R_SetViewSize(int blocks); // Called by M_Responder.
118void R_ExecuteSetViewSize(void); // cph - called by D_Display to complete a view resize
119
120#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 *-----------------------------------------------------------------------------*/
30
31#include "z_zone.h"
32#include "doomstat.h"
33#include "w_wad.h"
34#include "r_main.h"
35#include "r_sky.h"
36#include "r_bsp.h"
37#include "r_things.h"
38#include "p_tick.h"
39#include "i_system.h"
40#include "r_draw.h"
41#include "lprintf.h"
42#include "r_patch.h"
43#include <assert.h>
44
45// posts are runs of non masked source pixels
46typedef struct
47{
48 byte topdelta; // -1 is the last post in a column
49 byte length; // length data bytes follows
50} post_t;
51
52// column_t is a list of 0 or more post_t, (byte)-1 terminated
53typedef post_t column_t;
54
55//
56// Patches.
57// A patch holds one or more columns.
58// Patches are used for sprites and all masked pictures,
59// and we compose textures from the TEXTURE1/2 lists
60// of patches.
61//
62
63typedef struct
64{
65 short width, height; // bounding box size
66 short leftoffset; // pixels to the left of origin
67 short topoffset; // pixels below the origin
68 int columnofs[8]; // only [width] used
69} patch_t;
70
71//---------------------------------------------------------------------------
72// Re-engineered patch support
73//---------------------------------------------------------------------------
74static rpatch_t *patches = 0;
75
76static rpatch_t *texture_composites = 0;
77
78//---------------------------------------------------------------------------
79void R_InitPatches(void) {
80 if (!patches)
81 {
82 patches = (rpatch_t*)malloc(numlumps * sizeof(rpatch_t));
83 // clear out new patches to signal they're uninitialized
84 memset(patches, 0, sizeof(rpatch_t)*numlumps);
85 }
86 if (!texture_composites)
87 {
88 texture_composites = (rpatch_t*)malloc(numtextures * sizeof(rpatch_t));
89 // clear out new patches to signal they're uninitialized
90 memset(texture_composites, 0, sizeof(rpatch_t)*numtextures);
91 }
92}
93
94//---------------------------------------------------------------------------
95void R_FlushAllPatches(void) {
96 int i;
97
98 if (patches)
99 {
100 for (i=0; i < numlumps; i++)
101 if (patches[i].locks > 0)
102 I_Error("R_FlushAllPatches: patch number %i still locked",i);
103 free(patches);
104 patches = NULL;
105 }
106 if (texture_composites)
107 {
108 for (i=0; i<numtextures; i++)
109 if (texture_composites[i].data)
110 free(texture_composites[i].data);
111 free(texture_composites);
112 texture_composites = NULL;
113 }
114}
115
116//---------------------------------------------------------------------------
117int R_NumPatchWidth(int lump)
118{
119 const rpatch_t *patch = R_CachePatchNum(lump);
120 int width = patch->width;
121 R_UnlockPatchNum(lump);
122 return width;
123}
124
125//---------------------------------------------------------------------------
126int R_NumPatchHeight(int lump)
127{
128 const rpatch_t *patch = R_CachePatchNum(lump);
129 int height = patch->height;
130 R_UnlockPatchNum(lump);
131 return height;
132}
133
134//---------------------------------------------------------------------------
135static int getPatchIsNotTileable(const patch_t *patch) {
136 int x=0, numPosts, lastColumnDelta = 0;
137 const column_t *column;
138 int cornerCount = 0;
139 int hasAHole = 0;
140
141 for (x=0; x<SHORT(patch->width); x++) {
142 column = (const column_t *)((const byte *)patch + LONG(patch->columnofs[x]));
143 if (!x) lastColumnDelta = column->topdelta;
144 else if (lastColumnDelta != column->topdelta) hasAHole = 1;
145
146 numPosts = 0;
147 while (column->topdelta != 0xff) {
148 // check to see if a corner pixel filled
149 if (x == 0 && column->topdelta == 0) cornerCount++;
150 else if (x == 0 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++;
151 else if (x == SHORT(patch->width)-1 && column->topdelta == 0) cornerCount++;
152 else if (x == SHORT(patch->width)-1 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++;
153
154 if (numPosts++) hasAHole = 1;
155 column = (const column_t *)((const byte *)column + column->length + 4);
156 }
157 }
158
159 if (cornerCount == 4) return 0;
160 return hasAHole;
161}
162
163//---------------------------------------------------------------------------
164static int getIsSolidAtSpot(const column_t *column, int spot) {
165 if (!column) return 0;
166 while (column->topdelta != 0xff) {
167 if (spot < column->topdelta) return 0;
168 if ((spot >= column->topdelta) && (spot <= column->topdelta + column->length)) return 1;
169 column = (const column_t*)((const byte*)column + 3 + column->length + 1);
170 }
171 return 0;
172}
173
174//---------------------------------------------------------------------------
175// Used to determine whether a column edge (top or bottom) should slope
176// up or down for smoothed masked edges - POPE
177//---------------------------------------------------------------------------
178static int getColumnEdgeSlope(const column_t *prevcolumn, const column_t *nextcolumn, int spot) {
179 int holeToLeft = !getIsSolidAtSpot(prevcolumn, spot);
180 int holeToRight = !getIsSolidAtSpot(nextcolumn, spot);
181
182 if (holeToLeft && !holeToRight) return 1;
183 if (!holeToLeft && holeToRight) return -1;
184 return 0;
185}
186
187//---------------------------------------------------------------------------
188static void createPatch(int id) {
189 rpatch_t *patch;
190 const int patchNum = id;
191 const patch_t *oldPatch = (const patch_t*)W_CacheLumpNum(patchNum);
192 const column_t *oldColumn, *oldPrevColumn, *oldNextColumn;
193 int x, y;
194 int pixelDataSize;
195 int columnsDataSize;
196 int postsDataSize;
197 int dataSize;
198 int *numPostsInColumn;
199 int numPostsTotal;
200 const unsigned char *oldColumnPixelData;
201 int numPostsUsedSoFar;
202 int edgeSlope;
203
204#ifdef RANGECHECK
205 if (id >= numlumps)
206 I_Error("createPatch: %i >= numlumps", id);
207#endif
208
209 patch = &patches[id];
210 // proff - 2003-02-16 What about endianess?
211 patch->width = SHORT(oldPatch->width);
212 patch->widthmask = 0;
213 patch->height = SHORT(oldPatch->height);
214 patch->leftoffset = SHORT(oldPatch->leftoffset);
215 patch->topoffset = SHORT(oldPatch->topoffset);
216 patch->isNotTileable = getPatchIsNotTileable(oldPatch);
217
218 // work out how much memory we need to allocate for this patch's data
219 pixelDataSize = (patch->width * patch->height + 4) & ~3;
220 columnsDataSize = sizeof(rcolumn_t) * patch->width;
221
222 // count the number of posts in each column
223 numPostsInColumn = (int*)malloc(sizeof(int) * patch->width);
224 numPostsTotal = 0;
225
226 for (x=0; x<patch->width; x++) {
227 oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
228 numPostsInColumn[x] = 0;
229 while (oldColumn->topdelta != 0xff) {
230 numPostsInColumn[x]++;
231 numPostsTotal++;
232 oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
233 }
234 }
235
236 postsDataSize = numPostsTotal * sizeof(rpost_t);
237
238 // allocate our data chunk
239 dataSize = pixelDataSize + columnsDataSize + postsDataSize;
240 patch->data = (unsigned char*)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data);
241 memset(patch->data, 0, dataSize);
242
243 // set out pixel, column, and post pointers into our data array
244 patch->pixels = patch->data;
245 patch->columns = (rcolumn_t*)((unsigned char*)patch->pixels + pixelDataSize);
246 patch->posts = (rpost_t*)((unsigned char*)patch->columns + columnsDataSize);
247
248 // sanity check that we've got all the memory allocated we need
249 assert((((byte*)patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)patch->data) == dataSize);
250
251 memset(patch->pixels, 0xff, (patch->width*patch->height));
252
253 // fill in the pixels, posts, and columns
254 numPostsUsedSoFar = 0;
255 for (x=0; x<patch->width; x++) {
256
257 oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
258
259 if (patch->isNotTileable) {
260 // non-tiling
261 if (x == 0) oldPrevColumn = 0;
262 else oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x-1]));
263 if (x == patch->width-1) oldNextColumn = 0;
264 else oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x+1]));
265 }
266 else {
267 // tiling
268 int prevColumnIndex = x-1;
269 int nextColumnIndex = x+1;
270 while (prevColumnIndex < 0) prevColumnIndex += patch->width;
271 while (nextColumnIndex >= patch->width) nextColumnIndex -= patch->width;
272 oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex]));
273 oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex]));
274 }
275
276 // setup the column's data
277 patch->columns[x].pixels = patch->pixels + (x*patch->height) + 0;
278 patch->columns[x].numPosts = numPostsInColumn[x];
279 patch->columns[x].posts = patch->posts + numPostsUsedSoFar;
280
281 while (oldColumn->topdelta != 0xff) {
282 // set up the post's data
283 patch->posts[numPostsUsedSoFar].topdelta = oldColumn->topdelta;
284 patch->posts[numPostsUsedSoFar].length = oldColumn->length;
285 patch->posts[numPostsUsedSoFar].slope = 0;
286
287 edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta);
288 if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_UP;
289 else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_DOWN;
290
291 edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+oldColumn->length);
292 if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_UP;
293 else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_DOWN;
294
295 // fill in the post's pixels
296 oldColumnPixelData = (const byte *)oldColumn + 3;
297 for (y=0; y<oldColumn->length; y++) {
298 patch->pixels[x * patch->height + oldColumn->topdelta + y] = oldColumnPixelData[y];
299 }
300
301 oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
302 numPostsUsedSoFar++;
303 }
304 }
305
306 if (1 || patch->isNotTileable) {
307 const rcolumn_t *column, *prevColumn;
308
309 // copy the patch image down and to the right where there are
310 // holes to eliminate the black halo from bilinear filtering
311 for (x=0; x<patch->width; x++) {
312 //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]);
313
314 column = R_GetPatchColumnClamped(patch, x);
315 prevColumn = R_GetPatchColumnClamped(patch, x-1);
316
317 if (column->pixels[0] == 0xff) {
318 // force the first pixel (which is a hole), to use
319 // the color from the next solid spot in the column
320 for (y=0; y<patch->height; y++) {
321 if (column->pixels[y] != 0xff) {
322 column->pixels[0] = column->pixels[y];
323 break;
324 }
325 }
326 }
327
328 // copy from above or to the left
329 for (y=1; y<patch->height; y++) {
330 //if (getIsSolidAtSpot(oldColumn, y)) continue;
331 if (column->pixels[y] != 0xff) continue;
332
333 // this pixel is a hole
334
335 if (x && prevColumn->pixels[y-1] != 0xff) {
336 // copy the color from the left
337 column->pixels[y] = prevColumn->pixels[y];
338 }
339 else {
340 // copy the color from above
341 column->pixels[y] = column->pixels[y-1];
342 }
343 }
344 }
345
346 // verify that the patch truly is non-rectangular since
347 // this determines tiling later on
348 }
349
350 W_UnlockLumpNum(patchNum);
351 free(numPostsInColumn);
352}
353
354typedef struct {
355 unsigned short patches;
356 unsigned short posts;
357 unsigned short posts_used;
358} count_t;
359
360static void switchPosts(rpost_t *post1, rpost_t *post2) {
361 rpost_t dummy;
362
363 dummy.topdelta = post1->topdelta;
364 dummy.length = post1->length;
365 dummy.slope = post1->slope;
366 post1->topdelta = post2->topdelta;
367 post1->length = post2->length;
368 post1->slope = post2->slope;
369 post2->topdelta = dummy.topdelta;
370 post2->length = dummy.length;
371 post2->slope = dummy.slope;
372}
373
374static void removePostFromColumn(rcolumn_t *column, int post) {
375 int i;
376#ifdef RANGECHECK
377 if (post >= column->numPosts)
378 I_Error("removePostFromColumn: invalid post index");
379#endif
380 if (post < column->numPosts)
381 for (i=post; i<(column->numPosts-1); i++) {
382 rpost_t *post1 = &column->posts[i];
383 rpost_t *post2 = &column->posts[i+1];
384 post1->topdelta = post2->topdelta;
385 post1->length = post2->length;
386 post1->slope = post2->slope;
387 }
388 column->numPosts--;
389}
390
391//---------------------------------------------------------------------------
392static void createTextureCompositePatch(int id) {
393 rpatch_t *composite_patch;
394 texture_t *texture;
395 texpatch_t *texpatch;
396 int patchNum;
397 const patch_t *oldPatch;
398 const column_t *oldColumn, *oldPrevColumn, *oldNextColumn;
399 int i, x, y;
400 int oy, count;
401 int pixelDataSize;
402 int columnsDataSize;
403 int postsDataSize;
404 int dataSize;
405 int numPostsTotal;
406 const unsigned char *oldColumnPixelData;
407 int numPostsUsedSoFar;
408 int edgeSlope;
409 count_t *countsInColumn;
410
411#ifdef RANGECHECK
412 if (id >= numtextures)
413 I_Error("createTextureCompositePatch: %i >= numtextures", id);
414#endif
415
416 composite_patch = &texture_composites[id];
417
418 texture = textures[id];
419
420 composite_patch->width = texture->width;
421 composite_patch->height = texture->height;
422 composite_patch->widthmask = texture->widthmask;
423 composite_patch->leftoffset = 0;
424 composite_patch->topoffset = 0;
425 composite_patch->isNotTileable = 0;
426
427 // work out how much memory we need to allocate for this patch's data
428 pixelDataSize = (composite_patch->width * composite_patch->height + 4) & ~3;
429 columnsDataSize = sizeof(rcolumn_t) * composite_patch->width;
430
431 // count the number of posts in each column
432 countsInColumn = (count_t *)calloc(sizeof(count_t), composite_patch->width);
433 numPostsTotal = 0;
434
435 for (i=0; i<texture->patchcount; i++) {
436 texpatch = &texture->patches[i];
437 patchNum = texpatch->patch;
438 oldPatch = (const patch_t*)W_CacheLumpNum(patchNum);
439
440 for (x=0; x<SHORT(oldPatch->width); x++) {
441 int tx = texpatch->originx + x;
442
443 if (tx < 0)
444 continue;
445 if (tx >= composite_patch->width)
446 break;
447
448 countsInColumn[tx].patches++;
449
450 oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
451 while (oldColumn->topdelta != 0xff) {
452 countsInColumn[tx].posts++;
453 numPostsTotal++;
454 oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
455 }
456 }
457
458 W_UnlockLumpNum(patchNum);
459 }
460
461 postsDataSize = numPostsTotal * sizeof(rpost_t);
462
463 // allocate our data chunk
464 dataSize = pixelDataSize + columnsDataSize + postsDataSize;
465 composite_patch->data = (unsigned char*)Z_Malloc(dataSize, PU_STATIC, (void **)&composite_patch->data);
466 memset(composite_patch->data, 0, dataSize);
467
468 // set out pixel, column, and post pointers into our data array
469 composite_patch->pixels = composite_patch->data;
470 composite_patch->columns = (rcolumn_t*)((unsigned char*)composite_patch->pixels + pixelDataSize);
471 composite_patch->posts = (rpost_t*)((unsigned char*)composite_patch->columns + columnsDataSize);
472
473 // sanity check that we've got all the memory allocated we need
474 assert((((byte*)composite_patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)composite_patch->data) == dataSize);
475
476 memset(composite_patch->pixels, 0xff, (composite_patch->width*composite_patch->height));
477
478 numPostsUsedSoFar = 0;
479
480 for (x=0; x<texture->width; x++) {
481 // setup the column's data
482 composite_patch->columns[x].pixels = composite_patch->pixels + (x*composite_patch->height);
483 composite_patch->columns[x].numPosts = countsInColumn[x].posts;
484 composite_patch->columns[x].posts = composite_patch->posts + numPostsUsedSoFar;
485 numPostsUsedSoFar += countsInColumn[x].posts;
486 }
487
488 // fill in the pixels, posts, and columns
489 for (i=0; i<texture->patchcount; i++) {
490 texpatch = &texture->patches[i];
491 patchNum = texpatch->patch;
492 oldPatch = (const patch_t*)W_CacheLumpNum(patchNum);
493
494 for (x=0; x<SHORT(oldPatch->width); x++) {
495 int tx = texpatch->originx + x;
496
497 if (tx < 0)
498 continue;
499 if (tx >= composite_patch->width)
500 break;
501
502 oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
503
504 {
505 // tiling
506 int prevColumnIndex = x-1;
507 int nextColumnIndex = x+1;
508 while (prevColumnIndex < 0) prevColumnIndex += SHORT(oldPatch->width);
509 while (nextColumnIndex >= SHORT(oldPatch->width)) nextColumnIndex -= SHORT(oldPatch->width);
510 oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex]));
511 oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex]));
512 }
513
514 while (oldColumn->topdelta != 0xff) {
515 rpost_t *post = &composite_patch->columns[tx].posts[countsInColumn[tx].posts_used];
516 oldColumnPixelData = (const byte *)oldColumn + 3;
517 oy = texpatch->originy;
518 count = oldColumn->length;
519 // the original renderer had several bugs which we reproduce here
520 if (countsInColumn[tx].patches > 1) {
521 // when there are multiple patches, then we need to handle the
522 // column differently
523 if (i == 0) {
524 // draw first patch at original position, it will be partly
525 // overdrawn below
526 for (y=0; y<count; y++) {
527 int ty = oy + oldColumn->topdelta + y;
528 if (ty < 0)
529 continue;
530 if (ty >= composite_patch->height)
531 break;
532 composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y];
533 }
534 }
535 // do the buggy clipping
536 if ((oy + oldColumn->topdelta) < 0) {
537 count += oy;
538 oy = 0;
539 }
540 } else {
541 // with a single patch only negative y origins are wrong
542 oy = 0;
543 }
544 // set up the post's data
545 post->topdelta = oldColumn->topdelta + oy;
546 post->length = count;
547 if ((post->topdelta + post->length) > composite_patch->height) {
548 if (post->topdelta > composite_patch->height)
549 post->length = 0;
550 else
551 post->length = composite_patch->height - post->topdelta;
552 }
553 if (post->topdelta < 0) {
554 if ((post->topdelta + post->length) <= 0)
555 post->length = 0;
556 else
557 post->length -= post->topdelta;
558 post->topdelta = 0;
559 }
560 post->slope = 0;
561
562 edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta);
563 if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_TOP_UP;
564 else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_TOP_DOWN;
565
566 edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+count);
567 if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_BOT_UP;
568 else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_BOT_DOWN;
569
570 // fill in the post's pixels
571 for (y=0; y<count; y++) {
572 int ty = oy + oldColumn->topdelta + y;
573 if (ty < 0)
574 continue;
575 if (ty >= composite_patch->height)
576 break;
577 composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y];
578 }
579
580 oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
581 countsInColumn[tx].posts_used++;
582 assert(countsInColumn[tx].posts_used <= countsInColumn[tx].posts);
583 }
584 }
585
586 W_UnlockLumpNum(patchNum);
587 }
588
589 for (x=0; x<texture->width; x++) {
590 rcolumn_t *column;
591
592 if (countsInColumn[x].patches <= 1)
593 continue;
594
595 // cleanup posts on multipatch columns
596 column = &composite_patch->columns[x];
597
598 i = 0;
599 while (i<(column->numPosts-1)) {
600 rpost_t *post1 = &column->posts[i];
601 rpost_t *post2 = &column->posts[i+1];
602 int length;
603
604 if ((post2->topdelta - post1->topdelta) < 0)
605 switchPosts(post1, post2);
606
607 if ((post1->topdelta + post1->length) >= post2->topdelta) {
608 length = (post1->length + post2->length) - ((post1->topdelta + post1->length) - post2->topdelta);
609 if (post1->length < length) {
610 post1->slope = post2->slope;
611 post1->length = length;
612 }
613 removePostFromColumn(column, i+1);
614 i = 0;
615 continue;
616 }
617 i++;
618 }
619 }
620
621 if (1 || composite_patch->isNotTileable) {
622 const rcolumn_t *column, *prevColumn;
623
624 // copy the patch image down and to the right where there are
625 // holes to eliminate the black halo from bilinear filtering
626 for (x=0; x<composite_patch->width; x++) {
627 //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]);
628
629 column = R_GetPatchColumnClamped(composite_patch, x);
630 prevColumn = R_GetPatchColumnClamped(composite_patch, x-1);
631
632 if (column->pixels[0] == 0xff) {
633 // force the first pixel (which is a hole), to use
634 // the color from the next solid spot in the column
635 for (y=0; y<composite_patch->height; y++) {
636 if (column->pixels[y] != 0xff) {
637 column->pixels[0] = column->pixels[y];
638 break;
639 }
640 }
641 }
642
643 // copy from above or to the left
644 for (y=1; y<composite_patch->height; y++) {
645 //if (getIsSolidAtSpot(oldColumn, y)) continue;
646 if (column->pixels[y] != 0xff) continue;
647
648 // this pixel is a hole
649
650 if (x && prevColumn->pixels[y-1] != 0xff) {
651 // copy the color from the left
652 column->pixels[y] = prevColumn->pixels[y];
653 }
654 else {
655 // copy the color from above
656 column->pixels[y] = column->pixels[y-1];
657 }
658 }
659 }
660
661 // verify that the patch truly is non-rectangular since
662 // this determines tiling later on
663 }
664
665 free(countsInColumn);
666}
667
668//---------------------------------------------------------------------------
669const rpatch_t *R_CachePatchNum(int id) {
670 const int locks = 1;
671
672 if (!patches)
673 I_Error("R_CachePatchNum: Patches not initialized");
674
675#ifdef RANGECHECK
676 if (id >= numlumps)
677 I_Error("createPatch: %i >= numlumps", id);
678#endif
679
680 if (!patches[id].data)
681 createPatch(id);
682
683 /* cph - if wasn't locked but now is, tell z_zone to hold it */
684 if (!patches[id].locks && locks) {
685 Z_ChangeTag(patches[id].data,PU_STATIC);
686#ifdef TIMEDIAG
687 patches[id].locktic = gametic;
688#endif
689 }
690 patches[id].locks += locks;
691
692#ifdef SIMPLECHECKS
693 if (!((patches[id].locks+1) & 0xf))
694 lprintf(LO_DEBUG, "R_CachePatchNum: High lock on %8s (%d)\n",
695 lumpinfo[id].name, patches[id].locks);
696#endif
697
698 return &patches[id];
699}
700
701void R_UnlockPatchNum(int id)
702{
703 const int unlocks = 1;
704#ifdef SIMPLECHECKS
705 if ((signed short)patches[id].locks < unlocks)
706 lprintf(LO_DEBUG, "R_UnlockPatchNum: Excess unlocks on %8s (%d-%d)\n",
707 lumpinfo[id].name, patches[id].locks, unlocks);
708#endif
709 patches[id].locks -= unlocks;
710 /* cph - Note: must only tell z_zone to make purgeable if currently locked,
711 * else it might already have been purged
712 */
713 if (unlocks && !patches[id].locks)
714 Z_ChangeTag(patches[id].data, PU_CACHE);
715}
716
717//---------------------------------------------------------------------------
718const rpatch_t *R_CacheTextureCompositePatchNum(int id) {
719 const int locks = 1;
720
721 if (!texture_composites)
722 I_Error("R_CacheTextureCompositePatchNum: Composite patches not initialized");
723
724#ifdef RANGECHECK
725 if (id >= numtextures)
726 I_Error("createTextureCompositePatch: %i >= numtextures", id);
727#endif
728
729 if (!texture_composites[id].data)
730 createTextureCompositePatch(id);
731
732 /* cph - if wasn't locked but now is, tell z_zone to hold it */
733 if (!texture_composites[id].locks && locks) {
734 Z_ChangeTag(texture_composites[id].data,PU_STATIC);
735#ifdef TIMEDIAG
736 texture_composites[id].locktic = gametic;
737#endif
738 }
739 texture_composites[id].locks += locks;
740
741#ifdef SIMPLECHECKS
742 if (!((texture_composites[id].locks+1) & 0xf))
743 lprintf(LO_DEBUG, "R_CacheTextureCompositePatchNum: High lock on %8s (%d)\n",
744 textures[id]->name, texture_composites[id].locks);
745#endif
746
747 return &texture_composites[id];
748
749}
750
751void R_UnlockTextureCompositePatchNum(int id)
752{
753 const int unlocks = 1;
754#ifdef SIMPLECHECKS
755 if ((signed short)texture_composites[id].locks < unlocks)
756 lprintf(LO_DEBUG, "R_UnlockTextureCompositePatchNum: Excess unlocks on %8s (%d-%d)\n",
757 textures[id]->name, texture_composites[id].locks, unlocks);
758#endif
759 texture_composites[id].locks -= unlocks;
760 /* cph - Note: must only tell z_zone to make purgeable if currently locked,
761 * else it might already have been purged
762 */
763 if (unlocks && !texture_composites[id].locks)
764 Z_ChangeTag(texture_composites[id].data, PU_CACHE);
765}
766
767//---------------------------------------------------------------------------
768const rcolumn_t *R_GetPatchColumnWrapped(const rpatch_t *patch, int columnIndex) {
769 while (columnIndex < 0) columnIndex += patch->width;
770 columnIndex %= patch->width;
771 return &patch->columns[columnIndex];
772}
773
774//---------------------------------------------------------------------------
775const rcolumn_t *R_GetPatchColumnClamped(const rpatch_t *patch, int columnIndex) {
776 if (columnIndex < 0) columnIndex = 0;
777 if (columnIndex >= patch->width) columnIndex = patch->width-1;
778 return &patch->columns[columnIndex];
779}
780
781//---------------------------------------------------------------------------
782const rcolumn_t *R_GetPatchColumn(const rpatch_t *patch, int columnIndex) {
783 if (patch->isNotTileable) return R_GetPatchColumnClamped(patch, columnIndex);
784 else return R_GetPatchColumnWrapped(patch, columnIndex);
785}
786
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 *-----------------------------------------------------------------------------*/
30
31
32#ifndef R_PATCH_H
33#define R_PATCH_H
34
35// Used to specify the sloping of the top and bottom of a column post
36typedef enum {
37 RDRAW_EDGESLOPE_TOP_UP = (1<<0),
38 RDRAW_EDGESLOPE_TOP_DOWN = (1<<1),
39 RDRAW_EDGESLOPE_BOT_UP = (1<<2),
40 RDRAW_EDGESLOPE_BOT_DOWN = (1<<3),
41 RDRAW_EDGESLOPE_TOP_MASK = 0x3,
42 RDRAW_EDGESLOPE_BOT_MASK = 0xc,
43} edgeslope_t;
44
45typedef struct {
46 int topdelta;
47 int length;
48 edgeslope_t slope;
49} rpost_t;
50
51typedef struct {
52 int numPosts;
53 rpost_t *posts;
54 unsigned char *pixels;
55} rcolumn_t;
56
57typedef struct {
58 int width;
59 int height;
60 unsigned widthmask;
61
62 unsigned char isNotTileable;
63
64 int leftoffset;
65 int topoffset;
66
67 // this is the single malloc'ed/free'd array
68 // for this patch
69 unsigned char *data;
70
71 // these are pointers into the data array
72 unsigned char *pixels;
73 rcolumn_t *columns;
74 rpost_t *posts;
75
76#ifdef TIMEDIAG
77 int locktic;
78#endif
79 unsigned int locks;
80} rpatch_t;
81
82
83const rpatch_t *R_CachePatchNum(int id);
84void R_UnlockPatchNum(int id);
85#define R_CachePatchName(name) R_CachePatchNum(W_GetNumForName(name))
86#define R_UnlockPatchName(name) R_UnlockPatchNum(W_GetNumForName(name))
87
88const rpatch_t *R_CacheTextureCompositePatchNum(int id);
89void R_UnlockTextureCompositePatchNum(int id);
90
91
92// Size query funcs
93int R_NumPatchWidth(int lump) ;
94int R_NumPatchHeight(int lump);
95#define R_NamePatchWidth(name) R_NumPatchWidth(W_GetNumForName(name))
96#define R_NamePatchHeight(name) R_NumPatchHeight(W_GetNumForName(name))
97
98
99const rcolumn_t *R_GetPatchColumnWrapped(const rpatch_t *patch, int columnIndex);
100const rcolumn_t *R_GetPatchColumnClamped(const rpatch_t *patch, int columnIndex);
101
102
103// returns R_GetPatchColumnWrapped for square, non-holed textures
104// and R_GetPatchColumnClamped otherwise
105const rcolumn_t *R_GetPatchColumn(const rpatch_t *patch, int columnIndex);
106
107
108void R_InitPatches();
109void R_FlushAllPatches();
110
111#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Here is a core component: drawing the floors and ceilings,
31 * while maintaining a per column clipping list only.
32 * Moreover, the sky areas have to be determined.
33 *
34 * MAXVISPLANES is no longer a limit on the number of visplanes,
35 * but a limit on the number of hash slots; larger numbers mean
36 * better performance usually but after a point they are wasted,
37 * and memory and time overheads creep in.
38 *
39 * For more information on visplanes, see:
40 *
41 * http://classicgaming.com/doom/editing/
42 *
43 * Lee Killough
44 *
45 *-----------------------------------------------------------------------------*/
46
47#ifdef HAVE_CONFIG_H
48#include "config.h"
49#endif
50
51#include "z_zone.h" /* memory allocation wrappers -- killough */
52
53#include "doomstat.h"
54#include "w_wad.h"
55#include "r_main.h"
56#include "r_draw.h"
57#include "r_things.h"
58#include "r_sky.h"
59#include "r_plane.h"
60#include "v_video.h"
61#include "lprintf.h"
62
63#define MAXVISPLANES 128 /* must be a power of 2 */
64
65static visplane_t *visplanes[MAXVISPLANES]; // killough
66static visplane_t *freetail; // killough
67static visplane_t **freehead = &freetail; // killough
68visplane_t *floorplane, *ceilingplane;
69
70// killough -- hash function for visplanes
71// Empirically verified to be fairly uniform:
72
73#define visplane_hash(picnum,lightlevel,height) \
74 ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & (MAXVISPLANES-1))
75
76size_t maxopenings;
77int *openings,*lastopening; // dropoff overflow
78
79// Clip values are the solid pixel bounding the range.
80// floorclip starts out SCREENHEIGHT
81// ceilingclip starts out -1
82
83int floorclip[MAX_SCREENWIDTH], ceilingclip[MAX_SCREENWIDTH]; // dropoff overflow
84
85// spanstart holds the start of a plane span; initialized to 0 at start
86
87static int spanstart[MAX_SCREENHEIGHT]; // killough 2/8/98
88
89//
90// texture mapping
91//
92
93static const lighttable_t **planezlight;
94static fixed_t planeheight;
95
96// killough 2/8/98: make variables static
97
98static fixed_t basexscale, baseyscale;
99static fixed_t cachedheight[MAX_SCREENHEIGHT];
100static fixed_t cacheddistance[MAX_SCREENHEIGHT];
101static fixed_t cachedxstep[MAX_SCREENHEIGHT];
102static fixed_t cachedystep[MAX_SCREENHEIGHT];
103static fixed_t xoffs,yoffs; // killough 2/28/98: flat offsets
104
105fixed_t yslope[MAX_SCREENHEIGHT], distscale[MAX_SCREENWIDTH];
106
107//
108// R_InitPlanes
109// Only at game startup.
110//
111void R_InitPlanes (void)
112{
113}
114
115//
116// R_MapPlane
117//
118// Uses global vars:
119// planeheight
120// dsvars.source
121// basexscale
122// baseyscale
123// viewx
124// viewy
125// xoffs
126// yoffs
127//
128// BASIC PRIMITIVE
129//
130
131static void R_MapPlane(int y, int x1, int x2, draw_span_vars_t *dsvars)
132{
133 angle_t angle;
134 fixed_t distance, length;
135 unsigned index;
136
137#ifdef RANGECHECK
138 if (x2 < x1 || x1<0 || x2>=viewwidth || (unsigned)y>(unsigned)viewheight)
139 I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
140#endif
141
142 if (planeheight != cachedheight[y])
143 {
144 cachedheight[y] = planeheight;
145 distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
146 dsvars->xstep = cachedxstep[y] = FixedMul (distance,basexscale);
147 dsvars->ystep = cachedystep[y] = FixedMul (distance,baseyscale);
148 }
149 else
150 {
151 distance = cacheddistance[y];
152 dsvars->xstep = cachedxstep[y];
153 dsvars->ystep = cachedystep[y];
154 }
155
156 length = FixedMul (distance,distscale[x1]);
157 angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT;
158
159 // killough 2/28/98: Add offsets
160 dsvars->xfrac = viewx + FixedMul(finecosine[angle], length) + xoffs;
161 dsvars->yfrac = -viewy - FixedMul(finesine[angle], length) + yoffs;
162
163 if (drawvars.filterfloor == RDRAW_FILTER_LINEAR) {
164 dsvars->xfrac -= (FRACUNIT>>1);
165 dsvars->yfrac -= (FRACUNIT>>1);
166 }
167
168 if (!(dsvars->colormap = fixedcolormap))
169 {
170 dsvars->z = distance;
171 index = distance >> LIGHTZSHIFT;
172 if (index >= MAXLIGHTZ )
173 index = MAXLIGHTZ-1;
174 dsvars->colormap = planezlight[index];
175 dsvars->nextcolormap = planezlight[index+1 >= MAXLIGHTZ ? MAXLIGHTZ-1 : index+1];
176 }
177 else
178 {
179 dsvars->z = 0;
180 }
181
182 dsvars->y = y;
183 dsvars->x1 = x1;
184 dsvars->x2 = x2;
185
186 if (V_GetMode() != VID_MODEGL)
187 R_DrawSpan(dsvars);
188}
189
190//
191// R_ClearPlanes
192// At begining of frame.
193//
194
195void R_ClearPlanes(void)
196{
197 int i;
198
199 // opening / clipping determination
200 for (i=0 ; i<viewwidth ; i++)
201 floorclip[i] = viewheight, ceilingclip[i] = -1;
202
203 for (i=0;i<MAXVISPLANES;i++) // new code -- killough
204 for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; )
205 freehead = &(*freehead)->next;
206
207 lastopening = openings;
208
209 // texture calculation
210 memset (cachedheight, 0, sizeof(cachedheight));
211
212 // scale will be unit scale at SCREENWIDTH/2 distance
213 basexscale = FixedDiv (viewsin,projection);
214 baseyscale = FixedDiv (viewcos,projection);
215}
216
217// New function, by Lee Killough
218
219static visplane_t *new_visplane(unsigned hash)
220{
221 visplane_t *check = freetail;
222 if (!check)
223 check = calloc(1, sizeof *check);
224 else
225 if (!(freetail = freetail->next))
226 freehead = &freetail;
227 check->next = visplanes[hash];
228 visplanes[hash] = check;
229 return check;
230}
231
232/*
233 * R_DupPlane
234 *
235 * cph 2003/04/18 - create duplicate of existing visplane and set initial range
236 */
237visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop)
238{
239 unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height);
240 visplane_t *new_pl = new_visplane(hash);
241
242 new_pl->height = pl->height;
243 new_pl->picnum = pl->picnum;
244 new_pl->lightlevel = pl->lightlevel;
245 new_pl->xoffs = pl->xoffs; // killough 2/28/98
246 new_pl->yoffs = pl->yoffs;
247 new_pl->minx = start;
248 new_pl->maxx = stop;
249 memset(new_pl->top, 0xff, sizeof new_pl->top);
250 return new_pl;
251}
252//
253// R_FindPlane
254//
255// killough 2/28/98: Add offsets
256
257visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel,
258 fixed_t xoffs, fixed_t yoffs)
259{
260 visplane_t *check;
261 unsigned hash; // killough
262
263 if (picnum == skyflatnum || picnum & PL_SKYFLAT)
264 height = lightlevel = 0; // killough 7/19/98: most skies map together
265
266 // New visplane algorithm uses hash table -- killough
267 hash = visplane_hash(picnum,lightlevel,height);
268
269 for (check=visplanes[hash]; check; check=check->next) // killough
270 if (height == check->height &&
271 picnum == check->picnum &&
272 lightlevel == check->lightlevel &&
273 xoffs == check->xoffs && // killough 2/28/98: Add offset checks
274 yoffs == check->yoffs)
275 return check;
276
277 check = new_visplane(hash); // killough
278
279 check->height = height;
280 check->picnum = picnum;
281 check->lightlevel = lightlevel;
282 check->minx = viewwidth; // Was SCREENWIDTH -- killough 11/98
283 check->maxx = -1;
284 check->xoffs = xoffs; // killough 2/28/98: Save offsets
285 check->yoffs = yoffs;
286
287 memset (check->top, 0xff, sizeof check->top);
288
289 return check;
290}
291
292//
293// R_CheckPlane
294//
295visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop)
296{
297 int intrl, intrh, unionl, unionh, x;
298
299 if (start < pl->minx)
300 intrl = pl->minx, unionl = start;
301 else
302 unionl = pl->minx, intrl = start;
303
304 if (stop > pl->maxx)
305 intrh = pl->maxx, unionh = stop;
306 else
307 unionh = pl->maxx, intrh = stop;
308
309 for (x=intrl ; x <= intrh && pl->top[x] == 0xffffffffu; x++) // dropoff overflow
310 ;
311
312 if (x > intrh) { /* Can use existing plane; extend range */
313 pl->minx = unionl; pl->maxx = unionh;
314 return pl;
315 } else /* Cannot use existing plane; create a new one */
316 return R_DupPlane(pl,start,stop);
317}
318
319//
320// R_MakeSpans
321//
322
323static void R_MakeSpans(int x, unsigned int t1, unsigned int b1,
324 unsigned int t2, unsigned int b2,
325 draw_span_vars_t *dsvars)
326{
327 for (; t1 < t2 && t1 <= b1; t1++)
328 R_MapPlane(t1, spanstart[t1], x-1, dsvars);
329 for (; b1 > b2 && b1 >= t1; b1--)
330 R_MapPlane(b1, spanstart[b1] ,x-1, dsvars);
331 while (t2 < t1 && t2 <= b2)
332 spanstart[t2++] = x;
333 while (b2 > b1 && b2 >= t2)
334 spanstart[b2--] = x;
335}
336
337// New function, by Lee Killough
338
339static void R_DoDrawPlane(visplane_t *pl)
340{
341 register int x;
342 draw_column_vars_t dcvars;
343 R_DrawColumn_f colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz);
344
345 R_SetDefaultDrawColumnVars(&dcvars);
346
347 if (pl->minx <= pl->maxx) {
348 if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT) { // sky flat
349 int texture;
350 const rpatch_t *tex_patch;
351 angle_t an, flip;
352
353 // killough 10/98: allow skies to come from sidedefs.
354 // Allows scrolling and/or animated skies, as well as
355 // arbitrary multiple skies per level without having
356 // to use info lumps.
357
358 an = viewangle;
359
360 if (pl->picnum & PL_SKYFLAT)
361 {
362 // Sky Linedef
363 const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT];
364
365 // Sky transferred from first sidedef
366 const side_t *s = *l->sidenum + sides;
367
368 // Texture comes from upper texture of reference sidedef
369 texture = texturetranslation[s->toptexture];
370
371 // Horizontal offset is turned into an angle offset,
372 // to allow sky rotation as well as careful positioning.
373 // However, the offset is scaled very small, so that it
374 // allows a long-period of sky rotation.
375
376 an += s->textureoffset;
377
378 // Vertical offset allows careful sky positioning.
379
380 dcvars.texturemid = s->rowoffset - 28*FRACUNIT;
381
382 // We sometimes flip the picture horizontally.
383 //
384 // Doom always flipped the picture, so we make it optional,
385 // to make it easier to use the new feature, while to still
386 // allow old sky textures to be used.
387
388 flip = l->special==272 ? 0u : ~0u;
389 }
390 else
391 { // Normal Doom sky, only one allowed per level
392 dcvars.texturemid = skytexturemid; // Default y-offset
393 texture = skytexture; // Default texture
394 flip = 0; // Doom flips it
395 }
396
397 /* Sky is always drawn full bright, i.e. colormaps[0] is used.
398 * Because of this hack, sky is not affected by INVUL inverse mapping.
399 * Until Boom fixed this. Compat option added in MBF. */
400
401 if (comp[comp_skymap] || !(dcvars.colormap = fixedcolormap))
402 dcvars.colormap = fullcolormap; // killough 3/20/98
403
404 dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE
405
406 //dcvars.texturemid = skytexturemid;
407 dcvars.texheight = textureheight[skytexture]>>FRACBITS; // killough
408 // proff 09/21/98: Changed for high-res
409 dcvars.iscale = FRACUNIT*200/viewheight;
410
411 tex_patch = R_CacheTextureCompositePatchNum(texture);
412
413 // killough 10/98: Use sky scrolling offset, and possibly flip picture
414 for (x = pl->minx; (dcvars.x = x) <= pl->maxx; x++)
415 if ((dcvars.yl = pl->top[x]) != -1 && dcvars.yl <= (dcvars.yh = pl->bottom[x])) // dropoff overflow
416 {
417 dcvars.source = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x])^flip) >> ANGLETOSKYSHIFT);
418 dcvars.prevsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x-1])^flip) >> ANGLETOSKYSHIFT);
419 dcvars.nextsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x+1])^flip) >> ANGLETOSKYSHIFT);
420 colfunc(&dcvars);
421 }
422
423 R_UnlockTextureCompositePatchNum(texture);
424
425 } else { // regular flat
426
427 int stop, light;
428 draw_span_vars_t dsvars;
429
430 dsvars.source = W_CacheLumpNum(firstflat + flattranslation[pl->picnum]);
431
432 xoffs = pl->xoffs; // killough 2/28/98: Add offsets
433 yoffs = pl->yoffs;
434 planeheight = D_abs(pl->height-viewz);
435 light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight;
436
437 if (light >= LIGHTLEVELS)
438 light = LIGHTLEVELS-1;
439
440 if (light < 0)
441 light = 0;
442
443 stop = pl->maxx + 1;
444 planezlight = zlight[light];
445 pl->top[pl->minx-1] = pl->top[stop] = 0xffffffffu; // dropoff overflow
446
447 for (x = pl->minx ; x <= stop ; x++)
448 R_MakeSpans(x,pl->top[x-1],pl->bottom[x-1],
449 pl->top[x],pl->bottom[x], &dsvars);
450
451 W_UnlockLumpNum(firstflat + flattranslation[pl->picnum]);
452 }
453 }
454}
455
456//
457// RDrawPlanes
458// At the end of each frame.
459//
460
461void R_DrawPlanes (void)
462{
463 visplane_t *pl;
464 int i;
465 for (i=0;i<MAXVISPLANES;i++)
466 for (pl=visplanes[i]; pl; pl=pl->next, rendered_visplanes++)
467 R_DoDrawPlane(pl);
468}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Refresh, visplane stuff (floor, ceilings).
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_PLANE__
35#define __R_PLANE__
36
37#include "r_data.h"
38
39#ifdef __GNUG__
40#pragma interface
41#endif
42
43/* killough 10/98: special mask indicates sky flat comes from sidedef */
44#define PL_SKYFLAT (0x80000000)
45
46/* Visplane related. */
47extern int *lastopening; // dropoff overflow
48
49extern int floorclip[], ceilingclip[]; // dropoff overflow
50extern fixed_t yslope[], distscale[];
51
52void R_InitPlanes(void);
53void R_ClearPlanes(void);
54void R_DrawPlanes (void);
55
56visplane_t *R_FindPlane(
57 fixed_t height,
58 int picnum,
59 int lightlevel,
60 fixed_t xoffs, /* killough 2/28/98: add x-y offsets */
61 fixed_t yoffs
62 );
63
64visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop);
65visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop);
66
67#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2004 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * All the clipping: columns, horizontal spans, sky columns.
31 *
32 *-----------------------------------------------------------------------------*/
33//
34// 4/25/98, 5/2/98 killough: reformatted, beautified
35
36#include "doomstat.h"
37#include "r_main.h"
38#include "r_bsp.h"
39#include "r_segs.h"
40#include "r_plane.h"
41#include "r_things.h"
42#include "r_draw.h"
43#include "w_wad.h"
44#include "v_video.h"
45#include "lprintf.h"
46
47// OPTIMIZE: closed two sided lines as single sided
48
49// killough 1/6/98: replaced globals with statics where appropriate
50
51// True if any of the segs textures might be visible.
52static boolean segtextured;
53static boolean markfloor; // False if the back side is the same plane.
54static boolean markceiling;
55static boolean maskedtexture;
56static int toptexture;
57static int bottomtexture;
58static int midtexture;
59
60static fixed_t toptexheight, midtexheight, bottomtexheight; // cph
61
62angle_t rw_normalangle; // angle to line origin
63int rw_angle1;
64fixed_t rw_distance;
65
66//
67// regular wall
68//
69static int rw_x;
70static int rw_stopx;
71static angle_t rw_centerangle;
72static fixed_t rw_offset;
73static fixed_t rw_scale;
74static fixed_t rw_scalestep;
75static fixed_t rw_midtexturemid;
76static fixed_t rw_toptexturemid;
77static fixed_t rw_bottomtexturemid;
78static int rw_lightlevel;
79static int worldtop;
80static int worldbottom;
81static int worldhigh;
82static int worldlow;
83static fixed_t pixhigh;
84static fixed_t pixlow;
85static fixed_t pixhighstep;
86static fixed_t pixlowstep;
87static fixed_t topfrac;
88static fixed_t topstep;
89static fixed_t bottomfrac;
90static fixed_t bottomstep;
91static int *maskedtexturecol; // dropoff overflow
92
93//
94// R_ScaleFromGlobalAngle
95// Returns the texture mapping scale
96// for the current line (horizontal span)
97// at the given angle.
98// rw_distance must be calculated first.
99//
100// killough 5/2/98: reformatted, cleaned up
101// CPhipps - moved here from r_main.c
102
103static fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
104{
105 int anglea = ANG90 + (visangle-viewangle);
106 int angleb = ANG90 + (visangle-rw_normalangle);
107 int den = FixedMul(rw_distance, finesine[anglea>>ANGLETOFINESHIFT]);
108// proff 11/06/98: Changed for high-res
109 fixed_t num = FixedMul(projectiony, finesine[angleb>>ANGLETOFINESHIFT]);
110 return den > num>>16 ? (num = FixedDiv(num, den)) > 64*FRACUNIT ?
111 64*FRACUNIT : num < 256 ? 256 : num : 64*FRACUNIT;
112}
113
114//
115// R_RenderMaskedSegRange
116//
117
118void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2)
119{
120 int texnum;
121 sector_t tempsec; // killough 4/13/98
122 const rpatch_t *patch;
123 R_DrawColumn_f colfunc;
124 draw_column_vars_t dcvars;
125 angle_t angle;
126
127 R_SetDefaultDrawColumnVars(&dcvars);
128
129 // Calculate light table.
130 // Use different light tables
131 // for horizontal / vertical / diagonal. Diagonal?
132
133 curline = ds->curline; // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
134
135 // killough 4/11/98: draw translucent 2s normal textures
136
137 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz);
138 if (curline->linedef->tranlump >= 0 && general_translucency)
139 {
140 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, drawvars.filterwall, drawvars.filterz);
141 tranmap = main_tranmap;
142 if (curline->linedef->tranlump > 0)
143 tranmap = W_CacheLumpNum(curline->linedef->tranlump-1);
144 }
145 // killough 4/11/98: end translucent 2s normal code
146
147 frontsector = curline->frontsector;
148 backsector = curline->backsector;
149
150 // cph 2001/11/25 - middle textures did not animate in v1.2
151 texnum = curline->sidedef->midtexture;
152 if (!comp[comp_maskedanim])
153 texnum = texturetranslation[texnum];
154
155 // killough 4/13/98: get correct lightlevel for 2s normal textures
156 rw_lightlevel = R_FakeFlat(frontsector, &tempsec, NULL, NULL, false) ->lightlevel;
157
158 maskedtexturecol = ds->maskedtexturecol;
159
160 rw_scalestep = ds->scalestep;
161 spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
162 mfloorclip = ds->sprbottomclip;
163 mceilingclip = ds->sprtopclip;
164
165 // find positioning
166 if (curline->linedef->flags & ML_DONTPEGBOTTOM)
167 {
168 dcvars.texturemid = frontsector->floorheight > backsector->floorheight
169 ? frontsector->floorheight : backsector->floorheight;
170 dcvars.texturemid = dcvars.texturemid + textureheight[texnum] - viewz;
171 }
172 else
173 {
174 dcvars.texturemid =frontsector->ceilingheight<backsector->ceilingheight
175 ? frontsector->ceilingheight : backsector->ceilingheight;
176 dcvars.texturemid = dcvars.texturemid - viewz;
177 }
178
179 dcvars.texturemid += curline->sidedef->rowoffset;
180
181 if (fixedcolormap) {
182 dcvars.colormap = fixedcolormap;
183 dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE
184 }
185
186 patch = R_CacheTextureCompositePatchNum(texnum);
187
188 // draw the columns
189 for (dcvars.x = x1 ; dcvars.x <= x2 ; dcvars.x++, spryscale += rw_scalestep)
190 if (maskedtexturecol[dcvars.x] != INT_MAX) // dropoff overflow
191 {
192 // calculate texture offset - POPE
193 angle = (ds->rw_centerangle + xtoviewangle[dcvars.x]) >> ANGLETOFINESHIFT;
194 dcvars.texu = ds->rw_offset - FixedMul(finetangent[angle], ds->rw_distance);
195 if (drawvars.filterwall == RDRAW_FILTER_LINEAR)
196 dcvars.texu -= (FRACUNIT>>1);
197
198 if (!fixedcolormap)
199 dcvars.z = spryscale; // for filtering -- POPE
200 dcvars.colormap = R_ColourMap(rw_lightlevel,spryscale);
201 dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,spryscale); // for filtering -- POPE
202
203 // killough 3/2/98:
204 //
205 // This calculation used to overflow and cause crashes in Doom:
206 //
207 // sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid, spryscale);
208 //
209 // This code fixes it, by using double-precision intermediate
210 // arithmetic and by skipping the drawing of 2s normals whose
211 // mapping to screen coordinates is totally out of range:
212
213 {
214 int_64_t t = ((int_64_t) centeryfrac << FRACBITS) -
215 (int_64_t) dcvars.texturemid * spryscale;
216 if (t + (int_64_t) textureheight[texnum] * spryscale < 0 ||
217 t > (int_64_t) MAX_SCREENHEIGHT << FRACBITS*2)
218 continue; // skip if the texture is out of screen's range
219 sprtopscreen = (long)(t >> FRACBITS);
220 }
221
222 dcvars.iscale = 0xffffffffu / (unsigned) spryscale;
223
224 // killough 1/25/98: here's where Medusa came in, because
225 // it implicitly assumed that the column was all one patch.
226 // Originally, Doom did not construct complete columns for
227 // multipatched textures, so there were no header or trailer
228 // bytes in the column referred to below, which explains
229 // the Medusa effect. The fix is to construct true columns
230 // when forming multipatched textures (see r_data.c).
231
232 // draw the texture
233 R_DrawMaskedColumn(
234 patch,
235 colfunc,
236 &dcvars,
237 R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]),
238 R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]-1),
239 R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]+1)
240 );
241
242 maskedtexturecol[dcvars.x] = INT_MAX; // dropoff overflow
243 }
244
245 // Except for main_tranmap, mark others purgable at this point
246 if (curline->linedef->tranlump > 0 && general_translucency)
247 W_UnlockLumpNum(curline->linedef->tranlump-1); // cph - unlock it
248
249 R_UnlockTextureCompositePatchNum(texnum);
250
251 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 */
252}
253
254//
255// R_RenderSegLoop
256// Draws zero, one, or two textures (and possibly a masked texture) for walls.
257// Can draw or mark the starting pixel of floor and ceiling textures.
258// CALLED: CORE LOOPING ROUTINE.
259//
260
261#define HEIGHTBITS 12
262#define HEIGHTUNIT (1<<HEIGHTBITS)
263static int didsolidcol; /* True if at least one column was marked solid */
264
265static void R_RenderSegLoop (void)
266{
267 const rpatch_t *tex_patch;
268 R_DrawColumn_f colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz);
269 draw_column_vars_t dcvars;
270 fixed_t texturecolumn = 0; // shut up compiler warning
271
272 R_SetDefaultDrawColumnVars(&dcvars);
273
274 rendered_segs++;
275 for ( ; rw_x < rw_stopx ; rw_x++)
276 {
277
278 // mark floor / ceiling areas
279
280 int yh = bottomfrac>>HEIGHTBITS;
281 int yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
282
283 // no space above wall?
284 int bottom,top = ceilingclip[rw_x]+1;
285
286 if (yl < top)
287 yl = top;
288
289 if (markceiling)
290 {
291 bottom = yl-1;
292
293 if (bottom >= floorclip[rw_x])
294 bottom = floorclip[rw_x]-1;
295
296 if (top <= bottom)
297 {
298 ceilingplane->top[rw_x] = top;
299 ceilingplane->bottom[rw_x] = bottom;
300 }
301 // SoM: this should be set here
302 ceilingclip[rw_x] = bottom;
303 }
304
305// yh = bottomfrac>>HEIGHTBITS;
306
307 bottom = floorclip[rw_x]-1;
308 if (yh > bottom)
309 yh = bottom;
310
311 if (markfloor)
312 {
313
314 top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh;
315
316 if (++top <= bottom)
317 {
318 floorplane->top[rw_x] = top;
319 floorplane->bottom[rw_x] = bottom;
320 }
321 // SoM: This should be set here to prevent overdraw
322 floorclip[rw_x] = top;
323 }
324
325 // texturecolumn and lighting are independent of wall tiers
326 if (segtextured)
327 {
328 // calculate texture offset
329 angle_t angle =(rw_centerangle+xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
330
331 texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
332 if (drawvars.filterwall == RDRAW_FILTER_LINEAR)
333 texturecolumn -= (FRACUNIT>>1);
334 dcvars.texu = texturecolumn; // for filtering -- POPE
335 texturecolumn >>= FRACBITS;
336
337 dcvars.colormap = R_ColourMap(rw_lightlevel,rw_scale);
338 dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,rw_scale); // for filtering -- POPE
339 dcvars.z = rw_scale; // for filtering -- POPE
340
341 dcvars.x = rw_x;
342 dcvars.iscale = 0xffffffffu / (unsigned)rw_scale;
343 }
344
345 // draw the wall tiers
346 if (midtexture)
347 {
348
349 dcvars.yl = yl; // single sided line
350 dcvars.yh = yh;
351 dcvars.texturemid = rw_midtexturemid;
352 tex_patch = R_CacheTextureCompositePatchNum(midtexture);
353 dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn);
354 dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1);
355 dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1);
356 dcvars.texheight = midtexheight;
357 colfunc (&dcvars);
358 R_UnlockTextureCompositePatchNum(midtexture);
359 tex_patch = NULL;
360 ceilingclip[rw_x] = viewheight;
361 floorclip[rw_x] = -1;
362 }
363 else
364 {
365
366 // two sided line
367 if (toptexture)
368 {
369 // top wall
370 int mid = pixhigh>>HEIGHTBITS;
371 pixhigh += pixhighstep;
372
373 if (mid >= floorclip[rw_x])
374 mid = floorclip[rw_x]-1;
375
376 if (mid >= yl)
377 {
378 dcvars.yl = yl;
379 dcvars.yh = mid;
380 dcvars.texturemid = rw_toptexturemid;
381 tex_patch = R_CacheTextureCompositePatchNum(toptexture);
382 dcvars.source = R_GetTextureColumn(tex_patch,texturecolumn);
383 dcvars.prevsource = R_GetTextureColumn(tex_patch,texturecolumn-1);
384 dcvars.nextsource = R_GetTextureColumn(tex_patch,texturecolumn+1);
385 dcvars.texheight = toptexheight;
386 colfunc (&dcvars);
387 R_UnlockTextureCompositePatchNum(toptexture);
388 tex_patch = NULL;
389 ceilingclip[rw_x] = mid;
390 }
391 else
392 ceilingclip[rw_x] = yl-1;
393 }
394 else // no top wall
395 {
396
397 if (markceiling)
398 ceilingclip[rw_x] = yl-1;
399 }
400
401 if (bottomtexture) // bottom wall
402 {
403 int mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
404 pixlow += pixlowstep;
405
406 // no space above wall?
407 if (mid <= ceilingclip[rw_x])
408 mid = ceilingclip[rw_x]+1;
409
410 if (mid <= yh)
411 {
412 dcvars.yl = mid;
413 dcvars.yh = yh;
414 dcvars.texturemid = rw_bottomtexturemid;
415 tex_patch = R_CacheTextureCompositePatchNum(bottomtexture);
416 dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn);
417 dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1);
418 dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1);
419 dcvars.texheight = bottomtexheight;
420 colfunc (&dcvars);
421 R_UnlockTextureCompositePatchNum(bottomtexture);
422 tex_patch = NULL;
423 floorclip[rw_x] = mid;
424 }
425 else
426 floorclip[rw_x] = yh+1;
427 }
428 else // no bottom wall
429 {
430 if (markfloor)
431 floorclip[rw_x] = yh+1;
432 }
433
434 // cph - if we completely blocked further sight through this column,
435 // add this info to the solid columns array for r_bsp.c
436 if ((markceiling || markfloor) &&
437 (floorclip[rw_x] <= ceilingclip[rw_x] + 1)) {
438 solidcol[rw_x] = 1; didsolidcol = 1;
439 }
440
441 // save texturecol for backdrawing of masked mid texture
442 if (maskedtexture)
443 maskedtexturecol[rw_x] = texturecolumn;
444 }
445
446 rw_scale += rw_scalestep;
447 topfrac += topstep;
448 bottomfrac += bottomstep;
449 }
450}
451
452// killough 5/2/98: move from r_main.c, made static, simplified
453
454static fixed_t R_PointToDist(fixed_t x, fixed_t y)
455{
456 fixed_t dx = D_abs(x - viewx);
457 fixed_t dy = D_abs(y - viewy);
458
459 if (dy > dx)
460 {
461 fixed_t t = dx;
462 dx = dy;
463 dy = t;
464 }
465
466 return FixedDiv(dx, finesine[(tantoangle[FixedDiv(dy,dx) >> DBITS]
467 + ANG90) >> ANGLETOFINESHIFT]);
468}
469
470//
471// R_StoreWallRange
472// A wall segment will be drawn
473// between start and stop pixels (inclusive).
474//
475void R_StoreWallRange(const int start, const int stop)
476{
477 fixed_t hyp;
478 angle_t offsetangle;
479
480 if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM
481 {
482 unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a
483 unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough
484 drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs));
485 ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a
486 maxdrawsegs = newmax;
487 }
488
489 if(curline->miniseg == false) // figgi -- skip minisegs
490 curline->linedef->flags |= ML_MAPPED;
491
492#ifdef GL_DOOM
493 if (V_GetMode() == VID_MODEGL)
494 {
495 // proff 11/99: the rest of the calculations is not needed for OpenGL
496 ds_p++->curline = curline;
497 gld_AddWall(curline);
498
499 return;
500 }
501#endif
502
503
504#ifdef RANGECHECK
505 if (start >=viewwidth || start > stop)
506 I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
507#endif
508
509 sidedef = curline->sidedef;
510 linedef = curline->linedef;
511
512 // mark the segment as visible for auto map
513 linedef->flags |= ML_MAPPED;
514
515 // calculate rw_distance for scale calculation
516 rw_normalangle = curline->angle + ANG90;
517
518 offsetangle = rw_normalangle-rw_angle1;
519
520 if (D_abs(offsetangle) > ANG90)
521 offsetangle = ANG90;
522
523 hyp = (viewx==curline->v1->x && viewy==curline->v1->y)?
524 0 : R_PointToDist (curline->v1->x, curline->v1->y);
525 rw_distance = FixedMul(hyp, finecosine[offsetangle>>ANGLETOFINESHIFT]);
526
527 ds_p->x1 = rw_x = start;
528 ds_p->x2 = stop;
529 ds_p->curline = curline;
530 rw_stopx = stop+1;
531
532 { // killough 1/6/98, 2/1/98: remove limit on openings
533 extern int *openings; // dropoff overflow
534 extern size_t maxopenings;
535 size_t pos = lastopening - openings;
536 size_t need = (rw_stopx - start)*4 + pos;
537 if (need > maxopenings)
538 {
539 drawseg_t *ds; //jff 8/9/98 needed for fix from ZDoom
540 int *oldopenings = openings; // dropoff overflow
541 int *oldlast = lastopening; // dropoff overflow
542
543 do
544 maxopenings = maxopenings ? maxopenings*2 : 16384;
545 while (need > maxopenings);
546 openings = realloc(openings, maxopenings * sizeof(*openings));
547 lastopening = openings + pos;
548
549 // jff 8/9/98 borrowed fix for openings from ZDOOM1.14
550 // [RH] We also need to adjust the openings pointers that
551 // were already stored in drawsegs.
552 for (ds = drawsegs; ds < ds_p; ds++)
553 {
554#define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast)\
555 ds->p = ds->p - oldopenings + openings;
556 ADJUST (maskedtexturecol);
557 ADJUST (sprtopclip);
558 ADJUST (sprbottomclip);
559 }
560#undef ADJUST
561 }
562 } // killough: end of code to remove limits on openings
563
564 // calculate scale at both ends and step
565
566 ds_p->scale1 = rw_scale =
567 R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
568
569 if (stop > start)
570 {
571 ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
572 ds_p->scalestep = rw_scalestep = (ds_p->scale2-rw_scale) / (stop-start);
573 }
574 else
575 ds_p->scale2 = ds_p->scale1;
576
577 // calculate texture boundaries
578 // and decide if floor / ceiling marks are needed
579
580 worldtop = frontsector->ceilingheight - viewz;
581 worldbottom = frontsector->floorheight - viewz;
582
583 midtexture = toptexture = bottomtexture = maskedtexture = 0;
584 ds_p->maskedtexturecol = NULL;
585
586 if (!backsector)
587 {
588 // single sided line
589 midtexture = texturetranslation[sidedef->midtexture];
590 midtexheight = (linedef->r_flags & RF_MID_TILE) ? 0 : textureheight[midtexture] >> FRACBITS;
591
592 // a single sided line is terminal, so it must mark ends
593 markfloor = markceiling = true;
594
595 if (linedef->flags & ML_DONTPEGBOTTOM)
596 { // bottom of texture at bottom
597 fixed_t vtop = frontsector->floorheight +
598 textureheight[sidedef->midtexture];
599 rw_midtexturemid = vtop - viewz;
600 }
601 else // top of texture at top
602 rw_midtexturemid = worldtop;
603
604 rw_midtexturemid += FixedMod(sidedef->rowoffset, textureheight[midtexture]);
605
606 ds_p->silhouette = SIL_BOTH;
607 ds_p->sprtopclip = screenheightarray;
608 ds_p->sprbottomclip = negonearray;
609 ds_p->bsilheight = INT_MAX;
610 ds_p->tsilheight = INT_MIN;
611 }
612 else // two sided line
613 {
614 ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
615 ds_p->silhouette = 0;
616
617 if (linedef->r_flags & RF_CLOSED) { /* cph - closed 2S line e.g. door */
618 // cph - killough's (outdated) comment follows - this deals with both
619 // "automap fixes", his and mine
620 // killough 1/17/98: this test is required if the fix
621 // for the automap bug (r_bsp.c) is used, or else some
622 // sprites will be displayed behind closed doors. That
623 // fix prevents lines behind closed doors with dropoffs
624 // from being displayed on the automap.
625
626 ds_p->silhouette = SIL_BOTH;
627 ds_p->sprbottomclip = negonearray;
628 ds_p->bsilheight = INT_MAX;
629 ds_p->sprtopclip = screenheightarray;
630 ds_p->tsilheight = INT_MIN;
631
632 } else { /* not solid - old code */
633
634 if (frontsector->floorheight > backsector->floorheight)
635 {
636 ds_p->silhouette = SIL_BOTTOM;
637 ds_p->bsilheight = frontsector->floorheight;
638 }
639 else
640 if (backsector->floorheight > viewz)
641 {
642 ds_p->silhouette = SIL_BOTTOM;
643 ds_p->bsilheight = INT_MAX;
644 }
645
646 if (frontsector->ceilingheight < backsector->ceilingheight)
647 {
648 ds_p->silhouette |= SIL_TOP;
649 ds_p->tsilheight = frontsector->ceilingheight;
650 }
651 else
652 if (backsector->ceilingheight < viewz)
653 {
654 ds_p->silhouette |= SIL_TOP;
655 ds_p->tsilheight = INT_MIN;
656 }
657 }
658
659 worldhigh = backsector->ceilingheight - viewz;
660 worldlow = backsector->floorheight - viewz;
661
662 // hack to allow height changes in outdoor areas
663 if (frontsector->ceilingpic == skyflatnum
664 && backsector->ceilingpic == skyflatnum)
665 worldtop = worldhigh;
666
667 markfloor = worldlow != worldbottom
668 || backsector->floorpic != frontsector->floorpic
669 || backsector->lightlevel != frontsector->lightlevel
670
671 // killough 3/7/98: Add checks for (x,y) offsets
672 || backsector->floor_xoffs != frontsector->floor_xoffs
673 || backsector->floor_yoffs != frontsector->floor_yoffs
674
675 // killough 4/15/98: prevent 2s normals
676 // from bleeding through deep water
677 || frontsector->heightsec != -1
678
679 // killough 4/17/98: draw floors if different light levels
680 || backsector->floorlightsec != frontsector->floorlightsec
681 ;
682
683 markceiling = worldhigh != worldtop
684 || backsector->ceilingpic != frontsector->ceilingpic
685 || backsector->lightlevel != frontsector->lightlevel
686
687 // killough 3/7/98: Add checks for (x,y) offsets
688 || backsector->ceiling_xoffs != frontsector->ceiling_xoffs
689 || backsector->ceiling_yoffs != frontsector->ceiling_yoffs
690
691 // killough 4/15/98: prevent 2s normals
692 // from bleeding through fake ceilings
693 || (frontsector->heightsec != -1 &&
694 frontsector->ceilingpic!=skyflatnum)
695
696 // killough 4/17/98: draw ceilings if different light levels
697 || backsector->ceilinglightsec != frontsector->ceilinglightsec
698 ;
699
700 if (backsector->ceilingheight <= frontsector->floorheight
701 || backsector->floorheight >= frontsector->ceilingheight)
702 markceiling = markfloor = true; // closed door
703
704 if (worldhigh < worldtop) // top texture
705 {
706 toptexture = texturetranslation[sidedef->toptexture];
707 toptexheight = (linedef->r_flags & RF_TOP_TILE) ? 0 : textureheight[toptexture] >> FRACBITS;
708 rw_toptexturemid = linedef->flags & ML_DONTPEGTOP ? worldtop :
709 backsector->ceilingheight+textureheight[sidedef->toptexture]-viewz;
710 rw_toptexturemid += FixedMod(sidedef->rowoffset, textureheight[toptexture]);
711 }
712
713 if (worldlow > worldbottom) // bottom texture
714 {
715 bottomtexture = texturetranslation[sidedef->bottomtexture];
716 bottomtexheight = (linedef->r_flags & RF_BOT_TILE) ? 0 : textureheight[bottomtexture] >> FRACBITS;
717 rw_bottomtexturemid = linedef->flags & ML_DONTPEGBOTTOM ? worldtop :
718 worldlow;
719 rw_bottomtexturemid += FixedMod(sidedef->rowoffset, textureheight[bottomtexture]);
720 }
721
722 // allocate space for masked texture tables
723 if (sidedef->midtexture) // masked midtexture
724 {
725 maskedtexture = true;
726 ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
727 lastopening += rw_stopx - rw_x;
728 }
729 }
730
731 // calculate rw_offset (only needed for textured lines)
732 segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
733
734 if (segtextured)
735 {
736 rw_offset = FixedMul (hyp, -finesine[offsetangle >>ANGLETOFINESHIFT]);
737
738 rw_offset += sidedef->textureoffset + curline->offset;
739
740 rw_centerangle = ANG90 + viewangle - rw_normalangle;
741
742 rw_lightlevel = frontsector->lightlevel;
743 }
744
745 // Remember the vars used to determine fractional U texture
746 // coords for later - POPE
747 ds_p->rw_offset = rw_offset;
748 ds_p->rw_distance = rw_distance;
749 ds_p->rw_centerangle = rw_centerangle;
750
751 // if a floor / ceiling plane is on the wrong side of the view
752 // plane, it is definitely invisible and doesn't need to be marked.
753
754 // killough 3/7/98: add deep water check
755 if (frontsector->heightsec == -1)
756 {
757 if (frontsector->floorheight >= viewz) // above view plane
758 markfloor = false;
759 if (frontsector->ceilingheight <= viewz &&
760 frontsector->ceilingpic != skyflatnum) // below view plane
761 markceiling = false;
762 }
763
764 // calculate incremental stepping values for texture edges
765 worldtop >>= 4;
766 worldbottom >>= 4;
767
768 topstep = -FixedMul (rw_scalestep, worldtop);
769 topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
770
771 bottomstep = -FixedMul (rw_scalestep,worldbottom);
772 bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
773
774 if (backsector)
775 {
776 worldhigh >>= 4;
777 worldlow >>= 4;
778
779 if (worldhigh < worldtop)
780 {
781 pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
782 pixhighstep = -FixedMul (rw_scalestep,worldhigh);
783 }
784 if (worldlow > worldbottom)
785 {
786 pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
787 pixlowstep = -FixedMul (rw_scalestep,worldlow);
788 }
789 }
790
791 // render it
792 if (markceiling) {
793 if (ceilingplane) // killough 4/11/98: add NULL ptr checks
794 ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
795 else
796 markceiling = 0;
797 }
798
799 if (markfloor) {
800 if (floorplane) // killough 4/11/98: add NULL ptr checks
801 /* cph 2003/04/18 - ceilingplane and floorplane might be the same
802 * visplane (e.g. if both skies); R_CheckPlane doesn't know about
803 * modifications to the plane that might happen in parallel with the check
804 * being made, so we have to override it and split them anyway if that is
805 * a possibility, otherwise the floor marking would overwrite the ceiling
806 * marking, resulting in HOM. */
807 if (markceiling && ceilingplane == floorplane)
808 floorplane = R_DupPlane (floorplane, rw_x, rw_stopx-1);
809 else
810 floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
811 else
812 markfloor = 0;
813 }
814
815 didsolidcol = 0;
816 R_RenderSegLoop();
817
818 /* cph - if a column was made solid by this wall, we _must_ save full clipping info */
819 if (backsector && didsolidcol) {
820 if (!(ds_p->silhouette & SIL_BOTTOM)) {
821 ds_p->silhouette |= SIL_BOTTOM;
822 ds_p->bsilheight = backsector->floorheight;
823 }
824 if (!(ds_p->silhouette & SIL_TOP)) {
825 ds_p->silhouette |= SIL_TOP;
826 ds_p->tsilheight = backsector->ceilingheight;
827 }
828 }
829
830 // save sprite clipping info
831 if ((ds_p->silhouette & SIL_TOP || maskedtexture) && !ds_p->sprtopclip)
832 {
833 memcpy (lastopening, ceilingclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow
834 ds_p->sprtopclip = lastopening - start;
835 lastopening += rw_stopx - start;
836 }
837 if ((ds_p->silhouette & SIL_BOTTOM || maskedtexture) && !ds_p->sprbottomclip)
838 {
839 memcpy (lastopening, floorclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow
840 ds_p->sprbottomclip = lastopening - start;
841 lastopening += rw_stopx - start;
842 }
843 if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
844 {
845 ds_p->silhouette |= SIL_TOP;
846 ds_p->tsilheight = INT_MIN;
847 }
848 if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
849 {
850 ds_p->silhouette |= SIL_BOTTOM;
851 ds_p->bsilheight = INT_MAX;
852 }
853 ds_p++;
854}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Refresh module, drawing LineSegs from BSP.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_SEGS__
35#define __R_SEGS__
36
37#ifdef __GNUG__
38#pragma interface
39#endif
40
41void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2);
42void R_StoreWallRange(const int start, const int stop);
43
44#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Sky rendering. The DOOM sky is a texture map like any
31 * wall, wrapping around. A 1024 columns equal 360 degrees.
32 * The default sky map is 256 columns and repeats 4 times
33 * on a 320 screen?
34 *
35 *-----------------------------------------------------------------------------*/
36
37#ifdef __GNUG__
38#pragma implementation "r_sky.h"
39#endif
40#include "r_sky.h"
41
42//
43// sky mapping
44//
45int skyflatnum;
46int skytexture;
47int skytexturemid;
48
49//
50// R_InitSkyMap
51// Called whenever the view size changes.
52//
53void R_InitSkyMap (void)
54{
55 skytexturemid = 100*FRACUNIT;
56}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Sky rendering.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_SKY__
35#define __R_SKY__
36
37#include "m_fixed.h"
38
39#ifdef __GNUG__
40#pragma interface
41#endif
42
43/* SKY, store the number for name. */
44#define SKYFLATNAME "F_SKY1"
45
46/* The sky map is 256*128*4 maps. */
47#define ANGLETOSKYSHIFT 22
48
49extern int skytexture;
50extern int skytexturemid;
51
52/* Called whenever the view size changes. */
53void R_InitSkyMap(void);
54
55#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Refresh/render internal state variables (global).
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __R_STATE__
36#define __R_STATE__
37
38// Need data structure definitions.
39#include "d_player.h"
40#include "r_data.h"
41
42#ifdef __GNUG__
43#pragma interface
44#endif
45
46
47//
48// Refresh internal data structures,
49// for rendering.
50//
51
52// needed for texture pegging
53extern fixed_t *textureheight;
54
55extern int scaledviewwidth;
56
57extern int firstflat, numflats;
58
59// for global animation
60extern int *flattranslation;
61extern int *texturetranslation;
62
63// Sprite....
64extern int firstspritelump;
65extern int lastspritelump;
66extern int numspritelumps;
67
68//
69// Lookup tables for map data.
70//
71extern int numsprites;
72extern spritedef_t *sprites;
73
74extern int numvertexes;
75extern vertex_t *vertexes;
76
77extern int numsegs;
78extern seg_t *segs;
79
80extern int numsectors;
81extern sector_t *sectors;
82
83extern int numsubsectors;
84extern subsector_t *subsectors;
85
86extern int numnodes;
87extern node_t *nodes;
88
89extern int numlines;
90extern line_t *lines;
91
92extern int numsides;
93extern side_t *sides;
94
95
96//
97// POV data.
98//
99extern fixed_t viewx;
100extern fixed_t viewy;
101extern fixed_t viewz;
102extern angle_t viewangle;
103extern player_t *viewplayer;
104extern angle_t clipangle;
105extern int viewangletox[FINEANGLES/2];
106extern angle_t xtoviewangle[MAX_SCREENWIDTH+1]; // killough 2/8/98
107extern fixed_t rw_distance;
108extern angle_t rw_normalangle;
109
110// angle to line origin
111extern int rw_angle1;
112
113extern visplane_t *floorplane;
114extern visplane_t *ceilingplane;
115
116#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Refresh of things, i.e. objects represented by sprites.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "w_wad.h"
36#include "r_main.h"
37#include "r_bsp.h"
38#include "r_segs.h"
39#include "r_draw.h"
40#include "r_things.h"
41#include "r_fps.h"
42#include "v_video.h"
43#include "lprintf.h"
44
45#define MINZ (FRACUNIT*4)
46#define BASEYCENTER 100
47
48typedef struct {
49 int x1;
50 int x2;
51 int column;
52 int topclip;
53 int bottomclip;
54} maskdraw_t;
55
56//
57// Sprite rotation 0 is facing the viewer,
58// rotation 1 is one angle turn CLOCKWISE around the axis.
59// This is not the same as the angle,
60// which increases counter clockwise (protractor).
61// There was a lot of stuff grabbed wrong, so I changed it...
62//
63
64fixed_t pspritescale;
65fixed_t pspriteiscale;
66// proff 11/06/98: Added for high-res
67fixed_t pspriteyscale;
68
69// constant arrays
70// used for psprite clipping and initializing clipping
71
72int negonearray[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow
73int screenheightarray[MAX_SCREENWIDTH]; // change to MAX_* // dropoff overflow
74
75//
76// INITIALIZATION FUNCTIONS
77//
78
79// variables used to look up and range check thing_t sprites patches
80
81spritedef_t *sprites;
82int numsprites;
83
84#define MAX_SPRITE_FRAMES 29 /* Macroized -- killough 1/25/98 */
85
86static spriteframe_t sprtemp[MAX_SPRITE_FRAMES];
87static int maxframe;
88
89//
90// R_InstallSpriteLump
91// Local function for R_InitSprites.
92//
93
94static void R_InstallSpriteLump(int lump, unsigned frame,
95 unsigned rotation, boolean flipped)
96{
97 if (frame >= MAX_SPRITE_FRAMES || rotation > 8)
98 I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
99
100 if ((int) frame > maxframe)
101 maxframe = frame;
102
103 if (rotation == 0)
104 { // the lump should be used for all rotations
105 int r;
106 for (r=0 ; r<8 ; r++)
107 if (sprtemp[frame].lump[r]==-1)
108 {
109 sprtemp[frame].lump[r] = lump - firstspritelump;
110 sprtemp[frame].flip[r] = (byte) flipped;
111 sprtemp[frame].rotate = false; //jff 4/24/98 if any subbed, rotless
112 }
113 return;
114 }
115
116 // the lump is only used for one rotation
117
118 if (sprtemp[frame].lump[--rotation] == -1)
119 {
120 sprtemp[frame].lump[rotation] = lump - firstspritelump;
121 sprtemp[frame].flip[rotation] = (byte) flipped;
122 sprtemp[frame].rotate = true; //jff 4/24/98 only change if rot used
123 }
124}
125
126//
127// R_InitSpriteDefs
128// Pass a null terminated list of sprite names
129// (4 chars exactly) to be used.
130//
131// Builds the sprite rotation matrixes to account
132// for horizontally flipped sprites.
133//
134// Will report an error if the lumps are inconsistent.
135// Only called at startup.
136//
137// Sprite lump names are 4 characters for the actor,
138// a letter for the frame, and a number for the rotation.
139//
140// A sprite that is flippable will have an additional
141// letter/number appended.
142//
143// The rotation character can be 0 to signify no rotations.
144//
145// 1/25/98, 1/31/98 killough : Rewritten for performance
146//
147// Empirically verified to have excellent hash
148// properties across standard Doom sprites:
149
150#define R_SpriteNameHash(s) ((unsigned)((s)[0]-((s)[1]*3-(s)[3]*2-(s)[2])*2))
151
152static void R_InitSpriteDefs(const char * const * namelist)
153{
154 size_t numentries = lastspritelump-firstspritelump+1;
155 struct { int index, next; } *hash;
156 int i;
157
158 if (!numentries || !*namelist)
159 return;
160
161 // count the number of sprite names
162 for (i=0; namelist[i]; i++)
163 ;
164
165 numsprites = i;
166
167 sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
168
169 // Create hash table based on just the first four letters of each sprite
170 // killough 1/31/98
171
172 hash = malloc(sizeof(*hash)*numentries); // allocate hash table
173
174 for (i=0; (size_t)i<numentries; i++) // initialize hash table as empty
175 hash[i].index = -1;
176
177 for (i=0; (size_t)i<numentries; i++) // Prepend each sprite to hash chain
178 { // prepend so that later ones win
179 int j = R_SpriteNameHash(lumpinfo[i+firstspritelump].name) % numentries;
180 hash[i].next = hash[j].index;
181 hash[j].index = i;
182 }
183
184 // scan all the lump names for each of the names,
185 // noting the highest frame letter.
186
187 for (i=0 ; i<numsprites ; i++)
188 {
189 const char *spritename = namelist[i];
190 int j = hash[R_SpriteNameHash(spritename) % numentries].index;
191
192 if (j >= 0)
193 {
194 memset(sprtemp, -1, sizeof(sprtemp));
195 maxframe = -1;
196 do
197 {
198 register lumpinfo_t *lump = lumpinfo + j + firstspritelump;
199
200 // Fast portable comparison -- killough
201 // (using int pointer cast is nonportable):
202
203 if (!((lump->name[0] ^ spritename[0]) |
204 (lump->name[1] ^ spritename[1]) |
205 (lump->name[2] ^ spritename[2]) |
206 (lump->name[3] ^ spritename[3])))
207 {
208 R_InstallSpriteLump(j+firstspritelump,
209 lump->name[4] - 'A',
210 lump->name[5] - '0',
211 false);
212 if (lump->name[6])
213 R_InstallSpriteLump(j+firstspritelump,
214 lump->name[6] - 'A',
215 lump->name[7] - '0',
216 true);
217 }
218 }
219 while ((j = hash[j].next) >= 0);
220
221 // check the frames that were found for completeness
222 if ((sprites[i].numframes = ++maxframe)) // killough 1/31/98
223 {
224 int frame;
225 for (frame = 0; frame < maxframe; frame++)
226 switch ((int) sprtemp[frame].rotate)
227 {
228 case -1:
229 // no rotations were found for that frame at all
230 I_Error ("R_InitSprites: No patches found "
231 "for %.8s frame %c", namelist[i], frame+'A');
232 break;
233
234 case 0:
235 // only the first rotation is needed
236 break;
237
238 case 1:
239 // must have all 8 frames
240 {
241 int rotation;
242 for (rotation=0 ; rotation<8 ; rotation++)
243 if (sprtemp[frame].lump[rotation] == -1)
244 I_Error ("R_InitSprites: Sprite %.8s frame %c "
245 "is missing rotations",
246 namelist[i], frame+'A');
247 break;
248 }
249 }
250 // allocate space for the frames present and copy sprtemp to it
251 sprites[i].spriteframes =
252 Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
253 memcpy (sprites[i].spriteframes, sprtemp,
254 maxframe*sizeof(spriteframe_t));
255 }
256 }
257 }
258 free(hash); // free hash table
259}
260
261//
262// GAME FUNCTIONS
263//
264
265static vissprite_t *vissprites, **vissprite_ptrs; // killough
266static size_t num_vissprite, num_vissprite_alloc, num_vissprite_ptrs;
267
268//
269// R_InitSprites
270// Called at program start.
271//
272
273void R_InitSprites(const char * const *namelist)
274{
275 int i;
276 for (i=0; i<MAX_SCREENWIDTH; i++) // killough 2/8/98
277 negonearray[i] = -1;
278 R_InitSpriteDefs(namelist);
279}
280
281//
282// R_ClearSprites
283// Called at frame start.
284//
285
286void R_ClearSprites (void)
287{
288 num_vissprite = 0; // killough
289}
290
291//
292// R_NewVisSprite
293//
294
295static vissprite_t *R_NewVisSprite(void)
296{
297 if (num_vissprite >= num_vissprite_alloc) // killough
298 {
299 size_t num_vissprite_alloc_prev = num_vissprite_alloc;
300
301 num_vissprite_alloc = num_vissprite_alloc ? num_vissprite_alloc*2 : 128;
302 vissprites = realloc(vissprites,num_vissprite_alloc*sizeof(*vissprites));
303
304 //e6y: set all fields to zero
305 memset(vissprites + num_vissprite_alloc_prev, 0,
306 (num_vissprite_alloc - num_vissprite_alloc_prev)*sizeof(*vissprites));
307 }
308 return vissprites + num_vissprite++;
309}
310
311//
312// R_DrawMaskedColumn
313// Used for sprites and masked mid textures.
314// Masked means: partly transparent, i.e. stored
315// in posts/runs of opaque pixels.
316//
317
318int *mfloorclip; // dropoff overflow
319int *mceilingclip; // dropoff overflow
320fixed_t spryscale;
321fixed_t sprtopscreen;
322
323void R_DrawMaskedColumn(
324 const rpatch_t *patch,
325 R_DrawColumn_f colfunc,
326 draw_column_vars_t *dcvars,
327 const rcolumn_t *column,
328 const rcolumn_t *prevcolumn,
329 const rcolumn_t *nextcolumn
330)
331{
332 int i;
333 int topscreen;
334 int bottomscreen;
335 fixed_t basetexturemid = dcvars->texturemid;
336
337 dcvars->texheight = patch->height; // killough 11/98
338 for (i=0; i<column->numPosts; i++) {
339 const rpost_t *post = &column->posts[i];
340
341 // calculate unclipped screen coordinates for post
342 topscreen = sprtopscreen + spryscale*post->topdelta;
343 bottomscreen = topscreen + spryscale*post->length;
344
345 dcvars->yl = (topscreen+FRACUNIT-1)>>FRACBITS;
346 dcvars->yh = (bottomscreen-1)>>FRACBITS;
347
348 if (dcvars->yh >= mfloorclip[dcvars->x])
349 dcvars->yh = mfloorclip[dcvars->x]-1;
350
351 if (dcvars->yl <= mceilingclip[dcvars->x])
352 dcvars->yl = mceilingclip[dcvars->x]+1;
353
354 // killough 3/2/98, 3/27/98: Failsafe against overflow/crash:
355 if (dcvars->yl <= dcvars->yh && dcvars->yh < viewheight)
356 {
357 dcvars->source = column->pixels + post->topdelta;
358 dcvars->prevsource = prevcolumn->pixels + post->topdelta;
359 dcvars->nextsource = nextcolumn->pixels + post->topdelta;
360
361 dcvars->texturemid = basetexturemid - (post->topdelta<<FRACBITS);
362
363 dcvars->edgeslope = post->slope;
364 // Drawn by either R_DrawColumn
365 // or (SHADOW) R_DrawFuzzColumn.
366 dcvars->drawingmasked = 1; // POPE
367 colfunc (dcvars);
368 dcvars->drawingmasked = 0; // POPE
369 }
370 }
371 dcvars->texturemid = basetexturemid;
372}
373
374//
375// R_DrawVisSprite
376// mfloorclip and mceilingclip should also be set.
377//
378// CPhipps - new wad lump handling, *'s to const*'s
379static void R_DrawVisSprite(vissprite_t *vis, int x1, int x2)
380{
381 int texturecolumn;
382 fixed_t frac;
383 const rpatch_t *patch = R_CachePatchNum(vis->patch+firstspritelump);
384 R_DrawColumn_f colfunc;
385 draw_column_vars_t dcvars;
386 enum draw_filter_type_e filter;
387 enum draw_filter_type_e filterz;
388
389 R_SetDefaultDrawColumnVars(&dcvars);
390 if (vis->isplayersprite) {
391 dcvars.edgetype = drawvars.patch_edges;
392 filter = drawvars.filterpatch;
393 filterz = RDRAW_FILTER_POINT;
394 } else {
395 dcvars.edgetype = drawvars.sprite_edges;
396 filter = drawvars.filtersprite;
397 filterz = drawvars.filterz;
398 }
399
400 dcvars.colormap = vis->colormap;
401 dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE
402
403 // killough 4/11/98: rearrange and handle translucent sprites
404 // mixed with translucent/non-translucenct 2s normals
405
406 if (!dcvars.colormap) // NULL colormap = shadow draw
407 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_FUZZ, filter, filterz); // killough 3/14/98
408 else
409 if (vis->mobjflags & MF_TRANSLATION)
410 {
411 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, filter, filterz);
412 dcvars.translation = translationtables - 256 +
413 ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
414 }
415 else
416 if (vis->mobjflags & MF_TRANSLUCENT && general_translucency) // phares
417 {
418 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, filter, filterz);
419 tranmap = main_tranmap; // killough 4/11/98
420 }
421 else
422 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, filter, filterz); // killough 3/14/98, 4/11/98
423
424// proff 11/06/98: Changed for high-res
425 dcvars.iscale = FixedDiv (FRACUNIT, vis->scale);
426 dcvars.texturemid = vis->texturemid;
427 frac = vis->startfrac;
428 if (filter == RDRAW_FILTER_LINEAR)
429 frac -= (FRACUNIT>>1);
430 spryscale = vis->scale;
431 sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid,spryscale);
432
433 for (dcvars.x=vis->x1 ; dcvars.x<=vis->x2 ; dcvars.x++, frac += vis->xiscale)
434 {
435 texturecolumn = frac>>FRACBITS;
436 dcvars.texu = frac;
437
438 R_DrawMaskedColumn(
439 patch,
440 colfunc,
441 &dcvars,
442 R_GetPatchColumnClamped(patch, texturecolumn),
443 R_GetPatchColumnClamped(patch, texturecolumn-1),
444 R_GetPatchColumnClamped(patch, texturecolumn+1)
445 );
446 }
447 R_UnlockPatchNum(vis->patch+firstspritelump); // cph - release lump
448}
449
450//
451// R_ProjectSprite
452// Generates a vissprite for a thing if it might be visible.
453//
454
455static void R_ProjectSprite (mobj_t* thing, int lightlevel)
456{
457 fixed_t gzt; // killough 3/27/98
458 fixed_t tx;
459 fixed_t xscale;
460 int x1;
461 int x2;
462 spritedef_t *sprdef;
463 spriteframe_t *sprframe;
464 int lump;
465 boolean flip;
466 vissprite_t *vis;
467 fixed_t iscale;
468 int heightsec; // killough 3/27/98
469
470 // transform the origin point
471 fixed_t tr_x, tr_y;
472 fixed_t fx, fy, fz;
473 fixed_t gxt, gyt;
474 fixed_t tz;
475 int width;
476
477 if (movement_smooth)
478 {
479 fx = thing->PrevX + FixedMul (tic_vars.frac, thing->x - thing->PrevX);
480 fy = thing->PrevY + FixedMul (tic_vars.frac, thing->y - thing->PrevY);
481 fz = thing->PrevZ + FixedMul (tic_vars.frac, thing->z - thing->PrevZ);
482 }
483 else
484 {
485 fx = thing->x;
486 fy = thing->y;
487 fz = thing->z;
488 }
489 tr_x = fx - viewx;
490 tr_y = fy - viewy;
491
492 gxt = FixedMul(tr_x,viewcos);
493 gyt = -FixedMul(tr_y,viewsin);
494
495 tz = gxt-gyt;
496
497 // thing is behind view plane?
498 if (tz < MINZ)
499 return;
500
501 xscale = FixedDiv(projection, tz);
502
503 gxt = -FixedMul(tr_x,viewsin);
504 gyt = FixedMul(tr_y,viewcos);
505 tx = -(gyt+gxt);
506
507 // too far off the side?
508 if (D_abs(tx)>(tz<<2))
509 return;
510
511 // decide which patch to use for sprite relative to player
512#ifdef RANGECHECK
513 if ((unsigned) thing->sprite >= (unsigned)numsprites)
514 I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite);
515#endif
516
517 sprdef = &sprites[thing->sprite];
518
519#ifdef RANGECHECK
520 if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
521 I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite,
522 thing->frame);
523#endif
524
525 if (!sprdef->spriteframes)
526 I_Error ("R_ProjectSprite: Missing spriteframes %i : %i", thing->sprite,
527 thing->frame);
528
529 sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
530
531 if (sprframe->rotate)
532 {
533 // choose a different rotation based on player view
534 angle_t ang = R_PointToAngle(fx, fy);
535 unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
536 lump = sprframe->lump[rot];
537 flip = (boolean) sprframe->flip[rot];
538 }
539 else
540 {
541 // use single rotation for all views
542 lump = sprframe->lump[0];
543 flip = (boolean) sprframe->flip[0];
544 }
545
546 {
547 const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump);
548
549 /* calculate edges of the shape
550 * cph 2003/08/1 - fraggle points out that this offset must be flipped
551 * if the sprite is flipped; e.g. FreeDoom imp is messed up by this. */
552 if (flip) {
553 tx -= (patch->width - patch->leftoffset) << FRACBITS;
554 } else {
555 tx -= patch->leftoffset << FRACBITS;
556 }
557 x1 = (centerxfrac + FixedMul(tx,xscale)) >> FRACBITS;
558
559 tx += patch->width<<FRACBITS;
560 x2 = ((centerxfrac + FixedMul (tx,xscale) ) >> FRACBITS) - 1;
561
562 gzt = fz + (patch->topoffset << FRACBITS);
563 width = patch->width;
564 R_UnlockPatchNum(lump+firstspritelump);
565 }
566
567 // off the side?
568 if (x1 > viewwidth || x2 < 0)
569 return;
570
571 // killough 4/9/98: clip things which are out of view due to height
572 // e6y: fix of hanging decoration disappearing in Batman Doom MAP02
573 // centeryfrac -> viewheightfrac
574 if (fz > viewz + FixedDiv(viewheightfrac, xscale) ||
575 gzt < viewz - FixedDiv(viewheightfrac-viewheight, xscale))
576 return;
577
578 // killough 3/27/98: exclude things totally separated
579 // from the viewer, by either water or fake ceilings
580 // killough 4/11/98: improve sprite clipping for underwater/fake ceilings
581
582 heightsec = thing->subsector->sector->heightsec;
583
584 if (heightsec != -1) // only clip things which are in special sectors
585 {
586 int phs = viewplayer->mo->subsector->sector->heightsec;
587 if (phs != -1 && viewz < sectors[phs].floorheight ?
588 fz >= sectors[heightsec].floorheight :
589 gzt < sectors[heightsec].floorheight)
590 return;
591 if (phs != -1 && viewz > sectors[phs].ceilingheight ?
592 gzt < sectors[heightsec].ceilingheight &&
593 viewz >= sectors[heightsec].ceilingheight :
594 fz >= sectors[heightsec].ceilingheight)
595 return;
596 }
597
598 // store information in a vissprite
599 vis = R_NewVisSprite ();
600
601#ifdef GL_DOOM
602 if (V_GetMode() == VID_MODEGL)
603 {
604 // proff 11/99: add sprite for OpenGL
605 vis->thing = thing;
606 vis->flip = flip;
607 vis->scale = FixedDiv(projectiony, tz);
608 vis->patch = lump;
609 gld_AddSprite(vis);
610
611 return;
612 }
613#endif
614 // killough 3/27/98: save sector for special clipping later
615 vis->heightsec = heightsec;
616
617 vis->mobjflags = thing->flags;
618// proff 11/06/98: Changed for high-res
619 vis->scale = FixedDiv(projectiony, tz);
620 vis->gx = fx;
621 vis->gy = fy;
622 vis->gz = fz;
623 vis->gzt = gzt; // killough 3/27/98
624 vis->texturemid = vis->gzt - viewz;
625 vis->x1 = x1 < 0 ? 0 : x1;
626 vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
627 iscale = FixedDiv (FRACUNIT, xscale);
628
629 if (flip)
630 {
631 vis->startfrac = (width<<FRACBITS)-1;
632 vis->xiscale = -iscale;
633 }
634 else
635 {
636 vis->startfrac = 0;
637 vis->xiscale = iscale;
638 }
639
640 if (vis->x1 > x1)
641 vis->startfrac += vis->xiscale*(vis->x1-x1);
642 vis->patch = lump;
643
644 // get light level
645 if (thing->flags & MF_SHADOW)
646 vis->colormap = NULL; // shadow draw
647 else if (fixedcolormap)
648 vis->colormap = fixedcolormap; // fixed map
649 else if (thing->frame & FF_FULLBRIGHT)
650 vis->colormap = fullcolormap; // full bright // killough 3/20/98
651 else
652 { // diminished light
653 vis->colormap = R_ColourMap(lightlevel,xscale);
654 }
655}
656
657//
658// R_AddSprites
659// During BSP traversal, this adds sprites by sector.
660//
661// killough 9/18/98: add lightlevel as parameter, fixing underwater lighting
662void R_AddSprites(subsector_t* subsec, int lightlevel)
663{
664 sector_t* sec=subsec->sector;
665 mobj_t *thing;
666
667 // BSP is traversed by subsector.
668 // A sector might have been split into several
669 // subsectors during BSP building.
670 // Thus we check whether its already added.
671
672 if (sec->validcount == validcount)
673 return;
674
675 // Well, now it will be done.
676 sec->validcount = validcount;
677
678 // Handle all things in sector.
679
680 for (thing = sec->thinglist; thing; thing = thing->snext)
681 R_ProjectSprite(thing, lightlevel);
682}
683
684//
685// R_DrawPSprite
686//
687
688static void R_DrawPSprite (pspdef_t *psp, int lightlevel)
689{
690 int x1, x2;
691 spritedef_t *sprdef;
692 spriteframe_t *sprframe;
693 int lump;
694 boolean flip;
695 vissprite_t *vis;
696 vissprite_t avis;
697 int width;
698 fixed_t topoffset;
699
700 avis.isplayersprite = true;
701
702 // decide which patch to use
703
704#ifdef RANGECHECK
705 if ( (unsigned)psp->state->sprite >= (unsigned)numsprites)
706 I_Error ("R_ProjectSprite: Invalid sprite number %i", psp->state->sprite);
707#endif
708
709 sprdef = &sprites[psp->state->sprite];
710
711#ifdef RANGECHECK
712 if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
713 I_Error ("R_ProjectSprite: Invalid sprite frame %i : %li",
714 psp->state->sprite, psp->state->frame);
715#endif
716
717 sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
718
719 lump = sprframe->lump[0];
720 flip = (boolean) sprframe->flip[0];
721
722 {
723 const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump);
724 // calculate edges of the shape
725 fixed_t tx;
726 tx = psp->sx-160*FRACUNIT;
727
728 tx -= patch->leftoffset<<FRACBITS;
729 x1 = (centerxfrac + FixedMul (tx,pspritescale))>>FRACBITS;
730
731 tx += patch->width<<FRACBITS;
732 x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
733
734 width = patch->width;
735 topoffset = patch->topoffset<<FRACBITS;
736 R_UnlockPatchNum(lump+firstspritelump);
737 }
738
739 // off the side
740 if (x2 < 0 || x1 > viewwidth)
741 return;
742
743 // store information in a vissprite
744 vis = &avis;
745 vis->mobjflags = 0;
746 // killough 12/98: fix psprite positioning problem
747 vis->texturemid = (BASEYCENTER<<FRACBITS) /* + FRACUNIT/2 */ -
748 (psp->sy-topoffset);
749 vis->x1 = x1 < 0 ? 0 : x1;
750 vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
751// proff 11/06/98: Added for high-res
752 vis->scale = pspriteyscale;
753
754 if (flip)
755 {
756 vis->xiscale = -pspriteiscale;
757 vis->startfrac = (width<<FRACBITS)-1;
758 }
759 else
760 {
761 vis->xiscale = pspriteiscale;
762 vis->startfrac = 0;
763 }
764
765 if (vis->x1 > x1)
766 vis->startfrac += vis->xiscale*(vis->x1-x1);
767
768 vis->patch = lump;
769
770 if (viewplayer->powers[pw_invisibility] > 4*32
771 || viewplayer->powers[pw_invisibility] & 8)
772 vis->colormap = NULL; // shadow draw
773 else if (fixedcolormap)
774 vis->colormap = fixedcolormap; // fixed color
775 else if (psp->state->frame & FF_FULLBRIGHT)
776 vis->colormap = fullcolormap; // full bright // killough 3/20/98
777 else
778 // add a fudge factor to better match the original game
779 vis->colormap = R_ColourMap(lightlevel,
780 FixedMul(pspritescale, 0x2b000)); // local light
781
782 // proff 11/99: don't use software stuff in OpenGL
783 if (V_GetMode() != VID_MODEGL)
784 {
785 R_DrawVisSprite(vis, vis->x1, vis->x2);
786 }
787#ifdef GL_DOOM
788 else
789 {
790 int lightlevel;
791 sector_t tmpsec;
792 int floorlightlevel, ceilinglightlevel;
793
794 if ((vis->colormap==fixedcolormap) || (vis->colormap==fullcolormap))
795 lightlevel=255;
796 else
797 {
798// lightlevel = (viewplayer->mo->subsector->sector->lightlevel) + (extralight << LIGHTSEGSHIFT);
799 R_FakeFlat( viewplayer->mo->subsector->sector, &tmpsec,
800 &floorlightlevel, &ceilinglightlevel, false);
801 lightlevel = ((floorlightlevel+ceilinglightlevel) >> 1) + (extralight << LIGHTSEGSHIFT);
802
803 if (lightlevel < 0)
804 lightlevel = 0;
805 else if (lightlevel >= 255)
806 lightlevel = 255;
807 }
808 gld_DrawWeapon(lump,vis,lightlevel);
809 }
810#endif
811}
812
813//
814// R_DrawPlayerSprites
815//
816
817void R_DrawPlayerSprites(void)
818{
819 int i, lightlevel = viewplayer->mo->subsector->sector->lightlevel;
820 pspdef_t *psp;
821
822 // clip to screen bounds
823 mfloorclip = screenheightarray;
824 mceilingclip = negonearray;
825
826 // add all active psprites
827 for (i=0, psp=viewplayer->psprites; i<NUMPSPRITES; i++,psp++)
828 if (psp->state)
829 R_DrawPSprite (psp, lightlevel);
830}
831
832//
833// R_SortVisSprites
834//
835// Rewritten by Lee Killough to avoid using unnecessary
836// linked lists, and to use faster sorting algorithm.
837//
838
839#ifdef DJGPP
840
841// killough 9/22/98: inlined memcpy of pointer arrays
842// CPhipps - added memory as modified
843#define bcopyp(d, s, n) asm(" cld; rep; movsl;" :: "D"(d), "S"(s), "c"(n) : "%cc", "%esi", "%edi", "%ecx", "memory")
844
845#else
846
847#define bcopyp(d, s, n) memcpy(d, s, (n) * sizeof(void *))
848
849#endif
850
851// killough 9/2/98: merge sort
852
853static void msort(vissprite_t **s, vissprite_t **t, int n)
854{
855 if (n >= 16)
856 {
857 int n1 = n/2, n2 = n - n1;
858 vissprite_t **s1 = s, **s2 = s + n1, **d = t;
859
860 msort(s1, t, n1);
861 msort(s2, t, n2);
862
863 while ((*s1)->scale > (*s2)->scale ?
864 (*d++ = *s1++, --n1) : (*d++ = *s2++, --n2));
865
866 if (n2)
867 bcopyp(d, s2, n2);
868 else
869 bcopyp(d, s1, n1);
870
871 bcopyp(s, t, n);
872 }
873 else
874 {
875 int i;
876 for (i = 1; i < n; i++)
877 {
878 vissprite_t *temp = s[i];
879 if (s[i-1]->scale < temp->scale)
880 {
881 int j = i;
882 while ((s[j] = s[j-1])->scale < temp->scale && --j);
883 s[j] = temp;
884 }
885 }
886 }
887}
888
889void R_SortVisSprites (void)
890{
891 if (num_vissprite)
892 {
893 int i = num_vissprite;
894
895 // If we need to allocate more pointers for the vissprites,
896 // allocate as many as were allocated for sprites -- killough
897 // killough 9/22/98: allocate twice as many
898
899 if (num_vissprite_ptrs < num_vissprite*2)
900 {
901 free(vissprite_ptrs); // better than realloc -- no preserving needed
902 vissprite_ptrs = malloc((num_vissprite_ptrs = num_vissprite_alloc*2)
903 * sizeof *vissprite_ptrs);
904 }
905
906 while (--i>=0)
907 vissprite_ptrs[i] = vissprites+i;
908
909 // killough 9/22/98: replace qsort with merge sort, since the keys
910 // are roughly in order to begin with, due to BSP rendering.
911
912 msort(vissprite_ptrs, vissprite_ptrs + num_vissprite, num_vissprite);
913 }
914}
915
916//
917// R_DrawSprite
918//
919
920static void R_DrawSprite (vissprite_t* spr)
921{
922 drawseg_t *ds;
923 int clipbot[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow
924 int cliptop[MAX_SCREENWIDTH]; // change to MAX_* // dropoff overflow
925 int x;
926 int r1;
927 int r2;
928 fixed_t scale;
929 fixed_t lowscale;
930
931 for (x = spr->x1 ; x<=spr->x2 ; x++)
932 clipbot[x] = cliptop[x] = -2;
933
934 // Scan drawsegs from end to start for obscuring segs.
935 // The first drawseg that has a greater scale is the clip seg.
936
937 // Modified by Lee Killough:
938 // (pointer check was originally nonportable
939 // and buggy, by going past LEFT end of array):
940
941 // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code
942
943 for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough
944 { // determine if the drawseg obscures the sprite
945 if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
946 (!ds->silhouette && !ds->maskedtexturecol))
947 continue; // does not cover sprite
948
949 r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
950 r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
951
952 if (ds->scale1 > ds->scale2)
953 {
954 lowscale = ds->scale2;
955 scale = ds->scale1;
956 }
957 else
958 {
959 lowscale = ds->scale1;
960 scale = ds->scale2;
961 }
962
963 if (scale < spr->scale || (lowscale < spr->scale &&
964 !R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
965 {
966 if (ds->maskedtexturecol) // masked mid texture?
967 R_RenderMaskedSegRange(ds, r1, r2);
968 continue; // seg is behind sprite
969 }
970
971 // clip this piece of the sprite
972 // killough 3/27/98: optimized and made much shorter
973
974 if (ds->silhouette&SIL_BOTTOM && spr->gz < ds->bsilheight) //bottom sil
975 for (x=r1 ; x<=r2 ; x++)
976 if (clipbot[x] == -2)
977 clipbot[x] = ds->sprbottomclip[x];
978
979 if (ds->silhouette&SIL_TOP && spr->gzt > ds->tsilheight) // top sil
980 for (x=r1 ; x<=r2 ; x++)
981 if (cliptop[x] == -2)
982 cliptop[x] = ds->sprtopclip[x];
983 }
984
985 // killough 3/27/98:
986 // Clip the sprite against deep water and/or fake ceilings.
987 // killough 4/9/98: optimize by adding mh
988 // killough 4/11/98: improve sprite clipping for underwater/fake ceilings
989 // killough 11/98: fix disappearing sprites
990
991 if (spr->heightsec != -1) // only things in specially marked sectors
992 {
993 fixed_t h,mh;
994 int phs = viewplayer->mo->subsector->sector->heightsec;
995 if ((mh = sectors[spr->heightsec].floorheight) > spr->gz &&
996 (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0 &&
997 (h >>= FRACBITS) < viewheight) {
998 if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight))
999 { // clip bottom
1000 for (x=spr->x1 ; x<=spr->x2 ; x++)
1001 if (clipbot[x] == -2 || h < clipbot[x])
1002 clipbot[x] = h;
1003 }
1004 else // clip top
1005 if (phs != -1 && viewz <= sectors[phs].floorheight) // killough 11/98
1006 for (x=spr->x1 ; x<=spr->x2 ; x++)
1007 if (cliptop[x] == -2 || h > cliptop[x])
1008 cliptop[x] = h;
1009 }
1010
1011 if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt &&
1012 (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 &&
1013 (h >>= FRACBITS) < viewheight) {
1014 if (phs != -1 && viewz >= sectors[phs].ceilingheight)
1015 { // clip bottom
1016 for (x=spr->x1 ; x<=spr->x2 ; x++)
1017 if (clipbot[x] == -2 || h < clipbot[x])
1018 clipbot[x] = h;
1019 }
1020 else // clip top
1021 for (x=spr->x1 ; x<=spr->x2 ; x++)
1022 if (cliptop[x] == -2 || h > cliptop[x])
1023 cliptop[x] = h;
1024 }
1025 }
1026 // killough 3/27/98: end special clipping for deep water / fake ceilings
1027
1028 // all clipping has been performed, so draw the sprite
1029 // check for unclipped columns
1030
1031 for (x = spr->x1 ; x<=spr->x2 ; x++) {
1032 if (clipbot[x] == -2)
1033 clipbot[x] = viewheight;
1034
1035 if (cliptop[x] == -2)
1036 cliptop[x] = -1;
1037 }
1038
1039 mfloorclip = clipbot;
1040 mceilingclip = cliptop;
1041 R_DrawVisSprite (spr, spr->x1, spr->x2);
1042}
1043
1044//
1045// R_DrawMasked
1046//
1047
1048void R_DrawMasked(void)
1049{
1050 int i;
1051 drawseg_t *ds;
1052
1053 R_SortVisSprites();
1054
1055 // draw all vissprites back to front
1056
1057 rendered_vissprites = num_vissprite;
1058 for (i = num_vissprite ;--i>=0; )
1059 R_DrawSprite(vissprite_ptrs[i]); // killough
1060
1061 // render any remaining masked mid textures
1062
1063 // Modified by Lee Killough:
1064 // (pointer check was originally nonportable
1065 // and buggy, by going past LEFT end of array):
1066
1067 // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code
1068
1069 for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough
1070 if (ds->maskedtexturecol)
1071 R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
1072
1073 // draw the psprites on top of everything
1074 // but does not draw on side views
1075 if (!viewangleoffset)
1076 R_DrawPlayerSprites ();
1077}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Rendering of moving objects, sprites.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __R_THINGS__
35#define __R_THINGS__
36
37#ifdef __GNUG__
38#pragma interface
39#endif
40
41#include "r_draw.h"
42
43/* Constant arrays used for psprite clipping and initializing clipping. */
44
45extern int negonearray[MAX_SCREENWIDTH]; /* killough 2/8/98: */ // dropoff overflow
46extern int screenheightarray[MAX_SCREENWIDTH]; /* change to MAX_* */ // dropoff overflow
47
48/* Vars for R_DrawMaskedColumn */
49
50extern int *mfloorclip; // dropoff overflow
51extern int *mceilingclip; // dropoff overflow
52extern fixed_t spryscale;
53extern fixed_t sprtopscreen;
54extern fixed_t pspritescale;
55extern fixed_t pspriteiscale;
56/* proff 11/06/98: Added for high-res */
57extern fixed_t pspriteyscale;
58
59void R_DrawMaskedColumn(const rpatch_t *patch,
60 R_DrawColumn_f colfunc,
61 draw_column_vars_t *dcvars,
62 const rcolumn_t *column,
63 const rcolumn_t *prevcolumn,
64 const rcolumn_t *nextcolumn);
65void R_SortVisSprites(void);
66void R_AddSprites(subsector_t* subsec, int lightlevel);
67void R_DrawPlayerSprites(void);
68void R_InitSprites(const char * const * namelist);
69void R_ClearSprites(void);
70void R_DrawMasked(void);
71
72#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION: Platform-independent sound code
30 *
31 *-----------------------------------------------------------------------------*/
32
33// killough 3/7/98: modified to allow arbitrary listeners in spy mode
34// killough 5/2/98: reindented, removed useless code, beautified
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40#include "doomstat.h"
41#include "s_sound.h"
42#include "i_sound.h"
43#include "i_system.h"
44#include "d_main.h"
45#include "r_main.h"
46#include "m_random.h"
47#include "w_wad.h"
48#include "lprintf.h"
49
50// when to clip out sounds
51// Does not fit the large outdoor areas.
52#define S_CLIPPING_DIST (1200<<FRACBITS)
53
54// Distance tp origin when sounds should be maxed out.
55// This should relate to movement clipping resolution
56// (see BLOCKMAP handling).
57// Originally: (200*0x10000).
58
59#define S_CLOSE_DIST (160<<FRACBITS)
60#define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)
61
62// Adjustable by menu.
63#define NORM_PITCH 128
64#define NORM_PRIORITY 64
65#define NORM_SEP 128
66#define S_STEREO_SWING (96<<FRACBITS)
67
68const char* S_music_files[NUMMUSIC]; // cournia - stores music file names
69
70typedef struct
71{
72 sfxinfo_t *sfxinfo; // sound information (if null, channel avail.)
73 void *origin; // origin of sound
74 int handle; // handle of the sound being played
75 int is_pickup; // killough 4/25/98: whether sound is a player's weapon
76} channel_t;
77
78// the set of channels available
79static channel_t *channels;
80
81// These are not used, but should be (menu).
82// Maximum volume of a sound effect.
83// Internal default is max out of 0-15.
84int snd_SfxVolume = 15;
85
86// Maximum volume of music. Useless so far.
87int snd_MusicVolume = 15;
88
89// whether songs are mus_paused
90static boolean mus_paused;
91
92// music currently being played
93static musicinfo_t *mus_playing;
94
95// following is set
96// by the defaults code in M_misc:
97// number of channels available
98int default_numChannels;
99int numChannels;
100
101//jff 3/17/98 to keep track of last IDMUS specified music num
102int idmusnum;
103
104//
105// Internals.
106//
107
108void S_StopChannel(int cnum);
109
110int S_AdjustSoundParams(mobj_t *listener, mobj_t *source,
111 int *vol, int *sep, int *pitch);
112
113static int S_getChannel(void *origin, sfxinfo_t *sfxinfo, int is_pickup);
114
115// Initializes sound stuff, including volume
116// Sets channels, SFX and music volume,
117// allocates channel buffer, sets S_sfx lookup.
118//
119
120void S_Init(int sfxVolume, int musicVolume)
121{
122 //jff 1/22/98 skip sound init if sound not enabled
123 numChannels = default_numChannels;
124 if (snd_card && !nosfxparm)
125 {
126 int i;
127
128 lprintf(LO_CONFIRM, "S_Init: default sfx volume %d\n", sfxVolume);
129
130 // Whatever these did with DMX, these are rather dummies now.
131 I_SetChannels();
132
133 S_SetSfxVolume(sfxVolume);
134
135 // Allocating the internal channels for mixing
136 // (the maximum numer of sounds rendered
137 // simultaneously) within zone memory.
138 // CPhipps - calloc
139 channels =
140 (channel_t *) calloc(numChannels,sizeof(channel_t));
141
142 // Note that sounds have not been cached (yet).
143 for (i=1 ; i<NUMSFX ; i++)
144 S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
145 }
146
147 // CPhipps - music init reformatted
148 if (mus_card && !nomusicparm) {
149 S_SetMusicVolume(musicVolume);
150
151 // no sounds are playing, and they are not mus_paused
152 mus_paused = 0;
153 }
154}
155
156void S_Stop(void)
157{
158 int cnum;
159
160 //jff 1/22/98 skip sound init if sound not enabled
161 if (snd_card && !nosfxparm)
162 for (cnum=0 ; cnum<numChannels ; cnum++)
163 if (channels[cnum].sfxinfo)
164 S_StopChannel(cnum);
165}
166
167//
168// Per level startup code.
169// Kills playing sounds at start of level,
170// determines music if any, changes music.
171//
172void S_Start(void)
173{
174 int mnum;
175
176 // kill all playing sounds at start of level
177 // (trust me - a good idea)
178
179 S_Stop();
180
181 //jff 1/22/98 return if music is not enabled
182 if (!mus_card || nomusicparm)
183 return;
184
185 // start new music for the level
186 mus_paused = 0;
187
188 if (idmusnum!=-1)
189 mnum = idmusnum; //jff 3/17/98 reload IDMUS music if not -1
190 else
191 if (gamemode == commercial)
192 mnum = mus_runnin + gamemap - 1;
193 else
194 {
195 static const int spmus[] = // Song - Who? - Where?
196 {
197 mus_e3m4, // American e4m1
198 mus_e3m2, // Romero e4m2
199 mus_e3m3, // Shawn e4m3
200 mus_e1m5, // American e4m4
201 mus_e2m7, // Tim e4m5
202 mus_e2m4, // Romero e4m6
203 mus_e2m6, // J.Anderson e4m7 CHIRON.WAD
204 mus_e2m5, // Shawn e4m8
205 mus_e1m9 // Tim e4m9
206 };
207
208 if (gameepisode < 4)
209 mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
210 else
211 mnum = spmus[gamemap-1];
212 }
213 S_ChangeMusic(mnum, true);
214}
215
216void S_StartSoundAtVolume(void *origin_p, int sfx_id, int volume)
217{
218 int sep, pitch, priority, cnum, is_pickup;
219 sfxinfo_t *sfx;
220 mobj_t *origin = (mobj_t *) origin_p;
221
222 //jff 1/22/98 return if sound is not enabled
223 if (!snd_card || nosfxparm)
224 return;
225
226 is_pickup = sfx_id & PICKUP_SOUND || sfx_id == sfx_oof || (compatibility_level >= prboom_2_compatibility && sfx_id == sfx_noway); // killough 4/25/98
227 sfx_id &= ~PICKUP_SOUND;
228
229 // check for bogus sound #
230 if (sfx_id < 1 || sfx_id > NUMSFX)
231 I_Error("S_StartSoundAtVolume: Bad sfx #: %d", sfx_id);
232
233 sfx = &S_sfx[sfx_id];
234
235 // Initialize sound parameters
236 if (sfx->link)
237 {
238 pitch = sfx->pitch;
239 priority = sfx->priority;
240 volume += sfx->volume;
241
242 if (volume < 1)
243 return;
244
245 if (volume > snd_SfxVolume)
246 volume = snd_SfxVolume;
247 }
248 else
249 {
250 pitch = NORM_PITCH;
251 priority = NORM_PRIORITY;
252 }
253
254 // Check to see if it is audible, modify the params
255 // killough 3/7/98, 4/25/98: code rearranged slightly
256
257 if (!origin || origin == players[displayplayer].mo) {
258 sep = NORM_SEP;
259 volume *= 8;
260 } else
261 if (!S_AdjustSoundParams(players[displayplayer].mo, origin, &volume,
262 &sep, &pitch))
263 return;
264 else
265 if ( origin->x == players[displayplayer].mo->x &&
266 origin->y == players[displayplayer].mo->y)
267 sep = NORM_SEP;
268
269 // hacks to vary the sfx pitches
270 if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit)
271 pitch += 8 - (M_Random()&15);
272 else
273 if (sfx_id != sfx_itemup && sfx_id != sfx_tink)
274 pitch += 16 - (M_Random()&31);
275
276 if (pitch<0)
277 pitch = 0;
278
279 if (pitch>255)
280 pitch = 255;
281
282 // kill old sound
283 for (cnum=0 ; cnum<numChannels ; cnum++)
284 if (channels[cnum].sfxinfo && channels[cnum].origin == origin &&
285 (comp[comp_sound] || channels[cnum].is_pickup == is_pickup))
286 {
287 S_StopChannel(cnum);
288 break;
289 }
290
291 // try to find a channel
292 cnum = S_getChannel(origin, sfx, is_pickup);
293
294 if (cnum<0)
295 return;
296
297 // get lumpnum if necessary
298 // killough 2/28/98: make missing sounds non-fatal
299 if (sfx->lumpnum < 0 && (sfx->lumpnum = I_GetSfxLumpNum(sfx)) < 0)
300 return;
301
302 // increase the usefulness
303 if (sfx->usefulness++ < 0)
304 sfx->usefulness = 1;
305
306 // Assigns the handle to one of the channels in the mix/output buffer.
307 { // e6y: [Fix] Crash with zero-length sounds.
308 int h = I_StartSound(sfx_id, cnum, volume, sep, pitch, priority);
309 if (h != -1) channels[cnum].handle = h;
310 }
311}
312
313void S_StartSound(void *origin, int sfx_id)
314{
315 S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
316}
317
318void S_StopSound(void *origin)
319{
320 int cnum;
321
322 //jff 1/22/98 return if sound is not enabled
323 if (!snd_card || nosfxparm)
324 return;
325
326 for (cnum=0 ; cnum<numChannels ; cnum++)
327 if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
328 {
329 S_StopChannel(cnum);
330 break;
331 }
332}
333
334
335//
336// Stop and resume music, during game PAUSE.
337//
338void S_PauseSound(void)
339{
340 //jff 1/22/98 return if music is not enabled
341 if (!mus_card || nomusicparm)
342 return;
343
344 if (mus_playing && !mus_paused)
345 {
346 I_PauseSong(mus_playing->handle);
347 mus_paused = true;
348 }
349}
350
351void S_ResumeSound(void)
352{
353 //jff 1/22/98 return if music is not enabled
354 if (!mus_card || nomusicparm)
355 return;
356
357 if (mus_playing && mus_paused)
358 {
359 I_ResumeSong(mus_playing->handle);
360 mus_paused = false;
361 }
362}
363
364
365//
366// Updates music & sounds
367//
368void S_UpdateSounds(void* listener_p)
369{
370 mobj_t *listener = (mobj_t*) listener_p;
371 int cnum;
372
373 //jff 1/22/98 return if sound is not enabled
374 if (!snd_card || nosfxparm)
375 return;
376
377#ifdef UPDATE_MUSIC
378 I_UpdateMusic();
379#endif
380
381 for (cnum=0 ; cnum<numChannels ; cnum++)
382 {
383 sfxinfo_t *sfx;
384 channel_t *c = &channels[cnum];
385 if ((sfx = c->sfxinfo))
386 {
387 if (I_SoundIsPlaying(c->handle))
388 {
389 // initialize parameters
390 int volume = snd_SfxVolume;
391 int pitch = NORM_PITCH;
392 int sep = NORM_SEP;
393
394 if (sfx->link)
395 {
396 pitch = sfx->pitch;
397 volume += sfx->volume;
398 if (volume < 1)
399 {
400 S_StopChannel(cnum);
401 continue;
402 }
403 else
404 if (volume > snd_SfxVolume)
405 volume = snd_SfxVolume;
406 }
407
408 // check non-local sounds for distance clipping
409 // or modify their params
410 if (c->origin && listener_p != c->origin) { // killough 3/20/98
411 if (!S_AdjustSoundParams(listener, c->origin,
412 &volume, &sep, &pitch))
413 S_StopChannel(cnum);
414 else
415 I_UpdateSoundParams(c->handle, volume, sep, pitch);
416 }
417 }
418 else // if channel is allocated but sound has stopped, free it
419 S_StopChannel(cnum);
420 }
421 }
422}
423
424
425
426void S_SetMusicVolume(int volume)
427{
428 //jff 1/22/98 return if music is not enabled
429 if (!mus_card || nomusicparm)
430 return;
431 if (volume < 0 || volume > 15)
432 I_Error("S_SetMusicVolume: Attempt to set music volume at %d", volume);
433 I_SetMusicVolume(volume);
434 snd_MusicVolume = volume;
435}
436
437
438
439void S_SetSfxVolume(int volume)
440{
441 //jff 1/22/98 return if sound is not enabled
442 if (!snd_card || nosfxparm)
443 return;
444 if (volume < 0 || volume > 127)
445 I_Error("S_SetSfxVolume: Attempt to set sfx volume at %d", volume);
446 snd_SfxVolume = volume;
447}
448
449
450
451// Starts some music with the music id found in sounds.h.
452//
453void S_StartMusic(int m_id)
454{
455 //jff 1/22/98 return if music is not enabled
456 if (!mus_card || nomusicparm)
457 return;
458 S_ChangeMusic(m_id, false);
459}
460
461
462
463void S_ChangeMusic(int musicnum, int looping)
464{
465 musicinfo_t *music;
466 int music_file_failed; // cournia - if true load the default MIDI music
467 char* music_filename; // cournia
468
469 //jff 1/22/98 return if music is not enabled
470 if (!mus_card || nomusicparm)
471 return;
472
473 if (musicnum <= mus_None || musicnum >= NUMMUSIC)
474 I_Error("S_ChangeMusic: Bad music number %d", musicnum);
475
476 music = &S_music[musicnum];
477
478 if (mus_playing == music)
479 return;
480
481 // shutdown old music
482 S_StopMusic();
483
484 // get lumpnum if neccessary
485 if (!music->lumpnum)
486 {
487 char namebuf[9];
488 sprintf(namebuf, "d_%s", music->name);
489 music->lumpnum = W_GetNumForName(namebuf);
490 }
491
492 music_file_failed = 1;
493
494 // proff_fs - only load when from IWAD
495 if (lumpinfo[music->lumpnum].source == source_iwad)
496 {
497 // cournia - check to see if we can play a higher quality music file
498 // rather than the default MIDI
499 music_filename = I_FindFile(S_music_files[musicnum], "");
500 if (music_filename)
501 {
502 music_file_failed = I_RegisterMusic(music_filename, music);
503 free(music_filename);
504 }
505 }
506
507 if (music_file_failed)
508 {
509 //cournia - could not load music file, play default MIDI music
510
511 // load & register it
512 music->data = W_CacheLumpNum(music->lumpnum);
513 music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
514 }
515
516 // play it
517 I_PlaySong(music->handle, looping);
518
519 mus_playing = music;
520}
521
522
523void S_StopMusic(void)
524{
525 //jff 1/22/98 return if music is not enabled
526 if (!mus_card || nomusicparm)
527 return;
528
529 if (mus_playing)
530 {
531 if (mus_paused)
532 I_ResumeSong(mus_playing->handle);
533
534 I_StopSong(mus_playing->handle);
535 I_UnRegisterSong(mus_playing->handle);
536 if (mus_playing->lumpnum >= 0)
537 W_UnlockLumpNum(mus_playing->lumpnum); // cph - release the music data
538
539 mus_playing->data = 0;
540 mus_playing = 0;
541 }
542}
543
544
545
546void S_StopChannel(int cnum)
547{
548 int i;
549 channel_t *c = &channels[cnum];
550
551 //jff 1/22/98 return if sound is not enabled
552 if (!snd_card || nosfxparm)
553 return;
554
555 if (c->sfxinfo)
556 {
557 // stop the sound playing
558 if (I_SoundIsPlaying(c->handle))
559 I_StopSound(c->handle);
560
561 // check to see
562 // if other channels are playing the sound
563 for (i=0 ; i<numChannels ; i++)
564 if (cnum != i && c->sfxinfo == channels[i].sfxinfo)
565 break;
566
567 // degrade usefulness of sound data
568 c->sfxinfo->usefulness--;
569 c->sfxinfo = 0;
570 }
571}
572
573//
574// Changes volume, stereo-separation, and pitch variables
575// from the norm of a sound effect to be played.
576// If the sound is not audible, returns a 0.
577// Otherwise, modifies parameters and returns 1.
578//
579
580int S_AdjustSoundParams(mobj_t *listener, mobj_t *source,
581 int *vol, int *sep, int *pitch)
582{
583 fixed_t adx, ady,approx_dist;
584 angle_t angle;
585
586 //jff 1/22/98 return if sound is not enabled
587 if (!snd_card || nosfxparm)
588 return 0;
589
590 // e6y
591 // Fix crash when the program wants to S_AdjustSoundParams() for player
592 // which is not displayplayer and displayplayer was not spawned at the moment.
593 // It happens in multiplayer demos only.
594 //
595 // Stack trace is:
596 // P_SetupLevel() \ P_LoadThings() \ P_SpawnMapThing() \ P_SpawnPlayer(players[0]) \
597 // P_SetupPsprites() \ P_BringUpWeapon() \ S_StartSound(players[0]->mo, sfx_sawup) \
598 // S_StartSoundAtVolume() \ S_AdjustSoundParams(players[displayplayer]->mo, ...);
599 // players[displayplayer]->mo is NULL
600 //
601 // There is no more crash on e1cmnet3.lmp between e1m2 and e1m3
602 // http://competn.doom2.net/pub/compet-n/doom/coop/movies/e1cmnet3.zip
603 if (!listener)
604 return 0;
605
606 // calculate the distance to sound origin
607 // and clip it if necessary
608 adx = D_abs(listener->x - source->x);
609 ady = D_abs(listener->y - source->y);
610
611 // From _GG1_ p.428. Appox. eucledian distance fast.
612 approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
613
614 if (!approx_dist) // killough 11/98: handle zero-distance as special case
615 {
616 *sep = NORM_SEP;
617 *vol = snd_SfxVolume;
618 return *vol > 0;
619 }
620
621 if (approx_dist > S_CLIPPING_DIST)
622 return 0;
623
624 // angle of source to listener
625 angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y);
626
627 if (angle <= listener->angle)
628 angle += 0xffffffff;
629 angle -= listener->angle;
630 angle >>= ANGLETOFINESHIFT;
631
632 // stereo separation
633 *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS);
634
635 // volume calculation
636 if (approx_dist < S_CLOSE_DIST)
637 *vol = snd_SfxVolume*8;
638 else
639 // distance effect
640 *vol = (snd_SfxVolume * ((S_CLIPPING_DIST-approx_dist)>>FRACBITS) * 8)
641 / S_ATTENUATOR;
642
643 return (*vol > 0);
644}
645
646//
647// S_getChannel :
648// If none available, return -1. Otherwise channel #.
649//
650// killough 4/25/98: made static, added is_pickup argument
651
652static int S_getChannel(void *origin, sfxinfo_t *sfxinfo, int is_pickup)
653{
654 // channel number to use
655 int cnum;
656 channel_t *c;
657
658 //jff 1/22/98 return if sound is not enabled
659 if (!snd_card || nosfxparm)
660 return -1;
661
662 // Find an open channel
663 for (cnum=0; cnum<numChannels && channels[cnum].sfxinfo; cnum++)
664 if (origin && channels[cnum].origin == origin &&
665 channels[cnum].is_pickup == is_pickup)
666 {
667 S_StopChannel(cnum);
668 break;
669 }
670
671 // None available
672 if (cnum == numChannels)
673 { // Look for lower priority
674 for (cnum=0 ; cnum<numChannels ; cnum++)
675 if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
676 break;
677 if (cnum == numChannels)
678 return -1; // No lower priority. Sorry, Charlie.
679 else
680 S_StopChannel(cnum); // Otherwise, kick out lower priority.
681 }
682
683 c = &channels[cnum]; // channel is decided to be cnum.
684 c->sfxinfo = sfxinfo;
685 c->origin = origin;
686 c->is_pickup = is_pickup; // killough 4/25/98
687 return cnum;
688}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * The not so system specific sound interface.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __S_SOUND__
35#define __S_SOUND__
36
37#ifdef __GNUG__
38#pragma interface
39#endif
40
41//
42// Initializes sound stuff, including volume
43// Sets channels, SFX and music volume,
44// allocates channel buffer, sets S_sfx lookup.
45//
46void S_Init(int sfxVolume, int musicVolume);
47
48// Kills all sounds
49void S_Stop(void);
50
51//
52// Per level startup code.
53// Kills playing sounds at start of level,
54// determines music if any, changes music.
55//
56void S_Start(void);
57
58//
59// Start sound for thing at <origin>
60// using <sound_id> from sounds.h
61//
62void S_StartSound(void *origin, int sound_id);
63
64// Will start a sound at a given volume.
65void S_StartSoundAtVolume(void *origin, int sound_id, int volume);
66
67// killough 4/25/98: mask used to indicate sound origin is player item pickup
68#define PICKUP_SOUND (0x8000)
69
70// Stop sound for thing at <origin>
71void S_StopSound(void* origin);
72
73// Start music using <music_id> from sounds.h
74void S_StartMusic(int music_id);
75
76// Start music using <music_id> from sounds.h, and set whether looping
77void S_ChangeMusic(int music_id, int looping);
78
79// Stops the music fer sure.
80void S_StopMusic(void);
81
82// Stop and resume music, during game PAUSE.
83void S_PauseSound(void);
84void S_ResumeSound(void);
85
86//
87// Updates music & sounds
88//
89void S_UpdateSounds(void* listener);
90void S_SetMusicVolume(int volume);
91void S_SetSfxVolume(int volume);
92
93// machine-independent sound params
94extern int default_numChannels;
95extern int numChannels;
96
97//jff 3/17/98 holds last IDMUS number, or -1
98extern int idmusnum;
99
100#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Created by a sound utility.
31 * Kept as a sample, DOOM2 sounds.
32 *
33 *-----------------------------------------------------------------------------*/
34
35// killough 5/3/98: reformatted
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
41#include "doomtype.h"
42#include "sounds.h"
43
44//
45// Information about all the music
46//
47
48musicinfo_t S_music[] = {
49 { 0 },
50 { "e1m1", 0 },
51 { "e1m2", 0 },
52 { "e1m3", 0 },
53 { "e1m4", 0 },
54 { "e1m5", 0 },
55 { "e1m6", 0 },
56 { "e1m7", 0 },
57 { "e1m8", 0 },
58 { "e1m9", 0 },
59 { "e2m1", 0 },
60 { "e2m2", 0 },
61 { "e2m3", 0 },
62 { "e2m4", 0 },
63 { "e2m5", 0 },
64 { "e2m6", 0 },
65 { "e2m7", 0 },
66 { "e2m8", 0 },
67 { "e2m9", 0 },
68 { "e3m1", 0 },
69 { "e3m2", 0 },
70 { "e3m3", 0 },
71 { "e3m4", 0 },
72 { "e3m5", 0 },
73 { "e3m6", 0 },
74 { "e3m7", 0 },
75 { "e3m8", 0 },
76 { "e3m9", 0 },
77 { "inter", 0 },
78 { "intro", 0 },
79 { "bunny", 0 },
80 { "victor", 0 },
81 { "introa", 0 },
82 { "runnin", 0 },
83 { "stalks", 0 },
84 { "countd", 0 },
85 { "betwee", 0 },
86 { "doom", 0 },
87 { "the_da", 0 },
88 { "shawn", 0 },
89 { "ddtblu", 0 },
90 { "in_cit", 0 },
91 { "dead", 0 },
92 { "stlks2", 0 },
93 { "theda2", 0 },
94 { "doom2", 0 },
95 { "ddtbl2", 0 },
96 { "runni2", 0 },
97 { "dead2", 0 },
98 { "stlks3", 0 },
99 { "romero", 0 },
100 { "shawn2", 0 },
101 { "messag", 0 },
102 { "count2", 0 },
103 { "ddtbl3", 0 },
104 { "ampie", 0 },
105 { "theda3", 0 },
106 { "adrian", 0 },
107 { "messg2", 0 },
108 { "romer2", 0 },
109 { "tense", 0 },
110 { "shawn3", 0 },
111 { "openin", 0 },
112 { "evil", 0 },
113 { "ultima", 0 },
114 { "read_m", 0 },
115 { "dm2ttl", 0 },
116 { "dm2int", 0 },
117};
118
119
120//
121// Information about all the sfx
122//
123
124sfxinfo_t S_sfx[] = {
125 // S_sfx[0] needs to be a dummy for odd reasons.
126 { "none", false, 0, 0, -1, -1, 0 },
127
128 { "pistol", false, 64, 0, -1, -1, 0 },
129 { "shotgn", false, 64, 0, -1, -1, 0 },
130 { "sgcock", false, 64, 0, -1, -1, 0 },
131 { "dshtgn", false, 64, 0, -1, -1, 0 },
132 { "dbopn", false, 64, 0, -1, -1, 0 },
133 { "dbcls", false, 64, 0, -1, -1, 0 },
134 { "dbload", false, 64, 0, -1, -1, 0 },
135 { "plasma", false, 64, 0, -1, -1, 0 },
136 { "bfg", false, 64, 0, -1, -1, 0 },
137 { "sawup", false, 64, 0, -1, -1, 0 },
138 { "sawidl", false, 118, 0, -1, -1, 0 },
139 { "sawful", false, 64, 0, -1, -1, 0 },
140 { "sawhit", false, 64, 0, -1, -1, 0 },
141 { "rlaunc", false, 64, 0, -1, -1, 0 },
142 { "rxplod", false, 70, 0, -1, -1, 0 },
143 { "firsht", false, 70, 0, -1, -1, 0 },
144 { "firxpl", false, 70, 0, -1, -1, 0 },
145 { "pstart", false, 100, 0, -1, -1, 0 },
146 { "pstop", false, 100, 0, -1, -1, 0 },
147 { "doropn", false, 100, 0, -1, -1, 0 },
148 { "dorcls", false, 100, 0, -1, -1, 0 },
149 { "stnmov", false, 119, 0, -1, -1, 0 },
150 { "swtchn", false, 78, 0, -1, -1, 0 },
151 { "swtchx", false, 78, 0, -1, -1, 0 },
152 { "plpain", false, 96, 0, -1, -1, 0 },
153 { "dmpain", false, 96, 0, -1, -1, 0 },
154 { "popain", false, 96, 0, -1, -1, 0 },
155 { "vipain", false, 96, 0, -1, -1, 0 },
156 { "mnpain", false, 96, 0, -1, -1, 0 },
157 { "pepain", false, 96, 0, -1, -1, 0 },
158 { "slop", false, 78, 0, -1, -1, 0 },
159 { "itemup", true, 78, 0, -1, -1, 0 },
160 { "wpnup", true, 78, 0, -1, -1, 0 },
161 { "oof", false, 96, 0, -1, -1, 0 },
162 { "telept", false, 32, 0, -1, -1, 0 },
163 { "posit1", true, 98, 0, -1, -1, 0 },
164 { "posit2", true, 98, 0, -1, -1, 0 },
165 { "posit3", true, 98, 0, -1, -1, 0 },
166 { "bgsit1", true, 98, 0, -1, -1, 0 },
167 { "bgsit2", true, 98, 0, -1, -1, 0 },
168 { "sgtsit", true, 98, 0, -1, -1, 0 },
169 { "cacsit", true, 98, 0, -1, -1, 0 },
170 { "brssit", true, 94, 0, -1, -1, 0 },
171 { "cybsit", true, 92, 0, -1, -1, 0 },
172 { "spisit", true, 90, 0, -1, -1, 0 },
173 { "bspsit", true, 90, 0, -1, -1, 0 },
174 { "kntsit", true, 90, 0, -1, -1, 0 },
175 { "vilsit", true, 90, 0, -1, -1, 0 },
176 { "mansit", true, 90, 0, -1, -1, 0 },
177 { "pesit", true, 90, 0, -1, -1, 0 },
178 { "sklatk", false, 70, 0, -1, -1, 0 },
179 { "sgtatk", false, 70, 0, -1, -1, 0 },
180 { "skepch", false, 70, 0, -1, -1, 0 },
181 { "vilatk", false, 70, 0, -1, -1, 0 },
182 { "claw", false, 70, 0, -1, -1, 0 },
183 { "skeswg", false, 70, 0, -1, -1, 0 },
184 { "pldeth", false, 32, 0, -1, -1, 0 },
185 { "pdiehi", false, 32, 0, -1, -1, 0 },
186 { "podth1", false, 70, 0, -1, -1, 0 },
187 { "podth2", false, 70, 0, -1, -1, 0 },
188 { "podth3", false, 70, 0, -1, -1, 0 },
189 { "bgdth1", false, 70, 0, -1, -1, 0 },
190 { "bgdth2", false, 70, 0, -1, -1, 0 },
191 { "sgtdth", false, 70, 0, -1, -1, 0 },
192 { "cacdth", false, 70, 0, -1, -1, 0 },
193 { "skldth", false, 70, 0, -1, -1, 0 },
194 { "brsdth", false, 32, 0, -1, -1, 0 },
195 { "cybdth", false, 32, 0, -1, -1, 0 },
196 { "spidth", false, 32, 0, -1, -1, 0 },
197 { "bspdth", false, 32, 0, -1, -1, 0 },
198 { "vildth", false, 32, 0, -1, -1, 0 },
199 { "kntdth", false, 32, 0, -1, -1, 0 },
200 { "pedth", false, 32, 0, -1, -1, 0 },
201 { "skedth", false, 32, 0, -1, -1, 0 },
202 { "posact", true, 120, 0, -1, -1, 0 },
203 { "bgact", true, 120, 0, -1, -1, 0 },
204 { "dmact", true, 120, 0, -1, -1, 0 },
205 { "bspact", true, 100, 0, -1, -1, 0 },
206 { "bspwlk", true, 100, 0, -1, -1, 0 },
207 { "vilact", true, 100, 0, -1, -1, 0 },
208 { "noway", false, 78, 0, -1, -1, 0 },
209 { "barexp", false, 60, 0, -1, -1, 0 },
210 { "punch", false, 64, 0, -1, -1, 0 },
211 { "hoof", false, 70, 0, -1, -1, 0 },
212 { "metal", false, 70, 0, -1, -1, 0 },
213 { "chgun", false, 64, &S_sfx[sfx_pistol], 150, 0, 0 },
214 { "tink", false, 60, 0, -1, -1, 0 },
215 { "bdopn", false, 100, 0, -1, -1, 0 },
216 { "bdcls", false, 100, 0, -1, -1, 0 },
217 { "itmbk", false, 100, 0, -1, -1, 0 },
218 { "flame", false, 32, 0, -1, -1, 0 },
219 { "flamst", false, 32, 0, -1, -1, 0 },
220 { "getpow", false, 60, 0, -1, -1, 0 },
221 { "bospit", false, 70, 0, -1, -1, 0 },
222 { "boscub", false, 70, 0, -1, -1, 0 },
223 { "bossit", false, 70, 0, -1, -1, 0 },
224 { "bospn", false, 70, 0, -1, -1, 0 },
225 { "bosdth", false, 70, 0, -1, -1, 0 },
226 { "manatk", false, 70, 0, -1, -1, 0 },
227 { "mandth", false, 70, 0, -1, -1, 0 },
228 { "sssit", false, 70, 0, -1, -1, 0 },
229 { "ssdth", false, 70, 0, -1, -1, 0 },
230 { "keenpn", false, 70, 0, -1, -1, 0 },
231 { "keendt", false, 70, 0, -1, -1, 0 },
232 { "skeact", false, 70, 0, -1, -1, 0 },
233 { "skesit", false, 70, 0, -1, -1, 0 },
234 { "skeatk", false, 70, 0, -1, -1, 0 },
235 { "radio", false, 60, 0, -1, -1, 0 },
236
237#ifdef DOGS
238 // killough 11/98: dog sounds
239 { "dgsit", false, 98, 0, -1, -1, 0 },
240 { "dgatk", false, 70, 0, -1, -1, 0 },
241 { "dgact", false, 120, 0, -1, -1, 0 },
242 { "dgdth", false, 70, 0, -1, -1, 0 },
243 { "dgpain", false, 96, 0, -1, -1, 0 },
244#endif
245};
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Created by the sound utility written by Dave Taylor.
31 * Kept as a sample, DOOM2 sounds. Frozen.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#ifndef __SOUNDS__
36#define __SOUNDS__
37
38//
39// SoundFX struct.
40//
41
42struct sfxinfo_struct;
43
44typedef struct sfxinfo_struct sfxinfo_t;
45
46struct sfxinfo_struct {
47
48 // up to 6-character name
49 const char *name; // CPhipps - const
50
51 // Sfx singularity (only one at a time)
52 int singularity;
53
54 // Sfx priority
55 int priority;
56
57 // referenced sound if a link
58 sfxinfo_t *link;
59
60 // pitch if a link
61 int pitch;
62
63 // volume if a link
64 int volume;
65
66 // sound data
67 void *data;
68
69 // this is checked every second to see if sound
70 // can be thrown out (if 0, then decrement, if -1,
71 // then throw out, if > 0, then it is in use)
72 int usefulness;
73
74 // lump number of sfx
75 int lumpnum;
76};
77
78//
79// MusicInfo struct.
80//
81
82typedef struct {
83 // up to 6-character name
84 const char *name; // CPhipps - const
85
86 // lump number of music
87 int lumpnum;
88
89 /* music data - cphipps 4/11 made const void* */
90 const void *data;
91
92 // music handle once registered
93 int handle;
94} musicinfo_t;
95
96// the complete set of sound effects
97extern sfxinfo_t S_sfx[];
98
99// the complete set of music
100extern musicinfo_t S_music[];
101
102//
103// Identifiers for all music in game.
104//
105
106typedef enum {
107 mus_None,
108 mus_e1m1,
109 mus_e1m2,
110 mus_e1m3,
111 mus_e1m4,
112 mus_e1m5,
113 mus_e1m6,
114 mus_e1m7,
115 mus_e1m8,
116 mus_e1m9,
117 mus_e2m1,
118 mus_e2m2,
119 mus_e2m3,
120 mus_e2m4,
121 mus_e2m5,
122 mus_e2m6,
123 mus_e2m7,
124 mus_e2m8,
125 mus_e2m9,
126 mus_e3m1,
127 mus_e3m2,
128 mus_e3m3,
129 mus_e3m4,
130 mus_e3m5,
131 mus_e3m6,
132 mus_e3m7,
133 mus_e3m8,
134 mus_e3m9,
135 mus_inter,
136 mus_intro,
137 mus_bunny,
138 mus_victor,
139 mus_introa,
140 mus_runnin,
141 mus_stalks,
142 mus_countd,
143 mus_betwee,
144 mus_doom,
145 mus_the_da,
146 mus_shawn,
147 mus_ddtblu,
148 mus_in_cit,
149 mus_dead,
150 mus_stlks2,
151 mus_theda2,
152 mus_doom2,
153 mus_ddtbl2,
154 mus_runni2,
155 mus_dead2,
156 mus_stlks3,
157 mus_romero,
158 mus_shawn2,
159 mus_messag,
160 mus_count2,
161 mus_ddtbl3,
162 mus_ampie,
163 mus_theda3,
164 mus_adrian,
165 mus_messg2,
166 mus_romer2,
167 mus_tense,
168 mus_shawn3,
169 mus_openin,
170 mus_evil,
171 mus_ultima,
172 mus_read_m,
173 mus_dm2ttl,
174 mus_dm2int,
175 NUMMUSIC
176} musicenum_t;
177
178//
179// Identifiers for all sfx in game.
180//
181
182typedef enum {
183 sfx_None,
184 sfx_pistol,
185 sfx_shotgn,
186 sfx_sgcock,
187 sfx_dshtgn,
188 sfx_dbopn,
189 sfx_dbcls,
190 sfx_dbload,
191 sfx_plasma,
192 sfx_bfg,
193 sfx_sawup,
194 sfx_sawidl,
195 sfx_sawful,
196 sfx_sawhit,
197 sfx_rlaunc,
198 sfx_rxplod,
199 sfx_firsht,
200 sfx_firxpl,
201 sfx_pstart,
202 sfx_pstop,
203 sfx_doropn,
204 sfx_dorcls,
205 sfx_stnmov,
206 sfx_swtchn,
207 sfx_swtchx,
208 sfx_plpain,
209 sfx_dmpain,
210 sfx_popain,
211 sfx_vipain,
212 sfx_mnpain,
213 sfx_pepain,
214 sfx_slop,
215 sfx_itemup,
216 sfx_wpnup,
217 sfx_oof,
218 sfx_telept,
219 sfx_posit1,
220 sfx_posit2,
221 sfx_posit3,
222 sfx_bgsit1,
223 sfx_bgsit2,
224 sfx_sgtsit,
225 sfx_cacsit,
226 sfx_brssit,
227 sfx_cybsit,
228 sfx_spisit,
229 sfx_bspsit,
230 sfx_kntsit,
231 sfx_vilsit,
232 sfx_mansit,
233 sfx_pesit,
234 sfx_sklatk,
235 sfx_sgtatk,
236 sfx_skepch,
237 sfx_vilatk,
238 sfx_claw,
239 sfx_skeswg,
240 sfx_pldeth,
241 sfx_pdiehi,
242 sfx_podth1,
243 sfx_podth2,
244 sfx_podth3,
245 sfx_bgdth1,
246 sfx_bgdth2,
247 sfx_sgtdth,
248 sfx_cacdth,
249 sfx_skldth,
250 sfx_brsdth,
251 sfx_cybdth,
252 sfx_spidth,
253 sfx_bspdth,
254 sfx_vildth,
255 sfx_kntdth,
256 sfx_pedth,
257 sfx_skedth,
258 sfx_posact,
259 sfx_bgact,
260 sfx_dmact,
261 sfx_bspact,
262 sfx_bspwlk,
263 sfx_vilact,
264 sfx_noway,
265 sfx_barexp,
266 sfx_punch,
267 sfx_hoof,
268 sfx_metal,
269 sfx_chgun,
270 sfx_tink,
271 sfx_bdopn,
272 sfx_bdcls,
273 sfx_itmbk,
274 sfx_flame,
275 sfx_flamst,
276 sfx_getpow,
277 sfx_bospit,
278 sfx_boscub,
279 sfx_bossit,
280 sfx_bospn,
281 sfx_bosdth,
282 sfx_manatk,
283 sfx_mandth,
284 sfx_sssit,
285 sfx_ssdth,
286 sfx_keenpn,
287 sfx_keendt,
288 sfx_skeact,
289 sfx_skesit,
290 sfx_skeatk,
291 sfx_radio,
292
293#ifdef DOGS
294 /* killough 11/98: dog sounds */
295 sfx_dgsit,
296 sfx_dgatk,
297 sfx_dgact,
298 sfx_dgdth,
299 sfx_dgpain,
300#endif
301
302 NUMSFX
303} sfxenum_t;
304
305#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * The status bar widget code.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomdef.h"
35#include "doomstat.h"
36#include "v_video.h"
37#include "w_wad.h"
38#include "st_stuff.h"
39#include "st_lib.h"
40#include "r_main.h"
41#include "lprintf.h"
42
43int sts_always_red; //jff 2/18/98 control to disable status color changes
44int sts_pct_always_gray; // killough 2/21/98: always gray %'s? bug or feature?
45
46//
47// STlib_init()
48//
49void STlib_init(void)
50{
51 // cph - no longer hold STMINUS pointer
52}
53
54//
55// STlib_initNum()
56//
57// Initializes an st_number_t widget
58//
59// Passed the widget, its position, the patches for the digits, a pointer
60// to the value displayed, a pointer to the on/off control, and the width
61// Returns nothing
62//
63void STlib_initNum
64( st_number_t* n,
65 int x,
66 int y,
67 const patchnum_t* pl,
68 int* num,
69 boolean* on,
70 int width )
71{
72 n->x = x;
73 n->y = y;
74 n->oldnum = 0;
75 n->width = width;
76 n->num = num;
77 n->on = on;
78 n->p = pl;
79}
80
81/*
82 * STlib_drawNum()
83 *
84 * A fairly efficient way to draw a number based on differences from the
85 * old number.
86 *
87 * Passed a st_number_t widget, a color range for output, and a flag
88 * indicating whether refresh is needed.
89 * Returns nothing
90 *
91 * jff 2/16/98 add color translation to digit output
92 * cphipps 10/99 - const pointer to colour trans table, made function static
93 */
94static void STlib_drawNum
95( st_number_t* n,
96 int cm,
97 boolean refresh )
98{
99
100 int numdigits = n->width;
101 int num = *n->num;
102
103 int w = n->p[0].width;
104 int h = n->p[0].height;
105 int x = n->x;
106
107 int neg;
108
109 // leban 1/20/99:
110 // strange that somebody went through all the work to draw only the
111 // differences, and then went and constantly redrew all the numbers.
112 // return without drawing if the number didn't change and the bar
113 // isn't refreshing.
114 if(n->oldnum == num && !refresh)
115 return;
116
117 // CPhipps - compact some code, use num instead of *n->num
118 if ((neg = (n->oldnum = num) < 0))
119 {
120 if (numdigits == 2 && num < -9)
121 num = -9;
122 else if (numdigits == 3 && num < -99)
123 num = -99;
124
125 num = -num;
126 }
127
128 // clear the area
129 x = n->x - numdigits*w;
130
131#ifdef RANGECHECK
132 if (n->y - ST_Y < 0)
133 I_Error("STlib_drawNum: n->y - ST_Y < 0");
134#endif
135
136 V_CopyRect(x, n->y - ST_Y, BG, w*numdigits, h, x, n->y, FG, VPT_STRETCH);
137
138 // if non-number, do not draw it
139 if (num == 1994)
140 return;
141
142 x = n->x;
143
144 //jff 2/16/98 add color translation to digit output
145 // in the special case of 0, you draw 0
146 if (!num)
147 // CPhipps - patch drawing updated, reformatted
148 V_DrawNumPatch(x - w, n->y, FG, n->p[0].lumpnum, cm,
149 (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH);
150
151 // draw the new number
152 //jff 2/16/98 add color translation to digit output
153 while (num && numdigits--) {
154 // CPhipps - patch drawing updated, reformatted
155 x -= w;
156 V_DrawNumPatch(x, n->y, FG, n->p[num % 10].lumpnum, cm,
157 (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH);
158 num /= 10;
159 }
160
161 // draw a minus sign if necessary
162 //jff 2/16/98 add color translation to digit output
163 // cph - patch drawing updated, load by name instead of acquiring pointer earlier
164 if (neg)
165 V_DrawNamePatch(x - w, n->y, FG, "STTMINUS", cm,
166 (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH);
167}
168
169/*
170 * STlib_updateNum()
171 *
172 * Draws a number conditionally based on the widget's enable
173 *
174 * Passed a number widget, the output color range, and a refresh flag
175 * Returns nothing
176 *
177 * jff 2/16/98 add color translation to digit output
178 * cphipps 10/99 - make that pointer const
179 */
180void STlib_updateNum
181( st_number_t* n,
182 int cm,
183 boolean refresh )
184{
185 if (*n->on) STlib_drawNum(n, cm, refresh);
186}
187
188//
189// STlib_initPercent()
190//
191// Initialize a st_percent_t number with percent sign widget
192//
193// Passed a st_percent_t widget, the position, the digit patches, a pointer
194// to the number to display, a pointer to the enable flag, and patch
195// for the percent sign.
196// Returns nothing.
197//
198void STlib_initPercent
199( st_percent_t* p,
200 int x,
201 int y,
202 const patchnum_t* pl,
203 int* num,
204 boolean* on,
205 const patchnum_t* percent )
206{
207 STlib_initNum(&p->n, x, y, pl, num, on, 3);
208 p->p = percent;
209}
210
211/*
212 * STlib_updatePercent()
213 *
214 * Draws a number/percent conditionally based on the widget's enable
215 *
216 * Passed a precent widget, the output color range, and a refresh flag
217 * Returns nothing
218 *
219 * jff 2/16/98 add color translation to digit output
220 * cphipps - const for pointer to the colour translation table
221 */
222
223void STlib_updatePercent
224( st_percent_t* per,
225 int cm,
226 int refresh )
227{
228 if (*per->n.on && (refresh || (per->n.oldnum != *per->n.num))) {
229 // killough 2/21/98: fix percents not updated;
230 /* CPhipps - make %'s only be updated if number changed */
231 // CPhipps - patch drawing updated
232 V_DrawNumPatch(per->n.x, per->n.y, FG, per->p->lumpnum,
233 sts_pct_always_gray ? CR_GRAY : cm,
234 (sts_always_red ? VPT_NONE : VPT_TRANS) | VPT_STRETCH);
235 }
236
237 STlib_updateNum(&per->n, cm, refresh);
238}
239
240//
241// STlib_initMultIcon()
242//
243// Initialize a st_multicon_t widget, used for a multigraphic display
244// like the status bar's keys.
245//
246// Passed a st_multicon_t widget, the position, the graphic patches, a pointer
247// to the numbers representing what to display, and pointer to the enable flag
248// Returns nothing.
249//
250void STlib_initMultIcon
251( st_multicon_t* i,
252 int x,
253 int y,
254 const patchnum_t* il,
255 int* inum,
256 boolean* on )
257{
258 i->x = x;
259 i->y = y;
260 i->oldinum = -1;
261 i->inum = inum;
262 i->on = on;
263 i->p = il;
264}
265
266//
267// STlib_updateMultIcon()
268//
269// Draw a st_multicon_t widget, used for a multigraphic display
270// like the status bar's keys. Displays each when the control
271// numbers change or refresh is true
272//
273// Passed a st_multicon_t widget, and a refresh flag
274// Returns nothing.
275//
276void STlib_updateMultIcon
277( st_multicon_t* mi,
278 boolean refresh )
279{
280 int w;
281 int h;
282 int x;
283 int y;
284
285 if (*mi->on && (mi->oldinum != *mi->inum || refresh))
286 {
287 if (mi->oldinum != -1)
288 {
289 x = mi->x - mi->p[mi->oldinum].leftoffset;
290 y = mi->y - mi->p[mi->oldinum].topoffset;
291 w = mi->p[mi->oldinum].width;
292 h = mi->p[mi->oldinum].height;
293
294#ifdef RANGECHECK
295 if (y - ST_Y < 0)
296 I_Error("STlib_updateMultIcon: y - ST_Y < 0");
297#endif
298
299 V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH);
300 }
301 if (*mi->inum != -1) // killough 2/16/98: redraw only if != -1
302 V_DrawNumPatch(mi->x, mi->y, FG, mi->p[*mi->inum].lumpnum, CR_DEFAULT, VPT_STRETCH);
303 mi->oldinum = *mi->inum;
304 }
305}
306
307//
308// STlib_initBinIcon()
309//
310// Initialize a st_binicon_t widget, used for a multinumber display
311// like the status bar's weapons, that are present or not.
312//
313// Passed a st_binicon_t widget, the position, the digit patches, a pointer
314// to the flags representing what is displayed, and pointer to the enable flag
315// Returns nothing.
316//
317void STlib_initBinIcon
318( st_binicon_t* b,
319 int x,
320 int y,
321 const patchnum_t* i,
322 boolean* val,
323 boolean* on )
324{
325 b->x = x;
326 b->y = y;
327 b->oldval = 0;
328 b->val = val;
329 b->on = on;
330 b->p = i;
331}
332
333//
334// STlib_updateBinIcon()
335//
336// DInitialize a st_binicon_t widget, used for a multinumber display
337// like the status bar's weapons, that are present or not.
338//
339// Draw a st_binicon_t widget, used for a multinumber display
340// like the status bar's weapons that are present or not. Displays each
341// when the control flag changes or refresh is true
342//
343// Passed a st_binicon_t widget, and a refresh flag
344// Returns nothing.
345//
346void STlib_updateBinIcon
347( st_binicon_t* bi,
348 boolean refresh )
349{
350 int x;
351 int y;
352 int w;
353 int h;
354
355 if (*bi->on && (bi->oldval != *bi->val || refresh))
356 {
357 x = bi->x - bi->p->leftoffset;
358 y = bi->y - bi->p->topoffset;
359 w = bi->p->width;
360 h = bi->p->height;
361
362#ifdef RANGECHECK
363 if (y - ST_Y < 0)
364 I_Error("STlib_updateBinIcon: y - ST_Y < 0");
365#endif
366
367 if (*bi->val)
368 V_DrawNumPatch(bi->x, bi->y, FG, bi->p->lumpnum, CR_DEFAULT, VPT_STRETCH);
369 else
370 V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH);
371
372 bi->oldval = *bi->val;
373 }
374}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * The status bar widget definitions and prototypes
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __STLIB__
35#define __STLIB__
36
37// We are referring to patches.
38#include "r_defs.h"
39#include "v_video.h" // color ranges
40
41//
42// Background and foreground screen numbers
43//
44#define BG 4
45#define FG 0
46
47//
48// Typedefs of widgets
49//
50
51// Number widget
52
53typedef struct
54{
55 // upper right-hand corner
56 // of the number (right-justified)
57 int x;
58 int y;
59
60 // max # of digits in number
61 int width;
62
63 // last number value
64 int oldnum;
65
66 // pointer to current value
67 int* num;
68
69 // pointer to boolean stating
70 // whether to update number
71 boolean* on;
72
73 // list of patches for 0-9
74 const patchnum_t* p;
75
76 // user data
77 int data;
78} st_number_t;
79
80// Percent widget ("child" of number widget,
81// or, more precisely, contains a number widget.)
82typedef struct
83{
84 // number information
85 st_number_t n;
86
87 // percent sign graphic
88 const patchnum_t* p;
89} st_percent_t;
90
91// Multiple Icon widget
92typedef struct
93{
94 // center-justified location of icons
95 int x;
96 int y;
97
98 // last icon number
99 int oldinum;
100
101 // pointer to current icon
102 int* inum;
103
104 // pointer to boolean stating
105 // whether to update icon
106 boolean* on;
107
108 // list of icons
109 const patchnum_t* p;
110
111 // user data
112 int data;
113
114} st_multicon_t;
115
116// Binary Icon widget
117
118typedef struct
119{
120 // center-justified location of icon
121 int x;
122 int y;
123
124 // last icon value
125 boolean oldval;
126
127 // pointer to current icon status
128 boolean* val;
129
130 // pointer to boolean
131 // stating whether to update icon
132 boolean* on;
133
134 const patchnum_t* p; // icon
135 int data; // user data
136} st_binicon_t;
137
138//
139// Widget creation, access, and update routines
140//
141
142// Initializes widget library.
143// More precisely, initialize STMINUS,
144// everything else is done somewhere else.
145//
146void STlib_init(void);
147
148// Number widget routines
149void STlib_initNum
150( st_number_t* n,
151 int x,
152 int y,
153 const patchnum_t* pl,
154 int* num,
155 boolean* on,
156 int width );
157
158void STlib_updateNum
159( st_number_t* n,
160 int cm,
161 boolean refresh );
162
163
164// Percent widget routines
165void STlib_initPercent
166( st_percent_t* p,
167 int x,
168 int y,
169 const patchnum_t* pl,
170 int* num,
171 boolean* on,
172 const patchnum_t* percent );
173
174
175void STlib_updatePercent
176( st_percent_t* per,
177 int cm,
178 int refresh );
179
180
181// Multiple Icon widget routines
182void STlib_initMultIcon
183( st_multicon_t* mi,
184 int x,
185 int y,
186 const patchnum_t* il,
187 int* inum,
188 boolean* on );
189
190
191void STlib_updateMultIcon
192( st_multicon_t* mi,
193 boolean refresh );
194
195// Binary Icon widget routines
196
197void STlib_initBinIcon
198( st_binicon_t* b,
199 int x,
200 int y,
201 const patchnum_t* i,
202 boolean* val,
203 boolean* on );
204
205void STlib_updateBinIcon
206( st_binicon_t* bi,
207 boolean refresh );
208
209#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Status bar code.
31 * Does the face/direction indicator animatin.
32 * Does palette indicators as well (red pain/berserk, bright pickup)
33 *
34 *-----------------------------------------------------------------------------*/
35
36#include "doomdef.h"
37#include "doomstat.h"
38#include "m_random.h"
39#include "i_video.h"
40#include "w_wad.h"
41#include "st_stuff.h"
42#include "st_lib.h"
43#include "r_main.h"
44#include "am_map.h"
45#include "m_cheat.h"
46#include "s_sound.h"
47#include "sounds.h"
48#include "dstrings.h"
49#include "r_draw.h"
50
51//
52// STATUS BAR DATA
53//
54
55// Palette indices.
56// For damage/bonus red-/gold-shifts
57#define STARTREDPALS 1
58#define STARTBONUSPALS 9
59#define NUMREDPALS 8
60#define NUMBONUSPALS 4
61// Radiation suit, green shift.
62#define RADIATIONPAL 13
63
64// Location of status bar
65#define ST_X 0
66#define ST_X2 104
67
68// proff 08/18/98: Changed for high-res
69#define ST_FX (ST_X+143)
70#define ST_FY (ST_Y+1)
71//#define ST_FX 143
72//#define ST_FY 169
73
74// Should be set to patch width
75// for tall numbers later on
76#define ST_TALLNUMWIDTH (tallnum[0]->width)
77
78// Number of status faces.
79#define ST_NUMPAINFACES 5
80#define ST_NUMSTRAIGHTFACES 3
81#define ST_NUMTURNFACES 2
82#define ST_NUMSPECIALFACES 3
83
84#define ST_FACESTRIDE \
85 (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES)
86
87#define ST_NUMEXTRAFACES 2
88
89#define ST_NUMFACES \
90 (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES)
91
92#define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES)
93#define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES)
94#define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1)
95#define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1)
96#define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE)
97#define ST_DEADFACE (ST_GODFACE+1)
98
99// proff 08/18/98: Changed for high-res
100#define ST_FACESX (ST_X+143)
101#define ST_FACESY (ST_Y)
102//#define ST_FACESX 143
103//#define ST_FACESY 168
104
105#define ST_EVILGRINCOUNT (2*TICRATE)
106#define ST_STRAIGHTFACECOUNT (TICRATE/2)
107#define ST_TURNCOUNT (1*TICRATE)
108#define ST_OUCHCOUNT (1*TICRATE)
109#define ST_RAMPAGEDELAY (2*TICRATE)
110
111#define ST_MUCHPAIN 20
112
113// Location and size of statistics,
114// justified according to widget type.
115// Problem is, within which space? STbar? Screen?
116// Note: this could be read in by a lump.
117// Problem is, is the stuff rendered
118// into a buffer,
119// or into the frame buffer?
120// I dunno, why don't you go and find out!!! killough
121
122// AMMO number pos.
123#define ST_AMMOWIDTH 3
124// proff 08/18/98: Changed for high-res
125#define ST_AMMOX (ST_X+44)
126#define ST_AMMOY (ST_Y+3)
127//#define ST_AMMOX 44
128//#define ST_AMMOY 171
129
130// HEALTH number pos.
131#define ST_HEALTHWIDTH 3
132// proff 08/18/98: Changed for high-res
133#define ST_HEALTHX (ST_X+90)
134#define ST_HEALTHY (ST_Y+3)
135//#define ST_HEALTHX 90
136//#define ST_HEALTHY 171
137
138// Weapon pos.
139// proff 08/18/98: Changed for high-res
140#define ST_ARMSX (ST_X+111)
141#define ST_ARMSY (ST_Y+4)
142#define ST_ARMSBGX (ST_X+104)
143#define ST_ARMSBGY (ST_Y)
144//#define ST_ARMSX 111
145//#define ST_ARMSY 172
146//#define ST_ARMSBGX 104
147//#define ST_ARMSBGY 168
148#define ST_ARMSXSPACE 12
149#define ST_ARMSYSPACE 10
150
151// Frags pos.
152// proff 08/18/98: Changed for high-res
153#define ST_FRAGSX (ST_X+138)
154#define ST_FRAGSY (ST_Y+3)
155//#define ST_FRAGSX 138
156//#define ST_FRAGSY 171
157#define ST_FRAGSWIDTH 2
158
159// ARMOR number pos.
160#define ST_ARMORWIDTH 3
161// proff 08/18/98: Changed for high-res
162#define ST_ARMORX (ST_X+221)
163#define ST_ARMORY (ST_Y+3)
164//#define ST_ARMORX 221
165//#define ST_ARMORY 171
166
167// Key icon positions.
168#define ST_KEY0WIDTH 8
169#define ST_KEY0HEIGHT 5
170// proff 08/18/98: Changed for high-res
171#define ST_KEY0X (ST_X+239)
172#define ST_KEY0Y (ST_Y+3)
173//#define ST_KEY0X 239
174//#define ST_KEY0Y 171
175#define ST_KEY1WIDTH ST_KEY0WIDTH
176// proff 08/18/98: Changed for high-res
177#define ST_KEY1X (ST_X+239)
178#define ST_KEY1Y (ST_Y+13)
179//#define ST_KEY1X 239
180//#define ST_KEY1Y 181
181#define ST_KEY2WIDTH ST_KEY0WIDTH
182// proff 08/18/98: Changed for high-res
183#define ST_KEY2X (ST_X+239)
184#define ST_KEY2Y (ST_Y+23)
185//#define ST_KEY2X 239
186//#define ST_KEY2Y 191
187
188// Ammunition counter.
189#define ST_AMMO0WIDTH 3
190#define ST_AMMO0HEIGHT 6
191// proff 08/18/98: Changed for high-res
192#define ST_AMMO0X (ST_X+288)
193#define ST_AMMO0Y (ST_Y+5)
194//#define ST_AMMO0X 288
195//#define ST_AMMO0Y 173
196#define ST_AMMO1WIDTH ST_AMMO0WIDTH
197// proff 08/18/98: Changed for high-res
198#define ST_AMMO1X (ST_X+288)
199#define ST_AMMO1Y (ST_Y+11)
200//#define ST_AMMO1X 288
201//#define ST_AMMO1Y 179
202#define ST_AMMO2WIDTH ST_AMMO0WIDTH
203// proff 08/18/98: Changed for high-res
204#define ST_AMMO2X (ST_X+288)
205#define ST_AMMO2Y (ST_Y+23)
206//#define ST_AMMO2X 288
207//#define ST_AMMO2Y 191
208#define ST_AMMO3WIDTH ST_AMMO0WIDTH
209// proff 08/18/98: Changed for high-res
210#define ST_AMMO3X (ST_X+288)
211#define ST_AMMO3Y (ST_Y+17)
212//#define ST_AMMO3X 288
213//#define ST_AMMO3Y 185
214
215// Indicate maximum ammunition.
216// Only needed because backpack exists.
217#define ST_MAXAMMO0WIDTH 3
218#define ST_MAXAMMO0HEIGHT 5
219// proff 08/18/98: Changed for high-res
220#define ST_MAXAMMO0X (ST_X+314)
221#define ST_MAXAMMO0Y (ST_Y+5)
222//#define ST_MAXAMMO0X 314
223//#define ST_MAXAMMO0Y 173
224#define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH
225// proff 08/18/98: Changed for high-res
226#define ST_MAXAMMO1X (ST_X+314)
227#define ST_MAXAMMO1Y (ST_Y+11)
228//#define ST_MAXAMMO1X 314
229//#define ST_MAXAMMO1Y 179
230#define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH
231// proff 08/18/98: Changed for high-res
232#define ST_MAXAMMO2X (ST_X+314)
233#define ST_MAXAMMO2Y (ST_Y+23)
234//#define ST_MAXAMMO2X 314
235//#define ST_MAXAMMO2Y 191
236#define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH
237// proff 08/18/98: Changed for high-res
238#define ST_MAXAMMO3X (ST_X+314)
239#define ST_MAXAMMO3Y (ST_Y+17)
240//#define ST_MAXAMMO3X 314
241//#define ST_MAXAMMO3Y 185
242
243// killough 2/8/98: weapon info position macros UNUSED, removed here
244
245// main player in game
246static player_t *plyr;
247
248// ST_Start() has just been called
249static boolean st_firsttime;
250
251// used to execute ST_Init() only once
252static int veryfirsttime = 1;
253
254// CPhipps - no longer do direct PLAYPAL handling here
255
256// used for timing
257static unsigned int st_clock;
258
259// used for making messages go away
260static int st_msgcounter=0;
261
262// used when in chat
263static st_chatstateenum_t st_chatstate;
264
265// whether in automap or first-person
266static st_stateenum_t st_gamestate;
267
268// whether left-side main status bar is active
269static boolean st_statusbaron;
270
271// whether status bar chat is active
272static boolean st_chat;
273
274// value of st_chat before message popped up
275static boolean st_oldchat;
276
277// whether chat window has the cursor on
278static boolean st_cursoron;
279
280// !deathmatch
281static boolean st_notdeathmatch;
282
283// !deathmatch && st_statusbaron
284static boolean st_armson;
285
286// !deathmatch
287static boolean st_fragson;
288
289// 0-9, tall numbers
290static patchnum_t tallnum[10];
291
292// tall % sign
293static patchnum_t tallpercent;
294
295// 0-9, short, yellow (,different!) numbers
296static patchnum_t shortnum[10];
297
298// 3 key-cards, 3 skulls, 3 card/skull combos
299// jff 2/24/98 extend number of patches by three skull/card combos
300static patchnum_t keys[NUMCARDS+3];
301
302// face status patches
303static patchnum_t faces[ST_NUMFACES];
304
305// face background
306static patchnum_t faceback; // CPhipps - single background, translated for different players
307
308//e6y: status bar background
309static patchnum_t stbarbg;
310
311// main bar right
312static patchnum_t armsbg;
313
314// weapon ownership patches
315static patchnum_t arms[6][2];
316
317// ready-weapon widget
318static st_number_t w_ready;
319
320//jff 2/16/98 status color change levels
321int ammo_red; // ammo percent less than which status is red
322int ammo_yellow; // ammo percent less is yellow more green
323int health_red; // health amount less than which status is red
324int health_yellow; // health amount less than which status is yellow
325int health_green; // health amount above is blue, below is green
326int armor_red; // armor amount less than which status is red
327int armor_yellow; // armor amount less than which status is yellow
328int armor_green; // armor amount above is blue, below is green
329
330 // in deathmatch only, summary of frags stats
331static st_number_t w_frags;
332
333// health widget
334static st_percent_t w_health;
335
336// arms background
337static st_binicon_t w_armsbg;
338
339// weapon ownership widgets
340static st_multicon_t w_arms[6];
341
342// face status widget
343static st_multicon_t w_faces;
344
345// keycard widgets
346static st_multicon_t w_keyboxes[3];
347
348// armor widget
349static st_percent_t w_armor;
350
351// ammo widgets
352static st_number_t w_ammo[4];
353
354// max ammo widgets
355static st_number_t w_maxammo[4];
356
357 // number of frags so far in deathmatch
358static int st_fragscount;
359
360// used to use appopriately pained face
361static int st_oldhealth = -1;
362
363// used for evil grin
364static boolean oldweaponsowned[NUMWEAPONS];
365
366 // count until face changes
367static int st_facecount = 0;
368
369// current face index, used by w_faces
370static int st_faceindex = 0;
371
372// holds key-type for each key box on bar
373static int keyboxes[3];
374
375// a random number per tick
376static int st_randomnumber;
377
378extern char *mapnames[];
379
380//
381// STATUS BAR CODE
382//
383
384static void ST_Stop(void);
385
386static void ST_refreshBackground(void)
387{
388 int y=0;
389
390 if (st_statusbaron)
391 {
392 // proff 05/17/2000: draw to the frontbuffer in OpenGL
393 if (V_GetMode() == VID_MODEGL)
394 y=ST_Y;
395 V_DrawNumPatch(ST_X, y, BG, stbarbg.lumpnum, CR_DEFAULT, VPT_STRETCH);
396 if (st_armson)
397 V_DrawNumPatch(ST_ARMSBGX, y, BG, armsbg.lumpnum, CR_DEFAULT, VPT_STRETCH);
398
399 // killough 3/7/98: make face background change with displayplayer
400 if (netgame)
401 {
402 V_DrawNumPatch(ST_FX, y, BG, faceback.lumpnum,
403 displayplayer ? CR_LIMIT+displayplayer : CR_DEFAULT,
404 displayplayer ? (VPT_TRANS | VPT_STRETCH) : VPT_STRETCH);
405 }
406 V_CopyRect(ST_X, y, BG, ST_SCALED_WIDTH, ST_SCALED_HEIGHT, ST_X, ST_SCALED_Y, FG, VPT_NONE);
407 }
408}
409
410
411// Respond to keyboard input events,
412// intercept cheats.
413boolean ST_Responder(event_t *ev)
414{
415 // Filter automap on/off.
416 if (ev->type == ev_keyup && (ev->data1 & 0xffff0000) == AM_MSGHEADER)
417 {
418 switch(ev->data1)
419 {
420 case AM_MSGENTERED:
421 st_gamestate = AutomapState;
422 st_firsttime = true;
423 break;
424
425 case AM_MSGEXITED:
426 st_gamestate = FirstPersonState;
427 break;
428 }
429 }
430 else // if a user keypress...
431 if (ev->type == ev_keydown) // Try cheat responder in m_cheat.c
432 return M_FindCheats(ev->data1); // killough 4/17/98, 5/2/98
433 return false;
434}
435
436static int ST_calcPainOffset(void)
437{
438 static int lastcalc;
439 static int oldhealth = -1;
440 int health = plyr->health > 100 ? 100 : plyr->health;
441
442 if (health != oldhealth)
443 {
444 lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101);
445 oldhealth = health;
446 }
447 return lastcalc;
448}
449
450//
451// This is a not-very-pretty routine which handles
452// the face states and their timing.
453// the precedence of expressions is:
454// dead > evil grin > turned head > straight ahead
455//
456
457static void ST_updateFaceWidget(void)
458{
459 int i;
460 angle_t badguyangle;
461 angle_t diffang;
462 static int lastattackdown = -1;
463 static int priority = 0;
464 boolean doevilgrin;
465
466 if (priority < 10)
467 {
468 // dead
469 if (!plyr->health)
470 {
471 priority = 9;
472 st_faceindex = ST_DEADFACE;
473 st_facecount = 1;
474 }
475 }
476
477 if (priority < 9)
478 {
479 if (plyr->bonuscount)
480 {
481 // picking up bonus
482 doevilgrin = false;
483
484 for (i=0;i<NUMWEAPONS;i++)
485 {
486 if (oldweaponsowned[i] != plyr->weaponowned[i])
487 {
488 doevilgrin = true;
489 oldweaponsowned[i] = plyr->weaponowned[i];
490 }
491 }
492 if (doevilgrin)
493 {
494 // evil grin if just picked up weapon
495 priority = 8;
496 st_facecount = ST_EVILGRINCOUNT;
497 st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET;
498 }
499 }
500
501 }
502
503 if (priority < 8)
504 {
505 if (plyr->damagecount && plyr->attacker && plyr->attacker != plyr->mo)
506 {
507 // being attacked
508 priority = 7;
509
510 // haleyjd 10/12/03: classic DOOM problem of missing OUCH face
511 // was due to inversion of this test:
512 // if(plyr->health - st_oldhealth > ST_MUCHPAIN)
513 if(st_oldhealth - plyr->health > ST_MUCHPAIN)
514 {
515 st_facecount = ST_TURNCOUNT;
516 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
517 }
518 else
519 {
520 badguyangle = R_PointToAngle2(plyr->mo->x,
521 plyr->mo->y,
522 plyr->attacker->x,
523 plyr->attacker->y);
524
525 if (badguyangle > plyr->mo->angle)
526 {
527 // whether right or left
528 diffang = badguyangle - plyr->mo->angle;
529 i = diffang > ANG180;
530 }
531 else
532 {
533 // whether left or right
534 diffang = plyr->mo->angle - badguyangle;
535 i = diffang <= ANG180;
536 } // confusing, aint it?
537
538
539 st_facecount = ST_TURNCOUNT;
540 st_faceindex = ST_calcPainOffset();
541
542 if (diffang < ANG45)
543 {
544 // head-on
545 st_faceindex += ST_RAMPAGEOFFSET;
546 }
547 else if (i)
548 {
549 // turn face right
550 st_faceindex += ST_TURNOFFSET;
551 }
552 else
553 {
554 // turn face left
555 st_faceindex += ST_TURNOFFSET+1;
556 }
557 }
558 }
559 }
560
561 if (priority < 7)
562 {
563 // getting hurt because of your own damn stupidity
564 if (plyr->damagecount)
565 {
566 // haleyjd 10/12/03: classic DOOM problem of missing OUCH face
567 // was due to inversion of this test:
568 // if(plyr->health - st_oldhealth > ST_MUCHPAIN)
569 if(st_oldhealth - plyr->health > ST_MUCHPAIN)
570 {
571 priority = 7;
572 st_facecount = ST_TURNCOUNT;
573 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
574 }
575 else
576 {
577 priority = 6;
578 st_facecount = ST_TURNCOUNT;
579 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
580 }
581
582 }
583
584 }
585
586 if (priority < 6)
587 {
588 // rapid firing
589 if (plyr->attackdown)
590 {
591 if (lastattackdown==-1)
592 lastattackdown = ST_RAMPAGEDELAY;
593 else if (!--lastattackdown)
594 {
595 priority = 5;
596 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
597 st_facecount = 1;
598 lastattackdown = 1;
599 }
600 }
601 else
602 lastattackdown = -1;
603
604 }
605
606 if (priority < 5)
607 {
608 // invulnerability
609 if ((plyr->cheats & CF_GODMODE)
610 || plyr->powers[pw_invulnerability])
611 {
612 priority = 4;
613
614 st_faceindex = ST_GODFACE;
615 st_facecount = 1;
616
617 }
618
619 }
620
621 // look left or look right if the facecount has timed out
622 if (!st_facecount)
623 {
624 st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3);
625 st_facecount = ST_STRAIGHTFACECOUNT;
626 priority = 0;
627 }
628
629 st_facecount--;
630
631}
632
633int sts_traditional_keys; // killough 2/28/98: traditional status bar keys
634
635static void ST_updateWidgets(void)
636{
637 static int largeammo = 1994; // means "n/a"
638 int i;
639
640 // must redirect the pointer if the ready weapon has changed.
641 // if (w_ready.data != plyr->readyweapon)
642 // {
643 if (weaponinfo[plyr->readyweapon].ammo == am_noammo)
644 w_ready.num = &largeammo;
645 else
646 w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo];
647 //{
648 // static int tic=0;
649 // static int dir=-1;
650 // if (!(tic&15))
651 // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir;
652 // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100)
653 // dir = 1;
654 // tic++;
655 // }
656 w_ready.data = plyr->readyweapon;
657
658 // if (*w_ready.on)
659 // STlib_updateNum(&w_ready, true);
660 // refresh weapon change
661 // }
662
663 // update keycard multiple widgets
664 for (i=0;i<3;i++)
665 {
666 keyboxes[i] = plyr->cards[i] ? i : -1;
667
668 //jff 2/24/98 select double key
669 //killough 2/28/98: preserve traditional keys by config option
670
671 if (plyr->cards[i+3])
672 keyboxes[i] = keyboxes[i]==-1 || sts_traditional_keys ? i+3 : i+6;
673 }
674
675 // refresh everything if this is him coming back to life
676 ST_updateFaceWidget();
677
678 // used by the w_armsbg widget
679 st_notdeathmatch = !deathmatch;
680
681 // used by w_arms[] widgets
682 st_armson = st_statusbaron && !deathmatch;
683
684 // used by w_frags widget
685 st_fragson = deathmatch && st_statusbaron;
686 st_fragscount = 0;
687
688 for (i=0 ; i<MAXPLAYERS ; i++)
689 {
690 if (i != displayplayer) // killough 3/7/98
691 st_fragscount += plyr->frags[i];
692 else
693 st_fragscount -= plyr->frags[i];
694 }
695
696 // get rid of chat window if up because of message
697 if (!--st_msgcounter)
698 st_chat = st_oldchat;
699
700}
701
702void ST_Ticker(void)
703{
704 st_clock++;
705 st_randomnumber = M_Random();
706 ST_updateWidgets();
707 st_oldhealth = plyr->health;
708}
709
710int st_palette = 0;
711
712static void ST_doPaletteStuff(void)
713{
714 int palette;
715 int cnt = plyr->damagecount;
716
717 if (plyr->powers[pw_strength])
718 {
719 // slowly fade the berzerk out
720 int bzc = 12 - (plyr->powers[pw_strength]>>6);
721 if (bzc > cnt)
722 cnt = bzc;
723 }
724
725 if (cnt)
726 {
727 palette = (cnt+7)>>3;
728 if (palette >= NUMREDPALS)
729 palette = NUMREDPALS-1;
730
731 /* cph 2006/08/06 - if in the menu, reduce the red tint - navigating to
732 * load a game can be tricky if the screen is all red */
733 if (menuactive) palette >>=1;
734
735 palette += STARTREDPALS;
736 }
737 else
738 if (plyr->bonuscount)
739 {
740 palette = (plyr->bonuscount+7)>>3;
741 if (palette >= NUMBONUSPALS)
742 palette = NUMBONUSPALS-1;
743 palette += STARTBONUSPALS;
744 }
745 else
746 if (plyr->powers[pw_ironfeet] > 4*32 || plyr->powers[pw_ironfeet] & 8)
747 palette = RADIATIONPAL;
748 else
749 palette = 0;
750
751 if (palette != st_palette) {
752 V_SetPalette(st_palette = palette); // CPhipps - use new palette function
753
754 // have to redraw the entire status bar when the palette changes
755 // in truecolor modes - POPE
756 if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32)
757 st_firsttime = true;
758 }
759}
760
761static void ST_drawWidgets(boolean refresh)
762{
763 int i;
764
765 // used by w_arms[] widgets
766 st_armson = st_statusbaron && !deathmatch;
767
768 // used by w_frags widget
769 st_fragson = deathmatch && st_statusbaron;
770
771 //jff 2/16/98 make color of ammo depend on amount
772 if (*w_ready.num*100 < ammo_red*plyr->maxammo[weaponinfo[w_ready.data].ammo])
773 STlib_updateNum(&w_ready, CR_RED, refresh);
774 else
775 if (*w_ready.num*100 <
776 ammo_yellow*plyr->maxammo[weaponinfo[w_ready.data].ammo])
777 STlib_updateNum(&w_ready, CR_GOLD, refresh);
778 else
779 STlib_updateNum(&w_ready, CR_GREEN, refresh);
780
781 for (i=0;i<4;i++)
782 {
783 STlib_updateNum(&w_ammo[i], CR_DEFAULT, refresh); //jff 2/16/98 no xlation
784 STlib_updateNum(&w_maxammo[i], CR_DEFAULT, refresh);
785 }
786
787 //jff 2/16/98 make color of health depend on amount
788 if (*w_health.n.num<health_red)
789 STlib_updatePercent(&w_health, CR_RED, refresh);
790 else if (*w_health.n.num<health_yellow)
791 STlib_updatePercent(&w_health, CR_GOLD, refresh);
792 else if (*w_health.n.num<=health_green)
793 STlib_updatePercent(&w_health, CR_GREEN, refresh);
794 else
795 STlib_updatePercent(&w_health, CR_BLUE2, refresh); //killough 2/28/98
796
797 //jff 2/16/98 make color of armor depend on amount
798 if (*w_armor.n.num<armor_red)
799 STlib_updatePercent(&w_armor, CR_RED, refresh);
800 else if (*w_armor.n.num<armor_yellow)
801 STlib_updatePercent(&w_armor, CR_GOLD, refresh);
802 else if (*w_armor.n.num<=armor_green)
803 STlib_updatePercent(&w_armor, CR_GREEN, refresh);
804 else
805 STlib_updatePercent(&w_armor, CR_BLUE2, refresh); //killough 2/28/98
806
807 //e6y: moved to ST_refreshBackground() for correct single-pass stretching
808 //STlib_updateBinIcon(&w_armsbg, refresh);
809
810 for (i=0;i<6;i++)
811 STlib_updateMultIcon(&w_arms[i], refresh);
812
813 STlib_updateMultIcon(&w_faces, refresh);
814
815 for (i=0;i<3;i++)
816 STlib_updateMultIcon(&w_keyboxes[i], refresh);
817
818 STlib_updateNum(&w_frags, CR_DEFAULT, refresh);
819
820}
821
822static void ST_doRefresh(void)
823{
824
825 st_firsttime = false;
826
827 // draw status bar background to off-screen buff
828 ST_refreshBackground();
829
830 // and refresh all widgets
831 ST_drawWidgets(true);
832
833}
834
835static void ST_diffDraw(void)
836{
837 // update all widgets
838 ST_drawWidgets(false);
839}
840
841void ST_Drawer(boolean statusbaron, boolean refresh)
842{
843 /* cph - let status bar on be controlled
844 * completely by the call from D_Display
845 * proff - really do it
846 */
847 st_firsttime = st_firsttime || refresh;
848
849 ST_doPaletteStuff(); // Do red-/gold-shifts from damage/items
850
851 if (statusbaron) {
852 if (st_firsttime || (V_GetMode() == VID_MODEGL))
853 ST_doRefresh(); /* If just after ST_Start(), refresh all */
854 else
855 ST_diffDraw(); /* Otherwise, update as little as possible */
856 }
857}
858
859
860
861//
862// ST_loadGraphics
863//
864// CPhipps - Loads graphics needed for status bar if doload is true,
865// unloads them otherwise
866//
867static void ST_loadGraphics(boolean doload)
868{
869 int i, facenum;
870 char namebuf[9];
871 // cph - macro that either acquires a pointer and lock for a lump, or
872 // unlocks it. var is referenced exactly once in either case, so ++ in arg works
873
874 // Load the numbers, tall and short
875 for (i=0;i<10;i++)
876 {
877 sprintf(namebuf, "STTNUM%d", i);
878 R_SetPatchNum(&tallnum[i],namebuf);
879 sprintf(namebuf, "STYSNUM%d", i);
880 R_SetPatchNum(&shortnum[i],namebuf);
881 }
882
883 // Load percent key.
884 R_SetPatchNum(&tallpercent,"STTPRCNT");
885
886 // key cards
887 for (i=0;i<NUMCARDS+3;i++) //jff 2/23/98 show both keys too
888 {
889 sprintf(namebuf, "STKEYS%d", i);
890 R_SetPatchNum(&keys[i], namebuf);
891 }
892
893 //e6y: status bar background
894 R_SetPatchNum(&stbarbg, "STBAR");
895
896 // arms background
897 R_SetPatchNum(&armsbg, "STARMS");
898
899 // arms ownership widgets
900 for (i=0;i<6;i++)
901 {
902 sprintf(namebuf, "STGNUM%d", i+2);
903
904 // gray #
905 R_SetPatchNum(&arms[i][0], namebuf);
906
907 // yellow #
908 arms[i][1] = shortnum[i+2];
909 }
910
911 // face backgrounds for different color players
912 // killough 3/7/98: add better support for spy mode by loading all
913 // player face backgrounds and using displayplayer to choose them:
914 R_SetPatchNum(&faceback, "STFB0");
915
916 // face states
917 facenum = 0;
918 for (i=0;i<ST_NUMPAINFACES;i++)
919 {
920 int j;
921 for (j=0;j<ST_NUMSTRAIGHTFACES;j++)
922 {
923 sprintf(namebuf, "STFST%d%d", i, j);
924 R_SetPatchNum(&faces[facenum++], namebuf);
925 }
926 sprintf(namebuf, "STFTR%d0", i); // turn right
927 R_SetPatchNum(&faces[facenum++], namebuf);
928 sprintf(namebuf, "STFTL%d0", i); // turn left
929 R_SetPatchNum(&faces[facenum++], namebuf);
930 sprintf(namebuf, "STFOUCH%d", i); // ouch!
931 R_SetPatchNum(&faces[facenum++], namebuf);
932 sprintf(namebuf, "STFEVL%d", i); // evil grin ;)
933 R_SetPatchNum(&faces[facenum++], namebuf);
934 sprintf(namebuf, "STFKILL%d", i); // pissed off
935 R_SetPatchNum(&faces[facenum++], namebuf);
936 }
937 R_SetPatchNum(&faces[facenum++], "STFGOD0");
938 R_SetPatchNum(&faces[facenum++], "STFDEAD0");
939}
940
941static void ST_loadData(void)
942{
943 ST_loadGraphics(true);
944}
945
946static void ST_unloadData(void)
947{
948 ST_loadGraphics(false);
949}
950
951static void ST_initData(void)
952{
953 int i;
954
955 st_firsttime = true;
956 plyr = &players[displayplayer]; // killough 3/7/98
957
958 st_clock = 0;
959 st_chatstate = StartChatState;
960 st_gamestate = FirstPersonState;
961
962 st_statusbaron = true;
963 st_oldchat = st_chat = false;
964 st_cursoron = false;
965
966 st_faceindex = 0;
967 st_palette = -1;
968
969 st_oldhealth = -1;
970
971 for (i=0;i<NUMWEAPONS;i++)
972 oldweaponsowned[i] = plyr->weaponowned[i];
973
974 for (i=0;i<3;i++)
975 keyboxes[i] = -1;
976
977 STlib_init();
978}
979
980static void ST_createWidgets(void)
981{
982 int i;
983
984 // ready weapon ammo
985 STlib_initNum(&w_ready,
986 ST_AMMOX,
987 ST_AMMOY,
988 tallnum,
989 &plyr->ammo[weaponinfo[plyr->readyweapon].ammo],
990 &st_statusbaron,
991 ST_AMMOWIDTH );
992
993 // the last weapon type
994 w_ready.data = plyr->readyweapon;
995
996 // health percentage
997 STlib_initPercent(&w_health,
998 ST_HEALTHX,
999 ST_HEALTHY,
1000 tallnum,
1001 &plyr->health,
1002 &st_statusbaron,
1003 &tallpercent);
1004
1005 // arms background
1006 STlib_initBinIcon(&w_armsbg,
1007 ST_ARMSBGX,
1008 ST_ARMSBGY,
1009 &armsbg,
1010 &st_notdeathmatch,
1011 &st_statusbaron);
1012
1013 // weapons owned
1014 for(i=0;i<6;i++)
1015 {
1016 STlib_initMultIcon(&w_arms[i],
1017 ST_ARMSX+(i%3)*ST_ARMSXSPACE,
1018 ST_ARMSY+(i/3)*ST_ARMSYSPACE,
1019 arms[i], (int *) &plyr->weaponowned[i+1],
1020 &st_armson);
1021 }
1022
1023 // frags sum
1024 STlib_initNum(&w_frags,
1025 ST_FRAGSX,
1026 ST_FRAGSY,
1027 tallnum,
1028 &st_fragscount,
1029 &st_fragson,
1030 ST_FRAGSWIDTH);
1031
1032 // faces
1033 STlib_initMultIcon(&w_faces,
1034 ST_FACESX,
1035 ST_FACESY,
1036 faces,
1037 &st_faceindex,
1038 &st_statusbaron);
1039
1040 // armor percentage - should be colored later
1041 STlib_initPercent(&w_armor,
1042 ST_ARMORX,
1043 ST_ARMORY,
1044 tallnum,
1045 &plyr->armorpoints,
1046 &st_statusbaron, &tallpercent);
1047
1048 // keyboxes 0-2
1049 STlib_initMultIcon(&w_keyboxes[0],
1050 ST_KEY0X,
1051 ST_KEY0Y,
1052 keys,
1053 &keyboxes[0],
1054 &st_statusbaron);
1055
1056 STlib_initMultIcon(&w_keyboxes[1],
1057 ST_KEY1X,
1058 ST_KEY1Y,
1059 keys,
1060 &keyboxes[1],
1061 &st_statusbaron);
1062
1063 STlib_initMultIcon(&w_keyboxes[2],
1064 ST_KEY2X,
1065 ST_KEY2Y,
1066 keys,
1067 &keyboxes[2],
1068 &st_statusbaron);
1069
1070 // ammo count (all four kinds)
1071 STlib_initNum(&w_ammo[0],
1072 ST_AMMO0X,
1073 ST_AMMO0Y,
1074 shortnum,
1075 &plyr->ammo[0],
1076 &st_statusbaron,
1077 ST_AMMO0WIDTH);
1078
1079 STlib_initNum(&w_ammo[1],
1080 ST_AMMO1X,
1081 ST_AMMO1Y,
1082 shortnum,
1083 &plyr->ammo[1],
1084 &st_statusbaron,
1085 ST_AMMO1WIDTH);
1086
1087 STlib_initNum(&w_ammo[2],
1088 ST_AMMO2X,
1089 ST_AMMO2Y,
1090 shortnum,
1091 &plyr->ammo[2],
1092 &st_statusbaron,
1093 ST_AMMO2WIDTH);
1094
1095 STlib_initNum(&w_ammo[3],
1096 ST_AMMO3X,
1097 ST_AMMO3Y,
1098 shortnum,
1099 &plyr->ammo[3],
1100 &st_statusbaron,
1101 ST_AMMO3WIDTH);
1102
1103 // max ammo count (all four kinds)
1104 STlib_initNum(&w_maxammo[0],
1105 ST_MAXAMMO0X,
1106 ST_MAXAMMO0Y,
1107 shortnum,
1108 &plyr->maxammo[0],
1109 &st_statusbaron,
1110 ST_MAXAMMO0WIDTH);
1111
1112 STlib_initNum(&w_maxammo[1],
1113 ST_MAXAMMO1X,
1114 ST_MAXAMMO1Y,
1115 shortnum,
1116 &plyr->maxammo[1],
1117 &st_statusbaron,
1118 ST_MAXAMMO1WIDTH);
1119
1120 STlib_initNum(&w_maxammo[2],
1121 ST_MAXAMMO2X,
1122 ST_MAXAMMO2Y,
1123 shortnum,
1124 &plyr->maxammo[2],
1125 &st_statusbaron,
1126 ST_MAXAMMO2WIDTH);
1127
1128 STlib_initNum(&w_maxammo[3],
1129 ST_MAXAMMO3X,
1130 ST_MAXAMMO3Y,
1131 shortnum,
1132 &plyr->maxammo[3],
1133 &st_statusbaron,
1134 ST_MAXAMMO3WIDTH);
1135}
1136
1137static boolean st_stopped = true;
1138
1139void ST_Start(void)
1140{
1141 if (!st_stopped)
1142 ST_Stop();
1143 ST_initData();
1144 ST_createWidgets();
1145 st_stopped = false;
1146}
1147
1148static void ST_Stop(void)
1149{
1150 if (st_stopped)
1151 return;
1152 V_SetPalette(0);
1153 st_stopped = true;
1154}
1155
1156void ST_Init(void)
1157{
1158 veryfirsttime = 0;
1159 ST_loadData();
1160}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Status bar code.
31 * Does the face/direction indicator animatin.
32 * Does palette indicators as well (red pain/berserk, bright pickup)
33 *
34 *-----------------------------------------------------------------------------*/
35
36#ifndef __STSTUFF_H__
37#define __STSTUFF_H__
38
39#include "doomtype.h"
40#include "d_event.h"
41
42// Size of statusbar.
43// Now sensitive for scaling.
44
45// proff 08/18/98: Changed for high-res
46#define ST_HEIGHT 32
47#define ST_WIDTH 320
48#define ST_Y (200 - ST_HEIGHT)
49#define ST_SCALED_HEIGHT (ST_HEIGHT*SCREENHEIGHT/200)
50#define ST_SCALED_WIDTH SCREENWIDTH
51#define ST_SCALED_Y (SCREENHEIGHT - ST_SCALED_HEIGHT)
52
53//
54// STATUS BAR
55//
56
57// Called by main loop.
58boolean ST_Responder(event_t* ev);
59
60// Called by main loop.
61void ST_Ticker(void);
62
63// Called by main loop.
64void ST_Drawer(boolean st_statusbaron, boolean refresh);
65
66// Called when the console player is spawned on each level.
67void ST_Start(void);
68
69// Called by startup code.
70void ST_Init(void);
71
72// States for status bar code.
73typedef enum
74{
75 AutomapState,
76 FirstPersonState
77} st_stateenum_t;
78
79// States for the chat code.
80typedef enum
81{
82 StartChatState,
83 WaitDestState,
84 GetChatState
85} st_chatstateenum_t;
86
87// killough 5/2/98: moved from m_misc.c:
88
89extern int health_red; // health amount less than which status is red
90extern int health_yellow; // health amount less than which status is yellow
91extern int health_green; // health amount above is blue, below is green
92extern int armor_red; // armor amount less than which status is red
93extern int armor_yellow; // armor amount less than which status is yellow
94extern int armor_green; // armor amount above is blue, below is green
95extern int ammo_red; // ammo percent less than which status is red
96extern int ammo_yellow; // ammo percent less is yellow more green
97extern int sts_always_red;// status numbers do not change colors
98extern int sts_pct_always_gray;// status percents do not change colors
99extern int sts_traditional_keys; // display keys the traditional way
100
101extern int st_palette; // cph 2006/04/06 - make palette visible
102#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Lookup tables.
31 * Do not try to look them up :-).
32 * In the order of appearance:
33 *
34 * int finetangent[4096] - Tangens LUT.
35 * Should work with BAM fairly well (12 of 16bit,
36 * effectively, by shifting).
37 *
38 * int finesine[10240] - Sine lookup.
39 * Guess what, serves as cosine, too.
40 * Remarkable thing is, how to use BAMs with this?
41 *
42 * int tantoangle[2049] - ArcTan LUT,
43 * maps tan(angle) to angle fast. Gotta search.
44 *
45 *-----------------------------------------------------------------------------
46 */
47
48#ifdef HAVE_CONFIG_H
49#include "config.h"
50#endif
51
52#include <stddef.h>
53#include "w_wad.h"
54#include "tables.h"
55
56// killough 5/3/98: reformatted
57
58int SlopeDiv(unsigned num, unsigned den)
59{
60 unsigned ans;
61
62 if (den < 512)
63 return SLOPERANGE;
64 ans = (num<<3)/(den>>8);
65 return ans <= SLOPERANGE ? ans : SLOPERANGE;
66}
67
68fixed_t finetangent[4096];
69
70//const fixed_t *const finecosine = &finesine[FINEANGLES/4];
71
72fixed_t finesine[10240];
73
74angle_t tantoangle[2049];
75
76#include "m_swap.h"
77#include "lprintf.h"
78
79// R_LoadTrigTables
80// Load trig tables from a wad file lump
81// CPhipps 24/12/98 - fix endianness (!)
82//
83void R_LoadTrigTables(void)
84{
85 int lump;
86 {
87 lump = (W_CheckNumForName)("SINETABL",ns_prboom);
88 if (lump == -1) I_Error("Failed to locate trig tables");
89 if (W_LumpLength(lump) != sizeof(finesine))
90 I_Error("R_LoadTrigTables: Invalid SINETABL");
91 W_ReadLump(lump,(unsigned char*)finesine);
92 }
93 {
94 lump = (W_CheckNumForName)("TANGTABL",ns_prboom);
95 if (lump == -1) I_Error("Failed to locate trig tables");
96 if (W_LumpLength(lump) != sizeof(finetangent))
97 I_Error("R_LoadTrigTables: Invalid TANGTABL");
98 W_ReadLump(lump,(unsigned char*)finetangent);
99 }
100 {
101 lump = (W_CheckNumForName)("TANTOANG",ns_prboom);
102 if (lump == -1) I_Error("Failed to locate trig tables");
103 if (W_LumpLength(lump) != sizeof(tantoangle))
104 I_Error("R_LoadTrigTables: Invalid TANTOANG");
105 W_ReadLump(lump,(unsigned char*)tantoangle);
106 }
107 // Endianness correction - might still be non-portable, but is fast where possible
108 {
109 size_t n;
110 lprintf(LO_INFO, "Endianness...");
111
112 // This test doesn't assume the endianness of the tables, but deduces them from
113 // en entry. I hope this is portable.
114 if ((10 < finesine[1]) && (finesine[1] < 100)) {
115 lprintf(LO_INFO, "ok.");
116 return; // Endianness is correct
117 }
118
119 // Must correct endianness of every long loaded (!)
120#define CORRECT_TABLE_ENDIAN(tbl) \
121 for (n = 0; n<sizeof(tbl)/sizeof(tbl[0]); n++) tbl[n] = doom_swap_l(tbl[n])
122
123 CORRECT_TABLE_ENDIAN(finesine);
124 CORRECT_TABLE_ENDIAN(finetangent);
125 CORRECT_TABLE_ENDIAN(tantoangle);
126 lprintf(LO_INFO, "corrected.");
127 }
128}
diff --git a/src/tables.h b/src/tables.h
new file mode 100644
index 0000000..bbb4a27
--- /dev/null
+++ b/src/tables.h
@@ -0,0 +1,93 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Lookup tables.
31 * Do not try to look them up :-).
32 * In the order of appearance:
33 *
34 * int finetangent[4096] - Tangens LUT.
35 * Should work with BAM fairly well (12 of 16bit,
36 * effectively, by shifting).
37 *
38 * int finesine[10240] - Sine lookup.
39 * Guess what, serves as cosine, too.
40 * Remarkable thing is, how to use BAMs with this?
41 *
42 * int tantoangle[2049] - ArcTan LUT,
43 * maps tan(angle) to angle fast. Gotta search.
44 *
45 *-----------------------------------------------------------------------------*/
46
47#ifndef __TABLES__
48#define __TABLES__
49
50#include "m_fixed.h"
51
52#define FINEANGLES 8192
53#define FINEMASK (FINEANGLES-1)
54
55// 0x100000000 to 0x2000
56#define ANGLETOFINESHIFT 19
57
58// Binary Angle Measument, BAM.
59#define ANG45 0x20000000
60#define ANG90 0x40000000
61#define ANG180 0x80000000
62#define ANG270 0xc0000000
63#ifndef M_PI
64#define M_PI 3.14159265358979323846
65#endif
66
67#define SLOPERANGE 2048
68#define SLOPEBITS 11
69#define DBITS (FRACBITS-SLOPEBITS)
70
71typedef unsigned angle_t;
72
73// Load trig tables if needed
74void R_LoadTrigTables(void);
75
76// Effective size is 10240.
77extern fixed_t finesine[5*FINEANGLES/4];
78
79// Re-use data, is just PI/2 phase shift.
80static fixed_t *const finecosine = finesine + (FINEANGLES/4);
81
82// Effective size is 4096.
83extern fixed_t finetangent[FINEANGLES/2];
84
85// Effective size is 2049;
86// The +1 size is to handle the case when x==y without additional checking.
87
88extern angle_t tantoangle[SLOPERANGE+1];
89
90// Utility function, called by R_PointToAngle.
91int SlopeDiv(unsigned num, unsigned den);
92
93#endif
diff --git a/src/v_video.c b/src/v_video.c
new file mode 100644
index 0000000..0921fe5
--- /dev/null
+++ b/src/v_video.c
@@ -0,0 +1,1037 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Gamma correction LUT stuff.
31 * Color range translation support
32 * Functions to draw patches (by post) directly to screen.
33 * Functions to blit a block to the screen.
34 *
35 *-----------------------------------------------------------------------------
36 */
37
38#include "doomdef.h"
39#include "r_main.h"
40#include "r_draw.h"
41#include "m_bbox.h"
42#include "w_wad.h" /* needed for color translation lump lookup */
43#include "v_video.h"
44#include "i_video.h"
45#include "r_filter.h"
46#include "lprintf.h"
47
48// Each screen is [SCREENWIDTH*SCREENHEIGHT];
49screeninfo_t screens[NUM_SCREENS];
50
51/* jff 4/24/98 initialize this at runtime */
52const byte *colrngs[CR_LIMIT];
53
54int usegamma;
55
56/*
57 * V_InitColorTranslation
58 *
59 * Loads the color translation tables from predefined lumps at game start
60 * No return
61 *
62 * Used for translating text colors from the red palette range
63 * to other colors. The first nine entries can be used to dynamically
64 * switch the output of text color thru the HUlib_drawText routine
65 * by embedding ESCn in the text to obtain color n. Symbols for n are
66 * provided in v_video.h.
67 *
68 * cphipps - constness of crdef_t stuff fixed
69 */
70
71typedef struct {
72 const char *name;
73 const byte **map;
74} crdef_t;
75
76// killough 5/2/98: table-driven approach
77static const crdef_t crdefs[] = {
78 {"CRBRICK", &colrngs[CR_BRICK ]},
79 {"CRTAN", &colrngs[CR_TAN ]},
80 {"CRGRAY", &colrngs[CR_GRAY ]},
81 {"CRGREEN", &colrngs[CR_GREEN ]},
82 {"CRBROWN", &colrngs[CR_BROWN ]},
83 {"CRGOLD", &colrngs[CR_GOLD ]},
84 {"CRRED", &colrngs[CR_RED ]},
85 {"CRBLUE", &colrngs[CR_BLUE ]},
86 {"CRORANGE", &colrngs[CR_ORANGE]},
87 {"CRYELLOW", &colrngs[CR_YELLOW]},
88 {"CRBLUE2", &colrngs[CR_BLUE2]},
89 {NULL}
90};
91
92// killough 5/2/98: tiny engine driven by table above
93void V_InitColorTranslation(void)
94{
95 register const crdef_t *p;
96 for (p=crdefs; p->name; p++)
97 *p->map = W_CacheLumpName(p->name);
98}
99
100//
101// V_CopyRect
102//
103// Copies a source rectangle in a screen buffer to a destination
104// rectangle in another screen buffer. Source origin in srcx,srcy,
105// destination origin in destx,desty, common size in width and height.
106// Source buffer specfified by srcscrn, destination buffer by destscrn.
107//
108// Marks the destination rectangle on the screen dirty.
109//
110// No return.
111//
112static void FUNC_V_CopyRect(int srcx, int srcy, int srcscrn, int width,
113 int height, int destx, int desty, int destscrn,
114 enum patch_translation_e flags)
115{
116 byte *src;
117 byte *dest;
118
119 if (flags & VPT_STRETCH)
120 {
121 srcx=srcx*SCREENWIDTH/320;
122 srcy=srcy*SCREENHEIGHT/200;
123 width=width*SCREENWIDTH/320;
124 height=height*SCREENHEIGHT/200;
125 destx=destx*SCREENWIDTH/320;
126 desty=desty*SCREENHEIGHT/200;
127 }
128
129#ifdef RANGECHECK
130 if (srcx<0
131 ||srcx+width >SCREENWIDTH
132 || srcy<0
133 || srcy+height>SCREENHEIGHT
134 ||destx<0||destx+width >SCREENWIDTH
135 || desty<0
136 || desty+height>SCREENHEIGHT)
137 I_Error ("V_CopyRect: Bad arguments");
138#endif
139
140 src = screens[srcscrn].data+screens[srcscrn].byte_pitch*srcy+srcx*V_GetPixelDepth();
141 dest = screens[destscrn].data+screens[destscrn].byte_pitch*desty+destx*V_GetPixelDepth();
142
143 for ( ; height>0 ; height--)
144 {
145 memcpy (dest, src, width*V_GetPixelDepth());
146 src += screens[srcscrn].byte_pitch;
147 dest += screens[destscrn].byte_pitch;
148 }
149}
150
151/*
152 * V_DrawBackground tiles a 64x64 patch over the entire screen, providing the
153 * background for the Help and Setup screens, and plot text betwen levels.
154 * cphipps - used to have M_DrawBackground, but that was used the framebuffer
155 * directly, so this is my code from the equivalent function in f_finale.c
156 */
157static void FUNC_V_DrawBackground(const char* flatname, int scrn)
158{
159 /* erase the entire screen to a tiled background */
160 const byte *src;
161 int x,y;
162 int width,height;
163 int lump;
164
165 // killough 4/17/98:
166 src = W_CacheLumpNum(lump = firstflat + R_FlatNumForName(flatname));
167
168 /* V_DrawBlock(0, 0, scrn, 64, 64, src, 0); */
169 width = height = 64;
170 if (V_GetMode() == VID_MODE8) {
171 byte *dest = screens[scrn].data;
172
173 while (height--) {
174 memcpy (dest, src, width);
175 src += width;
176 dest += screens[scrn].byte_pitch;
177 }
178 } else if (V_GetMode() == VID_MODE15) {
179 unsigned short *dest = (unsigned short *)screens[scrn].data;
180
181 while (height--) {
182 int i;
183 for (i=0; i<width; i++) {
184 dest[i] = VID_PAL15(src[i], VID_COLORWEIGHTMASK);
185 }
186 src += width;
187 dest += screens[scrn].short_pitch;
188 }
189 } else if (V_GetMode() == VID_MODE16) {
190 unsigned short *dest = (unsigned short *)screens[scrn].data;
191
192 while (height--) {
193 int i;
194 for (i=0; i<width; i++) {
195 dest[i] = VID_PAL16(src[i], VID_COLORWEIGHTMASK);
196 }
197 src += width;
198 dest += screens[scrn].short_pitch;
199 }
200 } else if (V_GetMode() == VID_MODE32) {
201 unsigned int *dest = (unsigned int *)screens[scrn].data;
202
203 while (height--) {
204 int i;
205 for (i=0; i<width; i++) {
206 dest[i] = VID_PAL32(src[i], VID_COLORWEIGHTMASK);
207 }
208 src += width;
209 dest += screens[scrn].int_pitch;
210 }
211 }
212 /* end V_DrawBlock */
213
214 for (y=0 ; y<SCREENHEIGHT ; y+=64)
215 for (x=y ? 0 : 64; x<SCREENWIDTH ; x+=64)
216 V_CopyRect(0, 0, scrn, ((SCREENWIDTH-x) < 64) ? (SCREENWIDTH-x) : 64,
217 ((SCREENHEIGHT-y) < 64) ? (SCREENHEIGHT-y) : 64, x, y, scrn, VPT_NONE);
218 W_UnlockLumpNum(lump);
219}
220
221//
222// V_Init
223//
224// Allocates the 4 full screen buffers in low DOS memory
225// No return
226//
227
228void V_Init (void)
229{
230 int i;
231
232 // reset the all
233 for (i = 0; i<NUM_SCREENS; i++) {
234 screens[i].data = NULL;
235 screens[i].not_on_heap = false;
236 screens[i].width = 0;
237 screens[i].height = 0;
238 screens[i].byte_pitch = 0;
239 screens[i].short_pitch = 0;
240 screens[i].int_pitch = 0;
241 }
242}
243
244//
245// V_DrawMemPatch
246//
247// CPhipps - unifying patch drawing routine, handles all cases and combinations
248// of stretching, flipping and translating
249//
250// This function is big, hopefully not too big that gcc can't optimise it well.
251// In fact it packs pretty well, there is no big performance lose for all this merging;
252// the inner loops themselves are just the same as they always were
253// (indeed, laziness of the people who wrote the 'clones' of the original V_DrawPatch
254// means that their inner loops weren't so well optimised, so merging code may even speed them).
255//
256static void V_DrawMemPatch(int x, int y, int scrn, const rpatch_t *patch,
257 int cm, enum patch_translation_e flags)
258{
259 const byte *trans;
260
261 if (cm<CR_LIMIT)
262 trans=colrngs[cm];
263 else
264 trans=translationtables + 256*((cm-CR_LIMIT)-1);
265 y -= patch->topoffset;
266 x -= patch->leftoffset;
267
268 // CPhipps - auto-no-stretch if not high-res
269 if (flags & VPT_STRETCH)
270 if ((SCREENWIDTH==320) && (SCREENHEIGHT==200))
271 flags &= ~VPT_STRETCH;
272
273 // CPhipps - null translation pointer => no translation
274 if (!trans)
275 flags &= ~VPT_TRANS;
276
277 if (V_GetMode() == VID_MODE8 && !(flags & VPT_STRETCH)) {
278 int col;
279 byte *desttop = screens[scrn].data+y*screens[scrn].byte_pitch+x*V_GetPixelDepth();
280 unsigned int w = patch->width;
281
282 if (y<0 || y+patch->height > ((flags & VPT_STRETCH) ? 200 : SCREENHEIGHT)) {
283 // killough 1/19/98: improved error message:
284 lprintf(LO_WARN, "V_DrawMemPatch8: Patch (%d,%d)-(%d,%d) exceeds LFB in vertical direction (horizontal is clipped)\n"
285 "Bad V_DrawMemPatch8 (flags=%u)", x, y, x+patch->width, y+patch->height, flags);
286 return;
287 }
288
289 w--; // CPhipps - note: w = width-1 now, speeds up flipping
290
291 for (col=0 ; (unsigned int)col<=w ; desttop++, col++, x++) {
292 int i;
293 const int colindex = (flags & VPT_FLIP) ? (w - col) : (col);
294 const rcolumn_t *column = R_GetPatchColumn(patch, colindex);
295
296 if (x < 0)
297 continue;
298 if (x >= SCREENWIDTH)
299 break;
300
301 // step through the posts in a column
302 for (i=0; i<column->numPosts; i++) {
303 const rpost_t *post = &column->posts[i];
304 // killough 2/21/98: Unrolled and performance-tuned
305
306 const byte *source = column->pixels + post->topdelta;
307 byte *dest = desttop + post->topdelta*screens[scrn].byte_pitch;
308 int count = post->length;
309
310 if (!(flags & VPT_TRANS)) {
311 if ((count-=4)>=0)
312 do {
313 register byte s0,s1;
314 s0 = source[0];
315 s1 = source[1];
316 dest[0] = s0;
317 dest[screens[scrn].byte_pitch] = s1;
318 dest += screens[scrn].byte_pitch*2;
319 s0 = source[2];
320 s1 = source[3];
321 source += 4;
322 dest[0] = s0;
323 dest[screens[scrn].byte_pitch] = s1;
324 dest += screens[scrn].byte_pitch*2;
325 } while ((count-=4)>=0);
326 if (count+=4)
327 do {
328 *dest = *source++;
329 dest += screens[scrn].byte_pitch;
330 } while (--count);
331 } else {
332 // CPhipps - merged translation code here
333 if ((count-=4)>=0)
334 do {
335 register byte s0,s1;
336 s0 = source[0];
337 s1 = source[1];
338 s0 = trans[s0];
339 s1 = trans[s1];
340 dest[0] = s0;
341 dest[screens[scrn].byte_pitch] = s1;
342 dest += screens[scrn].byte_pitch*2;
343 s0 = source[2];
344 s1 = source[3];
345 s0 = trans[s0];
346 s1 = trans[s1];
347 source += 4;
348 dest[0] = s0;
349 dest[screens[scrn].byte_pitch] = s1;
350 dest += screens[scrn].byte_pitch*2;
351 } while ((count-=4)>=0);
352 if (count+=4)
353 do {
354 *dest = trans[*source++];
355 dest += screens[scrn].byte_pitch;
356 } while (--count);
357 }
358 }
359 }
360 }
361 else {
362 // CPhipps - move stretched patch drawing code here
363 // - reformat initialisers, move variables into inner blocks
364
365 int col;
366 int w = (patch->width << 16) - 1; // CPhipps - -1 for faster flipping
367 int left, right, top, bottom;
368 int DX = (SCREENWIDTH<<16) / 320;
369 int DXI = (320<<16) / SCREENWIDTH;
370 int DY = (SCREENHEIGHT<<16) / 200;
371 int DYI = (200<<16) / SCREENHEIGHT;
372 R_DrawColumn_f colfunc;
373 draw_column_vars_t dcvars;
374 draw_vars_t olddrawvars = drawvars;
375
376 R_SetDefaultDrawColumnVars(&dcvars);
377
378 drawvars.byte_topleft = screens[scrn].data;
379 drawvars.short_topleft = (unsigned short *)screens[scrn].data;
380 drawvars.int_topleft = (unsigned int *)screens[scrn].data;
381 drawvars.byte_pitch = screens[scrn].byte_pitch;
382 drawvars.short_pitch = screens[scrn].short_pitch;
383 drawvars.int_pitch = screens[scrn].int_pitch;
384
385 if (!(flags & VPT_STRETCH)) {
386 DX = 1 << 16;
387 DXI = 1 << 16;
388 DY = 1 << 16;
389 DYI = 1 << 16;
390 }
391
392 if (flags & VPT_TRANS) {
393 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, drawvars.filterpatch, RDRAW_FILTER_NONE);
394 dcvars.translation = trans;
395 } else {
396 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterpatch, RDRAW_FILTER_NONE);
397 }
398
399 left = ( x * DX ) >> FRACBITS;
400 top = ( y * DY ) >> FRACBITS;
401 right = ( (x + patch->width) * DX ) >> FRACBITS;
402 bottom = ( (y + patch->height) * DY ) >> FRACBITS;
403
404 dcvars.texheight = patch->height;
405 dcvars.iscale = DYI;
406 dcvars.drawingmasked = MAX(patch->width, patch->height) > 8;
407 dcvars.edgetype = drawvars.patch_edges;
408
409 if (drawvars.filterpatch == RDRAW_FILTER_LINEAR) {
410 // bias the texture u coordinate
411 if (patch->isNotTileable)
412 col = -(FRACUNIT>>1);
413 else
414 col = (patch->width<<FRACBITS)-(FRACUNIT>>1);
415 }
416 else {
417 col = 0;
418 }
419
420 for (dcvars.x=left; dcvars.x<right; dcvars.x++, col+=DXI) {
421 int i;
422 const int colindex = (flags & VPT_FLIP) ? ((w - col)>>16): (col>>16);
423 const rcolumn_t *column = R_GetPatchColumn(patch, colindex);
424 const rcolumn_t *prevcolumn = R_GetPatchColumn(patch, colindex-1);
425 const rcolumn_t *nextcolumn = R_GetPatchColumn(patch, colindex+1);
426
427 // ignore this column if it's to the left of our clampRect
428 if (dcvars.x < 0)
429 continue;
430 if (dcvars.x >= SCREENWIDTH)
431 break;
432
433 dcvars.texu = ((flags & VPT_FLIP) ? ((patch->width<<FRACBITS)-col) : col) % (patch->width<<FRACBITS);
434
435 // step through the posts in a column
436 for (i=0; i<column->numPosts; i++) {
437 const rpost_t *post = &column->posts[i];
438 int yoffset = 0;
439
440 dcvars.yl = (((y + post->topdelta) * DY)>>FRACBITS);
441 dcvars.yh = (((y + post->topdelta + post->length) * DY - (FRACUNIT>>1))>>FRACBITS);
442 dcvars.edgeslope = post->slope;
443
444 if ((dcvars.yh < 0) || (dcvars.yh < top))
445 continue;
446 if ((dcvars.yl >= SCREENHEIGHT) || (dcvars.yl >= bottom))
447 continue;
448
449 if (dcvars.yh >= bottom) {
450 dcvars.yh = bottom-1;
451 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK;
452 }
453 if (dcvars.yh >= SCREENHEIGHT) {
454 dcvars.yh = SCREENHEIGHT-1;
455 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK;
456 }
457
458 if (dcvars.yl < 0) {
459 yoffset = 0-dcvars.yl;
460 dcvars.yl = 0;
461 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK;
462 }
463 if (dcvars.yl < top) {
464 yoffset = top-dcvars.yl;
465 dcvars.yl = top;
466 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK;
467 }
468
469 dcvars.source = column->pixels + post->topdelta + yoffset;
470 dcvars.prevsource = prevcolumn ? prevcolumn->pixels + post->topdelta + yoffset: dcvars.source;
471 dcvars.nextsource = nextcolumn ? nextcolumn->pixels + post->topdelta + yoffset: dcvars.source;
472
473 dcvars.texturemid = -((dcvars.yl-centery)*dcvars.iscale);
474
475 colfunc(&dcvars);
476 }
477 }
478
479 R_ResetColumnBuffer();
480 drawvars = olddrawvars;
481 }
482}
483
484// CPhipps - some simple, useful wrappers for that function, for drawing patches from wads
485
486// CPhipps - GNU C only suppresses generating a copy of a function if it is
487// static inline; other compilers have different behaviour.
488// This inline is _only_ for the function below
489
490static void FUNC_V_DrawNumPatch(int x, int y, int scrn, int lump,
491 int cm, enum patch_translation_e flags)
492{
493 V_DrawMemPatch(x, y, scrn, R_CachePatchNum(lump), cm, flags);
494 R_UnlockPatchNum(lump);
495}
496
497unsigned short *V_Palette15 = NULL;
498unsigned short *V_Palette16 = NULL;
499unsigned int *V_Palette32 = NULL;
500static unsigned short *Palettes15 = NULL;
501static unsigned short *Palettes16 = NULL;
502static unsigned int *Palettes32 = NULL;
503static int currentPaletteIndex = 0;
504
505//
506// V_UpdateTrueColorPalette
507//
508void V_UpdateTrueColorPalette(video_mode_t mode) {
509 int i, w, p;
510 byte r,g,b;
511 int nr,ng,nb;
512 float t;
513 int paletteNum = (V_GetMode() == VID_MODEGL ? 0 : currentPaletteIndex);
514 static int usegammaOnLastPaletteGeneration = -1;
515
516 int pplump = W_GetNumForName("PLAYPAL");
517 int gtlump = (W_CheckNumForName)("GAMMATBL",ns_prboom);
518 const byte *pal = W_CacheLumpNum(pplump);
519 // opengl doesn't use the gamma
520 const byte *const gtable =
521 (const byte *)W_CacheLumpNum(gtlump) +
522 (V_GetMode() == VID_MODEGL ? 0 : 256*(usegamma))
523 ;
524
525 int numPals = W_LumpLength(pplump) / (3*256);
526 const float dontRoundAbove = 220;
527 float roundUpR, roundUpG, roundUpB;
528
529 if (usegammaOnLastPaletteGeneration != usegamma) {
530 if (Palettes15) free(Palettes15);
531 if (Palettes16) free(Palettes16);
532 if (Palettes32) free(Palettes32);
533 Palettes15 = NULL;
534 Palettes16 = NULL;
535 Palettes32 = NULL;
536 usegammaOnLastPaletteGeneration = usegamma;
537 }
538
539 if (mode == VID_MODE32) {
540 if (!Palettes32) {
541 // set int palette
542 Palettes32 = (int*)malloc(numPals*256*sizeof(int)*VID_NUMCOLORWEIGHTS);
543 for (p=0; p<numPals; p++) {
544 for (i=0; i<256; i++) {
545 r = gtable[pal[(256*p+i)*3+0]];
546 g = gtable[pal[(256*p+i)*3+1]];
547 b = gtable[pal[(256*p+i)*3+2]];
548
549 // ideally, we should always round up, but very bright colors
550 // overflow the blending adds, so they don't get rounded.
551 roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
552 roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
553 roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
554
555 for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
556 t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
557 nr = (int)(r*t+roundUpR);
558 ng = (int)(g*t+roundUpG);
559 nb = (int)(b*t+roundUpB);
560 Palettes32[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
561 (nr<<16) | (ng<<8) | nb
562 );
563 }
564 }
565 }
566 }
567 V_Palette32 = Palettes32 + paletteNum*256*VID_NUMCOLORWEIGHTS;
568 }
569 else if (mode == VID_MODE16) {
570 if (!Palettes16) {
571 // set short palette
572 Palettes16 = (short*)malloc(numPals*256*sizeof(short)*VID_NUMCOLORWEIGHTS);
573 for (p=0; p<numPals; p++) {
574 for (i=0; i<256; i++) {
575 r = gtable[pal[(256*p+i)*3+0]];
576 g = gtable[pal[(256*p+i)*3+1]];
577 b = gtable[pal[(256*p+i)*3+2]];
578
579 // ideally, we should always round up, but very bright colors
580 // overflow the blending adds, so they don't get rounded.
581 roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
582 roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
583 roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
584
585 for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
586 t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
587 nr = (int)((r>>3)*t+roundUpR);
588 ng = (int)((g>>2)*t+roundUpG);
589 nb = (int)((b>>3)*t+roundUpB);
590 Palettes16[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
591 (nr<<11) | (ng<<5) | nb
592 );
593 }
594 }
595 }
596 }
597 V_Palette16 = Palettes16 + paletteNum*256*VID_NUMCOLORWEIGHTS;
598 }
599 else if (mode == VID_MODE15) {
600 if (!Palettes15) {
601 // set short palette
602 Palettes15 = (short*)malloc(numPals*256*sizeof(short)*VID_NUMCOLORWEIGHTS);
603 for (p=0; p<numPals; p++) {
604 for (i=0; i<256; i++) {
605 r = gtable[pal[(256*p+i)*3+0]];
606 g = gtable[pal[(256*p+i)*3+1]];
607 b = gtable[pal[(256*p+i)*3+2]];
608
609 // ideally, we should always round up, but very bright colors
610 // overflow the blending adds, so they don't get rounded.
611 roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
612 roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
613 roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
614
615 for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
616 t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
617 nr = (int)((r>>3)*t+roundUpR);
618 ng = (int)((g>>3)*t+roundUpG);
619 nb = (int)((b>>3)*t+roundUpB);
620 Palettes15[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
621 (nr<<10) | (ng<<5) | nb
622 );
623 }
624 }
625 }
626 }
627 V_Palette15 = Palettes15 + paletteNum*256*VID_NUMCOLORWEIGHTS;
628 }
629
630 W_UnlockLumpNum(pplump);
631 W_UnlockLumpNum(gtlump);
632}
633
634
635//---------------------------------------------------------------------------
636// V_DestroyTrueColorPalette
637//---------------------------------------------------------------------------
638static void V_DestroyTrueColorPalette(video_mode_t mode) {
639 if (mode == VID_MODE15) {
640 if (Palettes15) free(Palettes15);
641 Palettes15 = NULL;
642 V_Palette15 = NULL;
643 }
644 if (mode == VID_MODE16) {
645 if (Palettes16) free(Palettes16);
646 Palettes16 = NULL;
647 V_Palette16 = NULL;
648 }
649 if (mode == VID_MODE32) {
650 if (Palettes32) free(Palettes32);
651 Palettes32 = NULL;
652 V_Palette32 = NULL;
653 }
654}
655
656void V_DestroyUnusedTrueColorPalettes(void) {
657 if (V_GetMode() != VID_MODE15) V_DestroyTrueColorPalette(VID_MODE15);
658 if (V_GetMode() != VID_MODE16) V_DestroyTrueColorPalette(VID_MODE16);
659 if (V_GetMode() != VID_MODE32) V_DestroyTrueColorPalette(VID_MODE32);
660}
661
662//
663// V_SetPalette
664//
665// CPhipps - New function to set the palette to palette number pal.
666// Handles loading of PLAYPAL and calls I_SetPalette
667
668void V_SetPalette(int pal)
669{
670 currentPaletteIndex = pal;
671
672 if (V_GetMode() == VID_MODEGL) {
673#ifdef GL_DOOM
674 gld_SetPalette(pal);
675#endif
676 } else {
677 I_SetPalette(pal);
678 if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32) {
679 // V_SetPalette can be called as part of the gamma setting before
680 // we've loaded any wads, which prevents us from reading the palette - POPE
681 if (W_CheckNumForName("PLAYPAL") >= 0) {
682 V_UpdateTrueColorPalette(V_GetMode());
683 }
684 }
685 }
686}
687
688//
689// V_FillRect
690//
691// CPhipps - New function to fill a rectangle with a given colour
692static void V_FillRect8(int scrn, int x, int y, int width, int height, byte colour)
693{
694 byte* dest = screens[scrn].data + x + y*screens[scrn].byte_pitch;
695 while (height--) {
696 memset(dest, colour, width);
697 dest += screens[scrn].byte_pitch;
698 }
699}
700
701static void V_FillRect15(int scrn, int x, int y, int width, int height, byte colour)
702{
703 unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch;
704 int w;
705 short c = VID_PAL15(colour, VID_COLORWEIGHTMASK);
706 while (height--) {
707 for (w=0; w<width; w++) {
708 dest[w] = c;
709 }
710 dest += screens[scrn].short_pitch;
711 }
712}
713
714static void V_FillRect16(int scrn, int x, int y, int width, int height, byte colour)
715{
716 unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch;
717 int w;
718 short c = VID_PAL16(colour, VID_COLORWEIGHTMASK);
719 while (height--) {
720 for (w=0; w<width; w++) {
721 dest[w] = c;
722 }
723 dest += screens[scrn].short_pitch;
724 }
725}
726
727static void V_FillRect32(int scrn, int x, int y, int width, int height, byte colour)
728{
729 unsigned int* dest = (unsigned int *)screens[scrn].data + x + y*screens[scrn].int_pitch;
730 int w;
731 int c = VID_PAL32(colour, VID_COLORWEIGHTMASK);
732 while (height--) {
733 for (w=0; w<width; w++) {
734 dest[w] = c;
735 }
736 dest += screens[scrn].int_pitch;
737 }
738}
739
740static void WRAP_V_DrawLine(fline_t* fl, int color);
741static void V_PlotPixel8(int scrn, int x, int y, byte color);
742static void V_PlotPixel15(int scrn, int x, int y, byte color);
743static void V_PlotPixel16(int scrn, int x, int y, byte color);
744static void V_PlotPixel32(int scrn, int x, int y, byte color);
745
746#ifdef GL_DOOM
747static void WRAP_gld_FillRect(int scrn, int x, int y, int width, int height, byte colour)
748{
749 gld_FillBlock(x,y,width,height,colour);
750}
751static void WRAP_gld_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags)
752{
753}
754static void WRAP_gld_DrawBackground(const char *flatname, int n)
755{
756 gld_DrawBackground(flatname);
757}
758static void WRAP_gld_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags)
759{
760 gld_DrawNumPatch(x,y,lump,cm,flags);
761}
762static void WRAP_gld_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags)
763{
764}
765static void V_PlotPixelGL(int scrn, int x, int y, byte color) {
766 gld_DrawLine(x-1, y, x+1, y, color);
767 gld_DrawLine(x, y-1, x, y+1, color);
768}
769static void WRAP_gld_DrawLine(fline_t* fl, int color)
770{
771 gld_DrawLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, color);
772}
773#endif
774
775static void NULL_FillRect(int scrn, int x, int y, int width, int height, byte colour) {}
776static void NULL_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags) {}
777static void NULL_DrawBackground(const char *flatname, int n) {}
778static void NULL_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags) {}
779static void NULL_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags) {}
780static void NULL_PlotPixel(int scrn, int x, int y, byte color) {}
781static void NULL_DrawLine(fline_t* fl, int color) {}
782
783const char *default_videomode;
784static video_mode_t current_videomode = VID_MODE8;
785
786V_CopyRect_f V_CopyRect = NULL_CopyRect;
787V_FillRect_f V_FillRect = NULL_FillRect;
788V_DrawNumPatch_f V_DrawNumPatch = NULL_DrawNumPatch;
789V_DrawBackground_f V_DrawBackground = NULL_DrawBackground;
790V_PlotPixel_f V_PlotPixel = NULL_PlotPixel;
791V_DrawLine_f V_DrawLine = NULL_DrawLine;
792
793//
794// V_InitMode
795//
796void V_InitMode(video_mode_t mode) {
797#ifndef GL_DOOM
798 if (mode == VID_MODEGL)
799 mode = VID_MODE8;
800#endif
801 switch (mode) {
802 case VID_MODE8:
803 lprintf(LO_INFO, "V_InitMode: using 8 bit video mode\n");
804 V_CopyRect = FUNC_V_CopyRect;
805 V_FillRect = V_FillRect8;
806 V_DrawNumPatch = FUNC_V_DrawNumPatch;
807 V_DrawBackground = FUNC_V_DrawBackground;
808 V_PlotPixel = V_PlotPixel8;
809 V_DrawLine = WRAP_V_DrawLine;
810 current_videomode = VID_MODE8;
811 break;
812 case VID_MODE15:
813 lprintf(LO_INFO, "V_InitMode: using 15 bit video mode\n");
814 V_CopyRect = FUNC_V_CopyRect;
815 V_FillRect = V_FillRect15;
816 V_DrawNumPatch = FUNC_V_DrawNumPatch;
817 V_DrawBackground = FUNC_V_DrawBackground;
818 V_PlotPixel = V_PlotPixel15;
819 V_DrawLine = WRAP_V_DrawLine;
820 current_videomode = VID_MODE15;
821 break;
822 case VID_MODE16:
823 lprintf(LO_INFO, "V_InitMode: using 16 bit video mode\n");
824 V_CopyRect = FUNC_V_CopyRect;
825 V_FillRect = V_FillRect16;
826 V_DrawNumPatch = FUNC_V_DrawNumPatch;
827 V_DrawBackground = FUNC_V_DrawBackground;
828 V_PlotPixel = V_PlotPixel16;
829 V_DrawLine = WRAP_V_DrawLine;
830 current_videomode = VID_MODE16;
831 break;
832 case VID_MODE32:
833 lprintf(LO_INFO, "V_InitMode: using 32 bit video mode\n");
834 V_CopyRect = FUNC_V_CopyRect;
835 V_FillRect = V_FillRect32;
836 V_DrawNumPatch = FUNC_V_DrawNumPatch;
837 V_DrawBackground = FUNC_V_DrawBackground;
838 V_PlotPixel = V_PlotPixel32;
839 V_DrawLine = WRAP_V_DrawLine;
840 current_videomode = VID_MODE32;
841 break;
842#ifdef GL_DOOM
843 case VID_MODEGL:
844 lprintf(LO_INFO, "V_InitMode: using OpenGL video mode\n");
845 V_CopyRect = WRAP_gld_CopyRect;
846 V_FillRect = WRAP_gld_FillRect;
847 V_DrawNumPatch = WRAP_gld_DrawNumPatch;
848 V_DrawBackground = WRAP_gld_DrawBackground;
849 V_PlotPixel = V_PlotPixelGL;
850 V_DrawLine = WRAP_gld_DrawLine;
851 current_videomode = VID_MODEGL;
852 break;
853#endif
854 }
855 R_FilterInit();
856}
857
858//
859// V_GetMode
860//
861video_mode_t V_GetMode(void) {
862 return current_videomode;
863}
864
865//
866// V_GetModePixelDepth
867//
868int V_GetModePixelDepth(video_mode_t mode) {
869 switch (mode) {
870 case VID_MODE8: return 1;
871 case VID_MODE15: return 2;
872 case VID_MODE16: return 2;
873 case VID_MODE32: return 4;
874 default: return 0;
875 }
876}
877
878//
879// V_GetNumPixelBits
880//
881int V_GetNumPixelBits(void) {
882 switch (current_videomode) {
883 case VID_MODE8: return 8;
884 case VID_MODE15: return 15;
885 case VID_MODE16: return 16;
886 case VID_MODE32: return 32;
887 default: return 0;
888 }
889}
890
891//
892// V_GetPixelDepth
893//
894int V_GetPixelDepth(void) {
895 return V_GetModePixelDepth(current_videomode);
896}
897
898//
899// V_AllocScreen
900//
901void V_AllocScreen(screeninfo_t *scrn) {
902 if (!scrn->not_on_heap)
903 if ((scrn->byte_pitch * scrn->height) > 0)
904 scrn->data = malloc(scrn->byte_pitch*scrn->height);
905}
906
907//
908// V_AllocScreens
909//
910void V_AllocScreens(void) {
911 int i;
912
913 for (i=0; i<NUM_SCREENS; i++)
914 V_AllocScreen(&screens[i]);
915}
916
917//
918// V_FreeScreen
919//
920void V_FreeScreen(screeninfo_t *scrn) {
921 if (!scrn->not_on_heap) {
922 free(scrn->data);
923 scrn->data = NULL;
924 }
925}
926
927//
928// V_FreeScreens
929//
930void V_FreeScreens(void) {
931 int i;
932
933 for (i=0; i<NUM_SCREENS; i++)
934 V_FreeScreen(&screens[i]);
935}
936
937static void V_PlotPixel8(int scrn, int x, int y, byte color) {
938 screens[scrn].data[x+screens[scrn].byte_pitch*y] = color;
939}
940
941static void V_PlotPixel15(int scrn, int x, int y, byte color) {
942 ((unsigned short *)screens[scrn].data)[x+screens[scrn].short_pitch*y] = VID_PAL15(color, VID_COLORWEIGHTMASK);
943}
944
945static void V_PlotPixel16(int scrn, int x, int y, byte color) {
946 ((unsigned short *)screens[scrn].data)[x+screens[scrn].short_pitch*y] = VID_PAL16(color, VID_COLORWEIGHTMASK);
947}
948
949static void V_PlotPixel32(int scrn, int x, int y, byte color) {
950 ((unsigned int *)screens[scrn].data)[x+screens[scrn].int_pitch*y] = VID_PAL32(color, VID_COLORWEIGHTMASK);
951}
952
953//
954// WRAP_V_DrawLine()
955//
956// Draw a line in the frame buffer.
957// Classic Bresenham w/ whatever optimizations needed for speed
958//
959// Passed the frame coordinates of line, and the color to be drawn
960// Returns nothing
961//
962static void WRAP_V_DrawLine(fline_t* fl, int color)
963{
964 register int x;
965 register int y;
966 register int dx;
967 register int dy;
968 register int sx;
969 register int sy;
970 register int ax;
971 register int ay;
972 register int d;
973
974#ifdef RANGECHECK // killough 2/22/98
975 static int fuck = 0;
976
977 // For debugging only
978 if
979 (
980 fl->a.x < 0 || fl->a.x >= SCREENWIDTH
981 || fl->a.y < 0 || fl->a.y >= SCREENHEIGHT
982 || fl->b.x < 0 || fl->b.x >= SCREENWIDTH
983 || fl->b.y < 0 || fl->b.y >= SCREENHEIGHT
984 )
985 {
986 //jff 8/3/98 use logical output routine
987 lprintf(LO_DEBUG, "fuck %d \r", fuck++);
988 return;
989 }
990#endif
991
992#define PUTDOT(xx,yy,cc) V_PlotPixel(0,xx,yy,(byte)cc)
993
994 dx = fl->b.x - fl->a.x;
995 ax = 2 * (dx<0 ? -dx : dx);
996 sx = dx<0 ? -1 : 1;
997
998 dy = fl->b.y - fl->a.y;
999 ay = 2 * (dy<0 ? -dy : dy);
1000 sy = dy<0 ? -1 : 1;
1001
1002 x = fl->a.x;
1003 y = fl->a.y;
1004
1005 if (ax > ay)
1006 {
1007 d = ay - ax/2;
1008 while (1)
1009 {
1010 PUTDOT(x,y,color);
1011 if (x == fl->b.x) return;
1012 if (d>=0)
1013 {
1014 y += sy;
1015 d -= ax;
1016 }
1017 x += sx;
1018 d += ay;
1019 }
1020 }
1021 else
1022 {
1023 d = ax - ay/2;
1024 while (1)
1025 {
1026 PUTDOT(x, y, color);
1027 if (y == fl->b.y) return;
1028 if (d >= 0)
1029 {
1030 x += sx;
1031 d -= ay;
1032 }
1033 y += sy;
1034 d += ax;
1035 }
1036 }
1037}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Gamma correction LUT.
31 * Color range translation support
32 * Functions to draw patches (by post) directly to screen.
33 * Functions to blit a block to the screen.
34 *
35 *-----------------------------------------------------------------------------*/
36
37#ifndef __V_VIDEO__
38#define __V_VIDEO__
39
40#include "doomtype.h"
41#include "doomdef.h"
42// Needed because we are refering to patches.
43#include "r_data.h"
44
45//
46// VIDEO
47//
48
49#define CENTERY (SCREENHEIGHT/2)
50
51// Screen 0 is the screen updated by I_Update screen.
52// Screen 1 is an extra buffer.
53
54// array of pointers to color translation tables
55extern const byte *colrngs[];
56
57// symbolic indices into color translation table pointer array
58typedef enum
59{
60 CR_BRICK, //0
61 CR_TAN, //1
62 CR_GRAY, //2
63 CR_GREEN, //3
64 CR_BROWN, //4
65 CR_GOLD, //5
66 CR_RED, //6
67 CR_BLUE, //7
68 CR_ORANGE, //8
69 CR_YELLOW, //9
70 CR_BLUE2, //10 // proff
71 CR_LIMIT //11 //jff 2/27/98 added for range check
72} crange_idx_e;
73//jff 1/16/98 end palette color range additions
74
75#define CR_DEFAULT CR_RED /* default value for out of range colors */
76
77typedef struct {
78 byte *data; // pointer to the screen content
79 boolean not_on_heap; // if set, no malloc or free is preformed and
80 // data never set to NULL. Used i.e. with SDL doublebuffer.
81 int width; // the width of the surface
82 int height; // the height of the surface, used when mallocing
83 int byte_pitch; // tha actual width of one line, used when mallocing
84 int short_pitch; // tha actual width of one line, used when mallocing
85 int int_pitch; // tha actual width of one line, used when mallocing
86} screeninfo_t;
87
88#define NUM_SCREENS 6
89extern screeninfo_t screens[NUM_SCREENS];
90extern int usegamma;
91
92// Varying bit-depth support -POPE
93//
94// For bilinear filtering, each palette color is pre-weighted and put in a
95// table for fast blending operations. These macros decide how many weights
96// to create for each color. The lower the number, the lower the blend
97// accuracy, which can produce very bad artifacts in texture filtering.
98#define VID_NUMCOLORWEIGHTS 64
99#define VID_COLORWEIGHTMASK (VID_NUMCOLORWEIGHTS-1)
100#define VID_COLORWEIGHTBITS 6
101
102// Palettes for converting from 8 bit color to 16 and 32 bit. Also
103// contains the weighted versions of each palette color for filtering
104// operations
105extern unsigned short *V_Palette15;
106extern unsigned short *V_Palette16;
107extern unsigned int *V_Palette32;
108
109#define VID_PAL15(color, weight) V_Palette15[ (color)*VID_NUMCOLORWEIGHTS + (weight) ]
110#define VID_PAL16(color, weight) V_Palette16[ (color)*VID_NUMCOLORWEIGHTS + (weight) ]
111#define VID_PAL32(color, weight) V_Palette32[ (color)*VID_NUMCOLORWEIGHTS + (weight) ]
112
113// The available bit-depth modes
114typedef enum {
115 VID_MODE8,
116 VID_MODE15,
117 VID_MODE16,
118 VID_MODE32,
119 VID_MODEGL,
120 VID_MODEMAX
121} video_mode_t;
122
123extern const char *default_videomode;
124
125void V_InitMode(video_mode_t mode);
126
127// video mode query interface
128video_mode_t V_GetMode(void);
129int V_GetModePixelDepth(video_mode_t mode);
130int V_GetNumPixelBits(void);
131int V_GetPixelDepth(void);
132
133//jff 4/24/98 loads color translation lumps
134void V_InitColorTranslation(void);
135
136// Allocates buffer screens, call before R_Init.
137void V_Init (void);
138
139// V_CopyRect
140typedef void (*V_CopyRect_f)(int srcx, int srcy, int srcscrn,
141 int width, int height,
142 int destx, int desty, int destscrn,
143 enum patch_translation_e flags);
144extern V_CopyRect_f V_CopyRect;
145
146// V_FillRect
147typedef void (*V_FillRect_f)(int scrn, int x, int y,
148 int width, int height, byte colour);
149extern V_FillRect_f V_FillRect;
150
151// CPhipps - patch drawing
152// Consolidated into the 3 really useful functions:
153
154// V_DrawNumPatch - Draws the patch from lump num
155typedef void (*V_DrawNumPatch_f)(int x, int y, int scrn,
156 int lump, int cm,
157 enum patch_translation_e flags);
158extern V_DrawNumPatch_f V_DrawNumPatch;
159
160// V_DrawNamePatch - Draws the patch from lump "name"
161#define V_DrawNamePatch(x,y,s,n,t,f) V_DrawNumPatch(x,y,s,W_GetNumForName(n),t,f)
162
163/* cph -
164 * Functions to return width & height of a patch.
165 * Doesn't really belong here, but is often used in conjunction with
166 * this code.
167 */
168#define V_NamePatchWidth(name) R_NumPatchWidth(W_GetNumForName(name))
169#define V_NamePatchHeight(name) R_NumPatchHeight(W_GetNumForName(name))
170
171/* cphipps 10/99: function to tile a flat over the screen */
172typedef void (*V_DrawBackground_f)(const char* flatname, int scrn);
173extern V_DrawBackground_f V_DrawBackground;
174
175void V_DestroyUnusedTrueColorPalettes(void);
176// CPhipps - function to set the palette to palette number pal.
177void V_SetPalette(int pal);
178
179// CPhipps - function to plot a pixel
180
181// V_PlotPixel
182typedef void (*V_PlotPixel_f)(int,int,int,byte);
183extern V_PlotPixel_f V_PlotPixel;
184
185typedef struct
186{
187 int x, y;
188} fpoint_t;
189
190typedef struct
191{
192 fpoint_t a, b;
193} fline_t;
194
195// V_DrawLine
196typedef void (*V_DrawLine_f)(fline_t* fl, int color);
197extern V_DrawLine_f V_DrawLine;
198
199void V_AllocScreen(screeninfo_t *scrn);
200void V_AllocScreens();
201void V_FreeScreen(screeninfo_t *scrn);
202void V_FreeScreens();
203
204#ifdef GL_DOOM
205#include "gl_struct.h"
206#endif
207#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Date stamp
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35
36#include "version.h"
37
38const 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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Doom version indicators.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __DOOMVERSION__
36#define __DOOMVERSION__
37
38extern const char version_date[];
39
40#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 2001 by
8 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
9 * Copyright 2005, 2006 by
10 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
26 *
27 * DESCRIPTION:
28 * Transparent access to data in WADs using mmap
29 *
30 *-----------------------------------------------------------------------------
31 */
32
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
36
37#ifdef HAVE_UNISTD_H
38#include <unistd.h>
39#endif
40#ifdef _WIN32
41#define WIN32_LEAN_AND_MEAN
42#include <windows.h>
43#else
44#include <sys/mman.h>
45#endif
46
47#include "doomstat.h"
48#include "doomtype.h"
49
50#ifdef __GNUG__
51#pragma implementation "w_wad.h"
52#endif
53#include "w_wad.h"
54#include "z_zone.h"
55#include "lprintf.h"
56#include "i_system.h"
57
58static struct {
59 void *cache;
60#ifdef TIMEDIAG
61 int locktic;
62#endif
63 int locks;
64} *cachelump;
65
66#ifdef HEAPDUMP
67void W_PrintLump(FILE* fp, void* p) {
68 int i;
69 for (i=0; i<numlumps; i++)
70 if (cachelump[i].cache == p) {
71 fprintf(fp, " %8.8s %6u %2d %6d", lumpinfo[i].name,
72 W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic);
73 return;
74 }
75 fprintf(fp, " not found");
76}
77#endif
78
79#ifdef TIMEDIAG
80static void W_ReportLocks(void)
81{
82 int i;
83 lprintf(LO_DEBUG, "W_ReportLocks:\nLump Size Locks Tics\n");
84 for (i=0; i<numlumps; i++) {
85 if (cachelump[i].locks > 0)
86 lprintf(LO_DEBUG, "%8.8s %6u %2d %6d\n", lumpinfo[i].name,
87 W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic);
88 }
89}
90#endif
91
92#ifdef _WIN32
93typedef struct {
94 HANDLE hnd;
95 OFSTRUCT fileinfo;
96 HANDLE hnd_map;
97 void *data;
98} mmap_info_t;
99
100mmap_info_t *mapped_wad;
101
102void W_DoneCache(void)
103{
104 size_t i;
105
106 if (cachelump) {
107 free(cachelump);
108 cachelump = NULL;
109 }
110
111 if (!mapped_wad)
112 return;
113 for (i=0; i<numwadfiles; i++)
114 {
115 if (mapped_wad[i].data)
116 {
117 UnmapViewOfFile(mapped_wad[i].data);
118 mapped_wad[i].data=NULL;
119 }
120 if (mapped_wad[i].hnd_map)
121 {
122 CloseHandle(mapped_wad[i].hnd_map);
123 mapped_wad[i].hnd_map=NULL;
124 }
125 if (mapped_wad[i].hnd)
126 {
127 CloseHandle(mapped_wad[i].hnd);
128 mapped_wad[i].hnd=NULL;
129 }
130 }
131 free(mapped_wad);
132}
133
134void W_InitCache(void)
135{
136 // set up caching
137 cachelump = calloc(numlumps, sizeof *cachelump);
138 if (!cachelump)
139 I_Error ("W_Init: Couldn't allocate lumpcache");
140
141#ifdef TIMEDIAG
142 atexit(W_ReportLocks);
143#endif
144
145 mapped_wad = calloc(numwadfiles,sizeof(mmap_info_t));
146 memset(mapped_wad,0,sizeof(mmap_info_t)*numwadfiles);
147 {
148 int i;
149 for (i=0; i<numlumps; i++)
150 {
151 int wad_index = (int)(lumpinfo[i].wadfile-wadfiles);
152
153 cachelump[i].locks = -1;
154
155 if (!lumpinfo[i].wadfile)
156 continue;
157#ifdef RANGECHECK
158 if ((wad_index<0)||((size_t)wad_index>=numwadfiles))
159 I_Error("W_InitCache: wad_index out of range");
160#endif
161 if (!mapped_wad[wad_index].data)
162 {
163 mapped_wad[wad_index].hnd =
164 (HANDLE)OpenFile(
165 wadfiles[wad_index].name,
166 &mapped_wad[wad_index].fileinfo,
167 OF_READ
168 );
169 if (mapped_wad[wad_index].hnd==(HANDLE)HFILE_ERROR)
170 I_Error("W_InitCache: OpenFile for memory mapping failed (LastError %i)",GetLastError());
171 mapped_wad[wad_index].hnd_map =
172 CreateFileMapping(
173 mapped_wad[wad_index].hnd,
174 NULL,
175 PAGE_READONLY,
176 0,
177 0,
178 NULL
179 );
180 if (mapped_wad[wad_index].hnd_map==NULL)
181 I_Error("W_InitCache: CreateFileMapping for memory mapping failed (LastError %i)",GetLastError());
182 mapped_wad[wad_index].data =
183 MapViewOfFile(
184 mapped_wad[wad_index].hnd_map,
185 FILE_MAP_READ,
186 0,
187 0,
188 0
189 );
190 if (mapped_wad[wad_index].hnd_map==NULL)
191 I_Error("W_InitCache: MapViewOfFile for memory mapping failed (LastError %i)",GetLastError());
192 }
193 }
194 }
195}
196
197const void* W_CacheLumpNum(int lump)
198{
199 int wad_index = (int)(lumpinfo[lump].wadfile-wadfiles);
200#ifdef RANGECHECK
201 if ((wad_index<0)||((size_t)wad_index>=numwadfiles))
202 I_Error("W_CacheLumpNum: wad_index out of range");
203 if ((unsigned)lump >= (unsigned)numlumps)
204 I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
205#endif
206 if (!lumpinfo[lump].wadfile)
207 return NULL;
208 return (void*)((unsigned char *)mapped_wad[wad_index].data+lumpinfo[lump].position);
209}
210
211#else
212
213void ** mapped_wad;
214
215void W_InitCache(void)
216{
217 int maxfd = 0;
218 // set up caching
219 cachelump = calloc(numlumps, sizeof *cachelump);
220 if (!cachelump)
221 I_Error ("W_Init: Couldn't allocate lumpcache");
222
223#ifdef TIMEDIAG
224 atexit(W_ReportLocks);
225#endif
226
227 {
228 int i;
229 for (i=0; i<numlumps; i++)
230 if (lumpinfo[i].wadfile)
231 if (lumpinfo[i].wadfile->handle > maxfd) maxfd = lumpinfo[i].wadfile->handle;
232 }
233 mapped_wad = calloc(maxfd+1,sizeof *mapped_wad);
234 {
235 int i;
236 for (i=0; i<numlumps; i++) {
237 cachelump[i].locks = -1;
238 if (lumpinfo[i].wadfile) {
239 int fd = lumpinfo[i].wadfile->handle;
240 if (!mapped_wad[fd])
241 if ((mapped_wad[fd] = mmap(NULL,I_Filelength(fd),PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED)
242 I_Error("W_InitCache: failed to mmap");
243 }
244 }
245 }
246}
247
248void W_DoneCache(void)
249{
250 {
251 int i;
252 for (i=0; i<numlumps; i++)
253 if (lumpinfo[i].wadfile) {
254 int fd = lumpinfo[i].wadfile->handle;
255 if (mapped_wad[fd]) {
256 if (munmap(mapped_wad[fd],I_Filelength(fd)))
257 I_Error("W_DoneCache: failed to munmap");
258 mapped_wad[fd] = NULL;
259 }
260 }
261 }
262 free(mapped_wad);
263}
264
265const void* W_CacheLumpNum(int lump)
266{
267#ifdef RANGECHECK
268 if ((unsigned)lump >= (unsigned)numlumps)
269 I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
270#endif
271 if (!lumpinfo[lump].wadfile)
272 return NULL;
273 return (mapped_wad[lumpinfo[lump].wadfile->handle]+lumpinfo[lump].position);
274}
275#endif
276
277/*
278 * W_LockLumpNum
279 *
280 * This copies the lump into a malloced memory region and returns its address
281 * instead of returning a pointer into the memory mapped area
282 *
283 */
284const void* W_LockLumpNum(int lump)
285{
286 size_t len = W_LumpLength(lump);
287 const void *data = W_CacheLumpNum(lump);
288
289 if (!cachelump[lump].cache) {
290 // read the lump in
291 Z_Malloc(len, PU_CACHE, &cachelump[lump].cache);
292 memcpy(cachelump[lump].cache, data, len);
293 }
294
295 /* cph - if wasn't locked but now is, tell z_zone to hold it */
296 if (cachelump[lump].locks <= 0) {
297 Z_ChangeTag(cachelump[lump].cache,PU_STATIC);
298#ifdef TIMEDIAG
299 cachelump[lump].locktic = gametic;
300#endif
301 // reset lock counter
302 cachelump[lump].locks = 1;
303 } else {
304 // increment lock counter
305 cachelump[lump].locks += 1;
306 }
307
308#ifdef SIMPLECHECKS
309 if (!((cachelump[lump].locks+1) & 0xf))
310 lprintf(LO_DEBUG, "W_CacheLumpNum: High lock on %8s (%d)\n",
311 lumpinfo[lump].name, cachelump[lump].locks);
312#endif
313
314 return cachelump[lump].cache;
315}
316
317void W_UnlockLumpNum(int lump) {
318 if (cachelump[lump].locks == -1)
319 return; // this lump is memory mapped
320
321#ifdef SIMPLECHECKS
322 if (cachelump[lump].locks == 0)
323 lprintf(LO_DEBUG, "W_UnlockLumpNum: Excess unlocks on %8s\n",
324 lumpinfo[lump].name);
325#endif
326 cachelump[lump].locks -= 1;
327 /* cph - Note: must only tell z_zone to make purgeable if currently locked,
328 * else it might already have been purged
329 */
330 if (cachelump[lump].locks == 0)
331 Z_ChangeTag(cachelump[lump].cache, PU_CACHE);
332}
333
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2001 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Handles WAD file header, directory, lump I/O.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35// use config.h if autoconf made one -- josh
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#ifdef _MSC_VER
43#include <stddef.h>
44#include <io.h>
45#endif
46#include <fcntl.h>
47
48#include "doomstat.h"
49#include "d_net.h"
50#include "doomtype.h"
51#include "i_system.h"
52
53#ifdef __GNUG__
54#pragma implementation "w_wad.h"
55#endif
56#include "w_wad.h"
57#include "lprintf.h"
58
59//
60// GLOBALS
61//
62
63// Location of each lump on disk.
64lumpinfo_t *lumpinfo;
65int numlumps; // killough
66
67void ExtractFileBase (const char *path, char *dest)
68{
69 const char *src = path + strlen(path) - 1;
70 int length;
71
72 // back up until a \ or the start
73 while (src != path && src[-1] != ':' // killough 3/22/98: allow c:filename
74 && *(src-1) != '\\'
75 && *(src-1) != '/')
76 {
77 src--;
78 }
79
80 // copy up to eight characters
81 memset(dest,0,8);
82 length = 0;
83
84 while ((*src) && (*src != '.') && (++length<9))
85 {
86 *dest++ = toupper(*src);
87 *src++;
88 }
89 /* cph - length check removed, just truncate at 8 chars.
90 * If there are 8 or more chars, we'll copy 8, and no zero termination
91 */
92}
93
94//
95// 1/18/98 killough: adds a default extension to a path
96// Note: Backslashes are treated specially, for MS-DOS.
97//
98
99char *AddDefaultExtension(char *path, const char *ext)
100{
101 char *p = path;
102 while (*p++);
103 while (p-->path && *p!='/' && *p!='\\')
104 if (*p=='.')
105 return path;
106 if (*ext!='.')
107 strcat(path,".");
108 return strcat(path,ext);
109}
110
111//
112// LUMP BASED ROUTINES.
113//
114
115//
116// W_AddFile
117// All files are optional, but at least one file must be
118// found (PWAD, if all required lumps are present).
119// Files with a .wad extension are wadlink files
120// with multiple lumps.
121// Other files are single lumps with the base filename
122// for the lump name.
123//
124// Reload hack removed by Lee Killough
125// CPhipps - source is an enum
126//
127// proff - changed using pointer to wadfile_info_t
128static void W_AddFile(wadfile_info_t *wadfile)
129// killough 1/31/98: static, const
130{
131 wadinfo_t header;
132 lumpinfo_t* lump_p;
133 unsigned i;
134 int length;
135 int startlump;
136 filelump_t *fileinfo, *fileinfo2free=NULL; //killough
137 filelump_t singleinfo;
138
139 // open the file and add to directory
140
141 wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY);
142
143#ifdef HAVE_NET
144 if (wadfile->handle == -1 && D_NetGetWad(wadfile->name)) // CPhipps
145 wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY);
146#endif
147
148 if (wadfile->handle == -1)
149 {
150 if ( strlen(wadfile->name)<=4 || // add error check -- killough
151 (strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".lmp" ) &&
152 strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".gwa" ) )
153 )
154 I_Error("W_AddFile: couldn't open %s",wadfile->name);
155 return;
156 }
157
158 //jff 8/3/98 use logical output routine
159 lprintf (LO_INFO," adding %s\n",wadfile->name);
160 startlump = numlumps;
161
162 if ( strlen(wadfile->name)<=4 ||
163 (
164 strcasecmp(wadfile->name+strlen(wadfile->name)-4,".wad") &&
165 strcasecmp(wadfile->name+strlen(wadfile->name)-4,".gwa")
166 )
167 )
168 {
169 // single lump file
170 fileinfo = &singleinfo;
171 singleinfo.filepos = 0;
172 singleinfo.size = LONG(I_Filelength(wadfile->handle));
173 ExtractFileBase(wadfile->name, singleinfo.name);
174 numlumps++;
175 }
176 else
177 {
178 // WAD file
179 I_Read(wadfile->handle, &header, sizeof(header));
180 if (strncmp(header.identification,"IWAD",4) &&
181 strncmp(header.identification,"PWAD",4))
182 I_Error("W_AddFile: Wad file %s doesn't have IWAD or PWAD id", wadfile->name);
183 header.numlumps = LONG(header.numlumps);
184 header.infotableofs = LONG(header.infotableofs);
185 length = header.numlumps*sizeof(filelump_t);
186 fileinfo2free = fileinfo = malloc(length); // killough
187 lseek(wadfile->handle, header.infotableofs, SEEK_SET);
188 I_Read(wadfile->handle, fileinfo, length);
189 numlumps += header.numlumps;
190 }
191
192 // Fill in lumpinfo
193 lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t));
194
195 lump_p = &lumpinfo[startlump];
196
197 for (i=startlump ; (int)i<numlumps ; i++,lump_p++, fileinfo++)
198 {
199 lump_p->wadfile = wadfile; // killough 4/25/98
200 lump_p->position = LONG(fileinfo->filepos);
201 lump_p->size = LONG(fileinfo->size);
202 lump_p->li_namespace = ns_global; // killough 4/17/98
203 strncpy (lump_p->name, fileinfo->name, 8);
204 lump_p->source = wadfile->src; // Ty 08/29/98
205 }
206
207 free(fileinfo2free); // killough
208}
209
210// jff 1/23/98 Create routines to reorder the master directory
211// putting all flats into one marked block, and all sprites into another.
212// This will allow loading of sprites and flats from a PWAD with no
213// other changes to code, particularly fast hashes of the lumps.
214//
215// killough 1/24/98 modified routines to be a little faster and smaller
216
217static int IsMarker(const char *marker, const char *name)
218{
219 return !strncasecmp(name, marker, 8) ||
220 (*name == *marker && !strncasecmp(name+1, marker, 7));
221}
222
223// killough 4/17/98: add namespace tags
224
225static void W_CoalesceMarkedResource(const char *start_marker,
226 const char *end_marker, int li_namespace)
227{
228 lumpinfo_t *marked = malloc(sizeof(*marked) * numlumps);
229 size_t i, num_marked = 0, num_unmarked = 0;
230 int is_marked = 0, mark_end = 0;
231 lumpinfo_t *lump = lumpinfo;
232
233 for (i=numlumps; i--; lump++)
234 if (IsMarker(start_marker, lump->name)) // start marker found
235 { // If this is the first start marker, add start marker to marked lumps
236 if (!num_marked)
237 {
238 strncpy(marked->name, start_marker, 8);
239 marked->size = 0; // killough 3/20/98: force size to be 0
240 marked->li_namespace = ns_global; // killough 4/17/98
241 marked->wadfile = NULL;
242 num_marked = 1;
243 }
244 is_marked = 1; // start marking lumps
245 }
246 else
247 if (IsMarker(end_marker, lump->name)) // end marker found
248 {
249 mark_end = 1; // add end marker below
250 is_marked = 0; // stop marking lumps
251 }
252 else
253 if (is_marked) // if we are marking lumps,
254 { // move lump to marked list
255 marked[num_marked] = *lump;
256 marked[num_marked++].li_namespace = li_namespace; // killough 4/17/98
257 }
258 else
259 lumpinfo[num_unmarked++] = *lump; // else move down THIS list
260
261 // Append marked list to end of unmarked list
262 memcpy(lumpinfo + num_unmarked, marked, num_marked * sizeof(*marked));
263
264 free(marked); // free marked list
265
266 numlumps = num_unmarked + num_marked; // new total number of lumps
267
268 if (mark_end) // add end marker
269 {
270 lumpinfo[numlumps].size = 0; // killough 3/20/98: force size to be 0
271 lumpinfo[numlumps].wadfile = NULL;
272 lumpinfo[numlumps].li_namespace = ns_global; // killough 4/17/98
273 strncpy(lumpinfo[numlumps++].name, end_marker, 8);
274 }
275}
276
277// Hash function used for lump names.
278// Must be mod'ed with table size.
279// Can be used for any 8-character names.
280// by Lee Killough
281
282unsigned W_LumpNameHash(const char *s)
283{
284 unsigned hash;
285 (void) ((hash = toupper(s[0]), s[1]) &&
286 (hash = hash*3+toupper(s[1]), s[2]) &&
287 (hash = hash*2+toupper(s[2]), s[3]) &&
288 (hash = hash*2+toupper(s[3]), s[4]) &&
289 (hash = hash*2+toupper(s[4]), s[5]) &&
290 (hash = hash*2+toupper(s[5]), s[6]) &&
291 (hash = hash*2+toupper(s[6]),
292 hash = hash*2+toupper(s[7]))
293 );
294 return hash;
295}
296
297//
298// W_CheckNumForName
299// Returns -1 if name not found.
300//
301// Rewritten by Lee Killough to use hash table for performance. Significantly
302// cuts down on time -- increases Doom performance over 300%. This is the
303// single most important optimization of the original Doom sources, because
304// lump name lookup is used so often, and the original Doom used a sequential
305// search. For large wads with > 1000 lumps this meant an average of over
306// 500 were probed during every search. Now the average is under 2 probes per
307// search. There is no significant benefit to packing the names into longwords
308// with this new hashing algorithm, because the work to do the packing is
309// just as much work as simply doing the string comparisons with the new
310// algorithm, which minimizes the expected number of comparisons to under 2.
311//
312// killough 4/17/98: add namespace parameter to prevent collisions
313// between different resources such as flats, sprites, colormaps
314//
315
316int (W_CheckNumForName)(register const char *name, register int li_namespace)
317{
318 // Hash function maps the name to one of possibly numlump chains.
319 // It has been tuned so that the average chain length never exceeds 2.
320
321 // proff 2001/09/07 - check numlumps==0, this happens when called before WAD loaded
322 register int i = (numlumps==0)?(-1):(lumpinfo[W_LumpNameHash(name) % (unsigned) numlumps].index);
323
324 // We search along the chain until end, looking for case-insensitive
325 // matches which also match a namespace tag. Separate hash tables are
326 // not used for each namespace, because the performance benefit is not
327 // worth the overhead, considering namespace collisions are rare in
328 // Doom wads.
329
330 while (i >= 0 && (strncasecmp(lumpinfo[i].name, name, 8) ||
331 lumpinfo[i].li_namespace != li_namespace))
332 i = lumpinfo[i].next;
333
334 // Return the matching lump, or -1 if none found.
335
336 return i;
337}
338
339//
340// killough 1/31/98: Initialize lump hash table
341//
342
343void W_HashLumps(void)
344{
345 int i;
346
347 for (i=0; i<numlumps; i++)
348 lumpinfo[i].index = -1; // mark slots empty
349
350 // Insert nodes to the beginning of each chain, in first-to-last
351 // lump order, so that the last lump of a given name appears first
352 // in any chain, observing pwad ordering rules. killough
353
354 for (i=0; i<numlumps; i++)
355 { // hash function:
356 int j = W_LumpNameHash(lumpinfo[i].name) % (unsigned) numlumps;
357 lumpinfo[i].next = lumpinfo[j].index; // Prepend to list
358 lumpinfo[j].index = i;
359 }
360}
361
362// End of lump hashing -- killough 1/31/98
363
364
365
366// W_GetNumForName
367// Calls W_CheckNumForName, but bombs out if not found.
368//
369int W_GetNumForName (const char* name) // killough -- const added
370{
371 int i = W_CheckNumForName (name);
372 if (i == -1)
373 I_Error("W_GetNumForName: %.8s not found", name);
374 return i;
375}
376
377
378
379// W_Init
380// Loads each of the files in the wadfiles array.
381// All files are optional, but at least one file
382// must be found.
383// Files with a .wad extension are idlink files
384// with multiple lumps.
385// Other files are single lumps with the base filename
386// for the lump name.
387// Lump names can appear multiple times.
388// The name searcher looks backwards, so a later file
389// does override all earlier ones.
390//
391// CPhipps - modified to use the new wadfiles array
392//
393wadfile_info_t *wadfiles=NULL;
394
395size_t numwadfiles = 0; // CPhipps - size of the wadfiles array (dynamic, no limit)
396
397void W_Init(void)
398{
399 // CPhipps - start with nothing
400
401 numlumps = 0; lumpinfo = NULL;
402
403 { // CPhipps - new wadfiles array used
404 // open all the files, load headers, and count lumps
405 int i;
406 for (i=0; (size_t)i<numwadfiles; i++)
407 W_AddFile(&wadfiles[i]);
408 }
409
410 if (!numlumps)
411 I_Error ("W_Init: No files found");
412
413 //jff 1/23/98
414 // get all the sprites and flats into one marked block each
415 // killough 1/24/98: change interface to use M_START/M_END explicitly
416 // killough 4/17/98: Add namespace tags to each entry
417 // killough 4/4/98: add colormap markers
418 W_CoalesceMarkedResource("S_START", "S_END", ns_sprites);
419 W_CoalesceMarkedResource("F_START", "F_END", ns_flats);
420 W_CoalesceMarkedResource("C_START", "C_END", ns_colormaps);
421 W_CoalesceMarkedResource("B_START", "B_END", ns_prboom);
422
423 // killough 1/31/98: initialize lump hash table
424 W_HashLumps();
425
426 /* cph 2001/07/07 - separated cache setup */
427 lprintf(LO_INFO,"W_InitCache\n");
428 W_InitCache();
429}
430
431void W_ReleaseAllWads(void)
432{
433 W_DoneCache();
434 numwadfiles = 0;
435 free(wadfiles);
436 wadfiles = NULL;
437 numlumps = 0;
438 free(lumpinfo);
439 lumpinfo = NULL;
440}
441
442//
443// W_LumpLength
444// Returns the buffer size needed to load the given lump.
445//
446int W_LumpLength (int lump)
447{
448 if (lump >= numlumps)
449 I_Error ("W_LumpLength: %i >= numlumps",lump);
450 return lumpinfo[lump].size;
451}
452
453//
454// W_ReadLump
455// Loads the lump into the given buffer,
456// which must be >= W_LumpLength().
457//
458
459void W_ReadLump(int lump, void *dest)
460{
461 lumpinfo_t *l = lumpinfo + lump;
462
463#ifdef RANGECHECK
464 if (lump >= numlumps)
465 I_Error ("W_ReadLump: %i >= numlumps",lump);
466#endif
467
468 {
469 if (l->wadfile)
470 {
471 lseek(l->wadfile->handle, l->position, SEEK_SET);
472 I_Read(l->wadfile->handle, dest, l->size);
473 }
474 }
475}
476
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * WAD I/O functions.
31 *
32 *-----------------------------------------------------------------------------*/
33
34
35#ifndef __W_WAD__
36#define __W_WAD__
37
38#ifdef __GNUG__
39#pragma interface
40#endif
41
42//
43// TYPES
44//
45
46typedef struct
47{
48 char identification[4]; // Should be "IWAD" or "PWAD".
49 int numlumps;
50 int infotableofs;
51} wadinfo_t;
52
53typedef struct
54{
55 int filepos;
56 int size;
57 char name[8];
58} filelump_t;
59
60//
61// WADFILE I/O related stuff.
62//
63
64// CPhipps - defined enum in wider scope
65// Ty 08/29/98 - add source field to identify where this lump came from
66typedef enum {
67 // CPhipps - define elements in order of 'how new/unusual'
68 source_iwad=0, // iwad file load
69 source_pre, // predefined lump
70 source_auto_load, // lump auto-loaded by config file
71 source_pwad, // pwad file load
72 source_lmp, // lmp file load
73 source_net // CPhipps
74} wad_source_t;
75
76// CPhipps - changed wad init
77// We _must_ have the wadfiles[] the same as those actually loaded, so there
78// is no point having these separate entities. This belongs here.
79typedef struct {
80 const char* name;
81 wad_source_t src;
82 int handle;
83} wadfile_info_t;
84
85extern wadfile_info_t *wadfiles;
86
87extern size_t numwadfiles; // CPhipps - size of the wadfiles array
88
89void W_Init(void); // CPhipps - uses the above array
90void W_ReleaseAllWads(void); // Proff - Added for iwad switching
91void W_InitCache(void);
92void W_DoneCache(void);
93
94typedef struct
95{
96 // WARNING: order of some fields important (see info.c).
97
98 char name[9];
99 int size;
100
101 // killough 1/31/98: hash table fields, used for ultra-fast hash table lookup
102 int index, next;
103
104 // killough 4/17/98: namespace tags, to prevent conflicts between resources
105 enum {
106 ns_global=0,
107 ns_sprites,
108 ns_flats,
109 ns_colormaps,
110 ns_prboom
111 } li_namespace; // haleyjd 05/21/02: renamed from "namespace"
112
113 wadfile_info_t *wadfile;
114 int position;
115 wad_source_t source;
116} lumpinfo_t;
117
118extern lumpinfo_t *lumpinfo;
119extern int numlumps;
120
121// killough 4/17/98: if W_CheckNumForName() called with only
122// one argument, pass ns_global as the default namespace
123
124#define W_CheckNumForName(name) (W_CheckNumForName)(name, ns_global)
125int (W_CheckNumForName)(const char* name, int); // killough 4/17/98
126int W_GetNumForName (const char* name);
127int W_LumpLength (int lump);
128void W_ReadLump (int lump, void *dest);
129// CPhipps - modified for 'new' lump locking
130const void* W_CacheLumpNum (int lump);
131const void* W_LockLumpNum(int lump);
132void W_UnlockLumpNum(int lump);
133
134// CPhipps - convenience macros
135//#define W_CacheLumpNum(num) (W_CacheLumpNum)((num),1)
136#define W_CacheLumpName(name) W_CacheLumpNum (W_GetNumForName(name))
137
138//#define W_UnlockLumpNum(num) (W_UnlockLumpNum)((num),1)
139#define W_UnlockLumpName(name) W_UnlockLumpNum (W_GetNumForName(name))
140
141char *AddDefaultExtension(char *, const char *); // killough 1/18/98
142void ExtractFileBase(const char *, char *); // killough
143unsigned W_LumpNameHash(const char *s); // killough 1/31/98
144void W_HashLumps(void); // cph 2001/07/07 - made public
145
146#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Intermission screens.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35#include "doomstat.h"
36#include "m_random.h"
37#include "w_wad.h"
38#include "g_game.h"
39#include "r_main.h"
40#include "v_video.h"
41#include "wi_stuff.h"
42#include "s_sound.h"
43#include "sounds.h"
44#include "lprintf.h" // jff 08/03/98 - declaration of lprintf
45#include "r_draw.h"
46
47// Ty 03/17/98: flag that new par times have been loaded in d_deh
48extern boolean deh_pars;
49
50//
51// Data needed to add patches to full screen intermission pics.
52// Patches are statistics messages, and animations.
53// Loads of by-pixel layout and placement, offsets etc.
54//
55
56//
57// Different vetween registered DOOM (1994) and
58// Ultimate DOOM - Final edition (retail, 1995?).
59// This is supposedly ignored for commercial
60// release (aka DOOM II), which had 34 maps
61// in one episode. So there.
62#define NUMEPISODES 4
63#define NUMMAPS 9
64
65
66// Not used
67// in tics
68//U #define PAUSELEN (TICRATE*2)
69//U #define SCORESTEP 100
70//U #define ANIMPERIOD 32
71// pixel distance from "(YOU)" to "PLAYER N"
72//U #define STARDIST 10
73//U #define WK 1
74
75
76// GLOBAL LOCATIONS
77#define WI_TITLEY 2
78#define WI_SPACINGY 33
79
80// SINGLE-PLAYER STUFF
81#define SP_STATSX 50
82#define SP_STATSY 50
83
84#define SP_TIMEX 8
85// proff/nicolas 09/20/98 -- changed for hi-res
86#define SP_TIMEY 160
87//#define SP_TIMEY (SCREENHEIGHT-32)
88
89
90// NET GAME STUFF
91#define NG_STATSY 50
92#define NG_STATSX (32 + V_NamePatchWidth(star)/2 + 32*!dofrags)
93
94#define NG_SPACINGX 64
95
96
97// Used to display the frags matrix at endgame
98// DEATHMATCH STUFF
99#define DM_MATRIXX 42
100#define DM_MATRIXY 68
101
102#define DM_SPACINGX 40
103
104#define DM_TOTALSX 269
105
106#define DM_KILLERSX 10
107#define DM_KILLERSY 100
108#define DM_VICTIMSX 5
109#define DM_VICTIMSY 50
110
111
112// These animation variables, structures, etc. are used for the
113// DOOM/Ultimate DOOM intermission screen animations. This is
114// totally different from any sprite or texture/flat animations
115typedef enum
116{
117 ANIM_ALWAYS, // determined by patch entry
118 ANIM_RANDOM, // occasional
119 ANIM_LEVEL // continuous
120} animenum_t;
121
122typedef struct
123{
124 int x; // x/y coordinate pair structure
125 int y;
126} point_t;
127
128
129//
130// Animation.
131// There is another anim_t used in p_spec.
132//
133typedef struct
134{
135 animenum_t type;
136
137 // period in tics between animations
138 int period;
139
140 // number of animation frames
141 int nanims;
142
143 // location of animation
144 point_t loc;
145
146 // ALWAYS: n/a,
147 // RANDOM: period deviation (<256),
148 // LEVEL: level
149 int data1;
150
151 // ALWAYS: n/a,
152 // RANDOM: random base period,
153 // LEVEL: n/a
154 int data2;
155
156 /* actual graphics for frames of animations
157 * cphipps - const
158 */
159 patchnum_t p[3];
160
161 // following must be initialized to zero before use!
162
163 // next value of bcnt (used in conjunction with period)
164 int nexttic;
165
166 // last drawn animation frame
167 int lastdrawn;
168
169 // next frame number to animate
170 int ctr;
171
172 // used by RANDOM and LEVEL when animating
173 int state;
174} anim_t;
175
176
177static point_t lnodes[NUMEPISODES][NUMMAPS] =
178{
179 // Episode 0 World Map
180 {
181 { 185, 164 }, // location of level 0 (CJ)
182 { 148, 143 }, // location of level 1 (CJ)
183 { 69, 122 }, // location of level 2 (CJ)
184 { 209, 102 }, // location of level 3 (CJ)
185 { 116, 89 }, // location of level 4 (CJ)
186 { 166, 55 }, // location of level 5 (CJ)
187 { 71, 56 }, // location of level 6 (CJ)
188 { 135, 29 }, // location of level 7 (CJ)
189 { 71, 24 } // location of level 8 (CJ)
190 },
191
192 // Episode 1 World Map should go here
193 {
194 { 254, 25 }, // location of level 0 (CJ)
195 { 97, 50 }, // location of level 1 (CJ)
196 { 188, 64 }, // location of level 2 (CJ)
197 { 128, 78 }, // location of level 3 (CJ)
198 { 214, 92 }, // location of level 4 (CJ)
199 { 133, 130 }, // location of level 5 (CJ)
200 { 208, 136 }, // location of level 6 (CJ)
201 { 148, 140 }, // location of level 7 (CJ)
202 { 235, 158 } // location of level 8 (CJ)
203 },
204
205 // Episode 2 World Map should go here
206 {
207 { 156, 168 }, // location of level 0 (CJ)
208 { 48, 154 }, // location of level 1 (CJ)
209 { 174, 95 }, // location of level 2 (CJ)
210 { 265, 75 }, // location of level 3 (CJ)
211 { 130, 48 }, // location of level 4 (CJ)
212 { 279, 23 }, // location of level 5 (CJ)
213 { 198, 48 }, // location of level 6 (CJ)
214 { 140, 25 }, // location of level 7 (CJ)
215 { 281, 136 } // location of level 8 (CJ)
216 }
217};
218
219
220//
221// Animation locations for episode 0 (1).
222// Using patches saves a lot of space,
223// as they replace 320x200 full screen frames.
224//
225static anim_t epsd0animinfo[] =
226{
227 { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 } },
228 { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 } },
229 { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 } },
230 { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 } },
231 { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 } },
232 { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 } },
233 { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 } },
234 { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 } },
235 { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 } },
236 { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 } }
237};
238
239static anim_t epsd1animinfo[] =
240{
241 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1 },
242 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2 },
243 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3 },
244 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4 },
245 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5 },
246 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6 },
247 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7 },
248 { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8 },
249 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8 }
250};
251
252static anim_t epsd2animinfo[] =
253{
254 { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 } },
255 { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 } },
256 { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 } },
257 { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 } },
258 { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 } },
259 { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 } }
260};
261
262static int NUMANIMS[NUMEPISODES] =
263{
264 sizeof(epsd0animinfo)/sizeof(anim_t),
265 sizeof(epsd1animinfo)/sizeof(anim_t),
266 sizeof(epsd2animinfo)/sizeof(anim_t)
267};
268
269static anim_t *anims[NUMEPISODES] =
270{
271 epsd0animinfo,
272 epsd1animinfo,
273 epsd2animinfo
274};
275
276
277//
278// GENERAL DATA
279//
280
281//
282// Locally used stuff.
283//
284#define FB 0
285
286
287// States for single-player
288#define SP_KILLS 0
289#define SP_ITEMS 2
290#define SP_SECRET 4
291#define SP_FRAGS 6
292#define SP_TIME 8
293#define SP_PAR ST_TIME
294
295#define SP_PAUSE 1
296
297// in seconds
298#define SHOWNEXTLOCDELAY 4
299//#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY
300
301
302// used to accelerate or skip a stage
303int acceleratestage; // killough 3/28/98: made global
304
305// wbs->pnum
306static int me;
307
308 // specifies current state
309static stateenum_t state;
310
311// contains information passed into intermission
312static wbstartstruct_t* wbs;
313
314static wbplayerstruct_t* plrs; // wbs->plyr[]
315
316// used for general timing
317static int cnt;
318
319// used for timing of background animation
320static int bcnt;
321
322// signals to refresh everything for one frame
323static int firstrefresh;
324
325static int cnt_time;
326static int cnt_total_time;
327static int cnt_par;
328static int cnt_pause;
329
330//
331// GRAPHICS
332//
333
334// You Are Here graphic
335static const char* yah[2] = { "WIURH0", "WIURH1" };
336
337// splat
338static const char* splat = "WISPLAT";
339
340// %, : graphics
341static const char percent[] = {"WIPCNT"};
342static const char colon[] = {"WICOLON"};
343
344// 0-9 graphic
345static patchnum_t num[10];
346
347// minus sign
348static const char wiminus[] = {"WIMINUS"};
349
350// "Finished!" graphics
351static const char finished[] = {"WIF"};
352
353// "Entering" graphic
354static const char entering[] = {"WIENTER"};
355
356// "secret"
357static const char sp_secret[] = {"WISCRT2"};
358
359// "Kills", "Scrt", "Items", "Frags"
360static const char kills[] = {"WIOSTK"};
361static const char secret[] = {"WIOSTS"};
362static const char items[] = {"WIOSTI"};
363static const char frags[] = {"WIFRGS"};
364
365// Time sucks.
366static const char time1[] = {"WITIME"};
367static const char par[] = {"WIPAR"};
368static const char sucks[] = {"WISUCKS"};
369
370// "killers", "victims"
371static const char killers[] = {"WIKILRS"};
372static const char victims[] = {"WIVCTMS"};
373
374// "Total", your face, your dead face
375static const char total[] = {"WIMSTT"};
376static const char star[] = {"STFST01"};
377static const char bstar[] = {"STFDEAD0"};
378
379// "red P[1..MAXPLAYERS]"
380static const char facebackp[] = {"STPB0"};
381
382//
383// CODE
384//
385
386static void WI_endDeathmatchStats(void);
387static void WI_endNetgameStats(void);
388#define WI_endStats WI_endNetgameStats
389
390/* ====================================================================
391 * WI_levelNameLump
392 * Purpore: Returns the name of the graphic lump containing the name of
393 * the given level.
394 * Args: Episode and level, and buffer (must by 9 chars) to write to
395 * Returns: void
396 */
397void WI_levelNameLump(int epis, int map, char* buf)
398{
399 if (gamemode == commercial) {
400 sprintf(buf, "CWILV%2.2d", map);
401 } else {
402 sprintf(buf, "WILV%d%d", epis, map);
403 }
404}
405
406// ====================================================================
407// WI_slamBackground
408// Purpose: Put the full-screen background up prior to patches
409// Args: none
410// Returns: void
411//
412static void WI_slamBackground(void)
413{
414 char name[9]; // limited to 8 characters
415
416 if (gamemode == commercial || (gamemode == retail && wbs->epsd == 3))
417 strcpy(name, "INTERPIC");
418 else
419 sprintf(name, "WIMAP%d", wbs->epsd);
420
421 // background
422 V_DrawNamePatch(0, 0, FB, name, CR_DEFAULT, VPT_STRETCH);
423}
424
425
426// ====================================================================
427// WI_Responder
428// Purpose: Draw animations on intermission background screen
429// Args: ev -- event pointer, not actually used here.
430// Returns: False -- dummy routine
431//
432// The ticker is used to detect keys
433// because of timing issues in netgames.
434boolean WI_Responder(event_t* ev)
435{
436 return false;
437}
438
439
440// ====================================================================
441// WI_drawLF
442// Purpose: Draw the "Finished" level name before showing stats
443// Args: none
444// Returns: void
445//
446void WI_drawLF(void)
447{
448 int y = WI_TITLEY;
449 char lname[9];
450
451 // draw <LevelName>
452 /* cph - get the graphic lump name and use it */
453 WI_levelNameLump(wbs->epsd, wbs->last, lname);
454 // CPhipps - patch drawing updated
455 V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y,
456 FB, lname, CR_DEFAULT, VPT_STRETCH);
457
458 // draw "Finished!"
459 y += (5*V_NamePatchHeight(lname))/4;
460
461 // CPhipps - patch drawing updated
462 V_DrawNamePatch((320 - V_NamePatchWidth(finished))/2, y,
463 FB, finished, CR_DEFAULT, VPT_STRETCH);
464}
465
466
467// ====================================================================
468// WI_drawEL
469// Purpose: Draw introductory "Entering" and level name
470// Args: none
471// Returns: void
472//
473void WI_drawEL(void)
474{
475 int y = WI_TITLEY;
476 char lname[9];
477
478 /* cph - get the graphic lump name */
479 WI_levelNameLump(wbs->epsd, wbs->next, lname);
480
481 // draw "Entering"
482 // CPhipps - patch drawing updated
483 V_DrawNamePatch((320 - V_NamePatchWidth(entering))/2,
484 y, FB, entering, CR_DEFAULT, VPT_STRETCH);
485
486 // draw level
487 y += (5*V_NamePatchHeight(lname))/4;
488
489 // CPhipps - patch drawing updated
490 V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, FB,
491 lname, CR_DEFAULT, VPT_STRETCH);
492}
493
494
495/* ====================================================================
496 * WI_drawOnLnode
497 * Purpose: Draw patches at a location based on episode/map
498 * Args: n -- index to map# within episode
499 * c[] -- array of names of patches to be drawn
500 * Returns: void
501 */
502void
503WI_drawOnLnode // draw stuff at a location by episode/map#
504( int n,
505 const char* const c[] )
506{
507 int i;
508 boolean fits = false;
509
510 i = 0;
511 do
512 {
513 int left;
514 int top;
515 int right;
516 int bottom;
517 const rpatch_t* patch = R_CachePatchName(c[i]);
518
519 left = lnodes[wbs->epsd][n].x - patch->leftoffset;
520 top = lnodes[wbs->epsd][n].y - patch->topoffset;
521 right = left + patch->width;
522 bottom = top + patch->height;
523 R_UnlockPatchName(c[i]);
524
525 if (left >= 0
526 && right < 320
527 && top >= 0
528 && bottom < 200)
529 {
530 fits = true;
531 }
532 else
533 {
534 i++;
535 }
536 } while (!fits && i!=2);
537
538 if (fits && i<2)
539 {
540 // CPhipps - patch drawing updated
541 V_DrawNamePatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y,
542 FB, c[i], CR_DEFAULT, VPT_STRETCH);
543 }
544 else
545 {
546 // DEBUG
547 //jff 8/3/98 use logical output routine
548 lprintf(LO_DEBUG,"Could not place patch on level %d", n+1);
549 }
550}
551
552
553// ====================================================================
554// WI_initAnimatedBack
555// Purpose: Initialize pointers and styles for background animation
556// Args: none
557// Returns: void
558//
559void WI_initAnimatedBack(void)
560{
561 int i;
562 anim_t* a;
563
564 if (gamemode == commercial) // no animation for DOOM2
565 return;
566
567 if (wbs->epsd > 2)
568 return;
569
570 for (i=0;i<NUMANIMS[wbs->epsd];i++)
571 {
572 a = &anims[wbs->epsd][i];
573
574 // init variables
575 a->ctr = -1;
576
577 // specify the next time to draw it
578 if (a->type == ANIM_ALWAYS)
579 a->nexttic = bcnt + 1 + (M_Random()%a->period);
580 else
581 if (a->type == ANIM_RANDOM)
582 a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1);
583 else
584 if (a->type == ANIM_LEVEL)
585 a->nexttic = bcnt + 1;
586 }
587}
588
589
590// ====================================================================
591// WI_updateAnimatedBack
592// Purpose: Figure out what animation we do on this iteration
593// Args: none
594// Returns: void
595//
596void WI_updateAnimatedBack(void)
597{
598 int i;
599 anim_t* a;
600
601 if (gamemode == commercial)
602 return;
603
604 if (wbs->epsd > 2)
605 return;
606
607 for (i=0;i<NUMANIMS[wbs->epsd];i++)
608 {
609 a = &anims[wbs->epsd][i];
610
611 if (bcnt == a->nexttic)
612 {
613 switch (a->type)
614 {
615 case ANIM_ALWAYS:
616 if (++a->ctr >= a->nanims) a->ctr = 0;
617 a->nexttic = bcnt + a->period;
618 break;
619
620 case ANIM_RANDOM:
621 a->ctr++;
622 if (a->ctr == a->nanims)
623 {
624 a->ctr = -1;
625 a->nexttic = bcnt+a->data2+(M_Random()%a->data1);
626 }
627 else
628 a->nexttic = bcnt + a->period;
629 break;
630
631 case ANIM_LEVEL:
632 // gawd-awful hack for level anims
633 if (!(state == StatCount && i == 7)
634 && wbs->next == a->data1)
635 {
636 a->ctr++;
637 if (a->ctr == a->nanims) a->ctr--;
638 a->nexttic = bcnt + a->period;
639 }
640 break;
641 }
642 }
643 }
644}
645
646
647// ====================================================================
648// WI_drawAnimatedBack
649// Purpose: Actually do the animation (whew!)
650// Args: none
651// Returns: void
652//
653void WI_drawAnimatedBack(void)
654{
655 int i;
656 anim_t* a;
657
658 if (gamemode==commercial) //jff 4/25/98 Someone forgot commercial an enum
659 return;
660
661 if (wbs->epsd > 2)
662 return;
663
664 for (i=0 ; i<NUMANIMS[wbs->epsd] ; i++)
665 {
666 a = &anims[wbs->epsd][i];
667
668 if (a->ctr >= 0)
669 // CPhipps - patch drawing updated
670 V_DrawNumPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr].lumpnum, CR_DEFAULT, VPT_STRETCH);
671 }
672}
673
674
675// ====================================================================
676// WI_drawNum
677// Purpose: Draws a number. If digits > 0, then use that many digits
678// minimum, otherwise only use as many as necessary
679// Args: x, y -- location
680// n -- the number to be drawn
681// digits -- number of digits minimum or zero
682// Returns: new x position after drawing (note we are going to the left)
683// CPhipps - static
684static int WI_drawNum (int x, int y, int n, int digits)
685{
686 int fontwidth = num[0].width;
687 int neg;
688 int temp;
689
690 if (digits < 0)
691 {
692 if (!n)
693 {
694 // make variable-length zeros 1 digit long
695 digits = 1;
696 }
697 else
698 {
699 // figure out # of digits in #
700 digits = 0;
701 temp = n;
702
703 while (temp)
704 {
705 temp /= 10;
706 digits++;
707 }
708 }
709 }
710
711 neg = n < 0;
712 if (neg)
713 n = -n;
714
715 // if non-number, do not draw it
716 if (n == 1994)
717 return 0;
718
719 // draw the new number
720 while (digits--)
721 {
722 x -= fontwidth;
723 // CPhipps - patch drawing updated
724 V_DrawNumPatch(x, y, FB, num[ n % 10 ].lumpnum, CR_DEFAULT, VPT_STRETCH);
725 n /= 10;
726 }
727
728 // draw a minus sign if necessary
729 if (neg)
730 // CPhipps - patch drawing updated
731 V_DrawNamePatch(x-=8, y, FB, wiminus, CR_DEFAULT, VPT_STRETCH);
732
733 return x;
734}
735
736
737// ====================================================================
738// WI_drawPercent
739// Purpose: Draws a percentage, really just a call to WI_drawNum
740// after putting a percent sign out there
741// Args: x, y -- location
742// p -- the percentage value to be drawn, no negatives
743// Returns: void
744// CPhipps - static
745static void WI_drawPercent(int x, int y, int p)
746{
747 if (p < 0)
748 return;
749
750 // CPhipps - patch drawing updated
751 V_DrawNamePatch(x, y, FB, percent, CR_DEFAULT, VPT_STRETCH);
752 WI_drawNum(x, y, p, -1);
753}
754
755
756// ====================================================================
757// WI_drawTime
758// Purpose: Draws the level completion time or par time, or "Sucks"
759// if 1 hour or more
760// Args: x, y -- location
761// t -- the time value to be drawn
762// Returns: void
763//
764// CPhipps - static
765// - largely rewritten to display hours and use slightly better algorithm
766
767static void WI_drawTime(int x, int y, int t)
768{
769 int n;
770
771 if (t<0)
772 return;
773
774 if (t < 100*60*60)
775 for(;;) {
776 n = t % 60;
777 t /= 60;
778 x = WI_drawNum(x, y, n, (t || n>9) ? 2 : 1) - V_NamePatchWidth(colon);
779
780 // draw
781 if (t)
782 // CPhipps - patch drawing updated
783 V_DrawNamePatch(x, y, FB, colon, CR_DEFAULT, VPT_STRETCH);
784 else break;
785 }
786 else // "sucks" (maybe should be "addicted", even I've never had a 100 hour game ;)
787 V_DrawNamePatch(x - V_NamePatchWidth(sucks),
788 y, FB, sucks, CR_DEFAULT, VPT_STRETCH);
789}
790
791
792// ====================================================================
793// WI_End
794// Purpose: Unloads data structures (inverse of WI_Start)
795// Args: none
796// Returns: void
797//
798void WI_End(void)
799{
800 if (deathmatch)
801 WI_endDeathmatchStats();
802 else if (netgame)
803 WI_endNetgameStats();
804 else
805 WI_endStats();
806}
807
808
809// ====================================================================
810// WI_initNoState
811// Purpose: Clear state, ready for end of level activity
812// Args: none
813// Returns: void
814//
815void WI_initNoState(void)
816{
817 state = NoState;
818 acceleratestage = 0;
819 cnt = 10;
820}
821
822
823// ====================================================================
824// WI_drawTimeStats
825// Purpose: Put the times on the screen
826// Args: time, total time, par time, in seconds
827// Returns: void
828//
829// cph - pulled from WI_drawStats below
830
831static void WI_drawTimeStats(int cnt_time, int cnt_total_time, int cnt_par)
832{
833 V_DrawNamePatch(SP_TIMEX, SP_TIMEY, FB, time1, CR_DEFAULT, VPT_STRETCH);
834 WI_drawTime(320/2 - SP_TIMEX, SP_TIMEY, cnt_time);
835
836 V_DrawNamePatch(SP_TIMEX, (SP_TIMEY+200)/2, FB, total, CR_DEFAULT, VPT_STRETCH);
837 WI_drawTime(320/2 - SP_TIMEX, (SP_TIMEY+200)/2, cnt_total_time);
838
839 // Ty 04/11/98: redid logic: should skip only if with pwad but
840 // without deh patch
841 // killough 2/22/98: skip drawing par times on pwads
842 // Ty 03/17/98: unless pars changed with deh patch
843
844 if (!(modifiedgame && !deh_pars))
845 {
846 if (wbs->epsd < 3)
847 {
848 V_DrawNamePatch(320/2 + SP_TIMEX, SP_TIMEY, FB, par, CR_DEFAULT, VPT_STRETCH);
849 WI_drawTime(320 - SP_TIMEX, SP_TIMEY, cnt_par);
850 }
851 }
852}
853
854// ====================================================================
855// WI_updateNoState
856// Purpose: Cycle until end of level activity is done
857// Args: none
858// Returns: void
859//
860void WI_updateNoState(void)
861{
862
863 WI_updateAnimatedBack();
864
865 if (!--cnt)
866 G_WorldDone();
867}
868
869static boolean snl_pointeron = false;
870
871
872// ====================================================================
873// WI_initShowNextLoc
874// Purpose: Prepare to show the next level's location
875// Args: none
876// Returns: void
877//
878void WI_initShowNextLoc(void)
879{
880 if ((gamemode != commercial) && (gamemap == 8)) {
881 G_WorldDone();
882 return;
883 }
884
885 state = ShowNextLoc;
886 acceleratestage = 0;
887
888 // e6y: That was pretty easy - only a HEX editor and luck
889 // There is no more desync on ddt-tas.zip\e4tux231.lmp
890 // --------- tasdoom.idb ---------
891 // .text:00031194 loc_31194: ; CODE XREF: WI_updateStats+3A9j
892 // .text:00031194 mov ds:state, 1
893 // .text:0003119E mov ds:acceleratestage, 0
894 // .text:000311A8 mov ds:cnt, 3Ch
895 // nowhere no hide
896 if (compatibility_level == tasdoom_compatibility)
897 cnt = 60;
898 else
899 cnt = SHOWNEXTLOCDELAY * TICRATE;
900
901 WI_initAnimatedBack();
902}
903
904
905// ====================================================================
906// WI_updateShowNextLoc
907// Purpose: Prepare to show the next level's location
908// Args: none
909// Returns: void
910//
911void WI_updateShowNextLoc(void)
912{
913 WI_updateAnimatedBack();
914
915 if (!--cnt || acceleratestage)
916 WI_initNoState();
917 else
918 snl_pointeron = (cnt & 31) < 20;
919}
920
921
922// ====================================================================
923// WI_drawShowNextLoc
924// Purpose: Show the next level's location on animated backgrounds
925// Args: none
926// Returns: void
927//
928void WI_drawShowNextLoc(void)
929{
930 int i;
931 int last;
932
933 WI_slamBackground();
934
935 // draw animated background
936 WI_drawAnimatedBack();
937
938 if ( gamemode != commercial)
939 {
940 if (wbs->epsd > 2)
941 {
942 WI_drawEL(); // "Entering..." if not E1 or E2
943 return;
944 }
945
946 last = (wbs->last == 8) ? wbs->next - 1 : wbs->last;
947
948 // draw a splat on taken cities.
949 for (i=0 ; i<=last ; i++)
950 WI_drawOnLnode(i, &splat);
951
952 // splat the secret level?
953 if (wbs->didsecret)
954 WI_drawOnLnode(8, &splat);
955
956 // draw flashing ptr
957 if (snl_pointeron)
958 WI_drawOnLnode(wbs->next, yah);
959 }
960
961 // draws which level you are entering..
962 if ( (gamemode != commercial)
963 || wbs->next != 30) // check for MAP30 end game
964 WI_drawEL();
965}
966
967// ====================================================================
968// WI_drawNoState
969// Purpose: Draw the pointer and next location
970// Args: none
971// Returns: void
972//
973void WI_drawNoState(void)
974{
975 snl_pointeron = true;
976 WI_drawShowNextLoc();
977}
978
979// ====================================================================
980// WI_fragSum
981// Purpose: Calculate frags for this player based on the current totals
982// of all the other players. Subtract self-frags.
983// Args: playernum -- the player to be calculated
984// Returns: the total frags for this player
985//
986int WI_fragSum(int playernum)
987{
988 int i;
989 int frags = 0;
990
991 for (i=0 ; i<MAXPLAYERS ; i++)
992 {
993 if (playeringame[i] // is this player playing?
994 && i!=playernum) // and it's not the player we're calculating
995 {
996 frags += plrs[playernum].frags[i];
997 }
998 }
999
1000
1001 // JDC hack - negative frags.
1002 frags -= plrs[playernum].frags[playernum];
1003
1004 return frags;
1005}
1006
1007static int dm_state;
1008// CPhipps - short, dynamically allocated
1009static short int **dm_frags; // frags matrix
1010static short int *dm_totals; // totals by player
1011
1012// ====================================================================
1013// WI_initDeathmatchStats
1014// Purpose: Set up to display DM stats at end of level. Calculate
1015// frags for all players.
1016// Args: none
1017// Returns: void
1018//
1019void WI_initDeathmatchStats(void)
1020{
1021 int i; // looping variables
1022
1023 // CPhipps - allocate data structures needed
1024 dm_frags = calloc(MAXPLAYERS, sizeof(*dm_frags));
1025 dm_totals = calloc(MAXPLAYERS, sizeof(*dm_totals));
1026
1027 state = StatCount; // We're doing stats
1028 acceleratestage = 0;
1029 dm_state = 1; // count how many times we've done a complete stat
1030
1031 cnt_pause = TICRATE;
1032
1033 for (i=0 ; i<MAXPLAYERS ; i++)
1034 {
1035 if (playeringame[i])
1036 {
1037 // CPhipps - allocate frags line
1038 dm_frags[i] = calloc(MAXPLAYERS, sizeof(**dm_frags)); // set all counts to zero
1039
1040 dm_totals[i] = 0;
1041 }
1042 }
1043 WI_initAnimatedBack();
1044}
1045
1046// ====================================================================
1047// CPhipps - WI_endDeathmatchStats
1048// Purpose: Deallocate dynamically allocated DM stats data
1049// Args: none
1050// Returns: void
1051//
1052
1053void WI_endDeathmatchStats(void)
1054{
1055 int i;
1056 for (i=0; i<MAXPLAYERS; i++)
1057 free(dm_frags[i]);
1058
1059 free(dm_frags); free(dm_totals);
1060}
1061
1062// ====================================================================
1063// WI_updateDeathmatchStats
1064// Purpose: Advance Deathmatch stats screen animation. Calculate
1065// frags for all players. Lots of noise and drama around
1066// the presentation.
1067// Args: none
1068// Returns: void
1069//
1070void WI_updateDeathmatchStats(void)
1071{
1072 int i;
1073 int j;
1074
1075 boolean stillticking;
1076
1077 WI_updateAnimatedBack();
1078
1079 if (acceleratestage && dm_state != 4) // still ticking
1080 {
1081 acceleratestage = 0;
1082
1083 for (i=0 ; i<MAXPLAYERS ; i++)
1084 {
1085 if (playeringame[i])
1086 {
1087 for (j=0 ; j<MAXPLAYERS ; j++)
1088 if (playeringame[j])
1089 dm_frags[i][j] = plrs[i].frags[j];
1090
1091 dm_totals[i] = WI_fragSum(i);
1092 }
1093 }
1094
1095
1096 S_StartSound(0, sfx_barexp); // bang
1097 dm_state = 4; // we're done with all 4 (or all we have to do)
1098 }
1099
1100
1101 if (dm_state == 2)
1102 {
1103 if (!(bcnt&3))
1104 S_StartSound(0, sfx_pistol); // noise while counting
1105
1106 stillticking = false;
1107
1108 for (i=0 ; i<MAXPLAYERS ; i++)
1109 {
1110 if (playeringame[i])
1111 {
1112 for (j=0 ; j<MAXPLAYERS ; j++)
1113 {
1114 if (playeringame[j]
1115 && dm_frags[i][j] != plrs[i].frags[j])
1116 {
1117 if (plrs[i].frags[j] < 0)
1118 dm_frags[i][j]--;
1119 else
1120 dm_frags[i][j]++;
1121
1122 if (dm_frags[i][j] > 999) // Ty 03/17/98 3-digit frag count
1123 dm_frags[i][j] = 999;
1124
1125 if (dm_frags[i][j] < -999)
1126 dm_frags[i][j] = -999;
1127
1128 stillticking = true;
1129 }
1130 }
1131 dm_totals[i] = WI_fragSum(i);
1132
1133 if (dm_totals[i] > 999)
1134 dm_totals[i] = 999;
1135
1136 if (dm_totals[i] < -999)
1137 dm_totals[i] = -999; // Ty 03/17/98 end 3-digit frag count
1138 }
1139 }
1140
1141 if (!stillticking)
1142 {
1143 S_StartSound(0, sfx_barexp);
1144 dm_state++;
1145 }
1146 }
1147 else if (dm_state == 4)
1148 {
1149 if (acceleratestage)
1150 {
1151 S_StartSound(0, sfx_slop);
1152
1153 if ( gamemode == commercial)
1154 WI_initNoState();
1155 else
1156 WI_initShowNextLoc();
1157 }
1158 }
1159 else if (dm_state & 1)
1160 {
1161 if (!--cnt_pause)
1162 {
1163 dm_state++;
1164 cnt_pause = TICRATE;
1165 }
1166 }
1167}
1168
1169
1170// ====================================================================
1171// WI_drawDeathmatchStats
1172// Purpose: Draw the stats on the screen in a matrix
1173// Args: none
1174// Returns: void
1175//
1176// proff/nicolas 09/20/98 -- changed for hi-res
1177// CPhipps - patch drawing updated
1178void WI_drawDeathmatchStats(void)
1179{
1180 int i;
1181 int j;
1182 int x;
1183 int y;
1184 int w;
1185
1186 int lh; // line height
1187 int halfface = V_NamePatchWidth(facebackp)/2;
1188
1189 lh = WI_SPACINGY;
1190
1191 WI_slamBackground();
1192
1193 // draw animated background
1194 WI_drawAnimatedBack();
1195 WI_drawLF();
1196
1197 // draw stat titles (top line)
1198 V_DrawNamePatch(DM_TOTALSX-V_NamePatchWidth(total)/2,
1199 DM_MATRIXY-WI_SPACINGY+10, FB, total, CR_DEFAULT, VPT_STRETCH);
1200
1201 V_DrawNamePatch(DM_KILLERSX, DM_KILLERSY, FB, killers, CR_DEFAULT, VPT_STRETCH);
1202 V_DrawNamePatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims, CR_DEFAULT, VPT_STRETCH);
1203
1204 // draw P?
1205 x = DM_MATRIXX + DM_SPACINGX;
1206 y = DM_MATRIXY;
1207
1208 for (i=0 ; i<MAXPLAYERS ; i++)
1209 {
1210 if (playeringame[i]) {
1211 //int trans = playernumtotrans[i];
1212 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
1213 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
1214 VPT_STRETCH | (i ? VPT_TRANS : 0));
1215 V_DrawNamePatch(DM_MATRIXX-halfface, y,
1216 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
1217 VPT_STRETCH | (i ? VPT_TRANS : 0));
1218
1219 if (i == me)
1220 {
1221 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
1222 FB, bstar, CR_DEFAULT, VPT_STRETCH);
1223 V_DrawNamePatch(DM_MATRIXX-halfface, y,
1224 FB, star, CR_DEFAULT, VPT_STRETCH);
1225 }
1226 }
1227 x += DM_SPACINGX;
1228 y += WI_SPACINGY;
1229 }
1230
1231 // draw stats
1232 y = DM_MATRIXY+10;
1233 w = num[0].width;
1234
1235 for (i=0 ; i<MAXPLAYERS ; i++)
1236 {
1237 x = DM_MATRIXX + DM_SPACINGX;
1238
1239 if (playeringame[i])
1240 {
1241 for (j=0 ; j<MAXPLAYERS ; j++)
1242 {
1243 if (playeringame[j])
1244 WI_drawNum(x+w, y, dm_frags[i][j], 2);
1245
1246 x += DM_SPACINGX;
1247 }
1248 WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
1249 }
1250 y += WI_SPACINGY;
1251 }
1252}
1253
1254
1255//
1256// Note: The term "Netgame" means a coop game
1257//
1258static short *cnt_kills;
1259static short *cnt_items;
1260static short *cnt_secret;
1261static short *cnt_frags;
1262static int dofrags;
1263static int ng_state;
1264
1265// ====================================================================
1266// CPhipps - WI_endNetgameStats
1267// Purpose: Clean up coop game stats
1268// Args: none
1269// Returns: void
1270//
1271static void WI_endNetgameStats(void)
1272{
1273 free(cnt_frags); cnt_frags = NULL;
1274 free(cnt_secret); cnt_secret = NULL;
1275 free(cnt_items); cnt_items = NULL;
1276 free(cnt_kills); cnt_kills = NULL;
1277}
1278
1279// ====================================================================
1280// WI_initNetgameStats
1281// Purpose: Prepare for coop game stats
1282// Args: none
1283// Returns: void
1284//
1285void WI_initNetgameStats(void)
1286{
1287 int i;
1288
1289 state = StatCount;
1290 acceleratestage = 0;
1291 ng_state = 1;
1292
1293 cnt_pause = TICRATE;
1294
1295 // CPhipps - allocate these dynamically, blank with calloc
1296 cnt_kills = calloc(MAXPLAYERS, sizeof(*cnt_kills));
1297 cnt_items = calloc(MAXPLAYERS, sizeof(*cnt_items));
1298 cnt_secret= calloc(MAXPLAYERS, sizeof(*cnt_secret));
1299 cnt_frags = calloc(MAXPLAYERS, sizeof(*cnt_frags));
1300
1301 for (i=0 ; i<MAXPLAYERS ; i++)
1302 if (playeringame[i])
1303 dofrags += WI_fragSum(i);
1304
1305 dofrags = !!dofrags; // set to true or false - did we have frags?
1306
1307 WI_initAnimatedBack();
1308}
1309
1310
1311// ====================================================================
1312// WI_updateNetgameStats
1313// Purpose: Calculate coop stats as we display them with noise and fury
1314// Args: none
1315// Returns: void
1316// Comment: This stuff sure is complicated for what it does
1317//
1318void WI_updateNetgameStats(void)
1319{
1320 int i;
1321 int fsum;
1322
1323 boolean stillticking;
1324
1325 WI_updateAnimatedBack();
1326
1327 if (acceleratestage && ng_state != 10)
1328 {
1329 acceleratestage = 0;
1330
1331 for (i=0 ; i<MAXPLAYERS ; i++)
1332 {
1333 if (!playeringame[i])
1334 continue;
1335
1336 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1337 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1338
1339 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1340 cnt_secret[i] = wbs->maxsecret ?
1341 (plrs[i].ssecret * 100) / wbs->maxsecret : 100;
1342 if (dofrags)
1343 cnt_frags[i] = WI_fragSum(i); // we had frags
1344 }
1345 S_StartSound(0, sfx_barexp); // bang
1346 ng_state = 10;
1347 }
1348
1349 if (ng_state == 2)
1350 {
1351 if (!(bcnt&3))
1352 S_StartSound(0, sfx_pistol); // pop
1353
1354 stillticking = false;
1355
1356 for (i=0 ; i<MAXPLAYERS ; i++)
1357 {
1358 if (!playeringame[i])
1359 continue;
1360
1361 cnt_kills[i] += 2;
1362
1363 if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills)
1364 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1365 else
1366 stillticking = true; // still got stuff to tally
1367 }
1368
1369 if (!stillticking)
1370 {
1371 S_StartSound(0, sfx_barexp);
1372 ng_state++;
1373 }
1374 }
1375 else if (ng_state == 4)
1376 {
1377 if (!(bcnt&3))
1378 S_StartSound(0, sfx_pistol);
1379
1380 stillticking = false;
1381
1382 for (i=0 ; i<MAXPLAYERS ; i++)
1383 {
1384 if (!playeringame[i])
1385 continue;
1386
1387 cnt_items[i] += 2;
1388 if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems)
1389 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1390 else
1391 stillticking = true;
1392 }
1393
1394 if (!stillticking)
1395 {
1396 S_StartSound(0, sfx_barexp);
1397 ng_state++;
1398 }
1399 }
1400 else if (ng_state == 6)
1401 {
1402 if (!(bcnt&3))
1403 S_StartSound(0, sfx_pistol);
1404
1405 stillticking = false;
1406
1407 for (i=0 ; i<MAXPLAYERS ; i++)
1408 {
1409 if (!playeringame[i])
1410 continue;
1411
1412 cnt_secret[i] += 2;
1413
1414 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1415
1416 if (cnt_secret[i] >= (wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : compatibility_level < lxdoom_1_compatibility ? 0 : 100))
1417 cnt_secret[i] = wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : 100;
1418 else
1419 stillticking = true;
1420 }
1421
1422 if (!stillticking)
1423 {
1424 S_StartSound(0, sfx_barexp);
1425 ng_state += 1 + 2*!dofrags;
1426 }
1427 }
1428 else if (ng_state == 8)
1429 {
1430 if (!(bcnt&3))
1431 S_StartSound(0, sfx_pistol);
1432
1433 stillticking = false;
1434
1435 for (i=0 ; i<MAXPLAYERS ; i++)
1436 {
1437 if (!playeringame[i])
1438 continue;
1439
1440 cnt_frags[i] += 1;
1441
1442 if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
1443 cnt_frags[i] = fsum;
1444 else
1445 stillticking = true;
1446 }
1447
1448 if (!stillticking)
1449 {
1450 S_StartSound(0, sfx_pldeth);
1451 ng_state++;
1452 }
1453 }
1454 else if (ng_state == 10)
1455 {
1456 if (acceleratestage)
1457 {
1458 S_StartSound(0, sfx_sgcock);
1459 if ( gamemode == commercial )
1460 WI_initNoState();
1461 else
1462 WI_initShowNextLoc();
1463 }
1464 }
1465 else if (ng_state & 1)
1466 {
1467 if (!--cnt_pause)
1468 {
1469 ng_state++;
1470 cnt_pause = TICRATE;
1471 }
1472 }
1473}
1474
1475
1476// ====================================================================
1477// WI_drawNetgameStats
1478// Purpose: Put the coop stats on the screen
1479// Args: none
1480// Returns: void
1481//
1482// proff/nicolas 09/20/98 -- changed for hi-res
1483// CPhipps - patch drawing updated
1484void WI_drawNetgameStats(void)
1485{
1486 int i;
1487 int x;
1488 int y;
1489 int pwidth = V_NamePatchWidth(percent);
1490 int fwidth = V_NamePatchWidth(facebackp);
1491
1492 WI_slamBackground();
1493
1494 // draw animated background
1495 WI_drawAnimatedBack();
1496
1497 WI_drawLF();
1498
1499 // draw stat titles (top line)
1500 V_DrawNamePatch(NG_STATSX+NG_SPACINGX-V_NamePatchWidth(kills),
1501 NG_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH);
1502
1503 V_DrawNamePatch(NG_STATSX+2*NG_SPACINGX-V_NamePatchWidth(items),
1504 NG_STATSY, FB, items, CR_DEFAULT, VPT_STRETCH);
1505
1506 V_DrawNamePatch(NG_STATSX+3*NG_SPACINGX-V_NamePatchWidth(secret),
1507 NG_STATSY, FB, secret, CR_DEFAULT, VPT_STRETCH);
1508
1509 if (dofrags)
1510 V_DrawNamePatch(NG_STATSX+4*NG_SPACINGX-V_NamePatchWidth(frags),
1511 NG_STATSY, FB, frags, CR_DEFAULT, VPT_STRETCH);
1512
1513 // draw stats
1514 y = NG_STATSY + V_NamePatchHeight(kills);
1515
1516 for (i=0 ; i<MAXPLAYERS ; i++)
1517 {
1518 //int trans = playernumtotrans[i];
1519 if (!playeringame[i])
1520 continue;
1521
1522 x = NG_STATSX;
1523 V_DrawNamePatch(x-fwidth, y, FB, facebackp,
1524 i ? CR_LIMIT+i : CR_DEFAULT,
1525 VPT_STRETCH | (i ? VPT_TRANS : 0));
1526
1527 if (i == me)
1528 V_DrawNamePatch(x-fwidth, y, FB, star, CR_DEFAULT, VPT_STRETCH);
1529
1530 x += NG_SPACINGX;
1531 if (cnt_kills)
1532 WI_drawPercent(x-pwidth, y+10, cnt_kills[i]);
1533 x += NG_SPACINGX;
1534 if (cnt_items)
1535 WI_drawPercent(x-pwidth, y+10, cnt_items[i]);
1536 x += NG_SPACINGX;
1537 if (cnt_secret)
1538 WI_drawPercent(x-pwidth, y+10, cnt_secret[i]);
1539 x += NG_SPACINGX;
1540
1541 if (dofrags && cnt_frags)
1542 WI_drawNum(x, y+10, cnt_frags[i], -1);
1543
1544 y += WI_SPACINGY;
1545 }
1546
1547 if (y <= SP_TIMEY)
1548 // cph - show times in coop on the entering screen
1549 WI_drawTimeStats(plrs[me].stime / TICRATE, wbs->totaltimes / TICRATE, wbs->partime / TICRATE);
1550}
1551
1552static int sp_state;
1553
1554// ====================================================================
1555// WI_initStats
1556// Purpose: Get ready for single player stats
1557// Args: none
1558// Returns: void
1559// Comment: Seems like we could do all these stats in a more generic
1560// set of routines that weren't duplicated for dm, coop, sp
1561//
1562void WI_initStats(void)
1563{
1564 state = StatCount;
1565 acceleratestage = 0;
1566 sp_state = 1;
1567
1568 // CPhipps - allocate (awful code, I know, but saves changing it all) and initialise
1569 *(cnt_kills = malloc(sizeof(*cnt_kills))) =
1570 *(cnt_items = malloc(sizeof(*cnt_items))) =
1571 *(cnt_secret= malloc(sizeof(*cnt_secret))) = -1;
1572 cnt_time = cnt_par = cnt_total_time = -1;
1573 cnt_pause = TICRATE;
1574
1575 WI_initAnimatedBack();
1576}
1577
1578// ====================================================================
1579// WI_updateStats
1580// Purpose: Calculate solo stats
1581// Args: none
1582// Returns: void
1583//
1584void WI_updateStats(void)
1585{
1586 WI_updateAnimatedBack();
1587
1588 if (acceleratestage && sp_state != 10)
1589 {
1590 acceleratestage = 0;
1591 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1592 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1593
1594 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1595 cnt_secret[0] = (wbs->maxsecret ?
1596 (plrs[me].ssecret * 100) / wbs->maxsecret : 100);
1597
1598 cnt_total_time = wbs->totaltimes / TICRATE;
1599 cnt_time = plrs[me].stime / TICRATE;
1600 cnt_par = wbs->partime / TICRATE;
1601 S_StartSound(0, sfx_barexp);
1602 sp_state = 10;
1603 }
1604
1605 if (sp_state == 2)
1606 {
1607 cnt_kills[0] += 2;
1608
1609 if (!(bcnt&3))
1610 S_StartSound(0, sfx_pistol);
1611
1612 if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills)
1613 {
1614 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1615 S_StartSound(0, sfx_barexp);
1616 sp_state++;
1617 }
1618 }
1619 else if (sp_state == 4)
1620 {
1621 cnt_items[0] += 2;
1622
1623 if (!(bcnt&3))
1624 S_StartSound(0, sfx_pistol);
1625
1626 if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems)
1627 {
1628 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1629 S_StartSound(0, sfx_barexp);
1630 sp_state++;
1631 }
1632 }
1633 else if (sp_state == 6)
1634 {
1635 cnt_secret[0] += 2;
1636
1637 if (!(bcnt&3))
1638 S_StartSound(0, sfx_pistol);
1639
1640 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1641 if ((!wbs->maxsecret && compatibility_level < lxdoom_1_compatibility) ||
1642 cnt_secret[0] >= (wbs->maxsecret ?
1643 (plrs[me].ssecret * 100) / wbs->maxsecret : 100))
1644 {
1645 cnt_secret[0] = (wbs->maxsecret ?
1646 (plrs[me].ssecret * 100) / wbs->maxsecret : 100);
1647 S_StartSound(0, sfx_barexp);
1648 sp_state++;
1649 }
1650 }
1651 else if (sp_state == 8)
1652 {
1653 if (!(bcnt&3))
1654 S_StartSound(0, sfx_pistol);
1655
1656 cnt_time += 3;
1657
1658 if (cnt_time >= plrs[me].stime / TICRATE)
1659 cnt_time = plrs[me].stime / TICRATE;
1660
1661 cnt_total_time += 3;
1662
1663 if (cnt_total_time >= wbs->totaltimes / TICRATE)
1664 cnt_total_time = wbs->totaltimes / TICRATE;
1665
1666 cnt_par += 3;
1667
1668 if (cnt_par >= wbs->partime / TICRATE)
1669 {
1670 cnt_par = wbs->partime / TICRATE;
1671
1672 if ((cnt_time >= plrs[me].stime / TICRATE) && (compatibility_level < lxdoom_1_compatibility || cnt_total_time >= wbs->totaltimes / TICRATE))
1673 {
1674 S_StartSound(0, sfx_barexp);
1675 sp_state++;
1676 }
1677 }
1678 }
1679 else if (sp_state == 10)
1680 {
1681 if (acceleratestage)
1682 {
1683 S_StartSound(0, sfx_sgcock);
1684
1685 if (gamemode == commercial)
1686 WI_initNoState();
1687 else
1688 WI_initShowNextLoc();
1689 }
1690 }
1691 else if (sp_state & 1)
1692 {
1693 if (!--cnt_pause)
1694 {
1695 sp_state++;
1696 cnt_pause = TICRATE;
1697 }
1698 }
1699}
1700
1701// ====================================================================
1702// WI_drawStats
1703// Purpose: Put the solo stats on the screen
1704// Args: none
1705// Returns: void
1706//
1707// proff/nicolas 09/20/98 -- changed for hi-res
1708// CPhipps - patch drawing updated
1709void WI_drawStats(void)
1710{
1711 // line height
1712 int lh;
1713
1714 lh = (3*num[0].height)/2;
1715
1716 WI_slamBackground();
1717
1718 // draw animated background
1719 WI_drawAnimatedBack();
1720
1721 WI_drawLF();
1722
1723 V_DrawNamePatch(SP_STATSX, SP_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH);
1724 if (cnt_kills)
1725 WI_drawPercent(320 - SP_STATSX, SP_STATSY, cnt_kills[0]);
1726
1727 V_DrawNamePatch(SP_STATSX, SP_STATSY+lh, FB, items, CR_DEFAULT, VPT_STRETCH);
1728 if (cnt_items)
1729 WI_drawPercent(320 - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
1730
1731 V_DrawNamePatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret, CR_DEFAULT, VPT_STRETCH);
1732 if (cnt_secret)
1733 WI_drawPercent(320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
1734
1735 WI_drawTimeStats(cnt_time, cnt_total_time, cnt_par);
1736}
1737
1738// ====================================================================
1739// WI_checkForAccelerate
1740// Purpose: See if the player has hit either the attack or use key
1741// or mouse button. If so we set acceleratestage to 1 and
1742// all those display routines above jump right to the end.
1743// Args: none
1744// Returns: void
1745//
1746void WI_checkForAccelerate(void)
1747{
1748 int i;
1749 player_t *player;
1750
1751 // check for button presses to skip delays
1752 for (i=0, player = players ; i<MAXPLAYERS ; i++, player++)
1753 {
1754 if (playeringame[i])
1755 {
1756 if (player->cmd.buttons & BT_ATTACK)
1757 {
1758 if (!player->attackdown)
1759 acceleratestage = 1;
1760 player->attackdown = true;
1761 }
1762 else
1763 player->attackdown = false;
1764
1765 if (player->cmd.buttons & BT_USE)
1766 {
1767 if (!player->usedown)
1768 acceleratestage = 1;
1769 player->usedown = true;
1770 }
1771 else
1772 player->usedown = false;
1773 }
1774 }
1775}
1776
1777// ====================================================================
1778// WI_Ticker
1779// Purpose: Do various updates every gametic, for stats, animation,
1780// checking that intermission music is running, etc.
1781// Args: none
1782// Returns: void
1783//
1784void WI_Ticker(void)
1785{
1786 // counter for general background animation
1787 bcnt++;
1788
1789 if (bcnt == 1)
1790 {
1791 // intermission music
1792 if ( gamemode == commercial )
1793 S_ChangeMusic(mus_dm2int, true);
1794 else
1795 S_ChangeMusic(mus_inter, true);
1796 }
1797
1798 WI_checkForAccelerate();
1799
1800 switch (state)
1801 {
1802 case StatCount:
1803 if (deathmatch) WI_updateDeathmatchStats();
1804 else if (netgame) WI_updateNetgameStats();
1805 else WI_updateStats();
1806 break;
1807
1808 case ShowNextLoc:
1809 WI_updateShowNextLoc();
1810 break;
1811
1812 case NoState:
1813 WI_updateNoState();
1814 break;
1815 }
1816}
1817
1818/* ====================================================================
1819 * WI_loadData
1820 * Purpose: Initialize intermission data such as background graphics,
1821 * patches, map names, etc.
1822 * Args: none
1823 * Returns: void
1824 *
1825 * CPhipps - modified for new wad lump handling.
1826 * - no longer preload most graphics, other funcs can use
1827 * them by name
1828 */
1829
1830void WI_loadData(void)
1831{
1832 int i;
1833 int j;
1834 char name[9]; // limited to 8 characters
1835 anim_t* a;
1836
1837 if (gamemode != commercial)
1838 {
1839 if (wbs->epsd < 3)
1840 {
1841 for (j=0;j<NUMANIMS[wbs->epsd];j++)
1842 {
1843 a = &anims[wbs->epsd][j];
1844 for (i=0;i<a->nanims;i++)
1845 {
1846 // MONDO HACK!
1847 if (wbs->epsd != 1 || j != 8)
1848 {
1849 // animations
1850 sprintf(name, "WIA%d%.2d%.2d", wbs->epsd, j, i);
1851 R_SetPatchNum(&a->p[i], name);
1852 }
1853 else
1854 {
1855 // HACK ALERT!
1856 a->p[i] = anims[1][4].p[i];
1857 }
1858 }
1859 }
1860 }
1861 }
1862
1863 for (i=0;i<10;i++)
1864 {
1865 // numbers 0-9
1866 sprintf(name, "WINUM%d", i);
1867 R_SetPatchNum(&num[i], name);
1868 }
1869}
1870
1871
1872// ====================================================================
1873// WI_Drawer
1874// Purpose: Call the appropriate stats drawing routine depending on
1875// what kind of game is being played (DM, coop, solo)
1876// Args: none
1877// Returns: void
1878//
1879void WI_Drawer (void)
1880{
1881 switch (state)
1882 {
1883 case StatCount:
1884 if (deathmatch)
1885 WI_drawDeathmatchStats();
1886 else if (netgame)
1887 WI_drawNetgameStats();
1888 else
1889 WI_drawStats();
1890 break;
1891
1892 case ShowNextLoc:
1893 WI_drawShowNextLoc();
1894 break;
1895
1896 case NoState:
1897 WI_drawNoState();
1898 break;
1899 }
1900}
1901
1902
1903// ====================================================================
1904// WI_initVariables
1905// Purpose: Initialize the intermission information structure
1906// Note: wbstartstruct_t is defined in d_player.h
1907// Args: wbstartstruct -- pointer to the structure with the data
1908// Returns: void
1909//
1910void WI_initVariables(wbstartstruct_t* wbstartstruct)
1911{
1912
1913 wbs = wbstartstruct;
1914
1915#ifdef RANGECHECKING
1916 if (gamemode != commercial)
1917 {
1918 if ( gamemode == retail )
1919 RNGCHECK(wbs->epsd, 0, 3);
1920 else
1921 RNGCHECK(wbs->epsd, 0, 2);
1922 }
1923 else
1924 {
1925 RNGCHECK(wbs->last, 0, 8);
1926 RNGCHECK(wbs->next, 0, 8);
1927 }
1928 RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1929 RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1930#endif
1931
1932 acceleratestage = 0;
1933 cnt = bcnt = 0;
1934 firstrefresh = 1;
1935 me = wbs->pnum;
1936 plrs = wbs->plyr;
1937
1938 if (!wbs->maxkills)
1939 wbs->maxkills = 1; // probably only useful in MAP30
1940
1941 if (!wbs->maxitems)
1942 wbs->maxitems = 1;
1943
1944 if ( gamemode != retail )
1945 if (wbs->epsd > 2)
1946 wbs->epsd -= 3;
1947}
1948
1949// ====================================================================
1950// WI_Start
1951// Purpose: Call the various init routines
1952// Note: wbstartstruct_t is defined in d_player.h
1953// Args: wbstartstruct -- pointer to the structure with the
1954// intermission data
1955// Returns: void
1956//
1957void WI_Start(wbstartstruct_t* wbstartstruct)
1958{
1959 WI_initVariables(wbstartstruct);
1960 WI_loadData();
1961
1962 if (deathmatch)
1963 WI_initDeathmatchStats();
1964 else if (netgame)
1965 WI_initNetgameStats();
1966 else
1967 WI_initStats();
1968}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Intermission screens.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#ifndef __WI_STUFF__
35#define __WI_STUFF__
36
37//#include "v_video.h"
38
39#include "doomdef.h"
40
41// States for the intermission
42
43typedef enum
44{
45 NoState = -1,
46 StatCount,
47 ShowNextLoc
48
49} stateenum_t;
50
51// Called by main loop, animate the intermission.
52void WI_Ticker (void);
53
54// Called by main loop,
55// draws the intermission directly into the screen buffer.
56void WI_Drawer (void);
57
58// Setup for an intermission screen.
59void WI_Start(wbstartstruct_t* wbstartstruct);
60
61// Release intermission screen memory
62void WI_End(void);
63
64#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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * This is designed to be a fast allocator for small, regularly used block sizes
31 *-----------------------------------------------------------------------------
32 */
33
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#include "doomtype.h"
39#include "z_zone.h"
40#include "z_bmalloc.h"
41#include "lprintf.h"
42
43typedef struct bmalpool_s {
44 struct bmalpool_s *nextpool;
45 size_t blocks;
46 byte used[0];
47} bmalpool_t;
48
49inline static void* getelem(bmalpool_t *p, size_t size, size_t n)
50{
51 return (((byte*)p) + sizeof(bmalpool_t) + sizeof(byte)*(p->blocks) + size*n);
52}
53
54inline static PUREFUNC int iselem(const bmalpool_t *pool, size_t size, const void* p)
55{
56 // CPhipps - need portable # of bytes between pointers
57 int dif = (const char*)p - (const char*)pool;
58
59 dif -= sizeof(bmalpool_t);
60 dif -= pool->blocks;
61 if (dif<0) return -1;
62 dif /= size;
63 return (((size_t)dif >= pool->blocks) ? -1 : dif);
64}
65
66enum { unused_block = 0, used_block = 1};
67
68void* Z_BMalloc(struct block_memory_alloc_s *pzone)
69{
70 register bmalpool_t **pool = (bmalpool_t **)&(pzone->firstpool);
71 while (*pool != NULL) {
72 byte *p = memchr((*pool)->used, unused_block, (*pool)->blocks); // Scan for unused marker
73 if (p) {
74 int n = p - (*pool)->used;
75#ifdef SIMPLECHECKS
76 if ((n<0) || ((size_t)n>=(*pool)->blocks))
77 I_Error("Z_BMalloc: memchr returned pointer outside of array");
78#endif
79 (*pool)->used[n] = used_block;
80 return getelem(*pool, pzone->size, n);
81 } else
82 pool = &((*pool)->nextpool);
83 }
84 {
85 // Nothing available, must allocate a new pool
86 bmalpool_t *newpool;
87
88 // CPhipps: Allocate new memory, initialised to 0
89
90 *pool = newpool = Z_Calloc(sizeof(*newpool) + (sizeof(byte) + pzone->size)*(pzone->perpool),
91 1, pzone->tag, NULL);
92 newpool->nextpool = NULL; // NULL = (void*)0 so this is redundant
93
94 // Return element 0 from this pool to satisfy the request
95 newpool->used[0] = used_block;
96 newpool->blocks = pzone->perpool;
97 return getelem(newpool, pzone->size, 0);
98 }
99}
100
101void Z_BFree(struct block_memory_alloc_s *pzone, void* p)
102{
103 register bmalpool_t **pool = (bmalpool_t**)&(pzone->firstpool);
104
105 while (*pool != NULL) {
106 int n = iselem(*pool, pzone->size, p);
107 if (n >= 0) {
108#ifdef SIMPLECHECKS
109 if ((*pool)->used[n] == unused_block)
110 I_Error("Z_BFree: Refree in zone %s", pzone->desc);
111#endif
112 (*pool)->used[n] = unused_block;
113 if (memchr(((*pool)->used), used_block, (*pool)->blocks) == NULL) {
114 // Block is all unused, can be freed
115 bmalpool_t *oldpool = *pool;
116 *pool = (*pool)->nextpool;
117 Z_Free(oldpool);
118 }
119 return;
120 } else pool = &((*pool)->nextpool);
121 }
122 I_Error("Z_BFree: Free not in zone %s", pzone->desc);
123}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Block memory allocator
31 * This is designed to be a fast allocator for small, regularly used block sizes
32 *-----------------------------------------------------------------------------*/
33
34struct block_memory_alloc_s {
35 void *firstpool;
36 size_t size;
37 size_t perpool;
38 int tag;
39 const char *desc;
40};
41
42#define DECLARE_BLOCK_MEMORY_ALLOC_ZONE(name) extern struct block_memory_alloc_s name
43#define IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(name, size, tag, num, desc) \
44struct block_memory_alloc_s name = { NULL, size, num, tag, desc}
45#define NULL_BLOCK_MEMORY_ALLOC_ZONE(name) name.firstpool = NULL
46
47void* Z_BMalloc(struct block_memory_alloc_s *pzone);
48
49inline static void* Z_BCalloc(struct block_memory_alloc_s *pzone)
50{ void *p = Z_BMalloc(pzone); memset(p,0,pzone->size); return p; }
51
52void 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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Zone Memory Allocation. Neat.
31 *
32 * Neat enough to be rewritten by Lee Killough...
33 *
34 * Must not have been real neat :)
35 *
36 * Made faster and more general, and added wrappers for all of Doom's
37 * memory allocation functions, including malloc() and similar functions.
38 * Added line and file numbers, in case of error. Added performance
39 * statistics and tunables.
40 *-----------------------------------------------------------------------------
41 */
42
43
44// use config.h if autoconf made one -- josh
45#ifdef HAVE_CONFIG_H
46#include "config.h"
47#endif
48
49#include <stdlib.h>
50#include <stdio.h>
51
52#include "z_zone.h"
53#include "doomstat.h"
54#include "m_argv.h"
55#include "v_video.h"
56#include "g_game.h"
57#include "lprintf.h"
58
59#ifdef DJGPP
60#include <dpmi.h>
61#endif
62
63// Tunables
64
65// Alignment of zone memory (benefit may be negated by HEADER_SIZE, CHUNK_SIZE)
66#define CACHE_ALIGN 32
67
68// Minimum chunk size at which blocks are allocated
69#define CHUNK_SIZE 32
70
71// Minimum size a block must be to become part of a split
72#define MIN_BLOCK_SPLIT (1024)
73
74// How much RAM to leave aside for other libraries
75#define LEAVE_ASIDE (128*1024)
76
77// Amount to subtract when retrying failed attempts to allocate initial pool
78#define RETRY_AMOUNT (256*1024)
79
80// signature for block header
81#define ZONEID 0x931d4a11
82
83// Number of mallocs & frees kept in history buffer (must be a power of 2)
84#define ZONE_HISTORY 4
85
86// End Tunables
87
88typedef struct memblock {
89
90#ifdef ZONEIDCHECK
91 unsigned id;
92#endif
93
94 struct memblock *next,*prev;
95 size_t size;
96 void **user;
97 unsigned char tag;
98
99#ifdef INSTRUMENTED
100 const char *file;
101 int line;
102#endif
103
104} memblock_t;
105
106/* size of block header
107 * cph - base on sizeof(memblock_t), which can be larger than CHUNK_SIZE on
108 * 64bit architectures */
109static const size_t HEADER_SIZE = (sizeof(memblock_t)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);
110
111static memblock_t *blockbytag[PU_MAX];
112
113// 0 means unlimited, any other value is a hard limit
114//static int memory_size = 8192*1024;
115static int memory_size = 0;
116static int free_memory = 0;
117
118#ifdef INSTRUMENTED
119
120// statistics for evaluating performance
121static int active_memory = 0;
122static int purgable_memory = 0;
123
124static void Z_DrawStats(void) // Print allocation statistics
125{
126 if (gamestate != GS_LEVEL)
127 return;
128
129 if (memory_size > 0) {
130 unsigned long total_memory = free_memory + memory_size + active_memory + purgable_memory;
131 double s = 100.0 / total_memory;
132
133 doom_printf("%-5i\t%6.01f%%\tstatic\n"
134 "%-5i\t%6.01f%%\tpurgable\n"
135 "%-5i\t%6.01f%%\tfree\n"
136 "%-5li\t\ttotal\n",
137 active_memory,
138 active_memory*s,
139 purgable_memory,
140 purgable_memory*s,
141 (free_memory + memory_size),
142 (free_memory + memory_size)*s,
143 total_memory
144 );
145 } else {
146 unsigned long total_memory = active_memory + purgable_memory;
147 double s = 100.0 / total_memory;
148
149 doom_printf("%-5i\t%6.01f%%\tstatic\n"
150 "%-5i\t%6.01f%%\tpurgable\n"
151 "%-5li\t\ttotal\n",
152 active_memory,
153 active_memory*s,
154 purgable_memory,
155 purgable_memory*s,
156 total_memory
157 );
158 }
159}
160
161#ifdef HEAPDUMP
162
163#ifndef HEAPDUMP_DIR
164#define HEAPDUMP_DIR "."
165#endif
166
167void W_PrintLump(FILE* fp, void* p);
168
169void Z_DumpMemory(void)
170{
171 static int dump;
172 char buf[PATH_MAX + 1];
173 FILE* fp;
174 size_t total_cache = 0, total_free = 0, total_malloc = 0;
175 int tag;
176
177 sprintf(buf, "%s/memdump.%d", HEAPDUMP_DIR, dump++);
178 fp = fopen(buf, "w");
179 for (tag = PU_FREE; tag < PU_MAX; tag++)
180 {
181 memblock_t* end_block, *block;
182 block = blockbytag[tag];
183 if (!block)
184 continue;
185 end_block = block->prev;
186 while (1)
187 {
188 switch (block->tag) {
189 case PU_FREE:
190 fprintf(fp, "free %d\n", block->size);
191 total_free += block->size;
192 break;
193 case PU_CACHE:
194 fprintf(fp, "cache %s:%d:%d\n", block->file, block->line, block->size);
195 total_cache += block->size;
196 break;
197 case PU_LEVEL:
198 fprintf(fp, "level %s:%d:%d\n", block->file, block->line, block->size);
199 total_malloc += block->size;
200 break;
201 default:
202 fprintf(fp, "malloc %s:%d:%d", block->file, block->line, block->size);
203 total_malloc += block->size;
204 if (block->file)
205 if (strstr(block->file,"w_memcache.c"))
206 W_PrintLump(fp, (char*)block + HEADER_SIZE);
207 fputc('\n', fp);
208 break;
209 }
210 if (block == end_block)
211 break;
212 block=block->next;
213 }
214 }
215 fprintf(fp, "malloc %d, cache %d, free %d, total %d\n",
216 total_malloc, total_cache, total_free,
217 total_malloc + total_cache + total_free);
218 fclose(fp);
219}
220#endif
221#endif
222
223#ifdef INSTRUMENTED
224
225// killough 4/26/98: Add history information
226
227enum {malloc_history, free_history, NUM_HISTORY_TYPES};
228
229static const char *file_history[NUM_HISTORY_TYPES][ZONE_HISTORY];
230static int line_history[NUM_HISTORY_TYPES][ZONE_HISTORY];
231static int history_index[NUM_HISTORY_TYPES];
232static const char *const desc[NUM_HISTORY_TYPES] = {"malloc()'s", "free()'s"};
233
234void Z_DumpHistory(char *buf)
235{
236 int i,j;
237 char s[1024];
238 strcat(buf,"\n");
239 for (i=0;i<NUM_HISTORY_TYPES;i++)
240 {
241 sprintf(s,"\nLast several %s:\n\n", desc[i]);
242 strcat(buf,s);
243 for (j=0; j<ZONE_HISTORY; j++)
244 {
245 int k = (history_index[i]-j-1) & (ZONE_HISTORY-1);
246 if (file_history[i][k])
247 {
248 sprintf(s, "File: %s, Line: %d\n", file_history[i][k],
249 line_history[i][k]);
250 strcat(buf,s);
251 }
252 }
253 }
254}
255#else
256
257void Z_DumpHistory(char *buf)
258{
259}
260
261#endif
262
263void Z_Close(void)
264{
265#if 0
266 (free)(zonebase);
267 zone = rover = zonebase = NULL;
268#endif
269}
270
271void Z_Init(void)
272{
273#if 0
274 size_t size = zone_size*1000;
275
276#ifdef HAVE_MMAP
277 return; /* cphipps - if we have mmap, we don't need our own heap */
278#endif
279
280#ifdef INSTRUMENTED
281 if (!(HEADER_SIZE >= sizeof(memblock_t) && size > HEADER_SIZE))
282 I_Error("Z_Init: Sanity check failed");
283#endif
284
285 size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size
286 size += HEADER_SIZE + CACHE_ALIGN;
287
288 // Allocate the memory
289
290 zonebase=(malloc)(size);
291 if (!zonebase)
292 I_Error("Z_Init: Failed on allocation of %lu bytes", (unsigned long)size);
293
294 lprintf(LO_INFO,"Z_Init : Allocated %lukb zone memory\n",
295 (long unsigned)size / 1000);
296
297 // Align on cache boundary
298
299 zone = (memblock_t *) ((char *) zonebase + CACHE_ALIGN -
300 ((unsigned) zonebase & (CACHE_ALIGN-1)));
301
302 rover = zone; // Rover points to base of zone mem
303 zone->next = zone->prev = zone; // Single node
304 zone->size = size; // All memory in one block
305 zone->tag = PU_FREE; // A free block
306 zone->vm = 0;
307
308#ifdef ZONEIDCHECK
309 zone->id = 0;
310#endif
311
312#ifdef INSTRUMENTED
313 free_memory = size;
314 /* cph - remove unnecessary initialisations to 0 */
315#endif
316#ifdef HEAPDUMP
317 atexit(Z_DumpMemory);
318#endif
319#endif
320}
321
322/* Z_Malloc
323 * You can pass a NULL user if the tag is < PU_PURGELEVEL.
324 *
325 * cph - the algorithm here was a very simple first-fit round-robin
326 * one - just keep looping around, freeing everything we can until
327 * we get a large enough space
328 *
329 * This has been changed now; we still do the round-robin first-fit,
330 * but we only free the blocks we actually end up using; we don't
331 * free all the stuff we just pass on the way.
332 */
333
334void *(Z_Malloc)(size_t size, int tag, void **user
335#ifdef INSTRUMENTED
336 , const char *file, int line
337#endif
338 )
339{
340 memblock_t *block = NULL;
341
342#ifdef INSTRUMENTED
343#ifdef CHECKHEAP
344 Z_CheckHeap();
345#endif
346
347 file_history[malloc_history][history_index[malloc_history]] = file;
348 line_history[malloc_history][history_index[malloc_history]++] = line;
349 history_index[malloc_history] &= ZONE_HISTORY-1;
350#endif
351
352#ifdef ZONEIDCHECK
353 if (tag >= PU_PURGELEVEL && !user)
354 I_Error ("Z_Malloc: An owner is required for purgable blocks"
355#ifdef INSTRUMENTED
356 "Source: %s:%d", file, line
357#endif
358 );
359#endif
360
361 if (!size)
362 return user ? *user = NULL : NULL; // malloc(0) returns NULL
363
364 size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size
365
366 if (memory_size > 0 && ((free_memory + memory_size) < (int)(size + HEADER_SIZE)))
367 {
368 memblock_t *end_block;
369 block = blockbytag[PU_CACHE];
370 if (block)
371 {
372 end_block = block->prev;
373 while (1)
374 {
375 memblock_t *next = block->next;
376#ifdef INSTRUMENTED
377 (Z_Free)((char *) block + HEADER_SIZE, file, line);
378#else
379 (Z_Free)((char *) block + HEADER_SIZE);
380#endif
381 if (((free_memory + memory_size) >= (int)(size + HEADER_SIZE)) || (block == end_block))
382 break;
383 block = next; // Advance to next block
384 }
385 }
386 block = NULL;
387 }
388
389#ifdef HAVE_LIBDMALLOC
390 while (!(block = dmalloc_malloc(file,line,size + HEADER_SIZE,DMALLOC_FUNC_MALLOC,0,0))) {
391#else
392 while (!(block = (malloc)(size + HEADER_SIZE))) {
393#endif
394 if (!blockbytag[PU_CACHE])
395 I_Error ("Z_Malloc: Failure trying to allocate %lu bytes"
396#ifdef INSTRUMENTED
397 "\nSource: %s:%d"
398#endif
399 ,(unsigned long) size
400#ifdef INSTRUMENTED
401 , file, line
402#endif
403 );
404 Z_FreeTags(PU_CACHE,PU_CACHE);
405 }
406
407 if (!blockbytag[tag])
408 {
409 blockbytag[tag] = block;
410 block->next = block->prev = block;
411 }
412 else
413 {
414 blockbytag[tag]->prev->next = block;
415 block->prev = blockbytag[tag]->prev;
416 block->next = blockbytag[tag];
417 blockbytag[tag]->prev = block;
418 }
419
420 block->size = size;
421
422#ifdef INSTRUMENTED
423 if (tag >= PU_PURGELEVEL)
424 purgable_memory += block->size;
425 else
426 active_memory += block->size;
427#endif
428 free_memory -= block->size;
429
430#ifdef INSTRUMENTED
431 block->file = file;
432 block->line = line;
433#endif
434
435#ifdef ZONEIDCHECK
436 block->id = ZONEID; // signature required in block header
437#endif
438 block->tag = tag; // tag
439 block->user = user; // user
440 block = (memblock_t *)((char *) block + HEADER_SIZE);
441 if (user) // if there is a user
442 *user = block; // set user to point to new block
443
444#ifdef INSTRUMENTED
445 Z_DrawStats(); // print memory allocation stats
446 // scramble memory -- weed out any bugs
447 memset(block, gametic & 0xff, size);
448#endif
449
450 return block;
451}
452
453void (Z_Free)(void *p
454#ifdef INSTRUMENTED
455 , const char *file, int line
456#endif
457 )
458{
459 memblock_t *block = (memblock_t *)((char *) p - HEADER_SIZE);
460
461#ifdef INSTRUMENTED
462#ifdef CHECKHEAP
463 Z_CheckHeap();
464#endif
465 file_history[free_history][history_index[free_history]] = file;
466 line_history[free_history][history_index[free_history]++] = line;
467 history_index[free_history] &= ZONE_HISTORY-1;
468#endif
469
470 if (!p)
471 return;
472
473
474#ifdef ZONEIDCHECK
475 if (block->id != ZONEID)
476 I_Error("Z_Free: freed a pointer without ZONEID"
477#ifdef INSTRUMENTED
478 "\nSource: %s:%d"
479 "\nSource of malloc: %s:%d"
480 , file, line, block->file, block->line
481#endif
482 );
483 block->id = 0; // Nullify id so another free fails
484#endif
485
486 if (block->user) // Nullify user if one exists
487 *block->user = NULL;
488
489 if (block == block->next)
490 blockbytag[block->tag] = NULL;
491 else
492 if (blockbytag[block->tag] == block)
493 blockbytag[block->tag] = block->next;
494 block->prev->next = block->next;
495 block->next->prev = block->prev;
496
497 free_memory += block->size;
498#ifdef INSTRUMENTED
499 if (block->tag >= PU_PURGELEVEL)
500 purgable_memory -= block->size;
501 else
502 active_memory -= block->size;
503
504 /* scramble memory -- weed out any bugs */
505 memset(block, gametic & 0xff, block->size + HEADER_SIZE);
506#endif
507
508#ifdef HAVE_LIBDMALLOC
509 dmalloc_free(file,line,block,DMALLOC_FUNC_MALLOC);
510#else
511 (free)(block);
512#endif
513#ifdef INSTRUMENTED
514 Z_DrawStats(); // print memory allocation stats
515#endif
516}
517
518void (Z_FreeTags)(int lowtag, int hightag
519#ifdef INSTRUMENTED
520 , const char *file, int line
521#endif
522 )
523{
524#ifdef HEAPDUMP
525 Z_DumpMemory();
526#endif
527
528 if (lowtag <= PU_FREE)
529 lowtag = PU_FREE+1;
530
531 if (hightag > PU_CACHE)
532 hightag = PU_CACHE;
533
534 for (;lowtag <= hightag; lowtag++)
535 {
536 memblock_t *block, *end_block;
537 block = blockbytag[lowtag];
538 if (!block)
539 continue;
540 end_block = block->prev;
541 while (1)
542 {
543 memblock_t *next = block->next;
544#ifdef INSTRUMENTED
545 (Z_Free)((char *) block + HEADER_SIZE, file, line);
546#else
547 (Z_Free)((char *) block + HEADER_SIZE);
548#endif
549 if (block == end_block)
550 break;
551 block = next; // Advance to next block
552 }
553 }
554}
555
556void (Z_ChangeTag)(void *ptr, int tag
557#ifdef INSTRUMENTED
558 , const char *file, int line
559#endif
560 )
561{
562 memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE);
563
564 // proff - added sanity check, this can happen when an empty lump is locked
565 if (!ptr)
566 return;
567
568 // proff - do nothing if tag doesn't differ
569 if (tag == block->tag)
570 return;
571
572#ifdef INSTRUMENTED
573#ifdef CHECKHEAP
574 Z_CheckHeap();
575#endif
576#endif
577
578#ifdef ZONEIDCHECK
579 if (block->id != ZONEID)
580 I_Error ("Z_ChangeTag: freed a pointer without ZONEID"
581#ifdef INSTRUMENTED
582 "\nSource: %s:%d"
583 "\nSource of malloc: %s:%d"
584 , file, line, block->file, block->line
585#endif
586 );
587
588 if (tag >= PU_PURGELEVEL && !block->user)
589 I_Error ("Z_ChangeTag: an owner is required for purgable blocks\n"
590#ifdef INSTRUMENTED
591 "Source: %s:%d"
592 "\nSource of malloc: %s:%d"
593 , file, line, block->file, block->line
594#endif
595 );
596
597#endif // ZONEIDCHECK
598
599 if (block == block->next)
600 blockbytag[block->tag] = NULL;
601 else
602 if (blockbytag[block->tag] == block)
603 blockbytag[block->tag] = block->next;
604 block->prev->next = block->next;
605 block->next->prev = block->prev;
606
607 if (!blockbytag[tag])
608 {
609 blockbytag[tag] = block;
610 block->next = block->prev = block;
611 }
612 else
613 {
614 blockbytag[tag]->prev->next = block;
615 block->prev = blockbytag[tag]->prev;
616 block->next = blockbytag[tag];
617 blockbytag[tag]->prev = block;
618 }
619
620#ifdef INSTRUMENTED
621 if (block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL)
622 {
623 active_memory -= block->size;
624 purgable_memory += block->size;
625 }
626 else
627 if (block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL)
628 {
629 active_memory += block->size;
630 purgable_memory -= block->size;
631 }
632#endif
633
634 block->tag = tag;
635}
636
637void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user
638#ifdef INSTRUMENTED
639 , const char *file, int line
640#endif
641 )
642{
643 void *p = (Z_Malloc)(n, tag, user DA(file, line));
644 if (ptr)
645 {
646 memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE);
647 memcpy(p, ptr, n <= block->size ? n : block->size);
648 (Z_Free)(ptr DA(file, line));
649 if (user) // in case Z_Free nullified same user
650 *user=p;
651 }
652 return p;
653}
654
655void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user
656#ifdef INSTRUMENTED
657 , const char *file, int line
658#endif
659 )
660{
661 return
662 (n1*=n2) ? memset((Z_Malloc)(n1, tag, user DA(file, line)), 0, n1) : NULL;
663}
664
665char *(Z_Strdup)(const char *s, int tag, void **user
666#ifdef INSTRUMENTED
667 , const char *file, int line
668#endif
669 )
670{
671 return strcpy((Z_Malloc)(strlen(s)+1, tag, user DA(file, line)), s);
672}
673
674void (Z_CheckHeap)(
675#ifdef INSTRUMENTED
676 const char *file, int line
677#else
678 void
679#endif
680 )
681{
682#if 0
683 memblock_t *block; // Start at base of zone mem
684 if (block)
685 do { // Consistency check (last node treated special)
686 if ((block->next != zone &&
687 (memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next)
688 || block->next->prev != block || block->prev->next != block)
689 I_Error("Z_CheckHeap: Block size does not touch the next block\n"
690#ifdef INSTRUMENTED
691 "Source: %s:%d"
692 "\nSource of offending block: %s:%d"
693 , file, line, block->file, block->line
694#endif
695 );
696//#ifdef INSTRUMENTED
697// shouldn't be needed anymore, was just for testing
698#if 0
699 if (((int)block->file < 0x00001000) && (block->file != NULL) && (block->tag != 0)) {
700 block->file = NULL;
701 }
702#endif
703 } while ((block=block->next) != zone);
704#endif
705}
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 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Zone Memory Allocation, perhaps NeXT ObjectiveC inspired.
31 * Remark: this was the only stuff that, according
32 * to John Carmack, might have been useful for
33 * Quake.
34 *
35 * Rewritten by Lee Killough, though, since it was not efficient enough.
36 *
37 *---------------------------------------------------------------------*/
38
39#ifndef __Z_ZONE__
40#define __Z_ZONE__
41
42#ifndef __GNUC__
43#define __attribute__(x)
44#endif
45
46// Include system definitions so that prototypes become
47// active before macro replacements below are in effect.
48
49#ifdef HAVE_CONFIG_H
50#include "config.h"
51#endif
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <assert.h>
56
57// ZONE MEMORY
58// PU - purge tags.
59
60enum {PU_FREE, PU_STATIC, PU_SOUND, PU_MUSIC, PU_LEVEL, PU_LEVSPEC, PU_CACHE,
61 /* Must always be last -- killough */ PU_MAX};
62
63#define PU_PURGELEVEL PU_CACHE /* First purgable tag's level */
64
65#ifdef INSTRUMENTED
66#define DA(x,y) ,x,y
67#define DAC(x,y) x,y
68#else
69#define DA(x,y)
70#define DAC(x,y)
71#endif
72
73void *(Z_Malloc)(size_t size, int tag, void **ptr DA(const char *, int));
74void (Z_Free)(void *ptr DA(const char *, int));
75void (Z_FreeTags)(int lowtag, int hightag DA(const char *, int));
76void (Z_ChangeTag)(void *ptr, int tag DA(const char *, int));
77void (Z_Init)(void);
78void Z_Close(void);
79void *(Z_Calloc)(size_t n, size_t n2, int tag, void **user DA(const char *, int));
80void *(Z_Realloc)(void *p, size_t n, int tag, void **user DA(const char *, int));
81char *(Z_Strdup)(const char *s, int tag, void **user DA(const char *, int));
82void (Z_CheckHeap)(DAC(const char *,int)); // killough 3/22/98: add file/line info
83void Z_DumpHistory(char *);
84
85#ifdef INSTRUMENTED
86/* cph - save space if not debugging, don't require file
87 * and line to memory calls */
88#define Z_Free(a) (Z_Free) (a, __FILE__,__LINE__)
89#define Z_FreeTags(a,b) (Z_FreeTags) (a,b, __FILE__,__LINE__)
90#define Z_ChangeTag(a,b) (Z_ChangeTag)(a,b, __FILE__,__LINE__)
91#define Z_Malloc(a,b,c) (Z_Malloc) (a,b,c, __FILE__,__LINE__)
92#define Z_Strdup(a,b,c) (Z_Strdup) (a,b,c, __FILE__,__LINE__)
93#define Z_Calloc(a,b,c,d) (Z_Calloc) (a,b,c,d,__FILE__,__LINE__)
94#define Z_Realloc(a,b,c,d) (Z_Realloc) (a,b,c,d,__FILE__,__LINE__)
95#define Z_CheckHeap() (Z_CheckHeap)(__FILE__,__LINE__)
96#endif
97
98/* cphipps 2001/11/18 -
99 * If we're using memory mapped file access to WADs, we won't need to maintain
100 * our own heap. So we *could* let "normal" malloc users use the libc malloc
101 * directly, for efficiency. Except we do need a wrapper to handle out of memory
102 * errors... damn, ok, we'll leave it for now.
103 */
104#ifndef HAVE_LIBDMALLOC
105// Remove all definitions before including system definitions
106
107#undef malloc
108#undef free
109#undef realloc
110#undef calloc
111#undef strdup
112
113#define malloc(n) Z_Malloc(n,PU_STATIC,0)
114#define free(p) Z_Free(p)
115#define realloc(p,n) Z_Realloc(p,n,PU_STATIC,0)
116#define calloc(n1,n2) Z_Calloc(n1,n2,PU_STATIC,0)
117#define strdup(s) Z_Strdup(s,PU_STATIC,0)
118
119#else
120
121#ifdef HAVE_LIBDMALLOC
122#include <dmalloc.h>
123#endif
124
125#endif
126
127void Z_ZoneHistory(char *);
128
129#endif