pax_global_header00006660000000000000000000000064125743220060014513gustar00rootroot0000000000000052 comment=2ddd290b8226e1d1f0c52e344e76150261a8c0c3 chocolate-doom-chocolate-doom-2.2.1/000077500000000000000000000000001257432200600173055ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/.gitignore000066400000000000000000000005251257432200600212770ustar00rootroot00000000000000CMDLINE INSTALL Makefile Makefile.in TAGS aclocal.m4 autom4te.cache autotools bin config.h config.hin config.log config.status configure lib obj rpm.spec stamp-h stamp-h.in stamp-h1 tags # These are the default patterns globally ignored by Subversion: *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo *.rej *~ .#* .*.swp .DS_store chocolate-doom-chocolate-doom-2.2.1/.lvimrc000066400000000000000000000014151257432200600206030ustar00rootroot00000000000000" Local vimrc configuration file. Install the localvimrc.vim vim script. set expandtab set tabstop=8 set softtabstop=4 set shiftwidth=4 " Add all tag files to tags path. let topdir = findfile("configure.in", ".;") let topdir = substitute(topdir, "configure.in", "", "") " Check tags file in current dir: set tags+=tags " Add tag files in parent directories: let tagfiles = findfile("tags", ".;", -1) " Add tag files for libraries: call add(tagfiles, topdir . "opl/tags") call add(tagfiles, topdir . "pcsound/tags") call add(tagfiles, topdir . "textscreen/tags") for tagfile in tagfiles " Don't go beyond the project top level when adding parent dirs: if stridx(tagfile, topdir) >= 0 exec "set tags+=" . tagfile endif endfor unlet topdir unlet tagfiles chocolate-doom-chocolate-doom-2.2.1/AUTHORS000066400000000000000000000001521257432200600203530ustar00rootroot00000000000000Simon Howard James Haley Samuel Villarreal chocolate-doom-chocolate-doom-2.2.1/COPYING000066400000000000000000000432541257432200600203500ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. chocolate-doom-chocolate-doom-2.2.1/ChangeLog000066400000000000000000000002411257432200600210540ustar00rootroot00000000000000Chocolate Doom's version history is stored in Git. For a full change log, clone the repository on Github: https://github.com/chocolate-doom/chocolate-doom chocolate-doom-chocolate-doom-2.2.1/HACKING000066400000000000000000000142551257432200600203030ustar00rootroot00000000000000 Coding style guidelines ======================= The coding style guidelines for Chocolate Doom are designed to keep the style of the original source code. This maintains consistency throughout the program, and does not require the original code to be changed. Some of these guidelines are stricter than what was done in the original source; follow these when writing new code only: there is no need to change existing code to fit them. You should set tabs to _display_ as eight spaces, not four. However, _indentation_ should be four spaces. If possible, do not use tab characters at all. There is a utility called "expand" which will remove tab characters. For the reasoning behind this, see: http://www.jwz.org/doc/tabs-vs-spaces.html Please write code to an 80 column limit so that it fits within a standard 80 column terminal. Do not leave trailing whitespace at the end of lines. Functions should be named like this: 'AB_FunctionName'. The 'AB' prefix denotes the subsystem (AM_ for automap, G_ for game, etc). If a function is static, you can omit the prefix and just name it like 'FunctionName'. Functions and global variables should always be made static if possible. Put '_t' on the end of types created with typedef. Type names like this should be all lowercase and have the subsystem name at the start. An example of this is 'txt_window_t'. When creating structures, always typedef them. Do not use Hungarian notation. Do not use the goto statement. Use C++-style comments, ie. '//' comments, not '/* ... */' comments. I don't care that this isn't standard ANSI C. Variables should be named like this: 'my_variable_name', not like this: 'MyVariableName'. In pointer variable declarations, place the '*' next to the variable name, not the type. When using an if, do, while, or for statement, always use the { } braces even when they are not necessary. For example, do this: if (condition) { body; } Not this: if (condition) // NO body; Write code like this: typedef struct { int member1; char *member2; } my_structure_t; void FunctionName(int argument, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) { int assign_var; assign_var = arg2 + arg3 * arg4 * (arg5 + arg6); if (foo && !bar || baz && qux || !(foo && bar && baz)) { body; } else if (xyz + 4 < abc * 4 + 3) { body; } else { body; } if (very_long_condition_like_this_one_that_forces_a_line_break && other_condition) { body; } switch (argument) { case FIRST: code; break; case SECOND: code; break; default: break; } for (a = 0; a < 10; ++a) { FunctionCall(arg1, arg2, arg3, arg4, arg_split_onto_second_line); } while (a < 10) { loop_body; } do { } while (condition); } Security ======== The C standard library has a number of unsafe functions that should be avoided when writing code for Chocolate Doom. These are: Unsafe function Safer alternative --------------------------------------------- gets() fgets(.., stdin) sprintf M_snprintf() snprintf M_snprintf() vsprintf M_vsnprintf() vsnprintf M_vsnprintf() strcpy() M_StringCopy() strncpy() M_StringCopy() strcat() M_StringConcat() strncat() M_StringConcat() strdup() M_StringDuplicate() Lots of the code includes calls to DEH_String() to simulate string replacement by the Dehacked tool. Be careful when using Dehacked replacements of printf format strings. For example, do not do this: printf(DEH_String("foo %s"), s); sprintf(mybuf, DEH_String("bar %s"), t); Instead do this: DEH_printf("foo %s", s); DEH_snprintf(mybuf, sizeof(mybuf), "bar %s", t); This does the format string replacement safely in a way that checks the arguments securely. Portability =========== Chocolate Doom is designed to be cross-platform and work on different Operating Systems and processors. Bear this in mind when writing code. Do not use the long type (its size differs across platforms; use int or int64_t depending on which you want). Use Doom's byte data type for byte data. 'int' is assumed to be a 32-bit integer, and 'short' is a 16-bit integer. You can also use the ISO C99 data types: intN_t and uintN_t where N is 8,16,32,64. Be careful with platform dependencies: do not use Windows API functions, for example. Use SDL where possible. Preprocessor #defines are set that can be used to identify the OS if necessary: _WIN32 for Windows and __MACOSX__ for MacOS X. Others are set through SDL. Try to avoid this if possible. Be careful of endianness! Doom has SHORT() and LONG() macros that do endianness conversion. Never assume that integer types have a particular byte ordering. Similarly, never assume that fields inside a structure are aligned in a particular way. This is most relevant when reading or writing data to a file or a network pipe. For signed integers, you shouldn't assume that (i >> n) is the same as (i / (1 << n)). However, most processors handle bitshifts of signed integers properly, so it's not a huge problem. GNU GPL and licensing ===================== All code submitted to the project must be licensed under the GNU GPL or a compatible license. If you use code that you haven't 100% written yourself, say so. Add a copyright header to the start of every file. Use this template: // // Copyright(C) YEAR Author's name // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // *File description goes here* // # vim: tw=70 chocolate-doom-chocolate-doom-2.2.1/Makefile.am000066400000000000000000000050631257432200600213450ustar00rootroot00000000000000AUX_DIST_GEN = \ $(ac_aux_dir)/install-sh \ $(ac_aux_dir)/missing MSVC_FILES= \ msvc/chocolate.sln \ msvc/config.h \ msvc/doom.vcproj \ msvc/heretic.vcproj \ msvc/hexen.vcproj \ msvc/inttypes.h \ msvc/libpcsound.vcproj \ msvc/libtextscreen.vcproj \ msvc/README \ msvc/server.vcproj \ msvc/setup.vcproj \ msvc/stdint.h \ msvc/win32.rc CODEBLOCKS_FILES= \ codeblocks/chocolate.workspace \ codeblocks/config.h \ codeblocks/doom.cbp \ codeblocks/game-res.rc \ codeblocks/heretic.cbp \ codeblocks/hexen.cbp \ codeblocks/libpcsound.cbp \ codeblocks/libtextscreen.cbp \ codeblocks/README \ codeblocks/server.cbp \ codeblocks/setup.cbp \ codeblocks/setup-res.rc DOC_FILES= \ README \ README.Music \ NEWS \ PHILOSOPHY \ ChangeLog EXTRA_DIST= \ $(AUX_DIST_GEN) \ $(MSVC_FILES) \ $(CODEBLOCKS_FILES) \ $(DOC_FILES) \ NOT-BUGS \ README.Strife \ .lvimrc \ HACKING \ TODO \ rpm.spec doomdocsdir = ${docdir}/../${PROGRAM_PREFIX}doom doomdocs_DATA = $(DOC_FILES) NOT-BUGS hereticdocsdir = ${docdir}/../${PROGRAM_PREFIX}heretic hereticdocs_DATA = $(DOC_FILES) hexendocsdir = ${docdir}/../${PROGRAM_PREFIX}hexen hexendocs_DATA = $(DOC_FILES) strifedocsdir = ${docdir}/../${PROGRAM_PREFIX}strife strifedocs_DATA = $(DOC_FILES) README.Strife MAINTAINERCLEANFILES = $(AUX_DIST_GEN) SUBDIRS=textscreen opl pcsound data src man DIST_SUBDIRS=pkg $(SUBDIRS) if HAVE_PYTHON INSTALL : man/INSTALL.template man/simplecpp ./man/simplecpp -DDOOM -DHERETIC -DHEXEN -DSTRIFE \ < man/INSTALL.template > $@ endif chocolate-doom-chocolate-doom-2.2.1/NEWS000066400000000000000000001541511257432200600200130ustar00rootroot000000000000002.2.1 (2015-09-10): Chocolate Doom has not seen a great deal of "stable" patch releases in its history. While the development tree sees major new features and changes, the purpose of this release, and hopefully others to follow like it, is to repair some deficiencies that existed in 2.2.0. General: * Preferences for the OS X launcher are now stored with a unique name to not conflict with other applications. (thanks Xeriphas1994) * Unix desktop entry files are now brought up to full desktop entry specification compliance. (thanks chungy, Fabian) * Unix AppData entries are now included, allowing software centers to display detailed information about the engines. (thanks chungy) * Partial XDG base directory specification compliance on Unix systems now exist to search for IWAD paths. One benefit is that $HOME/.local/share/games/doom is now a valid location to store and automatically find IWADs. (thanks chungy) Build systems: * The Microsoft Visual Studio build system was not fully functional in 2.2.0 and has been fixed. (thanks Linguica) * The autoconf build system checks for windres only for Windows toolchains. Some Linux distributions mistakingly include the program in their native toolchains. (thanks Fabian) * A compiler hint for packed structs has been added, which otherwise broke the games when built under recent GCC releases for Windows. (thanks Fabian) Doom: * The GOG.com releases of The Ultimate Doom, Doom II, and Final Doom are now detected and supported on Windows. (thanks chungy) * An integer overflow was used in spawn angle calculation, undefined C behavior which broke with Clang optimization. (thanks David Majnemer for insight) Setup tool: * The help URL for the level warp menu now points to the proper wiki page, rather than the multiplayer page. * The manifest has been updated for Windows 10 compatibility. (thanks chungy) 2.2.0 (2015-06-09): * The Hexen four level demo IWAD is now supported. Thanks to Fabian Greffrath for his careful investigation and emulation of the demo game's behavior in developing this. * OPL music playback has been improved in a number of ways to match the behavior of Vanilla Doom's DMX library much more closely. OPL3 playback is also now supported. Thanks go to Alexey Khokholov for his excellent research into the Vanilla DMX library that enabled these improvements. * New gamepad configurations: - PS4 DualShock 4 (thanks Matt '3nT' Davis). - Xbox One controller on Linux (thanks chungy). - "Super Joy Box 7" USB/PC gameport adapter. * The Doom reload hack has been added back. See the wiki for more context on this: http://doomwiki.org/wiki/Reload_hack * The IWAD file from Strife: Veteran Edition is now detected automatically (thanks chungy). * It's now possible to build outside of the source directory (thanks Dave Murphy). * MSVC project files were brought up to date (thanks dbrackett16). * M_StringDuplicate() has been added as a safer replacement for strdup() (thanks Quasar). M_StringCopy() now handles short buffers more gracefully. * The netgame discrepancy window is now dismissed by pressing enter to proceed, not escape (thanks Alexandre-Xavier). * A couple of source files that were in the previous release and were GPL3 have been replaced by GPL2 equivalents. Previous releases that included these files should be retroactively considered GPL3. Bug fixes: * A long-standing bug that could cause every display frame to be rendered twice was fixed (thanks Linguica, Harha, Alexandre- Xavier). * Lots of endianness fixes were integrated that were found by Ronald Lasmanowicz during development of his Wii port of Chocolate Doom, including a fix for a bug that could cause monsters to become partially invisible. * DeHackEd files without a newline character at the EOF are now correctly parsed (thanks Fabian). * An infinite loop that could occur in the weapon cycling code was fixed (thanks raithe, Fabian). * Mouse input triggered by cursor warp was fixed (thanks Super6-4). * Loop tags in substitute music files are ignored if both of the loop tags are equal to zero. This makes us consistent with other source ports that support the tags. * It's now possible to more conveniently play back demo .lmp files with names that end in the all-caps '.LMP' (thanks Ioan Chera). * Some code that accessed memory after freeing it was fixed. Two new parameters, -zonezero and -zonescan, were added to try to help detect these cases. * Mistaken assumptions about representations of booleans that affected some ARM systems were fixed (thanks floppes). * memcpy() uses on overlapping memory were changed to use memmove(), fixing abort traps on OpenBSD (thanks ryan-sg). * Hyphens in manpages were fixed (thanks chungy, Fabian). * Lots of compiler build warnings were fixed (thanks Fabian). Setup tool: * The setup tool now has help buttons for its various different screens, which link to articles on the wiki that give more information (thanks to chungy for helping to put the wiki pages together). * A fix was applied for a buffer overrun that could occur if the user had lots of IWAD files installed (thanks Fabian). * A crash related to username lookup was fixed. * It's now possible to connect via the setup tool to multiplayer servers that are not listening on the default port (thanks Alexandre-Xavier). Doom: * Sky transitions when emulating the id anthology version of the Final Doom executable were fixed (thanks Alexandre-Xavier, Fabian, chungy). * Structure fields in the stair-building functions were fixed to be deterministic, fixing a desync in mm09-512.lmp (thanks Fabian). Hexen: * A bug with texture names that had long names was fixed (thanks ETTiNGRiNDER). * Minotaur spawn time is now stored in little endian format, fixing a bug that affected compatibility with Vanilla savegames on big endian systems. * Code that starts ACS scripts is no longer compiler-dependent. Strife (all these are thanks to Quasar): * Sound priority was changed, so that the ticking sound that Stalker enemies make while active matches Vanilla behavior (thanks GeoffLedak). * Minor fixes to game behavior to match Vanilla, discovered during development of Strife: Veteran edition. * Behavior of descending stairs was fixed to match Vanilla. * Inventory items beyond the 8-bit range are now allowed in netgames. * Automap behavior better matches Vanilla now. * Multiplayer name changes were fixed. * Sound origin behavior for switches was fixed. * Teleport beacon behavior was fixed. * Default Strife skill level and screen size were changed to match Vanilla. * Bug was fixed where Rowan would not always take Beldin's ring. * Totally-invisible objects are now displayed correctly, and a Vanilla glitch with Shadow Acolytes is correctly emulated. * The level name for MAP29 (Entity's Lair) was fixed (thanks chungy). libtextscreen: * The main loop now exits immediately once all windows are closed (thanks Alexander-Xavier). * The large font is no longer selected based entirely on screen size. 2.1.0 (2014-10-22): Chocolate Doom now supports high-quality substitute music packs that are used in place of the original MIDI music tracks. I'm hoping to put together high-quality recordings of the music for all supported games using the Roland SC-55 synthesizer originally used to compose Doom's music (thanks twipley and MusicallyInspired). Support for joysticks and gamepads has been significantly improved in this version. Most gamepads should now work; if they don't, please report a bug. A number of gamepads are now automatically detected and configured automatically; if yours is not, you can help by sending in details. See the following page: http://www.chocolate-doom.org/wiki/index.php/Adding_your_gamepad OPL MIDI playback has been significantly improved, and problems with most tracks should now be resolved. Multi-track MIDI files now play back properly, MIDI tempo meta events are now supported and problems with stuttering when playing certain tracks have been fixed. If you still have problems with OPL playback, let me know. Also of note is that Chocolate Doom now has a document that describes the philosophy of the project and the reasoning behind its design (see PHILOSOPHY distributed with the source). Other new features: * There is now a -dehlump command line parameter to load Dehacked files contained inside WAD files (thanks Fabian Greffrath). * PNG format screenshots are now supported, and there is a dedicated key binding for taking screenshots without needing to always use -devparm (thanks Fabian Greffrath). The PrintScreen key can be used as a key binding (thanks Alexandre-Xavier). * There is now a config file variable (snd_maxslicetime_ms) to control the sound buffer size, and the default is more precise to reduce sound latency (thanks Holering). * You can now use an external command for music playback (thanks Holering). * All games now detect if you're tring to play using the wrong type of IWAD (doom.wad with Hexen, etc.) and exit with a helpful error message. A couple of users made this mistake after the 2.0 release introduced support for the new games. * The OS X app now associates with .hhe and .seh files. * There is now a -nodes parameter that automatically starts a netgame when a desired number of players have joined the game. * There is now more extensive documentation about music configuration (README.Music). * On Linux, a GUI pop-up is used when the game quits with an error to show the error message (thanks Willy Barro). * There are now Linux .desktop files for all supported games (thanks Mike Swanson). * The -geometry command line parameter can now be used to specify fullscreen or windowed modes, eg. -geometry 640x480w or -geometry 1024x768f. (thanks Mike Swanson) Doom: * Minor workarounds were added to allow the BFG Edition IWADs to be used without crashing the game (thanks Fabian Greffrath). * GUS patch files included with the BFG Edition are now automatically detected. * The 'no fog on spawn west' Vanilla bug is now correctly emulated (thanks xttl). * Behavior of older versions of Doom back to v1.666 can now be emulated. * The new Freedoom IWAD names are now recognized and supported. * Freedoom's DEHACKED lump can now be parsed and is automatically loaded when a Freedoom IWAD file is used (thanks Fabian Greffrath). A new command line parameter, -nodeh, can be used to prevent this from being loaded. * Behavior of the M_EPI4 menu item is now correctly emulated based on game version (thanks Alexandre-Xavier). * IDCLEV up to MAP40 is now supported, to match Vanilla (thanks Alexandre-Xavier). * Level warping on the command line (-warp) to episodes higher than 4 is possible, matching Vanilla behavior (thanks plumsinus). * The -cdrom command line parameter writes savegames to the correct directory now, matching Vanilla Doom behavior (thanks Alexandre-Xavier). * The Doom II mission pack to use can now be specified manually on the command line with the -pack parameter (thanks chungy) Heretic: * Weapon cycling keys for mouse and joystick were fixed (thanks Sander van Dijk). * The -timedemo parameter has been fixed, and -playdemo now handles full paths correctly. * A bug when panning the map was fixed (thanks Chris Fielder). * A savegame bug where plat_t structures were not restored correctly was fixed (thanks romeroyakovlev). * Rebinding of the pause key was fixed (thanks Fabian Greffrath). Hexen: * Music workarounds have been added so that it is possible to play using the Mac version of the Hexen IWAD file. * Weapon cycling keys for mouse and joystick were fixed (thanks Sander van Dijk). * The -timedemo parameter has been fixed, and -playdemo now handles full paths correctly. * There are now key bindings to allow the artifact keys to be rebound (thanks Fabian Greffrath). * Rebinding of the pause key was fixed (thanks Fabian Greffrath). * Maximum level number was extended to MAP60, allowing multiplayer games using the Deathkings add-on. * The startup screen can now be aborted by pressing escape, like in Vanilla. * Desync when playing back DEMO1 was fixed (thanks alexey.lysiuk). Strife: * 'Show mission' key is configured properly in setup (thanks Sander van Dijk). * Default music volume level now matches Vanilla (thanks Alexandre-Xavier). * Teleport beacon allegiance was fixed to match Vanilla (thanks Quasar). * The stair building code now more closely matches Vanilla (thanks Quasar). * Torpedo weapon changing behavior now matches Vanilla (thanks Quasar). Cleanups: * The copyright headers at the top of all source files have been vastly simplified. * Unsafe string functions have been eliminated from the codebase. Thanks to Theo de Raadt for calling out Chocolate Doom by name (alongside many other packages) for still using unsafe functions like strcpy: http://marc.info/?l=openbsd-tech&m=138733933417096 * vldoor_e enum values are now namespaced to avoid potential conflicts with POSIX standard functions. Bug fixes: * WAD and Dehacked checksums are now sent to clients and checked correctly when setting up netgames. * A bug was fixed that caused sound not to work in multiplayer games (thanks to everyone who reported this, and for Alexandre-Xavier and Quasar for help in fixing it). * The "D_DDTBLU disease" bug affecting certain MIDI files has been fixed (thanks plumsinus, Brad Harding and Quasar). * Calculation of the -devparm 'ticker' dots was fixed to match Vanilla behavior (thanks _bruce_ and Alexandre-Xavier). * The PC speaker code now supports the full range of sound frequencies (thanks Gez). * Annoying "jumping" behavior when grabbing the mouse cursor was fixed. * The screen is now initialized at the native bit depth by default, to avoid problems with systems that don't handle 8-bit screenbuffers very well any more. * The --docdir argument to the configure script is now honored (thanks Jan Engelhardt). * Various issues with the build were fixed (thanks Jan Engelhardt and Fabian Greffrath). * Backwards parameters were fixed in the sound code (thanks proteal). * A crash was fixed when running fullscreen with the -2 parameter (thanks Fabian Greffrath). * A crash when using large values of snd_channels was fixed (thanks Alexandre-Xavier). * A resource leak in the BSD PC speaker code was fixed (thanks Edward-san). * Windows resource files were fixed for Windows 7 (thanks Brad Harding). * A hard to trigger crash caused by a realloc() in the WAD code was fixed (thanks Fabian Greffrath for debugging). * A bug has been fixed where Chocolate Doom would stay running in the background on Windows after quitting. SDL_Quit() is called now (thanks johnsirett, Brad Harding, Quasar). * String replacements in dehacked lumps can now be overridden if a subsequent dehacked patch replaces the same string. libtextscreen: * Clicking on scrollbars now jumps to the correct position (thanks Alexandre-Xavier). * A use-after-free bug has been fixed where a click in a window that causes the window to close could lead to a crash (thanks DuClare). * Characters that are unprintable in the Extended ASCII chart are just ignored when they're typed, rather than appearing as an upside-down question mark (thanks Alexandre-Xavier). 2.0.0 (2013-12-09): This is version 2.0 of Chocolate Doom! This new major version is released to celeberate the 20th anniversary of the first release of Doom in 1993. Happy Birthday Doom! This new version has some major changes compared to the 1.0 series: * The codebase now includes Chocolate Heretic and Chocolate Hexen. These are based on the GPL source code released by Raven Software. * Also included is Chocolate Strife. This was developed through a mammoth four year reverse engineering project conducted by James "Quasar" Haley and Samuel "Kaiser" Villareal. The result is the most accurate reproduction of Strife to date, including full demo and savegame compatibility. See README.Strife for more information. Minor features that are nonetheless worth mentioning: * Chocolate Doom now includes a -statdump command line option, which emulates the output of the statdump.exe tool. This is used to implement a form of regression testing (statcheck) that directly compares against the Vanilla behavior. * Chocolate Heretic includes HHE patch file support, and I believe is the first Heretic port to include this feature. * GUS "pseudo-emulation" is now supported. This does not fully emulate a GUS, but Doom's DMXGUS lump can be used to generate a Timidity configuration file that plays music using the GUS patch set. * The setup tool now includes a built-in server browser, for use when selecting a server to join. Version 2.0 of Chocolate Doom has been in development for a long time, and there have been many bugs fixed over this time, too many to list here. Thanks to all the people who have tested it and diligently reported bugs over this time, and to all the people who have tested the beta releases over the past couple of months. Your contributions have been essential and invaluable. 1.7.0 (2012-06-09): * Fixed gnome-screensaver desktop file (thanks Rahul Sundaram). * Updated COPYING to current version of GPL2 (thanks Rahul Sundaram). * Running servers now re-resolve the address of the master server occasionally, to adapt to DNS address changes. * Error dialog is no longer shown on OS X when running from the console. * The Makefiles no longer use GNU make extensions, so the package builds on OpenBSD. * There is now an OPL MIDI debug option (-opldev), useful for when developing GENMIDI lumps. * A workaround for SDL mouse lag is now only used on Windows (where it is needed), and not on other systems. This fixes Chocolate Doom on AmigaOS (thanks Timo Sievänen). * UTF-8 usernames are supported, and Windows usernames with non-ASCII characters are now supported (thanks Alexandre Xavier). Compatibility: * Palette accuracy is reduced to 6 bits per channel, to more accurately emulate the PC VGA hardware (thanks GhostlyDeath). * Fixed teleport behavior when emulating the alternate Final Doom executable (-gameversion final2) (thanks xttl). Bugs fixed: * Fixed weapon cycling keys when playing in Shareware Doom and using the IDKFA cheat (thanks Alexandre Xavier). * Fixed the default mouse buttons in the setup tool (thanks Alexandre Xavier). * Chat macros now work when vanilla_keyboard_mapping is turned off. * Default chat macros were fixed in the setup tool. * Ping time calculation was fixed for LAN search, and made more accurate for all searches. * Fixed bug with detection of IWAD type by filename (thanks mether). libtextscreen: * There is now limited UTF-8 text support in the textscreen library, used in the label and input box widgets. * Scroll bar behavior was fixed (thanks Alexandre Xavier). * Input boxes stop editing and save when they lose their focus, correcting a previous counterintuitive behavior (thanks Twelve). * The numeric keypad now works properly when entering text values (thanks Twelve). 1.6.0 (2011-05-17): * The instructions in the INSTALL file are now customized for different platforms, and each binary package contains a version with instructions specific to the platform that it is targetting. This should help to avoid confusion that some users have reported experiencing. * The display settings window in the setup tool has been reorganised to a better arrangement. * It is now possible to load .lmp files (and play back demos) with long filenames (thanks blzut3). * In the setup tool, it is now possible to hold down shift when changing key/mouse/joystick bindings to prevent other bindings to the same key from being cleared (thanks myk). * The joystick menu in the setup tool now has a test button (thanks Alexandre Xavier). * Specifying the -privateserver option implies -server (thanks Porsche Monty). * The Mac OS X .dmg package now has a background and looks generally more polished. * In Mac OS X, it is now possible to simply double click an IWAD file in the Finder to configure its location within the launcher. * Freedesktop.org desktop files are now installed for Doom and the setup tool, which will appear in the main menu on desktop environments such as Gnome and KDE (thanks Adrián Chaves Fernández). * The Chex Quest dehacked patch (chex.deh) will now be detected if it is in the same directory as the IWAD file. Compatibility: * Added support for the alternate version of the Final Doom executable included in some later versions of the Id Anthology. This version fixed the demo loop crash that occurred with the "original" Final Doom executable. This executable can be selected on the command line with -gameversion final2. It has been made the default when playing with the Final Doom IWADs (the original behavior can be selected with -gameversion final). (thanks Porsche Monty, Enjay). * Very short sound effects are not played, to better emulate the behavior of DMX in Vanilla Doom (thanks to Quasar for help in investigating this). * The null sector dereference emulation code has been imported from Prboom+ - this fixes a desync with CLNJ-506.LMP (thanks entryway). * The IDMUS cheat doesn't work when emulating the v1.9 executable (thanks Alexandre Xavier). Bugs fixed: * Menu navigation when using joystick/joypad (thanks Alexandre Xavier). * For configuration file value for shift keys, use scan code for right shift, not left shift (thanks Alexandre Xavier). * Default joystick buttons for the setup tool now match Vanilla (thanks twipley). * Visual Studio project files work again (thanks GhostlyDeath). * The default sfx/music volume set by the setup tool is now 8 instead of 15, matching the game itself. (thanks Alexandre Xavier). * Weapon cycling from the shotgun to the chaingun in Doom 1 now works properly (thanks Alexandre Xavier). * MIDI playback that locked up when using an empty MUS / MIDI file (thanks Alexandre Xavier). * Default sampling rate used by setup tool changed to 44100Hz, to match the game default (thanks Alexandre Xavier). * Cheat codes and menu hot keys now work when shift is held down or capslock turned on (thanks Alexandre Xavier). libtextscreen: * The background on GUI controls now lights up when hovering over them, so that it is more obvious what you are selecting. * It is now possible to type a '+' in input boxes (thanks Alexandre Xavier). * It is possible to use the mouse wheel to scroll through scroll panes. * Clicking on scroll bars now moves the scroll handle to a matching location. * Clicking outside a dropdown list popup window now dismisses the window. * Window hotkeys that are an alphabetical letter now work when shift is held down or capslock turned on (thanks Alexandre Xavier). 1.5.0 (2011-01-02): Big changes in this version: * The DOSbox OPL emulator (DBOPL) has been imported to replace the older FMOPL code. The quality of OPL emulation is now therefore much better. * The game can now run in screen modes at any color depth (not just 8-bit modes). This is mainly to work around problems with Windows Vista/7, where 8-bit color modes don't always work properly. * Multiplayer servers now register themselves with an Internet master server. Use the -search command line parameter to find servers on the Internet to play on. You can also use DoomSeeker (http://skulltag.net/doomseeker/) which supports this functionality. * When running in windowed mode, it is now possible to dynamically resize the window by dragging the window borders. * Names can be specified for servers with the -servername command line parameter. * There are now keyboard, mouse and joystick bindings to cycle through available weapons, making play with joypads or mobile devices (ie. without a proper keyboard) much more practical. * There is now a key binding to change the multiplayer spy key (usually F12). * The setup tool now has a "warp" button on the main menu, like Vanilla setup.exe (thanks Proteh). * Up to 8 mouse buttons are now supported (including the mousewheel). * A new command line parameter has been added (-solo-net) which can be used to simulate being in a single player netgame. * There is now a configuration file parameter to set the OPL I/O port, for cards that don't use port 0x388. * The Python scripts used for building Chocolate Doom now work with Python 3 (but also continue to work with Python 2) (thanks arin). * There is now a NOT-BUGS file included that lists some common Vanilla Doom bugs/limitations that you might encounter (thanks to Sander van Dijk for feedback). Compatibility: * The -timer and -avg options now work the same as Vanilla when playing back demos (thanks xttl) * A texture lookup bug was fixed that caused the wrong sky to be displayed in Spooky01.wad (thanks Porsche Monty). * The HacX v1.2 IWAD file is now supported, and can be used standalone without the need for the Doom II IWAD (thanks atyth). * The I_Error function doesn't display "Error:" before the error message, matching the Vanilla behavior. "Error" has also been removed from the title of the dialog box that appears on Windows when this happens. This is desirable as not all such messages are actually errors (thanks Proteh). * The setup tool now passes through all command line arguments when launching the game (thanks AlexXav). * Demo loop behavior (ie. whether to play DEMO4) now depends on the version being emulated. When playing Final Doom the game will exit unexpectedly as it tries to play the fourth demo - this is Vanilla behaviour (thanks AlexXav). Bugs fixed: * A workaround has been a bug in old versions of SDL_mixer (v1.2.8 and earlier) that could cause the game to lock up. Please upgrade to a newer version if you haven't already. * It is now possible to use OPL emulation at 11025Hz sound sampling rate, due to the new OPL emulator (thanks Porsche Monty). * The span renderer function (used for drawing floors and ceilings) now behaves the same as Vanilla Doom, so screenshots are pixel-perfect identical to Vanilla Doom (thanks Porsche Monty). * The zone memory system now aligns allocated memory to 8-byte boundaries on 64-bit systems, which may fix crashes on systems such as sparc64 (thanks Ryan Freeman and Edd Barrett). * The configure script now checks for libm, fixing compile problems on Fedora Linux (thanks Sander van Dijk). * Sound distortion with certain music files when played back using OPL (eg. Heretic title screen). * Error in Windows when reading response files (thanks Porsche Monty, xttl, Janizdreg). * Windows Vista/7 8-bit color mode issues (the default is now to run in 32-bit color depth on these versions) (thanks to everybody who reported this and helped test the fix). * Screen borders no longer flash when running on widescreen monitors, if you choose a true-color screen mode (thanks exp(x)). * The controller player in a netgame is the first player to join, instead of just being someone who gets lucky. * Command line arguments that take an option now check that an option is provided (thanks Sander van Dijk). * Skill level names in the setup tool are now written the same as they are on the in-game "new game" menu (thanks AlexXav). * There is no longer a limit on the lengths of filenames provided to the -record command line parameter (thanks AlexXav). * Window title is not lost in setup tool when changing video driver (thanks AlexXav). libtextscreen: * The font used for the textscreen library can be forced by setting the TEXTSCREEN_FONT environment variable to "small" or "normal". * Tables or scroll panes that don't contain any selectable widgets are now themselves not selectable (thanks Proteh). * The actions displayed at the bottom of windows are now laid out in a more aesthetically pleasing way. 1.4.0 (2010-07-10): The biggest change in this version is the addition of OPL emulation. This emulates Vanilla Doom's MIDI playback when using a Yamaha OPL synthesizer chip, as was found on SoundBlaster compatible cards. A software OPL emulator is included as most modern computers do not have a hardware OPL chip any more. If you do have one, you can configure Chocolate Doom to use it; see README.OPL. The OPL playback feature is not yet perfect or 100% complete, but is judged to be good enough for general use. If you find music that does not play back properly, please report it as a bug. Other changes: * The REJECT overflow emulation code from PrBoom+ has been imported. This fixes demo desync on some demos, although others will still desync. * Warnings are now generated for invalid dehacked replacements of printf format strings. Some potential buffer overflows are also checked. * The installation instructions (INSTALL file) have been clarified and made more platform-agnostic. * The mouse is no longer warped to the center of the screen when the demo sequence advances. * Key bindings can now be changed for the demo recording quit key (normally 'q') and the multiplayer messaging keys (normally 't', 'g', 'i', 'b' and 'r'). 1.3.0 (2010-02-10): * Chocolate Doom now runs on Windows Mobile/Windows CE! * It is possible to rebind most/all of the keys that control the menu, shortcuts, automap and weapon switching. The main reason for this is to support the Windows CE port and other platforms where a full keyboard may not be present. * Chocolate Doom now includes a proper Mac OS X package; it is no longer necessary to compile binaries for this system by hand. The package includes a simple graphical launcher program and can be installed simply by dragging the "Chocolate Doom" icon to the Applications folder. (thanks to Rikard Lang for extensive testing and feedback) * The video mode auto-adjust code will automatically choose windowed mode if no fullscreen video modes are available. * The zone memory size is automatically reduced on systems with a small amount of memory. * The "join game" window in the setup tool now has an option to automatically join a game on the local network. * Chocolate Doom includes some initial hacks for compiling under SDL 1.3. * Recent versions of SDL_mixer include rewritten MIDI code on Mac OS X. If you are using a version of SDL_mixer with the new code, music will now be enabled by default. * Windows Vista and Windows 7 no longer prompt for elevated privileges when running the setup tool (thanks hobbs and MikeRS). * The Windows binaries now have better looking icons (thanks MikeRS). * Magic values specified using the -spechit command line parameter can now be hexadecimal. * DOOMWADDIR/DOOMWADPATH can now specify the complete path to IWAD files, rather than the path to the directory that contains them. * When recording shorttics demos, errors caused by the reduced turning resolution are carried forward, possibly making turning smoother. * The source tarball can now be used to build an RPM package: rpmbuild -tb chocolate-doom-VER.tar.gz Compatibility: * The A_BossDeath behavior in v1.9 emulation mode was fixed (thanks entryway) * The "loading" disk icon is drawn more like how it is drawn in Vanilla Doom, also fixing a bug with chook3.wad. * Desync on 64-bit systems with ep1-0500.lmp has (at long last) been fixed (thanks exp(x)). * Donut overrun emulation code imported from Prboom+ (thanks entryway). * The correct level name should now be shown in the automap for pl2.wad MAP33 (thanks Janizdreg). * In Chex Quest, the green radiation suit colormap is now used instead of the red colormaps normally used when taking damage or using the berserk pack. This matches Vanilla chex.exe behavior (thanks Fuzztooth). * Impassible glass now displays and works the same as in Vanilla, fixing wads such as OTTAWAU.WAD (thanks Never_Again). Bugs fixed: * Memory-mapped WAD I/O is disabled by default, as it caused various issues, including a slowdown/crash with Plutonia 2 MAP23. It can be explicitly re-enabled using the '-mmap' command line parameter. * Crash when saving games due to the ~/.chocolate-doom/savegames directory not being created (thanks to everyone who reported this). * Chocolate Doom will now run under Win95/98, as the SetProcessAffinityMask function is looked up dynamically. * Compilation under Linux with older versions of libc will now work (the semantics for sched_setaffinity were different in older versions) * Sound clipping when using libsamplerate was improved (thanks David Flater) * The audio buffer size is now calculated based on the sample rate, so there is not a noticeable delay when using a lower sample rate. * The manpage documentation for the DOOMWADPATH variable was fixed (thanks MikeRS). * Compilation with FEATURE_MULTIPLAYER and FEATURE_SOUND disabled was fixed. * Fixed crash when using the donut special type and the joining linedef is one sided (thanks Alexander Waldmann). * Key settings in a configuration file that are out of range do not cause a crash (thanks entryway). * Fix ear-piercing whistle when playing the MAP05 MIDI music using timidity with EAWPATS (thanks entryway / HackNeyed). libtextscreen: * There is now a second, small textscreen font, so that the ENDOOM screen and setup tool can be used on low resolution devices (eg. PDAs/embedded devices) * The textscreen library now has a scrollable pane widget. Thanks to LionsPhil for contributing code to scroll up and down using the keyboard. * Doxygen documentation was added for the textscreen library. 1.2.1 (2008-12-10): This version just fixes a crash at the intermission screen when playing Doom 1 levels. 1.2.0 (2008-12-10): Happy 15th Birthday, Doom! * Chocolate Doom now has an icon that is not based on the proprietary Doom artwork. * There is now memory-mapped WAD I/O support, which should be useful on some embedded systems. * Chex quest emulation support is now included, although an auxiliary dehacked patch is needed (chexdeh.zip in the idgames archive). Compatibility: * The armor class is always set to 2 when picking up a megasphere (thanks entryway). * The quit screen prompts to quit "to dos" instead of just to quit (thanks MikeRS) * The "dimensional shambler" quit message was fixed. * Fix crash related to A_BFGSpray with NULL target when using dehacked patches - discovered with insaned2.deh (thanks CSonicGo) * NUL characters are stripped from dehacked files, to ensure correct behavior with some dehacked patches (eg. the one with portal.wad). Bugs fixed: * "Python Image Library" should have been "Python Imaging Library" (thanks exp(x)). * The setup tool should no longer ask for elevated permissions on Windows Vista (this fix possibly may not work). * The application icon is set properly when running under Windows XP with the "Luna" theme. * Fix compilation under Cygwin to detect libraries and headers from the correct environment. * The video code does not try to read SDL events before SDL has been properly initialised - this was causing problems with some older versions of SDL. 1.1.1 (2008-04-20): The previous release (v1.1.0) included a bug that broke compilation when libsamplerate support was enabled. The only change in this version is to fix this bug. 1.1.0 (2008-04-19): * The video mode code has been radically restructured. The video mode is now chosen by directly specifying the mode to use; the scale factor is then chosen to fit the screen. This is helpful when using widescreen monitors (thanks Linguica) * MSVC build project files (thanks GhostlyDeath and entryway). * Unix manpage improvements; the manpage now lists the environment variables that Chocolate Doom uses. Manpages have been added for chocolate-setup and chocolate-server, from the versions for the Debian Chocolate Doom package (thanks Jon Dowland). * INSTALL file with installation instructions for installing Chocolate Doom on Unix systems. * Support for high quality resampling of sound effects using libsamplerate (thanks David Flater). * A low pass filter is applied when doing sound resampling in an attempt to filter out high frequency noise from the resampling process. * R_Main progress box is not displayed if stdout is a file (produces cleaner output). * Client/server version checking can be disabled to allow different versions of Chocolate Doom to play together, or Chocolate Doom clients to play with Strawberry Doom clients. * Unix manpages are now generated for the Chocolate Doom configuration files. * The BSD PC speaker driver now works on FreeBSD. Compatibility: * Use the same spechits compatibility value as PrBoom+, for consistency (thanks Lemonzest). * The intercepts overrun code has been refactored to work on big endian machines. * The default startup delay has been set to one second, to allow time for the screen to settle before starting the game (some monitors have a delay before they come back on after changing modes). * If a savegame buffer overrun occurs, the savegame does not get saved and existing savegames are not overwritten (same behaviour as Vanilla). Bugs fixed: * Desync with STRAIN demos and dehacked Misc values not being set properly (thanks Lemonzest) * Don't grab the mouse if the mouse is disabled via -nomouse or use_mouse in the configuration file (thanks MikeRS). * Don't center the mouse on startup if the mouse is disabled (thanks Siggi). * Reset the palette when the window is restored to clear any screen corruption (thanks Catoptromancy). * mus2mid.c should use MEM_SEEK_SET, not SEEK_SET (thanks Russell) * Fast/Respawn options were not being exchanged when starting netgames (thanks GhostlyDeath). * Letterbox mode is more accurately described as "pillarboxed" or "windowboxed" where appropriate (thanks MikeRS) * Process affinity mask is set to 1 on Windows, to work around a bug in SDL_mixer that can cause crashes on multi-core machines (thanks entryway). * Bugs in the joystick configuration dialog in the setup tool have been fixed. 1.0.0 (2007-12-10): This release is dedicated to Dylan 'Toke' McIntosh, who was tragically killed in a car crash in 2006. I knew Dylan from IRC and the Doomworld forums for several years, and he had a deep passion for this game. He was also a huge help for me while developing Chocolate Doom, as he helped point out a lot of small quirks in Vanilla Doom that I didn't know about. His death is a great loss. RIP Toke. This is the first release to reach full feature parity with Vanilla Doom. As a result, I have made this version 1.0.0, so Chocolate Doom is no longer beta! Big new features: * Multiplayer! This version includes an entirely new multiplayer engine, based on a packet server architecture. I'd like to thank joe, pritch, Meph and myk, and everyone else who has helped test the new code for their support, feedback and help in testing this. The new code still needs more testing, and I'm eager to hear any feedback on this. * A working setup tool. This has the same look and feel as the original setup.exe. I hope people like it! Note that it has some advantages over the original setup.exe - for example, you can use the mouse. Other new features: * New mus conversion code thanks to Ben Ryves. This converts the Doom .mus format to .mid a lot better. As one example, tnt.wad Map02 is now a lot closer to how Vanilla says. Also, the music on the deca.wad titlescreen now plays! * x3, x4 and x5 display scale (thanks to MikeRS for x5 scale). * Fullscreen "letterbox" mode allows Chocolate Doom to run on machines where 1.6:1 aspect ratio modes are unavailable (320x200/640x400). The game runs in 320x240/640x480 instead, with black borders. The system automatically adjusts to this if closer modes are unavailable. * Aspect ratio correction: you can (also) run at 640x480 without black borders at the top and bottom of the screen. * PC speaker sound effect support. Chocolate Doom can output real PC speaker sounds on Linux, or emulate a PC speaker through the sound card. * Working three-screen mode, as seen in early versions of Doom! To test this out, put three computers on a LAN and type: chocolate-doom -server chocolate-doom -autojoin -left chocolate-doom -autojoin -right * Allow a delay to be specified on startup, to allow the display to settle after changing modes before starting the game. * Allow the full path and filename to be specified when loading demos: It is now possible to type 'chocolate-doom -playdemo /tmp/foo.lmp' for example. * Savegames are now stored in separate directories depending on the IWAD: eg. the savegames for Doom II are stored in a different place to those for Doom I, Final Doom, etc. (this does not affect Windows). * New mouse acceleration code works based on a threshold and acceleration. Hopefully this should be closer to what the DOS drivers do. There is a 'test' feature in the setup tool to help in configuring this. * New '-nwtmerge' command line option that emulates NWT's '-merge' option. This allows TiC's Obituary TC to be played. * The ENDOOM screen no longer closes automatically, you have to click the window to make it go away. * Spechit overrun fixes and improvements. Thanks to entryway for his continued research on this topic (and because I stole your improvements :-). Thanks to Quasar for reporting a bug as well. * Multiple dehacked patches can be specified on the command line, in the same way as with WADs - eg. -deh foo.deh bar.deh baz.deh. * Default zone memory size increased to 16MB; this can be controlled using the -mb command-line option. * It is now possible to record demos of unlimited length (by default, the Vanilla limit still applies, but it can now be disabled). * Autoadjusting the screen mode can now be disabled. * On Windows, the registry is queried to detect installed versions of Doom and automatically locate IWAD files. IWADs installed through Steam are also autodetected. * Added DOOMWADPATH that can be used like PATH to specify multiple locations in which to search for IWAD files. Also, '-iwad' is now enhanced, so that eg. '-iwad doom.wad' will now search all IWAD search paths for 'doom.wad'. * Improved mouse tracking that should no longer lag. Thanks to entryway for research into this. * The SDL driver can now be specified in the configuration file. The setup tool has an option on Windows to select between DirectX and windib. * Joystick support. * Configuration file option to change the sound sample rate. * More than three mouse buttons are now supported. Portability improvements: * Chocolate Doom now compiles and runs cleanly on MacOS X. Huge thanks go to Insomniak who kindly gave me an account on his machine so that I could debug this remotely. Big thanks also go to athanatos on the Doomworld forums for his patience in testing various ideas as I tried to get Chocolate Doom up and running on MacOS. * Chocolate Doom now compiles and runs natively on AMD64. * Chocolate Doom now compiles and runs on Solaris/SPARC, including the Sun compiler. Thanks to Mike Spooner for some portability fixes. * Improved audio rate conversion, so that sound should play properly on machines that don't support low bitrate output. Compatibility fixes: * Check for IWADs in the same order as Vanilla Doom. * Dehacked code will now not allow string replacements to be longer than those possible through DOS dehacked. * Fix sound effects playing too loud on level 8 (thanks to myk for his continued persistence in getting me to fix this) * Save demos when quitting normally - it is no longer necessary to press 'q' to quit and save a demo. * Fix spacing of -devparm mode dots. * Fix sky behavior to be the same as Vanilla Doom - when playing in Doom II, the skies never change from the sky on the first level unless the player loads from a savegame. * Make -nomouse and config file use_mouse work again. * Fix the -nomusic command-line parameter. Make the snd_sfxdevice snd_musicdevice values in the configuration file work, so that it is possible to disable sound, as with Vanilla. * Repeat key presses when the key is held down (this is the Vanilla behavior) - thanks to Mad_Mac for pointing this out. * Don't print a list of all arguments read from response files - Vanilla doesn't do this. * Autorun only when joyb_speed >= 10, not >= 4. Thanks to Janizdreg for this. * Emulate a bug in DOS dehacked that can overflow the dehacked frame table and corrupt the weaponinfo table. Note that this means Batman Doom will no longer play properly (identical behavior to Vanilla); vbatman.deh needs to also be applied to fix it. (Thanks grazza) * Allow dehacked 2.3 patches to be loaded. * Add more dehacked string replacements. * Compatibility option to enable or disable native key mappings. This means that people with non-US keyboards can decide whether to use their correct native mapping or behave like Vanilla mapping (which assumes all keyboards are US). * Emulate overflow bug in P_FindNextHighestFloor. Thanks to entryway for the fix for this. * Add -netdemo command line parameter, for playing back netgame demos recorded with a single player. * The numeric keypad now behaves like Vanilla Doom does. * Fix some crashes when loading from savegames. * Add intercepts overrun emulation from PrBoom-plus. Thanks again to entryway for his research on this subject. * Add playeringame overrun emulation. Bugs fixed: * Fix crash when starting new levels due to the intermission screen being drawn after the WI_ subsystem is shut down (thanks pritch and joe) * Catch failures to initialise sound properly, and fail gracefully. * Fix crasher in 1427uv01.lmp (thanks ultdoomer) * Fix crash in udm1.wad. * Fix crash when loading a savegame with revenant tracer missiles. * Fix crash when loading a savegame when a mancubus was in the middle of firing. * Fix Doom 1 E1-3 intermission screen animations. * Fix loading of dehacked "sound" sections. * Make sure that modified copyright banners always end in a newline - this fixes a bug with av.wad (thanks myk) * Added missing quit message ("are you sure you want to quit this great game?"). * Fix when playing long sound effects - the death sound in marina.wad now plays properly, for example. * Fix buffer overrun on the quicksave prompt screen that caused a mysterious cycling character to appear. * IDCLEV should not work in net games (thanks Janizdreg) * Stop music playing at the ENDOOM screen. * Fix sound sample rate conversion crash. * Fix 'pop' heard at the end of sound effects. * Fix crash when playing long sounds. * Fix bug with -timedemo accuracy over multi-level demos. * Fix bug with the automap always following player 1 in multiplayer mode (thanks Janizdreg). 0.1.4 (2006-02-13): NWT-style merging command line options (allows Mordeth to be played) Unix manpage (thanks Jon Dowland) Dehacked improvements/fixes: * Allow changing the names of graphic lumps used in menu, status bar intermission screen, etc. * Allow changing skies, animated flats + textures * Allow changing more startup strings. * Allow text replacements on music + sfx lump names Fix for plutonia map12 crash. Fix bug with playing long sfx at odd sample rates. Big Endian fixes (for MacOS X). Thanks to athanatos for helping find some of these. Install into /usr/games, rather than /usr/bin (thanks Jon Dowland) 0.1.3 (2006-01-20): Imported the spechit overrun emulation code from prboom-plus. Thanks to Andrey Budko for this. New show_endoom option in the chocolate-doom.cfg config file allows the ENDOOM screen to be disabled. Chocolate Doom is now savegame-compatible with Vanilla Doom. Fixes for big endian machines (thanks locust) Fixed the behavior of the dehacked maximum health setting. Fix the "-skill 0" hack to play without any items (thanks to Janizdreg for pointing out that this was nonfunctional) Fix playing of sounds at odd sample rates (again). Sound effects at any sample rate now play, but only sounds with valid headers. This is the *real* way Vanilla Doom behaves. Thanks to myk for pointing out the incorrect behavior. 0.1.2 (2005-10-29): Silence sounds at odd sample rates (rather than bombing out); this is the way Vanilla Doom behaves. Handle multiple replacements of the same sprite in a PWAD. Support specifying a specific version to emulate via the command line (-gameversion) Fix help screen orderings and skull positions. Behave exactly as the original executables do. 0.1.1 (2005-10-18): Display startup "banners" if they have been modified through dehacked. Dehacked "Misc" section support. Bugs fixed: * Doom 1 skies always using Episode 1 sky * Crash when switching applications while running fullscreen * Lost soul bounce logic (do not bounce in Registered/Shareware) * Mouse buttons mapped incorrectly (button 1 is right, 2 is middle) * Music not pausing when game is paused, when using SDL_mixer's native MIDI playback. * Pink icon on startup (palette should be fully set before anything is loaded) 0.1.0 (2005-10-09): Dehacked support WAD merging for TCs ENDOOM display Fix bug with invalid MUS files causing crashes Final Doom fixes 0.0.4 (2005-09-27): Application icon and version info included in Windows .exe files Fixes for non-x86 architectures Fix uac_dead.wad (platform drop on e1m8 should occur when all bosses die, not just barons) Fix "loading" icon to work for all graphics modes 0.0.3 (2005-09-17): Mouse acceleration code to emulate the behaviour of old DOS mouse drivers (thanks to Toke for information about this and suggestions) Lock surfaces properly when we have to (fixes crash under Windows 98) 0.0.2 (2005-09-13): Remove temporary MIDI files generated by sound code. Fix sound not playing at the right volume Allow alt-tab away while running in fullscreen under Windows Add second configuration file (chocolate-doom.cfg) to allow chocolate-doom specific settings. Fix switches not changing in Ultimate Doom 0.0.1 (2005-09-07): First beta release # vim: tw=70 chocolate-doom-chocolate-doom-2.2.1/NOT-BUGS000066400000000000000000000155151257432200600204350ustar00rootroot00000000000000 The aim of Chocolate Doom is to behave as closely to Vanilla Doom as possible. As a result, you may experience problems that you would also experience when using Vanilla Doom. These are not "bugs" as Chocolate Doom is behaving as intended. This is not intended to be a comprehensive list of Vanilla Doom bugs. For more information, consult the "engine bugs" page of the Doom Wiki. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == Game exits after title screen with message about game version == The game may exit after the title screen is shown, with a message like the following: Demo is from a different game version! (read 106, should be 109) *** You may need to upgrade your version of Doom to v1.9. *** See: http://doomworld.com/files/patches.shtml This appears to be v1.6/v1.666. This usually indicates that your IWAD file that you are using to play the game (usually named doom.wad or doom2.wad) is out of date. Chocolate Doom only supports the v1.9 IWAD file. To fix the problem, you must upgrade to the v1.9 IWAD file. The URL in the message has downloadable upgrade patches that you can use to upgrade. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == Game exits in demo loop when playing Final Doom == When playing with the Final Doom IWAD files (tnt.wad, plutonia.wad), if you leave the game at the title screen to play through the demo loop, it will eventually exit with the following error message: W_GetNumForName: demo4 not found! This is the same behavior as the Vanilla executables that were bundled with Final Doom. When Ultimate Doom was developed, a fourth demo was added to the demo loop, and this change was retained in the Final Doom version of the executable. However, the Final Doom IWADs do not include a fourth demo, so the game crashes. An alternate version of Final Doom was included in the Id Anthology boxed set, and this version of the game fixed this bug. However, this version also changes the teleport behavior, so the default is to emulate the most commonly distributed version of the game. To use the alternate version, run with: chocolate-doom -gameversion final2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == Game exits when accessing the options menu == The game may exit with the message "Bad V_DrawPatch" when accessing the options menu, if you have your mouse sensitivity set high. The Doom options menu has a slider that allows the mouse sensitivity to be controlled; however, it has only a very limited range. It is common for experienced players to set a mouse sensitivity that is much higher than what can be set via the options menu. The setup program allows a larger range of values to be set. However, setting very high sensitivity values causes the game to exit when accessing the options menu under Vanilla Doom. Because Chocolate Doom aims to emulate Vanilla Doom as closely as possible, it does the same thing. One solution to the problem is to set a lower mouse sensitivity. Alternatively, all of the settings in the options menu can be controlled through Doom's key bindings anyway: End game: F7 Messages on/off: F8 Graphic detail high/low: F5 Screen size smaller/larger: -/+ Sound volume menu: F4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == Game exits with "Savegame buffer overrun" when saving the game == If you are playing on a particularly large level, it is possible that when you save the game, the game will quit with the message "Savegame buffer overrun". Vanilla Doom has a limited size memory buffer that it uses for saving games. If you are playing on a large level, the buffer may be too small for the entire savegame to fit. Chocolate Doom allows the limit to be disabled: in the setup tool, go to the "compatibility" menu and disable the "Vanilla savegame limit" option. If this error happens to you, your game has not been lost! A file named temp.dsg is saved; rename this to doomsav0.dsg to make it appear in the first slot in the "load game" menu. (On Unix systems, you will need to look in the .chocolate-doom/savegames directory in your home directory) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == Game ends suddenly when recording a demo == If you are recording a very long demo, the game may exit suddenly. Vanilla Doom has a limited size memory buffer that it uses to save the demo into. When the buffer is full, the game exits. You can tell if this happens, as the demo file will be around 131,072 bytes in size. You can work around this by using the -maxdemo command line parameter to specify a larger buffer size. Alternatively, the limit can be disabled: in the setup tool, go to the compatibility menu and disable the "Vanilla demo limit" option. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == Game exits with a message about "visplanes" == The game may exit with one of these messages: R_FindPlane: no more visplanes R_DrawPlanes: visplane overflow (129) This is known as the "visplane overflow" limit and is one of the most well-known Vanilla Doom engine limits. You should only ever experience this when trying to play an add-on level. The level you are trying to play is too complex; it was most likely designed to work with a limit removing source port. More information can be found here: http://rome.ro/lee_killough/editing/visplane.shtml ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == IDMUS## cheat doesn't work with shareware/registered Doom IWADs == The IDMUS cheat allows the in-game music to be changed. However, in the original v1.9 this cheat didn't work properly when playing with the Doom 1 (shareware and registered) IWADs. This bug was fixed in the Ultimate Doom and Final Doom executables. Chocolate Doom emulates this bug. When playing with the shareware or registered Doom IWADs, the IDMUS cheat therefore does not work properly. If you are playing with the Ultimate Doom IWAD, the Ultimate Doom executable is emulated by default, so the cheat works properly. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ == Some graphics are wrong when playing with BFG Edition IWADs == If you are playing using the IWAD files from Doom 3: BFG Edition, you may notice that certain graphics appear strange or wrong. This includes the title screen, and parts of the options menu. The IWAD files in the new BFG Edition have had some significant changes from the IWAD files in older releases. Some of the graphics lumps have been removed or changed, and the Doom 2 secret levels are also censored. Chocolate Doom includes some small workarounds that allow the game to run, but for the best experience, it's best to get a copy of the classic versions of the IWADs. These are still available to buy from Steam or Id's online store. # vim: tw=70 chocolate-doom-chocolate-doom-2.2.1/PHILOSOPHY000066400000000000000000000213751257432200600207360ustar00rootroot00000000000000 Chocolate Doom has been designed around a careful and deliberate philosophy that attempts to recreate the original ("Vanilla") DOS executables for Doom, Heretic, Hexen and Strife. This document describes some of that philosophy and the reasoning behind it. This document is descriptive, not proscriptive. == Vanilla behavior == Ideally Chocolate Doom aims to recreate the behavior of the Vanilla binaries, but different aspects of Vanilla behavior are held to varying degrees of importance. It can be imagined as different "tiers" of compatibility: * The game and gameplay itself is of central importance. Here, the Vanilla behavior ought to be maintained as accurately as possible. This includes the look, feel and sound, and things like demo compatibility. * The surrounding aspects of the game that aren't part of the central gameplay experience can be extended as long as there's a good reason and Vanilla behavior is respected. * The setup tool is not required to reproduce the behavior of the Vanilla setup tool, even though it reproduces its look and feel. "Vanilla" is defined as: * DOS Doom 1.9 (although there are actually multiple "1.9"s). * DOS Heretic 1.3. * DOS Hexen 1.1. * DOS Strife 1.31. "Vanilla" does not include ports (either official or unofficial), such as console ports, Doom 95 or Doom 3: BFG Edition. == Compatibility == Chocolate Doom aims to be compatible with Vanilla Doom in several different ways. Examples are: * Bug compatibility: the aim is to emulate compatibility of the original game down to bugs that were present in the DOS executables. This includes maintaining the limitations of the original engine: for example, the infamous "visplane overflow" bug is intentionally still present, where other source ports have removed it; this allows mappers targeting Vanilla Doom to use Chocolate Doom as a faithful substitute. * Demo compatibility: Doom was one of the first games to develop a 'speedrunning' community, and thousands of recordings of Doom gameplay (.lmp demo files) exist in the Compet-N archive. Chocolate Doom aims for the highest standard of demo compatibility with Vanilla Doom, a goal that is often complicated by obscure behavior that can be difficult to reproduce. * Configuration file compatibility: Chocolate Doom uses the same configuration file format as Vanilla Doom, such that a user should be able to reuse their existing Vanilla configuration file without making any changes. Extra non-Vanilla options are stored in a separate configuration file. * Savegame file compatibility: Chocolate Doom uses the same savegame file format as Vanilla, such that it should be possible to import and use existing savegame files. == DOS tools == Chocolate Doom includes some features that aren't part of Vanilla Doom but exist for compatibility with DOS tools that interact with it. These are considered part of the Vanilla experience and ought to be treated as such. Some examples are: * The novert setting, which reproduces the functionality of novert.exe. * The -deh parameter, which loads Dehacked patches like dehacked.exe does under DOS. Chocolate Doom imposes the same limitations that Vanilla Dehacked does. == Exceptions == Chocolate Doom differs from Vanilla Doom in a number of ways. In most cases these are subtle, minor differences. Nonetheless they deserve some explanation and justification. Here are some examples of situations where changes are considered acceptable: 1. Vanilla behavior can be broken that is harmful, eg. can damage the player's computer, or is just outright misleading. For example: - Vanilla uses unbounded sprintf and strcpy (security issue). - Vanilla has crashes that force the user to reboot the machine. - Vanilla has an out of memory message that recommends tweaking CONFIG.SYS. As Chocolate Doom doesn't run under DOS, reproducing this message would not be helpful. 2. Subtly extending behavior is okay where it's not clear what the Vanilla behavior is anyway. For example: - Opening the menu releases mouse grab in Chocolate Doom. - Chocolate Hexen's graphical startup screen runs in a window. 3. Supporting obsolete technology is not a goal: it's considered acceptable that Chocolate Doom does not support every type of hardware from 1993. However, Chocolate Doom should aim to recreate the functionality in a modern way. Examples of technology that isn't supported are: - No support for IPX networks, but TCP/IP is supported instead. - No support for dial-up/serial connections; modern operating systems have features that do that for you. - No MS-DOS version. 4. Changes are acceptable that allow the player to be able play the game. For example: - There are new key bindings for actions that can't be rebound with Vanilla Doom, because it's useful for portability to machines that don't have a full keyboard. - There are additional mouse and joystick key bindings that let you perform actions with them that can only be done with the keyboard in Vanilla Doom. - Chocolate Doom includes some hacks to support the Doom 3: BFG Edition IWAD files. The assumption is that being able to at least play is better than nothing, even if it's not Vanilla behavior. 5. Adding extra options to Vanilla functionality is acceptable as long as the defaults match Vanilla, it doesn't change gameplay and there's a good reason for it. For example: - PNG screenshots are supported because PCX is an obsolete format. - Chocolate Doom has the vanilla_keyboard_mapping option that allows the user to use the native keyboard mapping for their computer, rather than always assuming a US layout. 6. Changing configuration file defaults is acceptable where there's a very good reason. For example: - Vanilla Doom defaults to no sound or music if a configuration file is not found. Chocolate Doom defaults to having sound effects and music turned on by default, because modern computers support these; there's no need to configure hardware IRQ settings to get sound working. 7. Things can be changed if they're really just inconsequential. For example: - The startup messages in Chocolate Doom are not identical to Vanilla Doom and are not necessarily in the same order. - Vanilla Doom has command line options named -comdev, -shdev and -regdev used by id internally for development; these have been removed. A good litmus test of when it's acceptable to break from Vanilla behavior is to ask the question: "Although this is Vanilla behavior, is there anyone who would want this?". For example, emulating Vanilla bugs like the visplane overflow bug is something that is useful for people making Vanilla format maps. On the other hand, painstakingly emulating Vanilla Doom by starting with no sound or music by default is not helpful to anyone. == Minimalism == Chocolate Doom aims to be minimalist and straightforward to configure; in particular, the setup tool should have a sane interface. Part of the inspiration for Chocolate Doom came from Boom's complicated maze of options menus (and a desire to avoid them). Too many preferences lead to a bad user interface; see Havoc Pennington's essay on Free Software UI: http://ometer.com/free-software-ui.html Chocolate Doom has some options that are quite obscure and only really of interest to a small number of people. In these cases, the options are hidden away in configuration files and deliberately not exposed in the setup tool. The assumption is that if you care enough about those obscure features, editing a configuration file by hand should not be a huge problem for you. Also inspirational was the README file from Havoc's Metacity window manager, where the list of features begins: Boring window manager for the adult in you. Many window managers are like Marshmallow Froot Loops; Metacity is like Cheerios. I'd like to think that Chocolate Doom's philosophy towards features is similar. The idea is for a source port that is boring. I find the best software - both proprietary and open source - is software that is "egoless": it does a job well without pretentions about its importance or delusions of grandeur. A couple of other notable examples of software that I feel embody this spirit of design in a beautiful way are Marco Pesenti Gritti's Epiphany web browser and Evince PDF viewer. == Other philosophical aspects == Chocolate Doom aims for maximal portability. That includes running on many different CPUs, different operating systems and different devices (ie. not just a desktop machine with a keyboard and mouse). Chocolate Doom is and will always remain Free Software. It will never include code that is not compatible with the GNU GPL. # vim: tw=70 chocolate-doom-chocolate-doom-2.2.1/README000066400000000000000000000072341257432200600201730ustar00rootroot00000000000000 Chocolate Doom aims to accurately reproduce the original DOS version of Doom and other games based on the Doom engine in a form that can be run on modern computers. Originally, Chocolate Doom was only a Doom source port. The project now includes ports of Heretic and Hexen, and Strife. Chocolate Doom's aims are: * To always be 100% Free and Open Source software. * Portability to as many different operating systems as possible. * Accurate reproduction of the original DOS versions of the games, including bugs. * Compatibility with the DOS demo, configuration and savegame files. * To provide an accurate retro "feel" (display and input should behave the same). More information about the philosophy and design behind Chocolate Doom can be found in the PHILOSOPHY file distributed with the source code. == Setting up gameplay == For instructions on how to set up Chocolate Doom for play, see the INSTALL file. == Configuration File == Chocolate Doom is compatible with the DOS Doom configuration file (normally named 'default.cfg'). Existing configuration files for DOS Doom should therefore simply work out of the box. However, Chocolate Doom also provides some extra settings. These are stored in a separate file named 'chocolate-doom.cfg'. The configuration can be edited using the chocolate-setup tool. == Command line options == Chocolate Doom supports a number of command line parameters, including some extras that were not originally suported by the DOS versions. For binary distributions, see the CMDLINE file included with your download; more information is also available on the Chocolate Doom website. == Playing TCs == With Vanilla Doom there is no way to include sprites in PWAD files. Chocolate Doom's '-file' command line option behaves exactly the same as Vanilla Doom, and trying to play TCs by adding the WAD files using '-file' will not work. Many Total Conversions (TCs) are distributed as a PWAD file which must be merged into the main IWAD. Typically a copy of DEUSF.EXE is included which performs this merge. Chocolate Doom includes a new option, '-merge', which will simulate this merge. Essentially, the WAD directory is merged in memory, removing the need to modify the IWAD on disk. To play TCs using Chocolate Doom, run like this: chocolate-doom -merge thetc.wad Here are some examples: chocolate-doom -merge batman.wad -deh batman.deh vbatman.deh (Batman Doom) chocolate-doom -merge aoddoom1.wad -deh aoddoom1.deh (Army of Darkness Doom) == Other information == * Chocolate Doom includes a number of different options for music playback. See the README.Music file for more details. * More information, including information about how to play various classic TCs, is available on the Chocolate Doom website: http://www.chocolate-doom.org/ You are encouraged to sign up and contribute any useful information you may have regarding the port! * Chocolate Doom is not perfect. Although it aims to accurately emulate reproduce the DOS executables, some behavior can be very difficult to reproduce. Because of the nature of the project, you may also encounter Vanilla Doom bugs; these are intentionally present; see the NOT-BUGS file for more information. New bug reports can be submitted to the issue tracker on Github: https://github.com/chocolate-doom/chocolate-doom/issues * Source code patches are welcome, but please follow the style guidelines - see the file named HACKING included with the source distribution. * Chocolate Doom is distributed under the GNU GPL. See the COPYING file for more information. * Please send any feedback, questions or suggestions to fraggle@gmail.com. Thanks! # vim: tw=70 chocolate-doom-chocolate-doom-2.2.1/README.Music000066400000000000000000000144621257432200600212530ustar00rootroot00000000000000 Doom has a memorable and atmospheric soundtrack. Like many games of the era, it is MIDI-based. Chocolate Doom includes a number of different options for music playback, detailed below. == Native MIDI playback == Most modern operating systems have some kind of built-in support for MIDI playback; some have very good quality MIDI playback (Mac OS X for example). To use this, choose "Native MIDI" in the sound configuration dialog in the setup tool. == Timidity == Timidity is a software-based MIDI synthesizer, and a version of it is included in the SDL_mixer library used by Chocolate Doom. To use Timidity for MIDI playback, first download a sound font. An example of a good quality sound font is the eawpats font, which can be downloaded from the idgames archive as sounds/eawpats.zip: http://www.doomworld.com/idgames/index.php?file=sounds/eawpats.zip Having installed a sound font, select "Native MIDI" in the sound configuration dialog in the setup tool, and use the "Timidity configuration file" widget below to enter the path to the Timidity configuration file (normally named timidity.cfg). == Gravis Ultrasound (GUS) == The Gravis Ultrasound (GUS) was a PC sound card popular in the '90s, notable for having wavetable synthesis that provided MIDI playback that was superior to most other cards of the era. Chocolate Doom includes a "pseudo-GUS emulation" feature that simulates the GUS (using Timidity, under the hood). To use this feature you need a copy of the GUS patch files that were distributed with the original GUS patches. If you have Doom 3: BFG Edition, these patches are included with its version of classic Doom, and are automatically detected. Otherwise, they can be downloaded from the idgames archive as music/dgguspat.zip: http://www.doomworld.com/idgames/index.php?file=music/dgguspat.zip Having downloaded the patches, select "GUS (emulated)" in the sound configuration dialog in the setup tool, and use the "GUS patch path" widget to enter the path to the directory containing the patch files. By default a GUS card with 1024KB is simulated; to simulate a 256KB, 512KB or 768KB card instead, change the gus_ram_kb option in chocolate-doom.cfg. == OPL (Soundblaster / Adlib) == Most people playing Doom in the '90s had Soundblaster-compatible sound cards, which used the Yamaha OPL series of chips for FM-based MIDI synthesis. Chocolate Doom includes the ability to emulate these chips for a retro experience. OPL emulation is the default MIDI playback, but can be selected in the setup tool as "OPL (Adlib/SB)". Most modern computers do not include an OPL chip any more, as CPUs are fast enough to do decent software MIDI synthesis. However, no software emulator sounds exactly like a real (hardware) OPL chip, and a few cards do have real hardware OPL. If you have such a card, here's how to configure Chocolate Doom to use it. === Sound cards with OPL chips === If you have an ISA sound card, it almost certainly includes an OPL chip. Modern computers don't have slots for ISA cards though, so you must be running a pretty old machine. If you have a PCI sound card, you probably don't have an OPL chip. However, there are some exceptions to this. The following cards are known to include "legacy" OPL support: * C-Media CMI8738 (*) * Forte Media FM801 * Cards based on the Yamaha YMF724 (*) Other cards that apparently have OPL support but have not been tested: * S3 SonicVibes * AZTech PCI 168 (AZT 3328 chipset) * ESS Solo-1 sound cards (ES1938, ES1946, ES1969 chipset) * Conexant Riptide Audio/Modem combo cards * Cards based on the Crystal Semiconductors CS4281 * Cards based on the Avance Logic ALS300 * Cards based on the Avance Logic ALS4000 If you desperately want hardware OPL music, you may be able to find one of these cards for sale cheap on eBay. For the cards listed above with (*) next to them, OPL support is disabled by default and must be explictly enabled in software. If your machine is not a PC, you don't have an OPL chip, and you will have to use the software OPL. === Operating System support === If you're certain that you have a sound card with hardware OPL, you may need to take extra steps to configure your operating system to allow access to it. To do hardware OPL, Chocolate Doom must access the chip directly, which is usually not possible in modern operating systems unless you are running as the superuser (root/Administrator). === Windows 9x === If you're running Windows 95, 98 or Me, there is no need to configure anything. Windows allows direct access to the OPL chip. You can confirm that hardware OPL is working by checking for this message in stdout.txt: OPL_Init: Using driver 'Win32'. === Windows NT (including 2000, XP and later) === If you're running an NT-based system, it is not possible to directly access the OPL chip, even when running as Administrator. Fortunately, it is possible to use the "ioperm.sys" driver developed for Cygwin: http://openwince.sourceforge.net/ioperm/ It is not necessary to have Cygwin installed to use this. Copy the ioperm.sys file into the same directory as the Chocolate Doom executable and it should be automatically loaded. You can confirm that hardware OPL is working by checking for this message in stdout.txt: OPL_Init: Using driver 'Win32'. === Linux === If you are using a system based on the Linux kernel, you can access the OPL chip directly, but you must be running as root. You can confirm that hardware OPL is working, by checking for this message on startup: OPL_Init: Using driver 'Linux'. If you are using one of the PCI cards in the list above with a (*) next to it, you may need to manually enable FM legacy support. Add the following to your /etc/modprobe.conf file to do this: options snd-ymfpci fm_port=0x388 options snd-cmipci fm_port=0x388 === OpenBSD/NetBSD === You must be running as root to access the hardware OPL directly. You can confirm that hardware OPL is working by checking for this message on startup: OPL_Init: Using driver 'OpenBSD'. There is no native OPL backend for FreeBSD yet. Sorry! == Other options == If you have some other favorite MIDI playback option that isn't listed above, you can set a hook to invoke an external command for MIDI playback using the 'snd_musiccmd' configuration file option. For example, set: snd_musiccmd "aplaymidi -p 128:0" in your chocolate-doom.cfg file. # vim: set tw=70: chocolate-doom-chocolate-doom-2.2.1/README.Strife000066400000000000000000000116701257432200600214250ustar00rootroot00000000000000=============================================================================== Samuel 'Kaiser' Villarreal and James 'Quasar' Haley Present C H O C O L A T E ______________________________._________________________ / _____/\__ ___/\______ \ \_ _____/\_ _____/ \_____ \ | | | _/ || __) | __)_ / \ | | | | \ || \ | \ /_______ / |____| |____|_ /___|\___ / /_______ / \/ \/ \/ \/ =============================================================================== * What is it? * Chocolate Strife is the most accurate and complete recreation of Rogue Entertainment's "Strife: Quest for the Sigil." It was created through more than four years of reverse engineering effort with the blessings of the original programmers of the game. * Why? * The source code for Strife was lost, which means, unlike the code for all the other commercial DOOM-engine games, it cannot be released. The only access we have to the code is the binary executable file. Tools such as IDA Pro have been employed to disassemble and decompile the executable, which was cross- referenced against the Linux DOOM and DOS Heretic sources and painstakingly combed over multiple times, instruction-by-instruction, to ensure that the resulting Chocolate Doom-based executable is as close as possible to the original. * Is it Legal? * Chocolate Strife was originally reverse-engineered from the DOS Strife binaries. Although reverse engineering is legally a protected activity, this nonetheless left some open questions about its legal status. In 2014, a new commercial release of Strife was published (Strife: Veteran Edition) based on the Chocolate Strife code, and developed by the authors of Chocolate Strife under commercial license. The release of Strife: Veteran Edition, along with its GPL-licensed source code, constitutes tacit approval for the legal status of Chocolate Strife by its current copyright holder. * Is it Perfect? * Almost, but not entirely! That's where you come in. Help us by reporting any discrepancies you may notice between this executable and the vanilla DOS program! However, do *not* report any glitch that you can replicate in the vanilla EXE as a bug. The point of Chocolate Strife, like Chocolate Doom before it, is to be as bug-compatible with the original game as possible. Also be aware that some glitches are impossible to compatibly recreate, and wherever this is the case, Chocolate Strife has erred on the side of not crashing the program, for example by initializing pointers to NULL rather than using them without setting a value first. * What are some known problems? * - The demo version is *not* supported, and there are not any current plans to support it in the future, due to the vast number of differences (the demo version of Strife is based on a much earlier beta version of Rogue's codebase). You should use a commercial Strife IWAD file, preferably of version 1.2 or later. * How do I use it? * From the Run box or a command line, issue a command to Chocolate Strife just like you would run Chocolate Doom. Most of the same command line parameters are supported. voices.wad will be read from the same directory as the IWAD, if it can be found. If it is not found, then voices will be disabled just as would happen with the vanilla executable. Do not add voices.wad using -file, as that is redundant and unnecessary. Some new command-line parameters in Chocolate Strife include the following: -nograph Disables the graphical introduction sequence. -devparm implies this. -novoice Disables voices even if voices.wad can be found. -work Enables Rogue's playtesting mode. Automatic godmode, and pressing the inventory drop key will toggle noclipping. -flip Flips player gun graphics. This is buggy, however, because it does not reverse the graphics' x offsets (this is an accurate emulation of the vanilla engine's behavior). -random Randomizes the timing and location of item respawns in deathmatch, when item respawning is enabled. * Copyright * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. See the "COPYING" file for the full license text. The source code for this program is available from the same location where you downloaded this package. Aside from Chocolate Doom, portions of the code are derived from the Eternity Engine, Copyright 2011 Team Eternity, as published under the GNU GPL. chocolate-doom-chocolate-doom-2.2.1/TODO000066400000000000000000000033771257432200600200070ustar00rootroot00000000000000To do: * Multiplayer: - Use UPnP to automatically configure port forwarding for NATted networks. - Multiplayer options and configuration file (server name, etc) * Improve multiplayer startup: - Select an IWAD automatically from the server's game type rather than all players having to specify -iwad. - Send list of WADs to load instead of all clients having to specify -file. - Same applies to dehacked patches and wad merging parameters. * Portability improvements: - Test on and fix for architectures where ((-2) >> 1) != -1 - Use size-specific types (eg. int32_t instead of int) - Don't make structure packing assumptions when loading levels. - Port to every OS and architecture under the sun Heretic/Hexen: * Frequency shifted sounds. * Check for endianness assumptions - mostly done now * Structure packing macros for structures read from disk * Merge r_draw.c to common version and delete duplicate * Heretic v1.2 emulation (if possible) * Hexen v1.0 emulation (if possible/necessary) * Screensaver mode Crazy pie in the sky ideas: * Automatic WAD installer - download and run TCs from a list automatically (automating the current "instructions on wiki" system). * Textscreen interface to the Compet-N database: menu driven system to automatically download and play speedruns. * DWANGO-like interface for finding players and setting up games. * Video capture mode? == OPL TODO list == Needs research: * Strategy when no more voices are available is still wrong * Scale levels don't exactly match Vanilla (off-by-one?) Bad MIDIs: * doom2.wad MAP01 * gothicdm MAP05 * tnt.wad MAP30 * Alien Vendetta (title screen, MAP01, etc) Other tasks: * Get a better software OPL emulator * DMXOPTIONS opl3/phase option support. # vim: tw=70 chocolate-doom-chocolate-doom-2.2.1/acinclude.m4000066400000000000000000000016361257432200600215040ustar00rootroot00000000000000 dnl dnl SDL workaround autoconf macros, by Simon Howard. dnl I release the contents of this file to the public domain. dnl dnl Macro to check if autoconf's compile tests have been broken by dnl SDL. Tries to build the simplest possible program, and if it dnl fails, calls the given block. AC_DEFUN([AC_CHECK_SDL_BREAKAGE], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])], [], [ $1 ]) ]) dnl Macro to work around SDL redefining main. The provided block dnl is run with main #defined to SDL_main via a compiler switch dnl if autoconf tests are found to be broken. AC_DEFUN([AC_SDL_MAIN_WORKAROUND], [ sdl_workaround_saved_CFLAGS="$CFLAGS" AC_CHECK_SDL_BREAKAGE([ CFLAGS="$CFLAGS -Dmain=SDL_main" ]) AC_CHECK_SDL_BREAKAGE([ AC_MSG_ERROR([Autoconf checks broken by SDL, and can't figure out how to fix them.]) ]) $1 CFLAGS="$sdl_workaround_saved_CFLAGS" ]) chocolate-doom-chocolate-doom-2.2.1/autogen.sh000077500000000000000000000000531257432200600213040ustar00rootroot00000000000000#!/bin/sh autoreconf -fi ./configure "$@" chocolate-doom-chocolate-doom-2.2.1/codeblocks/000077500000000000000000000000001257432200600214155ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/codeblocks/README000066400000000000000000000001751257432200600223000ustar00rootroot00000000000000 This is a set of codeblocks project files for building chocolate doom under Windows. Thanks to Russell Rice for these :-) chocolate-doom-chocolate-doom-2.2.1/codeblocks/chocolate.workspace000066400000000000000000000021011257432200600252700ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/config.h000066400000000000000000000016751257432200600230440ustar00rootroot00000000000000 /* Name of package */ #define PACKAGE "chocolate-doom" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "fraggle@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "Chocolate Doom" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "Chocolate Doom 2.2.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "chocolate-doom" /* Define to the version of this package. */ #define PACKAGE_VERSION "2.2.1" /* Change this when you create your awesome forked version */ #define PROGRAM_PREFIX "chocolate-" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "2.2.1" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ /* #undef WORDS_BIGENDIAN */ chocolate-doom-chocolate-doom-2.2.1/codeblocks/doom.cbp000066400000000000000000000365461257432200600230570ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/game-res.rc000066400000000000000000000007661257432200600234540ustar00rootroot000000000000001 ICON "../data/doom.ico" 1 VERSIONINFO PRODUCTVERSION 2,2,1,0 FILEVERSION 2,2,1,0 FILETYPE 1 { BLOCK "StringFileInfo" { BLOCK "040904E4" { VALUE "FileVersion", "2.2.1" VALUE "FileDescription", "2.2.1" VALUE "InternalName", "Chocolate Doom" VALUE "CompanyName", "Chocolate Doom" VALUE "LegalCopyright", "GNU General Public License" VALUE "ProductName", "Chocolate Doom" VALUE "ProductVersion", "2.2.1" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x409, 1252 } } chocolate-doom-chocolate-doom-2.2.1/codeblocks/heretic.cbp000066400000000000000000000323121257432200600235270ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/hexen.cbp000066400000000000000000000322221257432200600232130ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/libopl.cbp000066400000000000000000000043241257432200600233670ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/libpcsound.cbp000066400000000000000000000033531257432200600242510ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/libtextscreen.cbp000066400000000000000000000104601257432200600247570ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/server.cbp000066400000000000000000000062511257432200600234150ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/setup-res.rc000066400000000000000000000010151257432200600236670ustar00rootroot000000000000001 ICON "../data/setup.ico" 1 VERSIONINFO PRODUCTVERSION 2,2,1,0 FILEVERSION 2,2,1,0 FILETYPE 1 { BLOCK "StringFileInfo" { BLOCK "040904E4" { VALUE "FileVersion", "2.2.1" VALUE "FileDescription", "Chocolate Doom Setup" VALUE "InternalName", "chocolate-setup" VALUE "CompanyName", "Chocolate Doom" VALUE "LegalCopyright", "GNU General Public License" VALUE "ProductName", "Chocolate Doom Setup" VALUE "ProductVersion", "2.2.1" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x409, 1252 } } chocolate-doom-chocolate-doom-2.2.1/codeblocks/setup.cbp000066400000000000000000000133211257432200600232430ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/codeblocks/strife.cbp000066400000000000000000000372231257432200600234060ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/configure.ac000066400000000000000000000116221257432200600215750ustar00rootroot00000000000000AC_INIT(Chocolate Doom, 2.2.1, fraggle@gmail.com, chocolate-doom) PACKAGE_SHORTNAME=${PACKAGE_NAME% Doom} PACKAGE_SHORTDESC="Conservative source port" PACKAGE_COPYRIGHT="Copyright (C) 1993-2015" PACKAGE_LICENSE="GNU General Public License, version 2" PACKAGE_MAINTAINER="Simon Howard" PACKAGE_URL="http://www.chocolate-doom.org/" PACKAGE_ISSUES="https://github.com/chocolate-doom/chocolate-doom/issues" AC_CONFIG_AUX_DIR(autotools) orig_CFLAGS="$CFLAGS" AC_PROG_CC AC_PROG_RANLIB AC_CHECK_PROG(HAVE_PYTHON, python, true, false) OPT_LEVEL=2 # Engine room, we need more speed! AC_ARG_ENABLE(penis-extension, [ --enable-penis-extension Enable counterproductive compiler optimisations ], [ OPT_LEVEL=3 ]) # If this is gcc, we have some options we'd like to turn on. Turn on # optimisation and debugging symbols. if test "$GCC" = "yes" then WARNINGS="-Wall -Wdeclaration-after-statement -Wredundant-decls" CFLAGS="-O$OPT_LEVEL -g $WARNINGS $orig_CFLAGS" fi dnl Search for SDL ... AM_PATH_SDL(1.1.3) # Add the SDL compiler flags to the default compiler flag variables. # It is important to do this now, before checking for headers and # library functions. The reason being that on Windows, sdl-config # sets the -mno-cygwin compiler option in order to generate MinGW # executables. If we don't do this now, we might end up discovering # header files that are not actually available to us when we come # to compile. CFLAGS="$CFLAGS $SDL_CFLAGS" LDFLAGS="$LDFLAGS $SDL_LIBS" # On some platforms, SDL renames main() to SDL_main() using a #define, # so that its own main, stored in the SDLmain library, can be run first. # Unfortunately, this causes problems for autoconf, which builds # test programs to probe the system. All library/header/symbol checks # must be run in this block, that performs a workaround for the problem. AC_SDL_MAIN_WORKAROUND([ # Check for SDL_mixer. AC_CHECK_LIB(SDL_mixer,Mix_LoadMUS,[ SDLMIXER_LIBS="$SDLMIXER_LIBS -lSDL_mixer" ],[ echo "*** Could not find SDL_mixer. Please install it." exit -1 ]) # Check for SDL_net. AC_CHECK_LIB(SDL_net,SDLNet_UDP_Send,[ SDLNET_LIBS="$SDLNET_LIBS -lSDL_net" ],[ echo "*** Could not find SDL_net. Please install it." exit -1 ]) # Check for libsamplerate. AC_ARG_WITH([libsamplerate], AS_HELP_STRING([--without-libsamplerate], [Build without libsamplerate @<:@default=check@:>@]), [], [ AC_CHECK_LIB(samplerate, src_new) ]) # Check for libpng. AC_ARG_WITH([libpng], AS_HELP_STRING([--without-libpng], [Build without libpng @<:@default=check@:>@]), [], [ AC_CHECK_LIB(z, zlibVersion) AC_CHECK_LIB(png, png_get_io_ptr) ]) AC_CHECK_LIB(m, log) AC_CHECK_HEADERS([linux/kd.h dev/isa/spkrio.h dev/speaker/speaker.h]) AC_CHECK_FUNCS(mmap ioperm) # OpenBSD I/O i386 library for I/O port access. # (64 bit has the same thing with a different name!) AC_CHECK_LIB(i386, i386_iopl) AC_CHECK_LIB(amd64, amd64_iopl) ]) case $host in *cygwin* | *mingw* ) AC_CHECK_TOOL(WINDRES, windres, ) ;; *) WINDRES= ;; esac AC_CHECK_TOOL(STRIP, strip, ) AM_CONDITIONAL(HAVE_WINDRES, test "$WINDRES" != "") AM_CONDITIONAL(HAVE_PYTHON, $HAVE_PYTHON) dnl Automake v1.8.0 is required, please upgrade! AM_INIT_AUTOMAKE([1.8.0 foreign]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) WINDOWS_RC_VERSION=`echo $PACKAGE_VERSION | sed 's/-.*//; s/\./, /g; s/$/, 0/'` # This controls the prefix added to the start of program names. For example, # if this is changed to "lemon-", the programs generated will be named # lemon-doom, lemon-heretic, etc. PROGRAM_PREFIX=chocolate- AC_SUBST(PROGRAM_PREFIX) AC_DEFINE_UNQUOTED(PROGRAM_PREFIX, "$PROGRAM_PREFIX", Change this when you create your awesome forked version) AM_CONFIG_HEADER(config.h:config.hin) AC_SUBST(WINDOWS_RC_VERSION) AC_SUBST(SDLMIXER_CFLAGS) AC_SUBST(SDLMIXER_LIBS) AC_SUBST(SDLNET_CFLAGS) AC_SUBST(SDLNET_LIBS) AC_SUBST(ac_aux_dir) AC_SUBST(PACKAGE_SHORTNAME) AC_SUBST(PACKAGE_SHORTDESC) AC_SUBST(PACKAGE_COPYRIGHT) AC_SUBST(PACKAGE_LICENSE) AC_SUBST(PACKAGE_MAINTAINER) AC_SUBST(PACKAGE_URL) AC_SUBST(PACKAGE_ISSUES) dnl Shut up the datarootdir warnings. AC_DEFUN([AC_DATAROOTDIR_CHECKED]) AC_OUTPUT([ Makefile man/Makefile opl/Makefile opl/examples/Makefile pcsound/Makefile pkg/Makefile pkg/config.make pkg/osx/Info-gnustep.plist pkg/osx/Info.plist rpm.spec data/Makefile src/Makefile src/doom.appdata.xml src/doom.desktop src/doom-screensaver.desktop src/doom/Makefile src/heretic.appdata.xml src/heretic.desktop src/heretic/Makefile src/hexen.appdata.xml src/hexen.desktop src/hexen/Makefile src/resource.rc src/setup-res.rc src/setup/Makefile src/setup/setup.desktop src/setup/setup-manifest.xml src/strife.appdata.xml src/strife.desktop src/strife/Makefile textscreen/Makefile textscreen/examples/Makefile ]) chocolate-doom-chocolate-doom-2.2.1/data/000077500000000000000000000000001257432200600202165ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/data/.gitignore000066400000000000000000000000541257432200600222050ustar00rootroot00000000000000Makefile.in Makefile *-doom.png *-setup.png chocolate-doom-chocolate-doom-2.2.1/data/Makefile.am000066400000000000000000000010201257432200600222430ustar00rootroot00000000000000 EXTRA_DIST= \ README \ doom.ico \ doom8.ico \ doom.png \ setup.ico \ setup8.ico \ setup.png \ convert-icon iconsdir = $(prefix)/share/icons icons_DATA = @PROGRAM_PREFIX@doom.png \ @PROGRAM_PREFIX@setup.png @PROGRAM_PREFIX@doom.png : doom.png cp $(top_srcdir)/data/doom.png $@ @PROGRAM_PREFIX@setup.png : setup.png cp $(top_srcdir)/data/setup.png $@ CLEANFILES = $(icons_DATA) chocolate-doom-chocolate-doom-2.2.1/data/README000066400000000000000000000013231257432200600210750ustar00rootroot00000000000000The Chocolate Doom icon is based on an image by Chris Metcalf (http://www.chrismetcalf.org/) which is copyrighted to him: http://www.flickr.com/photos/laffy4k/448920776/ Chris has kindly agreed that the Chocolate Doom icon may be used under the GNU GPL, so the copyright status of the icon is the same as that of the rest of the project. The "foo8.ico" files are 8-bit depth only, while the "foo.ico" files contain full 32-bit versions, scaled to different sizes and with proper alpha masks (as well as the 8-bit versions). The 8-bit versions are used when setting the icon within SDL, as SDL under Windows displays full color icons in a very poor quality. The full-color versions are used in the resource files. chocolate-doom-chocolate-doom-2.2.1/data/convert-icon000077500000000000000000000035451257432200600225610ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright(C) 2005-2014 Simon Howard # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # # Converts images into C structures to be inserted in programs # import sys import os import re try: import Image except ImportError: print("WARNING: Could not update %s. Please install the Python Imaging library." % sys.argv[2]) sys.exit(0) def convert_image(filename, output_filename): im = Image.open(filename).convert("RGB") outfile = open(output_filename, "w") size = im.size struct_name = os.path.basename(output_filename) struct_name = re.sub(re.compile("\\..*$"), "", struct_name) struct_name = re.sub(re.compile("\W"), "_", struct_name) outfile.write("static int %s_w = %i;\n" % (struct_name, size[0])) outfile.write("static int %s_h = %i;\n" % (struct_name, size[1])) outfile.write("\n") outfile.write("static unsigned char %s_data[] = {\n" % (struct_name)) elements_on_line = 0 outfile.write(" ") for y in range(size[1]): for x in range(size[0]): val = im.getpixel((x, y)) outfile.write("0x%02x,0x%02x,0x%02x, " % val) elements_on_line += 1 if elements_on_line >= 4: elements_on_line = 0 outfile.write("\n") outfile.write(" ") outfile.write("\n") outfile.write("};\n") convert_image(sys.argv[1], sys.argv[2]) chocolate-doom-chocolate-doom-2.2.1/data/doom.ico000066400000000000000000001075661257432200600216670ustar00rootroot00000000000000 f@@ (B 00 %6K  p  h( @2:07 )24485:.)6 5$/0-9#86(>H& B(R4H-$O5$_B"^E,mO'mN0fR7kR2dU?z\6x^>BHIR+I/K0B1I1N>M .R'T,_6T4]%5K" U+%Y0+S!5Q :S 8W(0]%?Y"8\'?^8c'>c$4i+>oB5FCNKWMZQ_"DY"B]*N_DfLdUd[j$@f&Ee&Bi)El/Gl Jm!Xg,Vi-Gt%Mv,Ip*Lu+Ky-N|0Mu.Rv%Yt-Px/P"Y.Y~*\|8U~ ev#f~'l~MDYRPaY]k\gqdiwdn~X'U3T5V1X5[9Z7^>_8]cw,f#o=`2m&r'q*v&y!n"m:`X1qQq֭{̤bբ̆˽|c~dcc}k^^^^^R{|zGPGGGR}cbx`++v+++Fbc~|d||V 8bJJQ@@;uwu5dB*QBACIB|~;uwu 5ULLoЌȒϜf,7=smoj\pY4&Ue"!3-ϋm]npVp9:YV\]?7  ӺyWoo]V4m. қyU6NK4a2ƛƐ]rY] %#Ѝ\җK܎$ym 1əɚ1tpppp00000?0s(@ //j{E51(l7;K<7?6;.s/ E7~92ES@4)w'o.)v-/+qD   ' _>8K:)t'p43C8B9A4T$ :k|G+! 1).~A5-.;SP<8:4284 f+3mKH0 :@K76?I>0.6'p-~10|80!&2 GgaZ b<"CB;?4/6)q<B=@*hzH (^fOOOPaX d<" $V4B<2)u-s>MWKJ:=>C4Q!  (^fOOOOOYd&FQG)  * cO:*w4KPA1.7)t*t@//,v['  )_fMMMMMMQeAyR2 1',|K7F<.)v)u62uCKXCOHC l- ) `dHHHHHHHI]X d<!9(T`H?&m$g{4DVJG;;*t4363.64 ) `cCCCCCCCCCQb%DOF) C(We?/4K<,y,}:(oYj:)i|6=>3EQ< ) ab??????????DbAxR2  "Q(i{/=5*v0(p'm:@RLHHJ>K+j|D * aa99999999999;WW c;!- k8253$cu?AI77*x,~1+|922)nL  * b_5555555555555Ga$DN}D%:!GQ775><31YiYj2&dv0p8CILG7U$  * c^0z0z0z0z0z0z0z0z0z0z0z0z0z0z8_BzE! H1s9+y+v6'pQ`-{3ACGC:=:;95`)  * c\+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o-qQW5 &W41"as$h|$dw7?>0%i}'p,z)t.'m+|66/!w/ +d[&e&e&e&e&e%h&e&e&e&e&e&e&e&e&e&eaE0',xH%k- [l#`r1"cu$gz-|Xi$ex5;EKWMHI(}U{OuOuOuOuOuOuOu_P F:x0/Ue*u&nXh1+x'pVfN\'qYjO^.2~<@?(_oC+ gUDiDiDiDiEi==4aDiDiDiDiDiEj_P &T60.(qTd"`r"asXiSc \m(r&l+{091?==>1zL , hQ9]9]9]9]:^:::9=a9]9]9]9]:^_O ;i2&m.)tJX&lYj"at%j~(s'p[lP`"cv!^p%i})w&n/3-xU$ , iM/R/R/R/R0S7777 1T/R/R/R/R0S\N !<^!&16#dv#dw(qIV*2P_DPER [mGTBO"as [l'n.24;=a* ,#kH $F $F $F $F %G4{4{4{4{ $F $F $F $F $F 'IYN  <3R|"4K'br&m0O]&lHV9D/7HUIWP_ ]nRaYj!_p [l"`s&n!_q%j~$gz*yu0,%lC::::<}1t1t1t1t|:::::@UM,&6n8]'5I+m*xP`$fz6?$=IXi!_qZk?K1;@L09Rb#exZkZkKY \n#fy*w6@7-(m?v11113 y.m.m.m.mu111119QL<3Ln,Jt 0F9C ]n&Zt&Db+Cd1L/Nz(F]0>DX1;5?XhWgP`Sc"buUe \nVf#cv+z!Q_?-*n $+AMERFS:DYi#exMZI --o9i00003 p(`~(`~(`~(`~g00000a+'6FHV+3M\ZkO^P`%k)u%dvZ- ./p6b00004 k%Zv%Zv%Zv%Zva00000>ExJ E(=[9^.Mw/P}0Q~5Y_Bk,Ir%?b'Bg%:)@,E(Dj&@d3P.H3J+=(5(,C":[)Gg!C]!J^wK+01r3\00006 f"So"So"So"So[00000AApJ,)6Ht_Cg1SGp?fGlUpqIg.Jq'@a'Ch4X3W4Y9`=g>h9`)El"5&;'Ci$=`4T(Dj5W$0*=_1#43t^u]:u]:u]:u]:q^A aMgMgMgMg2fs\:s\:s[:r[:r[:obMFyI8Tk_5Y>b,Ip/OzHcNp)@(>&@d-Mx0R3U3V1R3U6\6\7]:c9`#<^/I&Ae/P}7\;a0J'Bg<` -b095vce8e8e8e8e@ [F_F_F_F_9ee8e8d8d8d7~kMDvI?qaP{8X'<,E./Fd?b.O{0R/P|.Nz-Mx-Lw,Lv2T2T2U5Z5Z8^8`/P~)Fn4Y3O0K%@d/I@k*Bc8<7x`}^3}^3}^3}^3w^= V@X@X@X@X;a}^3}^3}^3}^3}^3wdKApH>}uNrW}'Bg&;-7Y.Nz1T.Ny,Ku+Is-Mx.My0Q~:b:b9`8_8_:c8^%?c1M-Jr3R|'Af1RCo*t9<9x]zwX/wX/wX/wW/pX:Q9P9P9P9P=]vW/vW/vW/vW/vW/q^I>kG5V_lkQs'Ad)@ 'Bh*Go1L-G+D!7V&@d:b6[:bBoCq@k?i@k;c5Z#;\%?b(Ad2S6Z@f[4: ;yZspQ+pQ+pQ*pP*jQ8K3H3H3H3K>XoP*oP*oP*oP*oP*jXFi;d5Z0Q}5Y5YX}7U~P/9 =zWliJ&iJ&iJ&iJ&cK5F,A,A,A.G>SiI&iI&iI&iI&iI&dRD9`F 'WRiPkqB_'3V1S-Mx+Ir,Ku2U0R3V9aCq\hnqrQ~Gs;d:aP{Fn]$4KO2<!>|SecC!cC!cC!bC!\E3@ &9 &9 &9)D?MbC!bC!bC!bC!bC!^LB7[F,^2E`Vo8NnldAcYldWubFqAk9aKw7^6\Gp`wc[VGtV\ aBF!BO_\<\<\<\<V>1: 2 2 2$A>G[<[<[<[<[<WF@5VE= 1H4T"9Y%; 5S,IrXxi`vkZDq=f;Z5T~Gp]R}GnX+Ho,Iq<]#7R+Eh.Jo dX!DKWU5U5U5U5P8/5*** ?=B~U5U5U5T5T5Q@>3RE & W<]5T2M4S}-Mx,'=Pih{vIq3W!8X#7TyZrk<_)BfQqLtoT~Mv*Gn'=(?.G$9,E4Xb9[#7!3,.H:Z;aOyIu8](Dj+Js5S/ 6T5Z?iFdxCCI~H(G(G(G(D++)~  ,-<3_G'G'G'G'G'E4:.HC>i]AdNs0Q~* -3W1S1S0Q~1S2U3W:aNt2N'Ae)El!9Y&@d>d9]+Ir)El5Z&)&z #%w14<'5@! @! @! @ @ @ @.9,CB?oڅdTwEi;a&?c#;].O{2T2T0Q0Q~+Hq/P}5Z5Z3U-Kv&@d&Af,F*%;/Nw3VW{AlU~`_GsWt J;;r::::8 ''6.37#9:::::::::)7*??8lujAcKsFp.O{1S-Lv0Q~8_1S6\5Z4W3V1S;`"9Z#;[%:(?!3+B$=_cNvfW{VDkEp]z} O64k333331=33333333334#5)=7) _txy~tuVt+Gn/P~5Y1S*Hp,Jt+Ir'Ch@d*Fn*Hp/I$<^ 6U0K%(AcQ|?eSx~>e4F_u U3.f00000000000000014;$4+:bo}if=`ImfZ=b&Ae#;\9]@e(Dj$=`)Fm0Q(Ci "#7JuKqz'6m [2+b00000000000000 2/q->Sz9  A$v鐬X|eHl3V8\Tyfp4U%?c'Ch6Z.Nz/O|6[2U2U "9YLx\kibf a1']0000000000000%V.:$lS5 "B4>Ko{hMpJi-Eg/Ny6WpwjiWz-Lv0Q4W5Z?i1R!41RNzcdHps`f0%Z00000000000;.5) _?( #GDN\]T|X4U(Bf.Mx8[__?f4XIq@i-Lv#:[\Dll,=UHM$v0"O000000&_+7aS8"  4+/5fMli9[;Stnu-.KtZZvS8F&{0!K0000 D.6&}[='  /NJTcy6\m8Rt 6Ug"o9)>(0!G00+/3".gC+ &Akʐ}[Ae1SGl]HhhXmA"3!,0%[0.'3 7vI0:dݡOsa5:AF$$%1,;`{K5!  @,7Gzh~{f5T~5YY-:KG% T60-! 'Rg~j+Ir?TpG^~/Jp)El/J0KBYxMiWwihkL'  6BRhEm/O|/Ozv{M* ?9EUxNvs􎛬P[i [@' < _x8@M?GS/7AFQaWI9) / C?GScK@82-&   xxppp?000000?0????(0` ,brB3.u9A:689*k} 188A@0.3y237,o. #" M?3-5PD::381> "j!;CX,(/h58D?+2+x1280U;g_.Uc>  ._m>41?7@?<>89-3nIdN]M Q$%:iv89A59 \m.4@<;AL NeMOT\ c/*%ZjA8-/uARKD9;?#Yi'NeMNNQd,R_=  5;x:8<=1-|:9C@:(aq0 PdIJJJJZLN$D;267)m< PaACCCCCL_d-S517D+z*{2#^o;1x>=+rKQ_;>>>>>=>^1\j=  %+p080,x5:;A<;@66 YR]466666667MMM"  .#OZ85=84![k)r%fy/s;FI> &gSZ.x0{0{0{0{0{0{0{0{1|:]5<_!=3~1(p2!`q,y5@E?8796)0x#SW'h*m*m)n)m*m*m*m*m*m)l-qV3:IV>'t!as$dw41+z[m-~29AB?DO)TU Z#_#_u~!c#]#_#_#_#_"^B6>^!!HT6'r'p"at,|(l563)p1335!Ud0 VRKqPvPvp8"cNtPvPvPvOv?29c ,8s/&k'm$i|&m*v$h|N]%n [l&j~3>A-m8WN1|*y-M\$h{ \n ]o%k~&n#ey+y,z3170~BXI -Q4W3V_58;#1T3W4W2V7r29a4k.2"dv'oHU?KJWL[Td@M"at"bu,}17=OZBA %H $FU~2}4|5{# A %G %H $G2g/8a53Q{%J]%k+yZkER7A?JKYP_TcSc ]n \n$j~Zk"dw(w i \L$j{ Rf$Jb$2&IeL\O`3;>JCPTe!asXiTd ^p*y5?ERFSHU#fyEQ+  ^3a (/.Bs'd(a)`|l )//0'N|%5]H@d=c2U.Nz9_.N{$=_%?c*Ek"9Y#:['0ACQ7CScJZ!Zn(o"[k@  `/X (//?r$[|$Xt%Xrc )//0$H{"4\ *:Qs@e.Ny:`;a_Pr,Gm%>_6U%?c/P}0Q-Kw*Fl)=(!8Y*Ci$?_(JjD #cGk82-965954+Ot Rs Pk Ng#`92.855745856@Z~ 3[ D\~:^;_/O{GeKk*@$=_,Lv1S3W1S5Z7^7^7^";]1L*Hp5Y8\2N8Y L, fic1e8e8OauIiG`E\0ae2d8d8d9ds3Z#)1RoY4R{,D*.Ed9]0S.O{-Lx,Kv,Lv2T2U5Z6[9b/P-Ny 7V3P6U=f#7R1#id~}Z*{\2|\2JZqA`>V_E- +j[kkIjK&jK'AKj0M-B+@6PlI jJ&jJ&iK)Q[v /W -1?RMhKk(>=b9Z1Ow3U2U4X=hUdmvQ~Cn;cS~X+=WG2 .mUab?aA `B!=Cg 'C $7 $97HbA`A `A `B#LTt /V;$8T=Uw"3MGdLointT~Ht;d4VChhZZ>eGkUu!2J*?E 5yOXY6X8X88;c 9-26AY7X8W8W9FLq .U"b7X2N0Nw4S!2XkX6X/EVw`zX},IqRt\XIq#:Z)@/J(?/P|:a 3L 6KOyO- O0O043_0#*59wP.O/O/N0@Em -T +KcaBd9W.I 4V6[.Nz/Q:]3T 2.2O6XJsDo.Nz-Mx6U*B4XFn*i +R 2u}KnHn%@d!5#<]3V/P~/P}.N{2W9`5T'Bf'Bh*C&?b4V7W:bIrJnHtg:Ld :>;i== = -*g"m,'_;%6=<=== 56g +P .wɇj<_Dn+Lx,N}-Mx7]0R5Z4X3V6Z$=`!8W#801KHeNvfW~AiKuBSiA71`333192443333400b /H 17?j{{|rqHe:YEg4U-Kv(El3S}/Ny(Ek6T#;]-G!4Lu?ek?d#K3*Y/ /////////0 0 <,9 #3  3`kyiNrCg_y]%Ag$?d/-0)D(/'(+m祼ahX{~Xi 9!-.0!* 'W+ /.8Fue4UU~7CR8e=GC. ?fMp2Ii9Sv+Hq#8U*>ZJd\{to:  "8DTrq ( V׹i{\dqT]iOXd%(,] @& 2!'0Q90(" p?``````?    ?8??( @ #O[s8?9422Q_z 1u9.B<;:%`qT% %6;;,y9<;/s/aV@.A4?8,38/z(:]N\7=f9B/>AD2:44;\NMYAx)  \D21A?E>?N!Sa>K222220}EAy!06$gz-~2384.6$bs?D(j(i%o(i(j(j(i0uJ #]4'r*u"as/15C=1|!@>TzPv%uQwTzTzOvK)Xe/"as _p&l!at$h|)o5?8*A6u>b:^-;!;`>b8]L2#^o+y#exLZZk"buFT ]n(s.88C-a )L $F+5~+ $E )L#FI3/Fk*t!bt?I>IVfGTDQ ^p!`rXh&o UE#Kv4.)|/p(z-41Dx+A`%>`"Ld%Dd$<]-Jq$Dd;MIV;FO^JX$h|3;{FAp/ )&q)c$l (/.=k$/Kq4X.N{Ci%@e!9Y4P 5T'92@=J@U&\u9D'H6m /*$e#Vr^( / 17\ '1>[Ov:^BeMg+De*Hp5Z5Y+W `nk9W&=0Ko0S.O{,Lw-My5Z5[9a,Lw&@d&?c4X$Y Qmorz[0{[0G~^?^C+"A1H&@e#<^"7SEad|i7]De\Ag*Aa#;\$<]1PznOERQ2R3 #Z$".aR0Q1P6%;~ pKq9Y#88^0Q4W4T%:%?ad+Kw-O}3V/Q~4W2U,Ir2O+&BgW}bKva8(;66 /*q766660|u ]izvhcgq5Y#=_<`"<](Dj$85USwHc ,23//////0-0z ;>CLYgIl:YPrGi1R~0Q7]3P:`m~7Rw a_rLs+Cd Iw0)000/#V(7/ɏxY|Xs/Nw[x0K^OVq0%/ 0>$* I 'KWhVxGoobSd{#jg1 C()z ?`" 19D{FoHR_" g?'l')v)Ht9U|Le^uvs&  @qҟʞu}L !3$ @@?@@@@?(0 %S`j9;63-z&,+NY 1v96:;4+32Z)KWI Z<7;075-5C/ZS0Xfl9C>2=B7908Y2YKTA & 7;449A@HT}3P@@EE%CKF"Q_h554.{3?(bs 3G3445A%c%s'h'e%d2vDyF -u&n%k&m*u0}?664tBg'*~X~InMrE{Q ?)r%jP`!`rQa#dw.7,8)Z $G&x6X~ ,N4VDzN 5,Kl%g{BQAQK[ERZkZk%k L:@i *"h.pCi2>?nK*Bd-Lu.Ry'Ag'Ad9U6E7BDS#_s3;{ <2c&[&^| 5_ -<7]J'Hl8[Hg0Il*Ho1T5[.P|5R.P{(Bc0GhEglnrV2(V}MhKX_mV6fZGKHMT]AmT4N914wCawV{2Py *0S.O~3V/J'Ae7Z1R-IpFl!('.v>cskW|IlLkLk,M{3T3P+E@``h$E4 /20/533 0&I"_,WdvX{Dc_^~3U,M{(Dk1SofG1(/00/.""^ < apt]4R|ud7Z_b?aNv0#0/ *"Y][& &r^}@\Ia~|Yc05):"gzITeV{N^sh=#l,b}=ZWomt$,A 7 .v|k;=>;#)2 A ?A AAAAAAAAAAAAAAAAAAAAAA(  #O\O8;6EQM,MU(*6/p;2:%]n}Y7i|g5~3B<,pRMF/|6/z;3|C76A 7;/Az -}+v3742v$q"c#^6u@J])v [l ^o(r8!Ot]2/R%Rq -,(QmE\!IbBPSc _q 2+QAh+q *6X6Ry8[;X(Ch*Go =X&Kk!9Q,BIT/Jb!V{?6/:GZf8Ru7V)Em7^Bm+Ku3TAo_LELU>axT'WTU&:VFaxLjIp]BhJ l'Ae$Do-P)Dk"9X9\?b:U~>&$, =/-=2(<k|ySse0P}+Kx#<^|%9_0/0+8!YRp<[h]|Lm Bk1 .+^ bp|xShM.&"_ Kfo|k}AAAAAAAAAAAAAAAAchocolate-doom-chocolate-doom-2.2.1/data/doom.png000066400000000000000000000162441257432200600216710ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYs B(xtIME, 7$IDATxݛywy?{>4eɒ-[m $Ef6L6RY)%-QJ*@V5mllɒ}4>~~zlW3|O ^X,W=V>?6X?Du ?8kZ6kǁ`{=8?=v= 5(gUK{`S@_0`^G>g(\s6 mloߵk##iꪐB@m= [{D~To-u 7A,-e*'O3Ͼzl_V Pn듿-(8o?λ|קʙE|රB E3ƚB*$7 IJ{ϧ/}?,F3E/ [}/~Wfb]ŗ0b.lM0MY\_GֺTF ֒;ZsǾݨ7^ cMwpynnqi:!p֩52U`kj<Cc1xm 5$0 h4 Ttӹ ΡVb .SJx` LP$*X%֚G#Dnjytk4 PU"bBN]Y62o7/\aiixS3i-X=8<_|!f~ښB*jav*uL%Us899L_{3T;?{|6ajh楩]=pf;[yog;/9ek&>E)ů@6:xCRei:\BURB}ci휝'_Tw{q}"0oGt$Q3;B/T*cynꗬHQ=4_PC%>>~\uv+ _r}36Z7H)i{6nBW_.rt"t FNedjۯ#:QX]TEJP)X6/R!EF@G3Kh `gKY ;:!] XJVmӏ:O=7tscƒ8 c*-NjqمE&l:K]z x(Bg9/UE|7ay UA4i1P:`*]r9}[vƙsxD)v#DUNƱ V$aE2ԝ$A(Նg8[ GH laQL4,#Z(@sڠ .W".+Ė+n MpmO(ST\3>|Dz]lGU!5Dkln-A br"S(c{~3ȩfn>zp, 䁐 C["0͗hz!芸 MQm:3:F9D1=<le?d0#  hm 2(Um|k(*QHgTeS:j3 ܔIJe_75& "TE}]z}߄]i}ӞLQ9ƶrnĉޤO2 kպ,Q=<_)(VmLd14EQI8wnDF]Ž0UtsHP@c:k"EWʀ{p1]r^ i )UjƲ=\%p!]FB%(FPw|N)X6qBlD5<ܙ85_"uS4$(ў6..Zj(굴 |ZDB)DžE?|R:K(lU| "||BFXA]Ex>bqum<vnMMܺdS0U4XSki|4aMW93S:;NeAK{OǗM4GM  l^ Ǔ[$]ѝ S:is"d*nya}/(AE5'((@5.IrYO8G׮wb1e>e.V ͐X|qS3,* DD7UNBP94'AP5=?[J5c5ni>JpN ` QGr\"]YY ?}4eHj{ !,mign(S:pl2l]Una>R*Z X\.i+Udӥz̏ ۸/?}߻;hyG&Hy\M}@H๑_ݳ"lȔk-'OR:%lMHӸҧ+@,0UgpF.H(@:f)`q(}_+Z%:do'%j@S&/iPE.N-hP!Q[,Yj;S, @KUg*ϸU e`PnL/8@qN  }`5Tc/%ZP&#RUd}AC:6[`MlIF 4Eʱ'T'Te`@RBA :ѰNS,H\#!q}肅8΀RiC1@bjxD#:Z C`%4K]O[lR.ָmGt֦Zsj[")[ܔtTEՐR21SlyRF$XMPՆ?ϡcSxcV U\JoPl쎲T+d%" uwْX|_ .VVKzY/)Ƶ@EѰmHxY!xE!*̜x}Nl pl CWQUAlk ©"MQ7'h! NqTEP,MWz4z99Af)_a" L-uLL~c$~TxTqA كHESa>SŶ˔%KuM]ma\ʕ:g'ks^ͺp=q]_ !W JFn.v׃Ma3:Qa T`ۖnUu1*MHQ !7ܙR"5U  0թ(lyK։F|Ԁo<Pj Z#tdg3!2HM%i*b%w5coRJTUdOcc,q r\w$soosE[u|±3E({Igެ0\:ZòH`!]M7X\HTU!ï$}c{j]k$s çg-@Cі2 Zz ) 曺P8.M+؅n8}B$tBQf:C0Zp_ /b3{no[̃ٶe(\t B8>2y39t(Bp<'G+Dɿ PU!#a~ ^O7, @qW;+QHăLx'lΎ$((ZChX4} E P 0̬+wGJ_f &WFe(0`H<4waUk켩zb~HٚannT%f0zpi4=ˎ> \7 \d~Ł`S?Cߚ[,3 ʯviZ%Wx~0WhEWcgIC :] !2][93zUWk+x2u` j>WO?,)Zb٥ƁXl/Idq8}snb]&֔S{w7(:Wo]4 HM_ _}'k3}%fZuX+]$Hz͢VϏҒ ?Uik6Ah+19kͮJP)WM@0~af_*^)^l^-Dz&bZ[<޵ !+-TX\*ъ따>R5} ,jʻf#c}O=  x)Zd; ݝ r j|ddDwGք¦߬rH"jArOT-~zzxs_y?yvYӯG8@G}]P -6]Ī8trx %] 'Ζ.\mB`c>_~B+S DlLT288{Jc^GU@5>SJ \ne|Űyv[R7vUS|aⲥ5e;*ZOwg| ’fPM AS%RK?9F.6vZs3tO婧ʗ5k~KMJR6O#j"3ٲJ9R |*}tntA/WvJ T NtIENDB`chocolate-doom-chocolate-doom-2.2.1/data/doom8.ico000066400000000000000000000042761257432200600217510ustar00rootroot00000000000000 ( @202:4 )74.)7855$:6 B/0H:H& I-9#8RB(+I" UH-$6(>'T+%YR40BO5$ .R/K1I0+S)&k1N,_T9)%5K(0]!5QB5F6T4] 8W_B" :S"8\$4i>M8c#c"B]"DY$@fHT+>oDf&BimO'+DcMDY!Fb&EemN0KW)ElMZkR2/GlfR7Ld Jm-Gt*N_,IpQ_dU?*Lu+Ky%Mv0MuRPaUd-N|-Pxz\6,Vi.Rv!Xg/Px^>[j2R'U%Yt8U~3T"YX.Y~5V!_o*\|1XY]k9Z5[ ev@^7^8]#f~B`=`c>_,f:`\gqDd'l~M7U%5K 3P"6S 8W#;Z"8\'?^'>cDOFSLXO[Q_"B]Zi[k#@e%Ag&Ee+Dc&Bh*Fm!Xg!_o,Ip)Kt+Ky,M{/O~1Nv-Px)[|0P8U~du"gx#f~IKJPRQTVUXZXZ][^a_cedgihlomdn~orpvywwzxx{y2R3T5V1W4[7]9Z8](m=`%q'q$w)u&y:`;b=d?d+~?q@^A_DdMkEfKoQlYoPnYte{AnEmBmEqVu^}KvMyO{\S`|-)+650</639<6=1?;jAX[GIDnmjszxcghvALH?`cnyt~Lq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQqjqynh677qtvsrt55.+17h{Cjdh0-6fkpi)pr70,6dzsyqd7106sodg66qBslghtDm)hh)CqE1/@ngvngiC5nE)'K)hzzp)DB(FCten)htn5CCD4#  E1: Z #$C0a:AN:;?I ##-wV8" !9=?#!,}~"9 HX^`J! H+9|ORYGLa^`O*7H9;3"ScU?b["+5N99>=#< "I# w01wA";99? 9Pax`]RAM &56W]\NS<"%5016Q#w_U-06}AT9x6-06u[\62+.56?6666aaaa???8a8a8axa(@ //j{E51(l7;K<7?6;.s/+34,   E7~92ES@4)w'o.)v-/+qD+Fz''&''&~I.  ' _>8K:)t'p43C8B9A4T$ + X222UWV~ced554b.1).~A5-.;SP<8:4284 f+ D110qus676K! :@K76?I>0.6'p-~10|80!&2*oPRPEFEDEDhji.CB;?4/6)q<B=@*hzH9!! sut%%$= $V4B<2)u-s>MWKJ:=>C4Q! 8oqp###< * cO:*w4KPA1.7)t*t@//,v[' 7lnm""!;1',|K7F<.)v)u62uCKXCOHC l-5ikj :9(T`H?&m$g{4DVJG;;*t4363.644fhg8C(We?/4K<,y,}:(oYj:)i|6=>3EQ<2cdc7 "Q(i{/=5*v0(p'm:@RLHHJ>K+j|D1~`a`~~5- k8253$cu?AI77*x,~1+|922)nL /y\^]yzy4:!GQ775><31YiYj2&dv0p8CILG7U$ . sY[Ytuu3H1s9+y+v6'pQ`-{3ACGC:=:;95`) - mVWVopo2 &W41"as$h|$dw7?>0%i}'p,z)t.'m+|66/!w/+gSTSjkj{00',xH%k- [l#`r1"cu$gz-|Xi$ex5;EKWMHI1zL  &ZDEDWXWh+;i2&m.)tJX&lYj"at%j~(s'p[lP`"cv!^p%i})w&n/3-xU$  %XAA@𴷶SSRd* !<^!&16#dv#dw(qIV*2P_DPER [mGTBO"as [l'n.24;=a*  $V==<첵NON`)  <3R|"4K'br&m0O]&lHV9D/7HUIWP_ ]nRaYj!_p [l"`s&n!_q%j~$gz*yu0 #T887谳IJI]( ,&6n8]'5I+m*xP`$fz6?$=IXi!_qZk?K1;@L09Rb#exZkZkKY \n#fy*w6@7 "R665㬰FGF[' <3Ln,Jt 0F9C ]n&Zt&Db+Cd1L/Nz(F]0>DX1;5?XhWgP`Sc"buUe \nVf#cv+z!Q_? P333ߨCCBY&  !N?a(Dk+Ho+Kp-W~*Ip 6U.H.Nz(Dk-Kv0Q/P}(FlBT2<7A4> $+AMERFS:DYi#exMZI  N110ڤ??>W% 0cEk?f7\/P|/O{4Y/P}*Hp$=_&@d(Ch1P{#;\%>a+'6FHV+3M\ZkO^P`%k)u%dvZ-M00/֠;<;U$  E(=[9^.Mw/P}0Q~5Y_Bk,Ir%?b'Bg%:)@,E(Dj&@d3P.H3J+=(5(,C":[)Gg!C]!J^wK+ K...њ998T# ,)6Ht_Cg1SGp?fGlUpqIg.Jq'@a'Ch4X3W4Y9`=g>h9`)El"5&;'Ci$=`4T(Dj5W$0*=^.I--,̕565R" 8Tk_5Y>b,Ip/OzHcNp)@(>&@d-Mx0R3U3V1R3U6\6\7]:c9`#<^/I&Ae/P}7\;a0J'Bg<`!.`! G,,+ǐ221P! ?qaP{8X'<,E./Fd?b.O{0R/P|.Nz-Mx-Lw,Lv2T2T2U5Z5Z8^8`/P~)Fn4Y3O0K%@d/I@k+Cd)E++*‹110O >}uNrW}'Bg&;-7Y.Nz1T.Ny,Ku+Is-Mx.My0Q~:b:b9`8_8_:c8^%?c1M-Jr3R|'Af1RCo+q*D**)00/M5V_lkQs'Ad)@ 'Bh*Go1L-G+D!7V&@d:b6[:bBoCq@k?i@k;c5Z#;\%?b(Ad2S6Z@fX% B(('//.K+_vRlyrDh1L +B)?3P,Is4X=b.Nz:a@k=hHvVY]P}>i;d5Z0Q}5Y5YX}7U~M @''&..-J 'WRiPkqB_'3V1S-Mx+Ir,Ku2U0R3V9aCq\hnqrQ~Gs;d:aP{Fn]$5KL" ?%%%{~}--,H,^2E`Vo8NnldAcYldWubFqAk9aKw7^6\Gp`wc[VGtV\ ]2=$$#x{z,,+G= 1H4T"9Y%; 5S,IrXxi`vkZDq=f;Z5T~Gp]R}GnX+Ho,Iq<]#7R+Eh/Jp T'=""!uxw***G & W<]5T2M4S}-Mx,'=Pih{vIq3W!8X#7TyZrk<_)BfQqLtoT~Mv*Gn'=(?.G$9,E4Xb9[#7!3,.H:Z;aOyIu8](Dj+Js5S/ 6T5Z?iHhF *Toqp&&%^0 >i]AdNs0Q~* -3W1S1S0Q~1S2U3W:aNt2N'Ae)El!9Y&@d>d9]+Ir)El5Ze8LfF-9 BCB򆈇VWV--, L :bo}if=`ImfZ=b&Ae#;\9]@e(Dj$=`)Fm0Q(Ci "#7JuKqz +;?0 TJKJnpo++*+ A$v鐬X|eHl3V8\Tyfp4U%?c'Ch6Z.Nz/O|6[2U2U "9YLx\kibt90TNON""!0"B4>Ko{hMpJi-Eg/Ny6WpwjiWz-Lv0Q4W5Z?i1R!41RNzcdHp b1,P554gih554<<>=}##"FGFBBAZ' )RٯiZchJl.Lv)FlLcMu`Lt 6T5WZTh6XCoAbE!>##"'''lMPt00/㔘///M 1 #b椻r6T}TxS|Ei&@e1FdR{$<\3Pe0AX>\Dll.?W55))(S14\110ޔ''&A 4+/5fMli9[;Stnu-.KtZZvN#-iggg**)I&*S111ܔ7 /NJTcy6\m8Rt 6Ug#o4 %WGGF**)F#&P221۔``_i- &Akʐ}[Ae1SGl]HhhXmA  K00/++*D!%M221ڔ<<;T$ :dݡOsa5:AF$=))(+++>"F232ؔ---D @,7Gzh~{f5T~5YY-:KG%-""!||{lml--,18332vxw&&%1'Rg~j+Ir?TpG^~/Jp)El/J0KBYxMiWwihkL' ;''&''&&&&(('O $_(('&&%&&&''' A 6BRhEm/O|/Ozv{M* *45-!/65+ ?9EUxNvs􎛬P[i [@'     < _x8@M?GS/7AFQaWI9) / C?GScK@82-&   ???????????????????????????????????@?@???(0` ,brB3.u9A:689*k}5A6  188A@0.3y237,o. )<>=^_^FHG.M?3-5PD::381>{[^]"(/h58D?+2+x1280U 4686-.-iljIJI;  ._m>41?7@?<>89-3nCIJI||{KLKfggI%:iv89A59 \m.4@<;AL FLMLffeK*%ZjA8-/uARKD9;?#Yi'DHIHabaI 5;x:8<=1-|:9C@:(aq0 AEFE]]]GD;267)m<  ?BCBʽXYXDS517D+z*{2#^o;1x>=+rK  &g 6797JKJ= =3~1(p2!`q,y5@E?8796)0x# 4454EEE; V>'t!as$dw41+z[m-~29AB?DO) 1111@A@8 !!HT6'r'p"at,|(l563)p1335!Ud0  /---;<;6  ,8s/&k'm$i|&m*v$h|N]%n [l&j~3>A-m8 ,))(5554 >1|*y-M\$h{ \n ]o%k~&n#ey+y,z3170~B+$$$0101 4k.2"dv'oHU?KJWL[Td@M"at"bu,}17=O) +++/ 53Q{%J]%k+yZkER7A?JKYP_TcSc ]n \n$j~Zk"dw(w i(%&%- $4Iw1P} >L$j{ Rf$Jb$2&IeL\O`3;>JCPTe!asXiTd ^p*y5?ERFSHU#fyEQ+ $*H@d=c2U.Nz9_.N{$=_%?c*Ek"9Y#:['0ACQ7CScJZ!Zn(o"[k@#) *:Qs@e.Ny:`;a_Pr,Gm%>_6U%?c/P}0Q-Kw*Fl)=(!8Y*Ci$?_(JjD!( D\~:^;_/O{GeKk*@$=_,Lv1S3W1S5Z7^7^7^";]1L*Hp5Y8\2N8Y I &#)1RoY4R{,D*.Ed9]0S.O{-Lx,Kv,Lv2T2U5Z6[9b/P-Ny 7V3P6U=f%9T|{~}% #(Ivp<]*B+0Q~'Di":[!9Z'Ci4X5[=h_Awqsr" -1?RMhKk(>=b9Z1Ow3U2U4X=hUdmvQ~Cn;cS~X+>WC smoo ;$8T=Uw"3MGdLointT~Ht;d4VChhZZ>eGkUu!2J+A(  nilk "b7X2N0Nw4S!2XkX6X/EVw`zX},IqRt\XIq#:Z)@/J(?/P|:a(?_ oegf $ +KcaBd9W.I 4V6[.Nz/Q:]3T 2.2O6XJsDo.Nz-Mx6U*B4XFo3If!3acb 9 2u}KnHn%@d!5#<]3V/P~/P}.N{2W9`5T'Bf'Bh*C&?b4V7W:bIrJnHtgCYw'2}?@?ܐBCB:  .wɇj<_Dn+Lx,N}-Mx7]0R5Z4X3V6Z$=`!8W#801KHeNvfW~AiKuMb*#B_a`npo))(W%  17?j{{|rqHe:YEg4U-Kv(El3S}/Ny(Ek6T#;]-G!4Lu?ek?d'3l. H;<;҈KLKi 3`kyiNrCg_y]%Ag$?d>>uxw"""%7KVfYX?c*Ej-NzTx|In@gDn(Ek/P|_juGs9\3!Vxxx@@?kHIH lKѣzkPqMq9\.Gjuo<^2Pa_u;ZU4Lm%E```343Q9X<=;꺽tttW $*UpQme2Jkf-Af`I5CBB776>$G>>>蹽XXWD 纽4432 /'(+m祼ahX{~Xi 9 8986=?@?$/.8Fue4UU~7CR8Z||{787(.==<嗙 f?fMp2Ii9Sv+Hq#8U*>ZJd\{to: !tN Zx% "8DTrq    ( V׹i{\dqT]iOXd%(,] @& 2!'0Q90(" ?~~~~>>????>?( @ #O[s8?9422Q_z ! Y [# 1u9.B<;:%`q!898ƛHIG$%6;;,y9<;/sTPQQ<>< a .A4?8,38/z( h r 9B/>AD2:44 cm \D21A?E>?N[f :D69-/4}?C@6?u S_ -n44<-p+y/};>!SaKX06$gz-~2384.6$bsCQ #]4'r*u"as/15C=1|!=J)Xe/"as _p&l!at$h|)o5?8*8|~}C2#^o+y#exLZZk"buFT ]n(s.885wxw=3/Fk*t!bt?I>IVfGTDQ ^p!`rXh&o U3qsr9+A`%>`"Ld%Dd$<]-Jq$Dd;MIV;FO^JX$h|3;{/kml6$/Kq4X.N{Ci%@e!9Y4P 5T'92@=J@U&\u9D(-egf4 '1>[Ov:^BeMg+De*Hp5Z5Yd+Kw-O}3V/Q~4W2U,Ir2O+&BgW}bKva3 jZ[Zbdc#]izvhcgq5Y#=_<`"<](Dj$85USwJf1%%$:;:CLYgIl:YPrGi1R~0Q7]3P:`m~9U{, y{zHII$nW}Y~/Mu<\VyS}$>a_rLs-Gj yVXWqy`ca/ɏxY|Xs/Nw[x0K^DMWXW39`cak  'KWhVxGoobSd{1XYX+1acb;19D{FoHR_"jjiTUU!%\^]pqp")v)Ht9U|Le^uvs& @iIOjC  @qҟʞu}L   !3$ xxxxxxx888880p(0 %S`j9;63-z&, 1<=2=B7908Y0<=< 7;449A@HT}*:;;~"Q_h554.{3?(bs #888w *o'o-}0}646*p~666o -u&n%k&m*u0}?6wyx333g ?)r%jP`!`rQa#dw.7,prq010` 5,Kl%g{BQAQK[ERZkZk%k Liji...[*Bd-Lu.Ry'Ag'Ad9U6E7BDS#_s3;{ acb-.-V'Hl8[Hg0Il*Ho1T5[.P|5R.P{(Bc0IhY[Z,-,RMT]AmN mond898O& &r^}@\Jc| 343^qsr*DFE'ITeV{N^s+++>kmlEFEpqp b}=ZWomt#*3J C 'X0 .v|k;=>;#)2 [[[AAAAAAAAAAAAAAAAAAAAAAAA(  #O\O8;6EQM? C/p;2:%]n}wyweff5~3B<,plml/|6/z;3|fgg{}| -}+v374_a`vww@J])v [l ^o(r8WYXqqq -,(QmE\!IbBPSc _q 3OPOjkj6Ry8[;X(Ch*Go =X&Kk 8Q EGFddcf8Ru7V)Em7^Bm+Ku3T<=<\]\&:VFaxLjIp]Bh;X*CC454|STT l'Ae$Do-P)Dk"9X9\?bHedfepqq'-.-k|ySse0P}+Kx#<^|,A^pp<[h]|Ll*9Ebp|xRh^_^cdcKfo|k}./AAAcAcAcAcA#A#A#AAAAAAAAchocolate-doom-chocolate-doom-2.2.1/data/setup.png000066400000000000000000000163451257432200600220750ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYs B(xtIME:HvceIDATxݛwyu39',H$(fQD餓H%K6;KJg]YΧ v|ْK]:KeJI 6`lݙٝ3Unfϛx^ҚOo?ɗ}[f@_X\`v]w/) txs8q 濣@kĚnm5wnfS@Plǧx|HjOŴ6u ޷wǎg $kO׈&SX^VaO0w<΁ lGg%Ө:sϟoy 䀊o25Lki4]'k&:)80_Տ~$g2D[BшHcVIyQ;?uK@G>*$Ā*_Sj=`uCa!)on%)ә2$m:Z¤b!SI#3ġ>I T׀ |%TU$Ir.T.;;ݮ$$I*VM+>XΪ@M(ww;wn\.Wش.>_' X :#+7ouyA\.P2|`-[iw^Ł^`s[{p+#{VHn0nݷ\|I-{f`P~^}Cy7@ {al籐s݈aw>t]g(O|jfu1@jBH=m_!IV:/o=Y>]# ?idH3?_ }}}x%) x%緺X<>d-x={[#ȓ֑Rrp3f1S7~[,;!5Ls>C yh `旨)OHuyױ8P'Ͽ w>_$ɋ`T9I͹y KTj x t o_{}2i"֟=w 73?[hZ4]7p[<~G,96ml0@KLM]{ݾ~qo~*Pa3jo2edxH$) oǀUTC@,.^evVa#;=X1x$G?2o~XF׶:Vk?s[PdGpB/>ig!W"} w5 / ~ \7tN=oc2Dtxb"T*AU!) *3P 5ʦR, &xwa:ziXV9׈ {س~\- sLB7^ C$ITU]7j'O“O>x?eY "w=˛f9B)dV Ұ[DK7ΖL<`&W%+C2 PWIi'+ȍ uaGB ZS=}bzZ5;){߿+fxyMOO?a{Xi3R yW0[;7,]82-(Y^ʐ)j XkBr\ZB[sGA*5žNu\_<`[ô85g5@g+T'Ͼrboo.\B6}T*} Z>w~eMM}X, __\sPб]B(m粤 I& z8C\,G}|5 jןx7j79N*[k#]S8;̾-G(f891GH&dFJ!ojZeYF+YUUe^+zk].s'瞺cs"?w|Ζ˭;rG#Kbժȁ%5~uxzf1y:-V2\l4lΎv\e>};?}BjmD˵|dM eZ>ee!Ib>Mfjog\8ܱٚom{(yAd|'z!V9E0kORY.#I"]Rj`0eYܿp4Njh F'6W Lmzf! !_FYpG%n(B8 NS%O]XѰi. i8$Vd-PUC2maVT r c0ikuz}*ִv$Hr=3!(B}-#ST ˔ L>') =p4Fc:P\xxH\k( ,!#zL6Br( 59InL ?kݽ%@PeYy ITIgE~=h^gE0#ʜ˔99ǙqIFtbAKp@Voа5CFáTkp "B/ܹiz-Vq!I 1r5;Sk4+<*- i tP7ҊpPlU ٲz~)rz@h1R+Mu'Ndm]BU@܌ Hd)(\X̑Urbߦ~BAQq=d!!!p灋KHVȖL HXKT#P^`;.]-A˰+Nd5&$IRPց^ Ϗs]'i m&o-7?=yuiUUAR(Iƾ$d,Tl٤7\wS"vth»ZV$uZ76Ug*Ͻ~bb1¾=T E0$'Ϝefvr mQ\C D*%TLc3y^;ES2X/u*rØz,G27j&p5d!(rNl3R{{5E$I"lIz3FMsv* 6th.i9Ula3T3$]bxuΔ륣S?NK$YRضܢB@[R04U75,x\7|o_Q!2@⦝`3CS ߳dJUmgo+Ͻ徽-*RlpAW!AkBc?DjDAdZb *lCpn>ϹN_Ndy}Ȳ,l" ˮ~I\1!Rjө69rJAH)V,,#V(WmV al<1dѰ `ɮ5{NAV !5J] xٲm&/ K*(DGJO<E# t elãRu(eTkƊIogX5Y]j Pe]E,+>7emW Fq<"!R&TkE((ӮӚ06 cAT2킮J,*E^H" q}Hn{RP.F!U38VYȘܹ;EvAʹ30L-#NW9JraL{*<|mu3@$(( YT/ή̏FYZ2q\V '8_C2#16 %]\lx ]rM^u=aLuiN$Ixi*,k x(w RbD[[8ۈUI/U,WjǶ4.Պr-{  !dYQcǎ_Z^{<~ $F7L-7how|JBtޮ }lޤby<)א _njl|>i?c~nnu]oDX\)51 =ßh>rQ(at%((k n+Nўb.eM#;Z$=[%<`CN%?YDPDO'?^'>cFS"B]#@e%AgIU&Bh+Dc&Ci!Fb&EeKWIKJ(EkLX)Fl+GnO[LOM,IpQ_)KtPRQ/Ls+Ky+NvUd,M{1Nv-N|TVU-Px.O}/O~!Xg0PZiXZX1R[k3S8U~3TZ][5V!_o)[|1W^a_3Z9Z`ca4[duadb ew@^ced7]"gxA_8^8]#f~=`>_:`gihDd&k};bhki=d(m9c?d#o:eEflom$pdn~&r'q=horpQl'sMk)u*vYoEmPn$wKoAnBm&yvywSrwzx({Yt?qx{y)|EqVu+~{~|-YxKve{60`|)f~My+2^}O{_~:.j5\X0SmnYs3[j,<6/cY1z`9fA3gc<sh6x=08?lvG2;InoJ<DLAytHL?~Fˤuw{¯uu=(U{eρK7wQ{K0wûՁwUKwυwwi?pQQelUB[eukQGQ?QpbMteˆQ694 ¬ue4 ##4#epg"1 4&lU>s'1 @eK>RN>APZ117y8.-3 doom_se.lha #endif The resulting file is an LHA archive file, and it can be extracted using an LHA archive tool (there is one available for almost every operating system). #endif == Running the game == #if __MACOSX__ Once you have an IWAD file, you can specify its location within the graphical launcher program. Click the "Configure..." button, and then click "Set..." for each IWAD to choose its location. From the main launcher dialog you can then choose which game you want to play and click the "Launch" button to start the game. If you are an advanced user and like to run Doom from the command line, you can use the "Command Prompt..." menu item to open a Terminal window. The DOOMWADPATH environment variable is preconfigured to point to the locations of the IWAD files set within the launcher. You can launch the game with a specific IWAD file by typing, for example: LONG_EXE_NAME -iwad tnt.wad #else LONG_GAME_NAME needs to know where to find your IWAD file. To do this, do one of the following: #if _WIN32 * Within Explorer, simply place the IWAD file in the same folder as the LONG_GAME_NAME files, and double-click LONG_EXE_NAME.exe. * Run LONG_GAME_NAME from the command prompt with the '-iwad' command line parameter to specify the IWAD file to use, eg. LONG_EXE_NAME -iwad c:\games\DEFAULT_IWAD * Set the environment variable DOOMWADDIR to the location of a directory containing your IWAD files. * If you have multiple IWADs in different directories, set the environment variable DOOMWADPATH to be a semicolon-separated list of directories to search (similar to the PATH environment variable). #else * Run LONG_GAME_NAME from the Unix console with the '-iwad' command line parameter to specify the IWAD file to use, eg. LONG_EXE_NAME -iwad /root/DEFAULT_IWAD * Put the file into one of the following directories: /usr/share/games/doom /usr/local/share/games/doom * Set the environment variable DOOMWADDIR to specify the path to a directory containing your IWAD files. * If you have multiple IWADs in different directories, set the environment variable DOOMWADPATH to be a colon-separated list of directories to search (similar to the Unix PATH environment variable). #endif #endif #if DOOM == Playing with Chex Quest == Chex Quest is a game based on Doom with some minor modifications that was distributed with boxes of Chex cereal in 1997. It is possible to play Chex Quest using LONG_GAME_NAME. To do this, the following files are needed: * The IWAD file 'chex.wad', from the Chex Quest CD. * The dehacked patch 'chex.deh', which can be found here: http://www.doomworld.com/idgames/?id=15420 (utils/exe_edit/patches/chexdeh.zip in your nearest /idgames mirror) Copy these files into a directory together and use the '-iwad' command line parameter to specify the Chex Quest IWAD file: LONG_EXE_NAME -iwad chex.wad #endif == Installing upgrades == #if DOOM LONG_GAME_NAME requires a version 1.9 IWAD file. Generally, if you install a recent version of Doom you should have a version 1.9 IWAD. #elif HERETIC LONG_GAME_NAME requires a version 1.2 (Shareware) or version 1.3 (Shadow of the Serpent Riders) IWAD file. Generally, if you install a recent version of Heretic you should have a version 1.2 or 1.3 IWAD. #elif HEXEN LONG_GAME_NAME requires a version 1.1 IWAD file. Generally, if you install a recent version of Hexen you should have a version 1.1 IWAD. #elif STRIFE LONG_GAME_NAME requires a version 1.2 IWAD file. Generally, if you install a recent version of Strife you should have a version 1.2 IWAD. Please note that Strife version 1.3 does not update the IWAD, if your version.txt file says "STRIFE(TM) VERSION 1.3", you are still good. #endif However, if you are installing from a very old CD version or from floppy disks, you might find you have an older version. The most obvious symptom of an out of date IWAD file is that the game will exit at the title screen before the demo starts, with the message "Demo is from a different game version!". If this happens, your IWAD file is out of date and you need to upgrade. Upgrade patches are available that will update your game to the latest version, the following sites have the patches: #if DOOM http://www.doom2.net/doom2/utils.html ftp://ftp.idsoftware.com/idstuff/doom ftp://ftp.idsoftware.com/idstuff/doom2 #elif HERETIC ftp://ftp.idsoftware.com/idstuff/heretic #elif HEXEN ftp://ftp.idsoftware.com/idstuff/hexen #elif STRIFE ftp://ftp.fu-berlin.de/pc/games/idgames/roguestuff #endif Please see http://doomwiki.org/wiki/Game_patch for more information. #if _WIN32 As the patches are binary patches that run as DOS executables, on recent 64-bit versions of Windows you will need to use a DOS emulator (such as DOSBox) to run them. #else As the patches are binary patches that run as DOS executables, you will need to use a DOS emulator (such as DOSBox) to run them. #endif == Music support == LONG_GAME_NAME includes OPL emulation code that accurately reproduces the way that the in-game music sounded under DOS when using an Adlib/Soundblaster card. This is, however, not to everyone's taste. LONG_GAME_NAME includes a number of different options for better quality MIDI playback; see the file README.Music for more details of how to set these up. #if !PRECOMPILED When compiling from source, be sure to compile and install Timidity before installing SDL_mixer. #endif # vim: tw=70 chocolate-doom-chocolate-doom-2.2.1/man/Makefile.am000066400000000000000000000131211257432200600221120ustar00rootroot00000000000000MANPAGE_GEN_FILES = environ.man \ iwad_paths.man \ doom.template \ heretic.template \ hexen.template \ strife.template \ docgen \ default.cfg.template \ extra.cfg.template doomdocsdir = ${docdir}/../${PROGRAM_PREFIX}doom hereticdocsdir = ${docdir}/../${PROGRAM_PREFIX}heretic hexendocsdir = ${docdir}/../${PROGRAM_PREFIX}hexen strifedocsdir = ${docdir}/../${PROGRAM_PREFIX}strife if HAVE_PYTHON GENERATED_MAN_PAGES = \ @PROGRAM_PREFIX@doom.6 \ default.cfg.5 \ @PROGRAM_PREFIX@doom.cfg.5 \ @PROGRAM_PREFIX@heretic.6 \ heretic.cfg.5 \ @PROGRAM_PREFIX@heretic.cfg.5 \ @PROGRAM_PREFIX@hexen.6 \ hexen.cfg.5 \ @PROGRAM_PREFIX@hexen.cfg.5 \ @PROGRAM_PREFIX@strife.6 \ strife.cfg.5 \ @PROGRAM_PREFIX@strife.cfg.5 SETUP_MAN_PAGES = \ @PROGRAM_PREFIX@doom-setup.6 \ @PROGRAM_PREFIX@heretic-setup.6 \ @PROGRAM_PREFIX@hexen-setup.6 \ @PROGRAM_PREFIX@strife-setup.6 man_MANS = chocolate-server.6 \ chocolate-setup.6 \ $(GENERATED_MAN_PAGES) \ $(SETUP_MAN_PAGES) doomdocs_DATA = INSTALL.doom CMDLINE.doom hereticdocs_DATA = INSTALL.heretic CMDLINE.heretic hexendocs_DATA = INSTALL.hexen CMDLINE.hexen strifedocs_DATA = INSTALL.strife CMDLINE.strife CLEANFILES = $(GENERATED_MAN_PAGES) $(SETUP_MAN_PAGES) \ $(doomdocs_DATA) $(hereticdocs_DATA) \ $(hexendocs_DATA) $(strifedocs_DATA) MANDIR = $(top_srcdir)/man DOCGEN = $(MANDIR)/docgen $(SETUP_MAN_PAGES): chocolate-setup.6 cp $< $@ @PROGRAM_PREFIX@doom.6: ../src $(MANPAGE_GEN_FILES) $(DOCGEN) -g doom -m doom.template $(top_srcdir)/src $(top_srcdir)/src/doom > $@ default.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template $(DOCGEN) -g doom -m $(MANDIR)/default.cfg.template \ -c default $(top_srcdir)/src/m_config.c > $@ @PROGRAM_PREFIX@doom.cfg.5: ../src extra.cfg.template $(DOCGEN) -g doom -m extra.cfg.template \ -c extended $(top_srcdir)/src/m_config.c > $@ CMDLINE.doom : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/doom $(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/doom/ > $@ INSTALL.doom: $(MANDIR)/INSTALL.template $(MANDIR)/simplecpp -DDOOM -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@ @PROGRAM_PREFIX@heretic.6: $(top_srcdir)/src $(MANPAGE_GEN_FILES) $(DOCGEN) -g heretic -m $(top_srcdir)/man/heretic.template $(top_srcdir)/src $(top_srcdir)/src/heretic > $@ heretic.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template $(DOCGEN) -g heretic -m $(MANDIR)/default.cfg.template \ -c default $(top_srcdir)/src/m_config.c > $@ @PROGRAM_PREFIX@heretic.cfg.5: $(top_srcdir)/src $(MANDIR)/extra.cfg.template $(DOCGEN) -g heretic -m $(MANDIR)/extra.cfg.template \ -c extended $(top_srcdir)/src/m_config.c > $@ CMDLINE.heretic : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/heretic $(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/heretic/ > $@ INSTALL.heretic: $(MANDIR)/INSTALL.template $(MANDIR)/simplecpp -DHERETIC -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@ @PROGRAM_PREFIX@hexen.6: $(top_srcdir)/src $(MANPAGE_GEN_FILES) $(DOCGEN) -g hexen -m $(MANDIR)/hexen.template $(top_srcdir)/src $(top_srcdir)/src/hexen > $@ hexen.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template $(DOCGEN) -g hexen -m $(MANDIR)/default.cfg.template \ -c default $(top_srcdir)/src/m_config.c > $@ @PROGRAM_PREFIX@hexen.cfg.5: $(top_srcdir)/src $(MANDIR)/extra.cfg.template $(DOCGEN) -g hexen -m $(MANDIR)/extra.cfg.template \ -c extended $(top_srcdir)/src/m_config.c > $@ CMDLINE.hexen : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/hexen $(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/hexen/ > $@ INSTALL.hexen: $(MANDIR)/INSTALL.template $(MANDIR)/simplecpp -DHEXEN -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@ @PROGRAM_PREFIX@strife.6: $(top_srcdir)/src $(MANPAGE_GEN_FILES) $(DOCGEN) -g strife -m $(MANDIR)/strife.template $(top_srcdir)/src $(top_srcdir)/src/strife > $@ strife.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template $(DOCGEN) -g strife -m $(MANDIR)/default.cfg.template \ -c default $(top_srcdir)/src/m_config.c > $@ @PROGRAM_PREFIX@strife.cfg.5: $(top_srcdir)/src $(MANDIR)/extra.cfg.template $(DOCGEN) -g strife -m $(MANDIR)/extra.cfg.template \ -c extended $(top_srcdir)/src/m_config.c > $@ CMDLINE.strife : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/strife $(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/strife/ > $@ INSTALL.strife: INSTALL.template $(MANDIR)/simplecpp -DSTRIFE -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@ INSTALL: $(MANDIR)/INSTALL.template $(MANDIR)//simplecpp -DDOOM -DHERETIC -DHEXEN -DSTRIFE \ -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@ endif EXTRA_DIST = $(man_MANS) $(MANPAGE_GEN_FILES) \ wikipages \ CMDLINE.template \ INSTALL.template \ simplecpp chocolate-doom-chocolate-doom-2.2.1/man/chocolate-server.6000066400000000000000000000030671257432200600234220ustar00rootroot00000000000000.TH chocolate\-server 6 .SH NAME chocolate\-server \- dedicated server for chocolate\-doom .SH SYNOPSIS .B chocolate\-server [OPTIONS] .SH DESCRIPTION .PP Chocolate Doom is a modern doom engine designed to behave as similar to the original doom game as is possible. .PP .B chocolate\-server is a dedicated server for Chocolate Doom. It is equivalent to running .B chocolate\-doom with the "\-dedicated" option. .PP Game options are not specified to the server, which merely acts to retransmit data between players in the game; parameters for the game should be specified by the first player to connect to the server, who is designated the controlling player. .br .SH OPTIONS .TP \fB-ignoreversion\fR Ignore version mismatches between the server and the client. Using this option may cause game desyncs to occur, or differences in protocol may mean the netgame will simply not function at all. .TP \fB-port \fR Use the specified UDP port for communications, instead of the default (2342). .TP \fB-privateserver\fR Don't register with the global master server. .TP \fB-servername \fR Specify a name for the server. .SH SEE ALSO \fBchocolate-doom\fR(6), \fBchocolate-setup\fR(6) .SH AUTHOR Chocolate Doom is written and maintained by Simon Howard. .PP This manual was written by Jon Dowland. .SH COPYRIGHT Copyright \(co id Software Inc. Copyright \(co 2005-8 Simon Howard. .br This is free software. You may redistribute copies of it under the terms of the GNU General Public License . There is NO WARRANTY, to the extent permitted by law. chocolate-doom-chocolate-doom-2.2.1/man/chocolate-setup.6000066400000000000000000000023171257432200600232510ustar00rootroot00000000000000.TH chocolate\-setup 6 .SH NAME chocolate\-setup \- configuration tool for chocolate\-doom .SH SYNOPSIS .B chocolate\-setup [OPTIONS] .SH DESCRIPTION .PP Chocolate Doom is a modern Doom engine designed to behave as similar to the original Doom game as is possible. .PP .B chocolate\-setup is a tool for configuring Chocolate Doom. It provides a menu\-based interface for the display, joystick, keyboard, mouse, sound and compatibility settings. .PP .B chocolate\-setup can also be used to start and join network games. .PP .SH OPTIONS .TP \fB-config \fR Load configuration from the specified file, instead of default.cfg. .TP \fB-extraconfig \fR Load extra configuration from the specified file, instead of chocolate-doom.cfg. .SH SEE ALSO \fBchocolate-doom\fR(6), \fBdefault.cfg\fR(5), \fBchocolate-doom.cfg\fR(5) .SH AUTHOR Chocolate Doom is written and maintained by Simon Howard. .PP This manual was written by Jon Dowland. .SH COPYRIGHT Copyright \(co id Software Inc. Copyright \(co 2005-8 Simon Howard. .br This is free software. You may redistribute copies of it under the terms of the GNU General Public License . There is NO WARRANTY, to the extent permitted by law. chocolate-doom-chocolate-doom-2.2.1/man/default.cfg.template000066400000000000000000000033221257432200600237770ustar00rootroot00000000000000.TH default.cfg 5 .SH NAME default.cfg \- Chocolate Doom configuration file .SH DESCRIPTION .PP \fIdefault.cfg\fR is the configuration file for \fBchocolate-doom\fR(6). The configuration options stored in the file are the same as those stored in the original DOS Vanilla Doom. Extra Chocolate Doom-specific options are stored in a separate configuration file, \fBchocolate-doom.cfg\fR. .PP \fIdefault.cfg\fR is normally stored in the user's home directory, in \fI~/.chocolate-doom/default.cfg\fR. .PP The \fBchocolate-setup\fR(6) tool provides a simple to use front-end for editing \fIdefault.cfg\fR. .br .SH FILE FORMAT The file is a plain-text file, consisting of a list of configuration options and their values, separated by whitespace. Each option is stored on a separate line. Options have different types; an option may have either an integer, floating point or string value. If the option is of a string type, the value is surrounded by quotes ("). .PP For example: .RS .PP integer_value 1 .br integer_value2 1 .br floating_point_value 4.2 .br string_value "hello world" .RE .PP Invalid lines or comments in the file will be ignored, but it is advisable not to put them in the file; the file is rewritten from scratch every time the game exits, so any invalid lines or comments will be lost. .PP Some options are used for keyboard key bindings; these are stored as integer values containing the keyboard scan code of the key to be bound to. Boolean values are also stored as integers, with a value of zero usually indicating "false" and a non-zero value indicating "true". @content .SH SEE ALSO \fBchocolate-doom\fR(6), \fBchocolate-doom.cfg\fR(5), \fBchocolate-setup\fR(6) chocolate-doom-chocolate-doom-2.2.1/man/docgen000077500000000000000000000304131257432200600212460ustar00rootroot00000000000000#!/usr/bin/env python # # Chocolate Doom self-documentation tool. This works similar to javadoc # or doxygen, but documents command line parameters and configuration # file values, generating documentation in Unix manpage, wikitext and # plain text forms. # # Comments are read from the source code in the following form: # # //! # // @arg # // @category Category # // @platform # // # // Long description of the parameter # // # # something_involving = M_CheckParm("-param"); # # For configuration file values: # # //! @begin_config_file myconfig # # //! # // Description of the configuration file value. # // # # CONFIG_VARIABLE_INT(my_variable, c_variable), # import sys import os import re import glob import getopt INCLUDE_STATEMENT_RE = re.compile("@include\s+(\S+)") # Find the maximum width of a list of parameters (for plain text output) def parameter_list_width(params): w = 0 for p in params: pw = len(p.name) + 5 if p.args: pw += len(p.args) if pw > w: w = pw return w class ConfigFile: def __init__(self, filename): self.filename = filename self.variables = [] def add_variable(self, variable): self.variables.append(variable) def manpage_output(self): result = ".SH CONFIGURATION VARIABLES\n" for v in self.variables: result += ".TP\n" result += v.manpage_output() return result def plaintext_output(self): result = "" w = parameter_list_width(self.variables) for p in self.variables: result += p.plaintext_output(w) result = result.rstrip() + "\n" return result class Category: def __init__(self, description): self.description = description self.params = [] def add_param(self, param): self.params.append(param) # Plain text output def plaintext_output(self): result = "=== %s ===\n\n" % self.description self.params.sort() w = parameter_list_width(self.params) for p in self.params: if p.should_show(): result += p.plaintext_output(w) result = result.rstrip() + "\n" return result def manpage_output(self): result = ".SH " + self.description.upper() + "\n" self.params.sort() for p in self.params: if p.should_show(): result += ".TP\n" result += p.manpage_output() return result def wiki_output(self): result = "=== %s ===\n" % self.description self.params.sort() for p in self.params: if p.should_show(): result += "; " + p.wiki_output() + "\n" # Escape special HTML characters result = result.replace("&", "&") result = result.replace("<", "<") result = result.replace(">", ">") return result categories = { None: Category("General options"), "video": Category("Display options"), "demo": Category("Demo options"), "net": Category("Networking options"), "mod": Category("Dehacked and WAD merging"), "compat": Category("Compatibility"), } wikipages = [] config_files = {} # Show options that are in Vanilla Doom? Or only new options? show_vanilla_options = True class Parameter: def __lt__(self, other): return self.name < other.name def __init__(self): self.text = "" self.name = "" self.args = None self.platform = None self.category = None self.vanilla_option = False self.games = None def should_show(self): return not self.vanilla_option or show_vanilla_options def add_text(self, text): if len(text) <= 0: pass elif text[0] == "@": match = re.match('@(\S+)\s*(.*)', text) if not match: raise "Malformed option line: %s" % text option_type = match.group(1) data = match.group(2) if option_type == "arg": self.args = data elif option_type == "platform": self.platform = data elif option_type == "category": self.category = data elif option_type == "vanilla": self.vanilla_option = True elif option_type == "game": self.games = re.split(r'\s+', data.strip()) else: raise "Unknown option type '%s'" % option_type else: self.text += text + " " def _games_only_text(self, pattern="(%s only)"): if not match_game and self.games: games_list = ", ".join(map(str.capitalize, self.games)) return " " + (pattern % games_list) else: return "" def manpage_output(self): result = self.name if self.args: result += " " + self.args result = '\\fB' + result + '\\fR' result += "\n" if self.platform: result += "[%s only] " % self.platform escaped = re.sub('\\\\', '\\\\\\\\', self.text) result += escaped + self._games_only_text() + "\n" return result def wiki_output(self): result = self.name if self.args: result += " " + self.args result += ": " result += add_wiki_links(self.text) if self.platform: result += "'''(%s only)'''" % self.platform result += self._games_only_text("'''(%s only)'''") return result def plaintext_output(self, w): # Build the first line, with the argument on line = " " + self.name if self.args: line += " " + self.args # pad up to the plaintext width line += " " * (w - len(line)) # Build the description text description = self.text if self.platform: description += " (%s only)" % self.platform description += self._games_only_text() # Build the complete text for the argument # Split the description into words and add a word at a time result = "" for word in re.split('\s+', description): # Break onto the next line? if len(line) + len(word) + 1 > 75: result += line + "\n" line = " " * w # Add another word line += word + " " result += line + "\n\n" return result # Read list of wiki pages def read_wikipages(): f = open("wikipages") try: for line in f: line = line.rstrip() line = re.sub('\#.*$', '', line) if not re.match('^\s*$', line): wikipages.append(line) finally: f.close() # Add wiki page links def add_wiki_links(text): for pagename in wikipages: page_re = re.compile('(%s)' % pagename, re.IGNORECASE) # text = page_re.sub("SHOES", text) text = page_re.sub('[[\\1]]', text) return text def add_parameter(param, line, config_file): # If we're only targeting a particular game, check this is one of # the ones we're targeting. if match_game and param.games and match_game not in param.games: return # Is this documenting a command line parameter? match = re.search('(M_CheckParm(WithArgs)|M_ParmExists)?\s*\(\s*"(.*?)"', line) if match: param.name = match.group(3) categories[param.category].add_param(param) return # Documenting a configuration file variable? match = re.search('CONFIG_VARIABLE_\S+\s*\(\s*(\S+?)\),', line) if match: param.name = match.group(1) config_file.add_variable(param) return raise Exception(param.text) def process_file(file): current_config_file = None f = open(file) try: param = None waiting_for_checkparm = False for line in f: line = line.rstrip() # Ignore empty lines if re.match('\s*$', line): continue # Currently reading a doc comment? if param: # End of doc comment if not re.match('\s*//', line): waiting_for_checkparm = True # The first non-empty line after the documentation comment # ends must contain the thing being documented. if waiting_for_checkparm: add_parameter(param, line, current_config_file) param = None else: # More documentation text munged_line = re.sub('\s*\/\/\s*', '', line, 1) munged_line = re.sub('\s*$', '', munged_line) param.add_text(munged_line) # Check for start of a doc comment if re.search("//!", line): match = re.search("@begin_config_file\s*(\S+)", line) if match: # Beginning a configuration file tagname = match.group(1) current_config_file = ConfigFile(tagname) config_files[tagname] = current_config_file else: # Start of a normal comment param = Parameter() waiting_for_checkparm = False finally: f.close() def process_files(path): # Process all C source files. if os.path.isdir(path): files = glob.glob(path + "/*.c") for file in files: process_file(file) else: # Special case to allow a single file to be specified as a target process_file(path) def print_template(template_file, content): f = open(template_file) try: for line in f: match = INCLUDE_STATEMENT_RE.search(line) if match: filename = match.group(1) print_template(filename, content) else: line = line.replace("@content", content) print(line.rstrip()) finally: f.close() def manpage_output(targets, template_file): content = "" for t in targets: content += t.manpage_output() + "\n" content = content.replace("-", "\\-") print_template(template_file, content) def wiki_output(targets, template): read_wikipages() for t in targets: print(t.wiki_output()) def plaintext_output(targets, template_file): content = "" for t in targets: content += t.plaintext_output() + "\n" print_template(template_file, content) def usage(): print("Usage: %s [-V] [-c tag] [-g game] ( -m | -w | -p ) ..." \ % sys.argv[0]) print(" -c : Provide documentation for the specified configuration file") print(" (matches the given tag name in the source file)") print(" -m : Manpage output") print(" -w : Wikitext output") print(" -p : Plaintext output") print(" -V : Don't show Vanilla Doom options") print(" -g : Only document options for specified game.") sys.exit(0) # Parse command line opts, args = getopt.getopt(sys.argv[1:], "m:wp:c:g:V") output_function = None template = None doc_config_file = None match_game = None for opt in opts: if opt[0] == "-m": output_function = manpage_output template = opt[1] elif opt[0] == "-w": output_function = wiki_output elif opt[0] == "-p": output_function = plaintext_output template = opt[1] elif opt[0] == "-V": show_vanilla_options = False elif opt[0] == "-c": doc_config_file = opt[1] elif opt[0] == "-g": match_game = opt[1] if output_function == None or len(args) < 1: usage() else: # Process specified files for path in args: process_files(path) # Build a list of things to document documentation_targets = [] if doc_config_file: documentation_targets.append(config_files[doc_config_file]) else: documentation_targets.append(categories[None]) for c in categories: if c != None: documentation_targets.append(categories[c]) # Generate the output output_function(documentation_targets, template) chocolate-doom-chocolate-doom-2.2.1/man/doom.template000066400000000000000000000025311257432200600225540ustar00rootroot00000000000000.TH chocolate\-doom 6 .SH NAME chocolate\-doom \- historically compatible Doom engine .SH SYNOPSIS .B chocolate\-doom [\fIOPTIONS\fR] .SH DESCRIPTION .PP Chocolate Doom is a port of Id Software's 1993 game "Doom" that is designed to behave as similar to the original DOS version of Doom as is possible. .br @content .SH IWAD SEARCH PATHS @include iwad_paths.man .SH ENVIRONMENT This section describes environment variables that control Chocolate Doom's behavior. @include environ.man .SH FILES .TP \fB$HOME/.chocolate-doom/default.cfg\fR The main configuration file for Chocolate Doom. See \fBdefault.cfg\fR(5). .TP \fB$HOME/.chocolate-doom/chocolate-doom.cfg\fR Extra configuration values that are specific to Chocolate Doom and not present in Vanilla Doom. See \fBchocolate-doom.cfg\fR(5). .SH SEE ALSO \fBchocolate-server\fR(6), \fBchocolate-setup\fR(6), \fBchocolate-heretic\fR(6), \fBchocolate-hexen\fR(6), \fBchocolate-strife\fR(6) .SH AUTHOR Chocolate Doom is written and maintained by Simon Howard. It is based on the LinuxDoom source code, released by Id Software. .SH COPYRIGHT Copyright \(co id Software Inc. Copyright \(co 2005-2013 Simon Howard. .br This is free software. You may redistribute copies of it under the terms of the GNU General Public License . There is NO WARRANTY, to the extent permitted by law. chocolate-doom-chocolate-doom-2.2.1/man/environ.man000066400000000000000000000017031257432200600222360ustar00rootroot00000000000000.TP \fBDOOMWADDIR\fR, \fBDOOMWADPATH\fR See the section, \fBIWAD SEARCH PATHS\fR above. .TP \fBPCSOUND_DRIVER\fR When running in PC speaker sound effect mode, this environment variable specifies a PC speaker driver to use for sound effect playback. Valid options are "Linux" for the Linux console mode driver, "BSD" for the NetBSD/OpenBSD PC speaker driver, and "SDL" for SDL-based emulated PC speaker playback (using the digital output). .TP \fBOPL_DRIVER\fR When using OPL MIDI playback, this environment variable specifies an OPL backend driver to use. Valid options are "SDL" for an SDL-based software emulated OPL chip, "Linux" for the Linux hardware OPL driver, and "OpenBSD" for the OpenBSD/NetBSD hardware OPL driver. Generally speaking, a real hardware OPL chip sounds better than software emulation; however, modern machines do not often include one. If present, it may still require extra work to set up and elevated security privileges to access. chocolate-doom-chocolate-doom-2.2.1/man/extra.cfg.template000066400000000000000000000016161257432200600235020ustar00rootroot00000000000000.TH chocolate-doom.cfg 5 .SH NAME chocolate-doom.cfg \- Chocolate Doom configuration file .SH DESCRIPTION .PP \fIchocolate-doom.cfg\fR is a configuration file for \fBchocolate-doom\fR(6). This file acts as an auxiliary configuration file; the main configuration options are stored in \fBdefault.cfg\fR, which contains the same configuration options as Vanilla Doom (for compatibility). \fIchocolate-doom.cfg\fR contains configuration options that are specific to Chocolate Doom only. .PP \fIchocolate-doom.cfg\fR is normally stored in the user's home directory, as \fI~/.chocolate-doom/chocolate-doom.cfg\fR. .PP The \fBchocolate-setup\fR(6) tool provides a simple to use front-end for editing \fIchocolate-doom.cfg\fR. .SH FILE FORMAT .PP The file format is the same as that used for \fBdefault.cfg\fR(5). .br @content .SH SEE ALSO \fBchocolate-doom\fR(6), \fBdefault.cfg\fR(5), \fBchocolate-setup\fR(6) chocolate-doom-chocolate-doom-2.2.1/man/heretic.template000066400000000000000000000026441257432200600232460ustar00rootroot00000000000000.TH chocolate\-heretic 6 .SH NAME chocolate\-heretic \- historically compatible Heretic engine .SH SYNOPSIS .B chocolate\-heretic [\fIOPTIONS\fR] .SH DESCRIPTION .PP Chocolate Heretic is a port of Raven Software's 1994 game "Heretic" that aims to behave as similar to the original DOS version of Heretic as possible. .br @content .SH IWAD SEARCH PATHS @include iwad_paths.man .SH ENVIRONMENT This section describes environment variables that control Chocolate Heretic's behavior. @include environ.man .SH FILES .TP \fB$HOME/.chocolate-doom/heretic.cfg\fR The main configuration file for Chocolate Heretic. See \fBheretic.cfg\fR(5). .TP \fB$HOME/.chocolate-doom/chocolate-heretic.cfg\fR Extra configuration values that are specific to Chocolate Heretic and not present in Vanilla Heretic. See \fBchocolate-heretic.cfg\fR(5). .SH SEE ALSO \fBchocolate-doom\fR(6), \fBchocolate-hexen\fR(6), \fBchocolate-server\fR(6), \fBchocolate-setup\fR(6) .SH AUTHOR Chocolate Heretic is part of the Chocolate Doom project, written and maintained by Simon Howard. It is based on the Heretic source code, released by Raven Software. .SH COPYRIGHT Copyright \(co id Software Inc. Copyright \(co Raven Software Inc. Copyright \(co 2005-2013 Simon Howard. .br This is free software. You may redistribute copies of it under the terms of the GNU General Public License . There is NO WARRANTY, to the extent permitted by law. chocolate-doom-chocolate-doom-2.2.1/man/hexen.template000066400000000000000000000026051257432200600227270ustar00rootroot00000000000000.TH chocolate\-hexen 6 .SH NAME chocolate\-hexen \- historically compatible Hexen engine .SH SYNOPSIS .B chocolate\-hexen [\fIOPTIONS\fR] .SH DESCRIPTION .PP Chocolate Hexen is a port of Raven Software's 1995 game "Hexen" that aims to behave as similar to the original DOS version of Hexen as possible. .br @content .SH IWAD SEARCH PATHS @include iwad_paths.man .SH ENVIRONMENT This section describes environment variables that control Chocolate Hexen's behavior. @include environ.man .SH FILES .TP \fB$HOME/.chocolate-doom/hexen.cfg\fR The main configuration file for Chocolate Hexen. See \fBhexen.cfg\fR(5). .TP \fB$HOME/.chocolate-doom/chocolate-hexen.cfg\fR Extra configuration values that are specific to Chocolate Hexen and not present in Vanilla Hexen. See \fBchocolate-hexen.cfg\fR(5). .SH SEE ALSO \fBchocolate-doom\fR(6), \fBchocolate-heretic\fR(6), \fBchocolate-server\fR(6), \fBchocolate-setup\fR(6) .SH AUTHOR Chocolate Hexen is part of the Chocolate Doom project, written and maintained by Simon Howard. It is based on the Hexen source code, released by Raven Software. .SH COPYRIGHT Copyright \(co id Software Inc. Copyright \(co Raven Software Inc. Copyright \(co 2005-2013 Simon Howard. .br This is free software. You may redistribute copies of it under the terms of the GNU General Public License . There is NO WARRANTY, to the extent permitted by law. chocolate-doom-chocolate-doom-2.2.1/man/iwad_paths.man000066400000000000000000000041441257432200600227030ustar00rootroot00000000000000To play, an IWAD file is needed. This is a large file containing all of the levels, graphics, sound effects, music and other material that make up the game. IWAD files are named according to the game; the standard names are: .TP \fBdoom.wad, doom1.wad, doom2.wad, tnt.wad, plutonia.wad\fR Doom, Doom II, Final Doom .TP \fBheretic.wad, heretic1.wad, hexen.wad, strife1.wad\fR Heretic, Hexen and Strife (commercial Doom engine games). .TP \fBhacx.wad, chex.wad\fR Hacx and Chex Quest - more obscure games based on the Doom engine. .TP \fBfreedm.wad, freedoom1.wad, freedoom2.wad\fR The Freedoom open content IWAD files. .LP The following directory paths are searched in order to find an IWAD: .TP \fBCurrent working directory\fR Any IWAD files found in the current working directory will be used in preference to IWADs found in any other directories. .TP \fBDOOMWADDIR\fR This environment variable can be set to contain a path to a single directory in which to look for IWAD files. This environment variable is supported by most Doom source ports. .TP \fBDOOMWADPATH\fR This environment variable, if set, can contain a colon-separated list of directories in which to look for IWAD files, or alternatively full paths to specific IWAD files. .TP \fB$HOME/.local/share/games/doom\fR Writeable directory in the user's home directory. The path can be overridden using the \fBXDG_DATA_HOME\fR environment variable (see the XDG Base Directory Specification). .TP \fB/usr/local/share/games/doom, /usr/share/games/doom\fR System-wide locations that can be accessed by all users. The path \fB/usr/share/games/doom\fR is a standard path that is supported by most Doom source ports. These paths can be overridden using the \fBXDG_DATA_DIRS\fR environment variable (see the XDG Base Directory Specification). .LP The above can be overridden on a one-time basis by using the \fB\-iwad\fR command line parameter to provide the path to an IWAD file to use. This parameter can also be used to specify the name of a particular IWAD to use from one of the above paths. For example, '\fB-iwad doom.wad\fR' will search the above paths for the file \fBdoom.wad\fR to use. chocolate-doom-chocolate-doom-2.2.1/man/simplecpp000077500000000000000000000126601257432200600220070ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Contributors to the Freedoom project. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the freedoom project nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER # OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # simple cpp-style preprocessor # # Understands most features of the C preprocessor, including: # #if .. #elif .. #else .. #endif # - with expressions # #ifdef # #define # #include # import collections import sys import re debug = False defines = collections.defaultdict(lambda: False) command_re = re.compile(r"\#(\w+)(\s+(.*))?") include_re = re.compile(r"\s*\"(.*)\"\s*") define_re = re.compile(r"\s*(\S+)\s*(.*?)\s*$") def debug_msg(message): if debug: sys.stderr.write(message) # Parse command line options def parse_cmdline(): for arg in sys.argv[1:]: if not arg.startswith("-D"): continue name = arg[2:] if '=' in name: name, value = name.split('=', 1) else: value = True defines[name] = value def parse_stream(stream): result = read_block(stream, False) if result is not None: raise Exception("Mismatched #if in '%s'" % stream.name) def parse_file(filename): f = open(filename) try: parse_stream(f) finally: f.close() # Evaluate an expression using Python's eval() function. def eval_expr(expr): expr = expr.replace("||", " or ") \ .replace("&&", " and ") \ .replace("!", "not ") code = compile(expr, "", "eval") result = eval(code, {}, defines) return result # #include def cmd_include(arg): # Extract the filename match = include_re.match(arg) if not match: raise Exception("Invalid 'include' command") filename = match.group(1) # Open the file and process it parse_file(filename) # #define def cmd_define(arg): match = define_re.match(arg) name = match.group(1) value = match.group(2) if value == '': value = True defines[name] = value # #undef def cmd_undef(arg): if arg in defines: del defines[arg] # #ifdef/#ifndef def cmd_ifdef(arg, command, stream, ignore): # Get the define name debug_msg("%s %s >\n" % (command, arg)) # Should we ignore the contents of this block? sub_ignore = not eval_expr(arg) if "n" in command: sub_ignore = not sub_ignore # Parse the block result, newarg = read_block(stream, ignore or sub_ignore) debug_msg("%s %s < (%s)\n" % (command, arg, result)) # There may be a second "else" block to parse: if result == "else": debug_msg("%s %s else >\n" % (command, arg)) result, arg = read_block(stream, ignore or (not sub_ignore)) debug_msg("%s %s else < (%s)\n" % (command, arg, result)) if result == "elif": debug_msg("%s %s elif %s>\n" % (command, arg, newarg)) cmd_ifdef(newarg, "if", stream, ignore or (not sub_ignore)) result = "endif" # Should end in an endif: if result != "endif": raise Exception("'if' block did not end in an 'endif'") commands = { "include" : cmd_include, "define" : cmd_define, "undef" : cmd_undef, "if" : cmd_ifdef, "ifdef" : cmd_ifdef, "ifn" : cmd_ifdef, "ifndef" : cmd_ifdef, } # Recursive block reading function # if 'ignore' argument is 1, contents are ignored def read_block(stream, ignore): for line in stream: # Remove newline line = line[0:-1] # Check if this line has a command match = command_re.match(line) if match: command = match.group(1) arg = match.group(3) if command in ("else", "elif", "endif"): return (command, arg) elif command not in commands: raise Exception("Unknown command: '%s'" % \ command) # Get the callback function. func = commands[command] # Invoke the callback function. #ifdef commands # are a special case and need extra arguments. # Other commands are only executed if we are not # ignoring this block. if func == cmd_ifdef: cmd_ifdef(arg, command=command, stream=stream, ignore=ignore) elif not ignore: func(arg) else: if not ignore: for key, value in defines.items(): if isinstance(value, str): line = line.replace(key, value) print(line) parse_cmdline() parse_stream(sys.stdin) chocolate-doom-chocolate-doom-2.2.1/man/strife.template000066400000000000000000000070241257432200600231140ustar00rootroot00000000000000.TH chocolate\-strife 6 .SH NAME chocolate\-strife \- historically compatible strife engine .SH SYNOPSIS .B chocolate\-strife [\fIOPTIONS\fR] .SH DESCRIPTION .PP Chocolate Strife is an accurate and complete recreation of Rogue Entertainment's "Strife: Quest for the Sigil". It was created through more than two years of reverse engineering effort with the blessings of the original programmers of the game (see the section HISTORY below). @content .SH IWAD SEARCH PATHS @include iwad_paths.man .SH ENVIRONMENT This section describes environment variables that control Chocolate Strife's behavior. @include environ.man .SH FILES .TP \fB$HOME/.chocolate-doom/strife.cfg\fR The main configuration file for Chocolate Strife. See \fBstrife.cfg\fR(5). .TP \fB$HOME/.chocolate-doom/chocolate-strife.cfg\fR Extra configuration values that are specific to Chocolate Strife and not present in Vanilla Strife. See \fBchocolate-strife.cfg\fR(5). .SH SEE ALSO \fBchocolate-doom\fR(6), \fBchocolate-server\fR(6), \fBchocolate-setup\fR(6) .SH HISTORY The source code for Strife was lost, which means, unlike the code for all the other commercial DOOM-engine games, it cannot be released. The only access we have to the code is the binary executable file. Reverse engineering tools were employed to disassemble and decompile the executables, which were cross- referenced against the Linux DOOM and DOS Heretic sources and painstakingly combed over multiple times, instruction-by-instruction, to ensure that the resulting Chocolate-Doom-based executable is as close as possible to the original. .SH LEGALITY Reverse engineering is a protected activity so long as the original code is not used directly in the product. Due to the vast amount of information lost through the process of compilation, and the need to refactor large portions of code in order to eliminate non-portable idioms or to adapt them properly to Chocolate Doom's framework, the resulting code behaves the same, but is not the *same* code. In addition, James Monroe and John Carmack have both stated that they have no objections to the project. Because they are the original authors of the code, and neither Rogue nor their publisher, Velocity, Inc., exist any longer as legal entities, this is effectively legal permission. .SH BUGS Chocolate Strife is almost, but not entirely perfect, in recreating the behavior of Vanilla Strife. Help us by reporting any discrepancies you might notice between this executable and the vanilla DOS program. However, do *not* report any glitch that you can replicate in the vanilla EXE as a bug. The point of Chocolate Strife, like Chocolate Doom before it, is to be as bug-compatible with the original game as possible. Also be aware that some glitches are impossible to compatibly recreate, and wherever this is the case, Chocolate Strife has erred on the side of not crashing the program, for example by initializing pointers to NULL rather than using them without setting a value first. .SH AUTHORS Chocolate Strife is part of the Chocolate Doom project. It was reverse engineered from the DOS versions of Strife by James Haley and Samuel Villarreal. Chocolate Doom was written and maintained by Simon Howard, and is based on the LinuxDoom source code released by Id Software. .SH COPYRIGHT Copyright \(co id Software Inc. Copyright \(co 2005-2013 Simon Howard, James Haley, Samuel Villarreal. .br This is free software. You may redistribute copies of it under the terms of the GNU General Public License . There is NO WARRANTY, to the extent permitted by law. chocolate-doom-chocolate-doom-2.2.1/man/wikipages000066400000000000000000000002421257432200600217640ustar00rootroot00000000000000# This is a list of wiki pages to automatically link to when generating # wikitext output. Dehacked Doom 1.91 Configuration Merging Multiplayer Three screen mode chocolate-doom-chocolate-doom-2.2.1/msvc/000077500000000000000000000000001257432200600202555ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/msvc/.gitignore000066400000000000000000000000621257432200600222430ustar00rootroot00000000000000*.cfg *.ncb *.suo *.user savegames strfsav* *.pcx chocolate-doom-chocolate-doom-2.2.1/msvc/README000066400000000000000000000003311257432200600211320ustar00rootroot00000000000000Project and header files for building with Microsoft Visual C++. Please note that the MSVC project files are not officially supported; the canonical way to build Chocolate Doom under Windows is using MingW + MSYS. chocolate-doom-chocolate-doom-2.2.1/msvc/chocolate.sln000066400000000000000000000134441257432200600227420ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Doom", "doom.vcproj", "{8B744A3B-8F18-41A0-85A3-293816E85B6E}" ProjectSection(ProjectDependencies) = postProject {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} = {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} {66CD7F50-73B9-482F-8B69-1AF54983F845} = {66CD7F50-73B9-482F-8B69-1AF54983F845} {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Heretic", "heretic.vcproj", "{8D4FF322-7414-4668-94BD-D63B45D9CBF8}" ProjectSection(ProjectDependencies) = postProject {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} = {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} {66CD7F50-73B9-482F-8B69-1AF54983F845} = {66CD7F50-73B9-482F-8B69-1AF54983F845} {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hexen", "hexen.vcproj", "{8FBB8720-340B-4185-9442-A76781FD6278}" ProjectSection(ProjectDependencies) = postProject {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} = {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} {66CD7F50-73B9-482F-8B69-1AF54983F845} = {66CD7F50-73B9-482F-8B69-1AF54983F845} {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server", "server.vcproj", "{10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Setup", "setup.vcproj", "{01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}" ProjectSection(ProjectDependencies) = postProject {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcsound", "libpcsound.vcproj", "{66CD7F50-73B9-482F-8B69-1AF54983F845}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtextscreen", "libtextscreen.vcproj", "{35F435DB-AC4A-4F28-BA2D-812E638FB01A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Strife", "strife.vcproj", "{FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}" ProjectSection(ProjectDependencies) = postProject {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} = {FC8D0610-1507-4F36-99BC-6F5A422B6AD3} {66CD7F50-73B9-482F-8B69-1AF54983F845} = {66CD7F50-73B9-482F-8B69-1AF54983F845} {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libopl", "libopl.vcproj", "{FC8D0610-1507-4F36-99BC-6F5A422B6AD3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug|Win32.ActiveCfg = Debug|Win32 {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug|Win32.Build.0 = Debug|Win32 {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release|Win32.ActiveCfg = Release|Win32 {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release|Win32.Build.0 = Release|Win32 {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Debug|Win32.ActiveCfg = Debug|Win32 {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Debug|Win32.Build.0 = Debug|Win32 {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Release|Win32.ActiveCfg = Release|Win32 {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Release|Win32.Build.0 = Release|Win32 {8FBB8720-340B-4185-9442-A76781FD6278}.Debug|Win32.ActiveCfg = Debug|Win32 {8FBB8720-340B-4185-9442-A76781FD6278}.Debug|Win32.Build.0 = Debug|Win32 {8FBB8720-340B-4185-9442-A76781FD6278}.Release|Win32.ActiveCfg = Release|Win32 {8FBB8720-340B-4185-9442-A76781FD6278}.Release|Win32.Build.0 = Release|Win32 {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Debug|Win32.ActiveCfg = Debug|Win32 {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Debug|Win32.Build.0 = Debug|Win32 {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Release|Win32.ActiveCfg = Release|Win32 {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Release|Win32.Build.0 = Release|Win32 {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Debug|Win32.ActiveCfg = Debug|Win32 {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Debug|Win32.Build.0 = Debug|Win32 {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Release|Win32.ActiveCfg = Release|Win32 {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Release|Win32.Build.0 = Release|Win32 {66CD7F50-73B9-482F-8B69-1AF54983F845}.Debug|Win32.ActiveCfg = Debug|Win32 {66CD7F50-73B9-482F-8B69-1AF54983F845}.Debug|Win32.Build.0 = Debug|Win32 {66CD7F50-73B9-482F-8B69-1AF54983F845}.Release|Win32.ActiveCfg = Release|Win32 {66CD7F50-73B9-482F-8B69-1AF54983F845}.Release|Win32.Build.0 = Release|Win32 {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Debug|Win32.ActiveCfg = Debug|Win32 {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Debug|Win32.Build.0 = Debug|Win32 {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Release|Win32.ActiveCfg = Release|Win32 {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Release|Win32.Build.0 = Release|Win32 {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Debug|Win32.ActiveCfg = Debug|Win32 {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Debug|Win32.Build.0 = Debug|Win32 {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Release|Win32.ActiveCfg = Release|Win32 {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Release|Win32.Build.0 = Release|Win32 {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Debug|Win32.ActiveCfg = Debug|Win32 {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Debug|Win32.Build.0 = Debug|Win32 {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Release|Win32.ActiveCfg = Release|Win32 {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal chocolate-doom-chocolate-doom-2.2.1/msvc/config.h000066400000000000000000000017021257432200600216730ustar00rootroot00000000000000/* config.h for MSVC builds. This is just the config.h created by * configure. */ /* Name of package */ #define PACKAGE "chocolate-doom" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "fraggle@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "Chocolate Doom" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "Chocolate Doom 2.2.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "chocolate-doom" /* Define to the version of this package. */ #define PACKAGE_VERSION "2.2.1" /* Change this when you create your awesome forked version */ #define PROGRAM_PREFIX "chocolate-" /* Version number of package */ #define VERSION "2.2.1" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ /* #undef WORDS_BIGENDIAN */ chocolate-doom-chocolate-doom-2.2.1/msvc/doom.vcproj000066400000000000000000000473231257432200600224510ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/heretic.vcproj000066400000000000000000000413771257432200600231410ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/hexen.vcproj000066400000000000000000000376471257432200600226320ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/inttypes.h000066400000000000000000000173031257432200600223110ustar00rootroot00000000000000// ISO C9x compliant inttypes.h for Miscrosoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #include // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_INTTYPES_H_ ] chocolate-doom-chocolate-doom-2.2.1/msvc/libopl.vcproj000066400000000000000000000113721257432200600227670ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/libpcsound.vcproj000066400000000000000000000101521257432200600236430ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/libtextscreen.vcproj000066400000000000000000000162031257432200600243570ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/server.vcproj000066400000000000000000000146271257432200600230220ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/setup.vcproj000066400000000000000000000212011257432200600226360ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/stdint.h000066400000000000000000000145471257432200600217460ustar00rootroot00000000000000// ISO C9x compliant stdint.h for Miscrosoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif #include #include #include // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers typedef INT_PTR intptr_t; typedef UINT_PTR uintptr_t; // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN _I8_MIN #define INT8_MAX _I8_MAX #define INT16_MIN _I16_MIN #define INT16_MAX _I16_MAX #define INT32_MIN _I32_MIN #define INT32_MAX _I32_MAX #define INT64_MIN _I64_MIN #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val #define INT16_C(val) val #define INT32_C(val) val##L #define INT64_C(val) val##i64 #define UINT8_C(val) val #define UINT16_C(val) val #define UINT32_C(val) val##UL #define UINT64_C(val) val##Ui64 // 7.18.4.2 Macros for greatest-width integer constants #define INTMAX_C INT64_C #define UINTMAX_C UINT64_C #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_STDINT_H_ ] chocolate-doom-chocolate-doom-2.2.1/msvc/strife.vcproj000066400000000000000000000506541257432200600230100ustar00rootroot00000000000000 chocolate-doom-chocolate-doom-2.2.1/msvc/win32.rc000066400000000000000000000030041257432200600215420ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // Copyright(C) 2008 "GhostlyDeath" (ghostlydeath@gmail.com) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Win32 Resources // #ifndef DEDICATEDSERVER #ifdef CHOCOLATESETUP 1 ICON "../data/setup.ico" #else 1 ICON "../data/doom.ico" #endif #endif 1 VERSIONINFO PRODUCTVERSION 2,2,1,0 FILEVERSION 2,2,1,0 FILETYPE 1 BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "FileVersion", "1.0.0" VALUE "FileDescription", "Chocolate Doom 2.2.1" VALUE "InternalName", "chocolate-doom" VALUE "CompanyName", "fraggle@gmail.com" VALUE "LegalCopyright", "GNU General Public License" VALUE "ProductName", "Chocolate Doom" VALUE "ProductVersion", "2.2.1" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END // GhostlyDeath - Preferebly for codeblocks (if it even uses this RC!) #ifdef __MINGW32__ #ifdef CHOCOLATESETUP // RT_MANIFEST might NOT be defined 1 24 "../setup/setup-manifest.xml" #endif #endif chocolate-doom-chocolate-doom-2.2.1/msvc/win_opendir.c000066400000000000000000000172331257432200600227440ustar00rootroot00000000000000// // 03/10/2006 James Haley // // For this module only: // This code is public domain. No change sufficient enough to constitute a // significant or original work has been made, and thus it remains as such. // // // DESCRIPTION: // // Implementation of POSIX opendir for Visual C++. // Derived from the MinGW C Library Extensions Source (released to the // public domain). As with other Win32 modules, don't include most DOOM // headers into this or conflicts will occur. // // Original Header: // // * dirent.c // * This file has no copyright assigned and is placed in the Public Domain. // * This file is a part of the mingw-runtime package. // * No warranty is given; refer to the file DISCLAIMER within the package. // * // * Derived from DIRLIB.C by Matt J. Weinstein // * This note appears in the DIRLIB.H // * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 // * // * Updated by Jeremy Bettis // * Significantly revised and rewinddir, seekdir and telldir added by Colin // * Peters // #ifndef _MSC_VER #error i_opndir.c is for Microsoft Visual C++ only #endif #include #include #include #define WIN32_LEAN_AND_MEAN #include /* for GetFileAttributes */ #include #define SUFFIX _T("*") #define SLASH _T("\\") #include "win_opendir.h" // // opendir // // Returns a pointer to a DIR structure appropriately filled in to begin // searching a directory. // DIR *opendir(const _TCHAR *szPath) { DIR *nd; unsigned int rc; _TCHAR szFullPath[MAX_PATH]; errno = 0; if(!szPath) { errno = EFAULT; return (DIR *)0; } if(szPath[0] == _T('\0')) { errno = ENOTDIR; return (DIR *)0; } /* Attempt to determine if the given path really is a directory. */ rc = GetFileAttributes(szPath); if(rc == (unsigned int)-1) { /* call GetLastError for more error info */ errno = ENOENT; return (DIR *)0; } if(!(rc & FILE_ATTRIBUTE_DIRECTORY)) { /* Error, entry exists but not a directory. */ errno = ENOTDIR; return (DIR *)0; } /* Make an absolute pathname. */ _tfullpath(szFullPath, szPath, MAX_PATH); /* Allocate enough space to store DIR structure and the complete * directory path given. */ nd = (DIR *)(malloc(sizeof(DIR) + (_tcslen(szFullPath) + _tcslen(SLASH) + _tcslen(SUFFIX) + 1) * sizeof(_TCHAR))); if(!nd) { /* Error, out of memory. */ errno = ENOMEM; return (DIR *)0; } /* Create the search expression. */ _tcscpy(nd->dd_name, szFullPath); /* Add on a slash if the path does not end with one. */ if(nd->dd_name[0] != _T('\0') && _tcsrchr(nd->dd_name, _T('/')) != nd->dd_name + _tcslen(nd->dd_name) - 1 && _tcsrchr(nd->dd_name, _T('\\')) != nd->dd_name + _tcslen(nd->dd_name) - 1) { _tcscat(nd->dd_name, SLASH); } /* Add on the search pattern */ _tcscat(nd->dd_name, SUFFIX); /* Initialize handle to -1 so that a premature closedir doesn't try * to call _findclose on it. */ nd->dd_handle = -1; /* Initialize the status. */ nd->dd_stat = 0; /* Initialize the dirent structure. ino and reclen are invalid under * Win32, and name simply points at the appropriate part of the * findfirst_t structure. */ nd->dd_dir.d_ino = 0; nd->dd_dir.d_reclen = 0; nd->dd_dir.d_namlen = 0; memset(nd->dd_dir.d_name, 0, FILENAME_MAX); return nd; } // // readdir // // Return a pointer to a dirent structure filled with the information on the // next entry in the directory. // struct dirent *readdir(DIR *dirp) { errno = 0; /* Check for valid DIR struct. */ if(!dirp) { errno = EFAULT; return (struct dirent *)0; } if (dirp->dd_stat < 0) { /* We have already returned all files in the directory * (or the structure has an invalid dd_stat). */ return (struct dirent *)0; } else if (dirp->dd_stat == 0) { /* We haven't started the search yet. */ /* Start the search */ dirp->dd_handle = _tfindfirst(dirp->dd_name, &(dirp->dd_dta)); if(dirp->dd_handle == -1) { /* Whoops! Seems there are no files in that * directory. */ dirp->dd_stat = -1; } else { dirp->dd_stat = 1; } } else { /* Get the next search entry. */ if(_tfindnext(dirp->dd_handle, &(dirp->dd_dta))) { /* We are off the end or otherwise error. _findnext sets errno to ENOENT if no more file Undo this. */ DWORD winerr = GetLastError(); if(winerr == ERROR_NO_MORE_FILES) errno = 0; _findclose(dirp->dd_handle); dirp->dd_handle = -1; dirp->dd_stat = -1; } else { /* Update the status to indicate the correct * number. */ dirp->dd_stat++; } } if (dirp->dd_stat > 0) { /* Successfully got an entry. Everything about the file is * already appropriately filled in except the length of the * file name. */ dirp->dd_dir.d_namlen = _tcslen(dirp->dd_dta.name); _tcscpy(dirp->dd_dir.d_name, dirp->dd_dta.name); return &dirp->dd_dir; } return (struct dirent *)0; } // // closedir // // Frees up resources allocated by opendir. // int closedir(DIR *dirp) { int rc; errno = 0; rc = 0; if(!dirp) { errno = EFAULT; return -1; } if(dirp->dd_handle != -1) { rc = _findclose(dirp->dd_handle); } /* Delete the dir structure. */ free(dirp); return rc; } // // rewinddir // // Return to the beginning of the directory "stream". We simply call findclose // and then reset things like an opendir. // void rewinddir(DIR * dirp) { errno = 0; if(!dirp) { errno = EFAULT; return; } if(dirp->dd_handle != -1) { _findclose(dirp->dd_handle); } dirp->dd_handle = -1; dirp->dd_stat = 0; } // // telldir // // Returns the "position" in the "directory stream" which can be used with // seekdir to go back to an old entry. We simply return the value in stat. // long telldir(DIR *dirp) { errno = 0; if(!dirp) { errno = EFAULT; return -1; } return dirp->dd_stat; } // // seekdir // // Seek to an entry previously returned by telldir. We rewind the directory // and call readdir repeatedly until either dd_stat is the position number // or -1 (off the end). This is not perfect, in that the directory may // have changed while we weren't looking. But that is probably the case with // any such system. // void seekdir(DIR *dirp, long lPos) { errno = 0; if(!dirp) { errno = EFAULT; return; } if(lPos < -1) { /* Seeking to an invalid position. */ errno = EINVAL; return; } else if(lPos == -1) { /* Seek past end. */ if(dirp->dd_handle != -1) { _findclose(dirp->dd_handle); } dirp->dd_handle = -1; dirp->dd_stat = -1; } else { /* Rewind and read forward to the appropriate index. */ rewinddir(dirp); while((dirp->dd_stat < lPos) && readdir(dirp)) ; /* do-nothing loop */ } } // EOF chocolate-doom-chocolate-doom-2.2.1/msvc/win_opendir.h000066400000000000000000000033341257432200600227460ustar00rootroot00000000000000// // 03/10/2006 James Haley // // For this module only: // This code is public domain. No change sufficient enough to constitute a // significant or original work has been made, and thus it remains as such. // // // DESCRIPTION: // // Implementation of POSIX opendir for Visual C++. // Derived from the MinGW C Library Extensions Source (released to the // public domain). // #ifndef I_OPNDIR_H__ #define I_OPNDIR_H__ #include #ifndef FILENAME_MAX #define FILENAME_MAX 260 #endif struct dirent { long d_ino; /* Always zero. */ unsigned short d_reclen; /* Always zero. */ unsigned short d_namlen; /* Length of name in d_name. */ char d_name[FILENAME_MAX]; /* File name. */ }; /* * This is an internal data structure. Good programmers will not use it * except as an argument to one of the functions below. * dd_stat field is now int (was short in older versions). */ typedef struct { /* disk transfer area for this dir */ struct _finddata_t dd_dta; /* dirent struct to return from dir (NOTE: this makes this thread * safe as long as only one thread uses a particular DIR struct at * a time) */ struct dirent dd_dir; /* _findnext handle */ long dd_handle; /* * Status of search: * 0 = not started yet (next entry to read is first entry) * -1 = off the end * positive = 0 based index of next entry */ int dd_stat; /* given path for dir with search pattern (struct is extended) */ char dd_name[1]; } DIR; DIR *opendir(const char *); struct dirent *readdir(DIR *); int closedir(DIR *); void rewinddir(DIR *); long telldir(DIR *); void seekdir(DIR *, long); #endif // EOF chocolate-doom-chocolate-doom-2.2.1/opl/000077500000000000000000000000001257432200600200775ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/opl/.gitignore000066400000000000000000000000631257432200600220660ustar00rootroot00000000000000Makefile.in Makefile .deps libopl.a *.rc tags TAGS chocolate-doom-chocolate-doom-2.2.1/opl/Makefile.am000066400000000000000000000011741257432200600221360ustar00rootroot00000000000000 AM_CFLAGS=@SDLMIXER_CFLAGS@ SUBDIRS = . examples noinst_LIBRARIES=libopl.a libopl_a_SOURCES = \ opl_internal.h \ opl.c opl.h \ opl_linux.c \ opl_obsd.c \ opl_queue.c opl_queue.h \ opl_sdl.c \ opl_timer.c opl_timer.h \ opl_win32.c \ ioperm_sys.c ioperm_sys.h \ dbopl.c dbopl.h chocolate-doom-chocolate-doom-2.2.1/opl/dbopl.c000066400000000000000000001372041257432200600213520ustar00rootroot00000000000000/* * Copyright (C) 2002-2010 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ // // Chocolate Doom-related discussion: // // This is the DosBox OPL emulator code (src/hardware/dbopl.cpp) r3635, // converted to C. The bulk of the work was done using the minus-minus // script in the Chocolate Doom SVN repository, then the result tweaked // by hand until working. // /* DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 Except for the table generation it's all integer math Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms The generation was based on the MAME implementation but tried to have it use less memory and be faster in general MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times //TODO Don't delay first operator 1 sample in opl3 mode //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? //TODO Check if having the same accuracy in all frequency multipliers sounds better or not //DUNNO Keyon in 4op, switch to 2op without keyoff. */ /* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */ #include #include #include //#include "dosbox.h" #include "dbopl.h" #define GCC_UNLIKELY(x) x #define TRUE 1 #define FALSE 0 #ifndef PI #define PI 3.14159265358979323846 #endif #define OPLRATE ((double)(14318180.0 / 288.0)) #define TREMOLO_TABLE 52 //Try to use most precision for frequencies //Else try to keep different waves in synch //#define WAVE_PRECISION 1 #ifndef WAVE_PRECISION //Wave bits available in the top of the 32bit range //Original adlib uses 10.10, we use 10.22 #define WAVE_BITS 10 #else //Need some extra bits at the top to have room for octaves and frequency multiplier //We support to 8 times lower rate //128 * 15 * 8 = 15350, 2^13.9, so need 14 bits #define WAVE_BITS 14 #endif #define WAVE_SH ( 32 - WAVE_BITS ) #define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 ) //Use the same accuracy as the waves #define LFO_SH ( WAVE_SH - 10 ) //LFO is controlled by our tremolo 256 sample limit #define LFO_MAX ( 256 << ( LFO_SH ) ) //Maximum amount of attenuation bits //Envelope goes to 511, 9 bits #if (DBOPL_WAVE == WAVE_TABLEMUL ) //Uses the value directly #define ENV_BITS ( 9 ) #else //Add 3 bits here for more accuracy and would have to be shifted up either way #define ENV_BITS ( 9 ) #endif //Limits of the envelope with those bits and when the envelope goes silent #define ENV_MIN 0 #define ENV_EXTRA ( ENV_BITS - 9 ) #define ENV_MAX ( 511 << ENV_EXTRA ) #define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) ) #define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT ) //Attack/decay/release rate counter shift #define RATE_SH 24 #define RATE_MASK ( ( 1 << RATE_SH ) - 1 ) //Has to fit within 16bit lookuptable #define MUL_SH 16 //Check some ranges #if ENV_EXTRA > 3 #error Too many envelope bits #endif static inline void Operator__SetState(Operator *self, Bit8u s ); static inline Bit32u Chip__ForwardNoise(Chip *self); // C++'s template<> sure is useful sometimes. static Channel* Channel__BlockTemplate(Channel *self, Chip* chip, Bit32u samples, Bit32s* output, SynthMode mode ); #define BLOCK_TEMPLATE(mode) \ static Channel* Channel__BlockTemplate_ ## mode(Channel *self, Chip* chip, \ Bit32u samples, Bit32s* output) \ { \ return Channel__BlockTemplate(self, chip, samples, output, mode); \ } BLOCK_TEMPLATE(sm2AM) BLOCK_TEMPLATE(sm2FM) BLOCK_TEMPLATE(sm3AM) BLOCK_TEMPLATE(sm3FM) BLOCK_TEMPLATE(sm3FMFM) BLOCK_TEMPLATE(sm3AMFM) BLOCK_TEMPLATE(sm3FMAM) BLOCK_TEMPLATE(sm3AMAM) BLOCK_TEMPLATE(sm2Percussion) BLOCK_TEMPLATE(sm3Percussion) //How much to substract from the base value for the final attenuation static const Bit8u KslCreateTable[16] = { //0 will always be be lower than 7 * 8 64, 32, 24, 19, 16, 12, 11, 10, 8, 6, 5, 4, 3, 2, 1, 0, }; #define M(_X_) ((Bit8u)( (_X_) * 2)) static const Bit8u FreqCreateTable[16] = { M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) }; #undef M //We're not including the highest attack rate, that gets a special value static const Bit8u AttackSamplesTable[13] = { 69, 55, 46, 40, 35, 29, 23, 20, 19, 15, 11, 10, 9 }; //On a real opl these values take 8 samples to reach and are based upon larger tables static const Bit8u EnvelopeIncreaseTable[13] = { 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, }; #if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) static Bit16u ExpTable[ 256 ]; #endif #if ( DBOPL_WAVE == WAVE_HANDLER ) //PI table used by WAVEHANDLER static Bit16u SinTable[ 512 ]; #endif #if ( DBOPL_WAVE > WAVE_HANDLER ) //Layout of the waveform table in 512 entry intervals //With overlapping waves we reduce the table to half it's size // | |//\\|____|WAV7|//__|/\ |____|/\/\| // |\\//| | |WAV7| | \/| | | // |06 |0126|17 |7 |3 |4 |4 5 |5 | //6 is just 0 shifted and masked static Bit16s WaveTable[ 8 * 512 ]; //Distance into WaveTable the wave starts static const Bit16u WaveBaseTable[8] = { 0x000, 0x200, 0x200, 0x800, 0xa00, 0xc00, 0x100, 0x400, }; //Mask the counter with this static const Bit16u WaveMaskTable[8] = { 1023, 1023, 511, 511, 1023, 1023, 512, 1023, }; //Where to start the counter on at keyon static const Bit16u WaveStartTable[8] = { 512, 0, 0, 0, 0, 512, 512, 256, }; #endif #if ( DBOPL_WAVE == WAVE_TABLEMUL ) static Bit16u MulTable[ 384 ]; #endif static Bit8u KslTable[ 8 * 16 ]; static Bit8u TremoloTable[ TREMOLO_TABLE ]; //Start of a channel behind the chip struct start static Bit16u ChanOffsetTable[32]; //Start of an operator behind the chip struct start static Bit16u OpOffsetTable[64]; //The lower bits are the shift of the operator vibrato value //The highest bit is right shifted to generate -1 or 0 for negation //So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 static const Bit8s VibratoTable[ 8 ] = { 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 }; //Shift strength for the ksl value determined by ksl strength static const Bit8u KslShiftTable[4] = { 31,1,2,0 }; //Generate a table index and table shift value using input value from a selected rate static void EnvelopeSelect( Bit8u val, Bit8u *index, Bit8u *shift ) { if ( val < 13 * 4 ) { //Rate 0 - 12 *shift = 12 - ( val >> 2 ); *index = val & 3; } else if ( val < 15 * 4 ) { //rate 13 - 14 *shift = 0; *index = val - 12 * 4; } else { //rate 15 and up *shift = 0; *index = 12; } } #if ( DBOPL_WAVE == WAVE_HANDLER ) /* Generate the different waveforms out of the sine/exponetial table using handlers */ static inline Bits MakeVolume( Bitu wave, Bitu volume ) { Bitu total = wave + volume; Bitu index = total & 0xff; Bitu sig = ExpTable[ index ]; Bitu exp = total >> 8; #if 0 //Check if we overflow the 31 shift limit if ( exp >= 32 ) { LOG_MSG( "WTF %d %d", total, exp ); } #endif return (sig >> exp); }; static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 Bitu wave = SinTable[i & 511]; return (MakeVolume( wave, volume ) ^ neg) - neg; } static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { Bit32u wave = SinTable[i & 511]; wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); return MakeVolume( wave, volume ); } static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { Bitu wave = SinTable[i & 511]; return MakeVolume( wave, volume ); } static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { Bitu wave = SinTable[i & 255]; wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); return MakeVolume( wave, volume ); } static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { //Twice as fast i <<= 1; Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 Bitu wave = SinTable[i & 511]; wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); return (MakeVolume( wave, volume ) ^ neg) - neg; } static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { //Twice as fast i <<= 1; Bitu wave = SinTable[i & 511]; wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); return MakeVolume( wave, volume ); } static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 return (MakeVolume( 0, volume ) ^ neg) - neg; } static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { //Negative is reversed here Bits neg = (( i >> 9) & 1) - 1; Bitu wave = (i << 3); //When negative the volume also runs backwards wave = ((wave ^ neg) - neg) & 4095; return (MakeVolume( wave, volume ) ^ neg) - neg; } static const WaveHandler WaveHandlerTable[8] = { WaveForm0, WaveForm1, WaveForm2, WaveForm3, WaveForm4, WaveForm5, WaveForm6, WaveForm7 }; #endif /* Operator */ //We zero out when rate == 0 static inline void Operator__UpdateAttack(Operator *self, const Chip* chip ) { Bit8u rate = self->reg60 >> 4; if ( rate ) { Bit8u val = (rate << 2) + self->ksr; self->attackAdd = chip->attackRates[ val ]; self->rateZero &= ~(1 << ATTACK); } else { self->attackAdd = 0; self->rateZero |= (1 << ATTACK); } } static inline void Operator__UpdateDecay(Operator *self, const Chip* chip ) { Bit8u rate = self->reg60 & 0xf; if ( rate ) { Bit8u val = (rate << 2) + self->ksr; self->decayAdd = chip->linearRates[ val ]; self->rateZero &= ~(1 << DECAY); } else { self->decayAdd = 0; self->rateZero |= (1 << DECAY); } } static inline void Operator__UpdateRelease(Operator *self, const Chip* chip ) { Bit8u rate = self->reg80 & 0xf; if ( rate ) { Bit8u val = (rate << 2) + self->ksr; self->releaseAdd = chip->linearRates[ val ]; self->rateZero &= ~(1 << RELEASE); if ( !(self->reg20 & MASK_SUSTAIN ) ) { self->rateZero &= ~( 1 << SUSTAIN ); } } else { self->rateZero |= (1 << RELEASE); self->releaseAdd = 0; if ( !(self->reg20 & MASK_SUSTAIN ) ) { self->rateZero |= ( 1 << SUSTAIN ); } } } static inline void Operator__UpdateAttenuation(Operator *self) { Bit8u kslBase = (Bit8u)((self->chanData >> SHIFT_KSLBASE) & 0xff); Bit32u tl = self->reg40 & 0x3f; Bit8u kslShift = KslShiftTable[ self->reg40 >> 6 ]; //Make sure the attenuation goes to the right bits self->totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max self->totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; } static void Operator__UpdateFrequency(Operator *self) { Bit32u freq = self->chanData & (( 1 << 10 ) - 1); Bit32u block = (self->chanData >> 10) & 0xff; #ifdef WAVE_PRECISION block = 7 - block; self->waveAdd = ( freq * self->freqMul ) >> block; #else self->waveAdd = ( freq << block ) * self->freqMul; #endif if ( self->reg20 & MASK_VIBRATO ) { self->vibStrength = (Bit8u)(freq >> 7); #ifdef WAVE_PRECISION self->vibrato = ( self->vibStrength * self->freqMul ) >> block; #else self->vibrato = ( self->vibStrength << block ) * self->freqMul; #endif } else { self->vibStrength = 0; self->vibrato = 0; } } static void Operator__UpdateRates(Operator *self, const Chip* chip ) { //Mame seems to reverse this where enabling ksr actually lowers //the rate, but pdf manuals says otherwise? Bit8u newKsr = (Bit8u)((self->chanData >> SHIFT_KEYCODE) & 0xff); if ( !( self->reg20 & MASK_KSR ) ) { newKsr >>= 2; } if ( self->ksr == newKsr ) return; self->ksr = newKsr; Operator__UpdateAttack( self, chip ); Operator__UpdateDecay( self, chip ); Operator__UpdateRelease( self, chip ); } static inline Bit32s Operator__RateForward(Operator *self, Bit32u add ) { Bit32s ret; // haleyjd: GNUisms out! self->rateIndex += add; ret = self->rateIndex >> RATE_SH; self->rateIndex = self->rateIndex & RATE_MASK; return ret; } static Bits Operator__TemplateVolume(Operator *self, OperatorState yes) { Bit32s vol = self->volume; Bit32s change; switch ( yes ) { case OFF: return ENV_MAX; case ATTACK: change = Operator__RateForward( self, self->attackAdd ); if ( !change ) return vol; vol += ( (~vol) * change ) >> 3; if ( vol < ENV_MIN ) { self->volume = ENV_MIN; self->rateIndex = 0; Operator__SetState( self, DECAY ); return ENV_MIN; } break; case DECAY: vol += Operator__RateForward( self, self->decayAdd ); if ( GCC_UNLIKELY(vol >= self->sustainLevel) ) { //Check if we didn't overshoot max attenuation, then just go off if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { self->volume = ENV_MAX; Operator__SetState( self, OFF ); return ENV_MAX; } //Continue as sustain self->rateIndex = 0; Operator__SetState( self, SUSTAIN ); } break; case SUSTAIN: if ( self->reg20 & MASK_SUSTAIN ) { return vol; } //In sustain phase, but not sustaining, do regular release case RELEASE: vol += Operator__RateForward( self, self->releaseAdd );; if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { self->volume = ENV_MAX; Operator__SetState( self, OFF ); return ENV_MAX; } break; } self->volume = vol; return vol; } #define TEMPLATE_VOLUME(mode) \ static Bits Operator__TemplateVolume ## mode(Operator *self) \ { \ return Operator__TemplateVolume(self, mode); \ } TEMPLATE_VOLUME(OFF) TEMPLATE_VOLUME(RELEASE) TEMPLATE_VOLUME(SUSTAIN) TEMPLATE_VOLUME(ATTACK) TEMPLATE_VOLUME(DECAY) static const VolumeHandler VolumeHandlerTable[5] = { &Operator__TemplateVolumeOFF, &Operator__TemplateVolumeRELEASE, &Operator__TemplateVolumeSUSTAIN, &Operator__TemplateVolumeDECAY, &Operator__TemplateVolumeATTACK, }; static inline Bitu Operator__ForwardVolume(Operator *self) { return self->currentLevel + (self->volHandler)(self); } static inline Bitu Operator__ForwardWave(Operator *self) { self->waveIndex += self->waveCurrent; return self->waveIndex >> WAVE_SH; } static void Operator__Write20(Operator *self, const Chip* chip, Bit8u val ) { Bit8u change = (self->reg20 ^ val ); if ( !change ) return; self->reg20 = val; //Shift the tremolo bit over the entire register, saved a branch, YES! self->tremoloMask = (Bit8s)(val) >> 7; self->tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); //Update specific features based on changes if ( change & MASK_KSR ) { Operator__UpdateRates( self, chip ); } //With sustain enable the volume doesn't change if ( self->reg20 & MASK_SUSTAIN || ( !self->releaseAdd ) ) { self->rateZero |= ( 1 << SUSTAIN ); } else { self->rateZero &= ~( 1 << SUSTAIN ); } //Frequency multiplier or vibrato changed if ( change & (0xf | MASK_VIBRATO) ) { self->freqMul = chip->freqMul[ val & 0xf ]; Operator__UpdateFrequency(self); } } static void Operator__Write40(Operator *self, const Chip *chip, Bit8u val ) { if (!(self->reg40 ^ val )) return; self->reg40 = val; Operator__UpdateAttenuation( self ); } static void Operator__Write60(Operator *self, const Chip* chip, Bit8u val ) { Bit8u change = self->reg60 ^ val; self->reg60 = val; if ( change & 0x0f ) { Operator__UpdateDecay( self, chip ); } if ( change & 0xf0 ) { Operator__UpdateAttack( self, chip ); } } static void Operator__Write80(Operator *self, const Chip* chip, Bit8u val ) { Bit8u change = (self->reg80 ^ val ); Bit8u sustain; // haleyjd 09/09/10: GNUisms out! if ( !change ) return; self->reg80 = val; sustain = val >> 4; //Turn 0xf into 0x1f sustain |= ( sustain + 1) & 0x10; self->sustainLevel = sustain << ( ENV_BITS - 5 ); if ( change & 0x0f ) { Operator__UpdateRelease( self, chip ); } } static void Operator__WriteE0(Operator *self, const Chip* chip, Bit8u val ) { Bit8u waveForm; // haleyjd 09/09/10: GNUisms out! if ( !(self->regE0 ^ val) ) return; //in opl3 mode you can always selet 7 waveforms regardless of waveformselect waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); self->regE0 = val; #if( DBOPL_WAVE == WAVE_HANDLER ) self->waveHandler = WaveHandlerTable[ waveForm ]; #else self->waveBase = WaveTable + WaveBaseTable[ waveForm ]; self->waveStart = WaveStartTable[ waveForm ] << WAVE_SH; self->waveMask = WaveMaskTable[ waveForm ]; #endif } static inline void Operator__SetState(Operator *self, Bit8u s ) { self->state = s; self->volHandler = VolumeHandlerTable[ s ]; } static inline int Operator__Silent(Operator *self) { if ( !ENV_SILENT( self->totalLevel + self->volume ) ) return FALSE; if ( !(self->rateZero & ( 1 << self->state ) ) ) return FALSE; return TRUE; } static inline void Operator__Prepare(Operator *self, const Chip* chip ) { self->currentLevel = self->totalLevel + (chip->tremoloValue & self->tremoloMask); self->waveCurrent = self->waveAdd; if ( self->vibStrength >> chip->vibratoShift ) { Bit32s add = self->vibrato >> chip->vibratoShift; //Sign extend over the shift value Bit32s neg = chip->vibratoSign; //Negate the add with -1 or 0 add = ( add ^ neg ) - neg; self->waveCurrent += add; } } static void Operator__KeyOn(Operator *self, Bit8u mask ) { if ( !self->keyOn ) { //Restart the frequency generator #if( DBOPL_WAVE > WAVE_HANDLER ) self->waveIndex = self->waveStart; #else self->waveIndex = 0; #endif self->rateIndex = 0; Operator__SetState( self, ATTACK ); } self->keyOn |= mask; } static void Operator__KeyOff(Operator *self, Bit8u mask ) { self->keyOn &= ~mask; if ( !self->keyOn ) { if ( self->state != OFF ) { Operator__SetState( self, RELEASE ); } } } static inline Bits Operator__GetWave(Operator *self, Bitu index, Bitu vol ) { #if( DBOPL_WAVE == WAVE_HANDLER ) return self->waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); #elif( DBOPL_WAVE == WAVE_TABLEMUL ) return(self->waveBase[ index & self->waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; #elif( DBOPL_WAVE == WAVE_TABLELOG ) Bit32s wave = self->waveBase[ index & self->waveMask ]; Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); Bit32s sig = ExpTable[ total & 0xff ]; Bit32u exp = total >> 8; Bit32s neg = wave >> 16; return((sig ^ neg) - neg) >> exp; #else #error "No valid wave routine" #endif } static inline Bits Operator__GetSample(Operator *self, Bits modulation ) { Bitu vol = Operator__ForwardVolume(self); if ( ENV_SILENT( vol ) ) { //Simply forward the wave self->waveIndex += self->waveCurrent; return 0; } else { Bitu index = Operator__ForwardWave(self); index += modulation; return Operator__GetWave( self, index, vol ); } } static void Operator__Operator(Operator *self) { self->chanData = 0; self->freqMul = 0; self->waveIndex = 0; self->waveAdd = 0; self->waveCurrent = 0; self->keyOn = 0; self->ksr = 0; self->reg20 = 0; self->reg40 = 0; self->reg60 = 0; self->reg80 = 0; self->regE0 = 0; Operator__SetState( self, OFF ); self->rateZero = (1 << OFF); self->sustainLevel = ENV_MAX; self->currentLevel = ENV_MAX; self->totalLevel = ENV_MAX; self->volume = ENV_MAX; self->releaseAdd = 0; } /* Channel */ static void Channel__Channel(Channel *self) { Operator__Operator(&self->op[0]); Operator__Operator(&self->op[1]); self->old[0] = self->old[1] = 0; self->chanData = 0; self->regB0 = 0; self->regC0 = 0; self->maskLeft = -1; self->maskRight = -1; self->feedback = 31; self->fourMask = 0; self->synthHandler = Channel__BlockTemplate_sm2FM; }; static inline Operator* Channel__Op( Channel *self, Bitu index ) { return &( ( self + (index >> 1) )->op[ index & 1 ]); } static void Channel__SetChanData(Channel *self, const Chip* chip, Bit32u data ) { Bit32u change = self->chanData ^ data; self->chanData = data; Channel__Op( self, 0 )->chanData = data; Channel__Op( self, 1 )->chanData = data; //Since a frequency update triggered this, always update frequency Operator__UpdateFrequency(Channel__Op( self, 0 )); Operator__UpdateFrequency(Channel__Op( self, 1 )); if ( change & ( 0xff << SHIFT_KSLBASE ) ) { Operator__UpdateAttenuation(Channel__Op( self, 0 )); Operator__UpdateAttenuation(Channel__Op( self, 1 )); } if ( change & ( 0xff << SHIFT_KEYCODE ) ) { Operator__UpdateRates(Channel__Op( self, 0 ), chip); Operator__UpdateRates(Channel__Op( self, 1 ), chip); } } static void Channel__UpdateFrequency(Channel *self, const Chip* chip, Bit8u fourOp ) { //Extrace the frequency bits Bit32u data = self->chanData & 0xffff; Bit32u kslBase = KslTable[ data >> 6 ]; Bit32u keyCode = ( data & 0x1c00) >> 9; if ( chip->reg08 & 0x40 ) { keyCode |= ( data & 0x100)>>8; /* notesel == 1 */ } else { keyCode |= ( data & 0x200)>>9; /* notesel == 0 */ } //Add the keycode and ksl into the highest bits of chanData data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); Channel__SetChanData( self + 0, chip, data ); if ( fourOp & 0x3f ) { Channel__SetChanData( self + 1, chip, data ); } } static void Channel__WriteA0(Channel *self, const Chip* chip, Bit8u val ) { Bit8u fourOp = chip->reg104 & chip->opl3Active & self->fourMask; Bit32u change; // haleyjd 09/09/10: GNUisms out! //Don't handle writes to silent fourop channels if ( fourOp > 0x80 ) return; change = (self->chanData ^ val ) & 0xff; if ( change ) { self->chanData ^= change; Channel__UpdateFrequency( self, chip, fourOp ); } } static void Channel__WriteB0(Channel *self, const Chip* chip, Bit8u val ) { Bit8u fourOp = chip->reg104 & chip->opl3Active & self->fourMask; Bitu change; // haleyjd 09/09/10: GNUisms out! //Don't handle writes to silent fourop channels if ( fourOp > 0x80 ) return; change = (self->chanData ^ ( val << 8 ) ) & 0x1f00; if ( change ) { self->chanData ^= change; Channel__UpdateFrequency( self, chip, fourOp ); } //Check for a change in the keyon/off state if ( !(( val ^ self->regB0) & 0x20)) return; self->regB0 = val; if ( val & 0x20 ) { Operator__KeyOn( Channel__Op(self, 0), 0x1 ); Operator__KeyOn( Channel__Op(self, 1), 0x1 ); if ( fourOp & 0x3f ) { Operator__KeyOn( Channel__Op(self + 1, 0), 1 ); Operator__KeyOn( Channel__Op(self + 1, 1), 1 ); } } else { Operator__KeyOff( Channel__Op(self, 0), 0x1 ); Operator__KeyOff( Channel__Op(self, 1), 0x1 ); if ( fourOp & 0x3f ) { Operator__KeyOff( Channel__Op(self + 1, 0), 1 ); Operator__KeyOff( Channel__Op(self + 1, 1), 1 ); } } } static void Channel__WriteC0(Channel *self, const Chip* chip, Bit8u val ) { Bit8u change = val ^ self->regC0; if ( !change ) return; self->regC0 = val; self->feedback = ( val >> 1 ) & 7; if ( self->feedback ) { //We shift the input to the right 10 bit wave index value self->feedback = 9 - self->feedback; } else { self->feedback = 31; } //Select the new synth mode if ( chip->opl3Active ) { //4-op mode enabled for this channel if ( (chip->reg104 & self->fourMask) & 0x3f ) { Channel* chan0, *chan1; Bit8u synth; // haleyjd 09/09/10: GNUisms out! //Check if it's the 2nd channel in a 4-op if ( !(self->fourMask & 0x80 ) ) { chan0 = self; chan1 = self + 1; } else { chan0 = self - 1; chan1 = self; } synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); switch ( synth ) { case 0: chan0->synthHandler = Channel__BlockTemplate_sm3FMFM; break; case 1: chan0->synthHandler = Channel__BlockTemplate_sm3AMFM; break; case 2: chan0->synthHandler = Channel__BlockTemplate_sm3FMAM ; break; case 3: chan0->synthHandler = Channel__BlockTemplate_sm3AMAM ; break; } //Disable updating percussion channels } else if ((self->fourMask & 0x40) && ( chip->regBD & 0x20) ) { //Regular dual op, am or fm } else if ( val & 1 ) { self->synthHandler = Channel__BlockTemplate_sm3AM; } else { self->synthHandler = Channel__BlockTemplate_sm3FM; } self->maskLeft = ( val & 0x10 ) ? -1 : 0; self->maskRight = ( val & 0x20 ) ? -1 : 0; //opl2 active } else { //Disable updating percussion channels if ( (self->fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { //Regular dual op, am or fm } else if ( val & 1 ) { self->synthHandler = Channel__BlockTemplate_sm2AM; } else { self->synthHandler = Channel__BlockTemplate_sm2FM; } } } static void Channel__ResetC0(Channel *self, const Chip* chip ) { Bit8u val = self->regC0; self->regC0 ^= 0xff; Channel__WriteC0( self, chip, val ); }; static inline void Channel__GeneratePercussion(Channel *self, Chip* chip, Bit32s* output, int opl3Mode ) { Channel* chan = self; //BassDrum Bit32s mod = (Bit32u)((self->old[0] + self->old[1])) >> self->feedback; Bit32s sample; // haleyjd 09/09/10 Bit32u noiseBit; Bit32u c2; Bit32u c5; Bit32u phaseBit; Bit32u hhVol; Bit32u sdVol; Bit32u tcVol; self->old[0] = self->old[1]; self->old[1] = Operator__GetSample( Channel__Op(self, 0), mod ); //When bassdrum is in AM mode first operator is ignoed if ( chan->regC0 & 1 ) { mod = 0; } else { mod = self->old[0]; } sample = Operator__GetSample( Channel__Op(self, 1), mod ); //Precalculate stuff used by other outputs noiseBit = Chip__ForwardNoise(chip) & 0x1; c2 = Operator__ForwardWave(Channel__Op(self, 2)); c5 = Operator__ForwardWave(Channel__Op(self, 5)); phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; //Hi-Hat hhVol = Operator__ForwardVolume(Channel__Op(self, 2)); if ( !ENV_SILENT( hhVol ) ) { Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); sample += Operator__GetWave( Channel__Op(self, 2), hhIndex, hhVol ); } //Snare Drum sdVol = Operator__ForwardVolume( Channel__Op(self, 3) ); if ( !ENV_SILENT( sdVol ) ) { Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); sample += Operator__GetWave( Channel__Op(self, 3), sdIndex, sdVol ); } //Tom-tom sample += Operator__GetSample( Channel__Op(self, 4), 0 ); //Top-Cymbal tcVol = Operator__ForwardVolume(Channel__Op(self, 5)); if ( !ENV_SILENT( tcVol ) ) { Bit32u tcIndex = (1 + phaseBit) << 8; sample += Operator__GetWave( Channel__Op(self, 5), tcIndex, tcVol ); } sample <<= 1; if ( opl3Mode ) { output[0] += sample; output[1] += sample; } else { output[0] += sample; } } Channel* Channel__BlockTemplate(Channel *self, Chip* chip, Bit32u samples, Bit32s* output, SynthMode mode ) { Bitu i; switch( mode ) { case sm2AM: case sm3AM: if ( Operator__Silent(Channel__Op(self, 0)) && Operator__Silent(Channel__Op(self, 1))) { self->old[0] = self->old[1] = 0; return(self + 1); } break; case sm2FM: case sm3FM: if ( Operator__Silent(Channel__Op(self, 1))) { self->old[0] = self->old[1] = 0; return (self + 1); } break; case sm3FMFM: if ( Operator__Silent(Channel__Op(self, 3))) { self->old[0] = self->old[1] = 0; return (self + 2); } break; case sm3AMFM: if ( Operator__Silent( Channel__Op(self, 0) ) && Operator__Silent( Channel__Op(self, 3) )) { self->old[0] = self->old[1] = 0; return (self + 2); } break; case sm3FMAM: if ( Operator__Silent( Channel__Op(self, 1)) && Operator__Silent( Channel__Op(self, 3))) { self->old[0] = self->old[1] = 0; return (self + 2); } break; case sm3AMAM: if ( Operator__Silent( Channel__Op(self, 0) ) && Operator__Silent( Channel__Op(self, 2) ) && Operator__Silent( Channel__Op(self, 3) )) { self->old[0] = self->old[1] = 0; return (self + 2); } break; default: abort(); } //Init the operators with the the current vibrato and tremolo values Operator__Prepare( Channel__Op( self, 0 ), chip ); Operator__Prepare( Channel__Op( self, 1 ), chip ); if ( mode > sm4Start ) { Operator__Prepare( Channel__Op( self, 2 ), chip ); Operator__Prepare( Channel__Op( self, 3 ), chip ); } if ( mode > sm6Start ) { Operator__Prepare( Channel__Op( self, 4 ), chip ); Operator__Prepare( Channel__Op( self, 5 ), chip ); } for ( i = 0; i < samples; i++ ) { Bit32s mod; // haleyjd 09/09/10: GNUisms out! Bit32s sample; Bit32s out0; //Early out for percussion handlers if ( mode == sm2Percussion ) { Channel__GeneratePercussion( self, chip, output + i, FALSE ); continue; //Prevent some unitialized value bitching } else if ( mode == sm3Percussion ) { Channel__GeneratePercussion( self, chip, output + i * 2, TRUE ); continue; //Prevent some unitialized value bitching } //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise mod = (Bit32u)((self->old[0] + self->old[1])) >> self->feedback; self->old[0] = self->old[1]; self->old[1] = Operator__GetSample( Channel__Op(self, 0), mod ); sample = 0; out0 = self->old[0]; if ( mode == sm2AM || mode == sm3AM ) { sample = out0 + Operator__GetSample( Channel__Op(self, 1), 0 ); } else if ( mode == sm2FM || mode == sm3FM ) { sample = Operator__GetSample( Channel__Op(self, 1), out0 ); } else if ( mode == sm3FMFM ) { Bits next = Operator__GetSample( Channel__Op(self, 1), out0 ); next = Operator__GetSample( Channel__Op(self, 2), next ); sample = Operator__GetSample( Channel__Op(self, 3), next ); } else if ( mode == sm3AMFM ) { Bits next; // haleyjd 09/09/10: GNUisms out! sample = out0; next = Operator__GetSample( Channel__Op(self, 1), 0 ); next = Operator__GetSample( Channel__Op(self, 2), next ); sample += Operator__GetSample( Channel__Op(self, 3), next ); } else if ( mode == sm3FMAM ) { Bits next; // haleyjd 09/09/10: GNUisms out! sample = Operator__GetSample( Channel__Op(self, 1), out0 ); next = Operator__GetSample( Channel__Op(self, 2), 0 ); sample += Operator__GetSample( Channel__Op(self, 3), next ); } else if ( mode == sm3AMAM ) { Bits next; // haleyjd 09/09/10: GNUisms out! sample = out0; next = Operator__GetSample( Channel__Op(self, 1), 0 ); sample += Operator__GetSample( Channel__Op(self, 2), next ); sample += Operator__GetSample( Channel__Op(self, 3), 0 ); } switch( mode ) { case sm2AM: case sm2FM: output[ i ] += sample; break; case sm3AM: case sm3FM: case sm3FMFM: case sm3AMFM: case sm3FMAM: case sm3AMAM: output[ i * 2 + 0 ] += sample & self->maskLeft; output[ i * 2 + 1 ] += sample & self->maskRight; break; default: abort(); } } switch( mode ) { case sm2AM: case sm2FM: case sm3AM: case sm3FM: return ( self + 1 ); case sm3FMFM: case sm3AMFM: case sm3FMAM: case sm3AMAM: return ( self + 2 ); case sm2Percussion: case sm3Percussion: return( self + 3 ); default: abort(); } return 0; } /* Chip */ void Chip__Chip(Chip *self) { int i; for (i=0; i<18; ++i) { Channel__Channel(&self->chan[i]); } self->reg08 = 0; self->reg04 = 0; self->regBD = 0; self->reg104 = 0; self->opl3Active = 0; } static inline Bit32u Chip__ForwardNoise(Chip *self) { Bitu count; self->noiseCounter += self->noiseAdd; count = self->noiseCounter >> LFO_SH; self->noiseCounter &= WAVE_MASK; for ( ; count > 0; --count ) { //Noise calculation from mame self->noiseValue ^= ( 0x800302 ) & ( 0 - (self->noiseValue & 1 ) ); self->noiseValue >>= 1; } return self->noiseValue; } static inline Bit32u Chip__ForwardLFO(Chip *self, Bit32u samples ) { Bit32u todo; // haleyjd 09/09/10: GNUisms out!!!!!! Bit32u count; //Current vibrato value, runs 4x slower than tremolo self->vibratoSign = ( VibratoTable[ self->vibratoIndex >> 2] ) >> 7; self->vibratoShift = ( VibratoTable[ self->vibratoIndex >> 2] & 7) + self->vibratoStrength; self->tremoloValue = TremoloTable[ self->tremoloIndex ] >> self->tremoloStrength; //Check hom many samples there can be done before the value changes todo = LFO_MAX - self->lfoCounter; count = (todo + self->lfoAdd - 1) / self->lfoAdd; if ( count > samples ) { count = samples; self->lfoCounter += count * self->lfoAdd; } else { self->lfoCounter += count * self->lfoAdd; self->lfoCounter &= (LFO_MAX - 1); //Maximum of 7 vibrato value * 4 self->vibratoIndex = ( self->vibratoIndex + 1 ) & 31; //Clip tremolo to the the table size if ( self->tremoloIndex + 1 < TREMOLO_TABLE ) ++self->tremoloIndex; else self->tremoloIndex = 0; } return count; } static void Chip__WriteBD(Chip *self, Bit8u val ) { Bit8u change = self->regBD ^ val; if ( !change ) return; self->regBD = val; //TODO could do this with shift and xor? self->vibratoStrength = (val & 0x40) ? 0x00 : 0x01; self->tremoloStrength = (val & 0x80) ? 0x00 : 0x02; if ( val & 0x20 ) { //Drum was just enabled, make sure channel 6 has the right synth if ( change & 0x20 ) { if ( self->opl3Active ) { self->chan[6].synthHandler = Channel__BlockTemplate_sm3Percussion; } else { self->chan[6].synthHandler = Channel__BlockTemplate_sm2Percussion; } } //Bass Drum if ( val & 0x10 ) { Operator__KeyOn( &self->chan[6].op[0], 0x2 ); Operator__KeyOn( &self->chan[6].op[1], 0x2 ); } else { Operator__KeyOff( &self->chan[6].op[0], 0x2 ); Operator__KeyOff( &self->chan[6].op[1], 0x2 ); } //Hi-Hat if ( val & 0x1 ) { Operator__KeyOn( &self->chan[7].op[0], 0x2 ); } else { Operator__KeyOff( &self->chan[7].op[0], 0x2 ); } //Snare if ( val & 0x8 ) { Operator__KeyOn( &self->chan[7].op[1], 0x2 ); } else { Operator__KeyOff( &self->chan[7].op[1], 0x2 ); } //Tom-Tom if ( val & 0x4 ) { Operator__KeyOn( &self->chan[8].op[0], 0x2 ); } else { Operator__KeyOff( &self->chan[8].op[0], 0x2 ); } //Top Cymbal if ( val & 0x2 ) { Operator__KeyOn( &self->chan[8].op[1], 0x2 ); } else { Operator__KeyOff( &self->chan[8].op[1], 0x2 ); } //Toggle keyoffs when we turn off the percussion } else if ( change & 0x20 ) { //Trigger a reset to setup the original synth handler Channel__ResetC0( &self->chan[6], self ); Operator__KeyOff( &self->chan[6].op[0], 0x2 ); Operator__KeyOff( &self->chan[6].op[1], 0x2 ); Operator__KeyOff( &self->chan[7].op[0], 0x2 ); Operator__KeyOff( &self->chan[7].op[1], 0x2 ); Operator__KeyOff( &self->chan[8].op[0], 0x2 ); Operator__KeyOff( &self->chan[8].op[1], 0x2 ); } } #define REGOP( _FUNC_ ) \ index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ if ( OpOffsetTable[ index ] ) { \ Operator* regOp = (Operator*)( ((char *)self ) + OpOffsetTable[ index ] ); \ Operator__ ## _FUNC_ (regOp, self, val); \ } #define REGCHAN( _FUNC_ ) \ index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ if ( ChanOffsetTable[ index ] ) { \ Channel* regChan = (Channel*)( ((char *)self ) + ChanOffsetTable[ index ] ); \ Channel__ ## _FUNC_ (regChan, self, val); \ } void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val ) { Bitu index; switch ( (reg & 0xf0) >> 4 ) { case 0x00 >> 4: if ( reg == 0x01 ) { self->waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; } else if ( reg == 0x104 ) { //Only detect changes in lowest 6 bits if ( !((self->reg104 ^ val) & 0x3f) ) return; //Always keep the highest bit enabled, for checking > 0x80 self->reg104 = 0x80 | ( val & 0x3f ); } else if ( reg == 0x105 ) { int i; //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register if ( !((self->opl3Active ^ val) & 1 ) ) return; self->opl3Active = ( val & 1 ) ? 0xff : 0; //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers for ( i = 0; i < 18;i++ ) { Channel__ResetC0( &self->chan[i], self ); } } else if ( reg == 0x08 ) { self->reg08 = val; } case 0x10 >> 4: break; case 0x20 >> 4: case 0x30 >> 4: REGOP( Write20 ); break; case 0x40 >> 4: case 0x50 >> 4: REGOP( Write40 ); break; case 0x60 >> 4: case 0x70 >> 4: REGOP( Write60 ); break; case 0x80 >> 4: case 0x90 >> 4: REGOP( Write80 ); break; case 0xa0 >> 4: REGCHAN( WriteA0 ); break; case 0xb0 >> 4: if ( reg == 0xbd ) { Chip__WriteBD( self, val ); } else { REGCHAN( WriteB0 ); } break; case 0xc0 >> 4: REGCHAN( WriteC0 ); case 0xd0 >> 4: break; case 0xe0 >> 4: case 0xf0 >> 4: REGOP( WriteE0 ); break; } } Bit32u Chip__WriteAddr(Chip *self, Bit32u port, Bit8u val ) { switch ( port & 3 ) { case 0: return val; case 2: if ( self->opl3Active || (val == 0x05) ) return 0x100 | val; else return val; } return 0; } void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output ) { while ( total > 0 ) { Channel *ch; int count; Bit32u samples = Chip__ForwardLFO( self, total ); memset(output, 0, sizeof(Bit32s) * samples); count = 0; for ( ch = self->chan; ch < self->chan + 9; ) { count++; ch = (ch->synthHandler)( ch, self, samples, output ); } total -= samples; output += samples; } } void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output ) { while ( total > 0 ) { int count; Channel *ch; Bit32u samples = Chip__ForwardLFO( self, total ); memset(output, 0, sizeof(Bit32s) * samples *2); count = 0; for ( ch = self->chan; ch < self->chan + 18; ) { count++; ch = (ch->synthHandler)( ch, self, samples, output ); } total -= samples; output += samples * 2; } } void Chip__Setup(Chip *self, Bit32u rate ) { double original = OPLRATE; Bit32u i; Bit32u freqScale; // haleyjd 09/09/10: GNUisms out! // double original = rate; double scale = original / (double)rate; //Noise counter is run at the same precision as general waves self->noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); self->noiseCounter = 0; self->noiseValue = 1; //Make sure it triggers the noise xor the first time //The low frequency oscillation counter //Every time his overflows vibrato and tremoloindex are increased self->lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); self->lfoCounter = 0; self->vibratoIndex = 0; self->tremoloIndex = 0; //With higher octave this gets shifted up //-1 since the freqCreateTable = *2 #ifdef WAVE_PRECISION double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); for ( i = 0; i < 16; i++ ) { self->freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); } #else freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); for ( i = 0; i < 16; i++ ) { self->freqMul[i] = freqScale * FreqCreateTable[ i ]; } #endif //-3 since the real envelope takes 8 steps to reach the single value we supply for ( i = 0; i < 76; i++ ) { Bit8u index, shift; EnvelopeSelect( i, &index, &shift ); self->linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); } //Generate the best matching attack rate for ( i = 0; i < 62; i++ ) { Bit8u index, shift; Bit32s original; // haleyjd 09/09/10: GNUisms out! Bit32s guessAdd; Bit32s bestAdd; Bit32u bestDiff; Bit32u passes; EnvelopeSelect( i, &index, &shift ); //Original amount of samples the attack would take original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); bestAdd = guessAdd; bestDiff = 1 << 30; for ( passes = 0; passes < 16; passes ++ ) { Bit32s volume = ENV_MAX; Bit32s samples = 0; Bit32u count = 0; Bit32s diff; Bit32u lDiff; while ( volume > 0 && samples < original * 2 ) { Bit32s change; // haleyjd 09/09/10 count += guessAdd; change = count >> RATE_SH; count &= RATE_MASK; if ( GCC_UNLIKELY(change) ) { // less than 1 % volume += ( ~volume * change ) >> 3; } samples++; } diff = original - samples; lDiff = labs( diff ); //Init last on first pass if ( lDiff < bestDiff ) { bestDiff = lDiff; bestAdd = guessAdd; if ( !bestDiff ) break; } //Below our target if ( diff < 0 ) { //Better than the last time Bit32s mul = ((original - diff) << 12) / original; guessAdd = ((guessAdd * mul) >> 12); guessAdd++; } else if ( diff > 0 ) { Bit32s mul = ((original - diff) << 12) / original; guessAdd = (guessAdd * mul) >> 12; guessAdd--; } } self->attackRates[i] = bestAdd; } for ( i = 62; i < 76; i++ ) { //This should provide instant volume maximizing self->attackRates[i] = 8 << RATE_SH; } //Setup the channels with the correct four op flags //Channels are accessed through a table so they appear linear here self->chan[ 0].fourMask = 0x00 | ( 1 << 0 ); self->chan[ 1].fourMask = 0x80 | ( 1 << 0 ); self->chan[ 2].fourMask = 0x00 | ( 1 << 1 ); self->chan[ 3].fourMask = 0x80 | ( 1 << 1 ); self->chan[ 4].fourMask = 0x00 | ( 1 << 2 ); self->chan[ 5].fourMask = 0x80 | ( 1 << 2 ); self->chan[ 9].fourMask = 0x00 | ( 1 << 3 ); self->chan[10].fourMask = 0x80 | ( 1 << 3 ); self->chan[11].fourMask = 0x00 | ( 1 << 4 ); self->chan[12].fourMask = 0x80 | ( 1 << 4 ); self->chan[13].fourMask = 0x00 | ( 1 << 5 ); self->chan[14].fourMask = 0x80 | ( 1 << 5 ); //mark the percussion channels self->chan[ 6].fourMask = 0x40; self->chan[ 7].fourMask = 0x40; self->chan[ 8].fourMask = 0x40; //Clear Everything in opl3 mode Chip__WriteReg( self, 0x105, 0x1 ); for ( i = 0; i < 512; i++ ) { if ( i == 0x105 ) continue; Chip__WriteReg( self, i, 0xff ); Chip__WriteReg( self, i, 0x0 ); } Chip__WriteReg( self, 0x105, 0x0 ); //Clear everything in opl2 mode for ( i = 0; i < 255; i++ ) { Chip__WriteReg( self, i, 0xff ); Chip__WriteReg( self, i, 0x0 ); } } static int doneTables = FALSE; void DBOPL_InitTables( void ) { int i, oct; if ( doneTables ) return; doneTables = TRUE; #if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) //Exponential volume table, same as the real adlib for ( i = 0; i < 256; i++ ) { //Save them in reverse ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); ExpTable[i] += 1024; //or remove the -1 oh well :) //Preshift to the left once so the final volume can shift to the right ExpTable[i] *= 2; } #endif #if ( DBOPL_WAVE == WAVE_HANDLER ) //Add 0.5 for the trunc rounding of the integer cast //Do a PI sinetable instead of the original 0.5 PI for ( i = 0; i < 512; i++ ) { SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); } #endif #if ( DBOPL_WAVE == WAVE_TABLEMUL ) //Multiplication based tables for ( i = 0; i < 384; i++ ) { int s = i * 8; //TODO maybe keep some of the precision errors of the original table? double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); MulTable[i] = (Bit16u)(val); } //Sine Wave Base for ( i = 0; i < 512; i++ ) { WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; } //Exponential wave for ( i = 0; i < 256; i++ ) { WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; } #endif #if ( DBOPL_WAVE == WAVE_TABLELOG ) //Sine Wave Base for ( i = 0; i < 512; i++ ) { WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; } //Exponential wave for ( i = 0; i < 256; i++ ) { WaveTable[ 0x700 + i ] = i * 8; WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; } #endif // | |//\\|____|WAV7|//__|/\ |____|/\/\| // |\\//| | |WAV7| | \/| | | // |06 |0126|27 |7 |3 |4 |4 5 |5 | #if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) for ( i = 0; i < 256; i++ ) { //Fill silence gaps WaveTable[ 0x400 + i ] = WaveTable[0]; WaveTable[ 0x500 + i ] = WaveTable[0]; WaveTable[ 0x900 + i ] = WaveTable[0]; WaveTable[ 0xc00 + i ] = WaveTable[0]; WaveTable[ 0xd00 + i ] = WaveTable[0]; //Replicate sines in other pieces WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; //double speed sines WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; } #endif //Create the ksl table for ( oct = 0; oct < 8; oct++ ) { int base = oct * 8; for ( i = 0; i < 16; i++ ) { int val = base - KslCreateTable[i]; if ( val < 0 ) val = 0; //*4 for the final range to match attenuation range KslTable[ oct * 16 + i ] = val * 4; } } //Create the Tremolo table, just increase and decrease a triangle wave for ( i = 0; i < TREMOLO_TABLE / 2; i++ ) { Bit8u val = i << ENV_EXTRA; TremoloTable[i] = val; TremoloTable[TREMOLO_TABLE - 1 - i] = val; } //Create a table with offsets of the channels from the start of the chip { // haleyjd 09/09/10: Driving me #$%^@ insane Chip *chip = NULL; for ( i = 0; i < 32; i++ ) { Bitu index = i & 0xf; Bitu blah; // haleyjd 09/09/10 if ( index >= 9 ) { ChanOffsetTable[i] = 0; continue; } //Make sure the four op channels follow eachother if ( index < 6 ) { index = (index % 3) * 2 + ( index / 3 ); } //Add back the bits for highest ones if ( i >= 16 ) index += 9; blah = (Bitu) ( &(chip->chan[ index ]) ); ChanOffsetTable[i] = blah; } //Same for operators for ( i = 0; i < 64; i++ ) { Bitu chNum; // haleyjd 09/09/10 Bitu opNum; Bitu blah; Channel* chan = NULL; if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { OpOffsetTable[i] = 0; continue; } chNum = (i / 8) * 3 + (i % 8) % 3; //Make sure we use 16 and up for the 2nd range to match the chanoffset gap if ( chNum >= 12 ) chNum += 16 - 12; opNum = ( i % 8 ) / 3; blah = (Bitu) ( &(chan->op[opNum]) ); OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah; } #if 0 //Stupid checks if table's are correct for ( Bitu i = 0; i < 18; i++ ) { Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); for ( Bitu c = 0; c < 32; c++ ) { if ( ChanOffsetTable[c] == find ) { find = 0; break; } } if ( find ) { find = find; } } for ( Bitu i = 0; i < 36; i++ ) { Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) ); for ( Bitu c = 0; c < 64; c++ ) { if ( OpOffsetTable[c] == find ) { find = 0; break; } } if ( find ) { find = find; } } #endif } } /* Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { return chip.WriteAddr( port, val ); } void Handler::WriteReg( Bit32u addr, Bit8u val ) { chip.WriteReg( addr, val ); } void Handler::Generate( MixerChannel* chan, Bitu samples ) { Bit32s buffer[ 512 * 2 ]; if ( GCC_UNLIKELY(samples > 512) ) samples = 512; if ( !chip.opl3Active ) { chip.GenerateBlock2( samples, buffer ); chan->AddSamples_m32( samples, buffer ); } else { chip.GenerateBlock3( samples, buffer ); chan->AddSamples_s32( samples, buffer ); } } void Handler::Init( Bitu rate ) { InitTables(); chip.Setup( rate ); } */ chocolate-doom-chocolate-doom-2.2.1/opl/dbopl.h000066400000000000000000000126531257432200600213570ustar00rootroot00000000000000/* * Copyright (C) 2002-2010 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include //Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume #define WAVE_HANDLER 10 //Use a logarithmic wavetable with an exponential table for volume #define WAVE_TABLELOG 11 //Use a linear wavetable with a multiply table for volume #define WAVE_TABLEMUL 12 //Select the type of wave generator routine #define DBOPL_WAVE WAVE_TABLEMUL typedef struct _Chip Chip; typedef struct _Operator Operator; typedef struct _Channel Channel; typedef uintptr_t Bitu; typedef intptr_t Bits; typedef uint32_t Bit32u; typedef int32_t Bit32s; typedef uint16_t Bit16u; typedef int16_t Bit16s; typedef uint8_t Bit8u; typedef int8_t Bit8s; #if (DBOPL_WAVE == WAVE_HANDLER) typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); #endif #define DB_FASTCALL typedef Bits (*VolumeHandler)(Operator *self); typedef Channel* (*SynthHandler)(Channel *self, Chip* chip, Bit32u samples, Bit32s* output ); //Different synth modes that can generate blocks of data typedef enum { sm2AM, sm2FM, sm3AM, sm3FM, sm4Start, sm3FMFM, sm3AMFM, sm3FMAM, sm3AMAM, sm6Start, sm2Percussion, sm3Percussion, } SynthMode; //Shifts for the values contained in chandata variable enum { SHIFT_KSLBASE = 16, SHIFT_KEYCODE = 24, }; //Masks for operator 20 values enum { MASK_KSR = 0x10, MASK_SUSTAIN = 0x20, MASK_VIBRATO = 0x40, MASK_TREMOLO = 0x80, }; typedef enum { OFF, RELEASE, SUSTAIN, DECAY, ATTACK, } OperatorState; struct _Operator { VolumeHandler volHandler; #if (DBOPL_WAVE == WAVE_HANDLER) WaveHandler waveHandler; //Routine that generate a wave #else Bit16s* waveBase; Bit32u waveMask; Bit32u waveStart; #endif Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index Bit32u waveAdd; //The base frequency without vibrato Bit32u waveCurrent; //waveAdd + vibratao Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? Bit32u vibrato; //Scaled up vibrato strength Bit32s sustainLevel; //When stopping at sustain level stop here Bit32s totalLevel; //totalLevel is added to every generated volume Bit32u currentLevel; //totalLevel + tremolo Bit32s volume; //The currently active volume Bit32u attackAdd; //Timers for the different states of the envelope Bit32u decayAdd; Bit32u releaseAdd; Bit32u rateIndex; //Current position of the evenlope Bit8u rateZero; //Bits for the different states of the envelope having no changes Bit8u keyOn; //Bitmask of different values that can generate keyon //Registers, also used to check for changes Bit8u reg20, reg40, reg60, reg80, regE0; //Active part of the envelope we're in Bit8u state; //0xff when tremolo is enabled Bit8u tremoloMask; //Strength of the vibrato Bit8u vibStrength; //Keep track of the calculated KSR so we can check for changes Bit8u ksr; }; struct _Channel { Operator op[2]; SynthHandler synthHandler; Bit32u chanData; //Frequency/octave and derived values Bit32s old[2]; //Old data for feedback Bit8u feedback; //Feedback shift Bit8u regB0; //Register values to check for changes Bit8u regC0; //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel Bit8u fourMask; Bit8s maskLeft; //Sign extended values for both channel's panning Bit8s maskRight; }; struct _Chip { //This is used as the base counter for vibrato and tremolo Bit32u lfoCounter; Bit32u lfoAdd; Bit32u noiseCounter; Bit32u noiseAdd; Bit32u noiseValue; //Frequency scales for the different multiplications Bit32u freqMul[16]; //Rates for decay and release for rate of this chip Bit32u linearRates[76]; //Best match attack rates for the rate of this chip Bit32u attackRates[76]; //18 channels with 2 operators each Channel chan[18]; Bit8u reg104; Bit8u reg08; Bit8u reg04; Bit8u regBD; Bit8u vibratoIndex; Bit8u tremoloIndex; Bit8s vibratoSign; Bit8u vibratoShift; Bit8u tremoloValue; Bit8u vibratoStrength; Bit8u tremoloStrength; //Mask for allowed wave forms Bit8u waveFormMask; //0 or -1 when enabled Bit8s opl3Active; }; /* struct Handler : public Adlib::Handler { DBOPL::Chip chip; virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); virtual void WriteReg( Bit32u addr, Bit8u val ); virtual void Generate( MixerChannel* chan, Bitu samples ); virtual void Init( Bitu rate ); }; */ void Chip__Setup(Chip *self, Bit32u rate ); void DBOPL_InitTables( void ); void Chip__Chip(Chip *self); void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val ); void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output ); void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output ); // haleyjd 09/09/10: Not standard C. #ifdef _MSC_VER #define inline __inline #endif chocolate-doom-chocolate-doom-2.2.1/opl/examples/000077500000000000000000000000001257432200600217155ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/opl/examples/.gitignore000066400000000000000000000000631257432200600237040ustar00rootroot00000000000000Makefile.in Makefile .deps droplay *.exe tags TAGS chocolate-doom-chocolate-doom-2.2.1/opl/examples/Makefile.am000066400000000000000000000002311257432200600237450ustar00rootroot00000000000000 AM_CFLAGS = -I$(top_srcdir)/opl noinst_PROGRAMS=droplay droplay_LDADD = ../libopl.a @LDFLAGS@ @SDL_LIBS@ @SDLMIXER_LIBS@ droplay_SOURCES = droplay.c chocolate-doom-chocolate-doom-2.2.1/opl/examples/droplay.c000066400000000000000000000076051257432200600235430ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Demonstration program for OPL library to play back DRO // format files. // #include #include #include #include "SDL.h" #include "opl.h" #define HEADER_STRING "DBRAWOPL" #define ADLIB_PORT 0x388 void WriteReg(unsigned int reg, unsigned int val) { int i; // This was recorded from an OPL2, but we are probably playing // back on an OPL3, so we need to enable the original OPL2 // channels. Doom does this already, but other games don't. if ((reg & 0xf0) == OPL_REGS_FEEDBACK) { val |= 0x30; } OPL_WritePort(OPL_REGISTER_PORT, reg); for (i=0; i<6; ++i) { OPL_ReadPort(OPL_REGISTER_PORT); } OPL_WritePort(OPL_DATA_PORT, val); for (i=0; i<35; ++i) { OPL_ReadPort(OPL_REGISTER_PORT); } } void ClearAllRegs(void) { int i; for (i=0; i<=0xff; ++i) { WriteReg(i, 0x00); } } void Init(void) { if (SDL_Init(SDL_INIT_TIMER) < 0) { fprintf(stderr, "Unable to initialise SDL timer\n"); exit(-1); } if (!OPL_Init(ADLIB_PORT)) { fprintf(stderr, "Unable to initialise OPL layer\n"); exit(-1); } } void Shutdown(void) { OPL_Shutdown(); } struct timer_data { int running; FILE *fstream; }; void TimerCallback(void *data) { struct timer_data *timer_data = data; int delay; if (!timer_data->running) { return; } // Read data until we must make a delay. for (;;) { int reg, val; // End of file? if (feof(timer_data->fstream)) { timer_data->running = 0; return; } reg = fgetc(timer_data->fstream); val = fgetc(timer_data->fstream); // Register value of 0 or 1 indicates a delay. if (reg == 0x00) { delay = val; break; } else if (reg == 0x01) { val |= (fgetc(timer_data->fstream) << 8); delay = val; break; } else { WriteReg(reg, val); } } // Schedule the next timer callback. OPL_SetCallback(delay * OPL_MS, TimerCallback, timer_data); } void PlayFile(char *filename) { struct timer_data timer_data; int running; char buf[8]; timer_data.fstream = fopen(filename, "rb"); if (timer_data.fstream == NULL) { fprintf(stderr, "Failed to open %s\n", filename); exit(-1); } if (fread(buf, 1, 8, timer_data.fstream) < 8) { fprintf(stderr, "failed to read raw OPL header\n"); exit(-1); } if (strncmp(buf, HEADER_STRING, 8) != 0) { fprintf(stderr, "Raw OPL header not found\n"); exit(-1); } fseek(timer_data.fstream, 28, SEEK_SET); timer_data.running = 1; // Start callback loop sequence. OPL_SetCallback(0, TimerCallback, &timer_data); // Sleep until the playback finishes. do { OPL_Lock(); running = timer_data.running; OPL_Unlock(); SDL_Delay(100 * OPL_MS); } while (running); fclose(timer_data.fstream); } int main(int argc, char *argv[]) { if (argc < 2) { printf("Usage: %s \n", argv[0]); exit(-1); } Init(); PlayFile(argv[1]); ClearAllRegs(); Shutdown(); return 0; } chocolate-doom-chocolate-doom-2.2.1/opl/ioperm_sys.c000066400000000000000000000225301257432200600224360ustar00rootroot00000000000000// // Copyright(C) 2002, 2003 Marcel Telka // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Interface to the ioperm.sys driver, based on code from the // Cygwin ioperm library. // #ifdef _WIN32 #include #define WIN32_LEAN_AND_MEAN #include #include #include #include "ioperm_sys.h" #define IOPERM_FILE L"\\\\.\\ioperm" #define IOCTL_IOPERM \ CTL_CODE(FILE_DEVICE_UNKNOWN, 0xA00, METHOD_BUFFERED, FILE_ANY_ACCESS) struct ioperm_data { unsigned long from; unsigned long num; int turn_on; }; // Function pointers for advapi32.dll. This DLL does not exist on // Windows 9x, so they are dynamically loaded from the DLL at runtime. // haleyjd 09/09/10: Moved calling conventions into ()'s static SC_HANDLE (WINAPI *MyOpenSCManagerW)(wchar_t *lpMachineName, wchar_t *lpDatabaseName, DWORD dwDesiredAccess) = NULL; static SC_HANDLE (WINAPI *MyCreateServiceW)(SC_HANDLE hSCManager, wchar_t *lpServiceName, wchar_t *lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, wchar_t *lpBinaryPathName, wchar_t *lpLoadOrderGroup, LPDWORD lpdwTagId, wchar_t *lpDependencies, wchar_t *lpServiceStartName, wchar_t *lpPassword); static SC_HANDLE (WINAPI *MyOpenServiceW)(SC_HANDLE hSCManager, wchar_t *lpServiceName, DWORD dwDesiredAccess); static BOOL (WINAPI *MyStartServiceW)(SC_HANDLE hService, DWORD dwNumServiceArgs, wchar_t **lpServiceArgVectors); static BOOL (WINAPI *MyControlService)(SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus); static BOOL (WINAPI *MyCloseServiceHandle)(SC_HANDLE hSCObject); static BOOL (WINAPI *MyDeleteService)(SC_HANDLE hService); static struct { char *name; void **fn; } dll_functions[] = { { "OpenSCManagerW", (void **) &MyOpenSCManagerW }, { "CreateServiceW", (void **) &MyCreateServiceW }, { "OpenServiceW", (void **) &MyOpenServiceW }, { "StartServiceW", (void **) &MyStartServiceW }, { "ControlService", (void **) &MyControlService }, { "CloseServiceHandle", (void **) &MyCloseServiceHandle }, { "DeleteService", (void **) &MyDeleteService }, }; // Globals static SC_HANDLE scm = NULL; static SC_HANDLE svc = NULL; static int service_was_created = 0; static int service_was_started = 0; static int LoadLibraryPointers(void) { HMODULE dll; int i; // Already loaded? if (MyOpenSCManagerW != NULL) { return 1; } dll = LoadLibraryW(L"advapi32.dll"); if (dll == NULL) { fprintf(stderr, "LoadLibraryPointers: Failed to open advapi32.dll\n"); return 0; } for (i = 0; i < sizeof(dll_functions) / sizeof(*dll_functions); ++i) { *dll_functions[i].fn = GetProcAddress(dll, dll_functions[i].name); if (*dll_functions[i].fn == NULL) { fprintf(stderr, "LoadLibraryPointers: Failed to get address " "for '%s'\n", dll_functions[i].name); return 0; } } return 1; } int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on) { HANDLE h; struct ioperm_data ioperm_data; DWORD BytesReturned; BOOL r; h = CreateFileW(IOPERM_FILE, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; return -1; } ioperm_data.from = from; ioperm_data.num = num; ioperm_data.turn_on = turn_on; r = DeviceIoControl(h, IOCTL_IOPERM, &ioperm_data, sizeof ioperm_data, NULL, 0, &BytesReturned, NULL); if (!r) { errno = EPERM; } CloseHandle(h); return r != 0; } // Load ioperm.sys driver. // Returns 1 for success, 0 for failure. // Remember to call IOperm_UninstallDriver to uninstall the driver later. int IOperm_InstallDriver(void) { wchar_t driver_path[MAX_PATH]; int error; int result = 1; if (!LoadLibraryPointers()) { return 0; } scm = MyOpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (scm == NULL) { error = GetLastError(); fprintf(stderr, "IOperm_InstallDriver: OpenSCManager failed (%i).\n", error); return 0; } // Get the full path to the driver file. GetFullPathNameW(L"ioperm.sys", MAX_PATH, driver_path, NULL); // Create the service. svc = MyCreateServiceW(scm, L"ioperm", L"ioperm support for Cygwin driver", SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, driver_path, NULL, NULL, NULL, NULL, NULL); if (svc == NULL) { error = GetLastError(); if (error != ERROR_SERVICE_EXISTS) { fprintf(stderr, "IOperm_InstallDriver: Failed to create service (%i).\n", error); } else { svc = MyOpenServiceW(scm, L"ioperm", SERVICE_ALL_ACCESS); if (svc == NULL) { error = GetLastError(); fprintf(stderr, "IOperm_InstallDriver: Failed to open service (%i).\n", error); } } if (svc == NULL) { MyCloseServiceHandle(scm); return 0; } } else { service_was_created = 1; } // Start the service. If the service already existed, it might have // already been running as well. if (!MyStartServiceW(svc, 0, NULL)) { error = GetLastError(); if (error != ERROR_SERVICE_ALREADY_RUNNING) { fprintf(stderr, "IOperm_InstallDriver: Failed to start service (%i).\n", error); result = 0; } else { printf("IOperm_InstallDriver: ioperm driver already running.\n"); } } else { printf("IOperm_InstallDriver: ioperm driver installed.\n"); service_was_started = 1; } // If we failed to start the driver running, we need to clean up // before finishing. if (result == 0) { IOperm_UninstallDriver(); } return result; } int IOperm_UninstallDriver(void) { SERVICE_STATUS stat; int result = 1; int error; // If we started the service, stop it. if (service_was_started) { if (!MyControlService(svc, SERVICE_CONTROL_STOP, &stat)) { error = GetLastError(); if (error == ERROR_SERVICE_NOT_ACTIVE) { fprintf(stderr, "IOperm_UninstallDriver: Service not active? (%i)\n", error); } else { fprintf(stderr, "IOperm_UninstallDriver: Failed to stop service (%i).\n", error); result = 0; } } } // If we created the service, delete it. if (service_was_created) { if (!MyDeleteService(svc)) { error = GetLastError(); fprintf(stderr, "IOperm_UninstallDriver: DeleteService failed (%i).\n", error); result = 0; } else if (service_was_started) { printf("IOperm_UnInstallDriver: ioperm driver uninstalled.\n"); } } // Close handles. if (svc != NULL) { MyCloseServiceHandle(svc); svc = NULL; } if (scm != NULL) { MyCloseServiceHandle(scm); scm = NULL; } service_was_created = 0; service_was_started = 0; return result; } #endif /* #ifndef _WIN32 */ chocolate-doom-chocolate-doom-2.2.1/opl/ioperm_sys.h000066400000000000000000000016401257432200600224420ustar00rootroot00000000000000// // Copyright(C) 2002, 2003 Marcel Telka // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Interface to the ioperm.sys driver, based on code from the // Cygwin ioperm library. // #ifndef IOPERM_SYS_H #define IOPERM_SYS_H int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on); int IOperm_InstallDriver(void); int IOperm_UninstallDriver(void); #endif /* #ifndef IOPERM_SYS_H */ chocolate-doom-chocolate-doom-2.2.1/opl/opl.c000066400000000000000000000253441257432200600210450ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL interface. // #include "config.h" #include #include #include "SDL.h" #include "opl.h" #include "opl_internal.h" //#define OPL_DEBUG_TRACE #ifdef HAVE_IOPERM extern opl_driver_t opl_linux_driver; #endif #if defined(HAVE_LIBI386) || defined(HAVE_LIBAMD64) extern opl_driver_t opl_openbsd_driver; #endif #ifdef _WIN32 extern opl_driver_t opl_win32_driver; #endif extern opl_driver_t opl_sdl_driver; static opl_driver_t *drivers[] = { #ifdef HAVE_IOPERM &opl_linux_driver, #endif #if defined(HAVE_LIBI386) || defined(HAVE_LIBAMD64) &opl_openbsd_driver, #endif #ifdef _WIN32 &opl_win32_driver, #endif &opl_sdl_driver, NULL }; static opl_driver_t *driver = NULL; static int init_stage_reg_writes = 1; unsigned int opl_sample_rate = 22050; // // Init/shutdown code. // // Initialize the specified driver and detect an OPL chip. Returns // true if an OPL is detected. static opl_init_result_t InitDriver(opl_driver_t *_driver, unsigned int port_base) { opl_init_result_t result1, result2; // Initialize the driver. if (!_driver->init_func(port_base)) { return OPL_INIT_NONE; } // The driver was initialized okay, so we now have somewhere // to write to. It doesn't mean there's an OPL chip there, // though. Perform the detection sequence to make sure. // (it's done twice, like how Doom does it). driver = _driver; init_stage_reg_writes = 1; result1 = OPL_Detect(); result2 = OPL_Detect(); if (result1 == OPL_INIT_NONE || result2 == OPL_INIT_NONE) { printf("OPL_Init: No OPL detected using '%s' driver.\n", _driver->name); _driver->shutdown_func(); driver = NULL; return OPL_INIT_NONE; } init_stage_reg_writes = 0; printf("OPL_Init: Using driver '%s'.\n", driver->name); return result2; } // Find a driver automatically by trying each in the list. static opl_init_result_t AutoSelectDriver(unsigned int port_base) { int i; opl_init_result_t result; for (i=0; drivers[i] != NULL; ++i) { result = InitDriver(drivers[i], port_base); if (result != OPL_INIT_NONE) { return result; } } printf("OPL_Init: Failed to find a working driver.\n"); return OPL_INIT_NONE; } // Initialize the OPL library. Return value indicates type of OPL chip // detected, if any. opl_init_result_t OPL_Init(unsigned int port_base) { char *driver_name; int i; int result; driver_name = getenv("OPL_DRIVER"); if (driver_name != NULL) { // Search the list until we find the driver with this name. for (i=0; drivers[i] != NULL; ++i) { if (!strcmp(driver_name, drivers[i]->name)) { result = InitDriver(drivers[i], port_base); if (result) { return result; } else { printf("OPL_Init: Failed to initialize " "driver: '%s'.\n", driver_name); return OPL_INIT_NONE; } } } printf("OPL_Init: unknown driver: '%s'.\n", driver_name); return OPL_INIT_NONE; } else { return AutoSelectDriver(port_base); } } // Shut down the OPL library. void OPL_Shutdown(void) { if (driver != NULL) { driver->shutdown_func(); driver = NULL; } } // Set the sample rate used for software OPL emulation. void OPL_SetSampleRate(unsigned int rate) { opl_sample_rate = rate; } void OPL_WritePort(opl_port_t port, unsigned int value) { if (driver != NULL) { #ifdef OPL_DEBUG_TRACE printf("OPL_write: %i, %x\n", port, value); fflush(stdout); #endif driver->write_port_func(port, value); } } unsigned int OPL_ReadPort(opl_port_t port) { if (driver != NULL) { unsigned int result; #ifdef OPL_DEBUG_TRACE printf("OPL_read: %i...\n", port); fflush(stdout); #endif result = driver->read_port_func(port); #ifdef OPL_DEBUG_TRACE printf("OPL_read: %i -> %x\n", port, result); fflush(stdout); #endif return result; } else { return 0; } } // // Higher-level functions, based on the lower-level functions above // (register write, etc). // unsigned int OPL_ReadStatus(void) { return OPL_ReadPort(OPL_REGISTER_PORT); } // Write an OPL register value void OPL_WriteRegister(int reg, int value) { int i; if (reg & 0x100) { OPL_WritePort(OPL_REGISTER_PORT_OPL3, reg); } else { OPL_WritePort(OPL_REGISTER_PORT, reg); } // For timing, read the register port six times after writing the // register number to cause the appropriate delay for (i=0; i<6; ++i) { // An oddity of the Doom OPL code: at startup initialization, // the spacing here is performed by reading from the register // port; after initialization, the data port is read, instead. if (init_stage_reg_writes) { OPL_ReadPort(OPL_REGISTER_PORT); } else { OPL_ReadPort(OPL_DATA_PORT); } } OPL_WritePort(OPL_DATA_PORT, value); // Read the register port 24 times after writing the value to // cause the appropriate delay for (i=0; i<24; ++i) { OPL_ReadStatus(); } } // Detect the presence of an OPL chip opl_init_result_t OPL_Detect(void) { int result1, result2; int i; // Reset both timers: OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x60); // Enable interrupts: OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80); // Read status result1 = OPL_ReadStatus(); // Set timer: OPL_WriteRegister(OPL_REG_TIMER1, 0xff); // Start timer 1: OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x21); // Wait for 80 microseconds // This is how Doom does it: for (i=0; i<200; ++i) { OPL_ReadStatus(); } OPL_Delay(1 * OPL_MS); // Read status result2 = OPL_ReadStatus(); // Reset both timers: OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x60); // Enable interrupts: OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80); if ((result1 & 0xe0) == 0x00 && (result2 & 0xe0) == 0xc0) { result1 = OPL_ReadPort(OPL_REGISTER_PORT); result2 = OPL_ReadPort(OPL_REGISTER_PORT_OPL3); if (result1 == 0x00) { return OPL_INIT_OPL3; } else { return OPL_INIT_OPL2; } } else { return OPL_INIT_NONE; } } // Initialize registers on startup void OPL_InitRegisters(int opl3) { int r; // Initialize level registers for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r) { OPL_WriteRegister(r, 0x3f); } // Initialize other registers // These two loops write to registers that actually don't exist, // but this is what Doom does ... // Similarly, the <= is also intenational. for (r=OPL_REGS_ATTACK; r <= OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r) { OPL_WriteRegister(r, 0x00); } // More registers ... for (r=1; r < OPL_REGS_LEVEL; ++r) { OPL_WriteRegister(r, 0x00); } // Re-initialize the low registers: // Reset both timers and enable interrupts: OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x60); OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80); // "Allow FM chips to control the waveform of each operator": OPL_WriteRegister(OPL_REG_WAVEFORM_ENABLE, 0x20); if (opl3) { OPL_WriteRegister(OPL_REG_NEW, 0x01); // Initialize level registers for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r) { OPL_WriteRegister(r | 0x100, 0x3f); } // Initialize other registers // These two loops write to registers that actually don't exist, // but this is what Doom does ... // Similarly, the <= is also intenational. for (r=OPL_REGS_ATTACK; r <= OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r) { OPL_WriteRegister(r | 0x100, 0x00); } // More registers ... for (r=1; r < OPL_REGS_LEVEL; ++r) { OPL_WriteRegister(r | 0x100, 0x00); } } // Keyboard split point on (?) OPL_WriteRegister(OPL_REG_FM_MODE, 0x40); if (opl3) { OPL_WriteRegister(OPL_REG_NEW, 0x01); } } // // Timer functions. // void OPL_SetCallback(uint64_t us, opl_callback_t callback, void *data) { if (driver != NULL) { driver->set_callback_func(us, callback, data); } } void OPL_ClearCallbacks(void) { if (driver != NULL) { driver->clear_callbacks_func(); } } void OPL_Lock(void) { if (driver != NULL) { driver->lock_func(); } } void OPL_Unlock(void) { if (driver != NULL) { driver->unlock_func(); } } typedef struct { int finished; SDL_mutex *mutex; SDL_cond *cond; } delay_data_t; static void DelayCallback(void *_delay_data) { delay_data_t *delay_data = _delay_data; SDL_LockMutex(delay_data->mutex); delay_data->finished = 1; SDL_CondSignal(delay_data->cond); SDL_UnlockMutex(delay_data->mutex); } void OPL_Delay(uint64_t us) { delay_data_t delay_data; if (driver == NULL) { return; } // Create a callback that will signal this thread after the // specified time. delay_data.finished = 0; delay_data.mutex = SDL_CreateMutex(); delay_data.cond = SDL_CreateCond(); OPL_SetCallback(us, DelayCallback, &delay_data); // Wait until the callback is invoked. SDL_LockMutex(delay_data.mutex); while (!delay_data.finished) { SDL_CondWait(delay_data.cond, delay_data.mutex); } SDL_UnlockMutex(delay_data.mutex); // Clean up. SDL_DestroyMutex(delay_data.mutex); SDL_DestroyCond(delay_data.cond); } void OPL_SetPaused(int paused) { if (driver != NULL) { driver->set_paused_func(paused); } } void OPL_AdjustCallbacks(float value) { if (driver != NULL) { driver->adjust_callbacks_func(value); } } chocolate-doom-chocolate-doom-2.2.1/opl/opl.h000066400000000000000000000065451257432200600210540ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL interface. // #ifndef OPL_OPL_H #define OPL_OPL_H #include typedef void (*opl_callback_t)(void *data); // Result from OPL_Init(), indicating what type of OPL chip was detected, // if any. typedef enum { OPL_INIT_NONE, OPL_INIT_OPL2, OPL_INIT_OPL3, } opl_init_result_t; typedef enum { OPL_REGISTER_PORT = 0, OPL_DATA_PORT = 1, OPL_REGISTER_PORT_OPL3 = 2 } opl_port_t; #define OPL_NUM_OPERATORS 21 #define OPL_NUM_VOICES 9 #define OPL_REG_WAVEFORM_ENABLE 0x01 #define OPL_REG_TIMER1 0x02 #define OPL_REG_TIMER2 0x03 #define OPL_REG_TIMER_CTRL 0x04 #define OPL_REG_FM_MODE 0x08 #define OPL_REG_NEW 0x105 // Operator registers (21 of each): #define OPL_REGS_TREMOLO 0x20 #define OPL_REGS_LEVEL 0x40 #define OPL_REGS_ATTACK 0x60 #define OPL_REGS_SUSTAIN 0x80 #define OPL_REGS_WAVEFORM 0xE0 // Voice registers (9 of each): #define OPL_REGS_FREQ_1 0xA0 #define OPL_REGS_FREQ_2 0xB0 #define OPL_REGS_FEEDBACK 0xC0 // Times #define OPL_SECOND ((uint64_t) 1000 * 1000) #define OPL_MS ((uint64_t) 1000) #define OPL_US ((uint64_t) 1) // // Low-level functions. // // Initialize the OPL subsystem. opl_init_result_t OPL_Init(unsigned int port_base); // Shut down the OPL subsystem. void OPL_Shutdown(void); // Set the sample rate used for software emulation. void OPL_SetSampleRate(unsigned int rate); // Write to one of the OPL I/O ports: void OPL_WritePort(opl_port_t port, unsigned int value); // Read from one of the OPL I/O ports: unsigned int OPL_ReadPort(opl_port_t port); // // Higher-level functions. // // Read the cuurrent status byte of the OPL chip. unsigned int OPL_ReadStatus(void); // Write to an OPL register. void OPL_WriteRegister(int reg, int value); // Perform a detection sequence to determine that an // OPL chip is present. opl_init_result_t OPL_Detect(void); // Initialize all registers, performed on startup. void OPL_InitRegisters(int opl3); // // Timer callback functions. // // Set a timer callback. After the specified number of microseconds // have elapsed, the callback will be invoked. void OPL_SetCallback(uint64_t us, opl_callback_t callback, void *data); // Adjust callback times by the specified factor. For example, a value of // 0.5 will halve all remaining times. void OPL_AdjustCallbacks(float factor); // Clear all OPL callbacks that have been set. void OPL_ClearCallbacks(void); // Begin critical section, during which, OPL callbacks will not be // invoked. void OPL_Lock(void); // End critical section. void OPL_Unlock(void); // Block until the specified number of microseconds have elapsed. void OPL_Delay(uint64_t us); // Pause the OPL callbacks. void OPL_SetPaused(int paused); #endif chocolate-doom-chocolate-doom-2.2.1/opl/opl_internal.h000066400000000000000000000035151257432200600227420ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL internal interface. // #ifndef OPL_INTERNAL_H #define OPL_INTERNAL_H #include "opl.h" typedef int (*opl_init_func)(unsigned int port_base); typedef void (*opl_shutdown_func)(void); typedef unsigned int (*opl_read_port_func)(opl_port_t port); typedef void (*opl_write_port_func)(opl_port_t port, unsigned int value); typedef void (*opl_set_callback_func)(uint64_t us, opl_callback_t callback, void *data); typedef void (*opl_clear_callbacks_func)(void); typedef void (*opl_lock_func)(void); typedef void (*opl_unlock_func)(void); typedef void (*opl_set_paused_func)(int paused); typedef void (*opl_adjust_callbacks_func)(float value); typedef struct { char *name; opl_init_func init_func; opl_shutdown_func shutdown_func; opl_read_port_func read_port_func; opl_write_port_func write_port_func; opl_set_callback_func set_callback_func; opl_clear_callbacks_func clear_callbacks_func; opl_lock_func lock_func; opl_unlock_func unlock_func; opl_set_paused_func set_paused_func; opl_adjust_callbacks_func adjust_callbacks_func; } opl_driver_t; // Sample rate to use when doing software emulation. extern unsigned int opl_sample_rate; #endif /* #ifndef OPL_INTERNAL_H */ chocolate-doom-chocolate-doom-2.2.1/opl/opl_linux.c000066400000000000000000000043001257432200600222510ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL Linux interface. // #include "config.h" #ifdef HAVE_IOPERM #include #include #include #include #include #include "opl.h" #include "opl_internal.h" #include "opl_timer.h" static unsigned int opl_port_base; static int OPL_Linux_Init(unsigned int port_base) { // Try to get permissions: if (ioperm(port_base, 2, 1) < 0) { fprintf(stderr, "Failed to get I/O port permissions for 0x%x: %s\n", port_base, strerror(errno)); if (errno == EPERM) { fprintf(stderr, "\tYou may need to run the program as root in order\n" "\tto acquire I/O port permissions for OPL MIDI playback.\n"); } return 0; } opl_port_base = port_base; // Start callback thread if (!OPL_Timer_StartThread()) { ioperm(port_base, 2, 0); return 0; } return 1; } static void OPL_Linux_Shutdown(void) { // Stop callback thread OPL_Timer_StopThread(); // Release permissions ioperm(opl_port_base, 2, 0); } static unsigned int OPL_Linux_PortRead(opl_port_t port) { return inb(opl_port_base + port); } static void OPL_Linux_PortWrite(opl_port_t port, unsigned int value) { outb(value, opl_port_base + port); } opl_driver_t opl_linux_driver = { "Linux", OPL_Linux_Init, OPL_Linux_Shutdown, OPL_Linux_PortRead, OPL_Linux_PortWrite, OPL_Timer_SetCallback, OPL_Timer_ClearCallbacks, OPL_Timer_Lock, OPL_Timer_Unlock, OPL_Timer_SetPaused, OPL_Timer_AdjustCallbacks, }; #endif /* #ifdef HAVE_IOPERM */ chocolate-doom-chocolate-doom-2.2.1/opl/opl_obsd.c000066400000000000000000000047441257432200600220550ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL OpenBSD interface (also NetBSD) // #include "config.h" // OpenBSD has a i386_iopl on i386 and amd64_iopl on x86_64, // even though they do the same thing. Take care of this // here, and map set_iopl to point to the appropriate name. #if defined(HAVE_LIBI386) #include #include #include #define set_iopl i386_iopl #elif defined(HAVE_LIBAMD64) #include #include #include #define set_iopl amd64_iopl #else #define NO_OBSD_DRIVER #endif // If the above succeeded, proceed with the rest. #ifndef NO_OBSD_DRIVER #include #include #include #include #include "opl.h" #include "opl_internal.h" #include "opl_timer.h" static unsigned int opl_port_base; static int OPL_OpenBSD_Init(unsigned int port_base) { // Try to get permissions: if (set_iopl(3) < 0) { fprintf(stderr, "Failed to get raise I/O privilege level: " "check that you are running as root.\n"); return 0; } opl_port_base = port_base; // Start callback thread if (!OPL_Timer_StartThread()) { set_iopl(0); return 0; } return 1; } static void OPL_OpenBSD_Shutdown(void) { // Stop callback thread OPL_Timer_StopThread(); // Release I/O port permissions: set_iopl(0); } static unsigned int OPL_OpenBSD_PortRead(opl_port_t port) { return inb(opl_port_base + port); } static void OPL_OpenBSD_PortWrite(opl_port_t port, unsigned int value) { outb(opl_port_base + port, value); } opl_driver_t opl_openbsd_driver = { "OpenBSD", OPL_OpenBSD_Init, OPL_OpenBSD_Shutdown, OPL_OpenBSD_PortRead, OPL_OpenBSD_PortWrite, OPL_Timer_SetCallback, OPL_Timer_ClearCallbacks, OPL_Timer_Lock, OPL_Timer_Unlock, OPL_Timer_SetPaused, OPL_Timer_AdjustCallbacks, }; #endif /* #ifndef NO_OBSD_DRIVER */ chocolate-doom-chocolate-doom-2.2.1/opl/opl_queue.c000066400000000000000000000141231257432200600222420ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Queue of waiting callbacks, stored in a binary min heap, so that we // can always get the first callback. // #include #include #include #include "opl_queue.h" #define MAX_OPL_QUEUE 64 typedef struct { opl_callback_t callback; void *data; uint64_t time; } opl_queue_entry_t; struct opl_callback_queue_s { opl_queue_entry_t entries[MAX_OPL_QUEUE]; unsigned int num_entries; }; opl_callback_queue_t *OPL_Queue_Create(void) { opl_callback_queue_t *queue; queue = malloc(sizeof(opl_callback_queue_t)); queue->num_entries = 0; return queue; } void OPL_Queue_Destroy(opl_callback_queue_t *queue) { free(queue); } int OPL_Queue_IsEmpty(opl_callback_queue_t *queue) { return queue->num_entries == 0; } void OPL_Queue_Clear(opl_callback_queue_t *queue) { queue->num_entries = 0; } void OPL_Queue_Push(opl_callback_queue_t *queue, opl_callback_t callback, void *data, uint64_t time) { int entry_id; int parent_id; if (queue->num_entries >= MAX_OPL_QUEUE) { fprintf(stderr, "OPL_Queue_Push: Exceeded maximum callbacks\n"); return; } // Add to last queue entry. entry_id = queue->num_entries; ++queue->num_entries; // Shift existing entries down in the heap. while (entry_id > 0) { parent_id = (entry_id - 1) / 2; // Is the heap condition satisfied? if (time >= queue->entries[parent_id].time) { break; } // Move the existing entry down in the heap. memcpy(&queue->entries[entry_id], &queue->entries[parent_id], sizeof(opl_queue_entry_t)); // Advance to the parent. entry_id = parent_id; } // Insert new callback data. queue->entries[entry_id].callback = callback; queue->entries[entry_id].data = data; queue->entries[entry_id].time = time; } int OPL_Queue_Pop(opl_callback_queue_t *queue, opl_callback_t *callback, void **data) { opl_queue_entry_t *entry; int child1, child2; int i, next_i; // Empty? if (queue->num_entries <= 0) { return 0; } // Store the result: *callback = queue->entries[0].callback; *data = queue->entries[0].data; // Decrease the heap size, and keep pointer to the last entry in // the heap, which must now be percolated down from the top. --queue->num_entries; entry = &queue->entries[queue->num_entries]; // Percolate down. i = 0; for (;;) { child1 = i * 2 + 1; child2 = i * 2 + 2; if (child1 < queue->num_entries && queue->entries[child1].time < entry->time) { // Left child is less than entry. // Use the minimum of left and right children. if (child2 < queue->num_entries && queue->entries[child2].time < queue->entries[child1].time) { next_i = child2; } else { next_i = child1; } } else if (child2 < queue->num_entries && queue->entries[child2].time < entry->time) { // Right child is less than entry. Go down the right side. next_i = child2; } else { // Finished percolating. break; } // Percolate the next value up and advance. memcpy(&queue->entries[i], &queue->entries[next_i], sizeof(opl_queue_entry_t)); i = next_i; } // Store the old last-entry at its new position. memcpy(&queue->entries[i], entry, sizeof(opl_queue_entry_t)); return 1; } uint64_t OPL_Queue_Peek(opl_callback_queue_t *queue) { if (queue->num_entries > 0) { return queue->entries[0].time; } else { return 0; } } void OPL_Queue_AdjustCallbacks(opl_callback_queue_t *queue, uint64_t time, float factor) { int64_t offset; int i; for (i = 0; i < queue->num_entries; ++i) { offset = queue->entries[i].time - time; queue->entries[i].time = time + (uint64_t) (offset * factor); } } #ifdef TEST #include static void PrintQueueNode(opl_callback_queue_t *queue, int node, int depth) { int i; if (node >= queue->num_entries) { return; } for (i=0; ientries[node].time); PrintQueueNode(queue, node * 2 + 1, depth + 1); PrintQueueNode(queue, node * 2 + 2, depth + 1); } static void PrintQueue(opl_callback_queue_t *queue) { PrintQueueNode(queue, 0, 0); } int main() { opl_callback_queue_t *queue; int iteration; queue = OPL_Queue_Create(); for (iteration=0; iteration<5000; ++iteration) { opl_callback_t callback; void *data; unsigned int time; unsigned int newtime; int i; for (i=0; i= time); time = newtime; } assert(OPL_Queue_IsEmpty(queue)); assert(!OPL_Queue_Pop(queue, &callback, &data)); } } #endif chocolate-doom-chocolate-doom-2.2.1/opl/opl_queue.h000066400000000000000000000025351257432200600222530ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL callback queue. // #ifndef OPL_QUEUE_H #define OPL_QUEUE_H #include "opl.h" typedef struct opl_callback_queue_s opl_callback_queue_t; opl_callback_queue_t *OPL_Queue_Create(void); int OPL_Queue_IsEmpty(opl_callback_queue_t *queue); void OPL_Queue_Clear(opl_callback_queue_t *queue); void OPL_Queue_Destroy(opl_callback_queue_t *queue); void OPL_Queue_Push(opl_callback_queue_t *queue, opl_callback_t callback, void *data, uint64_t time); int OPL_Queue_Pop(opl_callback_queue_t *queue, opl_callback_t *callback, void **data); uint64_t OPL_Queue_Peek(opl_callback_queue_t *queue); void OPL_Queue_AdjustCallbacks(opl_callback_queue_t *queue, uint64_t time, float factor); #endif /* #ifndef OPL_QUEUE_H */ chocolate-doom-chocolate-doom-2.2.1/opl/opl_sdl.c000066400000000000000000000311171257432200600217020ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL SDL interface. // #include "config.h" #include #include #include #include #include "SDL.h" #include "SDL_mixer.h" #include "dbopl.h" #include "opl.h" #include "opl_internal.h" #include "opl_queue.h" #define MAX_SOUND_SLICE_TIME 100 /* ms */ typedef struct { unsigned int rate; // Number of times the timer is advanced per sec. unsigned int enabled; // Non-zero if timer is enabled. unsigned int value; // Last value that was set. uint64_t expire_time; // Calculated time that timer will expire. } opl_timer_t; // When the callback mutex is locked using OPL_Lock, callback functions // are not invoked. static SDL_mutex *callback_mutex = NULL; // Queue of callbacks waiting to be invoked. static opl_callback_queue_t *callback_queue; // Mutex used to control access to the callback queue. static SDL_mutex *callback_queue_mutex = NULL; // Current time, in us since startup: static uint64_t current_time; // If non-zero, playback is currently paused. static int opl_sdl_paused; // Time offset (in us) due to the fact that callbacks // were previously paused. static uint64_t pause_offset; // OPL software emulator structure. static Chip opl_chip; static int opl_opl3mode; // Temporary mixing buffer used by the mixing callback. static int32_t *mix_buffer = NULL; // Register number that was written. static int register_num = 0; // Timers; DBOPL does not do timer stuff itself. static opl_timer_t timer1 = { 12500, 0, 0, 0 }; static opl_timer_t timer2 = { 3125, 0, 0, 0 }; // SDL parameters. static int sdl_was_initialized = 0; static int mixing_freq, mixing_channels; static Uint16 mixing_format; static int SDLIsInitialized(void) { int freq, channels; Uint16 format; return Mix_QuerySpec(&freq, &format, &channels); } // Advance time by the specified number of samples, invoking any // callback functions as appropriate. static void AdvanceTime(unsigned int nsamples) { opl_callback_t callback; void *callback_data; uint64_t us; SDL_LockMutex(callback_queue_mutex); // Advance time. us = ((uint64_t) nsamples * OPL_SECOND) / mixing_freq; current_time += us; if (opl_sdl_paused) { pause_offset += us; } // Are there callbacks to invoke now? Keep invoking them // until there are no more left. while (!OPL_Queue_IsEmpty(callback_queue) && current_time >= OPL_Queue_Peek(callback_queue) + pause_offset) { // Pop the callback from the queue to invoke it. if (!OPL_Queue_Pop(callback_queue, &callback, &callback_data)) { break; } // The mutex stuff here is a bit complicated. We must // hold callback_mutex when we invoke the callback (so that // the control thread can use OPL_Lock() to prevent callbacks // from being invoked), but we must not be holding // callback_queue_mutex, as the callback must be able to // call OPL_SetCallback to schedule new callbacks. SDL_UnlockMutex(callback_queue_mutex); SDL_LockMutex(callback_mutex); callback(callback_data); SDL_UnlockMutex(callback_mutex); SDL_LockMutex(callback_queue_mutex); } SDL_UnlockMutex(callback_queue_mutex); } // Call the OPL emulator code to fill the specified buffer. static void FillBuffer(int16_t *buffer, unsigned int nsamples) { unsigned int i; // This seems like a reasonable assumption. mix_buffer is // 1 second long, which should always be much longer than the // SDL mix buffer. assert(nsamples < mixing_freq); if (opl_opl3mode) { Chip__GenerateBlock3(&opl_chip, nsamples, mix_buffer); // Mix into the destination buffer, doubling up into stereo. for (i=0; i buffer_len - filled) { nsamples = buffer_len - filled; } } SDL_UnlockMutex(callback_queue_mutex); // Add emulator output to buffer. FillBuffer(buffer + filled * 2, nsamples); filled += nsamples; // Invoke callbacks for this point in time. AdvanceTime(nsamples); } } static void OPL_SDL_Shutdown(void) { Mix_HookMusic(NULL, NULL); if (sdl_was_initialized) { Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); OPL_Queue_Destroy(callback_queue); free(mix_buffer); sdl_was_initialized = 0; } /* if (opl_chip != NULL) { OPLDestroy(opl_chip); opl_chip = NULL; } */ if (callback_mutex != NULL) { SDL_DestroyMutex(callback_mutex); callback_mutex = NULL; } if (callback_queue_mutex != NULL) { SDL_DestroyMutex(callback_queue_mutex); callback_queue_mutex = NULL; } } static unsigned int GetSliceSize(void) { int limit; int n; limit = (opl_sample_rate * MAX_SOUND_SLICE_TIME) / 1000; // Try all powers of two, not exceeding the limit. for (n=0;; ++n) { // 2^n <= limit < 2^n+1 ? if ((1 << (n + 1)) > limit) { return (1 << n); } } // Should never happen? return 1024; } static int OPL_SDL_Init(unsigned int port_base) { // Check if SDL_mixer has been opened already // If not, we must initialize it now if (!SDLIsInitialized()) { if (SDL_Init(SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to set up sound.\n"); return 0; } if (Mix_OpenAudio(opl_sample_rate, AUDIO_S16SYS, 2, GetSliceSize()) < 0) { fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); return 0; } SDL_PauseAudio(0); // When this module shuts down, it has the responsibility to // shut down SDL. sdl_was_initialized = 1; } else { sdl_was_initialized = 0; } opl_sdl_paused = 0; pause_offset = 0; // Queue structure of callbacks to invoke. callback_queue = OPL_Queue_Create(); current_time = 0; // Get the mixer frequency, format and number of channels. Mix_QuerySpec(&mixing_freq, &mixing_format, &mixing_channels); // Only supports AUDIO_S16SYS if (mixing_format != AUDIO_S16SYS || mixing_channels != 2) { fprintf(stderr, "OPL_SDL only supports native signed 16-bit LSB, " "stereo format!\n"); OPL_SDL_Shutdown(); return 0; } // Mix buffer: mix_buffer = malloc(mixing_freq * sizeof(uint32_t) * 2); // Create the emulator structure: DBOPL_InitTables(); Chip__Chip(&opl_chip); Chip__Setup(&opl_chip, mixing_freq); opl_opl3mode = 0; callback_mutex = SDL_CreateMutex(); callback_queue_mutex = SDL_CreateMutex(); // TODO: This should be music callback? or-? Mix_HookMusic(OPL_Mix_Callback, NULL); return 1; } static unsigned int OPL_SDL_PortRead(opl_port_t port) { unsigned int result = 0; if (port == OPL_REGISTER_PORT_OPL3) { return 0xff; } if (timer1.enabled && current_time > timer1.expire_time) { result |= 0x80; // Either have expired result |= 0x40; // Timer 1 has expired } if (timer2.enabled && current_time > timer2.expire_time) { result |= 0x80; // Either have expired result |= 0x20; // Timer 2 has expired } return result; } static void OPLTimer_CalculateEndTime(opl_timer_t *timer) { int tics; // If the timer is enabled, calculate the time when the timer // will expire. if (timer->enabled) { tics = 0x100 - timer->value; timer->expire_time = current_time + ((uint64_t) tics * OPL_SECOND) / timer->rate; } } static void WriteRegister(unsigned int reg_num, unsigned int value) { switch (reg_num) { case OPL_REG_TIMER1: timer1.value = value; OPLTimer_CalculateEndTime(&timer1); break; case OPL_REG_TIMER2: timer2.value = value; OPLTimer_CalculateEndTime(&timer2); break; case OPL_REG_TIMER_CTRL: if (value & 0x80) { timer1.enabled = 0; timer2.enabled = 0; } else { if ((value & 0x40) == 0) { timer1.enabled = (value & 0x01) != 0; OPLTimer_CalculateEndTime(&timer1); } if ((value & 0x20) == 0) { timer1.enabled = (value & 0x02) != 0; OPLTimer_CalculateEndTime(&timer2); } } break; case OPL_REG_NEW: opl_opl3mode = value & 0x01; default: Chip__WriteReg(&opl_chip, reg_num, value); break; } } static void OPL_SDL_PortWrite(opl_port_t port, unsigned int value) { if (port == OPL_REGISTER_PORT) { register_num = value; } else if (port == OPL_REGISTER_PORT_OPL3) { register_num = value | 0x100; } else if (port == OPL_DATA_PORT) { WriteRegister(register_num, value); } } static void OPL_SDL_SetCallback(uint64_t us, opl_callback_t callback, void *data) { SDL_LockMutex(callback_queue_mutex); OPL_Queue_Push(callback_queue, callback, data, current_time - pause_offset + us); SDL_UnlockMutex(callback_queue_mutex); } static void OPL_SDL_ClearCallbacks(void) { SDL_LockMutex(callback_queue_mutex); OPL_Queue_Clear(callback_queue); SDL_UnlockMutex(callback_queue_mutex); } static void OPL_SDL_Lock(void) { SDL_LockMutex(callback_mutex); } static void OPL_SDL_Unlock(void) { SDL_UnlockMutex(callback_mutex); } static void OPL_SDL_SetPaused(int paused) { opl_sdl_paused = paused; } static void OPL_SDL_AdjustCallbacks(float factor) { SDL_LockMutex(callback_queue_mutex); OPL_Queue_AdjustCallbacks(callback_queue, current_time, factor); SDL_UnlockMutex(callback_queue_mutex); } opl_driver_t opl_sdl_driver = { "SDL", OPL_SDL_Init, OPL_SDL_Shutdown, OPL_SDL_PortRead, OPL_SDL_PortWrite, OPL_SDL_SetCallback, OPL_SDL_ClearCallbacks, OPL_SDL_Lock, OPL_SDL_Unlock, OPL_SDL_SetPaused, OPL_SDL_AdjustCallbacks, }; chocolate-doom-chocolate-doom-2.2.1/opl/opl_timer.c000066400000000000000000000141121257432200600222340ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL timer thread. // Once started using OPL_Timer_StartThread, the thread sleeps, // waking up to invoke callbacks set using OPL_Timer_SetCallback. // #include "SDL.h" #include "opl_timer.h" #include "opl_queue.h" typedef enum { THREAD_STATE_STOPPED, THREAD_STATE_RUNNING, THREAD_STATE_STOPPING, } thread_state_t; static SDL_Thread *timer_thread = NULL; static thread_state_t timer_thread_state; static uint64_t current_time; // If non-zero, callbacks are currently paused. static int opl_timer_paused; // Offset in microseconds to adjust time due to the fact that playback // was paused. static uint64_t pause_offset = 0; // Queue of callbacks waiting to be invoked. // The callback queue mutex is held while the callback queue structure // or current_time is being accessed. static opl_callback_queue_t *callback_queue; static SDL_mutex *callback_queue_mutex; // The timer mutex is held while timer callback functions are being // invoked, so that the calling code can prevent clashes. static SDL_mutex *timer_mutex; // Returns true if there is a callback at the head of the queue ready // to be invoked. Otherwise, next_time is set to the time when the // timer thread must wake up again to check. static int CallbackWaiting(uint64_t *next_time) { // If paused, just wait in 50ms increments until unpaused. // Update pause_offset so after we unpause, the callback // times will be right. if (opl_timer_paused) { *next_time = current_time + 50 * OPL_MS; pause_offset += 50 * OPL_MS; return 0; } // If there are no queued callbacks, sleep for 50ms at a time // until a callback is added. if (OPL_Queue_IsEmpty(callback_queue)) { *next_time = current_time + 50 * OPL_MS; return 0; } // Read the time of the first callback in the queue. // If the time for the callback has not yet arrived, // we must sleep until the callback time. *next_time = OPL_Queue_Peek(callback_queue) + pause_offset; return *next_time <= current_time; } static uint64_t GetNextTime(void) { opl_callback_t callback; void *callback_data; uint64_t next_time; int have_callback; // Keep running through callbacks until there are none ready to // run. When we run out of callbacks, next_time will be set. do { SDL_LockMutex(callback_queue_mutex); // Check if the callback at the head of the list is ready to // be invoked. If so, pop from the head of the queue. have_callback = CallbackWaiting(&next_time); if (have_callback) { OPL_Queue_Pop(callback_queue, &callback, &callback_data); } SDL_UnlockMutex(callback_queue_mutex); // Now invoke the callback, if we have one. // The timer mutex is held while the callback is invoked. if (have_callback) { SDL_LockMutex(timer_mutex); callback(callback_data); SDL_UnlockMutex(timer_mutex); } } while (have_callback); return next_time; } static int ThreadFunction(void *unused) { uint64_t next_time; uint64_t now; // Keep running until OPL_Timer_StopThread is called. while (timer_thread_state == THREAD_STATE_RUNNING) { // Get the next time that we must sleep until, and // wait until that time. next_time = GetNextTime(); now = SDL_GetTicks() * OPL_MS; if (next_time > now) { SDL_Delay((next_time - now) / OPL_MS); } // Update the current time. SDL_LockMutex(callback_queue_mutex); current_time = next_time; SDL_UnlockMutex(callback_queue_mutex); } timer_thread_state = THREAD_STATE_STOPPED; return 0; } static void InitResources(void) { callback_queue = OPL_Queue_Create(); timer_mutex = SDL_CreateMutex(); callback_queue_mutex = SDL_CreateMutex(); } static void FreeResources(void) { OPL_Queue_Destroy(callback_queue); SDL_DestroyMutex(callback_queue_mutex); SDL_DestroyMutex(timer_mutex); } int OPL_Timer_StartThread(void) { InitResources(); timer_thread_state = THREAD_STATE_RUNNING; current_time = SDL_GetTicks(); opl_timer_paused = 0; pause_offset = 0; timer_thread = SDL_CreateThread(ThreadFunction, NULL); if (timer_thread == NULL) { timer_thread_state = THREAD_STATE_STOPPED; FreeResources(); return 0; } return 1; } void OPL_Timer_StopThread(void) { timer_thread_state = THREAD_STATE_STOPPING; while (timer_thread_state != THREAD_STATE_STOPPED) { SDL_Delay(1); } FreeResources(); } void OPL_Timer_SetCallback(uint64_t us, opl_callback_t callback, void *data) { SDL_LockMutex(callback_queue_mutex); OPL_Queue_Push(callback_queue, callback, data, current_time + us - pause_offset); SDL_UnlockMutex(callback_queue_mutex); } void OPL_Timer_ClearCallbacks(void) { SDL_LockMutex(callback_queue_mutex); OPL_Queue_Clear(callback_queue); SDL_UnlockMutex(callback_queue_mutex); } void OPL_Timer_AdjustCallbacks(float factor) { SDL_LockMutex(callback_queue_mutex); OPL_Queue_AdjustCallbacks(callback_queue, current_time, factor); SDL_UnlockMutex(callback_queue_mutex); } void OPL_Timer_Lock(void) { SDL_LockMutex(timer_mutex); } void OPL_Timer_Unlock(void) { SDL_UnlockMutex(timer_mutex); } void OPL_Timer_SetPaused(int paused) { SDL_LockMutex(callback_queue_mutex); opl_timer_paused = paused; SDL_UnlockMutex(callback_queue_mutex); } chocolate-doom-chocolate-doom-2.2.1/opl/opl_timer.h000066400000000000000000000017611257432200600222470ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL timer thread. // #ifndef OPL_TIMER_H #define OPL_TIMER_H #include "opl.h" int OPL_Timer_StartThread(void); void OPL_Timer_StopThread(void); void OPL_Timer_SetCallback(uint64_t us, opl_callback_t callback, void *data); void OPL_Timer_ClearCallbacks(void); void OPL_Timer_Lock(void); void OPL_Timer_Unlock(void); void OPL_Timer_SetPaused(int paused); void OPL_Timer_AdjustCallbacks(float factor); #endif /* #ifndef OPL_TIMER_H */ chocolate-doom-chocolate-doom-2.2.1/opl/opl_win32.c000066400000000000000000000072521257432200600220650ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // OPL Win32 native interface. // #include "config.h" #ifdef _WIN32 #include #define WIN32_LEAN_AND_MEAN #include #include "opl.h" #include "opl_internal.h" #include "opl_timer.h" #include "ioperm_sys.h" static unsigned int opl_port_base; // MingW? #if defined(__GNUC__) && defined(__i386__) static unsigned int OPL_Win32_PortRead(opl_port_t port) { unsigned char result; __asm__ volatile ( "movl %1, %%edx\n" "inb %%dx, %%al\n" "movb %%al, %0" : "=m" (result) : "r" (opl_port_base + port) : "edx", "al", "memory" ); return result; } static void OPL_Win32_PortWrite(opl_port_t port, unsigned int value) { __asm__ volatile ( "movl %0, %%edx\n" "movb %1, %%al\n" "outb %%al, %%dx" : : "r" (opl_port_base + port), "r" ((unsigned char) value) : "edx", "al" ); } // haleyjd 20110417: MSVC version #elif defined(_MSC_VER) && defined(_M_IX86) static unsigned int OPL_Win32_PortRead(opl_port_t port) { unsigned char result; opl_port_t dst_port = opl_port_base + port; __asm { mov edx, dword ptr [dst_port] in al, dx mov byte ptr [result], al } return result; } static void OPL_Win32_PortWrite(opl_port_t port, unsigned int value) { opl_port_t dst_port = opl_port_base + port; __asm { mov edx, dword ptr [dst_port] mov al, byte ptr [value] out dx, al } } #else // Not x86, or don't know how to do port R/W on this compiler. #define NO_PORT_RW static unsigned int OPL_Win32_PortRead(opl_port_t port) { return 0; } static void OPL_Win32_PortWrite(opl_port_t port, unsigned int value) { } #endif static int OPL_Win32_Init(unsigned int port_base) { #ifndef NO_PORT_RW OSVERSIONINFO version_info; opl_port_base = port_base; // Check the OS version. memset(&version_info, 0, sizeof(version_info)); version_info.dwOSVersionInfoSize = sizeof(version_info); GetVersionEx(&version_info); // On NT-based systems, we must acquire I/O port permissions // using the ioperm.sys driver. if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT) { // Install driver. if (!IOperm_InstallDriver()) { return 0; } // Open port range. if (!IOperm_EnablePortRange(opl_port_base, 2, 1)) { IOperm_UninstallDriver(); return 0; } } // Start callback thread if (!OPL_Timer_StartThread()) { IOperm_UninstallDriver(); return 0; } return 1; #endif return 0; } static void OPL_Win32_Shutdown(void) { // Stop callback thread OPL_Timer_StopThread(); // Unload IOperm library. IOperm_UninstallDriver(); } opl_driver_t opl_win32_driver = { "Win32", OPL_Win32_Init, OPL_Win32_Shutdown, OPL_Win32_PortRead, OPL_Win32_PortWrite, OPL_Timer_SetCallback, OPL_Timer_ClearCallbacks, OPL_Timer_Lock, OPL_Timer_Unlock, OPL_Timer_SetPaused, OPL_Timer_AdjustCallbacks, }; #endif /* #ifdef _WIN32 */ chocolate-doom-chocolate-doom-2.2.1/pcsound/000077500000000000000000000000001257432200600207605ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/pcsound/.gitignore000066400000000000000000000000701257432200600227450ustar00rootroot00000000000000Makefile.in Makefile .deps libpcsound.a *.rc tags TAGS chocolate-doom-chocolate-doom-2.2.1/pcsound/Makefile.am000066400000000000000000000006451257432200600230210ustar00rootroot00000000000000 AM_CFLAGS=@SDLMIXER_CFLAGS@ noinst_LIBRARIES=libpcsound.a libpcsound_a_SOURCES = \ pcsound.c pcsound.h \ pcsound_bsd.c \ pcsound_sdl.c \ pcsound_linux.c \ pcsound_win32.c \ pcsound_internal.h chocolate-doom-chocolate-doom-2.2.1/pcsound/pcsound.c000066400000000000000000000056221257432200600226040ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker interface. // #include #include #include #include "config.h" #include "pcsound.h" #include "pcsound_internal.h" #ifdef HAVE_DEV_ISA_SPKRIO_H #define HAVE_BSD_SPEAKER #endif #ifdef HAVE_DEV_SPEAKER_SPEAKER_H #define HAVE_BSD_SPEAKER #endif #ifdef _WIN32 extern pcsound_driver_t pcsound_win32_driver; #endif #ifdef HAVE_BSD_SPEAKER extern pcsound_driver_t pcsound_bsd_driver; #endif #ifdef HAVE_LINUX_KD_H extern pcsound_driver_t pcsound_linux_driver; #endif extern pcsound_driver_t pcsound_sdl_driver; static pcsound_driver_t *drivers[] = { #ifdef HAVE_LINUX_KD_H &pcsound_linux_driver, #endif #ifdef HAVE_BSD_SPEAKER &pcsound_bsd_driver, #endif #ifdef _WIN32 &pcsound_win32_driver, #endif &pcsound_sdl_driver, NULL, }; static pcsound_driver_t *pcsound_driver = NULL; int pcsound_sample_rate; void PCSound_SetSampleRate(int rate) { pcsound_sample_rate = rate; } int PCSound_Init(pcsound_callback_func callback_func) { char *driver_name; int i; if (pcsound_driver != NULL) { return 1; } // Check if the environment variable is set driver_name = getenv("PCSOUND_DRIVER"); if (driver_name != NULL) { for (i=0; drivers[i] != NULL; ++i) { if (!strcmp(drivers[i]->name, driver_name)) { // Found the driver! if (drivers[i]->init_func(callback_func)) { pcsound_driver = drivers[i]; } else { printf("Failed to initialize PC sound driver: %s\n", drivers[i]->name); break; } } } } else { // Try all drivers until we find a working one for (i=0; drivers[i] != NULL; ++i) { if (drivers[i]->init_func(callback_func)) { pcsound_driver = drivers[i]; break; } } } if (pcsound_driver != NULL) { printf("Using PC sound driver: %s\n", pcsound_driver->name); return 1; } else { printf("Failed to find a working PC sound driver.\n"); return 0; } } void PCSound_Shutdown(void) { pcsound_driver->shutdown_func(); pcsound_driver = NULL; } chocolate-doom-chocolate-doom-2.2.1/pcsound/pcsound.h000066400000000000000000000021641257432200600226070ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker interface. // #ifndef PCSOUND_H #define PCSOUND_H typedef void (*pcsound_callback_func)(int *duration, int *frequency); // Initialise the PC speaker subsystem. The given function is called // periodically to request more sound data to play. int PCSound_Init(pcsound_callback_func callback_func); // Shut down the PC speaker subsystem. void PCSound_Shutdown(void); // Set the preferred output sample rate when emulating a PC speaker. // This must be called before PCSound_Init. void PCSound_SetSampleRate(int rate); #endif /* #ifndef PCSOUND_H */ chocolate-doom-chocolate-doom-2.2.1/pcsound/pcsound_bsd.c000066400000000000000000000160361257432200600234350ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker driver for [Open]BSD // (Should be NetBSD as well, but untested). // #include "config.h" // OpenBSD/NetBSD: #ifdef HAVE_DEV_ISA_SPKRIO_H #define HAVE_BSD_SPEAKER #include #endif // FreeBSD #ifdef HAVE_DEV_SPEAKER_SPEAKER_H #define HAVE_BSD_SPEAKER #include #endif #ifdef HAVE_BSD_SPEAKER #include #include #include #include #include #include #include #include #include #include #include #include #include "SDL.h" #include "SDL_thread.h" #include "pcsound.h" #include "pcsound_internal.h" #define SPEAKER_DEVICE "/dev/speaker" // // This driver is far more complicated than it should be, because // OpenBSD has sucky support for threads. Because multithreading // is done in userspace, invoking the ioctl to make the speaker // beep will lock all threads until the beep has completed. // // Thus, to get the beeping to occur in real-time, we must invoke // the ioctl in a separate process. To do this, a separate // sound server is forked that listens on a socket for tones to // play. When a tone is received, a reply is sent back to the // main process and the tone played. // // Meanwhile, back in the main process, there is a sound thread // that runs, invoking the pcsound callback function to get // more tones. This blocks on the sound server socket, waiting // for replies. In this way, when the sound server finishes // playing a tone, the next one is sent. // // This driver is a bit less accurate than the others, because // we can only specify sound durations in 1/100ths of a second, // as opposed to the normal millisecond durations. static pcsound_callback_func callback; static int sound_server_pid; static int sleep_adjust = 0; static int sound_thread_running; static SDL_Thread *sound_thread_handle; static int sound_server_pipe[2]; // Play a sound, checking how long the system call takes to complete // and autoadjusting for drift. static void AdjustedBeep(int speaker_handle, int ms, int freq) { unsigned int start_time; unsigned int end_time; unsigned int actual_time; tone_t tone; // Adjust based on previous error to keep the tempo right if (sleep_adjust > ms) { sleep_adjust -= ms; return; } else { ms -= sleep_adjust; } // Invoke the system call and time how long it takes start_time = SDL_GetTicks(); tone.duration = ms / 10; // in 100ths of a second tone.frequency = freq; // Always a positive duration if (tone.duration < 1) { tone.duration = 1; } if (ioctl(speaker_handle, SPKRTONE, &tone) != 0) { perror("ioctl"); return; } end_time = SDL_GetTicks(); if (end_time > start_time) { actual_time = end_time - start_time; } else { actual_time = ms; } if (actual_time < ms) { actual_time = ms; } // Save sleep_adjust for next time sleep_adjust = actual_time - ms; } static void SoundServer(int speaker_handle) { tone_t tone; int result; // Run in a loop, invoking the callback for (;;) { result = read(sound_server_pipe[1], &tone, sizeof(tone_t)); if (result < 0) { perror("read"); return; } // Send back a response, so the main process knows to send another write(sound_server_pipe[1], &tone, sizeof(tone_t)); // Beep! (blocks until complete) AdjustedBeep(speaker_handle, tone.duration, tone.frequency); } } // Start up the sound server. Returns non-zero if successful. static int StartSoundServer(void) { int result; int speaker_handle; // Try to open the speaker device speaker_handle = open(SPEAKER_DEVICE, O_WRONLY); if (speaker_handle == -1) { // Don't have permissions for the console device? fprintf(stderr, "StartSoundServer: Failed to open '%s': %s\n", SPEAKER_DEVICE, strerror(errno)); return 0; } // Create a pipe for communications if (socketpair(AF_UNIX, SOCK_STREAM, 0, sound_server_pipe) < 0) { perror("socketpair"); close(speaker_handle); return 0; } // Start a separate process to generate PC speaker output // We can't use the SDL threading functions because OpenBSD's // threading sucks :-( result = fork(); if (result < 0) { fprintf(stderr, "Failed to fork sound server!\n"); close(speaker_handle); return 0; } else if (result == 0) { // This is the child (sound server) SoundServer(speaker_handle); close(speaker_handle); exit(0); } else { // This is the parent sound_server_pid = result; close(speaker_handle); } return 1; } static void StopSoundServer(void) { int status; kill(sound_server_pid, SIGINT); waitpid(sound_server_pid, &status, 0); } static int SoundThread(void *unused) { tone_t tone; int duration; int frequency; while (sound_thread_running) { // Get the next frequency to play callback(&duration, &frequency); //printf("dur: %i, freq: %i\n", duration, frequency); // Build up a tone structure and send to the sound server tone.frequency = frequency; tone.duration = duration; if (write(sound_server_pipe[0], &tone, sizeof(tone_t)) < 0) { perror("write"); break; } // Wait until the sound server responds before sending another if (read(sound_server_pipe[0], &tone, sizeof(tone_t)) < 0) { perror("read"); break; } } return 0; } static int PCSound_BSD_Init(pcsound_callback_func callback_func) { callback = callback_func; if (!StartSoundServer()) { fprintf(stderr, "PCSound_BSD_Init: Failed to start sound server.\n"); return 0; } sound_thread_running = 1; sound_thread_handle = SDL_CreateThread(SoundThread, NULL); return 1; } static void PCSound_BSD_Shutdown(void) { // Stop the sound thread sound_thread_running = 0; SDL_WaitThread(sound_thread_handle, NULL); // Stop the sound server StopSoundServer(); } pcsound_driver_t pcsound_bsd_driver = { "BSD", PCSound_BSD_Init, PCSound_BSD_Shutdown, }; #endif /* #ifdef HAVE_BSD_SPEAKER */ chocolate-doom-chocolate-doom-2.2.1/pcsound/pcsound_internal.h000066400000000000000000000020561257432200600245030ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker interface. // #ifndef PCSOUND_INTERNAL_H #define PCSOUND_INTERNAL_H #include "pcsound.h" #define PCSOUND_8253_FREQUENCY 1193280 typedef struct pcsound_driver_s pcsound_driver_t; typedef int (*pcsound_init_func)(pcsound_callback_func callback); typedef void (*pcsound_shutdown_func)(void); struct pcsound_driver_s { char *name; pcsound_init_func init_func; pcsound_shutdown_func shutdown_func; }; extern int pcsound_sample_rate; #endif /* #ifndef PCSOUND_INTERNAL_H */ chocolate-doom-chocolate-doom-2.2.1/pcsound/pcsound_linux.c000066400000000000000000000064411257432200600240230ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker driver for Linux. // #include "config.h" #ifdef HAVE_LINUX_KD_H #include #include #include #include #include #include #include #include #include "SDL.h" #include "SDL_thread.h" #include "pcsound.h" #include "pcsound_internal.h" #define CONSOLE_DEVICE "/dev/console" static int console_handle; static pcsound_callback_func callback; static int sound_thread_running = 0; static SDL_Thread *sound_thread_handle; static int sleep_adjust = 0; static void AdjustedSleep(unsigned int ms) { unsigned int start_time; unsigned int end_time; unsigned int actual_time; // Adjust based on previous error to keep the tempo right if (sleep_adjust > ms) { sleep_adjust -= ms; return; } else { ms -= sleep_adjust; } // Do the sleep and record how long it takes start_time = SDL_GetTicks(); SDL_Delay(ms); end_time = SDL_GetTicks(); if (end_time > start_time) { actual_time = end_time - start_time; } else { actual_time = ms; } if (actual_time < ms) { actual_time = ms; } // Save sleep_adjust for next time sleep_adjust = actual_time - ms; } static int SoundThread(void *unused) { int frequency; int duration; int cycles; while (sound_thread_running) { callback(&duration, &frequency); if (frequency != 0) { cycles = PCSOUND_8253_FREQUENCY / frequency; } else { cycles = 0; } ioctl(console_handle, KIOCSOUND, cycles); AdjustedSleep(duration); } return 0; } static int PCSound_Linux_Init(pcsound_callback_func callback_func) { // Try to open the console console_handle = open(CONSOLE_DEVICE, O_WRONLY); if (console_handle == -1) { // Don't have permissions for the console device? fprintf(stderr, "PCSound_Linux_Init: Failed to open '%s': %s\n", CONSOLE_DEVICE, strerror(errno)); return 0; } if (ioctl(console_handle, KIOCSOUND, 0) < 0) { // KIOCSOUND not supported: non-PC linux? close(console_handle); return 0; } // Start a thread up to generate PC speaker output callback = callback_func; sound_thread_running = 1; sound_thread_handle = SDL_CreateThread(SoundThread, NULL); return 1; } static void PCSound_Linux_Shutdown(void) { sound_thread_running = 0; SDL_WaitThread(sound_thread_handle, NULL); close(console_handle); } pcsound_driver_t pcsound_linux_driver = { "Linux", PCSound_Linux_Init, PCSound_Linux_Shutdown, }; #endif /* #ifdef HAVE_LINUX_KD_H */ chocolate-doom-chocolate-doom-2.2.1/pcsound/pcsound_sdl.c000066400000000000000000000132301257432200600234400ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker interface. // #include #include #include "SDL.h" #include "SDL_mixer.h" #include "pcsound.h" #include "pcsound_internal.h" #define MAX_SOUND_SLICE_TIME 70 /* ms */ #define SQUARE_WAVE_AMP 0x2000 // If true, we initialized SDL and have the responsibility to shut it // down static int sdl_was_initialized = 0; // Callback function to invoke when we want new sound data static pcsound_callback_func callback; // Output sound format static int mixing_freq; static Uint16 mixing_format; static int mixing_channels; // Currently playing sound // current_remaining is the number of remaining samples that must be played // before we invoke the callback to get the next frequency. static int current_remaining; static int current_freq; static int phase_offset = 0; // Mixer function that does the PC speaker emulation static void PCSound_Mix_Callback(void *udata, Uint8 *stream, int len) { Sint16 *leftptr; Sint16 *rightptr; Sint16 this_value; int oldfreq; int i; int nsamples; // Number of samples is quadrupled, because of 16-bit and stereo nsamples = len / 4; leftptr = (Sint16 *) stream; rightptr = ((Sint16 *) stream) + 1; // Fill the output buffer for (i=0; i limit) { return (1 << n); } } // Should never happen? return 1024; } static int PCSound_SDL_Init(pcsound_callback_func callback_func) { int slicesize; // Check if SDL_mixer has been opened already // If not, we must initialize it now if (!SDLIsInitialized()) { if (SDL_Init(SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to set up sound.\n"); return 0; } slicesize = GetSliceSize(); if (Mix_OpenAudio(pcsound_sample_rate, AUDIO_S16SYS, 2, slicesize) < 0) { fprintf(stderr, "Error initializing SDL_mixer: %s\n", Mix_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); return 0; } SDL_PauseAudio(0); // When this module shuts down, it has the responsibility to // shut down SDL. sdl_was_initialized = 1; } // Get the mixer frequency, format and number of channels. Mix_QuerySpec(&mixing_freq, &mixing_format, &mixing_channels); // Only supports AUDIO_S16SYS if (mixing_format != AUDIO_S16SYS || mixing_channels != 2) { fprintf(stderr, "PCSound_SDL only supports native signed 16-bit LSB, " "stereo format!\n"); PCSound_SDL_Shutdown(); return 0; } callback = callback_func; current_freq = 0; current_remaining = 0; Mix_SetPostMix(PCSound_Mix_Callback, NULL); return 1; } pcsound_driver_t pcsound_sdl_driver = { "SDL", PCSound_SDL_Init, PCSound_SDL_Shutdown, }; chocolate-doom-chocolate-doom-2.2.1/pcsound/pcsound_win32.c000066400000000000000000000044101257432200600236200ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker interface. // #ifdef _WIN32 #include "SDL.h" #include "SDL_thread.h" #include #include "pcsound.h" #include "pcsound_internal.h" static SDL_Thread *sound_thread_handle; static int sound_thread_running; static pcsound_callback_func callback; static int SoundThread(void *unused) { int frequency; int duration; while (sound_thread_running) { callback(&duration, &frequency); if (frequency != 0) { Beep(frequency, duration); } else { Sleep(duration); } } return 0; } static int PCSound_Win32_Init(pcsound_callback_func callback_func) { OSVERSIONINFO osvi; BOOL result; // Temporarily disabled - the Windows scheduler is strange and // stupid. return 0; // Find the OS version osvi.dwOSVersionInfoSize = sizeof(osvi); result = GetVersionEx(&osvi); if (!result) { return 0; } // Beep() ignores its arguments on win9x, so this driver will // not work there. if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) { // TODO: Use _out() to write directly to the PC speaker on // win9x: See PC/winsound.c in the Python standard library. return 0; } // Start a thread to play sound. callback = callback_func; sound_thread_running = 1; sound_thread_handle = SDL_CreateThread(SoundThread, NULL); return 1; } static void PCSound_Win32_Shutdown(void) { sound_thread_running = 0; SDL_WaitThread(sound_thread_handle, NULL); } pcsound_driver_t pcsound_win32_driver = { "Windows", PCSound_Win32_Init, PCSound_Win32_Shutdown, }; #endif /* #ifdef _WIN32 */ chocolate-doom-chocolate-doom-2.2.1/pkg/000077500000000000000000000000001257432200600200665ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/pkg/.gitignore000066400000000000000000000000411257432200600220510ustar00rootroot00000000000000Makefile Makefile.in config.make chocolate-doom-chocolate-doom-2.2.1/pkg/Makefile.am000066400000000000000000000033021257432200600221200ustar00rootroot00000000000000 OSX_FILES= \ osx/Resources/128x128.png \ osx/Resources/app.icns \ osx/Resources/app.png \ osx/Resources/wadfile.icns \ osx/Resources/wadfile.png \ osx/Resources/launcher.nib/designable.nib \ osx/Resources/launcher.nib/keyedobjects.nib \ osx/disk/dir.DS_Store \ osx/disk/background.png \ osx/GNUmakefile \ osx/Info.plist.in osx/Info-gnustep.plist.in \ osx/PkgInfo \ osx/cp-with-libs \ osx/dmgfix \ osx/main.m \ osx/AppController.m osx/AppController.h \ osx/Execute.m osx/Execute.h \ osx/IWADController.m osx/IWADController.h \ osx/IWADLocation.m osx/IWADLocation.h \ osx/LauncherManager.m osx/LauncherManager.h WIN32_FILES= \ win32/GNUmakefile \ win32/README EXTRA_DIST=$(OSX_FILES) $(WIN32_FILES) chocolate-doom-chocolate-doom-2.2.1/pkg/config.make.in000066400000000000000000000012171257432200600226000ustar00rootroot00000000000000# Shared file included by the makefiles used to build packages. # This contains various information needed by the makefiles, # and is autogenerated by configure to include various # necessary details. # Tools needed: CC = @CC@ STRIP = @STRIP@ # Package name and version number: PROGRAM_PREFIX = @PROGRAM_PREFIX@ PACKAGE = @PACKAGE@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ # Documentation files to distribute with packages. DOC_FILES = README \ README.Music \ COPYING \ ChangeLog \ NEWS chocolate-doom-chocolate-doom-2.2.1/pkg/osx/000077500000000000000000000000001257432200600206775ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/pkg/osx/.gitignore000066400000000000000000000000751257432200600226710ustar00rootroot00000000000000Info.plist Info-gnustep.plist launcher *.o *.d *.dmg staging chocolate-doom-chocolate-doom-2.2.1/pkg/osx/AppController.h000066400000000000000000000021751257432200600236410ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef LAUNCHER_APPCONTROLLER_H #define LAUNCHER_APPCONTROLLER_H #include #include "LauncherManager.h" @interface AppController : NSObject { LauncherManager *launcherManager; BOOL filesAdded; } + (void)initialize; - (id)init; - (void)dealloc; - (void)awakeFromNib; - (void)applicationDidFinishLaunching:(NSNotification *)aNotif; - (BOOL)applicationShouldTerminate:(id)sender; - (void)applicationWillTerminate:(NSNotification *)aNotif; - (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName; - (void)showPrefPanel:(id)sender; @end #endif chocolate-doom-chocolate-doom-2.2.1/pkg/osx/AppController.m000066400000000000000000000063671257432200600236550ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "AppController.h" #include "config.h" @implementation AppController + (void)initialize { NSMutableDictionary *defaults = [NSMutableDictionary dictionary]; /* * Register your app's defaults here by adding objects to the * dictionary, eg * * [defaults setObject:anObject forKey:keyForThatObject]; * */ [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; [[NSUserDefaults standardUserDefaults] synchronize]; } - (id)init { if ((self = [super init])) { } self->filesAdded = NO; return self; } - (void)dealloc { [super dealloc]; } - (void)awakeFromNib { [[NSApp mainMenu] setTitle:@PACKAGE_NAME]; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotif { // Uncomment if your application is Renaissance-based // [NSBundle loadGSMarkupNamed:@"Main" owner:self]; } - (BOOL)applicationShouldTerminate:(id)sender { return YES; } - (void)applicationWillTerminate:(NSNotification *)aNotif { } - (BOOL) application:(NSApplication *) application openFile:(NSString *) fileName { NSString *extension; // This may be an IWAD. If so, add it to the IWAD configuration; // don't add it like a PWAD. if ([self->launcherManager addIWADPath: fileName]) { return YES; } // If this is the first file added, clear out the existing // command line. This allows us to select multiple files // in the finder and open them all together (for TCs, etc). if (!self->filesAdded) { [self->launcherManager clearCommandLine]; } // Add file with appropriate command line option based on extension: extension = [fileName pathExtension]; if (![extension caseInsensitiveCompare: @"wad"]) { [self->launcherManager addFileToCommandLine: fileName forArgument: @"-merge"]; } else if (![extension caseInsensitiveCompare: @"deh"]) { [self->launcherManager addFileToCommandLine: fileName forArgument: @"-deh"]; [self->launcherManager selectGameByName: "doom"]; } else if (![extension caseInsensitiveCompare: @"hhe"]) { [self->launcherManager addFileToCommandLine: fileName forArgument: @"-deh"]; [self->launcherManager selectGameByName: "heretic"]; } else if (![extension caseInsensitiveCompare: @"seh"]) { [self->launcherManager addFileToCommandLine: fileName forArgument: @"-deh"]; [self->launcherManager selectGameByName: "strife"]; } else { return NO; } self->filesAdded = YES; return YES; } - (void)showPrefPanel:(id)sender { } @end chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Execute.h000066400000000000000000000015431257432200600224550ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef LAUNCHER_EXECUTE_H #define LAUNCHER_EXECUTE_H void SetProgramLocation(const char *path); void ExecuteProgram(const char *executable, const char *iwad, const char *args); void OpenTerminalWindow(const char *doomwadpath); void OpenDocumentation(const char *filename); #endif /* #ifndef LAUNCHER_EXECUTE_H */ chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Execute.m000066400000000000000000000126241257432200600224640ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include #include #include #include #include #include "config.h" #define RESPONSE_FILE "/tmp/launcher.rsp" #define TEMP_SCRIPT "/tmp/tempscript.sh" static char *executable_path; // Called on startup to save the location of the launcher program // (within a package, other executables should be in the same directory) void SetProgramLocation(const char *path) { char *p; executable_path = strdup(path); p = strrchr(executable_path, '/'); *p = '\0'; } // Write out the response file containing command line arguments. static void WriteResponseFile(const char *iwad, const char *args) { FILE *fstream; fstream = fopen(RESPONSE_FILE, "w"); if (iwad != NULL) { fprintf(fstream, "-iwad \"%s\"", iwad); } if (args != NULL) { fprintf(fstream, "%s", args); } fclose(fstream); } static void DoExec(const char *executable, const char *iwad, const char *args) { char *argv[3]; asprintf(&argv[0], "%s/%s", executable_path, executable); if (iwad != NULL || args != NULL) { WriteResponseFile(iwad, args); argv[1] = "@" RESPONSE_FILE; argv[2] = NULL; } else { argv[1] = NULL; } execv(argv[0], argv); exit(-1); } // Execute the specified executable contained in the same directory // as the launcher, with the specified arguments. void ExecuteProgram(const char *executable, const char *iwad, const char *args) { pid_t childpid; char *homedir; childpid = fork(); if (childpid == 0) { signal(SIGCHLD, SIG_DFL); // Change directory to home dir before launch, so that any demos // are saved somewhere sensible. homedir = getenv("HOME"); if (homedir != NULL) { chdir(homedir); } DoExec(executable, iwad, args); } else { signal(SIGCHLD, SIG_IGN); } } // Write a sequence of commands that will display the specified message // via shell commands. static void WriteMessage(FILE *script, char *msg) { char *p; fprintf(script, "echo \""); for (p=msg; *p != '\0'; ++p) { // Start new line? if (*p == '\n') { fprintf(script, "\"\necho \""); continue; } // Escaped character? if (*p == '\\' || *p == '\"') { fprintf(script, "\\"); } fprintf(script, "%c", *p); } fprintf(script, "\"\n"); } // Open a terminal window with the PATH set appropriately, and DOOMWADPATH // set to the specified value. void OpenTerminalWindow(const char *doomwadpath) { FILE *stream; // Generate a shell script that sets the PATH to include the location // where the Doom binaries are, and DOOMWADPATH to include the // IWAD files that have been configured in the launcher interface. // The script then deletes itself and starts a shell. stream = fopen(TEMP_SCRIPT, "w"); fprintf(stream, "#!/bin/sh\n"); //fprintf(stream, "set -x\n"); fprintf(stream, "PATH=\"%s:$PATH\"\n", executable_path); // MANPATH is set to point to the directory within the bundle that // contains the Unix manpages. However, the bundle name or path to // it can contain a space, and OS X doesn't like this! As a // workaround, create a symlink in /tmp to point to the real directory, // and put *this* in MANPATH. fprintf(stream, "rm -f \"/tmp/%s.man\"\n", PACKAGE_TARNAME); fprintf(stream, "ln -s \"%s/man\" \"/tmp/%s.man\"\n", executable_path, PACKAGE_TARNAME); fprintf(stream, "MANPATH=\"/tmp/%s.man:$(manpath)\"\n", PACKAGE_TARNAME); fprintf(stream, "export MANPATH\n"); fprintf(stream, "DOOMWADPATH=\"%s\"\n", doomwadpath); fprintf(stream, "export DOOMWADPATH\n"); fprintf(stream, "rm -f \"%s\"\n", TEMP_SCRIPT); // Display a useful message: fprintf(stream, "clear\n"); WriteMessage(stream, "\n" "This command line has the PATH variable configured so that you may\n" "launch the game with whatever parameters you desire.\n" "\n" "For example:\n" "\n" " " PACKAGE_TARNAME " -iwad doom2.wad -file sid.wad -warp 1\n" "\n" "Type 'exit' to exit.\n"); fprintf(stream, "exec $SHELL\n"); fprintf(stream, "\n"); fclose(stream); chmod(TEMP_SCRIPT, 0755); // Tell the terminal to open a window to run the script. [[NSWorkspace sharedWorkspace] openFile: @TEMP_SCRIPT withApplication: @"Terminal"]; } void OpenDocumentation(const char *filename) { NSString *path; path = [NSString stringWithFormat: @"%s/Documentation/%s", executable_path, filename]; [[NSWorkspace sharedWorkspace] openFile: path]; } chocolate-doom-chocolate-doom-2.2.1/pkg/osx/GNUmakefile000066400000000000000000000100331257432200600227460ustar00rootroot00000000000000 # Makefile for building the OS X launcher program and DMG package. # It is also possible to build and run the launcher under Unix # systems using GNUstep, although this is only here for development # and debugging purposes. include ../config.make DOC_FILES += README.Strife NOT-BUGS # Build so that the package will work on older versions. export MACOSX_DEPLOYMENT_TARGET=10.4 STAGING_DIR=staging DMG=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).dmg TOPLEVEL=../.. TOPLEVEL_DOCS=$(patsubst %,../../%,$(DOC_FILES)) ifndef GNUSTEP_MAKEFILES # DMG file containing package: $(DMG) : tmp.dmg rm -f $@ ./dmgfix "$(realpath tmp.dmg)" "$(PACKAGE_STRING)" "$(PACKAGE_NAME).app" hdiutil convert -format UDZO -o $@ tmp.dmg rm -f tmp.dmg tmp.dmg : $(STAGING_DIR) rm -f $@ hdiutil makehybrid -hfs -hfs-volume-name "$(PACKAGE_STRING)" \ -hfs-openfolder $(STAGING_DIR) $(STAGING_DIR) \ -o tmp.dmg endif # Staging dir build for package: APP_DIR=$(STAGING_DIR)/$(PACKAGE_NAME).app # OS X and GNUstep apps have a slightly different internal structure: # OS X apps have their files within a containing "Contents" directory # that does not exist in GNUstep apps. Similarly, the binaries are # installed at the top level, rather than in a "MacOS" directory. # Finally, we must install a different Info.plist file. ifdef GNUSTEP_MAKEFILES APP_TOP_DIR=$(APP_DIR) APP_BIN_DIR=$(APP_DIR) SRC_INFO_PLIST=Info-gnustep.plist else APP_TOP_DIR=$(APP_DIR)/Contents APP_BIN_DIR=$(APP_DIR)/Contents/MacOS SRC_INFO_PLIST=Info.plist endif APP_DOC_DIR=$(APP_BIN_DIR)/Documentation APP_DOC_RELDIR=$(patsubst $(STAGING_DIR)/%,%,$(APP_DOC_DIR)) $(STAGING_DIR): launcher $(TOPLEVEL_DOCS) rm -rf $(STAGING_DIR) mkdir $(STAGING_DIR) mkdir -p "$(APP_TOP_DIR)" cp -R Resources "$(APP_TOP_DIR)" cp PkgInfo "$(APP_TOP_DIR)" cp $(SRC_INFO_PLIST) "$(APP_TOP_DIR)" mkdir -p "$(APP_BIN_DIR)" mkdir -p "$(APP_DOC_DIR)" cp $(TOPLEVEL_DOCS) "$(APP_DOC_DIR)" ln -s "$(APP_DOC_RELDIR)/COPYING" "$(STAGING_DIR)/Software License" ln -s "$(APP_DOC_RELDIR)/README" "$(STAGING_DIR)/README" ln -s /Applications "$(STAGING_DIR)" cp launcher "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/launcher" ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)doom" ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)heretic" ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)hexen" ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)strife "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)strife" ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)setup" $(TOPLEVEL)/man/simplecpp -DPRECOMPILED -D__MACOSX__ \ -DDOOM -DHERETIC -DHEXEN -DSTRIFE \ < $(TOPLEVEL)/man/INSTALL.template \ > "$(APP_DOC_DIR)/INSTALL" find $(STAGING_DIR) -name .svn -delete -exec rm -rf {} \; || true mkdir -p "$(APP_BIN_DIR)/man/man5" "$(APP_BIN_DIR)/man/man6" cp $(TOPLEVEL)/man/*.5 "$(APP_BIN_DIR)/man/man5" cp $(TOPLEVEL)/man/*.6 "$(APP_BIN_DIR)/man/man6" for game in doom heretic hexen strife; do \ cp $(TOPLEVEL)/man/CMDLINE.$$game \ "$(APP_DOC_DIR)/CMDLINE-$$game"; \ done cp disk/dir.DS_Store $(STAGING_DIR)/.DS_Store cp disk/background.png $(STAGING_DIR)/background.png clean : launcher_clean rm -f $(DMG) rm -rf $(STAGING_DIR) # Launcher build: CFLAGS = -Wall -I$(TOPLEVEL) # Are we building using gs_make? ifdef GNUSTEP_MAKEFILES CFLAGS += $(shell gnustep-config --objc-flags) LDFLAGS = $(shell gnustep-config --gui-libs) else LDFLAGS = -framework Cocoa endif LAUNCHER_OBJS= \ AppController.o \ Execute.o \ IWADController.o \ IWADLocation.o \ LauncherManager.o \ main.o launcher : $(LAUNCHER_OBJS) $(CC) $(LDFLAGS) $(LAUNCHER_OBJS) -o $@ %.o : %.m $(CC) -c $(CFLAGS) $^ -o $@ launcher_clean : rm -f $(LAUNCHER_OBJS) launcher chocolate-doom-chocolate-doom-2.2.1/pkg/osx/IWADController.h000066400000000000000000000024441257432200600236440ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef LAUNCHER_IWADCONTROLLER_H #define LAUNCHER_IWADCONTROLLER_H #include #include @interface IWADController : NSObject { id iwadSelector; id configWindow; id chex; id doom1; id doom2; id plutonia; id tnt; id heretic; id hexen; id strife; } - (void) closeConfigWindow: (id)sender; - (void) openConfigWindow: (id)sender; - (NSString *) getIWADLocation; - (void) awakeFromNib; - (BOOL) setDropdownList; - (void) setDropdownSelection; - (void) saveConfig; - (char *) doomWadPath; - (void) setEnvironment; - (const char *) getGameName; - (BOOL) addIWADPath: (NSString *) path; - (BOOL) selectGameByName: (const char *) name; @end #endif /* #ifndef LAUNCHER_IWADCONTROLLER_H */ chocolate-doom-chocolate-doom-2.2.1/pkg/osx/IWADController.m000066400000000000000000000225451257432200600236550ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "IWADController.h" #include "IWADLocation.h" typedef enum { IWAD_DOOM1, IWAD_DOOM2, IWAD_TNT, IWAD_PLUTONIA, IWAD_CHEX, IWAD_HERETIC, IWAD_HEXEN, IWAD_STRIFE, NUM_IWAD_TYPES } IWAD; static NSString *IWADLabels[NUM_IWAD_TYPES] = { @"Doom", @"Doom II: Hell on Earth", @"Final Doom: TNT: Evilution", @"Final Doom: Plutonia Experiment", @"Chex Quest", @"Heretic", @"Hexen", @"Strife" }; static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] = { @"doom.wad", @"doom2.wad", @"tnt.wad", @"plutonia.wad", @"chex.wad", @"heretic.wad", @"hexen.wad", @"strife.wad", @"undefined" }; @implementation IWADController - (void) getIWADList: (IWADLocation **) iwadList { iwadList[IWAD_DOOM1] = self->doom1; iwadList[IWAD_DOOM2] = self->doom2; iwadList[IWAD_TNT] = self->tnt; iwadList[IWAD_PLUTONIA] = self->plutonia; iwadList[IWAD_CHEX] = self->chex; iwadList[IWAD_HERETIC] = self->heretic; iwadList[IWAD_HEXEN] = self->hexen; iwadList[IWAD_STRIFE] = self->strife; } - (IWAD) getSelectedIWAD { unsigned int i; for (i=0; iiwadSelector titleOfSelectedItem] == IWADLabels[i]) { return i; } } return NUM_IWAD_TYPES; } // Get the location of the selected IWAD. - (NSString *) getIWADLocation { IWAD selectedIWAD; IWADLocation *iwadList[NUM_IWAD_TYPES]; selectedIWAD = [self getSelectedIWAD]; if (selectedIWAD == NUM_IWAD_TYPES) { return nil; } else { [self getIWADList: iwadList]; return [iwadList[selectedIWAD] getLocation]; } } static const char *NameForIWAD(IWAD iwad) { switch (iwad) { case IWAD_HERETIC: return "heretic"; case IWAD_HEXEN: return "hexen"; case IWAD_STRIFE: return "strife"; default: return "doom"; } } // Get the name used for the executable for the selected IWAD. - (const char *) getGameName { return NameForIWAD([self getSelectedIWAD]); } - (void) setIWADConfig { IWADLocation *iwadList[NUM_IWAD_TYPES]; NSUserDefaults *defaults; NSString *key; NSString *value; unsigned int i; [self getIWADList: iwadList]; // Load IWAD filename paths defaults = [NSUserDefaults standardUserDefaults]; for (i=0; iiwadSelector selectItemWithTitle:IWADLabels[i]]; break; } } } // Set the dropdown list to include an entry for each IWAD that has // been configured. Returns true if at least one IWAD is configured. - (BOOL) setDropdownList { IWADLocation *iwadList[NUM_IWAD_TYPES]; BOOL have_wads; id location; unsigned int i; unsigned int enabled_wads; // Build the new list. [self getIWADList: iwadList]; [self->iwadSelector removeAllItems]; enabled_wads = 0; for (i=0; i 0) { [self->iwadSelector addItemWithTitle: IWADLabels[i]]; ++enabled_wads; } } // Enable/disable the dropdown depending on whether there // were any configured IWADs. have_wads = enabled_wads > 0; [self->iwadSelector setEnabled: have_wads]; // Restore the old selection. [self setDropdownSelection]; return have_wads; } - (void) saveConfig { IWADLocation *iwadList[NUM_IWAD_TYPES]; IWAD selectedIWAD; NSUserDefaults *defaults; NSString *key; NSString *value; unsigned int i; [self getIWADList: iwadList]; // Store all IWAD locations to user defaults. defaults = [NSUserDefaults standardUserDefaults]; for (i=0; iconfigWindow isVisible]) { [self->configWindow makeKeyAndOrderFront: sender]; } } // Callback method invoked when the close button is clicked. - (void) closeConfigWindow: (id)sender { [self->configWindow orderOut: sender]; [self saveConfig]; [self setDropdownList]; } - (void) awakeFromNib { [self->configWindow center]; // Set configuration for all IWADs from configuration file. [self setIWADConfig]; // Populate the dropdown IWAD list. if ([self setDropdownList]) { [self setDropdownSelection]; } } // Generate a value to set for the DOOMWADPATH environment variable // that contains each of the configured IWAD files. - (char *) doomWadPath { IWADLocation *iwadList[NUM_IWAD_TYPES]; NSString *location; unsigned int i; BOOL first; char *env; size_t env_len; [self getIWADList: iwadList]; // Calculate length of environment string. env_len = 0; for (i=0; i 0) { env_len += [location length] + 1; } } // Build string. env = malloc(env_len); strlcpy(env, "", env_len); first = YES; for (i=0; i 0) { if (!first) { strlcat(env, ":", env_len); } strlcat(env, [location UTF8String], env_len); first = NO; } } return env; } // Set the DOOMWADPATH environment variable to contain the path to each // of the configured IWAD files. - (void) setEnvironment { char *doomwadpath; char *env; // Get the value for the path. doomwadpath = [self doomWadPath]; asprintf(&env, "DOOMWADPATH=%s", doomwadpath); free(doomwadpath); // Load into environment: putenv(env); //free(env); } // Examine a path to a WAD and determine whether it is an IWAD file. // If so, it is added to the IWAD configuration, and true is returned. - (BOOL) addIWADPath: (NSString *) path { IWADLocation *iwadList[NUM_IWAD_TYPES]; NSArray *pathComponents; NSString *filename; unsigned int i; [self getIWADList: iwadList]; // Find an IWAD file that matches the filename in the path that we // have been given. pathComponents = [path pathComponents]; filename = [pathComponents objectAtIndex: [pathComponents count] - 1]; for (i = 0; i < NUM_IWAD_TYPES; ++i) { if ([filename caseInsensitiveCompare: IWADFilenames[i]] == 0) { // Configure this IWAD. [iwadList[i] setLocation: path]; // Rebuild dropdown list and select the new IWAD. [self setDropdownList]; [self->iwadSelector selectItemWithTitle:IWADLabels[i]]; return YES; } } // No IWAD found with this name. return NO; } - (BOOL) selectGameByName: (const char *) name { IWADLocation *iwadList[NUM_IWAD_TYPES]; NSString *location; const char *name2; int i; // Already selected an IWAD of the desired type? Just return // success. if (!strcmp(name, [self getGameName])) { return YES; } // Search through the configured IWADs and try to select the // desired game. [self getIWADList: iwadList]; for (i = 0; i < NUM_IWAD_TYPES; ++i) { location = [iwadList[i] getLocation]; name2 = NameForIWAD(i); if (!strcmp(name, name2) && location != nil && [location length] > 0) { [self->iwadSelector selectItemWithTitle:IWADLabels[i]]; return YES; } } // User hasn't configured any WAD(s) for the desired game type. return NO; } @end chocolate-doom-chocolate-doom-2.2.1/pkg/osx/IWADLocation.h000066400000000000000000000016511257432200600232700ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef LAUNCHER_IWADLOCATION_H #define LAUNCHER_IWADLOCATION_H #include #include "IWADController.h" @interface IWADLocation : NSObject { IWADController *iwadController; id locationConfigBox; } - (void) setButtonClicked: (id)sender; - (NSString *) getLocation; - (void) setLocation: (NSString *) value; @end #endif /* #ifndef LAUNCHER_IWADLOCATION_H */ chocolate-doom-chocolate-doom-2.2.1/pkg/osx/IWADLocation.m000066400000000000000000000031651257432200600232770ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "IWADLocation.h" static id WAD_TYPES[] = { @"wad", @"WAD" }; @implementation IWADLocation - (void) setButtonClicked: (id)sender { NSArray *wadTypes = [NSArray arrayWithObjects: WAD_TYPES count: 2]; NSOpenPanel *openPanel; NSArray *filenames; int result; [wadTypes retain]; // Open a file selector for the new file. openPanel = [NSOpenPanel openPanel]; [openPanel setTitle: @"Add IWAD file"]; [openPanel setCanChooseFiles: YES]; [openPanel setCanChooseDirectories: NO]; result = [openPanel runModalForTypes: wadTypes]; // If the "OK" button was clicked, add the new IWAD file to the list. if (result == NSOKButton) { filenames = [openPanel filenames]; [self setLocation: [filenames lastObject]]; [self->iwadController saveConfig]; [self->iwadController setDropdownList]; } } - (NSString *) getLocation { return [self->locationConfigBox stringValue]; } - (void) setLocation: (NSString *) filename { [self->locationConfigBox setStringValue: filename]; } @end chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Info-gnustep.plist.in000066400000000000000000000020261257432200600247370ustar00rootroot00000000000000{ ApplicationName = "@PACKAGE_NAME@"; ApplicationDescription = "@PACKAGE_SHORTDESC@"; ApplicationIcon = app.png; ApplicationRelease = @PACKAGE_VERSION@; ApplicationURL = "@PACKAGE_URL@"; Authors = ( "@PACKAGE_MAINTAINER@ <@PACKAGE_BUGREPORT@>" ); Copyright = "@PACKAGE_COPYRIGHT@"; CopyrightDescription = "@PACKAGE_LICENSE@"; FullVersionID = @PACKAGE_VERSION@; GSMainMarkupFile = ""; NSExecutable = "launcher"; NSIcon = app.png; NSMainNibFile = launcher.nib; NSPrincipalClass = NSApplication; NSRole = Application; NSTypes = ( { NSHumanReadableName = "Doom WAD file"; NSUnixExtensions = ( wad ); NSRole = Viewer; NSMimeTypes = ( "application/x-doom" ); NSIcon = "wadfile.png"; }, { NSHumanReadableName = "Dehacked patch"; NSUnixExtensions = ( deh ); NSRole = Viewer; NSIcon = "wadfile.png"; } ); } chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Info.plist.in000066400000000000000000000067331257432200600232650ustar00rootroot00000000000000 CFBundleIdentifier org.chocolate-doom.launcher CFBundleDevelopmentRegion English CFBundleDisplayName @PACKAGE_NAME@ CFBundleExecutable launcher CFBundleGetInfoString @PACKAGE_STRING@ CFBundleIconFile app.icns CFBundleInfoDictionaryVersion 6.0 CFBundleName @PACKAGE_NAME@ CFBundlePackageType APPL CFBundleShortVersionString @PACKAGE_VERSION@ CFBundleVersion @PACKAGE_VERSION@ NSPrincipalClass NSApplication NSMainNibFile launcher NSHumanReadableCopyright Copyright (C) 1993-2015, id Software and Raven Software, Simon Howard, James Haley, Samuel Villarreal and other contributors. Licensed under the GNU GPL v2. CFBundleDocumentTypes CFBundleTypeName Doom WAD file CFBundleTypeIconFile wadfile.icns CFBundleTypeRole Viewer CFBundleTypeExtensions wad CFBundleTypeName Doom Dehacked patch CFBundleTypeIconFile wadfile.icns CFBundleTypeRole Viewer CFBundleTypeExtensions deh CFBundleTypeName Heretic HHE patch CFBundleTypeIconFile wadfile.icns CFBundleTypeRole Viewer CFBundleTypeExtensions hhe CFBundleTypeName Strife Sehacked patch CFBundleTypeIconFile wadfile.icns CFBundleTypeRole Viewer CFBundleTypeExtensions seh chocolate-doom-chocolate-doom-2.2.1/pkg/osx/LauncherManager.h000066400000000000000000000026261257432200600241120ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef LAUNCHER_LAUNCHERMANAGER_H #define LAUNCHER_LAUNCHERMANAGER_H #include #include #include "IWADController.h" @interface LauncherManager : NSObject { IWADController *iwadController; id launcherWindow; id launchButton; id commandLineArguments; } - (void) launch: (id)sender; - (void) runSetup: (id)sender; - (void) awakeFromNib; - (void) clearCommandLine; - (BOOL) addIWADPath: (NSString *) path; - (void) addFileToCommandLine: (NSString *) fileName forArgument: (NSString *) args; - (BOOL) selectGameByName: (const char *) name; - (void) openTerminal: (id) sender; - (void) openREADME: (id) sender; - (void) openINSTALL: (id) sender; - (void) openCMDLINE: (id) sender; - (void) openCOPYING: (id) sender; - (void) openDocumentation: (id) sender; @end #endif /* #ifndef LAUNCHER_LAUNCHERMANAGER_H */ chocolate-doom-chocolate-doom-2.2.1/pkg/osx/LauncherManager.m000066400000000000000000000223221257432200600241120ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "Execute.h" #include "LauncherManager.h" #include "config.h" @implementation LauncherManager // Save configuration. Invoked when we launch the game or quit. - (void) saveConfig { NSUserDefaults *defaults; // Save IWAD configuration and selected IWAD. [self->iwadController saveConfig]; // Save command line arguments. defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:[self->commandLineArguments stringValue] forKey:@"command_line_args"]; } // Load configuration, invoked on startup. - (void) setConfig { NSUserDefaults *defaults; NSString *args; defaults = [NSUserDefaults standardUserDefaults]; args = [defaults stringForKey:@"command_line_args"]; if (args != nil) { [self->commandLineArguments setStringValue:args]; } } // Get the next command line argument from the command line. // The position counter used to iterate over arguments is in 'pos'. // The index of the argument that was found is saved in arg_pos. static NSString *GetNextArgument(NSString *commandLine, int *pos, int *arg_pos) { NSRange arg_range; // Skip past any whitespace while (*pos < [commandLine length] && isspace([commandLine characterAtIndex: *pos])) { ++*pos; } if (*pos >= [commandLine length]) { *arg_pos = *pos; return nil; } // We are at the start of the argument. This may be a quoted // string argument, or a "normal" one. if ([commandLine characterAtIndex: *pos] == '\"') { // Quoted string, skip past first quote ++*pos; // Save start position: *arg_pos = *pos; while (*pos < [commandLine length] && [commandLine characterAtIndex: *pos] != '\"') { ++*pos; } // Unexpected end of string? if (*pos >= [commandLine length]) { return nil; } arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos); // Skip past last quote ++*pos; } else { // Normal argument // Save position: *arg_pos = *pos; // Read until end: while (*pos < [commandLine length] && !isspace([commandLine characterAtIndex: *pos])) { ++*pos; } arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos); } return [commandLine substringWithRange: arg_range]; } // Given the specified command line argument, find the index // to insert the new file within the command line. Returns -1 if the // argument is not already within the arguments string. static int GetFileInsertIndex(NSString *commandLine, NSString *needle) { NSString *arg; int arg_pos; int pos; pos = 0; // Find the command line parameter we are searching // for (-merge, -deh, etc) for (;;) { arg = GetNextArgument(commandLine, &pos, &arg_pos); // Searched to end of string and never found? if (arg == nil) { return -1; } if (![arg caseInsensitiveCompare: needle]) { break; } } // Now skip over existing files. For example, if we // have -file foo.wad bar.wad, the new file should be appended // to the end of the list. for (;;) { arg = GetNextArgument(commandLine, &pos, &arg_pos); // If we search to the end of the string now, it is fine; // the new string should be added to the end of the command // line. Otherwise, if we find an argument that begins // with '-', it is a new command line parameter and the end // of the list. if (arg == nil || [arg characterAtIndex: 0] == '-') { break; } } // arg_pos should now contain the offset to insert the new filename. return arg_pos; } // Given the specified string, append a filename, quoted if necessary. static NSString *AppendQuotedFilename(NSString *str, NSString *fileName) { int i; // Search the filename for spaces, and quote if necessary. for (i=0; i<[fileName length]; ++i) { if (isspace([fileName characterAtIndex: i])) { str = [str stringByAppendingString: @" \""]; str = [str stringByAppendingString: fileName]; str = [str stringByAppendingString: @"\" "]; return str; } } str = [str stringByAppendingString: @" "]; str = [str stringByAppendingString: fileName]; return str; } // Clear out the existing command line options. // Invoked before the first file is added. - (void) clearCommandLine { [self->commandLineArguments setStringValue: @""]; } // Add a file to the command line to load with the game. - (void) addFileToCommandLine: (NSString *) fileName forArgument: (NSString *) arg { NSString *commandLine; int insert_pos; // Get the current command line commandLine = [self->commandLineArguments stringValue]; // Find the location to insert the new filename: insert_pos = GetFileInsertIndex(commandLine, arg); // If position < 0, we should add the new argument and filename // to the end. Otherwise, append the new filename to the existing // list of files. if (insert_pos < 0) { commandLine = [commandLine stringByAppendingString: @" "]; commandLine = [commandLine stringByAppendingString: arg]; commandLine = AppendQuotedFilename(commandLine, fileName); } else { NSString *start; NSString *end; // Divide existing command line in half: start = [commandLine substringToIndex: insert_pos]; end = [commandLine substringFromIndex: insert_pos]; // Construct new command line: commandLine = AppendQuotedFilename(start, fileName); commandLine = [commandLine stringByAppendingString: @" "]; commandLine = [commandLine stringByAppendingString: end]; } [self->commandLineArguments setStringValue: commandLine]; } - (void) launch: (id)sender { NSString *iwad; NSString *args; char *executable_name; const char *game_name; [self saveConfig]; iwad = [self->iwadController getIWADLocation]; args = [self->commandLineArguments stringValue]; if (iwad == nil) { NSRunAlertPanel(@"No IWAD selected", @"You have not selected an IWAD (game) file.\n\n" "You must configure and select a valid IWAD file " "in order to launch the game.", @"OK", nil, nil); return; } game_name = [self->iwadController getGameName]; asprintf(&executable_name, "%s%s", PROGRAM_PREFIX, game_name); ExecuteProgram(executable_name, [iwad UTF8String], [args UTF8String]); [NSApp terminate:sender]; } // Invoked when the "Setup Tool" button is clicked, to run the setup tool: - (void) runSetup: (id)sender { const char *game_name; char *arg; [self saveConfig]; [self->iwadController setEnvironment]; // Provide the -game command line parameter to select the game // to configure, based on the game selected in the dropdown. game_name = [self->iwadController getGameName]; asprintf(&arg, "-game %s", game_name); ExecuteProgram(PROGRAM_PREFIX "setup", NULL, arg); free(arg); } // Invoked when the "Terminal" option is selected from the menu, to open // a terminal window. - (void) openTerminal: (id) sender { char *doomwadpath; [self saveConfig]; doomwadpath = [self->iwadController doomWadPath]; OpenTerminalWindow(doomwadpath); free(doomwadpath); } - (void) openREADME: (id) sender { OpenDocumentation("README"); } - (void) openINSTALL: (id) sender { OpenDocumentation("INSTALL"); } - (void) openCMDLINE: (id) sender { const char *game_name; char filename[32]; // We need to open the appropriate doc file for the currently // selected game. game_name = [self->iwadController getGameName]; snprintf(filename, sizeof(filename), "CMDLINE-%s", game_name); OpenDocumentation(filename); } - (void) openCOPYING: (id) sender { OpenDocumentation("COPYING"); } - (void) openDocumentation: (id) sender { OpenDocumentation(""); } - (void) awakeFromNib { [self->launcherWindow setTitle: @PACKAGE_NAME " Launcher"]; [self->launcherWindow center]; [self->launcherWindow setDefaultButtonCell: [self->launchButton cell]]; [self setConfig]; } - (BOOL) addIWADPath: (NSString *) path { return [self->iwadController addIWADPath: path]; } - (BOOL) selectGameByName: (const char *) name { return [self->iwadController selectGameByName: name]; } @end chocolate-doom-chocolate-doom-2.2.1/pkg/osx/PkgInfo000066400000000000000000000000111257432200600221470ustar00rootroot00000000000000APPL???? chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Resources/000077500000000000000000000000001257432200600226515ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Resources/128x128.png000066400000000000000000000547651257432200600243350ustar00rootroot00000000000000PNG  IHDR>asRGBbKGD pHYs B(xtIME" ] IDATxwu^ίshd @0gQ%(ɔ4l˖-3-ӎ;;a=㲵ckVeklI&H$ b@{wxV4hҬnuWshU]?̿Ղฆ#fxfZe`A? 7r@x0\_?X{%usW/u `qr2.} ֬@/:`!1Zkb@"]PUV@H)U2g C}r#]'+)L s|t٥r ox:˿ \~(Xe4 @~w|7Ga;nޔyb\_@H,!DJJ~=E"k܉&qC25̊S]}~g`XTƏx.V6H)FƩ[K !sAQAB n+R3N๸*L=1wD٥ry/{ (wPj :r&_GebH;HxyJ F.@xu݌14Fv&'ƐK:Qa@,ׇKi^Qޛp+[©縞\15xp0u O?@_ӿ+ {Dj4vYeTcbQn:dbnRn:\B$^Ri9xAIr Bl$3v~l*Aqh=[7po|w'-I *WVVW~dԿ:tӽޟoy;bij,NclKyaILq%#4lFۣ~rahhG~zz{I z Ǟc8˓L>X4UiJ\ # ҧgo;pwu((lؼuȎ(ЮWAJ&׿9.Nϳszi !$bq%>OTmbh%ؚ{CW Ck_+__Į6+OᏢk@ƗlX+Ԥ"~0f<*??l߳3%-F)fD0aƻs&N; Ӧ4~GQ{?w,㓉lFI|gjePr,*e>3ㅫt:\>6טWwU_|Sz{~w[زG.=(DYEœTH2G!vem^O2{?b~}z?Q\ZPchU[/ej6jB{{th4[auTG ?t(XE_z}߃~"{e*PaKGbNnјcwR#^N}tCT>ͅ "aS0*E f]۶ \vdtrvkModK !ߔ37g ׶x4v֪a #zL g`FWz5' ~~ќ/4oC4]LzixqT,п!zc~ PafF0)t3Nܐ 2&DD$'K fVqj2kW_ޜZW&\{7<ܗ[hvVUt%>xWJ=@O}2yF; ̝~dϪXo=NsyV')f<(86R7@* 1jcX;3G[l!`qe4%v v`-N3қS3/5N /~rZeZy&͹2LpgFϾ/{=X˩,tƍ0<> ~>֯>k{C|cC_Kzx1&tm&88h^scx_uc6תaWsz4g5 H͈`fq&p,SgrwOrcS5!(AĐPO/9RʍZJgp-=ן;}B)安@CŻZJ~rhB9g?uxHUP^bujiw~m-0d/pߋi&ϲT*3i+ſ9'"8s3ŨOs~ O>b-EȎ#5NLj`;\/U1} 9P8^/"<\ #G&B_8A.a PKa`zL-uVF}|nWʐ7@>} !W@}_q-h_ٰdTH^Eg倞7rkt*mSE/?j?$$pmzsd99>W+q@' (|tmpކ[RZTlT F2jk"$ih|}hdUNF*qe^^|ԛTM,-1?9N$BGS5h妋a,T-wj" |O>FHha3xn'Pn9OЗrpEzSQz 9_3` t"f81̩2cdldfachtܤD^Б (&+,7m"Ɩb\ R7ڶOO$0b)tMPJ\O[>Z6L@_FrӇI] Bd=;'cJe!I[ǖmЯ ^QO=J ϪkӮHgs$tgqAZaxhRi€b*~*%V^FO`tLcj>vpېA$] 4McvN><4mI2q}ib}>y&CrnΎ4.Nkx`P<j6iM3.MNr%'"Lj ]w395]v[ #CҘ[)QMTbB/PRH_WKo}~fH?;OsrK??Y)5\ um @'|][w;-|g5Hl&nG}v8"L_s3bh|)r՟F$m7jLZ[.M'qqvnb:c 0Dj'k(3WmxAH*jPd&7L0)*Mb\O?&;M8DϞ8Y6oEcVvV$ax2 !uyKOgxyv%n ?ZڪٵeqN0KEvИgbFЉA)'ZSQhH8d[oSר]°c47踓|q6!B燴R ]-60Wk3O2s?vmR"Srgi-Mћ6Ǿ)Ϟ/q]rqs`ﱳ͕} P4t$ˢ pk^ MD܂kȇ񦽅^uGe0GJ|3s5$ړ%M3!R M TMb*J"茄L#8>- '=1|r&1XnҟѴ=R/ (秗9afs(" rS-N͒8?P_Yn5&" Ϟf:>:O+.05VH87$Gd򢭯"@B_7$5* mMvzFHBO~/Scg835O2da!521mlR5N!|]M  X]}?Q,_~RӦ0Ox|2B.ao(GbϦ>T%G::A_&Jrm&q![2z }s3~piχPh]ȍdo:QoR)~jS?89KϫQN9{]wR!MW`Y,yA֦NKX̗{AȳO?E! *݀NrґI~C poAw$ MMMt||6 5c@. d̖-l?x)S]U!*!}qtrS3rM2^x:GN,sUCY4"T,V- |Sq+MjC"bа="$jhT[m/|@QL鍢EbwN0DA>^;A;wa|O?F'ML]R \? B?fT,3UBɨΞ d%)ܰ+Kt]C Z @.*Pz{~r?pv;ʿ//)@SBBn()<(˕I*3H#B!dtj2IBtN!P(@uR:9KO{m"rK7=&)x۹=?N!:' B&#En=b0ȥTp\D<Kuzr-susfrF7,7]SѶ$bߺJX ^f+,4 !KH^OKKܟlյK X+$BhR\䋍0}6</.-f*=_~ Fiqvmd&A:R5$D Rc`4HQO#T%QBjDI$f~a L"j\1:[vDG0uDDg6A,񙅱@4_t]oʦ~E'\ D .Z]~])rˍe(~R\z >wLi0THј]^7ID&S_Fxh2ur}Es"i3$S/= Ja6!S fK-sq(/-`FLBg,sl 3ƌ' =yȤ$${7w&T*f9`vqec Mv\]]YuΨ/ .`ւYjKwdaώ$_ƓCD*|ӧ YfўIS4kxG*XŹiYn8TZ.qvfBT- 5ri]L]ۃDtM6ތOEj:nߝrmjT*`իJh4\ZBܭ=b .{/a&-n.|ؿ) 3Z. 6M'5|M_&ką9喃SQV e'3huD h{u(#CBǷ[nq#|;2B# ٻ2{現DD!Mr|@!ܾ]NrQb B8 v"npPu/qNh $ v'8fR:!A3SnI [ÑlK1QLǰR=#wupBPB[a J(UL] ~m.@0L&=gD~h4~JQ.K^\? o ABIԤfyfMNNW: !*b"T ]"zC?t2ѩK|ܰIF yr-$z*Duę)5IE]0M=^wRJ(\0+++j):BЫ?wkBz8-|1*;EL .,5Z.MG HEu2q1bmInǮ&:')fcC|*-4",'Cj`{a:]('$^*(Qml*$kg/s6H'K4mBt"B1߲cpǧc7 NxUB04j. Km@ &QiTߪqǛ:=@^(xģ&~gWe&Ud{glbKBlBTNhCdg7s6r4FJ)\XnRnd&u7Rco@qﴗyA (:+/xa+x.@4P\9\ @D M!Q*%K$M/ ʓd*MЪsncQ@&FtǃNcȍr\AI)B%髨KQMic妍 T$njf $bhH !`lqjʭۊlIE?e{_ 8ɨ+yӾA {}7PJu{VBWg_( ]m\Za)1^fkn\wPh͜ՠjшI,ڙ2AOFJi fy[L,7)" TuLR^IպF*LC# ;\{M]Ia.c$: qp\qߞ~1R!)>5NO4)}( \*ZqWԪA,)ne`gf땆<ܩ{DŽ̔Lݶm}u=#l˰gdг-I1_dk. tV(@!/u!кѿlr|<(fO7uvd,U>ˌ-vՓNu0Sχa~wB@0\emR] uI+Otͪ ] nRp"׏'#bh̗wL.jǞ T,sn֙:TTLFu>ӽRHVt?dMd&1S8c8sW-MYő/=?W|. ]v_-C ĵ֫ML:9LZղܛ%c4ф̋i<;xp)j&;䒝|1:c|2Ci`v5P)n86YdRQDD'fhFzCYLbf[_v&Ku_rX^M??:Lr6/_2N@a+.3@M_VYSZi ikmx>Liw `~JY:|6Ӷ8(_mCg93Wcd`TT' ;֗]DM ] "!/=c&MZN@i1s>Iųޛ"7kc/e͹Hr:rs׊4K8Wy{#_!.^ha䚢L5L\i.'/O~_ܽ[qife[gf,'3i..y;߶{iG g([s&Ǧ|B2[ atŢ˞uN: NBMHu˥.WXԪ!}dŎ% c cQjZ^U/u_6 n Rafgi_5!ZTl0Uv(,6՟Ex+ _=zF#~L-vpS$+UY(?G6F\e[Z&ύ/qq٩ &QnR 3.]PmL[RQ21{sI*N"(Z8~@*K`ԔK.p}K2/?P} 34PB1U)u]j?J!ty P\ X=t}actzyʽi¶\x$cnߑdFR!3HF BX_&-jMF zUOsqzqN,Zd h>sU / = !Nn[|VGEX. 0x\c"xʣdWƪ'~ 0$rUG4$8*0$._UKzi` X+ $a$cjaVD wn:drF)CEr)&#&q%5AXr~W岠R4e29N=wX\vBs8\<J! ouO# 4 S )ZfkK3a.3:VnXU2 d R]$qk\Ak!jۣ/TK6ږ1$589SvvNZtXOcv{oaǎ(3=oSmz ;4Ms$A2a1dKH m'$ z'6$"5Y\cD]qWa! .@H2zAccNx} m.Yع%Ʌ@.ˑ2#$I&4Ʋ{U]]Mj;NXA>l|@ `8J"/`eǓxlx23]/{>^zgN먤[y?JzN$Kˋ ,aV9:D\Yz;a˨7,'VұrQCQc^Gɹ¹`b!ͭv,.Vx%0@~  (Ҟߏ h]7{S#]"iS6ż!aRo)lڂokWrgq>\zG3Fʽf%.XNIDY\ }6k FV2))#IZ˫c}-F$ëHR3@Qdq!f>R|z9fɣN 20$Vt2b+oXߊ%V';NiY#+$ 7I2n27L ?*y IJf`pmBYn]|xC} ]fsʊc{;:& {`OQ@b Dڣ4"ӫ7D!A6 %GՒ5NDQ*<&AXԪ2q4 ImӐ2)T9g#I(ZY꽱n,1U5$p`BN%bMp܈W豲a3t.+n{|'CoJB9*~ 1vp}o1w$)K?q`3R$5l?8/|dꈔ<̹#֛'e*|61 R\߰|FV@zs[.ŜBNw1 )7!U+cFV@.Ȃ|%Z+i]жJ-7;@tEͺcHh?"U er kg禽(kG"~pVjg'XKJy(Ux"ǵ5I\_|9FKX~+c3'hqc>}Fx5 CEt-H2#+defn$QJ "tbLC bZXOFS ~tY21t !)R 鍔F+a(&%9%$T4ySdY"&pC xލy?2TIIh'7ևS2W#xX Wuh-$I ~0 p=Yxd.@'0 a$5L=K7F1gz\Z3]չaS|WG|[;AS$t],'6BVvBFv ɦd!AE8"A63?ey+ ygGؕpMNv B۾%!P3E'c~Ex׍!| ai l10v Olu<2i !|,f }I']IDAT*1U164U²C^pPC)N:J^zӡUqI$1U5YQ@a*2cpwFuH Gq)=' A, 仗+.X8P,k:&,xZcO1;apxcUd޿Zpܐb^Eo^0ҦI,LJr]ba#IW~͡u 7ZvglsjF%޺ġ,ݾjݡZД.yH VglBʐ94✅sB(~(#bk;8ݕMZ)<^o\6BRNjt޸8KC>x]W)mp}E|qh>G\r2Jtl6:R 5 LZBfj"H0q98qBrFwC!zK|D`ƦK/ w2n#@yg>eY(`nsl1 N-HhrVO?\?bfrWJ-RX*"K5d@Ҵk`j Bq6A(1?; bȿ D2A QǍxɤI HU|!%ɟ GawrdF4[?P"vHqHBVbecF'^.Lv/}IJ ǖ |;(rBޤXHqh$ l{j!#:| d !Ǭ7փnh.崈FSAHd=5(aŮdѭh• Φ4e~pK6pH. ћ~N+bYqk24FVɤg3!2i<ՠѲ1uXh\y|WϬp@z;hΣoA\@pFPAx`ȿĨU~.C wmqR &: !iSfnҤrYƅ>%`bRg8h0EiSfhQcvTA+~* KO$!vsp/#x`7L ൭ZA{|U B>$ S5D w753s)&2TKJ,  l6X\!t:ZH&֚pl=".y]]dy!_FJ>R[s}-m޽B܇v "seս2CW[iH).]33a2dZIB$e0@Udp"K0Ͷs:}pľj*'>BZpj_s_n IWI_9XkGš壩 Iڴ(t6nFp4btZT119NA$*E I2!3;i $Ɋ, 1#;dzBZx$n6َ+(}b $/(o.|-M t-”3)66.K:,PŘӳxҩ)f&>P" }|lYKCcc;Zv"(m(Lb0;lu=D=·-&IifhY/^v۳ ~')dpͺZʔ^G\(H|qSoNH =M rvyLldf'r4q#0t1  PTG+Wןrmշ箷v[1/p`ĉجD"sE>[](YPi|N/7x:#+R#rjlLR!¸HjzEյl׺aGsYf_oǴw}dM|7Yx*$ITPU>^Qz5GO1==x4@Ϗhm&:"尜%#K;DQi?=KI5hw=:Q6f+hq|F=p22eC&&(OOl[}|pǮ ^Q!@O(r-;q\dXN\.E=4d1K]P*d8xt&$dF9/b<\ O,{QZ4uᘣ .qGDiLMq݀b^6VxPR)JӳHȿ)+xǃ*>9hFLղO`O>~Eqt#iWX[hz>0PRRf۪wy>n5Bϗv vwLo*LTcxo|aREm•G u8OP2}FV=KGg75&9zDSGB%ЦH%h< $ VT:ٴ (Lލ>3nsXxs2"]!VSg6^_h6  n@N:AU*`d17qڀ>QvLsLOd0.' =~!1jnbY>SS LpF lgйC@2΄t/⩯0wN'P,xnI3`zfu$Q)jI^& c*dL8v0$Kd26BYT+E` p@;GoopJx߮.effn|_?{G n zOS md)ql^~-43y6]SpbtJ>QVrCopڈŹ Jo$ 5ūg7__K[S~!-W0:5\C -Ry,: E!Kd`d Ic(d2)Jl.t +7`bX(`d㵻Zm:m)ྐG_xO}8s9e3?Dء*Wn} |҄i*ղAw _bv@ިKϾT xխ3X4CC %bF\FVr\^!#\ߢ(i2)/)Wd\*2WkFkDetV:/nz)qǷ'/oo=3 mzp0UU D"ґ[ =$IC`c 3Z%Ekq|!ı`ҁ 4)H"zc Yz;ܸs#nouW u6zO In^! T:a SYc27i1Skr A0#C4MpLJg(ALo xw͠w*BFd&@MggŕAsoʹ8 ٍZ07fr̄p8#V9vFmb#UwG^gzOrB*l`847,'BĶ gY<Bhi0rfFE>j-wk9X .Ima2ٔ´Zk_bV$Ij).!#m^" ;:ab R춻V>.`/UO_x g)߬{W;ZWNL2acBd 7\V' c}F233K:"&.1>=f8Jg0336+av> HG_>aB} Pq̍ږVefN_`I\:q, M8z0 /鴎e3(4>r bvY\cQo9]w?;{Dnsޝ*(YvY"o aT43_\N±Gl rY" ^1 |FՕ>˗;8sȤ"g.Xo{e!*{;He׿m]^nln}\Ф" u;#K- Fm6^2AA{rЀg/7#SK%$YD}MR^zzA!opuuLZ!_$A4!M3P,q106B!lZWޙ]пav>>8  ???>>>8 is32zՈҾF ʳܽ9$HMԿ~u0Qʱ{ey 0qt-7>Hop|AEO)Wwhvch~K^h9Y lmaUWufAfy5D xttGq8J uked vk] ™}~MxxULhY]NAPon]krhjuoKN5#$.-vIJ_nWPgR<8NDWMCLCJ]wWQOUJ HSJELcy"AU( fbqU#Ka. bjIjr@K qwvjb dXx7$ k~\Z).*MzdZ[6.pS-30$rZ89.&1KN3/27:IUHGNH-6L%&M.^X.,8G6/Og7(m?W50'-"$'wd>1k? '$"%"  , !)6*   +//8:5"%# 462;8?-'+(* =5>@8BB:3$587.DI<UAB7*s8mkR%)EJLNJ^N {Ug Xe}nyICN#il32ږӽ• Թ9Uӯ댛΄$)UĘxġfϘ09RĹu)IIĪpWlfQ~0Y˷yuQT> 5‰u\^uuxF] :~xuQKpYHBS $_Ĉ³aT)]$it\Tl|ck""]8\"",olKxtee|w02iIl''2p ^\eKx w6>v]u66>t cKepQxBIY| q7?d~77?l peecv]^NNjN_ c42t424N ~ZMgZW_dZ c42254S vjjgNN c42224S v~~u888Y ~vā|RRR_fmfi~~~i~̂njvѐ̦ؿ؝] ~ܓqw `~T fPܛm@zm{}r^lP^MP}}`I`8E@5U%`KXXPdL5T6mz(`TPV[L[8?MdLPP50_TXnPo|o[qM5/ID((+&(-,Xdrm`qvzdP44'04454GT86EcnvvhN>c]BB4#8BBE>tE5PT[cGEENiNRB1GOORI ZZ_?8XX]dE/PP i\^RBM\\^G X>m/EI5P01D\q gRUULYRRUG IEE>MB?CC[CQv 8XYX1 lM>XMKQUMqy 8cfc: e[[XCC 8cfc: efyqlqqLmpm? vfe}o\..{w.NrqmDJ{DVlffvzXYnYVqfyp}}erszgͮ͆8 fvEvX-"xm=f~3[52."onE-yE$ON/022-ed^S@dQ/70/.020+y^^=,B )$!8~a/2202200+tX=+11/9*!3N\[O6020206aB3/55*5"'0?*-/XB:0(600:7>31dn-Y`K5SE0!,MBB0HBH1lnDsSE:E\gaKODR (RRO$mj-3")'"118?&/- dzx."0zzx- 1'B&,!-"*' \fd'.ffd/ ,&&'%"'*% '!'& , 9 !2<6, 4 #&'4/*"*"% 9*# *#5LL?* '7 *&966962A'2 )6',1'56##?A*8"!",9'H#9::A&=*7H1*H*LHN=16H?H4L*L?2,9A ,8NEE2D&5H22N<8A?8<N(G]!%{2).bdR$J|SWY=03y9xDG@2${2(=WHtܶĶ}E6JJ&=4%~0($Εj|JPO1(D< (~/(Q^>A`rpr}X T91JB +3(ͅ<b]LL]\Ua~#_XD;OI,3(ŕR1Pusokm}pgTPW8d^MFXQ02(dh^Xdx}y`PmwhFt3kbVP`V21(Yn`Wlzvd3#QolVk 'gb]j`'! 80m{wu^RQIO*-70>ASkD}g$#(mlhrd)%#90bxWifHYimoU::06I@Nn=~i$#'owq~i(%#731n:a`U2JTR4?EO_UQgu5}l$$'s~o)%#63]>|cH1BPOKF]`ogpt|p,,/wv1-,<.orsN@TSUP`f|z~;;=@;;I1mZia`tvrr|}xKLMPLKX1hxmkvu]ni}j x\ y]\[g3Rquz_ vmml{kmmkv3ko_s}~~|~6~xuMr7Mq{7sr˄| x{oՂ׹9 q lفט U kk ^AhF ]w'i Pij z{; | jh Pyp'?sM5:33 )`ko@ k~AFswI trno`e%bȾ˛{uk3 /zuVx\_x!UqTZ'qX mp\P:kDž;?GOe)BtkcD5Vȱ~]Z0Le[-|q^E<=B7$?ggtnb.  "tgQ9/>>:8@G?/*"9I\]`_v6  )YXD+?E<;AD''1/0%-/007<"6lw20:9IO^mngSF;?ZH3H88:. 47?C"lL20%&/CFQSPOG/+1?I6OAAB5%$'<@IHyuS*-E<:767?BCGI83,(-I:\L >.-/EKJIQO(^]C49Q6.2=?>BHI@1'8>5#<>dSSTE437LRRQ[X(3P@JHrc;0-6>A=3*;91 =?;+*)3I:M=9$.4::0+/$+:0?X3D/8NOQ2G8)OF9.>=(26?IDAQ])L3=WW[8L/+beO9'5?>;7HMWQXYP> E_`eB V XtZ[=1BAB?MPak|k WMMjjoN a"VqhGRLJ\][[arye ]Z"!"XqqwZ&"!.g&U`UT]b^HWSbuT ah//0a|}tI1/09o$A~eZ^kasnohy~~Kaq= ilJ<==ZhR! "#"6m`E48MitW& ! 1Pa|= "#!~__RS\MX>&% /7dC "#!XYFC8.$ *ACNLA"$"#$'YtA0 %" *79=3N**-,,%*,-#C]6'#%"' 0,-4 /344 .3 ) .WF$<@1->@/ (8=-=<$(+:{`]]J5-+1NA?+31 =FEE2EEDC'(E[t:3>,+*$.3;P_C60CODOPN7MONL-(*PiU%)2BF>,# 5)LYXV%;VWWU1(Ykl."$++()# (Qaa`'  >]``^3)`M2 &""$%&Zlmj, Ajklh8 (C8%"4" "%%  ^ttq0  Cqstp: !/"('SE"" 5775 4556+"*+  "       "     $ #    '  % ( " * #()# # +  *'   ,  "%"(+ . $' (.)2$ %& )0 4-%$#&$(&'4! ! +7* !(! &%'7%&5< $#!)().)('&:*)0:1 (' &% "!  $=1/006>& '#!%+,.()#$?324=8 *&' " %?27@6 '  $'*%# $>=># (&*H> !!  %+&!(.8 !*&$(,#h8mk  '4+   !{ޅH!'?>A"? $( Aa|!A2fB=jRC7GC"7 Fy/ EQ&A 7 . #jAdWމ9EFb* 67 M! )+ ~9 !%}e,o{L" |\w݁: YMkc-A= Gz8  *. fit32[IAk9ͳoļ̗Waٻ֠3 xy ؔۯ{pcr{ʲPÙfTc]`\bfaPKPa_csϳGe~eM@@hI¾m~Z22Stztur|lpyyzudnz[a=.4KCfuƚGS͝9h"Cɶyħp; otz~fQwIKONywmnbjxzvɪR G'J͗4 g'Cfӿs9 !yv{P2:[nbXqWqwfhepʶ? F(P̑0 f/BgNx< ?~}|skh|T67/(,HCmuºsm~m<:Fn'$F,Yˊf7B»`eO~A Y½wu}yE$,8/3)@TzecqZ>$-@\)F1!}e=BM=Gb>&{īzyt`EL]C9;:exþp<93,.6)#7W{-E5!YeFAaIIiHtq(/)IŢ\13ŷzªķ¿i@?@LRWcSF4Qp|2E:$V%eb@ vbl"LWQ5]cĽ~EkqϾqvilsi^.@nB8E>(T,ei*qd`84HG\{X`A\uǀ[lxNK^m=EC,S3dn+KnejX9lгzƀ LJBEG0Q:ds:2ѹmΚ¬ve¾]GEL4P@dw:+¿M&SznzijÿʺqL EP8OG cx;)Ȫ8֤Qmz}xrehzukllyvŽuR#"EU;NM"c{;·Xˡ|'!3c;BNPUq~pùγEW%EY?MS%$c|< ı~[2bD=LUfKezH}:\'E]CMY'c~=͖zyO(Hl[ZCOI22gyFkP}w2Un a)EaGM_)c>ѨsC[R6)%Eua4AAN]<=GvW\:Yrz~f,FfJMe+c߃>סȻѠyXB**2\|zpsxft{tzQA^t[vk_kj.FjNj.-c>Ŷrm_G9!6yzsqvv{xynwy}o?NH_\e_Zooo0FnRp0c>ѷMXWoMG5$g|zuwvrrsrqwuEt\,OGHUaUet2GrVu2cᜑ?«T# 2( 0Llx{~}}~~||wyhqjWHVkm Lx544GuZz4c⣑>.ǬvEBKU<^O,Lhu~||~}^^Zk{`=Rd}7Hy]6c⪒=˿ƗwuY,'B[ny|~R038Gaqzv:S~f|~)ゆ9H}a9c㮒<ΐxZfW962Kpl=4D=HQ30Z{`JlAE^daㆆ;Iǀe;c㲒9ZqԬiHhxz':)(D~y {9EƄi98\ޱ5{nFzr_Ѽ{iPA^qeL\clv|z{dTJ<3733>UihdWpf`a0<Ƈm0Rઔ4?ix}mS; #GUNN>!4MTfU6D>76>f06Ĕ|0J井3bdTjUd`}nlAHBpjbbx7[uYIKEB2)AOT\CTV=Ko[l}+h05ė0H引2|\W0)W|jlSaswag~YB8Sd4<8Iqre[XObfdlVUTAYaQw}i05š0F1cU=?PK\v^ZM07]{>_J2RW^B5,Zi}qck[T\~`hmwn262Aɖ1tMDPmv[>=cC1PbevQbugVYaYGOrYM[_zqfmbYtt7;7D̗0h@%vJ\vwdC'-0?PNHJ\qbg~pr:qy=A=GΘ/)-nsVqxvJ++04\EU[Rr|NJSK^u6n~CFCKМ*3k_T2:qx^ISFTq\\WHgSVTbri냆IKINԜ*mf^YY|uapzPSRMvrgzuvoq|f숆OQROR֝)riA[iygEmszujkhvsc퍆UVZUVٝ){YL]|YTZPLvzt`Z\bZ\ڝ)ox_X};tnsk_T_fŲǿr]`ai`bܝ)7ǡy\a~Mt{vyh~^Y]lsLP`¾ī*Wfgfgݝ)2klmWCvkTYc}yqfdtjsTlmtlmߞ'f{ufyNrrs'f{sG|c]]êIx}xy'̣uuBDvz|u_ouϻE}~~}~'HƿxjWovstdqisrv}?𱇃&kxkxĺhn}noxfktf<𵇉&qY^py˾x>6𹇏&p|qh|fWVt3 &!Ʒmnepgɳų1Nƞ}qnltbtƀɕ/ě֢$ɵajhifhWcuȪ{/ș$iĨgʧw‡~wk-̘.$Ġ`yʼÛZ+ϗ#pų~kitļ¹C)ҕ#KeotͽΨ*֔.!DŽɭm_^R~Ì'ٓȫ"̻uǼƑsgeg}%ܒ!DZ~~zzzq&.!ɼyx|l˹īr#Ȱ!lƻ|lӿƾкS!!mǽ̾v}ni_a½2!CŽǴĵjt}u ʑǢȎ½bȹovşĤ6ļõŰ¾ƈȸʦa^r~MԺ˽ɍrkgymt;4oʿzúɻ̽àοơ}|ιȵȶò27Ĵs~ƺϻtöxyxbƧwij}OCqƫäµ;hķ~Ļƨ&GūѹƽLj3X ɫ~p{qwòz{ksgòũ~y+ƹƃ·w7Ŷs~˿ʾԶb>4ҠV/׵oYԴwHMb`i˾-dZMNfƻwuSNH?IOhruu{~ =bB6?<=:>A>303>=?IRlyˮxT-Ko^RUA1)*'My}qgdpqz!GCNַoR6XүUENZZn}3"nɧuggUS]qf#_ȕؼ˾ɏa`{iCCE&ȸЫζkkۙtwB??A,)ĴJLZvŽTu¿A0$<>>*hƯԿ}v٭lZXOOevĴʐGlx|@0*>?8-ݸУzZZ{1Rt @10@>2.OŌרƚ\_sƿ:fa?16@=&0x˃μϽpɹߺ輑j2";?<4|_bTF4Ͽ~F%0Bz'7Dc=3(>>: 4Ňãe/O~h|`;HA_Ƚ~d-(0,[);cbr`=4.?>46ˠ…VgU{rXN1[Ѿnk/4<1Gxct <54@>+7bнtui[FODGCʇ|WR/IzW+FlpxU=6 9?= 8²|t|pyYRP?L8@ùvZ|u3#/h[bQ^misR<6&=>;8ϽǶ^qPLg6DHXJwೃvz^Ug\mW>3[cuotyd;7,?>79 qq}^Z?,VTNzu{̵VMYTX\sokXB(4JmxinoR;82@>/; sjujD.\B1\t}WGKXP\]UcrfF )SVpugq]:98?>$<iʼnw`WV>;,Mbj~lhPELTMYYaTigZC!?ausx|u#9:$Mg`uĸδ}z]E=83FbkY:?9QSHXPWH" 2hgwΣ~ňG?D/A]qq\j`qk<BP2RIPzf^iuOOKUMQ^WZZPGQa]^[WZX]RdM9/:8$!!!*>DCsb~uw`ekyCS#8"4TIXoONVKMQRV[UW[VPKBGUV\afe]N]7627E/"5nZG{n~lqxNDV%@@7#7W IfFibsQ9 5JNJTQSKIOXREHNUUNNK\Y@RGN:>'!0+ARkKXmadealw~s~oDY!'?2@7$9Z Csɼx|NrVH%GWJNTWTSRTQQWYSVbvA4LY`.032MMjgFG?DMTcr^NLeZqr<E\%)? 4@6&;]CMf|K[hST$ `ZVURNSLOZXTYVamvX3 %_Bt|YYB2M' (dq`VYQPUOJEBPlt6"#.+FK\Yl}lX\JFSRPF&%-GS_jlkGc-&.@  9A8&%@aBsv_?A3Q)9bRLKUPMYsb,$!)5_yp^ytwvqNA@H:();TbmcuGf1)1B +D*)CdB<{a[n'.lg>[' SoZNMJ>,1g{>-ak$&%AMhimcdgH&% ##8Ohle`rJi5-3E"F.,Eg!0F^Z//C.JSH1ЯhfZ;!ayrNqq{C) 158?5-!4Hbd^O\Kl906G#H20Hi)@ ZrK?E073"PV@=$".-=]lrŴԹŮzytjmlN8>*;KzyU;GOmb27AJOqB7:Os5:'LhiUio|wurYLASmn_uqd[_zdaU[tor{|FRvJ>BP(!)QA>=Rv8:%t15^g]T\NFNDDbfbT`UQ^uq}|~s`ffq}|k}QRyOBAER+$+SEAUy< $¬v}4 FNPMIACNKYE NKWenlp}wrjbgKbt^u~zp S|SEHT/'-UHDW{?;d8o|UP !?&*236HQU`deGctnkku~{ojgbaT`W_`V^w5T~WHKV2*/WLHGZ~D< Q:  ?,'06AfaWRX0@eui`agox{{zsieebcN].RQYVZop*U[LKNX6.1YOK]F=wdɩ`QN2 .WE;9+3/ BN-[kd_[^gpuusskpoonia_]E3PM 7FTS\|lS_OQZ913[SN_I>èK+:4#,XKS>!*)2<&'.LY_ZW]gmlpmiedbgig\[S8;%9cJNcPib[RcRT\=45]VRbN>sviN9* ;YONRTQHIMAJOJNUTRcefdbc^^``adb[Z4)I~gF=-%#wXNNSWTJIKLOMNGLMP`a^^_\]b^]cca\G(2.g=;@=9G`gvKUkYZ`C;`\Xg[{yy188G1-"EYONRVSKLLILSUTUSV\]XZ_^_\]J,J_;3..6>6@korRo]\]bG>a`\j`?pm6 1aERMORQPPRQQPOLNSURWSWXW[]`]_dWBH[ecD8.7EF0jgfRs`eJAbb``_me>#q[Z|M,*06&=]21CKQPPQTVTUUTPRTT\ZWVY^]aha<<:DSOU]po\='4@nu\UwcgMDcecoj=bLTm`nsaL9*:FMOSVUVVTQWX\c`^bbhigR4!$->IUVNLl%5QAPX R{giQHehfro/Fc-0@FHRjkTKfkjut9Bq{noRH_bhR^XlrpskC.B\ZXYZ^dfklicMVN%+UVTbxQMT^YSjQPRmWNgaNM\q5VqZjG-TNWI=tOE3*+:2.)*'31>C7UQWU3q^UjO'm3[zs^gYX@IYXSUSTG8:=4%6D%/$94**BNR_ubOJM>%<9@@#&CMONEHJ7]k]vmOV7ud[nX%x3kkBQPQK_NXL=,>7)NG5P\ULHH>VN4(! )8=2 8BDJAG;8`XMuc7V9wg_p\$~3Yx?@7F;EFpWFE*.*RQHD??WZ[aM&JbJ>?:8*#7BGM8FI4?]M[wi)W;yjbq`#2vO;9'$IhYWW5>IL>B[RQC1';F)2/=_`lUMJBSVT[IGF6KRDeisZ=zmese"1x`?6+7Cs?NkXD@7 #MdqdT8 &(5CB=>Mu_SWkrlkpoymvoj^nn`zv}7VQ|v~&/&+_raH_e{c>$$),N;GLE`hB>E?Opc{{4UV!$y!)*/ZPxpzF*1_eO=F;F_NMI=WlFHFR{`z}T\&)|'&,­*mp\qUOrKKv{xhcQ^gCFE@d`Wgcdz^_iqouUb,./,0Ʋ)v`oX7LXfyW:\`g|}tlcYnZXca}t}|Qh23623ʸ)zzhyK@Oi~kKGLC@cu~}g|cPn78=78ͽ)w}^etPJi2ma]aZrPGPVpfNt<=D<>̾)2fMRujAbgcfX}jOJN[sa@CQs&KyBC`BC)0}Z[\J8cZGKSjf_VTxaYaqpG}GH{NGHž'wnVgcpwz|lpvVfoumDЁLMdLMž'VxhzaЅR|WRSĞ'tcl{b89lzdghcrP]bx|;ЉWiWXǞ'@wewyYI]daqbT_Xa`crk7Ѝ\~`\]˟&xZeZfX]i\u]meVnZa}trZ1Бbobџ&_KOnr^fqlel~vt{9-Дg{ighٟ&ch_WiUIHb~{+Θln&t[]Uo_Wq+Λq{B$xzi_~][bRqb)ϟwϺ$twxrRYXXVWISclq}i)΢}~w$_~W}vdlrmuj|dr}['Ϧ($|~Pfq{}x~{O%Ωά#`jZxvXbsr=%ϭr#AUyyn}]onb}#ΰ'!ptl\x~{yPOEjww#ϳϬ"~b~vzxpaWUWtxk!ζq!zjjgfgnaι'!lfeh[wzy|}fμϭ!^witz[nKοu!_cju\YPRŒ+!;xyz{tmYbi}buw ċίyzq{ox}xuNJxU{rr^dxtȈ/yyluȇαzROajEȆwpxw`ZVrf\bny5Ȅ-`g~uuqspp|}ȃϱyrtmji{ɂurrɀ+1oajncɿδwefezxVɿπndwt~isE9b{s~zz5[}k!Amvols3) ~uojok^i`}ufm|}wxpgvgZcZr{j|x{qk(nk|g3`qjnY5,ÂH)ɛ`vH~beؾƤ_<?Z:9Arлj&q^<5-.?߾atJ1.*%+/FQTU\_\VkȽz /^ue;' %#$#%'%%$%+0EPphM29}VA23&9nibfP?=CHq[!6s(=ɥU<$D•4).56DU'"iOۿQBL217DiK#Jrʤƻwn<8PP223&sʿeǽDBz~IIU~20/0 )rƯaWxĩ`+,5OaZl3I0.-*^Ũ\RYKhˏC54./=5+`¶ּS*(Xpz !(;_i-0/+4{agF7]TCU9#*'EϵԜR<;fo#E=HG.0.'6_8B6iUgOM7.FӼwCD$cx *gP:GdZ -0. 7U]MRmplzF8*/(**^{^Rd[^40,PZzD)ABK[;,0/-8\RYrVIk[61/&.!*׮M6ZgTI?6]O58A>E9-0., 8~9_bJiY/-@ (+4,OԘYLO82@e6C4%6;Ibecev_BFKB,0/(9 wllq\GIV=8%32/PM\NTeZ3-4246HBD4',BU\`TewCAC2,0/#;}n|OeCzQL+7'@TkouU4*,4/672;F<)13ChoO_j=D:+0/-<Gc\R:75&#-=ASyw[YVD@/)-2.54:2>=5(%9GEUx]WM+0.,=NzO40&!).49*'/:=/446 6KG`}RpM-+101/+=htWaHM\VARZb-,301332"@3|wr_tm|\>8hcd`iY:/%&(=78+- &$*3' >Q\8e}ϣoL,401433Atypc?'#7;+))*',4.*'$+B)*7* $"+% 1RGF7;TtBFX,50355:BvtgXdzSR^[;0%#$-749;82'&(,(+'5a1#*,OkA9E]_Ke98_ ,70156Bqc}O/fSV;,032%0&.=945784360/20-B?)!(!%(|h7OT7?d9F@^4,82157HywdXr0V=8@I//,3.08455/*0978635470=-"#!&('R`:gUp`HK9<@Npw,95303578H}ws\f_7XF//4,./03623630,'*2369=<7.7! !) F5*ZOApSkud@DL`?,;985//15899GLdlU`)I>H0",.,201,+/40)*.22..,:5&1)."%'1@-4D:;S>9EYKRFR]jP+<8.#/28<;:C\KT/sK3*  *3+.231101003513)*%(.2:F7.-<5D]wrI+,=?:. %/3;?>;C=f=U-8A32  95330.1-/541439CK7%*%!+!+=IK3-1''359:&*458O_sS#,>BCB =.&/5>B@< Bjhd[NV88'- BfJIbZ@&]&0 "_W:1-,2/-5JX>  =VI:NHKIG.&&+" #1:@:Ky,AHIB..HIE?B-U;9JED%6  6cdD5.-+$@T(HqH&.AA{cZA:<=* !.=@<:L.BKLD- -JLH@0286(,1+lpk>=5# >fKH/H|teHrjePa]( !%*:;8/>/CNPG- -LPOJA! 8H,%) !#%sѺjgT259asVG?J^KNOR^\XB+KPA.()+(#*8<7,0DQSJ, ,NSMC*75&$&8AFšu]MKF?A@.!$",M\TK]dk5#+2F_C'+11ESWL, +PVPD9%/'5#:al`;I^ûKJB?=:@L904>F/5`qj`b`Z`]GBNdxmC3GVZO+ +RZYRF : _or4CK3ABOJIZdH4-'1AB8KF<68UM;926Gbpz}n^U[VCEOOTy_`52HY^R* *S]UG":"eiS{}h8=727.*.((:=:29208FCOai[iqqv}qZMQF9<99=BHMSTNTXLE><<:;.830535DF2Mbk^''UjaL(=h?l?3.4)#"'.6?;968=BFFDE@CBBA>:87)/- )217PI2Ndnb'&VndN*>a~nm."4,1%#,58547=@@C@><;:=>=661!#"?..<0?:70Ogrqe&&VqgO-)Ro_OB.!$4/.010*+-',/+.221:<=;::889;:55#,#C?,)$uvh`+U>)$ P4..132++,,.--*--/9977867977::96*A$"&$"*9=I23Rkxl%$UxmQ4PN\N!!* ,a5..031,--+-121213674587877,,9# % &@BI1Sl|p$#T{pS7mreEBTV g>)0-.10//0//,.12041457978;3'*5<;(! () ?=?0Tns#"SsT9>{oF65R/ %@_',0//0232232/12265335879=9$#"(1.27DE8$&BJ?0Upw#!RvU<={^j;-2E;DG9izm." ")-/2323320347;98::=>=0%+23.,C0&0;/Vr{"!PyV@qgB;.;K]P;hC8+ZW-!*15123578<>@BA>)"/%); "*/6/Ws! O}WB91FPIF1+8;?2;4MHFHD('654558;;-3.221:P0.2870VYba`Z! :^]\ZW@53:MH9>54&+541211*!"$ *"  #$$!$+-,/(3R"$ UA3FV==269*)184,,+$($'.09K:.,-$   %!)&&/T#&  VD3FC'0/0,9.4-$$!.*/62-+*$2.  ")#0V$'  XF3=O%&!,"$!2-*)10+(%%3569."   )%%0X$)! ZJ2N/#" %!1%+-%'6100#(!!&#$/0Z%*! \L1Q:% ()(,-(#1!#)$!'(%&),-743[&," ^N1IB/1&&0"&'$$!%% ','*0./]&-# `Q1?A,97,&/&$" %#& %&!%%&)*/_ '/$ bS1 D,#(1 *,/#'%#""$&! ''*+)/a#'0% dV0P8*(2-#:+#'# (!%(&%''*&)&%!&&"*),).c&'1& fX/&((6(=7"!#+" !$'"+241::1+686B70.e((3' hZ*,95.3,*(+!#!&,".04<@=?<-g+ (4(  j^**:' 3-(/(-)+*$"!$#!$"#+!!$2''7)3-i.  (6* k_)1:0"'0-#* "$/3+,)&"& #"+--(,2/0>22+k1)8,mb)494*$61+%,&#-*04620,.,$0./-51+1:3**m4)9-ne);F.3,0!#(-%&" "(.'-9HD;5NRPBHPCKE4(n6);7 nf)U/14#*.%."2$##+% (")585*7&$/"'/*+/2E;7/-&')0$')2/-&-44/<-5#p=*?/kh'=8.*4$+"$43()7@821< % )5!&#8(",<0)@(3-pE%!%hp&;251!&(!4%7NU>71)&,-);(+.291/@-2$pG' '(ht&/>56$!$08/#2;PNVD;64.+3=023=9/0?0.oH*+Moz&AE59,)A6:1 '8!+5AKXY_Q:?HJ;;CA7?<9nJ,3^os"$CD*94/DLH/+%!,7 "'9%6J>36EQYKLTZ[Ia]BV\;nT;?apj!5K'(->DaR44& *,+C.%K08@=AEGLB3+oV=Jko[HR715,"0IK=542)0H+*'"7B:?.(=*/+nW@Won;!KQF5?*%%$0PA4)?%(+ &84FIYZJhikHCSVFQ`B)o\GHZon=!5hE;36QU?4#%-)6M ,"0.).  n_LUlo]6aQ+'+,':TfgNH012-1I*+*6D?:22-// n`NO^on>$9L>/+,((!&>GHSULEBJ/0*3@0787150 oaORfoj>@9GSD:8*1*&46ANibSMceR9;GGBG]F4 naOWln]RP619UN3*/00=7&&35DTQJJZSFOO:& naO^oo@9n=20*>ORC44L*! .7($ "<13'36*/& oaORfpj0RE.//3&Fff@?/,))8;(('1J89'<2+/ oaOWlo`6EEC/*.(,*8B@bc]CD1&%$;<13->20.obO^on>5Z;GM50-3,/7(6OTFBK_ZI;5172?7?< obORfplT:03E<50-=5&!%&159OH[AQbL8LaA,pbOOWln` =7,47E^I9C4*.;1##$+7+:987-1.qbO^ooD-E296#8RPJ871*3:0)-,:7,%(=410" refoq0=I33+,(-CTdXXA1-**0B829/811." uppt0E8<2..,60&?PZKIJJA3C331.:<87vwt)D14KK417-&)'&<5Q[d@BOJ?4FaN/eN=5-L`N3)'%'2=%!($,23>?35*0*-PA-05MIH9++66**'$1,)$6-/1*3:A45/B;^m_L60(+%+3*-+'70.156GD7/D'&2GE=:51-*(%$!  '2>IZaUPKFB?<961-(#  +9HWoid`\YUQKE>70)#   -=Oa|ͫìjcZRI@7.&  -?Rlf\QF:/$  +=R}vaRD5( &8NտxK9*   1GddM:) *>WfL8'    #5LgaJ6%    .C\^G4%  !%&%!  *OczYB0"'8Mz`QC7+!  '4CThU?-!!-?Vr]N@4)   ,:J[qiN:+$&2E^kZK=1&  #0?Pc_H6,,6JcߐfWH:/$  $3CVi{VB52;Mg΁bSE7," $3E]fN?9?Pju_PB5*   "2E[[H@DSkm[L>2'  /BYjRGHVmhXI;/%  *=T[NMXnԆdTF9-#  &8NjdUQ[oy`QC6*! #4IakZU]pp]M@3( "1D[wr_Y_rjYJ<0& !/BXwxd\bsٌeVG:.$ !/AVnh`dt~aRC6+    /AUlmcfus]N?2%  -@UlqfhviWG7)  *=Rvjkxߍ_K9)  $7Mq{onzqK7% .D^̀tr}D/  $8PyvQ9$ *@\}z\@* /G|eF.2L~lJ1 3MpM22L~sN4 /H}|vP5  +B_}yxP5   &;Vwt}yQ5    3Kwooy{Q6! +@[egtR6!  "6Nl`Z_oR6! ,C]t\QNWiS7!  %9Sp馋r\LCDOdS7"   3LieO?8YeI7/2BZT8# ,DdnN;14BZU9# /IR>35CZU9# 2LT?56C[V9#  3MS?46CZV:$ 2KO<35CZW:$ /GmF6/3AYW:$ *A]VXX;%  1IvwaO>/% *=WX;% )>Xt^K:,!';VX;%  !3Kg|aJ8)&:UX;% *?ZxmR;) $9UY<%  "5NkbG0 #9UY<% -D`Z>)  #8TY<%  &&  0Fy^A)  "7S[>' '9OY=&  "7S\>'  ,=yU9#  "7S\?'   -[aC+  !6Qy]@(  #8S]?(  !6QxZ='  2LkY<%   5QwU:$ -EbT8#   5PvN5!  '>ZvP5    5PvE. "7RylL2  5PvX:' 1JggH/  5PuYB. *B_bD+  5PuZE3#  %:V]@(   5PurXE3%   4MpX<%   4OtgTB2$ -FcT8" 4OtaN=."  (?[tO4  4Oss[H8*  #9TtjK14OshTC3&  3NmeF-4OsaN=/" /Hf`B* 4Nrt[I8*  +Ca[>' 4NrhTC3&  '>[V:$ 3NraO>/#  $:VyQ6! 3Nqt[I8*  !6QnM23NqhUC3& 2LkgH/3NpaO>/# /IgbD,3Mpu[I8* ,Ed]@) 3MpiUC4&  *C`Y<& 2MobO>/#  (@^T8# 2Lnu[I9+  '>[uP5  1LmhUC4&  $;WkK11JjbO>/#  "8SfG./Hfu[I9+  4N|aC+ -D`hUC4' 0Ih\?( *?X`O>/# ,DbX;%  %8NnXH8+  (?\S7"   0BYM@3&  $:UsN3  &5kHA7,"   4NfH/ (?52-% .Fe_C+  #$!  (>XV<&    "4LK4!  +>^?+ !1JS2" chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Resources/app.png000066400000000000000000000107651257432200600241500ustar00rootroot00000000000000PNG  IHDR00WsRGBbKGD pHYs3tIME 5 5 uIDATh՚ygy}w=vunɖ%aclQ6C( *EJll@(R. T16/˧lK^=%jٙ{{;hV]"tUѳ>}/- (.`n*Ѐ2PnHz@Xy7#|DSz2뮽dhh5B ěa@5?w4n2- Y㹧鱆Ɠ{`~yc1`ƈW{P'5wܶ$AKԯ hlDlV\uV Lc| S5I5v;f,} OcG>yW|vJEgn#3<0(NF]W|H\KRhk̺oUfE~˷lYx-ѵ~S'Xa3~"MD"\~N%knZuٶ֧}]"lt="] xV۷^vѕ[x#mAٷ1vʼnI^z)޳iR+ھQXm}.xՁ%7[HjL]T}H(얛>w×>.W *dk $Zs! whc+`o@ٸ8{w͌S|] r"GA`nƏonbSg$Sdӌf׮]?Ov)c)'OR:ox!(]I`ϼԿ*we'S2l 9)%|ckʩr%j-~CbMK~[!x1I!_ݻt}dÏ]exK:ۙr|tM,l'܁]Γ8{j+F)/.=%Q[Rb7߱=`0Uv].T9o6=wTՠ=j0x|  q7S$9?{*Uv;2ІWLXq)dc/1G _rβ :jm7uF 3i܅Q ިu$ɥaʙ$v;7nk&ҳY{z'{cH.Jɪb."XI6,j@,mF:}):zX# |ڞuI]7-o|WH8-&k#UXDXSբ; "ڥmlZ^$J3O.aV|~u9<6É<'2e x%Ty')]YAҰܨ[>-j}i4ίW7oK`bl uyLjw/r |nTfUܪ`2G2k3-s޾"_^w"Udiޓk˒(J"(r}ԡ*J< Q݈"JtE\T=9G ]k6 c~*9rx'{Y3D$e!UƧk=9Cԯ[;״9:xPdGP$n;dL5*3M$BuUU$W_r XTM{fxI3x{se4ZlBSEc:~&:bq% E)#ȗmKq}1m `dU@y|@43;~;9HH0255-*0dgK芈낦HlE9b mUK}BDwM@Uy>*Y;ssmŮY|~&~hh )TlQMq= 3%K-cU['R@fHU 䅭a =:[ŻIjGhp߼O"3Mc>Oq\R &o3WX|˵L=?~,ϫ'&NӚp׀9<˛ڦY {~׬M)[Gd! #3H4| +CaVH(=w^5`PG3Z3؃j}! @HɊ;8&W)mÁ q?Ŧq4E"W,c"҈ ڕ0^5~G*iҼ@ |^rU$  q֫ݤ8ט 8Jg'4) gx%⥱)\`K .]ħI4u>ZR 0Wy`կ6""t@yV %5P2&+2LrQddhS=O5t.* tj[TQEo!(ίظ+F6L\}9^?Ck, ,j2He,V. P1PP#(<՝=火4"a蠋 \M=P*00WY`8Rcl~8qX"Hs$ %t2&>C\pUǃxxFP!RĪH$UM707#oPr&[ ZTX"wX2B8DQf2Ej .4"3tƀNtB88EdE<9(|m7p\mosr, lX݌,VHio6-3=S!o]϶OD/>ÀOw)믒JKDk@SDtMgb dGZ%!DTED@Wl ڎ,Y ϳ-_Xs߭j:d&`蘂ʄCg$"&9s 7̖{z$}NVb4 Ç@\fjATPvM>NڶjD |^ 8w0)Lg lo_swiqU\+*d6[72t"O"W"G[ mqFNYb}8sX㪊ջpcz>ɇŲ@0Ng{[7"f_ XI4HHJ";UBgyJ4{|'/2fy})*#9ʼn54RXH4qsZhs3 (wSswx6fjw/օ[Ѷ"CBUL28.Hh]~A6W"C:e 9( ~pGo{)Lƛ깾b@/xuR*D㝴4(N0{*T%Sjdşс;jIMsqR>K{kAprSe?<=5[0W&oI4Mb]C'g̝{zNKf\{+Nˎcb6BXS;nsQjc'i\ZL2S:UA8X6̞r 7?zGrd ;x7@Їf`W=vD\LhއN2ZPKWC3=?@\P2o vہFGhbY'AdC-.Vy 1060 10K549 851 1038.36 461.00 com.apple.InterfaceBuilder.CocoaPlugin 851 YES YES com.apple.InterfaceBuilder.CocoaPlugin PluginDependencyRecalculationVersion YES NSApplication FirstResponder NSApplication 7 2 {{350, 488}, {530, 190}} 1886912512 (Package Name) Launcher NSWindow View {1.79769e+308, 1.79769e+308} {243.529, 107} 256 YES 256 {{17, 159}, {360, 11}} YES 67239424 272629760 U2VsZWN0IGEgZ2FtZToKA LucidaGrande 9 3614 6 System controlColor 3 MC42NjY2NjY2NjY3AA 6 System controlTextColor 3 MAA 256 {{17, 127}, {259, 26}} YES -2076049856 2048 LucidaGrande 13 1044 109199615 1 LucidaGrande 13 16 400 75 Game name 1048576 2147483647 1 NSImage NSMenuCheckmark NSImage NSMenuMixedState _popUpItemAction: YES OtherViews YES 3 YES YES 1 256 YES YES Apple PDF pasteboard type Apple PICT pasteboard type Apple PNG pasteboard type NSFilenamesPboardType NeXT Encapsulated PostScript v1.2 pasteboard type NeXT TIFF v4.0 pasteboard type {{382, 51}, {128, 128}} YES 130560 33554432 NSImage 128x128 0 1 0 YES YES 256 {{281, 129}, {93, 23}} YES 67239424 134217728 Configure... -2038021889 32 400 75 256 {{17, 100}, {360, 11}} YES 67239424 272629760 Q29tbWFuZCBsaW5lIGFyZ3VtZW50czoKA 256 {{20, 70}, {354, 22}} YES -1804468671 272630784 YES 6 System textBackgroundColor 3 MQA 6 System textColor 256 {{387, 12}, {129, 32}} YES -2080244224 134217728 Launch Game -2038284033 1 200 25 256 {{14, 12}, {149, 32}} YES 67239424 134217728 Run Setup Tool... -2038284033 1 200 25 {530, 190} {{0, 0}, {1440, 878}} {243.529, 129} {1.79769e+308, 1.79769e+308} MainMenu YES Launcher 1048576 2147483647 submenuAction: Launcher YES About... 2147483647 YES YES 1048576 2147483647 IWAD configuration... , 1048576 2147483647 Command Prompt... t 1048576 2147483647 YES YES 1048576 2147483647 Services 1048576 2147483647 submenuAction: Services YES _NSServicesMenu YES YES 1048576 2147483647 Hide h 1048576 2147483647 Hide Others h 1572864 2147483647 Show All 1048576 2147483647 YES YES 1048576 2147483647 Quit q 1048576 2147483647 _NSAppleMenu Edit 1048576 2147483647 submenuAction: Edit YES Undo z 1048576 2147483647 Redo Z 1048576 2147483647 YES YES 1048576 2147483647 Cut x 1048576 2147483647 Copy c 1048576 2147483647 Paste v 1048576 2147483647 Delete 1048576 2147483647 Select All a 1048576 2147483647 Window 1048576 2147483647 submenuAction: Window YES Minimize m 1048576 2147483647 Zoom 1048576 2147483647 YES YES 1048576 2147483647 Bring All to Front 1048576 2147483647 _NSWindowsMenu Help 2147483647 submenuAction: Help YES Introduction ? 1048576 2147483647 Set up guide 2147483647 Command line reference 2147483647 More documentation... 2147483647 YES YES 2147483647 Software license 2147483647 _NSHelpMenu _NSMainMenu LauncherManager IWADController 7 2 {{377, 417}, {518, 308}} 1886912512 IWAD configuration NSWindow View {1.79769e+308, 1.79769e+308} {213, 107} 256 YES 256 {{422, 12}, {82, 32}} YES 67239424 134217728 Close -2038284033 1 200 25 268 {{17, 16}, {25, 25}} YES 67239424 134217728 -2038415105 161 200 25 12 {{13, 42}, {492, 260}} YES 1 256 YES 256 {{14, 200}, {446, 11}} YES 67239424 272629760 Doom IWAD location (doom.wad): 256 {{17, 171}, {369, 22}} YES -1804468671 272630784 YES 256 {{393, 169}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 256 {{14, 152}, {446, 11}} YES 67239424 272629760 Doom II IWAD location (doom2.wad): 256 {{17, 122}, {369, 22}} YES -1804468671 272630784 YES 256 {{393, 122}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 256 {{14, 103}, {446, 11}} YES 67239424 272629760 RmluYWwgRG9vbTogVE5UOiBFdmlsdXRpb24gbG9jYXRpb24gKHRudC53YWQpOgo 256 {{17, 73}, {369, 22}} YES -1804468671 272630784 YES 256 {{393, 73}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 256 {{14, 55}, {446, 11}} YES 67239424 272629760 RmluYWwgRG9vbTogUGx1dG9uaWEgRXhwZXJpbWVudCBsb2NhdGlvbiAocGx1dG9uaWEud2FkKToKA 256 {{17, 25}, {369, 22}} YES -1804468671 272630784 YES 256 {{393, 25}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 {{10, 33}, {472, 214}} Doom 2 256 YES 256 {{14, 55}, {446, 11}} YES 67239424 272629760 Chex Quest IWAD location (chex.wad): 256 {{17, 25}, {369, 22}} YES -1804468671 272630784 YES 256 {{393, 25}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 256 {{393, 73}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 256 {{393, 122}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 268 {{17, 122}, {369, 22}} YES -1804468671 272630784 YES 268 {{17, 171}, {369, 22}} YES -1804468671 272630784 YES 256 {{14, 145}, {446, 17}} YES 67239424 272629760 Hexen IWAD location (hexen.wad): 256 {{14, 194}, {446, 17}} YES 67239424 272629760 Heretic IWAD location (heretic.wad): 256 {{393, 169}, {63, 23}} YES 67239424 134217728 Set... -2038021889 32 400 75 256 {{14, 103}, {446, 11}} YES 67239424 272629760 Strife IWAD location (strife1.wad): 256 {{17, 73}, {369, 22}} YES -1804468671 272630784 YES {{10, 33}, {472, 214}} Other games 0 YES YES YES {518, 308} {{0, 0}, {1440, 878}} {213, 129} {1.79769e+308, 1.79769e+308} IWADLocation IWADLocation IWADLocation IWADLocation IWADLocation AppController IWADLocation IWADLocation IWADLocation YES performMiniaturize: 37 arrangeInFront: 39 terminate: 139 orderFrontStandardAboutPanel: 142 hideOtherApplications: 146 hide: 152 unhideAllApplications: 153 performZoom: 198 launcherWindow 207 commandLineArguments 222 runSetup: 223 launch: 224 openConfigWindow: 226 locationConfigBox 251 locationConfigBox 252 locationConfigBox 253 locationConfigBox 254 setButtonClicked: 255 setButtonClicked: 256 setButtonClicked: 257 setButtonClicked: 258 closeConfigWindow: 259 doom1 260 doom2 261 tnt 262 plutonia 263 chex 264 configWindow 265 iwadSelector 266 locationConfigBox 267 openConfigWindow: 268 iwadController 269 delegate 271 launcherManager 272 setButtonClicked: 273 paste: 306 delete: 307 cut: 310 undo: 313 copy: 315 selectAll: 317 redo: 318 openTerminal: 321 launchButton 322 openINSTALL: 374 openCMDLINE: 376 openDocumentation: 378 openCOPYING: 381 openREADME: 382 openINSTALL: 385 locationConfigBox 403 locationConfigBox 404 setButtonClicked: 411 setButtonClicked: 412 heretic 413 hexen 414 locationConfigBox 423 setButtonClicked: 424 strife 425 YES 0 YES -2 File's Owner -1 First Responder 21 YES Launcher Window 2 YES 209 YES 211 YES 216 YES 217 YES 218 YES 219 YES 220 YES 221 YES 29 YES MainMenu 19 YES 24 YES 5 23 92 197 56 YES 57 YES 58 129 131 YES 130 134 136 143 144 145 149 150 196 320 274 YES 275 YES 281 282 287 289 290 291 293 301 206 LauncherManager 225 IWADController 227 YES Configuration Window 228 YES 250 YES 229 Doom1IWAD 230 Doom2IWAD 231 TNTIWAD 232 PlutoniaIWAD 233 ChexIWAD 270 AppController 325 326 YES 327 328 329 330 331 332 348 212 YES 213 -3 Application 369 YES 370 YES 371 373 375 377 379 380 383 YES 384 386 YES 387 YES 388 YES 389 YES 390 YES 234 YES 333 235 YES 334 236 YES 335 238 YES 336 239 YES 337 240 YES 338 241 YES 339 242 YES 340 243 YES 341 244 YES 342 245 YES 343 246 YES 344 247 YES 345 248 YES 346 249 YES 347 391 YES 392 393 YES 394 397 YES 398 399 YES 400 401 HereticIWAD 402 HexenIWAD 405 YES 406 408 YES 409 415 YES 416 417 YES 418 419 YES 420 422 StrifeIWAD YES YES 129.IBPluginDependency 129.ImportedFromIB2 130.IBEditorWindowLastContentRect 130.IBPluginDependency 130.ImportedFromIB2 131.IBPluginDependency 131.ImportedFromIB2 134.IBPluginDependency 134.ImportedFromIB2 136.IBPluginDependency 136.ImportedFromIB2 143.IBPluginDependency 143.ImportedFromIB2 144.IBPluginDependency 144.ImportedFromIB2 145.IBPluginDependency 145.ImportedFromIB2 149.IBPluginDependency 149.ImportedFromIB2 150.IBPluginDependency 150.ImportedFromIB2 19.IBPluginDependency 19.ImportedFromIB2 196.IBPluginDependency 196.ImportedFromIB2 197.IBPluginDependency 197.ImportedFromIB2 2.IBPluginDependency 2.ImportedFromIB2 206.ImportedFromIB2 209.IBPluginDependency 209.IBViewBoundsToFrameTransform 209.ImportedFromIB2 21.IBEditorWindowLastContentRect 21.IBPluginDependency 21.IBWindowTemplateEditedContentRect 21.ImportedFromIB2 21.NSWindowTemplate.visibleAtLaunch 21.windowTemplate.hasMinSize 21.windowTemplate.minSize 211.IBPluginDependency 211.IBViewBoundsToFrameTransform 211.ImportedFromIB2 212.IBPluginDependency 212.ImportedFromIB2 213.IBPluginDependency 213.ImportedFromIB2 216.IBPluginDependency 216.IBViewBoundsToFrameTransform 216.ImportedFromIB2 217.IBPluginDependency 217.IBViewBoundsToFrameTransform 217.ImportedFromIB2 218.IBPluginDependency 218.IBViewBoundsToFrameTransform 218.ImportedFromIB2 219.IBPluginDependency 219.IBViewBoundsToFrameTransform 219.ImportedFromIB2 220.IBPluginDependency 220.IBViewBoundsToFrameTransform 220.ImportedFromIB2 221.IBPluginDependency 221.IBViewBoundsToFrameTransform 221.ImportedFromIB2 225.ImportedFromIB2 227.IBEditorWindowLastContentRect 227.IBPluginDependency 227.IBWindowTemplateEditedContentRect 227.ImportedFromIB2 227.windowTemplate.hasMinSize 227.windowTemplate.minSize 228.IBPluginDependency 228.ImportedFromIB2 229.ImportedFromIB2 23.IBPluginDependency 23.ImportedFromIB2 230.ImportedFromIB2 231.ImportedFromIB2 232.ImportedFromIB2 233.ImportedFromIB2 234.IBPluginDependency 234.IBViewBoundsToFrameTransform 234.ImportedFromIB2 235.IBPluginDependency 235.IBViewBoundsToFrameTransform 235.ImportedFromIB2 236.IBPluginDependency 236.IBViewBoundsToFrameTransform 236.ImportedFromIB2 238.IBPluginDependency 238.IBViewBoundsToFrameTransform 238.ImportedFromIB2 239.IBPluginDependency 239.IBViewBoundsToFrameTransform 239.ImportedFromIB2 24.IBEditorWindowLastContentRect 24.IBPluginDependency 24.ImportedFromIB2 240.IBPluginDependency 240.IBViewBoundsToFrameTransform 240.ImportedFromIB2 241.IBPluginDependency 241.IBViewBoundsToFrameTransform 241.ImportedFromIB2 242.IBPluginDependency 242.IBViewBoundsToFrameTransform 242.ImportedFromIB2 243.IBPluginDependency 243.IBViewBoundsToFrameTransform 243.ImportedFromIB2 244.IBPluginDependency 244.IBViewBoundsToFrameTransform 244.ImportedFromIB2 245.IBPluginDependency 245.IBViewBoundsToFrameTransform 245.ImportedFromIB2 246.IBPluginDependency 246.IBViewBoundsToFrameTransform 246.ImportedFromIB2 247.IBPluginDependency 247.IBViewBoundsToFrameTransform 247.ImportedFromIB2 248.IBPluginDependency 248.IBViewBoundsToFrameTransform 248.ImportedFromIB2 249.IBPluginDependency 249.IBViewBoundsToFrameTransform 249.ImportedFromIB2 250.IBPluginDependency 250.IBViewBoundsToFrameTransform 250.ImportedFromIB2 270.ImportedFromIB2 274.IBPluginDependency 274.ImportedFromIB2 275.IBEditorWindowLastContentRect 275.IBPluginDependency 275.ImportedFromIB2 281.IBPluginDependency 281.ImportedFromIB2 282.IBPluginDependency 282.ImportedFromIB2 287.IBPluginDependency 287.ImportedFromIB2 289.IBPluginDependency 289.ImportedFromIB2 29.IBEditorWindowLastContentRect 29.IBPluginDependency 29.ImportedFromIB2 290.IBPluginDependency 290.ImportedFromIB2 291.IBPluginDependency 291.ImportedFromIB2 293.IBPluginDependency 293.ImportedFromIB2 301.IBPluginDependency 301.ImportedFromIB2 320.IBPluginDependency 320.ImportedFromIB2 369.IBPluginDependency 370.IBEditorWindowLastContentRect 370.IBPluginDependency 371.IBPluginDependency 373.IBPluginDependency 375.IBPluginDependency 377.IBPluginDependency 379.IBPluginDependency 380.IBPluginDependency 383.IBPluginDependency 383.IBViewBoundsToFrameTransform 384.IBPluginDependency 386.IBPluginDependency 386.IBViewBoundsToFrameTransform 387.IBPluginDependency 388.IBPluginDependency 389.IBPluginDependency 390.IBPluginDependency 391.IBPluginDependency 391.IBViewBoundsToFrameTransform 392.IBPluginDependency 393.IBPluginDependency 393.IBViewBoundsToFrameTransform 394.IBPluginDependency 397.IBPluginDependency 397.IBViewBoundsToFrameTransform 397.ImportedFromIB2 399.IBPluginDependency 399.IBViewBoundsToFrameTransform 399.ImportedFromIB2 401.IBPluginDependency 402.IBPluginDependency 405.IBPluginDependency 405.IBViewBoundsToFrameTransform 405.ImportedFromIB2 408.IBPluginDependency 408.IBViewBoundsToFrameTransform 408.ImportedFromIB2 415.IBPluginDependency 415.IBViewBoundsToFrameTransform 415.ImportedFromIB2 417.IBPluginDependency 417.IBViewBoundsToFrameTransform 417.ImportedFromIB2 419.IBPluginDependency 419.IBViewBoundsToFrameTransform 419.ImportedFromIB2 422.IBPluginDependency 5.IBPluginDependency 5.ImportedFromIB2 56.IBPluginDependency 56.ImportedFromIB2 57.IBEditorWindowLastContentRect 57.IBPluginDependency 57.ImportedFromIB2 58.IBPluginDependency 58.ImportedFromIB2 92.IBPluginDependency 92.ImportedFromIB2 YES com.apple.InterfaceBuilder.CocoaPlugin {{576, 728}, {64, 6}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwyEAAA {{368, 418}, {530, 190}} com.apple.InterfaceBuilder.CocoaPlugin {{368, 418}, {530, 190}} {243.529, 107} com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwxAAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin AUO/AABCTAAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDjIAAww8AAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwwoAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBoAAAwu4AAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDwYAAwgQAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBYAAAwigAAA {{358, 421}, {518, 308}} com.apple.InterfaceBuilder.CocoaPlugin {{358, 421}, {518, 308}} {213, 107} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABD24AAw5+AAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwz8AAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDxoAAxBJAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBYAAAwyAAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAww8AAA {{469, 741}, {194, 73}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDyoAAwwcAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBYAAAwuAAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwroAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDzoAAwqwAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBYAAAwmAAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwjQAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDzoAAwdAAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBYAAAwnwAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwjAAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDy4AAwfgAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABD2gAAwqIAAA com.apple.InterfaceBuilder.CocoaPlugin {{425, 661}, {151, 153}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{329, 814}, {272, 20}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{540, 701}, {238, 113}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwhwAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBUAAAw5YAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwxAAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBgAAAw0EAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBYAAAwyEAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBUAAAw1EAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDxIAAww0AAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABDxIAAw0AAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBYAAAwtYAAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABBiAAAwq4AAA com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABD0YAAwpYAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{341, 611}, {235, 203}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin YES YES YES YES 425 YES AppController NSObject launcherManager id launcherManager launcherManager id IBUserSource FirstResponder NSObject IBUserSource IWADController NSObject YES YES closeConfigWindow: openConfigWindow: YES id id YES YES closeConfigWindow: openConfigWindow: YES closeConfigWindow: id openConfigWindow: id YES YES chex configWindow doom1 doom2 heretic hexen iwadSelector plutonia strife tnt YES id id id id id id id id id id YES YES chex configWindow doom1 doom2 heretic hexen iwadSelector plutonia strife tnt YES chex id configWindow id doom1 id doom2 id heretic id hexen id iwadSelector id plutonia id strife id tnt id IBUserSource IWADLocation NSObject setButtonClicked: id setButtonClicked: setButtonClicked: id locationConfigBox id locationConfigBox locationConfigBox id IBUserSource LauncherManager NSObject YES YES launch: openCMDLINE: openCOPYING: openDocumentation: openINSTALL: openREADME: openTerminal: runSetup: YES id id id id id id id id YES YES launch: openCMDLINE: openCOPYING: openDocumentation: openINSTALL: openREADME: openTerminal: runSetup: YES launch: id openCMDLINE: id openCOPYING: id openDocumentation: id openINSTALL: id openREADME: id openTerminal: id runSetup: id YES YES commandLineArguments iwadController launchButton launcherWindow YES id id id id YES YES commandLineArguments iwadController launchButton launcherWindow YES commandLineArguments id iwadController id launchButton id launcherWindow id IBUserSource 0 IBCocoaFramework com.apple.InterfaceBuilder.CocoaPlugin.macosx com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES 3 YES YES 128x128 NSMenuCheckmark NSMenuMixedState YES {128, 128} {9, 8} {7, 2} chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Resources/launcher.nib/keyedobjects.nib000066400000000000000000000771561257432200600304060ustar00rootroot00000000000000bplist00 S TX$versionX$objectsY$archiverT$top-15<?@Eabcdghiw   %&+,-04569<@DGNR_hijklmnrs~ ^fijkotwxy~ "+,56?@JSTbclmvw #$%*456:ABHW_`ijrs} %-.78@AKLMQRSTUV[^_dghmpqvyz %&'(-6789>GHINWXY]fghmrsxy~    "+01238@ABGOPQV^_`emnoty~   !$/:EPQ`kwxy~ q    \                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G J M PU$null  !"#$%&'()*+,_NSAccessibilityOidsKeys_NSVisibleWindows]NSObjectsKeys_NSClassesValues[NSFrameworkVNSRoot_NSAccessibilityOidsValues]NSClassesKeys\NSOidsValuesV$classYNSNextOidZNSOidsKeys]NSConnections_NSObjectsValues[NSNamesKeys_NSAccessibilityConnectors]NSFontManager]NSNamesValues JILKmƁǁ ./0[NSClassName234YNS.string]NSApplication6789Z$classnameX$classes_NSMutableString8:;XNSStringXNSObject67=>^NSCustomObject=;_IBCocoaFrameworkABCZNS.objectsCDFGHIJKLMNOPQRSTUVWXYZ[\]^_`\NSWindowRect]NSWindowTitleYNSMaxSize\NSWindowViewYNSMinSize_NSWindowContentMaxSize\NSScreenRect_NSWindowContentMinSize_NSWindowBackingYNSWTFlags]NSWindowClass[NSViewClass_NSWindowStyleMask kj ilpx _{{350, 488}, {530, 190}}_(Package Name) LauncherXNSWindow23fTView_{1.79769e+308, 1.79769e+308}^{243.529, 107}jklmnopqrstsv[NSSuperviewXNSvFlags_NSNextResponder[NSFrameSizeXNSWindowZNSSubviewshgfAxy7z{|}~#;JPT\ajklnVVsYNSEnabledWNSFrameVNSCell "_{{17, 159}, {360, 11}}z[NSCellFlags\NSCellFlags2ZNSContents]NSControlView[NSTextColorYNSSupport_NSBackgroundColor@!_Select a game: VNSNameVNSSizeXNSfFlags#@"\LucidaGrande67VNSFont;]NSCatalogName[NSColorName\NSColorSpaceWNSColorVSystem\controlColorWNSWhiteM0.666666666767WNSColor;Ā _controlTextColorȀB067_NSTextFieldCell;\NSActionCellVNSCell67[NSTextField;YNSControlVNSView[NSResponderjklnVVs $%:_{{17, 127}, {259, 26}}{_NSPeriodicInterval_NSPreferredEdge]NSButtonFlags_NSAlternateContents_NSKeyEquivalent_NSAlternateImageZNSMenuItem_NSMenuItemRespectAlignmentVNSMenu_NSPeriodicDelay_NSUsesItemFromMenu]NSAltersState_NSArrowPosition^NSButtonFlags2KA@@()'#* +& 9#@*#@*P23 P XNSAction_NSKeyEquivModMaskWNSStateYNSOnImageXNSTargetZNSKeyEquiv]NSMnemonicLoc\NSMixedImageWNSTitle3+-%4(1,!"#$[NSMenuItems685YGame name'.()*^NSResourceName0/.WNSImage_NSMenuCheckmark67./_NSCustomResource.;'.(2*02._NSMenuMixedState__popUpItemAction:6778ZNSMenuItem7;23;ZOtherViewsAx>7*67AB^NSMutableArrayAC;WNSArray67EFVNSMenuE;67HI_NSPopUpButtonCellHJKLM;^NSMenuItemCell\NSButtonCell\NSActionCellVNSCell67OP]NSPopUpButtonOQ;XNSButtonSjklnTVXVZ[Vs^ZNSEditable[NSDragTypes D EI<ABaCbcdefg=>?@AB_Apple PNG pasteboard type_Apple PDF pasteboard type_NSFilenamesPboardType_Apple PICT pasteboard type_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type67op\NSMutableSetoq;UNSSet_{{382, 51}, {128, 128}}tuvwxyz{z|WNSAlignWNSScaleWNSStyleZNSAnimatesFH '.(*0G.W128x12867[NSImageCell;VNSCell67[NSImageView;jklnVVs KLO_{{281, 129}, {93, 23}}}K@(('MJN& \Configure...67KK;\NSActionCellVNSCell67QQ;jklnVVs QR"_{{17, 100}, {360, 11}}~@SP!_Command line arguments: jklnVVs UV"_{{20, 70}, {354, 22}}_NSDrawsBackgroundqA@(T!Z& WրXY_textBackgroundColorڀB1Ā[ YtextColorjklnVVs ]^O_{{387, 12}, {129, 32}}@(`&_\N&[Launch Game23PjklnVVs bcO_{{14, 12}, {149, 32}}   @(e&daN&_Run Setup Tool...23PZ{530, 190}67;_{{0, 0}, {1680, 1028}}^{243.529, 129}_{1.79769e+308, 1.79769e+308}67_NSWindowTemplate;Ax"7;#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]nsw{}   !',16;@DHLMOQSTUVWY_dimrw|_`abcd WNSLabel]NSDestinationXNSSourcerqo./hp]AppControllerXdelegate67lm_NSNibOutletConnectorln;^NSNibConnector_`abqsrvTt./vu_LauncherManager_commandLineArguments_`ab{|srzxt./y^IWADController^iwadController_`absr|\t\launchButton_`abDsr~t^launcherWindow_`ab|rx./\IWADLocationTchex_`ab|rxFGHIJKLMNOPQRZ\`lpx_{{377, 417}, {518, 308}}_IWAD configuration23XNSWindow23TView_{1.79769e+308, 1.79769e+308}Z{213, 107}jklmnophAx7€jkln O_{{422, 12}, {82, 32}}@(&N&UClose23݀Pjkln  O_{{17, 16}, {25, 25}}@(((N&jklnoz_NSSelectedTabViewItem^NSTabViewItemsVNSFontYNSTvFlags_NSAllowTruncatedLabelsƀŀĀ& Ax 7 jklno pÀhAx7 !jkln$% '  "_{{14, 200}, {446, 11}}-./@!_Doom IWAD location (doom.wad):jkln89 ;  "_{{17, 171}, {369, 22}}ABqA@(!Z& WjklnLM O  O_{{393, 169}, {63, 23}}UVWX\`aK@(('N& VSet...jklnef h  "_{{14, 152}, {446, 11}}nop@!_"Doom II IWAD location (doom2.wad):jklnyz |  "_{{17, 122}, {369, 22}}qA@(!Z& Wjkln   O_{{393, 122}, {63, 23}}\K@(('N& jkln   "_{{14, 103}, {446, 11}}@!_/Final Doom: TNT: Evilution location (tnt.wad): jkln   "_{{17, 73}, {369, 22}}qA@(!Z& Wjkln   O_{{393, 73}, {63, 23}}\K@(('N& jkln   "_{{14, 55}, {446, 11}}@!_9Final Doom: Plutonia Experiment location (plutonia.wad): jkln   "_{{17, 25}, {369, 22}} qA@(!Z& Wjkln    €O_{{393, 25}, {63, 23}}\!!"K@(('N& _{{10, 33}, {472, 214}}_{{13, 42}, {492, 260}}Ax'7)ƀ+_,-.0 2YNSTabViewVNSView\NSIdentifierɀȀǀQ1TDoom6778]NSTabViewItem9;]NSTabViewItem+_,-.=>?ɀ̀ˀQ2kloCpE+GhAxJ7KLMNOPQRSTUV΀ҀՀ؀ۀހjklYZ>\> πЀ"_{{14, 55}, {446, 11}}abcK@р΀!_$Chex Quest IWAD location (chex.wad):jkllm>o> ӀԀ"_{{17, 25}, {369, 22}}tuLqA@(Ҁ!Z& Wjkl>> ր׀O_{{393, 25}, {63, 23}}\MK@(('ՀN& jkl>> ـڀO_{{393, 73}, {63, 23}}\NK@(('؀N& jkl>> ܀݀O_{{393, 122}, {63, 23}}\OK@(('ۀN& jkl>> ߀ "_{{17, 122}, {369, 22}}PqA@(ހ!Z& Wjkl>>  "_{{17, 171}, {369, 22}}QqA@(!Z& Wjkl>> "_{{14, 145}, {446, 17}}R@!_ Hexen IWAD location (hexen.wad):jkl>> "_{{14, 194}, {446, 17}}S@!_$Heretic IWAD location (heretic.wad):jkl>> O_{{393, 169}, {63, 23}}\T#$K@(('N& jkl'(>*> "_{{14, 103}, {446, 11}}/01U@!_#Strife IWAD location (strife1.wad):jkl:;>=> "_{{17, 73}, {369, 22}}BCVqA@(!Z& W_{{10, 33}, {472, 214}}[Other games67NOYNSTabViewP;YNSTabViewZ{518, 308}_{{0, 0}, {1680, 1028}}Z{213, 129}_{1.79769e+308, 1.79769e+308}\configWindow_`abXY|rx./Udoom1_`abab|rx./Udoom2_`abjk|rx./Wheretic_`abst|r  x./Uhexen_`ab|{|r #x\iwadSelector_`ab|rx./Xplutonia_`ab|rx./Vstrife_`ab|rx./Stnt_`abYr_locationConfigBox_`abbr_`abr_`ab r_`abLrҀ_`absdrto_launcherManager_`abQkr_`abPtrށ _`abVr_á&%"#-4(1$!#ہ8_Bring All to Front_arrangeInFront:67_NSNibControlConnector;^NSNibConnector_a&+(#-4*1)XMinimizeQm_performMiniaturize:_`a &0-.-4(1/!#8XAbout..._orderFrontStandardAboutPanel:_`a| &5x2 .-4413_IWAD configuration...Q,_openConfigWindow:_`a &:7!"$.-4918THideQhUhide:_`a* ,&?<.235.-4>1=TQuitQqZterminate:_`a; =&CA?!DF.-491B[Hide Others_hideOtherApplications:_`aK M&GEOTV.-4(1FXShow All_unhideAllApplications:_a[\&KI^ce#-4(1JTZoom\performZoom:_`a|}&5xJ_`aos&Nt\Wlaunch:_`aus&PtaYrunSetup:_`a{Y&R_setButtonClicked:_`a{b&R_`a{&R_`a{!&R_`a{M&R_`a|&Xx_closeConfigWindow:_a&^Z[-4]1\!#8SCutQxTcut:_a&c`[-4b1aTCopyQcUcopy:_a&he[-4g1fUPasteQvVpaste:_aЁ&lj[-4(1kVDeleteWdelete:_a߁&qn[-4p1oTUndoQzUundo:_a&vs[-4u1tZSelect AllQaZselectAll:_a&{x[-4z1yTRedoQZUredo:_`as&t}.-41~_Command Prompt...Qt]openTerminal:_`as!&t#$'(*-41!,#./8\IntroductionQ?[openREADME:_`a5s7&t$=?-4(1\Set up guide\openINSTALL:_`aDsF&t$LN-4(1_Command line reference\openCMDLINE:_`aSsU&t$[]-4(1_More documentation..._openDocumentation:_`absd&t$jl-4(1_Software license\openCOPYING:_`a5s&t_`a{tO&R _`a{kT&R_`a{N&RAůd9,~%;!M>|)L7|=Q\!b({SD  tYXdUfTMO}zRVUsNM kz$ZPVmKF$V!V}> $ UV>OP     |$  >  >>>V{ >> $ >   Vz VKV> QDSLM>$~RN.a󀘁[ʀ[́.+.J[́.#[̀ۀށƀ##.;.̀\.̀́[̀#̀̀[..T́.[[΀̀%ҁ.Ձ#.́PA sůd9,~%;!M>|)L7| =Q\!b({SD  tYXdUfTMO}zRVUsNM kz$ZPVmKF ? @ B C D E F G H I J K L M N O P Q R S T U V W Xv Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~Ɂʁˁ́́΁ρЁсҁӁԁՁցׁ؁ـyځہ܁݁ށ߁p      !"#u$%&'()*+,-./0123456789:;<=>?@ABCDEFGH_GStatic Text (Final Doom: Plutonia Experiment location (plutonia.wad): )_Menu Item (Software license)_Text Field Cell-6_Button Cell (Set...)_Menu Item (Quit)_Button Cell (Close)_KText Field Cell (Final Doom: Plutonia Experiment location (plutonia.wad): )_&Static Text (Command line arguments: )_0Text Field Cell (Doom IWAD location (doom.wad):)]Menu (Window)_Button Cell (Run Setup Tool...)_Text Field Cell-3_!Square Textured Button (Set...)-4_Menu Item (Undo)[Menu (Edit)_Button Cell (Set...)-6TViewWTNTIWAD_Tab View Item (Other games)_Menu Item (Delete)\Text Field-1_Menu Item (Set up guide)_Image View (128x128)[Separator-3_Button Cell (Set...)-4_Push Button (Run Setup Tool...)\File's Owner_Menu Item (Game name)_Menu Item (Hide Others)_Button Cell (Configure...)[Separator-2\Text Field-2[Separator-4_Menu Item (Zoom)_Menu Item (Copy)\PlutoniaIWAD_Menu Item (Introduction)YDoom2IWAD_5Text Field Cell (Strife IWAD location (strife1.wad):)]Pop Up Button_2Static Text (Heretic IWAD location (heretic.wad):)_Button Cell (Set...)-2_Text Field Cell-4_Menu (Launcher)_Launcher WindowVView-1_!Square Textured Button (Set...)-5_Menu Item (Minimize)_Menu Item (Window)_Configuration Window\Text Field-5YSeparator_!Menu Item (IWAD configuration...)_Menu Item (Help)\Text Field-6YHexenIWADYDoom1IWAD^Content View-1_Image Cell (128x128)_Push Button (Close)_Button Cell (Set...)-7[Separator-1_Text Field Cell-7_Menu Item (About...)XChexIWAD_1Static Text (Strife IWAD location (strife1.wad):)_,Static Text (Doom IWAD location (doom.wad):)_Menu Item (Edit)_4Text Field Cell (Doom II IWAD location (doom2.wad):)ZStrifeIWAD_Button Cell (Launch Game)_Menu Item (Command Prompt...)_Square Textured Button (Set...)_Selected Tab View Item (Doom)_!Square Textured Button (Set...)-1_Menu (Services)_Menu Item (Redo)_!Square Textured Button (Set...)-2_Text Field Cell-5_%Square Textured Button (Configure...)_Pop Up Button Cell (Game name)[Button Cell_0Static Text (Doom II IWAD location (doom2.wad):)_Text Field Cell-8_.Static Text (Hexen IWAD location (hexen.wad):)\Text Field-3_Button Cell (Set...)-5_!Square Textured Button (Set...)-6_Menu Item (Select All)_!Menu Item (More documentation...)_=Static Text (Final Doom: TNT: Evilution location (tnt.wad): )_ Top Tab View (Doom, Other games)_Menu Item (Services)_Menu Item (Hide)_Text Field Cell_Menu Item (Launcher)_!Square Textured Button (Set...)-3_Menu Item (Show All)\Text Field-7[HereticIWAD_AText Field Cell (Final Doom: TNT: Evilution location (tnt.wad): )_Menu Item (Cut)[Application_Static Text (Select a game: )[Menu (Help)_Menu Item (Paste)_!Text Field Cell (Select a game: )_!Square Textured Button (Set...)-7ZText Field_6Text Field Cell (Chex Quest IWAD location (chex.wad):)_Push Button (Launch Game)\Text Field-4\Text Field-8_Menu (OtherViews)[Help Button_Text Field Cell-2\Content View_6Text Field Cell (Heretic IWAD location (heretic.wad):)_Text Field Cell-1[Separator-5_Button Cell (Set...)-1_Menu Item (Bring All to Front)[Separator-6_2Static Text (Chex Quest IWAD location (chex.wad):)_"Menu Item (Command line reference)_*Text Field Cell (Command line arguments: )_2Text Field Cell (Hexen IWAD location (hexen.wad):)_Button Cell (Set...)-3A ŠA ŠA ůG,A]tIY'\>\O|4dK[K9T-, MO&3kN( })V1ZUH.DTSm*5 QBV{C$%(V!LXz9N7#=%UP$d~ZJ!>2?bXU)Q:|RzFMM<PY@DW=/;0MfSs+LE 6R;8F7Q<@ +T}x́Iۀ;V-}〱΁V`쀸"TEd{._񀬀JƀS %*|Ԁ2Dj#ځHwWe(݀7؁n,^isaoPЁU1n6sEʀm\ xrY怞ՁZ'#ށ;LA [RwctҁÁM!LׁOA Ɂů                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~  MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁   \%TJ:|@ESNU82B9; y FAZ !vRr W-zVM~K3Ys "#G9={Qw6%\}xOPI>qLX'H[uAx I7A LŠA OŠ67 Q R^NSIBObjectData Q;_NSKeyedArchiver U V]IB.objectdata"+5:?ci 0>KR\gu(*8ALUgnw    ) 6 @ Y f    & / 1 6 U d   $ . 6 = > @ B D G I K M f  # * 3 5 7 @ C P Y ` e z      ! 4 A C F O a j w ~ Ti{(:IKTY\^`bdfgiknoprt '2@MUW\^`bdfkmo|/8CHQS^gilnw (1Zeqrtuwy|~Ijs    ,3:COZ{|~ -4=Hijlnpsuwy  -Rfotvxz|~7lnw+-2;@BDFHJLNPdmop{wy{}  19GPRTVXaces|#%'6EVXZ\^k|~!#%')+-/468Shqs| "%')+Cxz(*/8=?ACEGIKM!#%.0IKMOQSUWY[]_a  $ % ' ) + . 0 2 4 M r { ! !!!!!!#!%!'!)!+!-!/!2!4!;!\!]!_!a!c!f!h!j!l!!!!!!!!!!!""""" " """"+"P"Y"^"`"b"d"f"h"i"k"""""""""""""""##### # # ###3#4#6#8#:#=#?#A#C#\#}##################$$3$<$A$C$E$G$I$K$L$N$o$p$r$t$v$y${$}$$$$$$$$$$$$$$$$%%%%%%%!%#%%%=%^%c%h%j%l%n%p%r%t%%%%%%%%%%%&&'&,&.&0&2&4&6&7&9&Z&[&]&_&a&d&f&h&j&&&&&&&&&&&&&&&&''''!'#'%'>'H'O'\'^'`'b'd'f'h'j'o'x'''''''''''''''''''(((( ( (((((((((9(:(<(>(@(C(E(G(_(((((((((((((((((())%).)3)5)7)9);)=)>)@)])^)`)b)d)g)i)k)))))))))))))))))***** * *#*X*Z*_*h*m*o*q*s*u*w*y*{*~************++ ++++++++++!+>+?+A+C+E+H+J+L+e+++++++++++++++++++,,,,, ,",$,&,',),F,G,I,K,M,P,R,T,m,,,,,,,,,,,,,,,,,,- -,-1-6-8-:-<->-@-B-i------------------..... .'.(.*.,...1.3.5.N.o.t.y.{.}..............///!/#/%/'/)/+/,/./G/S/\/f/o/y/////////////0000000&0(0*000A0C0F0I0K0T0V0X0`0q0s0v0y0{0000000000000000000000011 1 111&1(1+1.10191;1=1A1R1T1W1Y1\1p1111111111111111111111111222222"2325282:2=2N2P2S2U2X2e2h2k2n222222222222222223 33!3.3134373X3]3`3b3d3g3l3n3q3z3|333333333333333333344#44474:4<4?4`4e4h4j4l4o4t4v4y44444444444444444555 555!5#5&5G5L5O5Q5S5V5[5]5`5e5g5r555555555555555556666 6*6/626466686=6?6B6K6d6q6t6w6z6666666666666666666667777777(797<7?7B7D7X7i7l7o7r7t777777777777777777777888 8 8.8386888:8=8B8D8G8T8W8Y8\8`8b8g8t8w8z8}8888888888888888899999 999999#909396999Z9_9b9d9f9h9m9o9r9y999999999999999999999:::::!:$:):+:.:9:;:F:S:V:Y:\:}:::::::::::::::::::::::::; ;;;.;1;4;6;9;Z;_;b;d;f;i;n;p;s;;;;;;;;;;;;;;;;;;;;;<<>>>>>>>>>????? ?????????!?#?&?(?*?,?/?1?4?6?9?@G@J@M@P@S@|@@@@@@@@@@@@@@@@@@@@@@@@@AAA,A.A3A6A8A:AACAEAnApAuAxAzA|A~AAAAAAAAAAAAAAAAAAAAAABBBB BBBBBBCBEBJBMBOBQBSBTBUBZB\BBBBBBBBBBBBBBBBBBBBBBBCCCCCCCFCHCJCLCMCNCSCUCbCCCCCCCCCCCCCCCCCCDDDD D D DDDDDD-D6D8DEDHDKDNDQDTDWD|D~DDDDDDDDDDDDDDDDDDDDDDEE E EEEEE EIELEQETEWEYE[E]EbEdEgEvEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFGGGG G GGGGGGGGG!G#G%G(G*G,G.G1G4G6G8G;G>GAGCGEGGGIGKGMGOGRGTGWGYG[G]G_GbGdGfGhGjGmGoGqGsGvGyG{G}GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGIII I IIIIIIIII I"I%I(I*I,I.I1I3I6I8I;I=I@IBIDIFIHIKIMIPIRIUIXI[I^IaIdIfIhIjIlInIqIsIuIwIzI}IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIJJJJ J JJJJJJJJJJ!J#J%J'J*J,J/J2J4J7J9J;J=JFJIKTKWKZK]K`KcKfKiKlKoKrKuKxK{K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKLLLL L LLLLLLL!L$L'L*L-L0L3L6L9LPQP^PyPPPPQQ+Q=QOQVQzQQQQQQR RR"R,R;RRRhRRRRRRS$S7SnSySSSSTT-T@TdTxTTTUUUEURUkUUUV V/VFVYVkVVVVVWW,W8WXWdWxWWWXX X-X:XNXZXnX{XXXXYYYOYtYYYYYYZZZ ZZ[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\\\\\ \ \\\\\\\\ \"\$\&\(\+\.\1\4\6\8\;\>\@\B\D\G\I\K\M\P\S\U\X\[\]\_\b\d\f\h\k\n\p\r\t\v\x\{\~\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]]]] ] ]]]]]]]]!]#]&])],]/]2]5]7]:]=]?]A]D]F]I]L]N]P]R]U]W]Z]]]`]b]e]g]j]l]n]q]t]w]]___ _ _______"_%_(_+_._1_4_7_:_=_@_C_F_I_L_O_R_U_X_[_^_a_d_g_j_m_p_s_v_y_|___________________________________________```` ` ```````!`$`'`*`-`0`3`6`9`<`?`B`E`H`K`N`Q`T`W`Z`]```c`f`i`l`o`r`u`x`{`~```````````````````````````````````````````aaaa aaaaaaa a#a&a)a,a/a2a5a8a;a>aAaCaEaGaJaMaPaRaUaWaYa[a]a_abaeahajamaoarauaxaza|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb b bbbbbbbb"b%b(b+b-b/b2b4b7b9bځ WcQځ \zMہ 骉~܁ ܁߀܁ ܁ ځԃ Ѽ 彪 krɯ g2Ӂ܀l!3܁ `?7Jہ tNNUہ }7W,܁ ckZ܁ ܁р݁ ܁ہӆ ˵ ᷪ qyĩ o0G΁ q1/Gف؀`D.\ׁ l?/Y؁ jځ x $(ځ 37ہ _ہ ہ؁ҁӀӲs8mkICN#il32 دrǫ#zâ)1݂榅 1Nހ<L#U JF5=\ŀSR2M[ǂa)^FW)cɁ k5kZb5jʂ j4tof4h́n0zj0g {?x?nЁɐ^^ʦ}}}Ձ ̸ ˀ ڲCɯW­Ť &f訅 #7xށ /">Ɓ>*#-*EǂI<3<$"$=ʀ)*%˂22(́=$82̀H $" 9 Q-/o Z:JbGGf gP~m̯  ⾐l8mkich#Hih32 ˷ 岣 ﹥ͼⷢͤ֫͌jĹϡ͎ȴ̥͏$݅Ş̑BӅ֟̓`Ԅߟ̗Lrք埉̛ .TdI vׄ坉̠2I!ez؄杉̠6U/b"xڄ睉̥##;_"6AA@NԄ䛉 VMMHMLք噉OYYR WYXJ؀昉Uee\addRځ昉Zqqgjpp[ۂ昉^}}r  q||c݃斉cxwn$ gttfބ斉f $#3߄斉j")'4攉m$.+ 4甉r '30:甉x)84?甉|-0A璉}"!"F璉+-i璉Ԃ3>|萉ԅ<X萉 ՆEFo萉 ՇMT菉ֈOOe菉ֈPu 菉֋ 草ָ草狉狉 ݈h8mk it32@AņĀÄ ɰ ԲЩ߀ހ݀܀ۀ ۳߀ހ݀܀ۀڀ ߀ހ݀܀ۀڀǣ߀ހ݀܀ـ Ȣ߀ހ݀܁ۀڀ ʣ ߁ހ݀܀ۀڀɀʢ ʿ߁ހ݀܁ۀʀǠ ʾ߀ހ݁܀ۀ́āʾ߁ހ݀܁ۀ΁غʾļ߁ހ݁܀ۀتʾ•ûހ߁ހ݁܀ہ¾Рʾ1߀߀ށ݀܁ĿڿʽKŽ߀ށ݁܀ۀſ٣ʾgú߁ހ݁܀ہ߿ʾ¹߁ށ݁܁¿ۡʾ (݀ށ݁܆ ķ㹀ʽ AŽ߁ށ݇܅еʀɽ]úށݓ݀ʾ {·ڀݔ顜ɽ ݂ؑɾ 7ǽؔ񰛛ʽ Sĺڃތɽ p¸ݐʽ ڑɽ.ijۊ߄ɽ:Ĵۑɽ#V:ŵ܀ɽÄ$ħO ;ǵ܏ʽDŽ %OI ;ȵܑɽ˄ %TB ;ʶ݇ɽ΄&\Q<̶ݑɽ҄' ^<ϷޑɽՄ(ƒ%e<ѷߍɽ؄)Ã*j=Ӹߑɽۄ*Ń/q>ոɽ!+ƃ5w>ֹʽ'"+ǃ:|!?عɽ.%-ȃ?$@غɽ3(.ɃD'@ۺʾ9+/ʃI*Aܻʾ?.0ON-B޻ʾE1US0C˾J43[X3D˾P766a]6E̿U:9gb9F̿Z=<mg;G̿90rl09:0xq06;0}v04<0{02=00>00µ@00߆µC3†3µL;>;öSBHBö\JSJödR^RölZgZötbmbö{iuiķ탄qqķ슄yyķ쒄Ÿ뙄Ÿ렄Ÿ꧔Ź뮓 ƹ굑 ƹ꼐 ƹ ƺɎ Ǻό Ǻ֋ Ǻ܊ Ǻ Ǻ Ⱥ Ⱥ ȺȺȺ Ⱥ ȺȺȺ Ⱥ Ⱥ  ԀՌƌĆń ̳ ֵ ԫ߀ށ ޶߀ހ݀ ä߀ށ ʥ߀ހ݁ ̥߁ހ݀ ͥ ߁ހ̀Τ߁ހ̀ʣͿ߀ށ΁ǁ ̿߀ހҁܼͿs@k߀ށۭ̿u35B}߁ށӣ̿w0  ?1('5hߑ˾f-/B57,9j˾j13E7;100Hs̾zECDR&>LCLw˾~KHIU*@PGO{˾OLY.BSLS̿UQ[3EVPW̿ZU^7GZU[̿`Za<;J^Y^d^dA@Ma^cjcfEDOeccbfphgiKIShgkrihhlOMUjgfilSQXaoXV\f´p\Z_lµra^bp´tfcfuöwjgizöyolmö zspqö)|wtö0!{y&!ö8(}0(ķ@/9/ķH6B6ķO=G=ĸWDODŸ_LjLŸeS[SŸlZpZƹrafaƹyhqhiƹoyƹ̇wǺ̍~ Ǻ˓ Ǻ̙ Ǻ̟ Ǻ˦ Ⱥˬ Ⱥ̱ Ⱥ̷ Ⱥ̽ Ⱥ† ȻÄ Ȼà Ȼ ȻÀ ȻÿȻĿȻȻ Ȼ Ⱥ  ՀՎ Ƭ Ү ͥހ݀܂ڀـ؀ د߀ހ݀ۀڀـ׀ ڼ܁ހ݀܀ۀڀ؀ր ß߀ހ݀܀ڀـ؀׀ ş߀ހ݀܀ۀڀـ؀ր ǟ ߂ހ݀܀ۀڀـ؀׀ƀƞ Ƚځ߀ށ܀ہـ؀׀ǀĝ ȼ߁ހ݀܁ڀـ؁ȁȻ߀ށ݀܀ۀڀـ؀́նȼi0`ހ݀܀ۀڀـ؀׀ԧǻj144sހ݁܀ۀځـ؀Ŀ̝ȼm2004:݀܀ہڀـ؀׼Ȼo30 4Hـ݀܁ۀڀف½՟ǻq30 3Yڀ܁ۀڀف؀¾ܼǻs3033k܁ۀځفÿٞǻv40 48~ւہڀن ീǻy40 4BہڀُͳȀǻz40 13S׀ۀڎقڀǻ}50 33fـڔ睘ǻ60 55wՋڈ쫘ǻ60 4?Քﭘǻ70 16N׀ۏ󮘘ǻ80 35aڏǻ:0 178sבǻ;019O؋܃Ǻ<13Fؑǻ>65/3656Fن݈Ǻ?:8.'.6:HّǻA?=,)/:?>HڑǺBC@-*0=CBIڎހǻCHE.,>GEIڑǺCLI-"?LJI܉߅ǺCQM-!@PMCܑǻEUQ, BURE݄ǺGZV+ CYVFݐǻH^[* C^ZHݑǺJbc`)Cb^JތǺKfgd(BgcKޑǻMjlj'@kgMǻOmpn&?pkNȼPrut%=tpPȼRuyx$;yuRȼSx~}$8}ySɽU{#6~UɽX#3VʾY" 0YʾN!QʾP#"S˾S$%$V˾U&'&X̿X()'[̿[)+*]̿]*-,_݆` ,/.bލc -1d߁e/3eߊf 05 hߐj17jµl29kµo3;:(kµp$4=5köq'5?>(köp*67köq-! !jöp1%#%jöq4($()k÷p7+2dzķr:.@nķq=2 3Sqķr@5 ;f{ŸrC8 GnŸrF; WrŸrI? DgzŹsLB NoƹrNE \rƹtQH LizƹuTL UpƹtWO arƹuWO Rk{ƺuWO WqƺuWO arƺvXO RjzƺuXOOWpƺwXO`rƺv[jzƺvqƹ~ ƹ ҀӉt8mk@chocolate-doom-chocolate-doom-2.2.1/pkg/osx/Resources/wadfile.png000066400000000000000000000043111257432200600247710ustar00rootroot00000000000000PNG  IHDR00WsRGBbKGD pHYs3tIME yIIDAThMG{gfwgv6q`H#$H(1. $8!q7 CD!a$$X8!19-ll]tq/ҫzﭯW1Λ6n{z ^ͫF IJv򉶁N-y Ȱk0[~ݻE4XX >dI0$c K-Er W]S'ȁn ~+WhZX@3Kd8.i%mc+|Bt8~mnwdf#pa&&/~kׯN $IXY^ux~]},1,//y4orevtXwXȢ "\:ss$&x1"t #{ض}QLbױu]h=i N6=Mq3) c2DQb$If$&j/?_1ObvvfiR"nމw7skAq?3#GX0"u /cu>qZd vBBcFAccݼ{ȁL-4$Dh+~GGp,stri"0lٲ;NN8:#瀝~M@u[=O?CWT1ݤq<8255EP Yj820 T÷/%=;=QDCrTp2MJ)oȱSǶ_FD2q4AK֪M>abJ8 kx8X~WNݠ^;6QfǁIJQMK(J~v4N )Ҋrt$_"`([n淉FuS7.s^pG+37"jijP:&MH6sI[焦pnHcj2s!E0115F!yVٲnJB(ZΨtEi2v 5"-.]‚fd\(D]({%sAsqMYe9}F17OMő?d-ۅl-iGΝOæIkwǭgzaLOU<ڨ)$KqĎǹs?A4FUr$ZrB"`oc[n{(zib<Yd8}=TcBeOvU|_xJ-eGk n”-!g9계:8qQ*tVSOܨ!R}/MIENDB`chocolate-doom-chocolate-doom-2.2.1/pkg/osx/cp-with-libs000077500000000000000000000034501257432200600231310ustar00rootroot00000000000000#!/bin/bash # # Copy a program to the specified destination, along # with libraries it depends upon. src_bin=$1 dest_dir=$2 # Returns true if the specified file is a dylib. is_dylib() { case "$1" in *.dylib) true ;; *) false ;; esac } # Returns true if the specified file is in a system location # (/System or /usr): is_sys_lib() { case "$1" in /System/*) true ;; /usr/*) true ;; *) false ;; esac } # Install the specified file to the location in dest_dir, along with # any libraries it depends upon (recursively): install_with_deps() { local src_file local bin_name local dest_file local lib_name src_file=$1 bin_name=$(basename "$src_file") dest_file="$dest_dir/$bin_name" # Already copied into the package? Don't copy again. # Prevents endless recursion. if [ -e "$dest_file" ]; then return fi echo "Installing $bin_name..." # Copy file into package. cp "$src_file" "$dest_file" # Copy libraries that this file depends on: otool -L "$src_file" | tail -n +2 | sed 's/^.//; s/ (.*//' | while read; do # Don't copy system libraries if is_sys_lib "$REPLY"; then continue fi #echo " - $bin_name depends on $REPLY" # Copy this library into the package, and: # recursively install any libraries that _this_ library depends on: install_with_deps "$REPLY" # Change destination binary to depend on the # copy inside the package: lib_name=$(basename "$REPLY") install_name_tool -change "$REPLY" "@executable_path/$lib_name" \ "$dest_file" done # If this is a library that we have installed, change its id: if is_dylib "$dest_file"; then install_name_tool -id "@executable_path/$bin_name" "$dest_file" fi } # Install the file, and recursively install any libraries: install_with_deps "$src_bin" chocolate-doom-chocolate-doom-2.2.1/pkg/osx/disk/000077500000000000000000000000001257432200600216315ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/pkg/osx/disk/background.png000066400000000000000000001231221257432200600244570ustar00rootroot00000000000000PNG  IHDRPUsRGB pHYs  tIMEf IDATx{yC?PFă0H"AQ!ʒ,EYđY׏q|s֯nG^{rrM,lY;NycI4e*%IQ$I@W;̠P㫪9=3(EOwuuUwoۿwxT_zq9bBtD2o3;Sr1yGι#\M BBrzUm:XXjƶcVbTK\5_vxǶT- f>fk,-FCñ-o9:/mpcLay2npK=r'N@`kw*fk*mUm.I[otJ1x܅3TM^A渌;h\^TjMcO.j^V0U9Jafe;Od>bgfRgi&w3gzSJTռ3G6'N8!|`4ZM2H*4F-R3*%|/9|ĉ'N~ĉ'NIE ➉!c锶[҅Ş~L+|]mϚLik_x\ƭ}g3 p?._>pĉ'A"c}[դ%IR,U6lyGR_;]dͳ"Lgof?g__4E{ҙ/<pEѰE «5kN8q1>'%V% 5yނv@,x5&5Xٱ(Xڙ'ϢxF+1M[u&S|UtԿTֺX9|ĉ'N`an {aca>9Զ73e&b.PRjaܒ-fI41.U> MS7/|]rKtI񚀽g.}Gu["8qĉ8qĉ#)+8i&4뒤  ͬUĭFf۹{0e"d~VlNS~6TGz/[Б8ԼwZ'N8W.*J\Lmhabƕ-imK %jb LY`]#/<^A f?]>pĉ'`:D`gm*%ذZ;hϾ"]iF=b iv h|q^kvq'N'N 6e4)o^"3+4Xݷ VrCZ<̳mTO;76,0M[eyNz9s;JEKqk'N8qAi>̀-)XraE94RMMy5$d$=\R s@lSd5#9C#yb5Ϟ{\kΙUe<:H2S]`ʙT?53b` ܅2z^{s/jY\/g+Zϫpɵ/9|ĉ'Nb+][͔2`BJAni/4;|Rs Bik?C=l<ҦHȪiv>2_]Lw~NM79MR:Bg~s'|ӚLz)XM}jx?]Z{ɵv'N8qS َ E$O#t>ћaۏdnd| E;>4MK{X$W),BY xZU˥? ;U5$Bt!(RE5y\2P?B0$C_ts~Xg9г]Dx 6)dҍ@;P*}t'CZRyͤ熴x*} -/ζeZKX$ſ|U,|'N8q'N8q$(ERJ"z5:#D:)qî0 zL] a7&UЕ%  *Rd0)XěW"Y]N=\#C)'p2|~NӜZ+m;4$7CԺ[2KZgf3ft1TGXӥwC,wb:q ;I=r~jotIՍhkTO9i'tH372E͝^ۏoؖlUإUZR6Kݺ3i!gu(;cbA8q H% <@&!^+$%=u~@Wc%FpJkns*Zr?md0k:M쑩Qy۬ ?m=gVy1yLZwڽd!Y!+^hVw`5B$<=hh$̾#[=H.%= ~ CRK{+l*RB(2Ijpl<Ɵ7?XI;`&: QUjPcBr˙z溼3dH ~tzNbzmZ4 ^4:ATIE#>pĉ'븅pv) $ښȫL1\ $*,:V\ūQ̹Z P55\2|"Ω*VPQ>=ߴ؍HtfgIޚIʵp'}QԲe58^ޫ>zy ,vHZɄqf-~+i.,'8qĉD# c~#Ԃ bR͵ ΀P Ltѓ>7ExԚxVqC\b*P<$Ij)=^eɝOa>YW&V=fNS.&_X kQT0;o3E?ӝ;] [15R>xŕyKeմ<h(x!xeF[I^+Ѣ=@+0Ʉ (4dt i䄘LN8q$Y7`| 1 u@o2R0@4 @4V6M!=âEr6Xz%*nsLP8WŷYRkf6V3cUĚl3okgF.;3lO:Ԟk2鹩 Ez'͕TUڡ?sRak P9 )٤ հoEHZ䇹Z LaHh ;v'N8{'N8"_t)NRt$3N"tE@GP)TO#2V;b0 Qіc7,ERsAL-@hZgꦜߚ[r67UմYp.IT5N݅Ozxk>s~Ms83NG([ԮZ Äj>-\ }f(6H[|XfM;3*L YC>pĉ'(tyd"QLr(Yx&#c}Ԟdv{qۥ2yE_Y{'E#g59HoJ+MnQDJhF7xU’:E;wSO=m߾a4<n{I/@P:UF=R2DsRA'T ;! /VI]1-NiJim#t a<̓"N,t><'}>pĉ'ś&lc-];-UsJ@N8qn?pĉ'Z$,DSNKƜv [x8i߮ `R0(HxL8 Mx) B::GVfAZ,Pnhg18-u{K/t6N&V2DO; KOuGN hvIE/p=ڍjw7Oz|zN0~T^sY~?+nsS|2wgXH)ZBЦ{sJ+eNRp;C1CM* [{&W!8 Zͪ.i=9n(cD'N8q T$"ЌشPvo_szK$=Yx96 )PM)tvuD `& -M#^<[;KVTdE}Wٌ0$xK^<.q8Ӓǯ"r8W^H}-u {;tKO,V J0Ş8*|ҋ^:3'j8 (ZTOa2T@T9]+hVM !xArF8YN n|ͩ[Uͬ s*eEL̗ՍrF<ڇIO8)oG?/AW^KBxL7չ'I[ɑdz=k_{亗S='jJVoXI& ,2ddoaZa)YAU/ěr*|]]]47MӥA/`e{~3o~-{6k׮@t߹8;M%g-axl`t4a{'0$yr>eV1N 5Fǖ7b*gSl|WpJJ%>Nbݎ߶~>D'Nop뛛я>y'/y|BT99!SWLפ^B2GU+iD"%tw[4m*R#8 H ~n"$E6AKZN4dOH4 t~߭! Dߩ2:MzZm+jи%&#n6 T+2E_ ~e M1+( 2pۃЇQ@*;kkv+ʄiY&LP~ v1Wn潆 XfNcO#uF&LAx xb$UmC| \; 1N('5$^d@S4 o4DRG| ]DË]u@8q2&3yI8%-n?pdn pm/I\^tH䁤H);4XHMtE6h\bOЭu+Ӧa~˃Q2mRtW5'Pf&Q |6Gpjق OlP0S;MwU_t$T x"k&Mg^ܿݛ-~[{ZV# <%Y)fr~eG#ѷE&5拮[I|K%EHȉߦT5'KSl+6$<pc8l<^i87sF8}mN4 xwX9%RP0Pg:Y+Sn]]@O@6 9rZeI7@I(d| =mQP6A'4@>l5.{U`bUF3) sdМdkddjtRһ@i3Jp `NεR?p$C`ő-p IDATg36( ӎNzV^2׼7XP(}UaqdPv;R%SPbUtMh/JyȦ*(n{CpUݮH4F.J5'Ԫՙb13*z l\ِ{qH~z)Rϧ,wj+wΎ= %֦tVk=8Y*{?oݻKwp*U"MiXaIҟ[ 1 t1^>ti /l f7m7m SX8j \X Q!T@VXm;~ZdB/LЇn="Zi 1S6˘xB;N4'm۶ͅ*{O8䥂x2ɍޛѸ&t7빊?Xo 83)‹m}CAH^)V;p"|v+&0N0%R2M"&sĐUkAu[Nmmi*ſ<jq!@F氓 X@iH q"Z)}߿v˟꯾9Jt{_dQBpngjr*i90׼WeVrYo+>z4qLX bdci8{TB h WycT0zVZK)&[Դq27j #8"4@fLHiV H{lA |s%:q\~}Pm %8N̻%o/%8k^$,A, i\%2I@N"" qEF3O<Y/Pz;]`: e6O#sӂ3\C]Ŝ!D"[zy((D!l,q9Ǎ/ԓY)ɂTIG aw)`^dErP'0!\̝dvpE{hx@4Y6N?y GяŽwؿ7q%In|N4M&ݞS5kTj,^ 0Y7v4%rOmRRfV]ĦRsC!rO#cO]+EG@6:dѴ;I7O)0]U078Mwnd._rHqCiS[@xS7veG'ϽǿPTOu(ɵ`Kh߈N ?ҹՎ0΄ Eˣ&8(3lc΄ADd<#1E qtIl;G3aOŘ<vRrN*E%vj W7m1 ֈ=KjJ=^1TCi܏ngϧ k H7Ht18w 0ݷP>n7zB`. /_/OXPU-#9}WhsoHy ': Sdx8 D+蘎~PQbfv(g| #)(D ƄBHYy]woV0r*.?p `LU3PmXu; bZd@Bdi#W͉._v(ɵ4[7eZ\tN&ς>PHh.A)k+!L} }sMRik/>51'%eաUe@LRD}Vt3#^P7ztDRY&p0HSOB^R$J+:0~;w󺙴%÷uϞ=Uq>(NzKYͤ/DH1IM/h^B f1@X_q\} CLbfGy5S[oSy&c8YV~_y@sυ 9AQ[d $Li'{򹴆5 2}Fx ]X:Bݚ хa82I6, $>nE}쐡I+{}tVg zC;< L.^"ZOM)Uŭd`Ih`gZu*df'gż %P|ёȑp*$?ý,wGɎlg ?!1J =4ZB tH+L${X(bAbD_XpdΝ|\(a<]z9RRr#x;1:1Ĩbŵcwx"@מXz&nm<S%ՓЅR2X09&BzIR79b&/f?=p|)62hRN:@ 7 i' [<F<8<+Jx2:`#R.?hE6˳쒕xj=9זy{^WცI4Ϫ)}+P>y bo2@P^{&WKEh}U4C^P^  M KZhP(/qq@*vbnK+[M7T2J81@\/΍*_tSIR%4h`J4a/@dnKtr7?>ݐ̇w;h8:Ƣ;c;jD+čMM:} -x<(I}pTwCOٔVA&Ő%@$ PYt5Vh2MMIvs&!aF7hşB_ *j @7KFT$p<Ōs2J'yr3qu߆VW }{Z>-|IUV҃ 8J֋۴2/h9syI^ЃЯC8s%g}+0+8esuie!*0',]Ν;WaƇNPØ4tIg*?`$pF- z4 joω'N'N{Rsa`bB'U$Nk1ctE\ E4 ߅I E!EK"Vt&?)p3 5|4ʓ8 )zdYRճM%~Ud(;KT˰aj:P(RΟU>b_I=` sAq} +>{VCkf9fx]:흱x7a(ZZѰ֨.7US;+yh4%: _jM7=7ԘqR4qoQvDwEN8q⤀V{ƀa5ҞC@ȁ6SИXTiMywdBSȑ+%+|V#-m鱌L9S ɡS7*I2X E)EmfgNN3`*&P0hT0Sb T`~(_?1'ҧrڄZnGakNJVV9t{ɼϞtUpy:U /R&khi?۞TWk7jRƺA2IGc@%~l?S{ѰaBTyo{ܘƝ7]`\/ ]ڳ) N~0'N9vz'/6>]TZG&~@ 7 5RM(ʆN&9KZHrvbӵH@!ˊA-DZm P~rhue;Hfd,H׵#t]h(%1let&h(^ BC᧚tmy{nƓ'z 'J'-N:w'.t*%B& ODNFr>'y z!L'Rfk\fH Ly:vv$MttěV}#V// N8`}pÎ Wyo̻=x`=bDJSx/'Zf6wÉ wx iP"8@u]ʓ]kWlx\^iSօ i}48@o߾$Μ:n>NAn7BiHDA[ ]2 nГ9Jpv!\mlں ƕW|hoRUg/rd7{?D~='W^%Ҙ>諞؀`0Ԟ4ɼEăڷFiD t:dd(Ǹzk)y] >N!٠U `N4DN".G̹M I+9 M:.:;a ,Znsїֈ&4tq?̀ ._ wѣ|@պ>"#b§e/9yқl3Ξ=[zb KDE(2󌓍e!-5j.<ϔLV]q})$+ +@&m' @4vTnWPbz`m%i*tcJ ׷=ETM 0AښU`4 iϼ<صCISS .^<^",X|6hkZstN̪M+-PjM)D{#%ƆZsMUG⎏B*ϘӧeXҙu |>!xa2 s쵒D![H'%O:ƆB28j*ݒ6dUAb2 R)۷o/I$[B(ڨ%ۦ+B*\粓L]530 vJNQG$q^U Қ1)hӥVFC BdhynEqÊϠt)a"ۆ2[nFӖ(q22*pP <~O}1~Un 5T:c$J mZT7RL ;5| ҲC~zkM򕯰c/x^G?Sw`eMiѨUZIvĞ\g> 7u*l@k='>HO2c4ȈQ?l<?$Mk&ɱ-,CIa@qYA׆lad~/׺ܖ@#3Q)g:l^p'g`^84!p&ȰC#5q׼ɂf3?7F5(n?pE k^d-0͈$3n0HT1HYHE2nlLTgF+ `($Ad!f aY*.S2Dn-ZDF]mG`hi]S dLORdBoZfFĒ`6[ݫ$e09msߥ i {Gr_ȧ?+QYbIK^?aER7|@*]{dx[B`U&h k }Y7< B+G`Y LEtd8~'Mi}x+d p) 8td+!5f*8q2~6'N2>6KjEa{/&2ӈT>jw,b9?BF~rHYOlbr]]`@o#7B0Єhux*J<&z2&gPpz  ijMs~E텫~)C9J8}0@W?RN}u@u.F0~#w \cXjއ )^MzcM )μ0"m2OL9@Ix|ќ{bb}s*D w^RI׃g$Ǚw:t08c< 9w v讶<89B3BRPpE 8:KGZV%m,UTd Q}So>F2TB0/HFoF]sX[LtmPHmBjp] a_iP)KK.҄B{Ҽ3 ! .͉rͻO% ղi`#?F1:ff4]32SI6@T)4t f"$ "fB|O641ﯭ0ndLgpr<`ZTY]y(Bl骳 Rt#ͩt$|=`ݞ/-VX?=2IrSEȏJO?wsM:ݸgRJ1[fB춙̜zD:t_{ԵGڽCF#)'.z^|P\P>_xeHql^lTr_gΜ\i'pm4fbgw_ VٞQ*8k'Nݫػ&mntKL~ISa玙[mnp]"ԱSBC<Hd#i'aK"EPSb-O)<1DSAU xxQH х6ҭE{J#@Hs2!T laZmVSI49 7Fԕ!a<]U_bN }p @ pvdgi/kk?z~OrN {u';QR|vp<`a*Ci+JR儗N=ZOS akzϓh++V3i_>#JZD 3ZHi8aA}͋2$ȼNZ0?Qto1'@r +#$) T0Vg@"453Z]Lh%9&gN%aur(mgӑQdѸʯ 0)/<[5-@UxFtel0'u(IKV]Kn*VUrE6ރ~xYfբT׫  vp#g|zs,wG 0kQ` F?`t8zG}m[]_0T}4VlR&^o)^|6%Vu qk=;Ƚ{dei0M>YmĨd(P攸4^ zgbuM|/x)u8ۗ|kǞ@*%=T>ǏäLW?eG|4'N8q8qĉ C2ӐVr3y!$ƈ3)?m+cz5 aJŸ,)T=/l[z׭j.M5 ?;4ڈy۴5 ȼf )R7\>d q:۹esܼ Ԓ߫;)}X`׸(sߞym;Fȝmj݂)l$ȼr_e!/g+5.X|f8%h?\__@ }tZ[Di<˘7ޟ0xTf*TŃ|Y'b=N|rlnݠ \I-Ak{8}l t'N@ k(")Ik;iN֡23')'C^$~ꚑ ߂7ڤjh{OfI aU1cFMS[]uP& TB=>핼o+$q%; פL&]W|qsS'!,Z\++XA[722,]Q+=,d^gJ Xg&?.R: R.\W]5ZaqkzXٗ)V$ð@DC<U KIoENL:R_D}=HYUE< T6Wyw?NxV F'N8q"'N8q<{Ȝs ,ô* Z]ӡPdY0qdAbEbWyr AZVKqZȸ@-DJ^\ׁkzpR/PE`0)BQoj3|ƙշs]_,qaՈ8עd=8Fvt\ L4m0s;>Q=Z5'¹"9姾jsVb {h֠d'bT?<% +UE}|`0"7!sP"#Q$ yts yM)R@֞3u#[<%0䰽r)?V[@GDowlJ.\8q'NdȢɆc9-/"Mqkh:ɋTN@ NAd{/]h fJwǞU7xZAsO ˝OMl5^U;=ς-WN5qTUnҫkgڢ%jsI*(RVd 4rg %谤\[uwƒ.)/9h/"x&﹀8wi,m߂QKȬ?CWn"f˫EsLw=gY x|>}?rnxlJ`E7^pr8|ĉ'N >H1ήV)6\yOzdjP ݶ2B ?NL$+xU ]NG]\s:#4V@Y-0 Mks3NPR*K7\\A-^ 5oӴr%@粔aܬ[^xK;P&En;ݖ!jt2ݼ6 =Sld'T )/携W{>]V &dBB<\Fջ馛x0N4q167Bv)cLn`J=;s IhNH? wd۶m^x7&MAe?>{#=.]/lnUw }vG_Sg}IJy׮_v^:tO>y(Ri/{?]~0sorLF gϞ__v4zG;vOq\wpoidƪ* `# ! H{!D]H)VVVBpݓÉ$1w@+gT$Y>J`؏ nHBڴ>ΔSFaGV0&GK؅tԣ g-_9@=/΂Jns5gZ]MW_.:C_}ɏ, TWgΝ~_O=_~*k& / _Vӹ>%EɡJG?7r:{{o--ZF~q! ;ox̩os/R낷Le)$Ne"˥tבJbV|g#co08]F$=zz~_k6& l4>;ck_0 |_զ=G1gI`uKA)C@bXg#iLԮ+?7Lv]2m?ׯz]0+8CG_z#5b0q(͋,4]Q2KeT'*jv[qild%_(,O3O3_"OX#yjb(E&A4ID2Ks_Qu]HZwV4/nH{z7nrd'#*oOK'_Wv^7XpǩSv|or7%}!o۶_J}_͝`ħas?NE WFuXr0\Ny3nf{3L-f)n2oOn$9?7YW E8e7pL(`A&fTWXJrs$zD[[CvL xDyϺq?mn[۫W`˴Dr ܹ@+`Bk6 ɴ @ #˂Vn,'?rwy+o/| k;D8ӯ>|oO>`28%ZaO8^t{1}n9xsF*=cX3ݳ}вPdXypr$TiЛTr.{,_r &}Gg : =xSk4/kzഷ¥n 'cm CR(`p`DWgVbL">]=[(Lu0w@`4anm" RV;I4bI:65p+G+1N4MgZȚꤦ`< ;(wq'Ԙx;^ulv8 8|T@~B#sv\D|Ȅ'O~G)|o|?i~瞻cEX{qB'I<4v;Yd?3+Yc<F(O&)Ig*SI0-cUPy)H ~6+*wh{ָD  ݾ^?rGLX0S6|RDǴ>cMcI2F#ZlI,~(+?07={h}ԟCȀسgO" ofO~۷ϞL[H1g-8q"%|70[ rࣸ\w޷ZrUw[{46!16dž! yB&FPa|@ZPd)?0(Q`fb%I $` $ IeOݾ}Sw>]V]um}hݮSڏ^#k[n;4}G{<|J7:= 99gk#pkk <50eafW:Y{aP,k7!JJ抹`ehwxF8Lٍ7 NPyfل&b<{*g04yuUecg4%' M7y_;LSnЛA8믿B~ǎG+a)o/jhuMr< 4D"Ialz9"jYѰ];EJJ=9+-_yw4i44g,i#&zAF>T3iE5!xwܤ%i0ǹ47$0+`@tڊHu+ b{1vfC39ڳEbw=TY"?8 ]-+m) Tn$n}}mݶ9~ok??>~/X]]Ї>SO=CgΜ'8^{퉓'ocǎ VN>MmUZ}~g27du@:㉂͡]L? E~˓::4zJѳ4S/2UUT:|UVjfH/`DϪEZ!:9 ZoV֠Ykڦa/ZZS+n /vCRbW%}+.Kt1 ZU6!uVoOc~@rt5~EJ˙lp%L7&t#uJĊgZiIfQM'G!.\5M"ъ A\ꢲYCN<"|teeKEs`мäaԠF@ x#6D*#eT*E eTn]nP߀2lΘ_3JUIdZ 2C%邾S_d-b[=ɬ8@]fPIeh3<zb!a2f({\BR1 ֗6O/g6s2]e|p^W0TSReeQW(uyо|VF4$(RhX]b?O6-[)p))^C<3NY7Ω~sz*hI9󡶂j5Pі'q5φFzAb@i/lgYhl̠ٙ7[bj&ԓ$]|p8Dݫ+-/feT0LB6(mu#(kXERɠ )0 ґ2(d EJAQSjU*& Y4s'Ȩ@ m[?Mӕei}>hЄzی^1Jϐ߼G~C[p@S1΋IgʆGhJR'QjigkjԵQc#CZ)xsҢ %-tw SEג z^E9ެ@|l`Tyv NWmls US?*7I܄3< gֶY4` r*[υJU'h*TdB+9k}'*l mPʨgT;|Ħ*ZY,Sn6A Y%QR 97x"`24Mg5$D!s?X8ΏUM'?+JFTp$ %0 6RYuX#հYlҹ"!O)0DAW$gN@D<"otT*QݣpX*eUawG#R? :OUlƱ:?uJ .8 kV?a"H (s3jou@95Qk;KrZ!9죋 ?z595\Hu`\ZYD*/.~^Ωzۢ 40Zab"[Fh:;cQ݂)ZVt4K}kQT{0kaF#^7 9ǫ CjG4UnFǨ%=zVpUTt EUV/JF~oy];KY!)* ocd}C(54.oJ, b1F1Xu)2~&Nʪӳ=Fa(Ǝ, ILxPg#`q5?~uUiK.TrO<BJA_<]#)] P`> h ]A@ TofgPlT@Տ`ٯv ފ!@pG)uNp,1U3+CY r-"!-*3 Ly#TCE%+T[ "B'Y{"j#ov.;Լd\t.HϨT4Iդqs) ЄP%T tӨ/>W'szzGRPХ{Pz!Ԗ6!aE\{9DQ`3 SzC1H8zF>\|Hz^#KlzC>k@ L@ T;@ NSuLnybYL'Ra lN(1&B#riN YPn'ƛ=ddy0MXoS 7S(ѥ[h뛭qYzz׮PmAO?;:\v,6^$uŐNŐ6ebzh14E?@%e$RRT9pz3[gw0(@)`4”vJܮm<(?Jt䩡!6[Ov1)$=]N_?;CeO%nO |[YIl? xrhrӤKũ{:S3JҐ7oR(>陛#zRAAx[ԜY# :yz1t-\z@[JUtƔ׫(%,oCQ*, E?Go],ySO \?[|ූbL?_ItG;_||Xh۵N@ \B VWz}k+oW,<"}'pppԃyyq oƮW]ع9wv]owo~K/6{ &us+pG>񃧶/f/逩(暭7rǛNA>q?mIM.+Cy#e Ӄ%S:Icó+G???ץK~x//[|9?w3}g|rF^S~?/m_q3>oԻ~m@\H(w_՛A.>/)/٧fpHxof_|WH'3 #t%&|J5ZQIՔ Q9?׿}oƯmlWb>JFG=z|{[ƻE<\#襴S:I^$X{{a?z򪧞y_|7 hC:;V.Qp^?_?>̳yǃKϼ^s\*;oVW|yܯ{ǎ+5ㆃez'\kZ'JϞk=|S.arrkm}硇r˅ +A&:4^⪭ZWvjRr0Xtx[Diۯ_$}å/m/l_OkuWnƇgɞ;BЭo|~&Y>)yQ~o0_;n}YMA`<ڕou.`X4ӭcuYߚ=w;W.ֹX/C>=׽>~L"D+0/e̳?a ~=l #'p9i{A(y7ƕVD+Gt\YYڊ命|9X,TCsi*ln.q~ 8t8~?'pڎ)?E>'`,zQݺ|ؓO=c\|cy?wzMK [U `c \©l8`nVJI%i]~Lr=$1Za"D] Li0ά:&).\Xg}wu%^3#QY|LY߉=~z/NLUwSnɫ`H6kP:x<df7WE0%.ōVw-huQM6ENON=(mBH[N5wWnʲrIjka& *xn<$ĴJv(Q_ek#{u+;fXų鍍 \`ŋ.6nZb,~߳I톐5lm<}_IZ۩4-cfP%}xX: {v^:?@  @ bp S jO24rq5Tr.4ϓpeIjXz6yٛM! jaJ7/x;e@ L?KHQtʯw_<8E_mƸ;SM9zMIک=wlwj!Ik;]ZkS-&D@6r%u.]NNY\$@ ~`M9-%>g؊6䆽ʈ iW*IꩼH߻Sazv#:I3uue]þ9I[g()==ip`u-Ȗ(E]VM/ \i;Zc4:=婹j]u{4WOk!fzF%Oo'4K"[Id0+\^Ӏ^CķV'fjs3D_kˁ]@ 7%َ 4uVeHv)~|ԩ7mMO[)16st5h˳4;yC|o@%Uu'@ FšI`RfXH6M&߃@Ǔugs7KeeebPYoQnx l2Jcá t&X6@ఌc͠okz!01I9~"IFq a)o'@~7Gea]Tݙ`u^x= qM@ $1L٤Gomy&MY]i-^ݷNtEAkۺDAY$ GK4h83$0GB؂*.eQ:l;mIyC 諭l@ ؗ&uI/!۔)ֻukSkHJ"S`ۿ;՛jD.YS` ҩ6>!wȶZD isE.%פ Hīh)om$}3f4[N)c!N`&ZvI.e>l8e :#ƀ=JӔ mTnjyY~yC w!R 1fM.oW@ .uMa Nag::n9oP (`Jޙknq ]Ti0m@bj9( J m5 f%ԿJd@ XG?m#,Gyc%bulkkkYVÖF#2Ns t:_.Ϡ~Z}6j@ eUBã!  IDAT_j/ @@ b< Yvm U + oO+q]a˩އm6=.A@-n-87k/t`qJj31}KMVN{8۪qz99TFzoxoo8BdAGh4‹>@i( GP98.bPRE IBsx5634}!l:ԱHam;‹H3zʖFƈ Xu! @ X9}44Vk7Tu?];$r$QK> C[Nc%>4O;ѿ_û :K /e[n+e[=mo{o_@ I=)I߬ӔS߯F7gjQ0+ Lr܇:Z-[uøxz<"evvv # GCX< AD{0L&z qiN$te%LiNUpVl x<њ HOmQ:C%n:5BX`d V.)Ty8<@ XH 2\1޻;k:(B}z"+j`6A8;2[]\m~ف0q%'H@vyA'^Tf@ @ r tgЇo4zzq7$yNP"T/0ࠆ/ih v+`HڪyuQ|bm#0J=Y<6 "qCNvܹ8S8k/6%)k1+ K:ۼ=B+m&⬱6~8BOӃgP@ X~_Ͳk@*+h"/esm61xy!Kvʗ8!/Q C6} lLoy%2) +St%&ɚ̢4dT\\ ?Lm+.*/ dRrY+[;$d&2"&8c:\ B6]u4\l]B %@ EOGO')dRa)첶@Q-1_TA@( TGFP{{_EqI: HZ]!1Z4%jq" u}AlXQD~5*@ @@ {?g$́fZ DԞ`tţS1>|7RR- emພ歶 BZOe0QޡYl~4n8ɐKqs3'C5enueZzx>1oUWw|QoHn'v oVVI> pOVny%陕VD7&2xeM<Եùi]`97=ˬ@ pa 7Y-Ffe9r.! hͳoƗLS`W (:Y9 q!(} OPpShót5COTEjXWlTERR<خ嚪H;n59yoKTEjS}"PC Q/t_ƩJ֩*@ AH e/z*ذu@ hΠBOWn^20fwhǣZr'P944!{u~j5G[xFI sa 2UtI\?9.ɒlt`.6leQjp/ .*B' =s5s=R?y5 2 Z'/5\뱅Z͘Vۺ2Sj̢`V̱'?xl4j J"ͧ#u.tjLaEm #5+ˁ,<̧06o(_ZEmVaR4EŔ0h2>a=3ܱNgKJ5z,:eƯ9"tسG۫@ @WQ +Mo(oeer?SVLhrcY\#=݉=- K6PnZ;.WbrŢ=VԾfrgkv4_n݈" g@ gUe˔@1~xjno 뗻IvYca]ngFHqف^8=TBgY!eptFI\ƣ}'~ƣu=!3^Ν:uJ:wܩE]SlL mc#W`psLs4G2r|8ip #z`ba=@YTxg}}K7/Hp~]@ ~  +Ǹmum6{g锎jiѺ[<+ّa/ZVvVx79ՂywOT֣хWp |<=$z_xFia~uD,q2R:'IBkHtcc.]/rS-;;;_#oq3g yzW#{ɂ؜(W)>YW4 YID?YoEXjҭeN\j[%+ЫTY]ɦDY~ $)cq33'5M g'yhg.ׅ˸D C +%C"#zm1 vX+UIU?LXb`^ ^GGd2rrp8 WpP 9(&)Gq{LsbfZ-E>[#746[L&z$c,8cUCS#exʊU_<+@ ~,|[7F<,ݍ̆O7Wњ 9aCj在Ոg~ T |,TVaoR=b)"Jjs$ тnjx7)M;M?N#g8 Q8Fh#BSrRCTy?ZG Ok-ZހW&@U(U@BQ5ހoA\Qu looQ؁24?쭧JJ%". Qq=.6mzʄ'-yBN/@ bcG~[GmxyCDme~ Nv@ɝkU,4PEуQے$2H !'G'Y'{(NAv0˲r^7ޟNNߏDNE2= ]{BCHOd{Hs6yN%p?N'&`O\ja1jp-ƫ86Ia-\+c6Ѭ|_-)x!@ ~<]յنHCindvS\)ɌynMkU @J- pv$䢚ED͕6KP`4S)0:O NNMԘ#ی\"OP5&.bas$ڂ Sd?}=ٮž}IR퉪]#1f"ysYuZ?1)te"O55¨ uvm1V 7iRū3 1jq4ONk=# _=6&l-fL.:h8sybg H ~CFj bGa A]Ȳk%~.[h1 @ i8r䕘kFyŬ[SIg=Gpx@U}sD= iI2G1kVp*]U#&y-O R`H8$0KjZ抅U|V$stev){sTN+0SQ3:0?UYv  T>EuYDN}]Aae4(yBCu(oExkXg:wCFRx)KA=\N1.]R"lV9J[nX[[phmrY#BP('z_F0)}w֒gیxbIAj|ӯ h`-Q 6n,0FQVzcͅGwnCVvj|B/ix6" ե4LJ ̱j"W,P3Emb4ңURI㐠S1{+Ѿ;-xj;mVQ:_sֈa8uk QuS#7ÕZN2MEhc(7FZ=tgJ% j}w${|>KiqteP+Bv| z%t%yt!] +u1D%]@ ~ m/h5ym_ǀ} krYшn'ح\7Ъ뤔Z=\ޞh y8xL%R0}"]ΚhU=yBf}'a'Гvj0@oijpKص֒ ܫPY֡$&GǮRي6"B#ԠJjDK8AU(csR$H?+FP_{3eѵ<.t!@ MvL\Aw?.&$juõ~@o1VΈIDATYUe8&l寫,vTE)yI)IvU~9g]j)WՒ+@ ߔz W Rrrv.Ni'ZC\q7MoMڑXj Wz ) ˕TϝH~:Qf(%j^jN!Q'0Yzv[a,.WTz@ @" -- on run argv set dmgFile to POSIX file (item 1 of argv) set diskName to item 2 of argv set appName to item 3 of argv tell application "Finder" --activate open dmgFile delay 1 set win to the front Finder window set theDisk to disk diskName set the target of win to theDisk -- window options: set bgfile to file "background.png" of theDisk set the bounds of win to {200, 200, 717, 536} set icon size of icon view options of win to 96 set background picture of icon view options of win to bgfile set toolbar visible of win to false -- hide background file: set bgloc to quoted form of POSIX path of (bgfile as text) do shell script "SetFile -a V " & bgloc -- icon positions: set position of file "README" of theDisk to {120, 250} set position of file "Software License" of theDisk to {380, 250} set position of file appName of theDisk to {70, 110} set position of file "Applications" of theDisk to {450, 110} eject theDisk end tell end run chocolate-doom-chocolate-doom-2.2.1/pkg/osx/main.m000066400000000000000000000013201257432200600217750ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "Execute.h" int main(int argc, const char *argv[]) { SetProgramLocation(argv[0]); return NSApplicationMain (argc, argv); } chocolate-doom-chocolate-doom-2.2.1/pkg/win32/000077500000000000000000000000001257432200600210305ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/pkg/win32/GNUmakefile000066400000000000000000000031161257432200600231030ustar00rootroot00000000000000 include ../config.make TOPLEVEL=../.. DOOM_ZIP=$(PROGRAM_PREFIX)doom-$(PACKAGE_VERSION)-win32.zip HERETIC_ZIP=$(PROGRAM_PREFIX)heretic-$(PACKAGE_VERSION)-win32.zip HEXEN_ZIP=$(PROGRAM_PREFIX)hexen-$(PACKAGE_VERSION)-win32.zip STRIFE_ZIP=$(PROGRAM_PREFIX)strife-$(PACKAGE_VERSION)-win32.zip ZIPS=$(DOOM_ZIP) $(HERETIC_ZIP) $(HEXEN_ZIP) $(STRIFE_ZIP) DLL_FILES=$(TOPLEVEL)/src/SDL.dll \ $(TOPLEVEL)/src/SDL_mixer.dll \ $(TOPLEVEL)/src/SDL_net.dll all: $(ZIPS) $(ZIPS): unix2dos $ $@/INSTALL.txt clean: rm -f $(ZIPS) rm -rf staging-* chocolate-doom-chocolate-doom-2.2.1/pkg/win32/README000066400000000000000000000001421257432200600217050ustar00rootroot00000000000000 Makefile to build Windows packages. Requires zip and unix2dos cygwin packages to be installed. chocolate-doom-chocolate-doom-2.2.1/rpm.spec.in000066400000000000000000000060271257432200600213710ustar00rootroot00000000000000 Name: @PACKAGE@ Summary: @PACKAGE_SHORTDESC@ Version: @VERSION@ Release: 1 Source: http://www.chocolate-doom.org/downloads/@VERSION@/@PACKAGE@-@VERSION@.tar.gz URL: @PACKAGE_URL@ Group: Amusements/Games BuildRoot: /var/tmp/@PACKAGE@-buildroot License: @PACKAGE_LICENSE@ Packager: @PACKAGE_MAINTAINER@ <@PACKAGE_BUGREPORT@> Prefix: %{_prefix} Autoreq: 0 Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0 %prep rm -rf $RPM_BUILD_ROOT %setup -q %build ./configure \ --prefix=/usr \ --exec-prefix=/usr \ --bindir=/usr/bin \ --sbindir=/usr/sbin \ --sysconfdir=/etc \ --datadir=/usr/share \ --includedir=/usr/include \ --libdir=/usr/lib \ --libexecdir=/usr/lib \ --localstatedir=/var/lib \ --sharedstatedir=/usr/com \ --mandir=/usr/share/man \ --infodir=/usr/share/info make %install %makeinstall %clean rm -rf $RPM_BUILD_ROOT %description %(sed -n "/==/ q; p " < README) See @PACKAGE_URL@ for more information. %package -n @PROGRAM_PREFIX@heretic Summary: @PACKAGE_SHORTDESC@ (Heretic binaries) Group: Amusements/Games Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0 %files %{_mandir}/man5/@PROGRAM_PREFIX@doom.cfg.5* %{_mandir}/man5/default.cfg.5* %{_mandir}/man6/@PROGRAM_PREFIX@doom.6* %{_mandir}/man6/@PROGRAM_PREFIX@setup.6* %{_mandir}/man6/@PROGRAM_PREFIX@server.6* /usr/share/doc/@PACKAGE@/* /usr/games/@PROGRAM_PREFIX@doom /usr/games/@PROGRAM_PREFIX@server /usr/games/@PROGRAM_PREFIX@doom-setup /usr/share/icons/* /usr/share/applications/* %description -n @PROGRAM_PREFIX@heretic %(sed -n "/==/ q; p " < README) These are the Heretic binaries. See @PACKAGE_URL@ for more information. %files -n @PROGRAM_PREFIX@heretic %{_mandir}/man5/@PROGRAM_PREFIX@heretic.cfg.5* %{_mandir}/man5/heretic.cfg.5* %{_mandir}/man6/@PROGRAM_PREFIX@heretic.6* /usr/share/doc/@PROGRAM_PREFIX@heretic/* /usr/games/@PROGRAM_PREFIX@heretic /usr/games/@PROGRAM_PREFIX@heretic-setup %package -n @PROGRAM_PREFIX@hexen Summary: @PACKAGE_SHORTDESC@ (Hexen binaries) Group: Amusements/Games Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0 %description -n @PROGRAM_PREFIX@hexen %(sed -n "/==/ q; p " < README) These are the Hexen binaries. See @PACKAGE_URL@ for more information. %files -n @PROGRAM_PREFIX@hexen %{_mandir}/man5/@PROGRAM_PREFIX@hexen.cfg.5* %{_mandir}/man5/hexen.cfg.5* %{_mandir}/man6/@PROGRAM_PREFIX@hexen.6* /usr/share/doc/@PROGRAM_PREFIX@hexen/* /usr/games/@PROGRAM_PREFIX@hexen /usr/games/@PROGRAM_PREFIX@hexen-setup %package -n @PROGRAM_PREFIX@strife Summary: @PACKAGE_SHORTDESC@ (Strife binaries) Group: Amusements/Games Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0 %description -n @PROGRAM_PREFIX@strife %(sed -n "/==/ q; p " < README) These are the Strife binaries. See @PACKAGE_URL@ for more information. %files -n @PROGRAM_PREFIX@strife %{_mandir}/man5/@PROGRAM_PREFIX@strife.cfg.5* %{_mandir}/man5/strife.cfg.5* %{_mandir}/man6/@PROGRAM_PREFIX@strife.6* /usr/share/doc/@PROGRAM_PREFIX@strife/* /usr/games/@PROGRAM_PREFIX@strife /usr/games/@PROGRAM_PREFIX@strife-setup chocolate-doom-chocolate-doom-2.2.1/src/000077500000000000000000000000001257432200600200745ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/src/.gitignore000066400000000000000000000004051257432200600220630ustar00rootroot00000000000000Makefile Makefile.in .deps *.rc chocolate-doom chocolate-heretic chocolate-hexen chocolate-server chocolate-strife chocolate-doom-setup chocolate-heretic-setup chocolate-hexen-setup chocolate-strife-setup chocolate-setup *.exe *.desktop *.appdata.xml tags TAGS chocolate-doom-chocolate-doom-2.2.1/src/Makefile.am000066400000000000000000000226761257432200600221450ustar00rootroot00000000000000 SUBDIRS = doom heretic hexen strife setup execgamesdir = ${exec_prefix}/games execgames_PROGRAMS = @PROGRAM_PREFIX@doom \ @PROGRAM_PREFIX@heretic \ @PROGRAM_PREFIX@hexen \ @PROGRAM_PREFIX@strife \ @PROGRAM_PREFIX@server noinst_PROGRAMS = @PROGRAM_PREFIX@setup SETUP_BINARIES = @PROGRAM_PREFIX@doom-setup$(EXEEXT) \ @PROGRAM_PREFIX@heretic-setup$(EXEEXT) \ @PROGRAM_PREFIX@hexen-setup$(EXEEXT) \ @PROGRAM_PREFIX@strife-setup$(EXEEXT) execgames_SCRIPTS = $(SETUP_BINARIES) AM_CFLAGS = -I$(top_srcdir)/textscreen \ -I$(top_srcdir)/opl \ -I$(top_srcdir)/pcsound \ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@ # Common source files used by absolutely everything: COMMON_SOURCE_FILES=\ i_main.c \ i_system.c i_system.h \ m_argv.c m_argv.h \ m_misc.c m_misc.h # Dedicated server (chocolate-server): DEDSERV_FILES=\ d_dedicated.c \ d_mode.c d_mode.h \ i_timer.c i_timer.h \ net_common.c net_common.h \ net_dedicated.c net_dedicated.h \ net_io.c net_io.h \ net_packet.c net_packet.h \ net_sdl.c net_sdl.h \ net_query.c net_query.h \ net_server.c net_server.h \ net_structrw.c net_structrw.h \ z_native.c z_zone.h @PROGRAM_PREFIX@server_SOURCES=$(COMMON_SOURCE_FILES) $(DEDSERV_FILES) @PROGRAM_PREFIX@server_LDADD = @LDFLAGS@ @SDLNET_LIBS@ # Source files used by the game binaries (chocolate-doom, etc.) GAME_SOURCE_FILES=\ d_event.c d_event.h \ doomkeys.h \ doomfeatures.h \ doomtype.h \ d_iwad.c d_iwad.h \ d_loop.c d_loop.h \ d_mode.c d_mode.h \ d_ticcmd.h \ deh_str.c deh_str.h \ i_cdmus.c i_cdmus.h \ i_endoom.c i_endoom.h \ i_joystick.c i_joystick.h \ i_scale.c i_scale.h \ i_swap.h \ i_sound.c i_sound.h \ i_timer.c i_timer.h \ i_video.c i_video.h \ i_videohr.c i_videohr.h \ m_bbox.c m_bbox.h \ m_cheat.c m_cheat.h \ m_config.c m_config.h \ m_controls.c m_controls.h \ m_fixed.c m_fixed.h \ sha1.c sha1.h \ memio.c memio.h \ tables.c tables.h \ v_video.c v_video.h \ v_patch.h \ w_checksum.c w_checksum.h \ w_main.c w_main.h \ w_wad.c w_wad.h \ w_file.c w_file.h \ w_file_stdc.c \ w_file_posix.c \ w_file_win32.c \ z_zone.c z_zone.h # source files needed for FEATURE_DEHACKED FEATURE_DEHACKED_SOURCE_FILES = \ deh_defs.h \ deh_io.c deh_io.h \ deh_main.c deh_main.h \ deh_mapping.c deh_mapping.h \ deh_text.c # source files needed for FEATURE_MULTIPLAYER FEATURE_MULTIPLAYER_SOURCE_FILES= \ aes_prng.c aes_prng.h \ net_client.c net_client.h \ net_common.c net_common.h \ net_dedicated.c net_dedicated.h \ net_defs.h \ net_gui.c net_gui.h \ net_io.c net_io.h \ net_loop.c net_loop.h \ net_packet.c net_packet.h \ net_query.c net_query.h \ net_sdl.c net_sdl.h \ net_server.c net_server.h \ net_structrw.c net_structrw.h # source files needed for FEATURE_WAD_MERGE FEATURE_WAD_MERGE_SOURCE_FILES = \ w_merge.c w_merge.h # source files needed for FEATURE_SOUND FEATURE_SOUND_SOURCE_FILES = \ gusconf.c gusconf.h \ i_pcsound.c \ i_sdlsound.c \ i_sdlmusic.c \ i_oplmusic.c \ midifile.c midifile.h \ mus2mid.c mus2mid.h # Some games support dehacked patches, some don't: SOURCE_FILES = $(COMMON_SOURCE_FILES) \ $(GAME_SOURCE_FILES) \ $(FEATURE_WAD_MERGE_SOURCE_FILES) \ $(FEATURE_SOUND_SOURCE_FILES) \ $(FEATURE_MULTIPLAYER_SOURCE_FILES) SOURCE_FILES_WITH_DEH = $(SOURCE_FILES) \ $(FEATURE_DEHACKED_SOURCE_FILES) EXTRA_LIBS = \ $(top_builddir)/textscreen/libtextscreen.a \ $(top_builddir)/pcsound/libpcsound.a \ $(top_builddir)/opl/libopl.a \ @LDFLAGS@ \ @SDL_LIBS@ \ @SDLMIXER_LIBS@ \ @SDLNET_LIBS@ if HAVE_WINDRES @PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else @PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@doom_LDADD = doom/libdoom.a $(EXTRA_LIBS) if HAVE_WINDRES @PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else @PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@heretic_LDADD = heretic/libheretic.a $(EXTRA_LIBS) if HAVE_WINDRES @PROGRAM_PREFIX@hexen_SOURCES=$(SOURCE_FILES) resource.rc else @PROGRAM_PREFIX@hexen_SOURCES=$(SOURCE_FILES) endif @PROGRAM_PREFIX@hexen_LDADD = hexen/libhexen.a $(EXTRA_LIBS) if HAVE_WINDRES @PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else @PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@strife_LDADD = strife/libstrife.a $(EXTRA_LIBS) $(SETUP_BINARIES): @PROGRAM_PREFIX@setup$(EXEEXT) cp $< $@ # Source files needed for chocolate-setup: SETUP_FILES= \ deh_str.c deh_str.h \ d_mode.c d_mode.h \ d_iwad.c d_iwad.h \ i_timer.c i_timer.h \ m_config.c m_config.h \ m_controls.c m_controls.h \ net_io.c net_io.h \ net_packet.c net_packet.h \ net_sdl.c net_sdl.h \ net_query.c net_query.h \ net_structrw.c net_structrw.h \ z_native.c z_zone.h if HAVE_WINDRES @PROGRAM_PREFIX@setup_SOURCES=$(SETUP_FILES) $(COMMON_SOURCE_FILES) setup-res.rc else @PROGRAM_PREFIX@setup_SOURCES=$(SETUP_FILES) $(COMMON_SOURCE_FILES) endif @PROGRAM_PREFIX@setup_LDADD = setup/libsetup.a \ $(top_builddir)/textscreen/libtextscreen.a \ @LDFLAGS@ @SDL_LIBS@ @SDLMIXER_LIBS@ @SDLNET_LIBS@ EXTRA_DIST = \ icon.c \ doom-screensaver.desktop.in \ manifest.xml appdatadir = $(prefix)/share/appdata appdata_DATA = \ @PROGRAM_PREFIX@doom.appdata.xml \ @PROGRAM_PREFIX@heretic.appdata.xml \ @PROGRAM_PREFIX@hexen.appdata.xml \ @PROGRAM_PREFIX@strife.appdata.xml @PROGRAM_PREFIX@doom.appdata.xml : doom.appdata.xml cp doom.appdata.xml $@ @PROGRAM_PREFIX@heretic.appdata.xml : heretic.appdata.xml cp heretic.appdata.xml $@ @PROGRAM_PREFIX@hexen.appdata.xml : hexen.appdata.xml cp hexen.appdata.xml $@ @PROGRAM_PREFIX@strife.appdata.xml : strife.appdata.xml cp strife.appdata.xml $@ appdir = $(prefix)/share/applications app_DATA = \ @PROGRAM_PREFIX@doom.desktop \ @PROGRAM_PREFIX@heretic.desktop \ @PROGRAM_PREFIX@hexen.desktop \ @PROGRAM_PREFIX@strife.desktop @PROGRAM_PREFIX@doom.desktop : doom.desktop cp doom.desktop $@ @PROGRAM_PREFIX@heretic.desktop : heretic.desktop cp heretic.desktop $@ @PROGRAM_PREFIX@hexen.desktop : hexen.desktop cp hexen.desktop $@ @PROGRAM_PREFIX@strife.desktop : strife.desktop cp strife.desktop $@ screensaverdir = $(prefix)/share/applications/screensavers screensaver_DATA = @PROGRAM_PREFIX@doom-screensaver.desktop @PROGRAM_PREFIX@doom-screensaver.desktop: doom-screensaver.desktop cp doom-screensaver.desktop $@ CLEANFILES = $(execgames_SCRIPTS) $(app_DATA) $(screensaver_DATA) .rc.o: $(WINDRES) $< -o $@ %.o : %.rc $(WINDRES) $< -o $@ if HAVE_PYTHON icon.c : $(top_builddir)/data/doom8.ico $(top_builddir)/data/convert-icon $< $@ endif midiread : midifile.c $(CC) -DTEST $(CFLAGS) @LDFLAGS@ $< -o $@ mus2mid : mus2mid.c memio.c z_native.c i_system.c m_argv.c m_misc.c $(CC) -DSTANDALONE -I$(top_builddir) $(CFLAGS) @LDFLAGS@ $^ -o $@ chocolate-doom-chocolate-doom-2.2.1/src/aes_prng.c000066400000000000000000001226431257432200600220460ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // This implements a cryptographically secure pseudorandom number // generator for implementing secure demos. The approach taken is to // use the AES (Rijndael) stream cipher in "counter" mode, encrypting // an incrementing counter. The cipher key acts as the random seed. // Cryptanalysis of AES used in this way has shown it to be an // effective PRNG (see: Empirical Evidence concerning AES, Hellekalek // & Wegenkittl, 2003). // // AES implementation is taken from the Linux kernel's AES // implementation, found in crypto/aes_generic.c. It has been hacked // up to work independently. // #include #include "aes_prng.h" #include "doomtype.h" #include "i_swap.h" /* * Cryptographic API. * * AES Cipher Algorithm. * * Based on Brian Gladman's code. * * Linux developers: * Alexander Kjeldaas * Herbert Valerio Riedel * Kyle McMartin * Adam J. Richter (conversion to 2.5 API). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * --------------------------------------------------------------------------- * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. * All rights reserved. * * LICENSE TERMS * * The free distribution and use of this software in both source and binary * form is allowed (with or without changes) provided that: * * 1. distributions of this source code include the above copyright * notice, this list of conditions and the following disclaimer; * * 2. distributions in binary form include the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other associated materials; * * 3. the copyright holder's name is not used to endorse products * built using this software without specific written permission. * * ALTERNATIVELY, provided that this notice is retained in full, this product * may be distributed under the terms of the GNU General Public License (GPL), * in which case the provisions of the GPL apply INSTEAD OF those given above. * * DISCLAIMER * * This software is provided 'as is' with no explicit or implied warranties * in respect of its properties, including, but not limited to, correctness * and/or fitness for purpose. * --------------------------------------------------------------------------- */ #define AES_MIN_KEY_SIZE 16 #define AES_MAX_KEY_SIZE 32 #define AES_KEYSIZE_128 16 #define AES_KEYSIZE_192 24 #define AES_KEYSIZE_256 32 #define AES_BLOCK_SIZE 16 #define AES_MAX_KEYLENGTH (15 * 16) #define AES_MAX_KEYLENGTH_U32 (AES_MAX_KEYLENGTH / sizeof(uint32_t)) /* * Please ensure that the first two fields are 16-byte aligned * relative to the start of the structure, i.e., don't move them! */ typedef struct { uint32_t key_enc[AES_MAX_KEYLENGTH_U32]; uint32_t key_dec[AES_MAX_KEYLENGTH_U32]; uint32_t key_length; } aes_context_t; static inline uint8_t get_byte(const uint32_t x, const unsigned n) { return x >> (n << 3); } static const uint32_t rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 }; static const uint32_t crypto_ft_tab[4][256] = { { 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, }, { 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, }, { 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, }, { 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616, } }; static const uint32_t crypto_fl_tab[4][256] = { { 0x00000063, 0x0000007c, 0x00000077, 0x0000007b, 0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5, 0x00000030, 0x00000001, 0x00000067, 0x0000002b, 0x000000fe, 0x000000d7, 0x000000ab, 0x00000076, 0x000000ca, 0x00000082, 0x000000c9, 0x0000007d, 0x000000fa, 0x00000059, 0x00000047, 0x000000f0, 0x000000ad, 0x000000d4, 0x000000a2, 0x000000af, 0x0000009c, 0x000000a4, 0x00000072, 0x000000c0, 0x000000b7, 0x000000fd, 0x00000093, 0x00000026, 0x00000036, 0x0000003f, 0x000000f7, 0x000000cc, 0x00000034, 0x000000a5, 0x000000e5, 0x000000f1, 0x00000071, 0x000000d8, 0x00000031, 0x00000015, 0x00000004, 0x000000c7, 0x00000023, 0x000000c3, 0x00000018, 0x00000096, 0x00000005, 0x0000009a, 0x00000007, 0x00000012, 0x00000080, 0x000000e2, 0x000000eb, 0x00000027, 0x000000b2, 0x00000075, 0x00000009, 0x00000083, 0x0000002c, 0x0000001a, 0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0, 0x00000052, 0x0000003b, 0x000000d6, 0x000000b3, 0x00000029, 0x000000e3, 0x0000002f, 0x00000084, 0x00000053, 0x000000d1, 0x00000000, 0x000000ed, 0x00000020, 0x000000fc, 0x000000b1, 0x0000005b, 0x0000006a, 0x000000cb, 0x000000be, 0x00000039, 0x0000004a, 0x0000004c, 0x00000058, 0x000000cf, 0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb, 0x00000043, 0x0000004d, 0x00000033, 0x00000085, 0x00000045, 0x000000f9, 0x00000002, 0x0000007f, 0x00000050, 0x0000003c, 0x0000009f, 0x000000a8, 0x00000051, 0x000000a3, 0x00000040, 0x0000008f, 0x00000092, 0x0000009d, 0x00000038, 0x000000f5, 0x000000bc, 0x000000b6, 0x000000da, 0x00000021, 0x00000010, 0x000000ff, 0x000000f3, 0x000000d2, 0x000000cd, 0x0000000c, 0x00000013, 0x000000ec, 0x0000005f, 0x00000097, 0x00000044, 0x00000017, 0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d, 0x00000064, 0x0000005d, 0x00000019, 0x00000073, 0x00000060, 0x00000081, 0x0000004f, 0x000000dc, 0x00000022, 0x0000002a, 0x00000090, 0x00000088, 0x00000046, 0x000000ee, 0x000000b8, 0x00000014, 0x000000de, 0x0000005e, 0x0000000b, 0x000000db, 0x000000e0, 0x00000032, 0x0000003a, 0x0000000a, 0x00000049, 0x00000006, 0x00000024, 0x0000005c, 0x000000c2, 0x000000d3, 0x000000ac, 0x00000062, 0x00000091, 0x00000095, 0x000000e4, 0x00000079, 0x000000e7, 0x000000c8, 0x00000037, 0x0000006d, 0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9, 0x0000006c, 0x00000056, 0x000000f4, 0x000000ea, 0x00000065, 0x0000007a, 0x000000ae, 0x00000008, 0x000000ba, 0x00000078, 0x00000025, 0x0000002e, 0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6, 0x000000e8, 0x000000dd, 0x00000074, 0x0000001f, 0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a, 0x00000070, 0x0000003e, 0x000000b5, 0x00000066, 0x00000048, 0x00000003, 0x000000f6, 0x0000000e, 0x00000061, 0x00000035, 0x00000057, 0x000000b9, 0x00000086, 0x000000c1, 0x0000001d, 0x0000009e, 0x000000e1, 0x000000f8, 0x00000098, 0x00000011, 0x00000069, 0x000000d9, 0x0000008e, 0x00000094, 0x0000009b, 0x0000001e, 0x00000087, 0x000000e9, 0x000000ce, 0x00000055, 0x00000028, 0x000000df, 0x0000008c, 0x000000a1, 0x00000089, 0x0000000d, 0x000000bf, 0x000000e6, 0x00000042, 0x00000068, 0x00000041, 0x00000099, 0x0000002d, 0x0000000f, 0x000000b0, 0x00000054, 0x000000bb, 0x00000016, }, { 0x00006300, 0x00007c00, 0x00007700, 0x00007b00, 0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500, 0x00003000, 0x00000100, 0x00006700, 0x00002b00, 0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600, 0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00, 0x0000fa00, 0x00005900, 0x00004700, 0x0000f000, 0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00, 0x00009c00, 0x0000a400, 0x00007200, 0x0000c000, 0x0000b700, 0x0000fd00, 0x00009300, 0x00002600, 0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00, 0x00003400, 0x0000a500, 0x0000e500, 0x0000f100, 0x00007100, 0x0000d800, 0x00003100, 0x00001500, 0x00000400, 0x0000c700, 0x00002300, 0x0000c300, 0x00001800, 0x00009600, 0x00000500, 0x00009a00, 0x00000700, 0x00001200, 0x00008000, 0x0000e200, 0x0000eb00, 0x00002700, 0x0000b200, 0x00007500, 0x00000900, 0x00008300, 0x00002c00, 0x00001a00, 0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000, 0x00005200, 0x00003b00, 0x0000d600, 0x0000b300, 0x00002900, 0x0000e300, 0x00002f00, 0x00008400, 0x00005300, 0x0000d100, 0x00000000, 0x0000ed00, 0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00, 0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900, 0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00, 0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00, 0x00004300, 0x00004d00, 0x00003300, 0x00008500, 0x00004500, 0x0000f900, 0x00000200, 0x00007f00, 0x00005000, 0x00003c00, 0x00009f00, 0x0000a800, 0x00005100, 0x0000a300, 0x00004000, 0x00008f00, 0x00009200, 0x00009d00, 0x00003800, 0x0000f500, 0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100, 0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200, 0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00, 0x00005f00, 0x00009700, 0x00004400, 0x00001700, 0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00, 0x00006400, 0x00005d00, 0x00001900, 0x00007300, 0x00006000, 0x00008100, 0x00004f00, 0x0000dc00, 0x00002200, 0x00002a00, 0x00009000, 0x00008800, 0x00004600, 0x0000ee00, 0x0000b800, 0x00001400, 0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00, 0x0000e000, 0x00003200, 0x00003a00, 0x00000a00, 0x00004900, 0x00000600, 0x00002400, 0x00005c00, 0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200, 0x00009100, 0x00009500, 0x0000e400, 0x00007900, 0x0000e700, 0x0000c800, 0x00003700, 0x00006d00, 0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900, 0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00, 0x00006500, 0x00007a00, 0x0000ae00, 0x00000800, 0x0000ba00, 0x00007800, 0x00002500, 0x00002e00, 0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600, 0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00, 0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00, 0x00007000, 0x00003e00, 0x0000b500, 0x00006600, 0x00004800, 0x00000300, 0x0000f600, 0x00000e00, 0x00006100, 0x00003500, 0x00005700, 0x0000b900, 0x00008600, 0x0000c100, 0x00001d00, 0x00009e00, 0x0000e100, 0x0000f800, 0x00009800, 0x00001100, 0x00006900, 0x0000d900, 0x00008e00, 0x00009400, 0x00009b00, 0x00001e00, 0x00008700, 0x0000e900, 0x0000ce00, 0x00005500, 0x00002800, 0x0000df00, 0x00008c00, 0x0000a100, 0x00008900, 0x00000d00, 0x0000bf00, 0x0000e600, 0x00004200, 0x00006800, 0x00004100, 0x00009900, 0x00002d00, 0x00000f00, 0x0000b000, 0x00005400, 0x0000bb00, 0x00001600, }, { 0x00630000, 0x007c0000, 0x00770000, 0x007b0000, 0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000, 0x00300000, 0x00010000, 0x00670000, 0x002b0000, 0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000, 0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000, 0x00fa0000, 0x00590000, 0x00470000, 0x00f00000, 0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000, 0x009c0000, 0x00a40000, 0x00720000, 0x00c00000, 0x00b70000, 0x00fd0000, 0x00930000, 0x00260000, 0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000, 0x00340000, 0x00a50000, 0x00e50000, 0x00f10000, 0x00710000, 0x00d80000, 0x00310000, 0x00150000, 0x00040000, 0x00c70000, 0x00230000, 0x00c30000, 0x00180000, 0x00960000, 0x00050000, 0x009a0000, 0x00070000, 0x00120000, 0x00800000, 0x00e20000, 0x00eb0000, 0x00270000, 0x00b20000, 0x00750000, 0x00090000, 0x00830000, 0x002c0000, 0x001a0000, 0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000, 0x00520000, 0x003b0000, 0x00d60000, 0x00b30000, 0x00290000, 0x00e30000, 0x002f0000, 0x00840000, 0x00530000, 0x00d10000, 0x00000000, 0x00ed0000, 0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000, 0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000, 0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000, 0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000, 0x00430000, 0x004d0000, 0x00330000, 0x00850000, 0x00450000, 0x00f90000, 0x00020000, 0x007f0000, 0x00500000, 0x003c0000, 0x009f0000, 0x00a80000, 0x00510000, 0x00a30000, 0x00400000, 0x008f0000, 0x00920000, 0x009d0000, 0x00380000, 0x00f50000, 0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000, 0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000, 0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000, 0x005f0000, 0x00970000, 0x00440000, 0x00170000, 0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000, 0x00640000, 0x005d0000, 0x00190000, 0x00730000, 0x00600000, 0x00810000, 0x004f0000, 0x00dc0000, 0x00220000, 0x002a0000, 0x00900000, 0x00880000, 0x00460000, 0x00ee0000, 0x00b80000, 0x00140000, 0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000, 0x00e00000, 0x00320000, 0x003a0000, 0x000a0000, 0x00490000, 0x00060000, 0x00240000, 0x005c0000, 0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000, 0x00910000, 0x00950000, 0x00e40000, 0x00790000, 0x00e70000, 0x00c80000, 0x00370000, 0x006d0000, 0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000, 0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000, 0x00650000, 0x007a0000, 0x00ae0000, 0x00080000, 0x00ba0000, 0x00780000, 0x00250000, 0x002e0000, 0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000, 0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000, 0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000, 0x00700000, 0x003e0000, 0x00b50000, 0x00660000, 0x00480000, 0x00030000, 0x00f60000, 0x000e0000, 0x00610000, 0x00350000, 0x00570000, 0x00b90000, 0x00860000, 0x00c10000, 0x001d0000, 0x009e0000, 0x00e10000, 0x00f80000, 0x00980000, 0x00110000, 0x00690000, 0x00d90000, 0x008e0000, 0x00940000, 0x009b0000, 0x001e0000, 0x00870000, 0x00e90000, 0x00ce0000, 0x00550000, 0x00280000, 0x00df0000, 0x008c0000, 0x00a10000, 0x00890000, 0x000d0000, 0x00bf0000, 0x00e60000, 0x00420000, 0x00680000, 0x00410000, 0x00990000, 0x002d0000, 0x000f0000, 0x00b00000, 0x00540000, 0x00bb0000, 0x00160000, }, { 0x63000000, 0x7c000000, 0x77000000, 0x7b000000, 0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000, 0x30000000, 0x01000000, 0x67000000, 0x2b000000, 0xfe000000, 0xd7000000, 0xab000000, 0x76000000, 0xca000000, 0x82000000, 0xc9000000, 0x7d000000, 0xfa000000, 0x59000000, 0x47000000, 0xf0000000, 0xad000000, 0xd4000000, 0xa2000000, 0xaf000000, 0x9c000000, 0xa4000000, 0x72000000, 0xc0000000, 0xb7000000, 0xfd000000, 0x93000000, 0x26000000, 0x36000000, 0x3f000000, 0xf7000000, 0xcc000000, 0x34000000, 0xa5000000, 0xe5000000, 0xf1000000, 0x71000000, 0xd8000000, 0x31000000, 0x15000000, 0x04000000, 0xc7000000, 0x23000000, 0xc3000000, 0x18000000, 0x96000000, 0x05000000, 0x9a000000, 0x07000000, 0x12000000, 0x80000000, 0xe2000000, 0xeb000000, 0x27000000, 0xb2000000, 0x75000000, 0x09000000, 0x83000000, 0x2c000000, 0x1a000000, 0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000, 0x52000000, 0x3b000000, 0xd6000000, 0xb3000000, 0x29000000, 0xe3000000, 0x2f000000, 0x84000000, 0x53000000, 0xd1000000, 0x00000000, 0xed000000, 0x20000000, 0xfc000000, 0xb1000000, 0x5b000000, 0x6a000000, 0xcb000000, 0xbe000000, 0x39000000, 0x4a000000, 0x4c000000, 0x58000000, 0xcf000000, 0xd0000000, 0xef000000, 0xaa000000, 0xfb000000, 0x43000000, 0x4d000000, 0x33000000, 0x85000000, 0x45000000, 0xf9000000, 0x02000000, 0x7f000000, 0x50000000, 0x3c000000, 0x9f000000, 0xa8000000, 0x51000000, 0xa3000000, 0x40000000, 0x8f000000, 0x92000000, 0x9d000000, 0x38000000, 0xf5000000, 0xbc000000, 0xb6000000, 0xda000000, 0x21000000, 0x10000000, 0xff000000, 0xf3000000, 0xd2000000, 0xcd000000, 0x0c000000, 0x13000000, 0xec000000, 0x5f000000, 0x97000000, 0x44000000, 0x17000000, 0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000, 0x64000000, 0x5d000000, 0x19000000, 0x73000000, 0x60000000, 0x81000000, 0x4f000000, 0xdc000000, 0x22000000, 0x2a000000, 0x90000000, 0x88000000, 0x46000000, 0xee000000, 0xb8000000, 0x14000000, 0xde000000, 0x5e000000, 0x0b000000, 0xdb000000, 0xe0000000, 0x32000000, 0x3a000000, 0x0a000000, 0x49000000, 0x06000000, 0x24000000, 0x5c000000, 0xc2000000, 0xd3000000, 0xac000000, 0x62000000, 0x91000000, 0x95000000, 0xe4000000, 0x79000000, 0xe7000000, 0xc8000000, 0x37000000, 0x6d000000, 0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000, 0x6c000000, 0x56000000, 0xf4000000, 0xea000000, 0x65000000, 0x7a000000, 0xae000000, 0x08000000, 0xba000000, 0x78000000, 0x25000000, 0x2e000000, 0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000, 0xe8000000, 0xdd000000, 0x74000000, 0x1f000000, 0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000, 0x70000000, 0x3e000000, 0xb5000000, 0x66000000, 0x48000000, 0x03000000, 0xf6000000, 0x0e000000, 0x61000000, 0x35000000, 0x57000000, 0xb9000000, 0x86000000, 0xc1000000, 0x1d000000, 0x9e000000, 0xe1000000, 0xf8000000, 0x98000000, 0x11000000, 0x69000000, 0xd9000000, 0x8e000000, 0x94000000, 0x9b000000, 0x1e000000, 0x87000000, 0xe9000000, 0xce000000, 0x55000000, 0x28000000, 0xdf000000, 0x8c000000, 0xa1000000, 0x89000000, 0x0d000000, 0xbf000000, 0xe6000000, 0x42000000, 0x68000000, 0x41000000, 0x99000000, 0x2d000000, 0x0f000000, 0xb0000000, 0x54000000, 0xbb000000, 0x16000000, } }; /* initialise the key schedule from the user supplied key */ static uint32_t aes_ror32(uint32_t word, unsigned int shift) { return (word >> shift) | (word << (32 - shift)); } #define cpu_to_le32(x) SDL_SwapLE32(x) #define le32_to_cpu(x) SDL_SwapLE32(x) #define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) #define imix_col(y, x) do { \ u = star_x(x); \ v = star_x(u); \ w = star_x(v); \ t = w ^ (x); \ (y) = u ^ v ^ w; \ (y) ^= aes_ror32(u ^ t, 8) ^ \ aes_ror32(v ^ t, 16) ^ \ aes_ror32(t, 24); \ } while (0) #define ls_box(x) \ crypto_fl_tab[0][get_byte(x, 0)] ^ \ crypto_fl_tab[1][get_byte(x, 1)] ^ \ crypto_fl_tab[2][get_byte(x, 2)] ^ \ crypto_fl_tab[3][get_byte(x, 3)] #define loop4(i) do { \ t = aes_ror32(t, 8); \ t = ls_box(t) ^ rco_tab[i]; \ t ^= ctx->key_enc[4 * i]; \ ctx->key_enc[4 * i + 4] = t; \ t ^= ctx->key_enc[4 * i + 1]; \ ctx->key_enc[4 * i + 5] = t; \ t ^= ctx->key_enc[4 * i + 2]; \ ctx->key_enc[4 * i + 6] = t; \ t ^= ctx->key_enc[4 * i + 3]; \ ctx->key_enc[4 * i + 7] = t; \ } while (0) #define loop6(i) do { \ t = aes_ror32(t, 8); \ t = ls_box(t) ^ rco_tab[i]; \ t ^= ctx->key_enc[6 * i]; \ ctx->key_enc[6 * i + 6] = t; \ t ^= ctx->key_enc[6 * i + 1]; \ ctx->key_enc[6 * i + 7] = t; \ t ^= ctx->key_enc[6 * i + 2]; \ ctx->key_enc[6 * i + 8] = t; \ t ^= ctx->key_enc[6 * i + 3]; \ ctx->key_enc[6 * i + 9] = t; \ t ^= ctx->key_enc[6 * i + 4]; \ ctx->key_enc[6 * i + 10] = t; \ t ^= ctx->key_enc[6 * i + 5]; \ ctx->key_enc[6 * i + 11] = t; \ } while (0) #define loop8tophalf(i) do { \ t = aes_ror32(t, 8); \ t = ls_box(t) ^ rco_tab[i]; \ t ^= ctx->key_enc[8 * i]; \ ctx->key_enc[8 * i + 8] = t; \ t ^= ctx->key_enc[8 * i + 1]; \ ctx->key_enc[8 * i + 9] = t; \ t ^= ctx->key_enc[8 * i + 2]; \ ctx->key_enc[8 * i + 10] = t; \ t ^= ctx->key_enc[8 * i + 3]; \ ctx->key_enc[8 * i + 11] = t; \ } while (0) #define loop8(i) do { \ loop8tophalf(i); \ t = ctx->key_enc[8 * i + 4] ^ ls_box(t); \ ctx->key_enc[8 * i + 12] = t; \ t ^= ctx->key_enc[8 * i + 5]; \ ctx->key_enc[8 * i + 13] = t; \ t ^= ctx->key_enc[8 * i + 6]; \ ctx->key_enc[8 * i + 14] = t; \ t ^= ctx->key_enc[8 * i + 7]; \ ctx->key_enc[8 * i + 15] = t; \ } while (0) /** * AES_ExpandKey - Expands the AES key as described in FIPS-197 * @ctx: The location where the computed key will be stored. * @in_key: The supplied key. * @key_len: The length of the supplied key. * * Returns 0 on success. The function fails only if an invalid key size (or * pointer) is supplied. * The expanded key size is 240 bytes (max of 14 rounds with a unique 16 bytes * key schedule plus a 16 bytes key which is used before the first round). * The decryption key is prepared for the "Equivalent Inverse Cipher" as * described in FIPS-197. The first slot (16 bytes) of each key (enc or dec) is * for the initial combination, the second slot for the first round and so on. */ static int AES_ExpandKey(aes_context_t *ctx, const uint8_t *in_key, unsigned int key_len) { const uint32_t *key = (const uint32_t *)in_key; uint32_t i, t, u, v, w, j; if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 && key_len != AES_KEYSIZE_256) return -1; ctx->key_length = key_len; ctx->key_dec[key_len + 24] = ctx->key_enc[0] = le32_to_cpu(key[0]); ctx->key_dec[key_len + 25] = ctx->key_enc[1] = le32_to_cpu(key[1]); ctx->key_dec[key_len + 26] = ctx->key_enc[2] = le32_to_cpu(key[2]); ctx->key_dec[key_len + 27] = ctx->key_enc[3] = le32_to_cpu(key[3]); switch (key_len) { case AES_KEYSIZE_128: t = ctx->key_enc[3]; for (i = 0; i < 10; ++i) loop4(i); break; case AES_KEYSIZE_192: ctx->key_enc[4] = le32_to_cpu(key[4]); t = ctx->key_enc[5] = le32_to_cpu(key[5]); for (i = 0; i < 8; ++i) loop6(i); break; case AES_KEYSIZE_256: ctx->key_enc[4] = le32_to_cpu(key[4]); ctx->key_enc[5] = le32_to_cpu(key[5]); ctx->key_enc[6] = le32_to_cpu(key[6]); t = ctx->key_enc[7] = le32_to_cpu(key[7]); for (i = 0; i < 6; ++i) loop8(i); loop8tophalf(i); break; } ctx->key_dec[0] = ctx->key_enc[key_len + 24]; ctx->key_dec[1] = ctx->key_enc[key_len + 25]; ctx->key_dec[2] = ctx->key_enc[key_len + 26]; ctx->key_dec[3] = ctx->key_enc[key_len + 27]; for (i = 4; i < key_len + 24; ++i) { j = key_len + 24 - (i & ~3) + (i & 3); imix_col(ctx->key_dec[j], ctx->key_enc[i]); } return 0; } /** * AES_SetKey - Set the AES key. * @ctx: AES context struct. * @in_key: The input key. * @key_len: The size of the key. * * Returns 0 on success, on failure -1 is returned. * The function uses AES_ExpandKey() to expand the key. */ static int AES_SetKey(aes_context_t *ctx, const uint8_t *in_key, unsigned int key_len) { int ret; ret = AES_ExpandKey(ctx, in_key, key_len); if (!ret) return 0; return -1; } /* encrypt a block of text */ #define f_rn(bo, bi, n, k) do { \ bo[n] = crypto_ft_tab[0][get_byte(bi[n], 0)] ^ \ crypto_ft_tab[1][get_byte(bi[(n + 1) & 3], 1)] ^ \ crypto_ft_tab[2][get_byte(bi[(n + 2) & 3], 2)] ^ \ crypto_ft_tab[3][get_byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \ } while (0) #define f_nround(bo, bi, k) do {\ f_rn(bo, bi, 0, k); \ f_rn(bo, bi, 1, k); \ f_rn(bo, bi, 2, k); \ f_rn(bo, bi, 3, k); \ k += 4; \ } while (0) #define f_rl(bo, bi, n, k) do { \ bo[n] = crypto_fl_tab[0][get_byte(bi[n], 0)] ^ \ crypto_fl_tab[1][get_byte(bi[(n + 1) & 3], 1)] ^ \ crypto_fl_tab[2][get_byte(bi[(n + 2) & 3], 2)] ^ \ crypto_fl_tab[3][get_byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \ } while (0) #define f_lround(bo, bi, k) do {\ f_rl(bo, bi, 0, k); \ f_rl(bo, bi, 1, k); \ f_rl(bo, bi, 2, k); \ f_rl(bo, bi, 3, k); \ } while (0) static void AES_Encrypt(aes_context_t *ctx, uint8_t *out, const uint8_t *in) { const uint32_t *src = (const uint32_t *)in; uint32_t *dst = (uint32_t *)out; uint32_t b0[4], b1[4]; const uint32_t *kp = ctx->key_enc + 4; const int key_len = ctx->key_length; b0[0] = le32_to_cpu(src[0]) ^ ctx->key_enc[0]; b0[1] = le32_to_cpu(src[1]) ^ ctx->key_enc[1]; b0[2] = le32_to_cpu(src[2]) ^ ctx->key_enc[2]; b0[3] = le32_to_cpu(src[3]) ^ ctx->key_enc[3]; if (key_len > 24) { f_nround(b1, b0, kp); f_nround(b0, b1, kp); } if (key_len > 16) { f_nround(b1, b0, kp); f_nround(b0, b1, kp); } f_nround(b1, b0, kp); f_nround(b0, b1, kp); f_nround(b1, b0, kp); f_nround(b0, b1, kp); f_nround(b1, b0, kp); f_nround(b0, b1, kp); f_nround(b1, b0, kp); f_nround(b0, b1, kp); f_nround(b1, b0, kp); f_lround(b0, b1, kp); dst[0] = cpu_to_le32(b0[0]); dst[1] = cpu_to_le32(b0[1]); dst[2] = cpu_to_le32(b0[2]); dst[3] = cpu_to_le32(b0[3]); } static boolean prng_enabled = false; static aes_context_t prng_context; static uint32_t prng_input_counter; static uint32_t prng_values[4]; static unsigned int prng_value_index = 0; // Initialize Pseudo-RNG using the specified 128-bit key. void PRNG_Start(prng_seed_t key) { AES_SetKey(&prng_context, key, sizeof(prng_seed_t)); prng_value_index = 4; prng_input_counter = 0; prng_enabled = true; } void PRNG_Stop(void) { prng_enabled = false; } // Generate a set of new PRNG values by encrypting a new block. static void PRNG_Generate(void) { byte input[16], output[16]; unsigned int i; // Input for the cipher is a consecutively increasing 32-bit counter. for (i = 0; i < 4; ++i) { input[4*i] = prng_input_counter & 0xff; input[4*i + 1] = (prng_input_counter >> 8) & 0xff; input[4*i + 2] = (prng_input_counter >> 16) & 0xff; input[4*i + 3] = (prng_input_counter >> 24) & 0xff; ++prng_input_counter; } AES_Encrypt(&prng_context, output, input); for (i = 0; i < 4; ++i) { prng_values[i] = output[4*i] | (output[4*i + 1] << 8) | (output[4*i + 2] << 16) | (output[4*i + 3] << 24); } prng_value_index = 0; } // Read a random 32-bit integer from the PRNG. unsigned int PRNG_Random(void) { unsigned int result; if (!prng_enabled) { return 0; } if (prng_value_index >= 4) { PRNG_Generate(); } result = prng_values[prng_value_index]; ++prng_value_index; return result; } chocolate-doom-chocolate-doom-2.2.1/src/aes_prng.h000066400000000000000000000016131257432200600220440ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Pseudo-random number generator for secure demos. // #ifndef __AES_PRNG_H__ #define __AES_PRNG_H__ #include "doomtype.h" // Nonce value used as random seed for secure demos. typedef byte prng_seed_t[16]; void PRNG_Start(prng_seed_t seed); void PRNG_Stop(void); unsigned int PRNG_Random(void); #endif /* #ifndef __AES_PRNG_H__ */ chocolate-doom-chocolate-doom-2.2.1/src/d_dedicated.c000066400000000000000000000022401257432200600224470ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Code specific to the standalone dedicated server. // #include #include #include #include "config.h" #include "m_argv.h" #include "net_defs.h" #include "net_dedicated.h" #include "net_server.h" #include "z_zone.h" void NET_CL_Run(void) { // No client present :-) // // This is here because the server code sometimes runs this // to let the client do some processing if it needs to. // In a standalone dedicated server, we don't have a client. } void D_DoomMain(void) { printf(PACKAGE_NAME " standalone dedicated server\n"); Z_Init(); NET_DedicatedServer(); } chocolate-doom-chocolate-doom-2.2.1/src/d_event.c000066400000000000000000000026231257432200600216670ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: Event handling. // // Events are asynchronous inputs generally generated by the game user. // Events can be discarded if no responder claims them // #include #include "d_event.h" #define MAXEVENTS 64 static event_t events[MAXEVENTS]; static int eventhead; static int eventtail; // // D_PostEvent // Called by the I/O functions when input is detected // void D_PostEvent (event_t* ev) { events[eventhead] = *ev; eventhead = (eventhead + 1) % MAXEVENTS; } // Read an event from the queue. event_t *D_PopEvent(void) { event_t *result; // No more events waiting. if (eventtail == eventhead) { return NULL; } result = &events[eventtail]; // Advance to the next event in the queue. eventtail = (eventtail + 1) % MAXEVENTS; return result; } chocolate-doom-chocolate-doom-2.2.1/src/d_event.h000066400000000000000000000061621257432200600216760ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __D_EVENT__ #define __D_EVENT__ #include "doomtype.h" // // Event handling. // // Input event types. typedef enum { ev_keydown, ev_keyup, ev_mouse, ev_joystick, ev_quit } evtype_t; // Event structure. typedef struct { evtype_t type; // Event-related data that depends on the type of event: // // ev_keydown/ev_keyup: // data1: Key code (from doomkeys.h) of the key that was // pressed or released. // data2: Ascii text of the character that was pressed, // shifted appropriately (eg. '$' if 4 was pressed // while shift was held). // // ev_mouse: // data1: Bitfield of buttons currently held down. // (bit 0 = left; bit 1 = right; bit 2 = middle). // data2: X axis mouse movement (turn). // data3: Y axis mouse movement (forward/backward). // // ev_joystick: // data1: Bitfield of buttons currently pressed. // data2: X axis mouse movement (turn). // data3: Y axis mouse movement (forward/backward). // data4: Third axis mouse movement (strafe). int data1, data2, data3, data4; } event_t; // // Button/action code definitions. // typedef enum { // Press "Fire". BT_ATTACK = 1, // Use button, to open doors, activate switches. BT_USE = 2, // Flag: game events, not really buttons. BT_SPECIAL = 128, BT_SPECIALMASK = 3, // Flag, weapon change pending. // If true, the next 3 bits hold weapon num. BT_CHANGE = 4, // The 3bit weapon mask and shift, convenience. BT_WEAPONMASK = (8+16+32), BT_WEAPONSHIFT = 3, // Pause the game. BTS_PAUSE = 1, // Save the game at each console. BTS_SAVEGAME = 2, // Savegame slot numbers // occupy the second byte of buttons. BTS_SAVEMASK = (4+8+16), BTS_SAVESHIFT = 2, } buttoncode_t; // villsa [STRIFE] Strife specific buttons // TODO - not finished typedef enum { // Player view look up BT2_LOOKUP = 1, // Player view look down BT2_LOOKDOWN = 2, // Center player's view BT2_CENTERVIEW = 4, // Use inventory item BT2_INVUSE = 8, // Drop inventory item BT2_INVDROP = 16, // Jump up and down BT2_JUMP = 32, // Use medkit BT2_HEALTH = 128, } buttoncode2_t; // Called by IO functions when input is detected. void D_PostEvent (event_t *ev); // Read an event from the event queue event_t *D_PopEvent(void); #endif chocolate-doom-chocolate-doom-2.2.1/src/d_iwad.c000066400000000000000000000514231257432200600214740ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Search for and locate an IWAD file, and initialize according // to the IWAD type. // #include #include #include #include #include "deh_str.h" #include "doomkeys.h" #include "d_iwad.h" #include "i_system.h" #include "m_argv.h" #include "m_config.h" #include "m_misc.h" #include "w_wad.h" #include "z_zone.h" static const iwad_t iwads[] = { { "doom2.wad", doom2, commercial, "Doom II" }, { "plutonia.wad", pack_plut, commercial, "Final Doom: Plutonia Experiment" }, { "tnt.wad", pack_tnt, commercial, "Final Doom: TNT: Evilution" }, { "doom.wad", doom, retail, "Doom" }, { "doom1.wad", doom, shareware, "Doom Shareware" }, { "chex.wad", pack_chex, shareware, "Chex Quest" }, { "hacx.wad", pack_hacx, commercial, "Hacx" }, { "freedm.wad", doom2, commercial, "FreeDM" }, { "freedoom2.wad", doom2, commercial, "Freedoom: Phase 2" }, { "freedoom1.wad", doom, retail, "Freedoom: Phase 1" }, { "heretic.wad", heretic, retail, "Heretic" }, { "heretic1.wad", heretic, shareware, "Heretic Shareware" }, { "hexen.wad", hexen, commercial, "Hexen" }, //{ "strife0.wad", strife, commercial, "Strife" }, // haleyjd: STRIFE-FIXME { "strife1.wad", strife, commercial, "Strife" }, }; // Array of locations to search for IWAD files // // "128 IWAD search directories should be enough for anybody". #define MAX_IWAD_DIRS 128 static boolean iwad_dirs_built = false; static char *iwad_dirs[MAX_IWAD_DIRS]; static int num_iwad_dirs = 0; static void AddIWADDir(char *dir) { if (num_iwad_dirs < MAX_IWAD_DIRS) { iwad_dirs[num_iwad_dirs] = dir; ++num_iwad_dirs; } } // This is Windows-specific code that automatically finds the location // of installed IWAD files. The registry is inspected to find special // keys installed by the Windows installers for various CD versions // of Doom. From these keys we can deduce where to find an IWAD. #if defined(_WIN32) && !defined(_WIN32_WCE) #define WIN32_LEAN_AND_MEAN #include typedef struct { HKEY root; char *path; char *value; } registry_value_t; #define UNINSTALLER_STRING "\\uninstl.exe /S " // Keys installed by the various CD editions. These are actually the // commands to invoke the uninstaller and look like this: // // C:\Program Files\Path\uninstl.exe /S C:\Program Files\Path // // With some munging we can find where Doom was installed. // [AlexMax] From the persepctive of a 64-bit executable, 32-bit registry // keys are located in a different spot. #if _WIN64 #define SOFTWARE_KEY "Software\\Wow6432Node" #else #define SOFTWARE_KEY "Software" #endif static registry_value_t uninstall_values[] = { // Ultimate Doom, CD version (Depths of Doom trilogy) { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\" "Uninstall\\Ultimate Doom for Windows 95", "UninstallString", }, // Doom II, CD version (Depths of Doom trilogy) { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\" "Uninstall\\Doom II for Windows 95", "UninstallString", }, // Final Doom { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\" "Uninstall\\Final Doom for Windows 95", "UninstallString", }, // Shareware version { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\" "Uninstall\\Doom Shareware for Windows 95", "UninstallString", }, }; // Values installed by the GOG.com and Collector's Edition versions static registry_value_t root_path_keys[] = { // Doom Collector's Edition { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\Activision\\DOOM Collector's Edition\\v1.0", "INSTALLPATH", }, // Ultimate Doom { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\GOG.com\\Games\\1435827232", "PATH", }, // Doom II { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\GOG.com\\Games\\1435848814", "PATH", }, // Final Doom { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\GOG.com\\Games\\1435848742", "PATH", }, }; // Subdirectories of the above install path, where IWADs are installed. static char *root_path_subdirs[] = { ".", "Doom2", "Final Doom", "Ultimate Doom", "TNT", "Plutonia", }; // Location where Steam is installed static registry_value_t steam_install_location = { HKEY_LOCAL_MACHINE, SOFTWARE_KEY "\\Valve\\Steam", "InstallPath", }; // Subdirs of the steam install directory where IWADs are found static char *steam_install_subdirs[] = { "steamapps\\common\\doom 2\\base", "steamapps\\common\\final doom\\base", "steamapps\\common\\ultimate doom\\base", "steamapps\\common\\heretic shadow of the serpent riders\\base", "steamapps\\common\\hexen\\base", "steamapps\\common\\hexen deathkings of the dark citadel\\base", // From Doom 3: BFG Edition: "steamapps\\common\\DOOM 3 BFG Edition\\base\\wads", // From Strife: Veteran Edition: "steamapps\\common\\Strife", }; #define STEAM_BFG_GUS_PATCHES \ "steamapps\\common\\DOOM 3 BFG Edition\\base\\classicmusic\\instruments" static char *GetRegistryString(registry_value_t *reg_val) { HKEY key; DWORD len; DWORD valtype; char *result; // Open the key (directory where the value is stored) if (RegOpenKeyEx(reg_val->root, reg_val->path, 0, KEY_READ, &key) != ERROR_SUCCESS) { return NULL; } result = NULL; // Find the type and length of the string, and only accept strings. if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, NULL, &len) == ERROR_SUCCESS && valtype == REG_SZ) { // Allocate a buffer for the value and read the value result = malloc(len); if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, (unsigned char *) result, &len) != ERROR_SUCCESS) { free(result); result = NULL; } } // Close the key RegCloseKey(key); return result; } // Check for the uninstall strings from the CD versions static void CheckUninstallStrings(void) { unsigned int i; for (i=0; i 0) { return; } install_path = GetRegistryString(&steam_install_location); if (install_path == NULL) { return; } len = strlen(install_path) + strlen(STEAM_BFG_GUS_PATCHES) + 20; patch_path = malloc(len); M_snprintf(patch_path, len, "%s\\%s\\ACBASS.PAT", install_path, STEAM_BFG_GUS_PATCHES); // Does acbass.pat exist? If so, then set gus_patch_path. if (M_FileExists(patch_path)) { M_snprintf(patch_path, len, "%s\\%s", install_path, STEAM_BFG_GUS_PATCHES); M_SetVariable("gus_patch_path", patch_path); } free(patch_path); free(install_path); } // Default install directories for DOS Doom static void CheckDOSDefaults(void) { // These are the default install directories used by the deice // installer program: AddIWADDir("\\doom2"); // Doom II AddIWADDir("\\plutonia"); // Final Doom AddIWADDir("\\tnt"); AddIWADDir("\\doom_se"); // Ultimate Doom AddIWADDir("\\doom"); // Shareware / Registered Doom AddIWADDir("\\dooms"); // Shareware versions AddIWADDir("\\doomsw"); AddIWADDir("\\heretic"); // Heretic AddIWADDir("\\hrtic_se"); // Heretic Shareware from Quake disc AddIWADDir("\\hexen"); // Hexen AddIWADDir("\\hexendk"); // Hexen Deathkings of the Dark Citadel AddIWADDir("\\strife"); // Strife } #endif // Returns true if the specified path is a path to a file // of the specified name. static boolean DirIsFile(char *path, char *filename) { size_t path_len; size_t filename_len; path_len = strlen(path); filename_len = strlen(filename); return path_len >= filename_len + 1 && path[path_len - filename_len - 1] == DIR_SEPARATOR && !strcasecmp(&path[path_len - filename_len], filename); } // Check if the specified directory contains the specified IWAD // file, returning the full path to the IWAD if found, or NULL // if not found. static char *CheckDirectoryHasIWAD(char *dir, char *iwadname) { char *filename; // As a special case, the "directory" may refer directly to an // IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH. if (DirIsFile(dir, iwadname) && M_FileExists(dir)) { return M_StringDuplicate(dir); } // Construct the full path to the IWAD if it is located in // this directory, and check if it exists. if (!strcmp(dir, ".")) { filename = M_StringDuplicate(iwadname); } else { filename = M_StringJoin(dir, DIR_SEPARATOR_S, iwadname, NULL); } if (M_FileExists(filename)) { return filename; } free(filename); return NULL; } // Search a directory to try to find an IWAD // Returns the location of the IWAD if found, otherwise NULL. static char *SearchDirectoryForIWAD(char *dir, int mask, GameMission_t *mission) { char *filename; size_t i; for (i=0; i static void AddXdgDirs(void) { char *env, *tmp_env; // Quote: // > $XDG_DATA_HOME defines the base directory relative to which // > user specific data files should be stored. If $XDG_DATA_HOME // > is either not set or empty, a default equal to // > $HOME/.local/share should be used. env = getenv("XDG_DATA_HOME"); tmp_env = NULL; if (env == NULL) { char *homedir = getenv("HOME"); if (homedir == NULL) { homedir = "/"; } tmp_env = M_StringJoin(homedir, "/.local/share", NULL); env = tmp_env; } // We support $XDG_DATA_HOME/games/doom (which will usually be // ~/.local/share/games/doom) as a user-writeable extension to // the usual /usr/share/games/doom location. AddIWADDir(M_StringJoin(env, "/games/doom", NULL)); free(tmp_env); // Quote: // > $XDG_DATA_DIRS defines the preference-ordered set of base // > directories to search for data files in addition to the // > $XDG_DATA_HOME base directory. The directories in $XDG_DATA_DIRS // > should be seperated with a colon ':'. // > // > If $XDG_DATA_DIRS is either not set or empty, a value equal to // > /usr/local/share/:/usr/share/ should be used. env = getenv("XDG_DATA_DIRS"); if (env == NULL) { // (Trailing / omitted from paths, as it is added below) env = "/usr/local/share:/usr/share"; } // The "standard" location for IWADs on Unix that is supported by most // source ports is /usr/share/games/doom - we support this through the // XDG_DATA_DIRS mechanism, through which it can be overridden. AddIWADPath(env, "/games/doom"); } // // Build a list of IWAD files // static void BuildIWADDirList(void) { char *env; if (iwad_dirs_built) { return; } // Look in the current directory. Doom always does this. AddIWADDir("."); // Add DOOMWADDIR if it is in the environment env = getenv("DOOMWADDIR"); if (env != NULL) { AddIWADDir(env); } // Add dirs from DOOMWADPATH: env = getenv("DOOMWADPATH"); if (env != NULL) { AddIWADPath(env, ""); } #ifdef _WIN32 // Search the registry and find where IWADs have been installed. CheckUninstallStrings(); CheckInstallRootPaths(); CheckSteamEdition(); CheckDOSDefaults(); // Check for GUS patches installed with the BFG edition! CheckSteamGUSPatches(); #else AddXdgDirs(); #endif // Don't run this function again. iwad_dirs_built = true; } // // Searches WAD search paths for an WAD with a specific filename. // char *D_FindWADByName(char *name) { char *path; int i; // Absolute path? if (M_FileExists(name)) { return name; } BuildIWADDirList(); // Search through all IWAD paths for a file with the given name. for (i=0; i // iwadparm = M_CheckParmWithArgs("-iwad", 1); if (iwadparm) { // Search through IWAD dirs for an IWAD with the given name. iwadfile = myargv[iwadparm + 1]; result = D_FindWADByName(iwadfile); if (result == NULL) { I_Error("IWAD file '%s' not found!", iwadfile); } *mission = IdentifyIWADByName(result, mask); } else { // Search through the list and look for an IWAD result = NULL; BuildIWADDirList(); for (i=0; result == NULL && i #include #include "doomfeatures.h" #include "d_event.h" #include "d_loop.h" #include "d_ticcmd.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "m_argv.h" #include "m_fixed.h" #include "net_client.h" #include "net_gui.h" #include "net_io.h" #include "net_query.h" #include "net_server.h" #include "net_sdl.h" #include "net_loop.h" // The complete set of data for a particular tic. typedef struct { ticcmd_t cmds[NET_MAXPLAYERS]; boolean ingame[NET_MAXPLAYERS]; } ticcmd_set_t; // Maximum time that we wait in TryRunTics() for netgame data to be // received before we bail out and render a frame anyway. // Vanilla Doom used 20 for this value, but we use a smaller value // instead for better responsiveness of the menu when we're stuck. #define MAX_NETGAME_STALL_TICS 5 // // gametic is the tic about to (or currently being) run // maketic is the tic that hasn't had control made for it yet // recvtic is the latest tic received from the server. // // a gametic cannot be run until ticcmds are received for it // from all players. // static ticcmd_set_t ticdata[BACKUPTICS]; // The index of the next tic to be made (with a call to BuildTiccmd). static int maketic; // The number of complete tics received from the server so far. static int recvtic; // The number of tics that have been run (using RunTic) so far. int gametic; // When set to true, a single tic is run each time TryRunTics() is called. // This is used for -timedemo mode. boolean singletics = false; // Index of the local player. static int localplayer; // Used for original sync code. static int skiptics = 0; // Reduce the bandwidth needed by sampling game input less and transmitting // less. If ticdup is 2, sample half normal, 3 = one third normal, etc. int ticdup; // Amount to offset the timer for game sync. fixed_t offsetms; // Use new client syncronisation code static boolean new_sync = true; // Callback functions for loop code. static loop_interface_t *loop_interface = NULL; // Current players in the multiplayer game. // This is distinct from playeringame[] used by the game code, which may // modify playeringame[] when playing back multiplayer demos. static boolean local_playeringame[NET_MAXPLAYERS]; // Requested player class "sent" to the server on connect. // If we are only doing a single player game then this needs to be remembered // and saved in the game settings. static int player_class; // 35 fps clock adjusted by offsetms milliseconds static int GetAdjustedTime(void) { int time_ms; time_ms = I_GetTimeMS(); if (new_sync) { // Use the adjustments from net_client.c only if we are // using the new sync mode. time_ms += (offsetms / FRACUNIT); } return (time_ms * TICRATE) / 1000; } static boolean BuildNewTic(void) { int gameticdiv; ticcmd_t cmd; gameticdiv = gametic/ticdup; I_StartTic (); loop_interface->ProcessEvents(); // Always run the menu loop_interface->RunMenu(); if (drone) { // In drone mode, do not generate any ticcmds. return false; } if (new_sync) { // If playing single player, do not allow tics to buffer // up very far if (!net_client_connected && maketic - gameticdiv > 2) return false; // Never go more than ~200ms ahead if (maketic - gameticdiv > 8) return false; } else { if (maketic - gameticdiv >= 5) return false; } //printf ("mk:%i ",maketic); memset(&cmd, 0, sizeof(ticcmd_t)); loop_interface->BuildTiccmd(&cmd, maketic); #ifdef FEATURE_MULTIPLAYER if (net_client_connected) { NET_CL_SendTiccmd(&cmd, maketic); } #endif ticdata[maketic % BACKUPTICS].cmds[localplayer] = cmd; ticdata[maketic % BACKUPTICS].ingame[localplayer] = true; ++maketic; return true; } // // NetUpdate // Builds ticcmds for console player, // sends out a packet // int lasttime; void NetUpdate (void) { int nowtime; int newtics; int i; // If we are running with singletics (timing a demo), this // is all done separately. if (singletics) return; #ifdef FEATURE_MULTIPLAYER // Run network subsystems NET_CL_Run(); NET_SV_Run(); #endif // check time nowtime = GetAdjustedTime() / ticdup; newtics = nowtime - lasttime; lasttime = nowtime; if (skiptics <= newtics) { newtics -= skiptics; skiptics = 0; } else { skiptics -= newtics; newtics = 0; } // build new ticcmds for console player for (i=0 ; iconsoleplayer = 0; settings->num_players = 1; settings->player_classes[0] = player_class; //! // @category net // // Use new network client sync code rather than the classic // sync code. This is currently disabled by default because it // has some bugs. // if (M_CheckParm("-newsync") > 0) settings->new_sync = 1; else settings->new_sync = 0; // TODO: New sync code is not enabled by default because it's // currently broken. //if (M_CheckParm("-oldsync") > 0) // settings->new_sync = 0; //else // settings->new_sync = 1; //! // @category net // @arg // // Send n extra tics in every packet as insurance against dropped // packets. // i = M_CheckParmWithArgs("-extratics", 1); if (i > 0) settings->extratics = atoi(myargv[i+1]); else settings->extratics = 1; //! // @category net // @arg // // Reduce the resolution of the game by a factor of n, reducing // the amount of network bandwidth needed. // i = M_CheckParmWithArgs("-dup", 1); if (i > 0) settings->ticdup = atoi(myargv[i+1]); else settings->ticdup = 1; if (net_client_connected) { // Send our game settings and block until game start is received // from the server. NET_CL_StartGame(settings); BlockUntilStart(settings, callback); // Read the game settings that were received. NET_CL_GetSettings(settings); } if (drone) { settings->consoleplayer = 0; } // Set the local player and playeringame[] values. localplayer = settings->consoleplayer; for (i = 0; i < NET_MAXPLAYERS; ++i) { local_playeringame[i] = i < settings->num_players; } // Copy settings to global variables. ticdup = settings->ticdup; new_sync = settings->new_sync; // TODO: Message disabled until we fix new_sync. //if (!new_sync) //{ // printf("Syncing netgames like Vanilla Doom.\n"); //} } boolean D_InitNetGame(net_connect_data_t *connect_data) { boolean result = false; net_addr_t *addr = NULL; int i; // Call D_QuitNetGame on exit: I_AtExit(D_QuitNetGame, true); player_class = connect_data->player_class; #ifdef FEATURE_MULTIPLAYER //! // @category net // // Start a multiplayer server, listening for connections. // if (M_CheckParm("-server") > 0 || M_CheckParm("-privateserver") > 0) { NET_SV_Init(); NET_SV_AddModule(&net_loop_server_module); NET_SV_AddModule(&net_sdl_module); NET_SV_RegisterWithMaster(); net_loop_client_module.InitClient(); addr = net_loop_client_module.ResolveAddress(NULL); } else { //! // @category net // // Automatically search the local LAN for a multiplayer // server and join it. // i = M_CheckParm("-autojoin"); if (i > 0) { addr = NET_FindLANServer(); if (addr == NULL) { I_Error("No server found on local LAN"); } } //! // @arg
// @category net // // Connect to a multiplayer server running on the given // address. // i = M_CheckParmWithArgs("-connect", 1); if (i > 0) { net_sdl_module.InitClient(); addr = net_sdl_module.ResolveAddress(myargv[i+1]); if (addr == NULL) { I_Error("Unable to resolve '%s'\n", myargv[i+1]); } } } if (addr != NULL) { if (M_CheckParm("-drone") > 0) { connect_data->drone = true; } if (!NET_CL_Connect(addr, connect_data)) { I_Error("D_InitNetGame: Failed to connect to %s\n", NET_AddrToString(addr)); } printf("D_InitNetGame: Connected to %s\n", NET_AddrToString(addr)); // Wait for launch message received from server. NET_WaitForLaunch(); result = true; } #endif return result; } // // D_QuitNetGame // Called before quitting to leave a net game // without hanging the other players // void D_QuitNetGame (void) { #ifdef FEATURE_MULTIPLAYER NET_SV_Shutdown(); NET_CL_Disconnect(); #endif } static int GetLowTic(void) { int lowtic; lowtic = maketic; #ifdef FEATURE_MULTIPLAYER if (net_client_connected) { if (drone || recvtic < lowtic) { lowtic = recvtic; } } #endif return lowtic; } static int frameon; static int frameskip[4]; static int oldnettics; static void OldNetSync(void) { unsigned int i; int keyplayer = -1; frameon++; // ideally maketic should be 1 - 3 tics above lowtic // if we are consistantly slower, speed up time for (i=0 ; i recvtic; oldnettics = maketic; if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) { skiptics = 1; // printf ("+"); } } } // Returns true if there are players in the game: static boolean PlayersInGame(void) { boolean result = false; unsigned int i; // If we are connected to a server, check if there are any players // in the game. if (net_client_connected) { for (i = 0; i < NET_MAXPLAYERS; ++i) { result = result || local_playeringame[i]; } } // Whether single or multi-player, unless we are running as a drone, // we are in the game. if (!drone) { result = true; } return result; } // When using ticdup, certain values must be cleared out when running // the duplicate ticcmds. static void TicdupSquash(ticcmd_set_t *set) { ticcmd_t *cmd; unsigned int i; for (i = 0; i < NET_MAXPLAYERS ; ++i) { cmd = &set->cmds[i]; cmd->chatchar = 0; if (cmd->buttons & BT_SPECIAL) cmd->buttons = 0; } } // When running in single player mode, clear all the ingame[] array // except the local player. static void SinglePlayerClear(ticcmd_set_t *set) { unsigned int i; for (i = 0; i < NET_MAXPLAYERS; ++i) { if (i != localplayer) { set->ingame[i] = false; } } } // // TryRunTics // void TryRunTics (void) { int i; int lowtic; int entertic; static int oldentertics; int realtics; int availabletics; int counts; // get real tics entertic = I_GetTime() / ticdup; realtics = entertic - oldentertics; oldentertics = entertic; // in singletics mode, run a single tic every time this function // is called. if (singletics) { BuildNewTic(); } else { NetUpdate (); } lowtic = GetLowTic(); availabletics = lowtic - gametic/ticdup; // decide how many tics to run if (new_sync) { counts = availabletics; } else { // decide how many tics to run if (realtics < availabletics-1) counts = realtics+1; else if (realtics < availabletics) counts = realtics; else counts = availabletics; if (counts < 1) counts = 1; if (net_client_connected) { OldNetSync(); } } if (counts < 1) counts = 1; // wait for new tics if needed while (!PlayersInGame() || lowtic < gametic/ticdup + counts) { NetUpdate (); lowtic = GetLowTic(); if (lowtic < gametic/ticdup) I_Error ("TryRunTics: lowtic < gametic"); // Still no tics to run? Sleep until some are available. if (lowtic < gametic/ticdup + counts) { // If we're in a netgame, we might spin forever waiting for // new network data to be received. So don't stay in here // forever - give the menu a chance to work. if (I_GetTime() / ticdup - entertic >= MAX_NETGAME_STALL_TICS) { return; } I_Sleep(1); } } // run the count * ticdup dics while (counts--) { ticcmd_set_t *set; if (!PlayersInGame()) { return; } set = &ticdata[(gametic / ticdup) % BACKUPTICS]; if (!net_client_connected) { SinglePlayerClear(set); } for (i=0 ; i lowtic) I_Error ("gametic>lowtic"); memcpy(local_playeringame, set->ingame, sizeof(local_playeringame)); loop_interface->RunTic(set->cmds, set->ingame); gametic++; // modify command for duplicated tics TicdupSquash(set); } NetUpdate (); // check for new console commands } } void D_RegisterLoopCallbacks(loop_interface_t *i) { loop_interface = i; } chocolate-doom-chocolate-doom-2.2.1/src/d_loop.h000066400000000000000000000044751257432200600215330ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Main loop stuff. // #ifndef __D_LOOP__ #define __D_LOOP__ #include "net_defs.h" // Callback function invoked while waiting for the netgame to start. // The callback is invoked when new players are ready. The callback // should return true, or return false to abort startup. typedef boolean (*netgame_startup_callback_t)(int ready_players, int num_players); typedef struct { // Read events from the event queue, and process them. void (*ProcessEvents)(); // Given the current input state, fill in the fields of the specified // ticcmd_t structure with data for a new tic. void (*BuildTiccmd)(ticcmd_t *cmd, int maketic); // Advance the game forward one tic, using the specified player input. void (*RunTic)(ticcmd_t *cmds, boolean *ingame); // Run the menu (runs independently of the game). void (*RunMenu)(); } loop_interface_t; // Register callback functions for the main loop code to use. void D_RegisterLoopCallbacks(loop_interface_t *i); // Create any new ticcmds and broadcast to other players. void NetUpdate (void); // Broadcasts special packets to other players // to notify of game exit void D_QuitNetGame (void); //? how many ticks to run? void TryRunTics (void); // Called at start of game loop to initialize timers void D_StartGameLoop(void); // Initialize networking code and connect to server. boolean D_InitNetGame(net_connect_data_t *connect_data); // Start game with specified settings. The structure will be updated // with the actual settings for the game. void D_StartNetGame(net_gamesettings_t *settings, netgame_startup_callback_t callback); extern boolean singletics; extern int gametic, ticdup; #endif chocolate-doom-chocolate-doom-2.2.1/src/d_mode.c000066400000000000000000000114011257432200600214640ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: // Functions and definitions relating to the game type and operational // mode. // #include "doomtype.h" #include "d_mode.h" // Valid game mode/mission combinations, with the number of // episodes/maps for each. static struct { GameMission_t mission; GameMode_t mode; int episode; int map; } valid_modes[] = { { pack_chex, shareware, 1, 5 }, { doom, shareware, 1, 9 }, { doom, registered, 3, 9 }, { doom, retail, 4, 9 }, { doom2, commercial, 1, 32 }, { pack_tnt, commercial, 1, 32 }, { pack_plut, commercial, 1, 32 }, { pack_hacx, commercial, 1, 32 }, { heretic, shareware, 1, 9 }, { heretic, registered, 3, 9 }, { heretic, retail, 5, 9 }, { hexen, commercial, 1, 60 }, { strife, commercial, 1, 34 }, }; // Check that a gamemode+gamemission received over the network is valid. boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode) { int i; for (i=0; i= 1 && map <= 3; } else if (mode == registered && episode == 4) { return map == 1; } } // Find the table entry for this mission/mode combination. for (i=0; i= 1 && episode <= valid_modes[i].episode && map >= 1 && map <= valid_modes[i].map; } } // Unknown mode/mission combination return false; } // Get the number of valid episodes for the specified mission/mode. int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode) { int episode; episode = 1; while (D_ValidEpisodeMap(mission, mode, episode, 1)) { ++episode; } return episode - 1; } // Table of valid versions static struct { GameMission_t mission; GameVersion_t version; } valid_versions[] = { { doom, exe_doom_1_9 }, { doom, exe_hacx }, { doom, exe_ultimate }, { doom, exe_final }, { doom, exe_final2 }, { doom, exe_chex }, { heretic, exe_heretic_1_3 }, { hexen, exe_hexen_1_1 }, { strife, exe_strife_1_2 }, { strife, exe_strife_1_31 }, }; boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version) { int i; // All Doom variants can use the Doom versions. if (mission == doom2 || mission == pack_plut || mission == pack_tnt || mission == pack_hacx || mission == pack_chex) { mission = doom; } for (i=0; i #include #include #include #include #include "m_misc.h" #include "w_wad.h" #include "z_zone.h" #include "deh_defs.h" #include "deh_io.h" typedef enum { DEH_INPUT_FILE, DEH_INPUT_LUMP } deh_input_type_t; struct deh_context_s { deh_input_type_t type; char *filename; // If the input comes from a memory buffer, pointer to the memory // buffer. unsigned char *input_buffer; size_t input_buffer_len; unsigned int input_buffer_pos; int lumpnum; // If the input comes from a file, the file stream for reading // data. FILE *stream; // Current line number that we have reached: int linenum; // Used by DEH_ReadLine: boolean last_was_newline; char *readbuffer; int readbuffer_size; // Error handling. boolean had_error; }; static deh_context_t *DEH_NewContext(void) { deh_context_t *context; context = Z_Malloc(sizeof(*context), PU_STATIC, NULL); // Initial read buffer size of 128 bytes context->readbuffer_size = 128; context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL); context->linenum = 0; context->last_was_newline = true; context->had_error = false; return context; } // Open a dehacked file for reading // Returns NULL if open failed deh_context_t *DEH_OpenFile(char *filename) { FILE *fstream; deh_context_t *context; fstream = fopen(filename, "r"); if (fstream == NULL) return NULL; context = DEH_NewContext(); context->type = DEH_INPUT_FILE; context->stream = fstream; context->filename = M_StringDuplicate(filename); return context; } // Open a WAD lump for reading. deh_context_t *DEH_OpenLump(int lumpnum) { deh_context_t *context; void *lump; lump = W_CacheLumpNum(lumpnum, PU_STATIC); context = DEH_NewContext(); context->type = DEH_INPUT_LUMP; context->lumpnum = lumpnum; context->input_buffer = lump; context->input_buffer_len = W_LumpLength(lumpnum); context->input_buffer_pos = 0; context->filename = malloc(9); M_StringCopy(context->filename, lumpinfo[lumpnum].name, 9); return context; } // Close dehacked file void DEH_CloseFile(deh_context_t *context) { if (context->type == DEH_INPUT_FILE) { fclose(context->stream); } else if (context->type == DEH_INPUT_LUMP) { W_ReleaseLumpNum(context->lumpnum); } free(context->filename); Z_Free(context->readbuffer); Z_Free(context); } int DEH_GetCharFile(deh_context_t *context) { if (feof(context->stream)) { // end of file return -1; } return fgetc(context->stream); } int DEH_GetCharLump(deh_context_t *context) { int result; if (context->input_buffer_pos >= context->input_buffer_len) { return -1; } result = context->input_buffer[context->input_buffer_pos]; ++context->input_buffer_pos; return result; } // Reads a single character from a dehacked file int DEH_GetChar(deh_context_t *context) { int result = 0; // Read characters, but ignore carriage returns // Essentially this is a DOS->Unix conversion do { switch (context->type) { case DEH_INPUT_FILE: result = DEH_GetCharFile(context); break; case DEH_INPUT_LUMP: result = DEH_GetCharLump(context); break; } } while (result == '\r'); // Track the current line number if (context->last_was_newline) { ++context->linenum; } context->last_was_newline = result == '\n'; return result; } // Increase the read buffer size static void IncreaseReadBuffer(deh_context_t *context) { char *newbuffer; int newbuffer_size; newbuffer_size = context->readbuffer_size * 2; newbuffer = Z_Malloc(newbuffer_size, PU_STATIC, NULL); memcpy(newbuffer, context->readbuffer, context->readbuffer_size); Z_Free(context->readbuffer); context->readbuffer = newbuffer; context->readbuffer_size = newbuffer_size; } // Read a whole line char *DEH_ReadLine(deh_context_t *context, boolean extended) { int c; int pos; boolean escaped = false; for (pos = 0;;) { c = DEH_GetChar(context); if (c < 0 && pos == 0) { // end of file return NULL; } // cope with lines of any length: increase the buffer size if (pos >= context->readbuffer_size) { IncreaseReadBuffer(context); } // extended string support if (extended && c == '\\') { c = DEH_GetChar(context); // "\n" in the middle of a string indicates an internal linefeed if (c == 'n') { context->readbuffer[pos] = '\n'; ++pos; continue; } // values to be assigned may be split onto multiple lines by ending // each line that is to be continued with a backslash if (c == '\n') { escaped = true; continue; } } // blanks before the backslash are included in the string // but indentation after the linefeed is not if (escaped && c >= 0 && isspace(c) && c != '\n') { continue; } else { escaped = false; } if (c == '\n' || c < 0) { // end of line: a full line has been read context->readbuffer[pos] = '\0'; break; } else if (c != '\0') { // normal character; don't allow NUL characters to be // added. context->readbuffer[pos] = (char) c; ++pos; } } return context->readbuffer; } void DEH_Warning(deh_context_t *context, char *msg, ...) { va_list args; va_start(args, msg); fprintf(stderr, "%s:%i: warning: ", context->filename, context->linenum); vfprintf(stderr, msg, args); fprintf(stderr, "\n"); va_end(args); } void DEH_Error(deh_context_t *context, char *msg, ...) { va_list args; va_start(args, msg); fprintf(stderr, "%s:%i: ", context->filename, context->linenum); vfprintf(stderr, msg, args); fprintf(stderr, "\n"); va_end(args); context->had_error = true; } boolean DEH_HadError(deh_context_t *context) { return context->had_error; } chocolate-doom-chocolate-doom-2.2.1/src/deh_io.h000066400000000000000000000021121257432200600214700ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Dehacked I/O code (does all reads from dehacked files) // #ifndef DEH_IO_H #define DEH_IO_H #include "deh_defs.h" deh_context_t *DEH_OpenFile(char *filename); deh_context_t *DEH_OpenLump(int lumpnum); void DEH_CloseFile(deh_context_t *context); int DEH_GetChar(deh_context_t *context); char *DEH_ReadLine(deh_context_t *context, boolean extended); void DEH_Error(deh_context_t *context, char *msg, ...); void DEH_Warning(deh_context_t *context, char *msg, ...); boolean DEH_HadError(deh_context_t *context); #endif /* #ifndef DEH_IO_H */ chocolate-doom-chocolate-doom-2.2.1/src/deh_main.c000066400000000000000000000254341257432200600220140ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Main dehacked code // #include #include #include #include #include "doomtype.h" #include "i_system.h" #include "d_iwad.h" #include "m_argv.h" #include "w_wad.h" #include "deh_defs.h" #include "deh_io.h" extern deh_section_t *deh_section_types[]; extern char *deh_signatures[]; static boolean deh_initialized = false; // If true, we can parse [STRINGS] sections in BEX format. boolean deh_allow_extended_strings = false; // If true, we can do long string replacements. boolean deh_allow_long_strings = false; // If true, we can do cheat replacements longer than the originals. boolean deh_allow_long_cheats = false; // If false, dehacked cheat replacements are ignored. boolean deh_apply_cheats = true; void DEH_Checksum(sha1_digest_t digest) { sha1_context_t sha1_context; unsigned int i; SHA1_Init(&sha1_context); for (i=0; deh_section_types[i] != NULL; ++i) { if (deh_section_types[i]->sha1_hash != NULL) { deh_section_types[i]->sha1_hash(&sha1_context); } } SHA1_Final(digest, &sha1_context); } // Called on startup to call the Init functions static void InitializeSections(void) { unsigned int i; for (i=0; deh_section_types[i] != NULL; ++i) { if (deh_section_types[i]->init != NULL) { deh_section_types[i]->init(); } } } static void DEH_Init(void) { //! // @category mod // // Ignore cheats in dehacked files. // if (M_CheckParm("-nocheats") > 0) { deh_apply_cheats = false; } // Call init functions for all the section definitions. InitializeSections(); deh_initialized = true; } // Given a section name, get the section structure which corresponds static deh_section_t *GetSectionByName(char *name) { unsigned int i; // we explicitely do not recognize [STRINGS] sections at all // if extended strings are not allowed if (!deh_allow_extended_strings && !strncasecmp("[STRINGS]", name, 9)) { return NULL; } for (i=0; deh_section_types[i] != NULL; ++i) { if (!strcasecmp(deh_section_types[i]->name, name)) { return deh_section_types[i]; } } return NULL; } // Is the string passed just whitespace? static boolean IsWhitespace(char *s) { for (; *s; ++s) { if (!isspace(*s)) return false; } return true; } // Strip whitespace from the start and end of a string static char *CleanString(char *s) { char *strending; // Leading whitespace while (*s && isspace(*s)) ++s; // Trailing whitespace strending = s + strlen(s) - 1; while (strlen(s) > 0 && isspace(*strending)) { *strending = '\0'; --strending; } return s; } // This pattern is used a lot of times in different sections, // an assignment is essentially just a statement of the form: // // Variable Name = Value // // The variable name can include spaces or any other characters. // The string is split on the '=', essentially. // // Returns true if read correctly boolean DEH_ParseAssignment(char *line, char **variable_name, char **value) { char *p; // find the equals p = strchr(line, '='); if (p == NULL) { return false; } // variable name at the start // turn the '=' into a \0 to terminate the string here *p = '\0'; *variable_name = CleanString(line); // value immediately follows the '=' *value = CleanString(p+1); return true; } static boolean CheckSignatures(deh_context_t *context) { size_t i; char *line; // Read the first line line = DEH_ReadLine(context, false); if (line == NULL) { return false; } // Check all signatures to see if one matches for (i=0; deh_signatures[i] != NULL; ++i) { if (!strcmp(deh_signatures[i], line)) { return true; } } return false; } // Parses a comment string in a dehacked file. static void DEH_ParseComment(char *comment) { // // Welcome, to the super-secret Chocolate Doom-specific Dehacked // overrides function. // // Putting these magic comments into your Dehacked lumps will // allow you to go beyond the normal limits of Vanilla Dehacked. // Because of this, these comments are deliberately undocumented, // and if you're using them you should be aware that your mod // is not compatible with Vanilla Doom and you're probably a // very naughty person. // // Allow comments containing this special value to allow string // replacements longer than those permitted by DOS dehacked. // This allows us to use a dehacked patch for doing string // replacements for emulating Chex Quest. // // If you use this, your dehacked patch may not work in Vanilla // Doom. if (strstr(comment, "*allow-long-strings*") != NULL) { deh_allow_long_strings = true; } // Allow magic comments to allow longer cheat replacements than // those permitted by DOS dehacked. This is also for Chex // Quest. if (strstr(comment, "*allow-long-cheats*") != NULL) { deh_allow_long_cheats = true; } // Allow magic comments to allow parsing [STRINGS] section // that are usually only found in BEX format files. This allows // for substitution of map and episode names when loading // Freedoom/FreeDM IWADs. if (strstr(comment, "*allow-extended-strings*") != NULL) { deh_allow_extended_strings = true; } } // Parses a dehacked file by reading from the context static void DEH_ParseContext(deh_context_t *context) { deh_section_t *current_section = NULL; char section_name[20]; void *tag = NULL; boolean extended; char *line; // Read the header and check it matches the signature if (!CheckSignatures(context)) { DEH_Error(context, "This is not a valid dehacked patch file!"); } // Read the file while (!DEH_HadError(context)) { // Read the next line. We only allow the special extended parsing // for the BEX [STRINGS] section. extended = current_section != NULL && !strcasecmp(current_section->name, "[STRINGS]"); line = DEH_ReadLine(context, extended); // end of file? if (line == NULL) { return; } while (line[0] != '\0' && isspace(line[0])) ++line; if (line[0] == '#') { // comment DEH_ParseComment(line); continue; } if (IsWhitespace(line)) { if (current_section != NULL) { // end of section if (current_section->end != NULL) { current_section->end(context, tag); } //printf("end %s tag\n", current_section->name); current_section = NULL; } } else { if (current_section != NULL) { // parse this line current_section->line_parser(context, line, tag); } else { // possibly the start of a new section sscanf(line, "%19s", section_name); current_section = GetSectionByName(section_name); if (current_section != NULL) { tag = current_section->start(context, line); //printf("started %s tag\n", section_name); } else { //printf("unknown section name %s\n", section_name); } } } } } // Parses a dehacked file int DEH_LoadFile(char *filename) { deh_context_t *context; if (!deh_initialized) { DEH_Init(); } // Before parsing a new file, reset special override flags to false. // Magic comments should only apply to the file in which they were // defined, and shouldn't carry over to subsequent files as well. deh_allow_long_strings = false; deh_allow_long_cheats = false; deh_allow_extended_strings = false; printf(" loading %s\n", filename); context = DEH_OpenFile(filename); if (context == NULL) { fprintf(stderr, "DEH_LoadFile: Unable to open %s\n", filename); return 0; } DEH_ParseContext(context); DEH_CloseFile(context); if (DEH_HadError(context)) { I_Error("Error parsing dehacked file"); } return 1; } // Load dehacked file from WAD lump. // If allow_long is set, allow long strings and cheats just for this lump. int DEH_LoadLump(int lumpnum, boolean allow_long, boolean allow_error) { deh_context_t *context; if (!deh_initialized) { DEH_Init(); } // Reset all special flags to defaults. deh_allow_long_strings = allow_long; deh_allow_long_cheats = allow_long; deh_allow_extended_strings = false; context = DEH_OpenLump(lumpnum); if (context == NULL) { fprintf(stderr, "DEH_LoadFile: Unable to open lump %i\n", lumpnum); return 0; } DEH_ParseContext(context); DEH_CloseFile(context); // If there was an error while parsing, abort with an error, but allow // errors to just be ignored if allow_error=true. if (!allow_error && DEH_HadError(context)) { I_Error("Error parsing dehacked lump"); } return 1; } int DEH_LoadLumpByName(char *name, boolean allow_long, boolean allow_error) { int lumpnum; lumpnum = W_CheckNumForName(name); if (lumpnum == -1) { fprintf(stderr, "DEH_LoadLumpByName: '%s' lump not found\n", name); return 0; } return DEH_LoadLump(lumpnum, allow_long, allow_error); } // Check the command line for -deh argument, and others. void DEH_ParseCommandLine(void) { char *filename; int p; //! // @arg // @category mod // // Load the given dehacked patch(es) // p = M_CheckParm("-deh"); if (p > 0) { ++p; while (p < myargc && myargv[p][0] != '-') { filename = D_TryFindWADByName(myargv[p]); DEH_LoadFile(filename); ++p; } } } chocolate-doom-chocolate-doom-2.2.1/src/deh_main.h000066400000000000000000000027251257432200600220170ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Dehacked entrypoint and common code // #ifndef DEH_MAIN_H #define DEH_MAIN_H #include "doomtype.h" #include "doomfeatures.h" #include "deh_str.h" #include "sha1.h" // These are the limits that dehacked uses (from dheinit.h in the dehacked // source). If these limits are exceeded, it does not generate an error, but // a warning is displayed. #define DEH_VANILLA_NUMSTATES 966 #define DEH_VANILLA_NUMSFX 107 void DEH_ParseCommandLine(void); int DEH_LoadFile(char *filename); int DEH_LoadLump(int lumpnum, boolean allow_long, boolean allow_error); int DEH_LoadLumpByName(char *name, boolean allow_long, boolean allow_error); boolean DEH_ParseAssignment(char *line, char **variable_name, char **value); void DEH_Checksum(sha1_digest_t digest); extern boolean deh_allow_extended_strings; extern boolean deh_allow_long_strings; extern boolean deh_allow_long_cheats; extern boolean deh_apply_cheats; #endif /* #ifndef DEH_MAIN_H */ chocolate-doom-chocolate-doom-2.2.1/src/deh_mapping.c000066400000000000000000000114161257432200600225160ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Dehacked "mapping" code // Allows the fields in structures to be mapped out and accessed by // name // #include #include #include #include "doomtype.h" #include "i_system.h" #include "m_misc.h" #include "deh_mapping.h" static deh_mapping_entry_t *GetMappingEntryByName(deh_context_t *context, deh_mapping_t *mapping, char *name) { int i; for (i=0; mapping->entries[i].name != NULL; ++i) { deh_mapping_entry_t *entry = &mapping->entries[i]; if (!strcasecmp(entry->name, name)) { if (entry->location == NULL) { DEH_Warning(context, "Field '%s' is unsupported", name); return NULL; } return entry; } } // Not found. DEH_Warning(context, "Field named '%s' not found", name); return NULL; } // // Get the location of the specified field in the specified structure. // static void *GetStructField(void *structptr, deh_mapping_t *mapping, deh_mapping_entry_t *entry) { unsigned int offset; offset = (uint8_t *)entry->location - (uint8_t *)mapping->base; return (uint8_t *)structptr + offset; } // // Set the value of a particular field in a structure by name // boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, void *structptr, char *name, int value) { deh_mapping_entry_t *entry; void *location; entry = GetMappingEntryByName(context, mapping, name); if (entry == NULL) { return false; } // Sanity check: if (entry->is_string) { DEH_Error(context, "Tried to set '%s' as integer (BUG)", name); return false; } location = GetStructField(structptr, mapping, entry); // printf("Setting %p::%s to %i (%i bytes)\n", // structptr, name, value, entry->size); // Set field content based on its type: switch (entry->size) { case 1: * ((uint8_t *) location) = value; break; case 2: * ((uint16_t *) location) = value; break; case 4: * ((uint32_t *) location) = value; break; default: DEH_Error(context, "Unknown field type for '%s' (BUG)", name); return false; } return true; } // // Set the value of a string field in a structure by name // boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping, void *structptr, char *name, char *value) { deh_mapping_entry_t *entry; void *location; entry = GetMappingEntryByName(context, mapping, name); if (entry == NULL) { return false; } // Sanity check: if (!entry->is_string) { DEH_Error(context, "Tried to set '%s' as string (BUG)", name); return false; } location = GetStructField(structptr, mapping, entry); // Copy value into field: M_StringCopy(location, value, entry->size); return true; } void DEH_StructSHA1Sum(sha1_context_t *context, deh_mapping_t *mapping, void *structptr) { int i; // Go through each mapping for (i=0; mapping->entries[i].name != NULL; ++i) { deh_mapping_entry_t *entry = &mapping->entries[i]; void *location; if (entry->location == NULL) { // Unsupported field continue; } // Add in data for this field location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); switch (entry->size) { case 1: SHA1_UpdateInt32(context, *((uint8_t *) location)); break; case 2: SHA1_UpdateInt32(context, *((uint16_t *) location)); break; case 4: SHA1_UpdateInt32(context, *((uint32_t *) location)); break; default: I_Error("Unknown dehacked mapping field type for '%s' (BUG)", entry->name); break; } } } chocolate-doom-chocolate-doom-2.2.1/src/deh_mapping.h000066400000000000000000000053771257432200600225340ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Dehacked "mapping" code // Allows the fields in structures to be mapped out and accessed by // name // #ifndef DEH_MAPPING_H #define DEH_MAPPING_H #include "doomtype.h" #include "deh_io.h" #include "sha1.h" #define DEH_BEGIN_MAPPING(mapping_name, structname) \ static structname deh_mapping_base; \ static deh_mapping_t mapping_name = \ { \ &deh_mapping_base, \ { #define DEH_MAPPING(deh_name, fieldname) \ {deh_name, &deh_mapping_base.fieldname, \ sizeof(deh_mapping_base.fieldname), \ false}, #define DEH_MAPPING_STRING(deh_name, fieldname) \ {deh_name, &deh_mapping_base.fieldname, \ sizeof(deh_mapping_base.fieldname), \ true}, #define DEH_UNSUPPORTED_MAPPING(deh_name) \ {deh_name, NULL, -1, false}, #define DEH_END_MAPPING \ {NULL, NULL, -1} \ } \ }; #define MAX_MAPPING_ENTRIES 32 typedef struct deh_mapping_s deh_mapping_t; typedef struct deh_mapping_entry_s deh_mapping_entry_t; struct deh_mapping_entry_s { // field name char *name; // location relative to the base in the deh_mapping_t struct // If this is NULL, it is an unsupported mapping void *location; // field size int size; // if true, this is a string value. boolean is_string; }; struct deh_mapping_s { void *base; deh_mapping_entry_t entries[MAX_MAPPING_ENTRIES]; }; boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, void *structptr, char *name, int value); boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping, void *structptr, char *name, char *value); void DEH_StructSHA1Sum(sha1_context_t *context, deh_mapping_t *mapping, void *structptr); #endif /* #ifndef DEH_MAPPING_H */ chocolate-doom-chocolate-doom-2.2.1/src/deh_str.c000066400000000000000000000221671257432200600217000ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses Text substitution sections in dehacked files // #include #include #include #include #include "doomtype.h" #include "deh_str.h" #include "m_misc.h" #include "z_zone.h" typedef struct { char *from_text; char *to_text; } deh_substitution_t; static deh_substitution_t **hash_table = NULL; static int hash_table_entries; static int hash_table_length = -1; // This is the algorithm used by glib static unsigned int strhash(char *s) { char *p = s; unsigned int h = *p; if (h) { for (p += 1; *p; p++) h = (h << 5) - h + *p; } return h; } static deh_substitution_t *SubstitutionForString(char *s) { int entry; // Fallback if we have not initialized the hash table yet if (hash_table_length < 0) return NULL; entry = strhash(s) % hash_table_length; while (hash_table[entry] != NULL) { if (!strcmp(hash_table[entry]->from_text, s)) { // substitution found! return hash_table[entry]; } entry = (entry + 1) % hash_table_length; } // no substitution found return NULL; } // Look up a string to see if it has been replaced with something else // This will be used throughout the program to substitute text char *DEH_String(char *s) { deh_substitution_t *subst; subst = SubstitutionForString(s); if (subst != NULL) { return subst->to_text; } else { return s; } } static void InitHashTable(void) { // init hash table hash_table_entries = 0; hash_table_length = 16; hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length, PU_STATIC, NULL); memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length); } static void DEH_AddToHashtable(deh_substitution_t *sub); static void IncreaseHashtable(void) { deh_substitution_t **old_table; int old_table_length; int i; // save the old table old_table = hash_table; old_table_length = hash_table_length; // double the size hash_table_length *= 2; hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length, PU_STATIC, NULL); memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length); // go through the old table and insert all the old entries for (i=0; i 6) { IncreaseHashtable(); } // find where to insert it entry = strhash(sub->from_text) % hash_table_length; while (hash_table[entry] != NULL) { entry = (entry + 1) % hash_table_length; } hash_table[entry] = sub; ++hash_table_entries; } void DEH_AddStringReplacement(char *from_text, char *to_text) { deh_substitution_t *sub; size_t len; // Initialize the hash table if this is the first time if (hash_table_length < 0) { InitHashTable(); } // Check to see if there is an existing substitution already in place. sub = SubstitutionForString(from_text); if (sub != NULL) { Z_Free(sub->to_text); len = strlen(to_text) + 1; sub->to_text = Z_Malloc(len, PU_STATIC, NULL); memcpy(sub->to_text, to_text, len); } else { // We need to allocate a new substitution. sub = Z_Malloc(sizeof(*sub), PU_STATIC, 0); // We need to create our own duplicates of the provided strings. len = strlen(from_text) + 1; sub->from_text = Z_Malloc(len, PU_STATIC, NULL); memcpy(sub->from_text, from_text, len); len = strlen(to_text) + 1; sub->to_text = Z_Malloc(len, PU_STATIC, NULL); memcpy(sub->to_text, to_text, len); DEH_AddToHashtable(sub); } } typedef enum { FORMAT_ARG_INVALID, FORMAT_ARG_INT, FORMAT_ARG_FLOAT, FORMAT_ARG_CHAR, FORMAT_ARG_STRING, FORMAT_ARG_PTR, FORMAT_ARG_SAVE_POS } format_arg_t; // Get the type of a format argument. // We can mix-and-match different format arguments as long as they // are for the same data type. static format_arg_t FormatArgumentType(char c) { switch (c) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': return FORMAT_ARG_INT; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': return FORMAT_ARG_FLOAT; case 'c': case 'C': return FORMAT_ARG_CHAR; case 's': case 'S': return FORMAT_ARG_STRING; case 'p': return FORMAT_ARG_PTR; case 'n': return FORMAT_ARG_SAVE_POS; default: return FORMAT_ARG_INVALID; } } // Given the specified string, get the type of the first format // string encountered. static format_arg_t NextFormatArgument(char **str) { format_arg_t argtype; // Search for the '%' starting the next string. while (**str != '\0') { if (**str == '%') { ++*str; // Don't stop for double-%s. if (**str != '%') { break; } } ++*str; } // Find the type of the format string. while (**str != '\0') { argtype = FormatArgumentType(**str); if (argtype != FORMAT_ARG_INVALID) { ++*str; return argtype; } ++*str; } // Stop searching, we have reached the end. *str = NULL; return FORMAT_ARG_INVALID; } // Check if the specified argument type is a valid replacement for // the original. static boolean ValidArgumentReplacement(format_arg_t original, format_arg_t replacement) { // In general, the original and replacement types should be // identical. However, there are some cases where the replacement // is valid and the types don't match. // Characters can be represented as ints. if (original == FORMAT_ARG_CHAR && replacement == FORMAT_ARG_INT) { return true; } // Strings are pointers. if (original == FORMAT_ARG_STRING && replacement == FORMAT_ARG_PTR) { return true; } return original == replacement; } // Return true if the specified string contains no format arguments. static boolean ValidFormatReplacement(char *original, char *replacement) { char *rover1; char *rover2; int argtype1, argtype2; // Check each argument in turn and compare types. rover1 = original; rover2 = replacement; for (;;) { argtype1 = NextFormatArgument(&rover1); argtype2 = NextFormatArgument(&rover2); if (argtype2 == FORMAT_ARG_INVALID) { // No more arguments left to read from the replacement string. break; } else if (argtype1 == FORMAT_ARG_INVALID) { // Replacement string has more arguments than the original. return false; } else if (!ValidArgumentReplacement(argtype1, argtype2)) { // Not a valid replacement argument. return false; } } return true; } // Get replacement format string, checking arguments. static char *FormatStringReplacement(char *s) { char *repl; repl = DEH_String(s); if (!ValidFormatReplacement(s, repl)) { printf("WARNING: Unsafe dehacked replacement provided for " "printf format string: %s\n", s); return s; } return repl; } // printf(), performing a replacement on the format string. void DEH_printf(char *fmt, ...) { va_list args; char *repl; repl = FormatStringReplacement(fmt); va_start(args, fmt); vprintf(repl, args); va_end(args); } // fprintf(), performing a replacement on the format string. void DEH_fprintf(FILE *fstream, char *fmt, ...) { va_list args; char *repl; repl = FormatStringReplacement(fmt); va_start(args, fmt); vfprintf(fstream, repl, args); va_end(args); } // snprintf(), performing a replacement on the format string. void DEH_snprintf(char *buffer, size_t len, char *fmt, ...) { va_list args; char *repl; repl = FormatStringReplacement(fmt); va_start(args, fmt); M_vsnprintf(buffer, len, repl, args); va_end(args); } chocolate-doom-chocolate-doom-2.2.1/src/deh_str.h000066400000000000000000000022041257432200600216730ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Dehacked string replacements // #ifndef DEH_STR_H #define DEH_STR_H #include #include "doomfeatures.h" // Used to do dehacked text substitutions throughout the program #ifdef FEATURE_DEHACKED char *DEH_String(char *s); void DEH_printf(char *fmt, ...); void DEH_fprintf(FILE *fstream, char *fmt, ...); void DEH_snprintf(char *buffer, size_t len, char *fmt, ...); void DEH_AddStringReplacement(char *from_text, char *to_text); #else #define DEH_String(x) (x) #define DEH_printf printf #define DEH_fprintf fprintf #define DEH_snprintf snprintf #endif #endif /* #ifndef DEH_STR_H */ chocolate-doom-chocolate-doom-2.2.1/src/deh_text.c000066400000000000000000000050361257432200600220500ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses Text substitution sections in dehacked files // #include #include #include #include "doomtype.h" #include "z_zone.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" // Given a string length, find the maximum length of a // string that can replace it. static int TXT_MaxStringLength(int len) { // Enough bytes for the string and the NUL terminator len += 1; // All strings in doom.exe are on 4-byte boundaries, so we may be able // to support a slightly longer string. // Extend up to the next 4-byte boundary len += (4 - (len % 4)) % 4; // Less one for the NUL terminator. return len - 1; } static void *DEH_TextStart(deh_context_t *context, char *line) { char *from_text, *to_text; int fromlen, tolen; int i; if (sscanf(line, "Text %i %i", &fromlen, &tolen) != 2) { DEH_Warning(context, "Parse error on section start"); return NULL; } // Only allow string replacements that are possible in Vanilla Doom. // Chocolate Doom is unforgiving! if (!deh_allow_long_strings && tolen > TXT_MaxStringLength(fromlen)) { DEH_Error(context, "Replacement string is longer than the maximum " "possible in doom.exe"); return NULL; } from_text = malloc(fromlen + 1); to_text = malloc(tolen + 1); // read in the "from" text for (i=0; i @PROGRAM_PREFIX@doom.desktop CC0-1.0 GPL-2.0+ @PACKAGE_MAINTAINER@ @PACKAGE_URL@ @PACKAGE_ISSUES@

@PACKAGE_SHORTNAME@ Doom is a conservative, historically-accurate Doom source port, which is compatible with the thousands of mods and levels that were made before the Doom source code was released. Unlike other source ports, the goal is to preserve the original look, feel, limitations, and bugs of the original DOS executable.

Full support for single- and multi-player games is provided, for all of the original Doom games, Chex Quest, and Hacx. Unlike the original executable, network play is implemented on the IP network stack, allowing it to function on modern LANs and the Internet.

http://www.chocolate-doom.org/wiki/images/9/97/GNOME_FreeDM_DEMO4.png FreeDM, DM05: Metal http://www.chocolate-doom.org/wiki/images/a/a6/GNOME_Doom_II_DEMO2.png Doom II, Level 5: The Waste Tunnels http://www.chocolate-doom.org/wiki/images/4/41/GNOME_Doomsday_of_UAC.png Doomsday of UAC (uac_dead.wad) http://www.chocolate-doom.org/wiki/images/2/2a/GNOME_Freedoom_DTWID_DEMO3.png Doom the Way id Did, on Freedoom. Level 3-2: City of Corpses
chocolate-doom-chocolate-doom-2.2.1/src/doom.desktop.in000066400000000000000000000003221257432200600230270ustar00rootroot00000000000000[Desktop Entry] Name=@PACKAGE_SHORTNAME@ Doom Exec=@PROGRAM_PREFIX@doom Icon=@PROGRAM_PREFIX@doom Type=Application Comment=@PACKAGE_SHORTDESC@ Categories=Game;ActionGame; Keywords=first;person;shooter;vanilla; chocolate-doom-chocolate-doom-2.2.1/src/doom/000077500000000000000000000000001257432200600210325ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/src/doom/.gitignore000066400000000000000000000000451257432200600230210ustar00rootroot00000000000000Makefile Makefile.in .deps tags TAGS chocolate-doom-chocolate-doom-2.2.1/src/doom/Makefile.am000066400000000000000000000051331257432200600230700ustar00rootroot00000000000000AM_CFLAGS = -I$(top_srcdir)/src @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@ noinst_LIBRARIES=libdoom.a SOURCE_FILES= \ am_map.c am_map.h \ d_englsh.h \ d_items.c d_items.h \ d_main.c d_main.h \ d_net.c \ doomdata.h \ doomdef.c doomdef.h \ doomstat.c doomstat.h \ d_player.h \ dstrings.c dstrings.h \ d_textur.h \ d_think.h \ f_finale.c f_finale.h \ f_wipe.c f_wipe.h \ g_game.c g_game.h \ hu_lib.c hu_lib.h \ hu_stuff.c hu_stuff.h \ info.c info.h \ m_menu.c m_menu.h \ m_random.c m_random.h \ p_ceilng.c \ p_doors.c \ p_enemy.c \ p_floor.c \ p_inter.c p_inter.h \ p_lights.c \ p_local.h \ p_map.c \ p_maputl.c \ p_mobj.c p_mobj.h \ p_plats.c \ p_pspr.c p_pspr.h \ p_saveg.c p_saveg.h \ p_setup.c p_setup.h \ p_sight.c \ p_spec.c p_spec.h \ p_switch.c \ p_telept.c \ p_tick.c p_tick.h \ p_user.c \ r_bsp.c r_bsp.h \ r_data.c r_data.h \ r_defs.h \ r_draw.c r_draw.h \ r_local.h \ r_main.c r_main.h \ r_plane.c r_plane.h \ r_segs.c r_segs.h \ r_sky.c r_sky.h \ r_state.h \ r_things.c r_things.h \ s_sound.c s_sound.h \ sounds.c sounds.h \ statdump.c statdump.h \ st_lib.c st_lib.h \ st_stuff.c st_stuff.h \ wi_stuff.c wi_stuff.h FEATURE_DEHACKED_SOURCE_FILES = \ deh_ammo.c \ deh_bexstr.c \ deh_cheat.c \ deh_doom.c \ deh_frame.c \ deh_misc.c deh_misc.h \ deh_ptr.c \ deh_sound.c \ deh_thing.c \ deh_weapon.c libdoom_a_SOURCES = $(SOURCE_FILES) \ $(FEATURE_DEHACKED_SOURCE_FILES) chocolate-doom-chocolate-doom-2.2.1/src/doom/am_map.c000066400000000000000000000662371257432200600224460ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: the automap code // #include #include "deh_main.h" #include "z_zone.h" #include "doomkeys.h" #include "doomdef.h" #include "st_stuff.h" #include "p_local.h" #include "w_wad.h" #include "m_cheat.h" #include "m_controls.h" #include "m_misc.h" #include "i_system.h" // Needs access to LFB. #include "v_video.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "dstrings.h" #include "am_map.h" // For use if I do walls with outsides/insides #define REDS (256-5*16) #define REDRANGE 16 #define BLUES (256-4*16+8) #define BLUERANGE 8 #define GREENS (7*16) #define GREENRANGE 16 #define GRAYS (6*16) #define GRAYSRANGE 16 #define BROWNS (4*16) #define BROWNRANGE 16 #define YELLOWS (256-32+7) #define YELLOWRANGE 1 #define BLACK 0 #define WHITE (256-47) // Automap colors #define BACKGROUND BLACK #define YOURCOLORS WHITE #define YOURRANGE 0 #define WALLCOLORS REDS #define WALLRANGE REDRANGE #define TSWALLCOLORS GRAYS #define TSWALLRANGE GRAYSRANGE #define FDWALLCOLORS BROWNS #define FDWALLRANGE BROWNRANGE #define CDWALLCOLORS YELLOWS #define CDWALLRANGE YELLOWRANGE #define THINGCOLORS GREENS #define THINGRANGE GREENRANGE #define SECRETWALLCOLORS WALLCOLORS #define SECRETWALLRANGE WALLRANGE #define GRIDCOLORS (GRAYS + GRAYSRANGE/2) #define GRIDRANGE 0 #define XHAIRCOLORS GRAYS // drawing stuff #define AM_NUMMARKPOINTS 10 // scale on entry #define INITSCALEMTOF (.2*FRACUNIT) // how much the automap moves window per tic in frame-buffer coordinates // moves 140 pixels in 1 second #define F_PANINC 4 // how much zoom-in per tic // goes to 2x in 1 second #define M_ZOOMIN ((int) (1.02*FRACUNIT)) // how much zoom-out per tic // pulls out to 0.5x in 1 second #define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // translates between frame-buffer and map distances #define FTOM(x) FixedMul(((x)<<16),scale_ftom) #define MTOF(x) (FixedMul((x),scale_mtof)>>16) // translates between frame-buffer and map coordinates #define CXMTOF(x) (f_x + MTOF((x)-m_x)) #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) // the following is crap #define LINE_NEVERSEE ML_DONTDRAW typedef struct { int x, y; } fpoint_t; typedef struct { fpoint_t a, b; } fline_t; typedef struct { fixed_t x,y; } mpoint_t; typedef struct { mpoint_t a, b; } mline_t; typedef struct { fixed_t slp, islp; } islope_t; // // The vector graphics for the automap. // A line drawing of the player pointing right, // starting from the middle. // #define R ((8*PLAYERRADIUS)/7) mline_t player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; #undef R #define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/6 } }, // -----> { { R, 0 }, { R-R/2, -R/6 } }, { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >-----> { { -R+R/8, 0 }, { -R-R/8, -R/6 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>-----> { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } }, { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d---> { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } }, { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } }, { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd--> { { -R/6, -R/6 }, { 0, -R/6 } }, { { 0, -R/6 }, { 0, R/4 } }, { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt-> { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } }; #undef R #define R (FRACUNIT) mline_t triangle_guy[] = { { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)(.867*R ), (fixed_t)(-.5*R) } }, { { (fixed_t)(.867*R ), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)(R ) } }, { { (fixed_t)(0 ), (fixed_t)(R ) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } }; #undef R #define R (FRACUNIT) mline_t thintriangle_guy[] = { { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } }, { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } }, { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } }; #undef R static int cheating = 0; static int grid = 0; static int leveljuststarted = 1; // kluge until AM_LevelInit() is called boolean automapactive = false; static int finit_width = SCREENWIDTH; static int finit_height = SCREENHEIGHT - 32; // location of window on screen static int f_x; static int f_y; // size of window on screen static int f_w; static int f_h; static int lightlev; // used for funky strobing effect static byte* fb; // pseudo-frame buffer static int amclock; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords) static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords) static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords) // // width/height of window on map (map coords) // static fixed_t m_w; static fixed_t m_h; // based on level size static fixed_t min_x; static fixed_t min_y; static fixed_t max_x; static fixed_t max_y; static fixed_t max_w; // max_x-min_x, static fixed_t max_h; // max_y-min_y // based on player size static fixed_t min_w; static fixed_t min_h; static fixed_t min_scale_mtof; // used to tell when to stop zooming out static fixed_t max_scale_mtof; // used to tell when to stop zooming in // old stuff for recovery later static fixed_t old_m_w, old_m_h; static fixed_t old_m_x, old_m_y; // old location used by the Follower routine static mpoint_t f_oldloc; // used by MTOF to scale from map-to-frame-buffer coords static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow static patch_t *marknums[10]; // numbers used for marking by the automap static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are static int markpointnum = 0; // next point to be assigned static int followplayer = 1; // specifies whether to follow the player around cheatseq_t cheat_amap = CHEAT("iddt", 0); static boolean stopped = true; // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so // that it can be used with the brain-dead drawing stuff. void AM_getIslope ( mline_t* ml, islope_t* is ) { int dx, dy; dy = ml->a.y - ml->b.y; dx = ml->b.x - ml->a.x; if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX); else is->islp = FixedDiv(dx, dy); if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX); else is->slp = FixedDiv(dy, dx); } // // // void AM_activateNewScale(void) { m_x += m_w/2; m_y += m_h/2; m_w = FTOM(f_w); m_h = FTOM(f_h); m_x -= m_w/2; m_y -= m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // // void AM_saveScaleAndLoc(void) { old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; } // // // void AM_restoreScaleAndLoc(void) { m_w = old_m_w; m_h = old_m_h; if (!followplayer) { m_x = old_m_x; m_y = old_m_y; } else { m_x = plr->mo->x - m_w/2; m_y = plr->mo->y - m_h/2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; // Change the scaling multipliers scale_mtof = FixedDiv(f_w< max_x) max_x = vertexes[i].x; if (vertexes[i].y < min_y) min_y = vertexes[i].y; else if (vertexes[i].y > max_y) max_y = vertexes[i].y; } max_w = max_x - min_x; max_h = max_y - min_y; min_w = 2*PLAYERRADIUS; // const? never changed? min_h = 2*PLAYERRADIUS; a = FixedDiv(f_w< max_x) m_x = max_x - m_w/2; else if (m_x + m_w/2 < min_x) m_x = min_x - m_w/2; if (m_y + m_h/2 > max_y) m_y = max_y - m_h/2; else if (m_y + m_h/2 < min_y) m_y = min_y - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // // void AM_initVariables(void) { int pnum; static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 }; automapactive = true; fb = I_VideoBuffer; f_oldloc.x = INT_MAX; amclock = 0; lightlev = 0; m_paninc.x = m_paninc.y = 0; ftom_zoommul = FRACUNIT; mtof_zoommul = FRACUNIT; m_w = FTOM(f_w); m_h = FTOM(f_h); // find player to center on initially if (playeringame[consoleplayer]) { plr = &players[consoleplayer]; } else { plr = &players[0]; for (pnum=0;pnummo->x - m_w/2; m_y = plr->mo->y - m_h/2; AM_changeWindowLoc(); // for saving & restoring old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; // inform the status bar of the change ST_Responder(&st_notify); } // // // void AM_loadPics(void) { int i; char namebuf[9]; for (i=0;i<10;i++) { DEH_snprintf(namebuf, 9, "AMMNUM%d", i); marknums[i] = W_CacheLumpName(namebuf, PU_STATIC); } } void AM_unloadPics(void) { int i; char namebuf[9]; for (i=0;i<10;i++) { DEH_snprintf(namebuf, 9, "AMMNUM%d", i); W_ReleaseLumpName(namebuf); } } void AM_clearMarks(void) { int i; for (i=0;i max_scale_mtof) scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } // // // void AM_Stop (void) { static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; AM_unloadPics(); automapactive = false; ST_Responder(&st_notify); stopped = true; } // // // void AM_Start (void) { static int lastlevel = -1, lastepisode = -1; if (!stopped) AM_Stop(); stopped = false; if (lastlevel != gamemap || lastepisode != gameepisode) { AM_LevelInit(); lastlevel = gamemap; lastepisode = gameepisode; } AM_initVariables(); AM_loadPics(); } // // set the window scale to the maximum size // void AM_minOutWindowScale(void) { scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // set the window scale to the minimum size // void AM_maxOutWindowScale(void) { scale_mtof = max_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // Handle events (user inputs) in automap mode // boolean AM_Responder ( event_t* ev ) { int rc; static int bigstate=0; static char buffer[20]; int key; rc = false; if (!automapactive) { if (ev->type == ev_keydown && ev->data1 == key_map_toggle) { AM_Start (); viewactive = false; rc = true; } } else if (ev->type == ev_keydown) { rc = true; key = ev->data1; if (key == key_map_east) // pan right { if (!followplayer) m_paninc.x = FTOM(F_PANINC); else rc = false; } else if (key == key_map_west) // pan left { if (!followplayer) m_paninc.x = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_north) // pan up { if (!followplayer) m_paninc.y = FTOM(F_PANINC); else rc = false; } else if (key == key_map_south) // pan down { if (!followplayer) m_paninc.y = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_zoomout) // zoom out { mtof_zoommul = M_ZOOMOUT; ftom_zoommul = M_ZOOMIN; } else if (key == key_map_zoomin) // zoom in { mtof_zoommul = M_ZOOMIN; ftom_zoommul = M_ZOOMOUT; } else if (key == key_map_toggle) { bigstate = 0; viewactive = true; AM_Stop (); } else if (key == key_map_maxzoom) { bigstate = !bigstate; if (bigstate) { AM_saveScaleAndLoc(); AM_minOutWindowScale(); } else AM_restoreScaleAndLoc(); } else if (key == key_map_follow) { followplayer = !followplayer; f_oldloc.x = INT_MAX; if (followplayer) plr->message = DEH_String(AMSTR_FOLLOWON); else plr->message = DEH_String(AMSTR_FOLLOWOFF); } else if (key == key_map_grid) { grid = !grid; if (grid) plr->message = DEH_String(AMSTR_GRIDON); else plr->message = DEH_String(AMSTR_GRIDOFF); } else if (key == key_map_mark) { M_snprintf(buffer, sizeof(buffer), "%s %d", DEH_String(AMSTR_MARKEDSPOT), markpointnum); plr->message = buffer; AM_addMark(); } else if (key == key_map_clearmark) { AM_clearMarks(); plr->message = DEH_String(AMSTR_MARKSCLEARED); } else { rc = false; } if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data2)) { rc = false; cheating = (cheating+1) % 3; } } else if (ev->type == ev_keyup) { rc = false; key = ev->data1; if (key == key_map_east) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_west) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_north) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_south) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_zoomout || key == key_map_zoomin) { mtof_zoommul = FRACUNIT; ftom_zoommul = FRACUNIT; } } return rc; } // // Zooming // void AM_changeWindowScale(void) { // Change the scaling multipliers scale_mtof = FixedMul(scale_mtof, mtof_zoommul); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); if (scale_mtof < min_scale_mtof) AM_minOutWindowScale(); else if (scale_mtof > max_scale_mtof) AM_maxOutWindowScale(); else AM_activateNewScale(); } // // // void AM_doFollowPlayer(void) { if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) { m_x = FTOM(MTOF(plr->mo->x)) - m_w/2; m_y = FTOM(MTOF(plr->mo->y)) - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; f_oldloc.x = plr->mo->x; f_oldloc.y = plr->mo->y; // m_x = FTOM(MTOF(plr->mo->x - m_w/2)); // m_y = FTOM(MTOF(plr->mo->y - m_h/2)); // m_x = plr->mo->x - m_w/2; // m_y = plr->mo->y - m_h/2; } } // // // void AM_updateLightLev(void) { static int nexttic = 0; //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 }; static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 }; static int litelevelscnt = 0; // Change light level if (amclock>nexttic) { lightlev = litelevels[litelevelscnt++]; if (litelevelscnt == arrlen(litelevels)) litelevelscnt = 0; nexttic = amclock + 6 - (amclock % 6); } } // // Updates on Game Tick // void AM_Ticker (void) { if (!automapactive) return; amclock++; if (followplayer) AM_doFollowPlayer(); // Change the zoom if necessary if (ftom_zoommul != FRACUNIT) AM_changeWindowScale(); // Change x,y location if (m_paninc.x || m_paninc.y) AM_changeWindowLoc(); // Update light level // AM_updateLightLev(); } // // Clear automap frame buffer. // void AM_clearFB(int color) { memset(fb, color, f_w*f_h); } // // Automap clipping of lines. // // Based on Cohen-Sutherland clipping algorithm but with a slightly // faster reject and precalculated slopes. If the speed is needed, // use a hash algorithm to handle the common cases. // boolean AM_clipMline ( mline_t* ml, fline_t* fl ) { enum { LEFT =1, RIGHT =2, BOTTOM =4, TOP =8 }; register int outcode1 = 0; register int outcode2 = 0; register int outside; fpoint_t tmp; int dx; int dy; #define DOOUTCODE(oc, mx, my) \ (oc) = 0; \ if ((my) < 0) (oc) |= TOP; \ else if ((my) >= f_h) (oc) |= BOTTOM; \ if ((mx) < 0) (oc) |= LEFT; \ else if ((mx) >= f_w) (oc) |= RIGHT; // do trivial rejects and outcodes if (ml->a.y > m_y2) outcode1 = TOP; else if (ml->a.y < m_y) outcode1 = BOTTOM; if (ml->b.y > m_y2) outcode2 = TOP; else if (ml->b.y < m_y) outcode2 = BOTTOM; if (outcode1 & outcode2) return false; // trivially outside if (ml->a.x < m_x) outcode1 |= LEFT; else if (ml->a.x > m_x2) outcode1 |= RIGHT; if (ml->b.x < m_x) outcode2 |= LEFT; else if (ml->b.x > m_x2) outcode2 |= RIGHT; if (outcode1 & outcode2) return false; // trivially outside // transform to frame-buffer coordinates. fl->a.x = CXMTOF(ml->a.x); fl->a.y = CYMTOF(ml->a.y); fl->b.x = CXMTOF(ml->b.x); fl->b.y = CYMTOF(ml->b.y); DOOUTCODE(outcode1, fl->a.x, fl->a.y); DOOUTCODE(outcode2, fl->b.x, fl->b.y); if (outcode1 & outcode2) return false; while (outcode1 | outcode2) { // may be partially inside box // find an outside point if (outcode1) outside = outcode1; else outside = outcode2; // clip to each side if (outside & TOP) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx*(fl->a.y))/dy; tmp.y = 0; } else if (outside & BOTTOM) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy; tmp.y = f_h-1; } else if (outside & RIGHT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx; tmp.x = f_w-1; } else if (outside & LEFT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; tmp.x = 0; } else { tmp.x = 0; tmp.y = 0; } if (outside == outcode1) { fl->a = tmp; DOOUTCODE(outcode1, fl->a.x, fl->a.y); } else { fl->b = tmp; DOOUTCODE(outcode2, fl->b.x, fl->b.y); } if (outcode1 & outcode2) return false; // trivially outside } return true; } #undef DOOUTCODE // // Classic Bresenham w/ whatever optimizations needed for speed // void AM_drawFline ( fline_t* fl, int color ) { register int x; register int y; register int dx; register int dy; register int sx; register int sy; register int ax; register int ay; register int d; static int fuck = 0; // For debugging only if ( fl->a.x < 0 || fl->a.x >= f_w || fl->a.y < 0 || fl->a.y >= f_h || fl->b.x < 0 || fl->b.x >= f_w || fl->b.y < 0 || fl->b.y >= f_h) { DEH_fprintf(stderr, "fuck %d \r", fuck++); return; } #define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) dx = fl->b.x - fl->a.x; ax = 2 * (dx<0 ? -dx : dx); sx = dx<0 ? -1 : 1; dy = fl->b.y - fl->a.y; ay = 2 * (dy<0 ? -dy : dy); sy = dy<0 ? -1 : 1; x = fl->a.x; y = fl->a.y; if (ax > ay) { d = ay - ax/2; while (1) { PUTDOT(x,y,color); if (x == fl->b.x) return; if (d>=0) { y += sy; d -= ax; } x += sx; d += ay; } } else { d = ax - ay/2; while (1) { PUTDOT(x, y, color); if (y == fl->b.y) return; if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; } } } // // Clip lines, draw visible part sof lines. // void AM_drawMline ( mline_t* ml, int color ) { static fline_t fl; if (AM_clipMline(ml, &fl)) AM_drawFline(&fl, color); // draws it on frame buffer using fb coords } // // Draws flat (floor/ceiling tile) aligned grid lines. // void AM_drawGrid(int color) { fixed_t x, y; fixed_t start, end; mline_t ml; // Figure out start of vertical gridlines start = m_x; if ((start-bmaporgx)%(MAPBLOCKUNITS<x; l.a.y = lines[i].v1->y; l.b.x = lines[i].v2->x; l.b.y = lines[i].v2->y; if (cheating || (lines[i].flags & ML_MAPPED)) { if ((lines[i].flags & LINE_NEVERSEE) && !cheating) continue; if (!lines[i].backsector) { AM_drawMline(&l, WALLCOLORS+lightlev); } else { if (lines[i].special == 39) { // teleporters AM_drawMline(&l, WALLCOLORS+WALLRANGE/2); } else if (lines[i].flags & ML_SECRET) // secret door { if (cheating) AM_drawMline(&l, SECRETWALLCOLORS + lightlev); else AM_drawMline(&l, WALLCOLORS+lightlev); } else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight) { AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change } else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight) { AM_drawMline(&l, CDWALLCOLORS+lightlev); // ceiling level change } else if (cheating) { AM_drawMline(&l, TSWALLCOLORS+lightlev); } } } else if (plr->powers[pw_allmap]) { if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3); } } } // // Rotation in 2D. // Used to rotate player arrow line character. // void AM_rotate ( fixed_t* x, fixed_t* y, angle_t a ) { fixed_t tmpx; tmpx = FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT]) - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]); *y = FixedMul(*x,finesine[a>>ANGLETOFINESHIFT]) + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]); *x = tmpx; } void AM_drawLineCharacter ( mline_t* lineguy, int lineguylines, fixed_t scale, angle_t angle, int color, fixed_t x, fixed_t y ) { int i; mline_t l; for (i=0;imo->angle, WHITE, plr->mo->x, plr->mo->y); else AM_drawLineCharacter (player_arrow, arrlen(player_arrow), 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y); return; } for (i=0;ipowers[pw_invisibility]) color = 246; // *close* to black else color = their_colors[their_color]; AM_drawLineCharacter (player_arrow, arrlen(player_arrow), 0, p->mo->angle, color, p->mo->x, p->mo->y); } } void AM_drawThings ( int colors, int colorrange) { int i; mobj_t* t; for (i=0;iangle, colors+lightlev, t->x, t->y); t = t->snext; } } } void AM_drawMarks(void) { int i, fx, fy, w, h; for (i=0;iwidth); // h = SHORT(marknums[i]->height); w = 5; // because something's wrong with the wad, i guess h = 6; // because something's wrong with the wad, i guess fx = CXMTOF(markpoints[i].x); fy = CYMTOF(markpoints[i].y); if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h) V_DrawPatch(fx, fy, marknums[i]); } } } void AM_drawCrosshair(int color) { fb[(f_w*(f_h+1))/2] = color; // single point for now } void AM_Drawer (void) { if (!automapactive) return; AM_clearFB(BACKGROUND); if (grid) AM_drawGrid(GRIDCOLORS); AM_drawWalls(); AM_drawPlayers(); if (cheating==2) AM_drawThings(THINGCOLORS, THINGRANGE); AM_drawCrosshair(XHAIRCOLORS); AM_drawMarks(); V_MarkRect(f_x, f_y, f_w, f_h); } chocolate-doom-chocolate-doom-2.2.1/src/doom/am_map.h000066400000000000000000000023331257432200600224360ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // AutoMap module. // #ifndef __AMMAP_H__ #define __AMMAP_H__ #include "d_event.h" #include "m_cheat.h" // Used by ST StatusBar stuff. #define AM_MSGHEADER (('a'<<24)+('m'<<16)) #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) #define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) // Called by main loop. boolean AM_Responder (event_t* ev); // Called by main loop. void AM_Ticker (void); // Called by main loop, // called instead of view drawer if automap active. void AM_Drawer (void); // Called to force the automap to quit // if the level is completed while it is up. void AM_Stop (void); extern cheatseq_t cheat_amap; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/d_englsh.h000066400000000000000000000523731257432200600230000ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Printed strings for translation. // English language support (default). // #ifndef __D_ENGLSH__ #define __D_ENGLSH__ // // Printed strings for translation // // // D_Main.C // #define D_DEVSTR "Development mode ON.\n" #define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n" // // M_Menu.C // #define PRESSKEY "press a key." #define PRESSYN "press y or n." #define QUITMSG "are you sure you want to\nquit this great game?" #define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY #define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY #define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY #define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY #define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN #define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN #define NEWGAME \ "you can't start a new game\n"\ "while in a network game.\n\n"PRESSKEY #define NIGHTMARE \ "are you sure? this skill level\n"\ "isn't even remotely fair.\n\n"PRESSYN #define SWSTRING \ "this is the shareware version of doom.\n\n"\ "you need to order the entire trilogy.\n\n"PRESSKEY #define MSGOFF "Messages OFF" #define MSGON "Messages ON" #define NETEND "you can't end a netgame!\n\n"PRESSKEY #define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN #define DOSY "(press y to quit to dos.)" #define DETAILHI "High detail" #define DETAILLO "Low detail" #define GAMMALVL0 "Gamma correction OFF" #define GAMMALVL1 "Gamma correction level 1" #define GAMMALVL2 "Gamma correction level 2" #define GAMMALVL3 "Gamma correction level 3" #define GAMMALVL4 "Gamma correction level 4" #define EMPTYSTRING "empty slot" // // P_inter.C // #define GOTARMOR "Picked up the armor." #define GOTMEGA "Picked up the MegaArmor!" #define GOTHTHBONUS "Picked up a health bonus." #define GOTARMBONUS "Picked up an armor bonus." #define GOTSTIM "Picked up a stimpack." #define GOTMEDINEED "Picked up a medikit that you REALLY need!" #define GOTMEDIKIT "Picked up a medikit." #define GOTSUPER "Supercharge!" #define GOTBLUECARD "Picked up a blue keycard." #define GOTYELWCARD "Picked up a yellow keycard." #define GOTREDCARD "Picked up a red keycard." #define GOTBLUESKUL "Picked up a blue skull key." #define GOTYELWSKUL "Picked up a yellow skull key." #define GOTREDSKULL "Picked up a red skull key." #define GOTINVUL "Invulnerability!" #define GOTBERSERK "Berserk!" #define GOTINVIS "Partial Invisibility" #define GOTSUIT "Radiation Shielding Suit" #define GOTMAP "Computer Area Map" #define GOTVISOR "Light Amplification Visor" #define GOTMSPHERE "MegaSphere!" #define GOTCLIP "Picked up a clip." #define GOTCLIPBOX "Picked up a box of bullets." #define GOTROCKET "Picked up a rocket." #define GOTROCKBOX "Picked up a box of rockets." #define GOTCELL "Picked up an energy cell." #define GOTCELLBOX "Picked up an energy cell pack." #define GOTSHELLS "Picked up 4 shotgun shells." #define GOTSHELLBOX "Picked up a box of shotgun shells." #define GOTBACKPACK "Picked up a backpack full of ammo!" #define GOTBFG9000 "You got the BFG9000! Oh, yes." #define GOTCHAINGUN "You got the chaingun!" #define GOTCHAINSAW "A chainsaw! Find some meat!" #define GOTLAUNCHER "You got the rocket launcher!" #define GOTPLASMA "You got the plasma gun!" #define GOTSHOTGUN "You got the shotgun!" #define GOTSHOTGUN2 "You got the super shotgun!" // // P_Doors.C // #define PD_BLUEO "You need a blue key to activate this object" #define PD_REDO "You need a red key to activate this object" #define PD_YELLOWO "You need a yellow key to activate this object" #define PD_BLUEK "You need a blue key to open this door" #define PD_REDK "You need a red key to open this door" #define PD_YELLOWK "You need a yellow key to open this door" // // G_game.C // #define GGSAVED "game saved." // // HU_stuff.C // #define HUSTR_MSGU "[Message unsent]" #define HUSTR_E1M1 "E1M1: Hangar" #define HUSTR_E1M2 "E1M2: Nuclear Plant" #define HUSTR_E1M3 "E1M3: Toxin Refinery" #define HUSTR_E1M4 "E1M4: Command Control" #define HUSTR_E1M5 "E1M5: Phobos Lab" #define HUSTR_E1M6 "E1M6: Central Processing" #define HUSTR_E1M7 "E1M7: Computer Station" #define HUSTR_E1M8 "E1M8: Phobos Anomaly" #define HUSTR_E1M9 "E1M9: Military Base" #define HUSTR_E2M1 "E2M1: Deimos Anomaly" #define HUSTR_E2M2 "E2M2: Containment Area" #define HUSTR_E2M3 "E2M3: Refinery" #define HUSTR_E2M4 "E2M4: Deimos Lab" #define HUSTR_E2M5 "E2M5: Command Center" #define HUSTR_E2M6 "E2M6: Halls of the Damned" #define HUSTR_E2M7 "E2M7: Spawning Vats" #define HUSTR_E2M8 "E2M8: Tower of Babel" #define HUSTR_E2M9 "E2M9: Fortress of Mystery" #define HUSTR_E3M1 "E3M1: Hell Keep" #define HUSTR_E3M2 "E3M2: Slough of Despair" #define HUSTR_E3M3 "E3M3: Pandemonium" #define HUSTR_E3M4 "E3M4: House of Pain" #define HUSTR_E3M5 "E3M5: Unholy Cathedral" #define HUSTR_E3M6 "E3M6: Mt. Erebus" #define HUSTR_E3M7 "E3M7: Limbo" #define HUSTR_E3M8 "E3M8: Dis" #define HUSTR_E3M9 "E3M9: Warrens" #define HUSTR_E4M1 "E4M1: Hell Beneath" #define HUSTR_E4M2 "E4M2: Perfect Hatred" #define HUSTR_E4M3 "E4M3: Sever The Wicked" #define HUSTR_E4M4 "E4M4: Unruly Evil" #define HUSTR_E4M5 "E4M5: They Will Repent" #define HUSTR_E4M6 "E4M6: Against Thee Wickedly" #define HUSTR_E4M7 "E4M7: And Hell Followed" #define HUSTR_E4M8 "E4M8: Unto The Cruel" #define HUSTR_E4M9 "E4M9: Fear" #define HUSTR_1 "level 1: entryway" #define HUSTR_2 "level 2: underhalls" #define HUSTR_3 "level 3: the gantlet" #define HUSTR_4 "level 4: the focus" #define HUSTR_5 "level 5: the waste tunnels" #define HUSTR_6 "level 6: the crusher" #define HUSTR_7 "level 7: dead simple" #define HUSTR_8 "level 8: tricks and traps" #define HUSTR_9 "level 9: the pit" #define HUSTR_10 "level 10: refueling base" #define HUSTR_11 "level 11: 'o' of destruction!" #define HUSTR_12 "level 12: the factory" #define HUSTR_13 "level 13: downtown" #define HUSTR_14 "level 14: the inmost dens" #define HUSTR_15 "level 15: industrial zone" #define HUSTR_16 "level 16: suburbs" #define HUSTR_17 "level 17: tenements" #define HUSTR_18 "level 18: the courtyard" #define HUSTR_19 "level 19: the citadel" #define HUSTR_20 "level 20: gotcha!" #define HUSTR_21 "level 21: nirvana" #define HUSTR_22 "level 22: the catacombs" #define HUSTR_23 "level 23: barrels o' fun" #define HUSTR_24 "level 24: the chasm" #define HUSTR_25 "level 25: bloodfalls" #define HUSTR_26 "level 26: the abandoned mines" #define HUSTR_27 "level 27: monster condo" #define HUSTR_28 "level 28: the spirit world" #define HUSTR_29 "level 29: the living end" #define HUSTR_30 "level 30: icon of sin" #define HUSTR_31 "level 31: wolfenstein" #define HUSTR_32 "level 32: grosse" #define PHUSTR_1 "level 1: congo" #define PHUSTR_2 "level 2: well of souls" #define PHUSTR_3 "level 3: aztec" #define PHUSTR_4 "level 4: caged" #define PHUSTR_5 "level 5: ghost town" #define PHUSTR_6 "level 6: baron's lair" #define PHUSTR_7 "level 7: caughtyard" #define PHUSTR_8 "level 8: realm" #define PHUSTR_9 "level 9: abattoire" #define PHUSTR_10 "level 10: onslaught" #define PHUSTR_11 "level 11: hunted" #define PHUSTR_12 "level 12: speed" #define PHUSTR_13 "level 13: the crypt" #define PHUSTR_14 "level 14: genesis" #define PHUSTR_15 "level 15: the twilight" #define PHUSTR_16 "level 16: the omen" #define PHUSTR_17 "level 17: compound" #define PHUSTR_18 "level 18: neurosphere" #define PHUSTR_19 "level 19: nme" #define PHUSTR_20 "level 20: the death domain" #define PHUSTR_21 "level 21: slayer" #define PHUSTR_22 "level 22: impossible mission" #define PHUSTR_23 "level 23: tombstone" #define PHUSTR_24 "level 24: the final frontier" #define PHUSTR_25 "level 25: the temple of darkness" #define PHUSTR_26 "level 26: bunker" #define PHUSTR_27 "level 27: anti-christ" #define PHUSTR_28 "level 28: the sewers" #define PHUSTR_29 "level 29: odyssey of noises" #define PHUSTR_30 "level 30: the gateway of hell" #define PHUSTR_31 "level 31: cyberden" #define PHUSTR_32 "level 32: go 2 it" #define THUSTR_1 "level 1: system control" #define THUSTR_2 "level 2: human bbq" #define THUSTR_3 "level 3: power control" #define THUSTR_4 "level 4: wormhole" #define THUSTR_5 "level 5: hanger" #define THUSTR_6 "level 6: open season" #define THUSTR_7 "level 7: prison" #define THUSTR_8 "level 8: metal" #define THUSTR_9 "level 9: stronghold" #define THUSTR_10 "level 10: redemption" #define THUSTR_11 "level 11: storage facility" #define THUSTR_12 "level 12: crater" #define THUSTR_13 "level 13: nukage processing" #define THUSTR_14 "level 14: steel works" #define THUSTR_15 "level 15: dead zone" #define THUSTR_16 "level 16: deepest reaches" #define THUSTR_17 "level 17: processing area" #define THUSTR_18 "level 18: mill" #define THUSTR_19 "level 19: shipping/respawning" #define THUSTR_20 "level 20: central processing" #define THUSTR_21 "level 21: administration center" #define THUSTR_22 "level 22: habitat" #define THUSTR_23 "level 23: lunar mining project" #define THUSTR_24 "level 24: quarry" #define THUSTR_25 "level 25: baron's den" #define THUSTR_26 "level 26: ballistyx" #define THUSTR_27 "level 27: mount pain" #define THUSTR_28 "level 28: heck" #define THUSTR_29 "level 29: river styx" #define THUSTR_30 "level 30: last call" #define THUSTR_31 "level 31: pharaoh" #define THUSTR_32 "level 32: caribbean" #define HUSTR_CHATMACRO1 "I'm ready to kick butt!" #define HUSTR_CHATMACRO2 "I'm OK." #define HUSTR_CHATMACRO3 "I'm not looking too good!" #define HUSTR_CHATMACRO4 "Help!" #define HUSTR_CHATMACRO5 "You suck!" #define HUSTR_CHATMACRO6 "Next time, scumbag..." #define HUSTR_CHATMACRO7 "Come here!" #define HUSTR_CHATMACRO8 "I'll take care of it." #define HUSTR_CHATMACRO9 "Yes" #define HUSTR_CHATMACRO0 "No" #define HUSTR_TALKTOSELF1 "You mumble to yourself" #define HUSTR_TALKTOSELF2 "Who's there?" #define HUSTR_TALKTOSELF3 "You scare yourself" #define HUSTR_TALKTOSELF4 "You start to rave" #define HUSTR_TALKTOSELF5 "You've lost it..." #define HUSTR_MESSAGESENT "[Message Sent]" // The following should NOT be changed unless it seems // just AWFULLY necessary #define HUSTR_PLRGREEN "Green: " #define HUSTR_PLRINDIGO "Indigo: " #define HUSTR_PLRBROWN "Brown: " #define HUSTR_PLRRED "Red: " #define HUSTR_KEYGREEN 'g' #define HUSTR_KEYINDIGO 'i' #define HUSTR_KEYBROWN 'b' #define HUSTR_KEYRED 'r' // // AM_map.C // #define AMSTR_FOLLOWON "Follow Mode ON" #define AMSTR_FOLLOWOFF "Follow Mode OFF" #define AMSTR_GRIDON "Grid ON" #define AMSTR_GRIDOFF "Grid OFF" #define AMSTR_MARKEDSPOT "Marked Spot" #define AMSTR_MARKSCLEARED "All Marks Cleared" // // ST_stuff.C // #define STSTR_MUS "Music Change" #define STSTR_NOMUS "IMPOSSIBLE SELECTION" #define STSTR_DQDON "Degreelessness Mode On" #define STSTR_DQDOFF "Degreelessness Mode Off" #define STSTR_KFAADDED "Very Happy Ammo Added" #define STSTR_FAADDED "Ammo (no keys) Added" #define STSTR_NCON "No Clipping Mode ON" #define STSTR_NCOFF "No Clipping Mode OFF" #define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" #define STSTR_BEHOLDX "Power-up Toggled" #define STSTR_CHOPPERS "... doesn't suck - GM" #define STSTR_CLEV "Changing Level..." // // F_Finale.C // #define E1TEXT \ "Once you beat the big badasses and\n"\ "clean out the moon base you're supposed\n"\ "to win, aren't you? Aren't you? Where's\n"\ "your fat reward and ticket home? What\n"\ "the hell is this? It's not supposed to\n"\ "end this way!\n"\ "\n" \ "It stinks like rotten meat, but looks\n"\ "like the lost Deimos base. Looks like\n"\ "you're stuck on The Shores of Hell.\n"\ "The only way out is through.\n"\ "\n"\ "To continue the DOOM experience, play\n"\ "The Shores of Hell and its amazing\n"\ "sequel, Inferno!\n" #define E2TEXT \ "You've done it! The hideous cyber-\n"\ "demon lord that ruled the lost Deimos\n"\ "moon base has been slain and you\n"\ "are triumphant! But ... where are\n"\ "you? You clamber to the edge of the\n"\ "moon and look down to see the awful\n"\ "truth.\n" \ "\n"\ "Deimos floats above Hell itself!\n"\ "You've never heard of anyone escaping\n"\ "from Hell, but you'll make the bastards\n"\ "sorry they ever heard of you! Quickly,\n"\ "you rappel down to the surface of\n"\ "Hell.\n"\ "\n" \ "Now, it's on to the final chapter of\n"\ "DOOM! -- Inferno." #define E3TEXT \ "The loathsome spiderdemon that\n"\ "masterminded the invasion of the moon\n"\ "bases and caused so much death has had\n"\ "its ass kicked for all time.\n"\ "\n"\ "A hidden doorway opens and you enter.\n"\ "You've proven too tough for Hell to\n"\ "contain, and now Hell at last plays\n"\ "fair -- for you emerge from the door\n"\ "to see the green fields of Earth!\n"\ "Home at last.\n" \ "\n"\ "You wonder what's been happening on\n"\ "Earth while you were battling evil\n"\ "unleashed. It's good that no Hell-\n"\ "spawn could have come through that\n"\ "door with you ..." #define E4TEXT \ "the spider mastermind must have sent forth\n"\ "its legions of hellspawn before your\n"\ "final confrontation with that terrible\n"\ "beast from hell. but you stepped forward\n"\ "and brought forth eternal damnation and\n"\ "suffering upon the horde as a true hero\n"\ "would in the face of something so evil.\n"\ "\n"\ "besides, someone was gonna pay for what\n"\ "happened to daisy, your pet rabbit.\n"\ "\n"\ "but now, you see spread before you more\n"\ "potential pain and gibbitude as a nation\n"\ "of demons run amok among our cities.\n"\ "\n"\ "next stop, hell on earth!" // after level 6, put this: #define C1TEXT \ "YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \ "STARPORT. BUT SOMETHING IS WRONG. THE\n" \ "MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \ "WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \ "IS BEING SUBVERTED BY THEIR PRESENCE.\n" \ "\n"\ "AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \ "FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \ "YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \ "OF THE STARBASE AND FIND THE CONTROLLING\n" \ "SWITCH WHICH HOLDS EARTH'S POPULATION\n" \ "HOSTAGE." // After level 11, put this: #define C2TEXT \ "YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \ "HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\ "THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\ "HUMAN LEFT ON THE FACE OF THE PLANET.\n"\ "CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\ "AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\ "YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\ "THAT YOU HAVE SAVED YOUR SPECIES.\n"\ "\n"\ "BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\ "MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\ "THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\ "GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\ "ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\ "YOUR OWN HOME CITY, NOT FAR FROM THE\n"\ "STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\ "UP AND RETURN TO THE FRAY." // After level 20, put this: #define C3TEXT \ "YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\ "SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\ "YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\ "ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\ "TEETH AND PLUNGE THROUGH IT.\n"\ "\n"\ "THERE MUST BE A WAY TO CLOSE IT ON THE\n"\ "OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\ "GOT TO GO THROUGH HELL TO GET TO IT?" // After level 29, put this: #define C4TEXT \ "THE HORRENDOUS VISAGE OF THE BIGGEST\n"\ "DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\ "YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\ "HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\ "UP AND DIES, ITS THRASHING LIMBS\n"\ "DEVASTATING UNTOLD MILES OF HELL'S\n"\ "SURFACE.\n"\ "\n"\ "YOU'VE DONE IT. THE INVASION IS OVER.\n"\ "EARTH IS SAVED. HELL IS A WRECK. YOU\n"\ "WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\ "DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\ "FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\ "HOME. REBUILDING EARTH OUGHT TO BE A\n"\ "LOT MORE FUN THAN RUINING IT WAS.\n" // Before level 31, put this: #define C5TEXT \ "CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\ "LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\ "HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\ "WHO THE INMATES OF THIS CORNER OF HELL\n"\ "WILL BE." // Before level 32, put this: #define C6TEXT \ "CONGRATULATIONS, YOU'VE FOUND THE\n"\ "SUPER SECRET LEVEL! YOU'D BETTER\n"\ "BLAZE THROUGH THIS ONE!\n" // after map 06 #define P1TEXT \ "You gloat over the steaming carcass of the\n"\ "Guardian. With its death, you've wrested\n"\ "the Accelerator from the stinking claws\n"\ "of Hell. You relax and glance around the\n"\ "room. Damn! There was supposed to be at\n"\ "least one working prototype, but you can't\n"\ "see it. The demons must have taken it.\n"\ "\n"\ "You must find the prototype, or all your\n"\ "struggles will have been wasted. Keep\n"\ "moving, keep fighting, keep killing.\n"\ "Oh yes, keep living, too." // after map 11 #define P2TEXT \ "Even the deadly Arch-Vile labyrinth could\n"\ "not stop you, and you've gotten to the\n"\ "prototype Accelerator which is soon\n"\ "efficiently and permanently deactivated.\n"\ "\n"\ "You're good at that kind of thing." // after map 20 #define P3TEXT \ "You've bashed and battered your way into\n"\ "the heart of the devil-hive. Time for a\n"\ "Search-and-Destroy mission, aimed at the\n"\ "Gatekeeper, whose foul offspring is\n"\ "cascading to Earth. Yeah, he's bad. But\n"\ "you know who's worse!\n"\ "\n"\ "Grinning evilly, you check your gear, and\n"\ "get ready to give the bastard a little Hell\n"\ "of your own making!" // after map 30 #define P4TEXT \ "The Gatekeeper's evil face is splattered\n"\ "all over the place. As its tattered corpse\n"\ "collapses, an inverted Gate forms and\n"\ "sucks down the shards of the last\n"\ "prototype Accelerator, not to mention the\n"\ "few remaining demons. You're done. Hell\n"\ "has gone back to pounding bad dead folks \n"\ "instead of good live ones. Remember to\n"\ "tell your grandkids to put a rocket\n"\ "launcher in your coffin. If you go to Hell\n"\ "when you die, you'll need it for some\n"\ "final cleaning-up ..." // before map 31 #define P5TEXT \ "You've found the second-hardest level we\n"\ "got. Hope you have a saved game a level or\n"\ "two previous. If not, be prepared to die\n"\ "aplenty. For master marines only." // before map 32 #define P6TEXT \ "Betcha wondered just what WAS the hardest\n"\ "level we had ready for ya? Now you know.\n"\ "No one gets out alive." #define T1TEXT \ "You've fought your way out of the infested\n"\ "experimental labs. It seems that UAC has\n"\ "once again gulped it down. With their\n"\ "high turnover, it must be hard for poor\n"\ "old UAC to buy corporate health insurance\n"\ "nowadays..\n"\ "\n"\ "Ahead lies the military complex, now\n"\ "swarming with diseased horrors hot to get\n"\ "their teeth into you. With luck, the\n"\ "complex still has some warlike ordnance\n"\ "laying around." #define T2TEXT \ "You hear the grinding of heavy machinery\n"\ "ahead. You sure hope they're not stamping\n"\ "out new hellspawn, but you're ready to\n"\ "ream out a whole herd if you have to.\n"\ "They might be planning a blood feast, but\n"\ "you feel about as mean as two thousand\n"\ "maniacs packed into one mad killer.\n"\ "\n"\ "You don't plan to go down easy." #define T3TEXT \ "The vista opening ahead looks real damn\n"\ "familiar. Smells familiar, too -- like\n"\ "fried excrement. You didn't like this\n"\ "place before, and you sure as hell ain't\n"\ "planning to like it now. The more you\n"\ "brood on it, the madder you get.\n"\ "Hefting your gun, an evil grin trickles\n"\ "onto your face. Time to take some names." #define T4TEXT \ "Suddenly, all is silent, from one horizon\n"\ "to the other. The agonizing echo of Hell\n"\ "fades away, the nightmare sky turns to\n"\ "blue, the heaps of monster corpses start \n"\ "to evaporate along with the evil stench \n"\ "that filled the air. Jeeze, maybe you've\n"\ "done it. Have you really won?\n"\ "\n"\ "Something rumbles in the distance.\n"\ "A blue light begins to glow inside the\n"\ "ruined skull of the demon-spitter." #define T5TEXT \ "What now? Looks totally different. Kind\n"\ "of like King Tut's condo. Well,\n"\ "whatever's here can't be any worse\n"\ "than usual. Can it? Or maybe it's best\n"\ "to let sleeping gods lie.." #define T6TEXT \ "Time for a vacation. You've burst the\n"\ "bowels of hell and by golly you're ready\n"\ "for a break. You mutter to yourself,\n"\ "Maybe someone else can kick Hell's ass\n"\ "next time around. Ahead lies a quiet town,\n"\ "with peaceful flowing water, quaint\n"\ "buildings, and presumably no Hellspawn.\n"\ "\n"\ "As you step off the transport, you hear\n"\ "the stomp of a cyberdemon's iron shoe." // // Character cast strings F_FINALE.C // #define CC_ZOMBIE "ZOMBIEMAN" #define CC_SHOTGUN "SHOTGUN GUY" #define CC_HEAVY "HEAVY WEAPON DUDE" #define CC_IMP "IMP" #define CC_DEMON "DEMON" #define CC_LOST "LOST SOUL" #define CC_CACO "CACODEMON" #define CC_HELL "HELL KNIGHT" #define CC_BARON "BARON OF HELL" #define CC_ARACH "ARACHNOTRON" #define CC_PAIN "PAIN ELEMENTAL" #define CC_REVEN "REVENANT" #define CC_MANCU "MANCUBUS" #define CC_ARCH "ARCH-VILE" #define CC_SPIDER "THE SPIDER MASTERMIND" #define CC_CYBER "THE CYBERDEMON" #define CC_HERO "OUR HERO" #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/d_items.c000066400000000000000000000035141257432200600226250ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // We are referring to sprite numbers. #include "info.h" #include "d_items.h" // // PSPRITE ACTIONS for waepons. // This struct controls the weapon animations. // // Each entry is: // ammo/amunition type // upstate // downstate // readystate // atkstate, i.e. attack/fire/hit frame // flashstate, muzzle flash // weaponinfo_t weaponinfo[NUMWEAPONS] = { { // fist am_noammo, S_PUNCHUP, S_PUNCHDOWN, S_PUNCH, S_PUNCH1, S_NULL }, { // pistol am_clip, S_PISTOLUP, S_PISTOLDOWN, S_PISTOL, S_PISTOL1, S_PISTOLFLASH }, { // shotgun am_shell, S_SGUNUP, S_SGUNDOWN, S_SGUN, S_SGUN1, S_SGUNFLASH1 }, { // chaingun am_clip, S_CHAINUP, S_CHAINDOWN, S_CHAIN, S_CHAIN1, S_CHAINFLASH1 }, { // missile launcher am_misl, S_MISSILEUP, S_MISSILEDOWN, S_MISSILE, S_MISSILE1, S_MISSILEFLASH1 }, { // plasma rifle am_cell, S_PLASMAUP, S_PLASMADOWN, S_PLASMA, S_PLASMA1, S_PLASMAFLASH1 }, { // bfg 9000 am_cell, S_BFGUP, S_BFGDOWN, S_BFG, S_BFG1, S_BFGFLASH1 }, { // chainsaw am_noammo, S_SAWUP, S_SAWDOWN, S_SAW, S_SAW1, S_NULL }, { // super shotgun am_shell, S_DSGUNUP, S_DSGUNDOWN, S_DSGUN, S_DSGUN1, S_DSGUNFLASH1 }, }; chocolate-doom-chocolate-doom-2.2.1/src/doom/d_items.h000066400000000000000000000017351257432200600226350ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Items: key cards, artifacts, weapon, ammunition. // #ifndef __D_ITEMS__ #define __D_ITEMS__ #include "doomdef.h" // Weapon info: sprite frames, ammunition use. typedef struct { ammotype_t ammo; int upstate; int downstate; int readystate; int atkstate; int flashstate; } weaponinfo_t; extern weaponinfo_t weaponinfo[NUMWEAPONS]; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/d_main.c000066400000000000000000001276231257432200600224400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM main program (D_DoomMain) and game loop (D_DoomLoop), // plus functions to determine game mode (shareware, registered), // parse command line parameters, configure game parameters (turbo), // and call the startup functions. // #include #include #include #include #include "config.h" #include "deh_main.h" #include "doomdef.h" #include "doomstat.h" #include "dstrings.h" #include "doomfeatures.h" #include "sounds.h" #include "d_iwad.h" #include "z_zone.h" #include "w_main.h" #include "w_wad.h" #include "s_sound.h" #include "v_video.h" #include "f_finale.h" #include "f_wipe.h" #include "m_argv.h" #include "m_config.h" #include "m_controls.h" #include "m_misc.h" #include "m_menu.h" #include "p_saveg.h" #include "i_endoom.h" #include "i_joystick.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "g_game.h" #include "hu_stuff.h" #include "wi_stuff.h" #include "st_stuff.h" #include "am_map.h" #include "net_client.h" #include "net_dedicated.h" #include "net_query.h" #include "p_setup.h" #include "r_local.h" #include "statdump.h" #include "d_main.h" // // D-DoomLoop() // Not a globally visible function, // just included for source reference, // called by D_DoomMain, never exits. // Manages timing and IO, // calls all ?_Responder, ?_Ticker, and ?_Drawer, // calls I_GetTime, I_StartFrame, and I_StartTic // void D_DoomLoop (void); // Location where savegames are stored char * savegamedir; // location of IWAD and WAD files char * iwadfile; boolean devparm; // started game with -devparm boolean nomonsters; // checkparm of -nomonsters boolean respawnparm; // checkparm of -respawn boolean fastparm; // checkparm of -fast //extern int soundVolume; //extern int sfxVolume; //extern int musicVolume; extern boolean inhelpscreens; skill_t startskill; int startepisode; int startmap; boolean autostart; int startloadgame; boolean advancedemo; // Store demo, do not accept any inputs boolean storedemo; // "BFG Edition" version of doom2.wad does not include TITLEPIC. boolean bfgedition; // If true, the main game loop has started. boolean main_loop_started = false; char wadfile[1024]; // primary wad file char mapdir[1024]; // directory of development maps int show_endoom = 1; void D_ConnectNetGame(void); void D_CheckNetGame(void); // // D_ProcessEvents // Send all the events of the given timestamp down the responder chain // void D_ProcessEvents (void) { event_t* ev; // IF STORE DEMO, DO NOT ACCEPT INPUT if (storedemo) return; while ((ev = D_PopEvent()) != NULL) { if (M_Responder (ev)) continue; // menu ate the event G_Responder (ev); } } // // D_Display // draw current display, possibly wiping it from the previous // // wipegamestate can be set to -1 to force a wipe on the next draw gamestate_t wipegamestate = GS_DEMOSCREEN; extern boolean setsizeneeded; extern int showMessages; void R_ExecuteSetViewSize (void); void D_Display (void) { static boolean viewactivestate = false; static boolean menuactivestate = false; static boolean inhelpscreensstate = false; static boolean fullscreen = false; static gamestate_t oldgamestate = -1; static int borderdrawcount; int nowtime; int tics; int wipestart; int y; boolean done; boolean wipe; boolean redrawsbar; if (nodrawers) return; // for comparative timing / profiling redrawsbar = false; // change the view size if needed if (setsizeneeded) { R_ExecuteSetViewSize (); oldgamestate = -1; // force background redraw borderdrawcount = 3; } // save the current screen if about to wipe if (gamestate != wipegamestate) { wipe = true; wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); } else wipe = false; if (gamestate == GS_LEVEL && gametic) HU_Erase(); // do buffered drawing switch (gamestate) { case GS_LEVEL: if (!gametic) break; if (automapactive) AM_Drawer (); if (wipe || (viewheight != 200 && fullscreen) ) redrawsbar = true; if (inhelpscreensstate && !inhelpscreens) redrawsbar = true; // just put away the help screen ST_Drawer (viewheight == 200, redrawsbar ); fullscreen = viewheight == 200; break; case GS_INTERMISSION: WI_Drawer (); break; case GS_FINALE: F_Drawer (); break; case GS_DEMOSCREEN: D_PageDrawer (); break; } // draw buffered stuff to screen I_UpdateNoBlit (); // draw the view directly if (gamestate == GS_LEVEL && !automapactive && gametic) R_RenderPlayerView (&players[displayplayer]); if (gamestate == GS_LEVEL && gametic) HU_Drawer (); // clean up border stuff if (gamestate != oldgamestate && gamestate != GS_LEVEL) I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE)); // see if the border needs to be initially drawn if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL) { viewactivestate = false; // view was not active R_FillBackScreen (); // draw the pattern into the back screen } // see if the border needs to be updated to the screen if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320) { if (menuactive || menuactivestate || !viewactivestate) borderdrawcount = 3; if (borderdrawcount) { R_DrawViewBorder (); // erase old menu stuff borderdrawcount--; } } if (testcontrols) { // Box showing current mouse speed V_DrawMouseSpeedBox(testcontrols_mousespeed); } menuactivestate = menuactive; viewactivestate = viewactive; inhelpscreensstate = inhelpscreens; oldgamestate = wipegamestate = gamestate; // draw pause pic if (paused) { if (automapactive) y = 4; else y = viewwindowy+4; V_DrawPatchDirect(viewwindowx + (scaledviewwidth - 68) / 2, y, W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE)); } // menus go directly to the screen M_Drawer (); // menu is drawn even on top of everything NetUpdate (); // send out any new accumulation // normal update if (!wipe) { I_FinishUpdate (); // page flip or blit buffer return; } // wipe update wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); wipestart = I_GetTime () - 1; do { do { nowtime = I_GetTime (); tics = nowtime - wipestart; I_Sleep(1); } while (tics <= 0); wipestart = nowtime; done = wipe_ScreenWipe(wipe_Melt , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics); I_UpdateNoBlit (); M_Drawer (); // menu is drawn even on top of wipes I_FinishUpdate (); // page flip or blit buffer } while (!done); } // // Add configuration file variable bindings. // void D_BindVariables(void) { int i; M_ApplyPlatformDefaults(); I_BindVideoVariables(); I_BindJoystickVariables(); I_BindSoundVariables(); M_BindBaseControls(); M_BindWeaponControls(); M_BindMapControls(); M_BindMenuControls(); M_BindChatControls(MAXPLAYERS); key_multi_msgplayer[0] = HUSTR_KEYGREEN; key_multi_msgplayer[1] = HUSTR_KEYINDIGO; key_multi_msgplayer[2] = HUSTR_KEYBROWN; key_multi_msgplayer[3] = HUSTR_KEYRED; #ifdef FEATURE_MULTIPLAYER NET_BindVariables(); #endif M_BindIntVariable("mouse_sensitivity", &mouseSensitivity); M_BindIntVariable("sfx_volume", &sfxVolume); M_BindIntVariable("music_volume", &musicVolume); M_BindIntVariable("show_messages", &showMessages); M_BindIntVariable("screenblocks", &screenblocks); M_BindIntVariable("detaillevel", &detailLevel); M_BindIntVariable("snd_channels", &snd_channels); M_BindIntVariable("vanilla_savegame_limit", &vanilla_savegame_limit); M_BindIntVariable("vanilla_demo_limit", &vanilla_demo_limit); M_BindIntVariable("show_endoom", &show_endoom); // Multiplayer chat macros for (i=0; i<10; ++i) { char buf[12]; M_snprintf(buf, sizeof(buf), "chatmacro%i", i); M_BindStringVariable(buf, &chat_macros[i]); } } // // D_GrabMouseCallback // // Called to determine whether to grab the mouse pointer // boolean D_GrabMouseCallback(void) { // Drone players don't need mouse focus if (drone) return false; // when menu is active or game is paused, release the mouse if (menuactive || paused) return false; // only grab mouse when playing levels (but not demos) return (gamestate == GS_LEVEL) && !demoplayback && !advancedemo; } // // D_DoomLoop // void D_DoomLoop (void) { if (bfgedition && (demorecording || (gameaction == ga_playdemo) || netgame)) { printf(" WARNING: You are playing using one of the Doom Classic\n" " IWAD files shipped with the Doom 3: BFG Edition. These are\n" " known to be incompatible with the regular IWAD files and\n" " may cause demos and network games to get out of sync.\n"); } if (demorecording) G_BeginRecording (); main_loop_started = true; TryRunTics(); I_SetWindowTitle(gamedescription); I_GraphicsCheckCommandLine(); I_SetGrabMouseCallback(D_GrabMouseCallback); I_InitGraphics(); I_EnableLoadingDisk(); V_RestoreBuffer(); R_ExecuteSetViewSize(); D_StartGameLoop(); if (testcontrols) { wipegamestate = gamestate; } while (1) { // frame syncronous IO operations I_StartFrame (); TryRunTics (); // will run at least one tic S_UpdateSounds (players[consoleplayer].mo);// move positional sounds // Update display, next frame, with current state. if (screenvisible) D_Display (); } } // // DEMO LOOP // int demosequence; int pagetic; char *pagename; // // D_PageTicker // Handles timing for warped projection // void D_PageTicker (void) { if (--pagetic < 0) D_AdvanceDemo (); } // // D_PageDrawer // void D_PageDrawer (void) { V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE)); } // // D_AdvanceDemo // Called after each demo or intro demosequence finishes // void D_AdvanceDemo (void) { advancedemo = true; } // // This cycles through the demo sequences. // FIXME - version dependend demo numbers? // void D_DoAdvanceDemo (void) { players[consoleplayer].playerstate = PST_LIVE; // not reborn advancedemo = false; usergame = false; // no save / end game here paused = false; gameaction = ga_nothing; // The Ultimate Doom executable changed the demo sequence to add // a DEMO4 demo. Final Doom was based on Ultimate, so also // includes this change; however, the Final Doom IWADs do not // include a DEMO4 lump, so the game bombs out with an error // when it reaches this point in the demo sequence. // However! There is an alternate version of Final Doom that // includes a fixed executable. if (gameversion == exe_ultimate || gameversion == exe_final) demosequence = (demosequence+1)%7; else demosequence = (demosequence+1)%6; switch (demosequence) { case 0: if ( gamemode == commercial ) pagetic = TICRATE * 11; else pagetic = 170; gamestate = GS_DEMOSCREEN; pagename = DEH_String("TITLEPIC"); if ( gamemode == commercial ) S_StartMusic(mus_dm2ttl); else S_StartMusic (mus_intro); break; case 1: G_DeferedPlayDemo(DEH_String("demo1")); break; case 2: pagetic = 200; gamestate = GS_DEMOSCREEN; pagename = DEH_String("CREDIT"); break; case 3: G_DeferedPlayDemo(DEH_String("demo2")); break; case 4: gamestate = GS_DEMOSCREEN; if ( gamemode == commercial) { pagetic = TICRATE * 11; pagename = DEH_String("TITLEPIC"); S_StartMusic(mus_dm2ttl); } else { pagetic = 200; if ( gamemode == retail ) pagename = DEH_String("CREDIT"); else pagename = DEH_String("HELP2"); } break; case 5: G_DeferedPlayDemo(DEH_String("demo3")); break; // THE DEFINITIVE DOOM Special Edition demo case 6: G_DeferedPlayDemo(DEH_String("demo4")); break; } // The Doom 3: BFG Edition version of doom2.wad does not have a // TITLETPIC lump. Use INTERPIC instead as a workaround. if (bfgedition && !strcasecmp(pagename, "TITLEPIC") && W_CheckNumForName("titlepic") < 0) { pagename = DEH_String("INTERPIC"); } } // // D_StartTitle // void D_StartTitle (void) { gameaction = ga_nothing; demosequence = -1; D_AdvanceDemo (); } // Strings for dehacked replacements of the startup banner // // These are from the original source: some of them are perhaps // not used in any dehacked patches static char *banners[] = { // doom2.wad " " "DOOM 2: Hell on Earth v%i.%i" " ", // doom1.wad " " "DOOM Shareware Startup v%i.%i" " ", // doom.wad " " "DOOM Registered Startup v%i.%i" " ", // Registered DOOM uses this " " "DOOM System Startup v%i.%i" " ", // doom.wad (Ultimate DOOM) " " "The Ultimate DOOM Startup v%i.%i" " ", // tnt.wad " " "DOOM 2: TNT - Evilution v%i.%i" " ", // plutonia.wad " " "DOOM 2: Plutonia Experiment v%i.%i" " ", }; // // Get game name: if the startup banner has been replaced, use that. // Otherwise, use the name given // static char *GetGameName(char *gamename) { size_t i; char *deh_sub; for (i=0; i 0) { // Ultimate Doom gamemode = retail; } else if (W_CheckNumForName("E3M1") > 0) { gamemode = registered; } else { gamemode = shareware; } } else { int p; // Doom 2 of some kind. gamemode = commercial; // We can manually override the gamemission that we got from the // IWAD detection code. This allows us to eg. play Plutonia 2 // with Freedoom and get the right level names. //! // @arg // // Explicitly specify a Doom II "mission pack" to run as, instead of // detecting it based on the filename. Valid values are: "doom2", // "tnt" and "plutonia". // p = M_CheckParmWithArgs("-pack", 1); if (p > 0) { SetMissionForPackName(myargv[p + 1]); } } } // Set the gamedescription string void D_SetGameDescription(void) { boolean is_freedoom = W_CheckNumForName("FREEDOOM") >= 0, is_freedm = W_CheckNumForName("FREEDM") >= 0; gamedescription = "Unknown"; if (logical_gamemission == doom) { // Doom 1. But which version? if (is_freedoom) { gamedescription = GetGameName("Freedoom: Phase 1"); } else if (gamemode == retail) { // Ultimate Doom gamedescription = GetGameName("The Ultimate DOOM"); } else if (gamemode == registered) { gamedescription = GetGameName("DOOM Registered"); } else if (gamemode == shareware) { gamedescription = GetGameName("DOOM Shareware"); } } else { // Doom 2 of some kind. But which mission? if (is_freedoom) { if (is_freedm) { gamedescription = GetGameName("FreeDM"); } else { gamedescription = GetGameName("Freedoom: Phase 2"); } } else if (logical_gamemission == doom2) { gamedescription = GetGameName("DOOM 2: Hell on Earth"); } else if (logical_gamemission == pack_plut) { gamedescription = GetGameName("DOOM 2: Plutonia Experiment"); } else if (logical_gamemission == pack_tnt) { gamedescription = GetGameName("DOOM 2: TNT - Evilution"); } } } // print title for every printed line char title[128]; static boolean D_AddFile(char *filename) { wad_file_t *handle; printf(" adding %s\n", filename); handle = W_AddFile(filename); return handle != NULL; } // Copyright message banners // Some dehacked mods replace these. These are only displayed if they are // replaced by dehacked. static char *copyright_banners[] = { "===========================================================================\n" "ATTENTION: This version of DOOM has been modified. If you would like to\n" "get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n" " You will not receive technical support for modified games.\n" " press enter to continue\n" "===========================================================================\n", "===========================================================================\n" " Commercial product - do not distribute!\n" " Please report software piracy to the SPA: 1-800-388-PIR8\n" "===========================================================================\n", "===========================================================================\n" " Shareware!\n" "===========================================================================\n" }; // Prints a message only if it has been modified by dehacked. void PrintDehackedBanners(void) { size_t i; for (i=0; i // @category compat // // Emulate a specific version of Doom. Valid values are "1.9", // "ultimate", "final", "final2", "hacx" and "chex". // p = M_CheckParmWithArgs("-gameversion", 1); if (p) { for (i=0; gameversions[i].description != NULL; ++i) { if (!strcmp(myargv[p+1], gameversions[i].cmdline)) { gameversion = gameversions[i].version; break; } } if (gameversions[i].description == NULL) { printf("Supported game versions:\n"); for (i=0; gameversions[i].description != NULL; ++i) { printf("\t%s (%s)\n", gameversions[i].cmdline, gameversions[i].description); } I_Error("Unknown game version '%s'", myargv[p+1]); } } else { // Determine automatically if (gamemission == pack_chex) { // chex.exe - identified by iwad filename gameversion = exe_chex; } else if (gamemission == pack_hacx) { // hacx.exe: identified by iwad filename gameversion = exe_hacx; } else if (gamemode == shareware || gamemode == registered) { // original gameversion = exe_doom_1_9; // TODO: Detect IWADs earlier than Doom v1.9. } else if (gamemode == retail) { gameversion = exe_ultimate; } else if (gamemode == commercial) { if (gamemission == doom2) { gameversion = exe_doom_1_9; } else { // Final Doom: tnt or plutonia // Defaults to emulating the first Final Doom executable, // which has the crash in the demo loop; however, having // this as the default should mean that it plays back // most demos correctly. gameversion = exe_final; } } } // The original exe does not support retail - 4th episode not supported if (gameversion < exe_ultimate && gamemode == retail) { gamemode = registered; } // EXEs prior to the Final Doom exes do not support Final Doom. if (gameversion < exe_final && gamemode == commercial && (gamemission == pack_tnt || gamemission == pack_plut)) { gamemission = doom2; } } void PrintGameVersion(void) { int i; for (i=0; gameversions[i].description != NULL; ++i) { if (gameversions[i].version == gameversion) { printf("Emulating the behavior of the " "'%s' executable.\n", gameversions[i].description); break; } } } // Function called at exit to display the ENDOOM screen static void D_Endoom(void) { byte *endoom; // Don't show ENDOOM if we have it disabled, or we're running // in screensaver or control test mode. Only show it once the // game has actually started. if (!show_endoom || !main_loop_started || screensaver_mode || M_CheckParm("-testcontrols") > 0) { return; } endoom = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC); I_Endoom(endoom); } // Load dehacked patches needed for certain IWADs. static void LoadIwadDeh(void) { // The Freedoom IWADs have DEHACKED lumps that must be loaded. if (W_CheckNumForName("FREEDOOM") >= 0) { // Old versions of Freedoom (before 2014-09) did not have technically // valid DEHACKED lumps, so ignore errors and just continue if this // is an old IWAD. DEH_LoadLumpByName("DEHACKED", false, true); } // If this is the HACX IWAD, we need to load the DEHACKED lump. if (gameversion == exe_hacx) { if (!DEH_LoadLumpByName("DEHACKED", true, false)) { I_Error("DEHACKED lump not found. Please check that this is the " "Hacx v1.2 IWAD."); } } // Chex Quest needs a separate Dehacked patch which must be downloaded // and installed next to the IWAD. if (gameversion == exe_chex) { char *chex_deh = NULL; char *sep; // Look for chex.deh in the same directory as the IWAD file. sep = strrchr(iwadfile, DIR_SEPARATOR); if (sep != NULL) { size_t chex_deh_len = strlen(iwadfile) + 9; chex_deh = malloc(chex_deh_len); M_StringCopy(chex_deh, iwadfile, chex_deh_len); chex_deh[sep - iwadfile + 1] = '\0'; M_StringConcat(chex_deh, "chex.deh", chex_deh_len); } else { chex_deh = M_StringDuplicate("chex.deh"); } // If the dehacked patch isn't found, try searching the WAD // search path instead. We might find it... if (!M_FileExists(chex_deh)) { free(chex_deh); chex_deh = D_FindWADByName("chex.deh"); } // Still not found? if (chex_deh == NULL) { I_Error("Unable to find Chex Quest dehacked file (chex.deh).\n" "The dehacked file is required in order to emulate\n" "chex.exe correctly. It can be found in your nearest\n" "/idgames repository mirror at:\n\n" " utils/exe_edit/patches/chexdeh.zip"); } if (!DEH_LoadFile(chex_deh)) { I_Error("Failed to load chex.deh needed for emulating chex.exe."); } } } static void G_CheckDemoStatusAtExit (void) { G_CheckDemoStatus(); } // // D_DoomMain // void D_DoomMain (void) { int p; char file[256]; char demolumpname[9]; int numiwadlumps; I_AtExit(D_Endoom, false); // print banner I_PrintBanner(PACKAGE_STRING); DEH_printf("Z_Init: Init zone memory allocation daemon. \n"); Z_Init (); #ifdef FEATURE_MULTIPLAYER //! // @category net // // Start a dedicated server, routing packets but not participating // in the game itself. // if (M_CheckParm("-dedicated") > 0) { printf("Dedicated server mode.\n"); NET_DedicatedServer(); // Never returns } //! // @category net // // Query the Internet master server for a global list of active // servers. // if (M_CheckParm("-search")) { NET_MasterQuery(); exit(0); } //! // @arg
// @category net // // Query the status of the server running on the given IP // address. // p = M_CheckParmWithArgs("-query", 1); if (p) { NET_QueryAddress(myargv[p+1]); exit(0); } //! // @category net // // Search the local LAN for running servers. // if (M_CheckParm("-localsearch")) { NET_LANQuery(); exit(0); } #endif //! // @vanilla // // Disable monsters. // nomonsters = M_CheckParm ("-nomonsters"); //! // @vanilla // // Monsters respawn after being killed. // respawnparm = M_CheckParm ("-respawn"); //! // @vanilla // // Monsters move faster. // fastparm = M_CheckParm ("-fast"); //! // @vanilla // // Developer mode. F1 saves a screenshot in the current working // directory. // devparm = M_CheckParm ("-devparm"); I_DisplayFPSDots(devparm); //! // @category net // @vanilla // // Start a deathmatch game. // if (M_CheckParm ("-deathmatch")) deathmatch = 1; //! // @category net // @vanilla // // Start a deathmatch 2.0 game. Weapons do not stay in place and // all items respawn after 30 seconds. // if (M_CheckParm ("-altdeath")) deathmatch = 2; if (devparm) DEH_printf(D_DEVSTR); // find which dir to use for config files #ifdef _WIN32 //! // @platform windows // @vanilla // // Save configuration data and savegames in c:\doomdata, // allowing play from CD. // if (M_ParmExists("-cdrom")) { printf(D_CDROM); M_SetConfigDir("c:\\doomdata\\"); } else #endif { // Auto-detect the configuration dir. M_SetConfigDir(NULL); } //! // @arg // @vanilla // // Turbo mode. The player's speed is multiplied by x%. If unspecified, // x defaults to 200. Values are rounded up to 10 and down to 400. // if ( (p=M_CheckParm ("-turbo")) ) { int scale = 200; extern int forwardmove[2]; extern int sidemove[2]; if (p 400) scale = 400; DEH_printf("turbo scale: %i%%\n", scale); forwardmove[0] = forwardmove[0]*scale/100; forwardmove[1] = forwardmove[1]*scale/100; sidemove[0] = sidemove[0]*scale/100; sidemove[1] = sidemove[1]*scale/100; } // init subsystems DEH_printf("V_Init: allocate screens.\n"); V_Init (); // Load configuration files before initialising other subsystems. DEH_printf("M_LoadDefaults: Load system defaults.\n"); M_SetConfigFilenames("default.cfg", PROGRAM_PREFIX "doom.cfg"); D_BindVariables(); M_LoadDefaults(); // Save configuration at exit. I_AtExit(M_SaveDefaults, false); // Find main IWAD file and load it. iwadfile = D_FindIWAD(IWAD_MASK_DOOM, &gamemission); // None found? if (iwadfile == NULL) { I_Error("Game mode indeterminate. No IWAD file was found. Try\n" "specifying one with the '-iwad' command line parameter.\n"); } modifiedgame = false; DEH_printf("W_Init: Init WADfiles.\n"); D_AddFile(iwadfile); numiwadlumps = numlumps; W_CheckCorrectIWAD(doom); // Now that we've loaded the IWAD, we can figure out what gamemission // we're playing and which version of Vanilla Doom we need to emulate. D_IdentifyVersion(); InitGameVersion(); //! // @category mod // // Disable automatic loading of Dehacked patches for certain // IWAD files. // if (!M_ParmExists("-nodeh")) { // Some IWADs have dehacked patches that need to be loaded for // them to be played properly. LoadIwadDeh(); } // Doom 3: BFG Edition includes modified versions of the classic // IWADs which can be identified by an additional DMENUPIC lump. // Furthermore, the M_GDHIGH lumps have been modified in a way that // makes them incompatible to Vanilla Doom and the modified version // of doom2.wad is missing the TITLEPIC lump. // We specifically check for DMENUPIC here, before PWADs have been // loaded which could probably include a lump of that name. if (W_CheckNumForName("dmenupic") >= 0) { printf("BFG Edition: Using workarounds as needed.\n"); bfgedition = true; // BFG Edition changes the names of the secret levels to // censor the Wolfenstein references. It also has an extra // secret level (MAP33). In Vanilla Doom (meaning the DOS // version), MAP33 overflows into the Plutonia level names // array, so HUSTR_33 is actually PHUSTR_1. DEH_AddStringReplacement(HUSTR_31, "level 31: idkfa"); DEH_AddStringReplacement(HUSTR_32, "level 32: keen"); DEH_AddStringReplacement(PHUSTR_1, "level 33: betray"); // The BFG edition doesn't have the "low detail" menu option (fair // enough). But bizarrely, it reuses the M_GDHIGH patch as a label // for the options menu (says "Fullscreen:"). Why the perpetrators // couldn't just add a new graphic lump and had to reuse this one, // I don't know. // // The end result is that M_GDHIGH is too wide and causes the game // to crash. As a workaround to get a minimum level of support for // the BFG edition IWADs, use the "ON"/"OFF" graphics instead. DEH_AddStringReplacement("M_GDHIGH", "M_MSGON"); DEH_AddStringReplacement("M_GDLOW", "M_MSGOFF"); } #ifdef FEATURE_DEHACKED // Load Dehacked patches specified on the command line with -deh. // Note that there's a very careful and deliberate ordering to how // Dehacked patches are loaded. The order we use is: // 1. IWAD dehacked patches. // 2. Command line dehacked patches specified with -deh. // 3. PWAD dehacked patches in DEHACKED lumps. DEH_ParseCommandLine(); #endif // Load PWAD files. modifiedgame = W_ParseCommandLine(); // Debug: // W_PrintDirectory(); //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp. // p = M_CheckParmWithArgs ("-playdemo", 1); if (!p) { //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp, determining the framerate // of the screen. // p = M_CheckParmWithArgs("-timedemo", 1); } if (p) { char *uc_filename = strdup(myargv[p + 1]); M_ForceUppercase(uc_filename); // With Vanilla you have to specify the file without extension, // but make that optional. if (M_StringEndsWith(uc_filename, ".LMP")) { M_StringCopy(file, myargv[p + 1], sizeof(file)); } else { DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p+1]); } free(uc_filename); if (D_AddFile(file)) { M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name, sizeof(demolumpname)); } else { // If file failed to load, still continue trying to play // the demo in the same way as Vanilla Doom. This makes // tricks like "-playdemo demo1" possible. M_StringCopy(demolumpname, myargv[p + 1], sizeof(demolumpname)); } printf("Playing demo %s.\n", file); } I_AtExit(G_CheckDemoStatusAtExit, true); // Generate the WAD hash table. Speed things up a bit. W_GenerateHashTable(); // Load DEHACKED lumps from WAD files - but only if we give the right // command line parameter. //! // @category mod // // Load Dehacked patches from DEHACKED lumps contained in one of the // loaded PWAD files. // if (M_ParmExists("-dehlump")) { int i, loaded = 0; for (i = numiwadlumps; i < numlumps; ++i) { if (!strncmp(lumpinfo[i].name, "DEHACKED", 8)) { DEH_LoadLump(i, false, false); loaded++; } } printf(" loaded %i DEHACKED lumps from PWAD files.\n", loaded); } // Set the gamedescription string. This is only possible now that // we've finished loading Dehacked patches. D_SetGameDescription(); #ifdef _WIN32 // In -cdrom mode, we write savegames to c:\doomdata as well as configs. if (M_ParmExists("-cdrom")) { savegamedir = configdir; } else #endif { savegamedir = M_GetSaveGameDir(D_SaveGameIWADName(gamemission)); } // Check for -file in shareware if (modifiedgame) { // These are the lumps that will be checked in IWAD, // if any one is not present, execution will be aborted. char name[23][8]= { "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9", "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9", "dphoof","bfgga0","heada1","cybra1","spida1d1" }; int i; if ( gamemode == shareware) I_Error(DEH_String("\nYou cannot -file with the shareware " "version. Register!")); // Check for fake IWAD with right name, // but w/o all the lumps of the registered version. if (gamemode == registered) for (i = 0;i < 23; i++) if (W_CheckNumForName(name[i])<0) I_Error(DEH_String("\nThis is not the registered version.")); } if (W_CheckNumForName("SS_START") >= 0 || W_CheckNumForName("FF_END") >= 0) { I_PrintDivider(); printf(" WARNING: The loaded WAD file contains modified sprites or\n" " floor textures. You may want to use the '-merge' command\n" " line option instead of '-file'.\n"); } I_PrintStartupBanner(gamedescription); PrintDehackedBanners(); // Freedoom's IWADs are Boom-compatible, which means they usually // don't work in Vanilla (though FreeDM is okay). Show a warning // message and give a link to the website. if (W_CheckNumForName("FREEDOOM") >= 0 && W_CheckNumForName("FREEDM") < 0) { printf(" WARNING: You are playing using one of the Freedoom IWAD\n" " files, which might not work in this port. See this page\n" " for more information on how to play using Freedoom:\n" " http://www.chocolate-doom.org/wiki/index.php/Freedoom\n"); I_PrintDivider(); } DEH_printf("I_Init: Setting up machine state.\n"); I_CheckIsScreensaver(); I_InitTimer(); I_InitJoystick(); I_InitSound(true); I_InitMusic(); #ifdef FEATURE_MULTIPLAYER printf ("NET_Init: Init network subsystem.\n"); NET_Init (); #endif // Initial netgame startup. Connect to server etc. D_ConnectNetGame(); // get skill / episode / map from parms startskill = sk_medium; startepisode = 1; startmap = 1; autostart = false; //! // @arg // @vanilla // // Set the game skill, 1-5 (1: easiest, 5: hardest). A skill of // 0 disables all monsters. // p = M_CheckParmWithArgs("-skill", 1); if (p) { startskill = myargv[p+1][0]-'1'; autostart = true; } //! // @arg // @vanilla // // Start playing on episode n (1-4) // p = M_CheckParmWithArgs("-episode", 1); if (p) { startepisode = myargv[p+1][0]-'0'; startmap = 1; autostart = true; } timelimit = 0; //! // @arg // @category net // @vanilla // // For multiplayer games: exit each level after n minutes. // p = M_CheckParmWithArgs("-timer", 1); if (p) { timelimit = atoi(myargv[p+1]); } //! // @category net // @vanilla // // Austin Virtual Gaming: end levels after 20 minutes. // p = M_CheckParm ("-avg"); if (p) { timelimit = 20; } //! // @arg [ | ] // @vanilla // // Start a game immediately, warping to ExMy (Doom 1) or MAPxy // (Doom 2) // p = M_CheckParmWithArgs("-warp", 1); if (p) { if (gamemode == commercial) startmap = atoi (myargv[p+1]); else { startepisode = myargv[p+1][0]-'0'; if (p + 2 < myargc) { startmap = myargv[p+2][0]-'0'; } else { startmap = 1; } } autostart = true; } // Undocumented: // Invoked by setup to test the controls. p = M_CheckParm("-testcontrols"); if (p > 0) { startepisode = 1; startmap = 1; autostart = true; testcontrols = true; } // Check for load game parameter // We do this here and save the slot number, so that the network code // can override it or send the load slot to other players. //! // @arg // @vanilla // // Load the game in slot s. // p = M_CheckParmWithArgs("-loadgame", 1); if (p) { startloadgame = atoi(myargv[p+1]); } else { // Not loading a game startloadgame = -1; } DEH_printf("M_Init: Init miscellaneous info.\n"); M_Init (); DEH_printf("R_Init: Init DOOM refresh daemon - "); R_Init (); DEH_printf("\nP_Init: Init Playloop state.\n"); P_Init (); DEH_printf("S_Init: Setting up sound.\n"); S_Init (sfxVolume * 8, musicVolume * 8); DEH_printf("D_CheckNetGame: Checking network game status.\n"); D_CheckNetGame (); PrintGameVersion(); DEH_printf("HU_Init: Setting up heads up display.\n"); HU_Init (); DEH_printf("ST_Init: Init status bar.\n"); ST_Init (); // If Doom II without a MAP01 lump, this is a store demo. // Moved this here so that MAP01 isn't constantly looked up // in the main loop. if (gamemode == commercial && W_CheckNumForName("map01") < 0) storedemo = true; if (M_CheckParmWithArgs("-statdump", 1)) { I_AtExit(StatDump, true); DEH_printf("External statistics registered.\n"); } //! // @arg // @category demo // @vanilla // // Record a demo named x.lmp. // p = M_CheckParmWithArgs("-record", 1); if (p) { G_RecordDemo (myargv[p+1]); autostart = true; } p = M_CheckParmWithArgs("-playdemo", 1); if (p) { singledemo = true; // quit after one demo G_DeferedPlayDemo (demolumpname); D_DoomLoop (); // never returns } p = M_CheckParmWithArgs("-timedemo", 1); if (p) { G_TimeDemo (demolumpname); D_DoomLoop (); // never returns } if (startloadgame >= 0) { M_StringCopy(file, P_SaveGameFile(startloadgame), sizeof(file)); G_LoadGame(file); } if (gameaction != ga_loadgame ) { if (autostart || netgame) G_InitNew (startskill, startepisode, startmap); else D_StartTitle (); // start up intro loop } D_DoomLoop (); // never returns } chocolate-doom-chocolate-doom-2.2.1/src/doom/d_main.h000066400000000000000000000017671257432200600224450ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // #ifndef __D_MAIN__ #define __D_MAIN__ #include "doomdef.h" // Read events from all input devices void D_ProcessEvents (void); // // BASE LEVEL // void D_PageTicker (void); void D_PageDrawer (void); void D_AdvanceDemo (void); void D_DoAdvanceDemo (void); void D_StartTitle (void); // // GLOBAL VARIABLES // extern gameaction_t gameaction; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/d_net.c000066400000000000000000000150331257432200600222710ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM Network game communication and protocol, // all OS independend parts. // #include #include "doomfeatures.h" #include "d_main.h" #include "m_argv.h" #include "m_menu.h" #include "m_misc.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "g_game.h" #include "doomdef.h" #include "doomstat.h" #include "w_checksum.h" #include "w_wad.h" #include "deh_main.h" #include "d_loop.h" ticcmd_t *netcmds; // Called when a player leaves the game static void PlayerQuitGame(player_t *player) { static char exitmsg[80]; unsigned int player_num; player_num = player - players; // Do this the same way as Vanilla Doom does, to allow dehacked // replacements of this message M_StringCopy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg)); exitmsg[7] += player_num; playeringame[player_num] = false; players[consoleplayer].message = exitmsg; // TODO: check if it is sensible to do this: if (demorecording) { G_CheckDemoStatus (); } } static void RunTic(ticcmd_t *cmds, boolean *ingame) { extern boolean advancedemo; unsigned int i; // Check for player quits. for (i = 0; i < MAXPLAYERS; ++i) { if (!demoplayback && playeringame[i] && !ingame[i]) { PlayerQuitGame(&players[i]); } } netcmds = cmds; // check that there are players in the game. if not, we cannot // run a tic. if (advancedemo) D_DoAdvanceDemo (); G_Ticker (); } static loop_interface_t doom_loop_interface = { D_ProcessEvents, G_BuildTiccmd, RunTic, M_Ticker }; // Load game settings from the specified structure and // set global variables. static void LoadGameSettings(net_gamesettings_t *settings) { unsigned int i; deathmatch = settings->deathmatch; startepisode = settings->episode; startmap = settings->map; startskill = settings->skill; startloadgame = settings->loadgame; lowres_turn = settings->lowres_turn; nomonsters = settings->nomonsters; fastparm = settings->fast_monsters; respawnparm = settings->respawn_monsters; timelimit = settings->timelimit; consoleplayer = settings->consoleplayer; if (lowres_turn) { printf("NOTE: Turning resolution is reduced; this is probably " "because there is a client recording a Vanilla demo.\n"); } for (i = 0; i < MAXPLAYERS; ++i) { playeringame[i] = i < settings->num_players; } } // Save the game settings from global variables to the specified // game settings structure. static void SaveGameSettings(net_gamesettings_t *settings) { // Fill in game settings structure with appropriate parameters // for the new game settings->deathmatch = deathmatch; settings->episode = startepisode; settings->map = startmap; settings->skill = startskill; settings->loadgame = startloadgame; settings->gameversion = gameversion; settings->nomonsters = nomonsters; settings->fast_monsters = fastparm; settings->respawn_monsters = respawnparm; settings->timelimit = timelimit; settings->lowres_turn = M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0; } static void InitConnectData(net_connect_data_t *connect_data) { connect_data->max_players = MAXPLAYERS; connect_data->drone = false; //! // @category net // // Run as the left screen in three screen mode. // if (M_CheckParm("-left") > 0) { viewangleoffset = ANG90; connect_data->drone = true; } //! // @category net // // Run as the right screen in three screen mode. // if (M_CheckParm("-right") > 0) { viewangleoffset = ANG270; connect_data->drone = true; } // // Connect data // // Game type fields: connect_data->gamemode = gamemode; connect_data->gamemission = gamemission; // Are we recording a demo? Possibly set lowres turn mode connect_data->lowres_turn = M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0; // Read checksums of our WAD directory and dehacked information W_Checksum(connect_data->wad_sha1sum); DEH_Checksum(connect_data->deh_sha1sum); // Are we playing with the Freedoom IWAD? connect_data->is_freedoom = W_CheckNumForName("FREEDOOM") >= 0; } void D_ConnectNetGame(void) { net_connect_data_t connect_data; InitConnectData(&connect_data); netgame = D_InitNetGame(&connect_data); //! // @category net // // Start the game playing as though in a netgame with a single // player. This can also be used to play back single player netgame // demos. // if (M_CheckParm("-solo-net") > 0) { netgame = true; } } // // D_CheckNetGame // Works out player numbers among the net participants // void D_CheckNetGame (void) { net_gamesettings_t settings; if (netgame) { autostart = true; } D_RegisterLoopCallbacks(&doom_loop_interface); SaveGameSettings(&settings); D_StartNetGame(&settings, NULL); LoadGameSettings(&settings); DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode); DEH_printf("player %i of %i (%i nodes)\n", consoleplayer+1, settings.num_players, settings.num_players); // Show players here; the server might have specified a time limit if (timelimit > 0 && deathmatch) { // Gross hack to work like Vanilla: if (timelimit == 20 && M_CheckParm("-avg")) { DEH_printf("Austin Virtual Gaming: Levels will end " "after 20 minutes\n"); } else { DEH_printf("Levels will end after %d minute", timelimit); if (timelimit > 1) printf("s"); printf(".\n"); } } } chocolate-doom-chocolate-doom-2.2.1/src/doom/d_player.h000066400000000000000000000105641257432200600230100ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __D_PLAYER__ #define __D_PLAYER__ // The player data structure depends on a number // of other structs: items (internal inventory), // animation states (closely tied to the sprites // used to represent them, unfortunately). #include "d_items.h" #include "p_pspr.h" // In addition, the player is just a special // case of the generic moving object/actor. #include "p_mobj.h" // Finally, for odd reasons, the player input // is buffered within the player data struct, // as commands per game tick. #include "d_ticcmd.h" #include "net_defs.h" // // Player states. // typedef enum { // Playing or camping. PST_LIVE, // Dead on the ground, view follows killer. PST_DEAD, // Ready to restart/respawn??? PST_REBORN } playerstate_t; // // Player internal flags, for cheats and debug. // typedef enum { // No clipping, walk through barriers. CF_NOCLIP = 1, // No damage, no health loss. CF_GODMODE = 2, // Not really a cheat, just a debug aid. CF_NOMOMENTUM = 4 } cheat_t; // // Extended player object info: player_t // typedef struct player_s { mobj_t* mo; playerstate_t playerstate; ticcmd_t cmd; // Determine POV, // including viewpoint bobbing during movement. // Focal origin above r.z fixed_t viewz; // Base height above floor for viewz. fixed_t viewheight; // Bob/squat speed. fixed_t deltaviewheight; // bounded/scaled total momentum. fixed_t bob; // This is only used between levels, // mo->health is used during levels. int health; int armorpoints; // Armor type is 0-2. int armortype; // Power ups. invinc and invis are tic counters. int powers[NUMPOWERS]; boolean cards[NUMCARDS]; boolean backpack; // Frags, kills of other players. int frags[MAXPLAYERS]; weapontype_t readyweapon; // Is wp_nochange if not changing. weapontype_t pendingweapon; int weaponowned[NUMWEAPONS]; int ammo[NUMAMMO]; int maxammo[NUMAMMO]; // True if button down last tic. int attackdown; int usedown; // Bit flags, for cheats and debug. // See cheat_t, above. int cheats; // Refired shots are less accurate. int refire; // For intermission stats. int killcount; int itemcount; int secretcount; // Hint messages. char* message; // For screen flashing (red or bright). int damagecount; int bonuscount; // Who did damage (NULL for floors/ceilings). mobj_t* attacker; // So gun flashes light up areas. int extralight; // Current PLAYPAL, ??? // can be set to REDCOLORMAP for pain, etc. int fixedcolormap; // Player skin colorshift, // 0-3 for which color to draw player. int colormap; // Overlay view sprites (gun, etc). pspdef_t psprites[NUMPSPRITES]; // True if secret level has been done. boolean didsecret; } player_t; // // INTERMISSION // Structure passed e.g. to WI_Start(wb) // typedef struct { boolean in; // whether the player is in game // Player stats, kills, collected items etc. int skills; int sitems; int ssecret; int stime; int frags[4]; int score; // current score on entry, modified on return } wbplayerstruct_t; typedef struct { int epsd; // episode # (0-2) // if true, splash the secret level boolean didsecret; // previous and next levels, origin 0 int last; int next; int maxkills; int maxitems; int maxsecret; int maxfrags; // the par time int partime; // index of this player in game int pnum; wbplayerstruct_t plyr[MAXPLAYERS]; } wbstartstruct_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/d_textur.h000066400000000000000000000016401257432200600230420ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Typedefs related to to textures etc., // isolated here to make it easier separating modules. // #ifndef __D_TEXTUR__ #define __D_TEXTUR__ #include "doomtype.h" // // Flats? // // a pic is an unmasked block of pixels typedef struct { byte width; byte height; byte data; } pic_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/d_think.h000066400000000000000000000027111257432200600226240ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // MapObj data. Map Objects or mobjs are actors, entities, // thinker, take-your-pick... anything that moves, acts, or // suffers state changes of more or less violent nature. // #ifndef __D_THINK__ #define __D_THINK__ // // Experimental stuff. // To compile this as "ANSI C with classes" // we will need to handle the various // action functions cleanly. // typedef void (*actionf_v)(); typedef void (*actionf_p1)( void* ); typedef void (*actionf_p2)( void*, void* ); typedef union { actionf_v acv; actionf_p1 acp1; actionf_p2 acp2; } actionf_t; // Historically, "think_t" is yet another // function pointer to a routine to handle // an actor. typedef actionf_t think_t; // Doubly linked list of actors. typedef struct thinker_s { struct thinker_s* prev; struct thinker_s* next; think_t function; } thinker_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/deh_ammo.c000066400000000000000000000044271257432200600227560ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Ammo" sections in dehacked files // #include #include #include #include "doomdef.h" #include "doomtype.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "p_local.h" static void *DEH_AmmoStart(deh_context_t *context, char *line) { int ammo_number = 0; if (sscanf(line, "Ammo %i", &ammo_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (ammo_number < 0 || ammo_number >= NUMAMMO) { DEH_Warning(context, "Invalid ammo number: %i", ammo_number); return NULL; } return &maxammo[ammo_number]; } static void DEH_AmmoParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; int ivalue; int ammo_number; if (tag == NULL) return; ammo_number = ((int *) tag) - maxammo; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); // maxammo if (!strcasecmp(variable_name, "Per ammo")) clipammo[ammo_number] = ivalue; else if (!strcasecmp(variable_name, "Max ammo")) maxammo[ammo_number] = ivalue; else { DEH_Warning(context, "Field named '%s' not found", variable_name); } } static void DEH_AmmoSHA1Hash(sha1_context_t *context) { int i; for (i=0; i #include #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "dstrings.h" typedef struct { char *macro; char *string; } bex_string_t; // mnemonic keys table static const bex_string_t bex_stringtable[] = { // part 1 - general initialization and prompts {"D_DEVSTR", D_DEVSTR}, {"D_CDROM", D_CDROM}, {"QUITMSG", QUITMSG}, {"LOADNET", LOADNET}, {"QLOADNET", QLOADNET}, {"QSAVESPOT", QSAVESPOT}, {"SAVEDEAD", SAVEDEAD}, {"QSPROMPT", QSPROMPT}, {"QLPROMPT", QLPROMPT}, {"NEWGAME", NEWGAME}, {"NIGHTMARE", NIGHTMARE}, {"SWSTRING", SWSTRING}, {"MSGOFF", MSGOFF}, {"MSGON", MSGON}, {"NETEND", NETEND}, {"ENDGAME", ENDGAME}, {"DETAILHI", DETAILHI}, {"DETAILLO", DETAILLO}, {"GAMMALVL0", GAMMALVL0}, {"GAMMALVL1", GAMMALVL1}, {"GAMMALVL2", GAMMALVL2}, {"GAMMALVL3", GAMMALVL3}, {"GAMMALVL4", GAMMALVL4}, {"EMPTYSTRING", EMPTYSTRING}, {"GGSAVED", GGSAVED}, {"SAVEGAMENAME", SAVEGAMENAME}, // part 2 - messages when the player gets things {"GOTARMOR", GOTARMOR}, {"GOTMEGA", GOTMEGA}, {"GOTHTHBONUS", GOTHTHBONUS}, {"GOTARMBONUS", GOTARMBONUS}, {"GOTSTIM", GOTSTIM}, {"GOTMEDINEED", GOTMEDINEED}, {"GOTMEDIKIT", GOTMEDIKIT}, {"GOTSUPER", GOTSUPER}, {"GOTBLUECARD", GOTBLUECARD}, {"GOTYELWCARD", GOTYELWCARD}, {"GOTREDCARD", GOTREDCARD}, {"GOTBLUESKUL", GOTBLUESKUL}, {"GOTYELWSKUL", GOTYELWSKUL}, {"GOTREDSKULL", GOTREDSKULL}, {"GOTINVUL", GOTINVUL}, {"GOTBERSERK", GOTBERSERK}, {"GOTINVIS", GOTINVIS}, {"GOTSUIT", GOTSUIT}, {"GOTMAP", GOTMAP}, {"GOTVISOR", GOTVISOR}, {"GOTMSPHERE", GOTMSPHERE}, {"GOTCLIP", GOTCLIP}, {"GOTCLIPBOX", GOTCLIPBOX}, {"GOTROCKET", GOTROCKET}, {"GOTROCKBOX", GOTROCKBOX}, {"GOTCELL", GOTCELL}, {"GOTCELLBOX", GOTCELLBOX}, {"GOTSHELLS", GOTSHELLS}, {"GOTSHELLBOX", GOTSHELLBOX}, {"GOTBACKPACK", GOTBACKPACK}, {"GOTBFG9000", GOTBFG9000}, {"GOTCHAINGUN", GOTCHAINGUN}, {"GOTCHAINSAW", GOTCHAINSAW}, {"GOTLAUNCHER", GOTLAUNCHER}, {"GOTPLASMA", GOTPLASMA}, {"GOTSHOTGUN", GOTSHOTGUN}, {"GOTSHOTGUN2", GOTSHOTGUN2}, // part 3 - messages when keys are needed {"PD_BLUEO", PD_BLUEO}, {"PD_REDO", PD_REDO}, {"PD_YELLOWO", PD_YELLOWO}, {"PD_BLUEK", PD_BLUEK}, {"PD_REDK", PD_REDK}, {"PD_YELLOWK", PD_YELLOWK}, // part 4 - multiplayer messaging {"HUSTR_MSGU", HUSTR_MSGU}, {"HUSTR_MESSAGESENT", HUSTR_MESSAGESENT}, {"HUSTR_CHATMACRO0", HUSTR_CHATMACRO0}, {"HUSTR_CHATMACRO1", HUSTR_CHATMACRO1}, {"HUSTR_CHATMACRO2", HUSTR_CHATMACRO2}, {"HUSTR_CHATMACRO3", HUSTR_CHATMACRO3}, {"HUSTR_CHATMACRO4", HUSTR_CHATMACRO4}, {"HUSTR_CHATMACRO5", HUSTR_CHATMACRO5}, {"HUSTR_CHATMACRO6", HUSTR_CHATMACRO6}, {"HUSTR_CHATMACRO7", HUSTR_CHATMACRO7}, {"HUSTR_CHATMACRO8", HUSTR_CHATMACRO8}, {"HUSTR_CHATMACRO9", HUSTR_CHATMACRO9}, {"HUSTR_TALKTOSELF1", HUSTR_TALKTOSELF1}, {"HUSTR_TALKTOSELF2", HUSTR_TALKTOSELF2}, {"HUSTR_TALKTOSELF3", HUSTR_TALKTOSELF3}, {"HUSTR_TALKTOSELF4", HUSTR_TALKTOSELF4}, {"HUSTR_TALKTOSELF5", HUSTR_TALKTOSELF5}, {"HUSTR_PLRGREEN", HUSTR_PLRGREEN}, {"HUSTR_PLRINDIGO", HUSTR_PLRINDIGO}, {"HUSTR_PLRBROWN", HUSTR_PLRBROWN}, {"HUSTR_PLRRED", HUSTR_PLRRED}, // part 5 - level names in the automap {"HUSTR_E1M1", HUSTR_E1M1}, {"HUSTR_E1M2", HUSTR_E1M2}, {"HUSTR_E1M3", HUSTR_E1M3}, {"HUSTR_E1M4", HUSTR_E1M4}, {"HUSTR_E1M5", HUSTR_E1M5}, {"HUSTR_E1M6", HUSTR_E1M6}, {"HUSTR_E1M7", HUSTR_E1M7}, {"HUSTR_E1M8", HUSTR_E1M8}, {"HUSTR_E1M9", HUSTR_E1M9}, {"HUSTR_E2M1", HUSTR_E2M1}, {"HUSTR_E2M2", HUSTR_E2M2}, {"HUSTR_E2M3", HUSTR_E2M3}, {"HUSTR_E2M4", HUSTR_E2M4}, {"HUSTR_E2M5", HUSTR_E2M5}, {"HUSTR_E2M6", HUSTR_E2M6}, {"HUSTR_E2M7", HUSTR_E2M7}, {"HUSTR_E2M8", HUSTR_E2M8}, {"HUSTR_E2M9", HUSTR_E2M9}, {"HUSTR_E3M1", HUSTR_E3M1}, {"HUSTR_E3M2", HUSTR_E3M2}, {"HUSTR_E3M3", HUSTR_E3M3}, {"HUSTR_E3M4", HUSTR_E3M4}, {"HUSTR_E3M5", HUSTR_E3M5}, {"HUSTR_E3M6", HUSTR_E3M6}, {"HUSTR_E3M7", HUSTR_E3M7}, {"HUSTR_E3M8", HUSTR_E3M8}, {"HUSTR_E3M9", HUSTR_E3M9}, {"HUSTR_E4M1", HUSTR_E4M1}, {"HUSTR_E4M2", HUSTR_E4M2}, {"HUSTR_E4M3", HUSTR_E4M3}, {"HUSTR_E4M4", HUSTR_E4M4}, {"HUSTR_E4M5", HUSTR_E4M5}, {"HUSTR_E4M6", HUSTR_E4M6}, {"HUSTR_E4M7", HUSTR_E4M7}, {"HUSTR_E4M8", HUSTR_E4M8}, {"HUSTR_E4M9", HUSTR_E4M9}, {"HUSTR_1", HUSTR_1}, {"HUSTR_2", HUSTR_2}, {"HUSTR_3", HUSTR_3}, {"HUSTR_4", HUSTR_4}, {"HUSTR_5", HUSTR_5}, {"HUSTR_6", HUSTR_6}, {"HUSTR_7", HUSTR_7}, {"HUSTR_8", HUSTR_8}, {"HUSTR_9", HUSTR_9}, {"HUSTR_10", HUSTR_10}, {"HUSTR_11", HUSTR_11}, {"HUSTR_12", HUSTR_12}, {"HUSTR_13", HUSTR_13}, {"HUSTR_14", HUSTR_14}, {"HUSTR_15", HUSTR_15}, {"HUSTR_16", HUSTR_16}, {"HUSTR_17", HUSTR_17}, {"HUSTR_18", HUSTR_18}, {"HUSTR_19", HUSTR_19}, {"HUSTR_20", HUSTR_20}, {"HUSTR_21", HUSTR_21}, {"HUSTR_22", HUSTR_22}, {"HUSTR_23", HUSTR_23}, {"HUSTR_24", HUSTR_24}, {"HUSTR_25", HUSTR_25}, {"HUSTR_26", HUSTR_26}, {"HUSTR_27", HUSTR_27}, {"HUSTR_28", HUSTR_28}, {"HUSTR_29", HUSTR_29}, {"HUSTR_30", HUSTR_30}, {"HUSTR_31", HUSTR_31}, {"HUSTR_32", HUSTR_32}, {"PHUSTR_1", PHUSTR_1}, {"PHUSTR_2", PHUSTR_2}, {"PHUSTR_3", PHUSTR_3}, {"PHUSTR_4", PHUSTR_4}, {"PHUSTR_5", PHUSTR_5}, {"PHUSTR_6", PHUSTR_6}, {"PHUSTR_7", PHUSTR_7}, {"PHUSTR_8", PHUSTR_8}, {"PHUSTR_9", PHUSTR_9}, {"PHUSTR_10", PHUSTR_10}, {"PHUSTR_11", PHUSTR_11}, {"PHUSTR_12", PHUSTR_12}, {"PHUSTR_13", PHUSTR_13}, {"PHUSTR_14", PHUSTR_14}, {"PHUSTR_15", PHUSTR_15}, {"PHUSTR_16", PHUSTR_16}, {"PHUSTR_17", PHUSTR_17}, {"PHUSTR_18", PHUSTR_18}, {"PHUSTR_19", PHUSTR_19}, {"PHUSTR_20", PHUSTR_20}, {"PHUSTR_21", PHUSTR_21}, {"PHUSTR_22", PHUSTR_22}, {"PHUSTR_23", PHUSTR_23}, {"PHUSTR_24", PHUSTR_24}, {"PHUSTR_25", PHUSTR_25}, {"PHUSTR_26", PHUSTR_26}, {"PHUSTR_27", PHUSTR_27}, {"PHUSTR_28", PHUSTR_28}, {"PHUSTR_29", PHUSTR_29}, {"PHUSTR_30", PHUSTR_30}, {"PHUSTR_31", PHUSTR_31}, {"PHUSTR_32", PHUSTR_32}, {"THUSTR_1", THUSTR_1}, {"THUSTR_2", THUSTR_2}, {"THUSTR_3", THUSTR_3}, {"THUSTR_4", THUSTR_4}, {"THUSTR_5", THUSTR_5}, {"THUSTR_6", THUSTR_6}, {"THUSTR_7", THUSTR_7}, {"THUSTR_8", THUSTR_8}, {"THUSTR_9", THUSTR_9}, {"THUSTR_10", THUSTR_10}, {"THUSTR_11", THUSTR_11}, {"THUSTR_12", THUSTR_12}, {"THUSTR_13", THUSTR_13}, {"THUSTR_14", THUSTR_14}, {"THUSTR_15", THUSTR_15}, {"THUSTR_16", THUSTR_16}, {"THUSTR_17", THUSTR_17}, {"THUSTR_18", THUSTR_18}, {"THUSTR_19", THUSTR_19}, {"THUSTR_20", THUSTR_20}, {"THUSTR_21", THUSTR_21}, {"THUSTR_22", THUSTR_22}, {"THUSTR_23", THUSTR_23}, {"THUSTR_24", THUSTR_24}, {"THUSTR_25", THUSTR_25}, {"THUSTR_26", THUSTR_26}, {"THUSTR_27", THUSTR_27}, {"THUSTR_28", THUSTR_28}, {"THUSTR_29", THUSTR_29}, {"THUSTR_30", THUSTR_30}, {"THUSTR_31", THUSTR_31}, {"THUSTR_32", THUSTR_32}, // part 6 - messages as a result of toggling states {"AMSTR_FOLLOWON", AMSTR_FOLLOWON}, {"AMSTR_FOLLOWOFF", AMSTR_FOLLOWOFF}, {"AMSTR_GRIDON", AMSTR_GRIDON}, {"AMSTR_GRIDOFF", AMSTR_GRIDOFF}, {"AMSTR_MARKEDSPOT", AMSTR_MARKEDSPOT}, {"AMSTR_MARKSCLEARED", AMSTR_MARKSCLEARED}, {"STSTR_MUS", STSTR_MUS}, {"STSTR_NOMUS", STSTR_NOMUS}, {"STSTR_DQDON", STSTR_DQDON}, {"STSTR_DQDOFF", STSTR_DQDOFF}, {"STSTR_KFAADDED", STSTR_KFAADDED}, {"STSTR_FAADDED", STSTR_FAADDED}, {"STSTR_NCON", STSTR_NCON}, {"STSTR_NCOFF", STSTR_NCOFF}, {"STSTR_BEHOLD", STSTR_BEHOLD}, {"STSTR_BEHOLDX", STSTR_BEHOLDX}, {"STSTR_CHOPPERS", STSTR_CHOPPERS}, {"STSTR_CLEV", STSTR_CLEV}, // part 7 - episode intermission texts {"E1TEXT", E1TEXT}, {"E2TEXT", E2TEXT}, {"E3TEXT", E3TEXT}, {"E4TEXT", E4TEXT}, {"C1TEXT", C1TEXT}, {"C2TEXT", C2TEXT}, {"C3TEXT", C3TEXT}, {"C4TEXT", C4TEXT}, {"C5TEXT", C5TEXT}, {"C6TEXT", C6TEXT}, {"P1TEXT", P1TEXT}, {"P2TEXT", P2TEXT}, {"P3TEXT", P3TEXT}, {"P4TEXT", P4TEXT}, {"P5TEXT", P5TEXT}, {"P6TEXT", P6TEXT}, {"T1TEXT", T1TEXT}, {"T2TEXT", T2TEXT}, {"T3TEXT", T3TEXT}, {"T4TEXT", T4TEXT}, {"T5TEXT", T5TEXT}, {"T6TEXT", T6TEXT}, // part 8 - creature names for the finale {"CC_ZOMBIE", CC_ZOMBIE}, {"CC_SHOTGUN", CC_SHOTGUN}, {"CC_HEAVY", CC_HEAVY}, {"CC_IMP", CC_IMP}, {"CC_DEMON", CC_DEMON}, {"CC_LOST", CC_LOST}, {"CC_CACO", CC_CACO}, {"CC_HELL", CC_HELL}, {"CC_BARON", CC_BARON}, {"CC_ARACH", CC_ARACH}, {"CC_PAIN", CC_PAIN}, {"CC_REVEN", CC_REVEN}, {"CC_MANCU", CC_MANCU}, {"CC_ARCH", CC_ARCH}, {"CC_SPIDER", CC_SPIDER}, {"CC_CYBER", CC_CYBER}, {"CC_HERO", CC_HERO}, // part 9 - intermission tiled backgrounds {"BGFLATE1", "FLOOR4_8"}, {"BGFLATE2", "SFLR6_1"}, {"BGFLATE3", "MFLR8_4"}, {"BGFLATE4", "MFLR8_3"}, {"BGFLAT06", "SLIME16"}, {"BGFLAT11", "RROCK14"}, {"BGFLAT20", "RROCK07"}, {"BGFLAT30", "RROCK17"}, {"BGFLAT15", "RROCK13"}, {"BGFLAT31", "RROCK19"}, {"BGCASTCALL", "BOSSBACK"}, }; static void *DEH_BEXStrStart(deh_context_t *context, char *line) { char s[10]; if (sscanf(line, "%9s", s) == 0 || strncmp("[STRINGS]", s, sizeof(s))) { DEH_Warning(context, "Parse error on section start"); } return NULL; } static void DEH_BEXStrParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; int i; if (!DEH_ParseAssignment(line, &variable_name, &value)) { DEH_Warning(context, "Failed to parse assignment"); return; } for (i = 0; i < arrlen(bex_stringtable); i++) { if (!strcmp(bex_stringtable[i].macro, variable_name)) { DEH_AddStringReplacement(bex_stringtable[i].string, value); } } } deh_section_t deh_section_bexstr = { "[STRINGS]", NULL, DEH_BEXStrStart, DEH_BEXStrParseLine, NULL, NULL, }; chocolate-doom-chocolate-doom-2.2.1/src/doom/deh_cheat.c000066400000000000000000000067511257432200600231130ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Cheat" sections in dehacked files // #include #include #include "doomtype.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "am_map.h" #include "st_stuff.h" typedef struct { char *name; cheatseq_t *seq; } deh_cheat_t; static deh_cheat_t allcheats[] = { {"Change music", &cheat_mus }, {"Chainsaw", &cheat_choppers }, {"God mode", &cheat_god }, {"Ammo & Keys", &cheat_ammo }, {"Ammo", &cheat_ammonokey }, {"No Clipping 1", &cheat_noclip }, {"No Clipping 2", &cheat_commercial_noclip }, {"Invincibility", &cheat_powerup[0] }, {"Berserk", &cheat_powerup[1] }, {"Invisibility", &cheat_powerup[2] }, {"Radiation Suit", &cheat_powerup[3] }, {"Auto-map", &cheat_powerup[4] }, {"Lite-Amp Goggles", &cheat_powerup[5] }, {"BEHOLD menu", &cheat_powerup[6] }, {"Level Warp", &cheat_clev }, {"Player Position", &cheat_mypos }, {"Map cheat", &cheat_amap }, }; static deh_cheat_t *FindCheatByName(char *name) { size_t i; for (i=0; i= cheat->seq->sequence_len) { DEH_Warning(context, "Cheat sequence longer than supported by " "Vanilla dehacked"); break; } if (deh_apply_cheats) { cheat->seq->sequence[i] = unsvalue[i]; } ++i; // Absolute limit - don't exceed if (i >= MAX_CHEAT_LEN - cheat->seq->parameter_chars) { DEH_Error(context, "Cheat sequence too long!"); return; } } if (deh_apply_cheats) { cheat->seq->sequence[i] = '\0'; } } deh_section_t deh_section_cheat = { "Cheat", NULL, DEH_CheatStart, DEH_CheatParseLine, NULL, NULL, }; chocolate-doom-chocolate-doom-2.2.1/src/doom/deh_doom.c000066400000000000000000000032061257432200600227550ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Top-level dehacked definitions for Doom dehacked. // #include #include "deh_defs.h" #include "deh_main.h" char *deh_signatures[] = { "Patch File for DeHackEd v2.3", "Patch File for DeHackEd v3.0", NULL }; // deh_ammo.c: extern deh_section_t deh_section_ammo; // deh_cheat.c: extern deh_section_t deh_section_cheat; // deh_frame.c: extern deh_section_t deh_section_frame; // deh_misc.c: extern deh_section_t deh_section_misc; // deh_ptr.c: extern deh_section_t deh_section_pointer; // deh_sound.c extern deh_section_t deh_section_sound; // deh_text.c: extern deh_section_t deh_section_text; // deh_thing.c: extern deh_section_t deh_section_thing; // deh_weapon.c: extern deh_section_t deh_section_weapon; // deh_bexstr.c: extern deh_section_t deh_section_bexstr; // // List of section types: // deh_section_t *deh_section_types[] = { &deh_section_ammo, &deh_section_cheat, &deh_section_frame, &deh_section_misc, &deh_section_pointer, &deh_section_sound, &deh_section_text, &deh_section_thing, &deh_section_weapon, &deh_section_bexstr, NULL }; chocolate-doom-chocolate-doom-2.2.1/src/doom/deh_frame.c000066400000000000000000000076561257432200600231260ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Frame" sections in dehacked files // #include #include #include "doomtype.h" #include "d_items.h" #include "info.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "deh_mapping.h" DEH_BEGIN_MAPPING(state_mapping, state_t) DEH_MAPPING("Sprite number", sprite) DEH_MAPPING("Sprite subnumber", frame) DEH_MAPPING("Duration", tics) DEH_MAPPING("Next frame", nextstate) DEH_MAPPING("Unknown 1", misc1) DEH_MAPPING("Unknown 2", misc2) DEH_UNSUPPORTED_MAPPING("Codep frame") DEH_END_MAPPING static void *DEH_FrameStart(deh_context_t *context, char *line) { int frame_number = 0; state_t *state; if (sscanf(line, "Frame %i", &frame_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (frame_number < 0 || frame_number >= NUMSTATES) { DEH_Warning(context, "Invalid frame number: %i", frame_number); return NULL; } if (frame_number >= DEH_VANILLA_NUMSTATES) { DEH_Warning(context, "Attempt to modify frame %i: this will cause " "problems in Vanilla dehacked.", frame_number); } state = &states[frame_number]; return state; } // Simulate a frame overflow: Doom has 967 frames in the states[] array, but // DOS dehacked internally only allocates memory for 966. As a result, // attempts to set frame 966 (the last frame) will overflow the dehacked // array and overwrite the weaponinfo[] array instead. // // This is noticable in Batman Doom where it is impossible to switch weapons // away from the fist once selected. static void DEH_FrameOverflow(deh_context_t *context, char *varname, int value) { if (!strcasecmp(varname, "Duration")) { weaponinfo[0].ammo = value; } else if (!strcasecmp(varname, "Codep frame")) { weaponinfo[0].upstate = value; } else if (!strcasecmp(varname, "Next frame")) { weaponinfo[0].downstate = value; } else if (!strcasecmp(varname, "Unknown 1")) { weaponinfo[0].readystate = value; } else if (!strcasecmp(varname, "Unknown 2")) { weaponinfo[0].atkstate = value; } else { DEH_Error(context, "Unable to simulate frame overflow: field '%s'", varname); } } static void DEH_FrameParseLine(deh_context_t *context, char *line, void *tag) { state_t *state; char *variable_name, *value; int ivalue; if (tag == NULL) return; state = (state_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // all values are integers ivalue = atoi(value); if (state == &states[NUMSTATES - 1]) { DEH_FrameOverflow(context, variable_name, ivalue); } else { // set the appropriate field DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue); } } static void DEH_FrameSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include "doomtype.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "deh_misc.h" // Dehacked: "Initial Health" // This is the initial health a player has when starting anew. // See G_PlayerReborn in g_game.c int deh_initial_health = DEH_DEFAULT_INITIAL_HEALTH; // Dehacked: "Initial bullets" // This is the number of bullets the player has when starting anew. // See G_PlayerReborn in g_game.c int deh_initial_bullets = DEH_DEFAULT_INITIAL_BULLETS; // Dehacked: "Max Health" // This is the maximum health that can be reached using medikits // alone. See P_TouchSpecialThing in p_inter.c int deh_max_health = DEH_DEFAULT_MAX_HEALTH; // Dehacked: "Max Armor" // This is the maximum armor which can be reached by picking up // armor helmets. See P_TouchSpecialThing in p_inter.c int deh_max_armor = DEH_DEFAULT_MAX_ARMOR; // Dehacked: "Green Armor Class" // This is the armor class that is given when picking up the green // armor or an armor helmet. See P_TouchSpecialThing in p_inter.c // // DOS dehacked only modifies the behavior of the green armor shirt, // the armor class set by armor helmets is not affected. int deh_green_armor_class = DEH_DEFAULT_GREEN_ARMOR_CLASS; // Dehacked: "Blue Armor Class" // This is the armor class that is given when picking up the blue // armor or a megasphere. See P_TouchSpecialThing in p_inter.c // // DOS dehacked only modifies the MegaArmor behavior and not // the MegaSphere, which always gives armor type 2. int deh_blue_armor_class = DEH_DEFAULT_BLUE_ARMOR_CLASS; // Dehacked: "Max soulsphere" // The maximum health which can be reached by picking up the // soulsphere. See P_TouchSpecialThing in p_inter.c int deh_max_soulsphere = DEH_DEFAULT_MAX_SOULSPHERE; // Dehacked: "Soulsphere health" // The amount of health bonus that picking up a soulsphere // gives. See P_TouchSpecialThing in p_inter.c int deh_soulsphere_health = DEH_DEFAULT_SOULSPHERE_HEALTH; // Dehacked: "Megasphere health" // This is what the health is set to after picking up a // megasphere. See P_TouchSpecialThing in p_inter.c int deh_megasphere_health = DEH_DEFAULT_MEGASPHERE_HEALTH; // Dehacked: "God mode health" // This is what the health value is set to when cheating using // the IDDQD god mode cheat. See ST_Responder in st_stuff.c int deh_god_mode_health = DEH_DEFAULT_GOD_MODE_HEALTH; // Dehacked: "IDFA Armor" // This is what the armor is set to when using the IDFA cheat. // See ST_Responder in st_stuff.c int deh_idfa_armor = DEH_DEFAULT_IDFA_ARMOR; // Dehacked: "IDFA Armor Class" // This is what the armor class is set to when using the IDFA cheat. // See ST_Responder in st_stuff.c int deh_idfa_armor_class = DEH_DEFAULT_IDFA_ARMOR_CLASS; // Dehacked: "IDKFA Armor" // This is what the armor is set to when using the IDKFA cheat. // See ST_Responder in st_stuff.c int deh_idkfa_armor = DEH_DEFAULT_IDKFA_ARMOR; // Dehacked: "IDKFA Armor Class" // This is what the armor class is set to when using the IDKFA cheat. // See ST_Responder in st_stuff.c int deh_idkfa_armor_class = DEH_DEFAULT_IDKFA_ARMOR_CLASS; // Dehacked: "BFG Cells/Shot" // This is the number of CELLs firing the BFG uses up. // See P_CheckAmmo and A_FireBFG in p_pspr.c int deh_bfg_cells_per_shot = DEH_DEFAULT_BFG_CELLS_PER_SHOT; // Dehacked: "Monsters infight" // This controls whether monsters can harm other monsters of the same // species. For example, whether an imp fireball will damage other // imps. The value of this in dehacked patches is weird - '202' means // off, while '221' means on. // // See PIT_CheckThing in p_map.c int deh_species_infighting = DEH_DEFAULT_SPECIES_INFIGHTING; static struct { char *deh_name; int *value; } misc_settings[] = { {"Initial Health", &deh_initial_health}, {"Initial Bullets", &deh_initial_bullets}, {"Max Health", &deh_max_health}, {"Max Armor", &deh_max_armor}, {"Green Armor Class", &deh_green_armor_class}, {"Blue Armor Class", &deh_blue_armor_class}, {"Max Soulsphere", &deh_max_soulsphere}, {"Soulsphere Health", &deh_soulsphere_health}, {"Megasphere Health", &deh_megasphere_health}, {"God Mode Health", &deh_god_mode_health}, {"IDFA Armor", &deh_idfa_armor}, {"IDFA Armor Class", &deh_idfa_armor_class}, {"IDKFA Armor", &deh_idkfa_armor}, {"IDKFA Armor Class", &deh_idkfa_armor_class}, {"BFG Cells/Shot", &deh_bfg_cells_per_shot}, }; static void *DEH_MiscStart(deh_context_t *context, char *line) { return NULL; } static void DEH_MiscParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; int ivalue; size_t i; if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); if (!strcasecmp(variable_name, "Monsters Infight")) { // See notes above. if (ivalue == 202) { deh_species_infighting = 0; } else if (ivalue == 221) { deh_species_infighting = 1; } else { DEH_Warning(context, "Invalid value for 'Monsters Infight': %i", ivalue); } return; } for (i=0; i #include #include #include "doomtype.h" #include "info.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" static actionf_t codeptrs[NUMSTATES]; static int CodePointerIndex(actionf_t *ptr) { int i; for (i=0; i= NUMSTATES) { DEH_Warning(context, "Invalid frame number: %i", frame_number); return NULL; } return &states[frame_number]; } static void DEH_PointerParseLine(deh_context_t *context, char *line, void *tag) { state_t *state; char *variable_name, *value; int ivalue; if (tag == NULL) return; state = (state_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // printf("Set %s to %s for state\n", variable_name, value); // all values are integers ivalue = atoi(value); // set the appropriate field if (!strcasecmp(variable_name, "Codep frame")) { if (ivalue < 0 || ivalue >= NUMSTATES) { DEH_Warning(context, "Invalid state '%i'", ivalue); } else { state->action = codeptrs[ivalue]; } } else { DEH_Warning(context, "Unknown variable name '%s'", variable_name); } } static void DEH_PointerSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include "doomfeatures.h" #include "doomtype.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" #include "sounds.h" DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t) DEH_UNSUPPORTED_MAPPING("Offset") DEH_UNSUPPORTED_MAPPING("Zero/One") DEH_MAPPING("Value", priority) DEH_MAPPING("Zero 1", link) DEH_MAPPING("Zero 2", pitch) DEH_MAPPING("Zero 3", volume) DEH_UNSUPPORTED_MAPPING("Zero 4") DEH_MAPPING("Neg. One 1", usefulness) DEH_MAPPING("Neg. One 2", lumpnum) DEH_END_MAPPING static void *DEH_SoundStart(deh_context_t *context, char *line) { int sound_number = 0; if (sscanf(line, "Sound %i", &sound_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (sound_number < 0 || sound_number >= NUMSFX) { DEH_Warning(context, "Invalid sound number: %i", sound_number); return NULL; } if (sound_number >= DEH_VANILLA_NUMSFX) { DEH_Warning(context, "Attempt to modify SFX %i. This will cause " "problems in Vanilla dehacked.", sound_number); } return &S_sfx[sound_number]; } static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag) { sfxinfo_t *sfx; char *variable_name, *value; int ivalue; if (tag == NULL) return; sfx = (sfxinfo_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // all values are integers ivalue = atoi(value); // Set the field value DEH_SetMapping(context, &sound_mapping, sfx, variable_name, ivalue); } deh_section_t deh_section_sound = { "Sound", NULL, DEH_SoundStart, DEH_SoundParseLine, NULL, NULL, }; chocolate-doom-chocolate-doom-2.2.1/src/doom/deh_thing.c000066400000000000000000000066111257432200600231330ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Thing" sections in dehacked files // #include #include #include "doomtype.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" #include "info.h" DEH_BEGIN_MAPPING(thing_mapping, mobjinfo_t) DEH_MAPPING("ID #", doomednum) DEH_MAPPING("Initial frame", spawnstate) DEH_MAPPING("Hit points", spawnhealth) DEH_MAPPING("First moving frame", seestate) DEH_MAPPING("Alert sound", seesound) DEH_MAPPING("Reaction time", reactiontime) DEH_MAPPING("Attack sound", attacksound) DEH_MAPPING("Injury frame", painstate) DEH_MAPPING("Pain chance", painchance) DEH_MAPPING("Pain sound", painsound) DEH_MAPPING("Close attack frame", meleestate) DEH_MAPPING("Far attack frame", missilestate) DEH_MAPPING("Death frame", deathstate) DEH_MAPPING("Exploding frame", xdeathstate) DEH_MAPPING("Death sound", deathsound) DEH_MAPPING("Speed", speed) DEH_MAPPING("Width", radius) DEH_MAPPING("Height", height) DEH_MAPPING("Mass", mass) DEH_MAPPING("Missile damage", damage) DEH_MAPPING("Action sound", activesound) DEH_MAPPING("Bits", flags) DEH_MAPPING("Respawn frame", raisestate) DEH_END_MAPPING static void *DEH_ThingStart(deh_context_t *context, char *line) { int thing_number = 0; mobjinfo_t *mobj; if (sscanf(line, "Thing %i", &thing_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } // dehacked files are indexed from 1 --thing_number; if (thing_number < 0 || thing_number >= NUMMOBJTYPES) { DEH_Warning(context, "Invalid thing number: %i", thing_number); return NULL; } mobj = &mobjinfo[thing_number]; return mobj; } static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag) { mobjinfo_t *mobj; char *variable_name, *value; int ivalue; if (tag == NULL) return; mobj = (mobjinfo_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // printf("Set %s to %s for mobj\n", variable_name, value); // all values are integers ivalue = atoi(value); // Set the field value DEH_SetMapping(context, &thing_mapping, mobj, variable_name, ivalue); } static void DEH_ThingSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include #include "doomtype.h" #include "d_items.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" DEH_BEGIN_MAPPING(weapon_mapping, weaponinfo_t) DEH_MAPPING("Ammo type", ammo) DEH_MAPPING("Deselect frame", upstate) DEH_MAPPING("Select frame", downstate) DEH_MAPPING("Bobbing frame", readystate) DEH_MAPPING("Shooting frame", atkstate) DEH_MAPPING("Firing frame", flashstate) DEH_END_MAPPING static void *DEH_WeaponStart(deh_context_t *context, char *line) { int weapon_number = 0; if (sscanf(line, "Weapon %i", &weapon_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (weapon_number < 0 || weapon_number >= NUMWEAPONS) { DEH_Warning(context, "Invalid weapon number: %i", weapon_number); return NULL; } return &weaponinfo[weapon_number]; } static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; weaponinfo_t *weapon; int ivalue; if (tag == NULL) return; weapon = (weaponinfo_t *) tag; if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); DEH_SetMapping(context, &weapon_mapping, weapon, variable_name, ivalue); } static void DEH_WeaponSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include "doomtype.h" #include "i_timer.h" #include "d_mode.h" // // Global parameters/defines. // // DOOM version #define DOOM_VERSION 109 // Version code for cph's longtics hack ("v1.91") #define DOOM_191_VERSION 111 // If rangecheck is undefined, // most parameter validation debugging code will not be compiled #define RANGECHECK // The maximum number of players, multiplayer/networking. #define MAXPLAYERS 4 // The current state of the game: whether we are // playing, gazing at the intermission screen, // the game final animation, or a demo. typedef enum { GS_LEVEL, GS_INTERMISSION, GS_FINALE, GS_DEMOSCREEN, } gamestate_t; typedef enum { ga_nothing, ga_loadlevel, ga_newgame, ga_loadgame, ga_savegame, ga_playdemo, ga_completed, ga_victory, ga_worlddone, ga_screenshot } gameaction_t; // // Difficulty/skill settings/filters. // // Skill flags. #define MTF_EASY 1 #define MTF_NORMAL 2 #define MTF_HARD 4 // Deaf monsters/do not react to sound. #define MTF_AMBUSH 8 // // Key cards. // typedef enum { it_bluecard, it_yellowcard, it_redcard, it_blueskull, it_yellowskull, it_redskull, NUMCARDS } card_t; // The defined weapons, // including a marker indicating // user has not changed weapon. typedef enum { wp_fist, wp_pistol, wp_shotgun, wp_chaingun, wp_missile, wp_plasma, wp_bfg, wp_chainsaw, wp_supershotgun, NUMWEAPONS, // No pending weapon change. wp_nochange } weapontype_t; // Ammunition types defined. typedef enum { am_clip, // Pistol / chaingun ammo. am_shell, // Shotgun / double barreled shotgun. am_cell, // Plasma rifle, BFG. am_misl, // Missile launcher. NUMAMMO, am_noammo // Unlimited for chainsaw / fist. } ammotype_t; // Power up artifacts. typedef enum { pw_invulnerability, pw_strength, pw_invisibility, pw_ironfeet, pw_allmap, pw_infrared, NUMPOWERS } powertype_t; // // Power up durations, // how many seconds till expiration, // assuming TICRATE is 35 ticks/second. // typedef enum { INVULNTICS = (30*TICRATE), INVISTICS = (60*TICRATE), INFRATICS = (120*TICRATE), IRONTICS = (60*TICRATE) } powerduration_t; #endif // __DOOMDEF__ chocolate-doom-chocolate-doom-2.2.1/src/doom/doomstat.c000066400000000000000000000016771257432200600230430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Put all global tate variables here. // #include #include "doomstat.h" // Game Mode - identify IWAD as shareware, retail etc. GameMode_t gamemode = indetermined; GameMission_t gamemission = doom; GameVersion_t gameversion = exe_final2; char *gamedescription; // Set if homebrew PWAD stuff has been added. boolean modifiedgame; chocolate-doom-chocolate-doom-2.2.1/src/doom/doomstat.h000066400000000000000000000152021257432200600230350ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // All the global variables that store the internal state. // Theoretically speaking, the internal state of the engine // should be found by looking at the variables collected // here, and every relevant module will have to include // this header file. // In practice, things are a bit messy. // #ifndef __D_STATE__ #define __D_STATE__ // We need globally shared data structures, // for defining the global state variables. #include "doomdata.h" #include "d_loop.h" // We need the playr data structure as well. #include "d_player.h" // Game mode/mission #include "d_mode.h" #include "net_defs.h" // ------------------------ // Command line parameters. // extern boolean nomonsters; // checkparm of -nomonsters extern boolean respawnparm; // checkparm of -respawn extern boolean fastparm; // checkparm of -fast extern boolean devparm; // DEBUG: launched with -devparm // ----------------------------------------------------- // Game Mode - identify IWAD as shareware, retail etc. // extern GameMode_t gamemode; extern GameMission_t gamemission; extern GameVersion_t gameversion; extern char *gamedescription; // If true, we're using one of the mangled BFG edition IWADs. extern boolean bfgedition; // Convenience macro. // 'gamemission' can be equal to pack_chex or pack_hacx, but these are // just modified versions of doom and doom2, and should be interpreted // as the same most of the time. #define logical_gamemission \ (gamemission == pack_chex ? doom : \ gamemission == pack_hacx ? doom2 : gamemission) // Set if homebrew PWAD stuff has been added. extern boolean modifiedgame; // ------------------------------------------- // Selected skill type, map etc. // // Defaults for menu, methinks. extern skill_t startskill; extern int startepisode; extern int startmap; // Savegame slot to load on startup. This is the value provided to // the -loadgame option. If this has not been provided, this is -1. extern int startloadgame; extern boolean autostart; // Selected by user. extern skill_t gameskill; extern int gameepisode; extern int gamemap; // If non-zero, exit the level after this number of minutes extern int timelimit; // Nightmare mode flag, single player. extern boolean respawnmonsters; // Netgame? Only true if >1 player. extern boolean netgame; // 0=Cooperative; 1=Deathmatch; 2=Altdeath extern int deathmatch; // ------------------------- // Internal parameters for sound rendering. // These have been taken from the DOS version, // but are not (yet) supported with Linux // (e.g. no sound volume adjustment with menu. // From m_menu.c: // Sound FX volume has default, 0 - 15 // Music volume has default, 0 - 15 // These are multiplied by 8. extern int sfxVolume; extern int musicVolume; // Current music/sfx card - index useless // w/o a reference LUT in a sound module. // Ideally, this would use indices found // in: /usr/include/linux/soundcard.h extern int snd_MusicDevice; extern int snd_SfxDevice; // Config file? Same disclaimer as above. extern int snd_DesiredMusicDevice; extern int snd_DesiredSfxDevice; // ------------------------- // Status flags for refresh. // // Depending on view size - no status bar? // Note that there is no way to disable the // status bar explicitely. extern boolean statusbaractive; extern boolean automapactive; // In AutoMap mode? extern boolean menuactive; // Menu overlayed? extern boolean paused; // Game Pause? extern boolean viewactive; extern boolean nodrawers; extern boolean testcontrols; extern int testcontrols_mousespeed; // This one is related to the 3-screen display mode. // ANG90 = left side, ANG270 = right extern int viewangleoffset; // Player taking events, and displaying. extern int consoleplayer; extern int displayplayer; // ------------------------------------- // Scores, rating. // Statistics on a given map, for intermission. // extern int totalkills; extern int totalitems; extern int totalsecret; // Timer, for scores. extern int levelstarttic; // gametic at level start extern int leveltime; // tics in game play for par // -------------------------------------- // DEMO playback/recording related stuff. // No demo, there is a human player in charge? // Disable save/end game? extern boolean usergame; //? extern boolean demoplayback; extern boolean demorecording; // Round angleturn in ticcmds to the nearest 256. This is used when // recording Vanilla demos in netgames. extern boolean lowres_turn; // Quit after playing a demo from cmdline. extern boolean singledemo; //? extern gamestate_t gamestate; //----------------------------- // Internal parameters, fixed. // These are set by the engine, and not changed // according to user inputs. Partly load from // WAD, partly set at startup time. // Bookkeeping on players - state. extern player_t players[MAXPLAYERS]; // Alive? Disconnected? extern boolean playeringame[MAXPLAYERS]; // Player spawn spots for deathmatch. #define MAX_DM_STARTS 10 extern mapthing_t deathmatchstarts[MAX_DM_STARTS]; extern mapthing_t* deathmatch_p; // Player spawn spots. extern mapthing_t playerstarts[MAXPLAYERS]; // Intermission stats. // Parameters for world map / intermission. extern wbstartstruct_t wminfo; //----------------------------------------- // Internal parameters, used for engine. // // File handling stuff. extern char * savegamedir; extern char basedefault[1024]; // if true, load all graphics at level load extern boolean precache; // wipegamestate can be set to -1 // to force a wipe on the next draw extern gamestate_t wipegamestate; extern int mouseSensitivity; extern int bodyqueslot; // Needed to store the number of the dummy sky flat. // Used for rendering, // as well as tracking projectiles etc. extern int skyflatnum; // Netgame stuff (buffers and pointers, i.e. indices). extern int rndindex; extern ticcmd_t *netcmds; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/dstrings.c000066400000000000000000000043771257432200600230460ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Globally defined strings. // #include "dstrings.h" char *doom1_endmsg[] = { "are you sure you want to\nquit this great game?", "please don't leave, there's more\ndemons to toast!", "let's beat it -- this is turning\ninto a bloodbath!", "i wouldn't leave if i were you.\ndos is much worse.", "you're trying to say you like dos\nbetter than me, right?", "don't leave yet -- there's a\ndemon around that corner!", "ya know, next time you come in here\ni'm gonna toast ya.", "go ahead and leave. see if i care.", }; char *doom2_endmsg[] = { // QuitDOOM II messages "are you sure you want to\nquit this great game?", "you want to quit?\nthen, thou hast lost an eighth!", "don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!", "get outta here and go back\nto your boring programs.", "if i were your boss, i'd \n deathmatch ya in a minute!", "look, bud. you leave now\nand you forfeit your body count!", "just leave. when you come\nback, i'll be waiting with a bat.", "you're lucky i don't smack\nyou for thinking about leaving.", }; #if 0 // UNUSED messages included in the source release char* endmsg[] = { // DOOM1 QUITMSG, // FinalDOOM? "fuck you, pussy!\nget the fuck out!", "you quit and i'll jizz\nin your cystholes!", "if you leave, i'll make\nthe lord drink my jizz.", "hey, ron! can we say\n'fuck' in the game?", "i'd leave: this is just\nmore monsters and levels.\nwhat a load.", "suck it down, asshole!\nyou're a fucking wimp!", "don't quit now! we're \nstill spending your money!", // Internal debug. Different style, too. "THIS IS NO MESSAGE!\nPage intentionally left blank." }; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/dstrings.h000066400000000000000000000016641257432200600230470ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: // DOOM strings, by language. // #ifndef __DSTRINGS__ #define __DSTRINGS__ // All important printed strings. #include "d_englsh.h" // Misc. other strings. #define SAVEGAMENAME "doomsav" // QuitDOOM messages // 8 per each game type #define NUM_QUITMESSAGES 8 extern char *doom1_endmsg[]; extern char *doom2_endmsg[]; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/f_finale.c000066400000000000000000000345431257432200600227520ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Game completion, final screen animation. // #include #include // Functions. #include "deh_main.h" #include "i_system.h" #include "i_swap.h" #include "z_zone.h" #include "v_video.h" #include "w_wad.h" #include "s_sound.h" // Data. #include "d_main.h" #include "dstrings.h" #include "sounds.h" #include "doomstat.h" #include "r_state.h" typedef enum { F_STAGE_TEXT, F_STAGE_ARTSCREEN, F_STAGE_CAST, } finalestage_t; // ? //#include "doomstat.h" //#include "r_local.h" //#include "f_finale.h" // Stage of animation: finalestage_t finalestage; unsigned int finalecount; #define TEXTSPEED 3 #define TEXTWAIT 250 typedef struct { GameMission_t mission; int episode, level; char *background; char *text; } textscreen_t; static textscreen_t textscreens[] = { { doom, 1, 8, "FLOOR4_8", E1TEXT}, { doom, 2, 8, "SFLR6_1", E2TEXT}, { doom, 3, 8, "MFLR8_4", E3TEXT}, { doom, 4, 8, "MFLR8_3", E4TEXT}, { doom2, 1, 6, "SLIME16", C1TEXT}, { doom2, 1, 11, "RROCK14", C2TEXT}, { doom2, 1, 20, "RROCK07", C3TEXT}, { doom2, 1, 30, "RROCK17", C4TEXT}, { doom2, 1, 15, "RROCK13", C5TEXT}, { doom2, 1, 31, "RROCK19", C6TEXT}, { pack_tnt, 1, 6, "SLIME16", T1TEXT}, { pack_tnt, 1, 11, "RROCK14", T2TEXT}, { pack_tnt, 1, 20, "RROCK07", T3TEXT}, { pack_tnt, 1, 30, "RROCK17", T4TEXT}, { pack_tnt, 1, 15, "RROCK13", T5TEXT}, { pack_tnt, 1, 31, "RROCK19", T6TEXT}, { pack_plut, 1, 6, "SLIME16", P1TEXT}, { pack_plut, 1, 11, "RROCK14", P2TEXT}, { pack_plut, 1, 20, "RROCK07", P3TEXT}, { pack_plut, 1, 30, "RROCK17", P4TEXT}, { pack_plut, 1, 15, "RROCK13", P5TEXT}, { pack_plut, 1, 31, "RROCK19", P6TEXT}, }; char* finaletext; char* finaleflat; void F_StartCast (void); void F_CastTicker (void); boolean F_CastResponder (event_t *ev); void F_CastDrawer (void); // // F_StartFinale // void F_StartFinale (void) { size_t i; gameaction = ga_nothing; gamestate = GS_FINALE; viewactive = false; automapactive = false; if (logical_gamemission == doom) { S_ChangeMusic(mus_victor, true); } else { S_ChangeMusic(mus_read_m, true); } // Find the right screen and set the text and background for (i=0; imission == doom) { screen->level = 5; } if (logical_gamemission == screen->mission && (logical_gamemission != doom || gameepisode == screen->episode) && gamemap == screen->level) { finaletext = screen->text; finaleflat = screen->background; } } // Do dehacked substitutions of strings finaletext = DEH_String(finaletext); finaleflat = DEH_String(finaleflat); finalestage = F_STAGE_TEXT; finalecount = 0; } boolean F_Responder (event_t *event) { if (finalestage == F_STAGE_CAST) return F_CastResponder (event); return false; } // // F_Ticker // void F_Ticker (void) { size_t i; // check for skipping if ( (gamemode == commercial) && ( finalecount > 50) ) { // go on to the next level for (i=0 ; istrlen (finaletext)*TEXTSPEED + TEXTWAIT) { finalecount = 0; finalestage = F_STAGE_ARTSCREEN; wipegamestate = -1; // force a wipe if (gameepisode == 3) S_StartMusic (mus_bunny); } } // // F_TextWrite // #include "hu_stuff.h" extern patch_t *hu_font[HU_FONTSIZE]; void F_TextWrite (void) { byte* src; byte* dest; int x,y,w; signed int count; char* ch; int c; int cx; int cy; // erase the entire screen to a tiled background src = W_CacheLumpName ( finaleflat , PU_CACHE); dest = I_VideoBuffer; for (y=0 ; y HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c]->width); if (cx+w > SCREENWIDTH) break; V_DrawPatch(cx, cy, hu_font[c]); cx+=w; } } // // Final DOOM 2 animation // Casting by id Software. // in order of appearance // typedef struct { char *name; mobjtype_t type; } castinfo_t; castinfo_t castorder[] = { {CC_ZOMBIE, MT_POSSESSED}, {CC_SHOTGUN, MT_SHOTGUY}, {CC_HEAVY, MT_CHAINGUY}, {CC_IMP, MT_TROOP}, {CC_DEMON, MT_SERGEANT}, {CC_LOST, MT_SKULL}, {CC_CACO, MT_HEAD}, {CC_HELL, MT_KNIGHT}, {CC_BARON, MT_BRUISER}, {CC_ARACH, MT_BABY}, {CC_PAIN, MT_PAIN}, {CC_REVEN, MT_UNDEAD}, {CC_MANCU, MT_FATSO}, {CC_ARCH, MT_VILE}, {CC_SPIDER, MT_SPIDER}, {CC_CYBER, MT_CYBORG}, {CC_HERO, MT_PLAYER}, {NULL,0} }; int castnum; int casttics; state_t* caststate; boolean castdeath; int castframes; int castonmelee; boolean castattacking; // // F_StartCast // void F_StartCast (void) { wipegamestate = -1; // force a screen wipe castnum = 0; caststate = &states[mobjinfo[castorder[castnum].type].seestate]; casttics = caststate->tics; castdeath = false; finalestage = F_STAGE_CAST; castframes = 0; castonmelee = 0; castattacking = false; S_ChangeMusic(mus_evil, true); } // // F_CastTicker // void F_CastTicker (void) { int st; int sfx; if (--casttics > 0) return; // not time to change state yet if (caststate->tics == -1 || caststate->nextstate == S_NULL) { // switch from deathstate to next monster castnum++; castdeath = false; if (castorder[castnum].name == NULL) castnum = 0; if (mobjinfo[castorder[castnum].type].seesound) S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound); caststate = &states[mobjinfo[castorder[castnum].type].seestate]; castframes = 0; } else { // just advance to next state in animation if (caststate == &states[S_PLAY_ATK1]) goto stopattack; // Oh, gross hack! st = caststate->nextstate; caststate = &states[st]; castframes++; // sound hacks.... switch (st) { case S_PLAY_ATK1: sfx = sfx_dshtgn; break; case S_POSS_ATK2: sfx = sfx_pistol; break; case S_SPOS_ATK2: sfx = sfx_shotgn; break; case S_VILE_ATK2: sfx = sfx_vilatk; break; case S_SKEL_FIST2: sfx = sfx_skeswg; break; case S_SKEL_FIST4: sfx = sfx_skepch; break; case S_SKEL_MISS2: sfx = sfx_skeatk; break; case S_FATT_ATK8: case S_FATT_ATK5: case S_FATT_ATK2: sfx = sfx_firsht; break; case S_CPOS_ATK2: case S_CPOS_ATK3: case S_CPOS_ATK4: sfx = sfx_shotgn; break; case S_TROO_ATK3: sfx = sfx_claw; break; case S_SARG_ATK2: sfx = sfx_sgtatk; break; case S_BOSS_ATK2: case S_BOS2_ATK2: case S_HEAD_ATK2: sfx = sfx_firsht; break; case S_SKULL_ATK2: sfx = sfx_sklatk; break; case S_SPID_ATK2: case S_SPID_ATK3: sfx = sfx_shotgn; break; case S_BSPI_ATK2: sfx = sfx_plasma; break; case S_CYBER_ATK2: case S_CYBER_ATK4: case S_CYBER_ATK6: sfx = sfx_rlaunc; break; case S_PAIN_ATK3: sfx = sfx_sklatk; break; default: sfx = 0; break; } if (sfx) S_StartSound (NULL, sfx); } if (castframes == 12) { // go into attack frame castattacking = true; if (castonmelee) caststate=&states[mobjinfo[castorder[castnum].type].meleestate]; else caststate=&states[mobjinfo[castorder[castnum].type].missilestate]; castonmelee ^= 1; if (caststate == &states[S_NULL]) { if (castonmelee) caststate= &states[mobjinfo[castorder[castnum].type].meleestate]; else caststate= &states[mobjinfo[castorder[castnum].type].missilestate]; } } if (castattacking) { if (castframes == 24 || caststate == &states[mobjinfo[castorder[castnum].type].seestate] ) { stopattack: castattacking = false; castframes = 0; caststate = &states[mobjinfo[castorder[castnum].type].seestate]; } } casttics = caststate->tics; if (casttics == -1) casttics = 15; } // // F_CastResponder // boolean F_CastResponder (event_t* ev) { if (ev->type != ev_keydown) return false; if (castdeath) return true; // already in dying frames // go into death frame castdeath = true; caststate = &states[mobjinfo[castorder[castnum].type].deathstate]; casttics = caststate->tics; castframes = 0; castattacking = false; if (mobjinfo[castorder[castnum].type].deathsound) S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound); return true; } void F_CastPrint (char* text) { char* ch; int c; int cx; int w; int width; // find width ch = text; width = 0; while (ch) { c = *ch++; if (!c) break; c = toupper(c) - HU_FONTSTART; if (c < 0 || c> HU_FONTSIZE) { width += 4; continue; } w = SHORT (hu_font[c]->width); width += w; } // draw it cx = 160-width/2; ch = text; while (ch) { c = *ch++; if (!c) break; c = toupper(c) - HU_FONTSTART; if (c < 0 || c> HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c]->width); V_DrawPatch(cx, 180, hu_font[c]); cx+=w; } } // // F_CastDrawer // void F_CastDrawer (void) { spritedef_t* sprdef; spriteframe_t* sprframe; int lump; boolean flip; patch_t* patch; // erase the entire screen to a background V_DrawPatch (0, 0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE)); F_CastPrint (DEH_String(castorder[castnum].name)); // draw the current frame in the middle of the screen sprdef = &sprites[caststate->sprite]; sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK]; lump = sprframe->lump[0]; flip = (boolean)sprframe->flip[0]; patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE); if (flip) V_DrawPatchFlipped(160, 170, patch); else V_DrawPatch(160, 170, patch); } // // F_DrawPatchCol // void F_DrawPatchCol ( int x, patch_t* patch, int col ) { column_t* column; byte* source; byte* dest; byte* desttop; int count; column = (column_t *)((byte *)patch + LONG(patch->columnofs[col])); desttop = I_VideoBuffer + x; // step through the posts in a column while (column->topdelta != 0xff ) { source = (byte *)column + 3; dest = desttop + column->topdelta*SCREENWIDTH; count = column->length; while (count--) { *dest = *source++; dest += SCREENWIDTH; } column = (column_t *)( (byte *)column + column->length + 4 ); } } // // F_BunnyScroll // void F_BunnyScroll (void) { signed int scrolled; int x; patch_t* p1; patch_t* p2; char name[10]; int stage; static int laststage; p1 = W_CacheLumpName (DEH_String("PFUB2"), PU_LEVEL); p2 = W_CacheLumpName (DEH_String("PFUB1"), PU_LEVEL); V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT); scrolled = (320 - ((signed int) finalecount-230)/2); if (scrolled > 320) scrolled = 320; if (scrolled < 0) scrolled = 0; for ( x=0 ; x 6) stage = 6; if (stage > laststage) { S_StartSound (NULL, sfx_pistol); laststage = stage; } DEH_snprintf(name, 10, "END%i", stage); V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, (SCREENHEIGHT - 8 * 8) / 2, W_CacheLumpName (name,PU_CACHE)); } static void F_ArtScreenDrawer(void) { char *lumpname; if (gameepisode == 3) { F_BunnyScroll(); } else { switch (gameepisode) { case 1: if (gamemode == retail) { lumpname = "CREDIT"; } else { lumpname = "HELP2"; } break; case 2: lumpname = "VICTORY2"; break; case 4: lumpname = "ENDPIC"; break; default: return; } lumpname = DEH_String(lumpname); V_DrawPatch (0, 0, W_CacheLumpName(lumpname, PU_CACHE)); } } // // F_Drawer // void F_Drawer (void) { switch (finalestage) { case F_STAGE_CAST: F_CastDrawer(); break; case F_STAGE_TEXT: F_TextWrite(); break; case F_STAGE_ARTSCREEN: F_ArtScreenDrawer(); break; } } chocolate-doom-chocolate-doom-2.2.1/src/doom/f_finale.h000066400000000000000000000016261257432200600227530ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __F_FINALE__ #define __F_FINALE__ #include "doomtype.h" #include "d_event.h" // // FINALE // // Called by main loop. boolean F_Responder (event_t* ev); // Called by main loop. void F_Ticker (void); // Called by main loop. void F_Drawer (void); void F_StartFinale (void); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/f_wipe.c000066400000000000000000000117241257432200600224540ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Mission begin melt/wipe screen special effect. // #include #include "z_zone.h" #include "i_video.h" #include "v_video.h" #include "m_random.h" #include "doomtype.h" #include "f_wipe.h" // // SCREEN WIPE PACKAGE // // when zero, stop the wipe static boolean go = 0; static byte* wipe_scr_start; static byte* wipe_scr_end; static byte* wipe_scr; void wipe_shittyColMajorXform ( short* array, int width, int height ) { int x; int y; short* dest; dest = (short*) Z_Malloc(width*height*2, PU_STATIC, 0); for(y=0;y *e) { newval = *w - ticks; if (newval < *e) *w = *e; else *w = newval; changed = true; } else if (*w < *e) { newval = *w + ticks; if (newval > *e) *w = *e; else *w = newval; changed = true; } } w++; e++; } return !changed; } int wipe_exitColorXForm ( int width, int height, int ticks ) { return 0; } static int* y; int wipe_initMelt ( int width, int height, int ticks ) { int i, r; // copy start screen to main screen memcpy(wipe_scr, wipe_scr_start, width*height); // makes this wipe faster (in theory) // to have stuff in column-major format wipe_shittyColMajorXform((short*)wipe_scr_start, width/2, height); wipe_shittyColMajorXform((short*)wipe_scr_end, width/2, height); // setup initial column positions // (y<0 => not ready to scroll yet) y = (int *) Z_Malloc(width*sizeof(int), PU_STATIC, 0); y[0] = -(M_Random()%16); for (i=1;i 0) y[i] = 0; else if (y[i] == -16) y[i] = -15; } return 0; } int wipe_doMelt ( int width, int height, int ticks ) { int i; int j; int dy; int idx; short* s; short* d; boolean done = true; width/=2; while (ticks--) { for (i=0;i= height) dy = height - y[i]; s = &((short *)wipe_scr_end)[i*height+y[i]]; d = &((short *)wipe_scr)[y[i]*width+i]; idx = 0; for (j=dy;j;j--) { d[idx] = *(s++); idx += width; } y[i] += dy; s = &((short *)wipe_scr_start)[i*height]; d = &((short *)wipe_scr)[y[i]*width+i]; idx = 0; for (j=height-y[i];j;j--) { d[idx] = *(s++); idx += width; } done = false; } } } return done; } int wipe_exitMelt ( int width, int height, int ticks ) { Z_Free(y); Z_Free(wipe_scr_start); Z_Free(wipe_scr_end); return 0; } int wipe_StartScreen ( int x, int y, int width, int height ) { wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); I_ReadScreen(wipe_scr_start); return 0; } int wipe_EndScreen ( int x, int y, int width, int height ) { wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); I_ReadScreen(wipe_scr_end); V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr. return 0; } int wipe_ScreenWipe ( int wipeno, int x, int y, int width, int height, int ticks ) { int rc; static int (*wipes[])(int, int, int) = { wipe_initColorXForm, wipe_doColorXForm, wipe_exitColorXForm, wipe_initMelt, wipe_doMelt, wipe_exitMelt }; // initial stuff if (!go) { go = 1; // wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG wipe_scr = I_VideoBuffer; (*wipes[wipeno*3])(width, height, ticks); } // do a piece of wipe-in V_MarkRect(0, 0, width, height); rc = (*wipes[wipeno*3+1])(width, height, ticks); // V_DrawBlock(x, y, 0, width, height, wipe_scr); // DEBUG // final stuff if (rc) { go = 0; (*wipes[wipeno*3+2])(width, height, ticks); } return !go; } chocolate-doom-chocolate-doom-2.2.1/src/doom/f_wipe.h000066400000000000000000000022131257432200600224520ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Mission start screen wipe/melt, special effects. // #ifndef __F_WIPE_H__ #define __F_WIPE_H__ // // SCREEN WIPE PACKAGE // enum { // simple gradual pixel change for 8-bit only wipe_ColorXForm, // weird screen melt wipe_Melt, wipe_NUMWIPES }; int wipe_StartScreen ( int x, int y, int width, int height ); int wipe_EndScreen ( int x, int y, int width, int height ); int wipe_ScreenWipe ( int wipeno, int x, int y, int width, int height, int ticks ); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/g_game.c000066400000000000000000001451111257432200600224200ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // #include #include #include #include "doomdef.h" #include "doomkeys.h" #include "doomstat.h" #include "deh_main.h" #include "deh_misc.h" #include "z_zone.h" #include "f_finale.h" #include "m_argv.h" #include "m_controls.h" #include "m_misc.h" #include "m_menu.h" #include "m_random.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "p_setup.h" #include "p_saveg.h" #include "p_tick.h" #include "d_main.h" #include "wi_stuff.h" #include "hu_stuff.h" #include "st_stuff.h" #include "am_map.h" #include "statdump.h" // Needs access to LFB. #include "v_video.h" #include "w_wad.h" #include "p_local.h" #include "s_sound.h" // Data. #include "dstrings.h" #include "sounds.h" // SKY handling - still the wrong place. #include "r_data.h" #include "r_sky.h" #include "g_game.h" #define SAVEGAMESIZE 0x2c000 void G_ReadDemoTiccmd (ticcmd_t* cmd); void G_WriteDemoTiccmd (ticcmd_t* cmd); void G_PlayerReborn (int player); void G_DoReborn (int playernum); void G_DoLoadLevel (void); void G_DoNewGame (void); void G_DoPlayDemo (void); void G_DoCompleted (void); void G_DoVictory (void); void G_DoWorldDone (void); void G_DoSaveGame (void); // Gamestate the last time G_Ticker was called. gamestate_t oldgamestate; gameaction_t gameaction; gamestate_t gamestate; skill_t gameskill; boolean respawnmonsters; int gameepisode; int gamemap; // If non-zero, exit the level after this number of minutes. int timelimit; boolean paused; boolean sendpause; // send a pause event next tic boolean sendsave; // send a save event next tic boolean usergame; // ok to save / end game boolean timingdemo; // if true, exit with report on completion boolean nodrawers; // for comparative timing purposes int starttime; // for comparative timing purposes boolean viewactive; int deathmatch; // only if started as net death boolean netgame; // only true if packets are broadcast boolean playeringame[MAXPLAYERS]; player_t players[MAXPLAYERS]; boolean turbodetected[MAXPLAYERS]; int consoleplayer; // player taking events and displaying int displayplayer; // view being displayed int levelstarttic; // gametic at level start int totalkills, totalitems, totalsecret; // for intermission char *demoname; boolean demorecording; boolean longtics; // cph's doom 1.91 longtics hack boolean lowres_turn; // low resolution turning for longtics boolean demoplayback; boolean netdemo; byte* demobuffer; byte* demo_p; byte* demoend; boolean singledemo; // quit after playing a demo from cmdline boolean precache = true; // if true, load all graphics at start boolean testcontrols = false; // Invoked by setup to test controls int testcontrols_mousespeed; wbstartstruct_t wminfo; // parms for world map / intermission byte consistancy[MAXPLAYERS][BACKUPTICS]; #define MAXPLMOVE (forwardmove[1]) #define TURBOTHRESHOLD 0x32 fixed_t forwardmove[2] = {0x19, 0x32}; fixed_t sidemove[2] = {0x18, 0x28}; fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn static int *weapon_keys[] = { &key_weapon1, &key_weapon2, &key_weapon3, &key_weapon4, &key_weapon5, &key_weapon6, &key_weapon7, &key_weapon8 }; // Set to -1 or +1 to switch to the previous or next weapon. static int next_weapon = 0; // Used for prev/next weapon keys. static const struct { weapontype_t weapon; weapontype_t weapon_num; } weapon_order_table[] = { { wp_fist, wp_fist }, { wp_chainsaw, wp_fist }, { wp_pistol, wp_pistol }, { wp_shotgun, wp_shotgun }, { wp_supershotgun, wp_shotgun }, { wp_chaingun, wp_chaingun }, { wp_missile, wp_missile }, { wp_plasma, wp_plasma }, { wp_bfg, wp_bfg } }; #define SLOWTURNTICS 6 #define NUMKEYS 256 #define MAX_JOY_BUTTONS 20 static boolean gamekeydown[NUMKEYS]; static int turnheld; // for accelerative turning static boolean mousearray[MAX_MOUSE_BUTTONS + 1]; static boolean *mousebuttons = &mousearray[1]; // allow [-1] // mouse values are used once int mousex; int mousey; static int dclicktime; static boolean dclickstate; static int dclicks; static int dclicktime2; static boolean dclickstate2; static int dclicks2; // joystick values are repeated static int joyxmove; static int joyymove; static int joystrafemove; static boolean joyarray[MAX_JOY_BUTTONS + 1]; static boolean *joybuttons = &joyarray[1]; // allow [-1] static int savegameslot; static char savedescription[32]; #define BODYQUESIZE 32 mobj_t* bodyque[BODYQUESIZE]; int bodyqueslot; int vanilla_savegame_limit = 1; int vanilla_demo_limit = 1; int G_CmdChecksum (ticcmd_t* cmd) { size_t i; int sum = 0; for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++) sum += ((int *)cmd)[i]; return sum; } static boolean WeaponSelectable(weapontype_t weapon) { // Can't select the super shotgun in Doom 1. if (weapon == wp_supershotgun && logical_gamemission == doom) { return false; } // These weapons aren't available in shareware. if ((weapon == wp_plasma || weapon == wp_bfg) && gamemission == doom && gamemode == shareware) { return false; } // Can't select a weapon if we don't own it. if (!players[consoleplayer].weaponowned[weapon]) { return false; } // Can't select the fist if we have the chainsaw, unless // we also have the berserk pack. if (weapon == wp_fist && players[consoleplayer].weaponowned[wp_chainsaw] && !players[consoleplayer].powers[pw_strength]) { return false; } return true; } static int G_NextWeapon(int direction) { weapontype_t weapon; int start_i, i; // Find index in the table. if (players[consoleplayer].pendingweapon == wp_nochange) { weapon = players[consoleplayer].readyweapon; } else { weapon = players[consoleplayer].pendingweapon; } for (i=0; iconsistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; // fraggle: support the old "joyb_speed = 31" hack which // allowed an autorun effect speed = key_speed >= NUMKEYS || joybspeed >= MAX_JOY_BUTTONS || gamekeydown[key_speed] || joybuttons[joybspeed]; forward = side = 0; // use two stage accelerative turning // on the keyboard and joystick if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left]) turnheld += ticdup; else turnheld = 0; if (turnheld < SLOWTURNTICS) tspeed = 2; // slow turn else tspeed = speed; // let movement keys cancel each other out if (strafe) { if (gamekeydown[key_right]) { // fprintf(stderr, "strafe right\n"); side += sidemove[speed]; } if (gamekeydown[key_left]) { // fprintf(stderr, "strafe left\n"); side -= sidemove[speed]; } if (joyxmove > 0) side += sidemove[speed]; if (joyxmove < 0) side -= sidemove[speed]; } else { if (gamekeydown[key_right]) cmd->angleturn -= angleturn[tspeed]; if (gamekeydown[key_left]) cmd->angleturn += angleturn[tspeed]; if (joyxmove > 0) cmd->angleturn -= angleturn[tspeed]; if (joyxmove < 0) cmd->angleturn += angleturn[tspeed]; } if (gamekeydown[key_up]) { // fprintf(stderr, "up\n"); forward += forwardmove[speed]; } if (gamekeydown[key_down]) { // fprintf(stderr, "down\n"); forward -= forwardmove[speed]; } if (joyymove < 0) forward += forwardmove[speed]; if (joyymove > 0) forward -= forwardmove[speed]; if (gamekeydown[key_strafeleft] || joybuttons[joybstrafeleft] || mousebuttons[mousebstrafeleft] || joystrafemove < 0) { side -= sidemove[speed]; } if (gamekeydown[key_straferight] || joybuttons[joybstraferight] || mousebuttons[mousebstraferight] || joystrafemove > 0) { side += sidemove[speed]; } // buttons cmd->chatchar = HU_dequeueChatChar(); if (gamekeydown[key_fire] || mousebuttons[mousebfire] || joybuttons[joybfire]) cmd->buttons |= BT_ATTACK; if (gamekeydown[key_use] || joybuttons[joybuse] || mousebuttons[mousebuse]) { cmd->buttons |= BT_USE; // clear double clicks if hit use button dclicks = 0; } // If the previous or next weapon button is pressed, the // next_weapon variable is set to change weapons when // we generate a ticcmd. Choose a new weapon. if (gamestate == GS_LEVEL && next_weapon != 0) { i = G_NextWeapon(next_weapon); cmd->buttons |= BT_CHANGE; cmd->buttons |= i << BT_WEAPONSHIFT; } else { // Check weapon keys. for (i=0; ibuttons |= BT_CHANGE; cmd->buttons |= i< 1 ) { dclickstate = mousebuttons[mousebforward]; if (dclickstate) dclicks++; if (dclicks == 2) { cmd->buttons |= BT_USE; dclicks = 0; } else dclicktime = 0; } else { dclicktime += ticdup; if (dclicktime > 20) { dclicks = 0; dclickstate = 0; } } // strafe double click bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; if (bstrafe != dclickstate2 && dclicktime2 > 1 ) { dclickstate2 = bstrafe; if (dclickstate2) dclicks2++; if (dclicks2 == 2) { cmd->buttons |= BT_USE; dclicks2 = 0; } else dclicktime2 = 0; } else { dclicktime2 += ticdup; if (dclicktime2 > 20) { dclicks2 = 0; dclickstate2 = 0; } } } forward += mousey; if (strafe) side += mousex*2; else cmd->angleturn -= mousex*0x8; if (mousex == 0) { // No movement in the previous frame testcontrols_mousespeed = 0; } mousex = mousey = 0; if (forward > MAXPLMOVE) forward = MAXPLMOVE; else if (forward < -MAXPLMOVE) forward = -MAXPLMOVE; if (side > MAXPLMOVE) side = MAXPLMOVE; else if (side < -MAXPLMOVE) side = -MAXPLMOVE; cmd->forwardmove += forward; cmd->sidemove += side; // special buttons if (sendpause) { sendpause = false; cmd->buttons = BT_SPECIAL | BTS_PAUSE; } if (sendsave) { sendsave = false; cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<angleturn + carry; // round angleturn to the nearest 256 unit boundary // for recording demos with single byte values for turn cmd->angleturn = (desired_angleturn + 128) & 0xff00; // Carry forward the error from the reduced resolution to the // next tic, so that successive small movements can accumulate. carry = desired_angleturn - cmd->angleturn; } } // // G_DoLoadLevel // void G_DoLoadLevel (void) { int i; // Set the sky map. // First thing, we have a dummy sky texture name, // a flat. The data is in the WAD only because // we look for an actual index, instead of simply // setting one. skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME)); // The "Sky never changes in Doom II" bug was fixed in // the id Anthology version of doom2.exe for Final Doom. if ((gamemode == commercial) && (gameversion == exe_final2)) { char *skytexturename; if (gamemap < 12) { skytexturename = "SKY1"; } else if (gamemap < 21) { skytexturename = "SKY2"; } else { skytexturename = "SKY3"; } skytexturename = DEH_String(skytexturename); skytexture = R_TextureNumForName(skytexturename); } levelstarttic = gametic; // for time calculation if (wipegamestate == GS_LEVEL) wipegamestate = -1; // force a wipe gamestate = GS_LEVEL; for (i=0 ; itype == ev_keydown && ev->data1 == key_spy && (singledemo || !deathmatch) ) { // spy mode do { displayplayer++; if (displayplayer == MAXPLAYERS) displayplayer = 0; } while (!playeringame[displayplayer] && displayplayer != consoleplayer); return true; } // any other key pops up menu if in demos if (gameaction == ga_nothing && !singledemo && (demoplayback || gamestate == GS_DEMOSCREEN) ) { if (ev->type == ev_keydown || (ev->type == ev_mouse && ev->data1) || (ev->type == ev_joystick && ev->data1) ) { M_StartControlPanel (); return true; } return false; } if (gamestate == GS_LEVEL) { #if 0 if (devparm && ev->type == ev_keydown && ev->data1 == ';') { G_DeathMatchSpawnPlayer (0); return true; } #endif if (HU_Responder (ev)) return true; // chat ate the event if (ST_Responder (ev)) return true; // status window ate it if (AM_Responder (ev)) return true; // automap ate it } if (gamestate == GS_FINALE) { if (F_Responder (ev)) return true; // finale ate the event } if (testcontrols && ev->type == ev_mouse) { // If we are invoked by setup to test the controls, save the // mouse speed so that we can display it on-screen. // Perform a low pass filter on this so that the thermometer // appears to move smoothly. testcontrols_mousespeed = abs(ev->data2); } // If the next/previous weapon keys are pressed, set the next_weapon // variable to change weapons when the next ticcmd is generated. if (ev->type == ev_keydown && ev->data1 == key_prevweapon) { next_weapon = -1; } else if (ev->type == ev_keydown && ev->data1 == key_nextweapon) { next_weapon = 1; } switch (ev->type) { case ev_keydown: if (ev->data1 == key_pause) { sendpause = true; } else if (ev->data1 data1] = true; } return true; // eat key down events case ev_keyup: if (ev->data1 data1] = false; return false; // always let key up events filter down case ev_mouse: SetMouseButtons(ev->data1); mousex = ev->data2*(mouseSensitivity+5)/10; mousey = ev->data3*(mouseSensitivity+5)/10; return true; // eat events case ev_joystick: SetJoyButtons(ev->data1); joyxmove = ev->data2; joyymove = ev->data3; joystrafemove = ev->data4; return true; // eat events default: break; } return false; } // // G_Ticker // Make ticcmd_ts for the players. // void G_Ticker (void) { int i; int buf; ticcmd_t* cmd; // do player reborns if needed for (i=0 ; iforwardmove > TURBOTHRESHOLD) { turbodetected[i] = true; } if ((gametic & 31) == 0 && ((gametic >> 5) % MAXPLAYERS) == i && turbodetected[i]) { static char turbomessage[80]; extern char *player_names[4]; M_snprintf(turbomessage, sizeof(turbomessage), "%s is turbo!", player_names[i]); players[consoleplayer].message = turbomessage; turbodetected[i] = false; } if (netgame && !netdemo && !(gametic%ticdup) ) { if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy) { I_Error ("consistency failure (%i should be %i)", cmd->consistancy, consistancy[i][buf]); } if (players[i].mo) consistancy[i][buf] = players[i].mo->x; else consistancy[i][buf] = rndindex; } } } // check for special buttons for (i=0 ; i>BTS_SAVESHIFT; gameaction = ga_savegame; break; } } } } // Have we just finished displaying an intermission screen? if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION) { WI_End(); } oldgamestate = gamestate; // do main actions switch (gamestate) { case GS_LEVEL: P_Ticker (); ST_Ticker (); AM_Ticker (); HU_Ticker (); break; case GS_INTERMISSION: WI_Ticker (); break; case GS_FINALE: F_Ticker (); break; case GS_DEMOSCREEN: D_PageTicker (); break; } } // // PLAYER STRUCTURE FUNCTIONS // also see P_SpawnPlayer in P_Things // // // G_InitPlayer // Called at the start. // Called by the game initialization functions. // void G_InitPlayer (int player) { // clear everything else to defaults G_PlayerReborn (player); } // // G_PlayerFinishLevel // Can when a player completes a level. // void G_PlayerFinishLevel (int player) { player_t* p; p = &players[player]; memset (p->powers, 0, sizeof (p->powers)); memset (p->cards, 0, sizeof (p->cards)); p->mo->flags &= ~MF_SHADOW; // cancel invisibility p->extralight = 0; // cancel gun flashes p->fixedcolormap = 0; // cancel ir gogles p->damagecount = 0; // no palette changes p->bonuscount = 0; } // // G_PlayerReborn // Called after a player dies // almost everything is cleared and initialized // void G_PlayerReborn (int player) { player_t* p; int i; int frags[MAXPLAYERS]; int killcount; int itemcount; int secretcount; memcpy (frags,players[player].frags,sizeof(frags)); killcount = players[player].killcount; itemcount = players[player].itemcount; secretcount = players[player].secretcount; p = &players[player]; memset (p, 0, sizeof(*p)); memcpy (players[player].frags, frags, sizeof(players[player].frags)); players[player].killcount = killcount; players[player].itemcount = itemcount; players[player].secretcount = secretcount; p->usedown = p->attackdown = true; // don't do anything immediately p->playerstate = PST_LIVE; p->health = deh_initial_health; // Use dehacked value p->readyweapon = p->pendingweapon = wp_pistol; p->weaponowned[wp_fist] = true; p->weaponowned[wp_pistol] = true; p->ammo[am_clip] = deh_initial_bullets; for (i=0 ; imaxammo[i] = maxammo[i]; } // // G_CheckSpot // Returns false if the player cannot be respawned // at the given mapthing_t spot // because something is occupying it // void P_SpawnPlayer (mapthing_t* mthing); boolean G_CheckSpot ( int playernum, mapthing_t* mthing ) { fixed_t x; fixed_t y; subsector_t* ss; mobj_t* mo; int i; if (!players[playernum].mo) { // first spawn of level, before corpses for (i=0 ; ix == mthing->x << FRACBITS && players[i].mo->y == mthing->y << FRACBITS) return false; return true; } x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (!P_CheckPosition (players[playernum].mo, x, y) ) return false; // flush an old corpse if needed if (bodyqueslot >= BODYQUESIZE) P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]); bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo; bodyqueslot++; // spawn a teleport fog ss = R_PointInSubsector (x,y); // The code in the released source looks like this: // // an = ( ANG45 * (((unsigned int) mthing->angle)/45) ) // >> ANGLETOFINESHIFT; // mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an] // , ss->sector->floorheight // , MT_TFOG); // // But 'an' can be a signed value in the DOS version. This means that // we get a negative index and the lookups into finecosine/finesine // end up dereferencing values in finetangent[]. // A player spawning on a deathmatch start facing directly west spawns // "silently" with no spawn fog. Emulate this. // // This code is imported from PrBoom+. { fixed_t xa, ya; signed int an; // This calculation overflows in Vanilla Doom, but here we deliberately // avoid integer overflow as it is undefined behavior, so the value of // 'an' will always be positive. an = (ANG45 >> ANGLETOFINESHIFT) * ((signed int) mthing->angle / 45); switch (an) { case 4096: // -4096: xa = finetangent[2048]; // finecosine[-4096] ya = finetangent[0]; // finesine[-4096] break; case 5120: // -3072: xa = finetangent[3072]; // finecosine[-3072] ya = finetangent[1024]; // finesine[-3072] break; case 6144: // -2048: xa = finesine[0]; // finecosine[-2048] ya = finetangent[2048]; // finesine[-2048] break; case 7168: // -1024: xa = finesine[1024]; // finecosine[-1024] ya = finetangent[3072]; // finesine[-1024] break; case 0: case 1024: case 2048: case 3072: xa = finecosine[an]; ya = finesine[an]; break; default: I_Error("G_CheckSpot: unexpected angle %d\n", an); xa = ya = 0; break; } mo = P_SpawnMobj(x + 20 * xa, y + 20 * ya, ss->sector->floorheight, MT_TFOG); } if (players[consoleplayer].viewz != 1) S_StartSound (mo, sfx_telept); // don't start sound on first frame return true; } // // G_DeathMatchSpawnPlayer // Spawns a player at one of the random death match spots // called at level load and each death // void G_DeathMatchSpawnPlayer (int playernum) { int i,j; int selections; selections = deathmatch_p - deathmatchstarts; if (selections < 4) I_Error ("Only %i deathmatch spots, 4 required", selections); for (j=0 ; j<20 ; j++) { i = P_Random() % selections; if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) { deathmatchstarts[i].type = playernum+1; P_SpawnPlayer (&deathmatchstarts[i]); return; } } // no good spot, so the player will probably get stuck P_SpawnPlayer (&playerstarts[playernum]); } // // G_DoReborn // void G_DoReborn (int playernum) { int i; if (!netgame) { // reload the level from scratch gameaction = ga_loadlevel; } else { // respawn at the start // first dissasociate the corpse players[playernum].mo->player = NULL; // spawn at random spot if in death match if (deathmatch) { G_DeathMatchSpawnPlayer (playernum); return; } if (G_CheckSpot (playernum, &playerstarts[playernum]) ) { P_SpawnPlayer (&playerstarts[playernum]); return; } // try to spawn at one of the other players spots for (i=0 ; i SAVEGAMESIZE) { I_Error ("Savegame buffer overrun"); } // Finish up, close the savegame file. fclose(save_stream); // Now rename the temporary savegame file to the actual savegame // file, overwriting the old savegame if there was one there. remove(savegame_file); rename(temp_savegame_file, savegame_file); gameaction = ga_nothing; M_StringCopy(savedescription, "", sizeof(savedescription)); players[consoleplayer].message = DEH_String(GGSAVED); // draw the pattern into the back screen R_FillBackScreen (); } // // G_InitNew // Can be called by the startup code or the menu task, // consoleplayer, displayplayer, playeringame[] should be set. // skill_t d_skill; int d_episode; int d_map; void G_DeferedInitNew ( skill_t skill, int episode, int map) { d_skill = skill; d_episode = episode; d_map = map; gameaction = ga_newgame; } void G_DoNewGame (void) { demoplayback = false; netdemo = false; netgame = false; deathmatch = false; playeringame[1] = playeringame[2] = playeringame[3] = 0; respawnparm = false; fastparm = false; nomonsters = false; consoleplayer = 0; G_InitNew (d_skill, d_episode, d_map); gameaction = ga_nothing; } void G_InitNew ( skill_t skill, int episode, int map ) { char *skytexturename; int i; if (paused) { paused = false; S_ResumeSound (); } /* // Note: This commented-out block of code was added at some point // between the DOS version(s) and the Doom source release. It isn't // found in disassemblies of the DOS version and causes IDCLEV and // the -warp command line parameter to behave differently. // This is left here for posterity. if (skill > sk_nightmare) skill = sk_nightmare; // This was quite messy with SPECIAL and commented parts. // Supposedly hacks to make the latest edition work. // It might not work properly. if (episode < 1) episode = 1; if ( gamemode == retail ) { if (episode > 4) episode = 4; } else if ( gamemode == shareware ) { if (episode > 1) episode = 1; // only start episode 1 on shareware } else { if (episode > 3) episode = 3; } */ if (map < 1) map = 1; if ( (map > 9) && ( gamemode != commercial) ) map = 9; M_ClearRandom (); if (skill == sk_nightmare || respawnparm ) respawnmonsters = true; else respawnmonsters = false; if (fastparm || (skill == sk_nightmare && gameskill != sk_nightmare) ) { for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++) states[i].tics >>= 1; mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT; mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT; mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT; } else if (skill != sk_nightmare && gameskill == sk_nightmare) { for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++) states[i].tics <<= 1; mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT; mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT; mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT; } // force players to be initialized upon first level load for (i=0 ; iforwardmove = ((signed char)*demo_p++); cmd->sidemove = ((signed char)*demo_p++); // If this is a longtics demo, read back in higher resolution if (longtics) { cmd->angleturn = *demo_p++; cmd->angleturn |= (*demo_p++) << 8; } else { cmd->angleturn = ((unsigned char) *demo_p++)<<8; } cmd->buttons = (unsigned char)*demo_p++; } // Increase the size of the demo buffer to allow unlimited demos static void IncreaseDemoBuffer(void) { int current_length; byte *new_demobuffer; byte *new_demop; int new_length; // Find the current size current_length = demoend - demobuffer; // Generate a new buffer twice the size new_length = current_length * 2; new_demobuffer = Z_Malloc(new_length, PU_STATIC, 0); new_demop = new_demobuffer + (demo_p - demobuffer); // Copy over the old data memcpy(new_demobuffer, demobuffer, current_length); // Free the old buffer and point the demo pointers at the new buffer. Z_Free(demobuffer); demobuffer = new_demobuffer; demo_p = new_demop; demoend = demobuffer + new_length; } void G_WriteDemoTiccmd (ticcmd_t* cmd) { byte *demo_start; if (gamekeydown[key_demo_quit]) // press q to end demo recording G_CheckDemoStatus (); demo_start = demo_p; *demo_p++ = cmd->forwardmove; *demo_p++ = cmd->sidemove; // If this is a longtics demo, record in higher resolution if (longtics) { *demo_p++ = (cmd->angleturn & 0xff); *demo_p++ = (cmd->angleturn >> 8) & 0xff; } else { *demo_p++ = cmd->angleturn >> 8; } *demo_p++ = cmd->buttons; // reset demo pointer back demo_p = demo_start; if (demo_p > demoend - 16) { if (vanilla_demo_limit) { // no more space G_CheckDemoStatus (); return; } else { // Vanilla demo limit disabled: unlimited // demo lengths! IncreaseDemoBuffer(); } } G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same } // // G_RecordDemo // void G_RecordDemo (char *name) { size_t demoname_size; int i; int maxsize; usergame = false; demoname_size = strlen(name) + 5; demoname = Z_Malloc(demoname_size, PU_STATIC, NULL); M_snprintf(demoname, demoname_size, "%s.lmp", name); maxsize = 0x20000; //! // @arg // @category demo // @vanilla // // Specify the demo buffer size (KiB) // i = M_CheckParmWithArgs("-maxdemo", 1); if (i) maxsize = atoi(myargv[i+1])*1024; demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL); demoend = demobuffer + maxsize; demorecording = true; } // Get the demo version code appropriate for the version set in gameversion. int G_VanillaVersionCode(void) { switch (gameversion) { case exe_doom_1_2: I_Error("Doom 1.2 does not have a version code!"); case exe_doom_1_666: return 106; case exe_doom_1_7: return 107; case exe_doom_1_8: return 108; case exe_doom_1_9: default: // All other versions are variants on v1.9: return 109; } } void G_BeginRecording (void) { int i; //! // @category demo // // Record a high resolution "Doom 1.91" demo. // longtics = M_CheckParm("-longtics") != 0; // If not recording a longtics demo, record in low res lowres_turn = !longtics; demo_p = demobuffer; // Save the right version code for this demo if (longtics) { *demo_p++ = DOOM_191_VERSION; } else { *demo_p++ = G_VanillaVersionCode(); } *demo_p++ = gameskill; *demo_p++ = gameepisode; *demo_p++ = gamemap; *demo_p++ = deathmatch; *demo_p++ = respawnparm; *demo_p++ = fastparm; *demo_p++ = nomonsters; *demo_p++ = consoleplayer; for (i=0 ; i= 0 && version <= 4) { return "v1.0/v1.1/v1.2"; } else { M_snprintf(resultbuf, sizeof(resultbuf), "%i.%i (unknown)", version / 100, version % 100); return resultbuf; } } void G_DoPlayDemo (void) { skill_t skill; int i, episode, map; int demoversion; gameaction = ga_nothing; demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC); demoversion = *demo_p++; if (demoversion == G_VanillaVersionCode()) { longtics = false; } else if (demoversion == DOOM_191_VERSION) { // demo recorded with cph's modified "v1.91" doom exe longtics = true; } else { char *message = "Demo is from a different game version!\n" "(read %i, should be %i)\n" "\n" "*** You may need to upgrade your version " "of Doom to v1.9. ***\n" " See: http://doomworld.com/files/patches.shtml\n" " This appears to be %s."; I_Error(message, demoversion, G_VanillaVersionCode(), DemoVersionDescription(demoversion)); } skill = *demo_p++; episode = *demo_p++; map = *demo_p++; deathmatch = *demo_p++; respawnparm = *demo_p++; fastparm = *demo_p++; nomonsters = *demo_p++; consoleplayer = *demo_p++; for (i=0 ; i 0 || M_CheckParm("-netdemo") > 0) { netgame = true; netdemo = true; } // don't spend a lot of time in loadlevel precache = false; G_InitNew (skill, episode, map); precache = true; starttime = I_GetTime (); usergame = false; demoplayback = true; } // // G_TimeDemo // void G_TimeDemo (char* name) { //! // @vanilla // // Disable rendering the screen entirely. // nodrawers = M_CheckParm ("-nodraw"); timingdemo = true; singletics = true; defdemoname = name; gameaction = ga_playdemo; } /* =================== = = G_CheckDemoStatus = = Called after a death or level completion to allow demos to be cleaned up = Returns true if a new demo loop action will take place =================== */ boolean G_CheckDemoStatus (void) { int endtime; if (timingdemo) { float fps; int realtics; endtime = I_GetTime (); realtics = endtime - starttime; fps = ((float) gametic * TICRATE) / realtics; // Prevent recursive calls timingdemo = false; demoplayback = false; I_Error ("timed %i gametics in %i realtics (%f fps)", gametic, realtics, fps); } if (demoplayback) { W_ReleaseLumpName(defdemoname); demoplayback = false; netdemo = false; netgame = false; deathmatch = false; playeringame[1] = playeringame[2] = playeringame[3] = 0; respawnparm = false; fastparm = false; nomonsters = false; consoleplayer = 0; if (singledemo) I_Quit (); else D_AdvanceDemo (); return true; } if (demorecording) { *demo_p++ = DEMOMARKER; M_WriteFile (demoname, demobuffer, demo_p - demobuffer); Z_Free (demobuffer); demorecording = false; I_Error ("Demo %s recorded",demoname); } return false; } chocolate-doom-chocolate-doom-2.2.1/src/doom/g_game.h000066400000000000000000000035741257432200600224330ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Duh. // #ifndef __G_GAME__ #define __G_GAME__ #include "doomdef.h" #include "d_event.h" #include "d_ticcmd.h" // // GAME // void G_DeathMatchSpawnPlayer (int playernum); void G_InitNew (skill_t skill, int episode, int map); // Can be called by the startup code or M_Responder. // A normal game starts at map 1, // but a warp test can start elsewhere void G_DeferedInitNew (skill_t skill, int episode, int map); void G_DeferedPlayDemo (char* demo); // Can be called by the startup code or M_Responder, // calls P_SetupLevel or W_EnterWorld. void G_LoadGame (char* name); void G_DoLoadGame (void); // Called by M_Responder. void G_SaveGame (int slot, char* description); // Only called by startup code. void G_RecordDemo (char* name); void G_BeginRecording (void); void G_PlayDemo (char* name); void G_TimeDemo (char* name); boolean G_CheckDemoStatus (void); void G_ExitLevel (void); void G_SecretExitLevel (void); void G_WorldDone (void); // Read current data from inputs and build a player movement command. void G_BuildTiccmd (ticcmd_t *cmd, int maketic); void G_Ticker (void); boolean G_Responder (event_t* ev); void G_ScreenShot (void); void G_DrawMouseSpeedBox(void); int G_VanillaVersionCode(void); extern int vanilla_savegame_limit; extern int vanilla_demo_limit; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/hu_lib.c000066400000000000000000000141371257432200600224460ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: heads-up text and input code // #include #include "doomdef.h" #include "doomkeys.h" #include "v_video.h" #include "i_swap.h" #include "hu_lib.h" #include "r_local.h" #include "r_draw.h" // boolean : whether the screen is always erased #define noterased viewwindowx extern boolean automapactive; // in AM_map.c void HUlib_init(void) { } void HUlib_clearTextLine(hu_textline_t* t) { t->len = 0; t->l[0] = 0; t->needsupdate = true; } void HUlib_initTextLine ( hu_textline_t* t, int x, int y, patch_t** f, int sc ) { t->x = x; t->y = y; t->f = f; t->sc = sc; HUlib_clearTextLine(t); } boolean HUlib_addCharToTextLine ( hu_textline_t* t, char ch ) { if (t->len == HU_MAXLINELENGTH) return false; else { t->l[t->len++] = ch; t->l[t->len] = 0; t->needsupdate = 4; return true; } } boolean HUlib_delCharFromTextLine(hu_textline_t* t) { if (!t->len) return false; else { t->l[--t->len] = 0; t->needsupdate = 4; return true; } } void HUlib_drawTextLine ( hu_textline_t* l, boolean drawcursor ) { int i; int w; int x; unsigned char c; // draw the new stuff x = l->x; for (i=0;ilen;i++) { c = toupper(l->l[i]); if (c != ' ' && c >= l->sc && c <= '_') { w = SHORT(l->f[c - l->sc]->width); if (x+w > SCREENWIDTH) break; V_DrawPatchDirect(x, l->y, l->f[c - l->sc]); x += w; } else { x += 4; if (x >= SCREENWIDTH) break; } } // draw the cursor if requested if (drawcursor && x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH) { V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]); } } // sorta called by HU_Erase and just better darn get things straight void HUlib_eraseTextLine(hu_textline_t* l) { int lh; int y; int yoffset; // Only erases when NOT in automap and the screen is reduced, // and the text must either need updating or refreshing // (because of a recent change back from the automap) if (!automapactive && viewwindowx && l->needsupdate) { lh = SHORT(l->f[0]->height) + 1; for (y=l->y,yoffset=y*SCREENWIDTH ; yy+lh ; y++,yoffset+=SCREENWIDTH) { if (y < viewwindowy || y >= viewwindowy + viewheight) R_VideoErase(yoffset, SCREENWIDTH); // erase entire line else { R_VideoErase(yoffset, viewwindowx); // erase left border R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx); // erase right border } } } if (l->needsupdate) l->needsupdate--; } void HUlib_initSText ( hu_stext_t* s, int x, int y, int h, patch_t** font, int startchar, boolean* on ) { int i; s->h = h; s->on = on; s->laston = true; s->cl = 0; for (i=0;il[i], x, y - i*(SHORT(font[0]->height)+1), font, startchar); } void HUlib_addLineToSText(hu_stext_t* s) { int i; // add a clear line if (++s->cl == s->h) s->cl = 0; HUlib_clearTextLine(&s->l[s->cl]); // everything needs updating for (i=0 ; ih ; i++) s->l[i].needsupdate = 4; } void HUlib_addMessageToSText ( hu_stext_t* s, char* prefix, char* msg ) { HUlib_addLineToSText(s); if (prefix) while (*prefix) HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++)); while (*msg) HUlib_addCharToTextLine(&s->l[s->cl], *(msg++)); } void HUlib_drawSText(hu_stext_t* s) { int i, idx; hu_textline_t *l; if (!*s->on) return; // if not on, don't draw // draw everything for (i=0 ; ih ; i++) { idx = s->cl - i; if (idx < 0) idx += s->h; // handle queue of lines l = &s->l[idx]; // need a decision made here on whether to skip the draw HUlib_drawTextLine(l, false); // no cursor, please } } void HUlib_eraseSText(hu_stext_t* s) { int i; for (i=0 ; ih ; i++) { if (s->laston && !*s->on) s->l[i].needsupdate = 4; HUlib_eraseTextLine(&s->l[i]); } s->laston = *s->on; } void HUlib_initIText ( hu_itext_t* it, int x, int y, patch_t** font, int startchar, boolean* on ) { it->lm = 0; // default left margin is start of text it->on = on; it->laston = true; HUlib_initTextLine(&it->l, x, y, font, startchar); } // The following deletion routines adhere to the left margin restriction void HUlib_delCharFromIText(hu_itext_t* it) { if (it->l.len != it->lm) HUlib_delCharFromTextLine(&it->l); } void HUlib_eraseLineFromIText(hu_itext_t* it) { while (it->lm != it->l.len) HUlib_delCharFromTextLine(&it->l); } // Resets left margin as well void HUlib_resetIText(hu_itext_t* it) { it->lm = 0; HUlib_clearTextLine(&it->l); } void HUlib_addPrefixToIText ( hu_itext_t* it, char* str ) { while (*str) HUlib_addCharToTextLine(&it->l, *(str++)); it->lm = it->l.len; } // wrapper function for handling general keyed input. // returns true if it ate the key boolean HUlib_keyInIText ( hu_itext_t* it, unsigned char ch ) { ch = toupper(ch); if (ch >= ' ' && ch <= '_') HUlib_addCharToTextLine(&it->l, (char) ch); else if (ch == KEY_BACKSPACE) HUlib_delCharFromIText(it); else if (ch != KEY_ENTER) return false; // did not eat key return true; // ate the key } void HUlib_drawIText(hu_itext_t* it) { hu_textline_t *l = &it->l; if (!*it->on) return; HUlib_drawTextLine(l, true); // draw the line w/ cursor } void HUlib_eraseIText(hu_itext_t* it) { if (it->laston && !*it->on) it->l.needsupdate = 4; HUlib_eraseTextLine(&it->l); it->laston = *it->on; } chocolate-doom-chocolate-doom-2.2.1/src/doom/hu_lib.h000066400000000000000000000070561257432200600224550ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // #ifndef __HULIB__ #define __HULIB__ // We are referring to patches. #include "r_defs.h" // font stuff #define HU_CHARERASE KEY_BACKSPACE #define HU_MAXLINES 4 #define HU_MAXLINELENGTH 80 // // Typedefs of widgets // // Text Line widget // (parent of Scrolling Text and Input Text widgets) typedef struct { // left-justified position of scrolling text window int x; int y; patch_t** f; // font int sc; // start character char l[HU_MAXLINELENGTH+1]; // line of text int len; // current line length // whether this line needs to be udpated int needsupdate; } hu_textline_t; // Scrolling Text window widget // (child of Text Line widget) typedef struct { hu_textline_t l[HU_MAXLINES]; // text lines to draw int h; // height in lines int cl; // current line number // pointer to boolean stating whether to update window boolean* on; boolean laston; // last value of *->on. } hu_stext_t; // Input Text Line widget // (child of Text Line widget) typedef struct { hu_textline_t l; // text line to input on // left margin past which I am not to delete characters int lm; // pointer to boolean stating whether to update window boolean* on; boolean laston; // last value of *->on; } hu_itext_t; // // Widget creation, access, and update routines // // initializes heads-up widget library void HUlib_init(void); // // textline code // // clear a line of text void HUlib_clearTextLine(hu_textline_t *t); void HUlib_initTextLine(hu_textline_t *t, int x, int y, patch_t **f, int sc); // returns success boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch); // returns success boolean HUlib_delCharFromTextLine(hu_textline_t *t); // draws tline void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor); // erases text line void HUlib_eraseTextLine(hu_textline_t *l); // // Scrolling Text window widget routines // // ? void HUlib_initSText ( hu_stext_t* s, int x, int y, int h, patch_t** font, int startchar, boolean* on ); // add a new line void HUlib_addLineToSText(hu_stext_t* s); // ? void HUlib_addMessageToSText ( hu_stext_t* s, char* prefix, char* msg ); // draws stext void HUlib_drawSText(hu_stext_t* s); // erases all stext lines void HUlib_eraseSText(hu_stext_t* s); // Input Text Line widget routines void HUlib_initIText ( hu_itext_t* it, int x, int y, patch_t** font, int startchar, boolean* on ); // enforces left margin void HUlib_delCharFromIText(hu_itext_t* it); // enforces left margin void HUlib_eraseLineFromIText(hu_itext_t* it); // resets line and left margin void HUlib_resetIText(hu_itext_t* it); // left of left-margin void HUlib_addPrefixToIText ( hu_itext_t* it, char* str ); // whether eaten boolean HUlib_keyInIText ( hu_itext_t* it, unsigned char ch ); void HUlib_drawIText(hu_itext_t* it); // erases all itext lines void HUlib_eraseIText(hu_itext_t* it); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/hu_stuff.c000066400000000000000000000277121257432200600230320ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Heads-up displays // #include #include "doomdef.h" #include "doomkeys.h" #include "z_zone.h" #include "deh_main.h" #include "i_swap.h" #include "i_video.h" #include "hu_stuff.h" #include "hu_lib.h" #include "m_controls.h" #include "m_misc.h" #include "w_wad.h" #include "s_sound.h" #include "doomstat.h" // Data. #include "dstrings.h" #include "sounds.h" // // Locally used constants, shortcuts. // #define HU_TITLE (mapnames[(gameepisode-1)*9+gamemap-1]) #define HU_TITLE2 (mapnames_commercial[gamemap-1]) #define HU_TITLEP (mapnames_commercial[gamemap-1 + 32]) #define HU_TITLET (mapnames_commercial[gamemap-1 + 64]) #define HU_TITLE_CHEX (mapnames[gamemap - 1]) #define HU_TITLEHEIGHT 1 #define HU_TITLEX 0 #define HU_TITLEY (167 - SHORT(hu_font[0]->height)) #define HU_INPUTTOGGLE 't' #define HU_INPUTX HU_MSGX #define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0]->height) +1)) #define HU_INPUTWIDTH 64 #define HU_INPUTHEIGHT 1 char *chat_macros[10] = { HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, HUSTR_CHATMACRO2, HUSTR_CHATMACRO3, HUSTR_CHATMACRO4, HUSTR_CHATMACRO5, HUSTR_CHATMACRO6, HUSTR_CHATMACRO7, HUSTR_CHATMACRO8, HUSTR_CHATMACRO9 }; char* player_names[] = { HUSTR_PLRGREEN, HUSTR_PLRINDIGO, HUSTR_PLRBROWN, HUSTR_PLRRED }; char chat_char; // remove later. static player_t* plr; patch_t* hu_font[HU_FONTSIZE]; static hu_textline_t w_title; boolean chat_on; static hu_itext_t w_chat; static boolean always_off = false; static char chat_dest[MAXPLAYERS]; static hu_itext_t w_inputbuffer[MAXPLAYERS]; static boolean message_on; boolean message_dontfuckwithme; static boolean message_nottobefuckedwith; static hu_stext_t w_message; static int message_counter; extern int showMessages; static boolean headsupactive = false; // // Builtin map names. // The actual names can be found in DStrings.h. // char* mapnames[] = // DOOM shareware/registered/retail (Ultimate) names. { HUSTR_E1M1, HUSTR_E1M2, HUSTR_E1M3, HUSTR_E1M4, HUSTR_E1M5, HUSTR_E1M6, HUSTR_E1M7, HUSTR_E1M8, HUSTR_E1M9, HUSTR_E2M1, HUSTR_E2M2, HUSTR_E2M3, HUSTR_E2M4, HUSTR_E2M5, HUSTR_E2M6, HUSTR_E2M7, HUSTR_E2M8, HUSTR_E2M9, HUSTR_E3M1, HUSTR_E3M2, HUSTR_E3M3, HUSTR_E3M4, HUSTR_E3M5, HUSTR_E3M6, HUSTR_E3M7, HUSTR_E3M8, HUSTR_E3M9, HUSTR_E4M1, HUSTR_E4M2, HUSTR_E4M3, HUSTR_E4M4, HUSTR_E4M5, HUSTR_E4M6, HUSTR_E4M7, HUSTR_E4M8, HUSTR_E4M9, "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL" }; // List of names for levels in commercial IWADs // (doom2.wad, plutonia.wad, tnt.wad). These are stored in a // single large array; WADs like pl2.wad have a MAP33, and rely on // the layout in the Vanilla executable, where it is possible to // overflow the end of one array into the next. char *mapnames_commercial[] = { // DOOM 2 map names. HUSTR_1, HUSTR_2, HUSTR_3, HUSTR_4, HUSTR_5, HUSTR_6, HUSTR_7, HUSTR_8, HUSTR_9, HUSTR_10, HUSTR_11, HUSTR_12, HUSTR_13, HUSTR_14, HUSTR_15, HUSTR_16, HUSTR_17, HUSTR_18, HUSTR_19, HUSTR_20, HUSTR_21, HUSTR_22, HUSTR_23, HUSTR_24, HUSTR_25, HUSTR_26, HUSTR_27, HUSTR_28, HUSTR_29, HUSTR_30, HUSTR_31, HUSTR_32, // Plutonia WAD map names. PHUSTR_1, PHUSTR_2, PHUSTR_3, PHUSTR_4, PHUSTR_5, PHUSTR_6, PHUSTR_7, PHUSTR_8, PHUSTR_9, PHUSTR_10, PHUSTR_11, PHUSTR_12, PHUSTR_13, PHUSTR_14, PHUSTR_15, PHUSTR_16, PHUSTR_17, PHUSTR_18, PHUSTR_19, PHUSTR_20, PHUSTR_21, PHUSTR_22, PHUSTR_23, PHUSTR_24, PHUSTR_25, PHUSTR_26, PHUSTR_27, PHUSTR_28, PHUSTR_29, PHUSTR_30, PHUSTR_31, PHUSTR_32, // TNT WAD map names. THUSTR_1, THUSTR_2, THUSTR_3, THUSTR_4, THUSTR_5, THUSTR_6, THUSTR_7, THUSTR_8, THUSTR_9, THUSTR_10, THUSTR_11, THUSTR_12, THUSTR_13, THUSTR_14, THUSTR_15, THUSTR_16, THUSTR_17, THUSTR_18, THUSTR_19, THUSTR_20, THUSTR_21, THUSTR_22, THUSTR_23, THUSTR_24, THUSTR_25, THUSTR_26, THUSTR_27, THUSTR_28, THUSTR_29, THUSTR_30, THUSTR_31, THUSTR_32 }; void HU_Init(void) { int i; int j; char buffer[9]; // load the heads-up font j = HU_FONTSTART; for (i=0;imessage && !message_nottobefuckedwith) || (plr->message && message_dontfuckwithme)) { HUlib_addMessageToSText(&w_message, 0, plr->message); plr->message = 0; message_on = true; message_counter = HU_MSGTIMEOUT; message_nottobefuckedwith = message_dontfuckwithme; message_dontfuckwithme = 0; } } // else message_on = false; // check for incoming chat characters if (netgame) { for (i=0 ; imessage = DEH_String(HUSTR_MSGU); } else { chatchars[head] = c; head = (head + 1) & (QUEUESIZE-1); } } char HU_dequeueChatChar(void) { char c; if (head != tail) { c = chatchars[tail]; tail = (tail + 1) & (QUEUESIZE-1); } else { c = 0; } return c; } boolean HU_Responder(event_t *ev) { static char lastmessage[HU_MAXLINELENGTH+1]; char* macromessage; boolean eatkey = false; static boolean altdown = false; unsigned char c; int i; int numplayers; static int num_nobrainers = 0; numplayers = 0; for (i=0 ; idata1 == KEY_RSHIFT) { return false; } else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT) { altdown = ev->type == ev_keydown; return false; } if (ev->type != ev_keydown) return false; if (!chat_on) { if (ev->data1 == key_message_refresh) { message_on = true; message_counter = HU_MSGTIMEOUT; eatkey = true; } else if (netgame && ev->data2 == key_multi_msg) { eatkey = chat_on = true; HUlib_resetIText(&w_chat); HU_queueChatChar(HU_BROADCAST); } else if (netgame && numplayers > 2) { for (i=0; idata2 == key_multi_msgplayer[i]) { if (playeringame[i] && i!=consoleplayer) { eatkey = chat_on = true; HUlib_resetIText(&w_chat); HU_queueChatChar(i+1); break; } else if (i == consoleplayer) { num_nobrainers++; if (num_nobrainers < 3) plr->message = DEH_String(HUSTR_TALKTOSELF1); else if (num_nobrainers < 6) plr->message = DEH_String(HUSTR_TALKTOSELF2); else if (num_nobrainers < 9) plr->message = DEH_String(HUSTR_TALKTOSELF3); else if (num_nobrainers < 32) plr->message = DEH_String(HUSTR_TALKTOSELF4); else plr->message = DEH_String(HUSTR_TALKTOSELF5); } } } } } else { // send a macro if (altdown) { c = ev->data1 - '0'; if (c > 9) return false; // fprintf(stderr, "got here\n"); macromessage = chat_macros[c]; // kill last message with a '\n' HU_queueChatChar(KEY_ENTER); // DEBUG!!! // send the macro message while (*macromessage) HU_queueChatChar(*macromessage++); HU_queueChatChar(KEY_ENTER); // leave chat mode and notify that it was sent chat_on = false; M_StringCopy(lastmessage, chat_macros[c], sizeof(lastmessage)); plr->message = lastmessage; eatkey = true; } else { c = ev->data2; eatkey = HUlib_keyInIText(&w_chat, c); if (eatkey) { // static unsigned char buf[20]; // DEBUG HU_queueChatChar(c); // M_snprintf(buf, sizeof(buf), "KEY: %d => %d", ev->data1, c); // plr->message = buf; } if (c == KEY_ENTER) { chat_on = false; if (w_chat.l.len) { M_StringCopy(lastmessage, w_chat.l.l, sizeof(lastmessage)); plr->message = lastmessage; } } else if (c == KEY_ESCAPE) chat_on = false; } } return eatkey; } chocolate-doom-chocolate-doom-2.2.1/src/doom/hu_stuff.h000066400000000000000000000024761257432200600230370ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Head up display // #ifndef __HU_STUFF_H__ #define __HU_STUFF_H__ #include "d_event.h" // // Globally visible constants. // #define HU_FONTSTART '!' // the first font characters #define HU_FONTEND '_' // the last font characters // Calculate # of glyphs in font. #define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) #define HU_BROADCAST 5 #define HU_MSGX 0 #define HU_MSGY 0 #define HU_MSGWIDTH 64 // in characters #define HU_MSGHEIGHT 1 // in lines #define HU_MSGTIMEOUT (4*TICRATE) // // HEADS UP TEXT // void HU_Init(void); void HU_Start(void); boolean HU_Responder(event_t* ev); void HU_Ticker(void); void HU_Drawer(void); char HU_dequeueChatChar(void); void HU_Erase(void); extern char *chat_macros[10]; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/info.c000066400000000000000000004204341257432200600221400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Thing frame/state LUT, // generated by multigen utilitiy. // This one is the original DOOM version, preserved. // #include #include // Data. #include "sounds.h" #include "m_fixed.h" #include "info.h" #include "p_mobj.h" char *sprnames[] = { "TROO","SHTG","PUNG","PISG","PISF","SHTF","SHT2","CHGG","CHGF","MISG", "MISF","SAWG","PLSG","PLSF","BFGG","BFGF","BLUD","PUFF","BAL1","BAL2", "PLSS","PLSE","MISL","BFS1","BFE1","BFE2","TFOG","IFOG","PLAY","POSS", "SPOS","VILE","FIRE","FATB","FBXP","SKEL","MANF","FATT","CPOS","SARG", "HEAD","BAL7","BOSS","BOS2","SKUL","SPID","BSPI","APLS","APBX","CYBR", "PAIN","SSWV","KEEN","BBRN","BOSF","ARM1","ARM2","BAR1","BEXP","FCAN", "BON1","BON2","BKEY","RKEY","YKEY","BSKU","RSKU","YSKU","STIM","MEDI", "SOUL","PINV","PSTR","PINS","MEGA","SUIT","PMAP","PVIS","CLIP","AMMO", "ROCK","BROK","CELL","CELP","SHEL","SBOX","BPAK","BFUG","MGUN","CSAW", "LAUN","PLAS","SHOT","SGN2","COLU","SMT2","GOR1","POL2","POL5","POL4", "POL3","POL1","POL6","GOR2","GOR3","GOR4","GOR5","SMIT","COL1","COL2", "COL3","COL4","CAND","CBRA","COL6","TRE1","TRE2","ELEC","CEYE","FSKU", "COL5","TBLU","TGRN","TRED","SMBT","SMGT","SMRT","HDB1","HDB2","HDB3", "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2", NULL }; // Doesn't work with g++, needs actionf_p1 void A_Light0(); void A_WeaponReady(); void A_Lower(); void A_Raise(); void A_Punch(); void A_ReFire(); void A_FirePistol(); void A_Light1(); void A_FireShotgun(); void A_Light2(); void A_FireShotgun2(); void A_CheckReload(); void A_OpenShotgun2(); void A_LoadShotgun2(); void A_CloseShotgun2(); void A_FireCGun(); void A_GunFlash(); void A_FireMissile(); void A_Saw(); void A_FirePlasma(); void A_BFGsound(); void A_FireBFG(); void A_BFGSpray(); void A_Explode(); void A_Pain(); void A_PlayerScream(); void A_Fall(); void A_XScream(); void A_Look(); void A_Chase(); void A_FaceTarget(); void A_PosAttack(); void A_Scream(); void A_SPosAttack(); void A_VileChase(); void A_VileStart(); void A_VileTarget(); void A_VileAttack(); void A_StartFire(); void A_Fire(); void A_FireCrackle(); void A_Tracer(); void A_SkelWhoosh(); void A_SkelFist(); void A_SkelMissile(); void A_FatRaise(); void A_FatAttack1(); void A_FatAttack2(); void A_FatAttack3(); void A_BossDeath(); void A_CPosAttack(); void A_CPosRefire(); void A_TroopAttack(); void A_SargAttack(); void A_HeadAttack(); void A_BruisAttack(); void A_SkullAttack(); void A_Metal(); void A_SpidRefire(); void A_BabyMetal(); void A_BspiAttack(); void A_Hoof(); void A_CyberAttack(); void A_PainAttack(); void A_PainDie(); void A_KeenDie(); void A_BrainPain(); void A_BrainScream(); void A_BrainDie(); void A_BrainAwake(); void A_BrainSpit(); void A_SpawnSound(); void A_SpawnFly(); void A_BrainExplode(); state_t states[NUMSTATES] = { {SPR_TROO,0,-1,{NULL},S_NULL,0,0}, // S_NULL {SPR_SHTG,4,0,{A_Light0},S_NULL,0,0}, // S_LIGHTDONE {SPR_PUNG,0,1,{A_WeaponReady},S_PUNCH,0,0}, // S_PUNCH {SPR_PUNG,0,1,{A_Lower},S_PUNCHDOWN,0,0}, // S_PUNCHDOWN {SPR_PUNG,0,1,{A_Raise},S_PUNCHUP,0,0}, // S_PUNCHUP {SPR_PUNG,1,4,{NULL},S_PUNCH2,0,0}, // S_PUNCH1 {SPR_PUNG,2,4,{A_Punch},S_PUNCH3,0,0}, // S_PUNCH2 {SPR_PUNG,3,5,{NULL},S_PUNCH4,0,0}, // S_PUNCH3 {SPR_PUNG,2,4,{NULL},S_PUNCH5,0,0}, // S_PUNCH4 {SPR_PUNG,1,5,{A_ReFire},S_PUNCH,0,0}, // S_PUNCH5 {SPR_PISG,0,1,{A_WeaponReady},S_PISTOL,0,0},// S_PISTOL {SPR_PISG,0,1,{A_Lower},S_PISTOLDOWN,0,0}, // S_PISTOLDOWN {SPR_PISG,0,1,{A_Raise},S_PISTOLUP,0,0}, // S_PISTOLUP {SPR_PISG,0,4,{NULL},S_PISTOL2,0,0}, // S_PISTOL1 {SPR_PISG,1,6,{A_FirePistol},S_PISTOL3,0,0},// S_PISTOL2 {SPR_PISG,2,4,{NULL},S_PISTOL4,0,0}, // S_PISTOL3 {SPR_PISG,1,5,{A_ReFire},S_PISTOL,0,0}, // S_PISTOL4 {SPR_PISF,32768,7,{A_Light1},S_LIGHTDONE,0,0}, // S_PISTOLFLASH {SPR_SHTG,0,1,{A_WeaponReady},S_SGUN,0,0}, // S_SGUN {SPR_SHTG,0,1,{A_Lower},S_SGUNDOWN,0,0}, // S_SGUNDOWN {SPR_SHTG,0,1,{A_Raise},S_SGUNUP,0,0}, // S_SGUNUP {SPR_SHTG,0,3,{NULL},S_SGUN2,0,0}, // S_SGUN1 {SPR_SHTG,0,7,{A_FireShotgun},S_SGUN3,0,0}, // S_SGUN2 {SPR_SHTG,1,5,{NULL},S_SGUN4,0,0}, // S_SGUN3 {SPR_SHTG,2,5,{NULL},S_SGUN5,0,0}, // S_SGUN4 {SPR_SHTG,3,4,{NULL},S_SGUN6,0,0}, // S_SGUN5 {SPR_SHTG,2,5,{NULL},S_SGUN7,0,0}, // S_SGUN6 {SPR_SHTG,1,5,{NULL},S_SGUN8,0,0}, // S_SGUN7 {SPR_SHTG,0,3,{NULL},S_SGUN9,0,0}, // S_SGUN8 {SPR_SHTG,0,7,{A_ReFire},S_SGUN,0,0}, // S_SGUN9 {SPR_SHTF,32768,4,{A_Light1},S_SGUNFLASH2,0,0}, // S_SGUNFLASH1 {SPR_SHTF,32769,3,{A_Light2},S_LIGHTDONE,0,0}, // S_SGUNFLASH2 {SPR_SHT2,0,1,{A_WeaponReady},S_DSGUN,0,0}, // S_DSGUN {SPR_SHT2,0,1,{A_Lower},S_DSGUNDOWN,0,0}, // S_DSGUNDOWN {SPR_SHT2,0,1,{A_Raise},S_DSGUNUP,0,0}, // S_DSGUNUP {SPR_SHT2,0,3,{NULL},S_DSGUN2,0,0}, // S_DSGUN1 {SPR_SHT2,0,7,{A_FireShotgun2},S_DSGUN3,0,0}, // S_DSGUN2 {SPR_SHT2,1,7,{NULL},S_DSGUN4,0,0}, // S_DSGUN3 {SPR_SHT2,2,7,{A_CheckReload},S_DSGUN5,0,0}, // S_DSGUN4 {SPR_SHT2,3,7,{A_OpenShotgun2},S_DSGUN6,0,0}, // S_DSGUN5 {SPR_SHT2,4,7,{NULL},S_DSGUN7,0,0}, // S_DSGUN6 {SPR_SHT2,5,7,{A_LoadShotgun2},S_DSGUN8,0,0}, // S_DSGUN7 {SPR_SHT2,6,6,{NULL},S_DSGUN9,0,0}, // S_DSGUN8 {SPR_SHT2,7,6,{A_CloseShotgun2},S_DSGUN10,0,0}, // S_DSGUN9 {SPR_SHT2,0,5,{A_ReFire},S_DSGUN,0,0}, // S_DSGUN10 {SPR_SHT2,1,7,{NULL},S_DSNR2,0,0}, // S_DSNR1 {SPR_SHT2,0,3,{NULL},S_DSGUNDOWN,0,0}, // S_DSNR2 {SPR_SHT2,32776,5,{A_Light1},S_DSGUNFLASH2,0,0}, // S_DSGUNFLASH1 {SPR_SHT2,32777,4,{A_Light2},S_LIGHTDONE,0,0}, // S_DSGUNFLASH2 {SPR_CHGG,0,1,{A_WeaponReady},S_CHAIN,0,0}, // S_CHAIN {SPR_CHGG,0,1,{A_Lower},S_CHAINDOWN,0,0}, // S_CHAINDOWN {SPR_CHGG,0,1,{A_Raise},S_CHAINUP,0,0}, // S_CHAINUP {SPR_CHGG,0,4,{A_FireCGun},S_CHAIN2,0,0}, // S_CHAIN1 {SPR_CHGG,1,4,{A_FireCGun},S_CHAIN3,0,0}, // S_CHAIN2 {SPR_CHGG,1,0,{A_ReFire},S_CHAIN,0,0}, // S_CHAIN3 {SPR_CHGF,32768,5,{A_Light1},S_LIGHTDONE,0,0}, // S_CHAINFLASH1 {SPR_CHGF,32769,5,{A_Light2},S_LIGHTDONE,0,0}, // S_CHAINFLASH2 {SPR_MISG,0,1,{A_WeaponReady},S_MISSILE,0,0}, // S_MISSILE {SPR_MISG,0,1,{A_Lower},S_MISSILEDOWN,0,0}, // S_MISSILEDOWN {SPR_MISG,0,1,{A_Raise},S_MISSILEUP,0,0}, // S_MISSILEUP {SPR_MISG,1,8,{A_GunFlash},S_MISSILE2,0,0}, // S_MISSILE1 {SPR_MISG,1,12,{A_FireMissile},S_MISSILE3,0,0}, // S_MISSILE2 {SPR_MISG,1,0,{A_ReFire},S_MISSILE,0,0}, // S_MISSILE3 {SPR_MISF,32768,3,{A_Light1},S_MISSILEFLASH2,0,0}, // S_MISSILEFLASH1 {SPR_MISF,32769,4,{NULL},S_MISSILEFLASH3,0,0}, // S_MISSILEFLASH2 {SPR_MISF,32770,4,{A_Light2},S_MISSILEFLASH4,0,0}, // S_MISSILEFLASH3 {SPR_MISF,32771,4,{A_Light2},S_LIGHTDONE,0,0}, // S_MISSILEFLASH4 {SPR_SAWG,2,4,{A_WeaponReady},S_SAWB,0,0}, // S_SAW {SPR_SAWG,3,4,{A_WeaponReady},S_SAW,0,0}, // S_SAWB {SPR_SAWG,2,1,{A_Lower},S_SAWDOWN,0,0}, // S_SAWDOWN {SPR_SAWG,2,1,{A_Raise},S_SAWUP,0,0}, // S_SAWUP {SPR_SAWG,0,4,{A_Saw},S_SAW2,0,0}, // S_SAW1 {SPR_SAWG,1,4,{A_Saw},S_SAW3,0,0}, // S_SAW2 {SPR_SAWG,1,0,{A_ReFire},S_SAW,0,0}, // S_SAW3 {SPR_PLSG,0,1,{A_WeaponReady},S_PLASMA,0,0}, // S_PLASMA {SPR_PLSG,0,1,{A_Lower},S_PLASMADOWN,0,0}, // S_PLASMADOWN {SPR_PLSG,0,1,{A_Raise},S_PLASMAUP,0,0}, // S_PLASMAUP {SPR_PLSG,0,3,{A_FirePlasma},S_PLASMA2,0,0}, // S_PLASMA1 {SPR_PLSG,1,20,{A_ReFire},S_PLASMA,0,0}, // S_PLASMA2 {SPR_PLSF,32768,4,{A_Light1},S_LIGHTDONE,0,0}, // S_PLASMAFLASH1 {SPR_PLSF,32769,4,{A_Light1},S_LIGHTDONE,0,0}, // S_PLASMAFLASH2 {SPR_BFGG,0,1,{A_WeaponReady},S_BFG,0,0}, // S_BFG {SPR_BFGG,0,1,{A_Lower},S_BFGDOWN,0,0}, // S_BFGDOWN {SPR_BFGG,0,1,{A_Raise},S_BFGUP,0,0}, // S_BFGUP {SPR_BFGG,0,20,{A_BFGsound},S_BFG2,0,0}, // S_BFG1 {SPR_BFGG,1,10,{A_GunFlash},S_BFG3,0,0}, // S_BFG2 {SPR_BFGG,1,10,{A_FireBFG},S_BFG4,0,0}, // S_BFG3 {SPR_BFGG,1,20,{A_ReFire},S_BFG,0,0}, // S_BFG4 {SPR_BFGF,32768,11,{A_Light1},S_BFGFLASH2,0,0}, // S_BFGFLASH1 {SPR_BFGF,32769,6,{A_Light2},S_LIGHTDONE,0,0}, // S_BFGFLASH2 {SPR_BLUD,2,8,{NULL},S_BLOOD2,0,0}, // S_BLOOD1 {SPR_BLUD,1,8,{NULL},S_BLOOD3,0,0}, // S_BLOOD2 {SPR_BLUD,0,8,{NULL},S_NULL,0,0}, // S_BLOOD3 {SPR_PUFF,32768,4,{NULL},S_PUFF2,0,0}, // S_PUFF1 {SPR_PUFF,1,4,{NULL},S_PUFF3,0,0}, // S_PUFF2 {SPR_PUFF,2,4,{NULL},S_PUFF4,0,0}, // S_PUFF3 {SPR_PUFF,3,4,{NULL},S_NULL,0,0}, // S_PUFF4 {SPR_BAL1,32768,4,{NULL},S_TBALL2,0,0}, // S_TBALL1 {SPR_BAL1,32769,4,{NULL},S_TBALL1,0,0}, // S_TBALL2 {SPR_BAL1,32770,6,{NULL},S_TBALLX2,0,0}, // S_TBALLX1 {SPR_BAL1,32771,6,{NULL},S_TBALLX3,0,0}, // S_TBALLX2 {SPR_BAL1,32772,6,{NULL},S_NULL,0,0}, // S_TBALLX3 {SPR_BAL2,32768,4,{NULL},S_RBALL2,0,0}, // S_RBALL1 {SPR_BAL2,32769,4,{NULL},S_RBALL1,0,0}, // S_RBALL2 {SPR_BAL2,32770,6,{NULL},S_RBALLX2,0,0}, // S_RBALLX1 {SPR_BAL2,32771,6,{NULL},S_RBALLX3,0,0}, // S_RBALLX2 {SPR_BAL2,32772,6,{NULL},S_NULL,0,0}, // S_RBALLX3 {SPR_PLSS,32768,6,{NULL},S_PLASBALL2,0,0}, // S_PLASBALL {SPR_PLSS,32769,6,{NULL},S_PLASBALL,0,0}, // S_PLASBALL2 {SPR_PLSE,32768,4,{NULL},S_PLASEXP2,0,0}, // S_PLASEXP {SPR_PLSE,32769,4,{NULL},S_PLASEXP3,0,0}, // S_PLASEXP2 {SPR_PLSE,32770,4,{NULL},S_PLASEXP4,0,0}, // S_PLASEXP3 {SPR_PLSE,32771,4,{NULL},S_PLASEXP5,0,0}, // S_PLASEXP4 {SPR_PLSE,32772,4,{NULL},S_NULL,0,0}, // S_PLASEXP5 {SPR_MISL,32768,1,{NULL},S_ROCKET,0,0}, // S_ROCKET {SPR_BFS1,32768,4,{NULL},S_BFGSHOT2,0,0}, // S_BFGSHOT {SPR_BFS1,32769,4,{NULL},S_BFGSHOT,0,0}, // S_BFGSHOT2 {SPR_BFE1,32768,8,{NULL},S_BFGLAND2,0,0}, // S_BFGLAND {SPR_BFE1,32769,8,{NULL},S_BFGLAND3,0,0}, // S_BFGLAND2 {SPR_BFE1,32770,8,{A_BFGSpray},S_BFGLAND4,0,0}, // S_BFGLAND3 {SPR_BFE1,32771,8,{NULL},S_BFGLAND5,0,0}, // S_BFGLAND4 {SPR_BFE1,32772,8,{NULL},S_BFGLAND6,0,0}, // S_BFGLAND5 {SPR_BFE1,32773,8,{NULL},S_NULL,0,0}, // S_BFGLAND6 {SPR_BFE2,32768,8,{NULL},S_BFGEXP2,0,0}, // S_BFGEXP {SPR_BFE2,32769,8,{NULL},S_BFGEXP3,0,0}, // S_BFGEXP2 {SPR_BFE2,32770,8,{NULL},S_BFGEXP4,0,0}, // S_BFGEXP3 {SPR_BFE2,32771,8,{NULL},S_NULL,0,0}, // S_BFGEXP4 {SPR_MISL,32769,8,{A_Explode},S_EXPLODE2,0,0}, // S_EXPLODE1 {SPR_MISL,32770,6,{NULL},S_EXPLODE3,0,0}, // S_EXPLODE2 {SPR_MISL,32771,4,{NULL},S_NULL,0,0}, // S_EXPLODE3 {SPR_TFOG,32768,6,{NULL},S_TFOG01,0,0}, // S_TFOG {SPR_TFOG,32769,6,{NULL},S_TFOG02,0,0}, // S_TFOG01 {SPR_TFOG,32768,6,{NULL},S_TFOG2,0,0}, // S_TFOG02 {SPR_TFOG,32769,6,{NULL},S_TFOG3,0,0}, // S_TFOG2 {SPR_TFOG,32770,6,{NULL},S_TFOG4,0,0}, // S_TFOG3 {SPR_TFOG,32771,6,{NULL},S_TFOG5,0,0}, // S_TFOG4 {SPR_TFOG,32772,6,{NULL},S_TFOG6,0,0}, // S_TFOG5 {SPR_TFOG,32773,6,{NULL},S_TFOG7,0,0}, // S_TFOG6 {SPR_TFOG,32774,6,{NULL},S_TFOG8,0,0}, // S_TFOG7 {SPR_TFOG,32775,6,{NULL},S_TFOG9,0,0}, // S_TFOG8 {SPR_TFOG,32776,6,{NULL},S_TFOG10,0,0}, // S_TFOG9 {SPR_TFOG,32777,6,{NULL},S_NULL,0,0}, // S_TFOG10 {SPR_IFOG,32768,6,{NULL},S_IFOG01,0,0}, // S_IFOG {SPR_IFOG,32769,6,{NULL},S_IFOG02,0,0}, // S_IFOG01 {SPR_IFOG,32768,6,{NULL},S_IFOG2,0,0}, // S_IFOG02 {SPR_IFOG,32769,6,{NULL},S_IFOG3,0,0}, // S_IFOG2 {SPR_IFOG,32770,6,{NULL},S_IFOG4,0,0}, // S_IFOG3 {SPR_IFOG,32771,6,{NULL},S_IFOG5,0,0}, // S_IFOG4 {SPR_IFOG,32772,6,{NULL},S_NULL,0,0}, // S_IFOG5 {SPR_PLAY,0,-1,{NULL},S_NULL,0,0}, // S_PLAY {SPR_PLAY,0,4,{NULL},S_PLAY_RUN2,0,0}, // S_PLAY_RUN1 {SPR_PLAY,1,4,{NULL},S_PLAY_RUN3,0,0}, // S_PLAY_RUN2 {SPR_PLAY,2,4,{NULL},S_PLAY_RUN4,0,0}, // S_PLAY_RUN3 {SPR_PLAY,3,4,{NULL},S_PLAY_RUN1,0,0}, // S_PLAY_RUN4 {SPR_PLAY,4,12,{NULL},S_PLAY,0,0}, // S_PLAY_ATK1 {SPR_PLAY,32773,6,{NULL},S_PLAY_ATK1,0,0}, // S_PLAY_ATK2 {SPR_PLAY,6,4,{NULL},S_PLAY_PAIN2,0,0}, // S_PLAY_PAIN {SPR_PLAY,6,4,{A_Pain},S_PLAY,0,0}, // S_PLAY_PAIN2 {SPR_PLAY,7,10,{NULL},S_PLAY_DIE2,0,0}, // S_PLAY_DIE1 {SPR_PLAY,8,10,{A_PlayerScream},S_PLAY_DIE3,0,0}, // S_PLAY_DIE2 {SPR_PLAY,9,10,{A_Fall},S_PLAY_DIE4,0,0}, // S_PLAY_DIE3 {SPR_PLAY,10,10,{NULL},S_PLAY_DIE5,0,0}, // S_PLAY_DIE4 {SPR_PLAY,11,10,{NULL},S_PLAY_DIE6,0,0}, // S_PLAY_DIE5 {SPR_PLAY,12,10,{NULL},S_PLAY_DIE7,0,0}, // S_PLAY_DIE6 {SPR_PLAY,13,-1,{NULL},S_NULL,0,0}, // S_PLAY_DIE7 {SPR_PLAY,14,5,{NULL},S_PLAY_XDIE2,0,0}, // S_PLAY_XDIE1 {SPR_PLAY,15,5,{A_XScream},S_PLAY_XDIE3,0,0}, // S_PLAY_XDIE2 {SPR_PLAY,16,5,{A_Fall},S_PLAY_XDIE4,0,0}, // S_PLAY_XDIE3 {SPR_PLAY,17,5,{NULL},S_PLAY_XDIE5,0,0}, // S_PLAY_XDIE4 {SPR_PLAY,18,5,{NULL},S_PLAY_XDIE6,0,0}, // S_PLAY_XDIE5 {SPR_PLAY,19,5,{NULL},S_PLAY_XDIE7,0,0}, // S_PLAY_XDIE6 {SPR_PLAY,20,5,{NULL},S_PLAY_XDIE8,0,0}, // S_PLAY_XDIE7 {SPR_PLAY,21,5,{NULL},S_PLAY_XDIE9,0,0}, // S_PLAY_XDIE8 {SPR_PLAY,22,-1,{NULL},S_NULL,0,0}, // S_PLAY_XDIE9 {SPR_POSS,0,10,{A_Look},S_POSS_STND2,0,0}, // S_POSS_STND {SPR_POSS,1,10,{A_Look},S_POSS_STND,0,0}, // S_POSS_STND2 {SPR_POSS,0,4,{A_Chase},S_POSS_RUN2,0,0}, // S_POSS_RUN1 {SPR_POSS,0,4,{A_Chase},S_POSS_RUN3,0,0}, // S_POSS_RUN2 {SPR_POSS,1,4,{A_Chase},S_POSS_RUN4,0,0}, // S_POSS_RUN3 {SPR_POSS,1,4,{A_Chase},S_POSS_RUN5,0,0}, // S_POSS_RUN4 {SPR_POSS,2,4,{A_Chase},S_POSS_RUN6,0,0}, // S_POSS_RUN5 {SPR_POSS,2,4,{A_Chase},S_POSS_RUN7,0,0}, // S_POSS_RUN6 {SPR_POSS,3,4,{A_Chase},S_POSS_RUN8,0,0}, // S_POSS_RUN7 {SPR_POSS,3,4,{A_Chase},S_POSS_RUN1,0,0}, // S_POSS_RUN8 {SPR_POSS,4,10,{A_FaceTarget},S_POSS_ATK2,0,0}, // S_POSS_ATK1 {SPR_POSS,5,8,{A_PosAttack},S_POSS_ATK3,0,0}, // S_POSS_ATK2 {SPR_POSS,4,8,{NULL},S_POSS_RUN1,0,0}, // S_POSS_ATK3 {SPR_POSS,6,3,{NULL},S_POSS_PAIN2,0,0}, // S_POSS_PAIN {SPR_POSS,6,3,{A_Pain},S_POSS_RUN1,0,0}, // S_POSS_PAIN2 {SPR_POSS,7,5,{NULL},S_POSS_DIE2,0,0}, // S_POSS_DIE1 {SPR_POSS,8,5,{A_Scream},S_POSS_DIE3,0,0}, // S_POSS_DIE2 {SPR_POSS,9,5,{A_Fall},S_POSS_DIE4,0,0}, // S_POSS_DIE3 {SPR_POSS,10,5,{NULL},S_POSS_DIE5,0,0}, // S_POSS_DIE4 {SPR_POSS,11,-1,{NULL},S_NULL,0,0}, // S_POSS_DIE5 {SPR_POSS,12,5,{NULL},S_POSS_XDIE2,0,0}, // S_POSS_XDIE1 {SPR_POSS,13,5,{A_XScream},S_POSS_XDIE3,0,0}, // S_POSS_XDIE2 {SPR_POSS,14,5,{A_Fall},S_POSS_XDIE4,0,0}, // S_POSS_XDIE3 {SPR_POSS,15,5,{NULL},S_POSS_XDIE5,0,0}, // S_POSS_XDIE4 {SPR_POSS,16,5,{NULL},S_POSS_XDIE6,0,0}, // S_POSS_XDIE5 {SPR_POSS,17,5,{NULL},S_POSS_XDIE7,0,0}, // S_POSS_XDIE6 {SPR_POSS,18,5,{NULL},S_POSS_XDIE8,0,0}, // S_POSS_XDIE7 {SPR_POSS,19,5,{NULL},S_POSS_XDIE9,0,0}, // S_POSS_XDIE8 {SPR_POSS,20,-1,{NULL},S_NULL,0,0}, // S_POSS_XDIE9 {SPR_POSS,10,5,{NULL},S_POSS_RAISE2,0,0}, // S_POSS_RAISE1 {SPR_POSS,9,5,{NULL},S_POSS_RAISE3,0,0}, // S_POSS_RAISE2 {SPR_POSS,8,5,{NULL},S_POSS_RAISE4,0,0}, // S_POSS_RAISE3 {SPR_POSS,7,5,{NULL},S_POSS_RUN1,0,0}, // S_POSS_RAISE4 {SPR_SPOS,0,10,{A_Look},S_SPOS_STND2,0,0}, // S_SPOS_STND {SPR_SPOS,1,10,{A_Look},S_SPOS_STND,0,0}, // S_SPOS_STND2 {SPR_SPOS,0,3,{A_Chase},S_SPOS_RUN2,0,0}, // S_SPOS_RUN1 {SPR_SPOS,0,3,{A_Chase},S_SPOS_RUN3,0,0}, // S_SPOS_RUN2 {SPR_SPOS,1,3,{A_Chase},S_SPOS_RUN4,0,0}, // S_SPOS_RUN3 {SPR_SPOS,1,3,{A_Chase},S_SPOS_RUN5,0,0}, // S_SPOS_RUN4 {SPR_SPOS,2,3,{A_Chase},S_SPOS_RUN6,0,0}, // S_SPOS_RUN5 {SPR_SPOS,2,3,{A_Chase},S_SPOS_RUN7,0,0}, // S_SPOS_RUN6 {SPR_SPOS,3,3,{A_Chase},S_SPOS_RUN8,0,0}, // S_SPOS_RUN7 {SPR_SPOS,3,3,{A_Chase},S_SPOS_RUN1,0,0}, // S_SPOS_RUN8 {SPR_SPOS,4,10,{A_FaceTarget},S_SPOS_ATK2,0,0}, // S_SPOS_ATK1 {SPR_SPOS,32773,10,{A_SPosAttack},S_SPOS_ATK3,0,0}, // S_SPOS_ATK2 {SPR_SPOS,4,10,{NULL},S_SPOS_RUN1,0,0}, // S_SPOS_ATK3 {SPR_SPOS,6,3,{NULL},S_SPOS_PAIN2,0,0}, // S_SPOS_PAIN {SPR_SPOS,6,3,{A_Pain},S_SPOS_RUN1,0,0}, // S_SPOS_PAIN2 {SPR_SPOS,7,5,{NULL},S_SPOS_DIE2,0,0}, // S_SPOS_DIE1 {SPR_SPOS,8,5,{A_Scream},S_SPOS_DIE3,0,0}, // S_SPOS_DIE2 {SPR_SPOS,9,5,{A_Fall},S_SPOS_DIE4,0,0}, // S_SPOS_DIE3 {SPR_SPOS,10,5,{NULL},S_SPOS_DIE5,0,0}, // S_SPOS_DIE4 {SPR_SPOS,11,-1,{NULL},S_NULL,0,0}, // S_SPOS_DIE5 {SPR_SPOS,12,5,{NULL},S_SPOS_XDIE2,0,0}, // S_SPOS_XDIE1 {SPR_SPOS,13,5,{A_XScream},S_SPOS_XDIE3,0,0}, // S_SPOS_XDIE2 {SPR_SPOS,14,5,{A_Fall},S_SPOS_XDIE4,0,0}, // S_SPOS_XDIE3 {SPR_SPOS,15,5,{NULL},S_SPOS_XDIE5,0,0}, // S_SPOS_XDIE4 {SPR_SPOS,16,5,{NULL},S_SPOS_XDIE6,0,0}, // S_SPOS_XDIE5 {SPR_SPOS,17,5,{NULL},S_SPOS_XDIE7,0,0}, // S_SPOS_XDIE6 {SPR_SPOS,18,5,{NULL},S_SPOS_XDIE8,0,0}, // S_SPOS_XDIE7 {SPR_SPOS,19,5,{NULL},S_SPOS_XDIE9,0,0}, // S_SPOS_XDIE8 {SPR_SPOS,20,-1,{NULL},S_NULL,0,0}, // S_SPOS_XDIE9 {SPR_SPOS,11,5,{NULL},S_SPOS_RAISE2,0,0}, // S_SPOS_RAISE1 {SPR_SPOS,10,5,{NULL},S_SPOS_RAISE3,0,0}, // S_SPOS_RAISE2 {SPR_SPOS,9,5,{NULL},S_SPOS_RAISE4,0,0}, // S_SPOS_RAISE3 {SPR_SPOS,8,5,{NULL},S_SPOS_RAISE5,0,0}, // S_SPOS_RAISE4 {SPR_SPOS,7,5,{NULL},S_SPOS_RUN1,0,0}, // S_SPOS_RAISE5 {SPR_VILE,0,10,{A_Look},S_VILE_STND2,0,0}, // S_VILE_STND {SPR_VILE,1,10,{A_Look},S_VILE_STND,0,0}, // S_VILE_STND2 {SPR_VILE,0,2,{A_VileChase},S_VILE_RUN2,0,0}, // S_VILE_RUN1 {SPR_VILE,0,2,{A_VileChase},S_VILE_RUN3,0,0}, // S_VILE_RUN2 {SPR_VILE,1,2,{A_VileChase},S_VILE_RUN4,0,0}, // S_VILE_RUN3 {SPR_VILE,1,2,{A_VileChase},S_VILE_RUN5,0,0}, // S_VILE_RUN4 {SPR_VILE,2,2,{A_VileChase},S_VILE_RUN6,0,0}, // S_VILE_RUN5 {SPR_VILE,2,2,{A_VileChase},S_VILE_RUN7,0,0}, // S_VILE_RUN6 {SPR_VILE,3,2,{A_VileChase},S_VILE_RUN8,0,0}, // S_VILE_RUN7 {SPR_VILE,3,2,{A_VileChase},S_VILE_RUN9,0,0}, // S_VILE_RUN8 {SPR_VILE,4,2,{A_VileChase},S_VILE_RUN10,0,0}, // S_VILE_RUN9 {SPR_VILE,4,2,{A_VileChase},S_VILE_RUN11,0,0}, // S_VILE_RUN10 {SPR_VILE,5,2,{A_VileChase},S_VILE_RUN12,0,0}, // S_VILE_RUN11 {SPR_VILE,5,2,{A_VileChase},S_VILE_RUN1,0,0}, // S_VILE_RUN12 {SPR_VILE,32774,0,{A_VileStart},S_VILE_ATK2,0,0}, // S_VILE_ATK1 {SPR_VILE,32774,10,{A_FaceTarget},S_VILE_ATK3,0,0}, // S_VILE_ATK2 {SPR_VILE,32775,8,{A_VileTarget},S_VILE_ATK4,0,0}, // S_VILE_ATK3 {SPR_VILE,32776,8,{A_FaceTarget},S_VILE_ATK5,0,0}, // S_VILE_ATK4 {SPR_VILE,32777,8,{A_FaceTarget},S_VILE_ATK6,0,0}, // S_VILE_ATK5 {SPR_VILE,32778,8,{A_FaceTarget},S_VILE_ATK7,0,0}, // S_VILE_ATK6 {SPR_VILE,32779,8,{A_FaceTarget},S_VILE_ATK8,0,0}, // S_VILE_ATK7 {SPR_VILE,32780,8,{A_FaceTarget},S_VILE_ATK9,0,0}, // S_VILE_ATK8 {SPR_VILE,32781,8,{A_FaceTarget},S_VILE_ATK10,0,0}, // S_VILE_ATK9 {SPR_VILE,32782,8,{A_VileAttack},S_VILE_ATK11,0,0}, // S_VILE_ATK10 {SPR_VILE,32783,20,{NULL},S_VILE_RUN1,0,0}, // S_VILE_ATK11 {SPR_VILE,32794,10,{NULL},S_VILE_HEAL2,0,0}, // S_VILE_HEAL1 {SPR_VILE,32795,10,{NULL},S_VILE_HEAL3,0,0}, // S_VILE_HEAL2 {SPR_VILE,32796,10,{NULL},S_VILE_RUN1,0,0}, // S_VILE_HEAL3 {SPR_VILE,16,5,{NULL},S_VILE_PAIN2,0,0}, // S_VILE_PAIN {SPR_VILE,16,5,{A_Pain},S_VILE_RUN1,0,0}, // S_VILE_PAIN2 {SPR_VILE,16,7,{NULL},S_VILE_DIE2,0,0}, // S_VILE_DIE1 {SPR_VILE,17,7,{A_Scream},S_VILE_DIE3,0,0}, // S_VILE_DIE2 {SPR_VILE,18,7,{A_Fall},S_VILE_DIE4,0,0}, // S_VILE_DIE3 {SPR_VILE,19,7,{NULL},S_VILE_DIE5,0,0}, // S_VILE_DIE4 {SPR_VILE,20,7,{NULL},S_VILE_DIE6,0,0}, // S_VILE_DIE5 {SPR_VILE,21,7,{NULL},S_VILE_DIE7,0,0}, // S_VILE_DIE6 {SPR_VILE,22,7,{NULL},S_VILE_DIE8,0,0}, // S_VILE_DIE7 {SPR_VILE,23,5,{NULL},S_VILE_DIE9,0,0}, // S_VILE_DIE8 {SPR_VILE,24,5,{NULL},S_VILE_DIE10,0,0}, // S_VILE_DIE9 {SPR_VILE,25,-1,{NULL},S_NULL,0,0}, // S_VILE_DIE10 {SPR_FIRE,32768,2,{A_StartFire},S_FIRE2,0,0}, // S_FIRE1 {SPR_FIRE,32769,2,{A_Fire},S_FIRE3,0,0}, // S_FIRE2 {SPR_FIRE,32768,2,{A_Fire},S_FIRE4,0,0}, // S_FIRE3 {SPR_FIRE,32769,2,{A_Fire},S_FIRE5,0,0}, // S_FIRE4 {SPR_FIRE,32770,2,{A_FireCrackle},S_FIRE6,0,0}, // S_FIRE5 {SPR_FIRE,32769,2,{A_Fire},S_FIRE7,0,0}, // S_FIRE6 {SPR_FIRE,32770,2,{A_Fire},S_FIRE8,0,0}, // S_FIRE7 {SPR_FIRE,32769,2,{A_Fire},S_FIRE9,0,0}, // S_FIRE8 {SPR_FIRE,32770,2,{A_Fire},S_FIRE10,0,0}, // S_FIRE9 {SPR_FIRE,32771,2,{A_Fire},S_FIRE11,0,0}, // S_FIRE10 {SPR_FIRE,32770,2,{A_Fire},S_FIRE12,0,0}, // S_FIRE11 {SPR_FIRE,32771,2,{A_Fire},S_FIRE13,0,0}, // S_FIRE12 {SPR_FIRE,32770,2,{A_Fire},S_FIRE14,0,0}, // S_FIRE13 {SPR_FIRE,32771,2,{A_Fire},S_FIRE15,0,0}, // S_FIRE14 {SPR_FIRE,32772,2,{A_Fire},S_FIRE16,0,0}, // S_FIRE15 {SPR_FIRE,32771,2,{A_Fire},S_FIRE17,0,0}, // S_FIRE16 {SPR_FIRE,32772,2,{A_Fire},S_FIRE18,0,0}, // S_FIRE17 {SPR_FIRE,32771,2,{A_Fire},S_FIRE19,0,0}, // S_FIRE18 {SPR_FIRE,32772,2,{A_FireCrackle},S_FIRE20,0,0}, // S_FIRE19 {SPR_FIRE,32773,2,{A_Fire},S_FIRE21,0,0}, // S_FIRE20 {SPR_FIRE,32772,2,{A_Fire},S_FIRE22,0,0}, // S_FIRE21 {SPR_FIRE,32773,2,{A_Fire},S_FIRE23,0,0}, // S_FIRE22 {SPR_FIRE,32772,2,{A_Fire},S_FIRE24,0,0}, // S_FIRE23 {SPR_FIRE,32773,2,{A_Fire},S_FIRE25,0,0}, // S_FIRE24 {SPR_FIRE,32774,2,{A_Fire},S_FIRE26,0,0}, // S_FIRE25 {SPR_FIRE,32775,2,{A_Fire},S_FIRE27,0,0}, // S_FIRE26 {SPR_FIRE,32774,2,{A_Fire},S_FIRE28,0,0}, // S_FIRE27 {SPR_FIRE,32775,2,{A_Fire},S_FIRE29,0,0}, // S_FIRE28 {SPR_FIRE,32774,2,{A_Fire},S_FIRE30,0,0}, // S_FIRE29 {SPR_FIRE,32775,2,{A_Fire},S_NULL,0,0}, // S_FIRE30 {SPR_PUFF,1,4,{NULL},S_SMOKE2,0,0}, // S_SMOKE1 {SPR_PUFF,2,4,{NULL},S_SMOKE3,0,0}, // S_SMOKE2 {SPR_PUFF,1,4,{NULL},S_SMOKE4,0,0}, // S_SMOKE3 {SPR_PUFF,2,4,{NULL},S_SMOKE5,0,0}, // S_SMOKE4 {SPR_PUFF,3,4,{NULL},S_NULL,0,0}, // S_SMOKE5 {SPR_FATB,32768,2,{A_Tracer},S_TRACER2,0,0}, // S_TRACER {SPR_FATB,32769,2,{A_Tracer},S_TRACER,0,0}, // S_TRACER2 {SPR_FBXP,32768,8,{NULL},S_TRACEEXP2,0,0}, // S_TRACEEXP1 {SPR_FBXP,32769,6,{NULL},S_TRACEEXP3,0,0}, // S_TRACEEXP2 {SPR_FBXP,32770,4,{NULL},S_NULL,0,0}, // S_TRACEEXP3 {SPR_SKEL,0,10,{A_Look},S_SKEL_STND2,0,0}, // S_SKEL_STND {SPR_SKEL,1,10,{A_Look},S_SKEL_STND,0,0}, // S_SKEL_STND2 {SPR_SKEL,0,2,{A_Chase},S_SKEL_RUN2,0,0}, // S_SKEL_RUN1 {SPR_SKEL,0,2,{A_Chase},S_SKEL_RUN3,0,0}, // S_SKEL_RUN2 {SPR_SKEL,1,2,{A_Chase},S_SKEL_RUN4,0,0}, // S_SKEL_RUN3 {SPR_SKEL,1,2,{A_Chase},S_SKEL_RUN5,0,0}, // S_SKEL_RUN4 {SPR_SKEL,2,2,{A_Chase},S_SKEL_RUN6,0,0}, // S_SKEL_RUN5 {SPR_SKEL,2,2,{A_Chase},S_SKEL_RUN7,0,0}, // S_SKEL_RUN6 {SPR_SKEL,3,2,{A_Chase},S_SKEL_RUN8,0,0}, // S_SKEL_RUN7 {SPR_SKEL,3,2,{A_Chase},S_SKEL_RUN9,0,0}, // S_SKEL_RUN8 {SPR_SKEL,4,2,{A_Chase},S_SKEL_RUN10,0,0}, // S_SKEL_RUN9 {SPR_SKEL,4,2,{A_Chase},S_SKEL_RUN11,0,0}, // S_SKEL_RUN10 {SPR_SKEL,5,2,{A_Chase},S_SKEL_RUN12,0,0}, // S_SKEL_RUN11 {SPR_SKEL,5,2,{A_Chase},S_SKEL_RUN1,0,0}, // S_SKEL_RUN12 {SPR_SKEL,6,0,{A_FaceTarget},S_SKEL_FIST2,0,0}, // S_SKEL_FIST1 {SPR_SKEL,6,6,{A_SkelWhoosh},S_SKEL_FIST3,0,0}, // S_SKEL_FIST2 {SPR_SKEL,7,6,{A_FaceTarget},S_SKEL_FIST4,0,0}, // S_SKEL_FIST3 {SPR_SKEL,8,6,{A_SkelFist},S_SKEL_RUN1,0,0}, // S_SKEL_FIST4 {SPR_SKEL,32777,0,{A_FaceTarget},S_SKEL_MISS2,0,0}, // S_SKEL_MISS1 {SPR_SKEL,32777,10,{A_FaceTarget},S_SKEL_MISS3,0,0}, // S_SKEL_MISS2 {SPR_SKEL,10,10,{A_SkelMissile},S_SKEL_MISS4,0,0}, // S_SKEL_MISS3 {SPR_SKEL,10,10,{A_FaceTarget},S_SKEL_RUN1,0,0}, // S_SKEL_MISS4 {SPR_SKEL,11,5,{NULL},S_SKEL_PAIN2,0,0}, // S_SKEL_PAIN {SPR_SKEL,11,5,{A_Pain},S_SKEL_RUN1,0,0}, // S_SKEL_PAIN2 {SPR_SKEL,11,7,{NULL},S_SKEL_DIE2,0,0}, // S_SKEL_DIE1 {SPR_SKEL,12,7,{NULL},S_SKEL_DIE3,0,0}, // S_SKEL_DIE2 {SPR_SKEL,13,7,{A_Scream},S_SKEL_DIE4,0,0}, // S_SKEL_DIE3 {SPR_SKEL,14,7,{A_Fall},S_SKEL_DIE5,0,0}, // S_SKEL_DIE4 {SPR_SKEL,15,7,{NULL},S_SKEL_DIE6,0,0}, // S_SKEL_DIE5 {SPR_SKEL,16,-1,{NULL},S_NULL,0,0}, // S_SKEL_DIE6 {SPR_SKEL,16,5,{NULL},S_SKEL_RAISE2,0,0}, // S_SKEL_RAISE1 {SPR_SKEL,15,5,{NULL},S_SKEL_RAISE3,0,0}, // S_SKEL_RAISE2 {SPR_SKEL,14,5,{NULL},S_SKEL_RAISE4,0,0}, // S_SKEL_RAISE3 {SPR_SKEL,13,5,{NULL},S_SKEL_RAISE5,0,0}, // S_SKEL_RAISE4 {SPR_SKEL,12,5,{NULL},S_SKEL_RAISE6,0,0}, // S_SKEL_RAISE5 {SPR_SKEL,11,5,{NULL},S_SKEL_RUN1,0,0}, // S_SKEL_RAISE6 {SPR_MANF,32768,4,{NULL},S_FATSHOT2,0,0}, // S_FATSHOT1 {SPR_MANF,32769,4,{NULL},S_FATSHOT1,0,0}, // S_FATSHOT2 {SPR_MISL,32769,8,{NULL},S_FATSHOTX2,0,0}, // S_FATSHOTX1 {SPR_MISL,32770,6,{NULL},S_FATSHOTX3,0,0}, // S_FATSHOTX2 {SPR_MISL,32771,4,{NULL},S_NULL,0,0}, // S_FATSHOTX3 {SPR_FATT,0,15,{A_Look},S_FATT_STND2,0,0}, // S_FATT_STND {SPR_FATT,1,15,{A_Look},S_FATT_STND,0,0}, // S_FATT_STND2 {SPR_FATT,0,4,{A_Chase},S_FATT_RUN2,0,0}, // S_FATT_RUN1 {SPR_FATT,0,4,{A_Chase},S_FATT_RUN3,0,0}, // S_FATT_RUN2 {SPR_FATT,1,4,{A_Chase},S_FATT_RUN4,0,0}, // S_FATT_RUN3 {SPR_FATT,1,4,{A_Chase},S_FATT_RUN5,0,0}, // S_FATT_RUN4 {SPR_FATT,2,4,{A_Chase},S_FATT_RUN6,0,0}, // S_FATT_RUN5 {SPR_FATT,2,4,{A_Chase},S_FATT_RUN7,0,0}, // S_FATT_RUN6 {SPR_FATT,3,4,{A_Chase},S_FATT_RUN8,0,0}, // S_FATT_RUN7 {SPR_FATT,3,4,{A_Chase},S_FATT_RUN9,0,0}, // S_FATT_RUN8 {SPR_FATT,4,4,{A_Chase},S_FATT_RUN10,0,0}, // S_FATT_RUN9 {SPR_FATT,4,4,{A_Chase},S_FATT_RUN11,0,0}, // S_FATT_RUN10 {SPR_FATT,5,4,{A_Chase},S_FATT_RUN12,0,0}, // S_FATT_RUN11 {SPR_FATT,5,4,{A_Chase},S_FATT_RUN1,0,0}, // S_FATT_RUN12 {SPR_FATT,6,20,{A_FatRaise},S_FATT_ATK2,0,0}, // S_FATT_ATK1 {SPR_FATT,32775,10,{A_FatAttack1},S_FATT_ATK3,0,0}, // S_FATT_ATK2 {SPR_FATT,8,5,{A_FaceTarget},S_FATT_ATK4,0,0}, // S_FATT_ATK3 {SPR_FATT,6,5,{A_FaceTarget},S_FATT_ATK5,0,0}, // S_FATT_ATK4 {SPR_FATT,32775,10,{A_FatAttack2},S_FATT_ATK6,0,0}, // S_FATT_ATK5 {SPR_FATT,8,5,{A_FaceTarget},S_FATT_ATK7,0,0}, // S_FATT_ATK6 {SPR_FATT,6,5,{A_FaceTarget},S_FATT_ATK8,0,0}, // S_FATT_ATK7 {SPR_FATT,32775,10,{A_FatAttack3},S_FATT_ATK9,0,0}, // S_FATT_ATK8 {SPR_FATT,8,5,{A_FaceTarget},S_FATT_ATK10,0,0}, // S_FATT_ATK9 {SPR_FATT,6,5,{A_FaceTarget},S_FATT_RUN1,0,0}, // S_FATT_ATK10 {SPR_FATT,9,3,{NULL},S_FATT_PAIN2,0,0}, // S_FATT_PAIN {SPR_FATT,9,3,{A_Pain},S_FATT_RUN1,0,0}, // S_FATT_PAIN2 {SPR_FATT,10,6,{NULL},S_FATT_DIE2,0,0}, // S_FATT_DIE1 {SPR_FATT,11,6,{A_Scream},S_FATT_DIE3,0,0}, // S_FATT_DIE2 {SPR_FATT,12,6,{A_Fall},S_FATT_DIE4,0,0}, // S_FATT_DIE3 {SPR_FATT,13,6,{NULL},S_FATT_DIE5,0,0}, // S_FATT_DIE4 {SPR_FATT,14,6,{NULL},S_FATT_DIE6,0,0}, // S_FATT_DIE5 {SPR_FATT,15,6,{NULL},S_FATT_DIE7,0,0}, // S_FATT_DIE6 {SPR_FATT,16,6,{NULL},S_FATT_DIE8,0,0}, // S_FATT_DIE7 {SPR_FATT,17,6,{NULL},S_FATT_DIE9,0,0}, // S_FATT_DIE8 {SPR_FATT,18,6,{NULL},S_FATT_DIE10,0,0}, // S_FATT_DIE9 {SPR_FATT,19,-1,{A_BossDeath},S_NULL,0,0}, // S_FATT_DIE10 {SPR_FATT,17,5,{NULL},S_FATT_RAISE2,0,0}, // S_FATT_RAISE1 {SPR_FATT,16,5,{NULL},S_FATT_RAISE3,0,0}, // S_FATT_RAISE2 {SPR_FATT,15,5,{NULL},S_FATT_RAISE4,0,0}, // S_FATT_RAISE3 {SPR_FATT,14,5,{NULL},S_FATT_RAISE5,0,0}, // S_FATT_RAISE4 {SPR_FATT,13,5,{NULL},S_FATT_RAISE6,0,0}, // S_FATT_RAISE5 {SPR_FATT,12,5,{NULL},S_FATT_RAISE7,0,0}, // S_FATT_RAISE6 {SPR_FATT,11,5,{NULL},S_FATT_RAISE8,0,0}, // S_FATT_RAISE7 {SPR_FATT,10,5,{NULL},S_FATT_RUN1,0,0}, // S_FATT_RAISE8 {SPR_CPOS,0,10,{A_Look},S_CPOS_STND2,0,0}, // S_CPOS_STND {SPR_CPOS,1,10,{A_Look},S_CPOS_STND,0,0}, // S_CPOS_STND2 {SPR_CPOS,0,3,{A_Chase},S_CPOS_RUN2,0,0}, // S_CPOS_RUN1 {SPR_CPOS,0,3,{A_Chase},S_CPOS_RUN3,0,0}, // S_CPOS_RUN2 {SPR_CPOS,1,3,{A_Chase},S_CPOS_RUN4,0,0}, // S_CPOS_RUN3 {SPR_CPOS,1,3,{A_Chase},S_CPOS_RUN5,0,0}, // S_CPOS_RUN4 {SPR_CPOS,2,3,{A_Chase},S_CPOS_RUN6,0,0}, // S_CPOS_RUN5 {SPR_CPOS,2,3,{A_Chase},S_CPOS_RUN7,0,0}, // S_CPOS_RUN6 {SPR_CPOS,3,3,{A_Chase},S_CPOS_RUN8,0,0}, // S_CPOS_RUN7 {SPR_CPOS,3,3,{A_Chase},S_CPOS_RUN1,0,0}, // S_CPOS_RUN8 {SPR_CPOS,4,10,{A_FaceTarget},S_CPOS_ATK2,0,0}, // S_CPOS_ATK1 {SPR_CPOS,32773,4,{A_CPosAttack},S_CPOS_ATK3,0,0}, // S_CPOS_ATK2 {SPR_CPOS,32772,4,{A_CPosAttack},S_CPOS_ATK4,0,0}, // S_CPOS_ATK3 {SPR_CPOS,5,1,{A_CPosRefire},S_CPOS_ATK2,0,0}, // S_CPOS_ATK4 {SPR_CPOS,6,3,{NULL},S_CPOS_PAIN2,0,0}, // S_CPOS_PAIN {SPR_CPOS,6,3,{A_Pain},S_CPOS_RUN1,0,0}, // S_CPOS_PAIN2 {SPR_CPOS,7,5,{NULL},S_CPOS_DIE2,0,0}, // S_CPOS_DIE1 {SPR_CPOS,8,5,{A_Scream},S_CPOS_DIE3,0,0}, // S_CPOS_DIE2 {SPR_CPOS,9,5,{A_Fall},S_CPOS_DIE4,0,0}, // S_CPOS_DIE3 {SPR_CPOS,10,5,{NULL},S_CPOS_DIE5,0,0}, // S_CPOS_DIE4 {SPR_CPOS,11,5,{NULL},S_CPOS_DIE6,0,0}, // S_CPOS_DIE5 {SPR_CPOS,12,5,{NULL},S_CPOS_DIE7,0,0}, // S_CPOS_DIE6 {SPR_CPOS,13,-1,{NULL},S_NULL,0,0}, // S_CPOS_DIE7 {SPR_CPOS,14,5,{NULL},S_CPOS_XDIE2,0,0}, // S_CPOS_XDIE1 {SPR_CPOS,15,5,{A_XScream},S_CPOS_XDIE3,0,0}, // S_CPOS_XDIE2 {SPR_CPOS,16,5,{A_Fall},S_CPOS_XDIE4,0,0}, // S_CPOS_XDIE3 {SPR_CPOS,17,5,{NULL},S_CPOS_XDIE5,0,0}, // S_CPOS_XDIE4 {SPR_CPOS,18,5,{NULL},S_CPOS_XDIE6,0,0}, // S_CPOS_XDIE5 {SPR_CPOS,19,-1,{NULL},S_NULL,0,0}, // S_CPOS_XDIE6 {SPR_CPOS,13,5,{NULL},S_CPOS_RAISE2,0,0}, // S_CPOS_RAISE1 {SPR_CPOS,12,5,{NULL},S_CPOS_RAISE3,0,0}, // S_CPOS_RAISE2 {SPR_CPOS,11,5,{NULL},S_CPOS_RAISE4,0,0}, // S_CPOS_RAISE3 {SPR_CPOS,10,5,{NULL},S_CPOS_RAISE5,0,0}, // S_CPOS_RAISE4 {SPR_CPOS,9,5,{NULL},S_CPOS_RAISE6,0,0}, // S_CPOS_RAISE5 {SPR_CPOS,8,5,{NULL},S_CPOS_RAISE7,0,0}, // S_CPOS_RAISE6 {SPR_CPOS,7,5,{NULL},S_CPOS_RUN1,0,0}, // S_CPOS_RAISE7 {SPR_TROO,0,10,{A_Look},S_TROO_STND2,0,0}, // S_TROO_STND {SPR_TROO,1,10,{A_Look},S_TROO_STND,0,0}, // S_TROO_STND2 {SPR_TROO,0,3,{A_Chase},S_TROO_RUN2,0,0}, // S_TROO_RUN1 {SPR_TROO,0,3,{A_Chase},S_TROO_RUN3,0,0}, // S_TROO_RUN2 {SPR_TROO,1,3,{A_Chase},S_TROO_RUN4,0,0}, // S_TROO_RUN3 {SPR_TROO,1,3,{A_Chase},S_TROO_RUN5,0,0}, // S_TROO_RUN4 {SPR_TROO,2,3,{A_Chase},S_TROO_RUN6,0,0}, // S_TROO_RUN5 {SPR_TROO,2,3,{A_Chase},S_TROO_RUN7,0,0}, // S_TROO_RUN6 {SPR_TROO,3,3,{A_Chase},S_TROO_RUN8,0,0}, // S_TROO_RUN7 {SPR_TROO,3,3,{A_Chase},S_TROO_RUN1,0,0}, // S_TROO_RUN8 {SPR_TROO,4,8,{A_FaceTarget},S_TROO_ATK2,0,0}, // S_TROO_ATK1 {SPR_TROO,5,8,{A_FaceTarget},S_TROO_ATK3,0,0}, // S_TROO_ATK2 {SPR_TROO,6,6,{A_TroopAttack},S_TROO_RUN1,0,0}, // S_TROO_ATK3 {SPR_TROO,7,2,{NULL},S_TROO_PAIN2,0,0}, // S_TROO_PAIN {SPR_TROO,7,2,{A_Pain},S_TROO_RUN1,0,0}, // S_TROO_PAIN2 {SPR_TROO,8,8,{NULL},S_TROO_DIE2,0,0}, // S_TROO_DIE1 {SPR_TROO,9,8,{A_Scream},S_TROO_DIE3,0,0}, // S_TROO_DIE2 {SPR_TROO,10,6,{NULL},S_TROO_DIE4,0,0}, // S_TROO_DIE3 {SPR_TROO,11,6,{A_Fall},S_TROO_DIE5,0,0}, // S_TROO_DIE4 {SPR_TROO,12,-1,{NULL},S_NULL,0,0}, // S_TROO_DIE5 {SPR_TROO,13,5,{NULL},S_TROO_XDIE2,0,0}, // S_TROO_XDIE1 {SPR_TROO,14,5,{A_XScream},S_TROO_XDIE3,0,0}, // S_TROO_XDIE2 {SPR_TROO,15,5,{NULL},S_TROO_XDIE4,0,0}, // S_TROO_XDIE3 {SPR_TROO,16,5,{A_Fall},S_TROO_XDIE5,0,0}, // S_TROO_XDIE4 {SPR_TROO,17,5,{NULL},S_TROO_XDIE6,0,0}, // S_TROO_XDIE5 {SPR_TROO,18,5,{NULL},S_TROO_XDIE7,0,0}, // S_TROO_XDIE6 {SPR_TROO,19,5,{NULL},S_TROO_XDIE8,0,0}, // S_TROO_XDIE7 {SPR_TROO,20,-1,{NULL},S_NULL,0,0}, // S_TROO_XDIE8 {SPR_TROO,12,8,{NULL},S_TROO_RAISE2,0,0}, // S_TROO_RAISE1 {SPR_TROO,11,8,{NULL},S_TROO_RAISE3,0,0}, // S_TROO_RAISE2 {SPR_TROO,10,6,{NULL},S_TROO_RAISE4,0,0}, // S_TROO_RAISE3 {SPR_TROO,9,6,{NULL},S_TROO_RAISE5,0,0}, // S_TROO_RAISE4 {SPR_TROO,8,6,{NULL},S_TROO_RUN1,0,0}, // S_TROO_RAISE5 {SPR_SARG,0,10,{A_Look},S_SARG_STND2,0,0}, // S_SARG_STND {SPR_SARG,1,10,{A_Look},S_SARG_STND,0,0}, // S_SARG_STND2 {SPR_SARG,0,2,{A_Chase},S_SARG_RUN2,0,0}, // S_SARG_RUN1 {SPR_SARG,0,2,{A_Chase},S_SARG_RUN3,0,0}, // S_SARG_RUN2 {SPR_SARG,1,2,{A_Chase},S_SARG_RUN4,0,0}, // S_SARG_RUN3 {SPR_SARG,1,2,{A_Chase},S_SARG_RUN5,0,0}, // S_SARG_RUN4 {SPR_SARG,2,2,{A_Chase},S_SARG_RUN6,0,0}, // S_SARG_RUN5 {SPR_SARG,2,2,{A_Chase},S_SARG_RUN7,0,0}, // S_SARG_RUN6 {SPR_SARG,3,2,{A_Chase},S_SARG_RUN8,0,0}, // S_SARG_RUN7 {SPR_SARG,3,2,{A_Chase},S_SARG_RUN1,0,0}, // S_SARG_RUN8 {SPR_SARG,4,8,{A_FaceTarget},S_SARG_ATK2,0,0}, // S_SARG_ATK1 {SPR_SARG,5,8,{A_FaceTarget},S_SARG_ATK3,0,0}, // S_SARG_ATK2 {SPR_SARG,6,8,{A_SargAttack},S_SARG_RUN1,0,0}, // S_SARG_ATK3 {SPR_SARG,7,2,{NULL},S_SARG_PAIN2,0,0}, // S_SARG_PAIN {SPR_SARG,7,2,{A_Pain},S_SARG_RUN1,0,0}, // S_SARG_PAIN2 {SPR_SARG,8,8,{NULL},S_SARG_DIE2,0,0}, // S_SARG_DIE1 {SPR_SARG,9,8,{A_Scream},S_SARG_DIE3,0,0}, // S_SARG_DIE2 {SPR_SARG,10,4,{NULL},S_SARG_DIE4,0,0}, // S_SARG_DIE3 {SPR_SARG,11,4,{A_Fall},S_SARG_DIE5,0,0}, // S_SARG_DIE4 {SPR_SARG,12,4,{NULL},S_SARG_DIE6,0,0}, // S_SARG_DIE5 {SPR_SARG,13,-1,{NULL},S_NULL,0,0}, // S_SARG_DIE6 {SPR_SARG,13,5,{NULL},S_SARG_RAISE2,0,0}, // S_SARG_RAISE1 {SPR_SARG,12,5,{NULL},S_SARG_RAISE3,0,0}, // S_SARG_RAISE2 {SPR_SARG,11,5,{NULL},S_SARG_RAISE4,0,0}, // S_SARG_RAISE3 {SPR_SARG,10,5,{NULL},S_SARG_RAISE5,0,0}, // S_SARG_RAISE4 {SPR_SARG,9,5,{NULL},S_SARG_RAISE6,0,0}, // S_SARG_RAISE5 {SPR_SARG,8,5,{NULL},S_SARG_RUN1,0,0}, // S_SARG_RAISE6 {SPR_HEAD,0,10,{A_Look},S_HEAD_STND,0,0}, // S_HEAD_STND {SPR_HEAD,0,3,{A_Chase},S_HEAD_RUN1,0,0}, // S_HEAD_RUN1 {SPR_HEAD,1,5,{A_FaceTarget},S_HEAD_ATK2,0,0}, // S_HEAD_ATK1 {SPR_HEAD,2,5,{A_FaceTarget},S_HEAD_ATK3,0,0}, // S_HEAD_ATK2 {SPR_HEAD,32771,5,{A_HeadAttack},S_HEAD_RUN1,0,0}, // S_HEAD_ATK3 {SPR_HEAD,4,3,{NULL},S_HEAD_PAIN2,0,0}, // S_HEAD_PAIN {SPR_HEAD,4,3,{A_Pain},S_HEAD_PAIN3,0,0}, // S_HEAD_PAIN2 {SPR_HEAD,5,6,{NULL},S_HEAD_RUN1,0,0}, // S_HEAD_PAIN3 {SPR_HEAD,6,8,{NULL},S_HEAD_DIE2,0,0}, // S_HEAD_DIE1 {SPR_HEAD,7,8,{A_Scream},S_HEAD_DIE3,0,0}, // S_HEAD_DIE2 {SPR_HEAD,8,8,{NULL},S_HEAD_DIE4,0,0}, // S_HEAD_DIE3 {SPR_HEAD,9,8,{NULL},S_HEAD_DIE5,0,0}, // S_HEAD_DIE4 {SPR_HEAD,10,8,{A_Fall},S_HEAD_DIE6,0,0}, // S_HEAD_DIE5 {SPR_HEAD,11,-1,{NULL},S_NULL,0,0}, // S_HEAD_DIE6 {SPR_HEAD,11,8,{NULL},S_HEAD_RAISE2,0,0}, // S_HEAD_RAISE1 {SPR_HEAD,10,8,{NULL},S_HEAD_RAISE3,0,0}, // S_HEAD_RAISE2 {SPR_HEAD,9,8,{NULL},S_HEAD_RAISE4,0,0}, // S_HEAD_RAISE3 {SPR_HEAD,8,8,{NULL},S_HEAD_RAISE5,0,0}, // S_HEAD_RAISE4 {SPR_HEAD,7,8,{NULL},S_HEAD_RAISE6,0,0}, // S_HEAD_RAISE5 {SPR_HEAD,6,8,{NULL},S_HEAD_RUN1,0,0}, // S_HEAD_RAISE6 {SPR_BAL7,32768,4,{NULL},S_BRBALL2,0,0}, // S_BRBALL1 {SPR_BAL7,32769,4,{NULL},S_BRBALL1,0,0}, // S_BRBALL2 {SPR_BAL7,32770,6,{NULL},S_BRBALLX2,0,0}, // S_BRBALLX1 {SPR_BAL7,32771,6,{NULL},S_BRBALLX3,0,0}, // S_BRBALLX2 {SPR_BAL7,32772,6,{NULL},S_NULL,0,0}, // S_BRBALLX3 {SPR_BOSS,0,10,{A_Look},S_BOSS_STND2,0,0}, // S_BOSS_STND {SPR_BOSS,1,10,{A_Look},S_BOSS_STND,0,0}, // S_BOSS_STND2 {SPR_BOSS,0,3,{A_Chase},S_BOSS_RUN2,0,0}, // S_BOSS_RUN1 {SPR_BOSS,0,3,{A_Chase},S_BOSS_RUN3,0,0}, // S_BOSS_RUN2 {SPR_BOSS,1,3,{A_Chase},S_BOSS_RUN4,0,0}, // S_BOSS_RUN3 {SPR_BOSS,1,3,{A_Chase},S_BOSS_RUN5,0,0}, // S_BOSS_RUN4 {SPR_BOSS,2,3,{A_Chase},S_BOSS_RUN6,0,0}, // S_BOSS_RUN5 {SPR_BOSS,2,3,{A_Chase},S_BOSS_RUN7,0,0}, // S_BOSS_RUN6 {SPR_BOSS,3,3,{A_Chase},S_BOSS_RUN8,0,0}, // S_BOSS_RUN7 {SPR_BOSS,3,3,{A_Chase},S_BOSS_RUN1,0,0}, // S_BOSS_RUN8 {SPR_BOSS,4,8,{A_FaceTarget},S_BOSS_ATK2,0,0}, // S_BOSS_ATK1 {SPR_BOSS,5,8,{A_FaceTarget},S_BOSS_ATK3,0,0}, // S_BOSS_ATK2 {SPR_BOSS,6,8,{A_BruisAttack},S_BOSS_RUN1,0,0}, // S_BOSS_ATK3 {SPR_BOSS,7,2,{NULL},S_BOSS_PAIN2,0,0}, // S_BOSS_PAIN {SPR_BOSS,7,2,{A_Pain},S_BOSS_RUN1,0,0}, // S_BOSS_PAIN2 {SPR_BOSS,8,8,{NULL},S_BOSS_DIE2,0,0}, // S_BOSS_DIE1 {SPR_BOSS,9,8,{A_Scream},S_BOSS_DIE3,0,0}, // S_BOSS_DIE2 {SPR_BOSS,10,8,{NULL},S_BOSS_DIE4,0,0}, // S_BOSS_DIE3 {SPR_BOSS,11,8,{A_Fall},S_BOSS_DIE5,0,0}, // S_BOSS_DIE4 {SPR_BOSS,12,8,{NULL},S_BOSS_DIE6,0,0}, // S_BOSS_DIE5 {SPR_BOSS,13,8,{NULL},S_BOSS_DIE7,0,0}, // S_BOSS_DIE6 {SPR_BOSS,14,-1,{A_BossDeath},S_NULL,0,0}, // S_BOSS_DIE7 {SPR_BOSS,14,8,{NULL},S_BOSS_RAISE2,0,0}, // S_BOSS_RAISE1 {SPR_BOSS,13,8,{NULL},S_BOSS_RAISE3,0,0}, // S_BOSS_RAISE2 {SPR_BOSS,12,8,{NULL},S_BOSS_RAISE4,0,0}, // S_BOSS_RAISE3 {SPR_BOSS,11,8,{NULL},S_BOSS_RAISE5,0,0}, // S_BOSS_RAISE4 {SPR_BOSS,10,8,{NULL},S_BOSS_RAISE6,0,0}, // S_BOSS_RAISE5 {SPR_BOSS,9,8,{NULL},S_BOSS_RAISE7,0,0}, // S_BOSS_RAISE6 {SPR_BOSS,8,8,{NULL},S_BOSS_RUN1,0,0}, // S_BOSS_RAISE7 {SPR_BOS2,0,10,{A_Look},S_BOS2_STND2,0,0}, // S_BOS2_STND {SPR_BOS2,1,10,{A_Look},S_BOS2_STND,0,0}, // S_BOS2_STND2 {SPR_BOS2,0,3,{A_Chase},S_BOS2_RUN2,0,0}, // S_BOS2_RUN1 {SPR_BOS2,0,3,{A_Chase},S_BOS2_RUN3,0,0}, // S_BOS2_RUN2 {SPR_BOS2,1,3,{A_Chase},S_BOS2_RUN4,0,0}, // S_BOS2_RUN3 {SPR_BOS2,1,3,{A_Chase},S_BOS2_RUN5,0,0}, // S_BOS2_RUN4 {SPR_BOS2,2,3,{A_Chase},S_BOS2_RUN6,0,0}, // S_BOS2_RUN5 {SPR_BOS2,2,3,{A_Chase},S_BOS2_RUN7,0,0}, // S_BOS2_RUN6 {SPR_BOS2,3,3,{A_Chase},S_BOS2_RUN8,0,0}, // S_BOS2_RUN7 {SPR_BOS2,3,3,{A_Chase},S_BOS2_RUN1,0,0}, // S_BOS2_RUN8 {SPR_BOS2,4,8,{A_FaceTarget},S_BOS2_ATK2,0,0}, // S_BOS2_ATK1 {SPR_BOS2,5,8,{A_FaceTarget},S_BOS2_ATK3,0,0}, // S_BOS2_ATK2 {SPR_BOS2,6,8,{A_BruisAttack},S_BOS2_RUN1,0,0}, // S_BOS2_ATK3 {SPR_BOS2,7,2,{NULL},S_BOS2_PAIN2,0,0}, // S_BOS2_PAIN {SPR_BOS2,7,2,{A_Pain},S_BOS2_RUN1,0,0}, // S_BOS2_PAIN2 {SPR_BOS2,8,8,{NULL},S_BOS2_DIE2,0,0}, // S_BOS2_DIE1 {SPR_BOS2,9,8,{A_Scream},S_BOS2_DIE3,0,0}, // S_BOS2_DIE2 {SPR_BOS2,10,8,{NULL},S_BOS2_DIE4,0,0}, // S_BOS2_DIE3 {SPR_BOS2,11,8,{A_Fall},S_BOS2_DIE5,0,0}, // S_BOS2_DIE4 {SPR_BOS2,12,8,{NULL},S_BOS2_DIE6,0,0}, // S_BOS2_DIE5 {SPR_BOS2,13,8,{NULL},S_BOS2_DIE7,0,0}, // S_BOS2_DIE6 {SPR_BOS2,14,-1,{NULL},S_NULL,0,0}, // S_BOS2_DIE7 {SPR_BOS2,14,8,{NULL},S_BOS2_RAISE2,0,0}, // S_BOS2_RAISE1 {SPR_BOS2,13,8,{NULL},S_BOS2_RAISE3,0,0}, // S_BOS2_RAISE2 {SPR_BOS2,12,8,{NULL},S_BOS2_RAISE4,0,0}, // S_BOS2_RAISE3 {SPR_BOS2,11,8,{NULL},S_BOS2_RAISE5,0,0}, // S_BOS2_RAISE4 {SPR_BOS2,10,8,{NULL},S_BOS2_RAISE6,0,0}, // S_BOS2_RAISE5 {SPR_BOS2,9,8,{NULL},S_BOS2_RAISE7,0,0}, // S_BOS2_RAISE6 {SPR_BOS2,8,8,{NULL},S_BOS2_RUN1,0,0}, // S_BOS2_RAISE7 {SPR_SKUL,32768,10,{A_Look},S_SKULL_STND2,0,0}, // S_SKULL_STND {SPR_SKUL,32769,10,{A_Look},S_SKULL_STND,0,0}, // S_SKULL_STND2 {SPR_SKUL,32768,6,{A_Chase},S_SKULL_RUN2,0,0}, // S_SKULL_RUN1 {SPR_SKUL,32769,6,{A_Chase},S_SKULL_RUN1,0,0}, // S_SKULL_RUN2 {SPR_SKUL,32770,10,{A_FaceTarget},S_SKULL_ATK2,0,0}, // S_SKULL_ATK1 {SPR_SKUL,32771,4,{A_SkullAttack},S_SKULL_ATK3,0,0}, // S_SKULL_ATK2 {SPR_SKUL,32770,4,{NULL},S_SKULL_ATK4,0,0}, // S_SKULL_ATK3 {SPR_SKUL,32771,4,{NULL},S_SKULL_ATK3,0,0}, // S_SKULL_ATK4 {SPR_SKUL,32772,3,{NULL},S_SKULL_PAIN2,0,0}, // S_SKULL_PAIN {SPR_SKUL,32772,3,{A_Pain},S_SKULL_RUN1,0,0}, // S_SKULL_PAIN2 {SPR_SKUL,32773,6,{NULL},S_SKULL_DIE2,0,0}, // S_SKULL_DIE1 {SPR_SKUL,32774,6,{A_Scream},S_SKULL_DIE3,0,0}, // S_SKULL_DIE2 {SPR_SKUL,32775,6,{NULL},S_SKULL_DIE4,0,0}, // S_SKULL_DIE3 {SPR_SKUL,32776,6,{A_Fall},S_SKULL_DIE5,0,0}, // S_SKULL_DIE4 {SPR_SKUL,9,6,{NULL},S_SKULL_DIE6,0,0}, // S_SKULL_DIE5 {SPR_SKUL,10,6,{NULL},S_NULL,0,0}, // S_SKULL_DIE6 {SPR_SPID,0,10,{A_Look},S_SPID_STND2,0,0}, // S_SPID_STND {SPR_SPID,1,10,{A_Look},S_SPID_STND,0,0}, // S_SPID_STND2 {SPR_SPID,0,3,{A_Metal},S_SPID_RUN2,0,0}, // S_SPID_RUN1 {SPR_SPID,0,3,{A_Chase},S_SPID_RUN3,0,0}, // S_SPID_RUN2 {SPR_SPID,1,3,{A_Chase},S_SPID_RUN4,0,0}, // S_SPID_RUN3 {SPR_SPID,1,3,{A_Chase},S_SPID_RUN5,0,0}, // S_SPID_RUN4 {SPR_SPID,2,3,{A_Metal},S_SPID_RUN6,0,0}, // S_SPID_RUN5 {SPR_SPID,2,3,{A_Chase},S_SPID_RUN7,0,0}, // S_SPID_RUN6 {SPR_SPID,3,3,{A_Chase},S_SPID_RUN8,0,0}, // S_SPID_RUN7 {SPR_SPID,3,3,{A_Chase},S_SPID_RUN9,0,0}, // S_SPID_RUN8 {SPR_SPID,4,3,{A_Metal},S_SPID_RUN10,0,0}, // S_SPID_RUN9 {SPR_SPID,4,3,{A_Chase},S_SPID_RUN11,0,0}, // S_SPID_RUN10 {SPR_SPID,5,3,{A_Chase},S_SPID_RUN12,0,0}, // S_SPID_RUN11 {SPR_SPID,5,3,{A_Chase},S_SPID_RUN1,0,0}, // S_SPID_RUN12 {SPR_SPID,32768,20,{A_FaceTarget},S_SPID_ATK2,0,0}, // S_SPID_ATK1 {SPR_SPID,32774,4,{A_SPosAttack},S_SPID_ATK3,0,0}, // S_SPID_ATK2 {SPR_SPID,32775,4,{A_SPosAttack},S_SPID_ATK4,0,0}, // S_SPID_ATK3 {SPR_SPID,32775,1,{A_SpidRefire},S_SPID_ATK2,0,0}, // S_SPID_ATK4 {SPR_SPID,8,3,{NULL},S_SPID_PAIN2,0,0}, // S_SPID_PAIN {SPR_SPID,8,3,{A_Pain},S_SPID_RUN1,0,0}, // S_SPID_PAIN2 {SPR_SPID,9,20,{A_Scream},S_SPID_DIE2,0,0}, // S_SPID_DIE1 {SPR_SPID,10,10,{A_Fall},S_SPID_DIE3,0,0}, // S_SPID_DIE2 {SPR_SPID,11,10,{NULL},S_SPID_DIE4,0,0}, // S_SPID_DIE3 {SPR_SPID,12,10,{NULL},S_SPID_DIE5,0,0}, // S_SPID_DIE4 {SPR_SPID,13,10,{NULL},S_SPID_DIE6,0,0}, // S_SPID_DIE5 {SPR_SPID,14,10,{NULL},S_SPID_DIE7,0,0}, // S_SPID_DIE6 {SPR_SPID,15,10,{NULL},S_SPID_DIE8,0,0}, // S_SPID_DIE7 {SPR_SPID,16,10,{NULL},S_SPID_DIE9,0,0}, // S_SPID_DIE8 {SPR_SPID,17,10,{NULL},S_SPID_DIE10,0,0}, // S_SPID_DIE9 {SPR_SPID,18,30,{NULL},S_SPID_DIE11,0,0}, // S_SPID_DIE10 {SPR_SPID,18,-1,{A_BossDeath},S_NULL,0,0}, // S_SPID_DIE11 {SPR_BSPI,0,10,{A_Look},S_BSPI_STND2,0,0}, // S_BSPI_STND {SPR_BSPI,1,10,{A_Look},S_BSPI_STND,0,0}, // S_BSPI_STND2 {SPR_BSPI,0,20,{NULL},S_BSPI_RUN1,0,0}, // S_BSPI_SIGHT {SPR_BSPI,0,3,{A_BabyMetal},S_BSPI_RUN2,0,0}, // S_BSPI_RUN1 {SPR_BSPI,0,3,{A_Chase},S_BSPI_RUN3,0,0}, // S_BSPI_RUN2 {SPR_BSPI,1,3,{A_Chase},S_BSPI_RUN4,0,0}, // S_BSPI_RUN3 {SPR_BSPI,1,3,{A_Chase},S_BSPI_RUN5,0,0}, // S_BSPI_RUN4 {SPR_BSPI,2,3,{A_Chase},S_BSPI_RUN6,0,0}, // S_BSPI_RUN5 {SPR_BSPI,2,3,{A_Chase},S_BSPI_RUN7,0,0}, // S_BSPI_RUN6 {SPR_BSPI,3,3,{A_BabyMetal},S_BSPI_RUN8,0,0}, // S_BSPI_RUN7 {SPR_BSPI,3,3,{A_Chase},S_BSPI_RUN9,0,0}, // S_BSPI_RUN8 {SPR_BSPI,4,3,{A_Chase},S_BSPI_RUN10,0,0}, // S_BSPI_RUN9 {SPR_BSPI,4,3,{A_Chase},S_BSPI_RUN11,0,0}, // S_BSPI_RUN10 {SPR_BSPI,5,3,{A_Chase},S_BSPI_RUN12,0,0}, // S_BSPI_RUN11 {SPR_BSPI,5,3,{A_Chase},S_BSPI_RUN1,0,0}, // S_BSPI_RUN12 {SPR_BSPI,32768,20,{A_FaceTarget},S_BSPI_ATK2,0,0}, // S_BSPI_ATK1 {SPR_BSPI,32774,4,{A_BspiAttack},S_BSPI_ATK3,0,0}, // S_BSPI_ATK2 {SPR_BSPI,32775,4,{NULL},S_BSPI_ATK4,0,0}, // S_BSPI_ATK3 {SPR_BSPI,32775,1,{A_SpidRefire},S_BSPI_ATK2,0,0}, // S_BSPI_ATK4 {SPR_BSPI,8,3,{NULL},S_BSPI_PAIN2,0,0}, // S_BSPI_PAIN {SPR_BSPI,8,3,{A_Pain},S_BSPI_RUN1,0,0}, // S_BSPI_PAIN2 {SPR_BSPI,9,20,{A_Scream},S_BSPI_DIE2,0,0}, // S_BSPI_DIE1 {SPR_BSPI,10,7,{A_Fall},S_BSPI_DIE3,0,0}, // S_BSPI_DIE2 {SPR_BSPI,11,7,{NULL},S_BSPI_DIE4,0,0}, // S_BSPI_DIE3 {SPR_BSPI,12,7,{NULL},S_BSPI_DIE5,0,0}, // S_BSPI_DIE4 {SPR_BSPI,13,7,{NULL},S_BSPI_DIE6,0,0}, // S_BSPI_DIE5 {SPR_BSPI,14,7,{NULL},S_BSPI_DIE7,0,0}, // S_BSPI_DIE6 {SPR_BSPI,15,-1,{A_BossDeath},S_NULL,0,0}, // S_BSPI_DIE7 {SPR_BSPI,15,5,{NULL},S_BSPI_RAISE2,0,0}, // S_BSPI_RAISE1 {SPR_BSPI,14,5,{NULL},S_BSPI_RAISE3,0,0}, // S_BSPI_RAISE2 {SPR_BSPI,13,5,{NULL},S_BSPI_RAISE4,0,0}, // S_BSPI_RAISE3 {SPR_BSPI,12,5,{NULL},S_BSPI_RAISE5,0,0}, // S_BSPI_RAISE4 {SPR_BSPI,11,5,{NULL},S_BSPI_RAISE6,0,0}, // S_BSPI_RAISE5 {SPR_BSPI,10,5,{NULL},S_BSPI_RAISE7,0,0}, // S_BSPI_RAISE6 {SPR_BSPI,9,5,{NULL},S_BSPI_RUN1,0,0}, // S_BSPI_RAISE7 {SPR_APLS,32768,5,{NULL},S_ARACH_PLAZ2,0,0}, // S_ARACH_PLAZ {SPR_APLS,32769,5,{NULL},S_ARACH_PLAZ,0,0}, // S_ARACH_PLAZ2 {SPR_APBX,32768,5,{NULL},S_ARACH_PLEX2,0,0}, // S_ARACH_PLEX {SPR_APBX,32769,5,{NULL},S_ARACH_PLEX3,0,0}, // S_ARACH_PLEX2 {SPR_APBX,32770,5,{NULL},S_ARACH_PLEX4,0,0}, // S_ARACH_PLEX3 {SPR_APBX,32771,5,{NULL},S_ARACH_PLEX5,0,0}, // S_ARACH_PLEX4 {SPR_APBX,32772,5,{NULL},S_NULL,0,0}, // S_ARACH_PLEX5 {SPR_CYBR,0,10,{A_Look},S_CYBER_STND2,0,0}, // S_CYBER_STND {SPR_CYBR,1,10,{A_Look},S_CYBER_STND,0,0}, // S_CYBER_STND2 {SPR_CYBR,0,3,{A_Hoof},S_CYBER_RUN2,0,0}, // S_CYBER_RUN1 {SPR_CYBR,0,3,{A_Chase},S_CYBER_RUN3,0,0}, // S_CYBER_RUN2 {SPR_CYBR,1,3,{A_Chase},S_CYBER_RUN4,0,0}, // S_CYBER_RUN3 {SPR_CYBR,1,3,{A_Chase},S_CYBER_RUN5,0,0}, // S_CYBER_RUN4 {SPR_CYBR,2,3,{A_Chase},S_CYBER_RUN6,0,0}, // S_CYBER_RUN5 {SPR_CYBR,2,3,{A_Chase},S_CYBER_RUN7,0,0}, // S_CYBER_RUN6 {SPR_CYBR,3,3,{A_Metal},S_CYBER_RUN8,0,0}, // S_CYBER_RUN7 {SPR_CYBR,3,3,{A_Chase},S_CYBER_RUN1,0,0}, // S_CYBER_RUN8 {SPR_CYBR,4,6,{A_FaceTarget},S_CYBER_ATK2,0,0}, // S_CYBER_ATK1 {SPR_CYBR,5,12,{A_CyberAttack},S_CYBER_ATK3,0,0}, // S_CYBER_ATK2 {SPR_CYBR,4,12,{A_FaceTarget},S_CYBER_ATK4,0,0}, // S_CYBER_ATK3 {SPR_CYBR,5,12,{A_CyberAttack},S_CYBER_ATK5,0,0}, // S_CYBER_ATK4 {SPR_CYBR,4,12,{A_FaceTarget},S_CYBER_ATK6,0,0}, // S_CYBER_ATK5 {SPR_CYBR,5,12,{A_CyberAttack},S_CYBER_RUN1,0,0}, // S_CYBER_ATK6 {SPR_CYBR,6,10,{A_Pain},S_CYBER_RUN1,0,0}, // S_CYBER_PAIN {SPR_CYBR,7,10,{NULL},S_CYBER_DIE2,0,0}, // S_CYBER_DIE1 {SPR_CYBR,8,10,{A_Scream},S_CYBER_DIE3,0,0}, // S_CYBER_DIE2 {SPR_CYBR,9,10,{NULL},S_CYBER_DIE4,0,0}, // S_CYBER_DIE3 {SPR_CYBR,10,10,{NULL},S_CYBER_DIE5,0,0}, // S_CYBER_DIE4 {SPR_CYBR,11,10,{NULL},S_CYBER_DIE6,0,0}, // S_CYBER_DIE5 {SPR_CYBR,12,10,{A_Fall},S_CYBER_DIE7,0,0}, // S_CYBER_DIE6 {SPR_CYBR,13,10,{NULL},S_CYBER_DIE8,0,0}, // S_CYBER_DIE7 {SPR_CYBR,14,10,{NULL},S_CYBER_DIE9,0,0}, // S_CYBER_DIE8 {SPR_CYBR,15,30,{NULL},S_CYBER_DIE10,0,0}, // S_CYBER_DIE9 {SPR_CYBR,15,-1,{A_BossDeath},S_NULL,0,0}, // S_CYBER_DIE10 {SPR_PAIN,0,10,{A_Look},S_PAIN_STND,0,0}, // S_PAIN_STND {SPR_PAIN,0,3,{A_Chase},S_PAIN_RUN2,0,0}, // S_PAIN_RUN1 {SPR_PAIN,0,3,{A_Chase},S_PAIN_RUN3,0,0}, // S_PAIN_RUN2 {SPR_PAIN,1,3,{A_Chase},S_PAIN_RUN4,0,0}, // S_PAIN_RUN3 {SPR_PAIN,1,3,{A_Chase},S_PAIN_RUN5,0,0}, // S_PAIN_RUN4 {SPR_PAIN,2,3,{A_Chase},S_PAIN_RUN6,0,0}, // S_PAIN_RUN5 {SPR_PAIN,2,3,{A_Chase},S_PAIN_RUN1,0,0}, // S_PAIN_RUN6 {SPR_PAIN,3,5,{A_FaceTarget},S_PAIN_ATK2,0,0}, // S_PAIN_ATK1 {SPR_PAIN,4,5,{A_FaceTarget},S_PAIN_ATK3,0,0}, // S_PAIN_ATK2 {SPR_PAIN,32773,5,{A_FaceTarget},S_PAIN_ATK4,0,0}, // S_PAIN_ATK3 {SPR_PAIN,32773,0,{A_PainAttack},S_PAIN_RUN1,0,0}, // S_PAIN_ATK4 {SPR_PAIN,6,6,{NULL},S_PAIN_PAIN2,0,0}, // S_PAIN_PAIN {SPR_PAIN,6,6,{A_Pain},S_PAIN_RUN1,0,0}, // S_PAIN_PAIN2 {SPR_PAIN,32775,8,{NULL},S_PAIN_DIE2,0,0}, // S_PAIN_DIE1 {SPR_PAIN,32776,8,{A_Scream},S_PAIN_DIE3,0,0}, // S_PAIN_DIE2 {SPR_PAIN,32777,8,{NULL},S_PAIN_DIE4,0,0}, // S_PAIN_DIE3 {SPR_PAIN,32778,8,{NULL},S_PAIN_DIE5,0,0}, // S_PAIN_DIE4 {SPR_PAIN,32779,8,{A_PainDie},S_PAIN_DIE6,0,0}, // S_PAIN_DIE5 {SPR_PAIN,32780,8,{NULL},S_NULL,0,0}, // S_PAIN_DIE6 {SPR_PAIN,12,8,{NULL},S_PAIN_RAISE2,0,0}, // S_PAIN_RAISE1 {SPR_PAIN,11,8,{NULL},S_PAIN_RAISE3,0,0}, // S_PAIN_RAISE2 {SPR_PAIN,10,8,{NULL},S_PAIN_RAISE4,0,0}, // S_PAIN_RAISE3 {SPR_PAIN,9,8,{NULL},S_PAIN_RAISE5,0,0}, // S_PAIN_RAISE4 {SPR_PAIN,8,8,{NULL},S_PAIN_RAISE6,0,0}, // S_PAIN_RAISE5 {SPR_PAIN,7,8,{NULL},S_PAIN_RUN1,0,0}, // S_PAIN_RAISE6 {SPR_SSWV,0,10,{A_Look},S_SSWV_STND2,0,0}, // S_SSWV_STND {SPR_SSWV,1,10,{A_Look},S_SSWV_STND,0,0}, // S_SSWV_STND2 {SPR_SSWV,0,3,{A_Chase},S_SSWV_RUN2,0,0}, // S_SSWV_RUN1 {SPR_SSWV,0,3,{A_Chase},S_SSWV_RUN3,0,0}, // S_SSWV_RUN2 {SPR_SSWV,1,3,{A_Chase},S_SSWV_RUN4,0,0}, // S_SSWV_RUN3 {SPR_SSWV,1,3,{A_Chase},S_SSWV_RUN5,0,0}, // S_SSWV_RUN4 {SPR_SSWV,2,3,{A_Chase},S_SSWV_RUN6,0,0}, // S_SSWV_RUN5 {SPR_SSWV,2,3,{A_Chase},S_SSWV_RUN7,0,0}, // S_SSWV_RUN6 {SPR_SSWV,3,3,{A_Chase},S_SSWV_RUN8,0,0}, // S_SSWV_RUN7 {SPR_SSWV,3,3,{A_Chase},S_SSWV_RUN1,0,0}, // S_SSWV_RUN8 {SPR_SSWV,4,10,{A_FaceTarget},S_SSWV_ATK2,0,0}, // S_SSWV_ATK1 {SPR_SSWV,5,10,{A_FaceTarget},S_SSWV_ATK3,0,0}, // S_SSWV_ATK2 {SPR_SSWV,32774,4,{A_CPosAttack},S_SSWV_ATK4,0,0}, // S_SSWV_ATK3 {SPR_SSWV,5,6,{A_FaceTarget},S_SSWV_ATK5,0,0}, // S_SSWV_ATK4 {SPR_SSWV,32774,4,{A_CPosAttack},S_SSWV_ATK6,0,0}, // S_SSWV_ATK5 {SPR_SSWV,5,1,{A_CPosRefire},S_SSWV_ATK2,0,0}, // S_SSWV_ATK6 {SPR_SSWV,7,3,{NULL},S_SSWV_PAIN2,0,0}, // S_SSWV_PAIN {SPR_SSWV,7,3,{A_Pain},S_SSWV_RUN1,0,0}, // S_SSWV_PAIN2 {SPR_SSWV,8,5,{NULL},S_SSWV_DIE2,0,0}, // S_SSWV_DIE1 {SPR_SSWV,9,5,{A_Scream},S_SSWV_DIE3,0,0}, // S_SSWV_DIE2 {SPR_SSWV,10,5,{A_Fall},S_SSWV_DIE4,0,0}, // S_SSWV_DIE3 {SPR_SSWV,11,5,{NULL},S_SSWV_DIE5,0,0}, // S_SSWV_DIE4 {SPR_SSWV,12,-1,{NULL},S_NULL,0,0}, // S_SSWV_DIE5 {SPR_SSWV,13,5,{NULL},S_SSWV_XDIE2,0,0}, // S_SSWV_XDIE1 {SPR_SSWV,14,5,{A_XScream},S_SSWV_XDIE3,0,0}, // S_SSWV_XDIE2 {SPR_SSWV,15,5,{A_Fall},S_SSWV_XDIE4,0,0}, // S_SSWV_XDIE3 {SPR_SSWV,16,5,{NULL},S_SSWV_XDIE5,0,0}, // S_SSWV_XDIE4 {SPR_SSWV,17,5,{NULL},S_SSWV_XDIE6,0,0}, // S_SSWV_XDIE5 {SPR_SSWV,18,5,{NULL},S_SSWV_XDIE7,0,0}, // S_SSWV_XDIE6 {SPR_SSWV,19,5,{NULL},S_SSWV_XDIE8,0,0}, // S_SSWV_XDIE7 {SPR_SSWV,20,5,{NULL},S_SSWV_XDIE9,0,0}, // S_SSWV_XDIE8 {SPR_SSWV,21,-1,{NULL},S_NULL,0,0}, // S_SSWV_XDIE9 {SPR_SSWV,12,5,{NULL},S_SSWV_RAISE2,0,0}, // S_SSWV_RAISE1 {SPR_SSWV,11,5,{NULL},S_SSWV_RAISE3,0,0}, // S_SSWV_RAISE2 {SPR_SSWV,10,5,{NULL},S_SSWV_RAISE4,0,0}, // S_SSWV_RAISE3 {SPR_SSWV,9,5,{NULL},S_SSWV_RAISE5,0,0}, // S_SSWV_RAISE4 {SPR_SSWV,8,5,{NULL},S_SSWV_RUN1,0,0}, // S_SSWV_RAISE5 {SPR_KEEN,0,-1,{NULL},S_KEENSTND,0,0}, // S_KEENSTND {SPR_KEEN,0,6,{NULL},S_COMMKEEN2,0,0}, // S_COMMKEEN {SPR_KEEN,1,6,{NULL},S_COMMKEEN3,0,0}, // S_COMMKEEN2 {SPR_KEEN,2,6,{A_Scream},S_COMMKEEN4,0,0}, // S_COMMKEEN3 {SPR_KEEN,3,6,{NULL},S_COMMKEEN5,0,0}, // S_COMMKEEN4 {SPR_KEEN,4,6,{NULL},S_COMMKEEN6,0,0}, // S_COMMKEEN5 {SPR_KEEN,5,6,{NULL},S_COMMKEEN7,0,0}, // S_COMMKEEN6 {SPR_KEEN,6,6,{NULL},S_COMMKEEN8,0,0}, // S_COMMKEEN7 {SPR_KEEN,7,6,{NULL},S_COMMKEEN9,0,0}, // S_COMMKEEN8 {SPR_KEEN,8,6,{NULL},S_COMMKEEN10,0,0}, // S_COMMKEEN9 {SPR_KEEN,9,6,{NULL},S_COMMKEEN11,0,0}, // S_COMMKEEN10 {SPR_KEEN,10,6,{A_KeenDie},S_COMMKEEN12,0,0},// S_COMMKEEN11 {SPR_KEEN,11,-1,{NULL},S_NULL,0,0}, // S_COMMKEEN12 {SPR_KEEN,12,4,{NULL},S_KEENPAIN2,0,0}, // S_KEENPAIN {SPR_KEEN,12,8,{A_Pain},S_KEENSTND,0,0}, // S_KEENPAIN2 {SPR_BBRN,0,-1,{NULL},S_NULL,0,0}, // S_BRAIN {SPR_BBRN,1,36,{A_BrainPain},S_BRAIN,0,0}, // S_BRAIN_PAIN {SPR_BBRN,0,100,{A_BrainScream},S_BRAIN_DIE2,0,0}, // S_BRAIN_DIE1 {SPR_BBRN,0,10,{NULL},S_BRAIN_DIE3,0,0}, // S_BRAIN_DIE2 {SPR_BBRN,0,10,{NULL},S_BRAIN_DIE4,0,0}, // S_BRAIN_DIE3 {SPR_BBRN,0,-1,{A_BrainDie},S_NULL,0,0}, // S_BRAIN_DIE4 {SPR_SSWV,0,10,{A_Look},S_BRAINEYE,0,0}, // S_BRAINEYE {SPR_SSWV,0,181,{A_BrainAwake},S_BRAINEYE1,0,0}, // S_BRAINEYESEE {SPR_SSWV,0,150,{A_BrainSpit},S_BRAINEYE1,0,0}, // S_BRAINEYE1 {SPR_BOSF,32768,3,{A_SpawnSound},S_SPAWN2,0,0}, // S_SPAWN1 {SPR_BOSF,32769,3,{A_SpawnFly},S_SPAWN3,0,0}, // S_SPAWN2 {SPR_BOSF,32770,3,{A_SpawnFly},S_SPAWN4,0,0}, // S_SPAWN3 {SPR_BOSF,32771,3,{A_SpawnFly},S_SPAWN1,0,0}, // S_SPAWN4 {SPR_FIRE,32768,4,{A_Fire},S_SPAWNFIRE2,0,0}, // S_SPAWNFIRE1 {SPR_FIRE,32769,4,{A_Fire},S_SPAWNFIRE3,0,0}, // S_SPAWNFIRE2 {SPR_FIRE,32770,4,{A_Fire},S_SPAWNFIRE4,0,0}, // S_SPAWNFIRE3 {SPR_FIRE,32771,4,{A_Fire},S_SPAWNFIRE5,0,0}, // S_SPAWNFIRE4 {SPR_FIRE,32772,4,{A_Fire},S_SPAWNFIRE6,0,0}, // S_SPAWNFIRE5 {SPR_FIRE,32773,4,{A_Fire},S_SPAWNFIRE7,0,0}, // S_SPAWNFIRE6 {SPR_FIRE,32774,4,{A_Fire},S_SPAWNFIRE8,0,0}, // S_SPAWNFIRE7 {SPR_FIRE,32775,4,{A_Fire},S_NULL,0,0}, // S_SPAWNFIRE8 {SPR_MISL,32769,10,{NULL},S_BRAINEXPLODE2,0,0}, // S_BRAINEXPLODE1 {SPR_MISL,32770,10,{NULL},S_BRAINEXPLODE3,0,0}, // S_BRAINEXPLODE2 {SPR_MISL,32771,10,{A_BrainExplode},S_NULL,0,0}, // S_BRAINEXPLODE3 {SPR_ARM1,0,6,{NULL},S_ARM1A,0,0}, // S_ARM1 {SPR_ARM1,32769,7,{NULL},S_ARM1,0,0}, // S_ARM1A {SPR_ARM2,0,6,{NULL},S_ARM2A,0,0}, // S_ARM2 {SPR_ARM2,32769,6,{NULL},S_ARM2,0,0}, // S_ARM2A {SPR_BAR1,0,6,{NULL},S_BAR2,0,0}, // S_BAR1 {SPR_BAR1,1,6,{NULL},S_BAR1,0,0}, // S_BAR2 {SPR_BEXP,32768,5,{NULL},S_BEXP2,0,0}, // S_BEXP {SPR_BEXP,32769,5,{A_Scream},S_BEXP3,0,0}, // S_BEXP2 {SPR_BEXP,32770,5,{NULL},S_BEXP4,0,0}, // S_BEXP3 {SPR_BEXP,32771,10,{A_Explode},S_BEXP5,0,0}, // S_BEXP4 {SPR_BEXP,32772,10,{NULL},S_NULL,0,0}, // S_BEXP5 {SPR_FCAN,32768,4,{NULL},S_BBAR2,0,0}, // S_BBAR1 {SPR_FCAN,32769,4,{NULL},S_BBAR3,0,0}, // S_BBAR2 {SPR_FCAN,32770,4,{NULL},S_BBAR1,0,0}, // S_BBAR3 {SPR_BON1,0,6,{NULL},S_BON1A,0,0}, // S_BON1 {SPR_BON1,1,6,{NULL},S_BON1B,0,0}, // S_BON1A {SPR_BON1,2,6,{NULL},S_BON1C,0,0}, // S_BON1B {SPR_BON1,3,6,{NULL},S_BON1D,0,0}, // S_BON1C {SPR_BON1,2,6,{NULL},S_BON1E,0,0}, // S_BON1D {SPR_BON1,1,6,{NULL},S_BON1,0,0}, // S_BON1E {SPR_BON2,0,6,{NULL},S_BON2A,0,0}, // S_BON2 {SPR_BON2,1,6,{NULL},S_BON2B,0,0}, // S_BON2A {SPR_BON2,2,6,{NULL},S_BON2C,0,0}, // S_BON2B {SPR_BON2,3,6,{NULL},S_BON2D,0,0}, // S_BON2C {SPR_BON2,2,6,{NULL},S_BON2E,0,0}, // S_BON2D {SPR_BON2,1,6,{NULL},S_BON2,0,0}, // S_BON2E {SPR_BKEY,0,10,{NULL},S_BKEY2,0,0}, // S_BKEY {SPR_BKEY,32769,10,{NULL},S_BKEY,0,0}, // S_BKEY2 {SPR_RKEY,0,10,{NULL},S_RKEY2,0,0}, // S_RKEY {SPR_RKEY,32769,10,{NULL},S_RKEY,0,0}, // S_RKEY2 {SPR_YKEY,0,10,{NULL},S_YKEY2,0,0}, // S_YKEY {SPR_YKEY,32769,10,{NULL},S_YKEY,0,0}, // S_YKEY2 {SPR_BSKU,0,10,{NULL},S_BSKULL2,0,0}, // S_BSKULL {SPR_BSKU,32769,10,{NULL},S_BSKULL,0,0}, // S_BSKULL2 {SPR_RSKU,0,10,{NULL},S_RSKULL2,0,0}, // S_RSKULL {SPR_RSKU,32769,10,{NULL},S_RSKULL,0,0}, // S_RSKULL2 {SPR_YSKU,0,10,{NULL},S_YSKULL2,0,0}, // S_YSKULL {SPR_YSKU,32769,10,{NULL},S_YSKULL,0,0}, // S_YSKULL2 {SPR_STIM,0,-1,{NULL},S_NULL,0,0}, // S_STIM {SPR_MEDI,0,-1,{NULL},S_NULL,0,0}, // S_MEDI {SPR_SOUL,32768,6,{NULL},S_SOUL2,0,0}, // S_SOUL {SPR_SOUL,32769,6,{NULL},S_SOUL3,0,0}, // S_SOUL2 {SPR_SOUL,32770,6,{NULL},S_SOUL4,0,0}, // S_SOUL3 {SPR_SOUL,32771,6,{NULL},S_SOUL5,0,0}, // S_SOUL4 {SPR_SOUL,32770,6,{NULL},S_SOUL6,0,0}, // S_SOUL5 {SPR_SOUL,32769,6,{NULL},S_SOUL,0,0}, // S_SOUL6 {SPR_PINV,32768,6,{NULL},S_PINV2,0,0}, // S_PINV {SPR_PINV,32769,6,{NULL},S_PINV3,0,0}, // S_PINV2 {SPR_PINV,32770,6,{NULL},S_PINV4,0,0}, // S_PINV3 {SPR_PINV,32771,6,{NULL},S_PINV,0,0}, // S_PINV4 {SPR_PSTR,32768,-1,{NULL},S_NULL,0,0}, // S_PSTR {SPR_PINS,32768,6,{NULL},S_PINS2,0,0}, // S_PINS {SPR_PINS,32769,6,{NULL},S_PINS3,0,0}, // S_PINS2 {SPR_PINS,32770,6,{NULL},S_PINS4,0,0}, // S_PINS3 {SPR_PINS,32771,6,{NULL},S_PINS,0,0}, // S_PINS4 {SPR_MEGA,32768,6,{NULL},S_MEGA2,0,0}, // S_MEGA {SPR_MEGA,32769,6,{NULL},S_MEGA3,0,0}, // S_MEGA2 {SPR_MEGA,32770,6,{NULL},S_MEGA4,0,0}, // S_MEGA3 {SPR_MEGA,32771,6,{NULL},S_MEGA,0,0}, // S_MEGA4 {SPR_SUIT,32768,-1,{NULL},S_NULL,0,0}, // S_SUIT {SPR_PMAP,32768,6,{NULL},S_PMAP2,0,0}, // S_PMAP {SPR_PMAP,32769,6,{NULL},S_PMAP3,0,0}, // S_PMAP2 {SPR_PMAP,32770,6,{NULL},S_PMAP4,0,0}, // S_PMAP3 {SPR_PMAP,32771,6,{NULL},S_PMAP5,0,0}, // S_PMAP4 {SPR_PMAP,32770,6,{NULL},S_PMAP6,0,0}, // S_PMAP5 {SPR_PMAP,32769,6,{NULL},S_PMAP,0,0}, // S_PMAP6 {SPR_PVIS,32768,6,{NULL},S_PVIS2,0,0}, // S_PVIS {SPR_PVIS,1,6,{NULL},S_PVIS,0,0}, // S_PVIS2 {SPR_CLIP,0,-1,{NULL},S_NULL,0,0}, // S_CLIP {SPR_AMMO,0,-1,{NULL},S_NULL,0,0}, // S_AMMO {SPR_ROCK,0,-1,{NULL},S_NULL,0,0}, // S_ROCK {SPR_BROK,0,-1,{NULL},S_NULL,0,0}, // S_BROK {SPR_CELL,0,-1,{NULL},S_NULL,0,0}, // S_CELL {SPR_CELP,0,-1,{NULL},S_NULL,0,0}, // S_CELP {SPR_SHEL,0,-1,{NULL},S_NULL,0,0}, // S_SHEL {SPR_SBOX,0,-1,{NULL},S_NULL,0,0}, // S_SBOX {SPR_BPAK,0,-1,{NULL},S_NULL,0,0}, // S_BPAK {SPR_BFUG,0,-1,{NULL},S_NULL,0,0}, // S_BFUG {SPR_MGUN,0,-1,{NULL},S_NULL,0,0}, // S_MGUN {SPR_CSAW,0,-1,{NULL},S_NULL,0,0}, // S_CSAW {SPR_LAUN,0,-1,{NULL},S_NULL,0,0}, // S_LAUN {SPR_PLAS,0,-1,{NULL},S_NULL,0,0}, // S_PLAS {SPR_SHOT,0,-1,{NULL},S_NULL,0,0}, // S_SHOT {SPR_SGN2,0,-1,{NULL},S_NULL,0,0}, // S_SHOT2 {SPR_COLU,32768,-1,{NULL},S_NULL,0,0}, // S_COLU {SPR_SMT2,0,-1,{NULL},S_NULL,0,0}, // S_STALAG {SPR_GOR1,0,10,{NULL},S_BLOODYTWITCH2,0,0}, // S_BLOODYTWITCH {SPR_GOR1,1,15,{NULL},S_BLOODYTWITCH3,0,0}, // S_BLOODYTWITCH2 {SPR_GOR1,2,8,{NULL},S_BLOODYTWITCH4,0,0}, // S_BLOODYTWITCH3 {SPR_GOR1,1,6,{NULL},S_BLOODYTWITCH,0,0}, // S_BLOODYTWITCH4 {SPR_PLAY,13,-1,{NULL},S_NULL,0,0}, // S_DEADTORSO {SPR_PLAY,18,-1,{NULL},S_NULL,0,0}, // S_DEADBOTTOM {SPR_POL2,0,-1,{NULL},S_NULL,0,0}, // S_HEADSONSTICK {SPR_POL5,0,-1,{NULL},S_NULL,0,0}, // S_GIBS {SPR_POL4,0,-1,{NULL},S_NULL,0,0}, // S_HEADONASTICK {SPR_POL3,32768,6,{NULL},S_HEADCANDLES2,0,0}, // S_HEADCANDLES {SPR_POL3,32769,6,{NULL},S_HEADCANDLES,0,0}, // S_HEADCANDLES2 {SPR_POL1,0,-1,{NULL},S_NULL,0,0}, // S_DEADSTICK {SPR_POL6,0,6,{NULL},S_LIVESTICK2,0,0}, // S_LIVESTICK {SPR_POL6,1,8,{NULL},S_LIVESTICK,0,0}, // S_LIVESTICK2 {SPR_GOR2,0,-1,{NULL},S_NULL,0,0}, // S_MEAT2 {SPR_GOR3,0,-1,{NULL},S_NULL,0,0}, // S_MEAT3 {SPR_GOR4,0,-1,{NULL},S_NULL,0,0}, // S_MEAT4 {SPR_GOR5,0,-1,{NULL},S_NULL,0,0}, // S_MEAT5 {SPR_SMIT,0,-1,{NULL},S_NULL,0,0}, // S_STALAGTITE {SPR_COL1,0,-1,{NULL},S_NULL,0,0}, // S_TALLGRNCOL {SPR_COL2,0,-1,{NULL},S_NULL,0,0}, // S_SHRTGRNCOL {SPR_COL3,0,-1,{NULL},S_NULL,0,0}, // S_TALLREDCOL {SPR_COL4,0,-1,{NULL},S_NULL,0,0}, // S_SHRTREDCOL {SPR_CAND,32768,-1,{NULL},S_NULL,0,0}, // S_CANDLESTIK {SPR_CBRA,32768,-1,{NULL},S_NULL,0,0}, // S_CANDELABRA {SPR_COL6,0,-1,{NULL},S_NULL,0,0}, // S_SKULLCOL {SPR_TRE1,0,-1,{NULL},S_NULL,0,0}, // S_TORCHTREE {SPR_TRE2,0,-1,{NULL},S_NULL,0,0}, // S_BIGTREE {SPR_ELEC,0,-1,{NULL},S_NULL,0,0}, // S_TECHPILLAR {SPR_CEYE,32768,6,{NULL},S_EVILEYE2,0,0}, // S_EVILEYE {SPR_CEYE,32769,6,{NULL},S_EVILEYE3,0,0}, // S_EVILEYE2 {SPR_CEYE,32770,6,{NULL},S_EVILEYE4,0,0}, // S_EVILEYE3 {SPR_CEYE,32769,6,{NULL},S_EVILEYE,0,0}, // S_EVILEYE4 {SPR_FSKU,32768,6,{NULL},S_FLOATSKULL2,0,0}, // S_FLOATSKULL {SPR_FSKU,32769,6,{NULL},S_FLOATSKULL3,0,0}, // S_FLOATSKULL2 {SPR_FSKU,32770,6,{NULL},S_FLOATSKULL,0,0}, // S_FLOATSKULL3 {SPR_COL5,0,14,{NULL},S_HEARTCOL2,0,0}, // S_HEARTCOL {SPR_COL5,1,14,{NULL},S_HEARTCOL,0,0}, // S_HEARTCOL2 {SPR_TBLU,32768,4,{NULL},S_BLUETORCH2,0,0}, // S_BLUETORCH {SPR_TBLU,32769,4,{NULL},S_BLUETORCH3,0,0}, // S_BLUETORCH2 {SPR_TBLU,32770,4,{NULL},S_BLUETORCH4,0,0}, // S_BLUETORCH3 {SPR_TBLU,32771,4,{NULL},S_BLUETORCH,0,0}, // S_BLUETORCH4 {SPR_TGRN,32768,4,{NULL},S_GREENTORCH2,0,0}, // S_GREENTORCH {SPR_TGRN,32769,4,{NULL},S_GREENTORCH3,0,0}, // S_GREENTORCH2 {SPR_TGRN,32770,4,{NULL},S_GREENTORCH4,0,0}, // S_GREENTORCH3 {SPR_TGRN,32771,4,{NULL},S_GREENTORCH,0,0}, // S_GREENTORCH4 {SPR_TRED,32768,4,{NULL},S_REDTORCH2,0,0}, // S_REDTORCH {SPR_TRED,32769,4,{NULL},S_REDTORCH3,0,0}, // S_REDTORCH2 {SPR_TRED,32770,4,{NULL},S_REDTORCH4,0,0}, // S_REDTORCH3 {SPR_TRED,32771,4,{NULL},S_REDTORCH,0,0}, // S_REDTORCH4 {SPR_SMBT,32768,4,{NULL},S_BTORCHSHRT2,0,0}, // S_BTORCHSHRT {SPR_SMBT,32769,4,{NULL},S_BTORCHSHRT3,0,0}, // S_BTORCHSHRT2 {SPR_SMBT,32770,4,{NULL},S_BTORCHSHRT4,0,0}, // S_BTORCHSHRT3 {SPR_SMBT,32771,4,{NULL},S_BTORCHSHRT,0,0}, // S_BTORCHSHRT4 {SPR_SMGT,32768,4,{NULL},S_GTORCHSHRT2,0,0}, // S_GTORCHSHRT {SPR_SMGT,32769,4,{NULL},S_GTORCHSHRT3,0,0}, // S_GTORCHSHRT2 {SPR_SMGT,32770,4,{NULL},S_GTORCHSHRT4,0,0}, // S_GTORCHSHRT3 {SPR_SMGT,32771,4,{NULL},S_GTORCHSHRT,0,0}, // S_GTORCHSHRT4 {SPR_SMRT,32768,4,{NULL},S_RTORCHSHRT2,0,0}, // S_RTORCHSHRT {SPR_SMRT,32769,4,{NULL},S_RTORCHSHRT3,0,0}, // S_RTORCHSHRT2 {SPR_SMRT,32770,4,{NULL},S_RTORCHSHRT4,0,0}, // S_RTORCHSHRT3 {SPR_SMRT,32771,4,{NULL},S_RTORCHSHRT,0,0}, // S_RTORCHSHRT4 {SPR_HDB1,0,-1,{NULL},S_NULL,0,0}, // S_HANGNOGUTS {SPR_HDB2,0,-1,{NULL},S_NULL,0,0}, // S_HANGBNOBRAIN {SPR_HDB3,0,-1,{NULL},S_NULL,0,0}, // S_HANGTLOOKDN {SPR_HDB4,0,-1,{NULL},S_NULL,0,0}, // S_HANGTSKULL {SPR_HDB5,0,-1,{NULL},S_NULL,0,0}, // S_HANGTLOOKUP {SPR_HDB6,0,-1,{NULL},S_NULL,0,0}, // S_HANGTNOBRAIN {SPR_POB1,0,-1,{NULL},S_NULL,0,0}, // S_COLONGIBS {SPR_POB2,0,-1,{NULL},S_NULL,0,0}, // S_SMALLPOOL {SPR_BRS1,0,-1,{NULL},S_NULL,0,0}, // S_BRAINSTEM {SPR_TLMP,32768,4,{NULL},S_TECHLAMP2,0,0}, // S_TECHLAMP {SPR_TLMP,32769,4,{NULL},S_TECHLAMP3,0,0}, // S_TECHLAMP2 {SPR_TLMP,32770,4,{NULL},S_TECHLAMP4,0,0}, // S_TECHLAMP3 {SPR_TLMP,32771,4,{NULL},S_TECHLAMP,0,0}, // S_TECHLAMP4 {SPR_TLP2,32768,4,{NULL},S_TECH2LAMP2,0,0}, // S_TECH2LAMP {SPR_TLP2,32769,4,{NULL},S_TECH2LAMP3,0,0}, // S_TECH2LAMP2 {SPR_TLP2,32770,4,{NULL},S_TECH2LAMP4,0,0}, // S_TECH2LAMP3 {SPR_TLP2,32771,4,{NULL},S_TECH2LAMP,0,0} // S_TECH2LAMP4 }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = { { // MT_PLAYER -1, // doomednum S_PLAY, // spawnstate 100, // spawnhealth S_PLAY_RUN1, // seestate sfx_None, // seesound 0, // reactiontime sfx_None, // attacksound S_PLAY_PAIN, // painstate 255, // painchance sfx_plpain, // painsound S_NULL, // meleestate S_PLAY_ATK1, // missilestate S_PLAY_DIE1, // deathstate S_PLAY_XDIE1, // xdeathstate sfx_pldeth, // deathsound 0, // speed 16*FRACUNIT, // radius 56*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags S_NULL // raisestate }, { // MT_POSSESSED 3004, // doomednum S_POSS_STND, // spawnstate 20, // spawnhealth S_POSS_RUN1, // seestate sfx_posit1, // seesound 8, // reactiontime sfx_pistol, // attacksound S_POSS_PAIN, // painstate 200, // painchance sfx_popain, // painsound 0, // meleestate S_POSS_ATK1, // missilestate S_POSS_DIE1, // deathstate S_POSS_XDIE1, // xdeathstate sfx_podth1, // deathsound 8, // speed 20*FRACUNIT, // radius 56*FRACUNIT, // height 100, // mass 0, // damage sfx_posact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_POSS_RAISE1 // raisestate }, { // MT_SHOTGUY 9, // doomednum S_SPOS_STND, // spawnstate 30, // spawnhealth S_SPOS_RUN1, // seestate sfx_posit2, // seesound 8, // reactiontime 0, // attacksound S_SPOS_PAIN, // painstate 170, // painchance sfx_popain, // painsound 0, // meleestate S_SPOS_ATK1, // missilestate S_SPOS_DIE1, // deathstate S_SPOS_XDIE1, // xdeathstate sfx_podth2, // deathsound 8, // speed 20*FRACUNIT, // radius 56*FRACUNIT, // height 100, // mass 0, // damage sfx_posact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_SPOS_RAISE1 // raisestate }, { // MT_VILE 64, // doomednum S_VILE_STND, // spawnstate 700, // spawnhealth S_VILE_RUN1, // seestate sfx_vilsit, // seesound 8, // reactiontime 0, // attacksound S_VILE_PAIN, // painstate 10, // painchance sfx_vipain, // painsound 0, // meleestate S_VILE_ATK1, // missilestate S_VILE_DIE1, // deathstate S_NULL, // xdeathstate sfx_vildth, // deathsound 15, // speed 20*FRACUNIT, // radius 56*FRACUNIT, // height 500, // mass 0, // damage sfx_vilact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_NULL // raisestate }, { // MT_FIRE -1, // doomednum S_FIRE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_UNDEAD 66, // doomednum S_SKEL_STND, // spawnstate 300, // spawnhealth S_SKEL_RUN1, // seestate sfx_skesit, // seesound 8, // reactiontime 0, // attacksound S_SKEL_PAIN, // painstate 100, // painchance sfx_popain, // painsound S_SKEL_FIST1, // meleestate S_SKEL_MISS1, // missilestate S_SKEL_DIE1, // deathstate S_NULL, // xdeathstate sfx_skedth, // deathsound 10, // speed 20*FRACUNIT, // radius 56*FRACUNIT, // height 500, // mass 0, // damage sfx_skeact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_SKEL_RAISE1 // raisestate }, { // MT_TRACER -1, // doomednum S_TRACER, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_skeatk, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_TRACEEXP1, // deathstate S_NULL, // xdeathstate sfx_barexp, // deathsound 10*FRACUNIT, // speed 11*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 10, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_SMOKE -1, // doomednum S_SMOKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_FATSO 67, // doomednum S_FATT_STND, // spawnstate 600, // spawnhealth S_FATT_RUN1, // seestate sfx_mansit, // seesound 8, // reactiontime 0, // attacksound S_FATT_PAIN, // painstate 80, // painchance sfx_mnpain, // painsound 0, // meleestate S_FATT_ATK1, // missilestate S_FATT_DIE1, // deathstate S_NULL, // xdeathstate sfx_mandth, // deathsound 8, // speed 48*FRACUNIT, // radius 64*FRACUNIT, // height 1000, // mass 0, // damage sfx_posact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_FATT_RAISE1 // raisestate }, { // MT_FATSHOT -1, // doomednum S_FATSHOT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_firsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_FATSHOTX1, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 20*FRACUNIT, // speed 6*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 8, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_CHAINGUY 65, // doomednum S_CPOS_STND, // spawnstate 70, // spawnhealth S_CPOS_RUN1, // seestate sfx_posit2, // seesound 8, // reactiontime 0, // attacksound S_CPOS_PAIN, // painstate 170, // painchance sfx_popain, // painsound 0, // meleestate S_CPOS_ATK1, // missilestate S_CPOS_DIE1, // deathstate S_CPOS_XDIE1, // xdeathstate sfx_podth2, // deathsound 8, // speed 20*FRACUNIT, // radius 56*FRACUNIT, // height 100, // mass 0, // damage sfx_posact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_CPOS_RAISE1 // raisestate }, { // MT_TROOP 3001, // doomednum S_TROO_STND, // spawnstate 60, // spawnhealth S_TROO_RUN1, // seestate sfx_bgsit1, // seesound 8, // reactiontime 0, // attacksound S_TROO_PAIN, // painstate 200, // painchance sfx_popain, // painsound S_TROO_ATK1, // meleestate S_TROO_ATK1, // missilestate S_TROO_DIE1, // deathstate S_TROO_XDIE1, // xdeathstate sfx_bgdth1, // deathsound 8, // speed 20*FRACUNIT, // radius 56*FRACUNIT, // height 100, // mass 0, // damage sfx_bgact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_TROO_RAISE1 // raisestate }, { // MT_SERGEANT 3002, // doomednum S_SARG_STND, // spawnstate 150, // spawnhealth S_SARG_RUN1, // seestate sfx_sgtsit, // seesound 8, // reactiontime sfx_sgtatk, // attacksound S_SARG_PAIN, // painstate 180, // painchance sfx_dmpain, // painsound S_SARG_ATK1, // meleestate 0, // missilestate S_SARG_DIE1, // deathstate S_NULL, // xdeathstate sfx_sgtdth, // deathsound 10, // speed 30*FRACUNIT, // radius 56*FRACUNIT, // height 400, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_SARG_RAISE1 // raisestate }, { // MT_SHADOWS 58, // doomednum S_SARG_STND, // spawnstate 150, // spawnhealth S_SARG_RUN1, // seestate sfx_sgtsit, // seesound 8, // reactiontime sfx_sgtatk, // attacksound S_SARG_PAIN, // painstate 180, // painchance sfx_dmpain, // painsound S_SARG_ATK1, // meleestate 0, // missilestate S_SARG_DIE1, // deathstate S_NULL, // xdeathstate sfx_sgtdth, // deathsound 10, // speed 30*FRACUNIT, // radius 56*FRACUNIT, // height 400, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_SHADOW|MF_COUNTKILL, // flags S_SARG_RAISE1 // raisestate }, { // MT_HEAD 3005, // doomednum S_HEAD_STND, // spawnstate 400, // spawnhealth S_HEAD_RUN1, // seestate sfx_cacsit, // seesound 8, // reactiontime 0, // attacksound S_HEAD_PAIN, // painstate 128, // painchance sfx_dmpain, // painsound 0, // meleestate S_HEAD_ATK1, // missilestate S_HEAD_DIE1, // deathstate S_NULL, // xdeathstate sfx_cacdth, // deathsound 8, // speed 31*FRACUNIT, // radius 56*FRACUNIT, // height 400, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags S_HEAD_RAISE1 // raisestate }, { // MT_BRUISER 3003, // doomednum S_BOSS_STND, // spawnstate 1000, // spawnhealth S_BOSS_RUN1, // seestate sfx_brssit, // seesound 8, // reactiontime 0, // attacksound S_BOSS_PAIN, // painstate 50, // painchance sfx_dmpain, // painsound S_BOSS_ATK1, // meleestate S_BOSS_ATK1, // missilestate S_BOSS_DIE1, // deathstate S_NULL, // xdeathstate sfx_brsdth, // deathsound 8, // speed 24*FRACUNIT, // radius 64*FRACUNIT, // height 1000, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_BOSS_RAISE1 // raisestate }, { // MT_BRUISERSHOT -1, // doomednum S_BRBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_firsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_BRBALLX1, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 15*FRACUNIT, // speed 6*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 8, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_KNIGHT 69, // doomednum S_BOS2_STND, // spawnstate 500, // spawnhealth S_BOS2_RUN1, // seestate sfx_kntsit, // seesound 8, // reactiontime 0, // attacksound S_BOS2_PAIN, // painstate 50, // painchance sfx_dmpain, // painsound S_BOS2_ATK1, // meleestate S_BOS2_ATK1, // missilestate S_BOS2_DIE1, // deathstate S_NULL, // xdeathstate sfx_kntdth, // deathsound 8, // speed 24*FRACUNIT, // radius 64*FRACUNIT, // height 1000, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_BOS2_RAISE1 // raisestate }, { // MT_SKULL 3006, // doomednum S_SKULL_STND, // spawnstate 100, // spawnhealth S_SKULL_RUN1, // seestate 0, // seesound 8, // reactiontime sfx_sklatk, // attacksound S_SKULL_PAIN, // painstate 256, // painchance sfx_dmpain, // painsound 0, // meleestate S_SKULL_ATK1, // missilestate S_SKULL_DIE1, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 8, // speed 16*FRACUNIT, // radius 56*FRACUNIT, // height 50, // mass 3, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_SPIDER 7, // doomednum S_SPID_STND, // spawnstate 3000, // spawnhealth S_SPID_RUN1, // seestate sfx_spisit, // seesound 8, // reactiontime sfx_shotgn, // attacksound S_SPID_PAIN, // painstate 40, // painchance sfx_dmpain, // painsound 0, // meleestate S_SPID_ATK1, // missilestate S_SPID_DIE1, // deathstate S_NULL, // xdeathstate sfx_spidth, // deathsound 12, // speed 128*FRACUNIT, // radius 100*FRACUNIT, // height 1000, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_NULL // raisestate }, { // MT_BABY 68, // doomednum S_BSPI_STND, // spawnstate 500, // spawnhealth S_BSPI_SIGHT, // seestate sfx_bspsit, // seesound 8, // reactiontime 0, // attacksound S_BSPI_PAIN, // painstate 128, // painchance sfx_dmpain, // painsound 0, // meleestate S_BSPI_ATK1, // missilestate S_BSPI_DIE1, // deathstate S_NULL, // xdeathstate sfx_bspdth, // deathsound 12, // speed 64*FRACUNIT, // radius 64*FRACUNIT, // height 600, // mass 0, // damage sfx_bspact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_BSPI_RAISE1 // raisestate }, { // MT_CYBORG 16, // doomednum S_CYBER_STND, // spawnstate 4000, // spawnhealth S_CYBER_RUN1, // seestate sfx_cybsit, // seesound 8, // reactiontime 0, // attacksound S_CYBER_PAIN, // painstate 20, // painchance sfx_dmpain, // painsound 0, // meleestate S_CYBER_ATK1, // missilestate S_CYBER_DIE1, // deathstate S_NULL, // xdeathstate sfx_cybdth, // deathsound 16, // speed 40*FRACUNIT, // radius 110*FRACUNIT, // height 1000, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_NULL // raisestate }, { // MT_PAIN 71, // doomednum S_PAIN_STND, // spawnstate 400, // spawnhealth S_PAIN_RUN1, // seestate sfx_pesit, // seesound 8, // reactiontime 0, // attacksound S_PAIN_PAIN, // painstate 128, // painchance sfx_pepain, // painsound 0, // meleestate S_PAIN_ATK1, // missilestate S_PAIN_DIE1, // deathstate S_NULL, // xdeathstate sfx_pedth, // deathsound 8, // speed 31*FRACUNIT, // radius 56*FRACUNIT, // height 400, // mass 0, // damage sfx_dmact, // activesound MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags S_PAIN_RAISE1 // raisestate }, { // MT_WOLFSS 84, // doomednum S_SSWV_STND, // spawnstate 50, // spawnhealth S_SSWV_RUN1, // seestate sfx_sssit, // seesound 8, // reactiontime 0, // attacksound S_SSWV_PAIN, // painstate 170, // painchance sfx_popain, // painsound 0, // meleestate S_SSWV_ATK1, // missilestate S_SSWV_DIE1, // deathstate S_SSWV_XDIE1, // xdeathstate sfx_ssdth, // deathsound 8, // speed 20*FRACUNIT, // radius 56*FRACUNIT, // height 100, // mass 0, // damage sfx_posact, // activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags S_SSWV_RAISE1 // raisestate }, { // MT_KEEN 72, // doomednum S_KEENSTND, // spawnstate 100, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_KEENPAIN, // painstate 256, // painchance sfx_keenpn, // painsound S_NULL, // meleestate S_NULL, // missilestate S_COMMKEEN, // deathstate S_NULL, // xdeathstate sfx_keendt, // deathsound 0, // speed 16*FRACUNIT, // radius 72*FRACUNIT, // height 10000000, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SHOOTABLE|MF_COUNTKILL, // flags S_NULL // raisestate }, { // MT_BOSSBRAIN 88, // doomednum S_BRAIN, // spawnstate 250, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_BRAIN_PAIN, // painstate 255, // painchance sfx_bospn, // painsound S_NULL, // meleestate S_NULL, // missilestate S_BRAIN_DIE1, // deathstate S_NULL, // xdeathstate sfx_bosdth, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 10000000, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SHOOTABLE, // flags S_NULL // raisestate }, { // MT_BOSSSPIT 89, // doomednum S_BRAINEYE, // spawnstate 1000, // spawnhealth S_BRAINEYESEE, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 32*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOSECTOR, // flags S_NULL // raisestate }, { // MT_BOSSTARGET 87, // doomednum S_NULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 32*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOSECTOR, // flags S_NULL // raisestate }, { // MT_SPAWNSHOT -1, // doomednum S_SPAWN1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_bospit, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 10*FRACUNIT, // speed 6*FRACUNIT, // radius 32*FRACUNIT, // height 100, // mass 3, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP, // flags S_NULL // raisestate }, { // MT_SPAWNFIRE -1, // doomednum S_SPAWNFIRE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_BARREL 2035, // doomednum S_BAR1, // spawnstate 20, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_BEXP, // deathstate S_NULL, // xdeathstate sfx_barexp, // deathsound 0, // speed 10*FRACUNIT, // radius 42*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags S_NULL // raisestate }, { // MT_TROOPSHOT -1, // doomednum S_TBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_firsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_TBALLX1, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 10*FRACUNIT, // speed 6*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 3, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_HEADSHOT -1, // doomednum S_RBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_firsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_RBALLX1, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 10*FRACUNIT, // speed 6*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_ROCKET -1, // doomednum S_ROCKET, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_rlaunc, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_EXPLODE1, // deathstate S_NULL, // xdeathstate sfx_barexp, // deathsound 20*FRACUNIT, // speed 11*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 20, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_PLASMA -1, // doomednum S_PLASBALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_plasma, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_PLASEXP, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 25*FRACUNIT, // speed 13*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_BFG -1, // doomednum S_BFGSHOT, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_BFGLAND, // deathstate S_NULL, // xdeathstate sfx_rxplod, // deathsound 25*FRACUNIT, // speed 13*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 100, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_ARACHPLAZ -1, // doomednum S_ARACH_PLAZ, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_plasma, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_ARACH_PLEX, // deathstate S_NULL, // xdeathstate sfx_firxpl, // deathsound 25*FRACUNIT, // speed 13*FRACUNIT, // radius 8*FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_PUFF -1, // doomednum S_PUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_BLOOD -1, // doomednum S_BLOOD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags S_NULL // raisestate }, { // MT_TFOG -1, // doomednum S_TFOG, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_IFOG -1, // doomednum S_IFOG, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_TELEPORTMAN 14, // doomednum S_NULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOSECTOR, // flags S_NULL // raisestate }, { // MT_EXTRABFG -1, // doomednum S_BFGEXP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC0 2018, // doomednum S_ARM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC1 2019, // doomednum S_ARM2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC2 2014, // doomednum S_BON1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_MISC3 2015, // doomednum S_BON2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_MISC4 5, // doomednum S_BKEY, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_NOTDMATCH, // flags S_NULL // raisestate }, { // MT_MISC5 13, // doomednum S_RKEY, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_NOTDMATCH, // flags S_NULL // raisestate }, { // MT_MISC6 6, // doomednum S_YKEY, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_NOTDMATCH, // flags S_NULL // raisestate }, { // MT_MISC7 39, // doomednum S_YSKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_NOTDMATCH, // flags S_NULL // raisestate }, { // MT_MISC8 38, // doomednum S_RSKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_NOTDMATCH, // flags S_NULL // raisestate }, { // MT_MISC9 40, // doomednum S_BSKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_NOTDMATCH, // flags S_NULL // raisestate }, { // MT_MISC10 2011, // doomednum S_STIM, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC11 2012, // doomednum S_MEDI, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC12 2013, // doomednum S_SOUL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_INV 2022, // doomednum S_PINV, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_MISC13 2023, // doomednum S_PSTR, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_INS 2024, // doomednum S_PINS, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_MISC14 2025, // doomednum S_SUIT, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC15 2026, // doomednum S_PMAP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_MISC16 2045, // doomednum S_PVIS, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_MEGA 83, // doomednum S_MEGA, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_COUNTITEM, // flags S_NULL // raisestate }, { // MT_CLIP 2007, // doomednum S_CLIP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC17 2048, // doomednum S_AMMO, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC18 2010, // doomednum S_ROCK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC19 2046, // doomednum S_BROK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC20 2047, // doomednum S_CELL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC21 17, // doomednum S_CELP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC22 2008, // doomednum S_SHEL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC23 2049, // doomednum S_SBOX, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC24 8, // doomednum S_BPAK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC25 2006, // doomednum S_BFUG, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_CHAINGUN 2002, // doomednum S_MGUN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC26 2005, // doomednum S_CSAW, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC27 2003, // doomednum S_LAUN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC28 2004, // doomednum S_PLAS, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_SHOTGUN 2001, // doomednum S_SHOT, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_SUPERSHOTGUN 82, // doomednum S_SHOT2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags S_NULL // raisestate }, { // MT_MISC29 85, // doomednum S_TECHLAMP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC30 86, // doomednum S_TECH2LAMP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC31 2028, // doomednum S_COLU, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC32 30, // doomednum S_TALLGRNCOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC33 31, // doomednum S_SHRTGRNCOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC34 32, // doomednum S_TALLREDCOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC35 33, // doomednum S_SHRTREDCOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC36 37, // doomednum S_SKULLCOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC37 36, // doomednum S_HEARTCOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC38 41, // doomednum S_EVILEYE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC39 42, // doomednum S_FLOATSKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC40 43, // doomednum S_TORCHTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC41 44, // doomednum S_BLUETORCH, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC42 45, // doomednum S_GREENTORCH, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC43 46, // doomednum S_REDTORCH, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC44 55, // doomednum S_BTORCHSHRT, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC45 56, // doomednum S_GTORCHSHRT, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC46 57, // doomednum S_RTORCHSHRT, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC47 47, // doomednum S_STALAGTITE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC48 48, // doomednum S_TECHPILLAR, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC49 34, // doomednum S_CANDLESTIK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC50 35, // doomednum S_CANDELABRA, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC51 49, // doomednum S_BLOODYTWITCH, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 68*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC52 50, // doomednum S_MEAT2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 84*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC53 51, // doomednum S_MEAT3, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 84*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC54 52, // doomednum S_MEAT4, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 68*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC55 53, // doomednum S_MEAT5, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 52*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC56 59, // doomednum S_MEAT2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 84*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC57 60, // doomednum S_MEAT4, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 68*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC58 61, // doomednum S_MEAT3, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 52*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC59 62, // doomednum S_MEAT5, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 52*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC60 63, // doomednum S_BLOODYTWITCH, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 68*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC61 22, // doomednum S_HEAD_DIE6, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC62 15, // doomednum S_PLAY_DIE7, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC63 18, // doomednum S_POSS_DIE5, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC64 21, // doomednum S_SARG_DIE6, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC65 23, // doomednum S_SKULL_DIE6, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC66 20, // doomednum S_TROO_DIE5, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC67 19, // doomednum S_SPOS_DIE5, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC68 10, // doomednum S_PLAY_XDIE9, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC69 12, // doomednum S_PLAY_XDIE9, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC70 28, // doomednum S_HEADSONSTICK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC71 24, // doomednum S_GIBS, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound 0, // flags S_NULL // raisestate }, { // MT_MISC72 27, // doomednum S_HEADONASTICK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC73 29, // doomednum S_HEADCANDLES, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC74 25, // doomednum S_DEADSTICK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC75 26, // doomednum S_LIVESTICK, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC76 54, // doomednum S_BIGTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 32*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC77 70, // doomednum S_BBAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags S_NULL // raisestate }, { // MT_MISC78 73, // doomednum S_HANGNOGUTS, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 88*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC79 74, // doomednum S_HANGBNOBRAIN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 88*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC80 75, // doomednum S_HANGTLOOKDN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 64*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC81 76, // doomednum S_HANGTSKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 64*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC82 77, // doomednum S_HANGTLOOKUP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 64*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC83 78, // doomednum S_HANGTNOBRAIN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius 64*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_MISC84 79, // doomednum S_COLONGIBS, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags S_NULL // raisestate }, { // MT_MISC85 80, // doomednum S_SMALLPOOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags S_NULL // raisestate }, { // MT_MISC86 81, // doomednum S_BRAINSTEM, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20*FRACUNIT, // radius 16*FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags S_NULL // raisestate } }; chocolate-doom-chocolate-doom-2.2.1/src/doom/info.h000066400000000000000000000523401257432200600221420ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Thing frame/state LUT, // generated by multigen utilitiy. // This one is the original DOOM version, preserved. // #ifndef __INFO__ #define __INFO__ // Needed for action function pointer handling. #include "d_think.h" typedef enum { SPR_TROO, SPR_SHTG, SPR_PUNG, SPR_PISG, SPR_PISF, SPR_SHTF, SPR_SHT2, SPR_CHGG, SPR_CHGF, SPR_MISG, SPR_MISF, SPR_SAWG, SPR_PLSG, SPR_PLSF, SPR_BFGG, SPR_BFGF, SPR_BLUD, SPR_PUFF, SPR_BAL1, SPR_BAL2, SPR_PLSS, SPR_PLSE, SPR_MISL, SPR_BFS1, SPR_BFE1, SPR_BFE2, SPR_TFOG, SPR_IFOG, SPR_PLAY, SPR_POSS, SPR_SPOS, SPR_VILE, SPR_FIRE, SPR_FATB, SPR_FBXP, SPR_SKEL, SPR_MANF, SPR_FATT, SPR_CPOS, SPR_SARG, SPR_HEAD, SPR_BAL7, SPR_BOSS, SPR_BOS2, SPR_SKUL, SPR_SPID, SPR_BSPI, SPR_APLS, SPR_APBX, SPR_CYBR, SPR_PAIN, SPR_SSWV, SPR_KEEN, SPR_BBRN, SPR_BOSF, SPR_ARM1, SPR_ARM2, SPR_BAR1, SPR_BEXP, SPR_FCAN, SPR_BON1, SPR_BON2, SPR_BKEY, SPR_RKEY, SPR_YKEY, SPR_BSKU, SPR_RSKU, SPR_YSKU, SPR_STIM, SPR_MEDI, SPR_SOUL, SPR_PINV, SPR_PSTR, SPR_PINS, SPR_MEGA, SPR_SUIT, SPR_PMAP, SPR_PVIS, SPR_CLIP, SPR_AMMO, SPR_ROCK, SPR_BROK, SPR_CELL, SPR_CELP, SPR_SHEL, SPR_SBOX, SPR_BPAK, SPR_BFUG, SPR_MGUN, SPR_CSAW, SPR_LAUN, SPR_PLAS, SPR_SHOT, SPR_SGN2, SPR_COLU, SPR_SMT2, SPR_GOR1, SPR_POL2, SPR_POL5, SPR_POL4, SPR_POL3, SPR_POL1, SPR_POL6, SPR_GOR2, SPR_GOR3, SPR_GOR4, SPR_GOR5, SPR_SMIT, SPR_COL1, SPR_COL2, SPR_COL3, SPR_COL4, SPR_CAND, SPR_CBRA, SPR_COL6, SPR_TRE1, SPR_TRE2, SPR_ELEC, SPR_CEYE, SPR_FSKU, SPR_COL5, SPR_TBLU, SPR_TGRN, SPR_TRED, SPR_SMBT, SPR_SMGT, SPR_SMRT, SPR_HDB1, SPR_HDB2, SPR_HDB3, SPR_HDB4, SPR_HDB5, SPR_HDB6, SPR_POB1, SPR_POB2, SPR_BRS1, SPR_TLMP, SPR_TLP2, NUMSPRITES } spritenum_t; typedef enum { S_NULL, S_LIGHTDONE, S_PUNCH, S_PUNCHDOWN, S_PUNCHUP, S_PUNCH1, S_PUNCH2, S_PUNCH3, S_PUNCH4, S_PUNCH5, S_PISTOL, S_PISTOLDOWN, S_PISTOLUP, S_PISTOL1, S_PISTOL2, S_PISTOL3, S_PISTOL4, S_PISTOLFLASH, S_SGUN, S_SGUNDOWN, S_SGUNUP, S_SGUN1, S_SGUN2, S_SGUN3, S_SGUN4, S_SGUN5, S_SGUN6, S_SGUN7, S_SGUN8, S_SGUN9, S_SGUNFLASH1, S_SGUNFLASH2, S_DSGUN, S_DSGUNDOWN, S_DSGUNUP, S_DSGUN1, S_DSGUN2, S_DSGUN3, S_DSGUN4, S_DSGUN5, S_DSGUN6, S_DSGUN7, S_DSGUN8, S_DSGUN9, S_DSGUN10, S_DSNR1, S_DSNR2, S_DSGUNFLASH1, S_DSGUNFLASH2, S_CHAIN, S_CHAINDOWN, S_CHAINUP, S_CHAIN1, S_CHAIN2, S_CHAIN3, S_CHAINFLASH1, S_CHAINFLASH2, S_MISSILE, S_MISSILEDOWN, S_MISSILEUP, S_MISSILE1, S_MISSILE2, S_MISSILE3, S_MISSILEFLASH1, S_MISSILEFLASH2, S_MISSILEFLASH3, S_MISSILEFLASH4, S_SAW, S_SAWB, S_SAWDOWN, S_SAWUP, S_SAW1, S_SAW2, S_SAW3, S_PLASMA, S_PLASMADOWN, S_PLASMAUP, S_PLASMA1, S_PLASMA2, S_PLASMAFLASH1, S_PLASMAFLASH2, S_BFG, S_BFGDOWN, S_BFGUP, S_BFG1, S_BFG2, S_BFG3, S_BFG4, S_BFGFLASH1, S_BFGFLASH2, S_BLOOD1, S_BLOOD2, S_BLOOD3, S_PUFF1, S_PUFF2, S_PUFF3, S_PUFF4, S_TBALL1, S_TBALL2, S_TBALLX1, S_TBALLX2, S_TBALLX3, S_RBALL1, S_RBALL2, S_RBALLX1, S_RBALLX2, S_RBALLX3, S_PLASBALL, S_PLASBALL2, S_PLASEXP, S_PLASEXP2, S_PLASEXP3, S_PLASEXP4, S_PLASEXP5, S_ROCKET, S_BFGSHOT, S_BFGSHOT2, S_BFGLAND, S_BFGLAND2, S_BFGLAND3, S_BFGLAND4, S_BFGLAND5, S_BFGLAND6, S_BFGEXP, S_BFGEXP2, S_BFGEXP3, S_BFGEXP4, S_EXPLODE1, S_EXPLODE2, S_EXPLODE3, S_TFOG, S_TFOG01, S_TFOG02, S_TFOG2, S_TFOG3, S_TFOG4, S_TFOG5, S_TFOG6, S_TFOG7, S_TFOG8, S_TFOG9, S_TFOG10, S_IFOG, S_IFOG01, S_IFOG02, S_IFOG2, S_IFOG3, S_IFOG4, S_IFOG5, S_PLAY, S_PLAY_RUN1, S_PLAY_RUN2, S_PLAY_RUN3, S_PLAY_RUN4, S_PLAY_ATK1, S_PLAY_ATK2, S_PLAY_PAIN, S_PLAY_PAIN2, S_PLAY_DIE1, S_PLAY_DIE2, S_PLAY_DIE3, S_PLAY_DIE4, S_PLAY_DIE5, S_PLAY_DIE6, S_PLAY_DIE7, S_PLAY_XDIE1, S_PLAY_XDIE2, S_PLAY_XDIE3, S_PLAY_XDIE4, S_PLAY_XDIE5, S_PLAY_XDIE6, S_PLAY_XDIE7, S_PLAY_XDIE8, S_PLAY_XDIE9, S_POSS_STND, S_POSS_STND2, S_POSS_RUN1, S_POSS_RUN2, S_POSS_RUN3, S_POSS_RUN4, S_POSS_RUN5, S_POSS_RUN6, S_POSS_RUN7, S_POSS_RUN8, S_POSS_ATK1, S_POSS_ATK2, S_POSS_ATK3, S_POSS_PAIN, S_POSS_PAIN2, S_POSS_DIE1, S_POSS_DIE2, S_POSS_DIE3, S_POSS_DIE4, S_POSS_DIE5, S_POSS_XDIE1, S_POSS_XDIE2, S_POSS_XDIE3, S_POSS_XDIE4, S_POSS_XDIE5, S_POSS_XDIE6, S_POSS_XDIE7, S_POSS_XDIE8, S_POSS_XDIE9, S_POSS_RAISE1, S_POSS_RAISE2, S_POSS_RAISE3, S_POSS_RAISE4, S_SPOS_STND, S_SPOS_STND2, S_SPOS_RUN1, S_SPOS_RUN2, S_SPOS_RUN3, S_SPOS_RUN4, S_SPOS_RUN5, S_SPOS_RUN6, S_SPOS_RUN7, S_SPOS_RUN8, S_SPOS_ATK1, S_SPOS_ATK2, S_SPOS_ATK3, S_SPOS_PAIN, S_SPOS_PAIN2, S_SPOS_DIE1, S_SPOS_DIE2, S_SPOS_DIE3, S_SPOS_DIE4, S_SPOS_DIE5, S_SPOS_XDIE1, S_SPOS_XDIE2, S_SPOS_XDIE3, S_SPOS_XDIE4, S_SPOS_XDIE5, S_SPOS_XDIE6, S_SPOS_XDIE7, S_SPOS_XDIE8, S_SPOS_XDIE9, S_SPOS_RAISE1, S_SPOS_RAISE2, S_SPOS_RAISE3, S_SPOS_RAISE4, S_SPOS_RAISE5, S_VILE_STND, S_VILE_STND2, S_VILE_RUN1, S_VILE_RUN2, S_VILE_RUN3, S_VILE_RUN4, S_VILE_RUN5, S_VILE_RUN6, S_VILE_RUN7, S_VILE_RUN8, S_VILE_RUN9, S_VILE_RUN10, S_VILE_RUN11, S_VILE_RUN12, S_VILE_ATK1, S_VILE_ATK2, S_VILE_ATK3, S_VILE_ATK4, S_VILE_ATK5, S_VILE_ATK6, S_VILE_ATK7, S_VILE_ATK8, S_VILE_ATK9, S_VILE_ATK10, S_VILE_ATK11, S_VILE_HEAL1, S_VILE_HEAL2, S_VILE_HEAL3, S_VILE_PAIN, S_VILE_PAIN2, S_VILE_DIE1, S_VILE_DIE2, S_VILE_DIE3, S_VILE_DIE4, S_VILE_DIE5, S_VILE_DIE6, S_VILE_DIE7, S_VILE_DIE8, S_VILE_DIE9, S_VILE_DIE10, S_FIRE1, S_FIRE2, S_FIRE3, S_FIRE4, S_FIRE5, S_FIRE6, S_FIRE7, S_FIRE8, S_FIRE9, S_FIRE10, S_FIRE11, S_FIRE12, S_FIRE13, S_FIRE14, S_FIRE15, S_FIRE16, S_FIRE17, S_FIRE18, S_FIRE19, S_FIRE20, S_FIRE21, S_FIRE22, S_FIRE23, S_FIRE24, S_FIRE25, S_FIRE26, S_FIRE27, S_FIRE28, S_FIRE29, S_FIRE30, S_SMOKE1, S_SMOKE2, S_SMOKE3, S_SMOKE4, S_SMOKE5, S_TRACER, S_TRACER2, S_TRACEEXP1, S_TRACEEXP2, S_TRACEEXP3, S_SKEL_STND, S_SKEL_STND2, S_SKEL_RUN1, S_SKEL_RUN2, S_SKEL_RUN3, S_SKEL_RUN4, S_SKEL_RUN5, S_SKEL_RUN6, S_SKEL_RUN7, S_SKEL_RUN8, S_SKEL_RUN9, S_SKEL_RUN10, S_SKEL_RUN11, S_SKEL_RUN12, S_SKEL_FIST1, S_SKEL_FIST2, S_SKEL_FIST3, S_SKEL_FIST4, S_SKEL_MISS1, S_SKEL_MISS2, S_SKEL_MISS3, S_SKEL_MISS4, S_SKEL_PAIN, S_SKEL_PAIN2, S_SKEL_DIE1, S_SKEL_DIE2, S_SKEL_DIE3, S_SKEL_DIE4, S_SKEL_DIE5, S_SKEL_DIE6, S_SKEL_RAISE1, S_SKEL_RAISE2, S_SKEL_RAISE3, S_SKEL_RAISE4, S_SKEL_RAISE5, S_SKEL_RAISE6, S_FATSHOT1, S_FATSHOT2, S_FATSHOTX1, S_FATSHOTX2, S_FATSHOTX3, S_FATT_STND, S_FATT_STND2, S_FATT_RUN1, S_FATT_RUN2, S_FATT_RUN3, S_FATT_RUN4, S_FATT_RUN5, S_FATT_RUN6, S_FATT_RUN7, S_FATT_RUN8, S_FATT_RUN9, S_FATT_RUN10, S_FATT_RUN11, S_FATT_RUN12, S_FATT_ATK1, S_FATT_ATK2, S_FATT_ATK3, S_FATT_ATK4, S_FATT_ATK5, S_FATT_ATK6, S_FATT_ATK7, S_FATT_ATK8, S_FATT_ATK9, S_FATT_ATK10, S_FATT_PAIN, S_FATT_PAIN2, S_FATT_DIE1, S_FATT_DIE2, S_FATT_DIE3, S_FATT_DIE4, S_FATT_DIE5, S_FATT_DIE6, S_FATT_DIE7, S_FATT_DIE8, S_FATT_DIE9, S_FATT_DIE10, S_FATT_RAISE1, S_FATT_RAISE2, S_FATT_RAISE3, S_FATT_RAISE4, S_FATT_RAISE5, S_FATT_RAISE6, S_FATT_RAISE7, S_FATT_RAISE8, S_CPOS_STND, S_CPOS_STND2, S_CPOS_RUN1, S_CPOS_RUN2, S_CPOS_RUN3, S_CPOS_RUN4, S_CPOS_RUN5, S_CPOS_RUN6, S_CPOS_RUN7, S_CPOS_RUN8, S_CPOS_ATK1, S_CPOS_ATK2, S_CPOS_ATK3, S_CPOS_ATK4, S_CPOS_PAIN, S_CPOS_PAIN2, S_CPOS_DIE1, S_CPOS_DIE2, S_CPOS_DIE3, S_CPOS_DIE4, S_CPOS_DIE5, S_CPOS_DIE6, S_CPOS_DIE7, S_CPOS_XDIE1, S_CPOS_XDIE2, S_CPOS_XDIE3, S_CPOS_XDIE4, S_CPOS_XDIE5, S_CPOS_XDIE6, S_CPOS_RAISE1, S_CPOS_RAISE2, S_CPOS_RAISE3, S_CPOS_RAISE4, S_CPOS_RAISE5, S_CPOS_RAISE6, S_CPOS_RAISE7, S_TROO_STND, S_TROO_STND2, S_TROO_RUN1, S_TROO_RUN2, S_TROO_RUN3, S_TROO_RUN4, S_TROO_RUN5, S_TROO_RUN6, S_TROO_RUN7, S_TROO_RUN8, S_TROO_ATK1, S_TROO_ATK2, S_TROO_ATK3, S_TROO_PAIN, S_TROO_PAIN2, S_TROO_DIE1, S_TROO_DIE2, S_TROO_DIE3, S_TROO_DIE4, S_TROO_DIE5, S_TROO_XDIE1, S_TROO_XDIE2, S_TROO_XDIE3, S_TROO_XDIE4, S_TROO_XDIE5, S_TROO_XDIE6, S_TROO_XDIE7, S_TROO_XDIE8, S_TROO_RAISE1, S_TROO_RAISE2, S_TROO_RAISE3, S_TROO_RAISE4, S_TROO_RAISE5, S_SARG_STND, S_SARG_STND2, S_SARG_RUN1, S_SARG_RUN2, S_SARG_RUN3, S_SARG_RUN4, S_SARG_RUN5, S_SARG_RUN6, S_SARG_RUN7, S_SARG_RUN8, S_SARG_ATK1, S_SARG_ATK2, S_SARG_ATK3, S_SARG_PAIN, S_SARG_PAIN2, S_SARG_DIE1, S_SARG_DIE2, S_SARG_DIE3, S_SARG_DIE4, S_SARG_DIE5, S_SARG_DIE6, S_SARG_RAISE1, S_SARG_RAISE2, S_SARG_RAISE3, S_SARG_RAISE4, S_SARG_RAISE5, S_SARG_RAISE6, S_HEAD_STND, S_HEAD_RUN1, S_HEAD_ATK1, S_HEAD_ATK2, S_HEAD_ATK3, S_HEAD_PAIN, S_HEAD_PAIN2, S_HEAD_PAIN3, S_HEAD_DIE1, S_HEAD_DIE2, S_HEAD_DIE3, S_HEAD_DIE4, S_HEAD_DIE5, S_HEAD_DIE6, S_HEAD_RAISE1, S_HEAD_RAISE2, S_HEAD_RAISE3, S_HEAD_RAISE4, S_HEAD_RAISE5, S_HEAD_RAISE6, S_BRBALL1, S_BRBALL2, S_BRBALLX1, S_BRBALLX2, S_BRBALLX3, S_BOSS_STND, S_BOSS_STND2, S_BOSS_RUN1, S_BOSS_RUN2, S_BOSS_RUN3, S_BOSS_RUN4, S_BOSS_RUN5, S_BOSS_RUN6, S_BOSS_RUN7, S_BOSS_RUN8, S_BOSS_ATK1, S_BOSS_ATK2, S_BOSS_ATK3, S_BOSS_PAIN, S_BOSS_PAIN2, S_BOSS_DIE1, S_BOSS_DIE2, S_BOSS_DIE3, S_BOSS_DIE4, S_BOSS_DIE5, S_BOSS_DIE6, S_BOSS_DIE7, S_BOSS_RAISE1, S_BOSS_RAISE2, S_BOSS_RAISE3, S_BOSS_RAISE4, S_BOSS_RAISE5, S_BOSS_RAISE6, S_BOSS_RAISE7, S_BOS2_STND, S_BOS2_STND2, S_BOS2_RUN1, S_BOS2_RUN2, S_BOS2_RUN3, S_BOS2_RUN4, S_BOS2_RUN5, S_BOS2_RUN6, S_BOS2_RUN7, S_BOS2_RUN8, S_BOS2_ATK1, S_BOS2_ATK2, S_BOS2_ATK3, S_BOS2_PAIN, S_BOS2_PAIN2, S_BOS2_DIE1, S_BOS2_DIE2, S_BOS2_DIE3, S_BOS2_DIE4, S_BOS2_DIE5, S_BOS2_DIE6, S_BOS2_DIE7, S_BOS2_RAISE1, S_BOS2_RAISE2, S_BOS2_RAISE3, S_BOS2_RAISE4, S_BOS2_RAISE5, S_BOS2_RAISE6, S_BOS2_RAISE7, S_SKULL_STND, S_SKULL_STND2, S_SKULL_RUN1, S_SKULL_RUN2, S_SKULL_ATK1, S_SKULL_ATK2, S_SKULL_ATK3, S_SKULL_ATK4, S_SKULL_PAIN, S_SKULL_PAIN2, S_SKULL_DIE1, S_SKULL_DIE2, S_SKULL_DIE3, S_SKULL_DIE4, S_SKULL_DIE5, S_SKULL_DIE6, S_SPID_STND, S_SPID_STND2, S_SPID_RUN1, S_SPID_RUN2, S_SPID_RUN3, S_SPID_RUN4, S_SPID_RUN5, S_SPID_RUN6, S_SPID_RUN7, S_SPID_RUN8, S_SPID_RUN9, S_SPID_RUN10, S_SPID_RUN11, S_SPID_RUN12, S_SPID_ATK1, S_SPID_ATK2, S_SPID_ATK3, S_SPID_ATK4, S_SPID_PAIN, S_SPID_PAIN2, S_SPID_DIE1, S_SPID_DIE2, S_SPID_DIE3, S_SPID_DIE4, S_SPID_DIE5, S_SPID_DIE6, S_SPID_DIE7, S_SPID_DIE8, S_SPID_DIE9, S_SPID_DIE10, S_SPID_DIE11, S_BSPI_STND, S_BSPI_STND2, S_BSPI_SIGHT, S_BSPI_RUN1, S_BSPI_RUN2, S_BSPI_RUN3, S_BSPI_RUN4, S_BSPI_RUN5, S_BSPI_RUN6, S_BSPI_RUN7, S_BSPI_RUN8, S_BSPI_RUN9, S_BSPI_RUN10, S_BSPI_RUN11, S_BSPI_RUN12, S_BSPI_ATK1, S_BSPI_ATK2, S_BSPI_ATK3, S_BSPI_ATK4, S_BSPI_PAIN, S_BSPI_PAIN2, S_BSPI_DIE1, S_BSPI_DIE2, S_BSPI_DIE3, S_BSPI_DIE4, S_BSPI_DIE5, S_BSPI_DIE6, S_BSPI_DIE7, S_BSPI_RAISE1, S_BSPI_RAISE2, S_BSPI_RAISE3, S_BSPI_RAISE4, S_BSPI_RAISE5, S_BSPI_RAISE6, S_BSPI_RAISE7, S_ARACH_PLAZ, S_ARACH_PLAZ2, S_ARACH_PLEX, S_ARACH_PLEX2, S_ARACH_PLEX3, S_ARACH_PLEX4, S_ARACH_PLEX5, S_CYBER_STND, S_CYBER_STND2, S_CYBER_RUN1, S_CYBER_RUN2, S_CYBER_RUN3, S_CYBER_RUN4, S_CYBER_RUN5, S_CYBER_RUN6, S_CYBER_RUN7, S_CYBER_RUN8, S_CYBER_ATK1, S_CYBER_ATK2, S_CYBER_ATK3, S_CYBER_ATK4, S_CYBER_ATK5, S_CYBER_ATK6, S_CYBER_PAIN, S_CYBER_DIE1, S_CYBER_DIE2, S_CYBER_DIE3, S_CYBER_DIE4, S_CYBER_DIE5, S_CYBER_DIE6, S_CYBER_DIE7, S_CYBER_DIE8, S_CYBER_DIE9, S_CYBER_DIE10, S_PAIN_STND, S_PAIN_RUN1, S_PAIN_RUN2, S_PAIN_RUN3, S_PAIN_RUN4, S_PAIN_RUN5, S_PAIN_RUN6, S_PAIN_ATK1, S_PAIN_ATK2, S_PAIN_ATK3, S_PAIN_ATK4, S_PAIN_PAIN, S_PAIN_PAIN2, S_PAIN_DIE1, S_PAIN_DIE2, S_PAIN_DIE3, S_PAIN_DIE4, S_PAIN_DIE5, S_PAIN_DIE6, S_PAIN_RAISE1, S_PAIN_RAISE2, S_PAIN_RAISE3, S_PAIN_RAISE4, S_PAIN_RAISE5, S_PAIN_RAISE6, S_SSWV_STND, S_SSWV_STND2, S_SSWV_RUN1, S_SSWV_RUN2, S_SSWV_RUN3, S_SSWV_RUN4, S_SSWV_RUN5, S_SSWV_RUN6, S_SSWV_RUN7, S_SSWV_RUN8, S_SSWV_ATK1, S_SSWV_ATK2, S_SSWV_ATK3, S_SSWV_ATK4, S_SSWV_ATK5, S_SSWV_ATK6, S_SSWV_PAIN, S_SSWV_PAIN2, S_SSWV_DIE1, S_SSWV_DIE2, S_SSWV_DIE3, S_SSWV_DIE4, S_SSWV_DIE5, S_SSWV_XDIE1, S_SSWV_XDIE2, S_SSWV_XDIE3, S_SSWV_XDIE4, S_SSWV_XDIE5, S_SSWV_XDIE6, S_SSWV_XDIE7, S_SSWV_XDIE8, S_SSWV_XDIE9, S_SSWV_RAISE1, S_SSWV_RAISE2, S_SSWV_RAISE3, S_SSWV_RAISE4, S_SSWV_RAISE5, S_KEENSTND, S_COMMKEEN, S_COMMKEEN2, S_COMMKEEN3, S_COMMKEEN4, S_COMMKEEN5, S_COMMKEEN6, S_COMMKEEN7, S_COMMKEEN8, S_COMMKEEN9, S_COMMKEEN10, S_COMMKEEN11, S_COMMKEEN12, S_KEENPAIN, S_KEENPAIN2, S_BRAIN, S_BRAIN_PAIN, S_BRAIN_DIE1, S_BRAIN_DIE2, S_BRAIN_DIE3, S_BRAIN_DIE4, S_BRAINEYE, S_BRAINEYESEE, S_BRAINEYE1, S_SPAWN1, S_SPAWN2, S_SPAWN3, S_SPAWN4, S_SPAWNFIRE1, S_SPAWNFIRE2, S_SPAWNFIRE3, S_SPAWNFIRE4, S_SPAWNFIRE5, S_SPAWNFIRE6, S_SPAWNFIRE7, S_SPAWNFIRE8, S_BRAINEXPLODE1, S_BRAINEXPLODE2, S_BRAINEXPLODE3, S_ARM1, S_ARM1A, S_ARM2, S_ARM2A, S_BAR1, S_BAR2, S_BEXP, S_BEXP2, S_BEXP3, S_BEXP4, S_BEXP5, S_BBAR1, S_BBAR2, S_BBAR3, S_BON1, S_BON1A, S_BON1B, S_BON1C, S_BON1D, S_BON1E, S_BON2, S_BON2A, S_BON2B, S_BON2C, S_BON2D, S_BON2E, S_BKEY, S_BKEY2, S_RKEY, S_RKEY2, S_YKEY, S_YKEY2, S_BSKULL, S_BSKULL2, S_RSKULL, S_RSKULL2, S_YSKULL, S_YSKULL2, S_STIM, S_MEDI, S_SOUL, S_SOUL2, S_SOUL3, S_SOUL4, S_SOUL5, S_SOUL6, S_PINV, S_PINV2, S_PINV3, S_PINV4, S_PSTR, S_PINS, S_PINS2, S_PINS3, S_PINS4, S_MEGA, S_MEGA2, S_MEGA3, S_MEGA4, S_SUIT, S_PMAP, S_PMAP2, S_PMAP3, S_PMAP4, S_PMAP5, S_PMAP6, S_PVIS, S_PVIS2, S_CLIP, S_AMMO, S_ROCK, S_BROK, S_CELL, S_CELP, S_SHEL, S_SBOX, S_BPAK, S_BFUG, S_MGUN, S_CSAW, S_LAUN, S_PLAS, S_SHOT, S_SHOT2, S_COLU, S_STALAG, S_BLOODYTWITCH, S_BLOODYTWITCH2, S_BLOODYTWITCH3, S_BLOODYTWITCH4, S_DEADTORSO, S_DEADBOTTOM, S_HEADSONSTICK, S_GIBS, S_HEADONASTICK, S_HEADCANDLES, S_HEADCANDLES2, S_DEADSTICK, S_LIVESTICK, S_LIVESTICK2, S_MEAT2, S_MEAT3, S_MEAT4, S_MEAT5, S_STALAGTITE, S_TALLGRNCOL, S_SHRTGRNCOL, S_TALLREDCOL, S_SHRTREDCOL, S_CANDLESTIK, S_CANDELABRA, S_SKULLCOL, S_TORCHTREE, S_BIGTREE, S_TECHPILLAR, S_EVILEYE, S_EVILEYE2, S_EVILEYE3, S_EVILEYE4, S_FLOATSKULL, S_FLOATSKULL2, S_FLOATSKULL3, S_HEARTCOL, S_HEARTCOL2, S_BLUETORCH, S_BLUETORCH2, S_BLUETORCH3, S_BLUETORCH4, S_GREENTORCH, S_GREENTORCH2, S_GREENTORCH3, S_GREENTORCH4, S_REDTORCH, S_REDTORCH2, S_REDTORCH3, S_REDTORCH4, S_BTORCHSHRT, S_BTORCHSHRT2, S_BTORCHSHRT3, S_BTORCHSHRT4, S_GTORCHSHRT, S_GTORCHSHRT2, S_GTORCHSHRT3, S_GTORCHSHRT4, S_RTORCHSHRT, S_RTORCHSHRT2, S_RTORCHSHRT3, S_RTORCHSHRT4, S_HANGNOGUTS, S_HANGBNOBRAIN, S_HANGTLOOKDN, S_HANGTSKULL, S_HANGTLOOKUP, S_HANGTNOBRAIN, S_COLONGIBS, S_SMALLPOOL, S_BRAINSTEM, S_TECHLAMP, S_TECHLAMP2, S_TECHLAMP3, S_TECHLAMP4, S_TECH2LAMP, S_TECH2LAMP2, S_TECH2LAMP3, S_TECH2LAMP4, NUMSTATES } statenum_t; typedef struct { spritenum_t sprite; int frame; int tics; // void (*action) (); actionf_t action; statenum_t nextstate; int misc1; int misc2; } state_t; extern state_t states[NUMSTATES]; extern char *sprnames[]; typedef enum { MT_PLAYER, MT_POSSESSED, MT_SHOTGUY, MT_VILE, MT_FIRE, MT_UNDEAD, MT_TRACER, MT_SMOKE, MT_FATSO, MT_FATSHOT, MT_CHAINGUY, MT_TROOP, MT_SERGEANT, MT_SHADOWS, MT_HEAD, MT_BRUISER, MT_BRUISERSHOT, MT_KNIGHT, MT_SKULL, MT_SPIDER, MT_BABY, MT_CYBORG, MT_PAIN, MT_WOLFSS, MT_KEEN, MT_BOSSBRAIN, MT_BOSSSPIT, MT_BOSSTARGET, MT_SPAWNSHOT, MT_SPAWNFIRE, MT_BARREL, MT_TROOPSHOT, MT_HEADSHOT, MT_ROCKET, MT_PLASMA, MT_BFG, MT_ARACHPLAZ, MT_PUFF, MT_BLOOD, MT_TFOG, MT_IFOG, MT_TELEPORTMAN, MT_EXTRABFG, MT_MISC0, MT_MISC1, MT_MISC2, MT_MISC3, MT_MISC4, MT_MISC5, MT_MISC6, MT_MISC7, MT_MISC8, MT_MISC9, MT_MISC10, MT_MISC11, MT_MISC12, MT_INV, MT_MISC13, MT_INS, MT_MISC14, MT_MISC15, MT_MISC16, MT_MEGA, MT_CLIP, MT_MISC17, MT_MISC18, MT_MISC19, MT_MISC20, MT_MISC21, MT_MISC22, MT_MISC23, MT_MISC24, MT_MISC25, MT_CHAINGUN, MT_MISC26, MT_MISC27, MT_MISC28, MT_SHOTGUN, MT_SUPERSHOTGUN, MT_MISC29, MT_MISC30, MT_MISC31, MT_MISC32, MT_MISC33, MT_MISC34, MT_MISC35, MT_MISC36, MT_MISC37, MT_MISC38, MT_MISC39, MT_MISC40, MT_MISC41, MT_MISC42, MT_MISC43, MT_MISC44, MT_MISC45, MT_MISC46, MT_MISC47, MT_MISC48, MT_MISC49, MT_MISC50, MT_MISC51, MT_MISC52, MT_MISC53, MT_MISC54, MT_MISC55, MT_MISC56, MT_MISC57, MT_MISC58, MT_MISC59, MT_MISC60, MT_MISC61, MT_MISC62, MT_MISC63, MT_MISC64, MT_MISC65, MT_MISC66, MT_MISC67, MT_MISC68, MT_MISC69, MT_MISC70, MT_MISC71, MT_MISC72, MT_MISC73, MT_MISC74, MT_MISC75, MT_MISC76, MT_MISC77, MT_MISC78, MT_MISC79, MT_MISC80, MT_MISC81, MT_MISC82, MT_MISC83, MT_MISC84, MT_MISC85, MT_MISC86, NUMMOBJTYPES } mobjtype_t; typedef struct { int doomednum; int spawnstate; int spawnhealth; int seestate; int seesound; int reactiontime; int attacksound; int painstate; int painchance; int painsound; int meleestate; int missilestate; int deathstate; int xdeathstate; int deathsound; int speed; int radius; int height; int mass; int damage; int activesound; int flags; int raisestate; } mobjinfo_t; extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/m_menu.c000066400000000000000000001143771257432200600224730ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM selection menu, options, episode etc. // Sliders and icons. Kinda widget stuff. // #include #include #include "doomdef.h" #include "doomkeys.h" #include "dstrings.h" #include "d_main.h" #include "deh_main.h" #include "i_swap.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "m_misc.h" #include "v_video.h" #include "w_wad.h" #include "z_zone.h" #include "r_local.h" #include "hu_stuff.h" #include "g_game.h" #include "m_argv.h" #include "m_controls.h" #include "p_saveg.h" #include "s_sound.h" #include "doomstat.h" // Data. #include "sounds.h" #include "m_menu.h" extern patch_t* hu_font[HU_FONTSIZE]; extern boolean message_dontfuckwithme; extern boolean chat_on; // in heads-up code // // defaulted values // int mouseSensitivity = 5; // Show messages has default, 0 = off, 1 = on int showMessages = 1; // Blocky mode, has default, 0 = high, 1 = normal int detailLevel = 0; int screenblocks = 9; // temp for screenblocks (0-9) int screenSize; // -1 = no quicksave slot picked! int quickSaveSlot; // 1 = message to be printed int messageToPrint; // ...and here is the message string! char* messageString; // message x & y int messx; int messy; int messageLastMenuActive; // timed message = no input from user boolean messageNeedsInput; void (*messageRoutine)(int response); char gammamsg[5][26] = { GAMMALVL0, GAMMALVL1, GAMMALVL2, GAMMALVL3, GAMMALVL4 }; // we are going to be entering a savegame string int saveStringEnter; int saveSlot; // which slot to save in int saveCharIndex; // which char we're editing // old save description before edit char saveOldString[SAVESTRINGSIZE]; boolean inhelpscreens; boolean menuactive; #define SKULLXOFF -32 #define LINEHEIGHT 16 extern boolean sendpause; char savegamestrings[10][SAVESTRINGSIZE]; char endstring[160]; static boolean opldev; // // MENU TYPEDEFS // typedef struct { // 0 = no cursor here, 1 = ok, 2 = arrows ok short status; char name[10]; // choice = menu item #. // if status = 2, // choice=0:leftarrow,1:rightarrow void (*routine)(int choice); // hotkey in menu char alphaKey; } menuitem_t; typedef struct menu_s { short numitems; // # of menu items struct menu_s* prevMenu; // previous menu menuitem_t* menuitems; // menu items void (*routine)(); // draw routine short x; short y; // x,y of menu short lastOn; // last item user was on in menu } menu_t; short itemOn; // menu item skull is on short skullAnimCounter; // skull animation counter short whichSkull; // which skull to draw // graphic name of skulls // warning: initializer-string for array of chars is too long char *skullName[2] = {"M_SKULL1","M_SKULL2"}; // current menudef menu_t* currentMenu; // // PROTOTYPES // void M_NewGame(int choice); void M_Episode(int choice); void M_ChooseSkill(int choice); void M_LoadGame(int choice); void M_SaveGame(int choice); void M_Options(int choice); void M_EndGame(int choice); void M_ReadThis(int choice); void M_ReadThis2(int choice); void M_QuitDOOM(int choice); void M_ChangeMessages(int choice); void M_ChangeSensitivity(int choice); void M_SfxVol(int choice); void M_MusicVol(int choice); void M_ChangeDetail(int choice); void M_SizeDisplay(int choice); void M_StartGame(int choice); void M_Sound(int choice); void M_FinishReadThis(int choice); void M_LoadSelect(int choice); void M_SaveSelect(int choice); void M_ReadSaveStrings(void); void M_QuickSave(void); void M_QuickLoad(void); void M_DrawMainMenu(void); void M_DrawReadThis1(void); void M_DrawReadThis2(void); void M_DrawNewGame(void); void M_DrawEpisode(void); void M_DrawOptions(void); void M_DrawSound(void); void M_DrawLoad(void); void M_DrawSave(void); void M_DrawSaveLoadBorder(int x,int y); void M_SetupNextMenu(menu_t *menudef); void M_DrawThermo(int x,int y,int thermWidth,int thermDot); void M_DrawEmptyCell(menu_t *menu,int item); void M_DrawSelCell(menu_t *menu,int item); void M_WriteText(int x, int y, char *string); int M_StringWidth(char *string); int M_StringHeight(char *string); void M_StartMessage(char *string,void *routine,boolean input); void M_StopMessage(void); void M_ClearMenus (void); // // DOOM MENU // enum { newgame = 0, options, loadgame, savegame, readthis, quitdoom, main_end } main_e; menuitem_t MainMenu[]= { {1,"M_NGAME",M_NewGame,'n'}, {1,"M_OPTION",M_Options,'o'}, {1,"M_LOADG",M_LoadGame,'l'}, {1,"M_SAVEG",M_SaveGame,'s'}, // Another hickup with Special edition. {1,"M_RDTHIS",M_ReadThis,'r'}, {1,"M_QUITG",M_QuitDOOM,'q'} }; menu_t MainDef = { main_end, NULL, MainMenu, M_DrawMainMenu, 97,64, 0 }; // // EPISODE SELECT // enum { ep1, ep2, ep3, ep4, ep_end } episodes_e; menuitem_t EpisodeMenu[]= { {1,"M_EPI1", M_Episode,'k'}, {1,"M_EPI2", M_Episode,'t'}, {1,"M_EPI3", M_Episode,'i'}, {1,"M_EPI4", M_Episode,'t'} }; menu_t EpiDef = { ep_end, // # of menu items &MainDef, // previous menu EpisodeMenu, // menuitem_t -> M_DrawEpisode, // drawing routine -> 48,63, // x,y ep1 // lastOn }; // // NEW GAME // enum { killthings, toorough, hurtme, violence, nightmare, newg_end } newgame_e; menuitem_t NewGameMenu[]= { {1,"M_JKILL", M_ChooseSkill, 'i'}, {1,"M_ROUGH", M_ChooseSkill, 'h'}, {1,"M_HURT", M_ChooseSkill, 'h'}, {1,"M_ULTRA", M_ChooseSkill, 'u'}, {1,"M_NMARE", M_ChooseSkill, 'n'} }; menu_t NewDef = { newg_end, // # of menu items &EpiDef, // previous menu NewGameMenu, // menuitem_t -> M_DrawNewGame, // drawing routine -> 48,63, // x,y hurtme // lastOn }; // // OPTIONS MENU // enum { endgame, messages, detail, scrnsize, option_empty1, mousesens, option_empty2, soundvol, opt_end } options_e; menuitem_t OptionsMenu[]= { {1,"M_ENDGAM", M_EndGame,'e'}, {1,"M_MESSG", M_ChangeMessages,'m'}, {1,"M_DETAIL", M_ChangeDetail,'g'}, {2,"M_SCRNSZ", M_SizeDisplay,'s'}, {-1,"",0,'\0'}, {2,"M_MSENS", M_ChangeSensitivity,'m'}, {-1,"",0,'\0'}, {1,"M_SVOL", M_Sound,'s'} }; menu_t OptionsDef = { opt_end, &MainDef, OptionsMenu, M_DrawOptions, 60,37, 0 }; // // Read This! MENU 1 & 2 // enum { rdthsempty1, read1_end } read_e; menuitem_t ReadMenu1[] = { {1,"",M_ReadThis2,0} }; menu_t ReadDef1 = { read1_end, &MainDef, ReadMenu1, M_DrawReadThis1, 280,185, 0 }; enum { rdthsempty2, read2_end } read_e2; menuitem_t ReadMenu2[]= { {1,"",M_FinishReadThis,0} }; menu_t ReadDef2 = { read2_end, &ReadDef1, ReadMenu2, M_DrawReadThis2, 330,175, 0 }; // // SOUND VOLUME MENU // enum { sfx_vol, sfx_empty1, music_vol, sfx_empty2, sound_end } sound_e; menuitem_t SoundMenu[]= { {2,"M_SFXVOL",M_SfxVol,'s'}, {-1,"",0,'\0'}, {2,"M_MUSVOL",M_MusicVol,'m'}, {-1,"",0,'\0'} }; menu_t SoundDef = { sound_end, &OptionsDef, SoundMenu, M_DrawSound, 80,64, 0 }; // // LOAD GAME MENU // enum { load1, load2, load3, load4, load5, load6, load_end } load_e; menuitem_t LoadMenu[]= { {1,"", M_LoadSelect,'1'}, {1,"", M_LoadSelect,'2'}, {1,"", M_LoadSelect,'3'}, {1,"", M_LoadSelect,'4'}, {1,"", M_LoadSelect,'5'}, {1,"", M_LoadSelect,'6'} }; menu_t LoadDef = { load_end, &MainDef, LoadMenu, M_DrawLoad, 80,54, 0 }; // // SAVE GAME MENU // menuitem_t SaveMenu[]= { {1,"", M_SaveSelect,'1'}, {1,"", M_SaveSelect,'2'}, {1,"", M_SaveSelect,'3'}, {1,"", M_SaveSelect,'4'}, {1,"", M_SaveSelect,'5'}, {1,"", M_SaveSelect,'6'} }; menu_t SaveDef = { load_end, &MainDef, SaveMenu, M_DrawSave, 80,54, 0 }; // // M_ReadSaveStrings // read the strings from the savegame files // void M_ReadSaveStrings(void) { FILE *handle; int i; char name[256]; for (i = 0;i < load_end;i++) { M_StringCopy(name, P_SaveGameFile(i), sizeof(name)); handle = fopen(name, "rb"); if (handle == NULL) { M_StringCopy(savegamestrings[i], EMPTYSTRING, SAVESTRINGSIZE); LoadMenu[i].status = 0; continue; } fread(&savegamestrings[i], 1, SAVESTRINGSIZE, handle); fclose(handle); LoadMenu[i].status = 1; } } // // M_LoadGame & Cie. // void M_DrawLoad(void) { int i; V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE)); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } } // // Draw border for the savegame description // void M_DrawSaveLoadBorder(int x,int y) { int i; V_DrawPatchDirect(x - 8, y + 7, W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE)); for (i = 0;i < 24;i++) { V_DrawPatchDirect(x, y + 7, W_CacheLumpName(DEH_String("M_LSCNTR"), PU_CACHE)); x += 8; } V_DrawPatchDirect(x, y + 7, W_CacheLumpName(DEH_String("M_LSRGHT"), PU_CACHE)); } // // User wants to load this game // void M_LoadSelect(int choice) { char name[256]; M_StringCopy(name, P_SaveGameFile(choice), sizeof(name)); G_LoadGame (name); M_ClearMenus (); } // // Selected from DOOM menu // void M_LoadGame (int choice) { if (netgame) { M_StartMessage(DEH_String(LOADNET),NULL,false); return; } M_SetupNextMenu(&LoadDef); M_ReadSaveStrings(); } // // M_SaveGame & Cie. // void M_DrawSave(void) { int i; V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE)); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } if (saveStringEnter) { i = M_StringWidth(savegamestrings[saveSlot]); M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_"); } } // // M_Responder calls this when user is finished // void M_DoSave(int slot) { G_SaveGame (slot,savegamestrings[slot]); M_ClearMenus (); // PICK QUICKSAVE SLOT YET? if (quickSaveSlot == -2) quickSaveSlot = slot; } // // User wants to save. Start string input for M_Responder // void M_SaveSelect(int choice) { // we are going to be intercepting all chars saveStringEnter = 1; saveSlot = choice; M_StringCopy(saveOldString,savegamestrings[choice], SAVESTRINGSIZE); if (!strcmp(savegamestrings[choice], EMPTYSTRING)) savegamestrings[choice][0] = 0; saveCharIndex = strlen(savegamestrings[choice]); } // // Selected from DOOM menu // void M_SaveGame (int choice) { if (!usergame) { M_StartMessage(DEH_String(SAVEDEAD),NULL,false); return; } if (gamestate != GS_LEVEL) return; M_SetupNextMenu(&SaveDef); M_ReadSaveStrings(); } // // M_QuickSave // char tempstring[80]; void M_QuickSaveResponse(int key) { if (key == key_menu_confirm) { M_DoSave(quickSaveSlot); S_StartSound(NULL,sfx_swtchx); } } void M_QuickSave(void) { if (!usergame) { S_StartSound(NULL,sfx_oof); return; } if (gamestate != GS_LEVEL) return; if (quickSaveSlot < 0) { M_StartControlPanel(); M_ReadSaveStrings(); M_SetupNextMenu(&SaveDef); quickSaveSlot = -2; // means to pick a slot now return; } DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickSaveResponse,true); } // // M_QuickLoad // void M_QuickLoadResponse(int key) { if (key == key_menu_confirm) { M_LoadSelect(quickSaveSlot); S_StartSound(NULL,sfx_swtchx); } } void M_QuickLoad(void) { if (netgame) { M_StartMessage(DEH_String(QLOADNET),NULL,false); return; } if (quickSaveSlot < 0) { M_StartMessage(DEH_String(QSAVESPOT),NULL,false); return; } DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickLoadResponse,true); } // // Read This Menus // Had a "quick hack to fix romero bug" // void M_DrawReadThis1(void) { char *lumpname = "CREDIT"; int skullx = 330, skully = 175; inhelpscreens = true; // Different versions of Doom 1.9 work differently switch (gameversion) { case exe_doom_1_9: case exe_hacx: if (gamemode == commercial) { // Doom 2 lumpname = "HELP"; skullx = 330; skully = 165; } else { // Doom 1 // HELP2 is the first screen shown in Doom 1 lumpname = "HELP2"; skullx = 280; skully = 185; } break; case exe_ultimate: case exe_chex: // Ultimate Doom always displays "HELP1". // Chex Quest version also uses "HELP1", even though it is based // on Final Doom. lumpname = "HELP1"; break; case exe_final: case exe_final2: // Final Doom always displays "HELP". lumpname = "HELP"; break; default: I_Error("Unhandled game version"); break; } lumpname = DEH_String(lumpname); V_DrawPatchDirect (0, 0, W_CacheLumpName(lumpname, PU_CACHE)); ReadDef1.x = skullx; ReadDef1.y = skully; } // // Read This Menus - optional second page. // void M_DrawReadThis2(void) { inhelpscreens = true; // We only ever draw the second page if this is // gameversion == exe_doom_1_9 and gamemode == registered V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE)); } // // Change Sfx & Music volumes // void M_DrawSound(void) { V_DrawPatchDirect (60, 38, W_CacheLumpName(DEH_String("M_SVOL"), PU_CACHE)); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1), 16,sfxVolume); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1), 16,musicVolume); } void M_Sound(int choice) { M_SetupNextMenu(&SoundDef); } void M_SfxVol(int choice) { switch(choice) { case 0: if (sfxVolume) sfxVolume--; break; case 1: if (sfxVolume < 15) sfxVolume++; break; } S_SetSfxVolume(sfxVolume * 8); } void M_MusicVol(int choice) { switch(choice) { case 0: if (musicVolume) musicVolume--; break; case 1: if (musicVolume < 15) musicVolume++; break; } S_SetMusicVolume(musicVolume * 8); } // // M_DrawMainMenu // void M_DrawMainMenu(void) { V_DrawPatchDirect(94, 2, W_CacheLumpName(DEH_String("M_DOOM"), PU_CACHE)); } // // M_NewGame // void M_DrawNewGame(void) { V_DrawPatchDirect(96, 14, W_CacheLumpName(DEH_String("M_NEWG"), PU_CACHE)); V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_SKILL"), PU_CACHE)); } void M_NewGame(int choice) { if (netgame && !demoplayback) { M_StartMessage(DEH_String(NEWGAME),NULL,false); return; } // Chex Quest disabled the episode select screen, as did Doom II. if (gamemode == commercial || gameversion == exe_chex) M_SetupNextMenu(&NewDef); else M_SetupNextMenu(&EpiDef); } // // M_Episode // int epi; void M_DrawEpisode(void) { V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE)); } void M_VerifyNightmare(int key) { if (key != key_menu_confirm) return; G_DeferedInitNew(nightmare,epi+1,1); M_ClearMenus (); } void M_ChooseSkill(int choice) { if (choice == nightmare) { M_StartMessage(DEH_String(NIGHTMARE),M_VerifyNightmare,true); return; } G_DeferedInitNew(choice,epi+1,1); M_ClearMenus (); } void M_Episode(int choice) { if ( (gamemode == shareware) && choice) { M_StartMessage(DEH_String(SWSTRING),NULL,false); M_SetupNextMenu(&ReadDef1); return; } // Yet another hack... if ( (gamemode == registered) && (choice > 2)) { fprintf( stderr, "M_Episode: 4th episode requires UltimateDOOM\n"); choice = 0; } epi = choice; M_SetupNextMenu(&NewDef); } // // M_Options // static char *detailNames[2] = {"M_GDHIGH","M_GDLOW"}; static char *msgNames[2] = {"M_MSGOFF","M_MSGON"}; void M_DrawOptions(void) { V_DrawPatchDirect(108, 15, W_CacheLumpName(DEH_String("M_OPTTTL"), PU_CACHE)); V_DrawPatchDirect(OptionsDef.x + 175, OptionsDef.y + LINEHEIGHT * detail, W_CacheLumpName(DEH_String(detailNames[detailLevel]), PU_CACHE)); V_DrawPatchDirect(OptionsDef.x + 120, OptionsDef.y + LINEHEIGHT * messages, W_CacheLumpName(DEH_String(msgNames[showMessages]), PU_CACHE)); M_DrawThermo(OptionsDef.x, OptionsDef.y + LINEHEIGHT * (mousesens + 1), 10, mouseSensitivity); M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1), 9,screenSize); } void M_Options(int choice) { M_SetupNextMenu(&OptionsDef); } // // Toggle messages on/off // void M_ChangeMessages(int choice) { // warning: unused parameter `int choice' choice = 0; showMessages = 1 - showMessages; if (!showMessages) players[consoleplayer].message = DEH_String(MSGOFF); else players[consoleplayer].message = DEH_String(MSGON); message_dontfuckwithme = true; } // // M_EndGame // void M_EndGameResponse(int key) { if (key != key_menu_confirm) return; currentMenu->lastOn = itemOn; M_ClearMenus (); D_StartTitle (); } void M_EndGame(int choice) { choice = 0; if (!usergame) { S_StartSound(NULL,sfx_oof); return; } if (netgame) { M_StartMessage(DEH_String(NETEND),NULL,false); return; } M_StartMessage(DEH_String(ENDGAME),M_EndGameResponse,true); } // // M_ReadThis // void M_ReadThis(int choice) { choice = 0; M_SetupNextMenu(&ReadDef1); } void M_ReadThis2(int choice) { // Doom 1.9 had two menus when playing Doom 1 // All others had only one if (gameversion == exe_doom_1_9 && gamemode != commercial) { choice = 0; M_SetupNextMenu(&ReadDef2); } else { // Close the menu M_FinishReadThis(0); } } void M_FinishReadThis(int choice) { choice = 0; M_SetupNextMenu(&MainDef); } // // M_QuitDOOM // int quitsounds[8] = { sfx_pldeth, sfx_dmpain, sfx_popain, sfx_slop, sfx_telept, sfx_posit1, sfx_posit3, sfx_sgtatk }; int quitsounds2[8] = { sfx_vilact, sfx_getpow, sfx_boscub, sfx_slop, sfx_skeswg, sfx_kntdth, sfx_bspact, sfx_sgtatk }; void M_QuitResponse(int key) { if (key != key_menu_confirm) return; if (!netgame) { if (gamemode == commercial) S_StartSound(NULL,quitsounds2[(gametic>>2)&7]); else S_StartSound(NULL,quitsounds[(gametic>>2)&7]); I_WaitVBL(105); } I_Quit (); } static char *M_SelectEndMessage(void) { char **endmsg; if (logical_gamemission == doom) { // Doom 1 endmsg = doom1_endmsg; } else { // Doom 2 endmsg = doom2_endmsg; } return endmsg[gametic % NUM_QUITMESSAGES]; } void M_QuitDOOM(int choice) { DEH_snprintf(endstring, sizeof(endstring), "%s\n\n" DOSY, DEH_String(M_SelectEndMessage())); M_StartMessage(endstring,M_QuitResponse,true); } void M_ChangeSensitivity(int choice) { switch(choice) { case 0: if (mouseSensitivity) mouseSensitivity--; break; case 1: if (mouseSensitivity < 9) mouseSensitivity++; break; } } void M_ChangeDetail(int choice) { choice = 0; detailLevel = 1 - detailLevel; R_SetViewSize (screenblocks, detailLevel); if (!detailLevel) players[consoleplayer].message = DEH_String(DETAILHI); else players[consoleplayer].message = DEH_String(DETAILLO); } void M_SizeDisplay(int choice) { switch(choice) { case 0: if (screenSize > 0) { screenblocks--; screenSize--; } break; case 1: if (screenSize < 8) { screenblocks++; screenSize++; } break; } R_SetViewSize (screenblocks, detailLevel); } // // Menu Functions // void M_DrawThermo ( int x, int y, int thermWidth, int thermDot ) { int xx; int i; xx = x; V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERML"), PU_CACHE)); xx += 8; for (i=0;ix - 10, menu->y + item * LINEHEIGHT - 1, W_CacheLumpName(DEH_String("M_CELL1"), PU_CACHE)); } void M_DrawSelCell ( menu_t* menu, int item ) { V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1, W_CacheLumpName(DEH_String("M_CELL2"), PU_CACHE)); } void M_StartMessage ( char* string, void* routine, boolean input ) { messageLastMenuActive = menuactive; messageToPrint = 1; messageString = string; messageRoutine = routine; messageNeedsInput = input; menuactive = true; return; } void M_StopMessage(void) { menuactive = messageLastMenuActive; messageToPrint = 0; } // // Find string width from hu_font chars // int M_StringWidth(char* string) { size_t i; int w = 0; int c; for (i = 0;i < strlen(string);i++) { c = toupper(string[i]) - HU_FONTSTART; if (c < 0 || c >= HU_FONTSIZE) w += 4; else w += SHORT (hu_font[c]->width); } return w; } // // Find string height from hu_font chars // int M_StringHeight(char* string) { size_t i; int h; int height = SHORT(hu_font[0]->height); h = height; for (i = 0;i < strlen(string);i++) if (string[i] == '\n') h += height; return h; } // // Write a string using the hu_font // void M_WriteText ( int x, int y, char* string) { int w; char* ch; int c; int cx; int cy; ch = string; cx = x; cy = y; while(1) { c = *ch++; if (!c) break; if (c == '\n') { cx = x; cy += 12; continue; } c = toupper(c) - HU_FONTSTART; if (c < 0 || c>= HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c]->width); if (cx+w > SCREENWIDTH) break; V_DrawPatchDirect(cx, cy, hu_font[c]); cx+=w; } } // These keys evaluate to a "null" key in Vanilla Doom that allows weird // jumping in the menus. Preserve this behavior for accuracy. static boolean IsNullKey(int key) { return key == KEY_PAUSE || key == KEY_CAPSLOCK || key == KEY_SCRLCK || key == KEY_NUMLOCK; } // // CONTROL PANEL // // // M_Responder // boolean M_Responder (event_t* ev) { int ch; int key; int i; static int joywait = 0; static int mousewait = 0; static int mousey = 0; static int lasty = 0; static int mousex = 0; static int lastx = 0; // In testcontrols mode, none of the function keys should do anything // - the only key is escape to quit. if (testcontrols) { if (ev->type == ev_quit || (ev->type == ev_keydown && (ev->data1 == key_menu_activate || ev->data1 == key_menu_quit))) { I_Quit(); return true; } return false; } // "close" button pressed on window? if (ev->type == ev_quit) { // First click on close button = bring up quit confirm message. // Second click on close button = confirm quit if (menuactive && messageToPrint && messageRoutine == M_QuitResponse) { M_QuitResponse(key_menu_confirm); } else { S_StartSound(NULL,sfx_swtchn); M_QuitDOOM(0); } return true; } // key is the key pressed, ch is the actual character typed ch = 0; key = -1; if (ev->type == ev_joystick && joywait < I_GetTime()) { if (ev->data3 < 0) { key = key_menu_up; joywait = I_GetTime() + 5; } else if (ev->data3 > 0) { key = key_menu_down; joywait = I_GetTime() + 5; } if (ev->data2 < 0) { key = key_menu_left; joywait = I_GetTime() + 2; } else if (ev->data2 > 0) { key = key_menu_right; joywait = I_GetTime() + 2; } if (ev->data1&1) { key = key_menu_forward; joywait = I_GetTime() + 5; } if (ev->data1&2) { key = key_menu_back; joywait = I_GetTime() + 5; } if (joybmenu >= 0 && (ev->data1 & (1 << joybmenu)) != 0) { key = key_menu_activate; joywait = I_GetTime() + 5; } } else { if (ev->type == ev_mouse && mousewait < I_GetTime()) { mousey += ev->data3; if (mousey < lasty-30) { key = key_menu_down; mousewait = I_GetTime() + 5; mousey = lasty -= 30; } else if (mousey > lasty+30) { key = key_menu_up; mousewait = I_GetTime() + 5; mousey = lasty += 30; } mousex += ev->data2; if (mousex < lastx-30) { key = key_menu_left; mousewait = I_GetTime() + 5; mousex = lastx -= 30; } else if (mousex > lastx+30) { key = key_menu_right; mousewait = I_GetTime() + 5; mousex = lastx += 30; } if (ev->data1&1) { key = key_menu_forward; mousewait = I_GetTime() + 15; } if (ev->data1&2) { key = key_menu_back; mousewait = I_GetTime() + 15; } } else { if (ev->type == ev_keydown) { key = ev->data1; ch = ev->data2; } } } if (key == -1) return false; // Save Game string input if (saveStringEnter) { switch(key) { case KEY_BACKSPACE: if (saveCharIndex > 0) { saveCharIndex--; savegamestrings[saveSlot][saveCharIndex] = 0; } break; case KEY_ESCAPE: saveStringEnter = 0; M_StringCopy(savegamestrings[saveSlot], saveOldString, SAVESTRINGSIZE); break; case KEY_ENTER: saveStringEnter = 0; if (savegamestrings[saveSlot][0]) M_DoSave(saveSlot); break; default: // This is complicated. // Vanilla has a bug where the shift key is ignored when entering // a savegame name. If vanilla_keyboard_mapping is on, we want // to emulate this bug by using 'data1'. But if it's turned off, // it implies the user doesn't care about Vanilla emulation: just // use the correct 'data2'. if (vanilla_keyboard_mapping) { ch = key; } ch = toupper(ch); if (ch != ' ' && (ch - HU_FONTSTART < 0 || ch - HU_FONTSTART >= HU_FONTSIZE)) { break; } if (ch >= 32 && ch <= 127 && saveCharIndex < SAVESTRINGSIZE-1 && M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8) { savegamestrings[saveSlot][saveCharIndex++] = ch; savegamestrings[saveSlot][saveCharIndex] = 0; } break; } return true; } // Take care of any messages that need input if (messageToPrint) { if (messageNeedsInput) { if (key != ' ' && key != KEY_ESCAPE && key != key_menu_confirm && key != key_menu_abort) { return false; } } menuactive = messageLastMenuActive; messageToPrint = 0; if (messageRoutine) messageRoutine(key); menuactive = false; S_StartSound(NULL,sfx_swtchx); return true; } if ((devparm && key == key_menu_help) || (key != 0 && key == key_menu_screenshot)) { G_ScreenShot (); return true; } // F-Keys if (!menuactive) { if (key == key_menu_decscreen) // Screen size down { if (automapactive || chat_on) return false; M_SizeDisplay(0); S_StartSound(NULL,sfx_stnmov); return true; } else if (key == key_menu_incscreen) // Screen size up { if (automapactive || chat_on) return false; M_SizeDisplay(1); S_StartSound(NULL,sfx_stnmov); return true; } else if (key == key_menu_help) // Help key { M_StartControlPanel (); if ( gamemode == retail ) currentMenu = &ReadDef2; else currentMenu = &ReadDef1; itemOn = 0; S_StartSound(NULL,sfx_swtchn); return true; } else if (key == key_menu_save) // Save { M_StartControlPanel(); S_StartSound(NULL,sfx_swtchn); M_SaveGame(0); return true; } else if (key == key_menu_load) // Load { M_StartControlPanel(); S_StartSound(NULL,sfx_swtchn); M_LoadGame(0); return true; } else if (key == key_menu_volume) // Sound Volume { M_StartControlPanel (); currentMenu = &SoundDef; itemOn = sfx_vol; S_StartSound(NULL,sfx_swtchn); return true; } else if (key == key_menu_detail) // Detail toggle { M_ChangeDetail(0); S_StartSound(NULL,sfx_swtchn); return true; } else if (key == key_menu_qsave) // Quicksave { S_StartSound(NULL,sfx_swtchn); M_QuickSave(); return true; } else if (key == key_menu_endgame) // End game { S_StartSound(NULL,sfx_swtchn); M_EndGame(0); return true; } else if (key == key_menu_messages) // Toggle messages { M_ChangeMessages(0); S_StartSound(NULL,sfx_swtchn); return true; } else if (key == key_menu_qload) // Quickload { S_StartSound(NULL,sfx_swtchn); M_QuickLoad(); return true; } else if (key == key_menu_quit) // Quit DOOM { S_StartSound(NULL,sfx_swtchn); M_QuitDOOM(0); return true; } else if (key == key_menu_gamma) // gamma toggle { usegamma++; if (usegamma > 4) usegamma = 0; players[consoleplayer].message = DEH_String(gammamsg[usegamma]); I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE)); return true; } } // Pop-up menu? if (!menuactive) { if (key == key_menu_activate) { M_StartControlPanel (); S_StartSound(NULL,sfx_swtchn); return true; } return false; } // Keys usable within menu if (key == key_menu_down) { // Move down to next item do { if (itemOn+1 > currentMenu->numitems-1) itemOn = 0; else itemOn++; S_StartSound(NULL,sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); return true; } else if (key == key_menu_up) { // Move back up to previous item do { if (!itemOn) itemOn = currentMenu->numitems-1; else itemOn--; S_StartSound(NULL,sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); return true; } else if (key == key_menu_left) { // Slide slider left if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { S_StartSound(NULL,sfx_stnmov); currentMenu->menuitems[itemOn].routine(0); } return true; } else if (key == key_menu_right) { // Slide slider right if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { S_StartSound(NULL,sfx_stnmov); currentMenu->menuitems[itemOn].routine(1); } return true; } else if (key == key_menu_forward) { // Activate menu item if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status) { currentMenu->lastOn = itemOn; if (currentMenu->menuitems[itemOn].status == 2) { currentMenu->menuitems[itemOn].routine(1); // right arrow S_StartSound(NULL,sfx_stnmov); } else { currentMenu->menuitems[itemOn].routine(itemOn); S_StartSound(NULL,sfx_pistol); } } return true; } else if (key == key_menu_activate) { // Deactivate menu currentMenu->lastOn = itemOn; M_ClearMenus (); S_StartSound(NULL,sfx_swtchx); return true; } else if (key == key_menu_back) { // Go back to previous menu currentMenu->lastOn = itemOn; if (currentMenu->prevMenu) { currentMenu = currentMenu->prevMenu; itemOn = currentMenu->lastOn; S_StartSound(NULL,sfx_swtchn); } return true; } // Keyboard shortcut? // Vanilla Doom has a weird behavior where it jumps to the scroll bars // when the certain keys are pressed, so emulate this. else if (ch != 0 || IsNullKey(key)) { for (i = itemOn+1;i < currentMenu->numitems;i++) { if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL,sfx_pstop); return true; } } for (i = 0;i <= itemOn;i++) { if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL,sfx_pstop); return true; } } } return false; } // // M_StartControlPanel // void M_StartControlPanel (void) { // intro might call this repeatedly if (menuactive) return; menuactive = 1; currentMenu = &MainDef; // JDC itemOn = currentMenu->lastOn; // JDC } // Display OPL debug messages - hack for GENMIDI development. static void M_DrawOPLDev(void) { extern void I_OPL_DevMessages(char *, size_t); char debug[1024]; char *curr, *p; int line; I_OPL_DevMessages(debug, sizeof(debug)); curr = debug; line = 0; for (;;) { p = strchr(curr, '\n'); if (p != NULL) { *p = '\0'; } M_WriteText(0, line * 8, curr); ++line; if (p == NULL) { break; } curr = p + 1; } } // // M_Drawer // Called after the view has been rendered, // but before it has been blitted. // void M_Drawer (void) { static short x; static short y; unsigned int i; unsigned int max; char string[80]; char *name; int start; inhelpscreens = false; // Horiz. & Vertically center string and print it. if (messageToPrint) { start = 0; y = 100 - M_StringHeight(messageString) / 2; while (messageString[start] != '\0') { int foundnewline = 0; for (i = 0; i < strlen(messageString + start); i++) { if (messageString[start + i] == '\n') { M_StringCopy(string, messageString + start, sizeof(string)); if (i < sizeof(string)) { string[i] = '\0'; } foundnewline = 1; start += i + 1; break; } } if (!foundnewline) { M_StringCopy(string, messageString + start, sizeof(string)); start += strlen(string); } x = 160 - M_StringWidth(string) / 2; M_WriteText(x, y, string); y += SHORT(hu_font[0]->height); } return; } if (opldev) { M_DrawOPLDev(); } if (!menuactive) return; if (currentMenu->routine) currentMenu->routine(); // call Draw routine // DRAW MENU x = currentMenu->x; y = currentMenu->y; max = currentMenu->numitems; for (i=0;imenuitems[i].name); if (name[0]) { V_DrawPatchDirect (x, y, W_CacheLumpName(name, PU_CACHE)); } y += LINEHEIGHT; } // DRAW SKULL V_DrawPatchDirect(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT, W_CacheLumpName(DEH_String(skullName[whichSkull]), PU_CACHE)); } // // M_ClearMenus // void M_ClearMenus (void) { menuactive = 0; // if (!netgame && usergame && paused) // sendpause = true; } // // M_SetupNextMenu // void M_SetupNextMenu(menu_t *menudef) { currentMenu = menudef; itemOn = currentMenu->lastOn; } // // M_Ticker // void M_Ticker (void) { if (--skullAnimCounter <= 0) { whichSkull ^= 1; skullAnimCounter = 8; } } // // M_Init // void M_Init (void) { currentMenu = &MainDef; menuactive = 0; itemOn = currentMenu->lastOn; whichSkull = 0; skullAnimCounter = 10; screenSize = screenblocks - 3; messageToPrint = 0; messageString = NULL; messageLastMenuActive = menuactive; quickSaveSlot = -1; // Here we could catch other version dependencies, // like HELP1/2, and four episodes. switch ( gamemode ) { case commercial: // Commercial has no "read this" entry. MainMenu[readthis] = MainMenu[quitdoom]; MainDef.numitems--; MainDef.y += 8; NewDef.prevMenu = &MainDef; break; case shareware: // Episode 2 and 3 are handled, // branching to an ad screen. case registered: break; case retail: // We are fine. default: break; } // Versions of doom.exe before the Ultimate Doom release only had // three episodes; if we're emulating one of those then don't try // to show episode four. If we are, then do show episode four // (should crash if missing). if (gameversion < exe_ultimate) { EpiDef.numitems--; } opldev = M_CheckParm("-opldev") > 0; } chocolate-doom-chocolate-doom-2.2.1/src/doom/m_menu.h000066400000000000000000000027011257432200600224630ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Menu widget stuff, episode selection and such. // #ifndef __M_MENU__ #define __M_MENU__ #include "d_event.h" // // MENUS // // Called by main loop, // saves config file and calls I_Quit when user exits. // Even when the menu is not displayed, // this can resize the view and change game parameters. // Does all the real work of the menu interaction. boolean M_Responder (event_t *ev); // Called by main loop, // only used for menu (skull cursor) animation. void M_Ticker (void); // Called by main loop, // draws the menus directly into the screen buffer. void M_Drawer (void); // Called by D_DoomMain, // loads the config file. void M_Init (void); // Called by intro code to force menu up upon a keypress, // does nothing if menu is already up. void M_StartControlPanel (void); extern int detailLevel; extern int screenblocks; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/m_random.c000066400000000000000000000047401257432200600227770ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Random number LUT. // #include #include "m_random.h" // // M_Random // Returns a 0-255 number // static const unsigned char rndtable[256] = { 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 , 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 , 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 , 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 , 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 , 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 , 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 , 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 , 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 , 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 , 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 , 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 , 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 , 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 , 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 , 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 , 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 , 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 , 120, 163, 236, 249 }; int rndindex = 0; int prndindex = 0; // Which one is deterministic? int P_Random (void) { prndindex = (prndindex+1)&0xff; return rndtable[prndindex]; } int M_Random (void) { rndindex = (rndindex+1)&0xff; return rndtable[rndindex]; } void M_ClearRandom (void) { prndindex = 0; // Seed the M_Random counter from the system time rndindex = time(NULL) & 0xff; } chocolate-doom-chocolate-doom-2.2.1/src/doom/m_random.h000066400000000000000000000016151257432200600230020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __M_RANDOM__ #define __M_RANDOM__ #include "doomtype.h" // Returns a number from 0 to 255, // from a lookup table. int M_Random (void); // As M_Random, but used only by the play simulation. int P_Random (void); // Fix randoms for demos. void M_ClearRandom (void); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/p_ceilng.c000066400000000000000000000136451257432200600227670ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Ceiling aninmation (lowering, crushing, raising) // #include "z_zone.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" // // CEILINGS // ceiling_t* activeceilings[MAXCEILINGS]; // // T_MoveCeiling // void T_MoveCeiling (ceiling_t* ceiling) { result_e res; switch(ceiling->direction) { case 0: // IN STASIS break; case 1: // UP res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false,1,ceiling->direction); if (!(leveltime&7)) { switch(ceiling->type) { case silentCrushAndRaise: break; default: S_StartSound(&ceiling->sector->soundorg, sfx_stnmov); // ? break; } } if (res == pastdest) { switch(ceiling->type) { case raiseToHighest: P_RemoveActiveCeiling(ceiling); break; case silentCrushAndRaise: S_StartSound(&ceiling->sector->soundorg, sfx_pstop); case fastCrushAndRaise: case crushAndRaise: ceiling->direction = -1; break; default: break; } } break; case -1: // DOWN res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush,1,ceiling->direction); if (!(leveltime&7)) { switch(ceiling->type) { case silentCrushAndRaise: break; default: S_StartSound(&ceiling->sector->soundorg, sfx_stnmov); } } if (res == pastdest) { switch(ceiling->type) { case silentCrushAndRaise: S_StartSound(&ceiling->sector->soundorg, sfx_pstop); case crushAndRaise: ceiling->speed = CEILSPEED; case fastCrushAndRaise: ceiling->direction = 1; break; case lowerAndCrush: case lowerToFloor: P_RemoveActiveCeiling(ceiling); break; default: break; } } else // ( res != pastdest ) { if (res == crushed) { switch(ceiling->type) { case silentCrushAndRaise: case crushAndRaise: case lowerAndCrush: ceiling->speed = CEILSPEED / 8; break; default: break; } } } break; } } // // EV_DoCeiling // Move a ceiling up/down and all around! // int EV_DoCeiling ( line_t* line, ceiling_e type ) { int secnum; int rtn; sector_t* sec; ceiling_t* ceiling; secnum = -1; rtn = 0; // Reactivate in-stasis ceilings...for certain types. switch(type) { case fastCrushAndRaise: case silentCrushAndRaise: case crushAndRaise: P_ActivateInStasisCeiling(line); default: break; } while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // new door thinker rtn = 1; ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); P_AddThinker (&ceiling->thinker); sec->specialdata = ceiling; ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling; ceiling->sector = sec; ceiling->crush = false; switch(type) { case fastCrushAndRaise: ceiling->crush = true; ceiling->topheight = sec->ceilingheight; ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); ceiling->direction = -1; ceiling->speed = CEILSPEED * 2; break; case silentCrushAndRaise: case crushAndRaise: ceiling->crush = true; ceiling->topheight = sec->ceilingheight; case lowerAndCrush: case lowerToFloor: ceiling->bottomheight = sec->floorheight; if (type != lowerToFloor) ceiling->bottomheight += 8*FRACUNIT; ceiling->direction = -1; ceiling->speed = CEILSPEED; break; case raiseToHighest: ceiling->topheight = P_FindHighestCeilingSurrounding(sec); ceiling->direction = 1; ceiling->speed = CEILSPEED; break; } ceiling->tag = sec->tag; ceiling->type = type; P_AddActiveCeiling(ceiling); } return rtn; } // // Add an active ceiling // void P_AddActiveCeiling(ceiling_t* c) { int i; for (i = 0; i < MAXCEILINGS;i++) { if (activeceilings[i] == NULL) { activeceilings[i] = c; return; } } } // // Remove a ceiling's thinker // void P_RemoveActiveCeiling(ceiling_t* c) { int i; for (i = 0;i < MAXCEILINGS;i++) { if (activeceilings[i] == c) { activeceilings[i]->sector->specialdata = NULL; P_RemoveThinker (&activeceilings[i]->thinker); activeceilings[i] = NULL; break; } } } // // Restart a ceiling that's in-stasis // void P_ActivateInStasisCeiling(line_t* line) { int i; for (i = 0;i < MAXCEILINGS;i++) { if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && (activeceilings[i]->direction == 0)) { activeceilings[i]->direction = activeceilings[i]->olddirection; activeceilings[i]->thinker.function.acp1 = (actionf_p1)T_MoveCeiling; } } } // // EV_CeilingCrushStop // Stop a ceiling from crushing! // int EV_CeilingCrushStop(line_t *line) { int i; int rtn; rtn = 0; for (i = 0;i < MAXCEILINGS;i++) { if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && (activeceilings[i]->direction != 0)) { activeceilings[i]->olddirection = activeceilings[i]->direction; activeceilings[i]->thinker.function.acv = (actionf_v)NULL; activeceilings[i]->direction = 0; // in-stasis rtn = 1; } } return rtn; } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_doors.c000066400000000000000000000400411257432200600226420ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Door animation code (opening/closing) // #include "z_zone.h" #include "doomdef.h" #include "deh_main.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "dstrings.h" #include "sounds.h" #if 0 // // Sliding door frame information // slidename_t slideFrameNames[MAXSLIDEDOORS] = { {"GDOORF1","GDOORF2","GDOORF3","GDOORF4", // front "GDOORB1","GDOORB2","GDOORB3","GDOORB4"}, // back {"\0","\0","\0","\0"} }; #endif // // VERTICAL DOORS // // // T_VerticalDoor // void T_VerticalDoor (vldoor_t* door) { result_e res; switch(door->direction) { case 0: // WAITING if (!--door->topcountdown) { switch(door->type) { case vld_blazeRaise: door->direction = -1; // time to go back down S_StartSound(&door->sector->soundorg, sfx_bdcls); break; case vld_normal: door->direction = -1; // time to go back down S_StartSound(&door->sector->soundorg, sfx_dorcls); break; case vld_close30ThenOpen: door->direction = 1; S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: break; } } break; case 2: // INITIAL WAIT if (!--door->topcountdown) { switch(door->type) { case vld_raiseIn5Mins: door->direction = 1; door->type = vld_normal; S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: break; } } break; case -1: // DOWN res = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false,1,door->direction); if (res == pastdest) { switch(door->type) { case vld_blazeRaise: case vld_blazeClose: door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free S_StartSound(&door->sector->soundorg, sfx_bdcls); break; case vld_normal: case vld_close: door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free break; case vld_close30ThenOpen: door->direction = 0; door->topcountdown = TICRATE*30; break; default: break; } } else if (res == crushed) { switch(door->type) { case vld_blazeClose: case vld_close: // DO NOT GO BACK UP! break; default: door->direction = 1; S_StartSound(&door->sector->soundorg, sfx_doropn); break; } } break; case 1: // UP res = T_MovePlane(door->sector, door->speed, door->topheight, false,1,door->direction); if (res == pastdest) { switch(door->type) { case vld_blazeRaise: case vld_normal: door->direction = 0; // wait at top door->topcountdown = door->topwait; break; case vld_close30ThenOpen: case vld_blazeOpen: case vld_open: door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free break; default: break; } } break; } } // // EV_DoLockedDoor // Move a locked door up/down // int EV_DoLockedDoor ( line_t* line, vldoor_e type, mobj_t* thing ) { player_t* p; p = thing->player; if (!p) return 0; switch(line->special) { case 99: // Blue Lock case 133: if ( !p ) return 0; if (!p->cards[it_bluecard] && !p->cards[it_blueskull]) { p->message = DEH_String(PD_BLUEO); S_StartSound(NULL,sfx_oof); return 0; } break; case 134: // Red Lock case 135: if ( !p ) return 0; if (!p->cards[it_redcard] && !p->cards[it_redskull]) { p->message = DEH_String(PD_REDO); S_StartSound(NULL,sfx_oof); return 0; } break; case 136: // Yellow Lock case 137: if ( !p ) return 0; if (!p->cards[it_yellowcard] && !p->cards[it_yellowskull]) { p->message = DEH_String(PD_YELLOWO); S_StartSound(NULL,sfx_oof); return 0; } break; } return EV_DoDoor(line,type); } int EV_DoDoor ( line_t* line, vldoor_e type ) { int secnum,rtn; sector_t* sec; vldoor_t* door; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // new door thinker rtn = 1; door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor; door->sector = sec; door->type = type; door->topwait = VDOORWAIT; door->speed = VDOORSPEED; switch(type) { case vld_blazeClose: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; door->speed = VDOORSPEED * 4; S_StartSound(&door->sector->soundorg, sfx_bdcls); break; case vld_close: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; S_StartSound(&door->sector->soundorg, sfx_dorcls); break; case vld_close30ThenOpen: door->topheight = sec->ceilingheight; door->direction = -1; S_StartSound(&door->sector->soundorg, sfx_dorcls); break; case vld_blazeRaise: case vld_blazeOpen: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->speed = VDOORSPEED * 4; if (door->topheight != sec->ceilingheight) S_StartSound(&door->sector->soundorg, sfx_bdopn); break; case vld_normal: case vld_open: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; if (door->topheight != sec->ceilingheight) S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: break; } } return rtn; } // // EV_VerticalDoor : open a door manually, no tag value // void EV_VerticalDoor ( line_t* line, mobj_t* thing ) { player_t* player; sector_t* sec; vldoor_t* door; int side; side = 0; // only front sides can be used // Check for locks player = thing->player; switch(line->special) { case 26: // Blue Lock case 32: if ( !player ) return; if (!player->cards[it_bluecard] && !player->cards[it_blueskull]) { player->message = DEH_String(PD_BLUEK); S_StartSound(NULL,sfx_oof); return; } break; case 27: // Yellow Lock case 34: if ( !player ) return; if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) { player->message = DEH_String(PD_YELLOWK); S_StartSound(NULL,sfx_oof); return; } break; case 28: // Red Lock case 33: if ( !player ) return; if (!player->cards[it_redcard] && !player->cards[it_redskull]) { player->message = DEH_String(PD_REDK); S_StartSound(NULL,sfx_oof); return; } break; } // if the sector has an active thinker, use it sec = sides[ line->sidenum[side^1]] .sector; if (sec->specialdata) { door = sec->specialdata; switch(line->special) { case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s case 26: case 27: case 28: case 117: if (door->direction == -1) door->direction = 1; // go back up else { if (!thing->player) return; // JDC: bad guys never close doors // When is a door not a door? // In Vanilla, door->direction is set, even though // "specialdata" might not actually point at a door. if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor) { door->direction = -1; // start going down immediately } else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise) { // Erm, this is a plat, not a door. // This notably causes a problem in ep1-0500.lmp where // a plat and a door are cross-referenced; the door // doesn't open on 64-bit. // The direction field in vldoor_t corresponds to the wait // field in plat_t. Let's set that to -1 instead. plat_t *plat; plat = (plat_t *) door; plat->wait = -1; } else { // This isn't a door OR a plat. Now we're in trouble. fprintf(stderr, "EV_VerticalDoor: Tried to close " "something that wasn't a door.\n"); // Try closing it anyway. At least it will work on 32-bit // machines. door->direction = -1; } } return; } } // for proper sound switch(line->special) { case 117: // BLAZING DOOR RAISE case 118: // BLAZING DOOR OPEN S_StartSound(&sec->soundorg,sfx_bdopn); break; case 1: // NORMAL DOOR SOUND case 31: S_StartSound(&sec->soundorg,sfx_doropn); break; default: // LOCKED DOOR SOUND S_StartSound(&sec->soundorg,sfx_doropn); break; } // new door thinker door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor; door->sector = sec; door->direction = 1; door->speed = VDOORSPEED; door->topwait = VDOORWAIT; switch(line->special) { case 1: case 26: case 27: case 28: door->type = vld_normal; break; case 31: case 32: case 33: case 34: door->type = vld_open; line->special = 0; break; case 117: // blazing door raise door->type = vld_blazeRaise; door->speed = VDOORSPEED*4; break; case 118: // blazing door open door->type = vld_blazeOpen; line->special = 0; door->speed = VDOORSPEED*4; break; } // find the top and bottom of the movement range door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; } // // Spawn a door that closes after 30 seconds // void P_SpawnDoorCloseIn30 (sector_t* sec) { vldoor_t* door; door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 0; door->type = vld_normal; door->speed = VDOORSPEED; door->topcountdown = 30 * TICRATE; } // // Spawn a door that opens after 5 minutes // void P_SpawnDoorRaiseIn5Mins ( sector_t* sec, int secnum ) { vldoor_t* door; door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 2; door->type = vld_raiseIn5Mins; door->speed = VDOORSPEED; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->topwait = VDOORWAIT; door->topcountdown = 5 * 60 * TICRATE; } // UNUSED // Separate into p_slidoor.c? #if 0 // ABANDONED TO THE MISTS OF TIME!!! // // EV_SlidingDoor : slide a door horizontally // (animate midtexture, then set noblocking line) // slideframe_t slideFrames[MAXSLIDEDOORS]; void P_InitSlidingDoorFrames(void) { int i; int f1; int f2; int f3; int f4; // DOOM II ONLY... if ( gamemode != commercial) return; for (i = 0;i < MAXSLIDEDOORS; i++) { if (!slideFrameNames[i].frontFrame1[0]) break; f1 = R_TextureNumForName(slideFrameNames[i].frontFrame1); f2 = R_TextureNumForName(slideFrameNames[i].frontFrame2); f3 = R_TextureNumForName(slideFrameNames[i].frontFrame3); f4 = R_TextureNumForName(slideFrameNames[i].frontFrame4); slideFrames[i].frontFrames[0] = f1; slideFrames[i].frontFrames[1] = f2; slideFrames[i].frontFrames[2] = f3; slideFrames[i].frontFrames[3] = f4; f1 = R_TextureNumForName(slideFrameNames[i].backFrame1); f2 = R_TextureNumForName(slideFrameNames[i].backFrame2); f3 = R_TextureNumForName(slideFrameNames[i].backFrame3); f4 = R_TextureNumForName(slideFrameNames[i].backFrame4); slideFrames[i].backFrames[0] = f1; slideFrames[i].backFrames[1] = f2; slideFrames[i].backFrames[2] = f3; slideFrames[i].backFrames[3] = f4; } } // // Return index into "slideFrames" array // for which door type to use // int P_FindSlidingDoorType(line_t* line) { int i; int val; for (i = 0;i < MAXSLIDEDOORS;i++) { val = sides[line->sidenum[0]].midtexture; if (val == slideFrames[i].frontFrames[0]) return i; } return -1; } void T_SlidingDoor (slidedoor_t* door) { switch(door->status) { case sd_opening: if (!door->timer--) { if (++door->frame == SNUMFRAMES) { // IF DOOR IS DONE OPENING... sides[door->line->sidenum[0]].midtexture = 0; sides[door->line->sidenum[1]].midtexture = 0; door->line->flags &= ML_BLOCKING^0xff; if (door->type == sdt_openOnly) { door->frontsector->specialdata = NULL; P_RemoveThinker (&door->thinker); break; } door->timer = SDOORWAIT; door->status = sd_waiting; } else { // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME... door->timer = SWAITTICS; sides[door->line->sidenum[0]].midtexture = slideFrames[door->whichDoorIndex]. frontFrames[door->frame]; sides[door->line->sidenum[1]].midtexture = slideFrames[door->whichDoorIndex]. backFrames[door->frame]; } } break; case sd_waiting: // IF DOOR IS DONE WAITING... if (!door->timer--) { // CAN DOOR CLOSE? if (door->frontsector->thinglist != NULL || door->backsector->thinglist != NULL) { door->timer = SDOORWAIT; break; } //door->frame = SNUMFRAMES-1; door->status = sd_closing; door->timer = SWAITTICS; } break; case sd_closing: if (!door->timer--) { if (--door->frame < 0) { // IF DOOR IS DONE CLOSING... door->line->flags |= ML_BLOCKING; door->frontsector->specialdata = NULL; P_RemoveThinker (&door->thinker); break; } else { // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME... door->timer = SWAITTICS; sides[door->line->sidenum[0]].midtexture = slideFrames[door->whichDoorIndex]. frontFrames[door->frame]; sides[door->line->sidenum[1]].midtexture = slideFrames[door->whichDoorIndex]. backFrames[door->frame]; } } break; } } void EV_SlidingDoor ( line_t* line, mobj_t* thing ) { sector_t* sec; slidedoor_t* door; // DOOM II ONLY... if (gamemode != commercial) return; // Make sure door isn't already being animated sec = line->frontsector; door = NULL; if (sec->specialdata) { if (!thing->player) return; door = sec->specialdata; if (door->type == sdt_openAndClose) { if (door->status == sd_waiting) door->status = sd_closing; } else return; } // Init sliding door vars if (!door) { door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->type = sdt_openAndClose; door->status = sd_opening; door->whichDoorIndex = P_FindSlidingDoorType(line); if (door->whichDoorIndex < 0) I_Error("EV_SlidingDoor: Can't use texture for sliding door!"); door->frontsector = sec; door->backsector = line->backsector; door->thinker.function = T_SlidingDoor; door->timer = SWAITTICS; door->frame = 0; door->line = line; } } #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/p_enemy.c000066400000000000000000001107521257432200600226400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Enemy thinking, AI. // Action Pointer Functions // that are associated with states/frames. // #include #include #include "m_random.h" #include "i_system.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "g_game.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" typedef enum { DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_NODIR, NUMDIRS } dirtype_t; // // P_NewChaseDir related LUT. // dirtype_t opposite[] = { DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR }; dirtype_t diags[] = { DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST }; void A_Fall (mobj_t *actor); // // ENEMY THINKING // Enemies are allways spawned // with targetplayer = -1, threshold = 0 // Most monsters are spawned unaware of all players, // but some can be made preaware // // // Called by P_NoiseAlert. // Recursively traverse adjacent sectors, // sound blocking lines cut off traversal. // mobj_t* soundtarget; void P_RecursiveSound ( sector_t* sec, int soundblocks ) { int i; line_t* check; sector_t* other; // wake up all monsters in this sector if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) { return; // already flooded } sec->validcount = validcount; sec->soundtraversed = soundblocks+1; sec->soundtarget = soundtarget; for (i=0 ;ilinecount ; i++) { check = sec->lines[i]; if (! (check->flags & ML_TWOSIDED) ) continue; P_LineOpening (check); if (openrange <= 0) continue; // closed door if ( sides[ check->sidenum[0] ].sector == sec) other = sides[ check->sidenum[1] ] .sector; else other = sides[ check->sidenum[0] ].sector; if (check->flags & ML_SOUNDBLOCK) { if (!soundblocks) P_RecursiveSound (other, 1); } else P_RecursiveSound (other, soundblocks); } } // // P_NoiseAlert // If a monster yells at a player, // it will alert other monsters to the player. // void P_NoiseAlert ( mobj_t* target, mobj_t* emmiter ) { soundtarget = target; validcount++; P_RecursiveSound (emmiter->subsector->sector, 0); } // // P_CheckMeleeRange // boolean P_CheckMeleeRange (mobj_t* actor) { mobj_t* pl; fixed_t dist; if (!actor->target) return false; pl = actor->target; dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y); if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius) return false; if (! P_CheckSight (actor, actor->target) ) return false; return true; } // // P_CheckMissileRange // boolean P_CheckMissileRange (mobj_t* actor) { fixed_t dist; if (! P_CheckSight (actor, actor->target) ) return false; if ( actor->flags & MF_JUSTHIT ) { // the target just hit the enemy, // so fight back! actor->flags &= ~MF_JUSTHIT; return true; } if (actor->reactiontime) return false; // do not attack yet // OPTIMIZE: get this from a global checksight dist = P_AproxDistance ( actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT; if (!actor->info->meleestate) dist -= 128*FRACUNIT; // no melee attack, so fire more dist >>= 16; if (actor->type == MT_VILE) { if (dist > 14*64) return false; // too far away } if (actor->type == MT_UNDEAD) { if (dist < 196) return false; // close for fist attack dist >>= 1; } if (actor->type == MT_CYBORG || actor->type == MT_SPIDER || actor->type == MT_SKULL) { dist >>= 1; } if (dist > 200) dist = 200; if (actor->type == MT_CYBORG && dist > 160) dist = 160; if (P_Random () < dist) return false; return true; } // // P_Move // Move in the current direction, // returns false if the move is blocked. // fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000}; fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000}; boolean P_Move (mobj_t* actor) { fixed_t tryx; fixed_t tryy; line_t* ld; // warning: 'catch', 'throw', and 'try' // are all C++ reserved words boolean try_ok; boolean good; if (actor->movedir == DI_NODIR) return false; if ((unsigned)actor->movedir >= 8) I_Error ("Weird actor->movedir!"); tryx = actor->x + actor->info->speed*xspeed[actor->movedir]; tryy = actor->y + actor->info->speed*yspeed[actor->movedir]; try_ok = P_TryMove (actor, tryx, tryy); if (!try_ok) { // open any specials if (actor->flags & MF_FLOAT && floatok) { // must adjust height if (actor->z < tmfloorz) actor->z += FLOATSPEED; else actor->z -= FLOATSPEED; actor->flags |= MF_INFLOAT; return true; } if (!numspechit) return false; actor->movedir = DI_NODIR; good = false; while (numspechit--) { ld = spechit[numspechit]; // if the special is not a door // that can be opened, // return false if (P_UseSpecialLine (actor, ld,0)) good = true; } return good; } else { actor->flags &= ~MF_INFLOAT; } if (! (actor->flags & MF_FLOAT) ) actor->z = actor->floorz; return true; } // // TryWalk // Attempts to move actor on // in its current (ob->moveangle) direction. // If blocked by either a wall or an actor // returns FALSE // If move is either clear or blocked only by a door, // returns TRUE and sets... // If a door is in the way, // an OpenDoor call is made to start it opening. // boolean P_TryWalk (mobj_t* actor) { if (!P_Move (actor)) { return false; } actor->movecount = P_Random()&15; return true; } void P_NewChaseDir (mobj_t* actor) { fixed_t deltax; fixed_t deltay; dirtype_t d[3]; int tdir; dirtype_t olddir; dirtype_t turnaround; if (!actor->target) I_Error ("P_NewChaseDir: called with no target"); olddir = actor->movedir; turnaround=opposite[olddir]; deltax = actor->target->x - actor->x; deltay = actor->target->y - actor->y; if (deltax>10*FRACUNIT) d[1]= DI_EAST; else if (deltax<-10*FRACUNIT) d[1]= DI_WEST; else d[1]=DI_NODIR; if (deltay<-10*FRACUNIT) d[2]= DI_SOUTH; else if (deltay>10*FRACUNIT) d[2]= DI_NORTH; else d[2]=DI_NODIR; // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { actor->movedir = diags[((deltay<0)<<1)+(deltax>0)]; if (actor->movedir != (int) turnaround && P_TryWalk(actor)) return; } // try other directions if (P_Random() > 200 || abs(deltay)>abs(deltax)) { tdir=d[1]; d[1]=d[2]; d[2]=tdir; } if (d[1]==turnaround) d[1]=DI_NODIR; if (d[2]==turnaround) d[2]=DI_NODIR; if (d[1]!=DI_NODIR) { actor->movedir = d[1]; if (P_TryWalk(actor)) { // either moved forward or attacked return; } } if (d[2]!=DI_NODIR) { actor->movedir =d[2]; if (P_TryWalk(actor)) return; } // there is no direct path to the player, // so pick another direction. if (olddir!=DI_NODIR) { actor->movedir =olddir; if (P_TryWalk(actor)) return; } // randomly determine direction of search if (P_Random()&1) { for ( tdir=DI_EAST; tdir<=DI_SOUTHEAST; tdir++ ) { if (tdir != (int) turnaround) { actor->movedir =tdir; if ( P_TryWalk(actor) ) return; } } } else { for ( tdir=DI_SOUTHEAST; tdir != (DI_EAST-1); tdir-- ) { if (tdir != (int) turnaround) { actor->movedir = tdir; if ( P_TryWalk(actor) ) return; } } } if (turnaround != DI_NODIR) { actor->movedir =turnaround; if ( P_TryWalk(actor) ) return; } actor->movedir = DI_NODIR; // can not move } // // P_LookForPlayers // If allaround is false, only look 180 degrees in front. // Returns true if a player is targeted. // boolean P_LookForPlayers ( mobj_t* actor, boolean allaround ) { int c; int stop; player_t* player; angle_t an; fixed_t dist; c = 0; stop = (actor->lastlook-1)&3; for ( ; ; actor->lastlook = (actor->lastlook+1)&3 ) { if (!playeringame[actor->lastlook]) continue; if (c++ == 2 || actor->lastlook == stop) { // done looking return false; } player = &players[actor->lastlook]; if (player->health <= 0) continue; // dead if (!P_CheckSight (actor, player->mo)) continue; // out of sight if (!allaround) { an = R_PointToAngle2 (actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; if (an > ANG90 && an < ANG270) { dist = P_AproxDistance (player->mo->x - actor->x, player->mo->y - actor->y); // if real close, react anyway if (dist > MELEERANGE) continue; // behind back } } actor->target = player->mo; return true; } return false; } // // A_KeenDie // DOOM II special, map 32. // Uses special tag 666. // void A_KeenDie (mobj_t* mo) { thinker_t* th; mobj_t* mo2; line_t junk; A_Fall (mo); // scan the remaining thinkers // to see if all Keens are dead for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acp1 != (actionf_p1)P_MobjThinker) continue; mo2 = (mobj_t *)th; if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) { // other Keen not dead return; } } junk.tag = 666; EV_DoDoor(&junk, vld_open); } // // ACTION ROUTINES // // // A_Look // Stay in state until a player is sighted. // void A_Look (mobj_t* actor) { mobj_t* targ; actor->threshold = 0; // any shot will wake up targ = actor->subsector->sector->soundtarget; if (targ && (targ->flags & MF_SHOOTABLE) ) { actor->target = targ; if ( actor->flags & MF_AMBUSH ) { if (P_CheckSight (actor, actor->target)) goto seeyou; } else goto seeyou; } if (!P_LookForPlayers (actor, false) ) return; // go into chase state seeyou: if (actor->info->seesound) { int sound; switch (actor->info->seesound) { case sfx_posit1: case sfx_posit2: case sfx_posit3: sound = sfx_posit1+P_Random()%3; break; case sfx_bgsit1: case sfx_bgsit2: sound = sfx_bgsit1+P_Random()%2; break; default: sound = actor->info->seesound; break; } if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) { // full volume S_StartSound (NULL, sound); } else S_StartSound (actor, sound); } P_SetMobjState (actor, actor->info->seestate); } // // A_Chase // Actor has a melee attack, // so it tries to close as fast as possible // void A_Chase (mobj_t* actor) { int delta; if (actor->reactiontime) actor->reactiontime--; // modify target threshold if (actor->threshold) { if (!actor->target || actor->target->health <= 0) { actor->threshold = 0; } else actor->threshold--; } // turn towards movement direction if not there yet if (actor->movedir < 8) { actor->angle &= (7<<29); delta = actor->angle - (actor->movedir << 29); if (delta > 0) actor->angle -= ANG90/2; else if (delta < 0) actor->angle += ANG90/2; } if (!actor->target || !(actor->target->flags&MF_SHOOTABLE)) { // look for a new target if (P_LookForPlayers(actor,true)) return; // got a new target P_SetMobjState (actor, actor->info->spawnstate); return; } // do not attack twice in a row if (actor->flags & MF_JUSTATTACKED) { actor->flags &= ~MF_JUSTATTACKED; if (gameskill != sk_nightmare && !fastparm) P_NewChaseDir (actor); return; } // check for melee attack if (actor->info->meleestate && P_CheckMeleeRange (actor)) { if (actor->info->attacksound) S_StartSound (actor, actor->info->attacksound); P_SetMobjState (actor, actor->info->meleestate); return; } // check for missile attack if (actor->info->missilestate) { if (gameskill < sk_nightmare && !fastparm && actor->movecount) { goto nomissile; } if (!P_CheckMissileRange (actor)) goto nomissile; P_SetMobjState (actor, actor->info->missilestate); actor->flags |= MF_JUSTATTACKED; return; } // ? nomissile: // possibly choose another target if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) ) { if (P_LookForPlayers(actor,true)) return; // got a new target } // chase towards player if (--actor->movecount<0 || !P_Move (actor)) { P_NewChaseDir (actor); } // make active sound if (actor->info->activesound && P_Random () < 3) { S_StartSound (actor, actor->info->activesound); } } // // A_FaceTarget // void A_FaceTarget (mobj_t* actor) { if (!actor->target) return; actor->flags &= ~MF_AMBUSH; actor->angle = R_PointToAngle2 (actor->x, actor->y, actor->target->x, actor->target->y); if (actor->target->flags & MF_SHADOW) actor->angle += (P_Random()-P_Random())<<21; } // // A_PosAttack // void A_PosAttack (mobj_t* actor) { int angle; int damage; int slope; if (!actor->target) return; A_FaceTarget (actor); angle = actor->angle; slope = P_AimLineAttack (actor, angle, MISSILERANGE); S_StartSound (actor, sfx_pistol); angle += (P_Random()-P_Random())<<20; damage = ((P_Random()%5)+1)*3; P_LineAttack (actor, angle, MISSILERANGE, slope, damage); } void A_SPosAttack (mobj_t* actor) { int i; int angle; int bangle; int damage; int slope; if (!actor->target) return; S_StartSound (actor, sfx_shotgn); A_FaceTarget (actor); bangle = actor->angle; slope = P_AimLineAttack (actor, bangle, MISSILERANGE); for (i=0 ; i<3 ; i++) { angle = bangle + ((P_Random()-P_Random())<<20); damage = ((P_Random()%5)+1)*3; P_LineAttack (actor, angle, MISSILERANGE, slope, damage); } } void A_CPosAttack (mobj_t* actor) { int angle; int bangle; int damage; int slope; if (!actor->target) return; S_StartSound (actor, sfx_shotgn); A_FaceTarget (actor); bangle = actor->angle; slope = P_AimLineAttack (actor, bangle, MISSILERANGE); angle = bangle + ((P_Random()-P_Random())<<20); damage = ((P_Random()%5)+1)*3; P_LineAttack (actor, angle, MISSILERANGE, slope, damage); } void A_CPosRefire (mobj_t* actor) { // keep firing unless target got out of sight A_FaceTarget (actor); if (P_Random () < 40) return; if (!actor->target || actor->target->health <= 0 || !P_CheckSight (actor, actor->target) ) { P_SetMobjState (actor, actor->info->seestate); } } void A_SpidRefire (mobj_t* actor) { // keep firing unless target got out of sight A_FaceTarget (actor); if (P_Random () < 10) return; if (!actor->target || actor->target->health <= 0 || !P_CheckSight (actor, actor->target) ) { P_SetMobjState (actor, actor->info->seestate); } } void A_BspiAttack (mobj_t *actor) { if (!actor->target) return; A_FaceTarget (actor); // launch a missile P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ); } // // A_TroopAttack // void A_TroopAttack (mobj_t* actor) { int damage; if (!actor->target) return; A_FaceTarget (actor); if (P_CheckMeleeRange (actor)) { S_StartSound (actor, sfx_claw); damage = (P_Random()%8+1)*3; P_DamageMobj (actor->target, actor, actor, damage); return; } // launch a missile P_SpawnMissile (actor, actor->target, MT_TROOPSHOT); } void A_SargAttack (mobj_t* actor) { int damage; if (!actor->target) return; A_FaceTarget (actor); if (P_CheckMeleeRange (actor)) { damage = ((P_Random()%10)+1)*4; P_DamageMobj (actor->target, actor, actor, damage); } } void A_HeadAttack (mobj_t* actor) { int damage; if (!actor->target) return; A_FaceTarget (actor); if (P_CheckMeleeRange (actor)) { damage = (P_Random()%6+1)*10; P_DamageMobj (actor->target, actor, actor, damage); return; } // launch a missile P_SpawnMissile (actor, actor->target, MT_HEADSHOT); } void A_CyberAttack (mobj_t* actor) { if (!actor->target) return; A_FaceTarget (actor); P_SpawnMissile (actor, actor->target, MT_ROCKET); } void A_BruisAttack (mobj_t* actor) { int damage; if (!actor->target) return; if (P_CheckMeleeRange (actor)) { S_StartSound (actor, sfx_claw); damage = (P_Random()%8+1)*10; P_DamageMobj (actor->target, actor, actor, damage); return; } // launch a missile P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT); } // // A_SkelMissile // void A_SkelMissile (mobj_t* actor) { mobj_t* mo; if (!actor->target) return; A_FaceTarget (actor); actor->z += 16*FRACUNIT; // so missile spawns higher mo = P_SpawnMissile (actor, actor->target, MT_TRACER); actor->z -= 16*FRACUNIT; // back to normal mo->x += mo->momx; mo->y += mo->momy; mo->tracer = actor->target; } int TRACEANGLE = 0xc000000; void A_Tracer (mobj_t* actor) { angle_t exact; fixed_t dist; fixed_t slope; mobj_t* dest; mobj_t* th; if (gametic & 3) return; // spawn a puff of smoke behind the rocket P_SpawnPuff (actor->x, actor->y, actor->z); th = P_SpawnMobj (actor->x-actor->momx, actor->y-actor->momy, actor->z, MT_SMOKE); th->momz = FRACUNIT; th->tics -= P_Random()&3; if (th->tics < 1) th->tics = 1; // adjust direction dest = actor->tracer; if (!dest || dest->health <= 0) return; // change angle exact = R_PointToAngle2 (actor->x, actor->y, dest->x, dest->y); if (exact != actor->angle) { if (exact - actor->angle > 0x80000000) { actor->angle -= TRACEANGLE; if (exact - actor->angle < 0x80000000) actor->angle = exact; } else { actor->angle += TRACEANGLE; if (exact - actor->angle > 0x80000000) actor->angle = exact; } } exact = actor->angle>>ANGLETOFINESHIFT; actor->momx = FixedMul (actor->info->speed, finecosine[exact]); actor->momy = FixedMul (actor->info->speed, finesine[exact]); // change slope dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y); dist = dist / actor->info->speed; if (dist < 1) dist = 1; slope = (dest->z+40*FRACUNIT - actor->z) / dist; if (slope < actor->momz) actor->momz -= FRACUNIT/8; else actor->momz += FRACUNIT/8; } void A_SkelWhoosh (mobj_t* actor) { if (!actor->target) return; A_FaceTarget (actor); S_StartSound (actor,sfx_skeswg); } void A_SkelFist (mobj_t* actor) { int damage; if (!actor->target) return; A_FaceTarget (actor); if (P_CheckMeleeRange (actor)) { damage = ((P_Random()%10)+1)*6; S_StartSound (actor, sfx_skepch); P_DamageMobj (actor->target, actor, actor, damage); } } // // PIT_VileCheck // Detect a corpse that could be raised. // mobj_t* corpsehit; mobj_t* vileobj; fixed_t viletryx; fixed_t viletryy; boolean PIT_VileCheck (mobj_t* thing) { int maxdist; boolean check; if (!(thing->flags & MF_CORPSE) ) return true; // not a monster if (thing->tics != -1) return true; // not lying still yet if (thing->info->raisestate == S_NULL) return true; // monster doesn't have a raise state maxdist = thing->info->radius + mobjinfo[MT_VILE].radius; if ( abs(thing->x - viletryx) > maxdist || abs(thing->y - viletryy) > maxdist ) return true; // not actually touching corpsehit = thing; corpsehit->momx = corpsehit->momy = 0; corpsehit->height <<= 2; check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y); corpsehit->height >>= 2; if (!check) return true; // doesn't fit here return false; // got one, so stop checking } // // A_VileChase // Check for ressurecting a body // void A_VileChase (mobj_t* actor) { int xl; int xh; int yl; int yh; int bx; int by; mobjinfo_t* info; mobj_t* temp; if (actor->movedir != DI_NODIR) { // check for corpses to raise viletryx = actor->x + actor->info->speed*xspeed[actor->movedir]; viletryy = actor->y + actor->info->speed*yspeed[actor->movedir]; xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT; xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT; yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT; yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT; vileobj = actor; for (bx=xl ; bx<=xh ; bx++) { for (by=yl ; by<=yh ; by++) { // Call PIT_VileCheck to check // whether object is a corpse // that canbe raised. if (!P_BlockThingsIterator(bx,by,PIT_VileCheck)) { // got one! temp = actor->target; actor->target = corpsehit; A_FaceTarget (actor); actor->target = temp; P_SetMobjState (actor, S_VILE_HEAL1); S_StartSound (corpsehit, sfx_slop); info = corpsehit->info; P_SetMobjState (corpsehit,info->raisestate); corpsehit->height <<= 2; corpsehit->flags = info->flags; corpsehit->health = info->spawnhealth; corpsehit->target = NULL; return; } } } } // Return to normal attack. A_Chase (actor); } // // A_VileStart // void A_VileStart (mobj_t* actor) { S_StartSound (actor, sfx_vilatk); } // // A_Fire // Keep fire in front of player unless out of sight // void A_Fire (mobj_t* actor); void A_StartFire (mobj_t* actor) { S_StartSound(actor,sfx_flamst); A_Fire(actor); } void A_FireCrackle (mobj_t* actor) { S_StartSound(actor,sfx_flame); A_Fire(actor); } void A_Fire (mobj_t* actor) { mobj_t* dest; mobj_t* target; unsigned an; dest = actor->tracer; if (!dest) return; target = P_SubstNullMobj(actor->target); // don't move it if the vile lost sight if (!P_CheckSight (target, dest) ) return; an = dest->angle >> ANGLETOFINESHIFT; P_UnsetThingPosition (actor); actor->x = dest->x + FixedMul (24*FRACUNIT, finecosine[an]); actor->y = dest->y + FixedMul (24*FRACUNIT, finesine[an]); actor->z = dest->z; P_SetThingPosition (actor); } // // A_VileTarget // Spawn the hellfire // void A_VileTarget (mobj_t* actor) { mobj_t* fog; if (!actor->target) return; A_FaceTarget (actor); fog = P_SpawnMobj (actor->target->x, actor->target->x, actor->target->z, MT_FIRE); actor->tracer = fog; fog->target = actor; fog->tracer = actor->target; A_Fire (fog); } // // A_VileAttack // void A_VileAttack (mobj_t* actor) { mobj_t* fire; int an; if (!actor->target) return; A_FaceTarget (actor); if (!P_CheckSight (actor, actor->target) ) return; S_StartSound (actor, sfx_barexp); P_DamageMobj (actor->target, actor, actor, 20); actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; an = actor->angle >> ANGLETOFINESHIFT; fire = actor->tracer; if (!fire) return; // move the fire between the vile and the player fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); P_RadiusAttack (fire, actor, 70 ); } // // Mancubus attack, // firing three missiles (bruisers) // in three different directions? // Doesn't look like it. // #define FATSPREAD (ANG90/8) void A_FatRaise (mobj_t *actor) { A_FaceTarget (actor); S_StartSound (actor, sfx_manatk); } void A_FatAttack1 (mobj_t* actor) { mobj_t* mo; mobj_t* target; int an; A_FaceTarget (actor); // Change direction to ... actor->angle += FATSPREAD; target = P_SubstNullMobj(actor->target); P_SpawnMissile (actor, target, MT_FATSHOT); mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle += FATSPREAD; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); mo->momy = FixedMul (mo->info->speed, finesine[an]); } void A_FatAttack2 (mobj_t* actor) { mobj_t* mo; mobj_t* target; int an; A_FaceTarget (actor); // Now here choose opposite deviation. actor->angle -= FATSPREAD; target = P_SubstNullMobj(actor->target); P_SpawnMissile (actor, target, MT_FATSHOT); mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle -= FATSPREAD*2; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); mo->momy = FixedMul (mo->info->speed, finesine[an]); } void A_FatAttack3 (mobj_t* actor) { mobj_t* mo; mobj_t* target; int an; A_FaceTarget (actor); target = P_SubstNullMobj(actor->target); mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle -= FATSPREAD/2; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); mo->momy = FixedMul (mo->info->speed, finesine[an]); mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle += FATSPREAD/2; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); mo->momy = FixedMul (mo->info->speed, finesine[an]); } // // SkullAttack // Fly at the player like a missile. // #define SKULLSPEED (20*FRACUNIT) void A_SkullAttack (mobj_t* actor) { mobj_t* dest; angle_t an; int dist; if (!actor->target) return; dest = actor->target; actor->flags |= MF_SKULLFLY; S_StartSound (actor, actor->info->attacksound); A_FaceTarget (actor); an = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul (SKULLSPEED, finecosine[an]); actor->momy = FixedMul (SKULLSPEED, finesine[an]); dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y); dist = dist / SKULLSPEED; if (dist < 1) dist = 1; actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist; } // // A_PainShootSkull // Spawn a lost soul and launch it at the target // void A_PainShootSkull ( mobj_t* actor, angle_t angle ) { fixed_t x; fixed_t y; fixed_t z; mobj_t* newmobj; angle_t an; int prestep; int count; thinker_t* currentthinker; // count total number of skull currently on the level count = 0; currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { if ( (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) && ((mobj_t *)currentthinker)->type == MT_SKULL) count++; currentthinker = currentthinker->next; } // if there are allready 20 skulls on the level, // don't spit another one if (count > 20) return; // okay, there's playe for another one an = angle >> ANGLETOFINESHIFT; prestep = 4*FRACUNIT + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2; x = actor->x + FixedMul (prestep, finecosine[an]); y = actor->y + FixedMul (prestep, finesine[an]); z = actor->z + 8*FRACUNIT; newmobj = P_SpawnMobj (x , y, z, MT_SKULL); // Check for movements. if (!P_TryMove (newmobj, newmobj->x, newmobj->y)) { // kill it immediately P_DamageMobj (newmobj,actor,actor,10000); return; } newmobj->target = actor->target; A_SkullAttack (newmobj); } // // A_PainAttack // Spawn a lost soul and launch it at the target // void A_PainAttack (mobj_t* actor) { if (!actor->target) return; A_FaceTarget (actor); A_PainShootSkull (actor, actor->angle); } void A_PainDie (mobj_t* actor) { A_Fall (actor); A_PainShootSkull (actor, actor->angle+ANG90); A_PainShootSkull (actor, actor->angle+ANG180); A_PainShootSkull (actor, actor->angle+ANG270); } void A_Scream (mobj_t* actor) { int sound; switch (actor->info->deathsound) { case 0: return; case sfx_podth1: case sfx_podth2: case sfx_podth3: sound = sfx_podth1 + P_Random ()%3; break; case sfx_bgdth1: case sfx_bgdth2: sound = sfx_bgdth1 + P_Random ()%2; break; default: sound = actor->info->deathsound; break; } // Check for bosses. if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) { // full volume S_StartSound (NULL, sound); } else S_StartSound (actor, sound); } void A_XScream (mobj_t* actor) { S_StartSound (actor, sfx_slop); } void A_Pain (mobj_t* actor) { if (actor->info->painsound) S_StartSound (actor, actor->info->painsound); } void A_Fall (mobj_t *actor) { // actor is on ground, it can be walked over actor->flags &= ~MF_SOLID; // So change this if corpse objects // are meant to be obstacles. } // // A_Explode // void A_Explode (mobj_t* thingy) { P_RadiusAttack(thingy, thingy->target, 128); } // Check whether the death of the specified monster type is allowed // to trigger the end of episode special action. // // This behavior changed in v1.9, the most notable effect of which // was to break uac_dead.wad static boolean CheckBossEnd(mobjtype_t motype) { if (gameversion < exe_ultimate) { if (gamemap != 8) { return false; } // Baron death on later episodes is nothing special. if (motype == MT_BRUISER && gameepisode != 1) { return false; } return true; } else { // New logic that appeared in Ultimate Doom. // Looks like the logic was overhauled while adding in the // episode 4 support. Now bosses only trigger on their // specific episode. switch(gameepisode) { case 1: return gamemap == 8 && motype == MT_BRUISER; case 2: return gamemap == 8 && motype == MT_CYBORG; case 3: return gamemap == 8 && motype == MT_SPIDER; case 4: return (gamemap == 6 && motype == MT_CYBORG) || (gamemap == 8 && motype == MT_SPIDER); default: return gamemap == 8; } } } // // A_BossDeath // Possibly trigger special effects // if on first boss level // void A_BossDeath (mobj_t* mo) { thinker_t* th; mobj_t* mo2; line_t junk; int i; if ( gamemode == commercial) { if (gamemap != 7) return; if ((mo->type != MT_FATSO) && (mo->type != MT_BABY)) return; } else { if (!CheckBossEnd(mo->type)) { return; } } // make sure there is a player alive for victory for (i=0 ; i 0) break; if (i==MAXPLAYERS) return; // no one left alive, so do not end game // scan the remaining thinkers to see // if all bosses are dead for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acp1 != (actionf_p1)P_MobjThinker) continue; mo2 = (mobj_t *)th; if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) { // other boss not dead return; } } // victory! if ( gamemode == commercial) { if (gamemap == 7) { if (mo->type == MT_FATSO) { junk.tag = 666; EV_DoFloor(&junk,lowerFloorToLowest); return; } if (mo->type == MT_BABY) { junk.tag = 667; EV_DoFloor(&junk,raiseToTexture); return; } } } else { switch(gameepisode) { case 1: junk.tag = 666; EV_DoFloor (&junk, lowerFloorToLowest); return; break; case 4: switch(gamemap) { case 6: junk.tag = 666; EV_DoDoor (&junk, vld_blazeOpen); return; break; case 8: junk.tag = 666; EV_DoFloor (&junk, lowerFloorToLowest); return; break; } } } G_ExitLevel (); } void A_Hoof (mobj_t* mo) { S_StartSound (mo, sfx_hoof); A_Chase (mo); } void A_Metal (mobj_t* mo) { S_StartSound (mo, sfx_metal); A_Chase (mo); } void A_BabyMetal (mobj_t* mo) { S_StartSound (mo, sfx_bspwlk); A_Chase (mo); } void A_OpenShotgun2 ( player_t* player, pspdef_t* psp ) { S_StartSound (player->mo, sfx_dbopn); } void A_LoadShotgun2 ( player_t* player, pspdef_t* psp ) { S_StartSound (player->mo, sfx_dbload); } void A_ReFire ( player_t* player, pspdef_t* psp ); void A_CloseShotgun2 ( player_t* player, pspdef_t* psp ) { S_StartSound (player->mo, sfx_dbcls); A_ReFire(player,psp); } mobj_t* braintargets[32]; int numbraintargets; int braintargeton = 0; void A_BrainAwake (mobj_t* mo) { thinker_t* thinker; mobj_t* m; // find all the target spots numbraintargets = 0; braintargeton = 0; thinker = thinkercap.next; for (thinker = thinkercap.next ; thinker != &thinkercap ; thinker = thinker->next) { if (thinker->function.acp1 != (actionf_p1)P_MobjThinker) continue; // not a mobj m = (mobj_t *)thinker; if (m->type == MT_BOSSTARGET ) { braintargets[numbraintargets] = m; numbraintargets++; } } S_StartSound (NULL,sfx_bossit); } void A_BrainPain (mobj_t* mo) { S_StartSound (NULL,sfx_bospn); } void A_BrainScream (mobj_t* mo) { int x; int y; int z; mobj_t* th; for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8) { y = mo->y - 320*FRACUNIT; z = 128 + P_Random()*2*FRACUNIT; th = P_SpawnMobj (x,y,z, MT_ROCKET); th->momz = P_Random()*512; P_SetMobjState (th, S_BRAINEXPLODE1); th->tics -= P_Random()&7; if (th->tics < 1) th->tics = 1; } S_StartSound (NULL,sfx_bosdth); } void A_BrainExplode (mobj_t* mo) { int x; int y; int z; mobj_t* th; x = mo->x + (P_Random () - P_Random ())*2048; y = mo->y; z = 128 + P_Random()*2*FRACUNIT; th = P_SpawnMobj (x,y,z, MT_ROCKET); th->momz = P_Random()*512; P_SetMobjState (th, S_BRAINEXPLODE1); th->tics -= P_Random()&7; if (th->tics < 1) th->tics = 1; } void A_BrainDie (mobj_t* mo) { G_ExitLevel (); } void A_BrainSpit (mobj_t* mo) { mobj_t* targ; mobj_t* newmobj; static int easy = 0; easy ^= 1; if (gameskill <= sk_easy && (!easy)) return; // shoot a cube at current target targ = braintargets[braintargeton]; braintargeton = (braintargeton+1)%numbraintargets; // spawn brain missile newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT); newmobj->target = targ; newmobj->reactiontime = ((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics; S_StartSound(NULL, sfx_bospit); } void A_SpawnFly (mobj_t* mo); // travelling cube sound void A_SpawnSound (mobj_t* mo) { S_StartSound (mo,sfx_boscub); A_SpawnFly(mo); } void A_SpawnFly (mobj_t* mo) { mobj_t* newmobj; mobj_t* fog; mobj_t* targ; int r; mobjtype_t type; if (--mo->reactiontime) return; // still flying targ = P_SubstNullMobj(mo->target); // First spawn teleport fog. fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE); S_StartSound (fog, sfx_telept); // Randomly select monster to spawn. r = P_Random (); // Probability distribution (kind of :), // decreasing likelihood. if ( r<50 ) type = MT_TROOP; else if (r<90) type = MT_SERGEANT; else if (r<120) type = MT_SHADOWS; else if (r<130) type = MT_PAIN; else if (r<160) type = MT_HEAD; else if (r<162) type = MT_VILE; else if (r<172) type = MT_UNDEAD; else if (r<192) type = MT_BABY; else if (r<222) type = MT_FATSO; else if (r<246) type = MT_KNIGHT; else type = MT_BRUISER; newmobj = P_SpawnMobj (targ->x, targ->y, targ->z, type); if (P_LookForPlayers (newmobj, true) ) P_SetMobjState (newmobj, newmobj->info->seestate); // telefrag anything in this spot P_TeleportMove (newmobj, newmobj->x, newmobj->y); // remove self (i.e., cube). P_RemoveMobj (mo); } void A_PlayerScream (mobj_t* mo) { // Default death sound. int sound = sfx_pldeth; if ( (gamemode == commercial) && (mo->health < -50)) { // IF THE PLAYER DIES // LESS THAN -50% WITHOUT GIBBING sound = sfx_pdiehi; } S_StartSound (mo, sound); } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_floor.c000066400000000000000000000262351257432200600226460ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Floor animation: raising stairs. // #include "z_zone.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" // // FLOORS // // // Move a plane (floor or ceiling) and check for crushing // result_e T_MovePlane ( sector_t* sector, fixed_t speed, fixed_t dest, boolean crush, int floorOrCeiling, int direction ) { boolean flag; fixed_t lastpos; switch(floorOrCeiling) { case 0: // FLOOR switch(direction) { case -1: // DOWN if (sector->floorheight - speed < dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->floorheight =lastpos; P_ChangeSector(sector,crush); //return crushed; } return pastdest; } else { lastpos = sector->floorheight; sector->floorheight -= speed; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector,crush); return crushed; } } break; case 1: // UP if (sector->floorheight + speed > dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector,crush); //return crushed; } return pastdest; } else { // COULD GET CRUSHED lastpos = sector->floorheight; sector->floorheight += speed; flag = P_ChangeSector(sector,crush); if (flag == true) { if (crush == true) return crushed; sector->floorheight = lastpos; P_ChangeSector(sector,crush); return crushed; } } break; } break; case 1: // CEILING switch(direction) { case -1: // DOWN if (sector->ceilingheight - speed < dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector,crush); //return crushed; } return pastdest; } else { // COULD GET CRUSHED lastpos = sector->ceilingheight; sector->ceilingheight -= speed; flag = P_ChangeSector(sector,crush); if (flag == true) { if (crush == true) return crushed; sector->ceilingheight = lastpos; P_ChangeSector(sector,crush); return crushed; } } break; case 1: // UP if (sector->ceilingheight + speed > dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector,crush); //return crushed; } return pastdest; } else { lastpos = sector->ceilingheight; sector->ceilingheight += speed; flag = P_ChangeSector(sector,crush); // UNUSED #if 0 if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector,crush); return crushed; } #endif } break; } break; } return ok; } // // MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN) // void T_MoveFloor(floormove_t* floor) { result_e res; res = T_MovePlane(floor->sector, floor->speed, floor->floordestheight, floor->crush,0,floor->direction); if (!(leveltime&7)) S_StartSound(&floor->sector->soundorg, sfx_stnmov); if (res == pastdest) { floor->sector->specialdata = NULL; if (floor->direction == 1) { switch(floor->type) { case donutRaise: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } } else if (floor->direction == -1) { switch(floor->type) { case lowerAndChange: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } } P_RemoveThinker(&floor->thinker); S_StartSound(&floor->sector->soundorg, sfx_pstop); } } // // HANDLE FLOOR TYPES // int EV_DoFloor ( line_t* line, floor_e floortype ) { int secnum; int rtn; int i; sector_t* sec; floormove_t* floor; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // new floor thinker rtn = 1; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); sec->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = floortype; floor->crush = false; switch(floortype) { case lowerFloor: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindHighestFloorSurrounding(sec); break; case lowerFloorToLowest: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestFloorSurrounding(sec); break; case turboLower: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED * 4; floor->floordestheight = P_FindHighestFloorSurrounding(sec); if (floor->floordestheight != sec->floorheight) floor->floordestheight += 8*FRACUNIT; break; case raiseFloorCrush: floor->crush = true; case raiseFloor: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestCeilingSurrounding(sec); if (floor->floordestheight > sec->ceilingheight) floor->floordestheight = sec->ceilingheight; floor->floordestheight -= (8*FRACUNIT)* (floortype == raiseFloorCrush); break; case raiseFloorTurbo: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED*4; floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); break; case raiseFloorToNearest: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); break; case raiseFloor24: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; break; case raiseFloor512: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT; break; case raiseFloor24AndChange: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; sec->floorpic = line->frontsector->floorpic; sec->special = line->frontsector->special; break; case raiseToTexture: { int minsize = INT_MAX; side_t* side; floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; for (i = 0; i < sec->linecount; i++) { if (twoSided (secnum, i) ) { side = getSide(secnum,i,0); if (side->bottomtexture >= 0) if (textureheight[side->bottomtexture] < minsize) minsize = textureheight[side->bottomtexture]; side = getSide(secnum,i,1); if (side->bottomtexture >= 0) if (textureheight[side->bottomtexture] < minsize) minsize = textureheight[side->bottomtexture]; } } floor->floordestheight = floor->sector->floorheight + minsize; } break; case lowerAndChange: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestFloorSurrounding(sec); floor->texture = sec->floorpic; for (i = 0; i < sec->linecount; i++) { if ( twoSided(secnum, i) ) { if (getSide(secnum,i,0)->sector-sectors == secnum) { sec = getSector(secnum,i,1); if (sec->floorheight == floor->floordestheight) { floor->texture = sec->floorpic; floor->newspecial = sec->special; break; } } else { sec = getSector(secnum,i,0); if (sec->floorheight == floor->floordestheight) { floor->texture = sec->floorpic; floor->newspecial = sec->special; break; } } } } default: break; } } return rtn; } // // BUILD A STAIRCASE! // int EV_BuildStairs ( line_t* line, stair_e type ) { int secnum; int height; int i; int newsecnum; int texture; int ok; int rtn; sector_t* sec; sector_t* tsec; floormove_t* floor; fixed_t stairsize = 0; fixed_t speed = 0; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // new floor thinker rtn = 1; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); sec->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->direction = 1; floor->sector = sec; switch(type) { case build8: speed = FLOORSPEED/4; stairsize = 8*FRACUNIT; break; case turbo16: speed = FLOORSPEED*4; stairsize = 16*FRACUNIT; break; } floor->speed = speed; height = sec->floorheight + stairsize; floor->floordestheight = height; // Initialize floor->type = lowerFloor; floor->crush = true; texture = sec->floorpic; // Find next sector to raise // 1. Find 2-sided line with same sector side[0] // 2. Other side is the next sector to raise do { ok = 0; for (i = 0;i < sec->linecount;i++) { if ( !((sec->lines[i])->flags & ML_TWOSIDED) ) continue; tsec = (sec->lines[i])->frontsector; newsecnum = tsec-sectors; if (secnum != newsecnum) continue; tsec = (sec->lines[i])->backsector; newsecnum = tsec - sectors; if (tsec->floorpic != texture) continue; height += stairsize; if (tsec->specialdata) continue; sec = tsec; secnum = newsecnum; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); sec->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->direction = 1; floor->sector = sec; floor->speed = speed; floor->floordestheight = height; // Initialize floor->type = lowerFloor; floor->crush = true; ok = 1; break; } } while(ok); } return rtn; } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_inter.c000066400000000000000000000451231257432200600226430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Handling interactions (i.e., collisions). // // Data. #include "doomdef.h" #include "dstrings.h" #include "sounds.h" #include "deh_main.h" #include "deh_misc.h" #include "doomstat.h" #include "m_random.h" #include "i_system.h" #include "am_map.h" #include "p_local.h" #include "s_sound.h" #include "p_inter.h" #define BONUSADD 6 // a weapon is found with two clip loads, // a big item has five clip loads int maxammo[NUMAMMO] = {200, 50, 300, 50}; int clipammo[NUMAMMO] = {10, 4, 20, 1}; // // GET STUFF // // // P_GiveAmmo // Num is the number of clip loads, // not the individual count (0= 1/2 clip). // Returns false if the ammo can't be picked up at all // boolean P_GiveAmmo ( player_t* player, ammotype_t ammo, int num ) { int oldammo; if (ammo == am_noammo) return false; if (ammo > NUMAMMO) I_Error ("P_GiveAmmo: bad type %i", ammo); if ( player->ammo[ammo] == player->maxammo[ammo] ) return false; if (num) num *= clipammo[ammo]; else num = clipammo[ammo]/2; if (gameskill == sk_baby || gameskill == sk_nightmare) { // give double ammo in trainer mode, // you'll need in nightmare num <<= 1; } oldammo = player->ammo[ammo]; player->ammo[ammo] += num; if (player->ammo[ammo] > player->maxammo[ammo]) player->ammo[ammo] = player->maxammo[ammo]; // If non zero ammo, // don't change up weapons, // player was lower on purpose. if (oldammo) return true; // We were down to zero, // so select a new weapon. // Preferences are not user selectable. switch (ammo) { case am_clip: if (player->readyweapon == wp_fist) { if (player->weaponowned[wp_chaingun]) player->pendingweapon = wp_chaingun; else player->pendingweapon = wp_pistol; } break; case am_shell: if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) { if (player->weaponowned[wp_shotgun]) player->pendingweapon = wp_shotgun; } break; case am_cell: if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) { if (player->weaponowned[wp_plasma]) player->pendingweapon = wp_plasma; } break; case am_misl: if (player->readyweapon == wp_fist) { if (player->weaponowned[wp_missile]) player->pendingweapon = wp_missile; } default: break; } return true; } // // P_GiveWeapon // The weapon name may have a MF_DROPPED flag ored in. // boolean P_GiveWeapon ( player_t* player, weapontype_t weapon, boolean dropped ) { boolean gaveammo; boolean gaveweapon; if (netgame && (deathmatch!=2) && !dropped ) { // leave placed weapons forever on net games if (player->weaponowned[weapon]) return false; player->bonuscount += BONUSADD; player->weaponowned[weapon] = true; if (deathmatch) P_GiveAmmo (player, weaponinfo[weapon].ammo, 5); else P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); player->pendingweapon = weapon; if (player == &players[consoleplayer]) S_StartSound (NULL, sfx_wpnup); return false; } if (weaponinfo[weapon].ammo != am_noammo) { // give one clip with a dropped weapon, // two clips with a found weapon if (dropped) gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1); else gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); } else gaveammo = false; if (player->weaponowned[weapon]) gaveweapon = false; else { gaveweapon = true; player->weaponowned[weapon] = true; player->pendingweapon = weapon; } return (gaveweapon || gaveammo); } // // P_GiveBody // Returns false if the body isn't needed at all // boolean P_GiveBody ( player_t* player, int num ) { if (player->health >= MAXHEALTH) return false; player->health += num; if (player->health > MAXHEALTH) player->health = MAXHEALTH; player->mo->health = player->health; return true; } // // P_GiveArmor // Returns false if the armor is worse // than the current armor. // boolean P_GiveArmor ( player_t* player, int armortype ) { int hits; hits = armortype*100; if (player->armorpoints >= hits) return false; // don't pick up player->armortype = armortype; player->armorpoints = hits; return true; } // // P_GiveCard // void P_GiveCard ( player_t* player, card_t card ) { if (player->cards[card]) return; player->bonuscount = BONUSADD; player->cards[card] = 1; } // // P_GivePower // boolean P_GivePower ( player_t* player, int /*powertype_t*/ power ) { if (power == pw_invulnerability) { player->powers[power] = INVULNTICS; return true; } if (power == pw_invisibility) { player->powers[power] = INVISTICS; player->mo->flags |= MF_SHADOW; return true; } if (power == pw_infrared) { player->powers[power] = INFRATICS; return true; } if (power == pw_ironfeet) { player->powers[power] = IRONTICS; return true; } if (power == pw_strength) { P_GiveBody (player, 100); player->powers[power] = 1; return true; } if (player->powers[power]) return false; // already got it player->powers[power] = 1; return true; } // // P_TouchSpecialThing // void P_TouchSpecialThing ( mobj_t* special, mobj_t* toucher ) { player_t* player; int i; fixed_t delta; int sound; delta = special->z - toucher->z; if (delta > toucher->height || delta < -8*FRACUNIT) { // out of reach return; } sound = sfx_itemup; player = toucher->player; // Dead thing touching. // Can happen with a sliding player corpse. if (toucher->health <= 0) return; // Identify by sprite. switch (special->sprite) { // armor case SPR_ARM1: if (!P_GiveArmor (player, deh_green_armor_class)) return; player->message = DEH_String(GOTARMOR); break; case SPR_ARM2: if (!P_GiveArmor (player, deh_blue_armor_class)) return; player->message = DEH_String(GOTMEGA); break; // bonus items case SPR_BON1: player->health++; // can go over 100% if (player->health > deh_max_health) player->health = deh_max_health; player->mo->health = player->health; player->message = DEH_String(GOTHTHBONUS); break; case SPR_BON2: player->armorpoints++; // can go over 100% if (player->armorpoints > deh_max_armor) player->armorpoints = deh_max_armor; // deh_green_armor_class only applies to the green armor shirt; // for the armor helmets, armortype 1 is always used. if (!player->armortype) player->armortype = 1; player->message = DEH_String(GOTARMBONUS); break; case SPR_SOUL: player->health += deh_soulsphere_health; if (player->health > deh_max_soulsphere) player->health = deh_max_soulsphere; player->mo->health = player->health; player->message = DEH_String(GOTSUPER); sound = sfx_getpow; break; case SPR_MEGA: if (gamemode != commercial) return; player->health = deh_megasphere_health; player->mo->health = player->health; // We always give armor type 2 for the megasphere; dehacked only // affects the MegaArmor. P_GiveArmor (player, 2); player->message = DEH_String(GOTMSPHERE); sound = sfx_getpow; break; // cards // leave cards for everyone case SPR_BKEY: if (!player->cards[it_bluecard]) player->message = DEH_String(GOTBLUECARD); P_GiveCard (player, it_bluecard); if (!netgame) break; return; case SPR_YKEY: if (!player->cards[it_yellowcard]) player->message = DEH_String(GOTYELWCARD); P_GiveCard (player, it_yellowcard); if (!netgame) break; return; case SPR_RKEY: if (!player->cards[it_redcard]) player->message = DEH_String(GOTREDCARD); P_GiveCard (player, it_redcard); if (!netgame) break; return; case SPR_BSKU: if (!player->cards[it_blueskull]) player->message = DEH_String(GOTBLUESKUL); P_GiveCard (player, it_blueskull); if (!netgame) break; return; case SPR_YSKU: if (!player->cards[it_yellowskull]) player->message = DEH_String(GOTYELWSKUL); P_GiveCard (player, it_yellowskull); if (!netgame) break; return; case SPR_RSKU: if (!player->cards[it_redskull]) player->message = DEH_String(GOTREDSKULL); P_GiveCard (player, it_redskull); if (!netgame) break; return; // medikits, heals case SPR_STIM: if (!P_GiveBody (player, 10)) return; player->message = DEH_String(GOTSTIM); break; case SPR_MEDI: if (!P_GiveBody (player, 25)) return; if (player->health < 25) player->message = DEH_String(GOTMEDINEED); else player->message = DEH_String(GOTMEDIKIT); break; // power ups case SPR_PINV: if (!P_GivePower (player, pw_invulnerability)) return; player->message = DEH_String(GOTINVUL); sound = sfx_getpow; break; case SPR_PSTR: if (!P_GivePower (player, pw_strength)) return; player->message = DEH_String(GOTBERSERK); if (player->readyweapon != wp_fist) player->pendingweapon = wp_fist; sound = sfx_getpow; break; case SPR_PINS: if (!P_GivePower (player, pw_invisibility)) return; player->message = DEH_String(GOTINVIS); sound = sfx_getpow; break; case SPR_SUIT: if (!P_GivePower (player, pw_ironfeet)) return; player->message = DEH_String(GOTSUIT); sound = sfx_getpow; break; case SPR_PMAP: if (!P_GivePower (player, pw_allmap)) return; player->message = DEH_String(GOTMAP); sound = sfx_getpow; break; case SPR_PVIS: if (!P_GivePower (player, pw_infrared)) return; player->message = DEH_String(GOTVISOR); sound = sfx_getpow; break; // ammo case SPR_CLIP: if (special->flags & MF_DROPPED) { if (!P_GiveAmmo (player,am_clip,0)) return; } else { if (!P_GiveAmmo (player,am_clip,1)) return; } player->message = DEH_String(GOTCLIP); break; case SPR_AMMO: if (!P_GiveAmmo (player, am_clip,5)) return; player->message = DEH_String(GOTCLIPBOX); break; case SPR_ROCK: if (!P_GiveAmmo (player, am_misl,1)) return; player->message = DEH_String(GOTROCKET); break; case SPR_BROK: if (!P_GiveAmmo (player, am_misl,5)) return; player->message = DEH_String(GOTROCKBOX); break; case SPR_CELL: if (!P_GiveAmmo (player, am_cell,1)) return; player->message = DEH_String(GOTCELL); break; case SPR_CELP: if (!P_GiveAmmo (player, am_cell,5)) return; player->message = DEH_String(GOTCELLBOX); break; case SPR_SHEL: if (!P_GiveAmmo (player, am_shell,1)) return; player->message = DEH_String(GOTSHELLS); break; case SPR_SBOX: if (!P_GiveAmmo (player, am_shell,5)) return; player->message = DEH_String(GOTSHELLBOX); break; case SPR_BPAK: if (!player->backpack) { for (i=0 ; imaxammo[i] *= 2; player->backpack = true; } for (i=0 ; imessage = DEH_String(GOTBACKPACK); break; // weapons case SPR_BFUG: if (!P_GiveWeapon (player, wp_bfg, false) ) return; player->message = DEH_String(GOTBFG9000); sound = sfx_wpnup; break; case SPR_MGUN: if (!P_GiveWeapon(player, wp_chaingun, (special->flags & MF_DROPPED) != 0)) return; player->message = DEH_String(GOTCHAINGUN); sound = sfx_wpnup; break; case SPR_CSAW: if (!P_GiveWeapon (player, wp_chainsaw, false) ) return; player->message = DEH_String(GOTCHAINSAW); sound = sfx_wpnup; break; case SPR_LAUN: if (!P_GiveWeapon (player, wp_missile, false) ) return; player->message = DEH_String(GOTLAUNCHER); sound = sfx_wpnup; break; case SPR_PLAS: if (!P_GiveWeapon (player, wp_plasma, false) ) return; player->message = DEH_String(GOTPLASMA); sound = sfx_wpnup; break; case SPR_SHOT: if (!P_GiveWeapon(player, wp_shotgun, (special->flags & MF_DROPPED) != 0)) return; player->message = DEH_String(GOTSHOTGUN); sound = sfx_wpnup; break; case SPR_SGN2: if (!P_GiveWeapon(player, wp_supershotgun, (special->flags & MF_DROPPED) != 0)) return; player->message = DEH_String(GOTSHOTGUN2); sound = sfx_wpnup; break; default: I_Error ("P_SpecialThing: Unknown gettable thing"); } if (special->flags & MF_COUNTITEM) player->itemcount++; P_RemoveMobj (special); player->bonuscount += BONUSADD; if (player == &players[consoleplayer]) S_StartSound (NULL, sound); } // // KillMobj // void P_KillMobj ( mobj_t* source, mobj_t* target ) { mobjtype_t item; mobj_t* mo; target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); if (target->type != MT_SKULL) target->flags &= ~MF_NOGRAVITY; target->flags |= MF_CORPSE|MF_DROPOFF; target->height >>= 2; if (source && source->player) { // count for intermission if (target->flags & MF_COUNTKILL) source->player->killcount++; if (target->player) source->player->frags[target->player-players]++; } else if (!netgame && (target->flags & MF_COUNTKILL) ) { // count all monster deaths, // even those caused by other monsters players[0].killcount++; } if (target->player) { // count environment kills against you if (!source) target->player->frags[target->player-players]++; target->flags &= ~MF_SOLID; target->player->playerstate = PST_DEAD; P_DropWeapon (target->player); if (target->player == &players[consoleplayer] && automapactive) { // don't die in auto map, // switch view prior to dying AM_Stop (); } } if (target->health < -target->info->spawnhealth && target->info->xdeathstate) { P_SetMobjState (target, target->info->xdeathstate); } else P_SetMobjState (target, target->info->deathstate); target->tics -= P_Random()&3; if (target->tics < 1) target->tics = 1; // I_StartSound (&actor->r, actor->info->deathsound); // In Chex Quest, monsters don't drop items. if (gameversion == exe_chex) { return; } // Drop stuff. // This determines the kind of object spawned // during the death frame of a thing. switch (target->type) { case MT_WOLFSS: case MT_POSSESSED: item = MT_CLIP; break; case MT_SHOTGUY: item = MT_SHOTGUN; break; case MT_CHAINGUY: item = MT_CHAINGUN; break; default: return; } mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item); mo->flags |= MF_DROPPED; // special versions of items } // // P_DamageMobj // Damages both enemies and players // "inflictor" is the thing that caused the damage // creature or missile, can be NULL (slime, etc) // "source" is the thing to target after taking damage // creature or NULL // Source and inflictor are the same for melee attacks. // Source can be NULL for slime, barrel explosions // and other environmental stuff. // void P_DamageMobj ( mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage ) { unsigned ang; int saved; player_t* player; fixed_t thrust; int temp; if ( !(target->flags & MF_SHOOTABLE) ) return; // shouldn't happen... if (target->health <= 0) return; if ( target->flags & MF_SKULLFLY ) { target->momx = target->momy = target->momz = 0; } player = target->player; if (player && gameskill == sk_baby) damage >>= 1; // take half damage in trainer mode // Some close combat weapons should not // inflict thrust and push the victim out of reach, // thus kick away unless using the chainsaw. if (inflictor && !(target->flags & MF_NOCLIP) && (!source || !source->player || source->player->readyweapon != wp_chainsaw)) { ang = R_PointToAngle2 ( inflictor->x, inflictor->y, target->x, target->y); thrust = damage*(FRACUNIT>>3)*100/target->info->mass; // make fall forwards sometimes if ( damage < 40 && damage > target->health && target->z - inflictor->z > 64*FRACUNIT && (P_Random ()&1) ) { ang += ANG180; thrust *= 4; } ang >>= ANGLETOFINESHIFT; target->momx += FixedMul (thrust, finecosine[ang]); target->momy += FixedMul (thrust, finesine[ang]); } // player specific if (player) { // end of game hell hack if (target->subsector->sector->special == 11 && damage >= target->health) { damage = target->health - 1; } // Below certain threshold, // ignore damage in GOD mode, or with INVUL power. if ( damage < 1000 && ( (player->cheats&CF_GODMODE) || player->powers[pw_invulnerability] ) ) { return; } if (player->armortype) { if (player->armortype == 1) saved = damage/3; else saved = damage/2; if (player->armorpoints <= saved) { // armor is used up saved = player->armorpoints; player->armortype = 0; } player->armorpoints -= saved; damage -= saved; } player->health -= damage; // mirror mobj health here for Dave if (player->health < 0) player->health = 0; player->attacker = source; player->damagecount += damage; // add damage after armor / invuln if (player->damagecount > 100) player->damagecount = 100; // teleport stomp does 10k points... temp = damage < 100 ? damage : 100; if (player == &players[consoleplayer]) I_Tactile (40,10,40+temp*2); } // do the damage target->health -= damage; if (target->health <= 0) { P_KillMobj (source, target); return; } if ( (P_Random () < target->info->painchance) && !(target->flags&MF_SKULLFLY) ) { target->flags |= MF_JUSTHIT; // fight back! P_SetMobjState (target, target->info->painstate); } target->reactiontime = 0; // we're awake now... if ( (!target->threshold || target->type == MT_VILE) && source && source != target && source->type != MT_VILE) { // if not intent on another player, // chase after this one target->target = source; target->threshold = BASETHRESHOLD; if (target->state == &states[target->info->spawnstate] && target->info->seestate != S_NULL) P_SetMobjState (target, target->info->seestate); } } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_inter.h000066400000000000000000000013041257432200600226410ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __P_INTER__ #define __P_INTER__ boolean P_GivePower(player_t*, int); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/p_lights.c000066400000000000000000000145601257432200600230150ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Handle Sector base lighting effects. // Muzzle flash? // #include "z_zone.h" #include "m_random.h" #include "doomdef.h" #include "p_local.h" // State. #include "r_state.h" // // FIRELIGHT FLICKER // // // T_FireFlicker // void T_FireFlicker (fireflicker_t* flick) { int amount; if (--flick->count) return; amount = (P_Random()&3)*16; if (flick->sector->lightlevel - amount < flick->minlight) flick->sector->lightlevel = flick->minlight; else flick->sector->lightlevel = flick->maxlight - amount; flick->count = 4; } // // P_SpawnFireFlicker // void P_SpawnFireFlicker (sector_t* sector) { fireflicker_t* flick; // Note that we are resetting sector attributes. // Nothing special about it during gameplay. sector->special = 0; flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0); P_AddThinker (&flick->thinker); flick->thinker.function.acp1 = (actionf_p1) T_FireFlicker; flick->sector = sector; flick->maxlight = sector->lightlevel; flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel)+16; flick->count = 4; } // // BROKEN LIGHT FLASHING // // // T_LightFlash // Do flashing lights. // void T_LightFlash (lightflash_t* flash) { if (--flash->count) return; if (flash->sector->lightlevel == flash->maxlight) { flash-> sector->lightlevel = flash->minlight; flash->count = (P_Random()&flash->mintime)+1; } else { flash-> sector->lightlevel = flash->maxlight; flash->count = (P_Random()&flash->maxtime)+1; } } // // P_SpawnLightFlash // After the map has been loaded, scan each sector // for specials that spawn thinkers // void P_SpawnLightFlash (sector_t* sector) { lightflash_t* flash; // nothing special about it during gameplay sector->special = 0; flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); P_AddThinker (&flash->thinker); flash->thinker.function.acp1 = (actionf_p1) T_LightFlash; flash->sector = sector; flash->maxlight = sector->lightlevel; flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); flash->maxtime = 64; flash->mintime = 7; flash->count = (P_Random()&flash->maxtime)+1; } // // STROBE LIGHT FLASHING // // // T_StrobeFlash // void T_StrobeFlash (strobe_t* flash) { if (--flash->count) return; if (flash->sector->lightlevel == flash->minlight) { flash-> sector->lightlevel = flash->maxlight; flash->count = flash->brighttime; } else { flash-> sector->lightlevel = flash->minlight; flash->count =flash->darktime; } } // // P_SpawnStrobeFlash // After the map has been loaded, scan each sector // for specials that spawn thinkers // void P_SpawnStrobeFlash ( sector_t* sector, int fastOrSlow, int inSync ) { strobe_t* flash; flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); P_AddThinker (&flash->thinker); flash->sector = sector; flash->darktime = fastOrSlow; flash->brighttime = STROBEBRIGHT; flash->thinker.function.acp1 = (actionf_p1) T_StrobeFlash; flash->maxlight = sector->lightlevel; flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); if (flash->minlight == flash->maxlight) flash->minlight = 0; // nothing special about it during gameplay sector->special = 0; if (!inSync) flash->count = (P_Random()&7)+1; else flash->count = 1; } // // Start strobing lights (usually from a trigger) // void EV_StartLightStrobing(line_t* line) { int secnum; sector_t* sec; secnum = -1; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; P_SpawnStrobeFlash (sec,SLOWDARK, 0); } } // // TURN LINE'S TAG LIGHTS OFF // void EV_TurnTagLightsOff(line_t* line) { int i; int j; int min; sector_t* sector; sector_t* tsec; line_t* templine; sector = sectors; for (j = 0;j < numsectors; j++, sector++) { if (sector->tag == line->tag) { min = sector->lightlevel; for (i = 0;i < sector->linecount; i++) { templine = sector->lines[i]; tsec = getNextSector(templine,sector); if (!tsec) continue; if (tsec->lightlevel < min) min = tsec->lightlevel; } sector->lightlevel = min; } } } // // TURN LINE'S TAG LIGHTS ON // void EV_LightTurnOn ( line_t* line, int bright ) { int i; int j; sector_t* sector; sector_t* temp; line_t* templine; sector = sectors; for (i=0;itag == line->tag) { // bright = 0 means to search // for highest light level // surrounding sector if (!bright) { for (j = 0;j < sector->linecount; j++) { templine = sector->lines[j]; temp = getNextSector(templine,sector); if (!temp) continue; if (temp->lightlevel > bright) bright = temp->lightlevel; } } sector-> lightlevel = bright; } } } // // Spawn glowing light // void T_Glow(glow_t* g) { switch(g->direction) { case -1: // DOWN g->sector->lightlevel -= GLOWSPEED; if (g->sector->lightlevel <= g->minlight) { g->sector->lightlevel += GLOWSPEED; g->direction = 1; } break; case 1: // UP g->sector->lightlevel += GLOWSPEED; if (g->sector->lightlevel >= g->maxlight) { g->sector->lightlevel -= GLOWSPEED; g->direction = -1; } break; } } void P_SpawnGlowingLight(sector_t* sector) { glow_t* g; g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0); P_AddThinker(&g->thinker); g->sector = sector; g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); g->maxlight = sector->lightlevel; g->thinker.function.acp1 = (actionf_p1) T_Glow; g->direction = -1; sector->special = 0; } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_local.h000066400000000000000000000144101257432200600226140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Play functions, animation, global header. // #ifndef __P_LOCAL__ #define __P_LOCAL__ #ifndef __R_LOCAL__ #include "r_local.h" #endif #define FLOATSPEED (FRACUNIT*4) #define MAXHEALTH 100 #define VIEWHEIGHT (41*FRACUNIT) // mapblocks are used to check movement // against lines and things #define MAPBLOCKUNITS 128 #define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) #define MAPBLOCKSHIFT (FRACBITS+7) #define MAPBMASK (MAPBLOCKSIZE-1) #define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) // player radius for movement checking #define PLAYERRADIUS 16*FRACUNIT // MAXRADIUS is for precalculated sector block boxes // the spider demon is larger, // but we do not have any moving sectors nearby #define MAXRADIUS 32*FRACUNIT #define GRAVITY FRACUNIT #define MAXMOVE (30*FRACUNIT) #define USERANGE (64*FRACUNIT) #define MELEERANGE (64*FRACUNIT) #define MISSILERANGE (32*64*FRACUNIT) // follow a player exlusively for 3 seconds #define BASETHRESHOLD 100 // // P_TICK // // both the head and tail of the thinker list extern thinker_t thinkercap; void P_InitThinkers (void); void P_AddThinker (thinker_t* thinker); void P_RemoveThinker (thinker_t* thinker); // // P_PSPR // void P_SetupPsprites (player_t* curplayer); void P_MovePsprites (player_t* curplayer); void P_DropWeapon (player_t* player); // // P_USER // void P_PlayerThink (player_t* player); // // P_MOBJ // #define ONFLOORZ INT_MIN #define ONCEILINGZ INT_MAX // Time interval for item respawning. #define ITEMQUESIZE 128 extern mapthing_t itemrespawnque[ITEMQUESIZE]; extern int itemrespawntime[ITEMQUESIZE]; extern int iquehead; extern int iquetail; void P_RespawnSpecials (void); mobj_t* P_SpawnMobj ( fixed_t x, fixed_t y, fixed_t z, mobjtype_t type ); void P_RemoveMobj (mobj_t* th); mobj_t* P_SubstNullMobj (mobj_t* th); boolean P_SetMobjState (mobj_t* mobj, statenum_t state); void P_MobjThinker (mobj_t* mobj); void P_SpawnPuff (fixed_t x, fixed_t y, fixed_t z); void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage); mobj_t* P_SpawnMissile (mobj_t* source, mobj_t* dest, mobjtype_t type); void P_SpawnPlayerMissile (mobj_t* source, mobjtype_t type); // // P_ENEMY // void P_NoiseAlert (mobj_t* target, mobj_t* emmiter); // // P_MAPUTL // typedef struct { fixed_t x; fixed_t y; fixed_t dx; fixed_t dy; } divline_t; typedef struct { fixed_t frac; // along trace line boolean isaline; union { mobj_t* thing; line_t* line; } d; } intercept_t; // Extended MAXINTERCEPTS, to allow for intercepts overrun emulation. #define MAXINTERCEPTS_ORIGINAL 128 #define MAXINTERCEPTS (MAXINTERCEPTS_ORIGINAL + 61) extern intercept_t intercepts[MAXINTERCEPTS]; extern intercept_t* intercept_p; typedef boolean (*traverser_t) (intercept_t *in); fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); int P_PointOnLineSide (fixed_t x, fixed_t y, line_t* line); int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t* line); void P_MakeDivline (line_t* li, divline_t* dl); fixed_t P_InterceptVector (divline_t* v2, divline_t* v1); int P_BoxOnLineSide (fixed_t* tmbox, line_t* ld); extern fixed_t opentop; extern fixed_t openbottom; extern fixed_t openrange; extern fixed_t lowfloor; void P_LineOpening (line_t* linedef); boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) ); boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) ); #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 #define PT_EARLYOUT 4 extern divline_t trace; boolean P_PathTraverse ( fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean (*trav) (intercept_t *)); void P_UnsetThingPosition (mobj_t* thing); void P_SetThingPosition (mobj_t* thing); // // P_MAP // // If "floatok" true, move would be ok // if within "tmfloorz - tmceilingz". extern boolean floatok; extern fixed_t tmfloorz; extern fixed_t tmceilingz; extern line_t* ceilingline; // fraggle: I have increased the size of this buffer. In the original Doom, // overrunning past this limit caused other bits of memory to be overwritten, // affecting demo playback. However, in doing so, the limit was still // exceeded. So we have to support more than 8 specials. // // We keep the original limit, to detect what variables in memory were // overwritten (see SpechitOverrun()) #define MAXSPECIALCROSS 20 #define MAXSPECIALCROSS_ORIGINAL 8 extern line_t* spechit[MAXSPECIALCROSS]; extern int numspechit; boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y); boolean P_TryMove (mobj_t* thing, fixed_t x, fixed_t y); boolean P_TeleportMove (mobj_t* thing, fixed_t x, fixed_t y); void P_SlideMove (mobj_t* mo); boolean P_CheckSight (mobj_t* t1, mobj_t* t2); void P_UseLines (player_t* player); boolean P_ChangeSector (sector_t* sector, boolean crunch); extern mobj_t* linetarget; // who got hit (or NULL) fixed_t P_AimLineAttack ( mobj_t* t1, angle_t angle, fixed_t distance ); void P_LineAttack ( mobj_t* t1, angle_t angle, fixed_t distance, fixed_t slope, int damage ); void P_RadiusAttack ( mobj_t* spot, mobj_t* source, int damage ); // // P_SETUP // extern byte* rejectmatrix; // for fast sight rejection extern short* blockmaplump; // offsets in blockmap are from here extern short* blockmap; extern int bmapwidth; extern int bmapheight; // in mapblocks extern fixed_t bmaporgx; extern fixed_t bmaporgy; // origin of block map extern mobj_t** blocklinks; // for thing chains // // P_INTER // extern int maxammo[NUMAMMO]; extern int clipammo[NUMAMMO]; void P_TouchSpecialThing ( mobj_t* special, mobj_t* toucher ); void P_DamageMobj ( mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage ); // // P_SPEC // #include "p_spec.h" #endif // __P_LOCAL__ chocolate-doom-chocolate-doom-2.2.1/src/doom/p_map.c000066400000000000000000000757471257432200600223160ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard, Andrey Budko // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Movement, collision handling. // Shooting and aiming. // #include #include #include "deh_misc.h" #include "m_bbox.h" #include "m_random.h" #include "i_system.h" #include "doomdef.h" #include "m_argv.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" // Spechit overrun magic value. // // This is the value used by PrBoom-plus. I think the value below is // actually better and works with more demos. However, I think // it's better for the spechits emulation to be compatible with // PrBoom-plus, at least so that the big spechits emulation list // on Doomworld can also be used with Chocolate Doom. #define DEFAULT_SPECHIT_MAGIC 0x01C09C98 // This is from a post by myk on the Doomworld forums, // outputted from entryway's spechit_magic generator for // s205n546.lmp. The _exact_ value of this isn't too // important; as long as it is in the right general // range, it will usually work. Otherwise, we can use // the generator (hacked doom2.exe) and provide it // with -spechit. //#define DEFAULT_SPECHIT_MAGIC 0x84f968e8 fixed_t tmbbox[4]; mobj_t* tmthing; int tmflags; fixed_t tmx; fixed_t tmy; // If "floatok" true, move would be ok // if within "tmfloorz - tmceilingz". boolean floatok; fixed_t tmfloorz; fixed_t tmceilingz; fixed_t tmdropoffz; // keep track of the line that lowers the ceiling, // so missiles don't explode against sky hack walls line_t* ceilingline; // keep track of special lines as they are hit, // but don't process them until the move is proven valid line_t* spechit[MAXSPECIALCROSS]; int numspechit; // // TELEPORT MOVE // // // PIT_StompThing // boolean PIT_StompThing (mobj_t* thing) { fixed_t blockdist; if (!(thing->flags & MF_SHOOTABLE) ) return true; blockdist = thing->radius + tmthing->radius; if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist ) { // didn't hit it return true; } // don't clip against self if (thing == tmthing) return true; // monsters don't stomp things except on boss level if ( !tmthing->player && gamemap != 30) return false; P_DamageMobj (thing, tmthing, tmthing, 10000); return true; } // // P_TeleportMove // boolean P_TeleportMove ( mobj_t* thing, fixed_t x, fixed_t y ) { int xl; int xh; int yl; int yh; int bx; int by; subsector_t* newsubsec; // kill anything occupying the position tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector (x,y); ceilingline = NULL; // The base floor/ceiling is from the subsector // that contains the point. // Any contacted lines the step closer together // will adjust them. tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; validcount++; numspechit = 0; // stomp on any things contacted xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockThingsIterator(bx,by,PIT_StompThing)) return false; // the move is ok, // so link the thing into its new position P_UnsetThingPosition (thing); thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; P_SetThingPosition (thing); return true; } // // MOVEMENT ITERATOR FUNCTIONS // static void SpechitOverrun(line_t *ld); // // PIT_CheckLine // Adjusts tmfloorz and tmceilingz as lines are contacted // boolean PIT_CheckLine (line_t* ld) { if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) return true; if (P_BoxOnLineSide (tmbbox, ld) != -1) return true; // A line has been hit // The moving thing's destination position will cross // the given line. // If this should not be allowed, return false. // If the line is special, keep track of it // to process later if the move is proven ok. // NOTE: specials are NOT sorted by order, // so two special lines that are only 8 pixels apart // could be crossed in either order. if (!ld->backsector) return false; // one sided line if (!(tmthing->flags & MF_MISSILE) ) { if ( ld->flags & ML_BLOCKING ) return false; // explicitly blocking everything if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS ) return false; // block monsters only } // set openrange, opentop, openbottom P_LineOpening (ld); // adjust floor / ceiling heights if (opentop < tmceilingz) { tmceilingz = opentop; ceilingline = ld; } if (openbottom > tmfloorz) tmfloorz = openbottom; if (lowfloor < tmdropoffz) tmdropoffz = lowfloor; // if contacted a special line, add it to the list if (ld->special) { spechit[numspechit] = ld; numspechit++; // fraggle: spechits overrun emulation code from prboom-plus if (numspechit > MAXSPECIALCROSS_ORIGINAL) { SpechitOverrun(ld); } } return true; } // // PIT_CheckThing // boolean PIT_CheckThing (mobj_t* thing) { fixed_t blockdist; boolean solid; int damage; if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) )) return true; blockdist = thing->radius + tmthing->radius; if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist ) { // didn't hit it return true; } // don't clip against self if (thing == tmthing) return true; // check for skulls slamming into things if (tmthing->flags & MF_SKULLFLY) { damage = ((P_Random()%8)+1)*tmthing->info->damage; P_DamageMobj (thing, tmthing, tmthing, damage); tmthing->flags &= ~MF_SKULLFLY; tmthing->momx = tmthing->momy = tmthing->momz = 0; P_SetMobjState (tmthing, tmthing->info->spawnstate); return false; // stop moving } // missiles can hit other things if (tmthing->flags & MF_MISSILE) { // see if it went over / under if (tmthing->z > thing->z + thing->height) return true; // overhead if (tmthing->z+tmthing->height < thing->z) return true; // underneath if (tmthing->target && (tmthing->target->type == thing->type || (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)|| (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) ) { // Don't hit same species as originator. if (thing == tmthing->target) return true; // sdh: Add deh_species_infighting here. We can override the // "monsters of the same species cant hurt each other" behavior // through dehacked patches if (thing->type != MT_PLAYER && !deh_species_infighting) { // Explode, but do no damage. // Let players missile other players. return false; } } if (! (thing->flags & MF_SHOOTABLE) ) { // didn't do any damage return !(thing->flags & MF_SOLID); } // damage / explode damage = ((P_Random()%8)+1)*tmthing->info->damage; P_DamageMobj (thing, tmthing, tmthing->target, damage); // don't traverse any more return false; } // check for special pickup if (thing->flags & MF_SPECIAL) { solid = (thing->flags & MF_SOLID) != 0; if (tmflags&MF_PICKUP) { // can remove thing P_TouchSpecialThing (thing, tmthing); } return !solid; } return !(thing->flags & MF_SOLID); } // // MOVEMENT CLIPPING // // // P_CheckPosition // This is purely informative, nothing is modified // (except things picked up). // // in: // a mobj_t (can be valid or invalid) // a position to be checked // (doesn't need to be related to the mobj_t->x,y) // // during: // special things are touched if MF_PICKUP // early out on solid lines? // // out: // newsubsec // floorz // ceilingz // tmdropoffz // the lowest point contacted // (monsters won't move to a dropoff) // speciallines[] // numspeciallines // boolean P_CheckPosition ( mobj_t* thing, fixed_t x, fixed_t y ) { int xl; int xh; int yl; int yh; int bx; int by; subsector_t* newsubsec; tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector (x,y); ceilingline = NULL; // The base floor / ceiling is from the subsector // that contains the point. // Any contacted lines the step closer together // will adjust them. tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; validcount++; numspechit = 0; if ( tmflags & MF_NOCLIP ) return true; // Check things first, possibly picking things up. // The bounding box is extended by MAXRADIUS // because mobj_ts are grouped into mapblocks // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) return false; // check lines xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) return false; return true; } // // P_TryMove // Attempt to move to a new position, // crossing special lines unless MF_TELEPORT is set. // boolean P_TryMove ( mobj_t* thing, fixed_t x, fixed_t y ) { fixed_t oldx; fixed_t oldy; int side; int oldside; line_t* ld; floatok = false; if (!P_CheckPosition (thing, x, y)) return false; // solid wall or thing if ( !(thing->flags & MF_NOCLIP) ) { if (tmceilingz - tmfloorz < thing->height) return false; // doesn't fit floatok = true; if ( !(thing->flags&MF_TELEPORT) &&tmceilingz - thing->z < thing->height) return false; // mobj must lower itself to fit if ( !(thing->flags&MF_TELEPORT) && tmfloorz - thing->z > 24*FRACUNIT ) return false; // too big a step up if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT)) && tmfloorz - tmdropoffz > 24*FRACUNIT ) return false; // don't stand over a dropoff } // the move is ok, // so link the thing into its new position P_UnsetThingPosition (thing); oldx = thing->x; oldy = thing->y; thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; P_SetThingPosition (thing); // if any special lines were hit, do the effect if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) ) { while (numspechit--) { // see if the line was crossed ld = spechit[numspechit]; side = P_PointOnLineSide (thing->x, thing->y, ld); oldside = P_PointOnLineSide (oldx, oldy, ld); if (side != oldside) { if (ld->special) P_CrossSpecialLine (ld-lines, oldside, thing); } } } return true; } // // P_ThingHeightClip // Takes a valid thing and adjusts the thing->floorz, // thing->ceilingz, and possibly thing->z. // This is called for all nearby monsters // whenever a sector changes height. // If the thing doesn't fit, // the z will be set to the lowest value // and false will be returned. // boolean P_ThingHeightClip (mobj_t* thing) { boolean onfloor; onfloor = (thing->z == thing->floorz); P_CheckPosition (thing, thing->x, thing->y); // what about stranding a monster partially off an edge? thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; if (onfloor) { // walking monsters rise and fall with the floor thing->z = thing->floorz; } else { // don't adjust a floating monster unless forced to if (thing->z+thing->height > thing->ceilingz) thing->z = thing->ceilingz - thing->height; } if (thing->ceilingz - thing->floorz < thing->height) return false; return true; } // // SLIDE MOVE // Allows the player to slide along any angled walls. // fixed_t bestslidefrac; fixed_t secondslidefrac; line_t* bestslideline; line_t* secondslideline; mobj_t* slidemo; fixed_t tmxmove; fixed_t tmymove; // // P_HitSlideLine // Adjusts the xmove / ymove // so that the next move will slide along the wall. // void P_HitSlideLine (line_t* ld) { int side; angle_t lineangle; angle_t moveangle; angle_t deltaangle; fixed_t movelen; fixed_t newlen; if (ld->slopetype == ST_HORIZONTAL) { tmymove = 0; return; } if (ld->slopetype == ST_VERTICAL) { tmxmove = 0; return; } side = P_PointOnLineSide (slidemo->x, slidemo->y, ld); lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy); if (side == 1) lineangle += ANG180; moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove); deltaangle = moveangle-lineangle; if (deltaangle > ANG180) deltaangle += ANG180; // I_Error ("SlideLine: ang>ANG180"); lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; movelen = P_AproxDistance (tmxmove, tmymove); newlen = FixedMul (movelen, finecosine[deltaangle]); tmxmove = FixedMul (newlen, finecosine[lineangle]); tmymove = FixedMul (newlen, finesine[lineangle]); } // // PTR_SlideTraverse // boolean PTR_SlideTraverse (intercept_t* in) { line_t* li; if (!in->isaline) I_Error ("PTR_SlideTraverse: not a line?"); li = in->d.line; if ( ! (li->flags & ML_TWOSIDED) ) { if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) { // don't hit the back side return true; } goto isblocking; } // set openrange, opentop, openbottom P_LineOpening (li); if (openrange < slidemo->height) goto isblocking; // doesn't fit if (opentop - slidemo->z < slidemo->height) goto isblocking; // mobj is too high if (openbottom - slidemo->z > 24*FRACUNIT ) goto isblocking; // too big a step up // this line doesn't block movement return true; // the line does block movement, // see if it is closer than best so far isblocking: if (in->frac < bestslidefrac) { secondslidefrac = bestslidefrac; secondslideline = bestslideline; bestslidefrac = in->frac; bestslideline = li; } return false; // stop } // // P_SlideMove // The momx / momy move is bad, so try to slide // along a wall. // Find the first line hit, move flush to it, // and slide along it // // This is a kludgy mess. // void P_SlideMove (mobj_t* mo) { fixed_t leadx; fixed_t leady; fixed_t trailx; fixed_t traily; fixed_t newx; fixed_t newy; int hitcount; slidemo = mo; hitcount = 0; retry: if (++hitcount == 3) goto stairstep; // don't loop forever // trace along the three leading corners if (mo->momx > 0) { leadx = mo->x + mo->radius; trailx = mo->x - mo->radius; } else { leadx = mo->x - mo->radius; trailx = mo->x + mo->radius; } if (mo->momy > 0) { leady = mo->y + mo->radius; traily = mo->y - mo->radius; } else { leady = mo->y - mo->radius; traily = mo->y + mo->radius; } bestslidefrac = FRACUNIT+1; P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy, PT_ADDLINES, PTR_SlideTraverse ); P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy, PT_ADDLINES, PTR_SlideTraverse ); P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy, PT_ADDLINES, PTR_SlideTraverse ); // move up to the wall if (bestslidefrac == FRACUNIT+1) { // the move most have hit the middle, so stairstep stairstep: if (!P_TryMove (mo, mo->x, mo->y + mo->momy)) P_TryMove (mo, mo->x + mo->momx, mo->y); return; } // fudge a bit to make sure it doesn't hit bestslidefrac -= 0x800; if (bestslidefrac > 0) { newx = FixedMul (mo->momx, bestslidefrac); newy = FixedMul (mo->momy, bestslidefrac); if (!P_TryMove (mo, mo->x+newx, mo->y+newy)) goto stairstep; } // Now continue along the wall. // First calculate remainder. bestslidefrac = FRACUNIT-(bestslidefrac+0x800); if (bestslidefrac > FRACUNIT) bestslidefrac = FRACUNIT; if (bestslidefrac <= 0) return; tmxmove = FixedMul (mo->momx, bestslidefrac); tmymove = FixedMul (mo->momy, bestslidefrac); P_HitSlideLine (bestslideline); // clip the moves mo->momx = tmxmove; mo->momy = tmymove; if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove)) { goto retry; } } // // P_LineAttack // mobj_t* linetarget; // who got hit (or NULL) mobj_t* shootthing; // Height if not aiming up or down // ???: use slope for monsters? fixed_t shootz; int la_damage; fixed_t attackrange; fixed_t aimslope; // slopes to top and bottom of target extern fixed_t topslope; extern fixed_t bottomslope; // // PTR_AimTraverse // Sets linetaget and aimslope when a target is aimed at. // boolean PTR_AimTraverse (intercept_t* in) { line_t* li; mobj_t* th; fixed_t slope; fixed_t thingtopslope; fixed_t thingbottomslope; fixed_t dist; if (in->isaline) { li = in->d.line; if ( !(li->flags & ML_TWOSIDED) ) return false; // stop // Crosses a two sided line. // A two sided line will restrict // the possible target ranges. P_LineOpening (li); if (openbottom >= opentop) return false; // stop dist = FixedMul (attackrange, in->frac); if (li->backsector == NULL || li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv (openbottom - shootz , dist); if (slope > bottomslope) bottomslope = slope; } if (li->backsector == NULL || li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv (opentop - shootz , dist); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop return true; // shot continues } // shoot a thing th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags&MF_SHOOTABLE)) return true; // corpse or something // check angles to see if the thing can be aimed at dist = FixedMul (attackrange, in->frac); thingtopslope = FixedDiv (th->z+th->height - shootz , dist); if (thingtopslope < bottomslope) return true; // shot over the thing thingbottomslope = FixedDiv (th->z - shootz, dist); if (thingbottomslope > topslope) return true; // shot under the thing // this thing can be hit! if (thingtopslope > topslope) thingtopslope = topslope; if (thingbottomslope < bottomslope) thingbottomslope = bottomslope; aimslope = (thingtopslope+thingbottomslope)/2; linetarget = th; return false; // don't go any farther } // // PTR_ShootTraverse // boolean PTR_ShootTraverse (intercept_t* in) { fixed_t x; fixed_t y; fixed_t z; fixed_t frac; line_t* li; mobj_t* th; fixed_t slope; fixed_t dist; fixed_t thingtopslope; fixed_t thingbottomslope; if (in->isaline) { li = in->d.line; if (li->special) P_ShootSpecialLine (shootthing, li); if ( !(li->flags & ML_TWOSIDED) ) goto hitline; // crosses a two sided line P_LineOpening (li); dist = FixedMul (attackrange, in->frac); // e6y: emulation of missed back side on two-sided lines. // backsector can be NULL when emulating missing back side. if (li->backsector == NULL) { slope = FixedDiv (openbottom - shootz , dist); if (slope > aimslope) goto hitline; slope = FixedDiv (opentop - shootz , dist); if (slope < aimslope) goto hitline; } else { if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv (openbottom - shootz , dist); if (slope > aimslope) goto hitline; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv (opentop - shootz , dist); if (slope < aimslope) goto hitline; } } // shot continues return true; // hit line hitline: // position a bit closer frac = in->frac - FixedDiv (4*FRACUNIT,attackrange); x = trace.x + FixedMul (trace.dx, frac); y = trace.y + FixedMul (trace.dy, frac); z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); if (li->frontsector->ceilingpic == skyflatnum) { // don't shoot the sky! if (z > li->frontsector->ceilingheight) return false; // it's a sky hack wall if (li->backsector && li->backsector->ceilingpic == skyflatnum) return false; } // Spawn bullet puffs. P_SpawnPuff (x,y,z); // don't go any farther return false; } // shoot a thing th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags&MF_SHOOTABLE)) return true; // corpse or something // check angles to see if the thing can be aimed at dist = FixedMul (attackrange, in->frac); thingtopslope = FixedDiv (th->z+th->height - shootz , dist); if (thingtopslope < aimslope) return true; // shot over the thing thingbottomslope = FixedDiv (th->z - shootz, dist); if (thingbottomslope > aimslope) return true; // shot under the thing // hit thing // position a bit closer frac = in->frac - FixedDiv (10*FRACUNIT,attackrange); x = trace.x + FixedMul (trace.dx, frac); y = trace.y + FixedMul (trace.dy, frac); z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); // Spawn bullet puffs or blod spots, // depending on target type. if (in->d.thing->flags & MF_NOBLOOD) P_SpawnPuff (x,y,z); else P_SpawnBlood (x,y,z, la_damage); if (la_damage) P_DamageMobj (th, shootthing, shootthing, la_damage); // don't go any farther return false; } // // P_AimLineAttack // fixed_t P_AimLineAttack ( mobj_t* t1, angle_t angle, fixed_t distance ) { fixed_t x2; fixed_t y2; t1 = P_SubstNullMobj(t1); angle >>= ANGLETOFINESHIFT; shootthing = t1; x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; // can't shoot outside view angles topslope = 100*FRACUNIT/160; bottomslope = -100*FRACUNIT/160; attackrange = distance; linetarget = NULL; P_PathTraverse ( t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse ); if (linetarget) return aimslope; return 0; } // // P_LineAttack // If damage == 0, it is just a test trace // that will leave linetarget set. // void P_LineAttack ( mobj_t* t1, angle_t angle, fixed_t distance, fixed_t slope, int damage ) { fixed_t x2; fixed_t y2; angle >>= ANGLETOFINESHIFT; shootthing = t1; la_damage = damage; x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; attackrange = distance; aimslope = slope; P_PathTraverse ( t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_ShootTraverse ); } // // USE LINES // mobj_t* usething; boolean PTR_UseTraverse (intercept_t* in) { int side; if (!in->d.line->special) { P_LineOpening (in->d.line); if (openrange <= 0) { S_StartSound (usething, sfx_noway); // can't use through a wall return false; } // not a special line, but keep checking return true ; } side = 0; if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) side = 1; // return false; // don't use back side P_UseSpecialLine (usething, in->d.line, side); // can't use for than one special line in a row return false; } // // P_UseLines // Looks for special lines in front of the player to activate. // void P_UseLines (player_t* player) { int angle; fixed_t x1; fixed_t y1; fixed_t x2; fixed_t y2; usething = player->mo; angle = player->mo->angle >> ANGLETOFINESHIFT; x1 = player->mo->x; y1 = player->mo->y; x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]; y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]; P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ); } // // RADIUS ATTACK // mobj_t* bombsource; mobj_t* bombspot; int bombdamage; // // PIT_RadiusAttack // "bombsource" is the creature // that caused the explosion at "bombspot". // boolean PIT_RadiusAttack (mobj_t* thing) { fixed_t dx; fixed_t dy; fixed_t dist; if (!(thing->flags & MF_SHOOTABLE) ) return true; // Boss spider and cyborg // take no damage from concussion. if (thing->type == MT_CYBORG || thing->type == MT_SPIDER) return true; dx = abs(thing->x - bombspot->x); dy = abs(thing->y - bombspot->y); dist = dx>dy ? dx : dy; dist = (dist - thing->radius) >> FRACBITS; if (dist < 0) dist = 0; if (dist >= bombdamage) return true; // out of range if ( P_CheckSight (thing, bombspot) ) { // must be in direct path P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist); } return true; } // // P_RadiusAttack // Source is the creature that caused the explosion at spot. // void P_RadiusAttack ( mobj_t* spot, mobj_t* source, int damage ) { int x; int y; int xl; int xh; int yl; int yh; fixed_t dist; dist = (damage+MAXRADIUS)<y + dist - bmaporgy)>>MAPBLOCKSHIFT; yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT; xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT; xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT; bombspot = spot; bombsource = source; bombdamage = damage; for (y=yl ; y<=yh ; y++) for (x=xl ; x<=xh ; x++) P_BlockThingsIterator (x, y, PIT_RadiusAttack ); } // // SECTOR HEIGHT CHANGING // After modifying a sectors floor or ceiling height, // call this routine to adjust the positions // of all things that touch the sector. // // If anything doesn't fit anymore, true will be returned. // If crunch is true, they will take damage // as they are being crushed. // If Crunch is false, you should set the sector height back // the way it was and call P_ChangeSector again // to undo the changes. // boolean crushchange; boolean nofit; // // PIT_ChangeSector // boolean PIT_ChangeSector (mobj_t* thing) { mobj_t* mo; if (P_ThingHeightClip (thing)) { // keep checking return true; } // crunch bodies to giblets if (thing->health <= 0) { P_SetMobjState (thing, S_GIBS); thing->flags &= ~MF_SOLID; thing->height = 0; thing->radius = 0; // keep checking return true; } // crunch dropped items if (thing->flags & MF_DROPPED) { P_RemoveMobj (thing); // keep checking return true; } if (! (thing->flags & MF_SHOOTABLE) ) { // assume it is bloody gibs or something return true; } nofit = true; if (crushchange && !(leveltime&3) ) { P_DamageMobj(thing,NULL,NULL,10); // spray blood in a random direction mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, MT_BLOOD); mo->momx = (P_Random() - P_Random ())<<12; mo->momy = (P_Random() - P_Random ())<<12; } // keep checking (crush other things) return true; } // // P_ChangeSector // boolean P_ChangeSector ( sector_t* sector, boolean crunch ) { int x; int y; nofit = false; crushchange = crunch; // re-check heights for all things near the moving sector for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++) for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++) P_BlockThingsIterator (x, y, PIT_ChangeSector); return nofit; } // Code to emulate the behavior of Vanilla Doom when encountering an overrun // of the spechit array. This is by Andrey Budko (e6y) and comes from his // PrBoom plus port. A big thanks to Andrey for this. static void SpechitOverrun(line_t *ld) { static unsigned int baseaddr = 0; unsigned int addr; if (baseaddr == 0) { int p; // This is the first time we have had an overrun. Work out // what base address we are going to use. // Allow a spechit value to be specified on the command line. //! // @category compat // @arg // // Use the specified magic value when emulating spechit overruns. // p = M_CheckParmWithArgs("-spechit", 1); if (p > 0) { M_StrToInt(myargv[p+1], (int *) &baseaddr); } else { baseaddr = DEFAULT_SPECHIT_MAGIC; } } // Calculate address used in doom2.exe addr = baseaddr + (ld - lines) * 0x3E; switch(numspechit) { case 9: case 10: case 11: case 12: tmbbox[numspechit-9] = addr; break; case 13: crushchange = addr; break; case 14: nofit = addr; break; default: fprintf(stderr, "SpechitOverrun: Warning: unable to emulate" "an overrun where numspechit=%i\n", numspechit); break; } } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_maputl.c000066400000000000000000000471471257432200600230340ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // Copyright(C) 2005, 2006 Andrey Budko // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Movement/collision utility functions, // as used by function in p_map.c. // BLOCKMAP Iterator functions, // and some PIT_* functions to use for iteration. // #include #include "m_bbox.h" #include "doomdef.h" #include "doomstat.h" #include "p_local.h" // State. #include "r_state.h" // // P_AproxDistance // Gives an estimation of distance (not exact) // fixed_t P_AproxDistance ( fixed_t dx, fixed_t dy ) { dx = abs(dx); dy = abs(dy); if (dx < dy) return dx+dy-(dx>>1); return dx+dy-(dy>>1); } // // P_PointOnLineSide // Returns 0 or 1 // int P_PointOnLineSide ( fixed_t x, fixed_t y, line_t* line ) { fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; if (!line->dx) { if (x <= line->v1->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->v1->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->v1->x); dy = (y - line->v1->y); left = FixedMul ( line->dy>>FRACBITS , dx ); right = FixedMul ( dy , line->dx>>FRACBITS ); if (right < left) return 0; // front side return 1; // back side } // // P_BoxOnLineSide // Considers the line to be infinite // Returns side 0 or 1, -1 if box crosses the line. // int P_BoxOnLineSide ( fixed_t* tmbox, line_t* ld ) { int p1 = 0; int p2 = 0; switch (ld->slopetype) { case ST_HORIZONTAL: p1 = tmbox[BOXTOP] > ld->v1->y; p2 = tmbox[BOXBOTTOM] > ld->v1->y; if (ld->dx < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_VERTICAL: p1 = tmbox[BOXRIGHT] < ld->v1->x; p2 = tmbox[BOXLEFT] < ld->v1->x; if (ld->dy < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_POSITIVE: p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld); break; case ST_NEGATIVE: p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld); break; } if (p1 == p2) return p1; return -1; } // // P_PointOnDivlineSide // Returns 0 or 1. // int P_PointOnDivlineSide ( fixed_t x, fixed_t y, divline_t* line ) { fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; if (!line->dx) { if (x <= line->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->x); dy = (y - line->y); // try to quickly decide by looking at sign bits if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 ) { if ( (line->dy ^ dx) & 0x80000000 ) return 1; // (left is negative) return 0; } left = FixedMul ( line->dy>>8, dx>>8 ); right = FixedMul ( dy>>8 , line->dx>>8 ); if (right < left) return 0; // front side return 1; // back side } // // P_MakeDivline // void P_MakeDivline ( line_t* li, divline_t* dl ) { dl->x = li->v1->x; dl->y = li->v1->y; dl->dx = li->dx; dl->dy = li->dy; } // // P_InterceptVector // Returns the fractional intercept point // along the first divline. // This is only called by the addthings // and addlines traversers. // fixed_t P_InterceptVector ( divline_t* v2, divline_t* v1 ) { #if 1 fixed_t frac; fixed_t num; fixed_t den; den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy); if (den == 0) return 0; // I_Error ("P_InterceptVector: parallel"); num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy ) +FixedMul ( (v2->y - v1->y)>>8, v1->dx ); frac = FixedDiv (num , den); return frac; #else // UNUSED, float debug. float frac; float num; float den; float v1x; float v1y; float v1dx; float v1dy; float v2x; float v2y; float v2dx; float v2dy; v1x = (float)v1->x/FRACUNIT; v1y = (float)v1->y/FRACUNIT; v1dx = (float)v1->dx/FRACUNIT; v1dy = (float)v1->dy/FRACUNIT; v2x = (float)v2->x/FRACUNIT; v2y = (float)v2->y/FRACUNIT; v2dx = (float)v2->dx/FRACUNIT; v2dy = (float)v2->dy/FRACUNIT; den = v1dy*v2dx - v1dx*v2dy; if (den == 0) return 0; // parallel num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx; frac = num / den; return frac*FRACUNIT; #endif } // // P_LineOpening // Sets opentop and openbottom to the window // through a two sided line. // OPTIMIZE: keep this precalculated // fixed_t opentop; fixed_t openbottom; fixed_t openrange; fixed_t lowfloor; void P_LineOpening (line_t* linedef) { sector_t* front; sector_t* back; if (linedef->sidenum[1] == -1) { // single sided line openrange = 0; return; } front = linedef->frontsector; back = linedef->backsector; if (front->ceilingheight < back->ceilingheight) opentop = front->ceilingheight; else opentop = back->ceilingheight; if (front->floorheight > back->floorheight) { openbottom = front->floorheight; lowfloor = back->floorheight; } else { openbottom = back->floorheight; lowfloor = front->floorheight; } openrange = opentop - openbottom; } // // THING POSITION SETTING // // // P_UnsetThingPosition // Unlinks a thing from block map and sectors. // On each position change, BLOCKMAP and other // lookups maintaining lists ot things inside // these structures need to be updated. // void P_UnsetThingPosition (mobj_t* thing) { int blockx; int blocky; if ( ! (thing->flags & MF_NOSECTOR) ) { // inert things don't need to be in blockmap? // unlink from subsector if (thing->snext) thing->snext->sprev = thing->sprev; if (thing->sprev) thing->sprev->snext = thing->snext; else thing->subsector->sector->thinglist = thing->snext; } if ( ! (thing->flags & MF_NOBLOCKMAP) ) { // inert things don't need to be in blockmap // unlink from block map if (thing->bnext) thing->bnext->bprev = thing->bprev; if (thing->bprev) thing->bprev->bnext = thing->bnext; else { blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky bnext; } } } } // // P_SetThingPosition // Links a thing into both a block and a subsector // based on it's x y. // Sets thing->subsector properly // void P_SetThingPosition (mobj_t* thing) { subsector_t* ss; sector_t* sec; int blockx; int blocky; mobj_t** link; // link into subsector ss = R_PointInSubsector (thing->x,thing->y); thing->subsector = ss; if ( ! (thing->flags & MF_NOSECTOR) ) { // invisible things don't go into the sector links sec = ss->sector; thing->sprev = NULL; thing->snext = sec->thinglist; if (sec->thinglist) sec->thinglist->sprev = thing; sec->thinglist = thing; } // link into blockmap if ( ! (thing->flags & MF_NOBLOCKMAP) ) { // inert things don't need to be in blockmap blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight) { link = &blocklinks[blocky*bmapwidth+blockx]; thing->bprev = NULL; thing->bnext = *link; if (*link) (*link)->bprev = thing; *link = thing; } else { // thing is off the map thing->bnext = thing->bprev = NULL; } } } // // BLOCK MAP ITERATORS // For each line/thing in the given mapblock, // call the passed PIT_* function. // If the function returns false, // exit with false without checking anything else. // // // P_BlockLinesIterator // The validcount flags are used to avoid checking lines // that are marked in multiple mapblocks, // so increment validcount before the first call // to P_BlockLinesIterator, then make one or more calls // to it. // boolean P_BlockLinesIterator ( int x, int y, boolean(*func)(line_t*) ) { int offset; short* list; line_t* ld; if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight) { return true; } offset = y*bmapwidth+x; offset = *(blockmap+offset); for ( list = blockmaplump+offset ; *list != -1 ; list++) { ld = &lines[*list]; if (ld->validcount == validcount) continue; // line has already been checked ld->validcount = validcount; if ( !func(ld) ) return false; } return true; // everything was checked } // // P_BlockThingsIterator // boolean P_BlockThingsIterator ( int x, int y, boolean(*func)(mobj_t*) ) { mobj_t* mobj; if ( x<0 || y<0 || x>=bmapwidth || y>=bmapheight) { return true; } for (mobj = blocklinks[y*bmapwidth+x] ; mobj ; mobj = mobj->bnext) { if (!func( mobj ) ) return false; } return true; } // // INTERCEPT ROUTINES // intercept_t intercepts[MAXINTERCEPTS]; intercept_t* intercept_p; divline_t trace; boolean earlyout; int ptflags; static void InterceptsOverrun(int num_intercepts, intercept_t *intercept); // // PIT_AddLineIntercepts. // Looks for lines in the given block // that intercept the given trace // to add to the intercepts list. // // A line is crossed if its endpoints // are on opposite sides of the trace. // Returns true if earlyout and a solid line hit. // boolean PIT_AddLineIntercepts (line_t* ld) { int s1; int s2; fixed_t frac; divline_t dl; // avoid precision problems with two routines if ( trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 || trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16) { s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace); } else { s1 = P_PointOnLineSide (trace.x, trace.y, ld); s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld); } if (s1 == s2) return true; // line isn't crossed // hit the line P_MakeDivline (ld, &dl); frac = P_InterceptVector (&trace, &dl); if (frac < 0) return true; // behind source // try to early out the check if (earlyout && frac < FRACUNIT && !ld->backsector) { return false; // stop checking } intercept_p->frac = frac; intercept_p->isaline = true; intercept_p->d.line = ld; InterceptsOverrun(intercept_p - intercepts, intercept_p); intercept_p++; return true; // continue } // // PIT_AddThingIntercepts // boolean PIT_AddThingIntercepts (mobj_t* thing) { fixed_t x1; fixed_t y1; fixed_t x2; fixed_t y2; int s1; int s2; boolean tracepositive; divline_t dl; fixed_t frac; tracepositive = (trace.dx ^ trace.dy)>0; // check a corner to corner crossection for hit if (tracepositive) { x1 = thing->x - thing->radius; y1 = thing->y + thing->radius; x2 = thing->x + thing->radius; y2 = thing->y - thing->radius; } else { x1 = thing->x - thing->radius; y1 = thing->y - thing->radius; x2 = thing->x + thing->radius; y2 = thing->y + thing->radius; } s1 = P_PointOnDivlineSide (x1, y1, &trace); s2 = P_PointOnDivlineSide (x2, y2, &trace); if (s1 == s2) return true; // line isn't crossed dl.x = x1; dl.y = y1; dl.dx = x2-x1; dl.dy = y2-y1; frac = P_InterceptVector (&trace, &dl); if (frac < 0) return true; // behind source intercept_p->frac = frac; intercept_p->isaline = false; intercept_p->d.thing = thing; InterceptsOverrun(intercept_p - intercepts, intercept_p); intercept_p++; return true; // keep going } // // P_TraverseIntercepts // Returns true if the traverser function returns true // for all lines. // boolean P_TraverseIntercepts ( traverser_t func, fixed_t maxfrac ) { int count; fixed_t dist; intercept_t* scan; intercept_t* in; count = intercept_p - intercepts; in = 0; // shut up compiler warning while (count--) { dist = INT_MAX; for (scan = intercepts ; scanfrac < dist) { dist = scan->frac; in = scan; } } if (dist > maxfrac) return true; // checked everything in range #if 0 // UNUSED { // don't check these yet, there may be others inserted in = scan = intercepts; for ( scan = intercepts ; scanfrac > maxfrac) *in++ = *scan; intercept_p = in; return false; } #endif if ( !func (in) ) return false; // don't bother going farther in->frac = INT_MAX; } return true; // everything was traversed } extern fixed_t bulletslope; // Intercepts Overrun emulation, from PrBoom-plus. // Thanks to Andrey Budko (entryway) for researching this and his // implementation of Intercepts Overrun emulation in PrBoom-plus // which this is based on. typedef struct { int len; void *addr; boolean int16_array; } intercepts_overrun_t; // Intercepts memory table. This is where various variables are located // in memory in Vanilla Doom. When the intercepts table overflows, we // need to write to them. // // Almost all of the values to overwrite are 32-bit integers, except for // playerstarts, which is effectively an array of 16-bit integers and // must be treated differently. static intercepts_overrun_t intercepts_overrun[] = { {4, NULL, false}, {4, NULL, /* &earlyout, */ false}, {4, NULL, /* &intercept_p, */ false}, {4, &lowfloor, false}, {4, &openbottom, false}, {4, &opentop, false}, {4, &openrange, false}, {4, NULL, false}, {120, NULL, /* &activeplats, */ false}, {8, NULL, false}, {4, &bulletslope, false}, {4, NULL, /* &swingx, */ false}, {4, NULL, /* &swingy, */ false}, {4, NULL, false}, {40, &playerstarts, true}, {4, NULL, /* &blocklinks, */ false}, {4, &bmapwidth, false}, {4, NULL, /* &blockmap, */ false}, {4, &bmaporgx, false}, {4, &bmaporgy, false}, {4, NULL, /* &blockmaplump, */ false}, {4, &bmapheight, false}, {0, NULL, false}, }; // Overwrite a specific memory location with a value. static void InterceptsMemoryOverrun(int location, int value) { int i, offset; int index; void *addr; i = 0; offset = 0; // Search down the array until we find the right entry while (intercepts_overrun[i].len != 0) { if (offset + intercepts_overrun[i].len > location) { addr = intercepts_overrun[i].addr; // Write the value to the memory location. // 16-bit and 32-bit values are written differently. if (addr != NULL) { if (intercepts_overrun[i].int16_array) { index = (location - offset) / 2; ((short *) addr)[index] = value & 0xffff; ((short *) addr)[index + 1] = (value >> 16) & 0xffff; } else { index = (location - offset) / 4; ((int *) addr)[index] = value; } } break; } offset += intercepts_overrun[i].len; ++i; } } // Emulate overruns of the intercepts[] array. static void InterceptsOverrun(int num_intercepts, intercept_t *intercept) { int location; if (num_intercepts <= MAXINTERCEPTS_ORIGINAL) { // No overrun return; } location = (num_intercepts - MAXINTERCEPTS_ORIGINAL - 1) * 12; // Overwrite memory that is overwritten in Vanilla Doom, using // the values from the intercept structure. // // Note: the ->d.{thing,line} member should really have its // address translated into the correct address value for // Vanilla Doom. InterceptsMemoryOverrun(location, intercept->frac); InterceptsMemoryOverrun(location + 4, intercept->isaline); InterceptsMemoryOverrun(location + 8, (intptr_t) intercept->d.thing); } // // P_PathTraverse // Traces a line from x1,y1 to x2,y2, // calling the traverser function for each. // Returns true if the traverser function returns true // for all lines. // boolean P_PathTraverse ( fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean (*trav) (intercept_t *)) { fixed_t xt1; fixed_t yt1; fixed_t xt2; fixed_t yt2; fixed_t xstep; fixed_t ystep; fixed_t partial; fixed_t xintercept; fixed_t yintercept; int mapx; int mapy; int mapxstep; int mapystep; int count; earlyout = (flags & PT_EARLYOUT) != 0; validcount++; intercept_p = intercepts; if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) x1 += FRACUNIT; // don't side exactly on a line if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0) y1 += FRACUNIT; // don't side exactly on a line trace.x = x1; trace.y = y1; trace.dx = x2 - x1; trace.dy = y2 - y1; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = x1>>MAPBLOCKSHIFT; yt1 = y1>>MAPBLOCKSHIFT; x2 -= bmaporgx; y2 -= bmaporgy; xt2 = x2>>MAPBLOCKSHIFT; yt2 = y2>>MAPBLOCKSHIFT; if (xt2 > xt1) { mapxstep = 1; partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1)); ystep = FixedDiv (y2-y1,abs(x2-x1)); } else if (xt2 < xt1) { mapxstep = -1; partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1); ystep = FixedDiv (y2-y1,abs(x2-x1)); } else { mapxstep = 0; partial = FRACUNIT; ystep = 256*FRACUNIT; } yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep); if (yt2 > yt1) { mapystep = 1; partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1)); xstep = FixedDiv (x2-x1,abs(y2-y1)); } else if (yt2 < yt1) { mapystep = -1; partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1); xstep = FixedDiv (x2-x1,abs(y2-y1)); } else { mapystep = 0; partial = FRACUNIT; xstep = 256*FRACUNIT; } xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep); // Step through map blocks. // Count is present to prevent a round off error // from skipping the break. mapx = xt1; mapy = yt1; for (count = 0 ; count < 64 ; count++) { if (flags & PT_ADDLINES) { if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts)) return false; // early out } if (flags & PT_ADDTHINGS) { if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts)) return false; // early out } if (mapx == xt2 && mapy == yt2) { break; } if ( (yintercept >> FRACBITS) == mapy) { yintercept += ystep; mapx += mapxstep; } else if ( (xintercept >> FRACBITS) == mapx) { xintercept += xstep; mapy += mapystep; } } // go through the sorted list return P_TraverseIntercepts ( trav, FRACUNIT ); } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_mobj.c000066400000000000000000000515121257432200600224500ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Moving object handling. Spawn functions. // #include #include "i_system.h" #include "z_zone.h" #include "m_random.h" #include "doomdef.h" #include "p_local.h" #include "sounds.h" #include "st_stuff.h" #include "hu_stuff.h" #include "s_sound.h" #include "doomstat.h" void G_PlayerReborn (int player); void P_SpawnMapThing (mapthing_t* mthing); // // P_SetMobjState // Returns true if the mobj is still present. // int test; boolean P_SetMobjState ( mobj_t* mobj, statenum_t state ) { state_t* st; do { if (state == S_NULL) { mobj->state = (state_t *) S_NULL; P_RemoveMobj (mobj); return false; } st = &states[state]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // Modified handling. // Call action functions when the state is set if (st->action.acp1) st->action.acp1(mobj); state = st->nextstate; } while (!mobj->tics); return true; } // // P_ExplodeMissile // void P_ExplodeMissile (mobj_t* mo) { mo->momx = mo->momy = mo->momz = 0; P_SetMobjState (mo, mobjinfo[mo->type].deathstate); mo->tics -= P_Random()&3; if (mo->tics < 1) mo->tics = 1; mo->flags &= ~MF_MISSILE; if (mo->info->deathsound) S_StartSound (mo, mo->info->deathsound); } // // P_XYMovement // #define STOPSPEED 0x1000 #define FRICTION 0xe800 void P_XYMovement (mobj_t* mo) { fixed_t ptryx; fixed_t ptryy; player_t* player; fixed_t xmove; fixed_t ymove; if (!mo->momx && !mo->momy) { if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->flags &= ~MF_SKULLFLY; mo->momx = mo->momy = mo->momz = 0; P_SetMobjState (mo, mo->info->spawnstate); } return; } player = mo->player; if (mo->momx > MAXMOVE) mo->momx = MAXMOVE; else if (mo->momx < -MAXMOVE) mo->momx = -MAXMOVE; if (mo->momy > MAXMOVE) mo->momy = MAXMOVE; else if (mo->momy < -MAXMOVE) mo->momy = -MAXMOVE; xmove = mo->momx; ymove = mo->momy; do { if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2) { ptryx = mo->x + xmove/2; ptryy = mo->y + ymove/2; xmove >>= 1; ymove >>= 1; } else { ptryx = mo->x + xmove; ptryy = mo->y + ymove; xmove = ymove = 0; } if (!P_TryMove (mo, ptryx, ptryy)) { // blocked move if (mo->player) { // try to slide along it P_SlideMove (mo); } else if (mo->flags & MF_MISSILE) { // explode a missile if (ceilingline && ceilingline->backsector && ceilingline->backsector->ceilingpic == skyflatnum) { // Hack to prevent missiles exploding // against the sky. // Does not handle sky floors. P_RemoveMobj (mo); return; } P_ExplodeMissile (mo); } else mo->momx = mo->momy = 0; } } while (xmove || ymove); // slow down if (player && player->cheats & CF_NOMOMENTUM) { // debug option for no sliding at all mo->momx = mo->momy = 0; return; } if (mo->flags & (MF_MISSILE | MF_SKULLFLY) ) return; // no friction for missiles ever if (mo->z > mo->floorz) return; // no friction when airborne if (mo->flags & MF_CORPSE) { // do not stop sliding // if halfway off a step with some momentum if (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 || mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) { if (mo->floorz != mo->subsector->sector->floorheight) return; } } if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && mo->momy > -STOPSPEED && mo->momy < STOPSPEED && (!player || (player->cmd.forwardmove== 0 && player->cmd.sidemove == 0 ) ) ) { // if in a walking frame, stop moving if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4) P_SetMobjState (player->mo, S_PLAY); mo->momx = 0; mo->momy = 0; } else { mo->momx = FixedMul (mo->momx, FRICTION); mo->momy = FixedMul (mo->momy, FRICTION); } } // // P_ZMovement // void P_ZMovement (mobj_t* mo) { fixed_t dist; fixed_t delta; // check for smooth step up if (mo->player && mo->z < mo->floorz) { mo->player->viewheight -= mo->floorz-mo->z; mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3; } // adjust height mo->z += mo->momz; if ( mo->flags & MF_FLOAT && mo->target) { // float down towards target if too close if ( !(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT) ) { dist = P_AproxDistance (mo->x - mo->target->x, mo->y - mo->target->y); delta =(mo->target->z + (mo->height>>1)) - mo->z; if (delta<0 && dist < -(delta*3) ) mo->z -= FLOATSPEED; else if (delta>0 && dist < (delta*3) ) mo->z += FLOATSPEED; } } // clip movement if (mo->z <= mo->floorz) { // hit the floor // Note (id): // somebody left this after the setting momz to 0, // kinda useless there. // // cph - This was the a bug in the linuxdoom-1.10 source which // caused it not to sync Doom 2 v1.9 demos. Someone // added the above comment and moved up the following code. So // demos would desync in close lost soul fights. // Note that this only applies to original Doom 1 or Doom2 demos - not // Final Doom and Ultimate Doom. So we test demo_compatibility *and* // gamemission. (Note we assume that Doom1 is always Ult Doom, which // seems to hold for most published demos.) // // fraggle - cph got the logic here slightly wrong. There are three // versions of Doom 1.9: // // * The version used in registered doom 1.9 + doom2 - no bounce // * The version used in ultimate doom - has bounce // * The version used in final doom - has bounce // // So we need to check that this is either retail or commercial // (but not doom2) int correct_lost_soul_bounce = gameversion >= exe_ultimate; if (correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; } if (mo->momz < 0) { if (mo->player && mo->momz < -GRAVITY*8) { // Squat down. // Decrease viewheight for a moment // after hitting the ground (hard), // and utter appropriate sound. mo->player->deltaviewheight = mo->momz>>3; S_StartSound (mo, sfx_oof); } mo->momz = 0; } mo->z = mo->floorz; // cph 2001/05/26 - // See lost soul bouncing comment above. We need this here for bug // compatibility with original Doom2 v1.9 - if a soul is charging and // hit by a raising floor this incorrectly reverses its Y momentum. // if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) mo->momz = -mo->momz; if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) { P_ExplodeMissile (mo); return; } } else if (! (mo->flags & MF_NOGRAVITY) ) { if (mo->momz == 0) mo->momz = -GRAVITY*2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // hit the ceiling if (mo->momz > 0) mo->momz = 0; { mo->z = mo->ceilingz - mo->height; } if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; } if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) { P_ExplodeMissile (mo); return; } } } // // P_NightmareRespawn // void P_NightmareRespawn (mobj_t* mobj) { fixed_t x; fixed_t y; fixed_t z; subsector_t* ss; mobj_t* mo; mapthing_t* mthing; x = mobj->spawnpoint.x << FRACBITS; y = mobj->spawnpoint.y << FRACBITS; // somthing is occupying it's position? if (!P_CheckPosition (mobj, x, y) ) return; // no respwan // spawn a teleport fog at old spot // because of removal of the body? mo = P_SpawnMobj (mobj->x, mobj->y, mobj->subsector->sector->floorheight , MT_TFOG); // initiate teleport sound S_StartSound (mo, sfx_telept); // spawn a teleport fog at the new spot ss = R_PointInSubsector (x,y); mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); S_StartSound (mo, sfx_telept); // spawn the new monster mthing = &mobj->spawnpoint; // spawn it if (mobj->info->flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; // inherit attributes from deceased one mo = P_SpawnMobj (x,y,z, mobj->type); mo->spawnpoint = mobj->spawnpoint; mo->angle = ANG45 * (mthing->angle/45); if (mthing->options & MTF_AMBUSH) mo->flags |= MF_AMBUSH; mo->reactiontime = 18; // remove the old monster, P_RemoveMobj (mobj); } // // P_MobjThinker // void P_MobjThinker (mobj_t* mobj) { // momentum movement if (mobj->momx || mobj->momy || (mobj->flags&MF_SKULLFLY) ) { P_XYMovement (mobj); // FIXME: decent NOP/NULL/Nil function pointer please. if (mobj->thinker.function.acv == (actionf_v) (-1)) return; // mobj was removed } if ( (mobj->z != mobj->floorz) || mobj->momz ) { P_ZMovement (mobj); // FIXME: decent NOP/NULL/Nil function pointer please. if (mobj->thinker.function.acv == (actionf_v) (-1)) return; // mobj was removed } // cycle through states, // calling action functions at transitions if (mobj->tics != -1) { mobj->tics--; // you can cycle through multiple states in a tic if (!mobj->tics) if (!P_SetMobjState (mobj, mobj->state->nextstate) ) return; // freed itself } else { // check for nightmare respawn if (! (mobj->flags & MF_COUNTKILL) ) return; if (!respawnmonsters) return; mobj->movecount++; if (mobj->movecount < 12*TICRATE) return; if ( leveltime&31 ) return; if (P_Random () > 4) return; P_NightmareRespawn (mobj); } } // // P_SpawnMobj // mobj_t* P_SpawnMobj ( fixed_t x, fixed_t y, fixed_t z, mobjtype_t type ) { mobj_t* mobj; state_t* st; mobjinfo_t* info; mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); memset (mobj, 0, sizeof (*mobj)); info = &mobjinfo[type]; mobj->type = type; mobj->info = info; mobj->x = x; mobj->y = y; mobj->radius = info->radius; mobj->height = info->height; mobj->flags = info->flags; mobj->health = info->spawnhealth; if (gameskill != sk_nightmare) mobj->reactiontime = info->reactiontime; mobj->lastlook = P_Random () % MAXPLAYERS; // do not set the state with P_SetMobjState, // because action routines can not be called yet st = &states[info->spawnstate]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // set subsector and/or block links P_SetThingPosition (mobj); mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; if (z == ONFLOORZ) mobj->z = mobj->floorz; else if (z == ONCEILINGZ) mobj->z = mobj->ceilingz - mobj->info->height; else mobj->z = z; mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; P_AddThinker (&mobj->thinker); return mobj; } // // P_RemoveMobj // mapthing_t itemrespawnque[ITEMQUESIZE]; int itemrespawntime[ITEMQUESIZE]; int iquehead; int iquetail; void P_RemoveMobj (mobj_t* mobj) { if ((mobj->flags & MF_SPECIAL) && !(mobj->flags & MF_DROPPED) && (mobj->type != MT_INV) && (mobj->type != MT_INS)) { itemrespawnque[iquehead] = mobj->spawnpoint; itemrespawntime[iquehead] = leveltime; iquehead = (iquehead+1)&(ITEMQUESIZE-1); // lose one off the end? if (iquehead == iquetail) iquetail = (iquetail+1)&(ITEMQUESIZE-1); } // unlink from sector and block lists P_UnsetThingPosition (mobj); // stop any playing sound S_StopSound (mobj); // free block P_RemoveThinker ((thinker_t*)mobj); } // // P_RespawnSpecials // void P_RespawnSpecials (void) { fixed_t x; fixed_t y; fixed_t z; subsector_t* ss; mobj_t* mo; mapthing_t* mthing; int i; // only respawn items in deathmatch if (deathmatch != 2) return; // // nothing left to respawn? if (iquehead == iquetail) return; // wait at least 30 seconds if (leveltime - itemrespawntime[iquetail] < 30*TICRATE) return; mthing = &itemrespawnque[iquetail]; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; // spawn a teleport fog at the new spot ss = R_PointInSubsector (x,y); mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); S_StartSound (mo, sfx_itmbk); // find which type to spawn for (i=0 ; i< NUMMOBJTYPES ; i++) { if (mthing->type == mobjinfo[i].doomednum) break; } // spawn it if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mo = P_SpawnMobj (x,y,z, i); mo->spawnpoint = *mthing; mo->angle = ANG45 * (mthing->angle/45); // pull it from the que iquetail = (iquetail+1)&(ITEMQUESIZE-1); } // // P_SpawnPlayer // Called when a player is spawned on the level. // Most of the player structure stays unchanged // between levels. // void P_SpawnPlayer (mapthing_t* mthing) { player_t* p; fixed_t x; fixed_t y; fixed_t z; mobj_t* mobj; int i; if (mthing->type == 0) { return; } // not playing? if (!playeringame[mthing->type-1]) return; p = &players[mthing->type-1]; if (p->playerstate == PST_REBORN) G_PlayerReborn (mthing->type-1); x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; z = ONFLOORZ; mobj = P_SpawnMobj (x,y,z, MT_PLAYER); // set color translations for player sprites if (mthing->type > 1) mobj->flags |= (mthing->type-1)<angle = ANG45 * (mthing->angle/45); mobj->player = p; mobj->health = p->health; p->mo = mobj; p->playerstate = PST_LIVE; p->refire = 0; p->message = NULL; p->damagecount = 0; p->bonuscount = 0; p->extralight = 0; p->fixedcolormap = 0; p->viewheight = VIEWHEIGHT; // setup gun psprite P_SetupPsprites (p); // give all cards in death match mode if (deathmatch) for (i=0 ; icards[i] = true; if (mthing->type-1 == consoleplayer) { // wake up the status bar ST_Start (); // wake up the heads up text HU_Start (); } } // // P_SpawnMapThing // The fields of the mapthing should // already be in host byte order. // void P_SpawnMapThing (mapthing_t* mthing) { int i; int bit; mobj_t* mobj; fixed_t x; fixed_t y; fixed_t z; // count deathmatch start positions if (mthing->type == 11) { if (deathmatch_p < &deathmatchstarts[10]) { memcpy (deathmatch_p, mthing, sizeof(*mthing)); deathmatch_p++; } return; } if (mthing->type <= 0) { // Thing type 0 is actually "player -1 start". // For some reason, Vanilla Doom accepts/ignores this. return; } // check for players specially if (mthing->type <= 4) { // save spots for respawning in network games playerstarts[mthing->type-1] = *mthing; if (!deathmatch) P_SpawnPlayer (mthing); return; } // check for apropriate skill level if (!netgame && (mthing->options & 16) ) return; if (gameskill == sk_baby) bit = 1; else if (gameskill == sk_nightmare) bit = 4; else bit = 1<<(gameskill-1); if (!(mthing->options & bit) ) return; // find which type to spawn for (i=0 ; i< NUMMOBJTYPES ; i++) if (mthing->type == mobjinfo[i].doomednum) break; if (i==NUMMOBJTYPES) I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type, mthing->x, mthing->y); // don't spawn keycards and players in deathmatch if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) return; // don't spawn any monsters if -nomonsters if (nomonsters && ( i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL)) ) { return; } // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mobj = P_SpawnMobj (x,y,z, i); mobj->spawnpoint = *mthing; if (mobj->tics > 0) mobj->tics = 1 + (P_Random () % mobj->tics); if (mobj->flags & MF_COUNTKILL) totalkills++; if (mobj->flags & MF_COUNTITEM) totalitems++; mobj->angle = ANG45 * (mthing->angle/45); if (mthing->options & MTF_AMBUSH) mobj->flags |= MF_AMBUSH; } // // GAME SPAWN FUNCTIONS // // // P_SpawnPuff // extern fixed_t attackrange; void P_SpawnPuff ( fixed_t x, fixed_t y, fixed_t z ) { mobj_t* th; z += ((P_Random()-P_Random())<<10); th = P_SpawnMobj (x,y,z, MT_PUFF); th->momz = FRACUNIT; th->tics -= P_Random()&3; if (th->tics < 1) th->tics = 1; // don't make punches spark on the wall if (attackrange == MELEERANGE) P_SetMobjState (th, S_PUFF3); } // // P_SpawnBlood // void P_SpawnBlood ( fixed_t x, fixed_t y, fixed_t z, int damage ) { mobj_t* th; z += ((P_Random()-P_Random())<<10); th = P_SpawnMobj (x,y,z, MT_BLOOD); th->momz = FRACUNIT*2; th->tics -= P_Random()&3; if (th->tics < 1) th->tics = 1; if (damage <= 12 && damage >= 9) P_SetMobjState (th,S_BLOOD2); else if (damage < 9) P_SetMobjState (th,S_BLOOD3); } // // P_CheckMissileSpawn // Moves the missile forward a bit // and possibly explodes it right there. // void P_CheckMissileSpawn (mobj_t* th) { th->tics -= P_Random()&3; if (th->tics < 1) th->tics = 1; // move a little forward so an angle can // be computed if it immediately explodes th->x += (th->momx>>1); th->y += (th->momy>>1); th->z += (th->momz>>1); if (!P_TryMove (th, th->x, th->y)) P_ExplodeMissile (th); } // Certain functions assume that a mobj_t pointer is non-NULL, // causing a crash in some situations where it is NULL. Vanilla // Doom did not crash because of the lack of proper memory // protection. This function substitutes NULL pointers for // pointers to a dummy mobj, to avoid a crash. mobj_t *P_SubstNullMobj(mobj_t *mobj) { if (mobj == NULL) { static mobj_t dummy_mobj; dummy_mobj.x = 0; dummy_mobj.y = 0; dummy_mobj.z = 0; dummy_mobj.flags = 0; mobj = &dummy_mobj; } return mobj; } // // P_SpawnMissile // mobj_t* P_SpawnMissile ( mobj_t* source, mobj_t* dest, mobjtype_t type ) { mobj_t* th; angle_t an; int dist; th = P_SpawnMobj (source->x, source->y, source->z + 4*8*FRACUNIT, type); if (th->info->seesound) S_StartSound (th, th->info->seesound); th->target = source; // where it came from an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); // fuzzy player if (dest->flags & MF_SHADOW) an += (P_Random()-P_Random())<<20; th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul (th->info->speed, finecosine[an]); th->momy = FixedMul (th->info->speed, finesine[an]); dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); dist = dist / th->info->speed; if (dist < 1) dist = 1; th->momz = (dest->z - source->z) / dist; P_CheckMissileSpawn (th); return th; } // // P_SpawnPlayerMissile // Tries to aim at a nearby monster // void P_SpawnPlayerMissile ( mobj_t* source, mobjtype_t type ) { mobj_t* th; angle_t an; fixed_t x; fixed_t y; fixed_t z; fixed_t slope; // see which target is to be aimed at an = source->angle; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); if (!linetarget) { an += 1<<26; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); if (!linetarget) { an -= 2<<26; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); } if (!linetarget) { an = source->angle; slope = 0; } } x = source->x; y = source->y; z = source->z + 4*8*FRACUNIT; th = P_SpawnMobj (x,y,z, type); if (th->info->seesound) S_StartSound (th, th->info->seesound); th->target = source; th->angle = an; th->momx = FixedMul( th->info->speed, finecosine[an>>ANGLETOFINESHIFT]); th->momy = FixedMul( th->info->speed, finesine[an>>ANGLETOFINESHIFT]); th->momz = FixedMul( th->info->speed, slope); P_CheckMissileSpawn (th); } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_mobj.h000066400000000000000000000207401257432200600224540ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Map Objects, MObj, definition and handling. // #ifndef __P_MOBJ__ #define __P_MOBJ__ // Basics. #include "tables.h" #include "m_fixed.h" // We need the thinker_t stuff. #include "d_think.h" // We need the WAD data structure for Map things, // from the THINGS lump. #include "doomdata.h" // States are tied to finite states are // tied to animation frames. // Needs precompiled tables/data structures. #include "info.h" // // NOTES: mobj_t // // mobj_ts are used to tell the refresh where to draw an image, // tell the world simulation when objects are contacted, // and tell the sound driver how to position a sound. // // The refresh uses the next and prev links to follow // lists of things in sectors as they are being drawn. // The sprite, frame, and angle elements determine which patch_t // is used to draw the sprite if it is visible. // The sprite and frame values are allmost allways set // from state_t structures. // The statescr.exe utility generates the states.h and states.c // files that contain the sprite/frame numbers from the // statescr.txt source file. // The xyz origin point represents a point at the bottom middle // of the sprite (between the feet of a biped). // This is the default origin position for patch_ts grabbed // with lumpy.exe. // A walking creature will have its z equal to the floor // it is standing on. // // The sound code uses the x,y, and subsector fields // to do stereo positioning of any sound effited by the mobj_t. // // The play simulation uses the blocklinks, x,y,z, radius, height // to determine when mobj_ts are touching each other, // touching lines in the map, or hit by trace lines (gunshots, // lines of sight, etc). // The mobj_t->flags element has various bit flags // used by the simulation. // // Every mobj_t is linked into a single sector // based on its origin coordinates. // The subsector_t is found with R_PointInSubsector(x,y), // and the sector_t can be found with subsector->sector. // The sector links are only used by the rendering code, // the play simulation does not care about them at all. // // Any mobj_t that needs to be acted upon by something else // in the play world (block movement, be shot, etc) will also // need to be linked into the blockmap. // If the thing has the MF_NOBLOCK flag set, it will not use // the block links. It can still interact with other things, // but only as the instigator (missiles will run into other // things, but nothing can run into a missile). // Each block in the grid is 128*128 units, and knows about // every line_t that it contains a piece of, and every // interactable mobj_t that has its origin contained. // // A valid mobj_t is a mobj_t that has the proper subsector_t // filled in for its xy coordinates and is linked into the // sector from which the subsector was made, or has the // MF_NOSECTOR flag set (the subsector_t needs to be valid // even if MF_NOSECTOR is set), and is linked into a blockmap // block or has the MF_NOBLOCKMAP flag set. // Links should only be modified by the P_[Un]SetThingPosition() // functions. // Do not change the MF_NO? flags while a thing is valid. // // Any questions? // // // Misc. mobj flags // typedef enum { // Call P_SpecialThing when touched. MF_SPECIAL = 1, // Blocks. MF_SOLID = 2, // Can be hit. MF_SHOOTABLE = 4, // Don't use the sector links (invisible but touchable). MF_NOSECTOR = 8, // Don't use the blocklinks (inert but displayable) MF_NOBLOCKMAP = 16, // Not to be activated by sound, deaf monster. MF_AMBUSH = 32, // Will try to attack right back. MF_JUSTHIT = 64, // Will take at least one step before attacking. MF_JUSTATTACKED = 128, // On level spawning (initial position), // hang from ceiling instead of stand on floor. MF_SPAWNCEILING = 256, // Don't apply gravity (every tic), // that is, object will float, keeping current height // or changing it actively. MF_NOGRAVITY = 512, // Movement flags. // This allows jumps from high places. MF_DROPOFF = 0x400, // For players, will pick up items. MF_PICKUP = 0x800, // Player cheat. ??? MF_NOCLIP = 0x1000, // Player: keep info about sliding along walls. MF_SLIDE = 0x2000, // Allow moves to any height, no gravity. // For active floaters, e.g. cacodemons, pain elementals. MF_FLOAT = 0x4000, // Don't cross lines // ??? or look at heights on teleport. MF_TELEPORT = 0x8000, // Don't hit same species, explode on block. // Player missiles as well as fireballs of various kinds. MF_MISSILE = 0x10000, // Dropped by a demon, not level spawned. // E.g. ammo clips dropped by dying former humans. MF_DROPPED = 0x20000, // Use fuzzy draw (shadow demons or spectres), // temporary player invisibility powerup. MF_SHADOW = 0x40000, // Flag: don't bleed when shot (use puff), // barrels and shootable furniture shall not bleed. MF_NOBLOOD = 0x80000, // Don't stop moving halfway off a step, // that is, have dead bodies slide down all the way. MF_CORPSE = 0x100000, // Floating to a height for a move, ??? // don't auto float to target's height. MF_INFLOAT = 0x200000, // On kill, count this enemy object // towards intermission kill total. // Happy gathering. MF_COUNTKILL = 0x400000, // On picking up, count this item object // towards intermission item total. MF_COUNTITEM = 0x800000, // Special handling: skull in flight. // Neither a cacodemon nor a missile. MF_SKULLFLY = 0x1000000, // Don't spawn this object // in death match mode (e.g. key cards). MF_NOTDMATCH = 0x2000000, // Player sprites in multiplayer modes are modified // using an internal color lookup table for re-indexing. // If 0x4 0x8 or 0xc, // use a translation table for player colormaps MF_TRANSLATION = 0xc000000, // Hmm ???. MF_TRANSSHIFT = 26 } mobjflag_t; // Map Object definition. typedef struct mobj_s { // List: thinker links. thinker_t thinker; // Info for drawing: position. fixed_t x; fixed_t y; fixed_t z; // More list: links in sector (if needed) struct mobj_s* snext; struct mobj_s* sprev; //More drawing info: to determine current sprite. angle_t angle; // orientation spritenum_t sprite; // used to find patch_t and flip value int frame; // might be ORed with FF_FULLBRIGHT // Interaction info, by BLOCKMAP. // Links in blocks (if needed). struct mobj_s* bnext; struct mobj_s* bprev; struct subsector_s* subsector; // The closest interval over all contacted Sectors. fixed_t floorz; fixed_t ceilingz; // For movement checking. fixed_t radius; fixed_t height; // Momentums, used to update position. fixed_t momx; fixed_t momy; fixed_t momz; // If == validcount, already checked. int validcount; mobjtype_t type; mobjinfo_t* info; // &mobjinfo[mobj->type] int tics; // state tic counter state_t* state; int flags; int health; // Movement direction, movement generation (zig-zagging). int movedir; // 0-7 int movecount; // when 0, select a new dir // Thing being chased/attacked (or NULL), // also the originator for missiles. struct mobj_s* target; // Reaction time: if non 0, don't attack yet. // Used by player to freeze a bit after teleporting. int reactiontime; // If >0, the target will be chased // no matter what (even if shot) int threshold; // Additional info record for player avatars only. // Only valid if type == MT_PLAYER struct player_s* player; // Player number last looked for. int lastlook; // For nightmare respawn. mapthing_t spawnpoint; // Thing being chased/attacked for tracers. struct mobj_s* tracer; } mobj_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/p_plats.c000066400000000000000000000143471257432200600226510ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Plats (i.e. elevator platforms) code, raising/lowering. // #include #include "i_system.h" #include "z_zone.h" #include "m_random.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" plat_t* activeplats[MAXPLATS]; // // Move a plat up and down // void T_PlatRaise(plat_t* plat) { result_e res; switch(plat->status) { case up: res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush,0,1); if (plat->type == raiseAndChange || plat->type == raiseToNearestAndChange) { if (!(leveltime&7)) S_StartSound(&plat->sector->soundorg, sfx_stnmov); } if (res == crushed && (!plat->crush)) { plat->count = plat->wait; plat->status = down; S_StartSound(&plat->sector->soundorg, sfx_pstart); } else { if (res == pastdest) { plat->count = plat->wait; plat->status = waiting; S_StartSound(&plat->sector->soundorg, sfx_pstop); switch(plat->type) { case blazeDWUS: case downWaitUpStay: P_RemoveActivePlat(plat); break; case raiseAndChange: case raiseToNearestAndChange: P_RemoveActivePlat(plat); break; default: break; } } } break; case down: res = T_MovePlane(plat->sector,plat->speed,plat->low,false,0,-1); if (res == pastdest) { plat->count = plat->wait; plat->status = waiting; S_StartSound(&plat->sector->soundorg,sfx_pstop); } break; case waiting: if (!--plat->count) { if (plat->sector->floorheight == plat->low) plat->status = up; else plat->status = down; S_StartSound(&plat->sector->soundorg,sfx_pstart); } case in_stasis: break; } } // // Do Platforms // "amount" is only used for SOME platforms. // int EV_DoPlat ( line_t* line, plattype_e type, int amount ) { plat_t* plat; int secnum; int rtn; sector_t* sec; secnum = -1; rtn = 0; // Activate all plats that are in_stasis switch(type) { case perpetualRaise: P_ActivateInStasis(line->tag); break; default: break; } while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // Find lowest & highest floors around sector rtn = 1; plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); P_AddThinker(&plat->thinker); plat->type = type; plat->sector = sec; plat->sector->specialdata = plat; plat->thinker.function.acp1 = (actionf_p1) T_PlatRaise; plat->crush = false; plat->tag = line->tag; switch(type) { case raiseToNearestAndChange: plat->speed = PLATSPEED/2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = P_FindNextHighestFloor(sec,sec->floorheight); plat->wait = 0; plat->status = up; // NO MORE DAMAGE, IF APPLICABLE sec->special = 0; S_StartSound(&sec->soundorg,sfx_stnmov); break; case raiseAndChange: plat->speed = PLATSPEED/2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = sec->floorheight + amount*FRACUNIT; plat->wait = 0; plat->status = up; S_StartSound(&sec->soundorg,sfx_stnmov); break; case downWaitUpStay: plat->speed = PLATSPEED * 4; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = TICRATE*PLATWAIT; plat->status = down; S_StartSound(&sec->soundorg,sfx_pstart); break; case blazeDWUS: plat->speed = PLATSPEED * 8; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = TICRATE*PLATWAIT; plat->status = down; S_StartSound(&sec->soundorg,sfx_pstart); break; case perpetualRaise: plat->speed = PLATSPEED; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = P_FindHighestFloorSurrounding(sec); if (plat->high < sec->floorheight) plat->high = sec->floorheight; plat->wait = TICRATE*PLATWAIT; plat->status = P_Random()&1; S_StartSound(&sec->soundorg,sfx_pstart); break; } P_AddActivePlat(plat); } return rtn; } void P_ActivateInStasis(int tag) { int i; for (i = 0;i < MAXPLATS;i++) if (activeplats[i] && (activeplats[i])->tag == tag && (activeplats[i])->status == in_stasis) { (activeplats[i])->status = (activeplats[i])->oldstatus; (activeplats[i])->thinker.function.acp1 = (actionf_p1) T_PlatRaise; } } void EV_StopPlat(line_t* line) { int j; for (j = 0;j < MAXPLATS;j++) if (activeplats[j] && ((activeplats[j])->status != in_stasis) && ((activeplats[j])->tag == line->tag)) { (activeplats[j])->oldstatus = (activeplats[j])->status; (activeplats[j])->status = in_stasis; (activeplats[j])->thinker.function.acv = (actionf_v)NULL; } } void P_AddActivePlat(plat_t* plat) { int i; for (i = 0;i < MAXPLATS;i++) if (activeplats[i] == NULL) { activeplats[i] = plat; return; } I_Error ("P_AddActivePlat: no more plats!"); } void P_RemoveActivePlat(plat_t* plat) { int i; for (i = 0;i < MAXPLATS;i++) if (plat == activeplats[i]) { (activeplats[i])->sector->specialdata = NULL; P_RemoveThinker(&(activeplats[i])->thinker); activeplats[i] = NULL; return; } I_Error ("P_RemoveActivePlat: can't find plat!"); } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_pspr.c000066400000000000000000000410141257432200600225010ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Weapon sprite animation, weapon objects. // Action functions for weapons. // #include "doomdef.h" #include "d_event.h" #include "deh_misc.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" // Data. #include "sounds.h" #include "p_pspr.h" #define LOWERSPEED FRACUNIT*6 #define RAISESPEED FRACUNIT*6 #define WEAPONBOTTOM 128*FRACUNIT #define WEAPONTOP 32*FRACUNIT // // P_SetPsprite // void P_SetPsprite ( player_t* player, int position, statenum_t stnum ) { pspdef_t* psp; state_t* state; psp = &player->psprites[position]; do { if (!stnum) { // object removed itself psp->state = NULL; break; } state = &states[stnum]; psp->state = state; psp->tics = state->tics; // could be 0 if (state->misc1) { // coordinate set psp->sx = state->misc1 << FRACBITS; psp->sy = state->misc2 << FRACBITS; } // Call action routine. // Modified handling. if (state->action.acp2) { state->action.acp2(player, psp); if (!psp->state) break; } stnum = psp->state->nextstate; } while (!psp->tics); // an initial state of 0 could cycle through } // // P_CalcSwing // fixed_t swingx; fixed_t swingy; void P_CalcSwing (player_t* player) { fixed_t swing; int angle; // OPTIMIZE: tablify this. // A LUT would allow for different modes, // and add flexibility. swing = player->bob; angle = (FINEANGLES/70*leveltime)&FINEMASK; swingx = FixedMul ( swing, finesine[angle]); angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK; swingy = -FixedMul ( swingx, finesine[angle]); } // // P_BringUpWeapon // Starts bringing the pending weapon up // from the bottom of the screen. // Uses player // void P_BringUpWeapon (player_t* player) { statenum_t newstate; if (player->pendingweapon == wp_nochange) player->pendingweapon = player->readyweapon; if (player->pendingweapon == wp_chainsaw) S_StartSound (player->mo, sfx_sawup); newstate = weaponinfo[player->pendingweapon].upstate; player->pendingweapon = wp_nochange; player->psprites[ps_weapon].sy = WEAPONBOTTOM; P_SetPsprite (player, ps_weapon, newstate); } // // P_CheckAmmo // Returns true if there is enough ammo to shoot. // If not, selects the next weapon to use. // boolean P_CheckAmmo (player_t* player) { ammotype_t ammo; int count; ammo = weaponinfo[player->readyweapon].ammo; // Minimal amount for one shot varies. if (player->readyweapon == wp_bfg) count = deh_bfg_cells_per_shot; else if (player->readyweapon == wp_supershotgun) count = 2; // Double barrel. else count = 1; // Regular. // Some do not need ammunition anyway. // Return if current ammunition sufficient. if (ammo == am_noammo || player->ammo[ammo] >= count) return true; // Out of ammo, pick a weapon to change to. // Preferences are set here. do { if (player->weaponowned[wp_plasma] && player->ammo[am_cell] && (gamemode != shareware) ) { player->pendingweapon = wp_plasma; } else if (player->weaponowned[wp_supershotgun] && player->ammo[am_shell]>2 && (gamemode == commercial) ) { player->pendingweapon = wp_supershotgun; } else if (player->weaponowned[wp_chaingun] && player->ammo[am_clip]) { player->pendingweapon = wp_chaingun; } else if (player->weaponowned[wp_shotgun] && player->ammo[am_shell]) { player->pendingweapon = wp_shotgun; } else if (player->ammo[am_clip]) { player->pendingweapon = wp_pistol; } else if (player->weaponowned[wp_chainsaw]) { player->pendingweapon = wp_chainsaw; } else if (player->weaponowned[wp_missile] && player->ammo[am_misl]) { player->pendingweapon = wp_missile; } else if (player->weaponowned[wp_bfg] && player->ammo[am_cell]>40 && (gamemode != shareware) ) { player->pendingweapon = wp_bfg; } else { // If everything fails. player->pendingweapon = wp_fist; } } while (player->pendingweapon == wp_nochange); // Now set appropriate weapon overlay. P_SetPsprite (player, ps_weapon, weaponinfo[player->readyweapon].downstate); return false; } // // P_FireWeapon. // void P_FireWeapon (player_t* player) { statenum_t newstate; if (!P_CheckAmmo (player)) return; P_SetMobjState (player->mo, S_PLAY_ATK1); newstate = weaponinfo[player->readyweapon].atkstate; P_SetPsprite (player, ps_weapon, newstate); P_NoiseAlert (player->mo, player->mo); } // // P_DropWeapon // Player died, so put the weapon away. // void P_DropWeapon (player_t* player) { P_SetPsprite (player, ps_weapon, weaponinfo[player->readyweapon].downstate); } // // A_WeaponReady // The player can fire the weapon // or change to another weapon at this time. // Follows after getting weapon up, // or after previous attack/fire sequence. // void A_WeaponReady ( player_t* player, pspdef_t* psp ) { statenum_t newstate; int angle; // get out of attack state if (player->mo->state == &states[S_PLAY_ATK1] || player->mo->state == &states[S_PLAY_ATK2] ) { P_SetMobjState (player->mo, S_PLAY); } if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW]) { S_StartSound (player->mo, sfx_sawidl); } // check for change // if player is dead, put the weapon away if (player->pendingweapon != wp_nochange || !player->health) { // change weapon // (pending weapon should allready be validated) newstate = weaponinfo[player->readyweapon].downstate; P_SetPsprite (player, ps_weapon, newstate); return; } // check for fire // the missile launcher and bfg do not auto fire if (player->cmd.buttons & BT_ATTACK) { if ( !player->attackdown || (player->readyweapon != wp_missile && player->readyweapon != wp_bfg) ) { player->attackdown = true; P_FireWeapon (player); return; } } else player->attackdown = false; // bob the weapon based on movement speed angle = (128*leveltime)&FINEMASK; psp->sx = FRACUNIT + FixedMul (player->bob, finecosine[angle]); angle &= FINEANGLES/2-1; psp->sy = WEAPONTOP + FixedMul (player->bob, finesine[angle]); } // // A_ReFire // The player can re-fire the weapon // without lowering it entirely. // void A_ReFire ( player_t* player, pspdef_t* psp ) { // check for fire // (if a weaponchange is pending, let it go through instead) if ( (player->cmd.buttons & BT_ATTACK) && player->pendingweapon == wp_nochange && player->health) { player->refire++; P_FireWeapon (player); } else { player->refire = 0; P_CheckAmmo (player); } } void A_CheckReload ( player_t* player, pspdef_t* psp ) { P_CheckAmmo (player); #if 0 if (player->ammo[am_shell]<2) P_SetPsprite (player, ps_weapon, S_DSNR1); #endif } // // A_Lower // Lowers current weapon, // and changes weapon at bottom. // void A_Lower ( player_t* player, pspdef_t* psp ) { psp->sy += LOWERSPEED; // Is already down. if (psp->sy < WEAPONBOTTOM ) return; // Player is dead. if (player->playerstate == PST_DEAD) { psp->sy = WEAPONBOTTOM; // don't bring weapon back up return; } // The old weapon has been lowered off the screen, // so change the weapon and start raising it if (!player->health) { // Player is dead, so keep the weapon off screen. P_SetPsprite (player, ps_weapon, S_NULL); return; } player->readyweapon = player->pendingweapon; P_BringUpWeapon (player); } // // A_Raise // void A_Raise ( player_t* player, pspdef_t* psp ) { statenum_t newstate; psp->sy -= RAISESPEED; if (psp->sy > WEAPONTOP ) return; psp->sy = WEAPONTOP; // The weapon has been raised all the way, // so change to the ready state. newstate = weaponinfo[player->readyweapon].readystate; P_SetPsprite (player, ps_weapon, newstate); } // // A_GunFlash // void A_GunFlash ( player_t* player, pspdef_t* psp ) { P_SetMobjState (player->mo, S_PLAY_ATK2); P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate); } // // WEAPON ATTACKS // // // A_Punch // void A_Punch ( player_t* player, pspdef_t* psp ) { angle_t angle; int damage; int slope; damage = (P_Random ()%10+1)<<1; if (player->powers[pw_strength]) damage *= 10; angle = player->mo->angle; angle += (P_Random()-P_Random())<<18; slope = P_AimLineAttack (player->mo, angle, MELEERANGE); P_LineAttack (player->mo, angle, MELEERANGE, slope, damage); // turn to face target if (linetarget) { S_StartSound (player->mo, sfx_punch); player->mo->angle = R_PointToAngle2 (player->mo->x, player->mo->y, linetarget->x, linetarget->y); } } // // A_Saw // void A_Saw ( player_t* player, pspdef_t* psp ) { angle_t angle; int damage; int slope; damage = 2*(P_Random ()%10+1); angle = player->mo->angle; angle += (P_Random()-P_Random())<<18; // use meleerange + 1 se the puff doesn't skip the flash slope = P_AimLineAttack (player->mo, angle, MELEERANGE+1); P_LineAttack (player->mo, angle, MELEERANGE+1, slope, damage); if (!linetarget) { S_StartSound (player->mo, sfx_sawful); return; } S_StartSound (player->mo, sfx_sawhit); // turn to face target angle = R_PointToAngle2 (player->mo->x, player->mo->y, linetarget->x, linetarget->y); if (angle - player->mo->angle > ANG180) { if ((signed int) (angle - player->mo->angle) < -ANG90/20) player->mo->angle = angle + ANG90/21; else player->mo->angle -= ANG90/20; } else { if (angle - player->mo->angle > ANG90/20) player->mo->angle = angle - ANG90/21; else player->mo->angle += ANG90/20; } player->mo->flags |= MF_JUSTATTACKED; } // Doom does not check the bounds of the ammo array. As a result, // it is possible to use an ammo type > 4 that overflows into the // maxammo array and affects that instead. Through dehacked, for // example, it is possible to make a weapon that decreases the max // number of ammo for another weapon. Emulate this. static void DecreaseAmmo(player_t *player, int ammonum, int amount) { if (ammonum < NUMAMMO) { player->ammo[ammonum] -= amount; } else { player->maxammo[ammonum - NUMAMMO] -= amount; } } // // A_FireMissile // void A_FireMissile ( player_t* player, pspdef_t* psp ) { DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SpawnPlayerMissile (player->mo, MT_ROCKET); } // // A_FireBFG // void A_FireBFG ( player_t* player, pspdef_t* psp ) { DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, deh_bfg_cells_per_shot); P_SpawnPlayerMissile (player->mo, MT_BFG); } // // A_FirePlasma // void A_FirePlasma ( player_t* player, pspdef_t* psp ) { DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, weaponinfo[player->readyweapon].flashstate+(P_Random ()&1) ); P_SpawnPlayerMissile (player->mo, MT_PLASMA); } // // P_BulletSlope // Sets a slope so a near miss is at aproximately // the height of the intended target // fixed_t bulletslope; void P_BulletSlope (mobj_t* mo) { angle_t an; // see which target is to be aimed at an = mo->angle; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); if (!linetarget) { an += 1<<26; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); if (!linetarget) { an -= 2<<26; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); } } } // // P_GunShot // void P_GunShot ( mobj_t* mo, boolean accurate ) { angle_t angle; int damage; damage = 5*(P_Random ()%3+1); angle = mo->angle; if (!accurate) angle += (P_Random()-P_Random())<<18; P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage); } // // A_FirePistol // void A_FirePistol ( player_t* player, pspdef_t* psp ) { S_StartSound (player->mo, sfx_pistol); P_SetMobjState (player->mo, S_PLAY_ATK2); DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, weaponinfo[player->readyweapon].flashstate); P_BulletSlope (player->mo); P_GunShot (player->mo, !player->refire); } // // A_FireShotgun // void A_FireShotgun ( player_t* player, pspdef_t* psp ) { int i; S_StartSound (player->mo, sfx_shotgn); P_SetMobjState (player->mo, S_PLAY_ATK2); DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, weaponinfo[player->readyweapon].flashstate); P_BulletSlope (player->mo); for (i=0 ; i<7 ; i++) P_GunShot (player->mo, false); } // // A_FireShotgun2 // void A_FireShotgun2 ( player_t* player, pspdef_t* psp ) { int i; angle_t angle; int damage; S_StartSound (player->mo, sfx_dshtgn); P_SetMobjState (player->mo, S_PLAY_ATK2); DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 2); P_SetPsprite (player, ps_flash, weaponinfo[player->readyweapon].flashstate); P_BulletSlope (player->mo); for (i=0 ; i<20 ; i++) { damage = 5*(P_Random ()%3+1); angle = player->mo->angle; angle += (P_Random()-P_Random())<<19; P_LineAttack (player->mo, angle, MISSILERANGE, bulletslope + ((P_Random()-P_Random())<<5), damage); } } // // A_FireCGun // void A_FireCGun ( player_t* player, pspdef_t* psp ) { S_StartSound (player->mo, sfx_pistol); if (!player->ammo[weaponinfo[player->readyweapon].ammo]) return; P_SetMobjState (player->mo, S_PLAY_ATK2); DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, weaponinfo[player->readyweapon].flashstate + psp->state - &states[S_CHAIN1] ); P_BulletSlope (player->mo); P_GunShot (player->mo, !player->refire); } // // ? // void A_Light0 (player_t *player, pspdef_t *psp) { player->extralight = 0; } void A_Light1 (player_t *player, pspdef_t *psp) { player->extralight = 1; } void A_Light2 (player_t *player, pspdef_t *psp) { player->extralight = 2; } // // A_BFGSpray // Spawn a BFG explosion on every monster in view // void A_BFGSpray (mobj_t* mo) { int i; int j; int damage; angle_t an; // offset angles from its attack angle for (i=0 ; i<40 ; i++) { an = mo->angle - ANG90/2 + ANG90/40*i; // mo->target is the originator (player) // of the missile P_AimLineAttack (mo->target, an, 16*64*FRACUNIT); if (!linetarget) continue; P_SpawnMobj (linetarget->x, linetarget->y, linetarget->z + (linetarget->height>>2), MT_EXTRABFG); damage = 0; for (j=0;j<15;j++) damage += (P_Random()&7) + 1; P_DamageMobj (linetarget, mo->target,mo->target, damage); } } // // A_BFGsound // void A_BFGsound ( player_t* player, pspdef_t* psp ) { S_StartSound (player->mo, sfx_bfg); } // // P_SetupPsprites // Called at start of level for each player. // void P_SetupPsprites (player_t* player) { int i; // remove all psprites for (i=0 ; ipsprites[i].state = NULL; // spawn the gun player->pendingweapon = player->readyweapon; P_BringUpWeapon (player); } // // P_MovePsprites // Called every tic by player thinking routine. // void P_MovePsprites (player_t* player) { int i; pspdef_t* psp; state_t* state; psp = &player->psprites[0]; for (i=0 ; istate) ) { // drop tic count and possibly change state // a -1 tic count never changes if (psp->tics != -1) { psp->tics--; if (!psp->tics) P_SetPsprite (player, i, psp->state->nextstate); } } } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_pspr.h000066400000000000000000000030141257432200600225040ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Sprite animation. // #ifndef __P_PSPR__ #define __P_PSPR__ // Basic data types. // Needs fixed point, and BAM angles. #include "m_fixed.h" #include "tables.h" // // Needs to include the precompiled // sprite animation tables. // Header generated by multigen utility. // This includes all the data for thing animation, // i.e. the Thing Atrributes table // and the Frame Sequence table. #include "info.h" // // Frame flags: // handles maximum brightness (torches, muzzle flare, light sources) // #define FF_FULLBRIGHT 0x8000 // flag in thing->frame #define FF_FRAMEMASK 0x7fff // // Overlay psprites are scaled shapes // drawn directly on the view screen, // coordinates are given for a 320*200 view screen. // typedef enum { ps_weapon, ps_flash, NUMPSPRITES } psprnum_t; typedef struct { state_t* state; // a NULL state means not active int tics; fixed_t sx; fixed_t sy; } pspdef_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/p_saveg.c000066400000000000000000001066521257432200600226340ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Archiving: SaveGame I/O. // #include #include #include "dstrings.h" #include "deh_main.h" #include "i_system.h" #include "z_zone.h" #include "p_local.h" #include "p_saveg.h" // State. #include "doomstat.h" #include "g_game.h" #include "m_misc.h" #include "r_state.h" #define SAVEGAME_EOF 0x1d #define VERSIONSIZE 16 FILE *save_stream; int savegamelength; boolean savegame_error; // Get the filename of a temporary file to write the savegame to. After // the file has been successfully saved, it will be renamed to the // real file. char *P_TempSaveGameFile(void) { static char *filename = NULL; if (filename == NULL) { filename = M_StringJoin(savegamedir, "temp.dsg", NULL); } return filename; } // Get the filename of the save game file to use for the specified slot. char *P_SaveGameFile(int slot) { static char *filename = NULL; static size_t filename_size = 0; char basename[32]; if (filename == NULL) { filename_size = strlen(savegamedir) + 32; filename = malloc(filename_size); } DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot); M_snprintf(filename, filename_size, "%s%s", savegamedir, basename); return filename; } // Endian-safe integer read/write functions static byte saveg_read8(void) { byte result; if (fread(&result, 1, 1, save_stream) < 1) { if (!savegame_error) { fprintf(stderr, "saveg_read8: Unexpected end of file while " "reading save game\n"); savegame_error = true; } } return result; } static void saveg_write8(byte value) { if (fwrite(&value, 1, 1, save_stream) < 1) { if (!savegame_error) { fprintf(stderr, "saveg_write8: Error while writing save game\n"); savegame_error = true; } } } static short saveg_read16(void) { int result; result = saveg_read8(); result |= saveg_read8() << 8; return result; } static void saveg_write16(short value) { saveg_write8(value & 0xff); saveg_write8((value >> 8) & 0xff); } static int saveg_read32(void) { int result; result = saveg_read8(); result |= saveg_read8() << 8; result |= saveg_read8() << 16; result |= saveg_read8() << 24; return result; } static void saveg_write32(int value) { saveg_write8(value & 0xff); saveg_write8((value >> 8) & 0xff); saveg_write8((value >> 16) & 0xff); saveg_write8((value >> 24) & 0xff); } // Pad to 4-byte boundaries static void saveg_read_pad(void) { unsigned long pos; int padding; int i; pos = ftell(save_stream); padding = (4 - (pos & 3)) & 3; for (i=0; ix = saveg_read16(); // short y; str->y = saveg_read16(); // short angle; str->angle = saveg_read16(); // short type; str->type = saveg_read16(); // short options; str->options = saveg_read16(); } static void saveg_write_mapthing_t(mapthing_t *str) { // short x; saveg_write16(str->x); // short y; saveg_write16(str->y); // short angle; saveg_write16(str->angle); // short type; saveg_write16(str->type); // short options; saveg_write16(str->options); } // // actionf_t // static void saveg_read_actionf_t(actionf_t *str) { // actionf_p1 acp1; str->acp1 = saveg_readp(); } static void saveg_write_actionf_t(actionf_t *str) { // actionf_p1 acp1; saveg_writep(str->acp1); } // // think_t // // This is just an actionf_t. // #define saveg_read_think_t saveg_read_actionf_t #define saveg_write_think_t saveg_write_actionf_t // // thinker_t // static void saveg_read_thinker_t(thinker_t *str) { // struct thinker_s* prev; str->prev = saveg_readp(); // struct thinker_s* next; str->next = saveg_readp(); // think_t function; saveg_read_think_t(&str->function); } static void saveg_write_thinker_t(thinker_t *str) { // struct thinker_s* prev; saveg_writep(str->prev); // struct thinker_s* next; saveg_writep(str->next); // think_t function; saveg_write_think_t(&str->function); } // // mobj_t // static void saveg_read_mobj_t(mobj_t *str) { int pl; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // fixed_t x; str->x = saveg_read32(); // fixed_t y; str->y = saveg_read32(); // fixed_t z; str->z = saveg_read32(); // struct mobj_s* snext; str->snext = saveg_readp(); // struct mobj_s* sprev; str->sprev = saveg_readp(); // angle_t angle; str->angle = saveg_read32(); // spritenum_t sprite; str->sprite = saveg_read_enum(); // int frame; str->frame = saveg_read32(); // struct mobj_s* bnext; str->bnext = saveg_readp(); // struct mobj_s* bprev; str->bprev = saveg_readp(); // struct subsector_s* subsector; str->subsector = saveg_readp(); // fixed_t floorz; str->floorz = saveg_read32(); // fixed_t ceilingz; str->ceilingz = saveg_read32(); // fixed_t radius; str->radius = saveg_read32(); // fixed_t height; str->height = saveg_read32(); // fixed_t momx; str->momx = saveg_read32(); // fixed_t momy; str->momy = saveg_read32(); // fixed_t momz; str->momz = saveg_read32(); // int validcount; str->validcount = saveg_read32(); // mobjtype_t type; str->type = saveg_read_enum(); // mobjinfo_t* info; str->info = saveg_readp(); // int tics; str->tics = saveg_read32(); // state_t* state; str->state = &states[saveg_read32()]; // int flags; str->flags = saveg_read32(); // int health; str->health = saveg_read32(); // int movedir; str->movedir = saveg_read32(); // int movecount; str->movecount = saveg_read32(); // struct mobj_s* target; str->target = saveg_readp(); // int reactiontime; str->reactiontime = saveg_read32(); // int threshold; str->threshold = saveg_read32(); // struct player_s* player; pl = saveg_read32(); if (pl > 0) { str->player = &players[pl - 1]; str->player->mo = str; } else { str->player = NULL; } // int lastlook; str->lastlook = saveg_read32(); // mapthing_t spawnpoint; saveg_read_mapthing_t(&str->spawnpoint); // struct mobj_s* tracer; str->tracer = saveg_readp(); } static void saveg_write_mobj_t(mobj_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // fixed_t x; saveg_write32(str->x); // fixed_t y; saveg_write32(str->y); // fixed_t z; saveg_write32(str->z); // struct mobj_s* snext; saveg_writep(str->snext); // struct mobj_s* sprev; saveg_writep(str->sprev); // angle_t angle; saveg_write32(str->angle); // spritenum_t sprite; saveg_write_enum(str->sprite); // int frame; saveg_write32(str->frame); // struct mobj_s* bnext; saveg_writep(str->bnext); // struct mobj_s* bprev; saveg_writep(str->bprev); // struct subsector_s* subsector; saveg_writep(str->subsector); // fixed_t floorz; saveg_write32(str->floorz); // fixed_t ceilingz; saveg_write32(str->ceilingz); // fixed_t radius; saveg_write32(str->radius); // fixed_t height; saveg_write32(str->height); // fixed_t momx; saveg_write32(str->momx); // fixed_t momy; saveg_write32(str->momy); // fixed_t momz; saveg_write32(str->momz); // int validcount; saveg_write32(str->validcount); // mobjtype_t type; saveg_write_enum(str->type); // mobjinfo_t* info; saveg_writep(str->info); // int tics; saveg_write32(str->tics); // state_t* state; saveg_write32(str->state - states); // int flags; saveg_write32(str->flags); // int health; saveg_write32(str->health); // int movedir; saveg_write32(str->movedir); // int movecount; saveg_write32(str->movecount); // struct mobj_s* target; saveg_writep(str->target); // int reactiontime; saveg_write32(str->reactiontime); // int threshold; saveg_write32(str->threshold); // struct player_s* player; if (str->player) { saveg_write32(str->player - players + 1); } else { saveg_write32(0); } // int lastlook; saveg_write32(str->lastlook); // mapthing_t spawnpoint; saveg_write_mapthing_t(&str->spawnpoint); // struct mobj_s* tracer; saveg_writep(str->tracer); } // // ticcmd_t // static void saveg_read_ticcmd_t(ticcmd_t *str) { // signed char forwardmove; str->forwardmove = saveg_read8(); // signed char sidemove; str->sidemove = saveg_read8(); // short angleturn; str->angleturn = saveg_read16(); // short consistancy; str->consistancy = saveg_read16(); // byte chatchar; str->chatchar = saveg_read8(); // byte buttons; str->buttons = saveg_read8(); } static void saveg_write_ticcmd_t(ticcmd_t *str) { // signed char forwardmove; saveg_write8(str->forwardmove); // signed char sidemove; saveg_write8(str->sidemove); // short angleturn; saveg_write16(str->angleturn); // short consistancy; saveg_write16(str->consistancy); // byte chatchar; saveg_write8(str->chatchar); // byte buttons; saveg_write8(str->buttons); } // // pspdef_t // static void saveg_read_pspdef_t(pspdef_t *str) { int state; // state_t* state; state = saveg_read32(); if (state > 0) { str->state = &states[state]; } else { str->state = NULL; } // int tics; str->tics = saveg_read32(); // fixed_t sx; str->sx = saveg_read32(); // fixed_t sy; str->sy = saveg_read32(); } static void saveg_write_pspdef_t(pspdef_t *str) { // state_t* state; if (str->state) { saveg_write32(str->state - states); } else { saveg_write32(0); } // int tics; saveg_write32(str->tics); // fixed_t sx; saveg_write32(str->sx); // fixed_t sy; saveg_write32(str->sy); } // // player_t // static void saveg_read_player_t(player_t *str) { int i; // mobj_t* mo; str->mo = saveg_readp(); // playerstate_t playerstate; str->playerstate = saveg_read_enum(); // ticcmd_t cmd; saveg_read_ticcmd_t(&str->cmd); // fixed_t viewz; str->viewz = saveg_read32(); // fixed_t viewheight; str->viewheight = saveg_read32(); // fixed_t deltaviewheight; str->deltaviewheight = saveg_read32(); // fixed_t bob; str->bob = saveg_read32(); // int health; str->health = saveg_read32(); // int armorpoints; str->armorpoints = saveg_read32(); // int armortype; str->armortype = saveg_read32(); // int powers[NUMPOWERS]; for (i=0; ipowers[i] = saveg_read32(); } // boolean cards[NUMCARDS]; for (i=0; icards[i] = saveg_read32(); } // boolean backpack; str->backpack = saveg_read32(); // int frags[MAXPLAYERS]; for (i=0; ifrags[i] = saveg_read32(); } // weapontype_t readyweapon; str->readyweapon = saveg_read_enum(); // weapontype_t pendingweapon; str->pendingweapon = saveg_read_enum(); // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i] = saveg_read32(); } // int ammo[NUMAMMO]; for (i=0; iammo[i] = saveg_read32(); } // int maxammo[NUMAMMO]; for (i=0; imaxammo[i] = saveg_read32(); } // int attackdown; str->attackdown = saveg_read32(); // int usedown; str->usedown = saveg_read32(); // int cheats; str->cheats = saveg_read32(); // int refire; str->refire = saveg_read32(); // int killcount; str->killcount = saveg_read32(); // int itemcount; str->itemcount = saveg_read32(); // int secretcount; str->secretcount = saveg_read32(); // char* message; str->message = saveg_readp(); // int damagecount; str->damagecount = saveg_read32(); // int bonuscount; str->bonuscount = saveg_read32(); // mobj_t* attacker; str->attacker = saveg_readp(); // int extralight; str->extralight = saveg_read32(); // int fixedcolormap; str->fixedcolormap = saveg_read32(); // int colormap; str->colormap = saveg_read32(); // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // boolean didsecret; str->didsecret = saveg_read32(); } static void saveg_write_player_t(player_t *str) { int i; // mobj_t* mo; saveg_writep(str->mo); // playerstate_t playerstate; saveg_write_enum(str->playerstate); // ticcmd_t cmd; saveg_write_ticcmd_t(&str->cmd); // fixed_t viewz; saveg_write32(str->viewz); // fixed_t viewheight; saveg_write32(str->viewheight); // fixed_t deltaviewheight; saveg_write32(str->deltaviewheight); // fixed_t bob; saveg_write32(str->bob); // int health; saveg_write32(str->health); // int armorpoints; saveg_write32(str->armorpoints); // int armortype; saveg_write32(str->armortype); // int powers[NUMPOWERS]; for (i=0; ipowers[i]); } // boolean cards[NUMCARDS]; for (i=0; icards[i]); } // boolean backpack; saveg_write32(str->backpack); // int frags[MAXPLAYERS]; for (i=0; ifrags[i]); } // weapontype_t readyweapon; saveg_write_enum(str->readyweapon); // weapontype_t pendingweapon; saveg_write_enum(str->pendingweapon); // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i]); } // int ammo[NUMAMMO]; for (i=0; iammo[i]); } // int maxammo[NUMAMMO]; for (i=0; imaxammo[i]); } // int attackdown; saveg_write32(str->attackdown); // int usedown; saveg_write32(str->usedown); // int cheats; saveg_write32(str->cheats); // int refire; saveg_write32(str->refire); // int killcount; saveg_write32(str->killcount); // int itemcount; saveg_write32(str->itemcount); // int secretcount; saveg_write32(str->secretcount); // char* message; saveg_writep(str->message); // int damagecount; saveg_write32(str->damagecount); // int bonuscount; saveg_write32(str->bonuscount); // mobj_t* attacker; saveg_writep(str->attacker); // int extralight; saveg_write32(str->extralight); // int fixedcolormap; saveg_write32(str->fixedcolormap); // int colormap; saveg_write32(str->colormap); // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // boolean didsecret; saveg_write32(str->didsecret); } // // ceiling_t // static void saveg_read_ceiling_t(ceiling_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // ceiling_e type; str->type = saveg_read_enum(); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // fixed_t bottomheight; str->bottomheight = saveg_read32(); // fixed_t topheight; str->topheight = saveg_read32(); // fixed_t speed; str->speed = saveg_read32(); // boolean crush; str->crush = saveg_read32(); // int direction; str->direction = saveg_read32(); // int tag; str->tag = saveg_read32(); // int olddirection; str->olddirection = saveg_read32(); } static void saveg_write_ceiling_t(ceiling_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // ceiling_e type; saveg_write_enum(str->type); // sector_t* sector; saveg_write32(str->sector - sectors); // fixed_t bottomheight; saveg_write32(str->bottomheight); // fixed_t topheight; saveg_write32(str->topheight); // fixed_t speed; saveg_write32(str->speed); // boolean crush; saveg_write32(str->crush); // int direction; saveg_write32(str->direction); // int tag; saveg_write32(str->tag); // int olddirection; saveg_write32(str->olddirection); } // // vldoor_t // static void saveg_read_vldoor_t(vldoor_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // vldoor_e type; str->type = saveg_read_enum(); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // fixed_t topheight; str->topheight = saveg_read32(); // fixed_t speed; str->speed = saveg_read32(); // int direction; str->direction = saveg_read32(); // int topwait; str->topwait = saveg_read32(); // int topcountdown; str->topcountdown = saveg_read32(); } static void saveg_write_vldoor_t(vldoor_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // vldoor_e type; saveg_write_enum(str->type); // sector_t* sector; saveg_write32(str->sector - sectors); // fixed_t topheight; saveg_write32(str->topheight); // fixed_t speed; saveg_write32(str->speed); // int direction; saveg_write32(str->direction); // int topwait; saveg_write32(str->topwait); // int topcountdown; saveg_write32(str->topcountdown); } // // floormove_t // static void saveg_read_floormove_t(floormove_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // floor_e type; str->type = saveg_read_enum(); // boolean crush; str->crush = saveg_read32(); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int direction; str->direction = saveg_read32(); // int newspecial; str->newspecial = saveg_read32(); // short texture; str->texture = saveg_read16(); // fixed_t floordestheight; str->floordestheight = saveg_read32(); // fixed_t speed; str->speed = saveg_read32(); } static void saveg_write_floormove_t(floormove_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // floor_e type; saveg_write_enum(str->type); // boolean crush; saveg_write32(str->crush); // sector_t* sector; saveg_write32(str->sector - sectors); // int direction; saveg_write32(str->direction); // int newspecial; saveg_write32(str->newspecial); // short texture; saveg_write16(str->texture); // fixed_t floordestheight; saveg_write32(str->floordestheight); // fixed_t speed; saveg_write32(str->speed); } // // plat_t // static void saveg_read_plat_t(plat_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // fixed_t speed; str->speed = saveg_read32(); // fixed_t low; str->low = saveg_read32(); // fixed_t high; str->high = saveg_read32(); // int wait; str->wait = saveg_read32(); // int count; str->count = saveg_read32(); // plat_e status; str->status = saveg_read_enum(); // plat_e oldstatus; str->oldstatus = saveg_read_enum(); // boolean crush; str->crush = saveg_read32(); // int tag; str->tag = saveg_read32(); // plattype_e type; str->type = saveg_read_enum(); } static void saveg_write_plat_t(plat_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // fixed_t speed; saveg_write32(str->speed); // fixed_t low; saveg_write32(str->low); // fixed_t high; saveg_write32(str->high); // int wait; saveg_write32(str->wait); // int count; saveg_write32(str->count); // plat_e status; saveg_write_enum(str->status); // plat_e oldstatus; saveg_write_enum(str->oldstatus); // boolean crush; saveg_write32(str->crush); // int tag; saveg_write32(str->tag); // plattype_e type; saveg_write_enum(str->type); } // // lightflash_t // static void saveg_read_lightflash_t(lightflash_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int count; str->count = saveg_read32(); // int maxlight; str->maxlight = saveg_read32(); // int minlight; str->minlight = saveg_read32(); // int maxtime; str->maxtime = saveg_read32(); // int mintime; str->mintime = saveg_read32(); } static void saveg_write_lightflash_t(lightflash_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // int count; saveg_write32(str->count); // int maxlight; saveg_write32(str->maxlight); // int minlight; saveg_write32(str->minlight); // int maxtime; saveg_write32(str->maxtime); // int mintime; saveg_write32(str->mintime); } // // strobe_t // static void saveg_read_strobe_t(strobe_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int count; str->count = saveg_read32(); // int minlight; str->minlight = saveg_read32(); // int maxlight; str->maxlight = saveg_read32(); // int darktime; str->darktime = saveg_read32(); // int brighttime; str->brighttime = saveg_read32(); } static void saveg_write_strobe_t(strobe_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // int count; saveg_write32(str->count); // int minlight; saveg_write32(str->minlight); // int maxlight; saveg_write32(str->maxlight); // int darktime; saveg_write32(str->darktime); // int brighttime; saveg_write32(str->brighttime); } // // glow_t // static void saveg_read_glow_t(glow_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int minlight; str->minlight = saveg_read32(); // int maxlight; str->maxlight = saveg_read32(); // int direction; str->direction = saveg_read32(); } static void saveg_write_glow_t(glow_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // int minlight; saveg_write32(str->minlight); // int maxlight; saveg_write32(str->maxlight); // int direction; saveg_write32(str->direction); } // // Write the header for a savegame // void P_WriteSaveGameHeader(char *description) { char name[VERSIONSIZE]; int i; for (i=0; description[i] != '\0'; ++i) saveg_write8(description[i]); for (; i> 16) & 0xff); saveg_write8((leveltime >> 8) & 0xff); saveg_write8(leveltime & 0xff); } // // Read the header for a savegame // boolean P_ReadSaveGameHeader(void) { int i; byte a, b, c; char vcheck[VERSIONSIZE]; char read_vcheck[VERSIONSIZE]; // skip the description field for (i=0; ifloorheight >> FRACBITS); saveg_write16(sec->ceilingheight >> FRACBITS); saveg_write16(sec->floorpic); saveg_write16(sec->ceilingpic); saveg_write16(sec->lightlevel); saveg_write16(sec->special); // needed? saveg_write16(sec->tag); // needed? } // do lines for (i=0, li = lines ; iflags); saveg_write16(li->special); saveg_write16(li->tag); for (j=0 ; j<2 ; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; saveg_write16(si->textureoffset >> FRACBITS); saveg_write16(si->rowoffset >> FRACBITS); saveg_write16(si->toptexture); saveg_write16(si->bottomtexture); saveg_write16(si->midtexture); } } } // // P_UnArchiveWorld // void P_UnArchiveWorld (void) { int i; int j; sector_t* sec; line_t* li; side_t* si; // do sectors for (i=0, sec = sectors ; ifloorheight = saveg_read16() << FRACBITS; sec->ceilingheight = saveg_read16() << FRACBITS; sec->floorpic = saveg_read16(); sec->ceilingpic = saveg_read16(); sec->lightlevel = saveg_read16(); sec->special = saveg_read16(); // needed? sec->tag = saveg_read16(); // needed? sec->specialdata = 0; sec->soundtarget = 0; } // do lines for (i=0, li = lines ; iflags = saveg_read16(); li->special = saveg_read16(); li->tag = saveg_read16(); for (j=0 ; j<2 ; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; si->textureoffset = saveg_read16() << FRACBITS; si->rowoffset = saveg_read16() << FRACBITS; si->toptexture = saveg_read16(); si->bottomtexture = saveg_read16(); si->midtexture = saveg_read16(); } } } // // Thinkers // typedef enum { tc_end, tc_mobj } thinkerclass_t; // // P_ArchiveThinkers // void P_ArchiveThinkers (void) { thinker_t* th; // save off the current thinkers for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acp1 == (actionf_p1)P_MobjThinker) { saveg_write8(tc_mobj); saveg_write_pad(); saveg_write_mobj_t((mobj_t *) th); continue; } // I_Error ("P_ArchiveThinkers: Unknown thinker function"); } // add a terminating marker saveg_write8(tc_end); } // // P_UnArchiveThinkers // void P_UnArchiveThinkers (void) { byte tclass; thinker_t* currentthinker; thinker_t* next; mobj_t* mobj; // remove all the current thinkers currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { next = currentthinker->next; if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) P_RemoveMobj ((mobj_t *)currentthinker); else Z_Free (currentthinker); currentthinker = next; } P_InitThinkers (); // read in saved thinkers while (1) { tclass = saveg_read8(); switch (tclass) { case tc_end: return; // end of list case tc_mobj: saveg_read_pad(); mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); saveg_read_mobj_t(mobj); mobj->target = NULL; mobj->tracer = NULL; P_SetThingPosition (mobj); mobj->info = &mobjinfo[mobj->type]; mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; P_AddThinker (&mobj->thinker); break; default: I_Error ("Unknown tclass %i in savegame",tclass); } } } // // P_ArchiveSpecials // enum { tc_ceiling, tc_door, tc_floor, tc_plat, tc_flash, tc_strobe, tc_glow, tc_endspecials } specials_e; // // Things to handle: // // T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list // T_VerticalDoor, (vldoor_t: sector_t * swizzle), // T_MoveFloor, (floormove_t: sector_t * swizzle), // T_LightFlash, (lightflash_t: sector_t * swizzle), // T_StrobeFlash, (strobe_t: sector_t *), // T_Glow, (glow_t: sector_t *), // T_PlatRaise, (plat_t: sector_t *), - active list // void P_ArchiveSpecials (void) { thinker_t* th; int i; // save off the current thinkers for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acv == (actionf_v)NULL) { for (i = 0; i < MAXCEILINGS;i++) if (activeceilings[i] == (ceiling_t *)th) break; if (ifunction.acp1 == (actionf_p1)T_MoveCeiling) { saveg_write8(tc_ceiling); saveg_write_pad(); saveg_write_ceiling_t((ceiling_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_VerticalDoor) { saveg_write8(tc_door); saveg_write_pad(); saveg_write_vldoor_t((vldoor_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_MoveFloor) { saveg_write8(tc_floor); saveg_write_pad(); saveg_write_floormove_t((floormove_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_PlatRaise) { saveg_write8(tc_plat); saveg_write_pad(); saveg_write_plat_t((plat_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_LightFlash) { saveg_write8(tc_flash); saveg_write_pad(); saveg_write_lightflash_t((lightflash_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_StrobeFlash) { saveg_write8(tc_strobe); saveg_write_pad(); saveg_write_strobe_t((strobe_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_Glow) { saveg_write8(tc_glow); saveg_write_pad(); saveg_write_glow_t((glow_t *) th); continue; } } // add a terminating marker saveg_write8(tc_endspecials); } // // P_UnArchiveSpecials // void P_UnArchiveSpecials (void) { byte tclass; ceiling_t* ceiling; vldoor_t* door; floormove_t* floor; plat_t* plat; lightflash_t* flash; strobe_t* strobe; glow_t* glow; // read in saved thinkers while (1) { tclass = saveg_read8(); switch (tclass) { case tc_endspecials: return; // end of list case tc_ceiling: saveg_read_pad(); ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL); saveg_read_ceiling_t(ceiling); ceiling->sector->specialdata = ceiling; if (ceiling->thinker.function.acp1) ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling; P_AddThinker (&ceiling->thinker); P_AddActiveCeiling(ceiling); break; case tc_door: saveg_read_pad(); door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL); saveg_read_vldoor_t(door); door->sector->specialdata = door; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; P_AddThinker (&door->thinker); break; case tc_floor: saveg_read_pad(); floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL); saveg_read_floormove_t(floor); floor->sector->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor; P_AddThinker (&floor->thinker); break; case tc_plat: saveg_read_pad(); plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL); saveg_read_plat_t(plat); plat->sector->specialdata = plat; if (plat->thinker.function.acp1) plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise; P_AddThinker (&plat->thinker); P_AddActivePlat(plat); break; case tc_flash: saveg_read_pad(); flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL); saveg_read_lightflash_t(flash); flash->thinker.function.acp1 = (actionf_p1)T_LightFlash; P_AddThinker (&flash->thinker); break; case tc_strobe: saveg_read_pad(); strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL); saveg_read_strobe_t(strobe); strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash; P_AddThinker (&strobe->thinker); break; case tc_glow: saveg_read_pad(); glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL); saveg_read_glow_t(glow); glow->thinker.function.acp1 = (actionf_p1)T_Glow; P_AddThinker (&glow->thinker); break; default: I_Error ("P_UnarchiveSpecials:Unknown tclass %i " "in savegame",tclass); } } } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_saveg.h000066400000000000000000000030411257432200600226250ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Savegame I/O, archiving, persistence. // #ifndef __P_SAVEG__ #define __P_SAVEG__ #include // maximum size of a savegame description #define SAVESTRINGSIZE 24 // temporary filename to use while saving. char *P_TempSaveGameFile(void); // filename to use for a savegame slot char *P_SaveGameFile(int slot); // Savegame file header read/write functions boolean P_ReadSaveGameHeader(void); void P_WriteSaveGameHeader(char *description); // Savegame end-of-file read/write functions boolean P_ReadSaveGameEOF(void); void P_WriteSaveGameEOF(void); // Persistent storage/archiving. // These are the load / save game routines. void P_ArchivePlayers (void); void P_UnArchivePlayers (void); void P_ArchiveWorld (void); void P_UnArchiveWorld (void); void P_ArchiveThinkers (void); void P_UnArchiveThinkers (void); void P_ArchiveSpecials (void); void P_UnArchiveSpecials (void); extern FILE *save_stream; extern boolean savegame_error; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/p_setup.c000066400000000000000000000451731257432200600226670ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Do all the WAD I/O, get map description, // set up initial state and misc. LUTs. // #include #include "z_zone.h" #include "deh_main.h" #include "i_swap.h" #include "m_argv.h" #include "m_bbox.h" #include "g_game.h" #include "i_system.h" #include "w_wad.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "doomstat.h" void P_SpawnMapThing (mapthing_t* mthing); // // MAP related Lookup tables. // Store VERTEXES, LINEDEFS, SIDEDEFS, etc. // int numvertexes; vertex_t* vertexes; int numsegs; seg_t* segs; int numsectors; sector_t* sectors; int numsubsectors; subsector_t* subsectors; int numnodes; node_t* nodes; int numlines; line_t* lines; int numsides; side_t* sides; static int totallines; // BLOCKMAP // Created from axis aligned bounding box // of the map, a rectangular array of // blocks of size ... // Used to speed up collision detection // by spatial subdivision in 2D. // // Blockmap size. int bmapwidth; int bmapheight; // size in mapblocks short* blockmap; // int for larger maps // offsets in blockmap are from here short* blockmaplump; // origin of block map fixed_t bmaporgx; fixed_t bmaporgy; // for thing chains mobj_t** blocklinks; // REJECT // For fast sight rejection. // Speeds up enemy AI by skipping detailed // LineOf Sight calculation. // Without special effect, this could be // used as a PVS lookup as well. // byte* rejectmatrix; // Maintain single and multi player starting spots. #define MAX_DEATHMATCH_STARTS 10 mapthing_t deathmatchstarts[MAX_DEATHMATCH_STARTS]; mapthing_t* deathmatch_p; mapthing_t playerstarts[MAXPLAYERS]; // // P_LoadVertexes // void P_LoadVertexes (int lump) { byte* data; int i; mapvertex_t* ml; vertex_t* li; // Determine number of lumps: // total lump length / vertex record length. numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t); // Allocate zone memory for buffer. vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); // Load data into cache. data = W_CacheLumpNum (lump, PU_STATIC); ml = (mapvertex_t *)data; li = vertexes; // Copy and convert vertex coordinates, // internal representation as fixed. for (i=0 ; ix = SHORT(ml->x)<y = SHORT(ml->y)<v1 = &vertexes[SHORT(ml->v1)]; li->v2 = &vertexes[SHORT(ml->v2)]; li->angle = (SHORT(ml->angle))<<16; li->offset = (SHORT(ml->offset))<<16; linedef = SHORT(ml->linedef); ldef = &lines[linedef]; li->linedef = ldef; side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; if (ldef-> flags & ML_TWOSIDED) { sidenum = ldef->sidenum[side ^ 1]; // If the sidenum is out of range, this may be a "glass hack" // impassible window. Point at side #0 (this may not be // the correct Vanilla behavior; however, it seems to work for // OTTAWAU.WAD, which is the one place I've seen this trick // used). if (sidenum < 0 || sidenum >= numsides) { li->backsector = GetSectorAtNullAddress(); } else { li->backsector = sides[sidenum].sector; } } else { li->backsector = 0; } } W_ReleaseLumpNum(lump); } // // P_LoadSubsectors // void P_LoadSubsectors (int lump) { byte* data; int i; mapsubsector_t* ms; subsector_t* ss; numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t); subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0); data = W_CacheLumpNum (lump,PU_STATIC); ms = (mapsubsector_t *)data; memset (subsectors,0, numsubsectors*sizeof(subsector_t)); ss = subsectors; for (i=0 ; inumlines = SHORT(ms->numsegs); ss->firstline = SHORT(ms->firstseg); } W_ReleaseLumpNum(lump); } // // P_LoadSectors // void P_LoadSectors (int lump) { byte* data; int i; mapsector_t* ms; sector_t* ss; numsectors = W_LumpLength (lump) / sizeof(mapsector_t); sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0); memset (sectors, 0, numsectors*sizeof(sector_t)); data = W_CacheLumpNum (lump,PU_STATIC); ms = (mapsector_t *)data; ss = sectors; for (i=0 ; ifloorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = R_FlatNumForName(ms->floorpic); ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); ss->lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); ss->tag = SHORT(ms->tag); ss->thinglist = NULL; } W_ReleaseLumpNum(lump); } // // P_LoadNodes // void P_LoadNodes (int lump) { byte* data; int i; int j; int k; mapnode_t* mn; node_t* no; numnodes = W_LumpLength (lump) / sizeof(mapnode_t); nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0); data = W_CacheLumpNum (lump,PU_STATIC); mn = (mapnode_t *)data; no = nodes; for (i=0 ; ix = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); for (k=0 ; k<4 ; k++) no->bbox[j][k] = SHORT(mn->bbox[j][k])<type)) { case 68: // Arachnotron case 64: // Archvile case 88: // Boss Brain case 89: // Boss Shooter case 69: // Hell Knight case 67: // Mancubus case 71: // Pain Elemental case 65: // Former Human Commando case 66: // Revenant case 84: // Wolf SS spawn = false; break; } } if (spawn == false) break; // Do spawn all other stuff. spawnthing.x = SHORT(mt->x); spawnthing.y = SHORT(mt->y); spawnthing.angle = SHORT(mt->angle); spawnthing.type = SHORT(mt->type); spawnthing.options = SHORT(mt->options); P_SpawnMapThing(&spawnthing); } W_ReleaseLumpNum(lump); } // // P_LoadLineDefs // Also counts secret lines for intermissions. // void P_LoadLineDefs (int lump) { byte* data; int i; maplinedef_t* mld; line_t* ld; vertex_t* v1; vertex_t* v2; numlines = W_LumpLength (lump) / sizeof(maplinedef_t); lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0); memset (lines, 0, numlines*sizeof(line_t)); data = W_CacheLumpNum (lump,PU_STATIC); mld = (maplinedef_t *)data; ld = lines; for (i=0 ; iflags = SHORT(mld->flags); ld->special = SHORT(mld->special); ld->tag = SHORT(mld->tag); v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) ld->slopetype = ST_HORIZONTAL; else { if (FixedDiv (ld->dy , ld->dx) > 0) ld->slopetype = ST_POSITIVE; else ld->slopetype = ST_NEGATIVE; } if (v1->x < v2->x) { ld->bbox[BOXLEFT] = v1->x; ld->bbox[BOXRIGHT] = v2->x; } else { ld->bbox[BOXLEFT] = v2->x; ld->bbox[BOXRIGHT] = v1->x; } if (v1->y < v2->y) { ld->bbox[BOXBOTTOM] = v1->y; ld->bbox[BOXTOP] = v2->y; } else { ld->bbox[BOXBOTTOM] = v2->y; ld->bbox[BOXTOP] = v1->y; } ld->sidenum[0] = SHORT(mld->sidenum[0]); ld->sidenum[1] = SHORT(mld->sidenum[1]); if (ld->sidenum[0] != -1) ld->frontsector = sides[ld->sidenum[0]].sector; else ld->frontsector = 0; if (ld->sidenum[1] != -1) ld->backsector = sides[ld->sidenum[1]].sector; else ld->backsector = 0; } W_ReleaseLumpNum(lump); } // // P_LoadSideDefs // void P_LoadSideDefs (int lump) { byte* data; int i; mapsidedef_t* msd; side_t* sd; numsides = W_LumpLength (lump) / sizeof(mapsidedef_t); sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0); memset (sides, 0, numsides*sizeof(side_t)); data = W_CacheLumpNum (lump,PU_STATIC); msd = (mapsidedef_t *)data; sd = sides; for (i=0 ; itextureoffset = SHORT(msd->textureoffset)<rowoffset = SHORT(msd->rowoffset)<toptexture = R_TextureNumForName(msd->toptexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->sector = §ors[SHORT(msd->sector)]; } W_ReleaseLumpNum(lump); } // // P_LoadBlockMap // void P_LoadBlockMap (int lump) { int i; int count; int lumplen; lumplen = W_LumpLength(lump); count = lumplen / 2; blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL); W_ReadLump(lump, blockmaplump); blockmap = blockmaplump + 4; // Swap all short integers to native byte ordering. for (i=0; ifirstline]; ss->sector = seg->sidedef->sector; } // count number of lines in each sector li = lines; totallines = 0; for (i=0 ; ifrontsector->linecount++; if (li->backsector && li->backsector != li->frontsector) { li->backsector->linecount++; totallines++; } } // build line tables for each sector linebuffer = Z_Malloc (totallines*sizeof(line_t *), PU_LEVEL, 0); for (i=0; ifrontsector != NULL) { sector = li->frontsector; sector->lines[sector->linecount] = li; ++sector->linecount; } if (li->backsector != NULL && li->frontsector != li->backsector) { sector = li->backsector; sector->lines[sector->linecount] = li; ++sector->linecount; } } // Generate bounding boxes for sectors sector = sectors; for (i=0 ; ilinecount; j++) { li = sector->lines[j]; M_AddToBox (bbox, li->v1->x, li->v1->y); M_AddToBox (bbox, li->v2->x, li->v2->y); } // set the degenmobj_t to the middle of the bounding box sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; // adjust bounding box to map blocks block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; block = block >= bmapheight ? bmapheight-1 : block; sector->blockbox[BOXTOP]=block; block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXBOTTOM]=block; block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; block = block >= bmapwidth ? bmapwidth-1 : block; sector->blockbox[BOXRIGHT]=block; block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXLEFT]=block; } } // Pad the REJECT lump with extra data when the lump is too small, // to simulate a REJECT buffer overflow in Vanilla Doom. static void PadRejectArray(byte *array, unsigned int len) { unsigned int i; unsigned int byte_num; byte *dest; unsigned int padvalue; // Values to pad the REJECT array with: unsigned int rejectpad[4] = { ((totallines * 4 + 3) & ~3) + 24, // Size 0, // Part of z_zone block header 50, // PU_LEVEL 0x1d4a11 // DOOM_CONST_ZONEID }; // Copy values from rejectpad into the destination array. dest = array; for (i=0; i> (byte_num * 8)) & 0xff; ++dest; } // We only have a limited pad size. Print a warning if the // REJECT lump is too small. if (len > sizeof(rejectpad)) { fprintf(stderr, "PadRejectArray: REJECT lump too short to pad! (%i > %i)\n", len, (int) sizeof(rejectpad)); // Pad remaining space with 0 (or 0xff, if specified on command line). if (M_CheckParm("-reject_pad_with_ff")) { padvalue = 0xff; } else { padvalue = 0xf00; } memset(array + sizeof(rejectpad), padvalue, len - sizeof(rejectpad)); } } static void P_LoadReject(int lumpnum) { int minlength; int lumplen; // Calculate the size that the REJECT lump *should* be. minlength = (numsectors * numsectors + 7) / 8; // If the lump meets the minimum length, it can be loaded directly. // Otherwise, we need to allocate a buffer of the correct size // and pad it with appropriate data. lumplen = W_LumpLength(lumpnum); if (lumplen >= minlength) { rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL); } else { rejectmatrix = Z_Malloc(minlength, PU_LEVEL, &rejectmatrix); W_ReadLump(lumpnum, rejectmatrix); PadRejectArray(rejectmatrix + lumplen, minlength - lumplen); } } // // P_SetupLevel // void P_SetupLevel ( int episode, int map, int playermask, skill_t skill) { int i; char lumpname[9]; int lumpnum; totalkills = totalitems = totalsecret = wminfo.maxfrags = 0; wminfo.partime = 180; for (i=0 ; idx) { if (x==node->x) return 2; if (x <= node->x) return node->dy > 0; return node->dy < 0; } if (!node->dy) { if (x==node->y) return 2; if (y <= node->y) return node->dx < 0; return node->dx > 0; } dx = (x - node->x); dy = (y - node->y); left = (node->dy>>FRACBITS) * (dx>>FRACBITS); right = (dy>>FRACBITS) * (node->dx>>FRACBITS); if (right < left) return 0; // front side if (left == right) return 2; return 1; // back side } // // P_InterceptVector2 // Returns the fractional intercept point // along the first divline. // This is only called by the addthings and addlines traversers. // fixed_t P_InterceptVector2 ( divline_t* v2, divline_t* v1 ) { fixed_t frac; fixed_t num; fixed_t den; den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy); if (den == 0) return 0; // I_Error ("P_InterceptVector: parallel"); num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) + FixedMul ( (v2->y - v1->y)>>8 , v1->dx); frac = FixedDiv (num , den); return frac; } // // P_CrossSubsector // Returns true // if strace crosses the given subsector successfully. // boolean P_CrossSubsector (int num) { seg_t* seg; line_t* line; int s1; int s2; int count; subsector_t* sub; sector_t* front; sector_t* back; fixed_t opentop; fixed_t openbottom; divline_t divl; vertex_t* v1; vertex_t* v2; fixed_t frac; fixed_t slope; #ifdef RANGECHECK if (num>=numsubsectors) I_Error ("P_CrossSubsector: ss %i with numss = %i", num, numsubsectors); #endif sub = &subsectors[num]; // check lines count = sub->numlines; seg = &segs[sub->firstline]; for ( ; count ; seg++, count--) { line = seg->linedef; // allready checked other side? if (line->validcount == validcount) continue; line->validcount = validcount; v1 = line->v1; v2 = line->v2; s1 = P_DivlineSide (v1->x,v1->y, &strace); s2 = P_DivlineSide (v2->x, v2->y, &strace); // line isn't crossed? if (s1 == s2) continue; divl.x = v1->x; divl.y = v1->y; divl.dx = v2->x - v1->x; divl.dy = v2->y - v1->y; s1 = P_DivlineSide (strace.x, strace.y, &divl); s2 = P_DivlineSide (t2x, t2y, &divl); // line isn't crossed? if (s1 == s2) continue; // Backsector may be NULL if this is an "impassible // glass" hack line. if (line->backsector == NULL) { return false; } // stop because it is not two sided anyway // might do this after updating validcount? if ( !(line->flags & ML_TWOSIDED) ) return false; // crosses a two sided line front = seg->frontsector; back = seg->backsector; // no wall to block sight with? if (front->floorheight == back->floorheight && front->ceilingheight == back->ceilingheight) continue; // possible occluder // because of ceiling height differences if (front->ceilingheight < back->ceilingheight) opentop = front->ceilingheight; else opentop = back->ceilingheight; // because of ceiling height differences if (front->floorheight > back->floorheight) openbottom = front->floorheight; else openbottom = back->floorheight; // quick test for totally closed doors if (openbottom >= opentop) return false; // stop frac = P_InterceptVector2 (&strace, &divl); if (front->floorheight != back->floorheight) { slope = FixedDiv (openbottom - sightzstart , frac); if (slope > bottomslope) bottomslope = slope; } if (front->ceilingheight != back->ceilingheight) { slope = FixedDiv (opentop - sightzstart , frac); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop } // passed the subsector ok return true; } // // P_CrossBSPNode // Returns true // if strace crosses the given node successfully. // boolean P_CrossBSPNode (int bspnum) { node_t* bsp; int side; if (bspnum & NF_SUBSECTOR) { if (bspnum == -1) return P_CrossSubsector (0); else return P_CrossSubsector (bspnum&(~NF_SUBSECTOR)); } bsp = &nodes[bspnum]; // decide which side the start point is on side = P_DivlineSide (strace.x, strace.y, (divline_t *)bsp); if (side == 2) side = 0; // an "on" should cross both sides // cross the starting side if (!P_CrossBSPNode (bsp->children[side]) ) return false; // the partition plane is crossed here if (side == P_DivlineSide (t2x, t2y,(divline_t *)bsp)) { // the line doesn't touch the other side return true; } // cross the ending side return P_CrossBSPNode (bsp->children[side^1]); } // // P_CheckSight // Returns true // if a straight line between t1 and t2 is unobstructed. // Uses REJECT. // boolean P_CheckSight ( mobj_t* t1, mobj_t* t2 ) { int s1; int s2; int pnum; int bytenum; int bitnum; // First check for trivial rejection. // Determine subsector entries in REJECT table. s1 = (t1->subsector->sector - sectors); s2 = (t2->subsector->sector - sectors); pnum = s1*numsectors + s2; bytenum = pnum>>3; bitnum = 1 << (pnum&7); // Check in REJECT table. if (rejectmatrix[bytenum]&bitnum) { sightcounts[0]++; // can't possibly be connected return false; } // An unobstructed LOS is possible. // Now look from eyes of t1 to any part of t2. sightcounts[1]++; validcount++; sightzstart = t1->z + t1->height - (t1->height>>2); topslope = (t2->z+t2->height) - sightzstart; bottomslope = (t2->z) - sightzstart; strace.x = t1->x; strace.y = t1->y; t2x = t2->x; t2y = t2->y; strace.dx = t2->x - t1->x; strace.dy = t2->y - t1->y; // the head node is the last node output return P_CrossBSPNode (numnodes-1); } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_spec.c000066400000000000000000000711031257432200600224510ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Implements special effects: // Texture animation, height or lighting changes // according to adjacent sectors, respective // utility functions, etc. // Line Tag handling. Line and Sector triggers. // #include #include "doomdef.h" #include "doomstat.h" #include "deh_main.h" #include "i_system.h" #include "z_zone.h" #include "m_argv.h" #include "m_misc.h" #include "m_random.h" #include "w_wad.h" #include "r_local.h" #include "p_local.h" #include "g_game.h" #include "s_sound.h" // State. #include "r_state.h" // Data. #include "sounds.h" // // Animating textures and planes // There is another anim_t used in wi_stuff, unrelated. // typedef struct { boolean istexture; int picnum; int basepic; int numpics; int speed; } anim_t; // // source animation definition // typedef struct { int istexture; // if false, it is a flat char endname[9]; char startname[9]; int speed; } animdef_t; #define MAXANIMS 32 extern anim_t anims[MAXANIMS]; extern anim_t* lastanim; // // P_InitPicAnims // // Floor/ceiling animation sequences, // defined by first and last frame, // i.e. the flat (64x64 tile) name to // be used. // The full animation sequence is given // using all the flats between the start // and end entry, in the order found in // the WAD file. // animdef_t animdefs[] = { {false, "NUKAGE3", "NUKAGE1", 8}, {false, "FWATER4", "FWATER1", 8}, {false, "SWATER4", "SWATER1", 8}, {false, "LAVA4", "LAVA1", 8}, {false, "BLOOD3", "BLOOD1", 8}, // DOOM II flat animations. {false, "RROCK08", "RROCK05", 8}, {false, "SLIME04", "SLIME01", 8}, {false, "SLIME08", "SLIME05", 8}, {false, "SLIME12", "SLIME09", 8}, {true, "BLODGR4", "BLODGR1", 8}, {true, "SLADRIP3", "SLADRIP1", 8}, {true, "BLODRIP4", "BLODRIP1", 8}, {true, "FIREWALL", "FIREWALA", 8}, {true, "GSTFONT3", "GSTFONT1", 8}, {true, "FIRELAVA", "FIRELAV3", 8}, {true, "FIREMAG3", "FIREMAG1", 8}, {true, "FIREBLU2", "FIREBLU1", 8}, {true, "ROCKRED3", "ROCKRED1", 8}, {true, "BFALL4", "BFALL1", 8}, {true, "SFALL4", "SFALL1", 8}, {true, "WFALL4", "WFALL1", 8}, {true, "DBRAIN4", "DBRAIN1", 8}, {-1, "", "", 0}, }; anim_t anims[MAXANIMS]; anim_t* lastanim; // // Animating line specials // #define MAXLINEANIMS 64 extern short numlinespecials; extern line_t* linespeciallist[MAXLINEANIMS]; void P_InitPicAnims (void) { int i; // Init animation lastanim = anims; for (i=0 ; animdefs[i].istexture != -1 ; i++) { char *startname, *endname; startname = DEH_String(animdefs[i].startname); endname = DEH_String(animdefs[i].endname); if (animdefs[i].istexture) { // different episode ? if (R_CheckTextureNumForName(startname) == -1) continue; lastanim->picnum = R_TextureNumForName(endname); lastanim->basepic = R_TextureNumForName(startname); } else { if (W_CheckNumForName(startname) == -1) continue; lastanim->picnum = R_FlatNumForName(endname); lastanim->basepic = R_FlatNumForName(startname); } lastanim->istexture = animdefs[i].istexture; lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; if (lastanim->numpics < 2) I_Error ("P_InitPicAnims: bad cycle from %s to %s", startname, endname); lastanim->speed = animdefs[i].speed; lastanim++; } } // // UTILITIES // // // getSide() // Will return a side_t* // given the number of the current sector, // the line number, and the side (0/1) that you want. // side_t* getSide ( int currentSector, int line, int side ) { return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; } // // getSector() // Will return a sector_t* // given the number of the current sector, // the line number and the side (0/1) that you want. // sector_t* getSector ( int currentSector, int line, int side ) { return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; } // // twoSided() // Given the sector number and the line number, // it will tell you whether the line is two-sided or not. // int twoSided ( int sector, int line ) { return (sectors[sector].lines[line])->flags & ML_TWOSIDED; } // // getNextSector() // Return sector_t * of sector next to current. // NULL if not two-sided line // sector_t* getNextSector ( line_t* line, sector_t* sec ) { if (!(line->flags & ML_TWOSIDED)) return NULL; if (line->frontsector == sec) return line->backsector; return line->frontsector; } // // P_FindLowestFloorSurrounding() // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS // fixed_t P_FindLowestFloorSurrounding(sector_t* sec) { int i; line_t* check; sector_t* other; fixed_t floor = sec->floorheight; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->floorheight < floor) floor = other->floorheight; } return floor; } // // P_FindHighestFloorSurrounding() // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS // fixed_t P_FindHighestFloorSurrounding(sector_t *sec) { int i; line_t* check; sector_t* other; fixed_t floor = -500*FRACUNIT; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->floorheight > floor) floor = other->floorheight; } return floor; } // // P_FindNextHighestFloor // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS // Note: this should be doable w/o a fixed array. // Thanks to entryway for the Vanilla overflow emulation. // 20 adjoining sectors max! #define MAX_ADJOINING_SECTORS 20 fixed_t P_FindNextHighestFloor ( sector_t* sec, int currentheight ) { int i; int h; int min; line_t* check; sector_t* other; fixed_t height = currentheight; fixed_t heightlist[MAX_ADJOINING_SECTORS + 2]; for (i=0, h=0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->floorheight > height) { // Emulation of memory (stack) overflow if (h == MAX_ADJOINING_SECTORS + 1) { height = other->floorheight; } else if (h == MAX_ADJOINING_SECTORS + 2) { // Fatal overflow: game crashes at 22 textures I_Error("Sector with more than 22 adjoining sectors. " "Vanilla will crash here"); } heightlist[h++] = other->floorheight; } } // Find lowest height in list if (!h) { return currentheight; } min = heightlist[0]; // Range checking? for (i = 1; i < h; i++) { if (heightlist[i] < min) { min = heightlist[i]; } } return min; } // // FIND LOWEST CEILING IN THE SURROUNDING SECTORS // fixed_t P_FindLowestCeilingSurrounding(sector_t* sec) { int i; line_t* check; sector_t* other; fixed_t height = INT_MAX; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->ceilingheight < height) height = other->ceilingheight; } return height; } // // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS // fixed_t P_FindHighestCeilingSurrounding(sector_t* sec) { int i; line_t* check; sector_t* other; fixed_t height = 0; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->ceilingheight > height) height = other->ceilingheight; } return height; } // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO // int P_FindSectorFromLineTag ( line_t* line, int start ) { int i; for (i=start+1;itag) return i; return -1; } // // Find minimum light from an adjacent sector // int P_FindMinSurroundingLight ( sector_t* sector, int max ) { int i; int min; line_t* line; sector_t* check; min = max; for (i=0 ; i < sector->linecount ; i++) { line = sector->lines[i]; check = getNextSector(line,sector); if (!check) continue; if (check->lightlevel < min) min = check->lightlevel; } return min; } // // EVENTS // Events are operations triggered by using, crossing, // or shooting special lines, or by timed thinkers. // // // P_CrossSpecialLine - TRIGGER // Called every time a thing origin is about // to cross a line with a non 0 special. // void P_CrossSpecialLine ( int linenum, int side, mobj_t* thing ) { line_t* line; int ok; line = &lines[linenum]; // Triggers that other things can activate if (!thing->player) { // Things that should NOT trigger specials... switch(thing->type) { case MT_ROCKET: case MT_PLASMA: case MT_BFG: case MT_TROOPSHOT: case MT_HEADSHOT: case MT_BRUISERSHOT: return; break; default: break; } ok = 0; switch(line->special) { case 39: // TELEPORT TRIGGER case 97: // TELEPORT RETRIGGER case 125: // TELEPORT MONSTERONLY TRIGGER case 126: // TELEPORT MONSTERONLY RETRIGGER case 4: // RAISE DOOR case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER ok = 1; break; } if (!ok) return; } // Note: could use some const's here. switch (line->special) { // TRIGGERS. // All from here to RETRIGGERS. case 2: // Open Door EV_DoDoor(line,vld_open); line->special = 0; break; case 3: // Close Door EV_DoDoor(line,vld_close); line->special = 0; break; case 4: // Raise Door EV_DoDoor(line,vld_normal); line->special = 0; break; case 5: // Raise Floor EV_DoFloor(line,raiseFloor); line->special = 0; break; case 6: // Fast Ceiling Crush & Raise EV_DoCeiling(line,fastCrushAndRaise); line->special = 0; break; case 8: // Build Stairs EV_BuildStairs(line,build8); line->special = 0; break; case 10: // PlatDownWaitUp EV_DoPlat(line,downWaitUpStay,0); line->special = 0; break; case 12: // Light Turn On - brightest near EV_LightTurnOn(line,0); line->special = 0; break; case 13: // Light Turn On 255 EV_LightTurnOn(line,255); line->special = 0; break; case 16: // Close Door 30 EV_DoDoor(line,vld_close30ThenOpen); line->special = 0; break; case 17: // Start Light Strobing EV_StartLightStrobing(line); line->special = 0; break; case 19: // Lower Floor EV_DoFloor(line,lowerFloor); line->special = 0; break; case 22: // Raise floor to nearest height and change texture EV_DoPlat(line,raiseToNearestAndChange,0); line->special = 0; break; case 25: // Ceiling Crush and Raise EV_DoCeiling(line,crushAndRaise); line->special = 0; break; case 30: // Raise floor to shortest texture height // on either side of lines. EV_DoFloor(line,raiseToTexture); line->special = 0; break; case 35: // Lights Very Dark EV_LightTurnOn(line,35); line->special = 0; break; case 36: // Lower Floor (TURBO) EV_DoFloor(line,turboLower); line->special = 0; break; case 37: // LowerAndChange EV_DoFloor(line,lowerAndChange); line->special = 0; break; case 38: // Lower Floor To Lowest EV_DoFloor( line, lowerFloorToLowest ); line->special = 0; break; case 39: // TELEPORT! EV_Teleport( line, side, thing ); line->special = 0; break; case 40: // RaiseCeilingLowerFloor EV_DoCeiling( line, raiseToHighest ); EV_DoFloor( line, lowerFloorToLowest ); line->special = 0; break; case 44: // Ceiling Crush EV_DoCeiling( line, lowerAndCrush ); line->special = 0; break; case 52: // EXIT! G_ExitLevel (); break; case 53: // Perpetual Platform Raise EV_DoPlat(line,perpetualRaise,0); line->special = 0; break; case 54: // Platform Stop EV_StopPlat(line); line->special = 0; break; case 56: // Raise Floor Crush EV_DoFloor(line,raiseFloorCrush); line->special = 0; break; case 57: // Ceiling Crush Stop EV_CeilingCrushStop(line); line->special = 0; break; case 58: // Raise Floor 24 EV_DoFloor(line,raiseFloor24); line->special = 0; break; case 59: // Raise Floor 24 And Change EV_DoFloor(line,raiseFloor24AndChange); line->special = 0; break; case 104: // Turn lights off in sector(tag) EV_TurnTagLightsOff(line); line->special = 0; break; case 108: // Blazing Door Raise (faster than TURBO!) EV_DoDoor (line,vld_blazeRaise); line->special = 0; break; case 109: // Blazing Door Open (faster than TURBO!) EV_DoDoor (line,vld_blazeOpen); line->special = 0; break; case 100: // Build Stairs Turbo 16 EV_BuildStairs(line,turbo16); line->special = 0; break; case 110: // Blazing Door Close (faster than TURBO!) EV_DoDoor (line,vld_blazeClose); line->special = 0; break; case 119: // Raise floor to nearest surr. floor EV_DoFloor(line,raiseFloorToNearest); line->special = 0; break; case 121: // Blazing PlatDownWaitUpStay EV_DoPlat(line,blazeDWUS,0); line->special = 0; break; case 124: // Secret EXIT G_SecretExitLevel (); break; case 125: // TELEPORT MonsterONLY if (!thing->player) { EV_Teleport( line, side, thing ); line->special = 0; } break; case 130: // Raise Floor Turbo EV_DoFloor(line,raiseFloorTurbo); line->special = 0; break; case 141: // Silent Ceiling Crush & Raise EV_DoCeiling(line,silentCrushAndRaise); line->special = 0; break; // RETRIGGERS. All from here till end. case 72: // Ceiling Crush EV_DoCeiling( line, lowerAndCrush ); break; case 73: // Ceiling Crush and Raise EV_DoCeiling(line,crushAndRaise); break; case 74: // Ceiling Crush Stop EV_CeilingCrushStop(line); break; case 75: // Close Door EV_DoDoor(line,vld_close); break; case 76: // Close Door 30 EV_DoDoor(line,vld_close30ThenOpen); break; case 77: // Fast Ceiling Crush & Raise EV_DoCeiling(line,fastCrushAndRaise); break; case 79: // Lights Very Dark EV_LightTurnOn(line,35); break; case 80: // Light Turn On - brightest near EV_LightTurnOn(line,0); break; case 81: // Light Turn On 255 EV_LightTurnOn(line,255); break; case 82: // Lower Floor To Lowest EV_DoFloor( line, lowerFloorToLowest ); break; case 83: // Lower Floor EV_DoFloor(line,lowerFloor); break; case 84: // LowerAndChange EV_DoFloor(line,lowerAndChange); break; case 86: // Open Door EV_DoDoor(line,vld_open); break; case 87: // Perpetual Platform Raise EV_DoPlat(line,perpetualRaise,0); break; case 88: // PlatDownWaitUp EV_DoPlat(line,downWaitUpStay,0); break; case 89: // Platform Stop EV_StopPlat(line); break; case 90: // Raise Door EV_DoDoor(line,vld_normal); break; case 91: // Raise Floor EV_DoFloor(line,raiseFloor); break; case 92: // Raise Floor 24 EV_DoFloor(line,raiseFloor24); break; case 93: // Raise Floor 24 And Change EV_DoFloor(line,raiseFloor24AndChange); break; case 94: // Raise Floor Crush EV_DoFloor(line,raiseFloorCrush); break; case 95: // Raise floor to nearest height // and change texture. EV_DoPlat(line,raiseToNearestAndChange,0); break; case 96: // Raise floor to shortest texture height // on either side of lines. EV_DoFloor(line,raiseToTexture); break; case 97: // TELEPORT! EV_Teleport( line, side, thing ); break; case 98: // Lower Floor (TURBO) EV_DoFloor(line,turboLower); break; case 105: // Blazing Door Raise (faster than TURBO!) EV_DoDoor (line,vld_blazeRaise); break; case 106: // Blazing Door Open (faster than TURBO!) EV_DoDoor (line,vld_blazeOpen); break; case 107: // Blazing Door Close (faster than TURBO!) EV_DoDoor (line,vld_blazeClose); break; case 120: // Blazing PlatDownWaitUpStay. EV_DoPlat(line,blazeDWUS,0); break; case 126: // TELEPORT MonsterONLY. if (!thing->player) EV_Teleport( line, side, thing ); break; case 128: // Raise To Nearest Floor EV_DoFloor(line,raiseFloorToNearest); break; case 129: // Raise Floor Turbo EV_DoFloor(line,raiseFloorTurbo); break; } } // // P_ShootSpecialLine - IMPACT SPECIALS // Called when a thing shoots a special line. // void P_ShootSpecialLine ( mobj_t* thing, line_t* line ) { int ok; // Impacts that other things can activate. if (!thing->player) { ok = 0; switch(line->special) { case 46: // OPEN DOOR IMPACT ok = 1; break; } if (!ok) return; } switch(line->special) { case 24: // RAISE FLOOR EV_DoFloor(line,raiseFloor); P_ChangeSwitchTexture(line,0); break; case 46: // OPEN DOOR EV_DoDoor(line,vld_open); P_ChangeSwitchTexture(line,1); break; case 47: // RAISE FLOOR NEAR AND CHANGE EV_DoPlat(line,raiseToNearestAndChange,0); P_ChangeSwitchTexture(line,0); break; } } // // P_PlayerInSpecialSector // Called every tic frame // that the player origin is in a special sector // void P_PlayerInSpecialSector (player_t* player) { sector_t* sector; sector = player->mo->subsector->sector; // Falling, not all the way down yet? if (player->mo->z != sector->floorheight) return; // Has hitten ground. switch (sector->special) { case 5: // HELLSLIME DAMAGE if (!player->powers[pw_ironfeet]) if (!(leveltime&0x1f)) P_DamageMobj (player->mo, NULL, NULL, 10); break; case 7: // NUKAGE DAMAGE if (!player->powers[pw_ironfeet]) if (!(leveltime&0x1f)) P_DamageMobj (player->mo, NULL, NULL, 5); break; case 16: // SUPER HELLSLIME DAMAGE case 4: // STROBE HURT if (!player->powers[pw_ironfeet] || (P_Random()<5) ) { if (!(leveltime&0x1f)) P_DamageMobj (player->mo, NULL, NULL, 20); } break; case 9: // SECRET SECTOR player->secretcount++; sector->special = 0; break; case 11: // EXIT SUPER DAMAGE! (for E1M8 finale) player->cheats &= ~CF_GODMODE; if (!(leveltime&0x1f)) P_DamageMobj (player->mo, NULL, NULL, 20); if (player->health <= 10) G_ExitLevel(); break; default: I_Error ("P_PlayerInSpecialSector: " "unknown special %i", sector->special); break; }; } // // P_UpdateSpecials // Animate planes, scroll walls, etc. // boolean levelTimer; int levelTimeCount; void P_UpdateSpecials (void) { anim_t* anim; int pic; int i; line_t* line; // LEVEL TIMER if (levelTimer == true) { levelTimeCount--; if (!levelTimeCount) G_ExitLevel(); } // ANIMATE FLATS AND TEXTURES GLOBALLY for (anim = anims ; anim < lastanim ; anim++) { for (i=anim->basepic ; ibasepic+anim->numpics ; i++) { pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics ); if (anim->istexture) texturetranslation[i] = pic; else flattranslation[i] = pic; } } // ANIMATE LINE SPECIALS for (i = 0; i < numlinespecials; i++) { line = linespeciallist[i]; switch(line->special) { case 48: // EFFECT FIRSTCOL SCROLL + sides[line->sidenum[0]].textureoffset += FRACUNIT; break; } } // DO BUTTONS for (i = 0; i < MAXBUTTONS; i++) if (buttonlist[i].btimer) { buttonlist[i].btimer--; if (!buttonlist[i].btimer) { switch(buttonlist[i].where) { case top: sides[buttonlist[i].line->sidenum[0]].toptexture = buttonlist[i].btexture; break; case middle: sides[buttonlist[i].line->sidenum[0]].midtexture = buttonlist[i].btexture; break; case bottom: sides[buttonlist[i].line->sidenum[0]].bottomtexture = buttonlist[i].btexture; break; } S_StartSound(&buttonlist[i].soundorg,sfx_swtchn); memset(&buttonlist[i],0,sizeof(button_t)); } } } // // Donut overrun emulation // // Derived from the code from PrBoom+. Thanks go to Andrey Budko (entryway) // as usual :-) // #define DONUT_FLOORHEIGHT_DEFAULT 0x00000000 #define DONUT_FLOORPIC_DEFAULT 0x16 static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic, line_t *line, sector_t *pillar_sector) { static int first = 1; static int tmp_s3_floorheight; static int tmp_s3_floorpic; extern int numflats; if (first) { int p; // This is the first time we have had an overrun. first = 0; // Default values tmp_s3_floorheight = DONUT_FLOORHEIGHT_DEFAULT; tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT; //! // @category compat // @arg // // Use the specified magic values when emulating behavior caused // by memory overruns from improperly constructed donuts. // In Vanilla Doom this can differ depending on the operating // system. The default (if this option is not specified) is to // emulate the behavior when running under Windows 98. p = M_CheckParmWithArgs("-donut", 2); if (p > 0) { // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008 // // C:\>debug // -d 0:0 // // DOS 6.22: // 0000:0000 (57 92 19 00) F4 06 70 00-(16 00) // DOS 7.1: // 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00) // Win98: // 0000:0000 (00 00 00 00) 65 04 70 00-(16 00) // DOSBox under XP: // 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00) M_StrToInt(myargv[p + 1], &tmp_s3_floorheight); M_StrToInt(myargv[p + 2], &tmp_s3_floorpic); if (tmp_s3_floorpic >= numflats) { fprintf(stderr, "DonutOverrun: The second parameter for \"-donut\" " "switch should be greater than 0 and less than number " "of flats (%d). Using default value (%d) instead. \n", numflats, DONUT_FLOORPIC_DEFAULT); tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT; } } } /* fprintf(stderr, "Linedef: %d; Sector: %d; " "New floor height: %d; New floor pic: %d\n", line->iLineID, pillar_sector->iSectorID, tmp_s3_floorheight >> 16, tmp_s3_floorpic); */ *s3_floorheight = (fixed_t) tmp_s3_floorheight; *s3_floorpic = (short) tmp_s3_floorpic; } // // Special Stuff that can not be categorized // int EV_DoDonut(line_t* line) { sector_t* s1; sector_t* s2; sector_t* s3; int secnum; int rtn; int i; floormove_t* floor; fixed_t s3_floorheight; short s3_floorpic; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { s1 = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (s1->specialdata) continue; rtn = 1; s2 = getNextSector(s1->lines[0],s1); // Vanilla Doom does not check if the linedef is one sided. The // game does not crash, but reads invalid memory and causes the // sector floor to move "down" to some unknown height. // DOSbox prints a warning about an invalid memory access. // // I'm not sure exactly what invalid memory is being read. This // isn't something that should be done, anyway. // Just print a warning and return. if (s2 == NULL) { fprintf(stderr, "EV_DoDonut: linedef had no second sidedef! " "Unexpected behavior may occur in Vanilla Doom. \n"); break; } for (i = 0; i < s2->linecount; i++) { s3 = s2->lines[i]->backsector; if (s3 == s1) continue; if (s3 == NULL) { // e6y // s3 is NULL, so // s3->floorheight is an int at 0000:0000 // s3->floorpic is a short at 0000:0008 // Trying to emulate fprintf(stderr, "EV_DoDonut: WARNING: emulating buffer overrun due to " "NULL back sector. " "Unexpected behavior may occur in Vanilla Doom.\n"); DonutOverrun(&s3_floorheight, &s3_floorpic, line, s1); } else { s3_floorheight = s3->floorheight; s3_floorpic = s3->floorpic; } // Spawn rising slime floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); s2->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = donutRaise; floor->crush = false; floor->direction = 1; floor->sector = s2; floor->speed = FLOORSPEED / 2; floor->texture = s3_floorpic; floor->newspecial = 0; floor->floordestheight = s3_floorheight; // Spawn lowering donut-hole floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); s1->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = lowerFloor; floor->crush = false; floor->direction = -1; floor->sector = s1; floor->speed = FLOORSPEED / 2; floor->floordestheight = s3_floorheight; break; } } return rtn; } // // SPECIAL SPAWNING // // // P_SpawnSpecials // After the map has been loaded, scan for specials // that spawn thinkers // short numlinespecials; line_t* linespeciallist[MAXLINEANIMS]; // Parses command line parameters. void P_SpawnSpecials (void) { sector_t* sector; int i; // See if -TIMER was specified. if (timelimit > 0 && deathmatch) { levelTimer = true; levelTimeCount = timelimit * 60 * TICRATE; } else { levelTimer = false; } // Init special SECTORs. sector = sectors; for (i=0 ; ispecial) continue; switch (sector->special) { case 1: // FLICKERING LIGHTS P_SpawnLightFlash (sector); break; case 2: // STROBE FAST P_SpawnStrobeFlash(sector,FASTDARK,0); break; case 3: // STROBE SLOW P_SpawnStrobeFlash(sector,SLOWDARK,0); break; case 4: // STROBE FAST/DEATH SLIME P_SpawnStrobeFlash(sector,FASTDARK,0); sector->special = 4; break; case 8: // GLOWING LIGHT P_SpawnGlowingLight(sector); break; case 9: // SECRET SECTOR totalsecret++; break; case 10: // DOOR CLOSE IN 30 SECONDS P_SpawnDoorCloseIn30 (sector); break; case 12: // SYNC STROBE SLOW P_SpawnStrobeFlash (sector, SLOWDARK, 1); break; case 13: // SYNC STROBE FAST P_SpawnStrobeFlash (sector, FASTDARK, 1); break; case 14: // DOOR RAISE IN 5 MINUTES P_SpawnDoorRaiseIn5Mins (sector, i); break; case 17: P_SpawnFireFlicker(sector); break; } } // Init line EFFECTs numlinespecials = 0; for (i = 0;i < numlines; i++) { switch(lines[i].special) { case 48: if (numlinespecials >= MAXLINEANIMS) { I_Error("Too many scrolling wall linedefs! " "(Vanilla limit is 64)"); } // EFFECT FIRSTCOL SCROLL+ linespeciallist[numlinespecials] = &lines[i]; numlinespecials++; break; } } // Init other misc stuff for (i = 0;i < MAXCEILINGS;i++) activeceilings[i] = NULL; for (i = 0;i < MAXPLATS;i++) activeplats[i] = NULL; for (i = 0;i < MAXBUTTONS;i++) memset(&buttonlist[i],0,sizeof(button_t)); // UNUSED: no horizonal sliders. // P_InitSlidingDoorFrames(); } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_spec.h000066400000000000000000000222241257432200600224560ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // Implements special effects: // Texture animation, height or lighting changes // according to adjacent sectors, respective // utility functions, etc. // #ifndef __P_SPEC__ #define __P_SPEC__ // // End-level timer (-TIMER option) // extern boolean levelTimer; extern int levelTimeCount; // Define values for map objects #define MO_TELEPORTMAN 14 // at game start void P_InitPicAnims (void); // at map load void P_SpawnSpecials (void); // every tic void P_UpdateSpecials (void); // when needed boolean P_UseSpecialLine ( mobj_t* thing, line_t* line, int side ); void P_ShootSpecialLine ( mobj_t* thing, line_t* line ); void P_CrossSpecialLine ( int linenum, int side, mobj_t* thing ); void P_PlayerInSpecialSector (player_t* player); int twoSided ( int sector, int line ); sector_t* getSector ( int currentSector, int line, int side ); side_t* getSide ( int currentSector, int line, int side ); fixed_t P_FindLowestFloorSurrounding(sector_t* sec); fixed_t P_FindHighestFloorSurrounding(sector_t* sec); fixed_t P_FindNextHighestFloor ( sector_t* sec, int currentheight ); fixed_t P_FindLowestCeilingSurrounding(sector_t* sec); fixed_t P_FindHighestCeilingSurrounding(sector_t* sec); int P_FindSectorFromLineTag ( line_t* line, int start ); int P_FindMinSurroundingLight ( sector_t* sector, int max ); sector_t* getNextSector ( line_t* line, sector_t* sec ); // // SPECIAL // int EV_DoDonut(line_t* line); // // P_LIGHTS // typedef struct { thinker_t thinker; sector_t* sector; int count; int maxlight; int minlight; } fireflicker_t; typedef struct { thinker_t thinker; sector_t* sector; int count; int maxlight; int minlight; int maxtime; int mintime; } lightflash_t; typedef struct { thinker_t thinker; sector_t* sector; int count; int minlight; int maxlight; int darktime; int brighttime; } strobe_t; typedef struct { thinker_t thinker; sector_t* sector; int minlight; int maxlight; int direction; } glow_t; #define GLOWSPEED 8 #define STROBEBRIGHT 5 #define FASTDARK 15 #define SLOWDARK 35 void P_SpawnFireFlicker (sector_t* sector); void T_LightFlash (lightflash_t* flash); void P_SpawnLightFlash (sector_t* sector); void T_StrobeFlash (strobe_t* flash); void P_SpawnStrobeFlash ( sector_t* sector, int fastOrSlow, int inSync ); void EV_StartLightStrobing(line_t* line); void EV_TurnTagLightsOff(line_t* line); void EV_LightTurnOn ( line_t* line, int bright ); void T_Glow(glow_t* g); void P_SpawnGlowingLight(sector_t* sector); // // P_SWITCH // typedef struct { char name1[9]; char name2[9]; short episode; } switchlist_t; typedef enum { top, middle, bottom } bwhere_e; typedef struct { line_t* line; bwhere_e where; int btexture; int btimer; degenmobj_t *soundorg; } button_t; // max # of wall switches in a level #define MAXSWITCHES 50 // 4 players, 4 buttons each at once, max. #define MAXBUTTONS 16 // 1 second, in ticks. #define BUTTONTIME 35 extern button_t buttonlist[MAXBUTTONS]; void P_ChangeSwitchTexture ( line_t* line, int useAgain ); void P_InitSwitchList(void); // // P_PLATS // typedef enum { up, down, waiting, in_stasis } plat_e; typedef enum { perpetualRaise, downWaitUpStay, raiseAndChange, raiseToNearestAndChange, blazeDWUS } plattype_e; typedef struct { thinker_t thinker; sector_t* sector; fixed_t speed; fixed_t low; fixed_t high; int wait; int count; plat_e status; plat_e oldstatus; boolean crush; int tag; plattype_e type; } plat_t; #define PLATWAIT 3 #define PLATSPEED FRACUNIT #define MAXPLATS 30 extern plat_t* activeplats[MAXPLATS]; void T_PlatRaise(plat_t* plat); int EV_DoPlat ( line_t* line, plattype_e type, int amount ); void P_AddActivePlat(plat_t* plat); void P_RemoveActivePlat(plat_t* plat); void EV_StopPlat(line_t* line); void P_ActivateInStasis(int tag); // // P_DOORS // typedef enum { vld_normal, vld_close30ThenOpen, vld_close, vld_open, vld_raiseIn5Mins, vld_blazeRaise, vld_blazeOpen, vld_blazeClose } vldoor_e; typedef struct { thinker_t thinker; vldoor_e type; sector_t* sector; fixed_t topheight; fixed_t speed; // 1 = up, 0 = waiting at top, -1 = down int direction; // tics to wait at the top int topwait; // (keep in case a door going down is reset) // when it reaches 0, start going down int topcountdown; } vldoor_t; #define VDOORSPEED FRACUNIT*2 #define VDOORWAIT 150 void EV_VerticalDoor ( line_t* line, mobj_t* thing ); int EV_DoDoor ( line_t* line, vldoor_e type ); int EV_DoLockedDoor ( line_t* line, vldoor_e type, mobj_t* thing ); void T_VerticalDoor (vldoor_t* door); void P_SpawnDoorCloseIn30 (sector_t* sec); void P_SpawnDoorRaiseIn5Mins ( sector_t* sec, int secnum ); #if 0 // UNUSED // // Sliding doors... // typedef enum { sd_opening, sd_waiting, sd_closing } sd_e; typedef enum { sdt_openOnly, sdt_closeOnly, sdt_openAndClose } sdt_e; typedef struct { thinker_t thinker; sdt_e type; line_t* line; int frame; int whichDoorIndex; int timer; sector_t* frontsector; sector_t* backsector; sd_e status; } slidedoor_t; typedef struct { char frontFrame1[9]; char frontFrame2[9]; char frontFrame3[9]; char frontFrame4[9]; char backFrame1[9]; char backFrame2[9]; char backFrame3[9]; char backFrame4[9]; } slidename_t; typedef struct { int frontFrames[4]; int backFrames[4]; } slideframe_t; // how many frames of animation #define SNUMFRAMES 4 #define SDOORWAIT 35*3 #define SWAITTICS 4 // how many diff. types of anims #define MAXSLIDEDOORS 5 void P_InitSlidingDoorFrames(void); void EV_SlidingDoor ( line_t* line, mobj_t* thing ); #endif // // P_CEILNG // typedef enum { lowerToFloor, raiseToHighest, lowerAndCrush, crushAndRaise, fastCrushAndRaise, silentCrushAndRaise } ceiling_e; typedef struct { thinker_t thinker; ceiling_e type; sector_t* sector; fixed_t bottomheight; fixed_t topheight; fixed_t speed; boolean crush; // 1 = up, 0 = waiting, -1 = down int direction; // ID int tag; int olddirection; } ceiling_t; #define CEILSPEED FRACUNIT #define CEILWAIT 150 #define MAXCEILINGS 30 extern ceiling_t* activeceilings[MAXCEILINGS]; int EV_DoCeiling ( line_t* line, ceiling_e type ); void T_MoveCeiling (ceiling_t* ceiling); void P_AddActiveCeiling(ceiling_t* c); void P_RemoveActiveCeiling(ceiling_t* c); int EV_CeilingCrushStop(line_t* line); void P_ActivateInStasisCeiling(line_t* line); // // P_FLOOR // typedef enum { // lower floor to highest surrounding floor lowerFloor, // lower floor to lowest surrounding floor lowerFloorToLowest, // lower floor to highest surrounding floor VERY FAST turboLower, // raise floor to lowest surrounding CEILING raiseFloor, // raise floor to next highest surrounding floor raiseFloorToNearest, // raise floor to shortest height texture around it raiseToTexture, // lower floor to lowest surrounding floor // and change floorpic lowerAndChange, raiseFloor24, raiseFloor24AndChange, raiseFloorCrush, // raise to next highest floor, turbo-speed raiseFloorTurbo, donutRaise, raiseFloor512 } floor_e; typedef enum { build8, // slowly build by 8 turbo16 // quickly build by 16 } stair_e; typedef struct { thinker_t thinker; floor_e type; boolean crush; sector_t* sector; int direction; int newspecial; short texture; fixed_t floordestheight; fixed_t speed; } floormove_t; #define FLOORSPEED FRACUNIT typedef enum { ok, crushed, pastdest } result_e; result_e T_MovePlane ( sector_t* sector, fixed_t speed, fixed_t dest, boolean crush, int floorOrCeiling, int direction ); int EV_BuildStairs ( line_t* line, stair_e type ); int EV_DoFloor ( line_t* line, floor_e floortype ); void T_MoveFloor( floormove_t* floor); // // P_TELEPT // int EV_Teleport ( line_t* line, int side, mobj_t* thing ); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/p_switch.c000066400000000000000000000317731257432200600230310ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: // Switches, buttons. Two-state animation. Exits. // #include #include "i_system.h" #include "deh_main.h" #include "doomdef.h" #include "p_local.h" #include "g_game.h" #include "s_sound.h" // Data. #include "sounds.h" // State. #include "doomstat.h" #include "r_state.h" // // CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE // switchlist_t alphSwitchList[] = { // Doom shareware episode 1 switches {"SW1BRCOM", "SW2BRCOM", 1}, {"SW1BRN1", "SW2BRN1", 1}, {"SW1BRN2", "SW2BRN2", 1}, {"SW1BRNGN", "SW2BRNGN", 1}, {"SW1BROWN", "SW2BROWN", 1}, {"SW1COMM", "SW2COMM", 1}, {"SW1COMP", "SW2COMP", 1}, {"SW1DIRT", "SW2DIRT", 1}, {"SW1EXIT", "SW2EXIT", 1}, {"SW1GRAY", "SW2GRAY", 1}, {"SW1GRAY1", "SW2GRAY1", 1}, {"SW1METAL", "SW2METAL", 1}, {"SW1PIPE", "SW2PIPE", 1}, {"SW1SLAD", "SW2SLAD", 1}, {"SW1STARG", "SW2STARG", 1}, {"SW1STON1", "SW2STON1", 1}, {"SW1STON2", "SW2STON2", 1}, {"SW1STONE", "SW2STONE", 1}, {"SW1STRTN", "SW2STRTN", 1}, // Doom registered episodes 2&3 switches {"SW1BLUE", "SW2BLUE", 2}, {"SW1CMT", "SW2CMT", 2}, {"SW1GARG", "SW2GARG", 2}, {"SW1GSTON", "SW2GSTON", 2}, {"SW1HOT", "SW2HOT", 2}, {"SW1LION", "SW2LION", 2}, {"SW1SATYR", "SW2SATYR", 2}, {"SW1SKIN", "SW2SKIN", 2}, {"SW1VINE", "SW2VINE", 2}, {"SW1WOOD", "SW2WOOD", 2}, // Doom II switches {"SW1PANEL", "SW2PANEL", 3}, {"SW1ROCK", "SW2ROCK", 3}, {"SW1MET2", "SW2MET2", 3}, {"SW1WDMET", "SW2WDMET", 3}, {"SW1BRIK", "SW2BRIK", 3}, {"SW1MOD1", "SW2MOD1", 3}, {"SW1ZIM", "SW2ZIM", 3}, {"SW1STON6", "SW2STON6", 3}, {"SW1TEK", "SW2TEK", 3}, {"SW1MARB", "SW2MARB", 3}, {"SW1SKULL", "SW2SKULL", 3}, {"\0", "\0", 0} }; int switchlist[MAXSWITCHES * 2]; int numswitches; button_t buttonlist[MAXBUTTONS]; // // P_InitSwitchList // Only called at game initialization. // void P_InitSwitchList(void) { int i; int index; int episode; episode = 1; if (gamemode == registered || gamemode == retail) episode = 2; else if ( gamemode == commercial ) episode = 3; for (index = 0,i = 0;i < MAXSWITCHES;i++) { if (!alphSwitchList[i].episode) { numswitches = index/2; switchlist[index] = -1; break; } if (alphSwitchList[i].episode <= episode) { #if 0 // UNUSED - debug? int value; if (R_CheckTextureNumForName(alphSwitchList[i].name1) < 0) { I_Error("Can't find switch texture '%s'!", alphSwitchList[i].name1); continue; } value = R_TextureNumForName(alphSwitchList[i].name1); #endif switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name1)); switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name2)); } } } // // Start a button counting down till it turns off. // void P_StartButton ( line_t* line, bwhere_e w, int texture, int time ) { int i; // See if button is already pressed for (i = 0;i < MAXBUTTONS;i++) { if (buttonlist[i].btimer && buttonlist[i].line == line) { return; } } for (i = 0;i < MAXBUTTONS;i++) { if (!buttonlist[i].btimer) { buttonlist[i].line = line; buttonlist[i].where = w; buttonlist[i].btexture = texture; buttonlist[i].btimer = time; buttonlist[i].soundorg = &line->frontsector->soundorg; return; } } I_Error("P_StartButton: no button slots left!"); } // // Function that changes wall texture. // Tell it if switch is ok to use again (1=yes, it's a button). // void P_ChangeSwitchTexture ( line_t* line, int useAgain ) { int texTop; int texMid; int texBot; int i; int sound; if (!useAgain) line->special = 0; texTop = sides[line->sidenum[0]].toptexture; texMid = sides[line->sidenum[0]].midtexture; texBot = sides[line->sidenum[0]].bottomtexture; sound = sfx_swtchn; // EXIT SWITCH? if (line->special == 11) sound = sfx_swtchx; for (i = 0;i < numswitches*2;i++) { if (switchlist[i] == texTop) { S_StartSound(buttonlist->soundorg,sound); sides[line->sidenum[0]].toptexture = switchlist[i^1]; if (useAgain) P_StartButton(line,top,switchlist[i],BUTTONTIME); return; } else { if (switchlist[i] == texMid) { S_StartSound(buttonlist->soundorg,sound); sides[line->sidenum[0]].midtexture = switchlist[i^1]; if (useAgain) P_StartButton(line, middle,switchlist[i],BUTTONTIME); return; } else { if (switchlist[i] == texBot) { S_StartSound(buttonlist->soundorg,sound); sides[line->sidenum[0]].bottomtexture = switchlist[i^1]; if (useAgain) P_StartButton(line, bottom,switchlist[i],BUTTONTIME); return; } } } } } // // P_UseSpecialLine // Called when a thing uses a special line. // Only the front sides of lines are usable. // boolean P_UseSpecialLine ( mobj_t* thing, line_t* line, int side ) { // Err... // Use the back sides of VERY SPECIAL lines... if (side) { switch(line->special) { case 124: // Sliding door open&close // UNUSED? break; default: return false; break; } } // Switches that other things can activate. if (!thing->player) { // never open secret doors if (line->flags & ML_SECRET) return false; switch(line->special) { case 1: // MANUAL DOOR RAISE case 32: // MANUAL BLUE case 33: // MANUAL RED case 34: // MANUAL YELLOW break; default: return false; break; } } // do something switch (line->special) { // MANUALS case 1: // Vertical Door case 26: // Blue Door/Locked case 27: // Yellow Door /Locked case 28: // Red Door /Locked case 31: // Manual door open case 32: // Blue locked door open case 33: // Red locked door open case 34: // Yellow locked door open case 117: // Blazing door raise case 118: // Blazing door open EV_VerticalDoor (line, thing); break; //UNUSED - Door Slide Open&Close // case 124: // EV_SlidingDoor (line, thing); // break; // SWITCHES case 7: // Build Stairs if (EV_BuildStairs(line,build8)) P_ChangeSwitchTexture(line,0); break; case 9: // Change Donut if (EV_DoDonut(line)) P_ChangeSwitchTexture(line,0); break; case 11: // Exit level P_ChangeSwitchTexture(line,0); G_ExitLevel (); break; case 14: // Raise Floor 32 and change texture if (EV_DoPlat(line,raiseAndChange,32)) P_ChangeSwitchTexture(line,0); break; case 15: // Raise Floor 24 and change texture if (EV_DoPlat(line,raiseAndChange,24)) P_ChangeSwitchTexture(line,0); break; case 18: // Raise Floor to next highest floor if (EV_DoFloor(line, raiseFloorToNearest)) P_ChangeSwitchTexture(line,0); break; case 20: // Raise Plat next highest floor and change texture if (EV_DoPlat(line,raiseToNearestAndChange,0)) P_ChangeSwitchTexture(line,0); break; case 21: // PlatDownWaitUpStay if (EV_DoPlat(line,downWaitUpStay,0)) P_ChangeSwitchTexture(line,0); break; case 23: // Lower Floor to Lowest if (EV_DoFloor(line,lowerFloorToLowest)) P_ChangeSwitchTexture(line,0); break; case 29: // Raise Door if (EV_DoDoor(line,vld_normal)) P_ChangeSwitchTexture(line,0); break; case 41: // Lower Ceiling to Floor if (EV_DoCeiling(line,lowerToFloor)) P_ChangeSwitchTexture(line,0); break; case 71: // Turbo Lower Floor if (EV_DoFloor(line,turboLower)) P_ChangeSwitchTexture(line,0); break; case 49: // Ceiling Crush And Raise if (EV_DoCeiling(line,crushAndRaise)) P_ChangeSwitchTexture(line,0); break; case 50: // Close Door if (EV_DoDoor(line,vld_close)) P_ChangeSwitchTexture(line,0); break; case 51: // Secret EXIT P_ChangeSwitchTexture(line,0); G_SecretExitLevel (); break; case 55: // Raise Floor Crush if (EV_DoFloor(line,raiseFloorCrush)) P_ChangeSwitchTexture(line,0); break; case 101: // Raise Floor if (EV_DoFloor(line,raiseFloor)) P_ChangeSwitchTexture(line,0); break; case 102: // Lower Floor to Surrounding floor height if (EV_DoFloor(line,lowerFloor)) P_ChangeSwitchTexture(line,0); break; case 103: // Open Door if (EV_DoDoor(line,vld_open)) P_ChangeSwitchTexture(line,0); break; case 111: // Blazing Door Raise (faster than TURBO!) if (EV_DoDoor (line,vld_blazeRaise)) P_ChangeSwitchTexture(line,0); break; case 112: // Blazing Door Open (faster than TURBO!) if (EV_DoDoor (line,vld_blazeOpen)) P_ChangeSwitchTexture(line,0); break; case 113: // Blazing Door Close (faster than TURBO!) if (EV_DoDoor (line,vld_blazeClose)) P_ChangeSwitchTexture(line,0); break; case 122: // Blazing PlatDownWaitUpStay if (EV_DoPlat(line,blazeDWUS,0)) P_ChangeSwitchTexture(line,0); break; case 127: // Build Stairs Turbo 16 if (EV_BuildStairs(line,turbo16)) P_ChangeSwitchTexture(line,0); break; case 131: // Raise Floor Turbo if (EV_DoFloor(line,raiseFloorTurbo)) P_ChangeSwitchTexture(line,0); break; case 133: // BlzOpenDoor BLUE case 135: // BlzOpenDoor RED case 137: // BlzOpenDoor YELLOW if (EV_DoLockedDoor (line,vld_blazeOpen,thing)) P_ChangeSwitchTexture(line,0); break; case 140: // Raise Floor 512 if (EV_DoFloor(line,raiseFloor512)) P_ChangeSwitchTexture(line,0); break; // BUTTONS case 42: // Close Door if (EV_DoDoor(line,vld_close)) P_ChangeSwitchTexture(line,1); break; case 43: // Lower Ceiling to Floor if (EV_DoCeiling(line,lowerToFloor)) P_ChangeSwitchTexture(line,1); break; case 45: // Lower Floor to Surrounding floor height if (EV_DoFloor(line,lowerFloor)) P_ChangeSwitchTexture(line,1); break; case 60: // Lower Floor to Lowest if (EV_DoFloor(line,lowerFloorToLowest)) P_ChangeSwitchTexture(line,1); break; case 61: // Open Door if (EV_DoDoor(line,vld_open)) P_ChangeSwitchTexture(line,1); break; case 62: // PlatDownWaitUpStay if (EV_DoPlat(line,downWaitUpStay,1)) P_ChangeSwitchTexture(line,1); break; case 63: // Raise Door if (EV_DoDoor(line,vld_normal)) P_ChangeSwitchTexture(line,1); break; case 64: // Raise Floor to ceiling if (EV_DoFloor(line,raiseFloor)) P_ChangeSwitchTexture(line,1); break; case 66: // Raise Floor 24 and change texture if (EV_DoPlat(line,raiseAndChange,24)) P_ChangeSwitchTexture(line,1); break; case 67: // Raise Floor 32 and change texture if (EV_DoPlat(line,raiseAndChange,32)) P_ChangeSwitchTexture(line,1); break; case 65: // Raise Floor Crush if (EV_DoFloor(line,raiseFloorCrush)) P_ChangeSwitchTexture(line,1); break; case 68: // Raise Plat to next highest floor and change texture if (EV_DoPlat(line,raiseToNearestAndChange,0)) P_ChangeSwitchTexture(line,1); break; case 69: // Raise Floor to next highest floor if (EV_DoFloor(line, raiseFloorToNearest)) P_ChangeSwitchTexture(line,1); break; case 70: // Turbo Lower Floor if (EV_DoFloor(line,turboLower)) P_ChangeSwitchTexture(line,1); break; case 114: // Blazing Door Raise (faster than TURBO!) if (EV_DoDoor (line,vld_blazeRaise)) P_ChangeSwitchTexture(line,1); break; case 115: // Blazing Door Open (faster than TURBO!) if (EV_DoDoor (line,vld_blazeOpen)) P_ChangeSwitchTexture(line,1); break; case 116: // Blazing Door Close (faster than TURBO!) if (EV_DoDoor (line,vld_blazeClose)) P_ChangeSwitchTexture(line,1); break; case 123: // Blazing PlatDownWaitUpStay if (EV_DoPlat(line,blazeDWUS,0)) P_ChangeSwitchTexture(line,1); break; case 132: // Raise Floor Turbo if (EV_DoFloor(line,raiseFloorTurbo)) P_ChangeSwitchTexture(line,1); break; case 99: // BlzOpenDoor BLUE case 134: // BlzOpenDoor RED case 136: // BlzOpenDoor YELLOW if (EV_DoLockedDoor (line,vld_blazeOpen,thing)) P_ChangeSwitchTexture(line,1); break; case 138: // Light Turn On EV_LightTurnOn(line,255); P_ChangeSwitchTexture(line,1); break; case 139: // Light Turn Off EV_LightTurnOn(line,35); P_ChangeSwitchTexture(line,1); break; } return true; } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_telept.c000066400000000000000000000054641257432200600230230ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Teleportation. // #include "doomdef.h" #include "doomstat.h" #include "s_sound.h" #include "p_local.h" // Data. #include "sounds.h" // State. #include "r_state.h" // // TELEPORTATION // int EV_Teleport ( line_t* line, int side, mobj_t* thing ) { int i; int tag; mobj_t* m; mobj_t* fog; unsigned an; thinker_t* thinker; sector_t* sector; fixed_t oldx; fixed_t oldy; fixed_t oldz; // don't teleport missiles if (thing->flags & MF_MISSILE) return 0; // Don't teleport if hit back of line, // so you can get out of teleporter. if (side == 1) return 0; tag = line->tag; for (i = 0; i < numsectors; i++) { if (sectors[ i ].tag == tag ) { thinker = thinkercap.next; for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { // not a mobj if (thinker->function.acp1 != (actionf_p1)P_MobjThinker) continue; m = (mobj_t *)thinker; // not a teleportman if (m->type != MT_TELEPORTMAN ) continue; sector = m->subsector->sector; // wrong sector if (sector-sectors != i ) continue; oldx = thing->x; oldy = thing->y; oldz = thing->z; if (!P_TeleportMove (thing, m->x, m->y)) return 0; // The first Final Doom executable does not set thing->z // when teleporting. This quirk is unique to this // particular version; the later version included in // some versions of the Id Anthology fixed this. if (gameversion != exe_final) thing->z = thing->floorz; if (thing->player) thing->player->viewz = thing->z+thing->player->viewheight; // spawn teleport fog at source and destination fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG); S_StartSound (fog, sfx_telept); an = m->angle >> ANGLETOFINESHIFT; fog = P_SpawnMobj (m->x+20*finecosine[an], m->y+20*finesine[an] , thing->z, MT_TFOG); // emit sound, where? S_StartSound (fog, sfx_telept); // don't move for a bit if (thing->player) thing->reactiontime = 18; thing->angle = m->angle; thing->momx = thing->momy = thing->momz = 0; return 1; } } } return 0; } chocolate-doom-chocolate-doom-2.2.1/src/doom/p_tick.c000066400000000000000000000055231257432200600224540ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Archiving: SaveGame I/O. // Thinker, Ticker. // #include "z_zone.h" #include "p_local.h" #include "doomstat.h" int leveltime; // // THINKERS // All thinkers should be allocated by Z_Malloc // so they can be operated on uniformly. // The actual structures will vary in size, // but the first element must be thinker_t. // // Both the head and tail of the thinker list. thinker_t thinkercap; // // P_InitThinkers // void P_InitThinkers (void) { thinkercap.prev = thinkercap.next = &thinkercap; } // // P_AddThinker // Adds a new thinker at the end of the list. // void P_AddThinker (thinker_t* thinker) { thinkercap.prev->next = thinker; thinker->next = &thinkercap; thinker->prev = thinkercap.prev; thinkercap.prev = thinker; } // // P_RemoveThinker // Deallocation is lazy -- it will not actually be freed // until its thinking turn comes up. // void P_RemoveThinker (thinker_t* thinker) { // FIXME: NOP. thinker->function.acv = (actionf_v)(-1); } // // P_AllocateThinker // Allocates memory and adds a new thinker at the end of the list. // void P_AllocateThinker (thinker_t* thinker) { } // // P_RunThinkers // void P_RunThinkers (void) { thinker_t *currentthinker, *nextthinker; currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { if ( currentthinker->function.acv == (actionf_v)(-1) ) { // time to remove it nextthinker = currentthinker->next; currentthinker->next->prev = currentthinker->prev; currentthinker->prev->next = currentthinker->next; Z_Free(currentthinker); } else { if (currentthinker->function.acp1) currentthinker->function.acp1 (currentthinker); nextthinker = currentthinker->next; } currentthinker = nextthinker; } } // // P_Ticker // void P_Ticker (void) { int i; // run the tic if (paused) return; // pause if in menu and at least one tic has been run if ( !netgame && menuactive && !demoplayback && players[consoleplayer].viewz != 1) { return; } for (i=0 ; i>= ANGLETOFINESHIFT; player->mo->momx += FixedMul(move,finecosine[angle]); player->mo->momy += FixedMul(move,finesine[angle]); } // // P_CalcHeight // Calculate the walking / running height adjustment // void P_CalcHeight (player_t* player) { int angle; fixed_t bob; // Regular movement bobbing // (needs to be calculated for gun swing // even if not on ground) // OPTIMIZE: tablify angle // Note: a LUT allows for effects // like a ramp with low health. player->bob = FixedMul (player->mo->momx, player->mo->momx) + FixedMul (player->mo->momy,player->mo->momy); player->bob >>= 2; if (player->bob>MAXBOB) player->bob = MAXBOB; if ((player->cheats & CF_NOMOMENTUM) || !onground) { player->viewz = player->mo->z + VIEWHEIGHT; if (player->viewz > player->mo->ceilingz-4*FRACUNIT) player->viewz = player->mo->ceilingz-4*FRACUNIT; player->viewz = player->mo->z + player->viewheight; return; } angle = (FINEANGLES/20*leveltime)&FINEMASK; bob = FixedMul ( player->bob/2, finesine[angle]); // move viewheight if (player->playerstate == PST_LIVE) { player->viewheight += player->deltaviewheight; if (player->viewheight > VIEWHEIGHT) { player->viewheight = VIEWHEIGHT; player->deltaviewheight = 0; } if (player->viewheight < VIEWHEIGHT/2) { player->viewheight = VIEWHEIGHT/2; if (player->deltaviewheight <= 0) player->deltaviewheight = 1; } if (player->deltaviewheight) { player->deltaviewheight += FRACUNIT/4; if (!player->deltaviewheight) player->deltaviewheight = 1; } } player->viewz = player->mo->z + player->viewheight + bob; if (player->viewz > player->mo->ceilingz-4*FRACUNIT) player->viewz = player->mo->ceilingz-4*FRACUNIT; } // // P_MovePlayer // void P_MovePlayer (player_t* player) { ticcmd_t* cmd; cmd = &player->cmd; player->mo->angle += (cmd->angleturn<<16); // Do not let the player control movement // if not onground. onground = (player->mo->z <= player->mo->floorz); if (cmd->forwardmove && onground) P_Thrust (player, player->mo->angle, cmd->forwardmove*2048); if (cmd->sidemove && onground) P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048); if ( (cmd->forwardmove || cmd->sidemove) && player->mo->state == &states[S_PLAY] ) { P_SetMobjState (player->mo, S_PLAY_RUN1); } } // // P_DeathThink // Fall on your face when dying. // Decrease POV height to floor height. // #define ANG5 (ANG90/18) void P_DeathThink (player_t* player) { angle_t angle; angle_t delta; P_MovePsprites (player); // fall to the ground if (player->viewheight > 6*FRACUNIT) player->viewheight -= FRACUNIT; if (player->viewheight < 6*FRACUNIT) player->viewheight = 6*FRACUNIT; player->deltaviewheight = 0; onground = (player->mo->z <= player->mo->floorz); P_CalcHeight (player); if (player->attacker && player->attacker != player->mo) { angle = R_PointToAngle2 (player->mo->x, player->mo->y, player->attacker->x, player->attacker->y); delta = angle - player->mo->angle; if (delta < ANG5 || delta > (unsigned)-ANG5) { // Looking at killer, // so fade damage flash down. player->mo->angle = angle; if (player->damagecount) player->damagecount--; } else if (delta < ANG180) player->mo->angle += ANG5; else player->mo->angle -= ANG5; } else if (player->damagecount) player->damagecount--; if (player->cmd.buttons & BT_USE) player->playerstate = PST_REBORN; } // // P_PlayerThink // void P_PlayerThink (player_t* player) { ticcmd_t* cmd; weapontype_t newweapon; // fixme: do this in the cheat code if (player->cheats & CF_NOCLIP) player->mo->flags |= MF_NOCLIP; else player->mo->flags &= ~MF_NOCLIP; // chain saw run forward cmd = &player->cmd; if (player->mo->flags & MF_JUSTATTACKED) { cmd->angleturn = 0; cmd->forwardmove = 0xc800/512; cmd->sidemove = 0; player->mo->flags &= ~MF_JUSTATTACKED; } if (player->playerstate == PST_DEAD) { P_DeathThink (player); return; } // Move around. // Reactiontime is used to prevent movement // for a bit after a teleport. if (player->mo->reactiontime) player->mo->reactiontime--; else P_MovePlayer (player); P_CalcHeight (player); if (player->mo->subsector->sector->special) P_PlayerInSpecialSector (player); // Check for weapon change. // A special event has no other buttons. if (cmd->buttons & BT_SPECIAL) cmd->buttons = 0; if (cmd->buttons & BT_CHANGE) { // The actual changing of the weapon is done // when the weapon psprite can do it // (read: not in the middle of an attack). newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT; if (newweapon == wp_fist && player->weaponowned[wp_chainsaw] && !(player->readyweapon == wp_chainsaw && player->powers[pw_strength])) { newweapon = wp_chainsaw; } if ( (gamemode == commercial) && newweapon == wp_shotgun && player->weaponowned[wp_supershotgun] && player->readyweapon != wp_supershotgun) { newweapon = wp_supershotgun; } if (player->weaponowned[newweapon] && newweapon != player->readyweapon) { // Do not go to plasma or BFG in shareware, // even if cheated. if ((newweapon != wp_plasma && newweapon != wp_bfg) || (gamemode != shareware) ) { player->pendingweapon = newweapon; } } } // check for use if (cmd->buttons & BT_USE) { if (!player->usedown) { P_UseLines (player); player->usedown = true; } } else player->usedown = false; // cycle psprites P_MovePsprites (player); // Counters, time dependend power ups. // Strength counts up to diminish fade. if (player->powers[pw_strength]) player->powers[pw_strength]++; if (player->powers[pw_invulnerability]) player->powers[pw_invulnerability]--; if (player->powers[pw_invisibility]) if (! --player->powers[pw_invisibility] ) player->mo->flags &= ~MF_SHADOW; if (player->powers[pw_infrared]) player->powers[pw_infrared]--; if (player->powers[pw_ironfeet]) player->powers[pw_ironfeet]--; if (player->damagecount) player->damagecount--; if (player->bonuscount) player->bonuscount--; // Handling colormaps. if (player->powers[pw_invulnerability]) { if (player->powers[pw_invulnerability] > 4*32 || (player->powers[pw_invulnerability]&8) ) player->fixedcolormap = INVERSECOLORMAP; else player->fixedcolormap = 0; } else if (player->powers[pw_infrared]) { if (player->powers[pw_infrared] > 4*32 || (player->powers[pw_infrared]&8) ) { // almost full bright player->fixedcolormap = 1; } else player->fixedcolormap = 0; } else player->fixedcolormap = 0; } chocolate-doom-chocolate-doom-2.2.1/src/doom/r_bsp.c000066400000000000000000000254241257432200600223120ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // BSP traversal, handling of LineSegs for rendering. // #include "doomdef.h" #include "m_bbox.h" #include "i_system.h" #include "r_main.h" #include "r_plane.h" #include "r_things.h" // State. #include "doomstat.h" #include "r_state.h" //#include "r_local.h" seg_t* curline; side_t* sidedef; line_t* linedef; sector_t* frontsector; sector_t* backsector; drawseg_t drawsegs[MAXDRAWSEGS]; drawseg_t* ds_p; void R_StoreWallRange ( int start, int stop ); // // R_ClearDrawSegs // void R_ClearDrawSegs (void) { ds_p = drawsegs; } // // ClipWallSegment // Clips the given range of columns // and includes it in the new clip list. // typedef struct { int first; int last; } cliprange_t; #define MAXSEGS 32 // newend is one past the last valid seg cliprange_t* newend; cliprange_t solidsegs[MAXSEGS]; // // R_ClipSolidWallSegment // Does handle solid walls, // e.g. single sided LineDefs (middle texture) // that entirely block the view. // void R_ClipSolidWallSegment ( int first, int last ) { cliprange_t* next; cliprange_t* start; // Find the first range that touches the range // (adjacent pixels are touching). start = solidsegs; while (start->last < first-1) start++; if (first < start->first) { if (last < start->first-1) { // Post is entirely visible (above start), // so insert a new clippost. R_StoreWallRange (first, last); next = newend; newend++; while (next != start) { *next = *(next-1); next--; } next->first = first; next->last = last; return; } // There is a fragment above *start. R_StoreWallRange (first, start->first - 1); // Now adjust the clip size. start->first = first; } // Bottom contained in start? if (last <= start->last) return; next = start; while (last >= (next+1)->first-1) { // There is a fragment between two posts. R_StoreWallRange (next->last + 1, (next+1)->first - 1); next++; if (last <= next->last) { // Bottom is contained in next. // Adjust the clip size. start->last = next->last; goto crunch; } } // There is a fragment after *next. R_StoreWallRange (next->last + 1, last); // Adjust the clip size. start->last = last; // Remove start+1 to next from the clip list, // because start now covers their area. crunch: if (next == start) { // Post just extended past the bottom of one post. return; } while (next++ != newend) { // Remove a post. *++start = *next; } newend = start+1; } // // R_ClipPassWallSegment // Clips the given range of columns, // but does not includes it in the clip list. // Does handle windows, // e.g. LineDefs with upper and lower texture. // void R_ClipPassWallSegment ( int first, int last ) { cliprange_t* start; // Find the first range that touches the range // (adjacent pixels are touching). start = solidsegs; while (start->last < first-1) start++; if (first < start->first) { if (last < start->first-1) { // Post is entirely visible (above start). R_StoreWallRange (first, last); return; } // There is a fragment above *start. R_StoreWallRange (first, start->first - 1); } // Bottom contained in start? if (last <= start->last) return; while (last >= (start+1)->first-1) { // There is a fragment between two posts. R_StoreWallRange (start->last + 1, (start+1)->first - 1); start++; if (last <= start->last) return; } // There is a fragment after *next. R_StoreWallRange (start->last + 1, last); } // // R_ClearClipSegs // void R_ClearClipSegs (void) { solidsegs[0].first = -0x7fffffff; solidsegs[0].last = -1; solidsegs[1].first = viewwidth; solidsegs[1].last = 0x7fffffff; newend = solidsegs+2; } // // R_AddLine // Clips the given segment // and adds any visible pieces to the line list. // void R_AddLine (seg_t* line) { int x1; int x2; angle_t angle1; angle_t angle2; angle_t span; angle_t tspan; curline = line; // OPTIMIZE: quickly reject orthogonal back sides. angle1 = R_PointToAngle (line->v1->x, line->v1->y); angle2 = R_PointToAngle (line->v2->x, line->v2->y); // Clip to view edges. // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW). span = angle1 - angle2; // Back side? I.e. backface culling? if (span >= ANG180) return; // Global angle needed by segcalc. rw_angle1 = angle1; angle1 -= viewangle; angle2 -= viewangle; tspan = angle1 + clipangle; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return; angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return; angle2 = -clipangle; } // The seg is in the view range, // but not necessarily visible. angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; x1 = viewangletox[angle1]; x2 = viewangletox[angle2]; // Does not cross a pixel? if (x1 == x2) return; backsector = line->backsector; // Single sided line? if (!backsector) goto clipsolid; // Closed door. if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) goto clipsolid; // Window. if (backsector->ceilingheight != frontsector->ceilingheight || backsector->floorheight != frontsector->floorheight) goto clippass; // Reject empty lines used for triggers // and special events. // Identical floor and ceiling on both sides, // identical light levels on both sides, // and no middle texture. if (backsector->ceilingpic == frontsector->ceilingpic && backsector->floorpic == frontsector->floorpic && backsector->lightlevel == frontsector->lightlevel && curline->sidedef->midtexture == 0) { return; } clippass: R_ClipPassWallSegment (x1, x2-1); return; clipsolid: R_ClipSolidWallSegment (x1, x2-1); } // // R_CheckBBox // Checks BSP node/subtree bounding box. // Returns true // if some part of the bbox might be visible. // int checkcoord[12][4] = { {3,0,2,1}, {3,0,2,0}, {3,1,2,0}, {0}, {2,0,2,1}, {0,0,0,0}, {3,1,3,0}, {0}, {2,0,3,1}, {2,1,3,1}, {2,1,3,0} }; boolean R_CheckBBox (fixed_t* bspcoord) { int boxx; int boxy; int boxpos; fixed_t x1; fixed_t y1; fixed_t x2; fixed_t y2; angle_t angle1; angle_t angle2; angle_t span; angle_t tspan; cliprange_t* start; int sx1; int sx2; // Find the corners of the box // that define the edges from current viewpoint. if (viewx <= bspcoord[BOXLEFT]) boxx = 0; else if (viewx < bspcoord[BOXRIGHT]) boxx = 1; else boxx = 2; if (viewy >= bspcoord[BOXTOP]) boxy = 0; else if (viewy > bspcoord[BOXBOTTOM]) boxy = 1; else boxy = 2; boxpos = (boxy<<2)+boxx; if (boxpos == 5) return true; x1 = bspcoord[checkcoord[boxpos][0]]; y1 = bspcoord[checkcoord[boxpos][1]]; x2 = bspcoord[checkcoord[boxpos][2]]; y2 = bspcoord[checkcoord[boxpos][3]]; // check clip list for an open space angle1 = R_PointToAngle (x1, y1) - viewangle; angle2 = R_PointToAngle (x2, y2) - viewangle; span = angle1 - angle2; // Sitting on a line? if (span >= ANG180) return true; tspan = angle1 + clipangle; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return false; angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return false; angle2 = -clipangle; } // Find the first clippost // that touches the source post // (adjacent pixels are touching). angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; sx1 = viewangletox[angle1]; sx2 = viewangletox[angle2]; // Does not cross a pixel. if (sx1 == sx2) return false; sx2--; start = solidsegs; while (start->last < sx2) start++; if (sx1 >= start->first && sx2 <= start->last) { // The clippost contains the new span. return false; } return true; } // // R_Subsector // Determine floor/ceiling planes. // Add sprites of things in sector. // Draw one or more line segments. // void R_Subsector (int num) { int count; seg_t* line; subsector_t* sub; #ifdef RANGECHECK if (num>=numsubsectors) I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors); #endif sscount++; sub = &subsectors[num]; frontsector = sub->sector; count = sub->numlines; line = &segs[sub->firstline]; if (frontsector->floorheight < viewz) { floorplane = R_FindPlane (frontsector->floorheight, frontsector->floorpic, frontsector->lightlevel); } else floorplane = NULL; if (frontsector->ceilingheight > viewz || frontsector->ceilingpic == skyflatnum) { ceilingplane = R_FindPlane (frontsector->ceilingheight, frontsector->ceilingpic, frontsector->lightlevel); } else ceilingplane = NULL; R_AddSprites (frontsector); while (count--) { R_AddLine (line); line++; } } // // RenderBSPNode // Renders all subsectors below a given node, // traversing subtree recursively. // Just call with BSP root. void R_RenderBSPNode (int bspnum) { node_t* bsp; int side; // Found a subsector? if (bspnum & NF_SUBSECTOR) { if (bspnum == -1) R_Subsector (0); else R_Subsector (bspnum&(~NF_SUBSECTOR)); return; } bsp = &nodes[bspnum]; // Decide which side the view point is on. side = R_PointOnSide (viewx, viewy, bsp); // Recursively divide front space. R_RenderBSPNode (bsp->children[side]); // Possibly divide back space. if (R_CheckBBox (bsp->bbox[side^1])) R_RenderBSPNode (bsp->children[side^1]); } chocolate-doom-chocolate-doom-2.2.1/src/doom/r_bsp.h000066400000000000000000000025311257432200600223110ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh module, BSP traversal and handling. // #ifndef __R_BSP__ #define __R_BSP__ extern seg_t* curline; extern side_t* sidedef; extern line_t* linedef; extern sector_t* frontsector; extern sector_t* backsector; extern int rw_x; extern int rw_stopx; extern boolean segtextured; // false if the back side is the same plane extern boolean markfloor; extern boolean markceiling; extern boolean skymap; extern drawseg_t drawsegs[MAXDRAWSEGS]; extern drawseg_t* ds_p; extern lighttable_t** hscalelight; extern lighttable_t** vscalelight; extern lighttable_t** dscalelight; typedef void (*drawfunc_t) (int start, int stop); // BSP? void R_ClearClipSegs (void); void R_ClearDrawSegs (void); void R_RenderBSPNode (int bspnum); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/r_data.c000066400000000000000000000471721257432200600224430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Preparation of data for rendering, // generation of lookups, caching, retrieval by name. // #include #include "deh_main.h" #include "i_swap.h" #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "doomdef.h" #include "m_misc.h" #include "r_local.h" #include "p_local.h" #include "doomstat.h" #include "r_sky.h" #include "r_data.h" // // Graphics. // DOOM graphics for walls and sprites // is stored in vertical runs of opaque pixels (posts). // A column is composed of zero or more posts, // a patch or sprite is composed of zero or more columns. // // // Texture definition. // Each texture is composed of one or more patches, // with patches being lumps stored in the WAD. // The lumps are referenced by number, and patched // into the rectangular texture space using origin // and possibly other attributes. // typedef struct { short originx; short originy; short patch; short stepdir; short colormap; } PACKEDATTR mappatch_t; // // Texture definition. // A DOOM wall texture is a list of patches // which are to be combined in a predefined order. // typedef struct { char name[8]; int masked; short width; short height; int obsolete; short patchcount; mappatch_t patches[1]; } PACKEDATTR maptexture_t; // A single patch from a texture definition, // basically a rectangular area within // the texture rectangle. typedef struct { // Block origin (allways UL), // which has allready accounted // for the internal origin of the patch. short originx; short originy; int patch; } texpatch_t; // A maptexturedef_t describes a rectangular texture, // which is composed of one or more mappatch_t structures // that arrange graphic patches. typedef struct texture_s texture_t; struct texture_s { // Keep name for switch changing, etc. char name[8]; short width; short height; // Index in textures list int index; // Next in hash table chain texture_t *next; // All the patches[patchcount] // are drawn back to front into the cached texture. short patchcount; texpatch_t patches[1]; }; int firstflat; int lastflat; int numflats; int firstpatch; int lastpatch; int numpatches; int firstspritelump; int lastspritelump; int numspritelumps; int numtextures; texture_t** textures; texture_t** textures_hashtable; int* texturewidthmask; // needed for texture pegging fixed_t* textureheight; int* texturecompositesize; short** texturecolumnlump; unsigned short** texturecolumnofs; byte** texturecomposite; // for global animation int* flattranslation; int* texturetranslation; // needed for pre rendering fixed_t* spritewidth; fixed_t* spriteoffset; fixed_t* spritetopoffset; lighttable_t *colormaps; // // MAPTEXTURE_T CACHING // When a texture is first needed, // it counts the number of composite columns // required in the texture and allocates space // for a column directory and any new columns. // The directory will simply point inside other patches // if there is only one patch in a given column, // but any columns with multiple patches // will have new column_ts generated. // // // R_DrawColumnInCache // Clip and draw a column // from a patch into a cached post. // void R_DrawColumnInCache ( column_t* patch, byte* cache, int originy, int cacheheight ) { int count; int position; byte* source; while (patch->topdelta != 0xff) { source = (byte *)patch + 3; count = patch->length; position = originy + patch->topdelta; if (position < 0) { count += position; position = 0; } if (position + count > cacheheight) count = cacheheight - position; if (count > 0) memcpy (cache + position, source, count); patch = (column_t *)( (byte *)patch + patch->length + 4); } } // // R_GenerateComposite // Using the texture definition, // the composite texture is created from the patches, // and each column is cached. // void R_GenerateComposite (int texnum) { byte* block; texture_t* texture; texpatch_t* patch; patch_t* realpatch; int x; int x1; int x2; int i; column_t* patchcol; short* collump; unsigned short* colofs; texture = textures[texnum]; block = Z_Malloc (texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]); collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // Composite the columns together. patch = texture->patches; for (i=0 , patch = texture->patches; ipatchcount; i++, patch++) { realpatch = W_CacheLumpNum (patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1<0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for ( ; x= 0) continue; patchcol = (column_t *)((byte *)realpatch + LONG(realpatch->columnofs[x-x1])); R_DrawColumnInCache (patchcol, block + colofs[x], patch->originy, texture->height); } } // Now that the texture has been built in column cache, // it is purgable from zone memory. Z_ChangeTag (block, PU_CACHE); } // // R_GenerateLookup // void R_GenerateLookup (int texnum) { texture_t* texture; byte* patchcount; // patchcount[texture->width] texpatch_t* patch; patch_t* realpatch; int x; int x1; int x2; int i; short* collump; unsigned short* colofs; texture = textures[texnum]; // Composited texture not created yet. texturecomposite[texnum] = 0; texturecompositesize[texnum] = 0; collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // Now count the number of columns // that are covered by more than one patch. // Fill in the lump / offset, so columns // with only a single patch are all done. patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); memset (patchcount, 0, texture->width); patch = texture->patches; for (i=0 , patch = texture->patches; ipatchcount; i++, patch++) { realpatch = W_CacheLumpNum (patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1 < 0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for ( ; xpatch; colofs[x] = LONG(realpatch->columnofs[x-x1])+3; } } for (x=0 ; xwidth ; x++) { if (!patchcount[x]) { printf ("R_GenerateLookup: column without a patch (%s)\n", texture->name); return; } // I_Error ("R_GenerateLookup: column without a patch"); if (patchcount[x] > 1) { // Use the cached block. collump[x] = -1; colofs[x] = texturecompositesize[texnum]; if (texturecompositesize[texnum] > 0x10000-texture->height) { I_Error ("R_GenerateLookup: texture %i is >64k", texnum); } texturecompositesize[texnum] += texture->height; } } Z_Free(patchcount); } // // R_GetColumn // byte* R_GetColumn ( int tex, int col ) { int lump; int ofs; col &= texturewidthmask[tex]; lump = texturecolumnlump[tex][col]; ofs = texturecolumnofs[tex][col]; if (lump > 0) return (byte *)W_CacheLumpNum(lump,PU_CACHE)+ofs; if (!texturecomposite[tex]) R_GenerateComposite (tex); return texturecomposite[tex] + ofs; } static void GenerateTextureHashTable(void) { texture_t **rover; int i; int key; textures_hashtable = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0); memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures); // Add all textures to hash table for (i=0; iindex = i; // Vanilla Doom does a linear search of the texures array // and stops at the first entry it finds. If there are two // entries with the same name, the first one in the array // wins. The new entry must therefore be added at the end // of the hash chain, so that earlier entries win. key = W_LumpNameHash(textures[i]->name) % numtextures; rover = &textures_hashtable[key]; while (*rover != NULL) { rover = &(*rover)->next; } // Hook into hash table textures[i]->next = NULL; *rover = textures[i]; } } // // R_InitTextures // Initializes the texture list // with the textures from the world map. // void R_InitTextures (void) { maptexture_t* mtexture; texture_t* texture; mappatch_t* mpatch; texpatch_t* patch; int i; int j; int* maptex; int* maptex2; int* maptex1; char name[9]; char* names; char* name_p; int* patchlookup; int totalwidth; int nummappatches; int offset; int maxoff; int maxoff2; int numtextures1; int numtextures2; int* directory; int temp1; int temp2; int temp3; // Load the patch names from pnames.lmp. name[8] = 0; names = W_CacheLumpName (DEH_String("PNAMES"), PU_STATIC); nummappatches = LONG ( *((int *)names) ); name_p = names + 4; patchlookup = Z_Malloc(nummappatches*sizeof(*patchlookup), PU_STATIC, NULL); for (i = 0; i < nummappatches; i++) { M_StringCopy(name, name_p + i * 8, sizeof(name)); patchlookup[i] = W_CheckNumForName(name); } W_ReleaseLumpName(DEH_String("PNAMES")); // Load the map texture definitions from textures.lmp. // The data is contained in one or two lumps, // TEXTURE1 for shareware, plus TEXTURE2 for commercial. maptex = maptex1 = W_CacheLumpName (DEH_String("TEXTURE1"), PU_STATIC); numtextures1 = LONG(*maptex); maxoff = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE1"))); directory = maptex+1; if (W_CheckNumForName (DEH_String("TEXTURE2")) != -1) { maptex2 = W_CacheLumpName (DEH_String("TEXTURE2"), PU_STATIC); numtextures2 = LONG(*maptex2); maxoff2 = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE2"))); } else { maptex2 = NULL; numtextures2 = 0; maxoff2 = 0; } numtextures = numtextures1 + numtextures2; textures = Z_Malloc (numtextures * sizeof(*textures), PU_STATIC, 0); texturecolumnlump = Z_Malloc (numtextures * sizeof(*texturecolumnlump), PU_STATIC, 0); texturecolumnofs = Z_Malloc (numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0); texturecomposite = Z_Malloc (numtextures * sizeof(*texturecomposite), PU_STATIC, 0); texturecompositesize = Z_Malloc (numtextures * sizeof(*texturecompositesize), PU_STATIC, 0); texturewidthmask = Z_Malloc (numtextures * sizeof(*texturewidthmask), PU_STATIC, 0); textureheight = Z_Malloc (numtextures * sizeof(*textureheight), PU_STATIC, 0); totalwidth = 0; // Really complex printing shit... temp1 = W_GetNumForName (DEH_String("S_START")); // P_??????? temp2 = W_GetNumForName (DEH_String("S_END")) - 1; temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64); // If stdout is a real console, use the classic vanilla "filling // up the box" effect, which uses backspace to "step back" inside // the box. If stdout is a file, don't draw the box. if (I_ConsoleStdout()) { printf("["); for (i = 0; i < temp3 + 9; i++) printf(" "); printf("]"); for (i = 0; i < temp3 + 10; i++) printf("\b"); } for (i=0 ; i maxoff) I_Error ("R_InitTextures: bad texture directory"); mtexture = (maptexture_t *) ( (byte *)maptex + offset); texture = textures[i] = Z_Malloc (sizeof(texture_t) + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1), PU_STATIC, 0); texture->width = SHORT(mtexture->width); texture->height = SHORT(mtexture->height); texture->patchcount = SHORT(mtexture->patchcount); memcpy (texture->name, mtexture->name, sizeof(texture->name)); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; for (j=0 ; jpatchcount ; j++, mpatch++, patch++) { patch->originx = SHORT(mpatch->originx); patch->originy = SHORT(mpatch->originy); patch->patch = patchlookup[SHORT(mpatch->patch)]; if (patch->patch == -1) { I_Error ("R_InitTextures: Missing patch in texture %s", texture->name); } } texturecolumnlump[i] = Z_Malloc (texture->width*sizeof(**texturecolumnlump), PU_STATIC,0); texturecolumnofs[i] = Z_Malloc (texture->width*sizeof(**texturecolumnofs), PU_STATIC,0); j = 1; while (j*2 <= texture->width) j<<=1; texturewidthmask[i] = j-1; textureheight[i] = texture->height<width; } Z_Free(patchlookup); W_ReleaseLumpName(DEH_String("TEXTURE1")); if (maptex2) W_ReleaseLumpName(DEH_String("TEXTURE2")); // Precalculate whatever possible. for (i=0 ; iwidth)<leftoffset)<topoffset)<name, name, 8) ) return texture->index; texture = texture->next; } return -1; } // // R_TextureNumForName // Calls R_CheckTextureNumForName, // aborts with error message. // int R_TextureNumForName (char* name) { int i; i = R_CheckTextureNumForName (name); if (i==-1) { I_Error ("R_TextureNumForName: %s not found", name); } return i; } // // R_PrecacheLevel // Preloads all relevant graphics for the level. // int flatmemory; int texturememory; int spritememory; void R_PrecacheLevel (void) { char* flatpresent; char* texturepresent; char* spritepresent; int i; int j; int k; int lump; texture_t* texture; thinker_t* th; spriteframe_t* sf; if (demoplayback) return; // Precache flats. flatpresent = Z_Malloc(numflats, PU_STATIC, NULL); memset (flatpresent,0,numflats); for (i=0 ; ipatchcount ; j++) { lump = texture->patches[j].patch; texturememory += lumpinfo[lump].size; W_CacheLumpNum(lump , PU_CACHE); } } Z_Free(texturepresent); // Precache sprites. spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL); memset (spritepresent,0, numsprites); for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acp1 == (actionf_p1)P_MobjThinker) spritepresent[((mobj_t *)th)->sprite] = 1; } spritememory = 0; for (i=0 ; ilump[k]; spritememory += lumpinfo[lump].size; W_CacheLumpNum(lump , PU_CACHE); } } } Z_Free(spritepresent); } chocolate-doom-chocolate-doom-2.2.1/src/doom/r_data.h000066400000000000000000000023541257432200600224410ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh module, data I/O, caching, retrieval of graphics // by name. // #ifndef __R_DATA__ #define __R_DATA__ #include "r_defs.h" #include "r_state.h" // Retrieve column data for span blitting. byte* R_GetColumn ( int tex, int col ); // I/O, setting up the stuff. void R_InitData (void); void R_PrecacheLevel (void); // Retrieval. // Floor/ceiling opaque texture tiles, // lookup by name. For animation? int R_FlatNumForName (char* name); // Called by P_Ticker for switches and animations, // returns the texture number for the texture name. int R_TextureNumForName (char *name); int R_CheckTextureNumForName (char *name); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/r_defs.h000066400000000000000000000177131257432200600224560ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh/rendering module, shared data struct definitions. // #ifndef __R_DEFS__ #define __R_DEFS__ // Screenwidth. #include "doomdef.h" // Some more or less basic data types // we depend on. #include "m_fixed.h" // We rely on the thinker data struct // to handle sound origins in sectors. #include "d_think.h" // SECTORS do store MObjs anyway. #include "p_mobj.h" #include "i_video.h" #include "v_patch.h" // Silhouette, needed for clipping Segs (mainly) // and sprites representing things. #define SIL_NONE 0 #define SIL_BOTTOM 1 #define SIL_TOP 2 #define SIL_BOTH 3 #define MAXDRAWSEGS 256 // // INTERNAL MAP TYPES // used by play and refresh // // // Your plain vanilla vertex. // Note: transformed values not buffered locally, // like some DOOM-alikes ("wt", "WebView") did. // typedef struct { fixed_t x; fixed_t y; } vertex_t; // Forward of LineDefs, for Sectors. struct line_s; // Each sector has a degenmobj_t in its center // for sound origin purposes. // I suppose this does not handle sound from // moving objects (doppler), because // position is prolly just buffered, not // updated. typedef struct { thinker_t thinker; // not used for anything fixed_t x; fixed_t y; fixed_t z; } degenmobj_t; // // The SECTORS record, at runtime. // Stores things/mobjs. // typedef struct { fixed_t floorheight; fixed_t ceilingheight; short floorpic; short ceilingpic; short lightlevel; short special; short tag; // 0 = untraversed, 1,2 = sndlines -1 int soundtraversed; // thing that made a sound (or null) mobj_t* soundtarget; // mapblock bounding box for height changes int blockbox[4]; // origin for any sounds played by the sector degenmobj_t soundorg; // if == validcount, already checked int validcount; // list of mobjs in sector mobj_t* thinglist; // thinker_t for reversable actions void* specialdata; int linecount; struct line_s** lines; // [linecount] size } sector_t; // // The SideDef. // typedef struct { // add this to the calculated texture column fixed_t textureoffset; // add this to the calculated texture top fixed_t rowoffset; // Texture indices. // We do not maintain names here. short toptexture; short bottomtexture; short midtexture; // Sector the SideDef is facing. sector_t* sector; } side_t; // // Move clipping aid for LineDefs. // typedef enum { ST_HORIZONTAL, ST_VERTICAL, ST_POSITIVE, ST_NEGATIVE } slopetype_t; typedef struct line_s { // Vertices, from v1 to v2. vertex_t* v1; vertex_t* v2; // Precalculated v2 - v1 for side checking. fixed_t dx; fixed_t dy; // Animation related. short flags; short special; short tag; // Visual appearance: SideDefs. // sidenum[1] will be -1 if one sided short sidenum[2]; // Neat. Another bounding box, for the extent // of the LineDef. fixed_t bbox[4]; // To aid move clipping. slopetype_t slopetype; // Front and back sector. // Note: redundant? Can be retrieved from SideDefs. sector_t* frontsector; sector_t* backsector; // if == validcount, already checked int validcount; // thinker_t for reversable actions void* specialdata; } line_t; // // A SubSector. // References a Sector. // Basically, this is a list of LineSegs, // indicating the visible walls that define // (all or some) sides of a convex BSP leaf. // typedef struct subsector_s { sector_t* sector; short numlines; short firstline; } subsector_t; // // The LineSeg. // typedef struct { vertex_t* v1; vertex_t* v2; fixed_t offset; angle_t angle; side_t* sidedef; line_t* linedef; // Sector references. // Could be retrieved from linedef, too. // backsector is NULL for one sided lines sector_t* frontsector; sector_t* backsector; } seg_t; // // BSP node. // typedef struct { // Partition line. fixed_t x; fixed_t y; fixed_t dx; fixed_t dy; // Bounding box for each child. fixed_t bbox[2][4]; // If NF_SUBSECTOR its a subsector. unsigned short children[2]; } node_t; // PC direct to screen pointers //B UNUSED - keep till detailshift in r_draw.c resolved //extern byte* destview; //extern byte* destscreen; // // OTHER TYPES // // This could be wider for >8 bit display. // Indeed, true color support is posibble // precalculating 24bpp lightmap/colormap LUT. // from darkening PLAYPAL to all black. // Could even us emore than 32 levels. typedef byte lighttable_t; // // ? // typedef struct drawseg_s { seg_t* curline; int x1; int x2; fixed_t scale1; fixed_t scale2; fixed_t scalestep; // 0=none, 1=bottom, 2=top, 3=both int silhouette; // do not clip sprites above this fixed_t bsilheight; // do not clip sprites below this fixed_t tsilheight; // Pointers to lists for sprite clipping, // all three adjusted so [x1] is first value. short* sprtopclip; short* sprbottomclip; short* maskedtexturecol; } drawseg_t; // A vissprite_t is a thing // that will be drawn during a refresh. // I.e. a sprite object that is partly visible. typedef struct vissprite_s { // Doubly linked list. struct vissprite_s* prev; struct vissprite_s* next; int x1; int x2; // for line side calculation fixed_t gx; fixed_t gy; // global bottom / top for silhouette clipping fixed_t gz; fixed_t gzt; // horizontal position of x1 fixed_t startfrac; fixed_t scale; // negative if flipped fixed_t xiscale; fixed_t texturemid; int patch; // for color translation and shadow draw, // maxbright frames as well lighttable_t* colormap; int mobjflags; } vissprite_t; // // Sprites are patches with a special naming convention // so they can be recognized by R_InitSprites. // The base name is NNNNFx or NNNNFxFx, with // x indicating the rotation, x = 0, 1-7. // The sprite and frame specified by a thing_t // is range checked at run time. // A sprite is a patch_t that is assumed to represent // a three dimensional object and may have multiple // rotations pre drawn. // Horizontal flipping is used to save space, // thus NNNNF2F5 defines a mirrored patch. // Some sprites will only have one picture used // for all views: NNNNF0 // typedef struct { // If false use 0 for any position. // Note: as eight entries are available, // we might as well insert the same name eight times. boolean rotate; // Lump to use for view angles 0-7. short lump[8]; // Flip bit (1 = flip) to use for view angles 0-7. byte flip[8]; } spriteframe_t; // // A sprite definition: // a number of animation frames. // typedef struct { int numframes; spriteframe_t* spriteframes; } spritedef_t; // // Now what is a visplane, anyway? // typedef struct { fixed_t height; int picnum; int lightlevel; int minx; int maxx; // leave pads for [minx-1]/[maxx+1] byte pad1; // Here lies the rub for all // dynamic resize/change of resolution. byte top[SCREENWIDTH]; byte pad2; byte pad3; // See above. byte bottom[SCREENWIDTH]; byte pad4; } visplane_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/r_draw.c000066400000000000000000000523341257432200600224630ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The actual span/column drawing functions. // Here find the main potential for optimization, // e.g. inline assembly, different algorithms. // #include "doomdef.h" #include "deh_main.h" #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "r_local.h" // Needs access to LFB (guess what). #include "v_video.h" // State. #include "doomstat.h" // ? #define MAXWIDTH 1120 #define MAXHEIGHT 832 // status bar height at bottom of screen #define SBARHEIGHT 32 // // All drawing to the view buffer is accomplished in this file. // The other refresh files only know about ccordinates, // not the architecture of the frame buffer. // Conveniently, the frame buffer is a linear one, // and we need only the base address, // and the total size == width*height*depth/8., // byte* viewimage; int viewwidth; int scaledviewwidth; int viewheight; int viewwindowx; int viewwindowy; byte* ylookup[MAXHEIGHT]; int columnofs[MAXWIDTH]; // Color tables for different players, // translate a limited part to another // (color ramps used for suit colors). // byte translations[3][256]; // Backing buffer containing the bezel drawn around the screen and // surrounding background. static byte *background_buffer = NULL; // // R_DrawColumn // Source is the top of the column to scale. // lighttable_t* dc_colormap; int dc_x; int dc_yl; int dc_yh; fixed_t dc_iscale; fixed_t dc_texturemid; // first pixel in a column (possibly virtual) byte* dc_source; // just for profiling int dccount; // // A column is a vertical slice/span from a wall texture that, // given the DOOM style restrictions on the view orientation, // will always have constant z depth. // Thus a special case loop for very fast rendering can // be used. It has also been used with Wolfenstein 3D. // void R_DrawColumn (void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; count = dc_yh - dc_yl; // Zero length, column does not exceed a pixel. if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif // Framebuffer destination address. // Use ylookup LUT to avoid multiply with ScreenWidth. // Use columnofs LUT for subwindows? dest = ylookup[dc_yl] + columnofs[dc_x]; // Determine scaling, // which is the only mapping to be done. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Inner loop that does the actual texture mapping, // e.g. a DDA-lile scaling. // This is as fast as it gets. do { // Re-map color indices from wall texture column // using a lighting/special effects LUT. *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } // UNUSED. // Loop unrolled. #if 0 void R_DrawColumn (void) { int count; byte* source; byte* dest; byte* colormap; unsigned frac; unsigned fracstep; unsigned fracstep2; unsigned fracstep3; unsigned fracstep4; count = dc_yh - dc_yl + 1; source = dc_source; colormap = dc_colormap; dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale<<9; frac = (dc_texturemid + (dc_yl-centery)*dc_iscale)<<9; fracstep2 = fracstep+fracstep; fracstep3 = fracstep2+fracstep; fracstep4 = fracstep3+fracstep; while (count >= 8) { dest[0] = colormap[source[frac>>25]]; dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]]; dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]]; dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]]; frac += fracstep4; dest[SCREENWIDTH*4] = colormap[source[frac>>25]]; dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]]; dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]]; dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]]; frac += fracstep4; dest += SCREENWIDTH*8; count -= 8; } while (count > 0) { *dest = colormap[source[frac>>25]]; dest += SCREENWIDTH; frac += fracstep; count--; } } #endif void R_DrawColumnLow (void) { int count; byte* dest; byte* dest2; fixed_t frac; fixed_t fracstep; int x; count = dc_yh - dc_yl; // Zero length. if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); } // dccount++; #endif // Blocky mode, need to multiply by 2. x = dc_x << 1; dest = ylookup[dc_yl] + columnofs[x]; dest2 = ylookup[dc_yl] + columnofs[x+1]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; do { // Hack. Does not work corretly. *dest2 = *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; dest += SCREENWIDTH; dest2 += SCREENWIDTH; frac += fracstep; } while (count--); } // // Spectre/Invisibility. // #define FUZZTABLE 50 #define FUZZOFF (SCREENWIDTH) int fuzzoffset[FUZZTABLE] = { FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF, FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF, FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF, FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF }; int fuzzpos = 0; // // Framebuffer postprocessing. // Creates a fuzzy image by copying pixels // from adjacent ones to left and right. // Used with an all black colormap, this // could create the SHADOW effect, // i.e. spectres and invisible players. // void R_DrawFuzzColumn (void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; // Adjust borders. Low... if (!dc_yl) dc_yl = 1; // .. and high. if (dc_yh == viewheight-1) dc_yh = viewheight - 2; count = dc_yh - dc_yl; // Zero length. if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); } #endif dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Looks like an attempt at dithering, // using the colormap #6 (of 0-31, a bit // brighter than average). do { // Lookup framebuffer, and retrieve // a pixel that is either one column // left or right of the current one. // Add index from colormap to index. *dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]]; // Clamp table lookup index. if (++fuzzpos == FUZZTABLE) fuzzpos = 0; dest += SCREENWIDTH; frac += fracstep; } while (count--); } // low detail mode version void R_DrawFuzzColumnLow (void) { int count; byte* dest; byte* dest2; fixed_t frac; fixed_t fracstep; int x; // Adjust borders. Low... if (!dc_yl) dc_yl = 1; // .. and high. if (dc_yh == viewheight-1) dc_yh = viewheight - 2; count = dc_yh - dc_yl; // Zero length. if (count < 0) return; // low detail mode, need to multiply by 2 x = dc_x << 1; #ifdef RANGECHECK if ((unsigned)x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); } #endif dest = ylookup[dc_yl] + columnofs[x]; dest2 = ylookup[dc_yl] + columnofs[x+1]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Looks like an attempt at dithering, // using the colormap #6 (of 0-31, a bit // brighter than average). do { // Lookup framebuffer, and retrieve // a pixel that is either one column // left or right of the current one. // Add index from colormap to index. *dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]]; *dest2 = colormaps[6*256+dest2[fuzzoffset[fuzzpos]]]; // Clamp table lookup index. if (++fuzzpos == FUZZTABLE) fuzzpos = 0; dest += SCREENWIDTH; dest2 += SCREENWIDTH; frac += fracstep; } while (count--); } // // R_DrawTranslatedColumn // Used to draw player sprites // with the green colorramp mapped to others. // Could be used with different translation // tables, e.g. the lighter colored version // of the BaronOfHell, the HellKnight, uses // identical sprites, kinda brightened up. // byte* dc_translation; byte* translationtables; void R_DrawTranslatedColumn (void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ( "R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); } #endif dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Here we do an additional index re-mapping. do { // Translation tables are used // to map certain colorramps to other ones, // used with PLAY sprites. // Thus the "green" ramp of the player 0 sprite // is mapped to gray, red, black/indigo. *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } void R_DrawTranslatedColumnLow (void) { int count; byte* dest; byte* dest2; fixed_t frac; fixed_t fracstep; int x; count = dc_yh - dc_yl; if (count < 0) return; // low detail, need to scale by 2 x = dc_x << 1; #ifdef RANGECHECK if ((unsigned)x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ( "R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, x); } #endif dest = ylookup[dc_yl] + columnofs[x]; dest2 = ylookup[dc_yl] + columnofs[x+1]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Here we do an additional index re-mapping. do { // Translation tables are used // to map certain colorramps to other ones, // used with PLAY sprites. // Thus the "green" ramp of the player 0 sprite // is mapped to gray, red, black/indigo. *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; *dest2 = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; dest += SCREENWIDTH; dest2 += SCREENWIDTH; frac += fracstep; } while (count--); } // // R_InitTranslationTables // Creates the translation tables to map // the green color ramp to gray, brown, red. // Assumes a given structure of the PLAYPAL. // Could be read from a lump instead. // void R_InitTranslationTables (void) { int i; translationtables = Z_Malloc (256*3, PU_STATIC, 0); // translate just the 16 green colors for (i=0 ; i<256 ; i++) { if (i >= 0x70 && i<= 0x7f) { // map green ramp to gray, brown, red translationtables[i] = 0x60 + (i&0xf); translationtables [i+256] = 0x40 + (i&0xf); translationtables [i+512] = 0x20 + (i&0xf); } else { // Keep all other colors as is. translationtables[i] = translationtables[i+256] = translationtables[i+512] = i; } } } // // R_DrawSpan // With DOOM style restrictions on view orientation, // the floors and ceilings consist of horizontal slices // or spans with constant z depth. // However, rotation around the world z axis is possible, // thus this mapping, while simpler and faster than // perspective correct texture mapping, has to traverse // the texture at an angle in all but a few cases. // In consequence, flats are not stored by column (like walls), // and the inner loop has to step in texture space u and v. // int ds_y; int ds_x1; int ds_x2; lighttable_t* ds_colormap; fixed_t ds_xfrac; fixed_t ds_yfrac; fixed_t ds_xstep; fixed_t ds_ystep; // start of a 64*64 tile image byte* ds_source; // just for profiling int dscount; // // Draws the actual span. void R_DrawSpan (void) { unsigned int position, step; byte *dest; int count; int spot; unsigned int xtemp, ytemp; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1<0 || ds_x2>=SCREENWIDTH || (unsigned)ds_y>SCREENHEIGHT) { I_Error( "R_DrawSpan: %i to %i at %i", ds_x1,ds_x2,ds_y); } // dscount++; #endif // Pack position and step variables into a single 32-bit integer, // with x in the top 16 bits and y in the bottom 16 bits. For // each 16-bit part, the top 6 bits are the integer part and the // bottom 10 bits are the fractional part of the pixel position. position = ((ds_xfrac << 10) & 0xffff0000) | ((ds_yfrac >> 6) & 0x0000ffff); step = ((ds_xstep << 10) & 0xffff0000) | ((ds_ystep >> 6) & 0x0000ffff); dest = ylookup[ds_y] + columnofs[ds_x1]; // We do not check for zero spans here? count = ds_x2 - ds_x1; do { // Calculate current texture index in u,v. ytemp = (position >> 4) & 0x0fc0; xtemp = (position >> 26); spot = xtemp | ytemp; // Lookup pixel from flat texture tile, // re-index using light/colormap. *dest++ = ds_colormap[ds_source[spot]]; position += step; } while (count--); } // UNUSED. // Loop unrolled by 4. #if 0 void R_DrawSpan (void) { unsigned position, step; byte* source; byte* colormap; byte* dest; unsigned count; usingned spot; unsigned value; unsigned temp; unsigned xtemp; unsigned ytemp; position = ((ds_xfrac<<10)&0xffff0000) | ((ds_yfrac>>6)&0xffff); step = ((ds_xstep<<10)&0xffff0000) | ((ds_ystep>>6)&0xffff); source = ds_source; colormap = ds_colormap; dest = ylookup[ds_y] + columnofs[ds_x1]; count = ds_x2 - ds_x1 + 1; while (count >= 4) { ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[0] = colormap[source[spot]]; ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[1] = colormap[source[spot]]; ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[2] = colormap[source[spot]]; ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[3] = colormap[source[spot]]; count -= 4; dest += 4; } while (count > 0) { ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; *dest++ = colormap[source[spot]]; count--; } } #endif // // Again.. // void R_DrawSpanLow (void) { unsigned int position, step; unsigned int xtemp, ytemp; byte *dest; int count; int spot; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1<0 || ds_x2>=SCREENWIDTH || (unsigned)ds_y>SCREENHEIGHT) { I_Error( "R_DrawSpan: %i to %i at %i", ds_x1,ds_x2,ds_y); } // dscount++; #endif position = ((ds_xfrac << 10) & 0xffff0000) | ((ds_yfrac >> 6) & 0x0000ffff); step = ((ds_xstep << 10) & 0xffff0000) | ((ds_ystep >> 6) & 0x0000ffff); count = (ds_x2 - ds_x1); // Blocky mode, need to multiply by 2. ds_x1 <<= 1; ds_x2 <<= 1; dest = ylookup[ds_y] + columnofs[ds_x1]; do { // Calculate current texture index in u,v. ytemp = (position >> 4) & 0x0fc0; xtemp = (position >> 26); spot = xtemp | ytemp; // Lowres/blocky mode does it twice, // while scale is adjusted appropriately. *dest++ = ds_colormap[ds_source[spot]]; *dest++ = ds_colormap[ds_source[spot]]; position += step; } while (count--); } // // R_InitBuffer // Creats lookup tables that avoid // multiplies and other hazzles // for getting the framebuffer address // of a pixel to draw. // void R_InitBuffer ( int width, int height ) { int i; // Handle resize, // e.g. smaller view windows // with border and/or status bar. viewwindowx = (SCREENWIDTH-width) >> 1; // Column offset. For windows. for (i=0 ; i> 1; // Preclaculate all row offsets. for (i=0 ; i #include #include "doomdef.h" #include "d_loop.h" #include "m_bbox.h" #include "m_menu.h" #include "r_local.h" #include "r_sky.h" // Fineangles in the SCREENWIDTH wide window. #define FIELDOFVIEW 2048 int viewangleoffset; // increment every time a check is made int validcount = 1; lighttable_t* fixedcolormap; extern lighttable_t** walllights; int centerx; int centery; fixed_t centerxfrac; fixed_t centeryfrac; fixed_t projection; // just for profiling purposes int framecount; int sscount; int linecount; int loopcount; fixed_t viewx; fixed_t viewy; fixed_t viewz; angle_t viewangle; fixed_t viewcos; fixed_t viewsin; player_t* viewplayer; // 0 = high, 1 = low int detailshift; // // precalculated math tables // angle_t clipangle; // The viewangletox[viewangle + FINEANGLES/4] lookup // maps the visible view angles to screen X coordinates, // flattening the arc to a flat projection plane. // There will be many angles mapped to the same X. int viewangletox[FINEANGLES/2]; // The xtoviewangleangle[] table maps a screen pixel // to the lowest viewangle that maps back to x ranges // from clipangle to -clipangle. angle_t xtoviewangle[SCREENWIDTH+1]; lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; lighttable_t* scalelightfixed[MAXLIGHTSCALE]; lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ]; // bumped light from gun blasts int extralight; void (*colfunc) (void); void (*basecolfunc) (void); void (*fuzzcolfunc) (void); void (*transcolfunc) (void); void (*spanfunc) (void); // // R_AddPointToBox // Expand a given bbox // so that it encloses a given point. // void R_AddPointToBox ( int x, int y, fixed_t* box ) { if (x< box[BOXLEFT]) box[BOXLEFT] = x; if (x> box[BOXRIGHT]) box[BOXRIGHT] = x; if (y< box[BOXBOTTOM]) box[BOXBOTTOM] = y; if (y> box[BOXTOP]) box[BOXTOP] = y; } // // R_PointOnSide // Traverse BSP (sub) tree, // check point against partition plane. // Returns side 0 (front) or 1 (back). // int R_PointOnSide ( fixed_t x, fixed_t y, node_t* node ) { fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; if (!node->dx) { if (x <= node->x) return node->dy > 0; return node->dy < 0; } if (!node->dy) { if (y <= node->y) return node->dx < 0; return node->dx > 0; } dx = (x - node->x); dy = (y - node->y); // Try to quickly decide by looking at sign bits. if ( (node->dy ^ node->dx ^ dx ^ dy)&0x80000000 ) { if ( (node->dy ^ dx) & 0x80000000 ) { // (left is negative) return 1; } return 0; } left = FixedMul ( node->dy>>FRACBITS , dx ); right = FixedMul ( dy , node->dx>>FRACBITS ); if (right < left) { // front side return 0; } // back side return 1; } int R_PointOnSegSide ( fixed_t x, fixed_t y, seg_t* line ) { fixed_t lx; fixed_t ly; fixed_t ldx; fixed_t ldy; fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; lx = line->v1->x; ly = line->v1->y; ldx = line->v2->x - lx; ldy = line->v2->y - ly; if (!ldx) { if (x <= lx) return ldy > 0; return ldy < 0; } if (!ldy) { if (y <= ly) return ldx < 0; return ldx > 0; } dx = (x - lx); dy = (y - ly); // Try to quickly decide by looking at sign bits. if ( (ldy ^ ldx ^ dx ^ dy)&0x80000000 ) { if ( (ldy ^ dx) & 0x80000000 ) { // (left is negative) return 1; } return 0; } left = FixedMul ( ldy>>FRACBITS , dx ); right = FixedMul ( dy , ldx>>FRACBITS ); if (right < left) { // front side return 0; } // back side return 1; } // // R_PointToAngle // To get a global angle from cartesian coordinates, // the coordinates are flipped until they are in // the first octant of the coordinate system, then // the y (<=x) is scaled and divided by x to get a // tangent (slope) value which is looked up in the // tantoangle[] table. // angle_t R_PointToAngle ( fixed_t x, fixed_t y ) { x -= viewx; y -= viewy; if ( (!x) && (!y) ) return 0; if (x>= 0) { // x >=0 if (y>= 0) { // y>= 0 if (x>y) { // octant 0 return tantoangle[ SlopeDiv(y,x)]; } else { // octant 1 return ANG90-1-tantoangle[ SlopeDiv(x,y)]; } } else { // y<0 y = -y; if (x>y) { // octant 8 return -tantoangle[SlopeDiv(y,x)]; } else { // octant 7 return ANG270+tantoangle[ SlopeDiv(x,y)]; } } } else { // x<0 x = -x; if (y>= 0) { // y>= 0 if (x>y) { // octant 3 return ANG180-1-tantoangle[ SlopeDiv(y,x)]; } else { // octant 2 return ANG90+ tantoangle[ SlopeDiv(x,y)]; } } else { // y<0 y = -y; if (x>y) { // octant 4 return ANG180+tantoangle[ SlopeDiv(y,x)]; } else { // octant 5 return ANG270-1-tantoangle[ SlopeDiv(x,y)]; } } } return 0; } angle_t R_PointToAngle2 ( fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2 ) { viewx = x1; viewy = y1; return R_PointToAngle (x2, y2); } fixed_t R_PointToDist ( fixed_t x, fixed_t y ) { int angle; fixed_t dx; fixed_t dy; fixed_t temp; fixed_t dist; fixed_t frac; dx = abs(x - viewx); dy = abs(y - viewy); if (dy>dx) { temp = dx; dx = dy; dy = temp; } // Fix crashes in udm1.wad if (dx != 0) { frac = FixedDiv(dy, dx); } else { frac = 0; } angle = (tantoangle[frac>>DBITS]+ANG90) >> ANGLETOFINESHIFT; // use as cosine dist = FixedDiv (dx, finesine[angle] ); return dist; } // // R_InitPointToAngle // void R_InitPointToAngle (void) { // UNUSED - now getting from tables.c #if 0 int i; long t; float f; // // slope (tangent) to angle lookup // for (i=0 ; i<=SLOPERANGE ; i++) { f = atan( (float)i/SLOPERANGE )/(3.141592657*2); t = 0xffffffff*f; tantoangle[i] = t; } #endif } // // R_ScaleFromGlobalAngle // Returns the texture mapping scale // for the current line (horizontal span) // at the given angle. // rw_distance must be calculated first. // fixed_t R_ScaleFromGlobalAngle (angle_t visangle) { fixed_t scale; angle_t anglea; angle_t angleb; int sinea; int sineb; fixed_t num; int den; // UNUSED #if 0 { fixed_t dist; fixed_t z; fixed_t sinv; fixed_t cosv; sinv = finesine[(visangle-rw_normalangle)>>ANGLETOFINESHIFT]; dist = FixedDiv (rw_distance, sinv); cosv = finecosine[(viewangle-visangle)>>ANGLETOFINESHIFT]; z = abs(FixedMul (dist, cosv)); scale = FixedDiv(projection, z); return scale; } #endif anglea = ANG90 + (visangle-viewangle); angleb = ANG90 + (visangle-rw_normalangle); // both sines are allways positive sinea = finesine[anglea>>ANGLETOFINESHIFT]; sineb = finesine[angleb>>ANGLETOFINESHIFT]; num = FixedMul(projection,sineb)< num>>16) { scale = FixedDiv (num, den); if (scale > 64*FRACUNIT) scale = 64*FRACUNIT; else if (scale < 256) scale = 256; } else scale = 64*FRACUNIT; return scale; } // // R_InitTables // void R_InitTables (void) { // UNUSED: now getting from tables.c #if 0 int i; float a; float fv; int t; // viewangle tangent table for (i=0 ; i FRACUNIT*2) t = -1; else if (finetangent[i] < -FRACUNIT*2) t = viewwidth+1; else { t = FixedMul (finetangent[i], focallength); t = (centerxfrac - t+FRACUNIT-1)>>FRACBITS; if (t < -1) t = -1; else if (t>viewwidth+1) t = viewwidth+1; } viewangletox[i] = t; } // Scan viewangletox[] to generate xtoviewangle[]: // xtoviewangle will give the smallest view angle // that maps to x. for (x=0;x<=viewwidth;x++) { i = 0; while (viewangletox[i]>x) i++; xtoviewangle[x] = (i<>= LIGHTSCALESHIFT; level = startmap - scale/DISTMAP; if (level < 0) level = 0; if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS-1; zlight[i][j] = colormaps + level*256; } } } // // R_SetViewSize // Do not really change anything here, // because it might be in the middle of a refresh. // The change will take effect next refresh. // boolean setsizeneeded; int setblocks; int setdetail; void R_SetViewSize ( int blocks, int detail ) { setsizeneeded = true; setblocks = blocks; setdetail = detail; } // // R_ExecuteSetViewSize // void R_ExecuteSetViewSize (void) { fixed_t cosadj; fixed_t dy; int i; int j; int level; int startmap; setsizeneeded = false; if (setblocks == 11) { scaledviewwidth = SCREENWIDTH; viewheight = SCREENHEIGHT; } else { scaledviewwidth = setblocks*32; viewheight = (setblocks*168/10)&~7; } detailshift = setdetail; viewwidth = scaledviewwidth>>detailshift; centery = viewheight/2; centerx = viewwidth/2; centerxfrac = centerx<>ANGLETOFINESHIFT]); distscale[i] = FixedDiv (FRACUNIT,cosadj); } // Calculate the light levels to use // for each level / scale combination. for (i=0 ; i< LIGHTLEVELS ; i++) { startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS; for (j=0 ; j= NUMCOLORMAPS) level = NUMCOLORMAPS-1; scalelight[i][j] = colormaps + level*256; } } } // // R_Init // void R_Init (void) { R_InitData (); printf ("."); R_InitPointToAngle (); printf ("."); R_InitTables (); // viewwidth / viewheight / detailLevel are set by the defaults printf ("."); R_SetViewSize (screenblocks, detailLevel); R_InitPlanes (); printf ("."); R_InitLightTables (); printf ("."); R_InitSkyMap (); R_InitTranslationTables (); printf ("."); framecount = 0; } // // R_PointInSubsector // subsector_t* R_PointInSubsector ( fixed_t x, fixed_t y ) { node_t* node; int side; int nodenum; // single subsector is a special case if (!numnodes) return subsectors; nodenum = numnodes-1; while (! (nodenum & NF_SUBSECTOR) ) { node = &nodes[nodenum]; side = R_PointOnSide (x, y, node); nodenum = node->children[side]; } return &subsectors[nodenum & ~NF_SUBSECTOR]; } // // R_SetupFrame // void R_SetupFrame (player_t* player) { int i; viewplayer = player; viewx = player->mo->x; viewy = player->mo->y; viewangle = player->mo->angle + viewangleoffset; extralight = player->extralight; viewz = player->viewz; viewsin = finesine[viewangle>>ANGLETOFINESHIFT]; viewcos = finecosine[viewangle>>ANGLETOFINESHIFT]; sscount = 0; if (player->fixedcolormap) { fixedcolormap = colormaps + player->fixedcolormap*256*sizeof(lighttable_t); walllights = scalelightfixed; for (i=0 ; i #include #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "doomdef.h" #include "doomstat.h" #include "r_local.h" #include "r_sky.h" planefunction_t floorfunc; planefunction_t ceilingfunc; // // opening // // Here comes the obnoxious "visplane". #define MAXVISPLANES 128 visplane_t visplanes[MAXVISPLANES]; visplane_t* lastvisplane; visplane_t* floorplane; visplane_t* ceilingplane; // ? #define MAXOPENINGS SCREENWIDTH*64 short openings[MAXOPENINGS]; short* lastopening; // // Clip values are the solid pixel bounding the range. // floorclip starts out SCREENHEIGHT // ceilingclip starts out -1 // short floorclip[SCREENWIDTH]; short ceilingclip[SCREENWIDTH]; // // spanstart holds the start of a plane span // initialized to 0 at start // int spanstart[SCREENHEIGHT]; int spanstop[SCREENHEIGHT]; // // texture mapping // lighttable_t** planezlight; fixed_t planeheight; fixed_t yslope[SCREENHEIGHT]; fixed_t distscale[SCREENWIDTH]; fixed_t basexscale; fixed_t baseyscale; fixed_t cachedheight[SCREENHEIGHT]; fixed_t cacheddistance[SCREENHEIGHT]; fixed_t cachedxstep[SCREENHEIGHT]; fixed_t cachedystep[SCREENHEIGHT]; // // R_InitPlanes // Only at game startup. // void R_InitPlanes (void) { // Doh! } // // R_MapPlane // // Uses global vars: // planeheight // ds_source // basexscale // baseyscale // viewx // viewy // // BASIC PRIMITIVE // void R_MapPlane ( int y, int x1, int x2 ) { angle_t angle; fixed_t distance; fixed_t length; unsigned index; #ifdef RANGECHECK if (x2 < x1 || x1 < 0 || x2 >= viewwidth || y > viewheight) { I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y); } #endif if (planeheight != cachedheight[y]) { cachedheight[y] = planeheight; distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]); ds_xstep = cachedxstep[y] = FixedMul (distance,basexscale); ds_ystep = cachedystep[y] = FixedMul (distance,baseyscale); } else { distance = cacheddistance[y]; ds_xstep = cachedxstep[y]; ds_ystep = cachedystep[y]; } length = FixedMul (distance,distscale[x1]); angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; ds_xfrac = viewx + FixedMul(finecosine[angle], length); ds_yfrac = -viewy - FixedMul(finesine[angle], length); if (fixedcolormap) ds_colormap = fixedcolormap; else { index = distance >> LIGHTZSHIFT; if (index >= MAXLIGHTZ ) index = MAXLIGHTZ-1; ds_colormap = planezlight[index]; } ds_y = y; ds_x1 = x1; ds_x2 = x2; // high or low detail spanfunc (); } // // R_ClearPlanes // At begining of frame. // void R_ClearPlanes (void) { int i; angle_t angle; // opening / clipping determination for (i=0 ; i>ANGLETOFINESHIFT; // scale will be unit scale at SCREENWIDTH/2 distance basexscale = FixedDiv (finecosine[angle],centerxfrac); baseyscale = -FixedDiv (finesine[angle],centerxfrac); } // // R_FindPlane // visplane_t* R_FindPlane ( fixed_t height, int picnum, int lightlevel ) { visplane_t* check; if (picnum == skyflatnum) { height = 0; // all skys map together lightlevel = 0; } for (check=visplanes; checkheight && picnum == check->picnum && lightlevel == check->lightlevel) { break; } } if (check < lastvisplane) return check; if (lastvisplane - visplanes == MAXVISPLANES) I_Error ("R_FindPlane: no more visplanes"); lastvisplane++; check->height = height; check->picnum = picnum; check->lightlevel = lightlevel; check->minx = SCREENWIDTH; check->maxx = -1; memset (check->top,0xff,sizeof(check->top)); return check; } // // R_CheckPlane // visplane_t* R_CheckPlane ( visplane_t* pl, int start, int stop ) { int intrl; int intrh; int unionl; int unionh; int x; if (start < pl->minx) { intrl = pl->minx; unionl = start; } else { unionl = pl->minx; intrl = start; } if (stop > pl->maxx) { intrh = pl->maxx; unionh = stop; } else { unionh = pl->maxx; intrh = stop; } for (x=intrl ; x<= intrh ; x++) if (pl->top[x] != 0xff) break; if (x > intrh) { pl->minx = unionl; pl->maxx = unionh; // use the same one return pl; } // make a new visplane lastvisplane->height = pl->height; lastvisplane->picnum = pl->picnum; lastvisplane->lightlevel = pl->lightlevel; pl = lastvisplane++; pl->minx = start; pl->maxx = stop; memset (pl->top,0xff,sizeof(pl->top)); return pl; } // // R_MakeSpans // void R_MakeSpans ( int x, int t1, int b1, int t2, int b2 ) { while (t1 < t2 && t1<=b1) { R_MapPlane (t1,spanstart[t1],x-1); t1++; } while (b1 > b2 && b1>=t1) { R_MapPlane (b1,spanstart[b1],x-1); b1--; } while (t2 < t1 && t2<=b2) { spanstart[t2] = x; t2++; } while (b2 > b1 && b2>=t2) { spanstart[b2] = x; b2--; } } // // R_DrawPlanes // At the end of each frame. // void R_DrawPlanes (void) { visplane_t* pl; int light; int x; int stop; int angle; int lumpnum; #ifdef RANGECHECK if (ds_p - drawsegs > MAXDRAWSEGS) I_Error ("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs); if (lastvisplane - visplanes > MAXVISPLANES) I_Error ("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes); if (lastopening - openings > MAXOPENINGS) I_Error ("R_DrawPlanes: opening overflow (%i)", lastopening - openings); #endif for (pl = visplanes ; pl < lastvisplane ; pl++) { if (pl->minx > pl->maxx) continue; // sky flat if (pl->picnum == skyflatnum) { dc_iscale = pspriteiscale>>detailshift; // Sky is allways drawn full bright, // i.e. colormaps[0] is used. // Because of this hack, sky is not affected // by INVUL inverse mapping. dc_colormap = colormaps; dc_texturemid = skytexturemid; for (x=pl->minx ; x <= pl->maxx ; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; if (dc_yl <= dc_yh) { angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; dc_x = x; dc_source = R_GetColumn(skytexture, angle); colfunc (); } } continue; } // regular flat lumpnum = firstflat + flattranslation[pl->picnum]; ds_source = W_CacheLumpNum(lumpnum, PU_STATIC); planeheight = abs(pl->height-viewz); light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight; if (light >= LIGHTLEVELS) light = LIGHTLEVELS-1; if (light < 0) light = 0; planezlight = zlight[light]; pl->top[pl->maxx+1] = 0xff; pl->top[pl->minx-1] = 0xff; stop = pl->maxx + 1; for (x=pl->minx ; x<= stop ; x++) { R_MakeSpans(x,pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x]); } W_ReleaseLumpNum(lumpnum); } } chocolate-doom-chocolate-doom-2.2.1/src/doom/r_plane.h000066400000000000000000000026271257432200600226320ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh, visplane stuff (floor, ceilings). // #ifndef __R_PLANE__ #define __R_PLANE__ #include "r_data.h" // Visplane related. extern short* lastopening; typedef void (*planefunction_t) (int top, int bottom); extern planefunction_t floorfunc; extern planefunction_t ceilingfunc_t; extern short floorclip[SCREENWIDTH]; extern short ceilingclip[SCREENWIDTH]; extern fixed_t yslope[SCREENHEIGHT]; extern fixed_t distscale[SCREENWIDTH]; void R_InitPlanes (void); void R_ClearPlanes (void); void R_MapPlane ( int y, int x1, int x2 ); void R_MakeSpans ( int x, int t1, int b1, int t2, int b2 ); void R_DrawPlanes (void); visplane_t* R_FindPlane ( fixed_t height, int picnum, int lightlevel ); visplane_t* R_CheckPlane ( visplane_t* pl, int start, int stop ); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/r_segs.c000066400000000000000000000407721257432200600224720ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // All the clipping: columns, horizontal spans, sky columns. // #include #include #include "i_system.h" #include "doomdef.h" #include "doomstat.h" #include "r_local.h" #include "r_sky.h" // OPTIMIZE: closed two sided lines as single sided // True if any of the segs textures might be visible. boolean segtextured; // False if the back side is the same plane. boolean markfloor; boolean markceiling; boolean maskedtexture; int toptexture; int bottomtexture; int midtexture; angle_t rw_normalangle; // angle to line origin int rw_angle1; // // regular wall // int rw_x; int rw_stopx; angle_t rw_centerangle; fixed_t rw_offset; fixed_t rw_distance; fixed_t rw_scale; fixed_t rw_scalestep; fixed_t rw_midtexturemid; fixed_t rw_toptexturemid; fixed_t rw_bottomtexturemid; int worldtop; int worldbottom; int worldhigh; int worldlow; fixed_t pixhigh; fixed_t pixlow; fixed_t pixhighstep; fixed_t pixlowstep; fixed_t topfrac; fixed_t topstep; fixed_t bottomfrac; fixed_t bottomstep; lighttable_t** walllights; short* maskedtexturecol; // // R_RenderMaskedSegRange // void R_RenderMaskedSegRange ( drawseg_t* ds, int x1, int x2 ) { unsigned index; column_t* col; int lightnum; int texnum; // Calculate light table. // Use different light tables // for horizontal / vertical / diagonal. Diagonal? // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; frontsector = curline->frontsector; backsector = curline->backsector; texnum = texturetranslation[curline->sidedef->midtexture]; lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight; if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS-1]; else walllights = scalelight[lightnum]; maskedtexturecol = ds->maskedtexturecol; rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; mfloorclip = ds->sprbottomclip; mceilingclip = ds->sprtopclip; // find positioning if (curline->linedef->flags & ML_DONTPEGBOTTOM) { dc_texturemid = frontsector->floorheight > backsector->floorheight ? frontsector->floorheight : backsector->floorheight; dc_texturemid = dc_texturemid + textureheight[texnum] - viewz; } else { dc_texturemid =frontsector->ceilingheightceilingheight ? frontsector->ceilingheight : backsector->ceilingheight; dc_texturemid = dc_texturemid - viewz; } dc_texturemid += curline->sidedef->rowoffset; if (fixedcolormap) dc_colormap = fixedcolormap; // draw the columns for (dc_x = x1 ; dc_x <= x2 ; dc_x++) { // calculate lighting if (maskedtexturecol[dc_x] != SHRT_MAX) { if (!fixedcolormap) { index = spryscale>>LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE ) index = MAXLIGHTSCALE-1; dc_colormap = walllights[index]; } sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); dc_iscale = 0xffffffffu / (unsigned)spryscale; // draw the texture col = (column_t *)( (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3); R_DrawMaskedColumn (col); maskedtexturecol[dc_x] = SHRT_MAX; } spryscale += rw_scalestep; } } // // R_RenderSegLoop // Draws zero, one, or two textures (and possibly a masked // texture) for walls. // Can draw or mark the starting pixel of floor and ceiling // textures. // CALLED: CORE LOOPING ROUTINE. // #define HEIGHTBITS 12 #define HEIGHTUNIT (1<>HEIGHTBITS; // no space above wall? if (yl < ceilingclip[rw_x]+1) yl = ceilingclip[rw_x]+1; if (markceiling) { top = ceilingclip[rw_x]+1; bottom = yl-1; if (bottom >= floorclip[rw_x]) bottom = floorclip[rw_x]-1; if (top <= bottom) { ceilingplane->top[rw_x] = top; ceilingplane->bottom[rw_x] = bottom; } } yh = bottomfrac>>HEIGHTBITS; if (yh >= floorclip[rw_x]) yh = floorclip[rw_x]-1; if (markfloor) { top = yh+1; bottom = floorclip[rw_x]-1; if (top <= ceilingclip[rw_x]) top = ceilingclip[rw_x]+1; if (top <= bottom) { floorplane->top[rw_x] = top; floorplane->bottom[rw_x] = bottom; } } // texturecolumn and lighting are independent of wall tiers if (segtextured) { // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT; texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance); texturecolumn >>= FRACBITS; // calculate lighting index = rw_scale>>LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE ) index = MAXLIGHTSCALE-1; dc_colormap = walllights[index]; dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned)rw_scale; } else { // purely to shut up the compiler texturecolumn = 0; } // draw the wall tiers if (midtexture) { // single sided line dc_yl = yl; dc_yh = yh; dc_texturemid = rw_midtexturemid; dc_source = R_GetColumn(midtexture,texturecolumn); colfunc (); ceilingclip[rw_x] = viewheight; floorclip[rw_x] = -1; } else { // two sided line if (toptexture) { // top wall mid = pixhigh>>HEIGHTBITS; pixhigh += pixhighstep; if (mid >= floorclip[rw_x]) mid = floorclip[rw_x]-1; if (mid >= yl) { dc_yl = yl; dc_yh = mid; dc_texturemid = rw_toptexturemid; dc_source = R_GetColumn(toptexture,texturecolumn); colfunc (); ceilingclip[rw_x] = mid; } else ceilingclip[rw_x] = yl-1; } else { // no top wall if (markceiling) ceilingclip[rw_x] = yl-1; } if (bottomtexture) { // bottom wall mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS; pixlow += pixlowstep; // no space above wall? if (mid <= ceilingclip[rw_x]) mid = ceilingclip[rw_x]+1; if (mid <= yh) { dc_yl = mid; dc_yh = yh; dc_texturemid = rw_bottomtexturemid; dc_source = R_GetColumn(bottomtexture, texturecolumn); colfunc (); floorclip[rw_x] = mid; } else floorclip[rw_x] = yh+1; } else { // no bottom wall if (markfloor) floorclip[rw_x] = yh+1; } if (maskedtexture) { // save texturecol // for backdrawing of masked mid texture maskedtexturecol[rw_x] = texturecolumn; } } rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; } } // // R_StoreWallRange // A wall segment will be drawn // between start and stop pixels (inclusive). // void R_StoreWallRange ( int start, int stop ) { fixed_t hyp; fixed_t sineval; angle_t distangle, offsetangle; fixed_t vtop; int lightnum; // don't overflow and crash if (ds_p == &drawsegs[MAXDRAWSEGS]) return; #ifdef RANGECHECK if (start >=viewwidth || start > stop) I_Error ("Bad R_RenderWallRange: %i to %i", start , stop); #endif sidedef = curline->sidedef; linedef = curline->linedef; // mark the segment as visible for auto map linedef->flags |= ML_MAPPED; // calculate rw_distance for scale calculation rw_normalangle = curline->angle + ANG90; offsetangle = abs(rw_normalangle-rw_angle1); if (offsetangle > ANG90) offsetangle = ANG90; distangle = ANG90 - offsetangle; hyp = R_PointToDist (curline->v1->x, curline->v1->y); sineval = finesine[distangle>>ANGLETOFINESHIFT]; rw_distance = FixedMul (hyp, sineval); ds_p->x1 = rw_x = start; ds_p->x2 = stop; ds_p->curline = curline; rw_stopx = stop+1; // calculate scale at both ends and step ds_p->scale1 = rw_scale = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]); if (stop > start ) { ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]); ds_p->scalestep = rw_scalestep = (ds_p->scale2 - rw_scale) / (stop-start); } else { // UNUSED: try to fix the stretched line bug #if 0 if (rw_distance < FRACUNIT/2) { fixed_t trx,try; fixed_t gxt,gyt; trx = curline->v1->x - viewx; try = curline->v1->y - viewy; gxt = FixedMul(trx,viewcos); gyt = -FixedMul(try,viewsin); ds_p->scale1 = FixedDiv(projection, gxt-gyt)<scale2 = ds_p->scale1; } // calculate texture boundaries // and decide if floor / ceiling marks are needed worldtop = frontsector->ceilingheight - viewz; worldbottom = frontsector->floorheight - viewz; midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; if (!backsector) { // single sided line midtexture = texturetranslation[sidedef->midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; if (linedef->flags & ML_DONTPEGBOTTOM) { vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; // bottom of texture at bottom rw_midtexturemid = vtop - viewz; } else { // top of texture at top rw_midtexturemid = worldtop; } rw_midtexturemid += sidedef->rowoffset; ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->tsilheight = INT_MIN; } else { // two sided line ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; if (frontsector->floorheight > backsector->floorheight) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = frontsector->floorheight; } else if (backsector->floorheight > viewz) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT_MAX; // ds_p->sprbottomclip = negonearray; } if (frontsector->ceilingheight < backsector->ceilingheight) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = frontsector->ceilingheight; } else if (backsector->ceilingheight < viewz) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; // ds_p->sprtopclip = screenheightarray; } if (backsector->ceilingheight <= frontsector->floorheight) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (backsector->floorheight >= frontsector->ceilingheight) { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT_MIN; ds_p->silhouette |= SIL_TOP; } worldhigh = backsector->ceilingheight - viewz; worldlow = backsector->floorheight - viewz; // hack to allow height changes in outdoor areas if (frontsector->ceilingpic == skyflatnum && backsector->ceilingpic == skyflatnum) { worldtop = worldhigh; } if (worldlow != worldbottom || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel) { markfloor = true; } else { // same plane on both sides markfloor = false; } if (worldhigh != worldtop || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel) { markceiling = true; } else { // same plane on both sides markceiling = false; } if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) { // closed door markceiling = markfloor = true; } if (worldhigh < worldtop) { // top texture toptexture = texturetranslation[sidedef->toptexture]; if (linedef->flags & ML_DONTPEGTOP) { // top of texture at top rw_toptexturemid = worldtop; } else { vtop = backsector->ceilingheight + textureheight[sidedef->toptexture]; // bottom of texture rw_toptexturemid = vtop - viewz; } } if (worldlow > worldbottom) { // bottom texture bottomtexture = texturetranslation[sidedef->bottomtexture]; if (linedef->flags & ML_DONTPEGBOTTOM ) { // bottom of texture at bottom // top of texture at top rw_bottomtexturemid = worldtop; } else // top of texture at top rw_bottomtexturemid = worldlow; } rw_toptexturemid += sidedef->rowoffset; rw_bottomtexturemid += sidedef->rowoffset; // allocate space for masked texture tables if (sidedef->midtexture) { // masked midtexture maskedtexture = true; ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; lastopening += rw_stopx - rw_x; } } // calculate rw_offset (only needed for textured lines) segtextured = midtexture | toptexture | bottomtexture | maskedtexture; if (segtextured) { offsetangle = rw_normalangle-rw_angle1; if (offsetangle > ANG180) offsetangle = -offsetangle; if (offsetangle > ANG90) offsetangle = ANG90; sineval = finesine[offsetangle >>ANGLETOFINESHIFT]; rw_offset = FixedMul (hyp, sineval); if (rw_normalangle-rw_angle1 < ANG180) rw_offset = -rw_offset; rw_offset += sidedef->textureoffset + curline->offset; rw_centerangle = ANG90 + viewangle - rw_normalangle; // calculate light table // use different light tables // for horizontal / vertical / diagonal // OPTIMIZE: get rid of LIGHTSEGSHIFT globally if (!fixedcolormap) { lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight; if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS-1]; else walllights = scalelight[lightnum]; } } // if a floor / ceiling plane is on the wrong side // of the view plane, it is definitely invisible // and doesn't need to be marked. if (frontsector->floorheight >= viewz) { // above view plane markfloor = false; } if (frontsector->ceilingheight <= viewz && frontsector->ceilingpic != skyflatnum) { // below view plane markceiling = false; } // calculate incremental stepping values for texture edges worldtop >>= 4; worldbottom >>= 4; topstep = -FixedMul (rw_scalestep, worldtop); topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); bottomstep = -FixedMul (rw_scalestep,worldbottom); bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); if (backsector) { worldhigh >>= 4; worldlow >>= 4; if (worldhigh < worldtop) { pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); pixhighstep = -FixedMul (rw_scalestep,worldhigh); } if (worldlow > worldbottom) { pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); pixlowstep = -FixedMul (rw_scalestep,worldlow); } } // render it if (markceiling) ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); if (markfloor) floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); R_RenderSegLoop (); // save sprite clipping info if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) { memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start)); ds_p->sprtopclip = lastopening - start; lastopening += rw_stopx - start; } if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) { memcpy (lastopening, floorclip+start, 2*(rw_stopx-start)); ds_p->sprbottomclip = lastopening - start; lastopening += rw_stopx - start; } if (maskedtexture && !(ds_p->silhouette&SIL_TOP)) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; } if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; ds_p->bsilheight = INT_MAX; } ds_p++; } chocolate-doom-chocolate-doom-2.2.1/src/doom/r_segs.h000066400000000000000000000014141257432200600224650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh module, drawing LineSegs from BSP. // #ifndef __R_SEGS__ #define __R_SEGS__ void R_RenderMaskedSegRange ( drawseg_t* ds, int x1, int x2 ); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/r_sky.c000066400000000000000000000022561257432200600223320ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Sky rendering. The DOOM sky is a texture map like any // wall, wrapping around. A 1024 columns equal 360 degrees. // The default sky map is 256 columns and repeats 4 times // on a 320 screen? // // // Needed for FRACUNIT. #include "m_fixed.h" // Needed for Flat retrieval. #include "r_data.h" #include "r_sky.h" // // sky mapping // int skyflatnum; int skytexture; int skytexturemid; // // R_InitSkyMap // Called whenever the view size changes. // void R_InitSkyMap (void) { // skyflatnum = R_FlatNumForName ( SKYFLATNAME ); skytexturemid = 100*FRACUNIT; } chocolate-doom-chocolate-doom-2.2.1/src/doom/r_sky.h000066400000000000000000000016431257432200600223360ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Sky rendering. // #ifndef __R_SKY__ #define __R_SKY__ // SKY, store the number for name. #define SKYFLATNAME "F_SKY1" // The sky map is 256*128*4 maps. #define ANGLETOSKYSHIFT 22 extern int skytexture; extern int skytexturemid; // Called whenever the view size changes. void R_InitSkyMap (void); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/r_state.h000066400000000000000000000044541257432200600226530ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh/render internal state variables (global). // #ifndef __R_STATE__ #define __R_STATE__ // Need data structure definitions. #include "d_player.h" #include "r_data.h" // // Refresh internal data structures, // for rendering. // // needed for texture pegging extern fixed_t* textureheight; // needed for pre rendering (fracs) extern fixed_t* spritewidth; extern fixed_t* spriteoffset; extern fixed_t* spritetopoffset; extern lighttable_t* colormaps; extern int viewwidth; extern int scaledviewwidth; extern int viewheight; extern int firstflat; // for global animation extern int* flattranslation; extern int* texturetranslation; // Sprite.... extern int firstspritelump; extern int lastspritelump; extern int numspritelumps; // // Lookup tables for map data. // extern int numsprites; extern spritedef_t* sprites; extern int numvertexes; extern vertex_t* vertexes; extern int numsegs; extern seg_t* segs; extern int numsectors; extern sector_t* sectors; extern int numsubsectors; extern subsector_t* subsectors; extern int numnodes; extern node_t* nodes; extern int numlines; extern line_t* lines; extern int numsides; extern side_t* sides; // // POV data. // extern fixed_t viewx; extern fixed_t viewy; extern fixed_t viewz; extern angle_t viewangle; extern player_t* viewplayer; // ? extern angle_t clipangle; extern int viewangletox[FINEANGLES/2]; extern angle_t xtoviewangle[SCREENWIDTH+1]; //extern fixed_t finetangent[FINEANGLES/2]; extern fixed_t rw_distance; extern angle_t rw_normalangle; // angle to line origin extern int rw_angle1; // Segs count? extern int sscount; extern visplane_t* floorplane; extern visplane_t* ceilingplane; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/r_things.c000066400000000000000000000501441257432200600230170ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh of things, i.e. objects represented by sprites. // #include #include #include "deh_main.h" #include "doomdef.h" #include "i_swap.h" #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "r_local.h" #include "doomstat.h" #define MINZ (FRACUNIT*4) #define BASEYCENTER 100 //void R_DrawColumn (void); //void R_DrawFuzzColumn (void); typedef struct { int x1; int x2; int column; int topclip; int bottomclip; } maskdraw_t; // // Sprite rotation 0 is facing the viewer, // rotation 1 is one angle turn CLOCKWISE around the axis. // This is not the same as the angle, // which increases counter clockwise (protractor). // There was a lot of stuff grabbed wrong, so I changed it... // fixed_t pspritescale; fixed_t pspriteiscale; lighttable_t** spritelights; // constant arrays // used for psprite clipping and initializing clipping short negonearray[SCREENWIDTH]; short screenheightarray[SCREENWIDTH]; // // INITIALIZATION FUNCTIONS // // variables used to look up // and range check thing_t sprites patches spritedef_t* sprites; int numsprites; spriteframe_t sprtemp[29]; int maxframe; char* spritename; // // R_InstallSpriteLump // Local function for R_InitSprites. // void R_InstallSpriteLump ( int lump, unsigned frame, unsigned rotation, boolean flipped ) { int r; if (frame >= 29 || rotation > 8) I_Error("R_InstallSpriteLump: " "Bad frame characters in lump %i", lump); if ((int)frame > maxframe) maxframe = frame; if (rotation == 0) { // the lump should be used for all rotations if (sprtemp[frame].rotate == false) I_Error ("R_InitSprites: Sprite %s frame %c has " "multip rot=0 lump", spritename, 'A'+frame); if (sprtemp[frame].rotate == true) I_Error ("R_InitSprites: Sprite %s frame %c has rotations " "and a rot=0 lump", spritename, 'A'+frame); sprtemp[frame].rotate = false; for (r=0 ; r<8 ; r++) { sprtemp[frame].lump[r] = lump - firstspritelump; sprtemp[frame].flip[r] = (byte)flipped; } return; } // the lump is only used for one rotation if (sprtemp[frame].rotate == false) I_Error ("R_InitSprites: Sprite %s frame %c has rotations " "and a rot=0 lump", spritename, 'A'+frame); sprtemp[frame].rotate = true; // make 0 based rotation--; if (sprtemp[frame].lump[rotation] != -1) I_Error ("R_InitSprites: Sprite %s : %c : %c " "has two lumps mapped to it", spritename, 'A'+frame, '1'+rotation); sprtemp[frame].lump[rotation] = lump - firstspritelump; sprtemp[frame].flip[rotation] = (byte)flipped; } // // R_InitSpriteDefs // Pass a null terminated list of sprite names // (4 chars exactly) to be used. // Builds the sprite rotation matrixes to account // for horizontally flipped sprites. // Will report an error if the lumps are inconsistant. // Only called at startup. // // Sprite lump names are 4 characters for the actor, // a letter for the frame, and a number for the rotation. // A sprite that is flippable will have an additional // letter/number appended. // The rotation character can be 0 to signify no rotations. // void R_InitSpriteDefs (char** namelist) { char** check; int i; int l; int frame; int rotation; int start; int end; int patched; // count the number of sprite names check = namelist; while (*check != NULL) check++; numsprites = check-namelist; if (!numsprites) return; sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL); start = firstspritelump-1; end = lastspritelump+1; // scan all the lump names for each of the names, // noting the highest frame letter. // Just compare 4 characters as ints for (i=0 ; itopdelta != 0xff ; ) { // calculate unclipped screen coordinates // for post topscreen = sprtopscreen + spryscale*column->topdelta; bottomscreen = topscreen + spryscale*column->length; dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS; if (dc_yh >= mfloorclip[dc_x]) dc_yh = mfloorclip[dc_x]-1; if (dc_yl <= mceilingclip[dc_x]) dc_yl = mceilingclip[dc_x]+1; if (dc_yl <= dc_yh) { dc_source = (byte *)column + 3; dc_texturemid = basetexturemid - (column->topdelta<topdelta; // Drawn by either R_DrawColumn // or (SHADOW) R_DrawFuzzColumn. colfunc (); } column = (column_t *)( (byte *)column + column->length + 4); } dc_texturemid = basetexturemid; } // // R_DrawVisSprite // mfloorclip and mceilingclip should also be set. // void R_DrawVisSprite ( vissprite_t* vis, int x1, int x2 ) { column_t* column; int texturecolumn; fixed_t frac; patch_t* patch; patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE); dc_colormap = vis->colormap; if (!dc_colormap) { // NULL colormap = shadow draw colfunc = fuzzcolfunc; } else if (vis->mobjflags & MF_TRANSLATION) { colfunc = transcolfunc; dc_translation = translationtables - 256 + ( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) ); } dc_iscale = abs(vis->xiscale)>>detailshift; dc_texturemid = vis->texturemid; frac = vis->startfrac; spryscale = vis->scale; sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale); for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale) { texturecolumn = frac>>FRACBITS; #ifdef RANGECHECK if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) I_Error ("R_DrawSpriteRange: bad texturecolumn"); #endif column = (column_t *) ((byte *)patch + LONG(patch->columnofs[texturecolumn])); R_DrawMaskedColumn (column); } colfunc = basecolfunc; } // // R_ProjectSprite // Generates a vissprite for a thing // if it might be visible. // void R_ProjectSprite (mobj_t* thing) { fixed_t tr_x; fixed_t tr_y; fixed_t gxt; fixed_t gyt; fixed_t tx; fixed_t tz; fixed_t xscale; int x1; int x2; spritedef_t* sprdef; spriteframe_t* sprframe; int lump; unsigned rot; boolean flip; int index; vissprite_t* vis; angle_t ang; fixed_t iscale; // transform the origin point tr_x = thing->x - viewx; tr_y = thing->y - viewy; gxt = FixedMul(tr_x,viewcos); gyt = -FixedMul(tr_y,viewsin); tz = gxt-gyt; // thing is behind view plane? if (tz < MINZ) return; xscale = FixedDiv(projection, tz); gxt = -FixedMul(tr_x,viewsin); gyt = FixedMul(tr_y,viewcos); tx = -(gyt+gxt); // too far off the side? if (abs(tx)>(tz<<2)) return; // decide which patch to use for sprite relative to player #ifdef RANGECHECK if ((unsigned int) thing->sprite >= (unsigned int) numsprites) I_Error ("R_ProjectSprite: invalid sprite number %i ", thing->sprite); #endif sprdef = &sprites[thing->sprite]; #ifdef RANGECHECK if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes ) I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", thing->sprite, thing->frame); #endif sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK]; if (sprframe->rotate) { // choose a different rotation based on player view ang = R_PointToAngle (thing->x, thing->y); rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29; lump = sprframe->lump[rot]; flip = (boolean)sprframe->flip[rot]; } else { // use single rotation for all views lump = sprframe->lump[0]; flip = (boolean)sprframe->flip[0]; } // calculate edges of the shape tx -= spriteoffset[lump]; x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS; // off the right side? if (x1 > viewwidth) return; tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1; // off the left side if (x2 < 0) return; // store information in a vissprite vis = R_NewVisSprite (); vis->mobjflags = thing->flags; vis->scale = xscale<gx = thing->x; vis->gy = thing->y; vis->gz = thing->z; vis->gzt = thing->z + spritetopoffset[lump]; vis->texturemid = vis->gzt - viewz; vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; iscale = FixedDiv (FRACUNIT, xscale); if (flip) { vis->startfrac = spritewidth[lump]-1; vis->xiscale = -iscale; } else { vis->startfrac = 0; vis->xiscale = iscale; } if (vis->x1 > x1) vis->startfrac += vis->xiscale*(vis->x1-x1); vis->patch = lump; // get light level if (thing->flags & MF_SHADOW) { // shadow draw vis->colormap = NULL; } else if (fixedcolormap) { // fixed map vis->colormap = fixedcolormap; } else if (thing->frame & FF_FULLBRIGHT) { // full bright vis->colormap = colormaps; } else { // diminished light index = xscale>>(LIGHTSCALESHIFT-detailshift); if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE-1; vis->colormap = spritelights[index]; } } // // R_AddSprites // During BSP traversal, this adds sprites by sector. // void R_AddSprites (sector_t* sec) { mobj_t* thing; int lightnum; // BSP is traversed by subsector. // A sector might have been split into several // subsectors during BSP building. // Thus we check whether its already added. if (sec->validcount == validcount) return; // Well, now it will be done. sec->validcount = validcount; lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS-1]; else spritelights = scalelight[lightnum]; // Handle all things in sector. for (thing = sec->thinglist ; thing ; thing = thing->snext) R_ProjectSprite (thing); } // // R_DrawPSprite // void R_DrawPSprite (pspdef_t* psp) { fixed_t tx; int x1; int x2; spritedef_t* sprdef; spriteframe_t* sprframe; int lump; boolean flip; vissprite_t* vis; vissprite_t avis; // decide which patch to use #ifdef RANGECHECK if ( (unsigned)psp->state->sprite >= (unsigned int) numsprites) I_Error ("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite); #endif sprdef = &sprites[psp->state->sprite]; #ifdef RANGECHECK if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame); #endif sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ]; lump = sprframe->lump[0]; flip = (boolean)sprframe->flip[0]; // calculate edges of the shape tx = psp->sx-160*FRACUNIT; tx -= spriteoffset[lump]; x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS; // off the right side if (x1 > viewwidth) return; tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1; // off the left side if (x2 < 0) return; // store information in a vissprite vis = &avis; vis->mobjflags = 0; vis->texturemid = (BASEYCENTER<sy-spritetopoffset[lump]); vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; vis->scale = pspritescale<xiscale = -pspriteiscale; vis->startfrac = spritewidth[lump]-1; } else { vis->xiscale = pspriteiscale; vis->startfrac = 0; } if (vis->x1 > x1) vis->startfrac += vis->xiscale*(vis->x1-x1); vis->patch = lump; if (viewplayer->powers[pw_invisibility] > 4*32 || viewplayer->powers[pw_invisibility] & 8) { // shadow draw vis->colormap = NULL; } else if (fixedcolormap) { // fixed color vis->colormap = fixedcolormap; } else if (psp->state->frame & FF_FULLBRIGHT) { // full bright vis->colormap = colormaps; } else { // local light vis->colormap = spritelights[MAXLIGHTSCALE-1]; } R_DrawVisSprite (vis, vis->x1, vis->x2); } // // R_DrawPlayerSprites // void R_DrawPlayerSprites (void) { int i; int lightnum; pspdef_t* psp; // get light level lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) +extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS-1]; else spritelights = scalelight[lightnum]; // clip to screen bounds mfloorclip = screenheightarray; mceilingclip = negonearray; // add all active psprites for (i=0, psp=viewplayer->psprites; istate) R_DrawPSprite (psp); } } // // R_SortVisSprites // vissprite_t vsprsortedhead; void R_SortVisSprites (void) { int i; int count; vissprite_t* ds; vissprite_t* best; vissprite_t unsorted; fixed_t bestscale; count = vissprite_p - vissprites; unsorted.next = unsorted.prev = &unsorted; if (!count) return; for (ds=vissprites ; dsnext = ds+1; ds->prev = ds-1; } vissprites[0].prev = &unsorted; unsorted.next = &vissprites[0]; (vissprite_p-1)->next = &unsorted; unsorted.prev = vissprite_p-1; // pull the vissprites out by scale vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; for (i=0 ; inext) { if (ds->scale < bestscale) { bestscale = ds->scale; best = ds; } } best->next->prev = best->prev; best->prev->next = best->next; best->next = &vsprsortedhead; best->prev = vsprsortedhead.prev; vsprsortedhead.prev->next = best; vsprsortedhead.prev = best; } } // // R_DrawSprite // void R_DrawSprite (vissprite_t* spr) { drawseg_t* ds; short clipbot[SCREENWIDTH]; short cliptop[SCREENWIDTH]; int x; int r1; int r2; fixed_t scale; fixed_t lowscale; int silhouette; for (x = spr->x1 ; x<=spr->x2 ; x++) clipbot[x] = cliptop[x] = -2; // Scan drawsegs from end to start for obscuring segs. // The first drawseg that has a greater scale // is the clip seg. for (ds=ds_p-1 ; ds >= drawsegs ; ds--) { // determine if the drawseg obscures the sprite if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || (!ds->silhouette && !ds->maskedtexturecol) ) { // does not cover sprite continue; } r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; if (ds->scale1 > ds->scale2) { lowscale = ds->scale2; scale = ds->scale1; } else { lowscale = ds->scale1; scale = ds->scale2; } if (scale < spr->scale || ( lowscale < spr->scale && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline) ) ) { // masked mid texture? if (ds->maskedtexturecol) R_RenderMaskedSegRange (ds, r1, r2); // seg is behind sprite continue; } // clip this piece of the sprite silhouette = ds->silhouette; if (spr->gz >= ds->bsilheight) silhouette &= ~SIL_BOTTOM; if (spr->gzt <= ds->tsilheight) silhouette &= ~SIL_TOP; if (silhouette == 1) { // bottom sil for (x=r1 ; x<=r2 ; x++) if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; } else if (silhouette == 2) { // top sil for (x=r1 ; x<=r2 ; x++) if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } else if (silhouette == 3) { // both for (x=r1 ; x<=r2 ; x++) { if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } } } // all clipping has been performed, so draw the sprite // check for unclipped columns for (x = spr->x1 ; x<=spr->x2 ; x++) { if (clipbot[x] == -2) clipbot[x] = viewheight; if (cliptop[x] == -2) cliptop[x] = -1; } mfloorclip = clipbot; mceilingclip = cliptop; R_DrawVisSprite (spr, spr->x1, spr->x2); } // // R_DrawMasked // void R_DrawMasked (void) { vissprite_t* spr; drawseg_t* ds; R_SortVisSprites (); if (vissprite_p > vissprites) { // draw all vissprites back to front for (spr = vsprsortedhead.next ; spr != &vsprsortedhead ; spr=spr->next) { R_DrawSprite (spr); } } // render any remaining masked mid textures for (ds=ds_p-1 ; ds >= drawsegs ; ds--) if (ds->maskedtexturecol) R_RenderMaskedSegRange (ds, ds->x1, ds->x2); // draw the psprites on top of everything // but does not draw on side views if (!viewangleoffset) R_DrawPlayerSprites (); } chocolate-doom-chocolate-doom-2.2.1/src/doom/r_things.h000066400000000000000000000030171257432200600230210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Rendering of moving objects, sprites. // #ifndef __R_THINGS__ #define __R_THINGS__ #define MAXVISSPRITES 128 extern vissprite_t vissprites[MAXVISSPRITES]; extern vissprite_t* vissprite_p; extern vissprite_t vsprsortedhead; // Constant arrays used for psprite clipping // and initializing clipping. extern short negonearray[SCREENWIDTH]; extern short screenheightarray[SCREENWIDTH]; // vars for R_DrawMaskedColumn extern short* mfloorclip; extern short* mceilingclip; extern fixed_t spryscale; extern fixed_t sprtopscreen; extern fixed_t pspritescale; extern fixed_t pspriteiscale; void R_DrawMaskedColumn (column_t* column); void R_SortVisSprites (void); void R_AddSprites (sector_t* sec); void R_AddPSprites (void); void R_DrawSprites (void); void R_InitSprites (char** namelist); void R_ClearSprites (void); void R_DrawMasked (void); void R_ClipVisSprite ( vissprite_t* vis, int xl, int xh ); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/s_sound.c000066400000000000000000000342651257432200600226620ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // #include #include #include "i_sound.h" #include "i_system.h" #include "doomfeatures.h" #include "deh_str.h" #include "doomstat.h" #include "doomtype.h" #include "sounds.h" #include "s_sound.h" #include "m_misc.h" #include "m_random.h" #include "m_argv.h" #include "p_local.h" #include "w_wad.h" #include "z_zone.h" // when to clip out sounds // Does not fit the large outdoor areas. #define S_CLIPPING_DIST (1200 * FRACUNIT) // Distance tp origin when sounds should be maxed out. // This should relate to movement clipping resolution // (see BLOCKMAP handling). // In the source code release: (160*FRACUNIT). Changed back to the // Vanilla value of 200 (why was this changed?) #define S_CLOSE_DIST (200 * FRACUNIT) // The range over which sound attenuates #define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS) // Stereo separation #define S_STEREO_SWING (96 * FRACUNIT) #define NORM_PITCH 128 #define NORM_PRIORITY 64 #define NORM_SEP 128 typedef struct { // sound information (if null, channel avail.) sfxinfo_t *sfxinfo; // origin of sound mobj_t *origin; // handle of the sound being played int handle; } channel_t; // The set of channels available static channel_t *channels; // Maximum volume of a sound effect. // Internal default is max out of 0-15. int sfxVolume = 8; // Maximum volume of music. int musicVolume = 8; // Internal volume level, ranging from 0-127 static int snd_SfxVolume; // Whether songs are mus_paused static boolean mus_paused; // Music currently being played static musicinfo_t *mus_playing = NULL; // Number of channels to use int snd_channels = 8; // // Initializes sound stuff, including volume // Sets channels, SFX and music volume, // allocates channel buffer, sets S_sfx lookup. // void S_Init(int sfxVolume, int musicVolume) { int i; I_SetOPLDriverVer(opl_v_new); I_PrecacheSounds(S_sfx, NUMSFX); S_SetSfxVolume(sfxVolume); S_SetMusicVolume(musicVolume); // Allocating the internal channels for mixing // (the maximum numer of sounds rendered // simultaneously) within zone memory. channels = Z_Malloc(snd_channels*sizeof(channel_t), PU_STATIC, 0); // Free all channels for use for (i=0 ; isfxinfo) { // stop the sound playing if (I_SoundIsPlaying(c->handle)) { I_StopSound(c->handle); } // check to see if other channels are playing the sound for (i=0; isfxinfo == channels[i].sfxinfo) { break; } } // degrade usefulness of sound data c->sfxinfo->usefulness--; c->sfxinfo = NULL; c->origin = NULL; } } // // Per level startup code. // Kills playing sounds at start of level, // determines music if any, changes music. // void S_Start(void) { int cnum; int mnum; // kill all playing sounds at start of level // (trust me - a good idea) for (cnum=0 ; cnumpriority >= sfxinfo->priority) { break; } } if (cnum == snd_channels) { // FUCK! No lower priority. Sorry, Charlie. return -1; } else { // Otherwise, kick out lower priority. S_StopChannel(cnum); } } c = &channels[cnum]; // channel is decided to be cnum. c->sfxinfo = sfxinfo; c->origin = origin; return cnum; } // // Changes volume and stereo-separation variables // from the norm of a sound effect to be played. // If the sound is not audible, returns a 0. // Otherwise, modifies parameters and returns 1. // static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, int *vol, int *sep) { fixed_t approx_dist; fixed_t adx; fixed_t ady; angle_t angle; // calculate the distance to sound origin // and clip it if necessary adx = abs(listener->x - source->x); ady = abs(listener->y - source->y); // From _GG1_ p.428. Appox. eucledian distance fast. approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); if (gamemap != 8 && approx_dist > S_CLIPPING_DIST) { return 0; } // angle of source to listener angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y); if (angle > listener->angle) { angle = angle - listener->angle; } else { angle = angle + (0xffffffff - listener->angle); } angle >>= ANGLETOFINESHIFT; // stereo separation *sep = 128 - (FixedMul(S_STEREO_SWING, finesine[angle]) >> FRACBITS); // volume calculation if (approx_dist < S_CLOSE_DIST) { *vol = snd_SfxVolume; } else if (gamemap == 8) { if (approx_dist > S_CLIPPING_DIST) { approx_dist = S_CLIPPING_DIST; } *vol = 15+ ((snd_SfxVolume-15) *((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; } else { // distance effect *vol = (snd_SfxVolume * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; } return (*vol > 0); } void S_StartSound(void *origin_p, int sfx_id) { sfxinfo_t *sfx; mobj_t *origin; int rc; int sep; int cnum; int volume; origin = (mobj_t *) origin_p; volume = snd_SfxVolume; // check for bogus sound # if (sfx_id < 1 || sfx_id > NUMSFX) { I_Error("Bad sfx #: %d", sfx_id); } sfx = &S_sfx[sfx_id]; // Initialize sound parameters if (sfx->link) { volume += sfx->volume; if (volume < 1) { return; } if (volume > snd_SfxVolume) { volume = snd_SfxVolume; } } // Check to see if it is audible, // and if not, modify the params if (origin && origin != players[consoleplayer].mo) { rc = S_AdjustSoundParams(players[consoleplayer].mo, origin, &volume, &sep); if (origin->x == players[consoleplayer].mo->x && origin->y == players[consoleplayer].mo->y) { sep = NORM_SEP; } if (!rc) { return; } } else { sep = NORM_SEP; } // kill old sound S_StopSound(origin); // try to find a channel cnum = S_GetChannel(origin, sfx); if (cnum < 0) { return; } // increase the usefulness if (sfx->usefulness++ < 0) { sfx->usefulness = 1; } if (sfx->lumpnum < 0) { sfx->lumpnum = I_GetSfxLumpNum(sfx); } channels[cnum].handle = I_StartSound(sfx, cnum, volume, sep); } // // Stop and resume music, during game PAUSE. // void S_PauseSound(void) { if (mus_playing && !mus_paused) { I_PauseSong(); mus_paused = true; } } void S_ResumeSound(void) { if (mus_playing && mus_paused) { I_ResumeSong(); mus_paused = false; } } // // Updates music & sounds // void S_UpdateSounds(mobj_t *listener) { int audible; int cnum; int volume; int sep; sfxinfo_t* sfx; channel_t* c; I_UpdateSound(); for (cnum=0; cnumsfxinfo; if (c->sfxinfo) { if (I_SoundIsPlaying(c->handle)) { // initialize parameters volume = snd_SfxVolume; sep = NORM_SEP; if (sfx->link) { volume += sfx->volume; if (volume < 1) { S_StopChannel(cnum); continue; } else if (volume > snd_SfxVolume) { volume = snd_SfxVolume; } } // check non-local sounds for distance clipping // or modify their params if (c->origin && listener != c->origin) { audible = S_AdjustSoundParams(listener, c->origin, &volume, &sep); if (!audible) { S_StopChannel(cnum); } else { I_UpdateSoundParams(c->handle, volume, sep); } } } else { // if channel is allocated but sound has stopped, // free it S_StopChannel(cnum); } } } } void S_SetMusicVolume(int volume) { if (volume < 0 || volume > 127) { I_Error("Attempt to set music volume at %d", volume); } I_SetMusicVolume(volume); } void S_SetSfxVolume(int volume) { if (volume < 0 || volume > 127) { I_Error("Attempt to set sfx volume at %d", volume); } snd_SfxVolume = volume; } // // Starts some music with the music id found in sounds.h. // void S_StartMusic(int m_id) { S_ChangeMusic(m_id, false); } void S_ChangeMusic(int musicnum, int looping) { musicinfo_t *music = NULL; char namebuf[9]; void *handle; // The Doom IWAD file has two versions of the intro music: d_intro // and d_introa. The latter is used for OPL playback. if (musicnum == mus_intro && (snd_musicdevice == SNDDEVICE_ADLIB || snd_musicdevice == SNDDEVICE_SB)) { musicnum = mus_introa; } if (musicnum <= mus_None || musicnum >= NUMMUSIC) { I_Error("Bad music number %d", musicnum); } else { music = &S_music[musicnum]; } if (mus_playing == music) { return; } // shutdown old music S_StopMusic(); // get lumpnum if neccessary if (!music->lumpnum) { M_snprintf(namebuf, sizeof(namebuf), "d_%s", DEH_String(music->name)); music->lumpnum = W_GetNumForName(namebuf); } music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC); handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); music->handle = handle; I_PlaySong(handle, looping); mus_playing = music; } boolean S_MusicPlaying(void) { return I_MusicIsPlaying(); } void S_StopMusic(void) { if (mus_playing) { if (mus_paused) { I_ResumeSong(); } I_StopSong(); I_UnRegisterSong(mus_playing->handle); W_ReleaseLumpNum(mus_playing->lumpnum); mus_playing->data = NULL; mus_playing = NULL; } } chocolate-doom-chocolate-doom-2.2.1/src/doom/s_sound.h000066400000000000000000000035651257432200600226660ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The not so system specific sound interface. // #ifndef __S_SOUND__ #define __S_SOUND__ #include "p_mobj.h" #include "sounds.h" // // Initializes sound stuff, including volume // Sets channels, SFX and music volume, // allocates channel buffer, sets S_sfx lookup. // void S_Init(int sfxVolume, int musicVolume); // Shut down sound void S_Shutdown(void); // // Per level startup code. // Kills playing sounds at start of level, // determines music if any, changes music. // void S_Start(void); // // Start sound for thing at // using from sounds.h // void S_StartSound(void *origin, int sound_id); // Stop sound for thing at void S_StopSound(mobj_t *origin); // Start music using from sounds.h void S_StartMusic(int music_id); // Start music using from sounds.h, // and set whether looping void S_ChangeMusic(int music_id, int looping); // query if music is playing boolean S_MusicPlaying(void); // Stops the music fer sure. void S_StopMusic(void); // Stop and resume music, during game PAUSE. void S_PauseSound(void); void S_ResumeSound(void); // // Updates music & sounds // void S_UpdateSounds(mobj_t *listener); void S_SetMusicVolume(int volume); void S_SetSfxVolume(int volume); extern int snd_channels; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/sounds.c000066400000000000000000000117711257432200600225200ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Created by a sound utility. // Kept as a sample, DOOM2 sounds. // #include #include "doomtype.h" #include "sounds.h" // // Information about all the music // #define MUSIC(name) \ { name, 0, NULL, NULL } musicinfo_t S_music[] = { MUSIC(NULL), MUSIC("e1m1"), MUSIC("e1m2"), MUSIC("e1m3"), MUSIC("e1m4"), MUSIC("e1m5"), MUSIC("e1m6"), MUSIC("e1m7"), MUSIC("e1m8"), MUSIC("e1m9"), MUSIC("e2m1"), MUSIC("e2m2"), MUSIC("e2m3"), MUSIC("e2m4"), MUSIC("e2m5"), MUSIC("e2m6"), MUSIC("e2m7"), MUSIC("e2m8"), MUSIC("e2m9"), MUSIC("e3m1"), MUSIC("e3m2"), MUSIC("e3m3"), MUSIC("e3m4"), MUSIC("e3m5"), MUSIC("e3m6"), MUSIC("e3m7"), MUSIC("e3m8"), MUSIC("e3m9"), MUSIC("inter"), MUSIC("intro"), MUSIC("bunny"), MUSIC("victor"), MUSIC("introa"), MUSIC("runnin"), MUSIC("stalks"), MUSIC("countd"), MUSIC("betwee"), MUSIC("doom"), MUSIC("the_da"), MUSIC("shawn"), MUSIC("ddtblu"), MUSIC("in_cit"), MUSIC("dead"), MUSIC("stlks2"), MUSIC("theda2"), MUSIC("doom2"), MUSIC("ddtbl2"), MUSIC("runni2"), MUSIC("dead2"), MUSIC("stlks3"), MUSIC("romero"), MUSIC("shawn2"), MUSIC("messag"), MUSIC("count2"), MUSIC("ddtbl3"), MUSIC("ampie"), MUSIC("theda3"), MUSIC("adrian"), MUSIC("messg2"), MUSIC("romer2"), MUSIC("tense"), MUSIC("shawn3"), MUSIC("openin"), MUSIC("evil"), MUSIC("ultima"), MUSIC("read_m"), MUSIC("dm2ttl"), MUSIC("dm2int") }; // // Information about all the sfx // #define SOUND(name, priority) \ { NULL, name, priority, NULL, -1, -1, 0, 0, -1, NULL } #define SOUND_LINK(name, priority, link_id, pitch, volume) \ { NULL, name, priority, &S_sfx[link_id], pitch, volume, 0, 0, -1, NULL } sfxinfo_t S_sfx[] = { // S_sfx[0] needs to be a dummy for odd reasons. SOUND("none", 0), SOUND("pistol", 64), SOUND("shotgn", 64), SOUND("sgcock", 64), SOUND("dshtgn", 64), SOUND("dbopn", 64), SOUND("dbcls", 64), SOUND("dbload", 64), SOUND("plasma", 64), SOUND("bfg", 64), SOUND("sawup", 64), SOUND("sawidl", 118), SOUND("sawful", 64), SOUND("sawhit", 64), SOUND("rlaunc", 64), SOUND("rxplod", 70), SOUND("firsht", 70), SOUND("firxpl", 70), SOUND("pstart", 100), SOUND("pstop", 100), SOUND("doropn", 100), SOUND("dorcls", 100), SOUND("stnmov", 119), SOUND("swtchn", 78), SOUND("swtchx", 78), SOUND("plpain", 96), SOUND("dmpain", 96), SOUND("popain", 96), SOUND("vipain", 96), SOUND("mnpain", 96), SOUND("pepain", 96), SOUND("slop", 78), SOUND("itemup", 78), SOUND("wpnup", 78), SOUND("oof", 96), SOUND("telept", 32), SOUND("posit1", 98), SOUND("posit2", 98), SOUND("posit3", 98), SOUND("bgsit1", 98), SOUND("bgsit2", 98), SOUND("sgtsit", 98), SOUND("cacsit", 98), SOUND("brssit", 94), SOUND("cybsit", 92), SOUND("spisit", 90), SOUND("bspsit", 90), SOUND("kntsit", 90), SOUND("vilsit", 90), SOUND("mansit", 90), SOUND("pesit", 90), SOUND("sklatk", 70), SOUND("sgtatk", 70), SOUND("skepch", 70), SOUND("vilatk", 70), SOUND("claw", 70), SOUND("skeswg", 70), SOUND("pldeth", 32), SOUND("pdiehi", 32), SOUND("podth1", 70), SOUND("podth2", 70), SOUND("podth3", 70), SOUND("bgdth1", 70), SOUND("bgdth2", 70), SOUND("sgtdth", 70), SOUND("cacdth", 70), SOUND("skldth", 70), SOUND("brsdth", 32), SOUND("cybdth", 32), SOUND("spidth", 32), SOUND("bspdth", 32), SOUND("vildth", 32), SOUND("kntdth", 32), SOUND("pedth", 32), SOUND("skedth", 32), SOUND("posact", 120), SOUND("bgact", 120), SOUND("dmact", 120), SOUND("bspact", 100), SOUND("bspwlk", 100), SOUND("vilact", 100), SOUND("noway", 78), SOUND("barexp", 60), SOUND("punch", 64), SOUND("hoof", 70), SOUND("metal", 70), SOUND_LINK("chgun", 64, sfx_pistol, 150, 0), SOUND("tink", 60), SOUND("bdopn", 100), SOUND("bdcls", 100), SOUND("itmbk", 100), SOUND("flame", 32), SOUND("flamst", 32), SOUND("getpow", 60), SOUND("bospit", 70), SOUND("boscub", 70), SOUND("bossit", 70), SOUND("bospn", 70), SOUND("bosdth", 70), SOUND("manatk", 70), SOUND("mandth", 70), SOUND("sssit", 70), SOUND("ssdth", 70), SOUND("keenpn", 70), SOUND("keendt", 70), SOUND("skeact", 70), SOUND("skesit", 70), SOUND("skeatk", 70), SOUND("radio", 60), }; chocolate-doom-chocolate-doom-2.2.1/src/doom/sounds.h000066400000000000000000000073331257432200600225240ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Created by the sound utility written by Dave Taylor. // Kept as a sample, DOOM2 sounds. Frozen. // #ifndef __SOUNDS__ #define __SOUNDS__ #include "i_sound.h" // the complete set of sound effects extern sfxinfo_t S_sfx[]; // the complete set of music extern musicinfo_t S_music[]; // // Identifiers for all music in game. // typedef enum { mus_None, mus_e1m1, mus_e1m2, mus_e1m3, mus_e1m4, mus_e1m5, mus_e1m6, mus_e1m7, mus_e1m8, mus_e1m9, mus_e2m1, mus_e2m2, mus_e2m3, mus_e2m4, mus_e2m5, mus_e2m6, mus_e2m7, mus_e2m8, mus_e2m9, mus_e3m1, mus_e3m2, mus_e3m3, mus_e3m4, mus_e3m5, mus_e3m6, mus_e3m7, mus_e3m8, mus_e3m9, mus_inter, mus_intro, mus_bunny, mus_victor, mus_introa, mus_runnin, mus_stalks, mus_countd, mus_betwee, mus_doom, mus_the_da, mus_shawn, mus_ddtblu, mus_in_cit, mus_dead, mus_stlks2, mus_theda2, mus_doom2, mus_ddtbl2, mus_runni2, mus_dead2, mus_stlks3, mus_romero, mus_shawn2, mus_messag, mus_count2, mus_ddtbl3, mus_ampie, mus_theda3, mus_adrian, mus_messg2, mus_romer2, mus_tense, mus_shawn3, mus_openin, mus_evil, mus_ultima, mus_read_m, mus_dm2ttl, mus_dm2int, NUMMUSIC } musicenum_t; // // Identifiers for all sfx in game. // typedef enum { sfx_None, sfx_pistol, sfx_shotgn, sfx_sgcock, sfx_dshtgn, sfx_dbopn, sfx_dbcls, sfx_dbload, sfx_plasma, sfx_bfg, sfx_sawup, sfx_sawidl, sfx_sawful, sfx_sawhit, sfx_rlaunc, sfx_rxplod, sfx_firsht, sfx_firxpl, sfx_pstart, sfx_pstop, sfx_doropn, sfx_dorcls, sfx_stnmov, sfx_swtchn, sfx_swtchx, sfx_plpain, sfx_dmpain, sfx_popain, sfx_vipain, sfx_mnpain, sfx_pepain, sfx_slop, sfx_itemup, sfx_wpnup, sfx_oof, sfx_telept, sfx_posit1, sfx_posit2, sfx_posit3, sfx_bgsit1, sfx_bgsit2, sfx_sgtsit, sfx_cacsit, sfx_brssit, sfx_cybsit, sfx_spisit, sfx_bspsit, sfx_kntsit, sfx_vilsit, sfx_mansit, sfx_pesit, sfx_sklatk, sfx_sgtatk, sfx_skepch, sfx_vilatk, sfx_claw, sfx_skeswg, sfx_pldeth, sfx_pdiehi, sfx_podth1, sfx_podth2, sfx_podth3, sfx_bgdth1, sfx_bgdth2, sfx_sgtdth, sfx_cacdth, sfx_skldth, sfx_brsdth, sfx_cybdth, sfx_spidth, sfx_bspdth, sfx_vildth, sfx_kntdth, sfx_pedth, sfx_skedth, sfx_posact, sfx_bgact, sfx_dmact, sfx_bspact, sfx_bspwlk, sfx_vilact, sfx_noway, sfx_barexp, sfx_punch, sfx_hoof, sfx_metal, sfx_chgun, sfx_tink, sfx_bdopn, sfx_bdcls, sfx_itmbk, sfx_flame, sfx_flamst, sfx_getpow, sfx_bospit, sfx_boscub, sfx_bossit, sfx_bospn, sfx_bosdth, sfx_manatk, sfx_mandth, sfx_sssit, sfx_ssdth, sfx_keenpn, sfx_keendt, sfx_skeact, sfx_skesit, sfx_skeatk, sfx_radio, NUMSFX } sfxenum_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/st_lib.c000066400000000000000000000111231257432200600224500ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The status bar widget code. // #include #include #include "deh_main.h" #include "doomdef.h" #include "z_zone.h" #include "v_video.h" #include "i_swap.h" #include "i_system.h" #include "w_wad.h" #include "st_stuff.h" #include "st_lib.h" #include "r_local.h" // in AM_map.c extern boolean automapactive; // // Hack display negative frags. // Loads and store the stminus lump. // patch_t* sttminus; void STlib_init(void) { sttminus = (patch_t *) W_CacheLumpName(DEH_String("STTMINUS"), PU_STATIC); } // ? void STlib_initNum ( st_number_t* n, int x, int y, patch_t** pl, int* num, boolean* on, int width ) { n->x = x; n->y = y; n->oldnum = 0; n->width = width; n->num = num; n->on = on; n->p = pl; } // // A fairly efficient way to draw a number // based on differences from the old number. // Note: worth the trouble? // void STlib_drawNum ( st_number_t* n, boolean refresh ) { int numdigits = n->width; int num = *n->num; int w = SHORT(n->p[0]->width); int h = SHORT(n->p[0]->height); int x = n->x; int neg; n->oldnum = *n->num; neg = num < 0; if (neg) { if (numdigits == 2 && num < -9) num = -9; else if (numdigits == 3 && num < -99) num = -99; num = -num; } // clear the area x = n->x - numdigits*w; if (n->y - ST_Y < 0) I_Error("drawNum: n->y - ST_Y < 0"); V_CopyRect(x, n->y - ST_Y, st_backing_screen, w*numdigits, h, x, n->y); // if non-number, do not draw it if (num == 1994) return; x = n->x; // in the special case of 0, you draw 0 if (!num) V_DrawPatch(x - w, n->y, n->p[ 0 ]); // draw the new number while (num && numdigits--) { x -= w; V_DrawPatch(x, n->y, n->p[ num % 10 ]); num /= 10; } // draw a minus sign if necessary if (neg) V_DrawPatch(x - 8, n->y, sttminus); } // void STlib_updateNum ( st_number_t* n, boolean refresh ) { if (*n->on) STlib_drawNum(n, refresh); } // void STlib_initPercent ( st_percent_t* p, int x, int y, patch_t** pl, int* num, boolean* on, patch_t* percent ) { STlib_initNum(&p->n, x, y, pl, num, on, 3); p->p = percent; } void STlib_updatePercent ( st_percent_t* per, int refresh ) { if (refresh && *per->n.on) V_DrawPatch(per->n.x, per->n.y, per->p); STlib_updateNum(&per->n, refresh); } void STlib_initMultIcon ( st_multicon_t* i, int x, int y, patch_t** il, int* inum, boolean* on ) { i->x = x; i->y = y; i->oldinum = -1; i->inum = inum; i->on = on; i->p = il; } void STlib_updateMultIcon ( st_multicon_t* mi, boolean refresh ) { int w; int h; int x; int y; if (*mi->on && (mi->oldinum != *mi->inum || refresh) && (*mi->inum!=-1)) { if (mi->oldinum != -1) { x = mi->x - SHORT(mi->p[mi->oldinum]->leftoffset); y = mi->y - SHORT(mi->p[mi->oldinum]->topoffset); w = SHORT(mi->p[mi->oldinum]->width); h = SHORT(mi->p[mi->oldinum]->height); if (y - ST_Y < 0) I_Error("updateMultIcon: y - ST_Y < 0"); V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y); } V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]); mi->oldinum = *mi->inum; } } void STlib_initBinIcon ( st_binicon_t* b, int x, int y, patch_t* i, boolean* val, boolean* on ) { b->x = x; b->y = y; b->oldval = false; b->val = val; b->on = on; b->p = i; } void STlib_updateBinIcon ( st_binicon_t* bi, boolean refresh ) { int x; int y; int w; int h; if (*bi->on && (bi->oldval != *bi->val || refresh)) { x = bi->x - SHORT(bi->p->leftoffset); y = bi->y - SHORT(bi->p->topoffset); w = SHORT(bi->p->width); h = SHORT(bi->p->height); if (y - ST_Y < 0) I_Error("updateBinIcon: y - ST_Y < 0"); if (*bi->val) V_DrawPatch(bi->x, bi->y, bi->p); else V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y); bi->oldval = *bi->val; } } chocolate-doom-chocolate-doom-2.2.1/src/doom/st_lib.h000066400000000000000000000063701257432200600224650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The status bar widget code. // #ifndef __STLIB__ #define __STLIB__ // We are referring to patches. #include "r_defs.h" // // Typedefs of widgets // // Number widget typedef struct { // upper right-hand corner // of the number (right-justified) int x; int y; // max # of digits in number int width; // last number value int oldnum; // pointer to current value int* num; // pointer to boolean stating // whether to update number boolean* on; // list of patches for 0-9 patch_t** p; // user data int data; } st_number_t; // Percent widget ("child" of number widget, // or, more precisely, contains a number widget.) typedef struct { // number information st_number_t n; // percent sign graphic patch_t* p; } st_percent_t; // Multiple Icon widget typedef struct { // center-justified location of icons int x; int y; // last icon number int oldinum; // pointer to current icon int* inum; // pointer to boolean stating // whether to update icon boolean* on; // list of icons patch_t** p; // user data int data; } st_multicon_t; // Binary Icon widget typedef struct { // center-justified location of icon int x; int y; // last icon value boolean oldval; // pointer to current icon status boolean* val; // pointer to boolean // stating whether to update icon boolean* on; patch_t* p; // icon int data; // user data } st_binicon_t; // // Widget creation, access, and update routines // // Initializes widget library. // More precisely, initialize STMINUS, // everything else is done somewhere else. // void STlib_init(void); // Number widget routines void STlib_initNum ( st_number_t* n, int x, int y, patch_t** pl, int* num, boolean* on, int width ); void STlib_updateNum ( st_number_t* n, boolean refresh ); // Percent widget routines void STlib_initPercent ( st_percent_t* p, int x, int y, patch_t** pl, int* num, boolean* on, patch_t* percent ); void STlib_updatePercent ( st_percent_t* per, int refresh ); // Multiple Icon widget routines void STlib_initMultIcon ( st_multicon_t* mi, int x, int y, patch_t** il, int* inum, boolean* on ); void STlib_updateMultIcon ( st_multicon_t* mi, boolean refresh ); // Binary Icon widget routines void STlib_initBinIcon ( st_binicon_t* b, int x, int y, patch_t* i, boolean* val, boolean* on ); void STlib_updateBinIcon ( st_binicon_t* bi, boolean refresh ); #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/st_stuff.c000066400000000000000000000722131257432200600230400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Status bar code. // Does the face/direction indicator animatin. // Does palette indicators as well (red pain/berserk, bright pickup) // #include #include "i_system.h" #include "i_video.h" #include "z_zone.h" #include "m_misc.h" #include "m_random.h" #include "w_wad.h" #include "deh_main.h" #include "deh_misc.h" #include "doomdef.h" #include "doomkeys.h" #include "g_game.h" #include "st_stuff.h" #include "st_lib.h" #include "r_local.h" #include "p_local.h" #include "p_inter.h" #include "am_map.h" #include "m_cheat.h" #include "s_sound.h" // Needs access to LFB. #include "v_video.h" // State. #include "doomstat.h" // Data. #include "dstrings.h" #include "sounds.h" // // STATUS BAR DATA // // Palette indices. // For damage/bonus red-/gold-shifts #define STARTREDPALS 1 #define STARTBONUSPALS 9 #define NUMREDPALS 8 #define NUMBONUSPALS 4 // Radiation suit, green shift. #define RADIATIONPAL 13 // N/256*100% probability // that the normal face state will change #define ST_FACEPROBABILITY 96 // For Responder #define ST_TOGGLECHAT KEY_ENTER // Location of status bar #define ST_X 0 #define ST_X2 104 #define ST_FX 143 #define ST_FY 169 // Should be set to patch width // for tall numbers later on #define ST_TALLNUMWIDTH (tallnum[0]->width) // Number of status faces. #define ST_NUMPAINFACES 5 #define ST_NUMSTRAIGHTFACES 3 #define ST_NUMTURNFACES 2 #define ST_NUMSPECIALFACES 3 #define ST_FACESTRIDE \ (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES) #define ST_NUMEXTRAFACES 2 #define ST_NUMFACES \ (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES) #define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES) #define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES) #define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1) #define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1) #define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE) #define ST_DEADFACE (ST_GODFACE+1) #define ST_FACESX 143 #define ST_FACESY 168 #define ST_EVILGRINCOUNT (2*TICRATE) #define ST_STRAIGHTFACECOUNT (TICRATE/2) #define ST_TURNCOUNT (1*TICRATE) #define ST_OUCHCOUNT (1*TICRATE) #define ST_RAMPAGEDELAY (2*TICRATE) #define ST_MUCHPAIN 20 // Location and size of statistics, // justified according to widget type. // Problem is, within which space? STbar? Screen? // Note: this could be read in by a lump. // Problem is, is the stuff rendered // into a buffer, // or into the frame buffer? // AMMO number pos. #define ST_AMMOWIDTH 3 #define ST_AMMOX 44 #define ST_AMMOY 171 // HEALTH number pos. #define ST_HEALTHWIDTH 3 #define ST_HEALTHX 90 #define ST_HEALTHY 171 // Weapon pos. #define ST_ARMSX 111 #define ST_ARMSY 172 #define ST_ARMSBGX 104 #define ST_ARMSBGY 168 #define ST_ARMSXSPACE 12 #define ST_ARMSYSPACE 10 // Frags pos. #define ST_FRAGSX 138 #define ST_FRAGSY 171 #define ST_FRAGSWIDTH 2 // ARMOR number pos. #define ST_ARMORWIDTH 3 #define ST_ARMORX 221 #define ST_ARMORY 171 // Key icon positions. #define ST_KEY0WIDTH 8 #define ST_KEY0HEIGHT 5 #define ST_KEY0X 239 #define ST_KEY0Y 171 #define ST_KEY1WIDTH ST_KEY0WIDTH #define ST_KEY1X 239 #define ST_KEY1Y 181 #define ST_KEY2WIDTH ST_KEY0WIDTH #define ST_KEY2X 239 #define ST_KEY2Y 191 // Ammunition counter. #define ST_AMMO0WIDTH 3 #define ST_AMMO0HEIGHT 6 #define ST_AMMO0X 288 #define ST_AMMO0Y 173 #define ST_AMMO1WIDTH ST_AMMO0WIDTH #define ST_AMMO1X 288 #define ST_AMMO1Y 179 #define ST_AMMO2WIDTH ST_AMMO0WIDTH #define ST_AMMO2X 288 #define ST_AMMO2Y 191 #define ST_AMMO3WIDTH ST_AMMO0WIDTH #define ST_AMMO3X 288 #define ST_AMMO3Y 185 // Indicate maximum ammunition. // Only needed because backpack exists. #define ST_MAXAMMO0WIDTH 3 #define ST_MAXAMMO0HEIGHT 5 #define ST_MAXAMMO0X 314 #define ST_MAXAMMO0Y 173 #define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH #define ST_MAXAMMO1X 314 #define ST_MAXAMMO1Y 179 #define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH #define ST_MAXAMMO2X 314 #define ST_MAXAMMO2Y 191 #define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH #define ST_MAXAMMO3X 314 #define ST_MAXAMMO3Y 185 // pistol #define ST_WEAPON0X 110 #define ST_WEAPON0Y 172 // shotgun #define ST_WEAPON1X 122 #define ST_WEAPON1Y 172 // chain gun #define ST_WEAPON2X 134 #define ST_WEAPON2Y 172 // missile launcher #define ST_WEAPON3X 110 #define ST_WEAPON3Y 181 // plasma gun #define ST_WEAPON4X 122 #define ST_WEAPON4Y 181 // bfg #define ST_WEAPON5X 134 #define ST_WEAPON5Y 181 // WPNS title #define ST_WPNSX 109 #define ST_WPNSY 191 // DETH title #define ST_DETHX 109 #define ST_DETHY 191 //Incoming messages window location //UNUSED // #define ST_MSGTEXTX (viewwindowx) // #define ST_MSGTEXTY (viewwindowy+viewheight-18) #define ST_MSGTEXTX 0 #define ST_MSGTEXTY 0 // Dimensions given in characters. #define ST_MSGWIDTH 52 // Or shall I say, in lines? #define ST_MSGHEIGHT 1 #define ST_OUTTEXTX 0 #define ST_OUTTEXTY 6 // Width, in characters again. #define ST_OUTWIDTH 52 // Height, in lines. #define ST_OUTHEIGHT 1 #define ST_MAPTITLEX \ (SCREENWIDTH - ST_MAPWIDTH * ST_CHATFONTWIDTH) #define ST_MAPTITLEY 0 #define ST_MAPHEIGHT 1 // graphics are drawn to a backing screen and blitted to the real screen byte *st_backing_screen; // main player in game static player_t* plyr; // ST_Start() has just been called static boolean st_firsttime; // lump number for PLAYPAL static int lu_palette; // used for timing static unsigned int st_clock; // used for making messages go away static int st_msgcounter=0; // used when in chat static st_chatstateenum_t st_chatstate; // whether in automap or first-person static st_stateenum_t st_gamestate; // whether left-side main status bar is active static boolean st_statusbaron; // whether status bar chat is active static boolean st_chat; // value of st_chat before message popped up static boolean st_oldchat; // whether chat window has the cursor on static boolean st_cursoron; // !deathmatch static boolean st_notdeathmatch; // !deathmatch && st_statusbaron static boolean st_armson; // !deathmatch static boolean st_fragson; // main bar left static patch_t* sbar; // 0-9, tall numbers static patch_t* tallnum[10]; // tall % sign static patch_t* tallpercent; // 0-9, short, yellow (,different!) numbers static patch_t* shortnum[10]; // 3 key-cards, 3 skulls static patch_t* keys[NUMCARDS]; // face status patches static patch_t* faces[ST_NUMFACES]; // face background static patch_t* faceback; // main bar right static patch_t* armsbg; // weapon ownership patches static patch_t* arms[6][2]; // ready-weapon widget static st_number_t w_ready; // in deathmatch only, summary of frags stats static st_number_t w_frags; // health widget static st_percent_t w_health; // arms background static st_binicon_t w_armsbg; // weapon ownership widgets static st_multicon_t w_arms[6]; // face status widget static st_multicon_t w_faces; // keycard widgets static st_multicon_t w_keyboxes[3]; // armor widget static st_percent_t w_armor; // ammo widgets static st_number_t w_ammo[4]; // max ammo widgets static st_number_t w_maxammo[4]; // number of frags so far in deathmatch static int st_fragscount; // used to use appopriately pained face static int st_oldhealth = -1; // used for evil grin static boolean oldweaponsowned[NUMWEAPONS]; // count until face changes static int st_facecount = 0; // current face index, used by w_faces static int st_faceindex = 0; // holds key-type for each key box on bar static int keyboxes[3]; // a random number per tick static int st_randomnumber; cheatseq_t cheat_mus = CHEAT("idmus", 2); cheatseq_t cheat_god = CHEAT("iddqd", 0); cheatseq_t cheat_ammo = CHEAT("idkfa", 0); cheatseq_t cheat_ammonokey = CHEAT("idfa", 0); cheatseq_t cheat_noclip = CHEAT("idspispopd", 0); cheatseq_t cheat_commercial_noclip = CHEAT("idclip", 0); cheatseq_t cheat_powerup[7] = { CHEAT("idbeholdv", 0), CHEAT("idbeholds", 0), CHEAT("idbeholdi", 0), CHEAT("idbeholdr", 0), CHEAT("idbeholda", 0), CHEAT("idbeholdl", 0), CHEAT("idbehold", 0), }; cheatseq_t cheat_choppers = CHEAT("idchoppers", 0); cheatseq_t cheat_clev = CHEAT("idclev", 2); cheatseq_t cheat_mypos = CHEAT("idmypos", 0); // // STATUS BAR CODE // void ST_Stop(void); void ST_refreshBackground(void) { if (st_statusbaron) { V_UseBuffer(st_backing_screen); V_DrawPatch(ST_X, 0, sbar); if (netgame) V_DrawPatch(ST_FX, 0, faceback); V_RestoreBuffer(); V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y); } } // Respond to keyboard input events, // intercept cheats. boolean ST_Responder (event_t* ev) { int i; // Filter automap on/off. if (ev->type == ev_keyup && ((ev->data1 & 0xffff0000) == AM_MSGHEADER)) { switch(ev->data1) { case AM_MSGENTERED: st_gamestate = AutomapState; st_firsttime = true; break; case AM_MSGEXITED: // fprintf(stderr, "AM exited\n"); st_gamestate = FirstPersonState; break; } } // if a user keypress... else if (ev->type == ev_keydown) { if (!netgame && gameskill != sk_nightmare) { // 'dqd' cheat for toggleable god mode if (cht_CheckCheat(&cheat_god, ev->data2)) { plyr->cheats ^= CF_GODMODE; if (plyr->cheats & CF_GODMODE) { if (plyr->mo) plyr->mo->health = 100; plyr->health = deh_god_mode_health; plyr->message = DEH_String(STSTR_DQDON); } else plyr->message = DEH_String(STSTR_DQDOFF); } // 'fa' cheat for killer fucking arsenal else if (cht_CheckCheat(&cheat_ammonokey, ev->data2)) { plyr->armorpoints = deh_idfa_armor; plyr->armortype = deh_idfa_armor_class; for (i=0;iweaponowned[i] = true; for (i=0;iammo[i] = plyr->maxammo[i]; plyr->message = DEH_String(STSTR_FAADDED); } // 'kfa' cheat for key full ammo else if (cht_CheckCheat(&cheat_ammo, ev->data2)) { plyr->armorpoints = deh_idkfa_armor; plyr->armortype = deh_idkfa_armor_class; for (i=0;iweaponowned[i] = true; for (i=0;iammo[i] = plyr->maxammo[i]; for (i=0;icards[i] = true; plyr->message = DEH_String(STSTR_KFAADDED); } // 'mus' cheat for changing music else if (cht_CheckCheat(&cheat_mus, ev->data2)) { char buf[3]; int musnum; plyr->message = DEH_String(STSTR_MUS); cht_GetParam(&cheat_mus, buf); // Note: The original v1.9 had a bug that tried to play back // the Doom II music regardless of gamemode. This was fixed // in the Ultimate Doom executable so that it would work for // the Doom 1 music as well. if (gamemode == commercial || gameversion < exe_ultimate) { musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1; if (((buf[0]-'0')*10 + buf[1]-'0') > 35) plyr->message = DEH_String(STSTR_NOMUS); else S_ChangeMusic(musnum, 1); } else { musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1'); if (((buf[0]-'1')*9 + buf[1]-'1') > 31) plyr->message = DEH_String(STSTR_NOMUS); else S_ChangeMusic(musnum, 1); } } else if ( (logical_gamemission == doom && cht_CheckCheat(&cheat_noclip, ev->data2)) || (logical_gamemission != doom && cht_CheckCheat(&cheat_commercial_noclip,ev->data2))) { // Noclip cheat. // For Doom 1, use the idspipsopd cheat; for all others, use // idclip plyr->cheats ^= CF_NOCLIP; if (plyr->cheats & CF_NOCLIP) plyr->message = DEH_String(STSTR_NCON); else plyr->message = DEH_String(STSTR_NCOFF); } // 'behold?' power-up cheats for (i=0;i<6;i++) { if (cht_CheckCheat(&cheat_powerup[i], ev->data2)) { if (!plyr->powers[i]) P_GivePower( plyr, i); else if (i!=pw_strength) plyr->powers[i] = 1; else plyr->powers[i] = 0; plyr->message = DEH_String(STSTR_BEHOLDX); } } // 'behold' power-up menu if (cht_CheckCheat(&cheat_powerup[6], ev->data2)) { plyr->message = DEH_String(STSTR_BEHOLD); } // 'choppers' invulnerability & chainsaw else if (cht_CheckCheat(&cheat_choppers, ev->data2)) { plyr->weaponowned[wp_chainsaw] = true; plyr->powers[pw_invulnerability] = true; plyr->message = DEH_String(STSTR_CHOPPERS); } // 'mypos' for player position else if (cht_CheckCheat(&cheat_mypos, ev->data2)) { static char buf[ST_MSGWIDTH]; M_snprintf(buf, sizeof(buf), "ang=0x%x;x,y=(0x%x,0x%x)", players[consoleplayer].mo->angle, players[consoleplayer].mo->x, players[consoleplayer].mo->y); plyr->message = buf; } } // 'clev' change-level cheat if (!netgame && cht_CheckCheat(&cheat_clev, ev->data2)) { char buf[3]; int epsd; int map; cht_GetParam(&cheat_clev, buf); if (gamemode == commercial) { epsd = 1; map = (buf[0] - '0')*10 + buf[1] - '0'; } else { epsd = buf[0] - '0'; map = buf[1] - '0'; } // Chex.exe always warps to episode 1. if (gameversion == exe_chex) { epsd = 1; } // Catch invalid maps. if (epsd < 1) return false; if (map < 1) return false; // Ohmygod - this is not going to work. if ((gamemode == retail) && ((epsd > 4) || (map > 9))) return false; if ((gamemode == registered) && ((epsd > 3) || (map > 9))) return false; if ((gamemode == shareware) && ((epsd > 1) || (map > 9))) return false; // The source release has this check as map > 34. However, Vanilla // Doom allows IDCLEV up to MAP40 even though it normally crashes. if ((gamemode == commercial) && (( epsd > 1) || (map > 40))) return false; // So be it. plyr->message = DEH_String(STSTR_CLEV); G_DeferedInitNew(gameskill, epsd, map); } } return false; } int ST_calcPainOffset(void) { int health; static int lastcalc; static int oldhealth = -1; health = plyr->health > 100 ? 100 : plyr->health; if (health != oldhealth) { lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101); oldhealth = health; } return lastcalc; } // // This is a not-very-pretty routine which handles // the face states and their timing. // the precedence of expressions is: // dead > evil grin > turned head > straight ahead // void ST_updateFaceWidget(void) { int i; angle_t badguyangle; angle_t diffang; static int lastattackdown = -1; static int priority = 0; boolean doevilgrin; if (priority < 10) { // dead if (!plyr->health) { priority = 9; st_faceindex = ST_DEADFACE; st_facecount = 1; } } if (priority < 9) { if (plyr->bonuscount) { // picking up bonus doevilgrin = false; for (i=0;iweaponowned[i]) { doevilgrin = true; oldweaponsowned[i] = plyr->weaponowned[i]; } } if (doevilgrin) { // evil grin if just picked up weapon priority = 8; st_facecount = ST_EVILGRINCOUNT; st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET; } } } if (priority < 8) { if (plyr->damagecount && plyr->attacker && plyr->attacker != plyr->mo) { // being attacked priority = 7; if (plyr->health - st_oldhealth > ST_MUCHPAIN) { st_facecount = ST_TURNCOUNT; st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; } else { badguyangle = R_PointToAngle2(plyr->mo->x, plyr->mo->y, plyr->attacker->x, plyr->attacker->y); if (badguyangle > plyr->mo->angle) { // whether right or left diffang = badguyangle - plyr->mo->angle; i = diffang > ANG180; } else { // whether left or right diffang = plyr->mo->angle - badguyangle; i = diffang <= ANG180; } // confusing, aint it? st_facecount = ST_TURNCOUNT; st_faceindex = ST_calcPainOffset(); if (diffang < ANG45) { // head-on st_faceindex += ST_RAMPAGEOFFSET; } else if (i) { // turn face right st_faceindex += ST_TURNOFFSET; } else { // turn face left st_faceindex += ST_TURNOFFSET+1; } } } } if (priority < 7) { // getting hurt because of your own damn stupidity if (plyr->damagecount) { if (plyr->health - st_oldhealth > ST_MUCHPAIN) { priority = 7; st_facecount = ST_TURNCOUNT; st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; } else { priority = 6; st_facecount = ST_TURNCOUNT; st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; } } } if (priority < 6) { // rapid firing if (plyr->attackdown) { if (lastattackdown==-1) lastattackdown = ST_RAMPAGEDELAY; else if (!--lastattackdown) { priority = 5; st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; st_facecount = 1; lastattackdown = 1; } } else lastattackdown = -1; } if (priority < 5) { // invulnerability if ((plyr->cheats & CF_GODMODE) || plyr->powers[pw_invulnerability]) { priority = 4; st_faceindex = ST_GODFACE; st_facecount = 1; } } // look left or look right if the facecount has timed out if (!st_facecount) { st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3); st_facecount = ST_STRAIGHTFACECOUNT; priority = 0; } st_facecount--; } void ST_updateWidgets(void) { static int largeammo = 1994; // means "n/a" int i; // must redirect the pointer if the ready weapon has changed. // if (w_ready.data != plyr->readyweapon) // { if (weaponinfo[plyr->readyweapon].ammo == am_noammo) w_ready.num = &largeammo; else w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo]; //{ // static int tic=0; // static int dir=-1; // if (!(tic&15)) // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir; // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100) // dir = 1; // tic++; // } w_ready.data = plyr->readyweapon; // if (*w_ready.on) // STlib_updateNum(&w_ready, true); // refresh weapon change // } // update keycard multiple widgets for (i=0;i<3;i++) { keyboxes[i] = plyr->cards[i] ? i : -1; if (plyr->cards[i+3]) keyboxes[i] = i+3; } // refresh everything if this is him coming back to life ST_updateFaceWidget(); // used by the w_armsbg widget st_notdeathmatch = !deathmatch; // used by w_arms[] widgets st_armson = st_statusbaron && !deathmatch; // used by w_frags widget st_fragson = deathmatch && st_statusbaron; st_fragscount = 0; for (i=0 ; ifrags[i]; else st_fragscount -= plyr->frags[i]; } // get rid of chat window if up because of message if (!--st_msgcounter) st_chat = st_oldchat; } void ST_Ticker (void) { st_clock++; st_randomnumber = M_Random(); ST_updateWidgets(); st_oldhealth = plyr->health; } static int st_palette = 0; void ST_doPaletteStuff(void) { int palette; byte* pal; int cnt; int bzc; cnt = plyr->damagecount; if (plyr->powers[pw_strength]) { // slowly fade the berzerk out bzc = 12 - (plyr->powers[pw_strength]>>6); if (bzc > cnt) cnt = bzc; } if (cnt) { palette = (cnt+7)>>3; if (palette >= NUMREDPALS) palette = NUMREDPALS-1; palette += STARTREDPALS; } else if (plyr->bonuscount) { palette = (plyr->bonuscount+7)>>3; if (palette >= NUMBONUSPALS) palette = NUMBONUSPALS-1; palette += STARTBONUSPALS; } else if ( plyr->powers[pw_ironfeet] > 4*32 || plyr->powers[pw_ironfeet]&8) palette = RADIATIONPAL; else palette = 0; // In Chex Quest, the player never sees red. Instead, the // radiation suit palette is used to tint the screen green, // as though the player is being covered in goo by an // attacking flemoid. if (gameversion == exe_chex && palette >= STARTREDPALS && palette < STARTREDPALS + NUMREDPALS) { palette = RADIATIONPAL; } if (palette != st_palette) { st_palette = palette; pal = (byte *) W_CacheLumpNum (lu_palette, PU_CACHE)+palette*768; I_SetPalette (pal); } } void ST_drawWidgets(boolean refresh) { int i; // used by w_arms[] widgets st_armson = st_statusbaron && !deathmatch; // used by w_frags widget st_fragson = deathmatch && st_statusbaron; STlib_updateNum(&w_ready, refresh); for (i=0;i<4;i++) { STlib_updateNum(&w_ammo[i], refresh); STlib_updateNum(&w_maxammo[i], refresh); } STlib_updatePercent(&w_health, refresh); STlib_updatePercent(&w_armor, refresh); STlib_updateBinIcon(&w_armsbg, refresh); for (i=0;i<6;i++) STlib_updateMultIcon(&w_arms[i], refresh); STlib_updateMultIcon(&w_faces, refresh); for (i=0;i<3;i++) STlib_updateMultIcon(&w_keyboxes[i], refresh); STlib_updateNum(&w_frags, refresh); } void ST_doRefresh(void) { st_firsttime = false; // draw status bar background to off-screen buff ST_refreshBackground(); // and refresh all widgets ST_drawWidgets(true); } void ST_diffDraw(void) { // update all widgets ST_drawWidgets(false); } void ST_Drawer (boolean fullscreen, boolean refresh) { st_statusbaron = (!fullscreen) || automapactive; st_firsttime = st_firsttime || refresh; // Do red-/gold-shifts from damage/items ST_doPaletteStuff(); // If just after ST_Start(), refresh all if (st_firsttime) ST_doRefresh(); // Otherwise, update as little as possible else ST_diffDraw(); } typedef void (*load_callback_t)(char *lumpname, patch_t **variable); // Iterates through all graphics to be loaded or unloaded, along with // the variable they use, invoking the specified callback function. static void ST_loadUnloadGraphics(load_callback_t callback) { int i; int j; int facenum; char namebuf[9]; // Load the numbers, tall and short for (i=0;i<10;i++) { DEH_snprintf(namebuf, 9, "STTNUM%d", i); callback(namebuf, &tallnum[i]); DEH_snprintf(namebuf, 9, "STYSNUM%d", i); callback(namebuf, &shortnum[i]); } // Load percent key. //Note: why not load STMINUS here, too? callback(DEH_String("STTPRCNT"), &tallpercent); // key cards for (i=0;iweaponowned[i]; for (i=0;i<3;i++) keyboxes[i] = -1; STlib_init(); } void ST_createWidgets(void) { int i; // ready weapon ammo STlib_initNum(&w_ready, ST_AMMOX, ST_AMMOY, tallnum, &plyr->ammo[weaponinfo[plyr->readyweapon].ammo], &st_statusbaron, ST_AMMOWIDTH ); // the last weapon type w_ready.data = plyr->readyweapon; // health percentage STlib_initPercent(&w_health, ST_HEALTHX, ST_HEALTHY, tallnum, &plyr->health, &st_statusbaron, tallpercent); // arms background STlib_initBinIcon(&w_armsbg, ST_ARMSBGX, ST_ARMSBGY, armsbg, &st_notdeathmatch, &st_statusbaron); // weapons owned for(i=0;i<6;i++) { STlib_initMultIcon(&w_arms[i], ST_ARMSX+(i%3)*ST_ARMSXSPACE, ST_ARMSY+(i/3)*ST_ARMSYSPACE, arms[i], &plyr->weaponowned[i+1], &st_armson); } // frags sum STlib_initNum(&w_frags, ST_FRAGSX, ST_FRAGSY, tallnum, &st_fragscount, &st_fragson, ST_FRAGSWIDTH); // faces STlib_initMultIcon(&w_faces, ST_FACESX, ST_FACESY, faces, &st_faceindex, &st_statusbaron); // armor percentage - should be colored later STlib_initPercent(&w_armor, ST_ARMORX, ST_ARMORY, tallnum, &plyr->armorpoints, &st_statusbaron, tallpercent); // keyboxes 0-2 STlib_initMultIcon(&w_keyboxes[0], ST_KEY0X, ST_KEY0Y, keys, &keyboxes[0], &st_statusbaron); STlib_initMultIcon(&w_keyboxes[1], ST_KEY1X, ST_KEY1Y, keys, &keyboxes[1], &st_statusbaron); STlib_initMultIcon(&w_keyboxes[2], ST_KEY2X, ST_KEY2Y, keys, &keyboxes[2], &st_statusbaron); // ammo count (all four kinds) STlib_initNum(&w_ammo[0], ST_AMMO0X, ST_AMMO0Y, shortnum, &plyr->ammo[0], &st_statusbaron, ST_AMMO0WIDTH); STlib_initNum(&w_ammo[1], ST_AMMO1X, ST_AMMO1Y, shortnum, &plyr->ammo[1], &st_statusbaron, ST_AMMO1WIDTH); STlib_initNum(&w_ammo[2], ST_AMMO2X, ST_AMMO2Y, shortnum, &plyr->ammo[2], &st_statusbaron, ST_AMMO2WIDTH); STlib_initNum(&w_ammo[3], ST_AMMO3X, ST_AMMO3Y, shortnum, &plyr->ammo[3], &st_statusbaron, ST_AMMO3WIDTH); // max ammo count (all four kinds) STlib_initNum(&w_maxammo[0], ST_MAXAMMO0X, ST_MAXAMMO0Y, shortnum, &plyr->maxammo[0], &st_statusbaron, ST_MAXAMMO0WIDTH); STlib_initNum(&w_maxammo[1], ST_MAXAMMO1X, ST_MAXAMMO1Y, shortnum, &plyr->maxammo[1], &st_statusbaron, ST_MAXAMMO1WIDTH); STlib_initNum(&w_maxammo[2], ST_MAXAMMO2X, ST_MAXAMMO2Y, shortnum, &plyr->maxammo[2], &st_statusbaron, ST_MAXAMMO2WIDTH); STlib_initNum(&w_maxammo[3], ST_MAXAMMO3X, ST_MAXAMMO3Y, shortnum, &plyr->maxammo[3], &st_statusbaron, ST_MAXAMMO3WIDTH); } static boolean st_stopped = true; void ST_Start (void) { if (!st_stopped) ST_Stop(); ST_initData(); ST_createWidgets(); st_stopped = false; } void ST_Stop (void) { if (st_stopped) return; I_SetPalette (W_CacheLumpNum (lu_palette, PU_CACHE)); st_stopped = true; } void ST_Init (void) { ST_loadData(); st_backing_screen = (byte *) Z_Malloc(ST_WIDTH * ST_HEIGHT, PU_STATIC, 0); } chocolate-doom-chocolate-doom-2.2.1/src/doom/st_stuff.h000066400000000000000000000036451257432200600230500ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Status bar code. // Does the face/direction indicator animatin. // Does palette indicators as well (red pain/berserk, bright pickup) // #ifndef __STSTUFF_H__ #define __STSTUFF_H__ #include "doomtype.h" #include "d_event.h" #include "m_cheat.h" // Size of statusbar. // Now sensitive for scaling. #define ST_HEIGHT 32 #define ST_WIDTH SCREENWIDTH #define ST_Y (SCREENHEIGHT - ST_HEIGHT) // // STATUS BAR // // Called by main loop. boolean ST_Responder (event_t* ev); // Called by main loop. void ST_Ticker (void); // Called by main loop. void ST_Drawer (boolean fullscreen, boolean refresh); // Called when the console player is spawned on each level. void ST_Start (void); // Called by startup code. void ST_Init (void); // States for status bar code. typedef enum { AutomapState, FirstPersonState } st_stateenum_t; // States for the chat code. typedef enum { StartChatState, WaitDestState, GetChatState } st_chatstateenum_t; extern byte *st_backing_screen; extern cheatseq_t cheat_mus; extern cheatseq_t cheat_god; extern cheatseq_t cheat_ammo; extern cheatseq_t cheat_ammonokey; extern cheatseq_t cheat_noclip; extern cheatseq_t cheat_commercial_noclip; extern cheatseq_t cheat_powerup[7]; extern cheatseq_t cheat_choppers; extern cheatseq_t cheat_clev; extern cheatseq_t cheat_mypos; #endif chocolate-doom-chocolate-doom-2.2.1/src/doom/statdump.c000066400000000000000000000205541257432200600230450ustar00rootroot00000000000000 /* Copyright(C) 2005-2014 Simon Howard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -- Functions for presenting the information captured from the statistics buffer to a file. */ #include #include #include #include "d_player.h" #include "d_mode.h" #include "m_argv.h" #include "statdump.h" /* Par times for E1M1-E1M9. */ static const int doom1_par_times[] = { 30, 75, 120, 90, 165, 180, 180, 30, 165, }; /* Par times for MAP01-MAP09. */ static const int doom2_par_times[] = { 30, 90, 120, 120, 90, 150, 120, 120, 270, }; /* Player colors. */ static const char *player_colors[] = { "Green", "Indigo", "Brown", "Red" }; // Array of end-of-level statistics that have been captured. #define MAX_CAPTURES 32 static wbstartstruct_t captured_stats[MAX_CAPTURES]; static int num_captured_stats = 0; static GameMission_t discovered_gamemission = none; /* Try to work out whether this is a Doom 1 or Doom 2 game, by looking * at the episode and map, and the par times. This is used to decide * how to format the level name. Unfortunately, in some cases it is * impossible to determine whether this is Doom 1 or Doom 2. */ static void DiscoverGamemode(wbstartstruct_t *stats, int num_stats) { int partime; int level; int i; if (discovered_gamemission != none) { return; } for (i=0; i 0) { discovered_gamemission = doom; return; } /* This is episode 1. If this is level 10 or higher, it must be Doom 2. */ if (level >= 9) { discovered_gamemission = doom2; return; } /* Try to work out if this is Doom 1 or Doom 2 by looking at the par time. */ partime = stats[i].partime; if (partime == doom1_par_times[level] * TICRATE && partime != doom2_par_times[level] * TICRATE) { discovered_gamemission = doom; return; } if (partime != doom1_par_times[level] * TICRATE && partime == doom2_par_times[level] * TICRATE) { discovered_gamemission = doom2; return; } } } /* Returns the number of players active in the given stats buffer. */ static int GetNumPlayers(wbstartstruct_t *stats) { int i; int num_players = 0; for (i=0; iplyr[i].in) { ++num_players; } } return num_players; } static void PrintBanner(FILE *stream) { fprintf(stream, "===========================================\n"); } static void PrintPercentage(FILE *stream, int amount, int total) { if (total == 0) { fprintf(stream, "0"); } else { fprintf(stream, "%i / %i", amount, total); // statdump.exe is a 16-bit program, so very occasionally an // integer overflow can occur when doing this calculation with // a large value. Therefore, cast to short to give the same // output. fprintf(stream, " (%i%%)", (short) (amount * 100) / total); } } /* Display statistics for a single player. */ static void PrintPlayerStats(FILE *stream, wbstartstruct_t *stats, int player_num) { wbplayerstruct_t *player = &stats->plyr[player_num]; fprintf(stream, "Player %i (%s):\n", player_num + 1, player_colors[player_num]); /* Kills percentage */ fprintf(stream, "\tKills: "); PrintPercentage(stream, player->skills, stats->maxkills); fprintf(stream, "\n"); /* Items percentage */ fprintf(stream, "\tItems: "); PrintPercentage(stream, player->sitems, stats->maxitems); fprintf(stream, "\n"); /* Secrets percentage */ fprintf(stream, "\tSecrets: "); PrintPercentage(stream, player->ssecret, stats->maxsecret); fprintf(stream, "\n"); } /* Frags table for multiplayer games. */ static void PrintFragsTable(FILE *stream, wbstartstruct_t *stats) { int x, y; fprintf(stream, "Frags:\n"); /* Print header */ fprintf(stream, "\t\t"); for (x=0; xplyr[x].in) { continue; } fprintf(stream, "%s\t", player_colors[x]); } fprintf(stream, "\n"); fprintf(stream, "\t\t-------------------------------- VICTIMS\n"); /* Print table */ for (y=0; yplyr[y].in) { continue; } fprintf(stream, "\t%s\t|", player_colors[y]); for (x=0; xplyr[x].in) { continue; } fprintf(stream, "%i\t", stats->plyr[y].frags[x]); } fprintf(stream, "\n"); } fprintf(stream, "\t\t|\n"); fprintf(stream, "\t KILLERS\n"); } /* Displays the level name: MAPxy or ExMy, depending on game mode. */ static void PrintLevelName(FILE *stream, int episode, int level) { PrintBanner(stream); switch (discovered_gamemission) { case doom: fprintf(stream, "E%iM%i\n", episode + 1, level + 1); break; case doom2: fprintf(stream, "MAP%02i\n", level + 1); break; default: case none: fprintf(stream, "E%iM%i / MAP%02i\n", episode + 1, level + 1, level + 1); break; } PrintBanner(stream); } /* Print details of a statistics buffer to the given file. */ static void PrintStats(FILE *stream, wbstartstruct_t *stats) { int leveltime, partime; int i; PrintLevelName(stream, stats->epsd, stats->last); fprintf(stream, "\n"); leveltime = stats->plyr[0].stime / TICRATE; partime = stats->partime / TICRATE; fprintf(stream, "Time: %i:%02i", leveltime / 60, leveltime % 60); fprintf(stream, " (par: %i:%02i)\n", partime / 60, partime % 60); fprintf(stream, "\n"); for (i=0; iplyr[i].in) { PrintPlayerStats(stream, stats, i); } } if (GetNumPlayers(stats) >= 2) { PrintFragsTable(stream, stats); } fprintf(stream, "\n"); } void StatCopy(wbstartstruct_t *stats) { if (M_ParmExists("-statdump") && num_captured_stats < MAX_CAPTURES) { memcpy(&captured_stats[num_captured_stats], stats, sizeof(wbstartstruct_t)); ++num_captured_stats; } } void StatDump(void) { FILE *dumpfile; int i; //! // @category compat // @arg // // Dump statistics information to the specified file on the levels // that were played. The output from this option matches the output // from statdump.exe (see ctrlapi.zip in the /idgames archive). // i = M_CheckParmWithArgs("-statdump", 1); if (i > 0) { printf("Statistics captured for %i level(s)\n", num_captured_stats); // We actually know what the real gamemission is, but this has // to match the output from statdump.exe. DiscoverGamemode(captured_stats, num_captured_stats); // Allow "-" as output file, for stdout. if (strcmp(myargv[i + 1], "-") != 0) { dumpfile = fopen(myargv[i + 1], "w"); } else { dumpfile = NULL; } for (i = 0; i < num_captured_stats; ++i) { PrintStats(dumpfile, &captured_stats[i]); } if (dumpfile != NULL) { fclose(dumpfile); } } } chocolate-doom-chocolate-doom-2.2.1/src/doom/statdump.h000066400000000000000000000012761257432200600230520ustar00rootroot00000000000000 /* Copyright(C) 2005-2014 Simon Howard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #ifndef DOOM_STATDUMP_H #define DOOM_STATDUMP_H void StatCopy(wbstartstruct_t *stats); void StatDump(void); #endif /* #ifndef DOOM_STATDUMP_H */ chocolate-doom-chocolate-doom-2.2.1/src/doom/wi_stuff.c000066400000000000000000001020461257432200600230270ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Intermission screens. // #include #include "z_zone.h" #include "m_misc.h" #include "m_random.h" #include "deh_main.h" #include "i_swap.h" #include "i_system.h" #include "w_wad.h" #include "g_game.h" #include "r_local.h" #include "s_sound.h" #include "doomstat.h" // Data. #include "sounds.h" // Needs access to LFB. #include "v_video.h" #include "wi_stuff.h" // // Data needed to add patches to full screen intermission pics. // Patches are statistics messages, and animations. // Loads of by-pixel layout and placement, offsets etc. // // // Different vetween registered DOOM (1994) and // Ultimate DOOM - Final edition (retail, 1995?). // This is supposedly ignored for commercial // release (aka DOOM II), which had 34 maps // in one episode. So there. #define NUMEPISODES 4 #define NUMMAPS 9 // in tics //U #define PAUSELEN (TICRATE*2) //U #define SCORESTEP 100 //U #define ANIMPERIOD 32 // pixel distance from "(YOU)" to "PLAYER N" //U #define STARDIST 10 //U #define WK 1 // GLOBAL LOCATIONS #define WI_TITLEY 2 #define WI_SPACINGY 33 // SINGPLE-PLAYER STUFF #define SP_STATSX 50 #define SP_STATSY 50 #define SP_TIMEX 16 #define SP_TIMEY (SCREENHEIGHT-32) // NET GAME STUFF #define NG_STATSY 50 #define NG_STATSX (32 + SHORT(star->width)/2 + 32*!dofrags) #define NG_SPACINGX 64 // DEATHMATCH STUFF #define DM_MATRIXX 42 #define DM_MATRIXY 68 #define DM_SPACINGX 40 #define DM_TOTALSX 269 #define DM_KILLERSX 10 #define DM_KILLERSY 100 #define DM_VICTIMSX 5 #define DM_VICTIMSY 50 typedef enum { ANIM_ALWAYS, ANIM_RANDOM, ANIM_LEVEL } animenum_t; typedef struct { int x; int y; } point_t; // // Animation. // There is another anim_t used in p_spec. // typedef struct { animenum_t type; // period in tics between animations int period; // number of animation frames int nanims; // location of animation point_t loc; // ALWAYS: n/a, // RANDOM: period deviation (<256), // LEVEL: level int data1; // ALWAYS: n/a, // RANDOM: random base period, // LEVEL: n/a int data2; // actual graphics for frames of animations patch_t* p[3]; // following must be initialized to zero before use! // next value of bcnt (used in conjunction with period) int nexttic; // last drawn animation frame int lastdrawn; // next frame number to animate int ctr; // used by RANDOM and LEVEL when animating int state; } anim_t; static point_t lnodes[NUMEPISODES][NUMMAPS] = { // Episode 0 World Map { { 185, 164 }, // location of level 0 (CJ) { 148, 143 }, // location of level 1 (CJ) { 69, 122 }, // location of level 2 (CJ) { 209, 102 }, // location of level 3 (CJ) { 116, 89 }, // location of level 4 (CJ) { 166, 55 }, // location of level 5 (CJ) { 71, 56 }, // location of level 6 (CJ) { 135, 29 }, // location of level 7 (CJ) { 71, 24 } // location of level 8 (CJ) }, // Episode 1 World Map should go here { { 254, 25 }, // location of level 0 (CJ) { 97, 50 }, // location of level 1 (CJ) { 188, 64 }, // location of level 2 (CJ) { 128, 78 }, // location of level 3 (CJ) { 214, 92 }, // location of level 4 (CJ) { 133, 130 }, // location of level 5 (CJ) { 208, 136 }, // location of level 6 (CJ) { 148, 140 }, // location of level 7 (CJ) { 235, 158 } // location of level 8 (CJ) }, // Episode 2 World Map should go here { { 156, 168 }, // location of level 0 (CJ) { 48, 154 }, // location of level 1 (CJ) { 174, 95 }, // location of level 2 (CJ) { 265, 75 }, // location of level 3 (CJ) { 130, 48 }, // location of level 4 (CJ) { 279, 23 }, // location of level 5 (CJ) { 198, 48 }, // location of level 6 (CJ) { 140, 25 }, // location of level 7 (CJ) { 281, 136 } // location of level 8 (CJ) } }; // // Animation locations for episode 0 (1). // Using patches saves a lot of space, // as they replace 320x200 full screen frames. // #define ANIM(type, period, nanims, x, y, nexttic) \ { (type), (period), (nanims), { (x), (y) }, (nexttic), \ 0, { NULL, NULL, NULL }, 0, 0, 0, 0 } static anim_t epsd0animinfo[] = { ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0), }; static anim_t epsd1animinfo[] = { ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7), ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8), }; static anim_t epsd2animinfo[] = { ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0), ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0), }; static int NUMANIMS[NUMEPISODES] = { arrlen(epsd0animinfo), arrlen(epsd1animinfo), arrlen(epsd2animinfo), }; static anim_t *anims[NUMEPISODES] = { epsd0animinfo, epsd1animinfo, epsd2animinfo }; // // GENERAL DATA // // // Locally used stuff. // // States for single-player #define SP_KILLS 0 #define SP_ITEMS 2 #define SP_SECRET 4 #define SP_FRAGS 6 #define SP_TIME 8 #define SP_PAR ST_TIME #define SP_PAUSE 1 // in seconds #define SHOWNEXTLOCDELAY 4 //#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY // used to accelerate or skip a stage static int acceleratestage; // wbs->pnum static int me; // specifies current state static stateenum_t state; // contains information passed into intermission static wbstartstruct_t* wbs; static wbplayerstruct_t* plrs; // wbs->plyr[] // used for general timing static int cnt; // used for timing of background animation static int bcnt; // signals to refresh everything for one frame static int firstrefresh; static int cnt_kills[MAXPLAYERS]; static int cnt_items[MAXPLAYERS]; static int cnt_secret[MAXPLAYERS]; static int cnt_time; static int cnt_par; static int cnt_pause; // # of commercial levels static int NUMCMAPS; // // GRAPHICS // // You Are Here graphic static patch_t* yah[3] = { NULL, NULL, NULL }; // splat static patch_t* splat[2] = { NULL, NULL }; // %, : graphics static patch_t* percent; static patch_t* colon; // 0-9 graphic static patch_t* num[10]; // minus sign static patch_t* wiminus; // "Finished!" graphics static patch_t* finished; // "Entering" graphic static patch_t* entering; // "secret" static patch_t* sp_secret; // "Kills", "Scrt", "Items", "Frags" static patch_t* kills; static patch_t* secret; static patch_t* items; static patch_t* frags; // Time sucks. static patch_t* timepatch; static patch_t* par; static patch_t* sucks; // "killers", "victims" static patch_t* killers; static patch_t* victims; // "Total", your face, your dead face static patch_t* total; static patch_t* star; static patch_t* bstar; // "red P[1..MAXPLAYERS]" static patch_t* p[MAXPLAYERS]; // "gray P[1..MAXPLAYERS]" static patch_t* bp[MAXPLAYERS]; // Name graphics of each level (centered) static patch_t** lnames; // Buffer storing the backdrop static patch_t *background; // // CODE // // slam background void WI_slamBackground(void) { V_DrawPatch(0, 0, background); } // The ticker is used to detect keys // because of timing issues in netgames. boolean WI_Responder(event_t* ev) { return false; } // Draws " Finished!" void WI_drawLF(void) { int y = WI_TITLEY; if (gamemode != commercial || wbs->last < NUMCMAPS) { // draw V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2, y, lnames[wbs->last]); // draw "Finished!" y += (5*SHORT(lnames[wbs->last]->height))/4; V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished); } else if (wbs->last == NUMCMAPS) { // MAP33 - nothing is displayed! } else if (wbs->last > NUMCMAPS) { // > MAP33. Doom bombs out here with a Bad V_DrawPatch error. // I'm pretty sure that doom2.exe is just reading into random // bits of memory at this point, but let's try to be accurate // anyway. This deliberately triggers a V_DrawPatch error. patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1, { 0, 0, 0, 0, 0, 0, 0, 0 } }; V_DrawPatch(0, y, &tmp); } } // Draws "Entering " void WI_drawEL(void) { int y = WI_TITLEY; // draw "Entering" V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2, y, entering); // draw level y += (5*SHORT(lnames[wbs->next]->height))/4; V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2, y, lnames[wbs->next]); } void WI_drawOnLnode ( int n, patch_t* c[] ) { int i; int left; int top; int right; int bottom; boolean fits = false; i = 0; do { left = lnodes[wbs->epsd][n].x - SHORT(c[i]->leftoffset); top = lnodes[wbs->epsd][n].y - SHORT(c[i]->topoffset); right = left + SHORT(c[i]->width); bottom = top + SHORT(c[i]->height); if (left >= 0 && right < SCREENWIDTH && top >= 0 && bottom < SCREENHEIGHT) { fits = true; } else { i++; } } while (!fits && i!=2 && c[i] != NULL); if (fits && i<2) { V_DrawPatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, c[i]); } else { // DEBUG printf("Could not place patch on level %d", n+1); } } void WI_initAnimatedBack(void) { int i; anim_t* a; if (gamemode == commercial) return; if (wbs->epsd > 2) return; for (i=0;iepsd];i++) { a = &anims[wbs->epsd][i]; // init variables a->ctr = -1; // specify the next time to draw it if (a->type == ANIM_ALWAYS) a->nexttic = bcnt + 1 + (M_Random()%a->period); else if (a->type == ANIM_RANDOM) a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1); else if (a->type == ANIM_LEVEL) a->nexttic = bcnt + 1; } } void WI_updateAnimatedBack(void) { int i; anim_t* a; if (gamemode == commercial) return; if (wbs->epsd > 2) return; for (i=0;iepsd];i++) { a = &anims[wbs->epsd][i]; if (bcnt == a->nexttic) { switch (a->type) { case ANIM_ALWAYS: if (++a->ctr >= a->nanims) a->ctr = 0; a->nexttic = bcnt + a->period; break; case ANIM_RANDOM: a->ctr++; if (a->ctr == a->nanims) { a->ctr = -1; a->nexttic = bcnt+a->data2+(M_Random()%a->data1); } else a->nexttic = bcnt + a->period; break; case ANIM_LEVEL: // gawd-awful hack for level anims if (!(state == StatCount && i == 7) && wbs->next == a->data1) { a->ctr++; if (a->ctr == a->nanims) a->ctr--; a->nexttic = bcnt + a->period; } break; } } } } void WI_drawAnimatedBack(void) { int i; anim_t* a; if (gamemode == commercial) return; if (wbs->epsd > 2) return; for (i=0 ; iepsd] ; i++) { a = &anims[wbs->epsd][i]; if (a->ctr >= 0) V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]); } } // // Draws a number. // If digits > 0, then use that many digits minimum, // otherwise only use as many as necessary. // Returns new x position. // int WI_drawNum ( int x, int y, int n, int digits ) { int fontwidth = SHORT(num[0]->width); int neg; int temp; if (digits < 0) { if (!n) { // make variable-length zeros 1 digit long digits = 1; } else { // figure out # of digits in # digits = 0; temp = n; while (temp) { temp /= 10; digits++; } } } neg = n < 0; if (neg) n = -n; // if non-number, do not draw it if (n == 1994) return 0; // draw the new number while (digits--) { x -= fontwidth; V_DrawPatch(x, y, num[ n % 10 ]); n /= 10; } // draw a minus sign if necessary if (neg) V_DrawPatch(x-=8, y, wiminus); return x; } void WI_drawPercent ( int x, int y, int p ) { if (p < 0) return; V_DrawPatch(x, y, percent); WI_drawNum(x, y, p, -1); } // // Display level completion time and par, // or "sucks" message if overflow. // void WI_drawTime ( int x, int y, int t ) { int div; int n; if (t<0) return; if (t <= 61*59) { div = 1; do { n = (t / div) % 60; x = WI_drawNum(x, y, n, 2) - SHORT(colon->width); div *= 60; // draw if (div==60 || t / div) V_DrawPatch(x, y, colon); } while (t / div); } else { // "sucks" V_DrawPatch(x - SHORT(sucks->width), y, sucks); } } void WI_End(void) { void WI_unloadData(void); WI_unloadData(); } void WI_initNoState(void) { state = NoState; acceleratestage = 0; cnt = 10; } void WI_updateNoState(void) { WI_updateAnimatedBack(); if (!--cnt) { // Don't call WI_End yet. G_WorldDone doesnt immediately // change gamestate, so WI_Drawer is still going to get // run until that happens. If we do that after WI_End // (which unloads all the graphics), we're in trouble. //WI_End(); G_WorldDone(); } } static boolean snl_pointeron = false; void WI_initShowNextLoc(void) { state = ShowNextLoc; acceleratestage = 0; cnt = SHOWNEXTLOCDELAY * TICRATE; WI_initAnimatedBack(); } void WI_updateShowNextLoc(void) { WI_updateAnimatedBack(); if (!--cnt || acceleratestage) WI_initNoState(); else snl_pointeron = (cnt & 31) < 20; } void WI_drawShowNextLoc(void) { int i; int last; WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); if ( gamemode != commercial) { if (wbs->epsd > 2) { WI_drawEL(); return; } last = (wbs->last == 8) ? wbs->next - 1 : wbs->last; // draw a splat on taken cities. for (i=0 ; i<=last ; i++) WI_drawOnLnode(i, splat); // splat the secret level? if (wbs->didsecret) WI_drawOnLnode(8, splat); // draw flashing ptr if (snl_pointeron) WI_drawOnLnode(wbs->next, yah); } // draws which level you are entering.. if ( (gamemode != commercial) || wbs->next != 30) WI_drawEL(); } void WI_drawNoState(void) { snl_pointeron = true; WI_drawShowNextLoc(); } int WI_fragSum(int playernum) { int i; int frags = 0; for (i=0 ; i 99) dm_frags[i][j] = 99; if (dm_frags[i][j] < -99) dm_frags[i][j] = -99; stillticking = true; } } dm_totals[i] = WI_fragSum(i); if (dm_totals[i] > 99) dm_totals[i] = 99; if (dm_totals[i] < -99) dm_totals[i] = -99; } } if (!stillticking) { S_StartSound(0, sfx_barexp); dm_state++; } } else if (dm_state == 4) { if (acceleratestage) { S_StartSound(0, sfx_slop); if ( gamemode == commercial) WI_initNoState(); else WI_initShowNextLoc(); } } else if (dm_state & 1) { if (!--cnt_pause) { dm_state++; cnt_pause = TICRATE; } } } void WI_drawDeathmatchStats(void) { int i; int j; int x; int y; int w; WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); WI_drawLF(); // draw stat titles (top line) V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2, DM_MATRIXY-WI_SPACINGY+10, total); V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers); V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims); // draw P? x = DM_MATRIXX + DM_SPACINGX; y = DM_MATRIXY; for (i=0 ; iwidth)/2, DM_MATRIXY - WI_SPACINGY, p[i]); V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, p[i]); if (i == me) { V_DrawPatch(x-SHORT(p[i]->width)/2, DM_MATRIXY - WI_SPACINGY, bstar); V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, star); } } else { // V_DrawPatch(x-SHORT(bp[i]->width)/2, // DM_MATRIXY - WI_SPACINGY, bp[i]); // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2, // y, bp[i]); } x += DM_SPACINGX; y += WI_SPACINGY; } // draw stats y = DM_MATRIXY+10; w = SHORT(num[0]->width); for (i=0 ; imaxkills; cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret; if (dofrags) cnt_frags[i] = WI_fragSum(i); } S_StartSound(0, sfx_barexp); ng_state = 10; } if (ng_state == 2) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (plrs[i].skills * 100) / wbs->maxkills) cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_barexp); ng_state++; } } else if (ng_state == 4) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (plrs[i].sitems * 100) / wbs->maxitems) cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_barexp); ng_state++; } } else if (ng_state == 6) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (plrs[i].ssecret * 100) / wbs->maxsecret) cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_barexp); ng_state += 1 + 2*!dofrags; } } else if (ng_state == 8) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (fsum = WI_fragSum(i))) cnt_frags[i] = fsum; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_pldeth); ng_state++; } } else if (ng_state == 10) { if (acceleratestage) { S_StartSound(0, sfx_sgcock); if ( gamemode == commercial ) WI_initNoState(); else WI_initShowNextLoc(); } } else if (ng_state & 1) { if (!--cnt_pause) { ng_state++; cnt_pause = TICRATE; } } } void WI_drawNetgameStats(void) { int i; int x; int y; int pwidth = SHORT(percent->width); WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); WI_drawLF(); // draw stat titles (top line) V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width), NG_STATSY, kills); V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width), NG_STATSY, items); V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width), NG_STATSY, secret); if (dofrags) V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width), NG_STATSY, frags); // draw stats y = NG_STATSY + SHORT(kills->height); for (i=0 ; iwidth), y, p[i]); if (i == me) V_DrawPatch(x-SHORT(p[i]->width), y, star); x += NG_SPACINGX; WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX; WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX; WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX; if (dofrags) WI_drawNum(x, y+10, cnt_frags[i], -1); y += WI_SPACINGY; } } static int sp_state; void WI_initStats(void) { state = StatCount; acceleratestage = 0; sp_state = 1; cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1; cnt_time = cnt_par = -1; cnt_pause = TICRATE; WI_initAnimatedBack(); } void WI_updateStats(void) { WI_updateAnimatedBack(); if (acceleratestage && sp_state != 10) { acceleratestage = 0; cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret; cnt_time = plrs[me].stime / TICRATE; cnt_par = wbs->partime / TICRATE; S_StartSound(0, sfx_barexp); sp_state = 10; } if (sp_state == 2) { cnt_kills[0] += 2; if (!(bcnt&3)) S_StartSound(0, sfx_pistol); if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) { cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; S_StartSound(0, sfx_barexp); sp_state++; } } else if (sp_state == 4) { cnt_items[0] += 2; if (!(bcnt&3)) S_StartSound(0, sfx_pistol); if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) { cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; S_StartSound(0, sfx_barexp); sp_state++; } } else if (sp_state == 6) { cnt_secret[0] += 2; if (!(bcnt&3)) S_StartSound(0, sfx_pistol); if (cnt_secret[0] >= (plrs[me].ssecret * 100) / wbs->maxsecret) { cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret; S_StartSound(0, sfx_barexp); sp_state++; } } else if (sp_state == 8) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); cnt_time += 3; if (cnt_time >= plrs[me].stime / TICRATE) cnt_time = plrs[me].stime / TICRATE; cnt_par += 3; if (cnt_par >= wbs->partime / TICRATE) { cnt_par = wbs->partime / TICRATE; if (cnt_time >= plrs[me].stime / TICRATE) { S_StartSound(0, sfx_barexp); sp_state++; } } } else if (sp_state == 10) { if (acceleratestage) { S_StartSound(0, sfx_sgcock); if (gamemode == commercial) WI_initNoState(); else WI_initShowNextLoc(); } } else if (sp_state & 1) { if (!--cnt_pause) { sp_state++; cnt_pause = TICRATE; } } } void WI_drawStats(void) { // line height int lh; lh = (3*SHORT(num[0]->height))/2; WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); WI_drawLF(); V_DrawPatch(SP_STATSX, SP_STATSY, kills); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]); V_DrawPatch(SP_STATSX, SP_STATSY+lh, items); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]); V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch); WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time); if (wbs->epsd < 3) { V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par); WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par); } } void WI_checkForAccelerate(void) { int i; player_t *player; // check for button presses to skip delays for (i=0, player = players ; icmd.buttons & BT_ATTACK) { if (!player->attackdown) acceleratestage = 1; player->attackdown = true; } else player->attackdown = false; if (player->cmd.buttons & BT_USE) { if (!player->usedown) acceleratestage = 1; player->usedown = true; } else player->usedown = false; } } } // Updates stuff each tick void WI_Ticker(void) { // counter for general background animation bcnt++; if (bcnt == 1) { // intermission music if ( gamemode == commercial ) S_ChangeMusic(mus_dm2int, true); else S_ChangeMusic(mus_inter, true); } WI_checkForAccelerate(); switch (state) { case StatCount: if (deathmatch) WI_updateDeathmatchStats(); else if (netgame) WI_updateNetgameStats(); else WI_updateStats(); break; case ShowNextLoc: WI_updateShowNextLoc(); break; case NoState: WI_updateNoState(); break; } } typedef void (*load_callback_t)(char *lumpname, patch_t **variable); // Common load/unload function. Iterates over all the graphics // lumps to be loaded/unloaded into memory. static void WI_loadUnloadData(load_callback_t callback) { int i, j; char name[9]; anim_t *a; if (gamemode == commercial) { for (i=0 ; iepsd, i); callback(name, &lnames[i]); } // you are here callback(DEH_String("WIURH0"), &yah[0]); // you are here (alt.) callback(DEH_String("WIURH1"), &yah[1]); // splat callback(DEH_String("WISPLAT"), &splat[0]); if (wbs->epsd < 3) { for (j=0;jepsd];j++) { a = &anims[wbs->epsd][j]; for (i=0;inanims;i++) { // MONDO HACK! if (wbs->epsd != 1 || j != 8) { // animations DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i); callback(name, &a->p[i]); } else { // HACK ALERT! a->p[i] = anims[1][4].p[i]; } } } } } // More hacks on minus sign. callback(DEH_String("WIMINUS"), &wiminus); for (i=0;i<10;i++) { // numbers 0-9 DEH_snprintf(name, 9, "WINUM%d", i); callback(name, &num[i]); } // percent sign callback(DEH_String("WIPCNT"), &percent); // "finished" callback(DEH_String("WIF"), &finished); // "entering" callback(DEH_String("WIENTER"), &entering); // "kills" callback(DEH_String("WIOSTK"), &kills); // "scrt" callback(DEH_String("WIOSTS"), &secret); // "secret" callback(DEH_String("WISCRT2"), &sp_secret); // french wad uses WIOBJ (?) if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0) { // "items" if (netgame && !deathmatch) callback(DEH_String("WIOBJ"), &items); else callback(DEH_String("WIOSTI"), &items); } else { callback(DEH_String("WIOSTI"), &items); } // "frgs" callback(DEH_String("WIFRGS"), &frags); // ":" callback(DEH_String("WICOLON"), &colon); // "time" callback(DEH_String("WITIME"), &timepatch); // "sucks" callback(DEH_String("WISUCKS"), &sucks); // "par" callback(DEH_String("WIPAR"), &par); // "killers" (vertical) callback(DEH_String("WIKILRS"), &killers); // "victims" (horiz) callback(DEH_String("WIVCTMS"), &victims); // "total" callback(DEH_String("WIMSTT"), &total); for (i=0 ; iepsd == 3) { M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name)); } else { DEH_snprintf(name, sizeof(name), "WIMAP%d", wbs->epsd); } // Draw backdrop and save to a temporary buffer callback(name, &background); } static void WI_loadCallback(char *name, patch_t **variable) { *variable = W_CacheLumpName(name, PU_STATIC); } void WI_loadData(void) { if (gamemode == commercial) { NUMCMAPS = 32; lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS, PU_STATIC, NULL); } else { lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS, PU_STATIC, NULL); } WI_loadUnloadData(WI_loadCallback); // These two graphics are special cased because we're sharing // them with the status bar code // your face star = W_CacheLumpName(DEH_String("STFST01"), PU_STATIC); // dead face bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC); } static void WI_unloadCallback(char *name, patch_t **variable) { W_ReleaseLumpName(name); *variable = NULL; } void WI_unloadData(void) { WI_loadUnloadData(WI_unloadCallback); // We do not free these lumps as they are shared with the status // bar code. // W_ReleaseLumpName("STFST01"); // W_ReleaseLumpName("STFDEAD0"); } void WI_Drawer (void) { switch (state) { case StatCount: if (deathmatch) WI_drawDeathmatchStats(); else if (netgame) WI_drawNetgameStats(); else WI_drawStats(); break; case ShowNextLoc: WI_drawShowNextLoc(); break; case NoState: WI_drawNoState(); break; } } void WI_initVariables(wbstartstruct_t* wbstartstruct) { wbs = wbstartstruct; #ifdef RANGECHECKING if (gamemode != commercial) { if ( gamemode == retail ) RNGCHECK(wbs->epsd, 0, 3); else RNGCHECK(wbs->epsd, 0, 2); } else { RNGCHECK(wbs->last, 0, 8); RNGCHECK(wbs->next, 0, 8); } RNGCHECK(wbs->pnum, 0, MAXPLAYERS); RNGCHECK(wbs->pnum, 0, MAXPLAYERS); #endif acceleratestage = 0; cnt = bcnt = 0; firstrefresh = 1; me = wbs->pnum; plrs = wbs->plyr; if (!wbs->maxkills) wbs->maxkills = 1; if (!wbs->maxitems) wbs->maxitems = 1; if (!wbs->maxsecret) wbs->maxsecret = 1; if ( gamemode != retail ) if (wbs->epsd > 2) wbs->epsd -= 3; } void WI_Start(wbstartstruct_t* wbstartstruct) { WI_initVariables(wbstartstruct); WI_loadData(); if (deathmatch) WI_initDeathmatchStats(); else if (netgame) WI_initNetgameStats(); else WI_initStats(); } chocolate-doom-chocolate-doom-2.2.1/src/doom/wi_stuff.h000066400000000000000000000022141257432200600230300ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Intermission. // #ifndef __WI_STUFF__ #define __WI_STUFF__ //#include "v_video.h" #include "doomdef.h" // States for the intermission typedef enum { NoState = -1, StatCount, ShowNextLoc, } stateenum_t; // Called by main loop, animate the intermission. void WI_Ticker (void); // Called by main loop, // draws the intermission directly into the screen buffer. void WI_Drawer (void); // Setup for an intermission screen. void WI_Start(wbstartstruct_t* wbstartstruct); // Shut down the intermission screen void WI_End(void); #endif chocolate-doom-chocolate-doom-2.2.1/src/doomfeatures.h000066400000000000000000000020061257432200600227400ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // List of features which can be enabled/disabled to slim down the // program. // #ifndef DOOM_FEATURES_H #define DOOM_FEATURES_H // Enables wad merging (the '-merge' command line parameter) #define FEATURE_WAD_MERGE 1 // Enables dehacked support ('-deh') #define FEATURE_DEHACKED 1 // Enables multiplayer support (network games) #define FEATURE_MULTIPLAYER 1 // Enables sound output #define FEATURE_SOUND 1 #endif /* #ifndef DOOM_FEATURES_H */ chocolate-doom-chocolate-doom-2.2.1/src/doomkeys.h000066400000000000000000000046721257432200600221100ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Key definitions // #ifndef __DOOMKEYS__ #define __DOOMKEYS__ // // DOOM keyboard definition. // This is the stuff configured by Setup.Exe. // Most key data are simple ascii (uppercased). // #define KEY_RIGHTARROW 0xae #define KEY_LEFTARROW 0xac #define KEY_UPARROW 0xad #define KEY_DOWNARROW 0xaf #define KEY_ESCAPE 27 #define KEY_ENTER 13 #define KEY_TAB 9 #define KEY_F1 (0x80+0x3b) #define KEY_F2 (0x80+0x3c) #define KEY_F3 (0x80+0x3d) #define KEY_F4 (0x80+0x3e) #define KEY_F5 (0x80+0x3f) #define KEY_F6 (0x80+0x40) #define KEY_F7 (0x80+0x41) #define KEY_F8 (0x80+0x42) #define KEY_F9 (0x80+0x43) #define KEY_F10 (0x80+0x44) #define KEY_F11 (0x80+0x57) #define KEY_F12 (0x80+0x58) #define KEY_BACKSPACE 0x7f #define KEY_PAUSE 0xff #define KEY_EQUALS 0x3d #define KEY_MINUS 0x2d #define KEY_RSHIFT (0x80+0x36) #define KEY_RCTRL (0x80+0x1d) #define KEY_RALT (0x80+0x38) #define KEY_LALT KEY_RALT // new keys: #define KEY_CAPSLOCK (0x80+0x3a) #define KEY_NUMLOCK (0x80+0x45) #define KEY_SCRLCK (0x80+0x46) #define KEY_PRTSCR (0x80+0x59) #define KEY_HOME (0x80+0x47) #define KEY_END (0x80+0x4f) #define KEY_PGUP (0x80+0x49) #define KEY_PGDN (0x80+0x51) #define KEY_INS (0x80+0x52) #define KEY_DEL (0x80+0x53) #define KEYP_0 0 #define KEYP_1 KEY_END #define KEYP_2 KEY_DOWNARROW #define KEYP_3 KEY_PGDN #define KEYP_4 KEY_LEFTARROW #define KEYP_5 '5' #define KEYP_6 KEY_RIGHTARROW #define KEYP_7 KEY_HOME #define KEYP_8 KEY_UPARROW #define KEYP_9 KEY_PGUP #define KEYP_DIVIDE '/' #define KEYP_PLUS '+' #define KEYP_MINUS '-' #define KEYP_MULTIPLY '*' #define KEYP_PERIOD 0 #define KEYP_EQUALS KEY_EQUALS #define KEYP_ENTER KEY_ENTER #endif // __DOOMKEYS__ chocolate-doom-chocolate-doom-2.2.1/src/doomtype.h000066400000000000000000000046611257432200600221140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Simple basic typedefs, isolated here to make it easier // separating modules. // #ifndef __DOOMTYPE__ #define __DOOMTYPE__ #if defined(_MSC_VER) && !defined(__cplusplus) #define inline __inline #endif // #define macros to provide functions missing in Windows. // Outside Windows, we use strings.h for str[n]casecmp. #ifdef _WIN32 #define strcasecmp stricmp #define strncasecmp strnicmp #else #include #endif // // The packed attribute forces structures to be packed into the minimum // space necessary. If this is not done, the compiler may align structure // fields differently to optimize memory access, inflating the overall // structure size. It is important to use the packed attribute on certain // structures where alignment is important, particularly data read/written // to disk. // #ifdef __GNUC__ #ifdef __clang__ #define PACKEDATTR __attribute__((packed)) #else #define PACKEDATTR __attribute__((packed,gcc_struct)) #endif #else #define PACKEDATTR #endif // C99 integer types; with gcc we just use this. Other compilers // should add conditional statements that define the C99 types. // What is really wanted here is stdint.h; however, some old versions // of Solaris don't have stdint.h and only have inttypes.h (the // pre-standardisation version). inttypes.h is also in the C99 // standard and defined to include stdint.h, so include this. #include #ifdef __cplusplus // Use builtin bool type with C++. typedef bool boolean; #else typedef enum { false, true } boolean; #endif typedef uint8_t byte; #include #ifdef _WIN32 #define DIR_SEPARATOR '\\' #define DIR_SEPARATOR_S "\\" #define PATH_SEPARATOR ';' #else #define DIR_SEPARATOR '/' #define DIR_SEPARATOR_S "/" #define PATH_SEPARATOR ':' #endif #define arrlen(array) (sizeof(array) / sizeof(*array)) #endif chocolate-doom-chocolate-doom-2.2.1/src/gusconf.c000066400000000000000000000132071257432200600217070ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // GUS emulation code. // // Actually emulating a GUS is far too much work; fortunately // GUS "emulation" already exists in the form of Timidity, which // supports GUS patch files. This code therefore converts Doom's // DMXGUS lump into an equivalent Timidity configuration file. // #include #include #include #include #include "m_misc.h" #include "w_wad.h" #include "z_zone.h" #define MAX_INSTRUMENTS 256 typedef struct { char *patch_names[MAX_INSTRUMENTS]; int mapping[MAX_INSTRUMENTS]; } gus_config_t; char *gus_patch_path = ""; int gus_ram_kb = 1024; static unsigned int MappingIndex(void) { unsigned int result = gus_ram_kb / 256; if (result < 1) { return 1; } else if (result > 4) { return 4; } else { return result; } } static int SplitLine(char *line, char **fields, unsigned int max_fields) { unsigned int num_fields; char *p; fields[0] = line; num_fields = 1; for (p = line; *p != '\0'; ++p) { if (*p == ',') { *p = '\0'; // Skip spaces following the comma. do { ++p; } while (*p != '\0' && isspace(*p)); fields[num_fields] = p; ++num_fields; --p; if (num_fields >= max_fields) { break; } } else if (*p == '#') { *p = '\0'; break; } } // Strip off trailing whitespace from the end of the line. p = fields[num_fields - 1] + strlen(fields[num_fields - 1]); while (p > fields[num_fields - 1] && isspace(*(p - 1))) { --p; *p = '\0'; } return num_fields; } static void ParseLine(gus_config_t *config, char *line) { char *fields[6]; unsigned int num_fields; unsigned int instr_id, mapped_id; num_fields = SplitLine(line, fields, 6); if (num_fields < 6) { return; } instr_id = atoi(fields[0]); mapped_id = atoi(fields[MappingIndex()]); free(config->patch_names[instr_id]); config->patch_names[instr_id] = M_StringDuplicate(fields[5]); config->mapping[instr_id] = mapped_id; } static void ParseDMXConfig(char *dmxconf, gus_config_t *config) { char *p, *newline; unsigned int i; memset(config, 0, sizeof(gus_config_t)); for (i = 0; i < MAX_INSTRUMENTS; ++i) { config->mapping[i] = -1; } p = dmxconf; for (;;) { newline = strchr(p, '\n'); if (newline != NULL) { *newline = '\0'; } ParseLine(config, p); if (newline == NULL) { break; } else { p = newline + 1; } } } static void FreeDMXConfig(gus_config_t *config) { unsigned int i; for (i = 0; i < MAX_INSTRUMENTS; ++i) { free(config->patch_names[i]); } } static char *ReadDMXConfig(void) { int lumpnum; unsigned int len; char *data; // TODO: This should be chosen based on gamemode == commercial: lumpnum = W_CheckNumForName("DMXGUS"); if (lumpnum < 0) { lumpnum = W_GetNumForName("DMXGUSC"); } len = W_LumpLength(lumpnum); data = Z_Malloc(len + 1, PU_STATIC, NULL); W_ReadLump(lumpnum, data); return data; } static boolean WriteTimidityConfig(char *path, gus_config_t *config) { FILE *fstream; unsigned int i; fstream = fopen(path, "w"); if (fstream == NULL) { return false; } fprintf(fstream, "# Autogenerated Timidity config.\n\n"); fprintf(fstream, "dir %s\n", gus_patch_path); fprintf(fstream, "\nbank 0\n\n"); for (i = 0; i < 128; ++i) { if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS && config->patch_names[config->mapping[i]] != NULL) { fprintf(fstream, "%i %s\n", i, config->patch_names[config->mapping[i]]); } } fprintf(fstream, "\ndrumset 0\n\n"); for (i = 128 + 25; i < MAX_INSTRUMENTS; ++i) { if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS && config->patch_names[config->mapping[i]] != NULL) { fprintf(fstream, "%i %s\n", i - 128, config->patch_names[config->mapping[i]]); } } fprintf(fstream, "\n"); fclose(fstream); return true; } boolean GUS_WriteConfig(char *path) { boolean result; char *dmxconf; gus_config_t config; if (!strcmp(gus_patch_path, "")) { printf("You haven't configured gus_patch_path.\n"); printf("gus_patch_path needs to point to the location of " "your GUS patch set.\n" "To get a copy of the \"standard\" GUS patches, " "download a copy of dgguspat.zip.\n"); return false; } dmxconf = ReadDMXConfig(); ParseDMXConfig(dmxconf, &config); result = WriteTimidityConfig(path, &config); FreeDMXConfig(&config); Z_Free(dmxconf); return result; } chocolate-doom-chocolate-doom-2.2.1/src/gusconf.h000066400000000000000000000014271257432200600217150ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // GUS emulation code. // #ifndef __GUSCONF_H__ #define __GUSCONF_H__ #include "doomtype.h" extern char *gus_patch_path; extern int gus_ram_kb; boolean GUS_WriteConfig(char *path); #endif /* #ifndef __GUSCONF_H__ */ chocolate-doom-chocolate-doom-2.2.1/src/heretic.appdata.xml.in000066400000000000000000000034161257432200600242630ustar00rootroot00000000000000 @PROGRAM_PREFIX@heretic.desktop CC0-1.0 GPL-2.0+ @PACKAGE_MAINTAINER@ @PACKAGE_URL@ @PACKAGE_ISSUES@

@PACKAGE_SHORTNAME@ Heretic is a conservative, historically-accurate Heretic source port, which is compatible with mods and levels that were made before the Heretic source code was released. Unlike other source ports, the goal is to preserve the original look, feel, limitations, and bugs of the original DOS executable.

Full support for single- and multi-player games is provided. Unlike the original executable, network play is implemented on the IP network stack, allowing it to function on modern LANs and the Internet.

http://www.chocolate-doom.org/wiki/images/9/93/GNOME_Heretic_E5M4.png Level E5M4: Courtyard http://www.chocolate-doom.org/wiki/images/1/14/GNOME_Heretic_Shareware_DEMO3.png Shareware Level E1M9: The Graveyard http://www.chocolate-doom.org/wiki/images/3/34/GNOME_Heretic_E4M1.png Level E4M1: Catafalque http://www.chocolate-doom.org/wiki/images/4/42/GNOME_Heretic_Shareware_DEMO1.png Shareware Level E1M3: The Gatehouse
chocolate-doom-chocolate-doom-2.2.1/src/heretic.desktop.in000066400000000000000000000003351257432200600235200ustar00rootroot00000000000000[Desktop Entry] Name=@PACKAGE_SHORTNAME@ Heretic Exec=@PROGRAM_PREFIX@heretic Icon=@PROGRAM_PREFIX@doom Type=Application Comment=@PACKAGE_SHORTDESC@ Categories=Game;ActionGame; Keywords=first;person;shooter;doom;vanilla; chocolate-doom-chocolate-doom-2.2.1/src/heretic/000077500000000000000000000000001257432200600215175ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/src/heretic/.gitignore000066400000000000000000000000461257432200600235070ustar00rootroot00000000000000Makefile Makefile.in .deps tags TAGS chocolate-doom-chocolate-doom-2.2.1/src/heretic/Makefile.am000066400000000000000000000062121257432200600235540ustar00rootroot00000000000000 AM_CFLAGS=-I$(top_srcdir)/src \ -I$(top_srcdir)/textscreen \ @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@ noinst_LIBRARIES=libheretic.a SOURCE_FILES= \ am_data.h \ am_map.c am_map.h \ ct_chat.c ct_chat.h \ d_main.c \ d_net.c \ doomdata.h \ doomdef.h \ dstrings.h \ f_finale.c \ g_game.c \ info.c info.h \ in_lude.c \ m_random.c m_random.h \ mn_menu.c \ p_action.h \ p_ceilng.c \ p_doors.c \ p_enemy.c \ p_floor.c \ p_inter.c \ p_lights.c \ p_local.h \ p_map.c \ p_maputl.c \ p_mobj.c \ p_plats.c \ p_pspr.c \ p_saveg.c \ p_setup.c \ p_sight.c \ p_spec.c p_spec.h \ p_switch.c \ p_telept.c \ p_tick.c \ p_user.c \ r_bsp.c \ r_data.c \ r_draw.c \ r_local.h \ r_main.c \ r_plane.c \ r_segs.c \ r_things.c \ sb_bar.c \ sounds.c sounds.h \ s_sound.c s_sound.h FEATURE_DEHACKED_SOURCE_FILES = \ deh_ammo.c \ deh_frame.c \ deh_htext.c \ deh_htic.c deh_htic.h \ deh_sound.c \ deh_thing.c \ deh_weapon.c libheretic_a_SOURCES=$(SOURCE_FILES) \ $(FEATURE_DEHACKED_SOURCE_FILES) chocolate-doom-chocolate-doom-2.2.1/src/heretic/am_data.h000066400000000000000000000072621257432200600232650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // AM_data.h : The vector graphics for the automap #ifndef __AMDATA_H__ #define __AMDATA_H__ // a line drawing of the player pointing right, starting from the middle. #define R ((8*PLAYERRADIUS)/7) mline_t player_arrow[] = { { { -R+R/4, 0 }, { 0, 0} }, // center line. { { -R+R/4, R/8 }, { R, 0} }, // blade { { -R+R/4, -R/8 }, { R, 0 } }, { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece { { -R+R/8, -R/4 }, { -R+R/8, R/4 } }, { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors { { -R+R/8, R/4 }, { -R+R/4, R/4} }, { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel { { -R-R/4, R/8 }, { -R+R/8, R/8 } }, { { -R-R/4, -R/8}, { -R+R/8, -R/8 } } }; mline_t keysquare[] = { { { 0, 0 }, { R/4, -R/2 } }, { { R/4, -R/2 }, { R/2, -R/2 } }, { { R/2, -R/2 }, { R/2, R/2 } }, { { R/2, R/2 }, { R/4, R/2 } }, { { R/4, R/2 }, { 0, 0 } }, // handle part type thing { { 0, 0 }, { -R, 0 } }, // stem { { -R, 0 }, { -R, -R/2 } }, // end lockpick part { { -3*R/4, 0 }, { -3*R/4, -R/4 } } }; /*mline_t player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; */ #undef R #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) #define NUMKEYSQUARELINES (sizeof(keysquare)/sizeof(mline_t)) #define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/6 } }, // -----> { { R, 0 }, { R-R/2, -R/6 } }, { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >-----> { { -R+R/8, 0 }, { -R-R/8, -R/6 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>-----> { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } }, { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d---> { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } }, { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } }, { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd--> { { -R/6, -R/6 }, { 0, -R/6 } }, { { 0, -R/6 }, { 0, R/4 } }, { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt-> { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } }; #undef R #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) #define R (FRACUNIT) mline_t triangle_guy[] = { { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)(.867*R ), (fixed_t)(-.5*R) } }, { { (fixed_t)(.867*R ), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)(R ) } }, { { (fixed_t)(0 ), (fixed_t)(R ) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } }; #undef R #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) #define R (FRACUNIT) mline_t thintriangle_guy[] = { { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } }, { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } }, { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } }; #undef R #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) #endif chocolate-doom-chocolate-doom-2.2.1/src/heretic/am_map.c000066400000000000000000001204231257432200600231170ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // AM_map.c #include #include "doomdef.h" #include "deh_str.h" #include "i_video.h" #include "m_controls.h" #include "p_local.h" #include "am_map.h" #include "am_data.h" #include "doomkeys.h" #include "v_video.h" vertex_t KeyPoints[NUMKEYS]; #define NUMALIAS 3 // Number of antialiased lines. char *LevelNames[] = { // EPISODE 1 - THE CITY OF THE DAMNED "E1M1: THE DOCKS", "E1M2: THE DUNGEONS", "E1M3: THE GATEHOUSE", "E1M4: THE GUARD TOWER", "E1M5: THE CITADEL", "E1M6: THE CATHEDRAL", "E1M7: THE CRYPTS", "E1M8: HELL'S MAW", "E1M9: THE GRAVEYARD", // EPISODE 2 - HELL'S MAW "E2M1: THE CRATER", "E2M2: THE LAVA PITS", "E2M3: THE RIVER OF FIRE", "E2M4: THE ICE GROTTO", "E2M5: THE CATACOMBS", "E2M6: THE LABYRINTH", "E2M7: THE GREAT HALL", "E2M8: THE PORTALS OF CHAOS", "E2M9: THE GLACIER", // EPISODE 3 - THE DOME OF D'SPARIL "E3M1: THE STOREHOUSE", "E3M2: THE CESSPOOL", "E3M3: THE CONFLUENCE", "E3M4: THE AZURE FORTRESS", "E3M5: THE OPHIDIAN LAIR", "E3M6: THE HALLS OF FEAR", "E3M7: THE CHASM", "E3M8: D'SPARIL'S KEEP", "E3M9: THE AQUIFER", // EPISODE 4: THE OSSUARY "E4M1: CATAFALQUE", "E4M2: BLOCKHOUSE", "E4M3: AMBULATORY", "E4M4: SEPULCHER", "E4M5: GREAT STAIR", "E4M6: HALLS OF THE APOSTATE", "E4M7: RAMPARTS OF PERDITION", "E4M8: SHATTERED BRIDGE", "E4M9: MAUSOLEUM", // EPISODE 5: THE STAGNANT DEMESNE "E5M1: OCHRE CLIFFS", "E5M2: RAPIDS", "E5M3: QUAY", "E5M4: COURTYARD", "E5M5: HYDRATYR", "E5M6: COLONNADE", "E5M7: FOETID MANSE", "E5M8: FIELD OF JUDGEMENT", "E5M9: SKEIN OF D'SPARIL" }; static int cheating = 0; static int grid = 0; static int leveljuststarted = 1; // kluge until AM_LevelInit() is called boolean automapactive = false; static int finit_width = SCREENWIDTH; static int finit_height = SCREENHEIGHT - 42; static int f_x, f_y; // location of window on screen static int f_w, f_h; // size of window on screen static int lightlev; // used for funky strobing effect static byte *fb; // pseudo-frame buffer static int amclock; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords) static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords) static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords) // width/height of window on map (map coords) static fixed_t m_w, m_h; static fixed_t min_x, min_y; // based on level size static fixed_t max_x, max_y; // based on level size static fixed_t max_w, max_h; // max_x-min_x, max_y-min_y static fixed_t min_w, min_h; // based on player size static fixed_t min_scale_mtof; // used to tell when to stop zooming out static fixed_t max_scale_mtof; // used to tell when to stop zooming in // old stuff for recovery later static fixed_t old_m_w, old_m_h; static fixed_t old_m_x, old_m_y; // old location used by the Follower routine static mpoint_t f_oldloc; // used by MTOF to scale from map-to-frame-buffer coords static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow static vertex_t oldplr; //static patch_t *marknums[10]; // numbers used for marking by the automap //static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are //static int markpointnum = 0; // next point to be assigned static int followplayer = 1; // specifies whether to follow the player around static char cheat_amap[] = { 'r', 'a', 'v', 'm', 'a', 'p' }; static byte cheatcount = 0; extern boolean viewactive; static byte antialias[NUMALIAS][8] = { {96, 97, 98, 99, 100, 101, 102, 103}, {110, 109, 108, 107, 106, 105, 104, 103}, {75, 76, 77, 78, 79, 80, 81, 103} }; /* static byte *aliasmax[NUMALIAS] = { &antialias[0][7], &antialias[1][7], &antialias[2][7] };*/ static byte *maplump; // pointer to the raw data for the automap background. static short mapystart = 0; // y-value for the start of the map bitmap...used in the paralax stuff. static short mapxstart = 0; //x-value for the bitmap. //byte screens[][SCREENWIDTH*SCREENHEIGHT]; //void V_MarkRect (int x, int y, int width, int height); // Functions void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor, int NumLevels, unsigned short IntensityBits); // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so // that it can be used with the brain-dead drawing stuff. // Ripped out for Heretic /* void AM_getIslope(mline_t *ml, islope_t *is) { int dx, dy; dy = ml->a.y - ml->b.y; dx = ml->b.x - ml->a.x; if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX); else is->islp = FixedDiv(dx, dy); if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX); else is->slp = FixedDiv(dy, dx); } */ void AM_activateNewScale(void) { m_x += m_w / 2; m_y += m_h / 2; m_w = FTOM(f_w); m_h = FTOM(f_h); m_x -= m_w / 2; m_y -= m_h / 2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } void AM_saveScaleAndLoc(void) { old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; } void AM_restoreScaleAndLoc(void) { m_w = old_m_w; m_h = old_m_h; if (!followplayer) { m_x = old_m_x; m_y = old_m_y; } else { m_x = plr->mo->x - m_w / 2; m_y = plr->mo->y - m_h / 2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; // Change the scaling multipliers scale_mtof = FixedDiv(f_w << FRACBITS, m_w); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } // adds a marker at the current location /* void AM_addMark(void) { markpoints[markpointnum].x = m_x + m_w/2; markpoints[markpointnum].y = m_y + m_h/2; markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS; } */ void AM_findMinMaxBoundaries(void) { int i; fixed_t a, b; min_x = min_y = INT_MAX; max_x = max_y = -INT_MAX; for (i = 0; i < numvertexes; i++) { if (vertexes[i].x < min_x) min_x = vertexes[i].x; else if (vertexes[i].x > max_x) max_x = vertexes[i].x; if (vertexes[i].y < min_y) min_y = vertexes[i].y; else if (vertexes[i].y > max_y) max_y = vertexes[i].y; } max_w = max_x - min_x; max_h = max_y - min_y; min_w = 2 * PLAYERRADIUS; min_h = 2 * PLAYERRADIUS; a = FixedDiv(f_w << FRACBITS, max_w); b = FixedDiv(f_h << FRACBITS, max_h); min_scale_mtof = a < b ? a : b; max_scale_mtof = FixedDiv(f_h << FRACBITS, 2 * PLAYERRADIUS); } void AM_changeWindowLoc(void) { if (m_paninc.x || m_paninc.y) { followplayer = 0; f_oldloc.x = INT_MAX; } m_x += m_paninc.x; m_y += m_paninc.y; if (m_x + m_w / 2 > max_x) { m_x = max_x - m_w / 2; m_paninc.x = 0; } else if (m_x + m_w / 2 < min_x) { m_x = min_x - m_w / 2; m_paninc.x = 0; } if (m_y + m_h / 2 > max_y) { m_y = max_y - m_h / 2; m_paninc.y = 0; } else if (m_y + m_h / 2 < min_y) { m_y = min_y - m_h / 2; m_paninc.y = 0; } // The following code was commented out in the released Heretic source, // but I believe we need to do this here to stop the background moving // when we reach the map boundaries. (In the released source it's done // in AM_clearFB). mapxstart += MTOF(m_paninc.x+FRACUNIT/2); mapystart -= MTOF(m_paninc.y+FRACUNIT/2); if(mapxstart >= finit_width) mapxstart -= finit_width; if(mapxstart < 0) mapxstart += finit_width; if(mapystart >= finit_height) mapystart -= finit_height; if(mapystart < 0) mapystart += finit_height; // - end of code that was commented-out m_x2 = m_x + m_w; m_y2 = m_y + m_h; } void AM_initVariables(void) { int pnum; thinker_t *think; mobj_t *mo; //static event_t st_notify = { ev_keyup, AM_MSGENTERED }; automapactive = true; fb = I_VideoBuffer; f_oldloc.x = INT_MAX; amclock = 0; lightlev = 0; m_paninc.x = m_paninc.y = 0; ftom_zoommul = FRACUNIT; mtof_zoommul = FRACUNIT; m_w = FTOM(f_w); m_h = FTOM(f_h); // find player to center on initially if (!playeringame[pnum = consoleplayer]) for (pnum = 0; pnum < MAXPLAYERS; pnum++) if (playeringame[pnum]) break; plr = &players[pnum]; oldplr.x = plr->mo->x; oldplr.y = plr->mo->y; m_x = plr->mo->x - m_w / 2; m_y = plr->mo->y - m_h / 2; AM_changeWindowLoc(); // for saving & restoring old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; // load in the location of keys, if in baby mode memset(KeyPoints, 0, sizeof(vertex_t) * 3); if (gameskill == sk_baby) { for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { //not a mobj continue; } mo = (mobj_t *) think; if (mo->type == MT_CKEY) { KeyPoints[0].x = mo->x; KeyPoints[0].y = mo->y; } else if (mo->type == MT_AKYY) { KeyPoints[1].x = mo->x; KeyPoints[1].y = mo->y; } else if (mo->type == MT_BKYY) { KeyPoints[2].x = mo->x; KeyPoints[2].y = mo->y; } } } // inform the status bar of the change //c ST_Responder(&st_notify); } void AM_loadPics(void) { //int i; //char namebuf[9]; /* for (i=0;i<10;i++) { M_snprintf(namebuf, sizeof(namebuf), "AMMNUM%d", i); marknums[i] = W_CacheLumpName(namebuf, PU_STATIC); }*/ maplump = W_CacheLumpName(DEH_String("AUTOPAGE"), PU_STATIC); } /*void AM_unloadPics(void) { int i; for (i=0;i<10;i++) Z_ChangeTag(marknums[i], PU_CACHE); }*/ /* void AM_clearMarks(void) { int i; for (i=0;i max_scale_mtof) scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } static boolean stopped = true; void AM_Stop(void) { //static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED }; // AM_unloadPics(); automapactive = false; // ST_Responder(&st_notify); stopped = true; BorderNeedRefresh = true; } void AM_Start(void) { static int lastlevel = -1, lastepisode = -1; if (!stopped) AM_Stop(); stopped = false; if (gamestate != GS_LEVEL) { return; // don't show automap if we aren't in a game! } if (lastlevel != gamemap || lastepisode != gameepisode) { AM_LevelInit(); lastlevel = gamemap; lastepisode = gameepisode; } AM_initVariables(); AM_loadPics(); } // set the window scale to the maximum size void AM_minOutWindowScale(void) { scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // set the window scale to the minimum size void AM_maxOutWindowScale(void) { scale_mtof = max_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } boolean AM_Responder(event_t * ev) { int rc; int key; static int bigstate = 0; key = ev->data1; rc = false; if (!automapactive) { if (ev->type == ev_keydown && key == key_map_toggle && gamestate == GS_LEVEL) { AM_Start(); viewactive = false; // viewactive = true; rc = true; } } else if (ev->type == ev_keydown) { rc = true; if (key == key_map_east) // pan right { if (!followplayer) m_paninc.x = FTOM(F_PANINC); else rc = false; } else if (key == key_map_west) // pan left { if (!followplayer) m_paninc.x = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_north) // pan up { if (!followplayer) m_paninc.y = FTOM(F_PANINC); else rc = false; } else if (key == key_map_south) // pan down { if (!followplayer) m_paninc.y = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_zoomout) // zoom out { mtof_zoommul = M_ZOOMOUT; ftom_zoommul = M_ZOOMIN; } else if (key == key_map_zoomin) // zoom in { mtof_zoommul = M_ZOOMIN; ftom_zoommul = M_ZOOMOUT; } else if (key == key_map_toggle) // toggle map (tab) { bigstate = 0; viewactive = true; AM_Stop(); } else if (key == key_map_maxzoom) { bigstate = !bigstate; if (bigstate) { AM_saveScaleAndLoc(); AM_minOutWindowScale(); } else AM_restoreScaleAndLoc(); } else if (key == key_map_follow) { followplayer = !followplayer; f_oldloc.x = INT_MAX; P_SetMessage(plr, followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF, true); } /* else if (key == key_map_grid) { grid = !grid; plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF; } else if (key == key_map_mark) { M_snprintf(buffer, sizeof(buffer), "%s %d", AMSTR_MARKEDSPOT, markpointnum); plr->message = buffer; AM_addMark(); } else if (key == key_map_clearmark) { AM_clearMarks(); plr->message = AMSTR_MARKSCLEARED; } */ else { rc = false; } if (cheat_amap[cheatcount] == ev->data1 && !netgame) cheatcount++; else cheatcount = 0; if (cheatcount == 6) { cheatcount = 0; rc = false; cheating = (cheating + 1) % 3; } } else if (ev->type == ev_keyup) { rc = false; if (key == key_map_east) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_west) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_north) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_south) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_zoomout || key == key_map_zoomin) { mtof_zoommul = FRACUNIT; ftom_zoommul = FRACUNIT; } } return rc; } void AM_changeWindowScale(void) { // Change the scaling multipliers scale_mtof = FixedMul(scale_mtof, mtof_zoommul); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); if (scale_mtof < min_scale_mtof) AM_minOutWindowScale(); else if (scale_mtof > max_scale_mtof) AM_maxOutWindowScale(); else AM_activateNewScale(); } void AM_doFollowPlayer(void) { if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) { // m_x = FTOM(MTOF(plr->mo->x - m_w/2)); // m_y = FTOM(MTOF(plr->mo->y - m_h/2)); // m_x = plr->mo->x - m_w/2; // m_y = plr->mo->y - m_h/2; m_x = FTOM(MTOF(plr->mo->x)) - m_w / 2; m_y = FTOM(MTOF(plr->mo->y)) - m_h / 2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; // do the parallax parchment scrolling. /* dmapx = (MTOF(plr->mo->x)-MTOF(f_oldloc.x)); //fixed point dmapy = (MTOF(f_oldloc.y)-MTOF(plr->mo->y)); if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first dmapx=0; //goes into the automap. mapxstart += dmapx; mapystart += dmapy; while(mapxstart >= finit_width) mapxstart -= finit_width; while(mapxstart < 0) mapxstart += finit_width; while(mapystart >= finit_height) mapystart -= finit_height; while(mapystart < 0) mapystart += finit_height; */ f_oldloc.x = plr->mo->x; f_oldloc.y = plr->mo->y; } } // Ripped out for Heretic /* void AM_updateLightLev(void) { static nexttic = 0; //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 }; static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 }; static int litelevelscnt = 0; // Change light level if (amclock>nexttic) { lightlev = litelevels[litelevelscnt++]; if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0; nexttic = amclock + 6 - (amclock % 6); } } */ void AM_Ticker(void) { if (!automapactive) return; amclock++; if (followplayer) AM_doFollowPlayer(); // Change the zoom if necessary if (ftom_zoommul != FRACUNIT) AM_changeWindowScale(); // Change x,y location if (m_paninc.x || m_paninc.y) AM_changeWindowLoc(); // Update light level // AM_updateLightLev(); } void AM_clearFB(int color) { int i, j; int dmapx; int dmapy; if (followplayer) { dmapx = (MTOF(plr->mo->x) - MTOF(oldplr.x)); //fixed point dmapy = (MTOF(oldplr.y) - MTOF(plr->mo->y)); oldplr.x = plr->mo->x; oldplr.y = plr->mo->y; // if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first // dmapx=0; //goes into the automap. mapxstart += dmapx >> 1; mapystart += dmapy >> 1; while (mapxstart >= finit_width) mapxstart -= finit_width; while (mapxstart < 0) mapxstart += finit_width; while (mapystart >= finit_height) mapystart -= finit_height; while (mapystart < 0) mapystart += finit_height; } else { // The released Heretic source does this here, but this causes a bug // where the map background keeps moving when we reach the map // boundaries. This is instead done in AM_changeWindowLoc. /* mapxstart += (MTOF(m_paninc.x) >> 1); mapystart -= (MTOF(m_paninc.y) >> 1); if (mapxstart >= finit_width) mapxstart -= finit_width; if (mapxstart < 0) mapxstart += finit_width; if (mapystart >= finit_height) mapystart -= finit_height; if (mapystart < 0) mapystart += finit_height; */ } //blit the automap background to the screen. j = mapystart * finit_width; for (i = 0; i < finit_height; i++) { memcpy(I_VideoBuffer + i * finit_width, maplump + j + mapxstart, finit_width - mapxstart); memcpy(I_VideoBuffer + i * finit_width + finit_width - mapxstart, maplump + j, mapxstart); j += finit_width; if (j >= finit_height * finit_width) j = 0; } // memcpy(I_VideoBuffer, maplump, finit_width*finit_height); // memset(fb, color, f_w*f_h); } // Based on Cohen-Sutherland clipping algorithm but with a slightly // faster reject and precalculated slopes. If I need the speed, will // hash algorithm to the common cases. boolean AM_clipMline(mline_t * ml, fline_t * fl) { enum { LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 }; int outcode1 = 0, outcode2 = 0, outside; fpoint_t tmp = { 0, 0 }; int dx, dy; #define DOOUTCODE(oc, mx, my) \ (oc) = 0; \ if ((my) < 0) (oc) |= TOP; \ else if ((my) >= f_h) (oc) |= BOTTOM; \ if ((mx) < 0) (oc) |= LEFT; \ else if ((mx) >= f_w) (oc) |= RIGHT // do trivial rejects and outcodes if (ml->a.y > m_y2) outcode1 = TOP; else if (ml->a.y < m_y) outcode1 = BOTTOM; if (ml->b.y > m_y2) outcode2 = TOP; else if (ml->b.y < m_y) outcode2 = BOTTOM; if (outcode1 & outcode2) return false; // trivially outside if (ml->a.x < m_x) outcode1 |= LEFT; else if (ml->a.x > m_x2) outcode1 |= RIGHT; if (ml->b.x < m_x) outcode2 |= LEFT; else if (ml->b.x > m_x2) outcode2 |= RIGHT; if (outcode1 & outcode2) return false; // trivially outside // transform to frame-buffer coordinates. fl->a.x = CXMTOF(ml->a.x); fl->a.y = CYMTOF(ml->a.y); fl->b.x = CXMTOF(ml->b.x); fl->b.y = CYMTOF(ml->b.y); DOOUTCODE(outcode1, fl->a.x, fl->a.y); DOOUTCODE(outcode2, fl->b.x, fl->b.y); if (outcode1 & outcode2) return false; while (outcode1 | outcode2) { // may be partially inside box // find an outside point if (outcode1) outside = outcode1; else outside = outcode2; // clip to each side if (outside & TOP) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx * (fl->a.y)) / dy; tmp.y = 0; } else if (outside & BOTTOM) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx * (fl->a.y - f_h)) / dy; tmp.y = f_h - 1; } else if (outside & RIGHT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy * (f_w - 1 - fl->a.x)) / dx; tmp.x = f_w - 1; } else if (outside & LEFT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy * (-fl->a.x)) / dx; tmp.x = 0; } if (outside == outcode1) { fl->a = tmp; DOOUTCODE(outcode1, fl->a.x, fl->a.y); } else { fl->b = tmp; DOOUTCODE(outcode2, fl->b.x, fl->b.y); } if (outcode1 & outcode2) return false; // trivially outside } return true; } #undef DOOUTCODE // Classic Bresenham w/ whatever optimizations I need for speed void AM_drawFline(fline_t * fl, int color) { register int x, y, dx, dy, sx, sy, ax, ay, d; static int fuck = 0; switch (color) { case WALLCOLORS: DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[0][0], 8, 3); break; case FDWALLCOLORS: DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[1][0], 8, 3); break; case CDWALLCOLORS: DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[2][0], 8, 3); break; default: { // For debugging only if (fl->a.x < 0 || fl->a.x >= f_w || fl->a.y < 0 || fl->a.y >= f_h || fl->b.x < 0 || fl->b.x >= f_w || fl->b.y < 0 || fl->b.y >= f_h) { fprintf(stderr, "fuck %d \r", fuck++); return; } #define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO! dx = fl->b.x - fl->a.x; ax = 2 * (dx < 0 ? -dx : dx); sx = dx < 0 ? -1 : 1; dy = fl->b.y - fl->a.y; ay = 2 * (dy < 0 ? -dy : dy); sy = dy < 0 ? -1 : 1; x = fl->a.x; y = fl->a.y; if (ax > ay) { d = ay - ax / 2; while (1) { DOT(x, y, color); if (x == fl->b.x) return; if (d >= 0) { y += sy; d -= ax; } x += sx; d += ay; } } else { d = ax - ay / 2; while (1) { DOT(x, y, color); if (y == fl->b.y) return; if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; } } } } } /* Wu antialiased line drawer. * (X0,Y0),(X1,Y1) = line to draw * BaseColor = color # of first color in block used for antialiasing, the * 100% intensity version of the drawing color * NumLevels = size of color block, with BaseColor+NumLevels-1 being the * 0% intensity version of the drawing color * IntensityBits = log base 2 of NumLevels; the # of bits used to describe * the intensity of the drawing color. 2**IntensityBits==NumLevels */ void PUTDOT(short xx, short yy, byte * cc, byte * cm) { static int oldyy; static int oldyyshifted; byte *oldcc = cc; if (xx < 32) cc += 7 - (xx >> 2); else if (xx > (finit_width - 32)) cc += 7 - ((finit_width - xx) >> 2); // if(cc==oldcc) //make sure that we don't double fade the corners. // { if (yy < 32) cc += 7 - (yy >> 2); else if (yy > (finit_height - 32)) cc += 7 - ((finit_height - yy) >> 2); // } if (cc > cm && cm != NULL) { cc = cm; } else if (cc > oldcc + 6) // don't let the color escape from the fade table... { cc = oldcc + 6; } if (yy == oldyy + 1) { oldyy++; oldyyshifted += 320; } else if (yy == oldyy - 1) { oldyy--; oldyyshifted -= 320; } else if (yy != oldyy) { oldyy = yy; oldyyshifted = yy * 320; } fb[oldyyshifted + xx] = *(cc); // fb[(yy)*f_w+(xx)]=*(cc); } void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor, int NumLevels, unsigned short IntensityBits) { unsigned short IntensityShift, ErrorAdj, ErrorAcc; unsigned short ErrorAccTemp, Weighting, WeightingComplementMask; short DeltaX, DeltaY, Temp, XDir; /* Make sure the line runs top to bottom */ if (Y0 > Y1) { Temp = Y0; Y0 = Y1; Y1 = Temp; Temp = X0; X0 = X1; X1 = Temp; } /* Draw the initial pixel, which is always exactly intersected by the line and so needs no weighting */ PUTDOT(X0, Y0, &BaseColor[0], NULL); if ((DeltaX = X1 - X0) >= 0) { XDir = 1; } else { XDir = -1; DeltaX = -DeltaX; /* make DeltaX positive */ } /* Special-case horizontal, vertical, and diagonal lines, which require no weighting because they go right through the center of every pixel */ if ((DeltaY = Y1 - Y0) == 0) { /* Horizontal line */ while (DeltaX-- != 0) { X0 += XDir; PUTDOT(X0, Y0, &BaseColor[0], NULL); } return; } if (DeltaX == 0) { /* Vertical line */ do { Y0++; PUTDOT(X0, Y0, &BaseColor[0], NULL); } while (--DeltaY != 0); return; } //diagonal line. if (DeltaX == DeltaY) { do { X0 += XDir; Y0++; PUTDOT(X0, Y0, &BaseColor[0], NULL); } while (--DeltaY != 0); return; } /* Line is not horizontal, diagonal, or vertical */ ErrorAcc = 0; /* initialize the line error accumulator to 0 */ /* # of bits by which to shift ErrorAcc to get intensity level */ IntensityShift = 16 - IntensityBits; /* Mask used to flip all bits in an intensity weighting, producing the result (1 - intensity weighting) */ WeightingComplementMask = NumLevels - 1; /* Is this an X-major or Y-major line? */ if (DeltaY > DeltaX) { /* Y-major line; calculate 16-bit fixed-point fractional part of a pixel that X advances each time Y advances 1 pixel, truncating the result so that we won't overrun the endpoint along the X axis */ ErrorAdj = ((unsigned int) DeltaX << 16) / (unsigned int) DeltaY; /* Draw all pixels other than the first and last */ while (--DeltaY) { ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ ErrorAcc += ErrorAdj; /* calculate error for next pixel */ if (ErrorAcc <= ErrorAccTemp) { /* The error accumulator turned over, so advance the X coord */ X0 += XDir; } Y0++; /* Y-major, so always advance Y */ /* The IntensityBits most significant bits of ErrorAcc give us the intensity weighting for this pixel, and the complement of the weighting for the paired pixel */ Weighting = ErrorAcc >> IntensityShift; PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]); PUTDOT(X0 + XDir, Y0, &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]); } /* Draw the final pixel, which is always exactly intersected by the line and so needs no weighting */ PUTDOT(X1, Y1, &BaseColor[0], NULL); return; } /* It's an X-major line; calculate 16-bit fixed-point fractional part of a pixel that Y advances each time X advances 1 pixel, truncating the result to avoid overrunning the endpoint along the X axis */ ErrorAdj = ((unsigned int) DeltaY << 16) / (unsigned int) DeltaX; /* Draw all pixels other than the first and last */ while (--DeltaX) { ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ ErrorAcc += ErrorAdj; /* calculate error for next pixel */ if (ErrorAcc <= ErrorAccTemp) { /* The error accumulator turned over, so advance the Y coord */ Y0++; } X0 += XDir; /* X-major, so always advance X */ /* The IntensityBits most significant bits of ErrorAcc give us the intensity weighting for this pixel, and the complement of the weighting for the paired pixel */ Weighting = ErrorAcc >> IntensityShift; PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]); PUTDOT(X0, Y0 + 1, &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]); } /* Draw the final pixel, which is always exactly intersected by the line and so needs no weighting */ PUTDOT(X1, Y1, &BaseColor[0], NULL); } void AM_drawMline(mline_t * ml, int color) { static fline_t fl; if (AM_clipMline(ml, &fl)) AM_drawFline(&fl, color); // draws it on frame buffer using fb coords } void AM_drawGrid(int color) { fixed_t x, y; fixed_t start, end; mline_t ml; // Figure out start of vertical gridlines start = m_x; if ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS)) start += (MAPBLOCKUNITS << FRACBITS) - ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS)); end = m_x + m_w; // draw vertical gridlines ml.a.y = m_y; ml.b.y = m_y + m_h; for (x = start; x < end; x += (MAPBLOCKUNITS << FRACBITS)) { ml.a.x = x; ml.b.x = x; AM_drawMline(&ml, color); } // Figure out start of horizontal gridlines start = m_y; if ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS)) start += (MAPBLOCKUNITS << FRACBITS) - ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS)); end = m_y + m_h; // draw horizontal gridlines ml.a.x = m_x; ml.b.x = m_x + m_w; for (y = start; y < end; y += (MAPBLOCKUNITS << FRACBITS)) { ml.a.y = y; ml.b.y = y; AM_drawMline(&ml, color); } } void AM_drawWalls(void) { int i; static mline_t l; for (i = 0; i < numlines; i++) { l.a.x = lines[i].v1->x; l.a.y = lines[i].v1->y; l.b.x = lines[i].v2->x; l.b.y = lines[i].v2->y; if (cheating || (lines[i].flags & ML_MAPPED)) { if ((lines[i].flags & LINE_NEVERSEE) && !cheating) continue; if (!lines[i].backsector) { AM_drawMline(&l, WALLCOLORS + lightlev); } else { if (lines[i].special == 39) { // teleporters AM_drawMline(&l, WALLCOLORS + WALLRANGE / 2); } else if (lines[i].flags & ML_SECRET) // secret door { if (cheating) AM_drawMline(&l, 0); else AM_drawMline(&l, WALLCOLORS + lightlev); } else if (lines[i].special > 25 && lines[i].special < 35) { switch (lines[i].special) { case 26: case 32: AM_drawMline(&l, BLUEKEY); break; case 27: case 34: AM_drawMline(&l, YELLOWKEY); break; case 28: case 33: AM_drawMline(&l, GREENKEY); break; default: break; } } else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight) { AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change } else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight) { AM_drawMline(&l, CDWALLCOLORS + lightlev); // ceiling level change } else if (cheating) { AM_drawMline(&l, TSWALLCOLORS + lightlev); } } } else if (plr->powers[pw_allmap]) { if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS + 3); } } } void AM_rotate(fixed_t * x, fixed_t * y, angle_t a) { fixed_t tmpx; tmpx = FixedMul(*x, finecosine[a >> ANGLETOFINESHIFT]) - FixedMul(*y, finesine[a >> ANGLETOFINESHIFT]); *y = FixedMul(*x, finesine[a >> ANGLETOFINESHIFT]) + FixedMul(*y, finecosine[a >> ANGLETOFINESHIFT]); *x = tmpx; } void AM_drawLineCharacter(mline_t * lineguy, int lineguylines, fixed_t scale, angle_t angle, int color, fixed_t x, fixed_t y) { int i; mline_t l; for (i = 0; i < lineguylines; i++) { l.a.x = lineguy[i].a.x; l.a.y = lineguy[i].a.y; if (scale) { l.a.x = FixedMul(scale, l.a.x); l.a.y = FixedMul(scale, l.a.y); } if (angle) AM_rotate(&l.a.x, &l.a.y, angle); l.a.x += x; l.a.y += y; l.b.x = lineguy[i].b.x; l.b.y = lineguy[i].b.y; if (scale) { l.b.x = FixedMul(scale, l.b.x); l.b.y = FixedMul(scale, l.b.y); } if (angle) AM_rotate(&l.b.x, &l.b.y, angle); l.b.x += x; l.b.y += y; AM_drawMline(&l, color); } } void AM_drawPlayers(void) { int i; player_t *p; static int their_colors[] = { GREENKEY, YELLOWKEY, BLOODRED, BLUEKEY }; int their_color = -1; int color; if (!netgame) { /* if (cheating) AM_drawLineCharacter(cheat_player_arrow, NUMCHEATPLYRLINES, 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y); *///cheat key player pointer is the same as non-cheat pointer.. AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y); return; } for (i = 0; i < MAXPLAYERS; i++) { their_color++; p = &players[i]; if (deathmatch && !singledemo && p != plr) { continue; } if (!playeringame[i]) continue; if (p->powers[pw_invisibility]) color = 102; // *close* to the automap color else color = their_colors[their_color]; AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle, color, p->mo->x, p->mo->y); } } void AM_drawThings(int colors, int colorrange) { int i; mobj_t *t; for (i = 0; i < numsectors; i++) { t = sectors[i].thinglist; while (t) { AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16 << FRACBITS, t->angle, colors + lightlev, t->x, t->y); t = t->snext; } } } /* void AM_drawMarks(void) { int i, fx, fy, w, h; for (i=0;iwidth); h = SHORT(marknums[i]->height); fx = CXMTOF(markpoints[i].x); fy = CYMTOF(markpoints[i].y); if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h) V_DrawPatch(fx, fy, marknums[i]); } } } */ void AM_drawkeys(void) { if (KeyPoints[0].x != 0 || KeyPoints[0].y != 0) { AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, YELLOWKEY, KeyPoints[0].x, KeyPoints[0].y); } if (KeyPoints[1].x != 0 || KeyPoints[1].y != 0) { AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, GREENKEY, KeyPoints[1].x, KeyPoints[1].y); } if (KeyPoints[2].x != 0 || KeyPoints[2].y != 0) { AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, BLUEKEY, KeyPoints[2].x, KeyPoints[2].y); } } void AM_drawCrosshair(int color) { fb[(f_w * (f_h + 1)) / 2] = color; // single point for now } void AM_Drawer(void) { char *level_name; int numepisodes; if (!automapactive) return; UpdateState |= I_FULLSCRN; AM_clearFB(BACKGROUND); if (grid) AM_drawGrid(GRIDCOLORS); AM_drawWalls(); AM_drawPlayers(); if (cheating == 2) AM_drawThings(THINGCOLORS, THINGRANGE); // AM_drawCrosshair(XHAIRCOLORS); // AM_drawMarks(); if (gameskill == sk_baby) { AM_drawkeys(); } if (gamemode == retail) { numepisodes = 5; } else { numepisodes = 3; } if (gameepisode <= numepisodes && gamemap < 10) { level_name = LevelNames[(gameepisode - 1) * 9 + gamemap - 1]; MN_DrTextA(DEH_String(level_name), 20, 145); } // I_Update(); // V_MarkRect(f_x, f_y, f_w, f_h); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/am_map.h000066400000000000000000000055641257432200600231340ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __AMMAP_H__ #define __AMMAP_H__ // For use if I do walls with outsides/insides #define REDS 12*8 #define REDRANGE 1 //16 #define BLUES (256-4*16+8) #define BLUERANGE 1 //8 #define GREENS (33*8) #define GREENRANGE 1 //16 #define GRAYS (5*8) #define GRAYSRANGE 1 //16 #define BROWNS (14*8) #define BROWNRANGE 1 //16 #define YELLOWS 10*8 #define YELLOWRANGE 1 #define BLACK 0 #define WHITE 4*8 #define PARCH 13*8-1 #define BLOODRED 150 #define BLUEKEY 197 #define YELLOWKEY 144 #define GREENKEY 220 // Automap colors #define BACKGROUND PARCH #define YOURCOLORS WHITE #define YOURRANGE 0 #define WALLCOLORS REDS #define WALLRANGE REDRANGE #define TSWALLCOLORS GRAYS #define TSWALLRANGE GRAYSRANGE #define FDWALLCOLORS BROWNS #define FDWALLRANGE BROWNRANGE #define CDWALLCOLORS YELLOWS #define CDWALLRANGE YELLOWRANGE #define THINGCOLORS GREENS #define THINGRANGE GREENRANGE #define SECRETWALLCOLORS WALLCOLORS #define SECRETWALLRANGE WALLRANGE #define GRIDCOLORS (GRAYS + GRAYSRANGE/2) #define GRIDRANGE 0 #define XHAIRCOLORS GRAYS // drawing stuff #define FB 0 #define AM_NUMMARKPOINTS 10 #define AM_MSGHEADER (('a'<<24)+('m'<<16)) #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) #define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) #define INITSCALEMTOF (.2*FRACUNIT) // scale on entry // how much the automap moves window per tic in frame-buffer coordinates #define F_PANINC 4 // moves 140 pixels in 1 second // how much zoom-in per tic #define M_ZOOMIN ((int) (1.02*FRACUNIT)) // goes to 2x in 1 second // how much zoom-out per tic #define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // pulls out to 0.5x in 1 second // translates between frame-buffer and map distances #define FTOM(x) FixedMul(((x)<<16),scale_ftom) #define MTOF(x) (FixedMul((x),scale_mtof)>>16) // translates between frame-buffer and map coordinates #define CXMTOF(x) (f_x + MTOF((x)-m_x)) #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) // the following is crap #define LINE_NEVERSEE ML_DONTDRAW typedef struct { int x, y; } fpoint_t; typedef struct { fpoint_t a, b; } fline_t; typedef vertex_t mpoint_t; typedef struct { mpoint_t a, b; } mline_t; typedef struct { fixed_t slp, islp; } islope_t; // extern int f_x, f_y, f_w, f_h; #endif chocolate-doom-chocolate-doom-2.2.1/src/heretic/ct_chat.c000066400000000000000000000274041257432200600232770ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Chat mode // #include #include #include "doomdef.h" #include "doomkeys.h" #include "deh_str.h" #include "m_controls.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" #define QUEUESIZE 128 #define MESSAGESIZE 128 #define MESSAGELEN 265 #define CT_PLR_GREEN 1 #define CT_PLR_YELLOW 2 #define CT_PLR_RED 3 #define CT_PLR_BLUE 4 #define CT_PLR_ALL 5 #define CT_ESCAPE 6 // Public data boolean chatmodeon; // Private data void CT_queueChatChar(char ch); void CT_ClearChatMessage(int player); void CT_AddChar(int player, char c); void CT_BackSpace(int player); int head; int tail; byte ChatQueue[QUEUESIZE]; int chat_dest[MAXPLAYERS]; char chat_msg[MAXPLAYERS][MESSAGESIZE]; char plr_lastmsg[MAXPLAYERS][MESSAGESIZE + 9]; // add in the length of the pre-string int msgptr[MAXPLAYERS]; int msglen[MAXPLAYERS]; boolean cheated; static int FontABaseLump; char *CT_FromPlrText[MAXPLAYERS] = { "GREEN: ", "YELLOW: ", "RED: ", "BLUE: " }; char *chat_macros[10]; boolean altdown; boolean shiftdown; //=========================================================================== // // CT_Init // // Initialize chat mode data //=========================================================================== void CT_Init(void) { int i; head = 0; //initialize the queue index tail = 0; chatmodeon = false; memset(ChatQueue, 0, QUEUESIZE); for (i = 0; i < MAXPLAYERS; i++) { chat_dest[i] = 0; msgptr[i] = 0; memset(plr_lastmsg[i], 0, MESSAGESIZE); memset(chat_msg[i], 0, MESSAGESIZE); } FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1; return; } //=========================================================================== // // CT_Stop // //=========================================================================== void CT_Stop(void) { chatmodeon = false; return; } // These keys are allowed by Vanilla Heretic: static boolean ValidChatChar(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '!' || c == '?' || c == ' ' || c == '\'' || c == ',' || c == '.' || c == '-' || c == '='; } //=========================================================================== // // CT_Responder // //=========================================================================== boolean CT_Responder(event_t * ev) { char *macro; int sendto; if (!netgame) { return false; } if (ev->data1 == KEY_LALT || ev->data2 == KEY_RALT) { altdown = (ev->type == ev_keydown); return false; } if (ev->data1 == KEY_RSHIFT) { shiftdown = (ev->type == ev_keydown); return false; } if (ev->type != ev_keydown) { return false; } if (!chatmodeon) { sendto = 0; if (ev->data1 == key_multi_msg) { sendto = CT_PLR_ALL; } else if (ev->data1 == key_multi_msgplayer[0]) { sendto = CT_PLR_GREEN; } else if (ev->data1 == key_multi_msgplayer[1]) { sendto = CT_PLR_YELLOW; } else if (ev->data1 == key_multi_msgplayer[2]) { sendto = CT_PLR_RED; } else if (ev->data1 == key_multi_msgplayer[3]) { sendto = CT_PLR_BLUE; } if (sendto == 0 || (sendto != CT_PLR_ALL && !playeringame[sendto - 1]) || sendto == consoleplayer + 1) { return false; } CT_queueChatChar(sendto); chatmodeon = true; return true; } else { if (altdown) { if (ev->data1 >= '0' && ev->data1 <= '9') { if (ev->data1 == '0') { // macro 0 comes after macro 9 ev->data1 = '9' + 1; } macro = chat_macros[ev->data1 - '1']; CT_queueChatChar(KEY_ENTER); //send old message CT_queueChatChar(chat_dest[consoleplayer]); // chose the dest. while (*macro) { CT_queueChatChar(toupper(*macro++)); } CT_queueChatChar(KEY_ENTER); //send it off... CT_Stop(); return true; } } if (ev->data1 == KEY_ENTER) { CT_queueChatChar(KEY_ENTER); CT_Stop(); return true; } else if (ev->data1 == KEY_ESCAPE) { CT_queueChatChar(CT_ESCAPE); CT_Stop(); return true; } else if (ev->data1 == KEY_BACKSPACE) { CT_queueChatChar(KEY_BACKSPACE); return true; } else if (ValidChatChar(ev->data2)) { CT_queueChatChar(toupper(ev->data2)); return true; } } return false; } //=========================================================================== // // CT_Ticker // //=========================================================================== void CT_Ticker(void) { int i; int j; char c; int numplayers; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) { continue; } if ((c = players[i].cmd.chatchar) != 0) { if (c <= 5) { chat_dest[i] = c; continue; } else if (c == CT_ESCAPE) { CT_ClearChatMessage(i); } else if (c == KEY_ENTER) { numplayers = 0; for (j = 0; j < MAXPLAYERS; j++) { numplayers += playeringame[j]; } CT_AddChar(i, 0); // set the end of message character if (numplayers > 2) { M_StringCopy(plr_lastmsg[i], DEH_String(CT_FromPlrText[i]), sizeof(plr_lastmsg[i])); M_StringConcat(plr_lastmsg[i], chat_msg[i], sizeof(plr_lastmsg[i])); } else { M_StringCopy(plr_lastmsg[i], chat_msg[i], sizeof(plr_lastmsg[i])); } if (i != consoleplayer && (chat_dest[i] == consoleplayer + 1 || chat_dest[i] == CT_PLR_ALL) && *chat_msg[i]) { P_SetMessage(&players[consoleplayer], plr_lastmsg[i], true); S_StartSound(NULL, sfx_chat); } else if (i == consoleplayer && (*chat_msg[i])) { if (numplayers > 1) { P_SetMessage(&players[consoleplayer], DEH_String("-MESSAGE SENT-"), true); S_StartSound(NULL, sfx_chat); } else { P_SetMessage(&players[consoleplayer], DEH_String("THERE ARE NO OTHER PLAYERS IN THE GAME!"), true); S_StartSound(NULL, sfx_chat); } } CT_ClearChatMessage(i); } else if (c == KEY_BACKSPACE) { CT_BackSpace(i); } else { CT_AddChar(i, c); } } } return; } //=========================================================================== // // CT_Drawer // //=========================================================================== void CT_Drawer(void) { int i; int x; patch_t *patch; if (chatmodeon) { x = 25; for (i = 0; i < msgptr[consoleplayer]; i++) { if (chat_msg[consoleplayer][i] < 33) { x += 6; } else { patch = W_CacheLumpNum(FontABaseLump + chat_msg[consoleplayer][i] - 33, PU_CACHE); V_DrawPatch(x, 10, patch); x += patch->width; } } V_DrawPatch(x, 10, W_CacheLumpName(DEH_String("FONTA59"), PU_CACHE)); BorderTopRefresh = true; UpdateState |= I_MESSAGES; } } //=========================================================================== // // CT_queueChatChar // //=========================================================================== void CT_queueChatChar(char ch) { if (((tail + 1) & (QUEUESIZE - 1)) == head) { // the queue is full return; } ChatQueue[tail] = ch; tail = (tail + 1) & (QUEUESIZE - 1); } //=========================================================================== // // CT_dequeueChatChar // //=========================================================================== char CT_dequeueChatChar(void) { byte temp; if (head == tail) { // queue is empty return 0; } temp = ChatQueue[head]; head = (head + 1) & (QUEUESIZE - 1); return temp; } //=========================================================================== // // CT_AddChar // //=========================================================================== void CT_AddChar(int player, char c) { patch_t *patch; if (msgptr[player] + 1 >= MESSAGESIZE || msglen[player] >= MESSAGELEN) { // full. return; } chat_msg[player][msgptr[player]] = c; msgptr[player]++; if (c < 33) { msglen[player] += 6; } else { patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); msglen[player] += patch->width; } } //=========================================================================== // // CT_BackSpace // // Backs up a space, when the user hits (obviously) backspace //=========================================================================== void CT_BackSpace(int player) { patch_t *patch; char c; if (msgptr[player] == 0) { // message is already blank return; } msgptr[player]--; c = chat_msg[player][msgptr[player]]; if (c < 33) { msglen[player] -= 6; } else { patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); msglen[player] -= patch->width; } chat_msg[player][msgptr[player]] = 0; } //=========================================================================== // // CT_ClearChatMessage // // Clears out the data for the chat message, but the player's message // is still saved in plrmsg. //=========================================================================== void CT_ClearChatMessage(int player) { memset(chat_msg[player], 0, MESSAGESIZE); msgptr[player] = 0; msglen[player] = 0; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/ct_chat.h000066400000000000000000000020001257432200600232650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Chat mode stuff // #ifndef HERETIC_CT_CHAT_H #define HERETIC_CT_CHAT_H #define CT_PLR_GREEN 1 #define CT_PLR_YELLOW 2 #define CT_PLR_RED 3 #define CT_PLR_BLUE 4 #define CT_PLR_ALL 5 #define CT_KEY_GREEN 'g' #define CT_KEY_YELLOW 'y' #define CT_KEY_RED 'r' #define CT_KEY_BLUE 'b' #define CT_KEY_ALL 't' extern char *chat_macros[10]; #endif /* #ifndef HERETIC_CT_CHAT_H */ chocolate-doom-chocolate-doom-2.2.1/src/heretic/d_main.c000066400000000000000000000622221257432200600231160ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // D_main.c #include #include #include "doomfeatures.h" #include "txt_main.h" #include "txt_io.h" #include "net_client.h" #include "config.h" #include "ct_chat.h" #include "doomdef.h" #include "deh_main.h" #include "d_iwad.h" #include "i_endoom.h" #include "i_joystick.h" #include "i_sound.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "m_argv.h" #include "m_config.h" #include "m_controls.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" #include "w_main.h" #include "v_video.h" #define CT_KEY_GREEN 'g' #define CT_KEY_YELLOW 'y' #define CT_KEY_RED 'r' #define CT_KEY_BLUE 'b' #define STARTUP_WINDOW_X 17 #define STARTUP_WINDOW_Y 7 GameMode_t gamemode = indetermined; char *gamedescription = "unknown"; boolean nomonsters; // checkparm of -nomonsters boolean respawnparm; // checkparm of -respawn boolean debugmode; // checkparm of -debug boolean ravpic; // checkparm of -ravpic boolean cdrom; // true if cd-rom mode active boolean noartiskip; // whether shift-enter skips an artifact skill_t startskill; int startepisode; int startmap; int UpdateState; static int graphical_startup = 1; static boolean using_graphical_startup; static boolean main_loop_started = false; boolean autostart; extern boolean automapactive; boolean advancedemo; FILE *debugfile; static int show_endoom = 1; void D_ConnectNetGame(void); void D_CheckNetGame(void); void D_PageDrawer(void); void D_AdvanceDemo(void); boolean F_Responder(event_t * ev); //--------------------------------------------------------------------------- // // PROC D_ProcessEvents // // Send all the events of the given timestamp down the responder chain. // //--------------------------------------------------------------------------- void D_ProcessEvents(void) { event_t *ev; while ((ev = D_PopEvent()) != NULL) { if (F_Responder(ev)) { continue; } if (MN_Responder(ev)) { continue; } G_Responder(ev); } } //--------------------------------------------------------------------------- // // PROC DrawMessage // //--------------------------------------------------------------------------- void DrawMessage(void) { player_t *player; player = &players[consoleplayer]; if (player->messageTics <= 0 || !player->message) { // No message return; } MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message) / 2, 1); } //--------------------------------------------------------------------------- // // PROC D_Display // // Draw current display, possibly wiping it from the previous. // //--------------------------------------------------------------------------- void R_ExecuteSetViewSize(void); extern boolean finalestage; void D_Display(void) { extern boolean askforquit; // Change the view size if needed if (setsizeneeded) { R_ExecuteSetViewSize(); } // // do buffered drawing // switch (gamestate) { case GS_LEVEL: if (!gametic) break; if (automapactive) AM_Drawer(); else R_RenderPlayerView(&players[displayplayer]); CT_Drawer(); UpdateState |= I_FULLVIEW; SB_Drawer(); break; case GS_INTERMISSION: IN_Drawer(); break; case GS_FINALE: F_Drawer(); break; case GS_DEMOSCREEN: D_PageDrawer(); break; } if (testcontrols) { V_DrawMouseSpeedBox(testcontrols_mousespeed); } if (paused && !MenuActive && !askforquit) { if (!netgame) { V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName(DEH_String("PAUSED"), PU_CACHE)); } else { V_DrawPatch(160, 70, W_CacheLumpName(DEH_String("PAUSED"), PU_CACHE)); } } // Handle player messages DrawMessage(); // Menu drawing MN_Drawer(); // Send out any new accumulation NetUpdate(); // Flush buffered stuff to screen I_FinishUpdate(); } // // D_GrabMouseCallback // // Called to determine whether to grab the mouse pointer // boolean D_GrabMouseCallback(void) { // when menu is active or game is paused, release the mouse if (MenuActive || paused) return false; // only grab mouse when playing levels (but not demos) return (gamestate == GS_LEVEL) && !demoplayback && !advancedemo; } //--------------------------------------------------------------------------- // // PROC D_DoomLoop // //--------------------------------------------------------------------------- void D_DoomLoop(void) { if (M_CheckParm("-debugfile")) { char filename[20]; M_snprintf(filename, sizeof(filename), "debug%i.txt", consoleplayer); debugfile = fopen(filename, "w"); } I_GraphicsCheckCommandLine(); I_SetGrabMouseCallback(D_GrabMouseCallback); I_InitGraphics(); main_loop_started = true; while (1) { // Frame syncronous IO operations I_StartFrame(); // Process one or more tics // Will run at least one tic TryRunTics(); // Move positional sounds S_UpdateSounds(players[consoleplayer].mo); D_Display(); } } /* =============================================================================== DEMO LOOP =============================================================================== */ int demosequence; int pagetic; char *pagename; /* ================ = = D_PageTicker = = Handles timing for warped projection = ================ */ void D_PageTicker(void) { if (--pagetic < 0) D_AdvanceDemo(); } /* ================ = = D_PageDrawer = ================ */ void D_PageDrawer(void) { V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE)); if (demosequence == 1) { V_DrawPatch(4, 160, W_CacheLumpName(DEH_String("ADVISOR"), PU_CACHE)); } UpdateState |= I_FULLSCRN; } /* ================= = = D_AdvanceDemo = = Called after each demo or intro demosequence finishes ================= */ void D_AdvanceDemo(void) { advancedemo = true; } void D_DoAdvanceDemo(void) { players[consoleplayer].playerstate = PST_LIVE; // don't reborn advancedemo = false; usergame = false; // can't save / end game here paused = false; gameaction = ga_nothing; demosequence = (demosequence + 1) % 7; switch (demosequence) { case 0: pagetic = 210; gamestate = GS_DEMOSCREEN; pagename = DEH_String("TITLE"); S_StartSong(mus_titl, false); break; case 1: pagetic = 140; gamestate = GS_DEMOSCREEN; pagename = DEH_String("TITLE"); break; case 2: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; G_DeferedPlayDemo(DEH_String("demo1")); break; case 3: pagetic = 200; gamestate = GS_DEMOSCREEN; pagename = DEH_String("CREDIT"); break; case 4: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; G_DeferedPlayDemo(DEH_String("demo2")); break; case 5: pagetic = 200; gamestate = GS_DEMOSCREEN; if (gamemode == shareware) { pagename = DEH_String("ORDER"); } else { pagename = DEH_String("CREDIT"); } break; case 6: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; G_DeferedPlayDemo(DEH_String("demo3")); break; } } /* ================= = = D_StartTitle = ================= */ void D_StartTitle(void) { gameaction = ga_nothing; demosequence = -1; D_AdvanceDemo(); } /* ============== = = D_CheckRecordFrom = = -recordfrom ============== */ void D_CheckRecordFrom(void) { int p; char *filename; //! // @vanilla // @category demo // @arg // // Record a demo, loading from the given filename. Equivalent // to -loadgame -record . p = M_CheckParmWithArgs("-recordfrom", 2); if (!p) return; filename = SV_Filename(myargv[p + 1][0] - '0'); G_LoadGame(filename); G_DoLoadGame(); // load the gameskill etc info from savegame G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]); D_DoomLoop(); // never returns free(filename); } /* =============== = = D_AddFile = =============== */ // MAPDIR should be defined as the directory that holds development maps // for the -wart # # command #define MAPDIR "\\data\\" #define SHAREWAREWADNAME "heretic1.wad" char *iwadfile; char *basedefault = "heretic.cfg"; void wadprintf(void) { if (debugmode) { return; } // haleyjd FIXME: convert to textscreen code? #ifdef __WATCOMC__ _settextposition(23, 2); _setbkcolor(1); _settextcolor(0); _outtext(exrnwads); _settextposition(24, 2); _outtext(exrnwads2); #endif } boolean D_AddFile(char *file) { wad_file_t *handle; printf(" adding %s\n", file); handle = W_AddFile(file); return handle != NULL; } //========================================================== // // Startup Thermo code // //========================================================== #define MSG_Y 9 #define THERM_X 14 #define THERM_Y 14 int thermMax; int thermCurrent; char smsg[80]; // status bar line // // Heretic startup screen shit // static int startup_line = STARTUP_WINDOW_Y; void hprintf(char *string) { if (using_graphical_startup) { TXT_BGColor(TXT_COLOR_CYAN, 0); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_GotoXY(STARTUP_WINDOW_X, startup_line); ++startup_line; TXT_Puts(string); TXT_UpdateScreen(); } // haleyjd: shouldn't be WATCOMC-only if (debugmode) puts(string); } void drawstatus(void) { int i; TXT_GotoXY(1, 24); TXT_BGColor(TXT_COLOR_BLUE, 0); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); for (i=0; smsg[i] != '\0'; ++i) { TXT_PutChar(smsg[i]); } } void status(char *string) { if (using_graphical_startup) { M_StringConcat(smsg, string, sizeof(smsg)); drawstatus(); } } void DrawThermo(void) { static int last_progress = -1; int progress; int i; if (!using_graphical_startup) { return; } #if 0 progress = (98 * thermCurrent) / thermMax; screen = (char *) 0xb8000 + (THERM_Y * 160 + THERM_X * 2); for (i = 0; i < progress / 2; i++) { switch (i) { case 4: case 9: case 14: case 19: case 29: case 34: case 39: case 44: *screen++ = 0xb3; *screen++ = (THERMCOLOR << 4) + 15; break; case 24: *screen++ = 0xba; *screen++ = (THERMCOLOR << 4) + 15; break; default: *screen++ = 0xdb; *screen++ = 0x40 + THERMCOLOR; break; } } if (progress & 1) { *screen++ = 0xdd; *screen++ = 0x40 + THERMCOLOR; } #else // No progress? Don't update the screen. progress = (50 * thermCurrent) / thermMax + 2; if (last_progress == progress) { return; } last_progress = progress; TXT_GotoXY(THERM_X, THERM_Y); TXT_FGColor(TXT_COLOR_BRIGHT_GREEN); TXT_BGColor(TXT_COLOR_GREEN, 0); for (i = 0; i < progress; i++) { TXT_PutChar(0xdb); } TXT_UpdateScreen(); #endif } void initStartup(void) { byte *textScreen; byte *loading; if (!graphical_startup || debugmode || testcontrols) { using_graphical_startup = false; return; } if (!TXT_Init()) { using_graphical_startup = false; return; } I_InitWindowTitle(); I_InitWindowIcon(); // Blit main screen textScreen = TXT_GetScreenData(); loading = W_CacheLumpName(DEH_String("LOADING"), PU_CACHE); memcpy(textScreen, loading, 4000); // Print version string TXT_BGColor(TXT_COLOR_RED, 0); TXT_FGColor(TXT_COLOR_YELLOW); TXT_GotoXY(46, 2); TXT_Puts(HERETIC_VERSION_TEXT); TXT_UpdateScreen(); using_graphical_startup = true; } static void finishStartup(void) { if (using_graphical_startup) { TXT_Shutdown(); } } char tmsg[300]; void tprintf(char *msg, int initflag) { // haleyjd FIXME: convert to textscreen code? #ifdef __WATCOMC__ char temp[80]; int start; int add; int i; if (initflag) tmsg[0] = 0; M_StringConcat(tmsg, msg, sizeof(tmsg)); blitStartup(); DrawThermo(); _setbkcolor(4); _settextcolor(15); for (add = start = i = 0; i <= strlen(tmsg); i++) if ((tmsg[i] == '\n') || (!tmsg[i])) { memset(temp, 0, 80); M_StringCopy(temp, tmsg + start, sizeof(temp)); if (i - start < sizeof(temp)) { temp[i - start] = '\0'; } _settextposition(MSG_Y + add, 40 - strlen(temp) / 2); _outtext(temp); start = i + 1; add++; } _settextposition(25, 1); drawstatus(); #else printf("%s", msg); #endif } // haleyjd: moved up, removed WATCOMC code void CleanExit(void) { DEH_printf("Exited from HERETIC.\n"); exit(1); } void CheckAbortStartup(void) { // haleyjd: removed WATCOMC // haleyjd FIXME: this should actually work in text mode too, but how to // get input before SDL video init? if(using_graphical_startup) { if(TXT_GetChar() == 27) CleanExit(); } } void IncThermo(void) { thermCurrent++; DrawThermo(); CheckAbortStartup(); } void InitThermo(int max) { thermMax = max; thermCurrent = 0; } // // Add configuration file variable bindings. // void D_BindVariables(void) { extern int screenblocks; extern int snd_Channels; int i; M_ApplyPlatformDefaults(); I_BindVideoVariables(); I_BindJoystickVariables(); I_BindSoundVariables(); M_BindBaseControls(); M_BindHereticControls(); M_BindWeaponControls(); M_BindChatControls(MAXPLAYERS); key_multi_msgplayer[0] = CT_KEY_GREEN; key_multi_msgplayer[1] = CT_KEY_YELLOW; key_multi_msgplayer[2] = CT_KEY_RED; key_multi_msgplayer[3] = CT_KEY_BLUE; M_BindMenuControls(); M_BindMapControls(); M_BindIntVariable("mouse_sensitivity", &mouseSensitivity); M_BindIntVariable("sfx_volume", &snd_MaxVolume); M_BindIntVariable("music_volume", &snd_MusicVolume); M_BindIntVariable("screenblocks", &screenblocks); M_BindIntVariable("snd_channels", &snd_Channels); M_BindIntVariable("show_endoom", &show_endoom); M_BindIntVariable("graphical_startup", &graphical_startup); for (i=0; i<10; ++i) { char buf[12]; M_snprintf(buf, sizeof(buf), "chatmacro%i", i); M_BindStringVariable(buf, &chat_macros[i]); } } // // Called at exit to display the ENDOOM screen (ENDTEXT in Heretic) // static void D_Endoom(void) { byte *endoom_data; // Disable ENDOOM? if (!show_endoom || testcontrols || !main_loop_started) { return; } endoom_data = W_CacheLumpName(DEH_String("ENDTEXT"), PU_STATIC); I_Endoom(endoom_data); } //--------------------------------------------------------------------------- // // PROC D_DoomMain // //--------------------------------------------------------------------------- void D_DoomMain(void) { GameMission_t gamemission; int p; char file[256]; char demolumpname[9]; I_PrintBanner(PACKAGE_STRING); I_AtExit(D_Endoom, false); //! // @vanilla // // Disable monsters. // nomonsters = M_ParmExists("-nomonsters"); //! // @vanilla // // Monsters respawn after being killed. // respawnparm = M_ParmExists("-respawn"); //! // @vanilla // // Take screenshots when F1 is pressed. // ravpic = M_ParmExists("-ravpic"); //! // @vanilla // // Allow artifacts to be used when the run key is held down. // noartiskip = M_ParmExists("-noartiskip"); debugmode = M_ParmExists("-debug"); startskill = sk_medium; startepisode = 1; startmap = 1; autostart = false; // // get skill / episode / map from parms // //! // @vanilla // @category net // // Start a deathmatch game. // if (M_ParmExists("-deathmatch")) { deathmatch = true; } //! // @arg // @vanilla // // Set the game skill, 1-5 (1: easiest, 5: hardest). A skill of // 0 disables all monsters. // p = M_CheckParmWithArgs("-skill", 1); if (p) { startskill = myargv[p + 1][0] - '1'; autostart = true; } //! // @arg // @vanilla // // Start playing on episode n (1-4) // p = M_CheckParmWithArgs("-episode", 1); if (p) { startepisode = myargv[p + 1][0] - '0'; startmap = 1; autostart = true; } //! // @arg // @vanilla // // Start a game immediately, warping to level ExMy. // p = M_CheckParmWithArgs("-warp", 2); if (p && p < myargc - 2) { startepisode = myargv[p + 1][0] - '0'; startmap = myargv[p + 2][0] - '0'; autostart = true; } // // init subsystems // DEH_printf("V_Init: allocate screens.\n"); V_Init(); // Check for -CDROM cdrom = false; #ifdef _WIN32 //! // @platform windows // @vanilla // // Save configuration data and savegames in c:\heretic.cd, // allowing play from CD. // if (M_CheckParm("-cdrom")) { cdrom = true; } #endif if (cdrom) { M_SetConfigDir(DEH_String("c:\\heretic.cd")); } else { M_SetConfigDir(NULL); } // Load defaults before initing other systems DEH_printf("M_LoadDefaults: Load system defaults.\n"); D_BindVariables(); M_SetConfigFilenames("heretic.cfg", PROGRAM_PREFIX "heretic.cfg"); M_LoadDefaults(); I_AtExit(M_SaveDefaults, false); DEH_printf("Z_Init: Init zone memory allocation daemon.\n"); Z_Init(); DEH_printf("W_Init: Init WADfiles.\n"); iwadfile = D_FindIWAD(IWAD_MASK_HERETIC, &gamemission); if (iwadfile == NULL) { I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n" "one with the '-iwad' command line parameter."); } D_AddFile(iwadfile); W_CheckCorrectIWAD(heretic); #ifdef FEATURE_DEHACKED // Load dehacked patches specified on the command line. DEH_ParseCommandLine(); #endif // Load PWAD files. W_ParseCommandLine(); //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp. // p = M_CheckParmWithArgs("-playdemo", 1); if (!p) { //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp, determining the framerate // of the screen. // p = M_CheckParmWithArgs("-timedemo", 1); } if (p) { char *uc_filename = strdup(myargv[p + 1]); M_ForceUppercase(uc_filename); // In Vanilla, the filename must be specified without .lmp, // but make that optional. if (M_StringEndsWith(uc_filename, ".LMP")) { M_StringCopy(file, myargv[p + 1], sizeof(file)); } else { DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p + 1]); } free(uc_filename); if (D_AddFile(file)) { M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name, sizeof(demolumpname)); } else { // The file failed to load, but copy the original arg as a // demo name to make tricks like -playdemo demo1 possible. M_StringCopy(demolumpname, myargv[p + 1], sizeof(demolumpname)); } printf("Playing demo %s.\n", file); } if (W_CheckNumForName(DEH_String("E2M1")) == -1) { gamemode = shareware; gamedescription = "Heretic (shareware)"; } else if (W_CheckNumForName("EXTENDED") != -1) { // Presence of the EXTENDED lump indicates the retail version gamemode = retail; gamedescription = "Heretic: Shadow of the Serpent Riders"; } else { gamemode = registered; gamedescription = "Heretic (registered)"; } I_SetWindowTitle(gamedescription); savegamedir = M_GetSaveGameDir("heretic.wad"); I_PrintStartupBanner(gamedescription); if (M_ParmExists("-testcontrols")) { startepisode = 1; startmap = 1; autostart = true; testcontrols = true; } I_InitTimer(); I_InitSound(false); I_InitMusic(); #ifdef FEATURE_MULTIPLAYER tprintf("NET_Init: Init network subsystem.\n", 1); NET_Init (); #endif D_ConnectNetGame(); // haleyjd: removed WATCOMC initStartup(); // // Build status bar line! // smsg[0] = 0; if (deathmatch) status(DEH_String("DeathMatch...")); if (nomonsters) status(DEH_String("No Monsters...")); if (respawnparm) status(DEH_String("Respawning...")); if (autostart) { char temp[64]; DEH_snprintf(temp, sizeof(temp), "Warp to Episode %d, Map %d, Skill %d ", startepisode, startmap, startskill + 1); status(temp); } wadprintf(); // print the added wadfiles tprintf(DEH_String("MN_Init: Init menu system.\n"), 1); MN_Init(); CT_Init(); tprintf(DEH_String("R_Init: Init Heretic refresh daemon."), 1); hprintf(DEH_String("Loading graphics")); R_Init(); tprintf("\n", 0); tprintf(DEH_String("P_Init: Init Playloop state.\n"), 1); hprintf(DEH_String("Init game engine.")); P_Init(); IncThermo(); tprintf(DEH_String("I_Init: Setting up machine state.\n"), 1); I_CheckIsScreensaver(); I_InitJoystick(); IncThermo(); tprintf(DEH_String("S_Init: Setting up sound.\n"), 1); S_Init(); //IO_StartupTimer(); S_Start(); tprintf(DEH_String("D_CheckNetGame: Checking network game status.\n"), 1); hprintf(DEH_String("Checking network game status.")); D_CheckNetGame(); IncThermo(); // haleyjd: removed WATCOMC tprintf(DEH_String("SB_Init: Loading patches.\n"), 1); SB_Init(); IncThermo(); // // start the apropriate game based on parms // D_CheckRecordFrom(); //! // @arg // @category demo // @vanilla // // Record a demo named x.lmp. // p = M_CheckParmWithArgs("-record", 1); if (p) { G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]); D_DoomLoop(); // Never returns } p = M_CheckParmWithArgs("-playdemo", 1); if (p) { singledemo = true; // Quit after one demo G_DeferedPlayDemo(demolumpname); D_DoomLoop(); // Never returns } p = M_CheckParmWithArgs("-timedemo", 1); if (p) { G_TimeDemo(demolumpname); D_DoomLoop(); // Never returns } //! // @arg // @vanilla // // Load the game in savegame slot s. // p = M_CheckParmWithArgs("-loadgame", 1); if (p && p < myargc - 1) { char *filename; filename = SV_Filename(myargv[p + 1][0] - '0'); G_LoadGame(filename); free(filename); } // Check valid episode and map if (autostart || netgame) { if (!D_ValidEpisodeMap(heretic, gamemode, startepisode, startmap)) { startepisode = 1; startmap = 1; } } if (gameaction != ga_loadgame) { UpdateState |= I_FULLSCRN; BorderNeedRefresh = true; if (autostart || netgame) { G_InitNew(startskill, startepisode, startmap); } else { D_StartTitle(); } } finishStartup(); D_DoomLoop(); // Never returns } chocolate-doom-chocolate-doom-2.2.1/src/heretic/d_net.c000066400000000000000000000115271257432200600227620ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM Network game communication and protocol, // all OS independend parts. // #include #include "doomfeatures.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "doomdef.h" #include "m_argv.h" #include "m_misc.h" #include "w_checksum.h" #include "deh_main.h" #include "d_loop.h" ticcmd_t *netcmds; extern void D_DoAdvanceDemo(void); extern void D_ProcessEvents(void); extern void G_BuildTiccmd(ticcmd_t *cmd, int maketic); extern boolean G_CheckDemoStatus(void); // Called when a player leaves the game static void PlayerQuitGame(player_t *player) { static char exitmsg[80]; unsigned int player_num; player_num = player - players; // Note: // The Heretic source code does this, which doesn't actually work. // As a result, the exit message is never seen. M_StringCopy(exitmsg, "PLAYER 1 LEFT THE GAME", sizeof(exitmsg)); exitmsg[7] += player_num; players[consoleplayer].message = exitmsg; playeringame[player_num] = false; players[consoleplayer].message = exitmsg; // TODO: check if it is sensible to do this: if (demorecording) { G_CheckDemoStatus (); } } static void RunTic(ticcmd_t *cmds, boolean *ingame) { extern boolean advancedemo; unsigned int i; // Check for player quits. for (i = 0; i < MAXPLAYERS; ++i) { if (!demoplayback && playeringame[i] && !ingame[i]) { PlayerQuitGame(&players[i]); } } netcmds = cmds; // check that there are players in the game. if not, we cannot // run a tic. if (advancedemo) D_DoAdvanceDemo (); G_Ticker (); } static loop_interface_t doom_loop_interface = { D_ProcessEvents, G_BuildTiccmd, RunTic, MN_Ticker }; // Load game settings from the specified structure and // set global variables. static void LoadGameSettings(net_gamesettings_t *settings) { unsigned int i; deathmatch = settings->deathmatch; ticdup = settings->ticdup; startepisode = settings->episode; startmap = settings->map; startskill = settings->skill; // TODO startloadgame = settings->loadgame; nomonsters = settings->nomonsters; respawnparm = settings->respawn_monsters; consoleplayer = settings->consoleplayer; for (i = 0; i < MAXPLAYERS; ++i) { playeringame[i] = i < settings->num_players; } } // Save the game settings from global variables to the specified // game settings structure. static void SaveGameSettings(net_gamesettings_t *settings) { // Fill in game settings structure with appropriate parameters // for the new game settings->deathmatch = deathmatch; settings->episode = startepisode; settings->map = startmap; settings->skill = startskill; // TODO settings->loadgame = startloadgame; settings->gameversion = exe_heretic_1_3; settings->nomonsters = nomonsters; settings->respawn_monsters = respawnparm; settings->timelimit = 0; settings->lowres_turn = false; } static void InitConnectData(net_connect_data_t *connect_data) { connect_data->drone = false; connect_data->max_players = MAXPLAYERS; // // Connect data // // Game type fields: connect_data->gamemode = gamemode; connect_data->gamemission = heretic; connect_data->lowres_turn = false; // Read checksums of our WAD directory and dehacked information W_Checksum(connect_data->wad_sha1sum); DEH_Checksum(connect_data->deh_sha1sum); connect_data->is_freedoom = 0; } void D_ConnectNetGame(void) { net_connect_data_t connect_data; InitConnectData(&connect_data); netgame = D_InitNetGame(&connect_data); //! // @category net // // Start the game playing as though in a netgame with a single // player. This can also be used to play back single player netgame // demos. // if (M_CheckParm("-solo-net") > 0) { netgame = true; } } // // D_CheckNetGame // Works out player numbers among the net participants // void D_CheckNetGame (void) { net_gamesettings_t settings; D_RegisterLoopCallbacks(&doom_loop_interface); if (netgame) { autostart = true; } SaveGameSettings(&settings); D_StartNetGame(&settings, NULL); LoadGameSettings(&settings); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/deh_ammo.c000066400000000000000000000050121257432200600234320ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Ammo" sections in dehacked files // #include #include #include #include "doomdef.h" #include "doomtype.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "p_local.h" static void *DEH_AmmoStart(deh_context_t *context, char *line) { int ammo_number = 0; if (sscanf(line, "Ammo %i", &ammo_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (ammo_number < 0 || ammo_number >= NUMAMMO) { DEH_Warning(context, "Invalid ammo number: %i", ammo_number); return NULL; } return &maxammo[ammo_number]; } static void DEH_AmmoParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; int ivalue; int ammo_number; if (tag == NULL) return; ammo_number = ((int *) tag) - maxammo; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); if (!strcasecmp(variable_name, "Per ammo")) { // Heretic doesn't have a "per clip" ammo array, instead // it is per weapon. However, the weapon number lines // up with the ammo number if we add one. GetWeaponAmmo[ammo_number + 1] = ivalue; } else if (!strcasecmp(variable_name, "Max ammo")) { maxammo[ammo_number] = ivalue; } else { DEH_Warning(context, "Field named '%s' not found", variable_name); } } static void DEH_AmmoSHA1Hash(sha1_context_t *context) { int i; for (i=0; i #include #include "doomtype.h" #include "info.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "deh_mapping.h" #include "deh_htic.h" #include "p_action.h" typedef struct { int offsets[deh_hhe_num_versions]; void (*func)(); } hhe_action_pointer_t; // Offsets of action pointers within the Heretic executables. // Different versions have different offsets. // (Seriously Greg, was this really necessary? What was wrong with the // "copying action pointer from another frame" technique used in dehacked?) // Offset Action function // v1.0 v1.2 v1.3 static const hhe_action_pointer_t action_pointers[] = { { { 77680, 80144, 80208 }, A_AccTeleGlitter }, { { 78608, 81104, 81168 }, A_AddPlayerCorpse }, { { 115808, 118000, 118240 }, A_AddPlayerRain }, { { 112272, 114480, 114720 }, A_BeakAttackPL1 }, { { 112448, 114656, 114896 }, A_BeakAttackPL2 }, { { 111856, 114176, 114416 }, A_BeakRaise }, { { 111568, 113888, 114128 }, A_BeakReady }, { { 74640, 77120, 77184 }, A_BeastAttack }, { { 70480, 72992, 73056 }, A_BeastPuff }, { { 73120, 75600, 75664 }, A_BlueSpark }, { { 115456, 117648, 117888 }, A_BoltSpark }, { { 77344, 79808, 79872 }, A_BossDeath }, { { 69328, 71856, 71920 }, A_Chase }, { { 0, 80976, 81040 }, A_CheckBurnGone }, { { 78480, 80944, 81008 }, A_CheckSkullDone }, { { 78448, 80912, 80976 }, A_CheckSkullFloor }, { { 71376, 73888, 73952 }, A_ChicAttack }, { { 71488, 74000, 74064 }, A_ChicChase }, { { 71456, 73968, 74032 }, A_ChicLook }, { { 71520, 74032, 74096 }, A_ChicPain }, { { 75792, 78208, 78272 }, A_ClinkAttack }, { { 108432, 110816, 111056 }, A_ContMobjSound }, { { 114752, 116944, 117184 }, A_DeathBallImpact }, { { 70016, 72528, 72592 }, A_DripBlood }, { { 77472, 79936, 80000 }, A_ESound }, { { 76784, 79248, 79312 }, A_Explode }, { { 69872, 72400, 72464 }, A_FaceTarget }, { { 71568, 74080, 74144 }, A_Feathers }, { { 112928, 115136, 115376 }, A_FireBlasterPL1 }, { { 113072, 115280, 115520 }, A_FireBlasterPL2 }, { { 115232, 117424, 117664 }, A_FireCrossbowPL1 }, { { 115312, 117504, 117744 }, A_FireCrossbowPL2 }, { { 113152, 115360, 115600 }, A_FireGoldWandPL1 }, { { 113296, 115504, 115744 }, A_FireGoldWandPL2 }, { { 113760, 115968, 116208 }, A_FireMacePL1 }, { { 114624, 116816, 117056 }, A_FireMacePL2 }, { { 116368, 118544, 118784 }, A_FirePhoenixPL1 }, { { 116736, 118896, 119136 }, A_FirePhoenixPL2 }, { { 115568, 117760, 118000 }, A_FireSkullRodPL1 }, { { 115648, 117840, 118080 }, A_FireSkullRodPL2 }, { { 117120, 119280, 119520 }, A_FlameEnd }, { { 78704, 81200, 81264 }, A_FlameSnd }, { { 117152, 119312, 119552 }, A_FloatPuff }, { { 78512, 81008, 81072 }, A_FreeTargMobj }, { { 117184, 119344, 119584 }, A_GauntletAttack }, { { 73232, 75712, 75776 }, A_GenWizard }, { { 75872, 78304, 78368 }, A_GhostOff }, { { 74752, 77232, 77296 }, A_HeadAttack }, { { 75488, 77984, 78048 }, A_HeadFireGrow }, { { 75328, 77824, 77888 }, A_HeadIceImpact }, { { 116336, 118512, 118752 }, A_HideInCeiling }, { { 78736, 81232, 81296 }, A_HideThing }, { { 70976, 73488, 73552 }, A_ImpDeath }, { { 70304, 72816, 72880 }, A_ImpExplode }, { { 70592, 73104, 73168 }, A_ImpMeAttack }, { { 70672, 73184, 73248 }, A_ImpMsAttack }, { { 70880, 73392, 73456 }, A_ImpMsAttack2 }, { { 71024, 73536, 73600 }, A_ImpXDeath1 }, { { 71072, 73584, 73648 }, A_ImpXDeath2 }, { { 77728, 80192, 80256 }, A_InitKeyGizmo }, { { 116720, 118880, 119120 }, A_InitPhoenixPL2 }, { { 70160, 72672, 72736 }, A_KnightAttack }, { { 117648, 119824, 120064 }, A_Light0 }, { { 69200, 71728, 71792 }, A_Look }, { { 111760, 114080, 114320 }, A_Lower }, { { 114032, 116224, 116464 }, A_MaceBallImpact }, { { 114192, 116384, 116624 }, A_MaceBallImpact2 }, { { 113904, 116112, 116352 }, A_MacePL1Check }, { { 77104, 79568, 79632 }, A_MakePod }, { { 73648, 76128, 76192 }, A_MinotaurAtk1 }, { { 74112, 76592, 76656 }, A_MinotaurAtk2 }, { { 74352, 76832, 76896 }, A_MinotaurAtk3 }, { { 74032, 76512, 76576 }, A_MinotaurCharge }, { { 73760, 76240, 76304 }, A_MinotaurDecide }, { { 74528, 77008, 77072 }, A_MntrFloorFire }, { { 71808, 74288, 74352 }, A_MummyAttack }, { { 71920, 74400, 74464 }, A_MummyAttack2 }, { { 72016, 74496, 74560 }, A_MummyFX1Seek }, { { 72048, 74528, 74592 }, A_MummySoul }, { { 76400, 78832, 78896 }, A_NoBlocking }, { { 69984, 72496, 72560 }, A_Pain }, { { 116496, 118656, 118896 }, A_PhoenixPuff }, { { 76896, 79360, 79424 }, A_PodPain }, { { 116272, 118448, 118688 }, A_RainImpact }, { { 111920, 114240, 114480 }, A_Raise }, { { 111696, 114016, 114256 }, A_ReFire }, { { 77056, 79520, 79584 }, A_RemovePod }, { { 116480, 0, 0 }, A_RemovedPhoenixFunc }, { { 81952, 84464, 84528 }, A_RestoreArtifact }, { { 82048, 84544, 84608 }, A_RestoreSpecialThing1 }, { { 82128, 84592, 84656 }, A_RestoreSpecialThing2 }, { { 76144, 78576, 78640 }, A_Scream }, { { 117104, 119264, 119504 }, A_ShutdownPhoenixPL2 }, { { 78288, 80752, 80816 }, A_SkullPop }, { { 115776, 117968, 118208 }, A_SkullRodPL2Seek }, { { 115984, 118176, 118416 }, A_SkullRodStorm }, { { 75632, 78048, 78112 }, A_SnakeAttack }, { { 75712, 78128, 78192 }, A_SnakeAttack2 }, { { 72144, 74624, 74688 }, A_Sor1Chase }, { { 72096, 74576, 74640 }, A_Sor1Pain }, { { 73392, 75872, 75936 }, A_Sor2DthInit }, { { 73424, 75904, 75968 }, A_Sor2DthLoop }, { { 73584, 76064, 76128 }, A_SorDBon }, { { 73552, 76032, 76096 }, A_SorDExp }, { { 73520, 76000, 76064 }, A_SorDSph }, { { 73488, 75968, 76032 }, A_SorRise }, { { 73616, 76096, 76160 }, A_SorSightSnd }, { { 73456, 75936, 76000 }, A_SorZap }, { { 72480, 74960, 75024 }, A_SorcererRise }, { { 115088, 117280, 117520 }, A_SpawnRippers }, { { 77520, 79984, 80048 }, A_SpawnTeleGlitter }, { { 77600, 80064, 80128 }, A_SpawnTeleGlitter2 }, { { 72192, 74672, 74736 }, A_Srcr1Attack }, { { 72896, 75376, 75440 }, A_Srcr2Attack }, { { 72816, 75296, 75360 }, A_Srcr2Decide }, { { 112640, 114848, 115088 }, A_StaffAttackPL1 }, { { 112784, 114992, 115232 }, A_StaffAttackPL2 }, { { 78752, 81248, 81312 }, A_UnHideThing }, { { 78080, 80544, 80608 }, A_VolcBallImpact }, { { 77856, 80320, 80384 }, A_VolcanoBlast }, { { 77824, 80288, 80352 }, A_VolcanoSet }, { { 111168, 113488, 113728 }, A_WeaponReady }, { { 75168, 77664, 77728 }, A_WhirlwindSeek }, { { 75888, 78320, 78384 }, A_WizAtk1 }, { { 75920, 78352, 78416 }, A_WizAtk2 }, { { 75952, 78384, 78448 }, A_WizAtk3 }, }; DEH_BEGIN_MAPPING(state_mapping, state_t) DEH_MAPPING("Sprite number", sprite) DEH_MAPPING("Sprite subnumber", frame) DEH_MAPPING("Duration", tics) DEH_MAPPING("Next frame", nextstate) DEH_MAPPING("Unknown 1", misc1) DEH_MAPPING("Unknown 2", misc2) DEH_END_MAPPING static void DEH_FrameInit(void) { // Bit of a hack here: DEH_HereticInit(); } static void *DEH_FrameStart(deh_context_t *context, char *line) { int frame_number = 0; int mapped_frame_number; state_t *state; if (sscanf(line, "Frame %i", &frame_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } // Map the HHE frame number (which assumes a Heretic 1.0 state table) // to the internal frame number (which is is the Heretic 1.3 state table): mapped_frame_number = DEH_MapHereticFrameNumber(frame_number); if (mapped_frame_number < 0 || mapped_frame_number >= DEH_HERETIC_NUMSTATES) { DEH_Warning(context, "Invalid frame number: %i", frame_number); return NULL; } state = &states[mapped_frame_number]; return state; } static boolean GetActionPointerForOffset(int offset, void **result) { int i; // Special case. if (offset == 0) { *result = NULL; return true; } for (i=0; iaction = func; } else { // "Next frame" numbers need to undergo mapping. if (!strcasecmp(variable_name, "Next frame")) { ivalue = DEH_MapHereticFrameNumber(ivalue); } DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue); } } static void DEH_FrameSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include #include "doomtype.h" #include "dstrings.h" #include "z_zone.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_htic.h" #include "deh_main.h" // // Ok, Greg, the action pointers thing was bad enough, but this really // takes the biscuit. Why does HHE's text replacement address strings // by offset??!! The dehacked way was much nicer, why change it? // typedef struct { unsigned int offsets[deh_hhe_num_versions]; char *string; } hhe_string_t; // Offsets String // v1.0 v1.2 v1.3 static const hhe_string_t strings[] = { { { 228, 228, 228 }, "PLAYPAL" }, { { 1240, 1252, 1252 }, "E1M1: THE DOCKS" }, { { 1260, 1272, 1272 }, "E1M2: THE DUNGEONS" }, { { 1280, 1292, 1292 }, "E1M3: THE GATEHOUSE" }, { { 1304, 1316, 1316 }, "E1M4: THE GUARD TOWER" }, { { 1328, 1340, 1340 }, "E1M5: THE CITADEL" }, { { 1348, 1360, 1360 }, "E1M6: THE CATHEDRAL" }, { { 1372, 1384, 1384 }, "E1M7: THE CRYPTS" }, { { 1392, 1404, 1404 }, "E1M8: HELL'S MAW" }, { { 1412, 1424, 1424 }, "E1M9: THE GRAVEYARD" }, { { 1436, 1448, 1448 }, "E2M1: THE CRATER" }, { { 1456, 1468, 1468 }, "E2M2: THE LAVA PITS" }, { { 1480, 1492, 1492 }, "E2M3: THE RIVER OF FIRE" }, { { 1508, 1520, 1520 }, "E2M4: THE ICE GROTTO" }, { { 1532, 1544, 1544 }, "E2M5: THE CATACOMBS" }, { { 1556, 1568, 1568 }, "E2M6: THE LABYRINTH" }, { { 1580, 1592, 1592 }, "E2M7: THE GREAT HALL" }, { { 1604, 1616, 1616 }, "E2M8: THE PORTALS OF CHAOS" }, { { 1632, 1644, 1644 }, "E2M9: THE GLACIER" }, { { 1652, 1664, 1664 }, "E3M1: THE STOREHOUSE" }, { { 1676, 1688, 1688 }, "E3M2: THE CESSPOOL" }, { { 1696, 1708, 1708 }, "E3M3: THE CONFLUENCE" }, { { 1720, 1732, 1732 }, "E3M4: THE AZURE FORTRESS" }, { { 1748, 1760, 1760 }, "E3M5: THE OPHIDIAN LAIR" }, { { 1776, 1788, 1788 }, "E3M6: THE HALLS OF FEAR" }, { { 1804, 1816, 1816 }, "E3M7: THE CHASM" }, { { 1824, 1836, 1836 }, "E3M8: D'SPARIL'S KEEP" }, { { 1848, 1860, 1860 }, "E3M9: THE AQUIFER" }, { { 0, 1880, 1880 }, "E4M1: CATAFALQUE" }, { { 0, 1900, 1900 }, "E4M2: BLOCKHOUSE" }, { { 0, 1920, 1920 }, "E4M3: AMBULATORY" }, { { 0, 1940, 1940 }, "E4M4: SEPULCHER" }, { { 0, 1960, 1960 }, "E4M5: GREAT STAIR" }, { { 0, 1980, 1980 }, "E4M6: HALLS OF THE APOSTATE" }, { { 0, 2012, 2012 }, "E4M7: RAMPARTS OF PERDITION" }, { { 0, 2044, 2044 }, "E4M8: SHATTERED BRIDGE" }, { { 0, 2068, 2068 }, "E4M9: MAUSOLEUM" }, { { 0, 2088, 2088 }, "E5M1: OCHRE CLIFFS" }, { { 0, 2108, 2108 }, "E5M2: RAPIDS" }, { { 0, 2124, 2124 }, "E5M3: QUAY" }, { { 0, 2136, 2136 }, "E5M4: COURTYARD" }, { { 0, 2156, 2156 }, "E5M5: HYDRATYR" }, { { 0, 2172, 2172 }, "E5M6: COLONNADE" }, { { 0, 2192, 2192 }, "E5M7: FOETID MANSE" }, { { 0, 2212, 2212 }, "E5M8: FIELD OF JUDGEMENT" }, { { 0, 2240, 2240 }, "E5M9: SKEIN OF D'SPARIL" }, { { 1868, 2268, 2268 }, "AUTOPAGE" }, { { 1880, 2280, 2280 }, "FOLLOW MODE ON" }, { { 1896, 2296, 2296 }, "FOLLOW MODE OFF" }, { { 1924, 2324, 2324 }, "GREEN: " }, { { 1936, 2336, 2336 }, "YELLOW: " }, { { 1948, 2348, 2348 }, "RED: " }, { { 1956, 2356, 2356 }, "BLUE: " }, { { 1964, 2364, 2364 }, "FONTA_S" }, { { 1972, 2372, 2372 }, "-MESSAGE SENT-" }, { { 1988, 2388, 2388 }, "THERE ARE NO OTHER PLAYERS IN THE GAME!" }, { { 2028, 2428, 2428 }, "FONTA59" }, { { 2036, 2504, 2504 }, "PAUSED" }, { { 2072, 2540, 2540 }, "ADVISOR" }, { { 2080, 2548, 2548 }, "TITLE" }, { { 2088, 2556, 2556 }, "demo1" }, { { 2096, 2564, 2564 }, "CREDIT" }, { { 2104, 2572, 2572 }, "demo2" }, { { 2112, 2580, 2580 }, "ORDER" }, { { 2120, 2588, 2588 }, "demo3" }, { { 2304, 2696, 2696 }, "Exited from HERETIC.\n" }, { { 2412, 2800, 2800 }, "c:\\heretic.cd" }, { { 2528, 2916, 2916 }, "Playing demo %s.lmp.\n" }, { { 2592, 2980, 2980 }, "V_Init: allocate screens.\n" }, { { 2620, 3008, 3008 }, "M_LoadDefaults: Load system defaults.\n" }, { { 2660, 3048, 3048 }, "Z_Init: Init zone memory allocation daemon.\n" }, { { 2708, 3096, 3096 }, "W_Init: Init WADfiles.\n" }, { { 2732, 3120, 3120 }, "E2M1" }, { { 0, 3128, 3128 }, "EXTENDED" }, { { 2740, 3140, 3140 }, "LOADING" }, { { 2748, 3148, 3148 }, "DeathMatch..." }, { { 2764, 3164, 3164 }, "No Monsters..." }, { { 2780, 3180, 3180 }, "Respawning..." }, { { 2796, 3196, 3196 }, "Warp to Episode %d, Map %d, Skill %d " }, { { 2836, 3236, 3236 }, "MN_Init: Init menu system.\n" }, { { 2864, 3264, 3264 }, "R_Init: Init Heretic refresh daemon." }, { { 2904, 3304, 3304 }, "Loading graphics" }, { { 2924, 3324, 3324 }, "P_Init: Init Playloop state." }, { { 2956, 3356, 3356 }, "Init game engine." }, { { 2976, 3376, 3376 }, "I_Init: Setting up machine state.\n" }, { { 3012, 3412, 3412 }, "D_CheckNetGame: Checking network game status.\n" }, { { 3060, 3460, 3460 }, "Checking network game status." }, { { 3092, 3492, 3492 }, "SB_Init: Loading patches.\n" }, { { 0, 3752, 3752 }, "PLAYER 1 LEFT THE GAME" }, { { 3508, 3932, 3932 }, "Network game synchronization aborted." }, { { 0, 3972, 3972 }, "Different DOOM versions cannot play a net game!" }, { { 3908, 4132, 4132 }, "SKY1" }, { { 3916, 4140, 4140 }, "SKY2" }, { { 3924, 4148, 4148 }, "SKY3" }, { { 3736, 4196, 4196 }, "NET GAME" }, { { 3748, 4208, 4208 }, "SAVE GAME" }, { { 3760, 4220, 4220 }, "Only %i deathmatch spots, 4 required" }, { { 3800, 4260, 4260 }, "version %i" }, { { 3828, 4372, 4372 }, "c:\\heretic.cd\\hticsav%d.hsg" }, { { 3856, 4400, 4400 }, "hticsav%d.hsg" }, { { 3896, 4416, 4416 }, "GAME SAVED" }, { { 4016, 4456, 4456 }, E1TEXT }, { { 4536, 4976, 4976 }, E2TEXT }, { { 5068, 5508, 5508 }, E3TEXT }, { { 0, 6072, 6072 }, E4TEXT }, { { 0, 6780, 6780 }, E5TEXT }, { { 5632, 7468, 7468 }, "FLOOR25" }, { { 5640, 7476, 7476 }, "FLATHUH1" }, { { 5652, 7488, 7488 }, "FLTWAWA2" }, { { 0, 7500, 7500 }, "FLOOR28" }, { { 0, 7508, 7508 }, "FLOOR08" }, { { 5664, 7516, 7516 }, "FONTA_S" }, { { 5704, 7524, 7524 }, "PLAYPAL" }, { { 5672, 7532, 7532 }, "FINAL1" }, { { 5680, 7540, 7540 }, "FINAL2" }, { { 5688, 7548, 7548 }, "E2PAL" }, { { 5696, 7556, 7556 }, "E2END" }, { { 7884, 7564, 7564 }, "TITLE" }, { { 5712, 7572, 7572 }, "ORDER" }, { { 0, 7580, 7580 }, "CREDIT" }, { { 5720, 7588, 7588 }, "IMPX" }, { { 5728, 7596, 7596 }, "ACLO" }, { { 5736, 7604, 7604 }, "PTN1" }, { { 5744, 7612, 7612 }, "SHLD" }, { { 5752, 7620, 7620 }, "SHD2" }, { { 5760, 7628, 7628 }, "BAGH" }, { { 5768, 7636, 7636 }, "SPMP" }, { { 5776, 7644, 7644 }, "INVS" }, { { 5784, 7652, 7652 }, "PTN2" }, { { 5792, 7660, 7660 }, "SOAR" }, { { 5800, 7668, 7668 }, "INVU" }, { { 5808, 7676, 7676 }, "PWBK" }, { { 5816, 7684, 7684 }, "EGGC" }, { { 5824, 7692, 7692 }, "EGGM" }, { { 5832, 7700, 7700 }, "FX01" }, { { 5840, 7708, 7708 }, "SPHL" }, { { 5848, 7716, 7716 }, "TRCH" }, { { 5856, 7724, 7724 }, "FBMB" }, { { 5864, 7732, 7732 }, "XPL1" }, { { 5872, 7740, 7740 }, "ATLP" }, { { 5880, 7748, 7748 }, "PPOD" }, { { 5888, 7756, 7756 }, "AMG1" }, { { 5896, 7764, 7764 }, "SPSH" }, { { 5904, 7772, 7772 }, "LVAS" }, { { 5912, 7780, 7780 }, "SLDG" }, { { 5920, 7788, 7788 }, "SKH1" }, { { 5928, 7796, 7796 }, "SKH2" }, { { 5936, 7804, 7804 }, "SKH3" }, { { 5944, 7812, 7812 }, "SKH4" }, { { 5952, 7820, 7820 }, "CHDL" }, { { 5960, 7828, 7828 }, "SRTC" }, { { 5968, 7836, 7836 }, "SMPL" }, { { 5976, 7844, 7844 }, "STGS" }, { { 5984, 7852, 7852 }, "STGL" }, { { 5992, 7860, 7860 }, "STCS" }, { { 6000, 7868, 7868 }, "STCL" }, { { 6008, 7876, 7876 }, "KFR1" }, { { 6016, 7884, 7884 }, "BARL" }, { { 6024, 7892, 7892 }, "BRPL" }, { { 6032, 7900, 7900 }, "MOS1" }, { { 6040, 7908, 7908 }, "MOS2" }, { { 6048, 7916, 7916 }, "WTRH" }, { { 6056, 7924, 7924 }, "HCOR" }, { { 6064, 7932, 7932 }, "KGZ1" }, { { 6072, 7940, 7940 }, "KGZB" }, { { 6080, 7948, 7948 }, "KGZG" }, { { 6088, 7956, 7956 }, "KGZY" }, { { 6096, 7964, 7964 }, "VLCO" }, { { 6104, 7972, 7972 }, "VFBL" }, { { 6112, 7980, 7980 }, "VTFB" }, { { 6120, 7988, 7988 }, "SFFI" }, { { 6128, 7996, 7996 }, "TGLT" }, { { 6136, 8004, 8004 }, "TELE" }, { { 6144, 8012, 8012 }, "STFF" }, { { 6152, 8020, 8020 }, "PUF3" }, { { 6160, 8028, 8028 }, "PUF4" }, { { 6168, 8036, 8036 }, "BEAK" }, { { 6176, 8044, 8044 }, "WGNT" }, { { 6184, 8052, 8052 }, "GAUN" }, { { 6192, 8060, 8060 }, "PUF1" }, { { 6200, 8068, 8068 }, "WBLS" }, { { 6208, 8076, 8076 }, "BLSR" }, { { 6216, 8084, 8084 }, "FX18" }, { { 6224, 8092, 8092 }, "FX17" }, { { 6232, 8100, 8100 }, "WMCE" }, { { 6240, 8108, 8108 }, "MACE" }, { { 6248, 8116, 8116 }, "FX02" }, { { 6256, 8124, 8124 }, "WSKL" }, { { 6264, 8132, 8132 }, "HROD" }, { { 6272, 8140, 8140 }, "FX00" }, { { 6280, 8148, 8148 }, "FX20" }, { { 6288, 8156, 8156 }, "FX21" }, { { 6296, 8164, 8164 }, "FX22" }, { { 6304, 8172, 8172 }, "FX23" }, { { 6312, 8180, 8180 }, "GWND" }, { { 6320, 8188, 8188 }, "PUF2" }, { { 6328, 8196, 8196 }, "WPHX" }, { { 6336, 8204, 8204 }, "PHNX" }, { { 6344, 8212, 8212 }, "FX04" }, { { 6352, 8220, 8220 }, "FX08" }, { { 6360, 8228, 8228 }, "FX09" }, { { 6368, 8236, 8236 }, "WBOW" }, { { 6376, 8244, 8244 }, "CRBW" }, { { 6384, 8252, 8252 }, "FX03" }, { { 6392, 8260, 8260 }, "BLOD" }, { { 6400, 8268, 8268 }, "PLAY" }, { { 6408, 8276, 8276 }, "FDTH" }, { { 6416, 8284, 8284 }, "BSKL" }, { { 6424, 8292, 8292 }, "CHKN" }, { { 6432, 8300, 8300 }, "MUMM" }, { { 6440, 8308, 8308 }, "FX15" }, { { 6448, 8316, 8316 }, "BEAS" }, { { 6456, 8324, 8324 }, "FRB1" }, { { 6464, 8332, 8332 }, "SNKE" }, { { 6472, 8340, 8340 }, "SNFX" }, { { 6480, 8348, 8348 }, "HEAD" }, { { 6488, 8356, 8356 }, "FX05" }, { { 6496, 8364, 8364 }, "FX06" }, { { 6504, 8372, 8372 }, "FX07" }, { { 6512, 8380, 8380 }, "CLNK" }, { { 6520, 8388, 8388 }, "WZRD" }, { { 6528, 8396, 8396 }, "FX11" }, { { 6536, 8404, 8404 }, "FX10" }, { { 6544, 8412, 8412 }, "KNIG" }, { { 6552, 8420, 8420 }, "SPAX" }, { { 6560, 8428, 8428 }, "RAXE" }, { { 6568, 8436, 8436 }, "SRCR" }, { { 6576, 8444, 8444 }, "FX14" }, { { 6584, 8452, 8452 }, "SOR2" }, { { 6592, 8460, 8460 }, "SDTH" }, { { 6600, 8468, 8468 }, "FX16" }, { { 6608, 8476, 8476 }, "MNTR" }, { { 6616, 8484, 8484 }, "FX12" }, { { 6624, 8492, 8492 }, "FX13" }, { { 6632, 8500, 8500 }, "AKYY" }, { { 6640, 8508, 8508 }, "BKYY" }, { { 6648, 8516, 8516 }, "CKYY" }, { { 6656, 8524, 8524 }, "AMG2" }, { { 6664, 8532, 8532 }, "AMM1" }, { { 6672, 8540, 8540 }, "AMM2" }, { { 6680, 8548, 8548 }, "AMC1" }, { { 6688, 8556, 8556 }, "AMC2" }, { { 6696, 8564, 8564 }, "AMS1" }, { { 6704, 8572, 8572 }, "AMS2" }, { { 6712, 8580, 8580 }, "AMP1" }, { { 6720, 8588, 8588 }, "AMP2" }, { { 6728, 8596, 8596 }, "AMB1" }, { { 6736, 8604, 8604 }, "AMB2" }, { { 6744, 8612, 8612 }, "K" }, { { 6748, 8616, 8616 }, "I" }, { { 6752, 8620, 8620 }, "L" }, { { 6756, 8624, 8624 }, "E" }, { { 6760, 8628, 8628 }, "R" }, { { 6764, 8632, 8632 }, "S" }, { { 6768, 8636, 8636 }, "PLAYPAL" }, { { 6776, 8644, 8644 }, "MAPE1" }, { { 6784, 8652, 8652 }, "MAPE2" }, { { 6792, 8660, 8660 }, "MAPE3" }, { { 6800, 8668, 8668 }, "IN_X" }, { { 6808, 8676, 8676 }, "IN_YAH" }, { { 6816, 8684, 8684 }, "FONTB16" }, { { 6824, 8692, 8692 }, "FONTB_S" }, { { 6832, 8700, 8700 }, "FONTB13" }, { { 6840, 8708, 8708 }, "FONTB15" }, { { 6848, 8716, 8716 }, "FONTB05" }, { { 6856, 8724, 8724 }, "FACEA0" }, { { 6864, 8732, 8732 }, "FACEB0" }, { { 6940, 8808, 8808 }, "FLOOR16" }, { { 6948, 8816, 8816 }, "FINISHED" }, { { 6960, 8828, 8828 }, "NOW ENTERING:" }, { { 6976, 8844, 8844 }, "KILLS" }, { { 6984, 8852, 8852 }, "ITEMS" }, { { 6992, 8860, 8860 }, "SECRETS" }, { { 7000, 8868, 8868 }, "TIME" }, { { 7008, 8876, 8876 }, "BONUS" }, { { 7016, 8884, 8884 }, "SECRET" }, { { 7024, 8892, 8892 }, "TOTAL" }, { { 7032, 8900, 8900 }, "VICTIMS" }, { { 7040, 8908, 8908 }, ":" }, { { 7044, 8912, 8912 }, "NEW GAME" }, { { 7056, 8924, 8924 }, "OPTIONS" }, { { 7064, 8932, 8932 }, "GAME FILES" }, { { 7076, 8944, 8944 }, "INFO" }, { { 7084, 8952, 8952 }, "QUIT GAME" }, { { 7096, 8964, 8964 }, "CITY OF THE DAMNED" }, { { 7116, 8984, 8984 }, "HELL'S MAW" }, { { 7128, 8996, 8996 }, "THE DOME OF D'SPARIL" }, { { 0, 9020, 9020 }, "THE OSSUARY" }, { { 0, 9032, 9032 }, "THE STAGNANT DEMESNE" }, { { 7152, 9056, 9056 }, "LOAD GAME" }, { { 7164, 9068, 9068 }, "SAVE GAME" }, { { 7176, 9080, 9080 }, "THOU NEEDETH A WET-NURSE" }, { { 7204, 9108, 9108 }, "YELLOWBELLIES-R-US" }, { { 7224, 9128, 9128 }, "BRINGEST THEM ONETH" }, { { 7244, 9148, 9148 }, "THOU ART A SMITE-MEISTER" }, { { 7272, 9176, 9176 }, "BLACK PLAGUE POSSESSES THEE" }, { { 7300, 9204, 9204 }, "END GAME" }, { { 7312, 9216, 9216 }, "MESSAGES : " }, { { 7324, 9228, 9228 }, "MOUSE SENSITIVITY" }, { { 7344, 9248, 9248 }, "MORE..." }, { { 7352, 9256, 9256 }, "SCREEN SIZE" }, { { 7364, 9268, 9268 }, "SFX VOLUME" }, { { 7376, 9280, 9280 }, "MUSIC VOLUME" }, { { 7416, 9296, 9296 }, "ARE YOU SURE YOU WANT TO QUIT?" }, { { 7448, 9328, 9328 }, "ARE YOU SURE YOU WANT TO END THE GAME?" }, { { 7488, 9368, 9368 }, "DO YOU WANT TO QUICKSAVE THE GAME NAMED" }, { { 7528, 9408, 9408 }, "DO YOU WANT TO QUICKLOAD THE GAME NAMED" }, { { 7392, 9448, 9448 }, "M_SKL00" }, { { 7400, 9456, 9456 }, "FONTA_S" }, { { 7408, 9464, 9464 }, "FONTB_S" }, { { 7568, 9472, 9472 }, "?" }, { { 7572, 9476, 9476 }, "M_SLCTR1" }, { { 7584, 9488, 9488 }, "M_SLCTR2" }, { { 7596, 9500, 9500 }, "M_HTIC" }, { { 7604, 9508, 9508 }, "c:\\heretic.cd\\hticsav%d.hsg" }, { { 7632, 9536, 9536 }, "hticsav%d.hsg" }, { { 7652, 9556, 9556 }, "M_FSLOT" }, { { 7660, 9564, 9564 }, "ON" }, { { 7664, 9568, 9568 }, "OFF" }, { { 0, 9572, 9572 }, "YOU CAN'T START A NEW GAME IN NETPLAY!" }, { { 0, 9612, 9612 }, "YOU CAN'T LOAD A GAME IN NETPLAY!" }, { { 7668, 9648, 9648 }, "MESSAGES ON" }, { { 7680, 9660, 9660 }, "MESSAGES OFF" }, { { 7748, 9676, 9676 }, "ONLY AVAILABLE IN THE REGISTERED VERSION" }, { { 7792, 9720, 9720 }, "PLAYPAL" }, { { 7800, 9728, 9728 }, "QUICKSAVING...." }, { { 7816, 9744, 9744 }, "QUICKLOADING...." }, { { 7836, 9764, 9764 }, "CHOOSE A QUICKSAVE SLOT" }, { { 7860, 9788, 9788 }, "CHOOSE A QUICKLOAD SLOT" }, { { 0, 9812, 9812 }, "TITLE" }, { { 7892, 9820, 9820 }, "M_SLDLT" }, { { 7900, 9828, 9828 }, "M_SLDMD1" }, { { 7912, 9840, 9840 }, "M_SLDMD2" }, { { 7924, 9852, 9852 }, "M_SLDRT" }, { { 7932, 9860, 9860 }, "M_SLDKB" }, { { 9016, 10944, 10944 }, "SCREEN SHOT" }, { { 9028, 10956, 10956 }, "YOU NEED A BLUE KEY TO OPEN THIS DOOR" }, { { 9068, 10996, 10996 }, "YOU NEED A YELLOW KEY TO OPEN THIS DOOR" }, { { 9108, 11036, 11036 }, "YOU NEED A GREEN KEY TO OPEN THIS DOOR" }, { { 9244, 11172, 11172 }, "CRYSTAL VIAL" }, { { 9260, 11188, 11188 }, "SILVER SHIELD" }, { { 9276, 11204, 11204 }, "ENCHANTED SHIELD" }, { { 9296, 11224, 11224 }, "BAG OF HOLDING" }, { { 9312, 11240, 11240 }, "MAP SCROLL" }, { { 9324, 11252, 11252 }, "BLUE KEY" }, { { 9336, 11264, 11264 }, "YELLOW KEY" }, { { 9348, 11276, 11276 }, "GREEN KEY" }, { { 9360, 11288, 11288 }, "QUARTZ FLASK" }, { { 9376, 11304, 11304 }, "WINGS OF WRATH" }, { { 9392, 11320, 11320 }, "RING OF INVINCIBILITY" }, { { 9416, 11344, 11344 }, "TOME OF POWER" }, { { 9432, 11360, 11360 }, "SHADOWSPHERE" }, { { 9448, 11376, 11376 }, "MORPH OVUM" }, { { 9460, 11388, 11388 }, "MYSTIC URN" }, { { 9472, 11400, 11400 }, "TORCH" }, { { 9480, 11408, 11408 }, "TIME BOMB OF THE ANCIENTS" }, { { 9508, 11436, 11436 }, "CHAOS DEVICE" }, { { 9524, 11452, 11452 }, "WAND CRYSTAL" }, { { 9540, 11468, 11468 }, "CRYSTAL GEODE" }, { { 9556, 11484, 11484 }, "MACE SPHERES" }, { { 9572, 11500, 11500 }, "PILE OF MACE SPHERES" }, { { 9596, 11524, 11524 }, "ETHEREAL ARROWS" }, { { 9612, 11540, 11540 }, "QUIVER OF ETHEREAL ARROWS" }, { { 9640, 11568, 11568 }, "CLAW ORB" }, { { 9652, 11580, 11580 }, "ENERGY ORB" }, { { 9664, 11592, 11592 }, "LESSER RUNES" }, { { 9680, 11608, 11608 }, "GREATER RUNES" }, { { 9696, 11624, 11624 }, "FLAME ORB" }, { { 9708, 11636, 11636 }, "INFERNO ORB" }, { { 9720, 11648, 11648 }, "FIREMACE" }, { { 9732, 11660, 11660 }, "ETHEREAL CROSSBOW" }, { { 9752, 11680, 11680 }, "DRAGON CLAW" }, { { 9764, 11692, 11692 }, "HELLSTAFF" }, { { 9776, 11704, 11704 }, "PHOENIX ROD" }, { { 9788, 11716, 11716 }, "GAUNTLETS OF THE NECROMANCER" }, { { 10088, 12016, 12016 }, "FLTWAWA1" }, { { 10100, 12028, 12028 }, "FLTFLWW1" }, { { 10112, 12040, 12040 }, "FLTLAVA1" }, { { 10124, 12052, 12052 }, "FLATHUH1" }, { { 10136, 12064, 12064 }, "FLTSLUD1" }, { { 10148, 12076, 12076 }, "END" }, { { 10236, 12164, 12164 }, "texture2" }, { { 10444, 12372, 12372 }, "PLAYPAL" }, { { 10596, 12488, 12488 }, "PNAMES" }, { { 10604, 12496, 12496 }, "TEXTURE1" }, { { 10616, 12508, 12508 }, "TEXTURE2" }, { { 10628, 12520, 12520 }, "S_END" }, { { 10636, 12528, 12528 }, "S_START" }, { { 10728, 12620, 12620 }, "F_START" }, { { 10736, 12628, 12628 }, "F_END" }, { { 10744, 12636, 12636 }, "COLORMAP" }, { { 10756, 12648, 12648 }, "\nR_InitTextures " }, { { 10776, 12668, 12668 }, "R_InitFlats\n" }, { { 10792, 12684, 12684 }, "R_InitSpriteLumps " }, { { 10948, 12772, 12772 }, "TINTTAB" }, { { 10984, 12780, 12780 }, "FLOOR04" }, { { 10992, 12788, 12788 }, "FLAT513" }, { { 11000, 12796, 12796 }, "bordt" }, { { 11008, 12804, 12804 }, "bordb" }, { { 11016, 12812, 12812 }, "bordl" }, { { 11024, 12820, 12820 }, "bordr" }, { { 11032, 12828, 12828 }, "bordtl" }, { { 11040, 12836, 12836 }, "bordtr" }, { { 11048, 12844, 12844 }, "bordbr" }, { { 11056, 12852, 12852 }, "bordbl" }, { { 11064, 12860, 12860 }, "R_InitData " }, { { 11076, 12872, 12872 }, "R_InitPointToAngle\n" }, { { 11096, 12892, 12892 }, "R_InitTables " }, { { 11112, 12908, 12908 }, "R_InitPlanes\n" }, { { 11128, 12924, 12924 }, "R_InitLightTables " }, { { 11148, 12944, 12944 }, "R_InitSkyMap\n" }, { { 11164, 12960, 12960 }, "F_SKY1" }, { { 12120, 13484, 13484 }, "LTFACE" }, { { 12128, 13492, 13492 }, "RTFACE" }, { { 12136, 13500, 13500 }, "BARBACK" }, { { 12144, 13508, 13508 }, "INVBAR" }, { { 12152, 13516, 13516 }, "CHAIN" }, { { 12160, 13524, 13524 }, "STATBAR" }, { { 12168, 13532, 13532 }, "LIFEBAR" }, { { 12176, 13540, 13540 }, "LIFEGEM2" }, { { 12188, 13552, 13552 }, "LIFEGEM0" }, { { 12200, 13564, 13564 }, "LTFCTOP" }, { { 12208, 13572, 13572 }, "RTFCTOP" }, { { 12224, 13580, 13580 }, "SELECTBOX" }, { { 12236, 13592, 13592 }, "INVGEML1" }, { { 12248, 13604, 13604 }, "INVGEML2" }, { { 12260, 13616, 13616 }, "INVGEMR1" }, { { 12272, 13628, 13628 }, "INVGEMR2" }, { { 12284, 13640, 13640 }, "BLACKSQ" }, { { 12292, 13648, 13648 }, "ARMCLEAR" }, { { 12304, 13660, 13660 }, "CHAINBACK" }, { { 12316, 13672, 13672 }, "IN0" }, { { 12320, 13676, 13676 }, "NEGNUM" }, { { 12328, 13684, 13684 }, "FONTB16" }, { { 12336, 13692, 13692 }, "SMALLIN0" }, { { 12348, 13704, 13704 }, "PLAYPAL" }, { { 12356, 13712, 13712 }, "SPINBK0" }, { { 12364, 13720, 13720 }, "SPFLY0" }, { { 12372, 13728, 13728 }, "LAME" }, { { 12380, 13736, 13736 }, "*** SOUND DEBUG INFO ***" }, { { 12408, 13764, 13764 }, "NAME" }, { { 12416, 13772, 13772 }, "MO.T" }, { { 12424, 13780, 13780 }, "MO.X" }, { { 12432, 13788, 13788 }, "MO.Y" }, { { 12440, 13796, 13796 }, "ID" }, { { 12444, 13800, 13800 }, "PRI" }, { { 12448, 13804, 13804 }, "DIST" }, { { 12456, 13812, 13812 }, "------" }, { { 12464, 13820, 13820 }, "%s" }, { { 12468, 13824, 13824 }, "%d" }, { { 12472, 13828, 13828 }, "GOD1" }, { { 12480, 13836, 13836 }, "GOD2" }, { { 12488, 13844, 13844 }, "useartia" }, { { 12500, 13856, 13856 }, "ykeyicon" }, { { 12512, 13868, 13868 }, "gkeyicon" }, { { 12524, 13880, 13880 }, "bkeyicon" }, { { 12216, 13892, 13892 }, "ARTIBOX" }, { { 12536, 13900, 13900 }, "GOD MODE ON" }, { { 12548, 13912, 13912 }, "GOD MODE OFF" }, { { 12564, 13928, 13928 }, "NO CLIPPING ON" }, { { 12580, 13944, 13944 }, "NO CLIPPING OFF" }, { { 12596, 13960, 13960 }, "ALL WEAPONS" }, { { 12608, 13972, 13972 }, "POWER OFF" }, { { 12620, 13984, 13984 }, "POWER ON" }, { { 12632, 13996, 13996 }, "FULL HEALTH" }, { { 12644, 14008, 14008 }, "ALL KEYS" }, { { 12656, 14020, 14020 }, "SOUND DEBUG ON" }, { { 12672, 14036, 14036 }, "SOUND DEBUG OFF" }, { { 12688, 14052, 14052 }, "TICKER ON" }, { { 12700, 14064, 14064 }, "TICKER OFF" }, { { 12712, 14076, 14076 }, "CHOOSE AN ARTIFACT ( A - J )" }, { { 12744, 14108, 14108 }, "HOW MANY ( 1 - 9 )" }, { { 12764, 14128, 14128 }, "YOU GOT IT" }, { { 12776, 14140, 14140 }, "BAD INPUT" }, { { 12788, 14152, 14152 }, "LEVEL WARP" }, { { 12800, 14164, 14164 }, "CHICKEN OFF" }, { { 12812, 14176, 14176 }, "CHICKEN ON" }, { { 12824, 14188, 14188 }, "MASSACRE" }, { { 12836, 14200, 14200 }, "CHEATER - YOU DON'T DESERVE WEAPONS" }, { { 12872, 14236, 14236 }, "TRYING TO CHEAT, EH? NOW YOU DIE!" }, }; // String offsets that are valid but we don't support. static const int unsupported_strings_1_0[] = { 0, 4, 64, 104, 160, 200, 220, 236, 244, 252, 272, 288, 296, 316, 332, 372, 436, 500, 504, 536, 544, 560, 576, 584, 592, 612, 640, 664, 708, 712, 744, 764, 808, 820, 828, 840, 876, 884, 908, 952, 992, 1028, 1036, 1048, 1088, 1128, 1160, 1192, 1212, 1912, 2044, 2056, 2068, 2128, 2140, 2168, 2184, 2196, 2212, 2228, 2240, 2252, 2260, 2264, 2284, 2292, 2296, 2300, 2328, 2340, 2352, 2364, 2372, 2384, 2388, 2404, 2428, 2436, 2444, 2464, 2496, 2508, 2520, 2552, 2564, 2572, 2584, 3120, 3128, 3140, 3184, 3220, 3248, 3252, 3256, 3280, 3304, 3320, 3352, 3380, 3400, 3432, 3464, 3548, 3600, 3624, 3664, 3696, 3812, 3872, 3932, 3940, 3976, 3996, 6872, 6896, 7648, 7696, 7940, 7964, 7968, 7992, 8020, 8028, 8052, 8056, 8076, 8088, 8104, 8116, 8128, 8136, 8148, 8164, 8180, 8192, 8204, 8220, 8232, 8248, 8264, 8276, 8292, 8308, 8320, 8328, 8340, 8352, 8364, 8376, 8392, 8408, 8424, 8436, 8448, 8460, 8472, 8488, 8504, 8520, 8536, 8548, 8560, 8572, 8584, 8596, 8608, 8612, 8624, 8648, 8660, 8668, 8680, 8708, 8720, 8728, 8740, 8752, 8764, 8788, 8800, 8812, 8824, 8848, 8860, 8864, 8868, 8876, 8888, 8896, 8916, 8944, 8948, 8960, 8964, 8968, 8980, 9148, 9172, 9212, 9216, 9220, 9820, 9860, 9892, 9940, 9972, 10012, 10036, 10040, 10052, 10080, 10152, 10192, 10248, 10284, 10320, 10360, 10392, 10452, 10488, 10508, 10556, 10644, 10684, 10812, 10844, 10880, 10912, 10956, 11172, 11200, 11232, 11272, 11312, 11348, 11380, 11404, 11436, 11492, 11548, 11616, 11684, 11748, 11792, 11840, 11896, 11936, 11980, 12028, 12072, 12908, 12924, 12956, 12960, 12968, 12976, 13020, 13048, 13076, 13104, 13136, 13168, 13196, 13240, 13272, 13292, 13296, 13308, 13312, 13320, 13324, 13364, 13408, 13460, 13492, 13516, 13560, 13612, 13664, 13700, 13744, 13796, 13848, 13884, 13940, 13996, 14040, 14084, 14140, 14148, 14156, 14164, 14184, 14192, 14204, 14208, 14212, 14256, 14272, 14284, 14296, 14300, 14312, 14320, 14324, 14348, 14356, 14360, 14372, 14380, 14392, 14432, 14440, 14444, 14472, 14496, 14516, 14536, 14548, 14560, 14572, 14580, 14588, 14596, 14604, 14612, 14620, 14636, 14660, 14704, 14740, 14748, 14756, 14760, 14768, -1, }; static const int unsupported_strings_1_2[] = { 0, 4, 64, 104, 160, 200, 220, 236, 244, 252, 272, 288, 296, 316, 332, 372, 436, 500, 504, 536, 544, 560, 576, 584, 592, 612, 640, 664, 708, 712, 744, 756, 776, 820, 832, 840, 852, 888, 896, 920, 964, 1004, 1040, 1048, 1060, 1100, 1140, 1172, 1204, 1224, 2312, 2436, 2448, 2464, 2480, 2492, 2512, 2524, 2536, 2596, 2608, 2636, 2652, 2656, 2676, 2684, 2688, 2720, 2732, 2744, 2752, 2764, 2772, 2776, 2792, 2816, 2824, 2832, 2852, 2884, 2896, 2908, 2940, 2952, 2960, 2972, 3520, 3528, 3540, 3584, 3620, 3648, 3652, 3656, 3680, 3704, 3720, 3776, 3804, 3824, 3856, 3888, 4020, 4044, 4084, 4116, 4156, 4272, 4288, 4296, 4332, 4352, 4428, 4432, 8740, 8764, 9552, 9868, 9888, 9900, 9916, 9928, 9940, 9948, 9960, 9976, 9992, 10004, 10016, 10032, 10044, 10060, 10076, 10088, 10104, 10120, 10132, 10140, 10152, 10164, 10176, 10188, 10204, 10220, 10236, 10248, 10260, 10272, 10284, 10300, 10316, 10332, 10348, 10360, 10372, 10384, 10396, 10408, 10420, 10424, 10436, 10460, 10472, 10480, 10492, 10520, 10532, 10540, 10552, 10564, 10576, 10600, 10612, 10624, 10636, 10660, 10672, 10676, 10700, 10704, 10728, 10756, 10764, 10788, 10792, 10796, 10804, 10816, 10824, 10844, 10872, 10876, 10888, 10892, 10896, 10908, 11076, 11100, 11140, 11144, 11148, 11748, 11788, 11820, 11868, 11900, 11940, 11964, 11968, 11980, 12008, 12080, 12120, 12176, 12212, 12248, 12288, 12320, 12380, 12400, 12448, 12536, 12576, 12704, 12736, 12968, 13000, 13024, 13080, 13136, 13204, 13272, 13336, 13380, 13428, 14272, 14288, 14320, 14324, 14332, 14340, 14384, 14412, 14440, 14468, 14500, 14532, 14560, 14604, 14636, 14656, 14696, 14740, 14792, 14824, 14848, 14892, 14944, 14996, 15032, 15076, 15128, 15180, 15216, 15272, 15328, 15372, 15416, 15472, 15480, 15488, 15496, 15516, 15524, 15536, 15540, 15544, 15588, 15604, 15616, 15628, 15632, 15644, 15652, 15656, 15680, 15688, 15692, 15704, 15712, 15724, 15764, 15772, 15776, 15804, 15828, 15848, 15868, 15880, 15892, 15904, 15912, 15920, 15928, 15936, -1, }; static const int unsupported_strings_1_3[] = { 0, 4, 64, 104, 160, 200, 220, 236, 244, 252, 272, 288, 296, 316, 332, 372, 436, 500, 504, 536, 544, 560, 576, 584, 592, 612, 640, 664, 708, 712, 744, 756, 776, 820, 832, 840, 852, 888, 896, 920, 964, 1004, 1040, 1048, 1060, 1100, 1140, 1172, 1204, 1224, 2312, 2436, 2448, 2464, 2480, 2492, 2512, 2524, 2536, 2596, 2608, 2636, 2652, 2656, 2676, 2684, 2688, 2720, 2732, 2744, 2752, 2764, 2772, 2776, 2792, 2816, 2824, 2832, 2852, 2884, 2896, 2908, 2940, 2952, 2960, 2972, 3520, 3528, 3540, 3584, 3620, 3648, 3652, 3656, 3680, 3704, 3720, 3776, 3804, 3824, 3856, 3888, 4020, 4044, 4084, 4116, 4156, 4272, 4288, 4296, 4332, 4352, 4428, 4432, 8740, 8764, 9552, 9868, 9888, 9900, 9916, 9928, 9940, 9948, 9960, 9976, 9992, 10004, 10016, 10032, 10044, 10060, 10076, 10088, 10104, 10120, 10132, 10140, 10152, 10164, 10176, 10188, 10204, 10220, 10236, 10248, 10260, 10272, 10284, 10300, 10316, 10332, 10348, 10360, 10372, 10384, 10396, 10408, 10420, 10424, 10436, 10460, 10472, 10480, 10492, 10520, 10532, 10540, 10552, 10564, 10576, 10600, 10612, 10624, 10636, 10660, 10672, 10676, 10700, 10704, 10728, 10756, 10764, 10788, 10792, 10796, 10804, 10816, 10824, 10844, 10872, 10876, 10888, 10892, 10896, 10908, 11076, 11100, 11140, 11144, 11148, 11748, 11788, 11820, 11868, 11900, 11940, 11964, 11968, 11980, 12008, 12080, 12120, 12176, 12212, 12248, 12288, 12320, 12380, 12400, 12448, 12536, 12576, 12704, 12736, 12968, 13000, 13024, 13080, 13136, 13204, 13272, 13336, 13380, 13428, 14272, 14288, 14320, 14324, 14332, 14340, 14384, 14412, 14440, 14468, 14500, 14532, 14560, 14604, 14636, 14656, 14696, 14740, 14792, 14824, 14848, 14892, 14944, 14996, 15032, 15076, 15128, 15180, 15216, 15272, 15328, 15372, 15416, 15472, 15480, 15488, 15496, 15516, 15524, 15536, 15540, 15544, 15588, 15604, 15616, 15628, 15632, 15644, 15652, 15656, 15680, 15688, 15692, 15704, 15712, 15724, 15764, 15772, 15776, 15804, 15828, 15848, 15868, 15880, 15892, 15904, 15912, 15920, 15928, 15936, -1, }; static const int *unsupported_strings[] = { unsupported_strings_1_0, unsupported_strings_1_2, unsupported_strings_1_3, }; static boolean StringIsUnsupported(unsigned int offset) { const int *string_list; int i; string_list = unsupported_strings[deh_hhe_version]; for (i=0; string_list[i] >= 0; ++i) { if ((unsigned int) string_list[i] == offset) { return true; } } return false; } static boolean GetStringByOffset(unsigned int offset, char **result) { int i; for (i=0; i= 0; ++i) { if (string_list[i] == offset) { DEH_SuggestHereticVersion(v); } } } } static void *DEH_TextStart(deh_context_t *context, char *line) { char *repl_text; char *orig_text; int orig_offset, repl_len; int i; if (sscanf(line, "Text %i %i", &orig_offset, &repl_len) != 2) { DEH_Warning(context, "Parse error on section start"); return NULL; } repl_text = malloc(repl_len + 1); // read in the "to" text for (i=0; i MaxStringLength(strlen(orig_text))) { DEH_Error(context, "Replacement string is longer than the maximum " "possible in heretic.exe"); } else { // Success. DEH_AddStringReplacement(orig_text, repl_text); } // We must always free the replacement text. free(repl_text); return NULL; } static void DEH_TextParseLine(deh_context_t *context, char *line, void *tag) { // not used } deh_section_t deh_section_heretic_text = { "Text", NULL, DEH_TextStart, DEH_TextParseLine, NULL, NULL, }; chocolate-doom-chocolate-doom-2.2.1/src/heretic/deh_htic.c000066400000000000000000000115351257432200600234370ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Top-level dehacked definitions for Heretic dehacked (HHE). // #include #include #include #include "deh_defs.h" #include "deh_main.h" #include "deh_htic.h" #include "info.h" #include "m_argv.h" char *deh_signatures[] = { "Patch File for HHE v1.0", "Patch File for HHE v1.1", NULL }; static char *hhe_versions[] = { "1.0", "1.2", "1.3" }; // Version number for patches. deh_hhe_version_t deh_hhe_version = deh_hhe_1_0; // deh_ammo.c: extern deh_section_t deh_section_ammo; // deh_frame.c: extern deh_section_t deh_section_frame; // deh_ptr.c: extern deh_section_t deh_section_pointer; // deh_sound.c extern deh_section_t deh_section_sound; // deh_htext.c: extern deh_section_t deh_section_heretic_text; // deh_thing.c: extern deh_section_t deh_section_thing; // deh_weapon.c: extern deh_section_t deh_section_weapon; // // List of section types: // deh_section_t *deh_section_types[] = { &deh_section_ammo, &deh_section_frame, // &deh_section_pointer, TODO &deh_section_sound, &deh_section_heretic_text, &deh_section_thing, &deh_section_weapon, NULL }; static void SetHHEVersionByName(char *name) { int i; for (i=0; i // @category mod // // Select the Heretic version number that was used to generate the // HHE patch to be loaded. Patches for each of the Vanilla // Heretic versions (1.0, 1.2, 1.3) can be loaded, but the correct // version number must be specified. i = M_CheckParm("-hhever"); if (i > 0) { SetHHEVersionByName(myargv[i + 1]); } // For v1.0 patches, we must apply a slight change to the states[] // table. The table was changed between 1.0 and 1.3 to add two extra // frames to the player "burning death" animation. // // If we are using a v1.0 patch, we must change the table to cut // these out again. if (deh_hhe_version < deh_hhe_1_2) { states[S_PLAY_FDTH18].nextstate = S_NULL; } } int DEH_MapHereticThingType(int type) { // Heretic 1.0 had an extra entry in the mobjinfo table that was removed // in later versions. This has been added back into the table for // compatibility. However, it also means that if we're loading a patch // for a later version, we need to translate to the index used internally. if (deh_hhe_version > deh_hhe_1_0) { if (type >= MT_PHOENIXFX_REMOVED) { ++type; } } return type; } int DEH_MapHereticFrameNumber(int frame) { if (deh_hhe_version < deh_hhe_1_2) { // Between Heretic 1.0 and 1.2, two new frames // were added to the "states" table, to extend the "flame death" // animation displayed when the player is killed by fire. Therefore, // we must map Heretic 1.0 frame numbers to corresponding indexes // for our state table. if (frame >= S_PLAY_FDTH19) { frame = (frame - S_PLAY_FDTH19) + S_BLOODYSKULL1; } } else { // After Heretic 1.2, three unused frames were removed from the // states table, unused phoenix rod frames. Our state table includes // these missing states for backwards compatibility. We must therefore // adjust frame numbers for v1.2/v1.3 to corresponding indexes for // our state table. if (frame >= S_PHOENIXFXIX_1) { frame = (frame - S_PHOENIXFXIX_1) + S_PHOENIXPUFF1; } } return frame; } void DEH_SuggestHereticVersion(deh_hhe_version_t version) { fprintf(stderr, "\n" "This patch may be for version %s. You are currently running in\n" "Heretic %s mode. For %s mode, add this to your command line:\n" "\n" "\t-hhever %s\n" "\n", hhe_versions[version], hhe_versions[deh_hhe_version], hhe_versions[version], hhe_versions[version]); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/deh_htic.h000066400000000000000000000027141257432200600234430ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Common header for Heretic dehacked (HHE) support. // #ifndef DEH_HTIC_H #define DEH_HTIC_H #include "info.h" // HHE executable version. Loading HHE patches is (unfortunately) // dependent on the version of the Heretic executable used to make them. typedef enum { deh_hhe_1_0, deh_hhe_1_2, deh_hhe_1_3, deh_hhe_num_versions } deh_hhe_version_t; // HHE doesn't know about the last two states in the state table, so // these are considered invalid. #define DEH_HERETIC_NUMSTATES (NUMSTATES - 2) // It also doesn't know about the last two things in the mobjinfo table // (which correspond to the states above) #define DEH_HERETIC_NUMMOBJTYPES (NUMMOBJTYPES - 2) void DEH_HereticInit(void); int DEH_MapHereticThingType(int type); int DEH_MapHereticFrameNumber(int frame); void DEH_SuggestHereticVersion(deh_hhe_version_t version); extern deh_hhe_version_t deh_hhe_version; #endif /* #ifndef DEH_HTIC_H */ chocolate-doom-chocolate-doom-2.2.1/src/heretic/deh_sound.c000066400000000000000000000051531257432200600236370ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Sound" sections in dehacked files // #include #include #include "doomfeatures.h" #include "doomtype.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" #include "doomdef.h" #include "i_sound.h" #include "sounds.h" DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t) DEH_MAPPING_STRING("Name", name) DEH_UNSUPPORTED_MAPPING("Special") DEH_MAPPING("Value", priority) DEH_MAPPING("Unknown 1", usefulness) DEH_UNSUPPORTED_MAPPING("Unknown 2") DEH_UNSUPPORTED_MAPPING("Unknown 3") DEH_MAPPING("One/Two", numchannels) DEH_END_MAPPING static void *DEH_SoundStart(deh_context_t *context, char *line) { int sound_number = 0; if (sscanf(line, "Sound %i", &sound_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (sound_number < 0 || sound_number >= NUMSFX) { DEH_Warning(context, "Invalid sound number: %i", sound_number); return NULL; } if (sound_number >= DEH_VANILLA_NUMSFX) { DEH_Warning(context, "Attempt to modify SFX %i. This will cause " "problems in Vanilla dehacked.", sound_number); } return &S_sfx[sound_number]; } static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag) { sfxinfo_t *sfx; char *variable_name, *value; if (tag == NULL) return; sfx = (sfxinfo_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // Set the field value: if (!strcasecmp(variable_name, "Name")) { DEH_SetStringMapping(context, &sound_mapping, sfx, variable_name, value); } else { DEH_SetMapping(context, &sound_mapping, sfx, variable_name, atoi(value)); } } deh_section_t deh_section_sound = { "Sound", NULL, DEH_SoundStart, DEH_SoundParseLine, NULL, NULL, }; chocolate-doom-chocolate-doom-2.2.1/src/heretic/deh_thing.c000066400000000000000000000075621257432200600236260ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Thing" sections in dehacked files // #include #include #include "doomtype.h" #include "m_misc.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" #include "deh_htic.h" #include "info.h" DEH_BEGIN_MAPPING(thing_mapping, mobjinfo_t) DEH_MAPPING("ID #", doomednum) DEH_MAPPING("Initial frame", spawnstate) DEH_MAPPING("Hit points", spawnhealth) DEH_MAPPING("First moving frame", seestate) DEH_MAPPING("Alert sound", seesound) DEH_MAPPING("Reaction time", reactiontime) DEH_MAPPING("Attack sound", attacksound) DEH_MAPPING("Injury frame", painstate) DEH_MAPPING("Pain chance", painchance) DEH_MAPPING("Pain sound", painsound) DEH_MAPPING("Close attack frame", meleestate) DEH_MAPPING("Far attack frame", missilestate) DEH_MAPPING("Burning frame", crashstate) DEH_MAPPING("Death frame", deathstate) DEH_MAPPING("Exploding frame", xdeathstate) DEH_MAPPING("Death sound", deathsound) DEH_MAPPING("Speed", speed) DEH_MAPPING("Width", radius) DEH_MAPPING("Height", height) DEH_MAPPING("Mass", mass) DEH_MAPPING("Missile damage", damage) DEH_MAPPING("Action sound", activesound) DEH_MAPPING("Bits 1", flags) DEH_MAPPING("Bits 2", flags2) DEH_END_MAPPING static void *DEH_ThingStart(deh_context_t *context, char *line) { int orig_thing_number = 0, thing_number = 0; mobjinfo_t *mobj; if (sscanf(line, "Thing %i", &orig_thing_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } // Translate to the correct thing number based on the exe version this // patch was made for. Subtract one because HHE thing numbers are // indexed from 1. thing_number = DEH_MapHereticThingType(orig_thing_number - 1); if (thing_number < 0 || thing_number >= DEH_HERETIC_NUMMOBJTYPES) { DEH_Warning(context, "Invalid thing number: %i", orig_thing_number); return NULL; } mobj = &mobjinfo[thing_number]; return mobj; } static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag) { mobjinfo_t *mobj; char *variable_name, *value; int ivalue; if (tag == NULL) return; mobj = (mobjinfo_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // all values are integers ivalue = atoi(value); // If the value to be set is a frame, the frame number must // undergo transformation from a Heretic 1.0 index to a // Heretic 1.3 index. if (M_StrCaseStr(variable_name, "frame") != NULL) { ivalue = DEH_MapHereticFrameNumber(ivalue); } // Set the field value DEH_SetMapping(context, &thing_mapping, mobj, variable_name, ivalue); } static void DEH_ThingSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include #include "doomtype.h" #include "m_misc.h" #include "doomdef.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" #include "deh_htic.h" DEH_BEGIN_MAPPING(weapon_mapping, weaponinfo_t) DEH_MAPPING("Ammo type", ammo) DEH_MAPPING("Deselect frame", upstate) DEH_MAPPING("Select frame", downstate) DEH_MAPPING("Bobbing frame", readystate) DEH_MAPPING("Shooting frame", atkstate) DEH_MAPPING("Firing frame", holdatkstate) DEH_MAPPING("Unknown frame", flashstate) DEH_END_MAPPING static void *DEH_WeaponStart(deh_context_t *context, char *line) { int weapon_number = 0; if (sscanf(line, "Weapon %i", &weapon_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (weapon_number < 0 || weapon_number >= NUMWEAPONS * 2) { DEH_Warning(context, "Invalid weapon number: %i", weapon_number); return NULL; } // Because of the tome of power, we have two levels of weapons: if (weapon_number < NUMWEAPONS) { return &wpnlev1info[weapon_number]; } else { return &wpnlev2info[weapon_number - NUMWEAPONS]; } } static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; weaponinfo_t *weapon; int ivalue; if (tag == NULL) return; weapon = (weaponinfo_t *) tag; if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); // If this is a frame field, we need to map from Heretic 1.0 frame // numbers to Heretic 1.3 frame numbers. if (M_StrCaseStr(variable_name, "frame") != NULL) { ivalue = DEH_MapHereticFrameNumber(ivalue); } DEH_SetMapping(context, &weapon_mapping, weapon, variable_name, ivalue); } static void DEH_WeaponSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include //haleyjd: removed WATCOMC #include #define HERETIC_VERSION 130 #define HERETIC_VERSION_TEXT "v1.3" // if rangecheck is undefined, most parameter validation debugging code // will not be compiled //#define RANGECHECK // all external data is defined here #include "doomdata.h" // all important printed strings #include "dstrings.h" // header generated by multigen utility #include "info.h" // WAD file access #include "w_wad.h" // fixed_t #include "m_fixed.h" // angle_t #include "tables.h" // events #include "d_event.h" // gamemode/mission #include "d_mode.h" // ticcmd_t #include "d_ticcmd.h" #include "d_loop.h" #define SAVEGAMENAME "hticsav" /* =============================================================================== GLOBAL TYPES =============================================================================== */ #define NUMARTIFCTS 28 #define MAXPLAYERS 4 #define BT_ATTACK 1 #define BT_USE 2 #define BT_CHANGE 4 // if true, the next 3 bits hold weapon num #define BT_WEAPONMASK (8+16+32) #define BT_WEAPONSHIFT 3 #define BT_SPECIAL 128 // game events, not really buttons #define BTS_SAVEMASK (4+8+16) #define BTS_SAVESHIFT 2 #define BT_SPECIALMASK 3 #define BTS_PAUSE 1 // pause the game #define BTS_SAVEGAME 2 // save the game at each console // savegame slot numbers occupy the second byte of buttons typedef enum { GS_LEVEL, GS_INTERMISSION, GS_FINALE, GS_DEMOSCREEN } gamestate_t; typedef enum { ga_nothing, ga_loadlevel, ga_newgame, ga_loadgame, ga_savegame, ga_playdemo, ga_completed, ga_victory, ga_worlddone, ga_screenshot } gameaction_t; typedef enum { wipe_0, wipe_1, wipe_2, wipe_3, wipe_4, NUMWIPES, wipe_random } wipe_t; /* =============================================================================== MAPOBJ DATA =============================================================================== */ // think_t is a function pointer to a routine to handle an actor typedef void (*think_t) (); typedef struct thinker_s { struct thinker_s *prev, *next; think_t function; } thinker_t; typedef union { int i; struct mobj_s *m; } specialval_t; struct player_s; typedef struct mobj_s { thinker_t thinker; // thinker links // info for drawing fixed_t x, y, z; struct mobj_s *snext, *sprev; // links in sector (if needed) angle_t angle; spritenum_t sprite; // used to find patch_t and flip value int frame; // might be ord with FF_FULLBRIGHT // interaction info struct mobj_s *bnext, *bprev; // links in blocks (if needed) struct subsector_s *subsector; fixed_t floorz, ceilingz; // closest together of contacted secs fixed_t radius, height; // for movement checking fixed_t momx, momy, momz; // momentums int validcount; // if == validcount, already checked mobjtype_t type; mobjinfo_t *info; // &mobjinfo[mobj->type] int tics; // state tic counter state_t *state; int damage; // For missiles int flags; int flags2; // Heretic flags specialval_t special1; // Special info specialval_t special2; // Special info int health; int movedir; // 0-7 int movecount; // when 0, select a new dir struct mobj_s *target; // thing being chased/attacked (or NULL) // also the originator for missiles int reactiontime; // if non 0, don't attack yet // used by player to freeze a bit after // teleporting int threshold; // if >0, the target will be chased // no matter what (even if shot) struct player_s *player; // only valid if type == MT_PLAYER int lastlook; // player number last looked for mapthing_t spawnpoint; // for nightmare respawn } mobj_t; // each sector has a degenmobj_t in it's center for sound origin purposes typedef struct { thinker_t thinker; // not used for anything fixed_t x, y, z; } degenmobj_t; // // frame flags // #define FF_FULLBRIGHT 0x8000 // flag in thing->frame #define FF_FRAMEMASK 0x7fff // --- mobj.flags --- #define MF_SPECIAL 1 // call P_SpecialThing when touched #define MF_SOLID 2 #define MF_SHOOTABLE 4 #define MF_NOSECTOR 8 // don't use the sector links // (invisible but touchable) #define MF_NOBLOCKMAP 16 // don't use the blocklinks // (inert but displayable) #define MF_AMBUSH 32 #define MF_JUSTHIT 64 // try to attack right back #define MF_JUSTATTACKED 128 // take at least one step before attacking #define MF_SPAWNCEILING 256 // hang from ceiling instead of floor #define MF_NOGRAVITY 512 // don't apply gravity every tic // movement flags #define MF_DROPOFF 0x400 // allow jumps from high places #define MF_PICKUP 0x800 // for players to pick up items #define MF_NOCLIP 0x1000 // player cheat #define MF_SLIDE 0x2000 // keep info about sliding along walls #define MF_FLOAT 0x4000 // allow moves to any height, no gravity #define MF_TELEPORT 0x8000 // don't cross lines or look at heights #define MF_MISSILE 0x10000 // don't hit same species, explode on block #define MF_DROPPED 0x20000 // dropped by a demon, not level spawned #define MF_SHADOW 0x40000 // use translucent draw (shadow demons / invis) #define MF_NOBLOOD 0x80000 // don't bleed when shot (use puff) #define MF_CORPSE 0x100000 // don't stop moving halfway off a step #define MF_INFLOAT 0x200000 // floating to a height for a move, don't // auto float to target's height #define MF_COUNTKILL 0x400000 // count towards intermission kill total #define MF_COUNTITEM 0x800000 // count towards intermission item total #define MF_SKULLFLY 0x1000000 // skull in flight #define MF_NOTDMATCH 0x2000000 // don't spawn in death match (key cards) #define MF_TRANSLATION 0xc000000 // if 0x4 0x8 or 0xc, use a translation #define MF_TRANSSHIFT 26 // table for player colormaps // --- mobj.flags2 --- #define MF2_LOGRAV 0x00000001 // alternate gravity setting #define MF2_WINDTHRUST 0x00000002 // gets pushed around by the wind // specials #define MF2_FLOORBOUNCE 0x00000004 // bounces off the floor #define MF2_THRUGHOST 0x00000008 // missile will pass through ghosts #define MF2_FLY 0x00000010 // fly mode is active #define MF2_FOOTCLIP 0x00000020 // if feet are allowed to be clipped #define MF2_SPAWNFLOAT 0x00000040 // spawn random float z #define MF2_NOTELEPORT 0x00000080 // does not teleport #define MF2_RIP 0x00000100 // missile rips through solid // targets #define MF2_PUSHABLE 0x00000200 // can be pushed by other moving // mobjs #define MF2_SLIDE 0x00000400 // slides against walls #define MF2_ONMOBJ 0x00000800 // mobj is resting on top of another // mobj #define MF2_PASSMOBJ 0x00001000 // Enable z block checking. If on, // this flag will allow the mobj to // pass over/under other mobjs. #define MF2_CANNOTPUSH 0x00002000 // cannot push other pushable mobjs #define MF2_FEETARECLIPPED 0x00004000 // a mobj's feet are now being cut #define MF2_BOSS 0x00008000 // mobj is a major boss #define MF2_FIREDAMAGE 0x00010000 // does fire damage #define MF2_NODMGTHRUST 0x00020000 // does not thrust target when // damaging #define MF2_TELESTOMP 0x00040000 // mobj can stomp another #define MF2_FLOATBOB 0x00080000 // use float bobbing z movement #define MF2_DONTDRAW 0X00100000 // don't generate a vissprite //============================================================================= typedef enum { PST_LIVE, // playing PST_DEAD, // dead on the ground PST_REBORN // ready to restart } playerstate_t; // psprites are scaled shapes directly on the view screen // coordinates are given for a 320*200 view screen typedef enum { ps_weapon, ps_flash, NUMPSPRITES } psprnum_t; typedef struct { state_t *state; // a NULL state means not active int tics; fixed_t sx, sy; } pspdef_t; typedef enum { key_yellow, key_green, key_blue, NUMKEYS } keytype_t; typedef enum { wp_staff, wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace, wp_gauntlets, wp_beak, NUMWEAPONS, wp_nochange } weapontype_t; #define AMMO_GWND_WIMPY 10 #define AMMO_GWND_HEFTY 50 #define AMMO_CBOW_WIMPY 5 #define AMMO_CBOW_HEFTY 20 #define AMMO_BLSR_WIMPY 10 #define AMMO_BLSR_HEFTY 25 #define AMMO_SKRD_WIMPY 20 #define AMMO_SKRD_HEFTY 100 #define AMMO_PHRD_WIMPY 1 #define AMMO_PHRD_HEFTY 10 #define AMMO_MACE_WIMPY 20 #define AMMO_MACE_HEFTY 100 typedef enum { am_goldwand, am_crossbow, am_blaster, am_skullrod, am_phoenixrod, am_mace, NUMAMMO, am_noammo // staff, gauntlets } ammotype_t; typedef struct { ammotype_t ammo; int upstate; int downstate; int readystate; int atkstate; int holdatkstate; int flashstate; } weaponinfo_t; extern weaponinfo_t wpnlev1info[NUMWEAPONS]; extern weaponinfo_t wpnlev2info[NUMWEAPONS]; typedef enum { arti_none, arti_invulnerability, arti_invisibility, arti_health, arti_superhealth, arti_tomeofpower, arti_torch, arti_firebomb, arti_egg, arti_fly, arti_teleport, NUMARTIFACTS } artitype_t; typedef enum { pw_None, pw_invulnerability, pw_invisibility, pw_allmap, pw_infrared, pw_weaponlevel2, pw_flight, pw_shield, pw_health2, NUMPOWERS } powertype_t; #define INVULNTICS (30*35) #define INVISTICS (60*35) #define INFRATICS (120*35) #define IRONTICS (60*35) #define WPNLEV2TICS (40*35) #define FLIGHTTICS (60*35) #define CHICKENTICS (40*35) #define MESSAGETICS (4*35) #define BLINKTHRESHOLD (4*32) #define NUMINVENTORYSLOTS 14 typedef struct { int type; int count; } inventory_t; /* ================ = = player_t = ================ */ typedef struct player_s { mobj_t *mo; playerstate_t playerstate; ticcmd_t cmd; fixed_t viewz; // focal origin above r.z fixed_t viewheight; // base height above floor for viewz fixed_t deltaviewheight; // squat speed fixed_t bob; // bounded/scaled total momentum int flyheight; int lookdir; boolean centering; int health; // only used between levels, mo->health // is used during levels int armorpoints, armortype; // armor type is 0-2 inventory_t inventory[NUMINVENTORYSLOTS]; artitype_t readyArtifact; int artifactCount; int inventorySlotNum; int powers[NUMPOWERS]; boolean keys[NUMKEYS]; boolean backpack; signed int frags[MAXPLAYERS]; // kills of other players weapontype_t readyweapon; weapontype_t pendingweapon; // wp_nochange if not changing boolean weaponowned[NUMWEAPONS]; int ammo[NUMAMMO]; int maxammo[NUMAMMO]; int attackdown, usedown; // true if button down last tic int cheats; // bit flags int refire; // refired shots are less accurate int killcount, itemcount, secretcount; // for intermission char *message; // hint messages int messageTics; // counter for showing messages int damagecount, bonuscount; // for screen flashing int flamecount; // for flame thrower duration mobj_t *attacker; // who did damage (NULL for floors) int extralight; // so gun flashes light up areas int fixedcolormap; // can be set to REDCOLORMAP, etc int colormap; // 0-3 for which color to draw player pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc) boolean didsecret; // true if secret level has been done int chickenTics; // player is a chicken if > 0 int chickenPeck; // chicken peck countdown mobj_t *rain1; // active rain maker 1 mobj_t *rain2; // active rain maker 2 } player_t; #define CF_NOCLIP 1 #define CF_GODMODE 2 #define CF_NOMOMENTUM 4 // not really a cheat, just a debug aid #define SBARHEIGHT 42 // status bar height at bottom of screen /* =============================================================================== GLOBAL VARIABLES =============================================================================== */ #define TELEFOGHEIGHT (32*FRACUNIT) extern gameaction_t gameaction; extern boolean paused; extern GameMode_t gamemode; extern boolean ExtendedWAD; // true if main WAD is the extended version extern boolean nomonsters; // checkparm of -nomonsters extern boolean respawnparm; // checkparm of -respawn extern boolean debugmode; // checkparm of -debug extern boolean usergame; // ok to save / end game extern boolean ravpic; // checkparm of -ravpic extern boolean altpal; // checkparm to use an alternate palette routine extern boolean cdrom; // true if cd-rom mode active ("-cdrom") extern boolean deathmatch; // only if started as net death extern boolean netgame; // only true if >1 player extern boolean playeringame[MAXPLAYERS]; extern int consoleplayer; // player taking events and displaying extern int displayplayer; extern int viewangleoffset; // ANG90 = left side, ANG270 = right extern player_t players[MAXPLAYERS]; extern boolean DebugSound; // debug flag for displaying sound info extern int GetWeaponAmmo[NUMWEAPONS]; extern boolean demorecording; extern boolean demoplayback; extern int skytexture; extern gamestate_t gamestate; extern skill_t gameskill; extern boolean respawnmonsters; extern int gameepisode; extern int gamemap; extern int prevmap; extern int totalkills, totalitems, totalsecret; // for intermission extern int levelstarttic; // gametic at level start extern int leveltime; // tics in game play for par extern ticcmd_t *netcmds; #define SAVEGAMESIZE 0x30000 #define SAVESTRINGSIZE 24 extern mapthing_t *deathmatch_p; extern mapthing_t deathmatchstarts[10]; extern mapthing_t playerstarts[MAXPLAYERS]; extern int mouseSensitivity; extern boolean precache; // if true, load all graphics at level load extern boolean singledemo; // quit after playing a demo from cmdline extern int bodyqueslot; extern skill_t startskill; extern int startepisode; extern int startmap; extern boolean autostart; extern boolean testcontrols; extern int testcontrols_mousespeed; /* =============================================================================== GLOBAL FUNCTIONS =============================================================================== */ #include "z_zone.h" //---------- //BASE LEVEL //---------- void D_DoomMain(void); void IncThermo(void); void InitThermo(int max); void tprintf(char *string, int initflag); // not a globally visible function, just included for source reference // calls all startup code // parses command line options // if not overrided, calls N_AdvanceDemo void D_DoomLoop(void); // not a globally visible function, just included for source reference // called by D_DoomMain, never exits // manages timing and IO // calls all ?_Responder, ?_Ticker, and ?_Drawer functions // calls I_GetTime, I_StartFrame, and I_StartTic //--------- //SYSTEM IO //--------- byte *I_AllocLow(int length); // allocates from low memory under dos, just mallocs under unix // haleyjd: was WATCOMC, preserved for historical interest. // This is similar to the -control structure in DOOM v1.4 and Strife. #if 0 extern boolean useexterndriver; #define EBT_FIRE 1 #define EBT_OPENDOOR 2 #define EBT_SPEED 4 #define EBT_STRAFE 8 #define EBT_MAP 0x10 #define EBT_INVENTORYLEFT 0x20 #define EBT_INVENTORYRIGHT 0x40 #define EBT_USEARTIFACT 0x80 #define EBT_FLYDROP 0x100 #define EBT_CENTERVIEW 0x200 #define EBT_PAUSE 0x400 #define EBT_WEAPONCYCLE 0x800 typedef struct { short vector; // Interrupt vector signed char moveForward; // forward/backward (maxes at 50) signed char moveSideways; // strafe (maxes at 24) short angleTurn; // turning speed (640 [slow] 1280 [fast]) short angleHead; // head angle (+2080 [left] : 0 [center] : -2048 [right]) signed char pitch; // look up/down (-110 : +90) signed char flyDirection; // flyheight (+1/-1) unsigned short buttons; // EBT_* flags } externdata_t; #endif //---- //GAME //---- void G_DeathMatchSpawnPlayer(int playernum); void G_InitNew(skill_t skill, int episode, int map); void G_DeferedInitNew(skill_t skill, int episode, int map); // can be called by the startup code or M_Responder // a normal game starts at map 1, but a warp test can start elsewhere void G_DeferedPlayDemo(char *demo); void G_LoadGame(char *name); // can be called by the startup code or M_Responder // calls P_SetupLevel or W_EnterWorld void G_DoLoadGame(void); void G_SaveGame(int slot, char *description); // called by M_Responder #define SAVE_GAME_TERMINATOR 0x1d // Support routines for saving games char *SV_Filename(int slot); void SV_Open(char *fileName); void SV_OpenRead(char *fileName); void SV_Close(char *fileName); void SV_Write(void *buffer, int size); void SV_WriteByte(byte val); void SV_WriteWord(unsigned short val); void SV_WriteLong(unsigned int val); void SV_Read(void *buffer, int size); byte SV_ReadByte(void); uint16_t SV_ReadWord(void); uint32_t SV_ReadLong(void); extern char *savegamedir; void G_RecordDemo(skill_t skill, int numplayers, int episode, int map, char *name); // only called by startup code void G_PlayDemo(char *name); void G_TimeDemo(char *name); void G_ExitLevel(void); void G_SecretExitLevel(void); void G_WorldDone(void); void G_Ticker(void); boolean G_Responder(event_t * ev); void G_ScreenShot(void); //----- //PLAY //----- void P_Ticker(void); // called by C_Ticker // can call G_PlayerExited // carries out all thinking of monsters and players void P_SetupLevel(int episode, int map, int playermask, skill_t skill); // called by W_Ticker void P_Init(void); // called by startup code void P_ArchivePlayers(void); void P_UnArchivePlayers(void); void P_ArchiveWorld(void); void P_UnArchiveWorld(void); void P_ArchiveThinkers(void); void P_UnArchiveThinkers(void); void P_ArchiveSpecials(void); void P_UnArchiveSpecials(void); // load / save game routines //------- //REFRESH //------- extern boolean setsizeneeded; extern boolean BorderNeedRefresh; extern boolean BorderTopRefresh; extern int UpdateState; // define the different areas for the dirty map #define I_NOUPDATE 0 #define I_FULLVIEW 1 #define I_STATBAR 2 #define I_MESSAGES 4 #define I_FULLSCRN 8 void R_RenderPlayerView(player_t * player); // called by G_Drawer void R_Init(void); // called by startup code void R_DrawViewBorder(void); void R_DrawTopBorder(void); // if the view size is not full screen, draws a border around it void R_SetViewSize(int blocks, int detail); // called by M_Responder int R_FlatNumForName(char *name); int R_TextureNumForName(char *name); int R_CheckTextureNumForName(char *name); // called by P_Ticker for switches and animations // returns the texture number for the texture name //---- //MISC //---- // returns the position of the given parameter in the arg list (0 if not found) int M_DrawText(int x, int y, boolean direct, char *string); //---------------------- // Interlude (IN_lude.c) //---------------------- extern boolean intermission; void IN_Start(void); void IN_Ticker(void); void IN_Drawer(void); //---------------------- // Chat mode (CT_chat.c) //---------------------- void CT_Init(void); void CT_Drawer(void); boolean CT_Responder(event_t * ev); void CT_Ticker(void); char CT_dequeueChatChar(void); extern boolean chatmodeon; extern boolean ultimatemsg; //-------------------- // Finale (F_finale.c) //-------------------- void F_Drawer(void); void F_Ticker(void); void F_StartFinale(void); //---------------------- // STATUS BAR (SB_bar.c) //---------------------- void SB_Init(void); boolean SB_Responder(event_t * event); void SB_Ticker(void); void SB_Drawer(void); //----------------- // MENU (MN_menu.c) //----------------- extern boolean MenuActive; void MN_Init(void); void MN_ActivateMenu(void); void MN_DeactivateMenu(void); boolean MN_Responder(event_t * event); void MN_Ticker(void); void MN_Drawer(void); void MN_DrTextA(char *text, int x, int y); int MN_TextAWidth(char *text); void MN_DrTextB(char *text, int x, int y); int MN_TextBWidth(char *text); #include "sounds.h" #endif // __DOOMDEF__ chocolate-doom-chocolate-doom-2.2.1/src/heretic/dstrings.h000066400000000000000000000212541257432200600235310ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DStrings.h //--------------------------------------------------------------------------- // // P_inter.c // //--------------------------------------------------------------------------- // Keys #define TXT_GOTBLUEKEY "BLUE KEY" #define TXT_GOTYELLOWKEY "YELLOW KEY" #define TXT_GOTGREENKEY "GREEN KEY" // Artifacts #define TXT_ARTIHEALTH "QUARTZ FLASK" #define TXT_ARTIFLY "WINGS OF WRATH" #define TXT_ARTIINVULNERABILITY "RING OF INVINCIBILITY" #define TXT_ARTITOMEOFPOWER "TOME OF POWER" #define TXT_ARTIINVISIBILITY "SHADOWSPHERE" #define TXT_ARTIEGG "MORPH OVUM" #define TXT_ARTISUPERHEALTH "MYSTIC URN" #define TXT_ARTITORCH "TORCH" #define TXT_ARTIFIREBOMB "TIME BOMB OF THE ANCIENTS" #define TXT_ARTITELEPORT "CHAOS DEVICE" // Items #define TXT_ITEMHEALTH "CRYSTAL VIAL" #define TXT_ITEMBAGOFHOLDING "BAG OF HOLDING" #define TXT_ITEMSHIELD1 "SILVER SHIELD" #define TXT_ITEMSHIELD2 "ENCHANTED SHIELD" #define TXT_ITEMSUPERMAP "MAP SCROLL" // Ammo #define TXT_AMMOGOLDWAND1 "WAND CRYSTAL" #define TXT_AMMOGOLDWAND2 "CRYSTAL GEODE" #define TXT_AMMOMACE1 "MACE SPHERES" #define TXT_AMMOMACE2 "PILE OF MACE SPHERES" #define TXT_AMMOCROSSBOW1 "ETHEREAL ARROWS" #define TXT_AMMOCROSSBOW2 "QUIVER OF ETHEREAL ARROWS" #define TXT_AMMOBLASTER1 "CLAW ORB" #define TXT_AMMOBLASTER2 "ENERGY ORB" #define TXT_AMMOSKULLROD1 "LESSER RUNES" #define TXT_AMMOSKULLROD2 "GREATER RUNES" #define TXT_AMMOPHOENIXROD1 "FLAME ORB" #define TXT_AMMOPHOENIXROD2 "INFERNO ORB" // Weapons #define TXT_WPNMACE "FIREMACE" #define TXT_WPNCROSSBOW "ETHEREAL CROSSBOW" #define TXT_WPNBLASTER "DRAGON CLAW" #define TXT_WPNSKULLROD "HELLSTAFF" #define TXT_WPNPHOENIXROD "PHOENIX ROD" #define TXT_WPNGAUNTLETS "GAUNTLETS OF THE NECROMANCER" //--------------------------------------------------------------------------- // // SB_bar.c // //--------------------------------------------------------------------------- #define TXT_CHEATGODON "GOD MODE ON" #define TXT_CHEATGODOFF "GOD MODE OFF" #define TXT_CHEATNOCLIPON "NO CLIPPING ON" #define TXT_CHEATNOCLIPOFF "NO CLIPPING OFF" #define TXT_CHEATWEAPONS "ALL WEAPONS" #define TXT_CHEATFLIGHTON "FLIGHT ON" #define TXT_CHEATFLIGHTOFF "FLIGHT OFF" #define TXT_CHEATPOWERON "POWER ON" #define TXT_CHEATPOWEROFF "POWER OFF" #define TXT_CHEATHEALTH "FULL HEALTH" #define TXT_CHEATKEYS "ALL KEYS" #define TXT_CHEATSOUNDON "SOUND DEBUG ON" #define TXT_CHEATSOUNDOFF "SOUND DEBUG OFF" #define TXT_CHEATTICKERON "TICKER ON" #define TXT_CHEATTICKEROFF "TICKER OFF" #define TXT_CHEATARTIFACTS1 "CHOOSE AN ARTIFACT ( A - J )" #define TXT_CHEATARTIFACTS2 "HOW MANY ( 1 - 9 )" #define TXT_CHEATARTIFACTS3 "YOU GOT IT" #define TXT_CHEATARTIFACTSFAIL "BAD INPUT" #define TXT_CHEATWARP "LEVEL WARP" #define TXT_CHEATSCREENSHOT "SCREENSHOT" #define TXT_CHEATCHICKENON "CHICKEN ON" #define TXT_CHEATCHICKENOFF "CHICKEN OFF" #define TXT_CHEATMASSACRE "MASSACRE" #define TXT_CHEATIDDQD "TRYING TO CHEAT, EH? NOW YOU DIE!" #define TXT_CHEATIDKFA "CHEATER - YOU DON'T DESERVE WEAPONS" //--------------------------------------------------------------------------- // // P_doors.c // //--------------------------------------------------------------------------- #define TXT_NEEDBLUEKEY "YOU NEED A BLUE KEY TO OPEN THIS DOOR" #define TXT_NEEDGREENKEY "YOU NEED A GREEN KEY TO OPEN THIS DOOR" #define TXT_NEEDYELLOWKEY "YOU NEED A YELLOW KEY TO OPEN THIS DOOR" //--------------------------------------------------------------------------- // // G_game.c // //--------------------------------------------------------------------------- #define TXT_GAMESAVED "GAME SAVED" //--------------------------------------------------------------------------- // // AM_map.c // //--------------------------------------------------------------------------- #define AMSTR_FOLLOWON "FOLLOW MODE ON" #define AMSTR_FOLLOWOFF "FOLLOW MODE OFF" #define AMSTR_GRIDON "Grid ON" #define AMSTR_GRIDOFF "Grid OFF" #define AMSTR_MARKEDSPOT "Marked Spot" #define AMSTR_MARKSCLEARED "All Marks Cleared" //--------------------------------------------------------------------------- // // F_finale.c // //--------------------------------------------------------------------------- #define E1TEXT "with the destruction of the iron\n"\ "liches and their minions, the last\n"\ "of the undead are cleared from this\n"\ "plane of existence.\n\n"\ "those creatures had to come from\n"\ "somewhere, though, and you have the\n"\ "sneaky suspicion that the fiery\n"\ "portal of hell's maw opens onto\n"\ "their home dimension.\n\n"\ "to make sure that more undead\n"\ "(or even worse things) don't come\n"\ "through, you'll have to seal hell's\n"\ "maw from the other side. of course\n"\ "this means you may get stuck in a\n"\ "very unfriendly world, but no one\n"\ "ever said being a Heretic was easy!" #define E2TEXT "the mighty maulotaurs have proved\n"\ "to be no match for you, and as\n"\ "their steaming corpses slide to the\n"\ "ground you feel a sense of grim\n"\ "satisfaction that they have been\n"\ "destroyed.\n\n"\ "the gateways which they guarded\n"\ "have opened, revealing what you\n"\ "hope is the way home. but as you\n"\ "step through, mocking laughter\n"\ "rings in your ears.\n\n"\ "was some other force controlling\n"\ "the maulotaurs? could there be even\n"\ "more horrific beings through this\n"\ "gate? the sweep of a crystal dome\n"\ "overhead where the sky should be is\n"\ "certainly not a good sign...." #define E3TEXT "the death of d'sparil has loosed\n"\ "the magical bonds holding his\n"\ "creatures on this plane, their\n"\ "dying screams overwhelming his own\n"\ "cries of agony.\n\n"\ "your oath of vengeance fulfilled,\n"\ "you enter the portal to your own\n"\ "world, mere moments before the dome\n"\ "shatters into a million pieces.\n\n"\ "but if d'sparil's power is broken\n"\ "forever, why don't you feel safe?\n"\ "was it that last shout just before\n"\ "his death, the one that sounded\n"\ "like a curse? or a summoning? you\n"\ "can't really be sure, but it might\n"\ "just have been a scream.\n\n"\ "then again, what about the other\n"\ "serpent riders?" #define E4TEXT "you thought you would return to your\n"\ "own world after d'sparil died, but\n"\ "his final act banished you to his\n"\ "own plane. here you entered the\n"\ "shattered remnants of lands\n"\ "conquered by d'sparil. you defeated\n"\ "the last guardians of these lands,\n"\ "but now you stand before the gates\n"\ "to d'sparil's stronghold. until this\n"\ "moment you had no doubts about your\n"\ "ability to face anything you might\n"\ "encounter, but beyond this portal\n"\ "lies the very heart of the evil\n"\ "which invaded your world. d'sparil\n"\ "might be dead, but the pit where he\n"\ "was spawned remains. now you must\n"\ "enter that pit in the hopes of\n"\ "finding a way out. and somewhere,\n"\ "in the darkest corner of d'sparil's\n"\ "demesne, his personal bodyguards\n"\ "await your arrival ..." #define E5TEXT "as the final maulotaur bellows his\n"\ "death-agony, you realize that you\n"\ "have never come so close to your own\n"\ "destruction. not even the fight with\n"\ "d'sparil and his disciples had been\n"\ "this desperate. grimly you stare at\n"\ "the gates which open before you,\n"\ "wondering if they lead home, or if\n"\ "they open onto some undreamed-of\n"\ "horror. you find yourself wondering\n"\ "if you have the strength to go on,\n"\ "if nothing but death and pain await\n"\ "you. but what else can you do, if\n"\ "the will to fight is gone? can you\n"\ "force yourself to continue in the\n"\ "face of such despair? do you have\n"\ "the courage? you find, in the end,\n"\ "that it is not within you to\n"\ "surrender without a fight. eyes\n"\ "wide, you go to meet your fate." chocolate-doom-chocolate-doom-2.2.1/src/heretic/f_finale.c000066400000000000000000000235311257432200600234320ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // F_finale.c #include #include "doomdef.h" #include "deh_str.h" #include "i_swap.h" #include "i_video.h" #include "i_scale.h" #include "s_sound.h" #include "v_video.h" int finalestage; // 0 = text, 1 = art screen int finalecount; #define TEXTSPEED 3 #define TEXTWAIT 250 char *finaletext; char *finaleflat; int FontABaseLump; extern boolean automapactive; extern boolean viewactive; extern void D_StartTitle(void); /* ======================= = = F_StartFinale = ======================= */ void F_StartFinale(void) { gameaction = ga_nothing; gamestate = GS_FINALE; viewactive = false; automapactive = false; players[consoleplayer].messageTics = 1; players[consoleplayer].message = NULL; switch (gameepisode) { case 1: finaleflat = DEH_String("FLOOR25"); finaletext = DEH_String(E1TEXT); break; case 2: finaleflat = DEH_String("FLATHUH1"); finaletext = DEH_String(E2TEXT); break; case 3: finaleflat = DEH_String("FLTWAWA2"); finaletext = DEH_String(E3TEXT); break; case 4: finaleflat = DEH_String("FLOOR28"); finaletext = DEH_String(E4TEXT); break; case 5: finaleflat = DEH_String("FLOOR08"); finaletext = DEH_String(E5TEXT); break; } finalestage = 0; finalecount = 0; FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1; // S_ChangeMusic(mus_victor, true); S_StartSong(mus_cptd, true); } boolean F_Responder(event_t * event) { if (event->type != ev_keydown) { return false; } if (finalestage == 1 && gameepisode == 2) { // we're showing the water pic, make any key kick to demo mode finalestage++; /* memset((byte *) 0xa0000, 0, SCREENWIDTH * SCREENHEIGHT); memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT); I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); */ return true; } return false; } /* ======================= = = F_Ticker = ======================= */ void F_Ticker(void) { finalecount++; if (!finalestage && finalecount > strlen(finaletext) * TEXTSPEED + TEXTWAIT) { finalecount = 0; if (!finalestage) { finalestage = 1; } // wipegamestate = -1; // force a wipe /* if (gameepisode == 3) S_StartMusic (mus_bunny); */ } } /* ======================= = = F_TextWrite = ======================= */ //#include "hu_stuff.h" //extern patch_t *hu_font[HU_FONTSIZE]; void F_TextWrite(void) { byte *src, *dest; int x, y; int count; char *ch; int c; int cx, cy; patch_t *w; // // erase the entire screen to a tiled background // src = W_CacheLumpName(finaleflat, PU_CACHE); dest = I_VideoBuffer; for (y = 0; y < SCREENHEIGHT; y++) { for (x = 0; x < SCREENWIDTH / 64; x++) { memcpy(dest, src + ((y & 63) << 6), 64); dest += 64; } if (SCREENWIDTH & 63) { memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63); dest += (SCREENWIDTH & 63); } } // V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT); // // draw some of the text onto the screen // cx = 20; cy = 5; ch = finaletext; count = (finalecount - 10) / TEXTSPEED; if (count < 0) count = 0; for (; count; count--) { c = *ch++; if (!c) break; if (c == '\n') { cx = 20; cy += 9; continue; } c = toupper(c); if (c < 33) { cx += 5; continue; } w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); if (cx + SHORT(w->width) > SCREENWIDTH) break; V_DrawPatch(cx, cy, w); cx += SHORT(w->width); } } void F_DrawPatchCol(int x, patch_t * patch, int col) { column_t *column; byte *source, *dest, *desttop; int count; column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); desttop = I_VideoBuffer + x; // step through the posts in a column while (column->topdelta != 0xff) { source = (byte *) column + 3; dest = desttop + column->topdelta * SCREENWIDTH; count = column->length; while (count--) { *dest = *source++; dest += SCREENWIDTH; } column = (column_t *) ((byte *) column + column->length + 4); } } /* ================== = = F_DemonScroll = ================== */ void F_DemonScroll(void) { byte *p1, *p2; static int yval = 0; static int nextscroll = 0; if (finalecount < nextscroll) { return; } p1 = W_CacheLumpName(DEH_String("FINAL1"), PU_LEVEL); p2 = W_CacheLumpName(DEH_String("FINAL2"), PU_LEVEL); if (finalecount < 70) { memcpy(I_VideoBuffer, p1, SCREENHEIGHT * SCREENWIDTH); nextscroll = finalecount; return; } if (yval < 64000) { memcpy(I_VideoBuffer, p2 + SCREENHEIGHT * SCREENWIDTH - yval, yval); memcpy(I_VideoBuffer + yval, p1, SCREENHEIGHT * SCREENWIDTH - yval); yval += SCREENWIDTH; nextscroll = finalecount + 3; } else { //else, we'll just sit here and wait, for now memcpy(I_VideoBuffer, p2, SCREENWIDTH * SCREENHEIGHT); } } /* ================== = = F_DrawUnderwater = ================== */ void F_DrawUnderwater(void) { static boolean underwawa = false; extern boolean askforquit; char *lumpname; byte *palette; // The underwater screen has its own palette, which is rather annoying. // The palette doesn't correspond to the normal palette. Because of // this, we must regenerate the lookup tables used in the video scaling // code. switch (finalestage) { case 1: if (!underwawa) { underwawa = true; V_DrawFilledBox(0, 0, SCREENWIDTH, SCREENHEIGHT, 0); lumpname = DEH_String("E2PAL"); palette = W_CacheLumpName(lumpname, PU_STATIC); I_SetPalette(palette); I_ResetScaleTables(palette); W_ReleaseLumpName(lumpname); V_DrawRawScreen(W_CacheLumpName(DEH_String("E2END"), PU_CACHE)); } paused = false; MenuActive = false; askforquit = false; break; case 2: if (underwawa) { lumpname = DEH_String("PLAYPAL"); palette = W_CacheLumpName(lumpname, PU_STATIC); I_SetPalette(palette); I_ResetScaleTables(palette); W_ReleaseLumpName(lumpname); underwawa = false; } V_DrawRawScreen(W_CacheLumpName(DEH_String("TITLE"), PU_CACHE)); //D_StartTitle(); // go to intro/demo mode. } } #if 0 /* ================== = = F_BunnyScroll = ================== */ void F_BunnyScroll(void) { int scrolled, x; patch_t *p1, *p2; char name[10]; int stage; static int laststage; p1 = W_CacheLumpName("PFUB2", PU_LEVEL); p2 = W_CacheLumpName("PFUB1", PU_LEVEL); V_MarkRect(0, 0, SCREENWIDTH, SCREENHEIGHT); scrolled = 320 - (finalecount - 230) / 2; if (scrolled > 320) scrolled = 320; if (scrolled < 0) scrolled = 0; for (x = 0; x < SCREENWIDTH; x++) { if (x + scrolled < 320) F_DrawPatchCol(x, p1, x + scrolled); else F_DrawPatchCol(x, p2, x + scrolled - 320); } if (finalecount < 1130) return; if (finalecount < 1180) { V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, (SCREENHEIGHT - 8 * 8) / 2, 0, W_CacheLumpName("END0", PU_CACHE)); laststage = 0; return; } stage = (finalecount - 1180) / 5; if (stage > 6) stage = 6; if (stage > laststage) { S_StartSound(NULL, sfx_pistol); laststage = stage; } M_snprintf(name, sizeof(name), "END%i", stage); V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, (SCREENHEIGHT - 8 * 8) / 2, W_CacheLumpName(name, PU_CACHE)); } #endif /* ======================= = = F_Drawer = ======================= */ void F_Drawer(void) { UpdateState |= I_FULLSCRN; if (!finalestage) F_TextWrite(); else { switch (gameepisode) { case 1: if (gamemode == shareware) { V_DrawRawScreen(W_CacheLumpName("ORDER", PU_CACHE)); } else { V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE)); } break; case 2: F_DrawUnderwater(); break; case 3: F_DemonScroll(); break; case 4: // Just show credits screen for extended episodes case 5: V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE)); break; } } } chocolate-doom-chocolate-doom-2.2.1/src/heretic/g_game.c000066400000000000000000001245561257432200600231170ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // G_game.c #include #include #include #include "doomdef.h" #include "doomkeys.h" #include "deh_str.h" #include "i_timer.h" #include "i_system.h" #include "m_controls.h" #include "m_misc.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" // Macros #define AM_STARTKEY 9 // Functions boolean G_CheckDemoStatus(void); void G_ReadDemoTiccmd(ticcmd_t * cmd); void G_WriteDemoTiccmd(ticcmd_t * cmd); void G_PlayerReborn(int player); void G_DoReborn(int playernum); void G_DoLoadLevel(void); void G_DoNewGame(void); void G_DoPlayDemo(void); void G_DoCompleted(void); void G_DoVictory(void); void G_DoWorldDone(void); void G_DoSaveGame(void); void D_PageTicker(void); void D_AdvanceDemo(void); struct { int type; // mobjtype_t int speed[2]; } MonsterMissileInfo[] = { { MT_IMPBALL, { 10, 20 } }, { MT_MUMMYFX1, { 9, 18 } }, { MT_KNIGHTAXE, { 9, 18 } }, { MT_REDAXE, { 9, 18 } }, { MT_BEASTBALL, { 12, 20 } }, { MT_WIZFX1, { 18, 24 } }, { MT_SNAKEPRO_A, { 14, 20 } }, { MT_SNAKEPRO_B, { 14, 20 } }, { MT_HEADFX1, { 13, 20 } }, { MT_HEADFX3, { 10, 18 } }, { MT_MNTRFX1, { 20, 26 } }, { MT_MNTRFX2, { 14, 20 } }, { MT_SRCRFX1, { 20, 28 } }, { MT_SOR2FX1, { 20, 28 } }, { -1, { -1, -1 } } // Terminator }; gameaction_t gameaction; gamestate_t gamestate; skill_t gameskill; boolean respawnmonsters; int gameepisode; int gamemap; int prevmap; boolean paused; boolean sendpause; // send a pause event next tic boolean sendsave; // send a save event next tic boolean usergame; // ok to save / end game boolean timingdemo; // if true, exit with report on completion int starttime; // for comparative timing purposes boolean viewactive; boolean deathmatch; // only if started as net death boolean netgame; // only true if packets are broadcast boolean playeringame[MAXPLAYERS]; player_t players[MAXPLAYERS]; int consoleplayer; // player taking events and displaying int displayplayer; // view being displayed int levelstarttic; // gametic at level start int totalkills, totalitems, totalsecret; // for intermission int mouseSensitivity; char demoname[32]; boolean demorecording; boolean demoplayback; byte *demobuffer, *demo_p; boolean singledemo; // quit after playing a demo from cmdline boolean precache = true; // if true, load all graphics at start // TODO: Heretic uses 16-bit shorts for consistency? byte consistancy[MAXPLAYERS][BACKUPTICS]; char *savegamedir; boolean testcontrols = false; int testcontrols_mousespeed; // // controls (have defaults) // #define MAXPLMOVE 0x32 fixed_t forwardmove[2] = { 0x19, 0x32 }; fixed_t sidemove[2] = { 0x18, 0x28 }; fixed_t angleturn[3] = { 640, 1280, 320 }; // + slow turn static int *weapon_keys[] = { &key_weapon1, &key_weapon2, &key_weapon3, &key_weapon4, &key_weapon5, &key_weapon6, &key_weapon7 }; // Set to -1 or +1 to switch to the previous or next weapon. static int next_weapon = 0; // Used for prev/next weapon keys. static const struct { weapontype_t weapon; weapontype_t weapon_num; } weapon_order_table[] = { { wp_staff, wp_staff }, { wp_gauntlets, wp_staff }, { wp_goldwand, wp_goldwand }, { wp_crossbow, wp_crossbow }, { wp_blaster, wp_blaster }, { wp_skullrod, wp_skullrod }, { wp_phoenixrod, wp_phoenixrod }, { wp_mace, wp_mace }, { wp_beak, wp_beak }, }; #define SLOWTURNTICS 6 #define NUMKEYS 256 boolean gamekeydown[NUMKEYS]; int turnheld; // for accelerative turning int lookheld; boolean mousearray[MAX_MOUSE_BUTTONS + 1]; boolean *mousebuttons = &mousearray[1]; // allow [-1] int mousex, mousey; // mouse values are used once int dclicktime, dclickstate, dclicks; int dclicktime2, dclickstate2, dclicks2; #define MAX_JOY_BUTTONS 20 int joyxmove, joyymove; // joystick values are repeated int joystrafemove; boolean joyarray[MAX_JOY_BUTTONS + 1]; boolean *joybuttons = &joyarray[1]; // allow [-1] int savegameslot; char savedescription[32]; int inventoryTics; // haleyjd: removed WATCOMC //============================================================================= // Not used - ripped out for Heretic /* int G_CmdChecksum(ticcmd_t *cmd) { int i; int sum; sum = 0; for(i = 0; i < sizeof(*cmd)/4-1; i++) { sum += ((int *)cmd)[i]; } return(sum); } */ static boolean WeaponSelectable(weapontype_t weapon) { if (weapon == wp_beak) { return false; } return players[consoleplayer].weaponowned[weapon]; } static int G_NextWeapon(int direction) { weapontype_t weapon; int start_i, i; // Find index in the table. if (players[consoleplayer].pendingweapon == wp_nochange) { weapon = players[consoleplayer].readyweapon; } else { weapon = players[consoleplayer].pendingweapon; } for (i=0; iconsistancy = // consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS]; cmd->consistancy = consistancy[consoleplayer][maketic % BACKUPTICS]; //printf ("cons: %i\n",cmd->consistancy); strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; speed = joybspeed >= MAX_JOY_BUTTONS || gamekeydown[key_speed] || joybuttons[joybspeed]; // haleyjd: removed externdriver crap forward = side = look = arti = flyheight = 0; // // use two stage accelerative turning on the keyboard and joystick // if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left]) turnheld += ticdup; else turnheld = 0; if (turnheld < SLOWTURNTICS) tspeed = 2; // slow turn else tspeed = speed; if (gamekeydown[key_lookdown] || gamekeydown[key_lookup]) { lookheld += ticdup; } else { lookheld = 0; } if (lookheld < SLOWTURNTICS) { lspeed = 1; } else { lspeed = 2; } // // let movement keys cancel each other out // if (strafe) { if (gamekeydown[key_right]) side += sidemove[speed]; if (gamekeydown[key_left]) side -= sidemove[speed]; if (joyxmove > 0) side += sidemove[speed]; if (joyxmove < 0) side -= sidemove[speed]; } else { if (gamekeydown[key_right]) cmd->angleturn -= angleturn[tspeed]; if (gamekeydown[key_left]) cmd->angleturn += angleturn[tspeed]; if (joyxmove > 0) cmd->angleturn -= angleturn[tspeed]; if (joyxmove < 0) cmd->angleturn += angleturn[tspeed]; } if (gamekeydown[key_up]) forward += forwardmove[speed]; if (gamekeydown[key_down]) forward -= forwardmove[speed]; if (joyymove < 0) forward += forwardmove[speed]; if (joyymove > 0) forward -= forwardmove[speed]; if (gamekeydown[key_straferight] || mousebuttons[mousebstraferight] || joybuttons[joybstraferight] || joystrafemove > 0) side += sidemove[speed]; if (gamekeydown[key_strafeleft] || mousebuttons[mousebstrafeleft] || joybuttons[joybstrafeleft] || joystrafemove < 0) side -= sidemove[speed]; // Look up/down/center keys if (gamekeydown[key_lookup]) { look = lspeed; } if (gamekeydown[key_lookdown]) { look = -lspeed; } // haleyjd: removed externdriver crap if (gamekeydown[key_lookcenter]) { look = TOCENTER; } // haleyjd: removed externdriver crap // Fly up/down/drop keys if (gamekeydown[key_flyup]) { flyheight = 5; // note that the actual flyheight will be twice this } if (gamekeydown[key_flydown]) { flyheight = -5; } if (gamekeydown[key_flycenter]) { flyheight = TOCENTER; // haleyjd: removed externdriver crap look = TOCENTER; } // Use artifact key if (gamekeydown[key_useartifact]) { if (gamekeydown[key_speed] && !noartiskip) { if (players[consoleplayer].inventory[inv_ptr].type != arti_none) { gamekeydown[key_useartifact] = false; cmd->arti = 0xff; // skip artifact code } } else { if (inventory) { players[consoleplayer].readyArtifact = players[consoleplayer].inventory[inv_ptr].type; inventory = false; cmd->arti = 0; usearti = false; } else if (usearti) { cmd->arti = players[consoleplayer].inventory[inv_ptr].type; usearti = false; } } } if (gamekeydown[127] && !cmd->arti && !players[consoleplayer].powers[pw_weaponlevel2]) { gamekeydown[127] = false; cmd->arti = arti_tomeofpower; } // // buttons // cmd->chatchar = CT_dequeueChatChar(); if (gamekeydown[key_fire] || mousebuttons[mousebfire] || joybuttons[joybfire]) cmd->buttons |= BT_ATTACK; if (gamekeydown[key_use] || joybuttons[joybuse] || mousebuttons[mousebuse]) { cmd->buttons |= BT_USE; dclicks = 0; // clear double clicks if hit use button } // If the previous or next weapon button is pressed, the // next_weapon variable is set to change weapons when // we generate a ticcmd. Choose a new weapon. // (Can't weapon cycle when the player is a chicken) if (gamestate == GS_LEVEL && players[consoleplayer].chickenTics == 0 && next_weapon != 0) { i = G_NextWeapon(next_weapon); cmd->buttons |= BT_CHANGE; cmd->buttons |= i << BT_WEAPONSHIFT; } else { for (i=0; ibuttons |= BT_CHANGE; cmd->buttons |= i< 1) { dclickstate = mousebuttons[mousebforward]; if (dclickstate) dclicks++; if (dclicks == 2) { cmd->buttons |= BT_USE; dclicks = 0; } else dclicktime = 0; } else { dclicktime += ticdup; if (dclicktime > 20) { dclicks = 0; dclickstate = 0; } } // // strafe double click // bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; if (bstrafe != dclickstate2 && dclicktime2 > 1) { dclickstate2 = bstrafe; if (dclickstate2) dclicks2++; if (dclicks2 == 2) { cmd->buttons |= BT_USE; dclicks2 = 0; } else dclicktime2 = 0; } else { dclicktime2 += ticdup; if (dclicktime2 > 20) { dclicks2 = 0; dclickstate2 = 0; } } } if (strafe) { side += mousex * 2; } else { cmd->angleturn -= mousex * 0x8; } // No mouse movement in previous frame? if (mousex == 0) { testcontrols_mousespeed = 0; } forward += mousey; mousex = mousey = 0; if (forward > MAXPLMOVE) forward = MAXPLMOVE; else if (forward < -MAXPLMOVE) forward = -MAXPLMOVE; if (side > MAXPLMOVE) side = MAXPLMOVE; else if (side < -MAXPLMOVE) side = -MAXPLMOVE; cmd->forwardmove += forward; cmd->sidemove += side; if (players[consoleplayer].playerstate == PST_LIVE) { if (look < 0) { look += 16; } cmd->lookfly = look; } if (flyheight < 0) { flyheight += 16; } cmd->lookfly |= flyheight << 4; // // special buttons // if (sendpause) { sendpause = false; cmd->buttons = BT_SPECIAL | BTS_PAUSE; } if (sendsave) { sendsave = false; cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot << BTS_SAVESHIFT); } } /* ============== = = G_DoLoadLevel = ============== */ void G_DoLoadLevel(void) { int i; levelstarttic = gametic; // for time calculation gamestate = GS_LEVEL; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && players[i].playerstate == PST_DEAD) players[i].playerstate = PST_REBORN; memset(players[i].frags, 0, sizeof(players[i].frags)); } P_SetupLevel(gameepisode, gamemap, 0, gameskill); displayplayer = consoleplayer; // view the guy you are playing starttime = I_GetTime(); gameaction = ga_nothing; Z_CheckHeap(); // // clear cmd building stuff // memset(gamekeydown, 0, sizeof(gamekeydown)); joyxmove = joyymove = joystrafemove = 0; mousex = mousey = 0; sendpause = sendsave = paused = false; memset(mousearray, 0, sizeof(mousearray)); memset(joyarray, 0, sizeof(joyarray)); if (testcontrols) { P_SetMessage(&players[consoleplayer], "PRESS ESCAPE TO QUIT.", false); } } static void SetJoyButtons(unsigned int buttons_mask) { int i; for (i=0; itype == ev_keyup && ev->data1 == key_useartifact) { // flag to denote that it's okay to use an artifact if (!inventory) { plr->readyArtifact = plr->inventory[inv_ptr].type; } usearti = true; } // Check for spy mode player cycle if (gamestate == GS_LEVEL && ev->type == ev_keydown && ev->data1 == KEY_F12 && !deathmatch) { // Cycle the display player do { displayplayer++; if (displayplayer == MAXPLAYERS) { displayplayer = 0; } } while (!playeringame[displayplayer] && displayplayer != consoleplayer); return (true); } if (gamestate == GS_LEVEL) { if (CT_Responder(ev)) { // Chat ate the event return (true); } if (SB_Responder(ev)) { // Status bar ate the event return (true); } if (AM_Responder(ev)) { // Automap ate the event return (true); } } if (ev->type == ev_mouse) { testcontrols_mousespeed = abs(ev->data2); } if (ev->type == ev_keydown && ev->data1 == key_prevweapon) { next_weapon = -1; } else if (ev->type == ev_keydown && ev->data1 == key_nextweapon) { next_weapon = 1; } switch (ev->type) { case ev_keydown: if (ev->data1 == key_invleft) { inventoryTics = 5 * 35; if (!inventory) { inventory = true; break; } inv_ptr--; if (inv_ptr < 0) { inv_ptr = 0; } else { curpos--; if (curpos < 0) { curpos = 0; } } return (true); } if (ev->data1 == key_invright) { inventoryTics = 5 * 35; if (!inventory) { inventory = true; break; } inv_ptr++; if (inv_ptr >= plr->inventorySlotNum) { inv_ptr--; if (inv_ptr < 0) inv_ptr = 0; } else { curpos++; if (curpos > 6) { curpos = 6; } } return (true); } if (ev->data1 == key_pause && !MenuActive) { sendpause = true; return (true); } if (ev->data1 < NUMKEYS) { gamekeydown[ev->data1] = true; } return (true); // eat key down events case ev_keyup: if (ev->data1 < NUMKEYS) { gamekeydown[ev->data1] = false; } return (false); // always let key up events filter down case ev_mouse: SetMouseButtons(ev->data1); mousex = ev->data2 * (mouseSensitivity + 5) / 10; mousey = ev->data3 * (mouseSensitivity + 5) / 10; return (true); // eat events case ev_joystick: SetJoyButtons(ev->data1); joyxmove = ev->data2; joyymove = ev->data3; joystrafemove = ev->data4; return (true); // eat events default: break; } return (false); } /* =============================================================================== = = G_Ticker = =============================================================================== */ void G_Ticker(void) { int i, buf; ticcmd_t *cmd = NULL; // // do player reborns if needed // for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].playerstate == PST_REBORN) G_DoReborn(i); // // do things to change the game state // while (gameaction != ga_nothing) { switch (gameaction) { case ga_loadlevel: G_DoLoadLevel(); break; case ga_newgame: G_DoNewGame(); break; case ga_loadgame: G_DoLoadGame(); break; case ga_savegame: G_DoSaveGame(); break; case ga_playdemo: G_DoPlayDemo(); break; case ga_screenshot: V_ScreenShot("HTIC%02i.%s"); gameaction = ga_nothing; break; case ga_completed: G_DoCompleted(); break; case ga_worlddone: G_DoWorldDone(); break; case ga_victory: F_StartFinale(); break; default: break; } } // // get commands, check consistancy, and build new consistancy check // //buf = gametic%BACKUPTICS; buf = (gametic / ticdup) % BACKUPTICS; for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { cmd = &players[i].cmd; memcpy(cmd, &netcmds[i], sizeof(ticcmd_t)); if (demoplayback) G_ReadDemoTiccmd(cmd); if (demorecording) G_WriteDemoTiccmd(cmd); if (netgame && !(gametic % ticdup)) { if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy) { I_Error("consistency failure (%i should be %i)", cmd->consistancy, consistancy[i][buf]); } if (players[i].mo) consistancy[i][buf] = players[i].mo->x; else consistancy[i][buf] = rndindex; } } // // check for special buttons // for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { if (players[i].cmd.buttons & BT_SPECIAL) { switch (players[i].cmd.buttons & BT_SPECIALMASK) { case BTS_PAUSE: paused ^= 1; if (paused) { S_PauseSound(); } else { S_ResumeSound(); } break; case BTS_SAVEGAME: if (!savedescription[0]) { if (netgame) { M_StringCopy(savedescription, DEH_String("NET GAME"), sizeof(savedescription)); } else { M_StringCopy(savedescription, DEH_String("SAVE GAME"), sizeof(savedescription)); } } savegameslot = (players[i].cmd. buttons & BTS_SAVEMASK) >> BTS_SAVESHIFT; gameaction = ga_savegame; break; } } } // turn inventory off after a certain amount of time if (inventory && !(--inventoryTics)) { players[consoleplayer].readyArtifact = players[consoleplayer].inventory[inv_ptr].type; inventory = false; cmd->arti = 0; } // // do main actions // // // do main actions // switch (gamestate) { case GS_LEVEL: P_Ticker(); SB_Ticker(); AM_Ticker(); CT_Ticker(); break; case GS_INTERMISSION: IN_Ticker(); break; case GS_FINALE: F_Ticker(); break; case GS_DEMOSCREEN: D_PageTicker(); break; } } /* ============================================================================== PLAYER STRUCTURE FUNCTIONS also see P_SpawnPlayer in P_Things ============================================================================== */ /* ==================== = = G_InitPlayer = = Called at the start = Called by the game initialization functions ==================== */ void G_InitPlayer(int player) { // clear everything else to defaults G_PlayerReborn(player); } /* ==================== = = G_PlayerFinishLevel = = Can when a player completes a level ==================== */ extern int playerkeys; void G_PlayerFinishLevel(int player) { player_t *p; int i; /* // BIG HACK inv_ptr = 0; curpos = 0; */ // END HACK p = &players[player]; for (i = 0; i < p->inventorySlotNum; i++) { p->inventory[i].count = 1; } p->artifactCount = p->inventorySlotNum; if (!deathmatch) { for (i = 0; i < 16; i++) { P_PlayerUseArtifact(p, arti_fly); } } memset(p->powers, 0, sizeof(p->powers)); memset(p->keys, 0, sizeof(p->keys)); playerkeys = 0; // memset(p->inventory, 0, sizeof(p->inventory)); if (p->chickenTics) { p->readyweapon = p->mo->special1.i; // Restore weapon p->chickenTics = 0; } p->messageTics = 0; p->lookdir = 0; p->mo->flags &= ~MF_SHADOW; // Remove invisibility p->extralight = 0; // Remove weapon flashes p->fixedcolormap = 0; // Remove torch p->damagecount = 0; // No palette changes p->bonuscount = 0; p->rain1 = NULL; p->rain2 = NULL; if (p == &players[consoleplayer]) { SB_state = -1; // refresh the status bar } } /* ==================== = = G_PlayerReborn = = Called after a player dies = almost everything is cleared and initialized ==================== */ void G_PlayerReborn(int player) { player_t *p; int i; int frags[MAXPLAYERS]; int killcount, itemcount, secretcount; boolean secret; secret = false; memcpy(frags, players[player].frags, sizeof(frags)); killcount = players[player].killcount; itemcount = players[player].itemcount; secretcount = players[player].secretcount; p = &players[player]; if (p->didsecret) { secret = true; } memset(p, 0, sizeof(*p)); memcpy(players[player].frags, frags, sizeof(players[player].frags)); players[player].killcount = killcount; players[player].itemcount = itemcount; players[player].secretcount = secretcount; p->usedown = p->attackdown = true; // don't do anything immediately p->playerstate = PST_LIVE; p->health = MAXHEALTH; p->readyweapon = p->pendingweapon = wp_goldwand; p->weaponowned[wp_staff] = true; p->weaponowned[wp_goldwand] = true; p->messageTics = 0; p->lookdir = 0; p->ammo[am_goldwand] = 50; for (i = 0; i < NUMAMMO; i++) { p->maxammo[i] = maxammo[i]; } if (gamemap == 9 || secret) { p->didsecret = true; } if (p == &players[consoleplayer]) { SB_state = -1; // refresh the status bar inv_ptr = 0; // reset the inventory pointer curpos = 0; } } /* ==================== = = G_CheckSpot = = Returns false if the player cannot be respawned at the given mapthing_t spot = because something is occupying it ==================== */ void P_SpawnPlayer(mapthing_t * mthing); boolean G_CheckSpot(int playernum, mapthing_t * mthing) { fixed_t x, y; subsector_t *ss; unsigned an; mobj_t *mo; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; players[playernum].mo->flags2 &= ~MF2_PASSMOBJ; if (!P_CheckPosition(players[playernum].mo, x, y)) { players[playernum].mo->flags2 |= MF2_PASSMOBJ; return false; } players[playernum].mo->flags2 |= MF2_PASSMOBJ; // spawn a teleport fog ss = R_PointInSubsector(x, y); an = ((unsigned) ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT; mo = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an], ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG); if (players[consoleplayer].viewz != 1) S_StartSound(mo, sfx_telept); // don't start sound on first frame return true; } /* ==================== = = G_DeathMatchSpawnPlayer = = Spawns a player at one of the random death match spots = called at level load and each death ==================== */ void G_DeathMatchSpawnPlayer(int playernum) { int i, j; int selections; selections = deathmatch_p - deathmatchstarts; if (selections < 4) I_Error("Only %i deathmatch spots, 4 required", selections); for (j = 0; j < 20; j++) { i = P_Random() % selections; if (G_CheckSpot(playernum, &deathmatchstarts[i])) { deathmatchstarts[i].type = playernum + 1; P_SpawnPlayer(&deathmatchstarts[i]); return; } } // no good spot, so the player will probably get stuck P_SpawnPlayer(&playerstarts[playernum]); } /* ==================== = = G_DoReborn = ==================== */ void G_DoReborn(int playernum) { int i; if (G_CheckDemoStatus()) return; if (!netgame) gameaction = ga_loadlevel; // reload the level from scratch else { // respawn at the start players[playernum].mo->player = NULL; // dissasociate the corpse // spawn at random spot if in death match if (deathmatch) { G_DeathMatchSpawnPlayer(playernum); return; } if (G_CheckSpot(playernum, &playerstarts[playernum])) { P_SpawnPlayer(&playerstarts[playernum]); return; } // try to spawn at one of the other players spots for (i = 0; i < MAXPLAYERS; i++) if (G_CheckSpot(playernum, &playerstarts[i])) { playerstarts[i].type = playernum + 1; // fake as other player P_SpawnPlayer(&playerstarts[i]); playerstarts[i].type = i + 1; // restore return; } // he's going to be inside something. Too bad. P_SpawnPlayer(&playerstarts[playernum]); } } void G_ScreenShot(void) { gameaction = ga_screenshot; } /* ==================== = = G_DoCompleted = ==================== */ boolean secretexit; void G_ExitLevel(void) { secretexit = false; gameaction = ga_completed; } void G_SecretExitLevel(void) { secretexit = true; gameaction = ga_completed; } void G_DoCompleted(void) { int i; static int afterSecret[5] = { 7, 5, 5, 5, 4 }; gameaction = ga_nothing; if (G_CheckDemoStatus()) { return; } for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { G_PlayerFinishLevel(i); } } prevmap = gamemap; if (secretexit == true) { gamemap = 9; } else if (gamemap == 9) { // Finished secret level gamemap = afterSecret[gameepisode - 1]; } else if (gamemap == 8) { gameaction = ga_victory; return; } else { gamemap++; } gamestate = GS_INTERMISSION; IN_Start(); } //============================================================================ // // G_WorldDone // //============================================================================ void G_WorldDone(void) { gameaction = ga_worlddone; } //============================================================================ // // G_DoWorldDone // //============================================================================ void G_DoWorldDone(void) { gamestate = GS_LEVEL; G_DoLoadLevel(); gameaction = ga_nothing; viewactive = true; } //--------------------------------------------------------------------------- // // PROC G_LoadGame // // Can be called by the startup code or the menu task. // //--------------------------------------------------------------------------- static char *savename = NULL; void G_LoadGame(char *name) { savename = M_StringDuplicate(name); gameaction = ga_loadgame; } //--------------------------------------------------------------------------- // // PROC G_DoLoadGame // // Called by G_Ticker based on gameaction. // //--------------------------------------------------------------------------- #define VERSIONSIZE 16 void G_DoLoadGame(void) { int i; int a, b, c; char savestr[SAVESTRINGSIZE]; char vcheck[VERSIONSIZE], readversion[VERSIONSIZE]; gameaction = ga_nothing; SV_OpenRead(savename); free(savename); savename = NULL; // Skip the description field SV_Read(savestr, SAVESTRINGSIZE); memset(vcheck, 0, sizeof(vcheck)); DEH_snprintf(vcheck, VERSIONSIZE, "version %i", HERETIC_VERSION); SV_Read(readversion, VERSIONSIZE); if (strncmp(readversion, vcheck, VERSIONSIZE) != 0) { // Bad version return; } gameskill = SV_ReadByte(); gameepisode = SV_ReadByte(); gamemap = SV_ReadByte(); for (i = 0; i < MAXPLAYERS; i++) { playeringame[i] = SV_ReadByte(); } // Load a base level G_InitNew(gameskill, gameepisode, gamemap); // Create leveltime a = SV_ReadByte(); b = SV_ReadByte(); c = SV_ReadByte(); leveltime = (a << 16) + (b << 8) + c; // De-archive all the modifications P_UnArchivePlayers(); P_UnArchiveWorld(); P_UnArchiveThinkers(); P_UnArchiveSpecials(); if (SV_ReadByte() != SAVE_GAME_TERMINATOR) { // Missing savegame termination marker I_Error("Bad savegame"); } } /* ==================== = = G_InitNew = = Can be called by the startup code or the menu task = consoleplayer, displayplayer, playeringame[] should be set ==================== */ skill_t d_skill; int d_episode; int d_map; void G_DeferedInitNew(skill_t skill, int episode, int map) { d_skill = skill; d_episode = episode; d_map = map; gameaction = ga_newgame; } void G_DoNewGame(void) { G_InitNew(d_skill, d_episode, d_map); gameaction = ga_nothing; } void G_InitNew(skill_t skill, int episode, int map) { int i; int speed; static char *skyLumpNames[5] = { "SKY1", "SKY2", "SKY3", "SKY1", "SKY3" }; if (paused) { paused = false; S_ResumeSound(); } if (skill < sk_baby) skill = sk_baby; if (skill > sk_nightmare) skill = sk_nightmare; if (episode < 1) episode = 1; // Up to 9 episodes for testing if (episode > 9) episode = 9; if (map < 1) map = 1; if (map > 9) map = 9; M_ClearRandom(); if (respawnparm) { respawnmonsters = true; } else { respawnmonsters = false; } // Set monster missile speeds speed = skill == sk_nightmare; for (i = 0; MonsterMissileInfo[i].type != -1; i++) { mobjinfo[MonsterMissileInfo[i].type].speed = MonsterMissileInfo[i].speed[speed] << FRACBITS; } // Force players to be initialized upon first level load for (i = 0; i < MAXPLAYERS; i++) { players[i].playerstate = PST_REBORN; players[i].didsecret = false; } // Set up a bunch of globals usergame = true; // will be set false if a demo paused = false; demorecording = false; demoplayback = false; viewactive = true; gameepisode = episode; gamemap = map; gameskill = skill; viewactive = true; BorderNeedRefresh = true; // Set the sky map if (episode > 5) { skytexture = R_TextureNumForName(DEH_String("SKY1")); } else { skytexture = R_TextureNumForName(DEH_String(skyLumpNames[episode - 1])); } // // give one null ticcmd_t // #if 0 gametic = 0; maketic = 1; for (i = 0; i < MAXPLAYERS; i++) nettics[i] = 1; // one null event for this gametic memset(localcmds, 0, sizeof(localcmds)); memset(netcmds, 0, sizeof(netcmds)); #endif G_DoLoadLevel(); } /* =============================================================================== DEMO RECORDING =============================================================================== */ #define DEMOMARKER 0x80 void G_ReadDemoTiccmd(ticcmd_t * cmd) { if (*demo_p == DEMOMARKER) { // end of demo data stream G_CheckDemoStatus(); return; } cmd->forwardmove = ((signed char) *demo_p++); cmd->sidemove = ((signed char) *demo_p++); cmd->angleturn = ((unsigned char) *demo_p++) << 8; cmd->buttons = (unsigned char) *demo_p++; cmd->lookfly = (unsigned char) *demo_p++; cmd->arti = (unsigned char) *demo_p++; } void G_WriteDemoTiccmd(ticcmd_t * cmd) { if (gamekeydown['q']) // press q to end demo recording G_CheckDemoStatus(); *demo_p++ = cmd->forwardmove; *demo_p++ = cmd->sidemove; *demo_p++ = cmd->angleturn >> 8; *demo_p++ = cmd->buttons; *demo_p++ = cmd->lookfly; *demo_p++ = cmd->arti; demo_p -= 6; G_ReadDemoTiccmd(cmd); // make SURE it is exactly the same } /* =================== = = G_RecordDemo = =================== */ void G_RecordDemo(skill_t skill, int numplayers, int episode, int map, char *name) { int i; G_InitNew(skill, episode, map); usergame = false; M_StringCopy(demoname, name, sizeof(demoname)); M_StringConcat(demoname, ".lmp", sizeof(demoname)); demobuffer = demo_p = Z_Malloc(0x20000, PU_STATIC, NULL); *demo_p++ = skill; *demo_p++ = episode; *demo_p++ = map; for (i = 0; i < MAXPLAYERS; i++) *demo_p++ = playeringame[i]; demorecording = true; } /* =================== = = G_PlayDemo = =================== */ char *defdemoname; void G_DeferedPlayDemo(char *name) { defdemoname = name; gameaction = ga_playdemo; } void G_DoPlayDemo(void) { skill_t skill; int i, episode, map; gameaction = ga_nothing; demobuffer = demo_p = W_CacheLumpName(defdemoname, PU_STATIC); skill = *demo_p++; episode = *demo_p++; map = *demo_p++; for (i = 0; i < MAXPLAYERS; i++) playeringame[i] = *demo_p++; precache = false; // don't spend a lot of time in loadlevel G_InitNew(skill, episode, map); precache = true; usergame = false; demoplayback = true; } /* =================== = = G_TimeDemo = =================== */ void G_TimeDemo(char *name) { skill_t skill; int episode, map, i; demobuffer = demo_p = W_CacheLumpName(name, PU_STATIC); skill = *demo_p++; episode = *demo_p++; map = *demo_p++; for (i = 0; i < MAXPLAYERS; i++) { playeringame[i] = *demo_p++; } G_InitNew(skill, episode, map); usergame = false; demoplayback = true; timingdemo = true; singletics = true; } /* =================== = = G_CheckDemoStatus = = Called after a death or level completion to allow demos to be cleaned up = Returns true if a new demo loop action will take place =================== */ boolean G_CheckDemoStatus(void) { int endtime, realtics; if (timingdemo) { float fps; endtime = I_GetTime(); realtics = endtime - starttime; fps = ((float) gametic * TICRATE) / realtics; I_Error("timed %i gametics in %i realtics (%f fps)", gametic, realtics, fps); } if (demoplayback) { if (singledemo) I_Quit(); W_ReleaseLumpName(defdemoname); demoplayback = false; D_AdvanceDemo(); return true; } if (demorecording) { *demo_p++ = DEMOMARKER; M_WriteFile(demoname, demobuffer, demo_p - demobuffer); Z_Free(demobuffer); demorecording = false; I_Error("Demo %s recorded", demoname); } return false; } /**************************************************************************/ /**************************************************************************/ //========================================================================== // // G_SaveGame // // Called by the menu task. is a 24 byte text string. // //========================================================================== void G_SaveGame(int slot, char *description) { savegameslot = slot; M_StringCopy(savedescription, description, sizeof(savedescription)); sendsave = true; } //========================================================================== // // G_DoSaveGame // // Called by G_Ticker based on gameaction. // //========================================================================== void G_DoSaveGame(void) { int i; char *filename; char verString[VERSIONSIZE]; char *description; filename = SV_Filename(savegameslot); description = savedescription; SV_Open(filename); SV_Write(description, SAVESTRINGSIZE); memset(verString, 0, sizeof(verString)); DEH_snprintf(verString, VERSIONSIZE, "version %i", HERETIC_VERSION); SV_Write(verString, VERSIONSIZE); SV_WriteByte(gameskill); SV_WriteByte(gameepisode); SV_WriteByte(gamemap); for (i = 0; i < MAXPLAYERS; i++) { SV_WriteByte(playeringame[i]); } SV_WriteByte(leveltime >> 16); SV_WriteByte(leveltime >> 8); SV_WriteByte(leveltime); P_ArchivePlayers(); P_ArchiveWorld(); P_ArchiveThinkers(); P_ArchiveSpecials(); SV_Close(filename); gameaction = ga_nothing; savedescription[0] = 0; P_SetMessage(&players[consoleplayer], DEH_String(TXT_GAMESAVED), true); free(filename); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/in_lude.c000066400000000000000000000650721257432200600233140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // /* ======================== = = IN_lude.c = ======================== */ #include "doomdef.h" #include "deh_str.h" #include "p_local.h" #include "s_sound.h" #include "i_swap.h" #include "i_system.h" #include "i_video.h" #include "v_video.h" typedef enum { SINGLE, COOPERATIVE, DEATHMATCH } gametype_t; // Public functions boolean intermission; // Private functions void IN_WaitStop(void); void IN_Stop(void); void IN_LoadPics(void); void IN_UnloadPics(void); void IN_CheckForSkip(void); void IN_InitStats(void); void IN_InitDeathmatchStats(void); void IN_InitNetgameStats(void); void IN_DrawOldLevel(void); void IN_DrawYAH(void); void IN_DrawStatBack(void); void IN_DrawSingleStats(void); void IN_DrawCoopStats(void); void IN_DrawDMStats(void); void IN_DrawNumber(int val, int x, int y, int digits); void IN_DrawTime(int x, int y, int h, int m, int s); void IN_DrTextB(char *text, int x, int y); static boolean skipintermission; static int interstate = 0; static int intertime = -1; static int oldintertime = 0; static gametype_t gametype; static int cnt; static int hours; static int minutes; static int seconds; static int slaughterboy; // in DM, the player with the most kills static int killPercent[MAXPLAYERS]; static int bonusPercent[MAXPLAYERS]; static int secretPercent[MAXPLAYERS]; static patch_t *patchINTERPIC; static patch_t *patchBEENTHERE; static patch_t *patchGOINGTHERE; static patch_t *FontBNumbers[10]; static patch_t *FontBNegative; static patch_t *FontBSlash; static patch_t *FontBPercent; static int FontBLump; static int FontBLumpBase; static int patchFaceOkayBase; static int patchFaceDeadBase; static signed int totalFrags[MAXPLAYERS]; static fixed_t dSlideX[MAXPLAYERS]; static fixed_t dSlideY[MAXPLAYERS]; static char *KillersText[] = { "K", "I", "L", "L", "E", "R", "S" }; extern char *LevelNames[]; typedef struct { int x; int y; } yahpt_t; static yahpt_t YAHspot[3][9] = { { {172, 78}, {86, 90}, {73, 66}, {159, 95}, {148, 126}, {132, 54}, {131, 74}, {208, 138}, {52, 101} }, { {218, 57}, {137, 81}, {155, 124}, {171, 68}, {250, 86}, {136, 98}, {203, 90}, {220, 140}, {279, 106} }, { {86, 99}, {124, 103}, {154, 79}, {202, 83}, {178, 59}, {142, 58}, {219, 66}, {247, 57}, {107, 80} } }; //======================================================================== // // IN_Start // //======================================================================== extern void AM_Stop(void); void IN_Start(void) { I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE)); IN_LoadPics(); IN_InitStats(); intermission = true; interstate = -1; skipintermission = false; intertime = 0; oldintertime = 0; AM_Stop(); S_StartSong(mus_intr, true); } //======================================================================== // // IN_WaitStop // //======================================================================== void IN_WaitStop(void) { if (!--cnt) { IN_Stop(); G_WorldDone(); } } //======================================================================== // // IN_Stop // //======================================================================== void IN_Stop(void) { intermission = false; IN_UnloadPics(); SB_state = -1; BorderNeedRefresh = true; } //======================================================================== // // IN_InitStats // // Initializes the stats for single player mode //======================================================================== void IN_InitStats(void) { int i; int j; signed int slaughterfrags; int posnum; int slaughtercount; int playercount; int count; if (!netgame) { gametype = SINGLE; count = leveltime / 35; hours = count / 3600; count -= hours * 3600; minutes = count / 60; count -= minutes * 60; seconds = count; } else if (netgame && !deathmatch) { gametype = COOPERATIVE; memset(killPercent, 0, MAXPLAYERS * sizeof(int)); memset(bonusPercent, 0, MAXPLAYERS * sizeof(int)); memset(secretPercent, 0, MAXPLAYERS * sizeof(int)); for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { if (totalkills) { killPercent[i] = players[i].killcount * 100 / totalkills; } if (totalitems) { bonusPercent[i] = players[i].itemcount * 100 / totalitems; } if (totalsecret) { secretPercent[i] = players[i].secretcount * 100 / totalsecret; } } } } else { gametype = DEATHMATCH; slaughterboy = 0; slaughterfrags = -9999; posnum = 0; playercount = 0; slaughtercount = 0; for (i = 0; i < MAXPLAYERS; i++) { totalFrags[i] = 0; if (playeringame[i]) { playercount++; for (j = 0; j < MAXPLAYERS; j++) { if (playeringame[j]) { totalFrags[i] += players[i].frags[j]; } } dSlideX[i] = (43 * posnum * FRACUNIT) / 20; dSlideY[i] = (36 * posnum * FRACUNIT) / 20; posnum++; } if (totalFrags[i] > slaughterfrags) { slaughterboy = 1 << i; slaughterfrags = totalFrags[i]; slaughtercount = 1; } else if (totalFrags[i] == slaughterfrags) { slaughterboy |= 1 << i; slaughtercount++; } } if (playercount == slaughtercount) { // don't do the slaughter stuff if everyone is equal slaughterboy = 0; } } } static void IN_LoadUnloadPics(void (*callback)(char *lumpname, int lumpnum, patch_t **ptr)) { int i; switch (gameepisode) { case 1: callback(DEH_String("MAPE1"), 0, &patchINTERPIC); break; case 2: callback(DEH_String("MAPE2"), 0, &patchINTERPIC); break; case 3: callback(DEH_String("MAPE3"), 0, &patchINTERPIC); break; default: break; } callback(DEH_String("IN_X"), 0, &patchBEENTHERE); callback(DEH_String("IN_YAH"), 0, &patchGOINGTHERE); callback(DEH_String("FONTB13"), 0, &FontBNegative); callback(DEH_String("FONTB15"), 0, &FontBSlash); callback(DEH_String("FONTB05"), 0, &FontBPercent); FontBLumpBase = W_GetNumForName(DEH_String("FONTB16")); for (i = 0; i < 10; i++) { callback(NULL, FontBLumpBase + i, &FontBNumbers[i]); } } //======================================================================== // // IN_LoadPics // //======================================================================== static void LoadLumpCallback(char *lumpname, int lumpnum, patch_t **ptr) { if (lumpname != NULL) { lumpnum = W_GetNumForName(lumpname); } // Cache the lump *ptr = W_CacheLumpNum(lumpnum, PU_STATIC); } void IN_LoadPics(void) { FontBLump = W_GetNumForName(DEH_String("FONTB_S")) + 1; patchFaceOkayBase = W_GetNumForName(DEH_String("FACEA0")); patchFaceDeadBase = W_GetNumForName(DEH_String("FACEB0")); IN_LoadUnloadPics(LoadLumpCallback); } //======================================================================== // // IN_UnloadPics // //======================================================================== static void UnloadLumpCallback(char *lumpname, int lumpnum, patch_t **ptr) { if (lumpname != NULL) { W_ReleaseLumpName(lumpname); } else { W_ReleaseLumpNum(lumpnum); } } void IN_UnloadPics(void) { IN_LoadUnloadPics(UnloadLumpCallback); } //======================================================================== // // IN_Ticker // //======================================================================== void IN_Ticker(void) { if (!intermission) { return; } if (interstate == 3) { IN_WaitStop(); return; } IN_CheckForSkip(); intertime++; if (oldintertime < intertime) { interstate++; if (gameepisode > 3 && interstate >= 1) { // Extended Wad levels: skip directly to the next level interstate = 3; } switch (interstate) { case 0: oldintertime = intertime + 300; if (gameepisode > 3) { oldintertime = intertime + 1200; } break; case 1: oldintertime = intertime + 200; break; case 2: oldintertime = INT_MAX; break; case 3: cnt = 10; break; default: break; } } if (skipintermission) { if (interstate == 0 && intertime < 150) { intertime = 150; skipintermission = false; return; } else if (interstate < 2 && gameepisode < 4) { interstate = 2; skipintermission = false; S_StartSound(NULL, sfx_dorcls); return; } interstate = 3; cnt = 10; skipintermission = false; S_StartSound(NULL, sfx_dorcls); } } //======================================================================== // // IN_CheckForSkip // // Check to see if any player hit a key //======================================================================== void IN_CheckForSkip(void) { int i; player_t *player; for (i = 0, player = players; i < MAXPLAYERS; i++, player++) { if (playeringame[i]) { if (player->cmd.buttons & BT_ATTACK) { if (!player->attackdown) { skipintermission = 1; } player->attackdown = true; } else { player->attackdown = false; } if (player->cmd.buttons & BT_USE) { if (!player->usedown) { skipintermission = 1; } player->usedown = true; } else { player->usedown = false; } } } } //======================================================================== // // IN_Drawer // //======================================================================== void IN_Drawer(void) { static int oldinterstate; if (!intermission) { return; } if (interstate == 3) { return; } UpdateState |= I_FULLSCRN; if (oldinterstate != 2 && interstate == 2) { S_StartSound(NULL, sfx_pstop); } oldinterstate = interstate; switch (interstate) { case 0: // draw stats IN_DrawStatBack(); switch (gametype) { case SINGLE: IN_DrawSingleStats(); break; case COOPERATIVE: IN_DrawCoopStats(); break; case DEATHMATCH: IN_DrawDMStats(); break; } break; case 1: // leaving old level if (gameepisode < 4) { V_DrawPatch(0, 0, patchINTERPIC); IN_DrawOldLevel(); } break; case 2: // going to the next level if (gameepisode < 4) { V_DrawPatch(0, 0, patchINTERPIC); IN_DrawYAH(); } break; case 3: // waiting before going to the next level if (gameepisode < 4) { V_DrawPatch(0, 0, patchINTERPIC); } break; default: I_Error("IN_lude: Intermission state out of range.\n"); break; } } //======================================================================== // // IN_DrawStatBack // //======================================================================== void IN_DrawStatBack(void) { int x; int y; byte *src; byte *dest; src = W_CacheLumpName(DEH_String("FLOOR16"), PU_CACHE); dest = I_VideoBuffer; for (y = 0; y < SCREENHEIGHT; y++) { for (x = 0; x < SCREENWIDTH / 64; x++) { memcpy(dest, src + ((y & 63) << 6), 64); dest += 64; } if (SCREENWIDTH & 63) { memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63); dest += (SCREENWIDTH & 63); } } } //======================================================================== // // IN_DrawOldLevel // //======================================================================== void IN_DrawOldLevel(void) { int i; int x; x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3); x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2; MN_DrTextA(DEH_String("FINISHED"), x, 25); if (prevmap == 9) { for (i = 0; i < gamemap - 1; i++) { V_DrawPatch(YAHspot[gameepisode - 1][i].x, YAHspot[gameepisode - 1][i].y, patchBEENTHERE); } if (!(intertime & 16)) { V_DrawPatch(YAHspot[gameepisode - 1][8].x, YAHspot[gameepisode - 1][8].y, patchBEENTHERE); } } else { for (i = 0; i < prevmap - 1; i++) { V_DrawPatch(YAHspot[gameepisode - 1][i].x, YAHspot[gameepisode - 1][i].y, patchBEENTHERE); } if (players[consoleplayer].didsecret) { V_DrawPatch(YAHspot[gameepisode - 1][8].x, YAHspot[gameepisode - 1][8].y, patchBEENTHERE); } if (!(intertime & 16)) { V_DrawPatch(YAHspot[gameepisode - 1][prevmap - 1].x, YAHspot[gameepisode - 1][prevmap - 1].y, patchBEENTHERE); } } } //======================================================================== // // IN_DrawYAH // //======================================================================== void IN_DrawYAH(void) { int i; int x; x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2; MN_DrTextA(DEH_String("NOW ENTERING:"), x, 10); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7, x, 20); if (prevmap == 9) { prevmap = gamemap - 1; } for (i = 0; i < prevmap; i++) { V_DrawPatch(YAHspot[gameepisode - 1][i].x, YAHspot[gameepisode - 1][i].y, patchBEENTHERE); } if (players[consoleplayer].didsecret) { V_DrawPatch(YAHspot[gameepisode - 1][8].x, YAHspot[gameepisode - 1][8].y, patchBEENTHERE); } if (!(intertime & 16) || interstate == 3) { // draw the destination 'X' V_DrawPatch(YAHspot[gameepisode - 1][gamemap - 1].x, YAHspot[gameepisode - 1][gamemap - 1].y, patchGOINGTHERE); } } //======================================================================== // // IN_DrawSingleStats // //======================================================================== void IN_DrawSingleStats(void) { int x; static int sounds; IN_DrTextB(DEH_String("KILLS"), 50, 65); IN_DrTextB(DEH_String("ITEMS"), 50, 90); IN_DrTextB(DEH_String("SECRETS"), 50, 115); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3); x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2; MN_DrTextA(DEH_String("FINISHED"), x, 25); if (intertime < 30) { sounds = 0; return; } if (sounds < 1 && intertime >= 30) { S_StartSound(NULL, sfx_dorcls); sounds++; } IN_DrawNumber(players[consoleplayer].killcount, 200, 65, 3); V_DrawShadowedPatch(237, 65, FontBSlash); IN_DrawNumber(totalkills, 248, 65, 3); if (intertime < 60) { return; } if (sounds < 2 && intertime >= 60) { S_StartSound(NULL, sfx_dorcls); sounds++; } IN_DrawNumber(players[consoleplayer].itemcount, 200, 90, 3); V_DrawShadowedPatch(237, 90, FontBSlash); IN_DrawNumber(totalitems, 248, 90, 3); if (intertime < 90) { return; } if (sounds < 3 && intertime >= 90) { S_StartSound(NULL, sfx_dorcls); sounds++; } IN_DrawNumber(players[consoleplayer].secretcount, 200, 115, 3); V_DrawShadowedPatch(237, 115, FontBSlash); IN_DrawNumber(totalsecret, 248, 115, 3); if (intertime < 150) { return; } if (sounds < 4 && intertime >= 150) { S_StartSound(NULL, sfx_dorcls); sounds++; } if (gamemode != retail || gameepisode <= 3) { IN_DrTextB(DEH_String("TIME"), 85, 160); IN_DrawTime(155, 160, hours, minutes, seconds); } else { x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2; MN_DrTextA(DEH_String("NOW ENTERING:"), x, 160); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7, x, 170); skipintermission = false; } } //======================================================================== // // IN_DrawCoopStats // //======================================================================== void IN_DrawCoopStats(void) { int i; int x; int ypos; static int sounds; IN_DrTextB(DEH_String("KILLS"), 95, 35); IN_DrTextB(DEH_String("BONUS"), 155, 35); IN_DrTextB(DEH_String("SECRET"), 232, 35); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3); x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2; MN_DrTextA(DEH_String("FINISHED"), x, 25); ypos = 50; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { V_DrawShadowedPatch(25, ypos, W_CacheLumpNum(patchFaceOkayBase + i, PU_CACHE)); if (intertime < 40) { sounds = 0; ypos += 37; continue; } else if (intertime >= 40 && sounds < 1) { S_StartSound(NULL, sfx_dorcls); sounds++; } IN_DrawNumber(killPercent[i], 85, ypos + 10, 3); V_DrawShadowedPatch(121, ypos + 10, FontBPercent); IN_DrawNumber(bonusPercent[i], 160, ypos + 10, 3); V_DrawShadowedPatch(196, ypos + 10, FontBPercent); IN_DrawNumber(secretPercent[i], 237, ypos + 10, 3); V_DrawShadowedPatch(273, ypos + 10, FontBPercent); ypos += 37; } } } //======================================================================== // // IN_DrawDMStats // //======================================================================== void IN_DrawDMStats(void) { int i; int j; int ypos; int xpos; int kpos; static int sounds; xpos = 90; ypos = 55; IN_DrTextB(DEH_String("TOTAL"), 265, 30); MN_DrTextA(DEH_String("VICTIMS"), 140, 8); for (i = 0; i < 7; i++) { MN_DrTextA(DEH_String(KillersText[i]), 10, 80 + 9 * i); } if (intertime < 20) { for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { V_DrawShadowedPatch(40, ((ypos << FRACBITS) + dSlideY[i] * intertime) >> FRACBITS, W_CacheLumpNum(patchFaceOkayBase + i, PU_CACHE)); V_DrawShadowedPatch(((xpos << FRACBITS) + dSlideX[i] * intertime) >> FRACBITS, 18, W_CacheLumpNum(patchFaceDeadBase + i, PU_CACHE)); } } sounds = 0; return; } if (intertime >= 20 && sounds < 1) { S_StartSound(NULL, sfx_dorcls); sounds++; } if (intertime >= 100 && slaughterboy && sounds < 2) { S_StartSound(NULL, sfx_wpnup); sounds++; } for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { if (intertime < 100 || i == consoleplayer) { V_DrawShadowedPatch(40, ypos, W_CacheLumpNum(patchFaceOkayBase + i, PU_CACHE)); V_DrawShadowedPatch(xpos, 18, W_CacheLumpNum(patchFaceDeadBase + i, PU_CACHE)); } else { V_DrawTLPatch(40, ypos, W_CacheLumpNum(patchFaceOkayBase + i, PU_CACHE)); V_DrawTLPatch(xpos, 18, W_CacheLumpNum(patchFaceDeadBase + i, PU_CACHE)); } kpos = 86; for (j = 0; j < MAXPLAYERS; j++) { if (playeringame[j]) { IN_DrawNumber(players[i].frags[j], kpos, ypos + 10, 3); kpos += 43; } } if (slaughterboy & (1 << i)) { if (!(intertime & 16)) { IN_DrawNumber(totalFrags[i], 263, ypos + 10, 3); } } else { IN_DrawNumber(totalFrags[i], 263, ypos + 10, 3); } ypos += 36; xpos += 43; } } } //======================================================================== // // IN_DrawTime // //======================================================================== void IN_DrawTime(int x, int y, int h, int m, int s) { if (h) { IN_DrawNumber(h, x, y, 2); IN_DrTextB(DEH_String(":"), x + 26, y); } x += 34; if (m || h) { IN_DrawNumber(m, x, y, 2); } x += 34; if (s) { IN_DrTextB(DEH_String(":"), x - 8, y); IN_DrawNumber(s, x, y, 2); } } //======================================================================== // // IN_DrawNumber // //======================================================================== void IN_DrawNumber(int val, int x, int y, int digits) { patch_t *patch; int xpos; int oldval; int realdigits; boolean neg; oldval = val; xpos = x; neg = false; realdigits = 1; if (val < 0) { //...this should reflect negative frags val = -val; neg = true; if (val > 99) { val = 99; } } if (val > 9) { realdigits++; if (digits < realdigits) { realdigits = digits; val = 9; } } if (val > 99) { realdigits++; if (digits < realdigits) { realdigits = digits; val = 99; } } if (val > 999) { realdigits++; if (digits < realdigits) { realdigits = digits; val = 999; } } if (digits == 4) { patch = FontBNumbers[val / 1000]; V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2 - 12, y, patch); } if (digits > 2) { if (realdigits > 2) { patch = FontBNumbers[val / 100]; V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } xpos += 12; } val = val % 100; if (digits > 1) { if (val > 9) { patch = FontBNumbers[val / 10]; V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } else if (digits == 2 || oldval > 99) { V_DrawShadowedPatch(xpos, y, FontBNumbers[0]); } xpos += 12; } val = val % 10; patch = FontBNumbers[val]; V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); if (neg) { patch = FontBNegative; V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2 - 12 * (realdigits), y, patch); } } //======================================================================== // // IN_DrTextB // //======================================================================== void IN_DrTextB(char *text, int x, int y) { char c; patch_t *p; while ((c = *text++) != 0) { if (c < 33) { x += 8; } else { p = W_CacheLumpNum(FontBLump + c - 33, PU_CACHE); V_DrawShadowedPatch(x, y, p); x += SHORT(p->width) - 1; } } } chocolate-doom-chocolate-doom-2.2.1/src/heretic/info.c000066400000000000000000010251311257432200600226210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "doomdef.h" #include "p_action.h" char *sprnames[] = { "IMPX","ACLO","PTN1","SHLD","SHD2","BAGH","SPMP","INVS","PTN2","SOAR", "INVU","PWBK","EGGC","EGGM","FX01","SPHL","TRCH","FBMB","XPL1","ATLP", "PPOD","AMG1","SPSH","LVAS","SLDG","SKH1","SKH2","SKH3","SKH4","CHDL", "SRTC","SMPL","STGS","STGL","STCS","STCL","KFR1","BARL","BRPL","MOS1", "MOS2","WTRH","HCOR","KGZ1","KGZB","KGZG","KGZY","VLCO","VFBL","VTFB", "SFFI","TGLT","TELE","STFF","PUF3","PUF4","BEAK","WGNT","GAUN","PUF1", "WBLS","BLSR","FX18","FX17","WMCE","MACE","FX02","WSKL","HROD","FX00", "FX20","FX21","FX22","FX23","GWND","PUF2","WPHX","PHNX","FX04","FX08", "FX09","WBOW","CRBW","FX03","BLOD","PLAY","FDTH","BSKL","CHKN","MUMM", "FX15","BEAS","FRB1","SNKE","SNFX","HEAD","FX05","FX06","FX07","CLNK", "WZRD","FX11","FX10","KNIG","SPAX","RAXE","SRCR","FX14","SOR2","SDTH", "FX16","MNTR","FX12","FX13","AKYY","BKYY","CKYY","AMG2","AMM1","AMM2", "AMC1","AMC2","AMS1","AMS2","AMP1","AMP2","AMB1","AMB2", NULL }; state_t states[NUMSTATES] = { {SPR_IMPX, 0, -1, NULL, S_NULL, 0, 0}, // S_NULL {SPR_ACLO, 4, 1050, A_FreeTargMobj, S_NULL, 0, 0}, // S_FREETARGMOBJ {SPR_PTN1, 0, 3, NULL, S_ITEM_PTN1_2, 0, 0}, // S_ITEM_PTN1_1 {SPR_PTN1, 1, 3, NULL, S_ITEM_PTN1_3, 0, 0}, // S_ITEM_PTN1_2 {SPR_PTN1, 2, 3, NULL, S_ITEM_PTN1_1, 0, 0}, // S_ITEM_PTN1_3 {SPR_SHLD, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_SHLD1 {SPR_SHD2, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_SHD2_1 {SPR_BAGH, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_BAGH1 {SPR_SPMP, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_SPMP1 {SPR_ACLO, 4, 1400, NULL, S_HIDESPECIAL2, 0, 0}, // S_HIDESPECIAL1 {SPR_ACLO, 0, 4, A_RestoreSpecialThing1, S_HIDESPECIAL3, 0, 0}, // S_HIDESPECIAL2 {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL4, 0, 0}, // S_HIDESPECIAL3 {SPR_ACLO, 0, 4, NULL, S_HIDESPECIAL5, 0, 0}, // S_HIDESPECIAL4 {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL6, 0, 0}, // S_HIDESPECIAL5 {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL7, 0, 0}, // S_HIDESPECIAL6 {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL8, 0, 0}, // S_HIDESPECIAL7 {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL9, 0, 0}, // S_HIDESPECIAL8 {SPR_ACLO, 3, 4, NULL, S_HIDESPECIAL10, 0, 0}, // S_HIDESPECIAL9 {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL11, 0, 0}, // S_HIDESPECIAL10 {SPR_ACLO, 3, 4, A_RestoreSpecialThing2, S_NULL, 0, 0}, // S_HIDESPECIAL11 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2, 0, 0}, // S_DORMANTARTI1 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3, 0, 0}, // S_DORMANTARTI2 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI4, 0, 0}, // S_DORMANTARTI3 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI5, 0, 0}, // S_DORMANTARTI4 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI6, 0, 0}, // S_DORMANTARTI5 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI7, 0, 0}, // S_DORMANTARTI6 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI8, 0, 0}, // S_DORMANTARTI7 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI9, 0, 0}, // S_DORMANTARTI8 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI10, 0, 0}, // S_DORMANTARTI9 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI11, 0, 0}, // S_DORMANTARTI10 {SPR_ACLO, 0, 1400, A_HideThing, S_DORMANTARTI12, 0, 0}, // S_DORMANTARTI11 {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI13, 0, 0}, // S_DORMANTARTI12 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI14, 0, 0}, // S_DORMANTARTI13 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI15, 0, 0}, // S_DORMANTARTI14 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI16, 0, 0}, // S_DORMANTARTI15 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI17, 0, 0}, // S_DORMANTARTI16 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI18, 0, 0}, // S_DORMANTARTI17 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI19, 0, 0}, // S_DORMANTARTI18 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI20, 0, 0}, // S_DORMANTARTI19 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI21, 0, 0}, // S_DORMANTARTI20 {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI21 {SPR_ACLO, 3, 3, NULL, S_DEADARTI2, 0, 0}, // S_DEADARTI1 {SPR_ACLO, 2, 3, NULL, S_DEADARTI3, 0, 0}, // S_DEADARTI2 {SPR_ACLO, 3, 3, NULL, S_DEADARTI4, 0, 0}, // S_DEADARTI3 {SPR_ACLO, 2, 3, NULL, S_DEADARTI5, 0, 0}, // S_DEADARTI4 {SPR_ACLO, 1, 3, NULL, S_DEADARTI6, 0, 0}, // S_DEADARTI5 {SPR_ACLO, 2, 3, NULL, S_DEADARTI7, 0, 0}, // S_DEADARTI6 {SPR_ACLO, 1, 3, NULL, S_DEADARTI8, 0, 0}, // S_DEADARTI7 {SPR_ACLO, 0, 3, NULL, S_DEADARTI9, 0, 0}, // S_DEADARTI8 {SPR_ACLO, 1, 3, NULL, S_DEADARTI10, 0, 0}, // S_DEADARTI9 {SPR_ACLO, 0, 3, NULL, S_NULL, 0, 0}, // S_DEADARTI10 {SPR_INVS, 32768, 350, NULL, S_ARTI_INVS1, 0, 0}, // S_ARTI_INVS1 {SPR_PTN2, 0, 4, NULL, S_ARTI_PTN2_2, 0, 0}, // S_ARTI_PTN2_1 {SPR_PTN2, 1, 4, NULL, S_ARTI_PTN2_3, 0, 0}, // S_ARTI_PTN2_2 {SPR_PTN2, 2, 4, NULL, S_ARTI_PTN2_1, 0, 0}, // S_ARTI_PTN2_3 {SPR_SOAR, 0, 5, NULL, S_ARTI_SOAR2, 0, 0}, // S_ARTI_SOAR1 {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR3, 0, 0}, // S_ARTI_SOAR2 {SPR_SOAR, 2, 5, NULL, S_ARTI_SOAR4, 0, 0}, // S_ARTI_SOAR3 {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR1, 0, 0}, // S_ARTI_SOAR4 {SPR_INVU, 0, 3, NULL, S_ARTI_INVU2, 0, 0}, // S_ARTI_INVU1 {SPR_INVU, 1, 3, NULL, S_ARTI_INVU3, 0, 0}, // S_ARTI_INVU2 {SPR_INVU, 2, 3, NULL, S_ARTI_INVU4, 0, 0}, // S_ARTI_INVU3 {SPR_INVU, 3, 3, NULL, S_ARTI_INVU1, 0, 0}, // S_ARTI_INVU4 {SPR_PWBK, 0, 350, NULL, S_ARTI_PWBK1, 0, 0}, // S_ARTI_PWBK1 {SPR_EGGC, 0, 6, NULL, S_ARTI_EGGC2, 0, 0}, // S_ARTI_EGGC1 {SPR_EGGC, 1, 6, NULL, S_ARTI_EGGC3, 0, 0}, // S_ARTI_EGGC2 {SPR_EGGC, 2, 6, NULL, S_ARTI_EGGC4, 0, 0}, // S_ARTI_EGGC3 {SPR_EGGC, 1, 6, NULL, S_ARTI_EGGC1, 0, 0}, // S_ARTI_EGGC4 {SPR_EGGM, 0, 4, NULL, S_EGGFX2, 0, 0}, // S_EGGFX1 {SPR_EGGM, 1, 4, NULL, S_EGGFX3, 0, 0}, // S_EGGFX2 {SPR_EGGM, 2, 4, NULL, S_EGGFX4, 0, 0}, // S_EGGFX3 {SPR_EGGM, 3, 4, NULL, S_EGGFX5, 0, 0}, // S_EGGFX4 {SPR_EGGM, 4, 4, NULL, S_EGGFX1, 0, 0}, // S_EGGFX5 {SPR_FX01, 32772, 3, NULL, S_EGGFXI1_2, 0, 0}, // S_EGGFXI1_1 {SPR_FX01, 32773, 3, NULL, S_EGGFXI1_3, 0, 0}, // S_EGGFXI1_2 {SPR_FX01, 32774, 3, NULL, S_EGGFXI1_4, 0, 0}, // S_EGGFXI1_3 {SPR_FX01, 32775, 3, NULL, S_NULL, 0, 0}, // S_EGGFXI1_4 {SPR_SPHL, 0, 350, NULL, S_ARTI_SPHL1, 0, 0}, // S_ARTI_SPHL1 {SPR_TRCH, 32768, 3, NULL, S_ARTI_TRCH2, 0, 0}, // S_ARTI_TRCH1 {SPR_TRCH, 32769, 3, NULL, S_ARTI_TRCH3, 0, 0}, // S_ARTI_TRCH2 {SPR_TRCH, 32770, 3, NULL, S_ARTI_TRCH1, 0, 0}, // S_ARTI_TRCH3 {SPR_FBMB, 4, 350, NULL, S_ARTI_FBMB1, 0, 0}, // S_ARTI_FBMB1 {SPR_FBMB, 0, 10, NULL, S_FIREBOMB2, 0, 0}, // S_FIREBOMB1 {SPR_FBMB, 1, 10, NULL, S_FIREBOMB3, 0, 0}, // S_FIREBOMB2 {SPR_FBMB, 2, 10, NULL, S_FIREBOMB4, 0, 0}, // S_FIREBOMB3 {SPR_FBMB, 3, 10, NULL, S_FIREBOMB5, 0, 0}, // S_FIREBOMB4 {SPR_FBMB, 4, 6, A_Scream, S_FIREBOMB6, 0, 0}, // S_FIREBOMB5 {SPR_XPL1, 32768, 4, A_Explode, S_FIREBOMB7, 0, 0}, // S_FIREBOMB6 {SPR_XPL1, 32769, 4, NULL, S_FIREBOMB8, 0, 0}, // S_FIREBOMB7 {SPR_XPL1, 32770, 4, NULL, S_FIREBOMB9, 0, 0}, // S_FIREBOMB8 {SPR_XPL1, 32771, 4, NULL, S_FIREBOMB10, 0, 0}, // S_FIREBOMB9 {SPR_XPL1, 32772, 4, NULL, S_FIREBOMB11, 0, 0}, // S_FIREBOMB10 {SPR_XPL1, 32773, 4, NULL, S_NULL, 0, 0}, // S_FIREBOMB11 {SPR_ATLP, 0, 4, NULL, S_ARTI_ATLP2, 0, 0}, // S_ARTI_ATLP1 {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP3, 0, 0}, // S_ARTI_ATLP2 {SPR_ATLP, 2, 4, NULL, S_ARTI_ATLP4, 0, 0}, // S_ARTI_ATLP3 {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP1, 0, 0}, // S_ARTI_ATLP4 {SPR_PPOD, 0, 10, NULL, S_POD_WAIT1, 0, 0}, // S_POD_WAIT1 {SPR_PPOD, 1, 14, A_PodPain, S_POD_WAIT1, 0, 0}, // S_POD_PAIN1 {SPR_PPOD, 32770, 5, A_RemovePod, S_POD_DIE2, 0, 0}, // S_POD_DIE1 {SPR_PPOD, 32771, 5, A_Scream, S_POD_DIE3, 0, 0}, // S_POD_DIE2 {SPR_PPOD, 32772, 5, A_Explode, S_POD_DIE4, 0, 0}, // S_POD_DIE3 {SPR_PPOD, 32773, 10, NULL, S_FREETARGMOBJ, 0, 0}, // S_POD_DIE4 {SPR_PPOD, 8, 3, NULL, S_POD_GROW2, 0, 0}, // S_POD_GROW1 {SPR_PPOD, 9, 3, NULL, S_POD_GROW3, 0, 0}, // S_POD_GROW2 {SPR_PPOD, 10, 3, NULL, S_POD_GROW4, 0, 0}, // S_POD_GROW3 {SPR_PPOD, 11, 3, NULL, S_POD_GROW5, 0, 0}, // S_POD_GROW4 {SPR_PPOD, 12, 3, NULL, S_POD_GROW6, 0, 0}, // S_POD_GROW5 {SPR_PPOD, 13, 3, NULL, S_POD_GROW7, 0, 0}, // S_POD_GROW6 {SPR_PPOD, 14, 3, NULL, S_POD_GROW8, 0, 0}, // S_POD_GROW7 {SPR_PPOD, 15, 3, NULL, S_POD_WAIT1, 0, 0}, // S_POD_GROW8 {SPR_PPOD, 6, 8, NULL, S_PODGOO2, 0, 0}, // S_PODGOO1 {SPR_PPOD, 7, 8, NULL, S_PODGOO1, 0, 0}, // S_PODGOO2 {SPR_PPOD, 6, 10, NULL, S_NULL, 0, 0}, // S_PODGOOX {SPR_AMG1, 0, 35, A_MakePod, S_PODGENERATOR, 0, 0}, // S_PODGENERATOR {SPR_SPSH, 0, 8, NULL, S_SPLASH2, 0, 0}, // S_SPLASH1 {SPR_SPSH, 1, 8, NULL, S_SPLASH3, 0, 0}, // S_SPLASH2 {SPR_SPSH, 2, 8, NULL, S_SPLASH4, 0, 0}, // S_SPLASH3 {SPR_SPSH, 3, 16, NULL, S_NULL, 0, 0}, // S_SPLASH4 {SPR_SPSH, 3, 10, NULL, S_NULL, 0, 0}, // S_SPLASHX {SPR_SPSH, 4, 5, NULL, S_SPLASHBASE2, 0, 0}, // S_SPLASHBASE1 {SPR_SPSH, 5, 5, NULL, S_SPLASHBASE3, 0, 0}, // S_SPLASHBASE2 {SPR_SPSH, 6, 5, NULL, S_SPLASHBASE4, 0, 0}, // S_SPLASHBASE3 {SPR_SPSH, 7, 5, NULL, S_SPLASHBASE5, 0, 0}, // S_SPLASHBASE4 {SPR_SPSH, 8, 5, NULL, S_SPLASHBASE6, 0, 0}, // S_SPLASHBASE5 {SPR_SPSH, 9, 5, NULL, S_SPLASHBASE7, 0, 0}, // S_SPLASHBASE6 {SPR_SPSH, 10, 5, NULL, S_NULL, 0, 0}, // S_SPLASHBASE7 {SPR_LVAS, 32768, 5, NULL, S_LAVASPLASH2, 0, 0}, // S_LAVASPLASH1 {SPR_LVAS, 32769, 5, NULL, S_LAVASPLASH3, 0, 0}, // S_LAVASPLASH2 {SPR_LVAS, 32770, 5, NULL, S_LAVASPLASH4, 0, 0}, // S_LAVASPLASH3 {SPR_LVAS, 32771, 5, NULL, S_LAVASPLASH5, 0, 0}, // S_LAVASPLASH4 {SPR_LVAS, 32772, 5, NULL, S_LAVASPLASH6, 0, 0}, // S_LAVASPLASH5 {SPR_LVAS, 32773, 5, NULL, S_NULL, 0, 0}, // S_LAVASPLASH6 {SPR_LVAS, 32774, 5, NULL, S_LAVASMOKE2, 0, 0}, // S_LAVASMOKE1 {SPR_LVAS, 32775, 5, NULL, S_LAVASMOKE3, 0, 0}, // S_LAVASMOKE2 {SPR_LVAS, 32776, 5, NULL, S_LAVASMOKE4, 0, 0}, // S_LAVASMOKE3 {SPR_LVAS, 32777, 5, NULL, S_LAVASMOKE5, 0, 0}, // S_LAVASMOKE4 {SPR_LVAS, 32778, 5, NULL, S_NULL, 0, 0}, // S_LAVASMOKE5 {SPR_SLDG, 0, 8, NULL, S_SLUDGECHUNK2, 0, 0}, // S_SLUDGECHUNK1 {SPR_SLDG, 1, 8, NULL, S_SLUDGECHUNK3, 0, 0}, // S_SLUDGECHUNK2 {SPR_SLDG, 2, 8, NULL, S_SLUDGECHUNK4, 0, 0}, // S_SLUDGECHUNK3 {SPR_SLDG, 3, 8, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNK4 {SPR_SLDG, 3, 6, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNKX {SPR_SLDG, 4, 5, NULL, S_SLUDGESPLASH2, 0, 0}, // S_SLUDGESPLASH1 {SPR_SLDG, 5, 5, NULL, S_SLUDGESPLASH3, 0, 0}, // S_SLUDGESPLASH2 {SPR_SLDG, 6, 5, NULL, S_SLUDGESPLASH4, 0, 0}, // S_SLUDGESPLASH3 {SPR_SLDG, 7, 5, NULL, S_NULL, 0, 0}, // S_SLUDGESPLASH4 {SPR_SKH1, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG70_1 {SPR_SKH2, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG60_1 {SPR_SKH3, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG45_1 {SPR_SKH4, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG35_1 {SPR_CHDL, 0, 4, NULL, S_CHANDELIER2, 0, 0}, // S_CHANDELIER1 {SPR_CHDL, 1, 4, NULL, S_CHANDELIER3, 0, 0}, // S_CHANDELIER2 {SPR_CHDL, 2, 4, NULL, S_CHANDELIER1, 0, 0}, // S_CHANDELIER3 {SPR_SRTC, 0, 4, NULL, S_SERPTORCH2, 0, 0}, // S_SERPTORCH1 {SPR_SRTC, 1, 4, NULL, S_SERPTORCH3, 0, 0}, // S_SERPTORCH2 {SPR_SRTC, 2, 4, NULL, S_SERPTORCH1, 0, 0}, // S_SERPTORCH3 {SPR_SMPL, 0, -1, NULL, S_NULL, 0, 0}, // S_SMALLPILLAR {SPR_STGS, 0, -1, NULL, S_NULL, 0, 0}, // S_STALAGMITESMALL {SPR_STGL, 0, -1, NULL, S_NULL, 0, 0}, // S_STALAGMITELARGE {SPR_STCS, 0, -1, NULL, S_NULL, 0, 0}, // S_STALACTITESMALL {SPR_STCL, 0, -1, NULL, S_NULL, 0, 0}, // S_STALACTITELARGE {SPR_KFR1, 32768, 3, NULL, S_FIREBRAZIER2, 0, 0}, // S_FIREBRAZIER1 {SPR_KFR1, 32769, 3, NULL, S_FIREBRAZIER3, 0, 0}, // S_FIREBRAZIER2 {SPR_KFR1, 32770, 3, NULL, S_FIREBRAZIER4, 0, 0}, // S_FIREBRAZIER3 {SPR_KFR1, 32771, 3, NULL, S_FIREBRAZIER5, 0, 0}, // S_FIREBRAZIER4 {SPR_KFR1, 32772, 3, NULL, S_FIREBRAZIER6, 0, 0}, // S_FIREBRAZIER5 {SPR_KFR1, 32773, 3, NULL, S_FIREBRAZIER7, 0, 0}, // S_FIREBRAZIER6 {SPR_KFR1, 32774, 3, NULL, S_FIREBRAZIER8, 0, 0}, // S_FIREBRAZIER7 {SPR_KFR1, 32775, 3, NULL, S_FIREBRAZIER1, 0, 0}, // S_FIREBRAZIER8 {SPR_BARL, 0, -1, NULL, S_NULL, 0, 0}, // S_BARREL {SPR_BRPL, 0, -1, NULL, S_NULL, 0, 0}, // S_BRPILLAR {SPR_MOS1, 0, -1, NULL, S_NULL, 0, 0}, // S_MOSS1 {SPR_MOS2, 0, -1, NULL, S_NULL, 0, 0}, // S_MOSS2 {SPR_WTRH, 32768, 6, NULL, S_WALLTORCH2, 0, 0}, // S_WALLTORCH1 {SPR_WTRH, 32769, 6, NULL, S_WALLTORCH3, 0, 0}, // S_WALLTORCH2 {SPR_WTRH, 32770, 6, NULL, S_WALLTORCH1, 0, 0}, // S_WALLTORCH3 {SPR_HCOR, 0, -1, NULL, S_NULL, 0, 0}, // S_HANGINGCORPSE {SPR_KGZ1, 0, 1, NULL, S_KEYGIZMO2, 0, 0}, // S_KEYGIZMO1 {SPR_KGZ1, 0, 1, A_InitKeyGizmo, S_KEYGIZMO3, 0, 0}, // S_KEYGIZMO2 {SPR_KGZ1, 0, -1, NULL, S_NULL, 0, 0}, // S_KEYGIZMO3 {SPR_KGZB, 0, 1, NULL, S_KGZ_START, 0, 0}, // S_KGZ_START {SPR_KGZB, 32768, -1, NULL, S_NULL, 0, 0}, // S_KGZ_BLUEFLOAT1 {SPR_KGZG, 32768, -1, NULL, S_NULL, 0, 0}, // S_KGZ_GREENFLOAT1 {SPR_KGZY, 32768, -1, NULL, S_NULL, 0, 0}, // S_KGZ_YELLOWFLOAT1 {SPR_VLCO, 0, 350, NULL, S_VOLCANO2, 0, 0}, // S_VOLCANO1 {SPR_VLCO, 0, 35, A_VolcanoSet, S_VOLCANO3, 0, 0}, // S_VOLCANO2 {SPR_VLCO, 1, 3, NULL, S_VOLCANO4, 0, 0}, // S_VOLCANO3 {SPR_VLCO, 2, 3, NULL, S_VOLCANO5, 0, 0}, // S_VOLCANO4 {SPR_VLCO, 3, 3, NULL, S_VOLCANO6, 0, 0}, // S_VOLCANO5 {SPR_VLCO, 1, 3, NULL, S_VOLCANO7, 0, 0}, // S_VOLCANO6 {SPR_VLCO, 2, 3, NULL, S_VOLCANO8, 0, 0}, // S_VOLCANO7 {SPR_VLCO, 3, 3, NULL, S_VOLCANO9, 0, 0}, // S_VOLCANO8 {SPR_VLCO, 4, 10, A_VolcanoBlast, S_VOLCANO2, 0, 0}, // S_VOLCANO9 {SPR_VFBL, 0, 4, A_BeastPuff, S_VOLCANOBALL2, 0, 0}, // S_VOLCANOBALL1 {SPR_VFBL, 1, 4, A_BeastPuff, S_VOLCANOBALL1, 0, 0}, // S_VOLCANOBALL2 {SPR_XPL1, 0, 4, A_VolcBallImpact, S_VOLCANOBALLX2, 0, 0}, // S_VOLCANOBALLX1 {SPR_XPL1, 1, 4, NULL, S_VOLCANOBALLX3, 0, 0}, // S_VOLCANOBALLX2 {SPR_XPL1, 2, 4, NULL, S_VOLCANOBALLX4, 0, 0}, // S_VOLCANOBALLX3 {SPR_XPL1, 3, 4, NULL, S_VOLCANOBALLX5, 0, 0}, // S_VOLCANOBALLX4 {SPR_XPL1, 4, 4, NULL, S_VOLCANOBALLX6, 0, 0}, // S_VOLCANOBALLX5 {SPR_XPL1, 5, 4, NULL, S_NULL, 0, 0}, // S_VOLCANOBALLX6 {SPR_VTFB, 0, 4, NULL, S_VOLCANOTBALL2, 0, 0}, // S_VOLCANOTBALL1 {SPR_VTFB, 1, 4, NULL, S_VOLCANOTBALL1, 0, 0}, // S_VOLCANOTBALL2 {SPR_SFFI, 2, 4, NULL, S_VOLCANOTBALLX2, 0, 0}, // S_VOLCANOTBALLX1 {SPR_SFFI, 1, 4, NULL, S_VOLCANOTBALLX3, 0, 0}, // S_VOLCANOTBALLX2 {SPR_SFFI, 0, 4, NULL, S_VOLCANOTBALLX4, 0, 0}, // S_VOLCANOTBALLX3 {SPR_SFFI, 1, 4, NULL, S_VOLCANOTBALLX5, 0, 0}, // S_VOLCANOTBALLX4 {SPR_SFFI, 2, 4, NULL, S_VOLCANOTBALLX6, 0, 0}, // S_VOLCANOTBALLX5 {SPR_SFFI, 3, 4, NULL, S_VOLCANOTBALLX7, 0, 0}, // S_VOLCANOTBALLX6 {SPR_SFFI, 4, 4, NULL, S_NULL, 0, 0}, // S_VOLCANOTBALLX7 {SPR_TGLT, 0, 8, A_SpawnTeleGlitter, S_TELEGLITGEN1, 0, 0}, // S_TELEGLITGEN1 {SPR_TGLT, 5, 8, A_SpawnTeleGlitter2, S_TELEGLITGEN2, 0, 0}, // S_TELEGLITGEN2 {SPR_TGLT, 32768, 2, NULL, S_TELEGLITTER1_2, 0, 0}, // S_TELEGLITTER1_1 {SPR_TGLT, 32769, 2, A_AccTeleGlitter, S_TELEGLITTER1_3, 0, 0}, // S_TELEGLITTER1_2 {SPR_TGLT, 32770, 2, NULL, S_TELEGLITTER1_4, 0, 0}, // S_TELEGLITTER1_3 {SPR_TGLT, 32771, 2, A_AccTeleGlitter, S_TELEGLITTER1_5, 0, 0}, // S_TELEGLITTER1_4 {SPR_TGLT, 32772, 2, NULL, S_TELEGLITTER1_1, 0, 0}, // S_TELEGLITTER1_5 {SPR_TGLT, 32773, 2, NULL, S_TELEGLITTER2_2, 0, 0}, // S_TELEGLITTER2_1 {SPR_TGLT, 32774, 2, A_AccTeleGlitter, S_TELEGLITTER2_3, 0, 0}, // S_TELEGLITTER2_2 {SPR_TGLT, 32775, 2, NULL, S_TELEGLITTER2_4, 0, 0}, // S_TELEGLITTER2_3 {SPR_TGLT, 32776, 2, A_AccTeleGlitter, S_TELEGLITTER2_5, 0, 0}, // S_TELEGLITTER2_4 {SPR_TGLT, 32777, 2, NULL, S_TELEGLITTER2_1, 0, 0}, // S_TELEGLITTER2_5 {SPR_TELE, 32768, 6, NULL, S_TFOG2, 0, 0}, // S_TFOG1 {SPR_TELE, 32769, 6, NULL, S_TFOG3, 0, 0}, // S_TFOG2 {SPR_TELE, 32770, 6, NULL, S_TFOG4, 0, 0}, // S_TFOG3 {SPR_TELE, 32771, 6, NULL, S_TFOG5, 0, 0}, // S_TFOG4 {SPR_TELE, 32772, 6, NULL, S_TFOG6, 0, 0}, // S_TFOG5 {SPR_TELE, 32773, 6, NULL, S_TFOG7, 0, 0}, // S_TFOG6 {SPR_TELE, 32774, 6, NULL, S_TFOG8, 0, 0}, // S_TFOG7 {SPR_TELE, 32775, 6, NULL, S_TFOG9, 0, 0}, // S_TFOG8 {SPR_TELE, 32774, 6, NULL, S_TFOG10, 0, 0}, // S_TFOG9 {SPR_TELE, 32773, 6, NULL, S_TFOG11, 0, 0}, // S_TFOG10 {SPR_TELE, 32772, 6, NULL, S_TFOG12, 0, 0}, // S_TFOG11 {SPR_TELE, 32771, 6, NULL, S_TFOG13, 0, 0}, // S_TFOG12 {SPR_TELE, 32770, 6, NULL, S_NULL, 0, 0}, // S_TFOG13 {SPR_STFF, 0, 0, A_Light0, S_NULL, 0, 0}, // S_LIGHTDONE {SPR_STFF, 0, 1, A_WeaponReady, S_STAFFREADY, 0, 0}, // S_STAFFREADY {SPR_STFF, 0, 1, A_Lower, S_STAFFDOWN, 0, 0}, // S_STAFFDOWN {SPR_STFF, 0, 1, A_Raise, S_STAFFUP, 0, 0}, // S_STAFFUP {SPR_STFF, 3, 4, A_WeaponReady, S_STAFFREADY2_2, 0, 0}, // S_STAFFREADY2_1 {SPR_STFF, 4, 4, A_WeaponReady, S_STAFFREADY2_3, 0, 0}, // S_STAFFREADY2_2 {SPR_STFF, 5, 4, A_WeaponReady, S_STAFFREADY2_1, 0, 0}, // S_STAFFREADY2_3 {SPR_STFF, 3, 1, A_Lower, S_STAFFDOWN2, 0, 0}, // S_STAFFDOWN2 {SPR_STFF, 3, 1, A_Raise, S_STAFFUP2, 0, 0}, // S_STAFFUP2 {SPR_STFF, 1, 6, NULL, S_STAFFATK1_2, 0, 0}, // S_STAFFATK1_1 {SPR_STFF, 2, 8, A_StaffAttackPL1, S_STAFFATK1_3, 0, 0}, // S_STAFFATK1_2 {SPR_STFF, 1, 8, A_ReFire, S_STAFFREADY, 0, 0}, // S_STAFFATK1_3 {SPR_STFF, 6, 6, NULL, S_STAFFATK2_2, 0, 0}, // S_STAFFATK2_1 {SPR_STFF, 7, 8, A_StaffAttackPL2, S_STAFFATK2_3, 0, 0}, // S_STAFFATK2_2 {SPR_STFF, 6, 8, A_ReFire, S_STAFFREADY2_1, 0, 0}, // S_STAFFATK2_3 {SPR_PUF3, 32768, 4, NULL, S_STAFFPUFF2, 0, 0}, // S_STAFFPUFF1 {SPR_PUF3, 1, 4, NULL, S_STAFFPUFF3, 0, 0}, // S_STAFFPUFF2 {SPR_PUF3, 2, 4, NULL, S_STAFFPUFF4, 0, 0}, // S_STAFFPUFF3 {SPR_PUF3, 3, 4, NULL, S_NULL, 0, 0}, // S_STAFFPUFF4 {SPR_PUF4, 32768, 4, NULL, S_STAFFPUFF2_2, 0, 0}, // S_STAFFPUFF2_1 {SPR_PUF4, 32769, 4, NULL, S_STAFFPUFF2_3, 0, 0}, // S_STAFFPUFF2_2 {SPR_PUF4, 32770, 4, NULL, S_STAFFPUFF2_4, 0, 0}, // S_STAFFPUFF2_3 {SPR_PUF4, 32771, 4, NULL, S_STAFFPUFF2_5, 0, 0}, // S_STAFFPUFF2_4 {SPR_PUF4, 32772, 4, NULL, S_STAFFPUFF2_6, 0, 0}, // S_STAFFPUFF2_5 {SPR_PUF4, 32773, 4, NULL, S_NULL, 0, 0}, // S_STAFFPUFF2_6 {SPR_BEAK, 0, 1, A_BeakReady, S_BEAKREADY, 0, 0}, // S_BEAKREADY {SPR_BEAK, 0, 1, A_Lower, S_BEAKDOWN, 0, 0}, // S_BEAKDOWN {SPR_BEAK, 0, 1, A_BeakRaise, S_BEAKUP, 0, 0}, // S_BEAKUP {SPR_BEAK, 0, 18, A_BeakAttackPL1, S_BEAKREADY, 0, 0}, // S_BEAKATK1_1 {SPR_BEAK, 0, 12, A_BeakAttackPL2, S_BEAKREADY, 0, 0}, // S_BEAKATK2_1 {SPR_WGNT, 0, -1, NULL, S_NULL, 0, 0}, // S_WGNT {SPR_GAUN, 0, 1, A_WeaponReady, S_GAUNTLETREADY, 0, 0}, // S_GAUNTLETREADY {SPR_GAUN, 0, 1, A_Lower, S_GAUNTLETDOWN, 0, 0}, // S_GAUNTLETDOWN {SPR_GAUN, 0, 1, A_Raise, S_GAUNTLETUP, 0, 0}, // S_GAUNTLETUP {SPR_GAUN, 6, 4, A_WeaponReady, S_GAUNTLETREADY2_2, 0, 0}, // S_GAUNTLETREADY2_1 {SPR_GAUN, 7, 4, A_WeaponReady, S_GAUNTLETREADY2_3, 0, 0}, // S_GAUNTLETREADY2_2 {SPR_GAUN, 8, 4, A_WeaponReady, S_GAUNTLETREADY2_1, 0, 0}, // S_GAUNTLETREADY2_3 {SPR_GAUN, 6, 1, A_Lower, S_GAUNTLETDOWN2, 0, 0}, // S_GAUNTLETDOWN2 {SPR_GAUN, 6, 1, A_Raise, S_GAUNTLETUP2, 0, 0}, // S_GAUNTLETUP2 {SPR_GAUN, 1, 4, NULL, S_GAUNTLETATK1_2, 0, 0}, // S_GAUNTLETATK1_1 {SPR_GAUN, 2, 4, NULL, S_GAUNTLETATK1_3, 0, 0}, // S_GAUNTLETATK1_2 {SPR_GAUN, 32771, 4, A_GauntletAttack, S_GAUNTLETATK1_4, 0, 0}, // S_GAUNTLETATK1_3 {SPR_GAUN, 32772, 4, A_GauntletAttack, S_GAUNTLETATK1_5, 0, 0}, // S_GAUNTLETATK1_4 {SPR_GAUN, 32773, 4, A_GauntletAttack, S_GAUNTLETATK1_6, 0, 0}, // S_GAUNTLETATK1_5 {SPR_GAUN, 2, 4, A_ReFire, S_GAUNTLETATK1_7, 0, 0}, // S_GAUNTLETATK1_6 {SPR_GAUN, 1, 4, A_Light0, S_GAUNTLETREADY, 0, 0}, // S_GAUNTLETATK1_7 {SPR_GAUN, 9, 4, NULL, S_GAUNTLETATK2_2, 0, 0}, // S_GAUNTLETATK2_1 {SPR_GAUN, 10, 4, NULL, S_GAUNTLETATK2_3, 0, 0}, // S_GAUNTLETATK2_2 {SPR_GAUN, 32779, 4, A_GauntletAttack, S_GAUNTLETATK2_4, 0, 0}, // S_GAUNTLETATK2_3 {SPR_GAUN, 32780, 4, A_GauntletAttack, S_GAUNTLETATK2_5, 0, 0}, // S_GAUNTLETATK2_4 {SPR_GAUN, 32781, 4, A_GauntletAttack, S_GAUNTLETATK2_6, 0, 0}, // S_GAUNTLETATK2_5 {SPR_GAUN, 10, 4, A_ReFire, S_GAUNTLETATK2_7, 0, 0}, // S_GAUNTLETATK2_6 {SPR_GAUN, 9, 4, A_Light0, S_GAUNTLETREADY2_1, 0, 0}, // S_GAUNTLETATK2_7 {SPR_PUF1, 32768, 4, NULL, S_GAUNTLETPUFF1_2, 0, 0}, // S_GAUNTLETPUFF1_1 {SPR_PUF1, 32769, 4, NULL, S_GAUNTLETPUFF1_3, 0, 0}, // S_GAUNTLETPUFF1_2 {SPR_PUF1, 32770, 4, NULL, S_GAUNTLETPUFF1_4, 0, 0}, // S_GAUNTLETPUFF1_3 {SPR_PUF1, 32771, 4, NULL, S_NULL, 0, 0}, // S_GAUNTLETPUFF1_4 {SPR_PUF1, 32772, 4, NULL, S_GAUNTLETPUFF2_2, 0, 0}, // S_GAUNTLETPUFF2_1 {SPR_PUF1, 32773, 4, NULL, S_GAUNTLETPUFF2_3, 0, 0}, // S_GAUNTLETPUFF2_2 {SPR_PUF1, 32774, 4, NULL, S_GAUNTLETPUFF2_4, 0, 0}, // S_GAUNTLETPUFF2_3 {SPR_PUF1, 32775, 4, NULL, S_NULL, 0, 0}, // S_GAUNTLETPUFF2_4 {SPR_WBLS, 0, -1, NULL, S_NULL, 0, 0}, // S_BLSR {SPR_BLSR, 0, 1, A_WeaponReady, S_BLASTERREADY, 0, 0}, // S_BLASTERREADY {SPR_BLSR, 0, 1, A_Lower, S_BLASTERDOWN, 0, 0}, // S_BLASTERDOWN {SPR_BLSR, 0, 1, A_Raise, S_BLASTERUP, 0, 0}, // S_BLASTERUP {SPR_BLSR, 1, 3, NULL, S_BLASTERATK1_2, 0, 0}, // S_BLASTERATK1_1 {SPR_BLSR, 2, 3, NULL, S_BLASTERATK1_3, 0, 0}, // S_BLASTERATK1_2 {SPR_BLSR, 3, 2, A_FireBlasterPL1, S_BLASTERATK1_4, 0, 0}, // S_BLASTERATK1_3 {SPR_BLSR, 2, 2, NULL, S_BLASTERATK1_5, 0, 0}, // S_BLASTERATK1_4 {SPR_BLSR, 1, 2, NULL, S_BLASTERATK1_6, 0, 0}, // S_BLASTERATK1_5 {SPR_BLSR, 0, 0, A_ReFire, S_BLASTERREADY, 0, 0}, // S_BLASTERATK1_6 {SPR_BLSR, 1, 0, NULL, S_BLASTERATK2_2, 0, 0}, // S_BLASTERATK2_1 {SPR_BLSR, 2, 0, NULL, S_BLASTERATK2_3, 0, 0}, // S_BLASTERATK2_2 {SPR_BLSR, 3, 3, A_FireBlasterPL2, S_BLASTERATK2_4, 0, 0}, // S_BLASTERATK2_3 {SPR_BLSR, 2, 4, NULL, S_BLASTERATK2_5, 0, 0}, // S_BLASTERATK2_4 {SPR_BLSR, 1, 4, NULL, S_BLASTERATK2_6, 0, 0}, // S_BLASTERATK2_5 {SPR_BLSR, 0, 0, A_ReFire, S_BLASTERREADY, 0, 0}, // S_BLASTERATK2_6 {SPR_ACLO, 4, 200, NULL, S_BLASTERFX1_1, 0, 0}, // S_BLASTERFX1_1 {SPR_FX18, 32768, 3, A_SpawnRippers, S_BLASTERFXI1_2, 0, 0}, // S_BLASTERFXI1_1 {SPR_FX18, 32769, 3, NULL, S_BLASTERFXI1_3, 0, 0}, // S_BLASTERFXI1_2 {SPR_FX18, 32770, 4, NULL, S_BLASTERFXI1_4, 0, 0}, // S_BLASTERFXI1_3 {SPR_FX18, 32771, 4, NULL, S_BLASTERFXI1_5, 0, 0}, // S_BLASTERFXI1_4 {SPR_FX18, 32772, 4, NULL, S_BLASTERFXI1_6, 0, 0}, // S_BLASTERFXI1_5 {SPR_FX18, 32773, 4, NULL, S_BLASTERFXI1_7, 0, 0}, // S_BLASTERFXI1_6 {SPR_FX18, 32774, 4, NULL, S_NULL, 0, 0}, // S_BLASTERFXI1_7 {SPR_FX18, 7, 4, NULL, S_BLASTERSMOKE2, 0, 0}, // S_BLASTERSMOKE1 {SPR_FX18, 8, 4, NULL, S_BLASTERSMOKE3, 0, 0}, // S_BLASTERSMOKE2 {SPR_FX18, 9, 4, NULL, S_BLASTERSMOKE4, 0, 0}, // S_BLASTERSMOKE3 {SPR_FX18, 10, 4, NULL, S_BLASTERSMOKE5, 0, 0}, // S_BLASTERSMOKE4 {SPR_FX18, 11, 4, NULL, S_NULL, 0, 0}, // S_BLASTERSMOKE5 {SPR_FX18, 12, 4, NULL, S_RIPPER2, 0, 0}, // S_RIPPER1 {SPR_FX18, 13, 5, NULL, S_RIPPER1, 0, 0}, // S_RIPPER2 {SPR_FX18, 32782, 4, NULL, S_RIPPERX2, 0, 0}, // S_RIPPERX1 {SPR_FX18, 32783, 4, NULL, S_RIPPERX3, 0, 0}, // S_RIPPERX2 {SPR_FX18, 32784, 4, NULL, S_RIPPERX4, 0, 0}, // S_RIPPERX3 {SPR_FX18, 32785, 4, NULL, S_RIPPERX5, 0, 0}, // S_RIPPERX4 {SPR_FX18, 32786, 4, NULL, S_NULL, 0, 0}, // S_RIPPERX5 {SPR_FX17, 32768, 4, NULL, S_BLASTERPUFF1_2, 0, 0}, // S_BLASTERPUFF1_1 {SPR_FX17, 32769, 4, NULL, S_BLASTERPUFF1_3, 0, 0}, // S_BLASTERPUFF1_2 {SPR_FX17, 32770, 4, NULL, S_BLASTERPUFF1_4, 0, 0}, // S_BLASTERPUFF1_3 {SPR_FX17, 32771, 4, NULL, S_BLASTERPUFF1_5, 0, 0}, // S_BLASTERPUFF1_4 {SPR_FX17, 32772, 4, NULL, S_NULL, 0, 0}, // S_BLASTERPUFF1_5 {SPR_FX17, 32773, 3, NULL, S_BLASTERPUFF2_2, 0, 0}, // S_BLASTERPUFF2_1 {SPR_FX17, 32774, 3, NULL, S_BLASTERPUFF2_3, 0, 0}, // S_BLASTERPUFF2_2 {SPR_FX17, 32775, 4, NULL, S_BLASTERPUFF2_4, 0, 0}, // S_BLASTERPUFF2_3 {SPR_FX17, 32776, 4, NULL, S_BLASTERPUFF2_5, 0, 0}, // S_BLASTERPUFF2_4 {SPR_FX17, 32777, 4, NULL, S_BLASTERPUFF2_6, 0, 0}, // S_BLASTERPUFF2_5 {SPR_FX17, 32778, 4, NULL, S_BLASTERPUFF2_7, 0, 0}, // S_BLASTERPUFF2_6 {SPR_FX17, 32779, 4, NULL, S_NULL, 0, 0}, // S_BLASTERPUFF2_7 {SPR_WMCE, 0, -1, NULL, S_NULL, 0, 0}, // S_WMCE {SPR_MACE, 0, 1, A_WeaponReady, S_MACEREADY, 0, 0}, // S_MACEREADY {SPR_MACE, 0, 1, A_Lower, S_MACEDOWN, 0, 0}, // S_MACEDOWN {SPR_MACE, 0, 1, A_Raise, S_MACEUP, 0, 0}, // S_MACEUP {SPR_MACE, 1, 4, NULL, S_MACEATK1_2, 0, 0}, // S_MACEATK1_1 {SPR_MACE, 2, 3, A_FireMacePL1, S_MACEATK1_3, 0, 0}, // S_MACEATK1_2 {SPR_MACE, 3, 3, A_FireMacePL1, S_MACEATK1_4, 0, 0}, // S_MACEATK1_3 {SPR_MACE, 4, 3, A_FireMacePL1, S_MACEATK1_5, 0, 0}, // S_MACEATK1_4 {SPR_MACE, 5, 3, A_FireMacePL1, S_MACEATK1_6, 0, 0}, // S_MACEATK1_5 {SPR_MACE, 2, 4, A_ReFire, S_MACEATK1_7, 0, 0}, // S_MACEATK1_6 {SPR_MACE, 3, 4, NULL, S_MACEATK1_8, 0, 0}, // S_MACEATK1_7 {SPR_MACE, 4, 4, NULL, S_MACEATK1_9, 0, 0}, // S_MACEATK1_8 {SPR_MACE, 5, 4, NULL, S_MACEATK1_10, 0, 0}, // S_MACEATK1_9 {SPR_MACE, 1, 4, NULL, S_MACEREADY, 0, 0}, // S_MACEATK1_10 {SPR_MACE, 1, 4, NULL, S_MACEATK2_2, 0, 0}, // S_MACEATK2_1 {SPR_MACE, 3, 4, A_FireMacePL2, S_MACEATK2_3, 0, 0}, // S_MACEATK2_2 {SPR_MACE, 1, 4, NULL, S_MACEATK2_4, 0, 0}, // S_MACEATK2_3 {SPR_MACE, 0, 8, A_ReFire, S_MACEREADY, 0, 0}, // S_MACEATK2_4 {SPR_FX02, 0, 4, A_MacePL1Check, S_MACEFX1_2, 0, 0}, // S_MACEFX1_1 {SPR_FX02, 1, 4, A_MacePL1Check, S_MACEFX1_1, 0, 0}, // S_MACEFX1_2 {SPR_FX02, 32773, 4, A_MaceBallImpact, S_MACEFXI1_2, 0, 0}, // S_MACEFXI1_1 {SPR_FX02, 32774, 4, NULL, S_MACEFXI1_3, 0, 0}, // S_MACEFXI1_2 {SPR_FX02, 32775, 4, NULL, S_MACEFXI1_4, 0, 0}, // S_MACEFXI1_3 {SPR_FX02, 32776, 4, NULL, S_MACEFXI1_5, 0, 0}, // S_MACEFXI1_4 {SPR_FX02, 32777, 4, NULL, S_NULL, 0, 0}, // S_MACEFXI1_5 {SPR_FX02, 2, 4, NULL, S_MACEFX2_2, 0, 0}, // S_MACEFX2_1 {SPR_FX02, 3, 4, NULL, S_MACEFX2_1, 0, 0}, // S_MACEFX2_2 {SPR_FX02, 32773, 4, A_MaceBallImpact2, S_MACEFXI1_2, 0, 0}, // S_MACEFXI2_1 {SPR_FX02, 0, 4, NULL, S_MACEFX3_2, 0, 0}, // S_MACEFX3_1 {SPR_FX02, 1, 4, NULL, S_MACEFX3_1, 0, 0}, // S_MACEFX3_2 {SPR_FX02, 4, 99, NULL, S_MACEFX4_1, 0, 0}, // S_MACEFX4_1 {SPR_FX02, 32770, 4, A_DeathBallImpact, S_MACEFXI1_2, 0, 0}, // S_MACEFXI4_1 {SPR_WSKL, 0, -1, NULL, S_NULL, 0, 0}, // S_WSKL {SPR_HROD, 0, 1, A_WeaponReady, S_HORNRODREADY, 0, 0}, // S_HORNRODREADY {SPR_HROD, 0, 1, A_Lower, S_HORNRODDOWN, 0, 0}, // S_HORNRODDOWN {SPR_HROD, 0, 1, A_Raise, S_HORNRODUP, 0, 0}, // S_HORNRODUP {SPR_HROD, 0, 4, A_FireSkullRodPL1, S_HORNRODATK1_2, 0, 0}, // S_HORNRODATK1_1 {SPR_HROD, 1, 4, A_FireSkullRodPL1, S_HORNRODATK1_3, 0, 0}, // S_HORNRODATK1_2 {SPR_HROD, 1, 0, A_ReFire, S_HORNRODREADY, 0, 0}, // S_HORNRODATK1_3 {SPR_HROD, 2, 2, NULL, S_HORNRODATK2_2, 0, 0}, // S_HORNRODATK2_1 {SPR_HROD, 3, 3, NULL, S_HORNRODATK2_3, 0, 0}, // S_HORNRODATK2_2 {SPR_HROD, 4, 2, NULL, S_HORNRODATK2_4, 0, 0}, // S_HORNRODATK2_3 {SPR_HROD, 5, 3, NULL, S_HORNRODATK2_5, 0, 0}, // S_HORNRODATK2_4 {SPR_HROD, 6, 4, A_FireSkullRodPL2, S_HORNRODATK2_6, 0, 0}, // S_HORNRODATK2_5 {SPR_HROD, 5, 2, NULL, S_HORNRODATK2_7, 0, 0}, // S_HORNRODATK2_6 {SPR_HROD, 4, 3, NULL, S_HORNRODATK2_8, 0, 0}, // S_HORNRODATK2_7 {SPR_HROD, 3, 2, NULL, S_HORNRODATK2_9, 0, 0}, // S_HORNRODATK2_8 {SPR_HROD, 2, 2, A_ReFire, S_HORNRODREADY, 0, 0}, // S_HORNRODATK2_9 {SPR_FX00, 32768, 6, NULL, S_HRODFX1_2, 0, 0}, // S_HRODFX1_1 {SPR_FX00, 32769, 6, NULL, S_HRODFX1_1, 0, 0}, // S_HRODFX1_2 {SPR_FX00, 32775, 5, NULL, S_HRODFXI1_2, 0, 0}, // S_HRODFXI1_1 {SPR_FX00, 32776, 5, NULL, S_HRODFXI1_3, 0, 0}, // S_HRODFXI1_2 {SPR_FX00, 32777, 4, NULL, S_HRODFXI1_4, 0, 0}, // S_HRODFXI1_3 {SPR_FX00, 32778, 4, NULL, S_HRODFXI1_5, 0, 0}, // S_HRODFXI1_4 {SPR_FX00, 32779, 3, NULL, S_HRODFXI1_6, 0, 0}, // S_HRODFXI1_5 {SPR_FX00, 32780, 3, NULL, S_NULL, 0, 0}, // S_HRODFXI1_6 {SPR_FX00, 32770, 3, NULL, S_HRODFX2_2, 0, 0}, // S_HRODFX2_1 {SPR_FX00, 32771, 3, A_SkullRodPL2Seek, S_HRODFX2_3, 0, 0}, // S_HRODFX2_2 {SPR_FX00, 32772, 3, NULL, S_HRODFX2_4, 0, 0}, // S_HRODFX2_3 {SPR_FX00, 32773, 3, A_SkullRodPL2Seek, S_HRODFX2_1, 0, 0}, // S_HRODFX2_4 {SPR_FX00, 32775, 5, A_AddPlayerRain, S_HRODFXI2_2, 0, 0}, // S_HRODFXI2_1 {SPR_FX00, 32776, 5, NULL, S_HRODFXI2_3, 0, 0}, // S_HRODFXI2_2 {SPR_FX00, 32777, 4, NULL, S_HRODFXI2_4, 0, 0}, // S_HRODFXI2_3 {SPR_FX00, 32778, 3, NULL, S_HRODFXI2_5, 0, 0}, // S_HRODFXI2_4 {SPR_FX00, 32779, 3, NULL, S_HRODFXI2_6, 0, 0}, // S_HRODFXI2_5 {SPR_FX00, 32780, 3, NULL, S_HRODFXI2_7, 0, 0}, // S_HRODFXI2_6 {SPR_FX00, 6, 1, A_HideInCeiling, S_HRODFXI2_8, 0, 0}, // S_HRODFXI2_7 {SPR_FX00, 6, 1, A_SkullRodStorm, S_HRODFXI2_8, 0, 0}, // S_HRODFXI2_8 {SPR_FX20, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR1_1 {SPR_FX21, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR2_1 {SPR_FX22, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR3_1 {SPR_FX23, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR4_1 {SPR_FX20, 32769, 4, A_RainImpact, S_RAINPLR1X_2, 0, 0}, // S_RAINPLR1X_1 {SPR_FX20, 32770, 4, NULL, S_RAINPLR1X_3, 0, 0}, // S_RAINPLR1X_2 {SPR_FX20, 32771, 4, NULL, S_RAINPLR1X_4, 0, 0}, // S_RAINPLR1X_3 {SPR_FX20, 32772, 4, NULL, S_RAINPLR1X_5, 0, 0}, // S_RAINPLR1X_4 {SPR_FX20, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR1X_5 {SPR_FX21, 32769, 4, A_RainImpact, S_RAINPLR2X_2, 0, 0}, // S_RAINPLR2X_1 {SPR_FX21, 32770, 4, NULL, S_RAINPLR2X_3, 0, 0}, // S_RAINPLR2X_2 {SPR_FX21, 32771, 4, NULL, S_RAINPLR2X_4, 0, 0}, // S_RAINPLR2X_3 {SPR_FX21, 32772, 4, NULL, S_RAINPLR2X_5, 0, 0}, // S_RAINPLR2X_4 {SPR_FX21, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR2X_5 {SPR_FX22, 32769, 4, A_RainImpact, S_RAINPLR3X_2, 0, 0}, // S_RAINPLR3X_1 {SPR_FX22, 32770, 4, NULL, S_RAINPLR3X_3, 0, 0}, // S_RAINPLR3X_2 {SPR_FX22, 32771, 4, NULL, S_RAINPLR3X_4, 0, 0}, // S_RAINPLR3X_3 {SPR_FX22, 32772, 4, NULL, S_RAINPLR3X_5, 0, 0}, // S_RAINPLR3X_4 {SPR_FX22, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR3X_5 {SPR_FX23, 32769, 4, A_RainImpact, S_RAINPLR4X_2, 0, 0}, // S_RAINPLR4X_1 {SPR_FX23, 32770, 4, NULL, S_RAINPLR4X_3, 0, 0}, // S_RAINPLR4X_2 {SPR_FX23, 32771, 4, NULL, S_RAINPLR4X_4, 0, 0}, // S_RAINPLR4X_3 {SPR_FX23, 32772, 4, NULL, S_RAINPLR4X_5, 0, 0}, // S_RAINPLR4X_4 {SPR_FX23, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR4X_5 {SPR_FX20, 32774, 4, NULL, S_RAINAIRXPLR1_2, 0, 0}, // S_RAINAIRXPLR1_1 {SPR_FX21, 32774, 4, NULL, S_RAINAIRXPLR2_2, 0, 0}, // S_RAINAIRXPLR2_1 {SPR_FX22, 32774, 4, NULL, S_RAINAIRXPLR3_2, 0, 0}, // S_RAINAIRXPLR3_1 {SPR_FX23, 32774, 4, NULL, S_RAINAIRXPLR4_2, 0, 0}, // S_RAINAIRXPLR4_1 {SPR_FX20, 32775, 4, NULL, S_RAINAIRXPLR1_3, 0, 0}, // S_RAINAIRXPLR1_2 {SPR_FX21, 32775, 4, NULL, S_RAINAIRXPLR2_3, 0, 0}, // S_RAINAIRXPLR2_2 {SPR_FX22, 32775, 4, NULL, S_RAINAIRXPLR3_3, 0, 0}, // S_RAINAIRXPLR3_2 {SPR_FX23, 32775, 4, NULL, S_RAINAIRXPLR4_3, 0, 0}, // S_RAINAIRXPLR4_2 {SPR_FX20, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR1_3 {SPR_FX21, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR2_3 {SPR_FX22, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR3_3 {SPR_FX23, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR4_3 {SPR_GWND, 0, 1, A_WeaponReady, S_GOLDWANDREADY, 0, 0}, // S_GOLDWANDREADY {SPR_GWND, 0, 1, A_Lower, S_GOLDWANDDOWN, 0, 0}, // S_GOLDWANDDOWN {SPR_GWND, 0, 1, A_Raise, S_GOLDWANDUP, 0, 0}, // S_GOLDWANDUP {SPR_GWND, 1, 3, NULL, S_GOLDWANDATK1_2, 0, 0}, // S_GOLDWANDATK1_1 {SPR_GWND, 2, 5, A_FireGoldWandPL1, S_GOLDWANDATK1_3, 0, 0}, // S_GOLDWANDATK1_2 {SPR_GWND, 3, 3, NULL, S_GOLDWANDATK1_4, 0, 0}, // S_GOLDWANDATK1_3 {SPR_GWND, 3, 0, A_ReFire, S_GOLDWANDREADY, 0, 0}, // S_GOLDWANDATK1_4 {SPR_GWND, 1, 3, NULL, S_GOLDWANDATK2_2, 0, 0}, // S_GOLDWANDATK2_1 {SPR_GWND, 2, 4, A_FireGoldWandPL2, S_GOLDWANDATK2_3, 0, 0}, // S_GOLDWANDATK2_2 {SPR_GWND, 3, 3, NULL, S_GOLDWANDATK2_4, 0, 0}, // S_GOLDWANDATK2_3 {SPR_GWND, 3, 0, A_ReFire, S_GOLDWANDREADY, 0, 0}, // S_GOLDWANDATK2_4 {SPR_FX01, 32768, 6, NULL, S_GWANDFX1_2, 0, 0}, // S_GWANDFX1_1 {SPR_FX01, 32769, 6, NULL, S_GWANDFX1_1, 0, 0}, // S_GWANDFX1_2 {SPR_FX01, 32772, 3, NULL, S_GWANDFXI1_2, 0, 0}, // S_GWANDFXI1_1 {SPR_FX01, 32773, 3, NULL, S_GWANDFXI1_3, 0, 0}, // S_GWANDFXI1_2 {SPR_FX01, 32774, 3, NULL, S_GWANDFXI1_4, 0, 0}, // S_GWANDFXI1_3 {SPR_FX01, 32775, 3, NULL, S_NULL, 0, 0}, // S_GWANDFXI1_4 {SPR_FX01, 32770, 6, NULL, S_GWANDFX2_2, 0, 0}, // S_GWANDFX2_1 {SPR_FX01, 32771, 6, NULL, S_GWANDFX2_1, 0, 0}, // S_GWANDFX2_2 {SPR_PUF2, 32768, 3, NULL, S_GWANDPUFF1_2, 0, 0}, // S_GWANDPUFF1_1 {SPR_PUF2, 32769, 3, NULL, S_GWANDPUFF1_3, 0, 0}, // S_GWANDPUFF1_2 {SPR_PUF2, 32770, 3, NULL, S_GWANDPUFF1_4, 0, 0}, // S_GWANDPUFF1_3 {SPR_PUF2, 32771, 3, NULL, S_GWANDPUFF1_5, 0, 0}, // S_GWANDPUFF1_4 {SPR_PUF2, 32772, 3, NULL, S_NULL, 0, 0}, // S_GWANDPUFF1_5 {SPR_WPHX, 0, -1, NULL, S_NULL, 0, 0}, // S_WPHX {SPR_PHNX, 0, 1, A_WeaponReady, S_PHOENIXREADY, 0, 0}, // S_PHOENIXREADY {SPR_PHNX, 0, 1, A_Lower, S_PHOENIXDOWN, 0, 0}, // S_PHOENIXDOWN {SPR_PHNX, 0, 1, A_Raise, S_PHOENIXUP, 0, 0}, // S_PHOENIXUP {SPR_PHNX, 1, 5, NULL, S_PHOENIXATK1_2, 0, 0}, // S_PHOENIXATK1_1 {SPR_PHNX, 2, 7, A_FirePhoenixPL1, S_PHOENIXATK1_3, 0, 0}, // S_PHOENIXATK1_2 {SPR_PHNX, 3, 4, NULL, S_PHOENIXATK1_4, 0, 0}, // S_PHOENIXATK1_3 {SPR_PHNX, 1, 4, NULL, S_PHOENIXATK1_5, 0, 0}, // S_PHOENIXATK1_4 {SPR_PHNX, 1, 0, A_ReFire, S_PHOENIXREADY, 0, 0}, // S_PHOENIXATK1_5 {SPR_PHNX, 1, 3, A_InitPhoenixPL2, S_PHOENIXATK2_2, 0, 0}, // S_PHOENIXATK2_1 {SPR_PHNX, 32770, 1, A_FirePhoenixPL2, S_PHOENIXATK2_3, 0, 0}, // S_PHOENIXATK2_2 {SPR_PHNX, 1, 4, A_ReFire, S_PHOENIXATK2_4, 0, 0}, // S_PHOENIXATK2_3 {SPR_PHNX, 1, 4, A_ShutdownPhoenixPL2, S_PHOENIXREADY, 0, 0}, // S_PHOENIXATK2_4 {SPR_FX04, 32768, 4, A_PhoenixPuff, S_PHOENIXFX1_1, 0, 0}, // S_PHOENIXFX1_1 {SPR_FX08, 32768, 6, A_Explode, S_PHOENIXFXI1_2, 0, 0}, // S_PHOENIXFXI1_1 {SPR_FX08, 32769, 5, NULL, S_PHOENIXFXI1_3, 0, 0}, // S_PHOENIXFXI1_2 {SPR_FX08, 32770, 5, NULL, S_PHOENIXFXI1_4, 0, 0}, // S_PHOENIXFXI1_3 {SPR_FX08, 32771, 4, NULL, S_PHOENIXFXI1_5, 0, 0}, // S_PHOENIXFXI1_4 {SPR_FX08, 32772, 4, NULL, S_PHOENIXFXI1_6, 0, 0}, // S_PHOENIXFXI1_5 {SPR_FX08, 32773, 4, NULL, S_PHOENIXFXI1_7, 0, 0}, // S_PHOENIXFXI1_6 {SPR_FX08, 32774, 4, NULL, S_PHOENIXFXI1_8, 0, 0}, // S_PHOENIXFXI1_7 {SPR_FX08, 32775, 4, NULL, S_NULL, 0, 0}, // S_PHOENIXFXI1_8 {SPR_FX08, 32776, 8, NULL, S_PHOENIXFXIX_1, 0, 0 }, // S_PHOENIXFXIX_1 {SPR_FX08, 32777, 8, A_RemovedPhoenixFunc, S_PHOENIXFXIX_2, 0, 0 }, // S_PHOENIXFXIX_2 {SPR_FX08, 32778, 8, NULL, S_NULL, 0, 0 }, // S_PHOENIXFXIX_3 {SPR_FX04, 1, 4, NULL, S_PHOENIXPUFF2, 0, 0}, // S_PHOENIXPUFF1 {SPR_FX04, 2, 4, NULL, S_PHOENIXPUFF3, 0, 0}, // S_PHOENIXPUFF2 {SPR_FX04, 3, 4, NULL, S_PHOENIXPUFF4, 0, 0}, // S_PHOENIXPUFF3 {SPR_FX04, 4, 4, NULL, S_PHOENIXPUFF5, 0, 0}, // S_PHOENIXPUFF4 {SPR_FX04, 5, 4, NULL, S_NULL, 0, 0}, // S_PHOENIXPUFF5 {SPR_FX09, 32768, 2, NULL, S_PHOENIXFX2_2, 0, 0}, // S_PHOENIXFX2_1 {SPR_FX09, 32769, 2, NULL, S_PHOENIXFX2_3, 0, 0}, // S_PHOENIXFX2_2 {SPR_FX09, 32768, 2, NULL, S_PHOENIXFX2_4, 0, 0}, // S_PHOENIXFX2_3 {SPR_FX09, 32769, 2, NULL, S_PHOENIXFX2_5, 0, 0}, // S_PHOENIXFX2_4 {SPR_FX09, 32768, 2, NULL, S_PHOENIXFX2_6, 0, 0}, // S_PHOENIXFX2_5 {SPR_FX09, 32769, 2, A_FlameEnd, S_PHOENIXFX2_7, 0, 0}, // S_PHOENIXFX2_6 {SPR_FX09, 32770, 2, NULL, S_PHOENIXFX2_8, 0, 0}, // S_PHOENIXFX2_7 {SPR_FX09, 32771, 2, NULL, S_PHOENIXFX2_9, 0, 0}, // S_PHOENIXFX2_8 {SPR_FX09, 32772, 2, NULL, S_PHOENIXFX2_10, 0, 0}, // S_PHOENIXFX2_9 {SPR_FX09, 32773, 2, NULL, S_NULL, 0, 0}, // S_PHOENIXFX2_10 {SPR_FX09, 32774, 3, NULL, S_PHOENIXFXI2_2, 0, 0}, // S_PHOENIXFXI2_1 {SPR_FX09, 32775, 3, A_FloatPuff, S_PHOENIXFXI2_3, 0, 0}, // S_PHOENIXFXI2_2 {SPR_FX09, 32776, 4, NULL, S_PHOENIXFXI2_4, 0, 0}, // S_PHOENIXFXI2_3 {SPR_FX09, 32777, 5, NULL, S_PHOENIXFXI2_5, 0, 0}, // S_PHOENIXFXI2_4 {SPR_FX09, 32778, 5, NULL, S_NULL, 0, 0}, // S_PHOENIXFXI2_5 {SPR_WBOW, 0, -1, NULL, S_NULL, 0, 0}, // S_WBOW {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW2, 0, 0}, // S_CRBOW1 {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW3, 0, 0}, // S_CRBOW2 {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW4, 0, 0}, // S_CRBOW3 {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW5, 0, 0}, // S_CRBOW4 {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW6, 0, 0}, // S_CRBOW5 {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW7, 0, 0}, // S_CRBOW6 {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW8, 0, 0}, // S_CRBOW7 {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW9, 0, 0}, // S_CRBOW8 {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW10, 0, 0}, // S_CRBOW9 {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW11, 0, 0}, // S_CRBOW10 {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW12, 0, 0}, // S_CRBOW11 {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW13, 0, 0}, // S_CRBOW12 {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW14, 0, 0}, // S_CRBOW13 {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW15, 0, 0}, // S_CRBOW14 {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW16, 0, 0}, // S_CRBOW15 {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW17, 0, 0}, // S_CRBOW16 {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW18, 0, 0}, // S_CRBOW17 {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW1, 0, 0}, // S_CRBOW18 {SPR_CRBW, 0, 1, A_Lower, S_CRBOWDOWN, 0, 0}, // S_CRBOWDOWN {SPR_CRBW, 0, 1, A_Raise, S_CRBOWUP, 0, 0}, // S_CRBOWUP {SPR_CRBW, 3, 6, A_FireCrossbowPL1, S_CRBOWATK1_2, 0, 0}, // S_CRBOWATK1_1 {SPR_CRBW, 4, 3, NULL, S_CRBOWATK1_3, 0, 0}, // S_CRBOWATK1_2 {SPR_CRBW, 5, 3, NULL, S_CRBOWATK1_4, 0, 0}, // S_CRBOWATK1_3 {SPR_CRBW, 6, 3, NULL, S_CRBOWATK1_5, 0, 0}, // S_CRBOWATK1_4 {SPR_CRBW, 7, 3, NULL, S_CRBOWATK1_6, 0, 0}, // S_CRBOWATK1_5 {SPR_CRBW, 0, 4, NULL, S_CRBOWATK1_7, 0, 0}, // S_CRBOWATK1_6 {SPR_CRBW, 1, 4, NULL, S_CRBOWATK1_8, 0, 0}, // S_CRBOWATK1_7 {SPR_CRBW, 2, 5, A_ReFire, S_CRBOW1, 0, 0}, // S_CRBOWATK1_8 {SPR_CRBW, 3, 5, A_FireCrossbowPL2, S_CRBOWATK2_2, 0, 0}, // S_CRBOWATK2_1 {SPR_CRBW, 4, 3, NULL, S_CRBOWATK2_3, 0, 0}, // S_CRBOWATK2_2 {SPR_CRBW, 5, 2, NULL, S_CRBOWATK2_4, 0, 0}, // S_CRBOWATK2_3 {SPR_CRBW, 6, 3, NULL, S_CRBOWATK2_5, 0, 0}, // S_CRBOWATK2_4 {SPR_CRBW, 7, 2, NULL, S_CRBOWATK2_6, 0, 0}, // S_CRBOWATK2_5 {SPR_CRBW, 0, 3, NULL, S_CRBOWATK2_7, 0, 0}, // S_CRBOWATK2_6 {SPR_CRBW, 1, 3, NULL, S_CRBOWATK2_8, 0, 0}, // S_CRBOWATK2_7 {SPR_CRBW, 2, 4, A_ReFire, S_CRBOW1, 0, 0}, // S_CRBOWATK2_8 {SPR_FX03, 32769, 1, NULL, S_CRBOWFX1, 0, 0}, // S_CRBOWFX1 {SPR_FX03, 32775, 8, NULL, S_CRBOWFXI1_2, 0, 0}, // S_CRBOWFXI1_1 {SPR_FX03, 32776, 8, NULL, S_CRBOWFXI1_3, 0, 0}, // S_CRBOWFXI1_2 {SPR_FX03, 32777, 8, NULL, S_NULL, 0, 0}, // S_CRBOWFXI1_3 {SPR_FX03, 32769, 1, A_BoltSpark, S_CRBOWFX2, 0, 0}, // S_CRBOWFX2 {SPR_FX03, 32768, 1, NULL, S_CRBOWFX3, 0, 0}, // S_CRBOWFX3 {SPR_FX03, 32770, 8, NULL, S_CRBOWFXI3_2, 0, 0}, // S_CRBOWFXI3_1 {SPR_FX03, 32771, 8, NULL, S_CRBOWFXI3_3, 0, 0}, // S_CRBOWFXI3_2 {SPR_FX03, 32772, 8, NULL, S_NULL, 0, 0}, // S_CRBOWFXI3_3 {SPR_FX03, 32773, 8, NULL, S_CRBOWFX4_2, 0, 0}, // S_CRBOWFX4_1 {SPR_FX03, 32774, 8, NULL, S_NULL, 0, 0}, // S_CRBOWFX4_2 {SPR_BLOD, 2, 8, NULL, S_BLOOD2, 0, 0}, // S_BLOOD1 {SPR_BLOD, 1, 8, NULL, S_BLOOD3, 0, 0}, // S_BLOOD2 {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOOD3 {SPR_BLOD, 2, 8, NULL, S_BLOODSPLATTER2, 0, 0}, // S_BLOODSPLATTER1 {SPR_BLOD, 1, 8, NULL, S_BLOODSPLATTER3, 0, 0}, // S_BLOODSPLATTER2 {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTER3 {SPR_BLOD, 0, 6, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTERX {SPR_PLAY, 0, -1, NULL, S_NULL, 0, 0}, // S_PLAY {SPR_PLAY, 0, 4, NULL, S_PLAY_RUN2, 0, 0}, // S_PLAY_RUN1 {SPR_PLAY, 1, 4, NULL, S_PLAY_RUN3, 0, 0}, // S_PLAY_RUN2 {SPR_PLAY, 2, 4, NULL, S_PLAY_RUN4, 0, 0}, // S_PLAY_RUN3 {SPR_PLAY, 3, 4, NULL, S_PLAY_RUN1, 0, 0}, // S_PLAY_RUN4 {SPR_PLAY, 4, 12, NULL, S_PLAY, 0, 0}, // S_PLAY_ATK1 {SPR_PLAY, 32773, 6, NULL, S_PLAY_ATK1, 0, 0}, // S_PLAY_ATK2 {SPR_PLAY, 6, 4, NULL, S_PLAY_PAIN2, 0, 0}, // S_PLAY_PAIN {SPR_PLAY, 6, 4, A_Pain, S_PLAY, 0, 0}, // S_PLAY_PAIN2 {SPR_PLAY, 7, 6, NULL, S_PLAY_DIE2, 0, 0}, // S_PLAY_DIE1 {SPR_PLAY, 8, 6, A_Scream, S_PLAY_DIE3, 0, 0}, // S_PLAY_DIE2 {SPR_PLAY, 9, 6, NULL, S_PLAY_DIE4, 0, 0}, // S_PLAY_DIE3 {SPR_PLAY, 10, 6, NULL, S_PLAY_DIE5, 0, 0}, // S_PLAY_DIE4 {SPR_PLAY, 11, 6, A_NoBlocking, S_PLAY_DIE6, 0, 0}, // S_PLAY_DIE5 {SPR_PLAY, 12, 6, NULL, S_PLAY_DIE7, 0, 0}, // S_PLAY_DIE6 {SPR_PLAY, 13, 6, NULL, S_PLAY_DIE8, 0, 0}, // S_PLAY_DIE7 {SPR_PLAY, 14, 6, NULL, S_PLAY_DIE9, 0, 0}, // S_PLAY_DIE8 {SPR_PLAY, 15, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_PLAY_DIE9 {SPR_PLAY, 16, 5, A_Scream, S_PLAY_XDIE2, 0, 0}, // S_PLAY_XDIE1 {SPR_PLAY, 17, 5, A_SkullPop, S_PLAY_XDIE3, 0, 0}, // S_PLAY_XDIE2 {SPR_PLAY, 18, 5, A_NoBlocking, S_PLAY_XDIE4, 0, 0}, // S_PLAY_XDIE3 {SPR_PLAY, 19, 5, NULL, S_PLAY_XDIE5, 0, 0}, // S_PLAY_XDIE4 {SPR_PLAY, 20, 5, NULL, S_PLAY_XDIE6, 0, 0}, // S_PLAY_XDIE5 {SPR_PLAY, 21, 5, NULL, S_PLAY_XDIE7, 0, 0}, // S_PLAY_XDIE6 {SPR_PLAY, 22, 5, NULL, S_PLAY_XDIE8, 0, 0}, // S_PLAY_XDIE7 {SPR_PLAY, 23, 5, NULL, S_PLAY_XDIE9, 0, 0}, // S_PLAY_XDIE8 {SPR_PLAY, 24, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_PLAY_XDIE9 {SPR_FDTH, 32768, 5, A_FlameSnd, S_PLAY_FDTH2, 0, 0}, // S_PLAY_FDTH1 {SPR_FDTH, 32769, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_FDTH2 {SPR_FDTH, 32770, 5, NULL, S_PLAY_FDTH4, 0, 0}, // S_PLAY_FDTH3 {SPR_FDTH, 32771, 4, A_Scream, S_PLAY_FDTH5, 0, 0}, // S_PLAY_FDTH4 {SPR_FDTH, 32772, 5, NULL, S_PLAY_FDTH6, 0, 0}, // S_PLAY_FDTH5 {SPR_FDTH, 32773, 4, NULL, S_PLAY_FDTH7, 0, 0}, // S_PLAY_FDTH6 {SPR_FDTH, 32774, 5, A_FlameSnd, S_PLAY_FDTH8, 0, 0}, // S_PLAY_FDTH7 {SPR_FDTH, 32775, 4, NULL, S_PLAY_FDTH9, 0, 0}, // S_PLAY_FDTH8 {SPR_FDTH, 32776, 5, NULL, S_PLAY_FDTH10, 0, 0}, // S_PLAY_FDTH9 {SPR_FDTH, 32777, 4, NULL, S_PLAY_FDTH11, 0, 0}, // S_PLAY_FDTH10 {SPR_FDTH, 32778, 5, NULL, S_PLAY_FDTH12, 0, 0}, // S_PLAY_FDTH11 {SPR_FDTH, 32779, 4, NULL, S_PLAY_FDTH13, 0, 0}, // S_PLAY_FDTH12 {SPR_FDTH, 32780, 5, NULL, S_PLAY_FDTH14, 0, 0}, // S_PLAY_FDTH13 {SPR_FDTH, 32781, 4, NULL, S_PLAY_FDTH15, 0, 0}, // S_PLAY_FDTH14 {SPR_FDTH, 32782, 5, A_NoBlocking, S_PLAY_FDTH16, 0, 0}, // S_PLAY_FDTH15 {SPR_FDTH, 32783, 4, NULL, S_PLAY_FDTH17, 0, 0}, // S_PLAY_FDTH16 {SPR_FDTH, 32784, 5, NULL, S_PLAY_FDTH18, 0, 0}, // S_PLAY_FDTH17 {SPR_FDTH, 32785, 4, NULL, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH18 {SPR_ACLO, 4, 35, A_CheckBurnGone, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH19 {SPR_ACLO, 4, 8, NULL, S_NULL, 0, 0}, // S_PLAY_FDTH20 {SPR_BSKL, 0, 5, A_CheckSkullFloor, S_BLOODYSKULL2, 0, 0}, // S_BLOODYSKULL1 {SPR_BSKL, 1, 5, A_CheckSkullFloor, S_BLOODYSKULL3, 0, 0}, // S_BLOODYSKULL2 {SPR_BSKL, 2, 5, A_CheckSkullFloor, S_BLOODYSKULL4, 0, 0}, // S_BLOODYSKULL3 {SPR_BSKL, 3, 5, A_CheckSkullFloor, S_BLOODYSKULL5, 0, 0}, // S_BLOODYSKULL4 {SPR_BSKL, 4, 5, A_CheckSkullFloor, S_BLOODYSKULL1, 0, 0}, // S_BLOODYSKULL5 {SPR_BSKL, 5, 16, A_CheckSkullDone, S_BLOODYSKULLX1, 0, 0}, // S_BLOODYSKULLX1 {SPR_BSKL, 5, 1050, NULL, S_NULL, 0, 0}, // S_BLOODYSKULLX2 {SPR_CHKN, 0, -1, NULL, S_NULL, 0, 0}, // S_CHICPLAY {SPR_CHKN, 0, 3, NULL, S_CHICPLAY_RUN2, 0, 0}, // S_CHICPLAY_RUN1 {SPR_CHKN, 1, 3, NULL, S_CHICPLAY_RUN3, 0, 0}, // S_CHICPLAY_RUN2 {SPR_CHKN, 0, 3, NULL, S_CHICPLAY_RUN4, 0, 0}, // S_CHICPLAY_RUN3 {SPR_CHKN, 1, 3, NULL, S_CHICPLAY_RUN1, 0, 0}, // S_CHICPLAY_RUN4 {SPR_CHKN, 2, 12, NULL, S_CHICPLAY, 0, 0}, // S_CHICPLAY_ATK1 {SPR_CHKN, 3, 4, A_Feathers, S_CHICPLAY_PAIN2, 0, 0}, // S_CHICPLAY_PAIN {SPR_CHKN, 2, 4, A_Pain, S_CHICPLAY, 0, 0}, // S_CHICPLAY_PAIN2 {SPR_CHKN, 0, 10, A_ChicLook, S_CHICKEN_LOOK2, 0, 0}, // S_CHICKEN_LOOK1 {SPR_CHKN, 1, 10, A_ChicLook, S_CHICKEN_LOOK1, 0, 0}, // S_CHICKEN_LOOK2 {SPR_CHKN, 0, 3, A_ChicChase, S_CHICKEN_WALK2, 0, 0}, // S_CHICKEN_WALK1 {SPR_CHKN, 1, 3, A_ChicChase, S_CHICKEN_WALK1, 0, 0}, // S_CHICKEN_WALK2 {SPR_CHKN, 3, 5, A_Feathers, S_CHICKEN_PAIN2, 0, 0}, // S_CHICKEN_PAIN1 {SPR_CHKN, 2, 5, A_ChicPain, S_CHICKEN_WALK1, 0, 0}, // S_CHICKEN_PAIN2 {SPR_CHKN, 0, 8, A_FaceTarget, S_CHICKEN_ATK2, 0, 0}, // S_CHICKEN_ATK1 {SPR_CHKN, 2, 10, A_ChicAttack, S_CHICKEN_WALK1, 0, 0}, // S_CHICKEN_ATK2 {SPR_CHKN, 4, 6, A_Scream, S_CHICKEN_DIE2, 0, 0}, // S_CHICKEN_DIE1 {SPR_CHKN, 5, 6, A_Feathers, S_CHICKEN_DIE3, 0, 0}, // S_CHICKEN_DIE2 {SPR_CHKN, 6, 6, NULL, S_CHICKEN_DIE4, 0, 0}, // S_CHICKEN_DIE3 {SPR_CHKN, 7, 6, A_NoBlocking, S_CHICKEN_DIE5, 0, 0}, // S_CHICKEN_DIE4 {SPR_CHKN, 8, 6, NULL, S_CHICKEN_DIE6, 0, 0}, // S_CHICKEN_DIE5 {SPR_CHKN, 9, 6, NULL, S_CHICKEN_DIE7, 0, 0}, // S_CHICKEN_DIE6 {SPR_CHKN, 10, 6, NULL, S_CHICKEN_DIE8, 0, 0}, // S_CHICKEN_DIE7 {SPR_CHKN, 11, -1, NULL, S_NULL, 0, 0}, // S_CHICKEN_DIE8 {SPR_CHKN, 12, 3, NULL, S_FEATHER2, 0, 0}, // S_FEATHER1 {SPR_CHKN, 13, 3, NULL, S_FEATHER3, 0, 0}, // S_FEATHER2 {SPR_CHKN, 14, 3, NULL, S_FEATHER4, 0, 0}, // S_FEATHER3 {SPR_CHKN, 15, 3, NULL, S_FEATHER5, 0, 0}, // S_FEATHER4 {SPR_CHKN, 16, 3, NULL, S_FEATHER6, 0, 0}, // S_FEATHER5 {SPR_CHKN, 15, 3, NULL, S_FEATHER7, 0, 0}, // S_FEATHER6 {SPR_CHKN, 14, 3, NULL, S_FEATHER8, 0, 0}, // S_FEATHER7 {SPR_CHKN, 13, 3, NULL, S_FEATHER1, 0, 0}, // S_FEATHER8 {SPR_CHKN, 13, 6, NULL, S_NULL, 0, 0}, // S_FEATHERX {SPR_MUMM, 0, 10, A_Look, S_MUMMY_LOOK2, 0, 0}, // S_MUMMY_LOOK1 {SPR_MUMM, 1, 10, A_Look, S_MUMMY_LOOK1, 0, 0}, // S_MUMMY_LOOK2 {SPR_MUMM, 0, 4, A_Chase, S_MUMMY_WALK2, 0, 0}, // S_MUMMY_WALK1 {SPR_MUMM, 1, 4, A_Chase, S_MUMMY_WALK3, 0, 0}, // S_MUMMY_WALK2 {SPR_MUMM, 2, 4, A_Chase, S_MUMMY_WALK4, 0, 0}, // S_MUMMY_WALK3 {SPR_MUMM, 3, 4, A_Chase, S_MUMMY_WALK1, 0, 0}, // S_MUMMY_WALK4 {SPR_MUMM, 4, 6, A_FaceTarget, S_MUMMY_ATK2, 0, 0}, // S_MUMMY_ATK1 {SPR_MUMM, 5, 6, A_MummyAttack, S_MUMMY_ATK3, 0, 0}, // S_MUMMY_ATK2 {SPR_MUMM, 6, 6, A_FaceTarget, S_MUMMY_WALK1, 0, 0}, // S_MUMMY_ATK3 {SPR_MUMM, 23, 5, A_FaceTarget, S_MUMMYL_ATK2, 0, 0}, // S_MUMMYL_ATK1 {SPR_MUMM, 32792, 5, A_FaceTarget, S_MUMMYL_ATK3, 0, 0}, // S_MUMMYL_ATK2 {SPR_MUMM, 23, 5, A_FaceTarget, S_MUMMYL_ATK4, 0, 0}, // S_MUMMYL_ATK3 {SPR_MUMM, 32792, 5, A_FaceTarget, S_MUMMYL_ATK5, 0, 0}, // S_MUMMYL_ATK4 {SPR_MUMM, 23, 5, A_FaceTarget, S_MUMMYL_ATK6, 0, 0}, // S_MUMMYL_ATK5 {SPR_MUMM, 32792, 15, A_MummyAttack2, S_MUMMY_WALK1, 0, 0}, // S_MUMMYL_ATK6 {SPR_MUMM, 7, 4, NULL, S_MUMMY_PAIN2, 0, 0}, // S_MUMMY_PAIN1 {SPR_MUMM, 7, 4, A_Pain, S_MUMMY_WALK1, 0, 0}, // S_MUMMY_PAIN2 {SPR_MUMM, 8, 5, NULL, S_MUMMY_DIE2, 0, 0}, // S_MUMMY_DIE1 {SPR_MUMM, 9, 5, A_Scream, S_MUMMY_DIE3, 0, 0}, // S_MUMMY_DIE2 {SPR_MUMM, 10, 5, A_MummySoul, S_MUMMY_DIE4, 0, 0}, // S_MUMMY_DIE3 {SPR_MUMM, 11, 5, NULL, S_MUMMY_DIE5, 0, 0}, // S_MUMMY_DIE4 {SPR_MUMM, 12, 5, A_NoBlocking, S_MUMMY_DIE6, 0, 0}, // S_MUMMY_DIE5 {SPR_MUMM, 13, 5, NULL, S_MUMMY_DIE7, 0, 0}, // S_MUMMY_DIE6 {SPR_MUMM, 14, 5, NULL, S_MUMMY_DIE8, 0, 0}, // S_MUMMY_DIE7 {SPR_MUMM, 15, -1, NULL, S_NULL, 0, 0}, // S_MUMMY_DIE8 {SPR_MUMM, 16, 5, NULL, S_MUMMY_SOUL2, 0, 0}, // S_MUMMY_SOUL1 {SPR_MUMM, 17, 5, NULL, S_MUMMY_SOUL3, 0, 0}, // S_MUMMY_SOUL2 {SPR_MUMM, 18, 5, NULL, S_MUMMY_SOUL4, 0, 0}, // S_MUMMY_SOUL3 {SPR_MUMM, 19, 9, NULL, S_MUMMY_SOUL5, 0, 0}, // S_MUMMY_SOUL4 {SPR_MUMM, 20, 5, NULL, S_MUMMY_SOUL6, 0, 0}, // S_MUMMY_SOUL5 {SPR_MUMM, 21, 5, NULL, S_MUMMY_SOUL7, 0, 0}, // S_MUMMY_SOUL6 {SPR_MUMM, 22, 5, NULL, S_NULL, 0, 0}, // S_MUMMY_SOUL7 {SPR_FX15, 32768, 5, A_ContMobjSound, S_MUMMYFX1_2, 0, 0}, // S_MUMMYFX1_1 {SPR_FX15, 32769, 5, A_MummyFX1Seek, S_MUMMYFX1_3, 0, 0}, // S_MUMMYFX1_2 {SPR_FX15, 32770, 5, NULL, S_MUMMYFX1_4, 0, 0}, // S_MUMMYFX1_3 {SPR_FX15, 32769, 5, A_MummyFX1Seek, S_MUMMYFX1_1, 0, 0}, // S_MUMMYFX1_4 {SPR_FX15, 32771, 5, NULL, S_MUMMYFXI1_2, 0, 0}, // S_MUMMYFXI1_1 {SPR_FX15, 32772, 5, NULL, S_MUMMYFXI1_3, 0, 0}, // S_MUMMYFXI1_2 {SPR_FX15, 32773, 5, NULL, S_MUMMYFXI1_4, 0, 0}, // S_MUMMYFXI1_3 {SPR_FX15, 32774, 5, NULL, S_NULL, 0, 0}, // S_MUMMYFXI1_4 {SPR_BEAS, 0, 10, A_Look, S_BEAST_LOOK2, 0, 0}, // S_BEAST_LOOK1 {SPR_BEAS, 1, 10, A_Look, S_BEAST_LOOK1, 0, 0}, // S_BEAST_LOOK2 {SPR_BEAS, 0, 3, A_Chase, S_BEAST_WALK2, 0, 0}, // S_BEAST_WALK1 {SPR_BEAS, 1, 3, A_Chase, S_BEAST_WALK3, 0, 0}, // S_BEAST_WALK2 {SPR_BEAS, 2, 3, A_Chase, S_BEAST_WALK4, 0, 0}, // S_BEAST_WALK3 {SPR_BEAS, 3, 3, A_Chase, S_BEAST_WALK5, 0, 0}, // S_BEAST_WALK4 {SPR_BEAS, 4, 3, A_Chase, S_BEAST_WALK6, 0, 0}, // S_BEAST_WALK5 {SPR_BEAS, 5, 3, A_Chase, S_BEAST_WALK1, 0, 0}, // S_BEAST_WALK6 {SPR_BEAS, 7, 10, A_FaceTarget, S_BEAST_ATK2, 0, 0}, // S_BEAST_ATK1 {SPR_BEAS, 8, 10, A_BeastAttack, S_BEAST_WALK1, 0, 0}, // S_BEAST_ATK2 {SPR_BEAS, 6, 3, NULL, S_BEAST_PAIN2, 0, 0}, // S_BEAST_PAIN1 {SPR_BEAS, 6, 3, A_Pain, S_BEAST_WALK1, 0, 0}, // S_BEAST_PAIN2 {SPR_BEAS, 17, 6, NULL, S_BEAST_DIE2, 0, 0}, // S_BEAST_DIE1 {SPR_BEAS, 18, 6, A_Scream, S_BEAST_DIE3, 0, 0}, // S_BEAST_DIE2 {SPR_BEAS, 19, 6, NULL, S_BEAST_DIE4, 0, 0}, // S_BEAST_DIE3 {SPR_BEAS, 20, 6, NULL, S_BEAST_DIE5, 0, 0}, // S_BEAST_DIE4 {SPR_BEAS, 21, 6, NULL, S_BEAST_DIE6, 0, 0}, // S_BEAST_DIE5 {SPR_BEAS, 22, 6, A_NoBlocking, S_BEAST_DIE7, 0, 0}, // S_BEAST_DIE6 {SPR_BEAS, 23, 6, NULL, S_BEAST_DIE8, 0, 0}, // S_BEAST_DIE7 {SPR_BEAS, 24, 6, NULL, S_BEAST_DIE9, 0, 0}, // S_BEAST_DIE8 {SPR_BEAS, 25, -1, NULL, S_NULL, 0, 0}, // S_BEAST_DIE9 {SPR_BEAS, 9, 5, NULL, S_BEAST_XDIE2, 0, 0}, // S_BEAST_XDIE1 {SPR_BEAS, 10, 6, A_Scream, S_BEAST_XDIE3, 0, 0}, // S_BEAST_XDIE2 {SPR_BEAS, 11, 5, NULL, S_BEAST_XDIE4, 0, 0}, // S_BEAST_XDIE3 {SPR_BEAS, 12, 6, NULL, S_BEAST_XDIE5, 0, 0}, // S_BEAST_XDIE4 {SPR_BEAS, 13, 5, NULL, S_BEAST_XDIE6, 0, 0}, // S_BEAST_XDIE5 {SPR_BEAS, 14, 6, A_NoBlocking, S_BEAST_XDIE7, 0, 0}, // S_BEAST_XDIE6 {SPR_BEAS, 15, 5, NULL, S_BEAST_XDIE8, 0, 0}, // S_BEAST_XDIE7 {SPR_BEAS, 16, -1, NULL, S_NULL, 0, 0}, // S_BEAST_XDIE8 {SPR_FRB1, 0, 2, A_BeastPuff, S_BEASTBALL2, 0, 0}, // S_BEASTBALL1 {SPR_FRB1, 0, 2, A_BeastPuff, S_BEASTBALL3, 0, 0}, // S_BEASTBALL2 {SPR_FRB1, 1, 2, A_BeastPuff, S_BEASTBALL4, 0, 0}, // S_BEASTBALL3 {SPR_FRB1, 1, 2, A_BeastPuff, S_BEASTBALL5, 0, 0}, // S_BEASTBALL4 {SPR_FRB1, 2, 2, A_BeastPuff, S_BEASTBALL6, 0, 0}, // S_BEASTBALL5 {SPR_FRB1, 2, 2, A_BeastPuff, S_BEASTBALL1, 0, 0}, // S_BEASTBALL6 {SPR_FRB1, 3, 4, NULL, S_BEASTBALLX2, 0, 0}, // S_BEASTBALLX1 {SPR_FRB1, 4, 4, NULL, S_BEASTBALLX3, 0, 0}, // S_BEASTBALLX2 {SPR_FRB1, 5, 4, NULL, S_BEASTBALLX4, 0, 0}, // S_BEASTBALLX3 {SPR_FRB1, 6, 4, NULL, S_BEASTBALLX5, 0, 0}, // S_BEASTBALLX4 {SPR_FRB1, 7, 4, NULL, S_NULL, 0, 0}, // S_BEASTBALLX5 {SPR_FRB1, 0, 4, NULL, S_BURNBALL2, 0, 0}, // S_BURNBALL1 {SPR_FRB1, 1, 4, NULL, S_BURNBALL3, 0, 0}, // S_BURNBALL2 {SPR_FRB1, 2, 4, NULL, S_BURNBALL4, 0, 0}, // S_BURNBALL3 {SPR_FRB1, 3, 4, NULL, S_BURNBALL5, 0, 0}, // S_BURNBALL4 {SPR_FRB1, 4, 4, NULL, S_BURNBALL6, 0, 0}, // S_BURNBALL5 {SPR_FRB1, 5, 4, NULL, S_BURNBALL7, 0, 0}, // S_BURNBALL6 {SPR_FRB1, 6, 4, NULL, S_BURNBALL8, 0, 0}, // S_BURNBALL7 {SPR_FRB1, 7, 4, NULL, S_NULL, 0, 0}, // S_BURNBALL8 {SPR_FRB1, 32768, 4, NULL, S_BURNBALLFB2, 0, 0}, // S_BURNBALLFB1 {SPR_FRB1, 32769, 4, NULL, S_BURNBALLFB3, 0, 0}, // S_BURNBALLFB2 {SPR_FRB1, 32770, 4, NULL, S_BURNBALLFB4, 0, 0}, // S_BURNBALLFB3 {SPR_FRB1, 32771, 4, NULL, S_BURNBALLFB5, 0, 0}, // S_BURNBALLFB4 {SPR_FRB1, 32772, 4, NULL, S_BURNBALLFB6, 0, 0}, // S_BURNBALLFB5 {SPR_FRB1, 32773, 4, NULL, S_BURNBALLFB7, 0, 0}, // S_BURNBALLFB6 {SPR_FRB1, 32774, 4, NULL, S_BURNBALLFB8, 0, 0}, // S_BURNBALLFB7 {SPR_FRB1, 32775, 4, NULL, S_NULL, 0, 0}, // S_BURNBALLFB8 {SPR_FRB1, 3, 4, NULL, S_PUFFY2, 0, 0}, // S_PUFFY1 {SPR_FRB1, 4, 4, NULL, S_PUFFY3, 0, 0}, // S_PUFFY2 {SPR_FRB1, 5, 4, NULL, S_PUFFY4, 0, 0}, // S_PUFFY3 {SPR_FRB1, 6, 4, NULL, S_PUFFY5, 0, 0}, // S_PUFFY4 {SPR_FRB1, 7, 4, NULL, S_NULL, 0, 0}, // S_PUFFY5 {SPR_SNKE, 0, 10, A_Look, S_SNAKE_LOOK2, 0, 0}, // S_SNAKE_LOOK1 {SPR_SNKE, 1, 10, A_Look, S_SNAKE_LOOK1, 0, 0}, // S_SNAKE_LOOK2 {SPR_SNKE, 0, 4, A_Chase, S_SNAKE_WALK2, 0, 0}, // S_SNAKE_WALK1 {SPR_SNKE, 1, 4, A_Chase, S_SNAKE_WALK3, 0, 0}, // S_SNAKE_WALK2 {SPR_SNKE, 2, 4, A_Chase, S_SNAKE_WALK4, 0, 0}, // S_SNAKE_WALK3 {SPR_SNKE, 3, 4, A_Chase, S_SNAKE_WALK1, 0, 0}, // S_SNAKE_WALK4 {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK2, 0, 0}, // S_SNAKE_ATK1 {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK3, 0, 0}, // S_SNAKE_ATK2 {SPR_SNKE, 5, 4, A_SnakeAttack, S_SNAKE_ATK4, 0, 0}, // S_SNAKE_ATK3 {SPR_SNKE, 5, 4, A_SnakeAttack, S_SNAKE_ATK5, 0, 0}, // S_SNAKE_ATK4 {SPR_SNKE, 5, 4, A_SnakeAttack, S_SNAKE_ATK6, 0, 0}, // S_SNAKE_ATK5 {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK7, 0, 0}, // S_SNAKE_ATK6 {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK8, 0, 0}, // S_SNAKE_ATK7 {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK9, 0, 0}, // S_SNAKE_ATK8 {SPR_SNKE, 5, 4, A_SnakeAttack2, S_SNAKE_WALK1, 0, 0}, // S_SNAKE_ATK9 {SPR_SNKE, 4, 3, NULL, S_SNAKE_PAIN2, 0, 0}, // S_SNAKE_PAIN1 {SPR_SNKE, 4, 3, A_Pain, S_SNAKE_WALK1, 0, 0}, // S_SNAKE_PAIN2 {SPR_SNKE, 6, 5, NULL, S_SNAKE_DIE2, 0, 0}, // S_SNAKE_DIE1 {SPR_SNKE, 7, 5, A_Scream, S_SNAKE_DIE3, 0, 0}, // S_SNAKE_DIE2 {SPR_SNKE, 8, 5, NULL, S_SNAKE_DIE4, 0, 0}, // S_SNAKE_DIE3 {SPR_SNKE, 9, 5, NULL, S_SNAKE_DIE5, 0, 0}, // S_SNAKE_DIE4 {SPR_SNKE, 10, 5, NULL, S_SNAKE_DIE6, 0, 0}, // S_SNAKE_DIE5 {SPR_SNKE, 11, 5, NULL, S_SNAKE_DIE7, 0, 0}, // S_SNAKE_DIE6 {SPR_SNKE, 12, 5, A_NoBlocking, S_SNAKE_DIE8, 0, 0}, // S_SNAKE_DIE7 {SPR_SNKE, 13, 5, NULL, S_SNAKE_DIE9, 0, 0}, // S_SNAKE_DIE8 {SPR_SNKE, 14, 5, NULL, S_SNAKE_DIE10, 0, 0}, // S_SNAKE_DIE9 {SPR_SNKE, 15, -1, NULL, S_NULL, 0, 0}, // S_SNAKE_DIE10 {SPR_SNFX, 32768, 5, NULL, S_SNAKEPRO_A2, 0, 0}, // S_SNAKEPRO_A1 {SPR_SNFX, 32769, 5, NULL, S_SNAKEPRO_A3, 0, 0}, // S_SNAKEPRO_A2 {SPR_SNFX, 32770, 5, NULL, S_SNAKEPRO_A4, 0, 0}, // S_SNAKEPRO_A3 {SPR_SNFX, 32771, 5, NULL, S_SNAKEPRO_A1, 0, 0}, // S_SNAKEPRO_A4 {SPR_SNFX, 32772, 5, NULL, S_SNAKEPRO_AX2, 0, 0}, // S_SNAKEPRO_AX1 {SPR_SNFX, 32773, 5, NULL, S_SNAKEPRO_AX3, 0, 0}, // S_SNAKEPRO_AX2 {SPR_SNFX, 32774, 4, NULL, S_SNAKEPRO_AX4, 0, 0}, // S_SNAKEPRO_AX3 {SPR_SNFX, 32775, 3, NULL, S_SNAKEPRO_AX5, 0, 0}, // S_SNAKEPRO_AX4 {SPR_SNFX, 32776, 3, NULL, S_NULL, 0, 0}, // S_SNAKEPRO_AX5 {SPR_SNFX, 32777, 6, NULL, S_SNAKEPRO_B2, 0, 0}, // S_SNAKEPRO_B1 {SPR_SNFX, 32778, 6, NULL, S_SNAKEPRO_B1, 0, 0}, // S_SNAKEPRO_B2 {SPR_SNFX, 32779, 5, NULL, S_SNAKEPRO_BX2, 0, 0}, // S_SNAKEPRO_BX1 {SPR_SNFX, 32780, 5, NULL, S_SNAKEPRO_BX3, 0, 0}, // S_SNAKEPRO_BX2 {SPR_SNFX, 32781, 4, NULL, S_SNAKEPRO_BX4, 0, 0}, // S_SNAKEPRO_BX3 {SPR_SNFX, 32782, 3, NULL, S_NULL, 0, 0}, // S_SNAKEPRO_BX4 {SPR_HEAD, 0, 10, A_Look, S_HEAD_LOOK, 0, 0}, // S_HEAD_LOOK {SPR_HEAD, 0, 4, A_Chase, S_HEAD_FLOAT, 0, 0}, // S_HEAD_FLOAT {SPR_HEAD, 0, 5, A_FaceTarget, S_HEAD_ATK2, 0, 0}, // S_HEAD_ATK1 {SPR_HEAD, 1, 20, A_HeadAttack, S_HEAD_FLOAT, 0, 0}, // S_HEAD_ATK2 {SPR_HEAD, 0, 4, NULL, S_HEAD_PAIN2, 0, 0}, // S_HEAD_PAIN1 {SPR_HEAD, 0, 4, A_Pain, S_HEAD_FLOAT, 0, 0}, // S_HEAD_PAIN2 {SPR_HEAD, 2, 7, NULL, S_HEAD_DIE2, 0, 0}, // S_HEAD_DIE1 {SPR_HEAD, 3, 7, A_Scream, S_HEAD_DIE3, 0, 0}, // S_HEAD_DIE2 {SPR_HEAD, 4, 7, NULL, S_HEAD_DIE4, 0, 0}, // S_HEAD_DIE3 {SPR_HEAD, 5, 7, NULL, S_HEAD_DIE5, 0, 0}, // S_HEAD_DIE4 {SPR_HEAD, 6, 7, A_NoBlocking, S_HEAD_DIE6, 0, 0}, // S_HEAD_DIE5 {SPR_HEAD, 7, 7, NULL, S_HEAD_DIE7, 0, 0}, // S_HEAD_DIE6 {SPR_HEAD, 8, -1, A_BossDeath, S_NULL, 0, 0}, // S_HEAD_DIE7 {SPR_FX05, 0, 6, NULL, S_HEADFX1_2, 0, 0}, // S_HEADFX1_1 {SPR_FX05, 1, 6, NULL, S_HEADFX1_3, 0, 0}, // S_HEADFX1_2 {SPR_FX05, 2, 6, NULL, S_HEADFX1_1, 0, 0}, // S_HEADFX1_3 {SPR_FX05, 3, 5, A_HeadIceImpact, S_HEADFXI1_2, 0, 0}, // S_HEADFXI1_1 {SPR_FX05, 4, 5, NULL, S_HEADFXI1_3, 0, 0}, // S_HEADFXI1_2 {SPR_FX05, 5, 5, NULL, S_HEADFXI1_4, 0, 0}, // S_HEADFXI1_3 {SPR_FX05, 6, 5, NULL, S_NULL, 0, 0}, // S_HEADFXI1_4 {SPR_FX05, 7, 6, NULL, S_HEADFX2_2, 0, 0}, // S_HEADFX2_1 {SPR_FX05, 8, 6, NULL, S_HEADFX2_3, 0, 0}, // S_HEADFX2_2 {SPR_FX05, 9, 6, NULL, S_HEADFX2_1, 0, 0}, // S_HEADFX2_3 {SPR_FX05, 3, 5, NULL, S_HEADFXI2_2, 0, 0}, // S_HEADFXI2_1 {SPR_FX05, 4, 5, NULL, S_HEADFXI2_3, 0, 0}, // S_HEADFXI2_2 {SPR_FX05, 5, 5, NULL, S_HEADFXI2_4, 0, 0}, // S_HEADFXI2_3 {SPR_FX05, 6, 5, NULL, S_NULL, 0, 0}, // S_HEADFXI2_4 {SPR_FX06, 0, 4, A_HeadFireGrow, S_HEADFX3_2, 0, 0}, // S_HEADFX3_1 {SPR_FX06, 1, 4, A_HeadFireGrow, S_HEADFX3_3, 0, 0}, // S_HEADFX3_2 {SPR_FX06, 2, 4, A_HeadFireGrow, S_HEADFX3_1, 0, 0}, // S_HEADFX3_3 {SPR_FX06, 0, 5, NULL, S_HEADFX3_5, 0, 0}, // S_HEADFX3_4 {SPR_FX06, 1, 5, NULL, S_HEADFX3_6, 0, 0}, // S_HEADFX3_5 {SPR_FX06, 2, 5, NULL, S_HEADFX3_4, 0, 0}, // S_HEADFX3_6 {SPR_FX06, 3, 5, NULL, S_HEADFXI3_2, 0, 0}, // S_HEADFXI3_1 {SPR_FX06, 4, 5, NULL, S_HEADFXI3_3, 0, 0}, // S_HEADFXI3_2 {SPR_FX06, 5, 5, NULL, S_HEADFXI3_4, 0, 0}, // S_HEADFXI3_3 {SPR_FX06, 6, 5, NULL, S_NULL, 0, 0}, // S_HEADFXI3_4 {SPR_FX07, 3, 3, NULL, S_HEADFX4_2, 0, 0}, // S_HEADFX4_1 {SPR_FX07, 4, 3, NULL, S_HEADFX4_3, 0, 0}, // S_HEADFX4_2 {SPR_FX07, 5, 3, NULL, S_HEADFX4_4, 0, 0}, // S_HEADFX4_3 {SPR_FX07, 6, 3, NULL, S_HEADFX4_5, 0, 0}, // S_HEADFX4_4 {SPR_FX07, 0, 3, A_WhirlwindSeek, S_HEADFX4_6, 0, 0}, // S_HEADFX4_5 {SPR_FX07, 1, 3, A_WhirlwindSeek, S_HEADFX4_7, 0, 0}, // S_HEADFX4_6 {SPR_FX07, 2, 3, A_WhirlwindSeek, S_HEADFX4_5, 0, 0}, // S_HEADFX4_7 {SPR_FX07, 6, 4, NULL, S_HEADFXI4_2, 0, 0}, // S_HEADFXI4_1 {SPR_FX07, 5, 4, NULL, S_HEADFXI4_3, 0, 0}, // S_HEADFXI4_2 {SPR_FX07, 4, 4, NULL, S_HEADFXI4_4, 0, 0}, // S_HEADFXI4_3 {SPR_FX07, 3, 4, NULL, S_NULL, 0, 0}, // S_HEADFXI4_4 {SPR_CLNK, 0, 10, A_Look, S_CLINK_LOOK2, 0, 0}, // S_CLINK_LOOK1 {SPR_CLNK, 1, 10, A_Look, S_CLINK_LOOK1, 0, 0}, // S_CLINK_LOOK2 {SPR_CLNK, 0, 3, A_Chase, S_CLINK_WALK2, 0, 0}, // S_CLINK_WALK1 {SPR_CLNK, 1, 3, A_Chase, S_CLINK_WALK3, 0, 0}, // S_CLINK_WALK2 {SPR_CLNK, 2, 3, A_Chase, S_CLINK_WALK4, 0, 0}, // S_CLINK_WALK3 {SPR_CLNK, 3, 3, A_Chase, S_CLINK_WALK1, 0, 0}, // S_CLINK_WALK4 {SPR_CLNK, 4, 5, A_FaceTarget, S_CLINK_ATK2, 0, 0}, // S_CLINK_ATK1 {SPR_CLNK, 5, 4, A_FaceTarget, S_CLINK_ATK3, 0, 0}, // S_CLINK_ATK2 {SPR_CLNK, 6, 7, A_ClinkAttack, S_CLINK_WALK1, 0, 0}, // S_CLINK_ATK3 {SPR_CLNK, 7, 3, NULL, S_CLINK_PAIN2, 0, 0}, // S_CLINK_PAIN1 {SPR_CLNK, 7, 3, A_Pain, S_CLINK_WALK1, 0, 0}, // S_CLINK_PAIN2 {SPR_CLNK, 8, 6, NULL, S_CLINK_DIE2, 0, 0}, // S_CLINK_DIE1 {SPR_CLNK, 9, 6, NULL, S_CLINK_DIE3, 0, 0}, // S_CLINK_DIE2 {SPR_CLNK, 10, 5, A_Scream, S_CLINK_DIE4, 0, 0}, // S_CLINK_DIE3 {SPR_CLNK, 11, 5, A_NoBlocking, S_CLINK_DIE5, 0, 0}, // S_CLINK_DIE4 {SPR_CLNK, 12, 5, NULL, S_CLINK_DIE6, 0, 0}, // S_CLINK_DIE5 {SPR_CLNK, 13, 5, NULL, S_CLINK_DIE7, 0, 0}, // S_CLINK_DIE6 {SPR_CLNK, 14, -1, NULL, S_NULL, 0, 0}, // S_CLINK_DIE7 {SPR_WZRD, 0, 10, A_Look, S_WIZARD_LOOK2, 0, 0}, // S_WIZARD_LOOK1 {SPR_WZRD, 1, 10, A_Look, S_WIZARD_LOOK1, 0, 0}, // S_WIZARD_LOOK2 {SPR_WZRD, 0, 3, A_Chase, S_WIZARD_WALK2, 0, 0}, // S_WIZARD_WALK1 {SPR_WZRD, 0, 4, A_Chase, S_WIZARD_WALK3, 0, 0}, // S_WIZARD_WALK2 {SPR_WZRD, 0, 3, A_Chase, S_WIZARD_WALK4, 0, 0}, // S_WIZARD_WALK3 {SPR_WZRD, 0, 4, A_Chase, S_WIZARD_WALK5, 0, 0}, // S_WIZARD_WALK4 {SPR_WZRD, 1, 3, A_Chase, S_WIZARD_WALK6, 0, 0}, // S_WIZARD_WALK5 {SPR_WZRD, 1, 4, A_Chase, S_WIZARD_WALK7, 0, 0}, // S_WIZARD_WALK6 {SPR_WZRD, 1, 3, A_Chase, S_WIZARD_WALK8, 0, 0}, // S_WIZARD_WALK7 {SPR_WZRD, 1, 4, A_Chase, S_WIZARD_WALK1, 0, 0}, // S_WIZARD_WALK8 {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK2, 0, 0}, // S_WIZARD_ATK1 {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK3, 0, 0}, // S_WIZARD_ATK2 {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK4, 0, 0}, // S_WIZARD_ATK3 {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK5, 0, 0}, // S_WIZARD_ATK4 {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK6, 0, 0}, // S_WIZARD_ATK5 {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK7, 0, 0}, // S_WIZARD_ATK6 {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK8, 0, 0}, // S_WIZARD_ATK7 {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK9, 0, 0}, // S_WIZARD_ATK8 {SPR_WZRD, 3, 12, A_WizAtk3, S_WIZARD_WALK1, 0, 0}, // S_WIZARD_ATK9 {SPR_WZRD, 4, 3, A_GhostOff, S_WIZARD_PAIN2, 0, 0}, // S_WIZARD_PAIN1 {SPR_WZRD, 4, 3, A_Pain, S_WIZARD_WALK1, 0, 0}, // S_WIZARD_PAIN2 {SPR_WZRD, 5, 6, A_GhostOff, S_WIZARD_DIE2, 0, 0}, // S_WIZARD_DIE1 {SPR_WZRD, 6, 6, A_Scream, S_WIZARD_DIE3, 0, 0}, // S_WIZARD_DIE2 {SPR_WZRD, 7, 6, NULL, S_WIZARD_DIE4, 0, 0}, // S_WIZARD_DIE3 {SPR_WZRD, 8, 6, NULL, S_WIZARD_DIE5, 0, 0}, // S_WIZARD_DIE4 {SPR_WZRD, 9, 6, A_NoBlocking, S_WIZARD_DIE6, 0, 0}, // S_WIZARD_DIE5 {SPR_WZRD, 10, 6, NULL, S_WIZARD_DIE7, 0, 0}, // S_WIZARD_DIE6 {SPR_WZRD, 11, 6, NULL, S_WIZARD_DIE8, 0, 0}, // S_WIZARD_DIE7 {SPR_WZRD, 12, -1, NULL, S_NULL, 0, 0}, // S_WIZARD_DIE8 {SPR_FX11, 32768, 6, NULL, S_WIZFX1_2, 0, 0}, // S_WIZFX1_1 {SPR_FX11, 32769, 6, NULL, S_WIZFX1_1, 0, 0}, // S_WIZFX1_2 {SPR_FX11, 32770, 5, NULL, S_WIZFXI1_2, 0, 0}, // S_WIZFXI1_1 {SPR_FX11, 32771, 5, NULL, S_WIZFXI1_3, 0, 0}, // S_WIZFXI1_2 {SPR_FX11, 32772, 5, NULL, S_WIZFXI1_4, 0, 0}, // S_WIZFXI1_3 {SPR_FX11, 32773, 5, NULL, S_WIZFXI1_5, 0, 0}, // S_WIZFXI1_4 {SPR_FX11, 32774, 5, NULL, S_NULL, 0, 0}, // S_WIZFXI1_5 {SPR_IMPX, 0, 10, A_Look, S_IMP_LOOK2, 0, 0}, // S_IMP_LOOK1 {SPR_IMPX, 1, 10, A_Look, S_IMP_LOOK3, 0, 0}, // S_IMP_LOOK2 {SPR_IMPX, 2, 10, A_Look, S_IMP_LOOK4, 0, 0}, // S_IMP_LOOK3 {SPR_IMPX, 1, 10, A_Look, S_IMP_LOOK1, 0, 0}, // S_IMP_LOOK4 {SPR_IMPX, 0, 3, A_Chase, S_IMP_FLY2, 0, 0}, // S_IMP_FLY1 {SPR_IMPX, 0, 3, A_Chase, S_IMP_FLY3, 0, 0}, // S_IMP_FLY2 {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY4, 0, 0}, // S_IMP_FLY3 {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY5, 0, 0}, // S_IMP_FLY4 {SPR_IMPX, 2, 3, A_Chase, S_IMP_FLY6, 0, 0}, // S_IMP_FLY5 {SPR_IMPX, 2, 3, A_Chase, S_IMP_FLY7, 0, 0}, // S_IMP_FLY6 {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY8, 0, 0}, // S_IMP_FLY7 {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY1, 0, 0}, // S_IMP_FLY8 {SPR_IMPX, 3, 6, A_FaceTarget, S_IMP_MEATK2, 0, 0}, // S_IMP_MEATK1 {SPR_IMPX, 4, 6, A_FaceTarget, S_IMP_MEATK3, 0, 0}, // S_IMP_MEATK2 {SPR_IMPX, 5, 6, A_ImpMeAttack, S_IMP_FLY1, 0, 0}, // S_IMP_MEATK3 {SPR_IMPX, 0, 10, A_FaceTarget, S_IMP_MSATK1_2, 0, 0}, // S_IMP_MSATK1_1 {SPR_IMPX, 1, 6, A_ImpMsAttack, S_IMP_MSATK1_3, 0, 0}, // S_IMP_MSATK1_2 {SPR_IMPX, 2, 6, NULL, S_IMP_MSATK1_4, 0, 0}, // S_IMP_MSATK1_3 {SPR_IMPX, 1, 6, NULL, S_IMP_MSATK1_5, 0, 0}, // S_IMP_MSATK1_4 {SPR_IMPX, 0, 6, NULL, S_IMP_MSATK1_6, 0, 0}, // S_IMP_MSATK1_5 {SPR_IMPX, 1, 6, NULL, S_IMP_MSATK1_3, 0, 0}, // S_IMP_MSATK1_6 {SPR_IMPX, 3, 6, A_FaceTarget, S_IMP_MSATK2_2, 0, 0}, // S_IMP_MSATK2_1 {SPR_IMPX, 4, 6, A_FaceTarget, S_IMP_MSATK2_3, 0, 0}, // S_IMP_MSATK2_2 {SPR_IMPX, 5, 6, A_ImpMsAttack2, S_IMP_FLY1, 0, 0}, // S_IMP_MSATK2_3 {SPR_IMPX, 6, 3, NULL, S_IMP_PAIN2, 0, 0}, // S_IMP_PAIN1 {SPR_IMPX, 6, 3, A_Pain, S_IMP_FLY1, 0, 0}, // S_IMP_PAIN2 {SPR_IMPX, 6, 4, A_ImpDeath, S_IMP_DIE2, 0, 0}, // S_IMP_DIE1 {SPR_IMPX, 7, 5, NULL, S_IMP_DIE2, 0, 0}, // S_IMP_DIE2 {SPR_IMPX, 18, 5, A_ImpXDeath1, S_IMP_XDIE2, 0, 0}, // S_IMP_XDIE1 {SPR_IMPX, 19, 5, NULL, S_IMP_XDIE3, 0, 0}, // S_IMP_XDIE2 {SPR_IMPX, 20, 5, NULL, S_IMP_XDIE4, 0, 0}, // S_IMP_XDIE3 {SPR_IMPX, 21, 5, A_ImpXDeath2, S_IMP_XDIE5, 0, 0}, // S_IMP_XDIE4 {SPR_IMPX, 22, 5, NULL, S_IMP_XDIE5, 0, 0}, // S_IMP_XDIE5 {SPR_IMPX, 8, 7, A_ImpExplode, S_IMP_CRASH2, 0, 0}, // S_IMP_CRASH1 {SPR_IMPX, 9, 7, A_Scream, S_IMP_CRASH3, 0, 0}, // S_IMP_CRASH2 {SPR_IMPX, 10, 7, NULL, S_IMP_CRASH4, 0, 0}, // S_IMP_CRASH3 {SPR_IMPX, 11, -1, NULL, S_NULL, 0, 0}, // S_IMP_CRASH4 {SPR_IMPX, 23, 7, NULL, S_IMP_XCRASH2, 0, 0}, // S_IMP_XCRASH1 {SPR_IMPX, 24, 7, NULL, S_IMP_XCRASH3, 0, 0}, // S_IMP_XCRASH2 {SPR_IMPX, 25, -1, NULL, S_NULL, 0, 0}, // S_IMP_XCRASH3 {SPR_IMPX, 12, 5, NULL, S_IMP_CHUNKA2, 0, 0}, // S_IMP_CHUNKA1 {SPR_IMPX, 13, 700, NULL, S_IMP_CHUNKA3, 0, 0}, // S_IMP_CHUNKA2 {SPR_IMPX, 14, 700, NULL, S_NULL, 0, 0}, // S_IMP_CHUNKA3 {SPR_IMPX, 15, 5, NULL, S_IMP_CHUNKB2, 0, 0}, // S_IMP_CHUNKB1 {SPR_IMPX, 16, 700, NULL, S_IMP_CHUNKB3, 0, 0}, // S_IMP_CHUNKB2 {SPR_IMPX, 17, 700, NULL, S_NULL, 0, 0}, // S_IMP_CHUNKB3 {SPR_FX10, 32768, 6, NULL, S_IMPFX2, 0, 0}, // S_IMPFX1 {SPR_FX10, 32769, 6, NULL, S_IMPFX3, 0, 0}, // S_IMPFX2 {SPR_FX10, 32770, 6, NULL, S_IMPFX1, 0, 0}, // S_IMPFX3 {SPR_FX10, 32771, 5, NULL, S_IMPFXI2, 0, 0}, // S_IMPFXI1 {SPR_FX10, 32772, 5, NULL, S_IMPFXI3, 0, 0}, // S_IMPFXI2 {SPR_FX10, 32773, 5, NULL, S_IMPFXI4, 0, 0}, // S_IMPFXI3 {SPR_FX10, 32774, 5, NULL, S_NULL, 0, 0}, // S_IMPFXI4 {SPR_KNIG, 0, 10, A_Look, S_KNIGHT_STND2, 0, 0}, // S_KNIGHT_STND1 {SPR_KNIG, 1, 10, A_Look, S_KNIGHT_STND1, 0, 0}, // S_KNIGHT_STND2 {SPR_KNIG, 0, 4, A_Chase, S_KNIGHT_WALK2, 0, 0}, // S_KNIGHT_WALK1 {SPR_KNIG, 1, 4, A_Chase, S_KNIGHT_WALK3, 0, 0}, // S_KNIGHT_WALK2 {SPR_KNIG, 2, 4, A_Chase, S_KNIGHT_WALK4, 0, 0}, // S_KNIGHT_WALK3 {SPR_KNIG, 3, 4, A_Chase, S_KNIGHT_WALK1, 0, 0}, // S_KNIGHT_WALK4 {SPR_KNIG, 4, 10, A_FaceTarget, S_KNIGHT_ATK2, 0, 0}, // S_KNIGHT_ATK1 {SPR_KNIG, 5, 8, A_FaceTarget, S_KNIGHT_ATK3, 0, 0}, // S_KNIGHT_ATK2 {SPR_KNIG, 6, 8, A_KnightAttack, S_KNIGHT_ATK4, 0, 0}, // S_KNIGHT_ATK3 {SPR_KNIG, 4, 10, A_FaceTarget, S_KNIGHT_ATK5, 0, 0}, // S_KNIGHT_ATK4 {SPR_KNIG, 5, 8, A_FaceTarget, S_KNIGHT_ATK6, 0, 0}, // S_KNIGHT_ATK5 {SPR_KNIG, 6, 8, A_KnightAttack, S_KNIGHT_WALK1, 0, 0}, // S_KNIGHT_ATK6 {SPR_KNIG, 7, 3, NULL, S_KNIGHT_PAIN2, 0, 0}, // S_KNIGHT_PAIN1 {SPR_KNIG, 7, 3, A_Pain, S_KNIGHT_WALK1, 0, 0}, // S_KNIGHT_PAIN2 {SPR_KNIG, 8, 6, NULL, S_KNIGHT_DIE2, 0, 0}, // S_KNIGHT_DIE1 {SPR_KNIG, 9, 6, A_Scream, S_KNIGHT_DIE3, 0, 0}, // S_KNIGHT_DIE2 {SPR_KNIG, 10, 6, NULL, S_KNIGHT_DIE4, 0, 0}, // S_KNIGHT_DIE3 {SPR_KNIG, 11, 6, A_NoBlocking, S_KNIGHT_DIE5, 0, 0}, // S_KNIGHT_DIE4 {SPR_KNIG, 12, 6, NULL, S_KNIGHT_DIE6, 0, 0}, // S_KNIGHT_DIE5 {SPR_KNIG, 13, 6, NULL, S_KNIGHT_DIE7, 0, 0}, // S_KNIGHT_DIE6 {SPR_KNIG, 14, -1, NULL, S_NULL, 0, 0}, // S_KNIGHT_DIE7 {SPR_SPAX, 32768, 3, A_ContMobjSound, S_SPINAXE2, 0, 0}, // S_SPINAXE1 {SPR_SPAX, 32769, 3, NULL, S_SPINAXE3, 0, 0}, // S_SPINAXE2 {SPR_SPAX, 32770, 3, NULL, S_SPINAXE1, 0, 0}, // S_SPINAXE3 {SPR_SPAX, 32771, 6, NULL, S_SPINAXEX2, 0, 0}, // S_SPINAXEX1 {SPR_SPAX, 32772, 6, NULL, S_SPINAXEX3, 0, 0}, // S_SPINAXEX2 {SPR_SPAX, 32773, 6, NULL, S_NULL, 0, 0}, // S_SPINAXEX3 {SPR_RAXE, 32768, 5, A_DripBlood, S_REDAXE2, 0, 0}, // S_REDAXE1 {SPR_RAXE, 32769, 5, A_DripBlood, S_REDAXE1, 0, 0}, // S_REDAXE2 {SPR_RAXE, 32770, 6, NULL, S_REDAXEX2, 0, 0}, // S_REDAXEX1 {SPR_RAXE, 32771, 6, NULL, S_REDAXEX3, 0, 0}, // S_REDAXEX2 {SPR_RAXE, 32772, 6, NULL, S_NULL, 0, 0}, // S_REDAXEX3 {SPR_SRCR, 0, 10, A_Look, S_SRCR1_LOOK2, 0, 0}, // S_SRCR1_LOOK1 {SPR_SRCR, 1, 10, A_Look, S_SRCR1_LOOK1, 0, 0}, // S_SRCR1_LOOK2 {SPR_SRCR, 0, 5, A_Sor1Chase, S_SRCR1_WALK2, 0, 0}, // S_SRCR1_WALK1 {SPR_SRCR, 1, 5, A_Sor1Chase, S_SRCR1_WALK3, 0, 0}, // S_SRCR1_WALK2 {SPR_SRCR, 2, 5, A_Sor1Chase, S_SRCR1_WALK4, 0, 0}, // S_SRCR1_WALK3 {SPR_SRCR, 3, 5, A_Sor1Chase, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_WALK4 {SPR_SRCR, 16, 6, A_Sor1Pain, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_PAIN1 {SPR_SRCR, 16, 7, A_FaceTarget, S_SRCR1_ATK2, 0, 0}, // S_SRCR1_ATK1 {SPR_SRCR, 17, 6, A_FaceTarget, S_SRCR1_ATK3, 0, 0}, // S_SRCR1_ATK2 {SPR_SRCR, 18, 10, A_Srcr1Attack, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_ATK3 {SPR_SRCR, 18, 10, A_FaceTarget, S_SRCR1_ATK5, 0, 0}, // S_SRCR1_ATK4 {SPR_SRCR, 16, 7, A_FaceTarget, S_SRCR1_ATK6, 0, 0}, // S_SRCR1_ATK5 {SPR_SRCR, 17, 6, A_FaceTarget, S_SRCR1_ATK7, 0, 0}, // S_SRCR1_ATK6 {SPR_SRCR, 18, 10, A_Srcr1Attack, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_ATK7 {SPR_SRCR, 4, 7, NULL, S_SRCR1_DIE2, 0, 0}, // S_SRCR1_DIE1 {SPR_SRCR, 5, 7, A_Scream, S_SRCR1_DIE3, 0, 0}, // S_SRCR1_DIE2 {SPR_SRCR, 6, 7, NULL, S_SRCR1_DIE4, 0, 0}, // S_SRCR1_DIE3 {SPR_SRCR, 7, 6, NULL, S_SRCR1_DIE5, 0, 0}, // S_SRCR1_DIE4 {SPR_SRCR, 8, 6, NULL, S_SRCR1_DIE6, 0, 0}, // S_SRCR1_DIE5 {SPR_SRCR, 9, 6, NULL, S_SRCR1_DIE7, 0, 0}, // S_SRCR1_DIE6 {SPR_SRCR, 10, 6, NULL, S_SRCR1_DIE8, 0, 0}, // S_SRCR1_DIE7 {SPR_SRCR, 11, 25, A_SorZap, S_SRCR1_DIE9, 0, 0}, // S_SRCR1_DIE8 {SPR_SRCR, 12, 5, NULL, S_SRCR1_DIE10, 0, 0}, // S_SRCR1_DIE9 {SPR_SRCR, 13, 5, NULL, S_SRCR1_DIE11, 0, 0}, // S_SRCR1_DIE10 {SPR_SRCR, 14, 4, NULL, S_SRCR1_DIE12, 0, 0}, // S_SRCR1_DIE11 {SPR_SRCR, 11, 20, A_SorZap, S_SRCR1_DIE13, 0, 0}, // S_SRCR1_DIE12 {SPR_SRCR, 12, 5, NULL, S_SRCR1_DIE14, 0, 0}, // S_SRCR1_DIE13 {SPR_SRCR, 13, 5, NULL, S_SRCR1_DIE15, 0, 0}, // S_SRCR1_DIE14 {SPR_SRCR, 14, 4, NULL, S_SRCR1_DIE16, 0, 0}, // S_SRCR1_DIE15 {SPR_SRCR, 11, 12, NULL, S_SRCR1_DIE17, 0, 0}, // S_SRCR1_DIE16 {SPR_SRCR, 15, -1, A_SorcererRise, S_NULL, 0, 0}, // S_SRCR1_DIE17 {SPR_FX14, 32768, 6, NULL, S_SRCRFX1_2, 0, 0}, // S_SRCRFX1_1 {SPR_FX14, 32769, 6, NULL, S_SRCRFX1_3, 0, 0}, // S_SRCRFX1_2 {SPR_FX14, 32770, 6, NULL, S_SRCRFX1_1, 0, 0}, // S_SRCRFX1_3 {SPR_FX14, 32771, 5, NULL, S_SRCRFXI1_2, 0, 0}, // S_SRCRFXI1_1 {SPR_FX14, 32772, 5, NULL, S_SRCRFXI1_3, 0, 0}, // S_SRCRFXI1_2 {SPR_FX14, 32773, 5, NULL, S_SRCRFXI1_4, 0, 0}, // S_SRCRFXI1_3 {SPR_FX14, 32774, 5, NULL, S_SRCRFXI1_5, 0, 0}, // S_SRCRFXI1_4 {SPR_FX14, 32775, 5, NULL, S_NULL, 0, 0}, // S_SRCRFXI1_5 {SPR_SOR2, 0, 4, NULL, S_SOR2_RISE2, 0, 0}, // S_SOR2_RISE1 {SPR_SOR2, 1, 4, NULL, S_SOR2_RISE3, 0, 0}, // S_SOR2_RISE2 {SPR_SOR2, 2, 4, A_SorRise, S_SOR2_RISE4, 0, 0}, // S_SOR2_RISE3 {SPR_SOR2, 3, 4, NULL, S_SOR2_RISE5, 0, 0}, // S_SOR2_RISE4 {SPR_SOR2, 4, 4, NULL, S_SOR2_RISE6, 0, 0}, // S_SOR2_RISE5 {SPR_SOR2, 5, 4, NULL, S_SOR2_RISE7, 0, 0}, // S_SOR2_RISE6 {SPR_SOR2, 6, 12, A_SorSightSnd, S_SOR2_WALK1, 0, 0}, // S_SOR2_RISE7 {SPR_SOR2, 12, 10, A_Look, S_SOR2_LOOK2, 0, 0}, // S_SOR2_LOOK1 {SPR_SOR2, 13, 10, A_Look, S_SOR2_LOOK1, 0, 0}, // S_SOR2_LOOK2 {SPR_SOR2, 12, 4, A_Chase, S_SOR2_WALK2, 0, 0}, // S_SOR2_WALK1 {SPR_SOR2, 13, 4, A_Chase, S_SOR2_WALK3, 0, 0}, // S_SOR2_WALK2 {SPR_SOR2, 14, 4, A_Chase, S_SOR2_WALK4, 0, 0}, // S_SOR2_WALK3 {SPR_SOR2, 15, 4, A_Chase, S_SOR2_WALK1, 0, 0}, // S_SOR2_WALK4 {SPR_SOR2, 16, 3, NULL, S_SOR2_PAIN2, 0, 0}, // S_SOR2_PAIN1 {SPR_SOR2, 16, 6, A_Pain, S_SOR2_WALK1, 0, 0}, // S_SOR2_PAIN2 {SPR_SOR2, 17, 9, A_Srcr2Decide, S_SOR2_ATK2, 0, 0}, // S_SOR2_ATK1 {SPR_SOR2, 18, 9, A_FaceTarget, S_SOR2_ATK3, 0, 0}, // S_SOR2_ATK2 {SPR_SOR2, 19, 20, A_Srcr2Attack, S_SOR2_WALK1, 0, 0}, // S_SOR2_ATK3 {SPR_SOR2, 11, 6, NULL, S_SOR2_TELE2, 0, 0}, // S_SOR2_TELE1 {SPR_SOR2, 10, 6, NULL, S_SOR2_TELE3, 0, 0}, // S_SOR2_TELE2 {SPR_SOR2, 9, 6, NULL, S_SOR2_TELE4, 0, 0}, // S_SOR2_TELE3 {SPR_SOR2, 8, 6, NULL, S_SOR2_TELE5, 0, 0}, // S_SOR2_TELE4 {SPR_SOR2, 7, 6, NULL, S_SOR2_TELE6, 0, 0}, // S_SOR2_TELE5 {SPR_SOR2, 6, 6, NULL, S_SOR2_WALK1, 0, 0}, // S_SOR2_TELE6 {SPR_SDTH, 0, 8, A_Sor2DthInit, S_SOR2_DIE2, 0, 0}, // S_SOR2_DIE1 {SPR_SDTH, 1, 8, NULL, S_SOR2_DIE3, 0, 0}, // S_SOR2_DIE2 {SPR_SDTH, 2, 8, A_SorDSph, S_SOR2_DIE4, 0, 0}, // S_SOR2_DIE3 {SPR_SDTH, 3, 7, NULL, S_SOR2_DIE5, 0, 0}, // S_SOR2_DIE4 {SPR_SDTH, 4, 7, NULL, S_SOR2_DIE6, 0, 0}, // S_SOR2_DIE5 {SPR_SDTH, 5, 7, A_Sor2DthLoop, S_SOR2_DIE7, 0, 0}, // S_SOR2_DIE6 {SPR_SDTH, 6, 6, A_SorDExp, S_SOR2_DIE8, 0, 0}, // S_SOR2_DIE7 {SPR_SDTH, 7, 6, NULL, S_SOR2_DIE9, 0, 0}, // S_SOR2_DIE8 {SPR_SDTH, 8, 18, NULL, S_SOR2_DIE10, 0, 0}, // S_SOR2_DIE9 {SPR_SDTH, 9, 6, A_NoBlocking, S_SOR2_DIE11, 0, 0}, // S_SOR2_DIE10 {SPR_SDTH, 10, 6, A_SorDBon, S_SOR2_DIE12, 0, 0}, // S_SOR2_DIE11 {SPR_SDTH, 11, 6, NULL, S_SOR2_DIE13, 0, 0}, // S_SOR2_DIE12 {SPR_SDTH, 12, 6, NULL, S_SOR2_DIE14, 0, 0}, // S_SOR2_DIE13 {SPR_SDTH, 13, 6, NULL, S_SOR2_DIE15, 0, 0}, // S_SOR2_DIE14 {SPR_SDTH, 14, -1, A_BossDeath, S_NULL, 0, 0}, // S_SOR2_DIE15 {SPR_FX16, 32768, 3, A_BlueSpark, S_SOR2FX1_2, 0, 0}, // S_SOR2FX1_1 {SPR_FX16, 32769, 3, A_BlueSpark, S_SOR2FX1_3, 0, 0}, // S_SOR2FX1_2 {SPR_FX16, 32770, 3, A_BlueSpark, S_SOR2FX1_1, 0, 0}, // S_SOR2FX1_3 {SPR_FX16, 32774, 5, A_Explode, S_SOR2FXI1_2, 0, 0}, // S_SOR2FXI1_1 {SPR_FX16, 32775, 5, NULL, S_SOR2FXI1_3, 0, 0}, // S_SOR2FXI1_2 {SPR_FX16, 32776, 5, NULL, S_SOR2FXI1_4, 0, 0}, // S_SOR2FXI1_3 {SPR_FX16, 32777, 5, NULL, S_SOR2FXI1_5, 0, 0}, // S_SOR2FXI1_4 {SPR_FX16, 32778, 5, NULL, S_SOR2FXI1_6, 0, 0}, // S_SOR2FXI1_5 {SPR_FX16, 32779, 5, NULL, S_NULL, 0, 0}, // S_SOR2FXI1_6 {SPR_FX16, 32771, 12, NULL, S_SOR2FXSPARK2, 0, 0}, // S_SOR2FXSPARK1 {SPR_FX16, 32772, 12, NULL, S_SOR2FXSPARK3, 0, 0}, // S_SOR2FXSPARK2 {SPR_FX16, 32773, 12, NULL, S_NULL, 0, 0}, // S_SOR2FXSPARK3 {SPR_FX11, 32768, 35, NULL, S_SOR2FX2_2, 0, 0}, // S_SOR2FX2_1 {SPR_FX11, 32768, 5, A_GenWizard, S_SOR2FX2_3, 0, 0}, // S_SOR2FX2_2 {SPR_FX11, 32769, 5, NULL, S_SOR2FX2_2, 0, 0}, // S_SOR2FX2_3 {SPR_FX11, 32770, 5, NULL, S_SOR2FXI2_2, 0, 0}, // S_SOR2FXI2_1 {SPR_FX11, 32771, 5, NULL, S_SOR2FXI2_3, 0, 0}, // S_SOR2FXI2_2 {SPR_FX11, 32772, 5, NULL, S_SOR2FXI2_4, 0, 0}, // S_SOR2FXI2_3 {SPR_FX11, 32773, 5, NULL, S_SOR2FXI2_5, 0, 0}, // S_SOR2FXI2_4 {SPR_FX11, 32774, 5, NULL, S_NULL, 0, 0}, // S_SOR2FXI2_5 {SPR_SOR2, 6, 8, NULL, S_SOR2TELEFADE2, 0, 0}, // S_SOR2TELEFADE1 {SPR_SOR2, 7, 6, NULL, S_SOR2TELEFADE3, 0, 0}, // S_SOR2TELEFADE2 {SPR_SOR2, 8, 6, NULL, S_SOR2TELEFADE4, 0, 0}, // S_SOR2TELEFADE3 {SPR_SOR2, 9, 6, NULL, S_SOR2TELEFADE5, 0, 0}, // S_SOR2TELEFADE4 {SPR_SOR2, 10, 6, NULL, S_SOR2TELEFADE6, 0, 0}, // S_SOR2TELEFADE5 {SPR_SOR2, 11, 6, NULL, S_NULL, 0, 0}, // S_SOR2TELEFADE6 {SPR_MNTR, 0, 10, A_Look, S_MNTR_LOOK2, 0, 0}, // S_MNTR_LOOK1 {SPR_MNTR, 1, 10, A_Look, S_MNTR_LOOK1, 0, 0}, // S_MNTR_LOOK2 {SPR_MNTR, 0, 5, A_Chase, S_MNTR_WALK2, 0, 0}, // S_MNTR_WALK1 {SPR_MNTR, 1, 5, A_Chase, S_MNTR_WALK3, 0, 0}, // S_MNTR_WALK2 {SPR_MNTR, 2, 5, A_Chase, S_MNTR_WALK4, 0, 0}, // S_MNTR_WALK3 {SPR_MNTR, 3, 5, A_Chase, S_MNTR_WALK1, 0, 0}, // S_MNTR_WALK4 {SPR_MNTR, 21, 10, A_FaceTarget, S_MNTR_ATK1_2, 0, 0}, // S_MNTR_ATK1_1 {SPR_MNTR, 22, 7, A_FaceTarget, S_MNTR_ATK1_3, 0, 0}, // S_MNTR_ATK1_2 {SPR_MNTR, 23, 12, A_MinotaurAtk1, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK1_3 {SPR_MNTR, 21, 10, A_MinotaurDecide, S_MNTR_ATK2_2, 0, 0}, // S_MNTR_ATK2_1 {SPR_MNTR, 24, 4, A_FaceTarget, S_MNTR_ATK2_3, 0, 0}, // S_MNTR_ATK2_2 {SPR_MNTR, 25, 9, A_MinotaurAtk2, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK2_3 {SPR_MNTR, 21, 10, A_FaceTarget, S_MNTR_ATK3_2, 0, 0}, // S_MNTR_ATK3_1 {SPR_MNTR, 22, 7, A_FaceTarget, S_MNTR_ATK3_3, 0, 0}, // S_MNTR_ATK3_2 {SPR_MNTR, 23, 12, A_MinotaurAtk3, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK3_3 {SPR_MNTR, 23, 12, NULL, S_MNTR_ATK3_1, 0, 0}, // S_MNTR_ATK3_4 {SPR_MNTR, 20, 2, A_MinotaurCharge, S_MNTR_ATK4_1, 0, 0}, // S_MNTR_ATK4_1 {SPR_MNTR, 4, 3, NULL, S_MNTR_PAIN2, 0, 0}, // S_MNTR_PAIN1 {SPR_MNTR, 4, 6, A_Pain, S_MNTR_WALK1, 0, 0}, // S_MNTR_PAIN2 {SPR_MNTR, 5, 6, NULL, S_MNTR_DIE2, 0, 0}, // S_MNTR_DIE1 {SPR_MNTR, 6, 5, NULL, S_MNTR_DIE3, 0, 0}, // S_MNTR_DIE2 {SPR_MNTR, 7, 6, A_Scream, S_MNTR_DIE4, 0, 0}, // S_MNTR_DIE3 {SPR_MNTR, 8, 5, NULL, S_MNTR_DIE5, 0, 0}, // S_MNTR_DIE4 {SPR_MNTR, 9, 6, NULL, S_MNTR_DIE6, 0, 0}, // S_MNTR_DIE5 {SPR_MNTR, 10, 5, NULL, S_MNTR_DIE7, 0, 0}, // S_MNTR_DIE6 {SPR_MNTR, 11, 6, NULL, S_MNTR_DIE8, 0, 0}, // S_MNTR_DIE7 {SPR_MNTR, 12, 5, A_NoBlocking, S_MNTR_DIE9, 0, 0}, // S_MNTR_DIE8 {SPR_MNTR, 13, 6, NULL, S_MNTR_DIE10, 0, 0}, // S_MNTR_DIE9 {SPR_MNTR, 14, 5, NULL, S_MNTR_DIE11, 0, 0}, // S_MNTR_DIE10 {SPR_MNTR, 15, 6, NULL, S_MNTR_DIE12, 0, 0}, // S_MNTR_DIE11 {SPR_MNTR, 16, 5, NULL, S_MNTR_DIE13, 0, 0}, // S_MNTR_DIE12 {SPR_MNTR, 17, 6, NULL, S_MNTR_DIE14, 0, 0}, // S_MNTR_DIE13 {SPR_MNTR, 18, 5, NULL, S_MNTR_DIE15, 0, 0}, // S_MNTR_DIE14 {SPR_MNTR, 19, -1, A_BossDeath, S_NULL, 0, 0}, // S_MNTR_DIE15 {SPR_FX12, 32768, 6, NULL, S_MNTRFX1_2, 0, 0}, // S_MNTRFX1_1 {SPR_FX12, 32769, 6, NULL, S_MNTRFX1_1, 0, 0}, // S_MNTRFX1_2 {SPR_FX12, 32770, 5, NULL, S_MNTRFXI1_2, 0, 0}, // S_MNTRFXI1_1 {SPR_FX12, 32771, 5, NULL, S_MNTRFXI1_3, 0, 0}, // S_MNTRFXI1_2 {SPR_FX12, 32772, 5, NULL, S_MNTRFXI1_4, 0, 0}, // S_MNTRFXI1_3 {SPR_FX12, 32773, 5, NULL, S_MNTRFXI1_5, 0, 0}, // S_MNTRFXI1_4 {SPR_FX12, 32774, 5, NULL, S_MNTRFXI1_6, 0, 0}, // S_MNTRFXI1_5 {SPR_FX12, 32775, 5, NULL, S_NULL, 0, 0}, // S_MNTRFXI1_6 {SPR_FX13, 0, 2, A_MntrFloorFire, S_MNTRFX2_1, 0, 0}, // S_MNTRFX2_1 {SPR_FX13, 32776, 4, A_Explode, S_MNTRFXI2_2, 0, 0}, // S_MNTRFXI2_1 {SPR_FX13, 32777, 4, NULL, S_MNTRFXI2_3, 0, 0}, // S_MNTRFXI2_2 {SPR_FX13, 32778, 4, NULL, S_MNTRFXI2_4, 0, 0}, // S_MNTRFXI2_3 {SPR_FX13, 32779, 4, NULL, S_MNTRFXI2_5, 0, 0}, // S_MNTRFXI2_4 {SPR_FX13, 32780, 4, NULL, S_NULL, 0, 0}, // S_MNTRFXI2_5 {SPR_FX13, 32771, 4, NULL, S_MNTRFX3_2, 0, 0}, // S_MNTRFX3_1 {SPR_FX13, 32770, 4, NULL, S_MNTRFX3_3, 0, 0}, // S_MNTRFX3_2 {SPR_FX13, 32769, 5, NULL, S_MNTRFX3_4, 0, 0}, // S_MNTRFX3_3 {SPR_FX13, 32770, 5, NULL, S_MNTRFX3_5, 0, 0}, // S_MNTRFX3_4 {SPR_FX13, 32771, 5, NULL, S_MNTRFX3_6, 0, 0}, // S_MNTRFX3_5 {SPR_FX13, 32772, 5, NULL, S_MNTRFX3_7, 0, 0}, // S_MNTRFX3_6 {SPR_FX13, 32773, 4, NULL, S_MNTRFX3_8, 0, 0}, // S_MNTRFX3_7 {SPR_FX13, 32774, 4, NULL, S_MNTRFX3_9, 0, 0}, // S_MNTRFX3_8 {SPR_FX13, 32775, 4, NULL, S_NULL, 0, 0}, // S_MNTRFX3_9 {SPR_AKYY, 32768, 3, NULL, S_AKYY2, 0, 0}, // S_AKYY1 {SPR_AKYY, 32769, 3, NULL, S_AKYY3, 0, 0}, // S_AKYY2 {SPR_AKYY, 32770, 3, NULL, S_AKYY4, 0, 0}, // S_AKYY3 {SPR_AKYY, 32771, 3, NULL, S_AKYY5, 0, 0}, // S_AKYY4 {SPR_AKYY, 32772, 3, NULL, S_AKYY6, 0, 0}, // S_AKYY5 {SPR_AKYY, 32773, 3, NULL, S_AKYY7, 0, 0}, // S_AKYY6 {SPR_AKYY, 32774, 3, NULL, S_AKYY8, 0, 0}, // S_AKYY7 {SPR_AKYY, 32775, 3, NULL, S_AKYY9, 0, 0}, // S_AKYY8 {SPR_AKYY, 32776, 3, NULL, S_AKYY10, 0, 0}, // S_AKYY9 {SPR_AKYY, 32777, 3, NULL, S_AKYY1, 0, 0}, // S_AKYY10 {SPR_BKYY, 32768, 3, NULL, S_BKYY2, 0, 0}, // S_BKYY1 {SPR_BKYY, 32769, 3, NULL, S_BKYY3, 0, 0}, // S_BKYY2 {SPR_BKYY, 32770, 3, NULL, S_BKYY4, 0, 0}, // S_BKYY3 {SPR_BKYY, 32771, 3, NULL, S_BKYY5, 0, 0}, // S_BKYY4 {SPR_BKYY, 32772, 3, NULL, S_BKYY6, 0, 0}, // S_BKYY5 {SPR_BKYY, 32773, 3, NULL, S_BKYY7, 0, 0}, // S_BKYY6 {SPR_BKYY, 32774, 3, NULL, S_BKYY8, 0, 0}, // S_BKYY7 {SPR_BKYY, 32775, 3, NULL, S_BKYY9, 0, 0}, // S_BKYY8 {SPR_BKYY, 32776, 3, NULL, S_BKYY10, 0, 0}, // S_BKYY9 {SPR_BKYY, 32777, 3, NULL, S_BKYY1, 0, 0}, // S_BKYY10 {SPR_CKYY, 32768, 3, NULL, S_CKYY2, 0, 0}, // S_CKYY1 {SPR_CKYY, 32769, 3, NULL, S_CKYY3, 0, 0}, // S_CKYY2 {SPR_CKYY, 32770, 3, NULL, S_CKYY4, 0, 0}, // S_CKYY3 {SPR_CKYY, 32771, 3, NULL, S_CKYY5, 0, 0}, // S_CKYY4 {SPR_CKYY, 32772, 3, NULL, S_CKYY6, 0, 0}, // S_CKYY5 {SPR_CKYY, 32773, 3, NULL, S_CKYY7, 0, 0}, // S_CKYY6 {SPR_CKYY, 32774, 3, NULL, S_CKYY8, 0, 0}, // S_CKYY7 {SPR_CKYY, 32775, 3, NULL, S_CKYY9, 0, 0}, // S_CKYY8 {SPR_CKYY, 32776, 3, NULL, S_CKYY1, 0, 0}, // S_CKYY9 {SPR_AMG1, 0, -1, NULL, S_NULL, 0, 0}, // S_AMG1 {SPR_AMG2, 0, 4, NULL, S_AMG2_2, 0, 0}, // S_AMG2_1 {SPR_AMG2, 1, 4, NULL, S_AMG2_3, 0, 0}, // S_AMG2_2 {SPR_AMG2, 2, 4, NULL, S_AMG2_1, 0, 0}, // S_AMG2_3 {SPR_AMM1, 0, -1, NULL, S_NULL, 0, 0}, // S_AMM1 {SPR_AMM2, 0, -1, NULL, S_NULL, 0, 0}, // S_AMM2 {SPR_AMC1, 0, -1, NULL, S_NULL, 0, 0}, // S_AMC1 {SPR_AMC2, 0, 5, NULL, S_AMC2_2, 0, 0}, // S_AMC2_1 {SPR_AMC2, 1, 5, NULL, S_AMC2_3, 0, 0}, // S_AMC2_2 {SPR_AMC2, 2, 5, NULL, S_AMC2_1, 0, 0}, // S_AMC2_3 {SPR_AMS1, 0, 5, NULL, S_AMS1_2, 0, 0}, // S_AMS1_1 {SPR_AMS1, 1, 5, NULL, S_AMS1_1, 0, 0}, // S_AMS1_2 {SPR_AMS2, 0, 5, NULL, S_AMS2_2, 0, 0}, // S_AMS2_1 {SPR_AMS2, 1, 5, NULL, S_AMS2_1, 0, 0}, // S_AMS2_2 {SPR_AMP1, 0, 4, NULL, S_AMP1_2, 0, 0}, // S_AMP1_1 {SPR_AMP1, 1, 4, NULL, S_AMP1_3, 0, 0}, // S_AMP1_2 {SPR_AMP1, 2, 4, NULL, S_AMP1_1, 0, 0}, // S_AMP1_3 {SPR_AMP2, 0, 4, NULL, S_AMP2_2, 0, 0}, // S_AMP2_1 {SPR_AMP2, 1, 4, NULL, S_AMP2_3, 0, 0}, // S_AMP2_2 {SPR_AMP2, 2, 4, NULL, S_AMP2_1, 0, 0}, // S_AMP2_3 {SPR_AMB1, 0, 4, NULL, S_AMB1_2, 0, 0}, // S_AMB1_1 {SPR_AMB1, 1, 4, NULL, S_AMB1_3, 0, 0}, // S_AMB1_2 {SPR_AMB1, 2, 4, NULL, S_AMB1_1, 0, 0}, // S_AMB1_3 {SPR_AMB2, 0, 4, NULL, S_AMB2_2, 0, 0}, // S_AMB2_1 {SPR_AMB2, 1, 4, NULL, S_AMB2_3, 0, 0}, // S_AMB2_2 {SPR_AMB2, 2, 4, NULL, S_AMB2_1, 0, 0}, // S_AMB2_3 {SPR_AMG1, 0, 100, A_ESound, S_SND_WIND, 0, 0}, // S_SND_WIND {SPR_AMG1, 0, 85, A_ESound, S_SND_WATERFALL, 0, 0} // S_SND_WATERFALL }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = { { // MT_MISC0 81, // doomednum S_ITEM_PTN1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_ITEMSHIELD1 85, // doomednum S_ITEM_SHLD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_ITEMSHIELD2 31, // doomednum S_ITEM_SHD2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_MISC1 8, // doomednum S_ITEM_BAGH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_MISC2 35, // doomednum S_ITEM_SPMP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTIINVISIBILITY 75, // doomednum S_ARTI_INVS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_SHADOW | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_MISC3 82, // doomednum S_ARTI_PTN2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTIFLY 83, // doomednum S_ARTI_SOAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTIINVULNERABILITY 84, // doomednum S_ARTI_INVU1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTITOMEOFPOWER 86, // doomednum S_ARTI_PWBK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTIEGG 30, // doomednum S_ARTI_EGGC1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_EGGFX -1, // doomednum S_EGGFX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_EGGFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 18 * FRACUNIT, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_ARTISUPERHEAL 32, // doomednum S_ARTI_SPHL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_MISC4 33, // doomednum S_ARTI_TRCH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_MISC5 34, // doomednum S_ARTI_FBMB1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_FIREBOMB -1, // doomednum S_FIREBOMB1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_phohit, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_ARTITELEPORT 36, // doomednum S_ARTI_ATLP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_COUNTITEM, // flags MF2_FLOATBOB // flags2 }, { // MT_POD 2035, // doomednum S_POD_WAIT1, // spawnstate 45, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_POD_PAIN1, // painstate 255, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_POD_DIE1, // deathstate S_NULL, // xdeathstate sfx_podexp, // deathsound 0, // speed 16 * FRACUNIT, // radius 54 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID | MF_NOBLOOD | MF_SHOOTABLE | MF_DROPOFF, // flags MF2_WINDTHRUST | MF2_PUSHABLE | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP // flags2 }, { // MT_PODGOO -1, // doomednum S_PODGOO1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_PODGOOX, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2 }, { // MT_PODGENERATOR 43, // doomednum S_PODGENERATOR, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_SPLASH -1, // doomednum S_SPLASH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SPLASHX, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2 }, { // MT_SPLASHBASE -1, // doomednum S_SPLASHBASE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_LAVASPLASH -1, // doomednum S_LAVASPLASH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_LAVASMOKE -1, // doomednum S_LAVASMOKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_SLUDGECHUNK -1, // doomednum S_SLUDGECHUNK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SLUDGECHUNKX, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2 }, { // MT_SLUDGESPLASH -1, // doomednum S_SLUDGESPLASH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_SKULLHANG70 17, // doomednum S_SKULLHANG70_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 70 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_SKULLHANG60 24, // doomednum S_SKULLHANG60_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 60 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_SKULLHANG45 25, // doomednum S_SKULLHANG45_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 45 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_SKULLHANG35 26, // doomednum S_SKULLHANG35_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 35 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_CHANDELIER 28, // doomednum S_CHANDELIER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 60 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_SERPTORCH 27, // doomednum S_SERPTORCH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 12 * FRACUNIT, // radius 54 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_SMALLPILLAR 29, // doomednum S_SMALLPILLAR, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16 * FRACUNIT, // radius 34 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_STALAGMITESMALL 37, // doomednum S_STALAGMITESMALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 8 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_STALAGMITELARGE 38, // doomednum S_STALAGMITELARGE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 12 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_STALACTITESMALL 39, // doomednum S_STALACTITESMALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 8 * FRACUNIT, // radius 36 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_STALACTITELARGE 40, // doomednum S_STALACTITELARGE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 12 * FRACUNIT, // radius 68 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC6 76, // doomednum S_FIREBRAZIER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16 * FRACUNIT, // radius 44 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_BARREL 44, // doomednum S_BARREL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 12 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC7 47, // doomednum S_BRPILLAR, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 14 * FRACUNIT, // radius 128 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC8 48, // doomednum S_MOSS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 23 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC9 49, // doomednum S_MOSS2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 27 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC10 50, // doomednum S_WALLTORCH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC11 51, // doomednum S_HANGINGCORPSE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 8 * FRACUNIT, // radius 104 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_KEYGIZMOBLUE 94, // doomednum S_KEYGIZMO1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16 * FRACUNIT, // radius 50 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_KEYGIZMOGREEN 95, // doomednum S_KEYGIZMO1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16 * FRACUNIT, // radius 50 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_KEYGIZMOYELLOW 96, // doomednum S_KEYGIZMO1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16 * FRACUNIT, // radius 50 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_KEYGIZMOFLOAT -1, // doomednum S_KGZ_START, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 16 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC12 87, // doomednum S_VOLCANO1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 12 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_VOLCANOBLAST -1, // doomednum S_VOLCANOBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_VOLCANOBALLX1, // deathstate S_NULL, // xdeathstate sfx_volhit, // deathsound 2 * FRACUNIT, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_LOGRAV | MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_VOLCANOTBLAST -1, // doomednum S_VOLCANOTBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_VOLCANOTBALLX1, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 2 * FRACUNIT, // speed 8 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_LOGRAV | MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_TELEGLITGEN 74, // doomednum S_TELEGLITGEN1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_TELEGLITGEN2 52, // doomednum S_TELEGLITGEN2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_TELEGLITTER -1, // doomednum S_TELEGLITTER1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags 0 // flags2 }, { // MT_TELEGLITTER2 -1, // doomednum S_TELEGLITTER2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags 0 // flags2 }, { // MT_TFOG -1, // doomednum S_TFOG1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_TELEPORTMAN 14, // doomednum S_NULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_STAFFPUFF -1, // doomednum S_STAFFPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_stfhit, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_STAFFPUFF2 -1, // doomednum S_STAFFPUFF2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_stfpow, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_BEAKPUFF -1, // doomednum S_STAFFPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_chicatk, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC13 2005, // doomednum S_WGNT, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_GAUNTLETPUFF1 -1, // doomednum S_GAUNTLETPUFF1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_GAUNTLETPUFF2 -1, // doomednum S_GAUNTLETPUFF2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_MISC14 53, // doomednum S_BLSR, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_BLASTERFX1 -1, // doomednum S_BLASTERFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BLASTERFXI1_1, // deathstate S_NULL, // xdeathstate sfx_blshit, // deathsound 184 * FRACUNIT, // speed 12 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_BLASTERSMOKE -1, // doomednum S_BLASTERSMOKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2 }, { // MT_RIPPER -1, // doomednum S_RIPPER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_RIPPERX1, // deathstate S_NULL, // xdeathstate sfx_hrnhit, // deathsound 14 * FRACUNIT, // speed 8 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_RIP // flags2 }, { // MT_BLASTERPUFF1 -1, // doomednum S_BLASTERPUFF1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_BLASTERPUFF2 -1, // doomednum S_BLASTERPUFF2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_WMACE 2002, // doomednum S_WMCE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_MACEFX1 -1, // doomednum S_MACEFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_lobsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MACEFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 20 * FRACUNIT, // speed 8 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_NOTELEPORT // flags2 }, { // MT_MACEFX2 -1, // doomednum S_MACEFX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MACEFXI2_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 8 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 6, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_LOGRAV | MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_NOTELEPORT // flags2 }, { // MT_MACEFX3 -1, // doomednum S_MACEFX3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MACEFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 7 * FRACUNIT, // speed 8 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 4, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_LOGRAV | MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_NOTELEPORT // flags2 }, { // MT_MACEFX4 -1, // doomednum S_MACEFX4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MACEFXI4_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 7 * FRACUNIT, // speed 8 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 18, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_LOGRAV | MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_TELESTOMP // flags2 }, { // MT_WSKULLROD 2004, // doomednum S_WSKL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_HORNRODFX1 -1, // doomednum S_HRODFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_hrnsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HRODFXI1_1, // deathstate S_NULL, // xdeathstate sfx_hrnhit, // deathsound 22 * FRACUNIT, // speed 12 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 3, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_WINDTHRUST | MF2_NOTELEPORT // flags2 }, { // MT_HORNRODFX2 -1, // doomednum S_HRODFX2_1, // spawnstate 4 * 35, // spawnhealth S_NULL, // seestate sfx_hrnsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HRODFXI2_1, // deathstate S_NULL, // xdeathstate sfx_ramphit, // deathsound 22 * FRACUNIT, // speed 12 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 10, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_RAINPLR1 -1, // doomednum S_RAINPLR1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_RAINPLR1X_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 12 * FRACUNIT, // speed 5 * FRACUNIT, // radius 12 * FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_RAINPLR2 -1, // doomednum S_RAINPLR2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_RAINPLR2X_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 12 * FRACUNIT, // speed 5 * FRACUNIT, // radius 12 * FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_RAINPLR3 -1, // doomednum S_RAINPLR3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_RAINPLR3X_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 12 * FRACUNIT, // speed 5 * FRACUNIT, // radius 12 * FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_RAINPLR4 -1, // doomednum S_RAINPLR4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_RAINPLR4X_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 12 * FRACUNIT, // speed 5 * FRACUNIT, // radius 12 * FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_GOLDWANDFX1 -1, // doomednum S_GWANDFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_GWANDFXI1_1, // deathstate S_NULL, // xdeathstate sfx_gldhit, // deathsound 22 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_GOLDWANDFX2 -1, // doomednum S_GWANDFX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_GWANDFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 18 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_GOLDWANDPUFF1 -1, // doomednum S_GWANDPUFF1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_GOLDWANDPUFF2 -1, // doomednum S_GWANDFXI1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_WPHOENIXROD 2003, // doomednum S_WPHX, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_PHOENIXFX1 -1, // doomednum S_PHOENIXFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_phosht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_PHOENIXFXI1_1, // deathstate S_NULL, // xdeathstate sfx_phohit, // deathsound 20 * FRACUNIT, // speed 11 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 20, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_THRUGHOST | MF2_NOTELEPORT // flags2 }, // The following thing is present in the mobjinfo table from Heretic 1.0, // but not in Heretic 1.3 (ie. it was removed). It has been re-inserted // here to support HHE patches. { // MT_PHOENIXFX_REMOVED -1, // doomednum S_PHOENIXFXIX_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_PHOENIXFXIX_3, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_PHOENIXPUFF -1, // doomednum S_PHOENIXPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2 }, { // MT_PHOENIXFX2 -1, // doomednum S_PHOENIXFX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_PHOENIXFXI2_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 6 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_MISC15 2001, // doomednum S_WBOW, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_CRBOWFX1 -1, // doomednum S_CRBOWFX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_bowsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CRBOWFXI1_1, // deathstate S_NULL, // xdeathstate sfx_hrnhit, // deathsound 30 * FRACUNIT, // speed 11 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 10, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_CRBOWFX2 -1, // doomednum S_CRBOWFX2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_bowsht, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CRBOWFXI1_1, // deathstate S_NULL, // xdeathstate sfx_hrnhit, // deathsound 32 * FRACUNIT, // speed 11 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 6, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_CRBOWFX3 -1, // doomednum S_CRBOWFX3, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CRBOWFXI3_1, // deathstate S_NULL, // xdeathstate sfx_hrnhit, // deathsound 20 * FRACUNIT, // speed 11 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_WINDTHRUST | MF2_THRUGHOST | MF2_NOTELEPORT // flags2 }, { // MT_CRBOWFX4 -1, // doomednum S_CRBOWFX4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags MF2_LOGRAV // flags2 }, { // MT_BLOOD -1, // doomednum S_BLOOD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_BLOODSPLATTER -1, // doomednum S_BLOODSPLATTER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BLOODSPLATTERX, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2 }, { // MT_PLAYER -1, // doomednum S_PLAY, // spawnstate 100, // spawnhealth S_PLAY_RUN1, // seestate sfx_None, // seesound 0, // reactiontime sfx_None, // attacksound S_PLAY_PAIN, // painstate 255, // painchance sfx_plrpai, // painsound S_NULL, // meleestate S_PLAY_ATK1, // missilestate S_NULL, // crashstate S_PLAY_DIE1, // deathstate S_PLAY_XDIE1, // xdeathstate sfx_plrdth, // deathsound 0, // speed 16 * FRACUNIT, // radius 56 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags MF2_WINDTHRUST | MF2_FOOTCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP // flags2 }, { // MT_BLOODYSKULL -1, // doomednum S_BLOODYSKULL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 4 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_DROPOFF, // flags MF2_LOGRAV | MF2_CANNOTPUSH // flags2 }, { // MT_CHICPLAYER -1, // doomednum S_CHICPLAY, // spawnstate 100, // spawnhealth S_CHICPLAY_RUN1, // seestate sfx_None, // seesound 0, // reactiontime sfx_None, // attacksound S_CHICPLAY_PAIN, // painstate 255, // painchance sfx_chicpai, // painsound S_NULL, // meleestate S_CHICPLAY_ATK1, // missilestate S_NULL, // crashstate S_CHICKEN_DIE1, // deathstate S_NULL, // xdeathstate sfx_chicdth, // deathsound 0, // speed 16 * FRACUNIT, // radius 24 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_NOTDMATCH, // flags MF2_WINDTHRUST | MF2_SLIDE | MF2_PASSMOBJ | MF2_FOOTCLIP | MF2_LOGRAV | MF2_TELESTOMP // flags2 }, { // MT_CHICKEN -1, // doomednum S_CHICKEN_LOOK1, // spawnstate 10, // spawnhealth S_CHICKEN_WALK1, // seestate sfx_chicpai, // seesound 8, // reactiontime sfx_chicatk, // attacksound S_CHICKEN_PAIN1, // painstate 200, // painchance sfx_chicpai, // painsound S_CHICKEN_ATK1, // meleestate 0, // missilestate S_NULL, // crashstate S_CHICKEN_DIE1, // deathstate S_NULL, // xdeathstate sfx_chicdth, // deathsound 4, // speed 9 * FRACUNIT, // radius 22 * FRACUNIT, // height 40, // mass 0, // damage sfx_chicact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF, // flags MF2_WINDTHRUST | MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_FEATHER -1, // doomednum S_FEATHER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FEATHERX, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH | MF2_WINDTHRUST // flags2 }, { // MT_MUMMY 68, // doomednum S_MUMMY_LOOK1, // spawnstate 80, // spawnhealth S_MUMMY_WALK1, // seestate sfx_mumsit, // seesound 8, // reactiontime sfx_mumat1, // attacksound S_MUMMY_PAIN1, // painstate 128, // painchance sfx_mumpai, // painsound S_MUMMY_ATK1, // meleestate 0, // missilestate S_NULL, // crashstate S_MUMMY_DIE1, // deathstate S_NULL, // xdeathstate sfx_mumdth, // deathsound 12, // speed 22 * FRACUNIT, // radius 62 * FRACUNIT, // height 75, // mass 0, // damage sfx_mumact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_MUMMYLEADER 45, // doomednum S_MUMMY_LOOK1, // spawnstate 100, // spawnhealth S_MUMMY_WALK1, // seestate sfx_mumsit, // seesound 8, // reactiontime sfx_mumat1, // attacksound S_MUMMY_PAIN1, // painstate 64, // painchance sfx_mumpai, // painsound S_MUMMY_ATK1, // meleestate S_MUMMYL_ATK1, // missilestate S_NULL, // crashstate S_MUMMY_DIE1, // deathstate S_NULL, // xdeathstate sfx_mumdth, // deathsound 12, // speed 22 * FRACUNIT, // radius 62 * FRACUNIT, // height 75, // mass 0, // damage sfx_mumact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_MUMMYGHOST 69, // doomednum S_MUMMY_LOOK1, // spawnstate 80, // spawnhealth S_MUMMY_WALK1, // seestate sfx_mumsit, // seesound 8, // reactiontime sfx_mumat1, // attacksound S_MUMMY_PAIN1, // painstate 128, // painchance sfx_mumpai, // painsound S_MUMMY_ATK1, // meleestate 0, // missilestate S_NULL, // crashstate S_MUMMY_DIE1, // deathstate S_NULL, // xdeathstate sfx_mumdth, // deathsound 12, // speed 22 * FRACUNIT, // radius 62 * FRACUNIT, // height 75, // mass 0, // damage sfx_mumact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_MUMMYLEADERGHOST 46, // doomednum S_MUMMY_LOOK1, // spawnstate 100, // spawnhealth S_MUMMY_WALK1, // seestate sfx_mumsit, // seesound 8, // reactiontime sfx_mumat1, // attacksound S_MUMMY_PAIN1, // painstate 64, // painchance sfx_mumpai, // painsound S_MUMMY_ATK1, // meleestate S_MUMMYL_ATK1, // missilestate S_NULL, // crashstate S_MUMMY_DIE1, // deathstate S_NULL, // xdeathstate sfx_mumdth, // deathsound 12, // speed 22 * FRACUNIT, // radius 62 * FRACUNIT, // height 75, // mass 0, // damage sfx_mumact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_MUMMYSOUL -1, // doomednum S_MUMMY_SOUL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MUMMYFX1 -1, // doomednum S_MUMMYFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MUMMYFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 9 * FRACUNIT, // speed 8 * FRACUNIT, // radius 14 * FRACUNIT, // height 100, // mass 4, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_BEAST 70, // doomednum S_BEAST_LOOK1, // spawnstate 220, // spawnhealth S_BEAST_WALK1, // seestate sfx_bstsit, // seesound 8, // reactiontime sfx_bstatk, // attacksound S_BEAST_PAIN1, // painstate 100, // painchance sfx_bstpai, // painsound 0, // meleestate S_BEAST_ATK1, // missilestate S_NULL, // crashstate S_BEAST_DIE1, // deathstate S_BEAST_XDIE1, // xdeathstate sfx_bstdth, // deathsound 14, // speed 32 * FRACUNIT, // radius 74 * FRACUNIT, // height 200, // mass 0, // damage sfx_bstact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_BEASTBALL -1, // doomednum S_BEASTBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BEASTBALLX1, // deathstate S_NULL, // xdeathstate 0, // deathsound 12 * FRACUNIT, // speed 9 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 4, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_WINDTHRUST | MF2_NOTELEPORT // flags2 }, { // MT_BURNBALL -1, // doomednum S_BURNBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BEASTBALLX1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 6 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_BURNBALLFB -1, // doomednum S_BURNBALLFB1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BEASTBALLX1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 6 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_PUFFY -1, // doomednum S_PUFFY1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_PUFFY1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 6 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_SNAKE 92, // doomednum S_SNAKE_LOOK1, // spawnstate 280, // spawnhealth S_SNAKE_WALK1, // seestate sfx_snksit, // seesound 8, // reactiontime sfx_snkatk, // attacksound S_SNAKE_PAIN1, // painstate 48, // painchance sfx_snkpai, // painsound 0, // meleestate S_SNAKE_ATK1, // missilestate S_NULL, // crashstate S_SNAKE_DIE1, // deathstate S_NULL, // xdeathstate sfx_snkdth, // deathsound 10, // speed 22 * FRACUNIT, // radius 70 * FRACUNIT, // height 100, // mass 0, // damage sfx_snkact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_SNAKEPRO_A -1, // doomednum S_SNAKEPRO_A1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SNAKEPRO_AX1, // deathstate S_NULL, // xdeathstate 0, // deathsound 14 * FRACUNIT, // speed 12 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_WINDTHRUST | MF2_NOTELEPORT // flags2 }, { // MT_SNAKEPRO_B -1, // doomednum S_SNAKEPRO_B1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SNAKEPRO_BX1, // deathstate S_NULL, // xdeathstate 0, // deathsound 14 * FRACUNIT, // speed 12 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 3, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_HEAD 6, // doomednum S_HEAD_LOOK, // spawnstate 700, // spawnhealth S_HEAD_FLOAT, // seestate sfx_hedsit, // seesound 8, // reactiontime sfx_hedat1, // attacksound S_HEAD_PAIN1, // painstate 32, // painchance sfx_hedpai, // painsound 0, // meleestate S_HEAD_ATK1, // missilestate S_NULL, // crashstate S_HEAD_DIE1, // deathstate S_NULL, // xdeathstate sfx_heddth, // deathsound 6, // speed 40 * FRACUNIT, // radius 72 * FRACUNIT, // height 325, // mass 0, // damage sfx_hedact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags MF2_PASSMOBJ // flags2 }, { // MT_HEADFX1 -1, // doomednum S_HEADFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HEADFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 13 * FRACUNIT, // speed 12 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_THRUGHOST // flags2 }, { // MT_HEADFX2 -1, // doomednum S_HEADFX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HEADFXI2_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 8 * FRACUNIT, // speed 12 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 3, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_HEADFX3 -1, // doomednum S_HEADFX3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HEADFXI3_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 14 * FRACUNIT, // radius 12 * FRACUNIT, // height 100, // mass 5, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_WINDTHRUST | MF2_NOTELEPORT // flags2 }, { // MT_WHIRLWIND -1, // doomednum S_HEADFX4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HEADFXI4_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 16 * FRACUNIT, // radius 74 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_SHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_CLINK 90, // doomednum S_CLINK_LOOK1, // spawnstate 150, // spawnhealth S_CLINK_WALK1, // seestate sfx_clksit, // seesound 8, // reactiontime sfx_clkatk, // attacksound S_CLINK_PAIN1, // painstate 32, // painchance sfx_clkpai, // painsound S_CLINK_ATK1, // meleestate 0, // missilestate S_NULL, // crashstate S_CLINK_DIE1, // deathstate S_NULL, // xdeathstate sfx_clkdth, // deathsound 14, // speed 20 * FRACUNIT, // radius 64 * FRACUNIT, // height 75, // mass 0, // damage sfx_clkact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_WIZARD 15, // doomednum S_WIZARD_LOOK1, // spawnstate 180, // spawnhealth S_WIZARD_WALK1, // seestate sfx_wizsit, // seesound 8, // reactiontime sfx_wizatk, // attacksound S_WIZARD_PAIN1, // painstate 64, // painchance sfx_wizpai, // painsound 0, // meleestate S_WIZARD_ATK1, // missilestate S_NULL, // crashstate S_WIZARD_DIE1, // deathstate S_NULL, // xdeathstate sfx_wizdth, // deathsound 12, // speed 16 * FRACUNIT, // radius 68 * FRACUNIT, // height 100, // mass 0, // damage sfx_wizact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_FLOAT | MF_NOGRAVITY, // flags MF2_PASSMOBJ // flags2 }, { // MT_WIZFX1 -1, // doomednum S_WIZFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_WIZFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 18 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 3, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_IMP 66, // doomednum S_IMP_LOOK1, // spawnstate 40, // spawnhealth S_IMP_FLY1, // seestate sfx_impsit, // seesound 8, // reactiontime sfx_impat1, // attacksound S_IMP_PAIN1, // painstate 200, // painchance sfx_imppai, // painsound S_IMP_MEATK1, // meleestate S_IMP_MSATK1_1, // missilestate S_IMP_CRASH1, // crashstate S_IMP_DIE1, // deathstate S_IMP_XDIE1, // xdeathstate sfx_impdth, // deathsound 10, // speed 16 * FRACUNIT, // radius 36 * FRACUNIT, // height 50, // mass 0, // damage sfx_impact, // activesound MF_SOLID | MF_SHOOTABLE | MF_FLOAT | MF_NOGRAVITY | MF_COUNTKILL, // flags MF2_SPAWNFLOAT | MF2_PASSMOBJ // flags2 }, { // MT_IMPLEADER 5, // doomednum S_IMP_LOOK1, // spawnstate 80, // spawnhealth S_IMP_FLY1, // seestate sfx_impsit, // seesound 8, // reactiontime sfx_impat2, // attacksound S_IMP_PAIN1, // painstate 200, // painchance sfx_imppai, // painsound 0, // meleestate S_IMP_MSATK2_1, // missilestate S_IMP_CRASH1, // crashstate S_IMP_DIE1, // deathstate S_IMP_XDIE1, // xdeathstate sfx_impdth, // deathsound 10, // speed 16 * FRACUNIT, // radius 36 * FRACUNIT, // height 50, // mass 0, // damage sfx_impact, // activesound MF_SOLID | MF_SHOOTABLE | MF_FLOAT | MF_NOGRAVITY | MF_COUNTKILL, // flags MF2_SPAWNFLOAT | MF2_PASSMOBJ // flags2 }, { // MT_IMPCHUNK1 -1, // doomednum S_IMP_CHUNKA1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_IMPCHUNK2 -1, // doomednum S_IMP_CHUNKB1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_IMPBALL -1, // doomednum S_IMPFX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_IMPFXI1, // deathstate S_NULL, // xdeathstate 0, // deathsound 10 * FRACUNIT, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_WINDTHRUST | MF2_NOTELEPORT // flags2 }, { // MT_KNIGHT 64, // doomednum S_KNIGHT_STND1, // spawnstate 200, // spawnhealth S_KNIGHT_WALK1, // seestate sfx_kgtsit, // seesound 8, // reactiontime sfx_kgtatk, // attacksound S_KNIGHT_PAIN1, // painstate 100, // painchance sfx_kgtpai, // painsound S_KNIGHT_ATK1, // meleestate S_KNIGHT_ATK1, // missilestate S_NULL, // crashstate S_KNIGHT_DIE1, // deathstate S_NULL, // xdeathstate sfx_kgtdth, // deathsound 12, // speed 24 * FRACUNIT, // radius 78 * FRACUNIT, // height 150, // mass 0, // damage sfx_kgtact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_KNIGHTGHOST 65, // doomednum S_KNIGHT_STND1, // spawnstate 200, // spawnhealth S_KNIGHT_WALK1, // seestate sfx_kgtsit, // seesound 8, // reactiontime sfx_kgtatk, // attacksound S_KNIGHT_PAIN1, // painstate 100, // painchance sfx_kgtpai, // painsound S_KNIGHT_ATK1, // meleestate S_KNIGHT_ATK1, // missilestate S_NULL, // crashstate S_KNIGHT_DIE1, // deathstate S_NULL, // xdeathstate sfx_kgtdth, // deathsound 12, // speed 24 * FRACUNIT, // radius 78 * FRACUNIT, // height 150, // mass 0, // damage sfx_kgtact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags MF2_FOOTCLIP | MF2_PASSMOBJ // flags2 }, { // MT_KNIGHTAXE -1, // doomednum S_SPINAXE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SPINAXEX1, // deathstate S_NULL, // xdeathstate sfx_hrnhit, // deathsound 9 * FRACUNIT, // speed 10 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_WINDTHRUST | MF2_NOTELEPORT | MF2_THRUGHOST // flags2 }, { // MT_REDAXE -1, // doomednum S_REDAXE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_REDAXEX1, // deathstate S_NULL, // xdeathstate sfx_hrnhit, // deathsound 9 * FRACUNIT, // speed 10 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 7, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_THRUGHOST // flags2 }, { // MT_SORCERER1 7, // doomednum S_SRCR1_LOOK1, // spawnstate 2000, // spawnhealth S_SRCR1_WALK1, // seestate sfx_sbtsit, // seesound 8, // reactiontime sfx_sbtatk, // attacksound S_SRCR1_PAIN1, // painstate 56, // painchance sfx_sbtpai, // painsound 0, // meleestate S_SRCR1_ATK1, // missilestate S_NULL, // crashstate S_SRCR1_DIE1, // deathstate S_NULL, // xdeathstate sfx_sbtdth, // deathsound 16, // speed 28 * FRACUNIT, // radius 100 * FRACUNIT, // height 800, // mass 0, // damage sfx_sbtact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FOOTCLIP | MF2_PASSMOBJ | MF2_BOSS // flags2 }, { // MT_SRCRFX1 -1, // doomednum S_SRCRFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SRCRFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 20 * FRACUNIT, // speed 10 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 10, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_SORCERER2 -1, // doomednum S_SOR2_LOOK1, // spawnstate 3500, // spawnhealth S_SOR2_WALK1, // seestate sfx_sorsit, // seesound 8, // reactiontime sfx_soratk, // attacksound S_SOR2_PAIN1, // painstate 32, // painchance sfx_sorpai, // painsound 0, // meleestate S_SOR2_ATK1, // missilestate S_NULL, // crashstate S_SOR2_DIE1, // deathstate S_NULL, // xdeathstate 0, // deathsound 14, // speed 16 * FRACUNIT, // radius 70 * FRACUNIT, // height 300, // mass 0, // damage sfx_soract, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF, // flags MF2_FOOTCLIP | MF2_PASSMOBJ | MF2_BOSS // flags2 }, { // MT_SOR2FX1 -1, // doomednum S_SOR2FX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SOR2FXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 20 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_SOR2FXSPARK -1, // doomednum S_SOR2FXSPARK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2 }, { // MT_SOR2FX2 -1, // doomednum S_SOR2FX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SOR2FXI2_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 6 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 10, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_SOR2TELEFADE -1, // doomednum S_SOR2TELEFADE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_MINOTAUR 9, // doomednum S_MNTR_LOOK1, // spawnstate 3000, // spawnhealth S_MNTR_WALK1, // seestate sfx_minsit, // seesound 8, // reactiontime sfx_minat1, // attacksound S_MNTR_PAIN1, // painstate 25, // painchance sfx_minpai, // painsound S_MNTR_ATK1_1, // meleestate S_MNTR_ATK2_1, // missilestate S_NULL, // crashstate S_MNTR_DIE1, // deathstate S_NULL, // xdeathstate sfx_mindth, // deathsound 16, // speed 28 * FRACUNIT, // radius 100 * FRACUNIT, // height 800, // mass 7, // damage sfx_minact, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF, // flags MF2_FOOTCLIP | MF2_PASSMOBJ | MF2_BOSS // flags2 }, { // MT_MNTRFX1 -1, // doomednum S_MNTRFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MNTRFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 20 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 3, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_MNTRFX2 -1, // doomednum S_MNTRFX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MNTRFXI2_1, // deathstate S_NULL, // xdeathstate sfx_phohit, // deathsound 14 * FRACUNIT, // speed 5 * FRACUNIT, // radius 12 * FRACUNIT, // height 100, // mass 4, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_MNTRFX3 -1, // doomednum S_MNTRFX3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MNTRFXI2_1, // deathstate S_NULL, // xdeathstate sfx_phohit, // deathsound 0, // speed 8 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 4, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_AKYY 73, // doomednum S_AKYY1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_NOTDMATCH, // flags 0 // flags2 }, { // MT_BKYY 79, // doomednum S_BKYY1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_NOTDMATCH, // flags 0 // flags2 }, { // MT_CKEY 80, // doomednum S_CKYY1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL | MF_NOTDMATCH, // flags 0 // flags2 }, { // MT_AMGWNDWIMPY 10, // doomednum S_AMG1, // spawnstate AMMO_GWND_WIMPY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMGWNDHEFTY 12, // doomednum S_AMG2_1, // spawnstate AMMO_GWND_HEFTY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMMACEWIMPY 13, // doomednum S_AMM1, // spawnstate AMMO_MACE_WIMPY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMMACEHEFTY 16, // doomednum S_AMM2, // spawnstate AMMO_MACE_HEFTY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMCBOWWIMPY 18, // doomednum S_AMC1, // spawnstate AMMO_CBOW_WIMPY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMCBOWHEFTY 19, // doomednum S_AMC2_1, // spawnstate AMMO_CBOW_HEFTY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMSKRDWIMPY 20, // doomednum S_AMS1_1, // spawnstate AMMO_SKRD_WIMPY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMSKRDHEFTY 21, // doomednum S_AMS2_1, // spawnstate AMMO_SKRD_HEFTY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMPHRDWIMPY 22, // doomednum S_AMP1_1, // spawnstate AMMO_PHRD_WIMPY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMPHRDHEFTY 23, // doomednum S_AMP2_1, // spawnstate AMMO_PHRD_HEFTY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMBLSRWIMPY 54, // doomednum S_AMB1_1, // spawnstate AMMO_BLSR_WIMPY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AMBLSRHEFTY 55, // doomednum S_AMB2_1, // spawnstate AMMO_BLSR_HEFTY, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_SOUNDWIND 42, // doomednum S_SND_WIND, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_SOUNDWATERFALL 41, // doomednum S_SND_WATERFALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags 0 // flags2 } }; chocolate-doom-chocolate-doom-2.2.1/src/heretic/info.h000066400000000000000000000677111257432200600226370ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef HERETIC_INFO_H #define HERETIC_INFO_H typedef enum { SPR_IMPX, SPR_ACLO, SPR_PTN1, SPR_SHLD, SPR_SHD2, SPR_BAGH, SPR_SPMP, SPR_INVS, SPR_PTN2, SPR_SOAR, SPR_INVU, SPR_PWBK, SPR_EGGC, SPR_EGGM, SPR_FX01, SPR_SPHL, SPR_TRCH, SPR_FBMB, SPR_XPL1, SPR_ATLP, SPR_PPOD, SPR_AMG1, SPR_SPSH, SPR_LVAS, SPR_SLDG, SPR_SKH1, SPR_SKH2, SPR_SKH3, SPR_SKH4, SPR_CHDL, SPR_SRTC, SPR_SMPL, SPR_STGS, SPR_STGL, SPR_STCS, SPR_STCL, SPR_KFR1, SPR_BARL, SPR_BRPL, SPR_MOS1, SPR_MOS2, SPR_WTRH, SPR_HCOR, SPR_KGZ1, SPR_KGZB, SPR_KGZG, SPR_KGZY, SPR_VLCO, SPR_VFBL, SPR_VTFB, SPR_SFFI, SPR_TGLT, SPR_TELE, SPR_STFF, SPR_PUF3, SPR_PUF4, SPR_BEAK, SPR_WGNT, SPR_GAUN, SPR_PUF1, SPR_WBLS, SPR_BLSR, SPR_FX18, SPR_FX17, SPR_WMCE, SPR_MACE, SPR_FX02, SPR_WSKL, SPR_HROD, SPR_FX00, SPR_FX20, SPR_FX21, SPR_FX22, SPR_FX23, SPR_GWND, SPR_PUF2, SPR_WPHX, SPR_PHNX, SPR_FX04, SPR_FX08, SPR_FX09, SPR_WBOW, SPR_CRBW, SPR_FX03, SPR_BLOD, SPR_PLAY, SPR_FDTH, SPR_BSKL, SPR_CHKN, SPR_MUMM, SPR_FX15, SPR_BEAS, SPR_FRB1, SPR_SNKE, SPR_SNFX, SPR_HEAD, SPR_FX05, SPR_FX06, SPR_FX07, SPR_CLNK, SPR_WZRD, SPR_FX11, SPR_FX10, SPR_KNIG, SPR_SPAX, SPR_RAXE, SPR_SRCR, SPR_FX14, SPR_SOR2, SPR_SDTH, SPR_FX16, SPR_MNTR, SPR_FX12, SPR_FX13, SPR_AKYY, SPR_BKYY, SPR_CKYY, SPR_AMG2, SPR_AMM1, SPR_AMM2, SPR_AMC1, SPR_AMC2, SPR_AMS1, SPR_AMS2, SPR_AMP1, SPR_AMP2, SPR_AMB1, SPR_AMB2, NUMSPRITES } spritenum_t; typedef enum { S_NULL, S_FREETARGMOBJ, S_ITEM_PTN1_1, S_ITEM_PTN1_2, S_ITEM_PTN1_3, S_ITEM_SHLD1, S_ITEM_SHD2_1, S_ITEM_BAGH1, S_ITEM_SPMP1, S_HIDESPECIAL1, S_HIDESPECIAL2, S_HIDESPECIAL3, S_HIDESPECIAL4, S_HIDESPECIAL5, S_HIDESPECIAL6, S_HIDESPECIAL7, S_HIDESPECIAL8, S_HIDESPECIAL9, S_HIDESPECIAL10, S_HIDESPECIAL11, S_DORMANTARTI1, S_DORMANTARTI2, S_DORMANTARTI3, S_DORMANTARTI4, S_DORMANTARTI5, S_DORMANTARTI6, S_DORMANTARTI7, S_DORMANTARTI8, S_DORMANTARTI9, S_DORMANTARTI10, S_DORMANTARTI11, S_DORMANTARTI12, S_DORMANTARTI13, S_DORMANTARTI14, S_DORMANTARTI15, S_DORMANTARTI16, S_DORMANTARTI17, S_DORMANTARTI18, S_DORMANTARTI19, S_DORMANTARTI20, S_DORMANTARTI21, S_DEADARTI1, S_DEADARTI2, S_DEADARTI3, S_DEADARTI4, S_DEADARTI5, S_DEADARTI6, S_DEADARTI7, S_DEADARTI8, S_DEADARTI9, S_DEADARTI10, S_ARTI_INVS1, S_ARTI_PTN2_1, S_ARTI_PTN2_2, S_ARTI_PTN2_3, S_ARTI_SOAR1, S_ARTI_SOAR2, S_ARTI_SOAR3, S_ARTI_SOAR4, S_ARTI_INVU1, S_ARTI_INVU2, S_ARTI_INVU3, S_ARTI_INVU4, S_ARTI_PWBK1, S_ARTI_EGGC1, S_ARTI_EGGC2, S_ARTI_EGGC3, S_ARTI_EGGC4, S_EGGFX1, S_EGGFX2, S_EGGFX3, S_EGGFX4, S_EGGFX5, S_EGGFXI1_1, S_EGGFXI1_2, S_EGGFXI1_3, S_EGGFXI1_4, S_ARTI_SPHL1, S_ARTI_TRCH1, S_ARTI_TRCH2, S_ARTI_TRCH3, S_ARTI_FBMB1, S_FIREBOMB1, S_FIREBOMB2, S_FIREBOMB3, S_FIREBOMB4, S_FIREBOMB5, S_FIREBOMB6, S_FIREBOMB7, S_FIREBOMB8, S_FIREBOMB9, S_FIREBOMB10, S_FIREBOMB11, S_ARTI_ATLP1, S_ARTI_ATLP2, S_ARTI_ATLP3, S_ARTI_ATLP4, S_POD_WAIT1, S_POD_PAIN1, S_POD_DIE1, S_POD_DIE2, S_POD_DIE3, S_POD_DIE4, S_POD_GROW1, S_POD_GROW2, S_POD_GROW3, S_POD_GROW4, S_POD_GROW5, S_POD_GROW6, S_POD_GROW7, S_POD_GROW8, S_PODGOO1, S_PODGOO2, S_PODGOOX, S_PODGENERATOR, S_SPLASH1, S_SPLASH2, S_SPLASH3, S_SPLASH4, S_SPLASHX, S_SPLASHBASE1, S_SPLASHBASE2, S_SPLASHBASE3, S_SPLASHBASE4, S_SPLASHBASE5, S_SPLASHBASE6, S_SPLASHBASE7, S_LAVASPLASH1, S_LAVASPLASH2, S_LAVASPLASH3, S_LAVASPLASH4, S_LAVASPLASH5, S_LAVASPLASH6, S_LAVASMOKE1, S_LAVASMOKE2, S_LAVASMOKE3, S_LAVASMOKE4, S_LAVASMOKE5, S_SLUDGECHUNK1, S_SLUDGECHUNK2, S_SLUDGECHUNK3, S_SLUDGECHUNK4, S_SLUDGECHUNKX, S_SLUDGESPLASH1, S_SLUDGESPLASH2, S_SLUDGESPLASH3, S_SLUDGESPLASH4, S_SKULLHANG70_1, S_SKULLHANG60_1, S_SKULLHANG45_1, S_SKULLHANG35_1, S_CHANDELIER1, S_CHANDELIER2, S_CHANDELIER3, S_SERPTORCH1, S_SERPTORCH2, S_SERPTORCH3, S_SMALLPILLAR, S_STALAGMITESMALL, S_STALAGMITELARGE, S_STALACTITESMALL, S_STALACTITELARGE, S_FIREBRAZIER1, S_FIREBRAZIER2, S_FIREBRAZIER3, S_FIREBRAZIER4, S_FIREBRAZIER5, S_FIREBRAZIER6, S_FIREBRAZIER7, S_FIREBRAZIER8, S_BARREL, S_BRPILLAR, S_MOSS1, S_MOSS2, S_WALLTORCH1, S_WALLTORCH2, S_WALLTORCH3, S_HANGINGCORPSE, S_KEYGIZMO1, S_KEYGIZMO2, S_KEYGIZMO3, S_KGZ_START, S_KGZ_BLUEFLOAT1, S_KGZ_GREENFLOAT1, S_KGZ_YELLOWFLOAT1, S_VOLCANO1, S_VOLCANO2, S_VOLCANO3, S_VOLCANO4, S_VOLCANO5, S_VOLCANO6, S_VOLCANO7, S_VOLCANO8, S_VOLCANO9, S_VOLCANOBALL1, S_VOLCANOBALL2, S_VOLCANOBALLX1, S_VOLCANOBALLX2, S_VOLCANOBALLX3, S_VOLCANOBALLX4, S_VOLCANOBALLX5, S_VOLCANOBALLX6, S_VOLCANOTBALL1, S_VOLCANOTBALL2, S_VOLCANOTBALLX1, S_VOLCANOTBALLX2, S_VOLCANOTBALLX3, S_VOLCANOTBALLX4, S_VOLCANOTBALLX5, S_VOLCANOTBALLX6, S_VOLCANOTBALLX7, S_TELEGLITGEN1, S_TELEGLITGEN2, S_TELEGLITTER1_1, S_TELEGLITTER1_2, S_TELEGLITTER1_3, S_TELEGLITTER1_4, S_TELEGLITTER1_5, S_TELEGLITTER2_1, S_TELEGLITTER2_2, S_TELEGLITTER2_3, S_TELEGLITTER2_4, S_TELEGLITTER2_5, S_TFOG1, S_TFOG2, S_TFOG3, S_TFOG4, S_TFOG5, S_TFOG6, S_TFOG7, S_TFOG8, S_TFOG9, S_TFOG10, S_TFOG11, S_TFOG12, S_TFOG13, S_LIGHTDONE, S_STAFFREADY, S_STAFFDOWN, S_STAFFUP, S_STAFFREADY2_1, S_STAFFREADY2_2, S_STAFFREADY2_3, S_STAFFDOWN2, S_STAFFUP2, S_STAFFATK1_1, S_STAFFATK1_2, S_STAFFATK1_3, S_STAFFATK2_1, S_STAFFATK2_2, S_STAFFATK2_3, S_STAFFPUFF1, S_STAFFPUFF2, S_STAFFPUFF3, S_STAFFPUFF4, S_STAFFPUFF2_1, S_STAFFPUFF2_2, S_STAFFPUFF2_3, S_STAFFPUFF2_4, S_STAFFPUFF2_5, S_STAFFPUFF2_6, S_BEAKREADY, S_BEAKDOWN, S_BEAKUP, S_BEAKATK1_1, S_BEAKATK2_1, S_WGNT, S_GAUNTLETREADY, S_GAUNTLETDOWN, S_GAUNTLETUP, S_GAUNTLETREADY2_1, S_GAUNTLETREADY2_2, S_GAUNTLETREADY2_3, S_GAUNTLETDOWN2, S_GAUNTLETUP2, S_GAUNTLETATK1_1, S_GAUNTLETATK1_2, S_GAUNTLETATK1_3, S_GAUNTLETATK1_4, S_GAUNTLETATK1_5, S_GAUNTLETATK1_6, S_GAUNTLETATK1_7, S_GAUNTLETATK2_1, S_GAUNTLETATK2_2, S_GAUNTLETATK2_3, S_GAUNTLETATK2_4, S_GAUNTLETATK2_5, S_GAUNTLETATK2_6, S_GAUNTLETATK2_7, S_GAUNTLETPUFF1_1, S_GAUNTLETPUFF1_2, S_GAUNTLETPUFF1_3, S_GAUNTLETPUFF1_4, S_GAUNTLETPUFF2_1, S_GAUNTLETPUFF2_2, S_GAUNTLETPUFF2_3, S_GAUNTLETPUFF2_4, S_BLSR, S_BLASTERREADY, S_BLASTERDOWN, S_BLASTERUP, S_BLASTERATK1_1, S_BLASTERATK1_2, S_BLASTERATK1_3, S_BLASTERATK1_4, S_BLASTERATK1_5, S_BLASTERATK1_6, S_BLASTERATK2_1, S_BLASTERATK2_2, S_BLASTERATK2_3, S_BLASTERATK2_4, S_BLASTERATK2_5, S_BLASTERATK2_6, S_BLASTERFX1_1, S_BLASTERFXI1_1, S_BLASTERFXI1_2, S_BLASTERFXI1_3, S_BLASTERFXI1_4, S_BLASTERFXI1_5, S_BLASTERFXI1_6, S_BLASTERFXI1_7, S_BLASTERSMOKE1, S_BLASTERSMOKE2, S_BLASTERSMOKE3, S_BLASTERSMOKE4, S_BLASTERSMOKE5, S_RIPPER1, S_RIPPER2, S_RIPPERX1, S_RIPPERX2, S_RIPPERX3, S_RIPPERX4, S_RIPPERX5, S_BLASTERPUFF1_1, S_BLASTERPUFF1_2, S_BLASTERPUFF1_3, S_BLASTERPUFF1_4, S_BLASTERPUFF1_5, S_BLASTERPUFF2_1, S_BLASTERPUFF2_2, S_BLASTERPUFF2_3, S_BLASTERPUFF2_4, S_BLASTERPUFF2_5, S_BLASTERPUFF2_6, S_BLASTERPUFF2_7, S_WMCE, S_MACEREADY, S_MACEDOWN, S_MACEUP, S_MACEATK1_1, S_MACEATK1_2, S_MACEATK1_3, S_MACEATK1_4, S_MACEATK1_5, S_MACEATK1_6, S_MACEATK1_7, S_MACEATK1_8, S_MACEATK1_9, S_MACEATK1_10, S_MACEATK2_1, S_MACEATK2_2, S_MACEATK2_3, S_MACEATK2_4, S_MACEFX1_1, S_MACEFX1_2, S_MACEFXI1_1, S_MACEFXI1_2, S_MACEFXI1_3, S_MACEFXI1_4, S_MACEFXI1_5, S_MACEFX2_1, S_MACEFX2_2, S_MACEFXI2_1, S_MACEFX3_1, S_MACEFX3_2, S_MACEFX4_1, S_MACEFXI4_1, S_WSKL, S_HORNRODREADY, S_HORNRODDOWN, S_HORNRODUP, S_HORNRODATK1_1, S_HORNRODATK1_2, S_HORNRODATK1_3, S_HORNRODATK2_1, S_HORNRODATK2_2, S_HORNRODATK2_3, S_HORNRODATK2_4, S_HORNRODATK2_5, S_HORNRODATK2_6, S_HORNRODATK2_7, S_HORNRODATK2_8, S_HORNRODATK2_9, S_HRODFX1_1, S_HRODFX1_2, S_HRODFXI1_1, S_HRODFXI1_2, S_HRODFXI1_3, S_HRODFXI1_4, S_HRODFXI1_5, S_HRODFXI1_6, S_HRODFX2_1, S_HRODFX2_2, S_HRODFX2_3, S_HRODFX2_4, S_HRODFXI2_1, S_HRODFXI2_2, S_HRODFXI2_3, S_HRODFXI2_4, S_HRODFXI2_5, S_HRODFXI2_6, S_HRODFXI2_7, S_HRODFXI2_8, S_RAINPLR1_1, S_RAINPLR2_1, S_RAINPLR3_1, S_RAINPLR4_1, S_RAINPLR1X_1, S_RAINPLR1X_2, S_RAINPLR1X_3, S_RAINPLR1X_4, S_RAINPLR1X_5, S_RAINPLR2X_1, S_RAINPLR2X_2, S_RAINPLR2X_3, S_RAINPLR2X_4, S_RAINPLR2X_5, S_RAINPLR3X_1, S_RAINPLR3X_2, S_RAINPLR3X_3, S_RAINPLR3X_4, S_RAINPLR3X_5, S_RAINPLR4X_1, S_RAINPLR4X_2, S_RAINPLR4X_3, S_RAINPLR4X_4, S_RAINPLR4X_5, S_RAINAIRXPLR1_1, S_RAINAIRXPLR2_1, S_RAINAIRXPLR3_1, S_RAINAIRXPLR4_1, S_RAINAIRXPLR1_2, S_RAINAIRXPLR2_2, S_RAINAIRXPLR3_2, S_RAINAIRXPLR4_2, S_RAINAIRXPLR1_3, S_RAINAIRXPLR2_3, S_RAINAIRXPLR3_3, S_RAINAIRXPLR4_3, S_GOLDWANDREADY, S_GOLDWANDDOWN, S_GOLDWANDUP, S_GOLDWANDATK1_1, S_GOLDWANDATK1_2, S_GOLDWANDATK1_3, S_GOLDWANDATK1_4, S_GOLDWANDATK2_1, S_GOLDWANDATK2_2, S_GOLDWANDATK2_3, S_GOLDWANDATK2_4, S_GWANDFX1_1, S_GWANDFX1_2, S_GWANDFXI1_1, S_GWANDFXI1_2, S_GWANDFXI1_3, S_GWANDFXI1_4, S_GWANDFX2_1, S_GWANDFX2_2, S_GWANDPUFF1_1, S_GWANDPUFF1_2, S_GWANDPUFF1_3, S_GWANDPUFF1_4, S_GWANDPUFF1_5, S_WPHX, S_PHOENIXREADY, S_PHOENIXDOWN, S_PHOENIXUP, S_PHOENIXATK1_1, S_PHOENIXATK1_2, S_PHOENIXATK1_3, S_PHOENIXATK1_4, S_PHOENIXATK1_5, S_PHOENIXATK2_1, S_PHOENIXATK2_2, S_PHOENIXATK2_3, S_PHOENIXATK2_4, S_PHOENIXFX1_1, S_PHOENIXFXI1_1, S_PHOENIXFXI1_2, S_PHOENIXFXI1_3, S_PHOENIXFXI1_4, S_PHOENIXFXI1_5, S_PHOENIXFXI1_6, S_PHOENIXFXI1_7, S_PHOENIXFXI1_8, S_PHOENIXFXIX_1, // [ States in Heretic 1.0 that were removed S_PHOENIXFXIX_2, S_PHOENIXFXIX_3, // ] S_PHOENIXPUFF1, S_PHOENIXPUFF2, S_PHOENIXPUFF3, S_PHOENIXPUFF4, S_PHOENIXPUFF5, S_PHOENIXFX2_1, S_PHOENIXFX2_2, S_PHOENIXFX2_3, S_PHOENIXFX2_4, S_PHOENIXFX2_5, S_PHOENIXFX2_6, S_PHOENIXFX2_7, S_PHOENIXFX2_8, S_PHOENIXFX2_9, S_PHOENIXFX2_10, S_PHOENIXFXI2_1, S_PHOENIXFXI2_2, S_PHOENIXFXI2_3, S_PHOENIXFXI2_4, S_PHOENIXFXI2_5, S_WBOW, S_CRBOW1, S_CRBOW2, S_CRBOW3, S_CRBOW4, S_CRBOW5, S_CRBOW6, S_CRBOW7, S_CRBOW8, S_CRBOW9, S_CRBOW10, S_CRBOW11, S_CRBOW12, S_CRBOW13, S_CRBOW14, S_CRBOW15, S_CRBOW16, S_CRBOW17, S_CRBOW18, S_CRBOWDOWN, S_CRBOWUP, S_CRBOWATK1_1, S_CRBOWATK1_2, S_CRBOWATK1_3, S_CRBOWATK1_4, S_CRBOWATK1_5, S_CRBOWATK1_6, S_CRBOWATK1_7, S_CRBOWATK1_8, S_CRBOWATK2_1, S_CRBOWATK2_2, S_CRBOWATK2_3, S_CRBOWATK2_4, S_CRBOWATK2_5, S_CRBOWATK2_6, S_CRBOWATK2_7, S_CRBOWATK2_8, S_CRBOWFX1, S_CRBOWFXI1_1, S_CRBOWFXI1_2, S_CRBOWFXI1_3, S_CRBOWFX2, S_CRBOWFX3, S_CRBOWFXI3_1, S_CRBOWFXI3_2, S_CRBOWFXI3_3, S_CRBOWFX4_1, S_CRBOWFX4_2, S_BLOOD1, S_BLOOD2, S_BLOOD3, S_BLOODSPLATTER1, S_BLOODSPLATTER2, S_BLOODSPLATTER3, S_BLOODSPLATTERX, S_PLAY, S_PLAY_RUN1, S_PLAY_RUN2, S_PLAY_RUN3, S_PLAY_RUN4, S_PLAY_ATK1, S_PLAY_ATK2, S_PLAY_PAIN, S_PLAY_PAIN2, S_PLAY_DIE1, S_PLAY_DIE2, S_PLAY_DIE3, S_PLAY_DIE4, S_PLAY_DIE5, S_PLAY_DIE6, S_PLAY_DIE7, S_PLAY_DIE8, S_PLAY_DIE9, S_PLAY_XDIE1, S_PLAY_XDIE2, S_PLAY_XDIE3, S_PLAY_XDIE4, S_PLAY_XDIE5, S_PLAY_XDIE6, S_PLAY_XDIE7, S_PLAY_XDIE8, S_PLAY_XDIE9, S_PLAY_FDTH1, S_PLAY_FDTH2, S_PLAY_FDTH3, S_PLAY_FDTH4, S_PLAY_FDTH5, S_PLAY_FDTH6, S_PLAY_FDTH7, S_PLAY_FDTH8, S_PLAY_FDTH9, S_PLAY_FDTH10, S_PLAY_FDTH11, S_PLAY_FDTH12, S_PLAY_FDTH13, S_PLAY_FDTH14, S_PLAY_FDTH15, S_PLAY_FDTH16, S_PLAY_FDTH17, S_PLAY_FDTH18, S_PLAY_FDTH19, // < These two frames were not present in the Heretic S_PLAY_FDTH20, // < 1.0 executable (fire death animation was extended) S_BLOODYSKULL1, S_BLOODYSKULL2, S_BLOODYSKULL3, S_BLOODYSKULL4, S_BLOODYSKULL5, S_BLOODYSKULLX1, S_BLOODYSKULLX2, S_CHICPLAY, S_CHICPLAY_RUN1, S_CHICPLAY_RUN2, S_CHICPLAY_RUN3, S_CHICPLAY_RUN4, S_CHICPLAY_ATK1, S_CHICPLAY_PAIN, S_CHICPLAY_PAIN2, S_CHICKEN_LOOK1, S_CHICKEN_LOOK2, S_CHICKEN_WALK1, S_CHICKEN_WALK2, S_CHICKEN_PAIN1, S_CHICKEN_PAIN2, S_CHICKEN_ATK1, S_CHICKEN_ATK2, S_CHICKEN_DIE1, S_CHICKEN_DIE2, S_CHICKEN_DIE3, S_CHICKEN_DIE4, S_CHICKEN_DIE5, S_CHICKEN_DIE6, S_CHICKEN_DIE7, S_CHICKEN_DIE8, S_FEATHER1, S_FEATHER2, S_FEATHER3, S_FEATHER4, S_FEATHER5, S_FEATHER6, S_FEATHER7, S_FEATHER8, S_FEATHERX, S_MUMMY_LOOK1, S_MUMMY_LOOK2, S_MUMMY_WALK1, S_MUMMY_WALK2, S_MUMMY_WALK3, S_MUMMY_WALK4, S_MUMMY_ATK1, S_MUMMY_ATK2, S_MUMMY_ATK3, S_MUMMYL_ATK1, S_MUMMYL_ATK2, S_MUMMYL_ATK3, S_MUMMYL_ATK4, S_MUMMYL_ATK5, S_MUMMYL_ATK6, S_MUMMY_PAIN1, S_MUMMY_PAIN2, S_MUMMY_DIE1, S_MUMMY_DIE2, S_MUMMY_DIE3, S_MUMMY_DIE4, S_MUMMY_DIE5, S_MUMMY_DIE6, S_MUMMY_DIE7, S_MUMMY_DIE8, S_MUMMY_SOUL1, S_MUMMY_SOUL2, S_MUMMY_SOUL3, S_MUMMY_SOUL4, S_MUMMY_SOUL5, S_MUMMY_SOUL6, S_MUMMY_SOUL7, S_MUMMYFX1_1, S_MUMMYFX1_2, S_MUMMYFX1_3, S_MUMMYFX1_4, S_MUMMYFXI1_1, S_MUMMYFXI1_2, S_MUMMYFXI1_3, S_MUMMYFXI1_4, S_BEAST_LOOK1, S_BEAST_LOOK2, S_BEAST_WALK1, S_BEAST_WALK2, S_BEAST_WALK3, S_BEAST_WALK4, S_BEAST_WALK5, S_BEAST_WALK6, S_BEAST_ATK1, S_BEAST_ATK2, S_BEAST_PAIN1, S_BEAST_PAIN2, S_BEAST_DIE1, S_BEAST_DIE2, S_BEAST_DIE3, S_BEAST_DIE4, S_BEAST_DIE5, S_BEAST_DIE6, S_BEAST_DIE7, S_BEAST_DIE8, S_BEAST_DIE9, S_BEAST_XDIE1, S_BEAST_XDIE2, S_BEAST_XDIE3, S_BEAST_XDIE4, S_BEAST_XDIE5, S_BEAST_XDIE6, S_BEAST_XDIE7, S_BEAST_XDIE8, S_BEASTBALL1, S_BEASTBALL2, S_BEASTBALL3, S_BEASTBALL4, S_BEASTBALL5, S_BEASTBALL6, S_BEASTBALLX1, S_BEASTBALLX2, S_BEASTBALLX3, S_BEASTBALLX4, S_BEASTBALLX5, S_BURNBALL1, S_BURNBALL2, S_BURNBALL3, S_BURNBALL4, S_BURNBALL5, S_BURNBALL6, S_BURNBALL7, S_BURNBALL8, S_BURNBALLFB1, S_BURNBALLFB2, S_BURNBALLFB3, S_BURNBALLFB4, S_BURNBALLFB5, S_BURNBALLFB6, S_BURNBALLFB7, S_BURNBALLFB8, S_PUFFY1, S_PUFFY2, S_PUFFY3, S_PUFFY4, S_PUFFY5, S_SNAKE_LOOK1, S_SNAKE_LOOK2, S_SNAKE_WALK1, S_SNAKE_WALK2, S_SNAKE_WALK3, S_SNAKE_WALK4, S_SNAKE_ATK1, S_SNAKE_ATK2, S_SNAKE_ATK3, S_SNAKE_ATK4, S_SNAKE_ATK5, S_SNAKE_ATK6, S_SNAKE_ATK7, S_SNAKE_ATK8, S_SNAKE_ATK9, S_SNAKE_PAIN1, S_SNAKE_PAIN2, S_SNAKE_DIE1, S_SNAKE_DIE2, S_SNAKE_DIE3, S_SNAKE_DIE4, S_SNAKE_DIE5, S_SNAKE_DIE6, S_SNAKE_DIE7, S_SNAKE_DIE8, S_SNAKE_DIE9, S_SNAKE_DIE10, S_SNAKEPRO_A1, S_SNAKEPRO_A2, S_SNAKEPRO_A3, S_SNAKEPRO_A4, S_SNAKEPRO_AX1, S_SNAKEPRO_AX2, S_SNAKEPRO_AX3, S_SNAKEPRO_AX4, S_SNAKEPRO_AX5, S_SNAKEPRO_B1, S_SNAKEPRO_B2, S_SNAKEPRO_BX1, S_SNAKEPRO_BX2, S_SNAKEPRO_BX3, S_SNAKEPRO_BX4, S_HEAD_LOOK, S_HEAD_FLOAT, S_HEAD_ATK1, S_HEAD_ATK2, S_HEAD_PAIN1, S_HEAD_PAIN2, S_HEAD_DIE1, S_HEAD_DIE2, S_HEAD_DIE3, S_HEAD_DIE4, S_HEAD_DIE5, S_HEAD_DIE6, S_HEAD_DIE7, S_HEADFX1_1, S_HEADFX1_2, S_HEADFX1_3, S_HEADFXI1_1, S_HEADFXI1_2, S_HEADFXI1_3, S_HEADFXI1_4, S_HEADFX2_1, S_HEADFX2_2, S_HEADFX2_3, S_HEADFXI2_1, S_HEADFXI2_2, S_HEADFXI2_3, S_HEADFXI2_4, S_HEADFX3_1, S_HEADFX3_2, S_HEADFX3_3, S_HEADFX3_4, S_HEADFX3_5, S_HEADFX3_6, S_HEADFXI3_1, S_HEADFXI3_2, S_HEADFXI3_3, S_HEADFXI3_4, S_HEADFX4_1, S_HEADFX4_2, S_HEADFX4_3, S_HEADFX4_4, S_HEADFX4_5, S_HEADFX4_6, S_HEADFX4_7, S_HEADFXI4_1, S_HEADFXI4_2, S_HEADFXI4_3, S_HEADFXI4_4, S_CLINK_LOOK1, S_CLINK_LOOK2, S_CLINK_WALK1, S_CLINK_WALK2, S_CLINK_WALK3, S_CLINK_WALK4, S_CLINK_ATK1, S_CLINK_ATK2, S_CLINK_ATK3, S_CLINK_PAIN1, S_CLINK_PAIN2, S_CLINK_DIE1, S_CLINK_DIE2, S_CLINK_DIE3, S_CLINK_DIE4, S_CLINK_DIE5, S_CLINK_DIE6, S_CLINK_DIE7, S_WIZARD_LOOK1, S_WIZARD_LOOK2, S_WIZARD_WALK1, S_WIZARD_WALK2, S_WIZARD_WALK3, S_WIZARD_WALK4, S_WIZARD_WALK5, S_WIZARD_WALK6, S_WIZARD_WALK7, S_WIZARD_WALK8, S_WIZARD_ATK1, S_WIZARD_ATK2, S_WIZARD_ATK3, S_WIZARD_ATK4, S_WIZARD_ATK5, S_WIZARD_ATK6, S_WIZARD_ATK7, S_WIZARD_ATK8, S_WIZARD_ATK9, S_WIZARD_PAIN1, S_WIZARD_PAIN2, S_WIZARD_DIE1, S_WIZARD_DIE2, S_WIZARD_DIE3, S_WIZARD_DIE4, S_WIZARD_DIE5, S_WIZARD_DIE6, S_WIZARD_DIE7, S_WIZARD_DIE8, S_WIZFX1_1, S_WIZFX1_2, S_WIZFXI1_1, S_WIZFXI1_2, S_WIZFXI1_3, S_WIZFXI1_4, S_WIZFXI1_5, S_IMP_LOOK1, S_IMP_LOOK2, S_IMP_LOOK3, S_IMP_LOOK4, S_IMP_FLY1, S_IMP_FLY2, S_IMP_FLY3, S_IMP_FLY4, S_IMP_FLY5, S_IMP_FLY6, S_IMP_FLY7, S_IMP_FLY8, S_IMP_MEATK1, S_IMP_MEATK2, S_IMP_MEATK3, S_IMP_MSATK1_1, S_IMP_MSATK1_2, S_IMP_MSATK1_3, S_IMP_MSATK1_4, S_IMP_MSATK1_5, S_IMP_MSATK1_6, S_IMP_MSATK2_1, S_IMP_MSATK2_2, S_IMP_MSATK2_3, S_IMP_PAIN1, S_IMP_PAIN2, S_IMP_DIE1, S_IMP_DIE2, S_IMP_XDIE1, S_IMP_XDIE2, S_IMP_XDIE3, S_IMP_XDIE4, S_IMP_XDIE5, S_IMP_CRASH1, S_IMP_CRASH2, S_IMP_CRASH3, S_IMP_CRASH4, S_IMP_XCRASH1, S_IMP_XCRASH2, S_IMP_XCRASH3, S_IMP_CHUNKA1, S_IMP_CHUNKA2, S_IMP_CHUNKA3, S_IMP_CHUNKB1, S_IMP_CHUNKB2, S_IMP_CHUNKB3, S_IMPFX1, S_IMPFX2, S_IMPFX3, S_IMPFXI1, S_IMPFXI2, S_IMPFXI3, S_IMPFXI4, S_KNIGHT_STND1, S_KNIGHT_STND2, S_KNIGHT_WALK1, S_KNIGHT_WALK2, S_KNIGHT_WALK3, S_KNIGHT_WALK4, S_KNIGHT_ATK1, S_KNIGHT_ATK2, S_KNIGHT_ATK3, S_KNIGHT_ATK4, S_KNIGHT_ATK5, S_KNIGHT_ATK6, S_KNIGHT_PAIN1, S_KNIGHT_PAIN2, S_KNIGHT_DIE1, S_KNIGHT_DIE2, S_KNIGHT_DIE3, S_KNIGHT_DIE4, S_KNIGHT_DIE5, S_KNIGHT_DIE6, S_KNIGHT_DIE7, S_SPINAXE1, S_SPINAXE2, S_SPINAXE3, S_SPINAXEX1, S_SPINAXEX2, S_SPINAXEX3, S_REDAXE1, S_REDAXE2, S_REDAXEX1, S_REDAXEX2, S_REDAXEX3, S_SRCR1_LOOK1, S_SRCR1_LOOK2, S_SRCR1_WALK1, S_SRCR1_WALK2, S_SRCR1_WALK3, S_SRCR1_WALK4, S_SRCR1_PAIN1, S_SRCR1_ATK1, S_SRCR1_ATK2, S_SRCR1_ATK3, S_SRCR1_ATK4, S_SRCR1_ATK5, S_SRCR1_ATK6, S_SRCR1_ATK7, S_SRCR1_DIE1, S_SRCR1_DIE2, S_SRCR1_DIE3, S_SRCR1_DIE4, S_SRCR1_DIE5, S_SRCR1_DIE6, S_SRCR1_DIE7, S_SRCR1_DIE8, S_SRCR1_DIE9, S_SRCR1_DIE10, S_SRCR1_DIE11, S_SRCR1_DIE12, S_SRCR1_DIE13, S_SRCR1_DIE14, S_SRCR1_DIE15, S_SRCR1_DIE16, S_SRCR1_DIE17, S_SRCRFX1_1, S_SRCRFX1_2, S_SRCRFX1_3, S_SRCRFXI1_1, S_SRCRFXI1_2, S_SRCRFXI1_3, S_SRCRFXI1_4, S_SRCRFXI1_5, S_SOR2_RISE1, S_SOR2_RISE2, S_SOR2_RISE3, S_SOR2_RISE4, S_SOR2_RISE5, S_SOR2_RISE6, S_SOR2_RISE7, S_SOR2_LOOK1, S_SOR2_LOOK2, S_SOR2_WALK1, S_SOR2_WALK2, S_SOR2_WALK3, S_SOR2_WALK4, S_SOR2_PAIN1, S_SOR2_PAIN2, S_SOR2_ATK1, S_SOR2_ATK2, S_SOR2_ATK3, S_SOR2_TELE1, S_SOR2_TELE2, S_SOR2_TELE3, S_SOR2_TELE4, S_SOR2_TELE5, S_SOR2_TELE6, S_SOR2_DIE1, S_SOR2_DIE2, S_SOR2_DIE3, S_SOR2_DIE4, S_SOR2_DIE5, S_SOR2_DIE6, S_SOR2_DIE7, S_SOR2_DIE8, S_SOR2_DIE9, S_SOR2_DIE10, S_SOR2_DIE11, S_SOR2_DIE12, S_SOR2_DIE13, S_SOR2_DIE14, S_SOR2_DIE15, S_SOR2FX1_1, S_SOR2FX1_2, S_SOR2FX1_3, S_SOR2FXI1_1, S_SOR2FXI1_2, S_SOR2FXI1_3, S_SOR2FXI1_4, S_SOR2FXI1_5, S_SOR2FXI1_6, S_SOR2FXSPARK1, S_SOR2FXSPARK2, S_SOR2FXSPARK3, S_SOR2FX2_1, S_SOR2FX2_2, S_SOR2FX2_3, S_SOR2FXI2_1, S_SOR2FXI2_2, S_SOR2FXI2_3, S_SOR2FXI2_4, S_SOR2FXI2_5, S_SOR2TELEFADE1, S_SOR2TELEFADE2, S_SOR2TELEFADE3, S_SOR2TELEFADE4, S_SOR2TELEFADE5, S_SOR2TELEFADE6, S_MNTR_LOOK1, S_MNTR_LOOK2, S_MNTR_WALK1, S_MNTR_WALK2, S_MNTR_WALK3, S_MNTR_WALK4, S_MNTR_ATK1_1, S_MNTR_ATK1_2, S_MNTR_ATK1_3, S_MNTR_ATK2_1, S_MNTR_ATK2_2, S_MNTR_ATK2_3, S_MNTR_ATK3_1, S_MNTR_ATK3_2, S_MNTR_ATK3_3, S_MNTR_ATK3_4, S_MNTR_ATK4_1, S_MNTR_PAIN1, S_MNTR_PAIN2, S_MNTR_DIE1, S_MNTR_DIE2, S_MNTR_DIE3, S_MNTR_DIE4, S_MNTR_DIE5, S_MNTR_DIE6, S_MNTR_DIE7, S_MNTR_DIE8, S_MNTR_DIE9, S_MNTR_DIE10, S_MNTR_DIE11, S_MNTR_DIE12, S_MNTR_DIE13, S_MNTR_DIE14, S_MNTR_DIE15, S_MNTRFX1_1, S_MNTRFX1_2, S_MNTRFXI1_1, S_MNTRFXI1_2, S_MNTRFXI1_3, S_MNTRFXI1_4, S_MNTRFXI1_5, S_MNTRFXI1_6, S_MNTRFX2_1, S_MNTRFXI2_1, S_MNTRFXI2_2, S_MNTRFXI2_3, S_MNTRFXI2_4, S_MNTRFXI2_5, S_MNTRFX3_1, S_MNTRFX3_2, S_MNTRFX3_3, S_MNTRFX3_4, S_MNTRFX3_5, S_MNTRFX3_6, S_MNTRFX3_7, S_MNTRFX3_8, S_MNTRFX3_9, S_AKYY1, S_AKYY2, S_AKYY3, S_AKYY4, S_AKYY5, S_AKYY6, S_AKYY7, S_AKYY8, S_AKYY9, S_AKYY10, S_BKYY1, S_BKYY2, S_BKYY3, S_BKYY4, S_BKYY5, S_BKYY6, S_BKYY7, S_BKYY8, S_BKYY9, S_BKYY10, S_CKYY1, S_CKYY2, S_CKYY3, S_CKYY4, S_CKYY5, S_CKYY6, S_CKYY7, S_CKYY8, S_CKYY9, S_AMG1, S_AMG2_1, S_AMG2_2, S_AMG2_3, S_AMM1, S_AMM2, S_AMC1, S_AMC2_1, S_AMC2_2, S_AMC2_3, S_AMS1_1, S_AMS1_2, S_AMS2_1, S_AMS2_2, S_AMP1_1, S_AMP1_2, S_AMP1_3, S_AMP2_1, S_AMP2_2, S_AMP2_3, S_AMB1_1, S_AMB1_2, S_AMB1_3, S_AMB2_1, S_AMB2_2, S_AMB2_3, S_SND_WIND, S_SND_WATERFALL, NUMSTATES } statenum_t; typedef struct { spritenum_t sprite; int frame; int tics; void (*action) (); statenum_t nextstate; int misc1, misc2; } state_t; extern state_t states[NUMSTATES]; extern char *sprnames[]; typedef enum { MT_MISC0, MT_ITEMSHIELD1, MT_ITEMSHIELD2, MT_MISC1, MT_MISC2, MT_ARTIINVISIBILITY, MT_MISC3, MT_ARTIFLY, MT_ARTIINVULNERABILITY, MT_ARTITOMEOFPOWER, MT_ARTIEGG, MT_EGGFX, MT_ARTISUPERHEAL, MT_MISC4, MT_MISC5, MT_FIREBOMB, MT_ARTITELEPORT, MT_POD, MT_PODGOO, MT_PODGENERATOR, MT_SPLASH, MT_SPLASHBASE, MT_LAVASPLASH, MT_LAVASMOKE, MT_SLUDGECHUNK, MT_SLUDGESPLASH, MT_SKULLHANG70, MT_SKULLHANG60, MT_SKULLHANG45, MT_SKULLHANG35, MT_CHANDELIER, MT_SERPTORCH, MT_SMALLPILLAR, MT_STALAGMITESMALL, MT_STALAGMITELARGE, MT_STALACTITESMALL, MT_STALACTITELARGE, MT_MISC6, MT_BARREL, MT_MISC7, MT_MISC8, MT_MISC9, MT_MISC10, MT_MISC11, MT_KEYGIZMOBLUE, MT_KEYGIZMOGREEN, MT_KEYGIZMOYELLOW, MT_KEYGIZMOFLOAT, MT_MISC12, MT_VOLCANOBLAST, MT_VOLCANOTBLAST, MT_TELEGLITGEN, MT_TELEGLITGEN2, MT_TELEGLITTER, MT_TELEGLITTER2, MT_TFOG, MT_TELEPORTMAN, MT_STAFFPUFF, MT_STAFFPUFF2, MT_BEAKPUFF, MT_MISC13, MT_GAUNTLETPUFF1, MT_GAUNTLETPUFF2, MT_MISC14, MT_BLASTERFX1, MT_BLASTERSMOKE, MT_RIPPER, MT_BLASTERPUFF1, MT_BLASTERPUFF2, MT_WMACE, MT_MACEFX1, MT_MACEFX2, MT_MACEFX3, MT_MACEFX4, MT_WSKULLROD, MT_HORNRODFX1, MT_HORNRODFX2, MT_RAINPLR1, MT_RAINPLR2, MT_RAINPLR3, MT_RAINPLR4, MT_GOLDWANDFX1, MT_GOLDWANDFX2, MT_GOLDWANDPUFF1, MT_GOLDWANDPUFF2, MT_WPHOENIXROD, MT_PHOENIXFX1, MT_PHOENIXFX_REMOVED, // In Heretic 1.0, but removed. MT_PHOENIXPUFF, MT_PHOENIXFX2, MT_MISC15, MT_CRBOWFX1, MT_CRBOWFX2, MT_CRBOWFX3, MT_CRBOWFX4, MT_BLOOD, MT_BLOODSPLATTER, MT_PLAYER, MT_BLOODYSKULL, MT_CHICPLAYER, MT_CHICKEN, MT_FEATHER, MT_MUMMY, MT_MUMMYLEADER, MT_MUMMYGHOST, MT_MUMMYLEADERGHOST, MT_MUMMYSOUL, MT_MUMMYFX1, MT_BEAST, MT_BEASTBALL, MT_BURNBALL, MT_BURNBALLFB, MT_PUFFY, MT_SNAKE, MT_SNAKEPRO_A, MT_SNAKEPRO_B, MT_HEAD, MT_HEADFX1, MT_HEADFX2, MT_HEADFX3, MT_WHIRLWIND, MT_CLINK, MT_WIZARD, MT_WIZFX1, MT_IMP, MT_IMPLEADER, MT_IMPCHUNK1, MT_IMPCHUNK2, MT_IMPBALL, MT_KNIGHT, MT_KNIGHTGHOST, MT_KNIGHTAXE, MT_REDAXE, MT_SORCERER1, MT_SRCRFX1, MT_SORCERER2, MT_SOR2FX1, MT_SOR2FXSPARK, MT_SOR2FX2, MT_SOR2TELEFADE, MT_MINOTAUR, MT_MNTRFX1, MT_MNTRFX2, MT_MNTRFX3, MT_AKYY, MT_BKYY, MT_CKEY, MT_AMGWNDWIMPY, MT_AMGWNDHEFTY, MT_AMMACEWIMPY, MT_AMMACEHEFTY, MT_AMCBOWWIMPY, MT_AMCBOWHEFTY, MT_AMSKRDWIMPY, MT_AMSKRDHEFTY, MT_AMPHRDWIMPY, MT_AMPHRDHEFTY, MT_AMBLSRWIMPY, MT_AMBLSRHEFTY, MT_SOUNDWIND, MT_SOUNDWATERFALL, NUMMOBJTYPES } mobjtype_t; typedef struct { int doomednum; int spawnstate; int spawnhealth; int seestate; int seesound; int reactiontime; int attacksound; int painstate; int painchance; int painsound; int meleestate; int missilestate; int crashstate; int deathstate; int xdeathstate; int deathsound; int speed; int radius; int height; int mass; int damage; int activesound; int flags; int flags2; } mobjinfo_t; extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; #endif /* #ifndef HERETIC_INFO_H */ chocolate-doom-chocolate-doom-2.2.1/src/heretic/m_random.c000066400000000000000000000044101257432200600234560ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "m_random.h" /* =============== = = M_Random = = Returns a 0-255 number = =============== */ const unsigned int rndtable[256] = { 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36, 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224, 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242, 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0, 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235, 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113, 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75, 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196, 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113, 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241, 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224, 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95, 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226, 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36, 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136, 120, 163, 236, 249 }; int rndindex = 0; int prndindex = 0; int P_Random(void) { prndindex = (prndindex + 1) & 0xff; return rndtable[prndindex]; } int M_Random(void) { rndindex = (rndindex + 1) & 0xff; return rndtable[rndindex]; } void M_ClearRandom(void) { rndindex = prndindex = 0; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/m_random.h000066400000000000000000000017521257432200600234710ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef HERETIC_M_RANDOM_H #define HERETIC_M_RANDOM_H // Most damage defined using HITDICE #define HITDICE(a) ((1+(P_Random()&7))*a) int M_Random(void); // returns a number from 0 to 255 int P_Random(void); // as M_Random, but used only by the play simulation void M_ClearRandom(void); // fix randoms for demos extern int rndindex; #endif // HERETIC_M_RANDOM_H chocolate-doom-chocolate-doom-2.2.1/src/heretic/mn_menu.c000066400000000000000000001241431257432200600233260ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // MN_menu.c #include #include #include "deh_str.h" #include "doomdef.h" #include "doomkeys.h" #include "i_system.h" #include "i_swap.h" #include "m_controls.h" #include "m_misc.h" #include "p_local.h" #include "r_local.h" #include "s_sound.h" #include "v_video.h" // Macros #define LEFT_DIR 0 #define RIGHT_DIR 1 #define ITEM_HEIGHT 20 #define SELECTOR_XOFFSET (-28) #define SELECTOR_YOFFSET (-1) #define SLOTTEXTLEN 16 #define ASCII_CURSOR '[' // Types typedef enum { ITT_EMPTY, ITT_EFUNC, ITT_LRFUNC, ITT_SETMENU, ITT_INERT } ItemType_t; typedef enum { MENU_MAIN, MENU_EPISODE, MENU_SKILL, MENU_OPTIONS, MENU_OPTIONS2, MENU_FILES, MENU_LOAD, MENU_SAVE, MENU_NONE } MenuType_t; typedef struct { ItemType_t type; char *text; boolean(*func) (int option); int option; MenuType_t menu; } MenuItem_t; typedef struct { int x; int y; void (*drawFunc) (void); int itemCount; MenuItem_t *items; int oldItPos; MenuType_t prevMenu; } Menu_t; // Private Functions static void InitFonts(void); static void SetMenu(MenuType_t menu); static boolean SCNetCheck(int option); static boolean SCQuitGame(int option); static boolean SCEpisode(int option); static boolean SCSkill(int option); static boolean SCMouseSensi(int option); static boolean SCSfxVolume(int option); static boolean SCMusicVolume(int option); static boolean SCScreenSize(int option); static boolean SCLoadGame(int option); static boolean SCSaveGame(int option); static boolean SCMessages(int option); static boolean SCEndGame(int option); static boolean SCInfo(int option); static void DrawMainMenu(void); static void DrawEpisodeMenu(void); static void DrawSkillMenu(void); static void DrawOptionsMenu(void); static void DrawOptions2Menu(void); static void DrawFileSlots(Menu_t * menu); static void DrawFilesMenu(void); static void MN_DrawInfo(void); static void DrawLoadMenu(void); static void DrawSaveMenu(void); static void DrawSlider(Menu_t * menu, int item, int width, int slot); void MN_LoadSlotText(void); // External Data extern int detailLevel; extern int screenblocks; // Public Data boolean MenuActive; int InfoType; boolean messageson; // Private Data static int FontABaseLump; static int FontBBaseLump; static int SkullBaseLump; static Menu_t *CurrentMenu; static int CurrentItPos; static int MenuEpisode; static int MenuTime; static boolean soundchanged; boolean askforquit; static int typeofask; static boolean FileMenuKeySteal; static boolean slottextloaded; static char SlotText[6][SLOTTEXTLEN + 2]; static char oldSlotText[SLOTTEXTLEN + 2]; static int SlotStatus[6]; static int slotptr; static int currentSlot; static int quicksave; static int quickload; static MenuItem_t MainItems[] = { {ITT_EFUNC, "NEW GAME", SCNetCheck, 1, MENU_EPISODE}, {ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS}, {ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES}, {ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE}, {ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE} }; static Menu_t MainMenu = { 110, 56, DrawMainMenu, 5, MainItems, 0, MENU_NONE }; static MenuItem_t EpisodeItems[] = { {ITT_EFUNC, "CITY OF THE DAMNED", SCEpisode, 1, MENU_NONE}, {ITT_EFUNC, "HELL'S MAW", SCEpisode, 2, MENU_NONE}, {ITT_EFUNC, "THE DOME OF D'SPARIL", SCEpisode, 3, MENU_NONE}, {ITT_EFUNC, "THE OSSUARY", SCEpisode, 4, MENU_NONE}, {ITT_EFUNC, "THE STAGNANT DEMESNE", SCEpisode, 5, MENU_NONE} }; static Menu_t EpisodeMenu = { 80, 50, DrawEpisodeMenu, 3, EpisodeItems, 0, MENU_MAIN }; static MenuItem_t FilesItems[] = { {ITT_EFUNC, "LOAD GAME", SCNetCheck, 2, MENU_LOAD}, {ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE} }; static Menu_t FilesMenu = { 110, 60, DrawFilesMenu, 2, FilesItems, 0, MENU_MAIN }; static MenuItem_t LoadItems[] = { {ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE} }; static Menu_t LoadMenu = { 70, 30, DrawLoadMenu, 6, LoadItems, 0, MENU_FILES }; static MenuItem_t SaveItems[] = { {ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE} }; static Menu_t SaveMenu = { 70, 30, DrawSaveMenu, 6, SaveItems, 0, MENU_FILES }; static MenuItem_t SkillItems[] = { {ITT_EFUNC, "THOU NEEDETH A WET-NURSE", SCSkill, sk_baby, MENU_NONE}, {ITT_EFUNC, "YELLOWBELLIES-R-US", SCSkill, sk_easy, MENU_NONE}, {ITT_EFUNC, "BRINGEST THEM ONETH", SCSkill, sk_medium, MENU_NONE}, {ITT_EFUNC, "THOU ART A SMITE-MEISTER", SCSkill, sk_hard, MENU_NONE}, {ITT_EFUNC, "BLACK PLAGUE POSSESSES THEE", SCSkill, sk_nightmare, MENU_NONE} }; static Menu_t SkillMenu = { 38, 30, DrawSkillMenu, 5, SkillItems, 2, MENU_EPISODE }; static MenuItem_t OptionsItems[] = { {ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE}, {ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE}, {ITT_LRFUNC, "MOUSE SENSITIVITY", SCMouseSensi, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}, {ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2} }; static Menu_t OptionsMenu = { 88, 30, DrawOptionsMenu, 5, OptionsItems, 0, MENU_MAIN }; static MenuItem_t Options2Items[] = { {ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}, {ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}, {ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE} }; static Menu_t Options2Menu = { 90, 20, DrawOptions2Menu, 6, Options2Items, 0, MENU_OPTIONS }; static Menu_t *Menus[] = { &MainMenu, &EpisodeMenu, &SkillMenu, &OptionsMenu, &Options2Menu, &FilesMenu, &LoadMenu, &SaveMenu }; //--------------------------------------------------------------------------- // // PROC MN_Init // //--------------------------------------------------------------------------- void MN_Init(void) { InitFonts(); MenuActive = false; messageson = true; SkullBaseLump = W_GetNumForName(DEH_String("M_SKL00")); if (gamemode == retail) { // Add episodes 4 and 5 to the menu EpisodeMenu.itemCount = 5; EpisodeMenu.y -= ITEM_HEIGHT; } } //--------------------------------------------------------------------------- // // PROC InitFonts // //--------------------------------------------------------------------------- static void InitFonts(void) { FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1; FontBBaseLump = W_GetNumForName(DEH_String("FONTB_S")) + 1; } //--------------------------------------------------------------------------- // // PROC MN_DrTextA // // Draw text using font A. // //--------------------------------------------------------------------------- void MN_DrTextA(char *text, int x, int y) { char c; patch_t *p; while ((c = *text++) != 0) { if (c < 33) { x += 5; } else { p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); V_DrawPatch(x, y, p); x += SHORT(p->width) - 1; } } } //--------------------------------------------------------------------------- // // FUNC MN_TextAWidth // // Returns the pixel width of a string using font A. // //--------------------------------------------------------------------------- int MN_TextAWidth(char *text) { char c; int width; patch_t *p; width = 0; while ((c = *text++) != 0) { if (c < 33) { width += 5; } else { p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); width += SHORT(p->width) - 1; } } return (width); } //--------------------------------------------------------------------------- // // PROC MN_DrTextB // // Draw text using font B. // //--------------------------------------------------------------------------- void MN_DrTextB(char *text, int x, int y) { char c; patch_t *p; while ((c = *text++) != 0) { if (c < 33) { x += 8; } else { p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE); V_DrawPatch(x, y, p); x += SHORT(p->width) - 1; } } } //--------------------------------------------------------------------------- // // FUNC MN_TextBWidth // // Returns the pixel width of a string using font B. // //--------------------------------------------------------------------------- int MN_TextBWidth(char *text) { char c; int width; patch_t *p; width = 0; while ((c = *text++) != 0) { if (c < 33) { width += 5; } else { p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE); width += SHORT(p->width) - 1; } } return (width); } //--------------------------------------------------------------------------- // // PROC MN_Ticker // //--------------------------------------------------------------------------- void MN_Ticker(void) { if (MenuActive == false) { return; } MenuTime++; } //--------------------------------------------------------------------------- // // PROC MN_Drawer // //--------------------------------------------------------------------------- char *QuitEndMsg[] = { "ARE YOU SURE YOU WANT TO QUIT?", "ARE YOU SURE YOU WANT TO END THE GAME?", "DO YOU WANT TO QUICKSAVE THE GAME NAMED", "DO YOU WANT TO QUICKLOAD THE GAME NAMED" }; void MN_Drawer(void) { int i; int x; int y; MenuItem_t *item; char *message; char *selName; if (MenuActive == false) { if (askforquit) { message = DEH_String(QuitEndMsg[typeofask - 1]); MN_DrTextA(message, 160 - MN_TextAWidth(message) / 2, 80); if (typeofask == 3) { MN_DrTextA(SlotText[quicksave - 1], 160 - MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90); MN_DrTextA(DEH_String("?"), 160 + MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90); } if (typeofask == 4) { MN_DrTextA(SlotText[quickload - 1], 160 - MN_TextAWidth(SlotText[quickload - 1]) / 2, 90); MN_DrTextA(DEH_String("?"), 160 + MN_TextAWidth(SlotText[quickload - 1]) / 2, 90); } UpdateState |= I_FULLSCRN; } return; } else { UpdateState |= I_FULLSCRN; if (InfoType) { MN_DrawInfo(); return; } if (screenblocks < 10) { BorderNeedRefresh = true; } if (CurrentMenu->drawFunc != NULL) { CurrentMenu->drawFunc(); } x = CurrentMenu->x; y = CurrentMenu->y; item = CurrentMenu->items; for (i = 0; i < CurrentMenu->itemCount; i++) { if (item->type != ITT_EMPTY && item->text) { MN_DrTextB(DEH_String(item->text), x, y); } y += ITEM_HEIGHT; item++; } y = CurrentMenu->y + (CurrentItPos * ITEM_HEIGHT) + SELECTOR_YOFFSET; selName = DEH_String(MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2"); V_DrawPatch(x + SELECTOR_XOFFSET, y, W_CacheLumpName(selName, PU_CACHE)); } } //--------------------------------------------------------------------------- // // PROC DrawMainMenu // //--------------------------------------------------------------------------- static void DrawMainMenu(void) { int frame; frame = (MenuTime / 3) % 18; V_DrawPatch(88, 0, W_CacheLumpName(DEH_String("M_HTIC"), PU_CACHE)); V_DrawPatch(40, 10, W_CacheLumpNum(SkullBaseLump + (17 - frame), PU_CACHE)); V_DrawPatch(232, 10, W_CacheLumpNum(SkullBaseLump + frame, PU_CACHE)); } //--------------------------------------------------------------------------- // // PROC DrawEpisodeMenu // //--------------------------------------------------------------------------- static void DrawEpisodeMenu(void) { } //--------------------------------------------------------------------------- // // PROC DrawSkillMenu // //--------------------------------------------------------------------------- static void DrawSkillMenu(void) { } //--------------------------------------------------------------------------- // // PROC DrawFilesMenu // //--------------------------------------------------------------------------- static void DrawFilesMenu(void) { // clear out the quicksave/quickload stuff quicksave = 0; quickload = 0; players[consoleplayer].message = NULL; players[consoleplayer].messageTics = 1; } //--------------------------------------------------------------------------- // // PROC DrawLoadMenu // //--------------------------------------------------------------------------- static void DrawLoadMenu(void) { char *title; title = DEH_String("LOAD GAME"); MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&LoadMenu); } //--------------------------------------------------------------------------- // // PROC DrawSaveMenu // //--------------------------------------------------------------------------- static void DrawSaveMenu(void) { char *title; title = DEH_String("SAVE GAME"); MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&SaveMenu); } //=========================================================================== // // MN_LoadSlotText // // Loads in the text message for each slot //=========================================================================== void MN_LoadSlotText(void) { FILE *fp; int i; char *filename; for (i = 0; i < 6; i++) { filename = SV_Filename(i); fp = fopen(filename, "rb+"); free(filename); if (!fp) { SlotText[i][0] = 0; // empty the string SlotStatus[i] = 0; continue; } fread(&SlotText[i], SLOTTEXTLEN, 1, fp); fclose(fp); SlotStatus[i] = 1; } slottextloaded = true; } //--------------------------------------------------------------------------- // // PROC DrawFileSlots // //--------------------------------------------------------------------------- static void DrawFileSlots(Menu_t * menu) { int i; int x; int y; x = menu->x; y = menu->y; for (i = 0; i < 6; i++) { V_DrawPatch(x, y, W_CacheLumpName(DEH_String("M_FSLOT"), PU_CACHE)); if (SlotStatus[i]) { MN_DrTextA(SlotText[i], x + 5, y + 5); } y += ITEM_HEIGHT; } } //--------------------------------------------------------------------------- // // PROC DrawOptionsMenu // //--------------------------------------------------------------------------- static void DrawOptionsMenu(void) { if (messageson) { MN_DrTextB(DEH_String("ON"), 196, 50); } else { MN_DrTextB(DEH_String("OFF"), 196, 50); } DrawSlider(&OptionsMenu, 3, 10, mouseSensitivity); } //--------------------------------------------------------------------------- // // PROC DrawOptions2Menu // //--------------------------------------------------------------------------- static void DrawOptions2Menu(void) { DrawSlider(&Options2Menu, 1, 9, screenblocks - 3); DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume); DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume); } //--------------------------------------------------------------------------- // // PROC SCNetCheck // //--------------------------------------------------------------------------- static boolean SCNetCheck(int option) { if (!netgame) { // okay to go into the menu return true; } switch (option) { case 1: P_SetMessage(&players[consoleplayer], "YOU CAN'T START A NEW GAME IN NETPLAY!", true); break; case 2: P_SetMessage(&players[consoleplayer], "YOU CAN'T LOAD A GAME IN NETPLAY!", true); break; default: break; } MenuActive = false; return false; } //--------------------------------------------------------------------------- // // PROC SCQuitGame // //--------------------------------------------------------------------------- static boolean SCQuitGame(int option) { MenuActive = false; askforquit = true; typeofask = 1; //quit game if (!netgame && !demoplayback) { paused = true; } return true; } //--------------------------------------------------------------------------- // // PROC SCEndGame // //--------------------------------------------------------------------------- static boolean SCEndGame(int option) { if (demoplayback || netgame) { return false; } MenuActive = false; askforquit = true; typeofask = 2; //endgame if (!netgame && !demoplayback) { paused = true; } return true; } //--------------------------------------------------------------------------- // // PROC SCMessages // //--------------------------------------------------------------------------- static boolean SCMessages(int option) { messageson ^= 1; if (messageson) { P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES ON"), true); } else { P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES OFF"), true); } S_StartSound(NULL, sfx_chat); return true; } //--------------------------------------------------------------------------- // // PROC SCLoadGame // //--------------------------------------------------------------------------- static boolean SCLoadGame(int option) { char *filename; if (!SlotStatus[option]) { // slot's empty...don't try and load return false; } filename = SV_Filename(option); G_LoadGame(filename); free(filename); MN_DeactivateMenu(); BorderNeedRefresh = true; if (quickload == -1) { quickload = option + 1; players[consoleplayer].message = NULL; players[consoleplayer].messageTics = 1; } return true; } //--------------------------------------------------------------------------- // // PROC SCSaveGame // //--------------------------------------------------------------------------- static boolean SCSaveGame(int option) { char *ptr; if (!FileMenuKeySteal) { FileMenuKeySteal = true; M_StringCopy(oldSlotText, SlotText[option], sizeof(oldSlotText)); ptr = SlotText[option]; while (*ptr) { ptr++; } *ptr = '['; *(ptr + 1) = 0; SlotStatus[option]++; currentSlot = option; slotptr = ptr - SlotText[option]; return false; } else { G_SaveGame(option, SlotText[option]); FileMenuKeySteal = false; MN_DeactivateMenu(); } BorderNeedRefresh = true; if (quicksave == -1) { quicksave = option + 1; players[consoleplayer].message = NULL; players[consoleplayer].messageTics = 1; } return true; } //--------------------------------------------------------------------------- // // PROC SCEpisode // //--------------------------------------------------------------------------- static boolean SCEpisode(int option) { if (gamemode == shareware && option > 1) { P_SetMessage(&players[consoleplayer], "ONLY AVAILABLE IN THE REGISTERED VERSION", true); } else { MenuEpisode = option; SetMenu(MENU_SKILL); } return true; } //--------------------------------------------------------------------------- // // PROC SCSkill // //--------------------------------------------------------------------------- static boolean SCSkill(int option) { G_DeferedInitNew(option, MenuEpisode, 1); MN_DeactivateMenu(); return true; } //--------------------------------------------------------------------------- // // PROC SCMouseSensi // //--------------------------------------------------------------------------- static boolean SCMouseSensi(int option) { if (option == RIGHT_DIR) { if (mouseSensitivity < 9) { mouseSensitivity++; } } else if (mouseSensitivity) { mouseSensitivity--; } return true; } //--------------------------------------------------------------------------- // // PROC SCSfxVolume // //--------------------------------------------------------------------------- static boolean SCSfxVolume(int option) { if (option == RIGHT_DIR) { if (snd_MaxVolume < 15) { snd_MaxVolume++; } } else if (snd_MaxVolume) { snd_MaxVolume--; } S_SetMaxVolume(false); // don't recalc the sound curve, yet soundchanged = true; // we'll set it when we leave the menu return true; } //--------------------------------------------------------------------------- // // PROC SCMusicVolume // //--------------------------------------------------------------------------- static boolean SCMusicVolume(int option) { if (option == RIGHT_DIR) { if (snd_MusicVolume < 15) { snd_MusicVolume++; } } else if (snd_MusicVolume) { snd_MusicVolume--; } S_SetMusicVolume(); return true; } //--------------------------------------------------------------------------- // // PROC SCScreenSize // //--------------------------------------------------------------------------- static boolean SCScreenSize(int option) { if (option == RIGHT_DIR) { if (screenblocks < 11) { screenblocks++; } } else if (screenblocks > 3) { screenblocks--; } R_SetViewSize(screenblocks, detailLevel); return true; } //--------------------------------------------------------------------------- // // PROC SCInfo // //--------------------------------------------------------------------------- static boolean SCInfo(int option) { InfoType = 1; S_StartSound(NULL, sfx_dorcls); if (!netgame && !demoplayback) { paused = true; } return true; } //--------------------------------------------------------------------------- // // FUNC MN_Responder // //--------------------------------------------------------------------------- boolean MN_Responder(event_t * event) { int charTyped; int key; int i; MenuItem_t *item; extern boolean automapactive; extern void D_StartTitle(void); extern void G_CheckDemoStatus(void); char *textBuffer; // In testcontrols mode, none of the function keys should do anything // - the only key is escape to quit. if (testcontrols) { if (event->type == ev_quit || (event->type == ev_keydown && (event->data1 == key_menu_activate || event->data1 == key_menu_quit))) { I_Quit(); return true; } return false; } // "close" button pressed on window? if (event->type == ev_quit) { // First click on close = bring up quit confirm message. // Second click = confirm quit. if (!MenuActive && askforquit && typeofask == 1) { G_CheckDemoStatus(); I_Quit(); } else { SCQuitGame(0); S_StartSound(NULL, sfx_chat); } return true; } // Allow the menu to be activated from a joystick button if a button // is bound for joybmenu. if (event->type == ev_joystick) { if (joybmenu >= 0 && (event->data1 & (1 << joybmenu)) != 0) { MN_ActivateMenu(); return true; } } if (event->type != ev_keydown) { return false; } key = event->data1; charTyped = event->data2; if (InfoType) { if (gamemode == shareware) { InfoType = (InfoType + 1) % 5; } else { InfoType = (InfoType + 1) % 4; } if (key == KEY_ESCAPE) { InfoType = 0; } if (!InfoType) { paused = false; MN_DeactivateMenu(); SB_state = -1; //refresh the statbar BorderNeedRefresh = true; } S_StartSound(NULL, sfx_dorcls); return (true); //make the info screen eat the keypress } if ((ravpic && key == KEY_F1) || (key != 0 && key == key_menu_screenshot)) { G_ScreenShot(); return (true); } if (askforquit) { if (key == key_menu_confirm) { switch (typeofask) { case 1: G_CheckDemoStatus(); I_Quit(); return false; case 2: players[consoleplayer].messageTics = 0; //set the msg to be cleared players[consoleplayer].message = NULL; paused = false; I_SetPalette(W_CacheLumpName ("PLAYPAL", PU_CACHE)); D_StartTitle(); // go to intro/demo mode. break; case 3: P_SetMessage(&players[consoleplayer], "QUICKSAVING....", false); FileMenuKeySteal = true; SCSaveGame(quicksave - 1); BorderNeedRefresh = true; break; case 4: P_SetMessage(&players[consoleplayer], "QUICKLOADING....", false); SCLoadGame(quickload - 1); BorderNeedRefresh = true; break; default: break; } askforquit = false; typeofask = 0; return true; } else if (key == key_menu_abort || key == KEY_ESCAPE) { players[consoleplayer].messageTics = 1; //set the msg to be cleared askforquit = false; typeofask = 0; paused = false; UpdateState |= I_FULLSCRN; BorderNeedRefresh = true; return true; } return false; // don't let the keys filter thru } if (!MenuActive && !chatmodeon) { if (key == key_menu_decscreen) { if (automapactive) { // Don't screen size in automap return (false); } SCScreenSize(LEFT_DIR); S_StartSound(NULL, sfx_keyup); BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; return (true); } else if (key == key_menu_incscreen) { if (automapactive) { // Don't screen size in automap return (false); } SCScreenSize(RIGHT_DIR); S_StartSound(NULL, sfx_keyup); BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; return (true); } else if (key == key_menu_help) // F1 { SCInfo(0); // start up info screens MenuActive = true; return (true); } else if (key == key_menu_save) // F2 (save game) { if (gamestate == GS_LEVEL && !demoplayback) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &SaveMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, sfx_dorcls); slottextloaded = false; //reload the slot text, when needed } return true; } else if (key == key_menu_load) // F3 (load game) { if (SCNetCheck(2)) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &LoadMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, sfx_dorcls); slottextloaded = false; //reload the slot text, when needed } return true; } else if (key == key_menu_volume) // F4 (volume) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &Options2Menu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, sfx_dorcls); slottextloaded = false; //reload the slot text, when needed return true; } else if (key == key_menu_detail) // F5 (detail) { // F5 isn't used in Heretic. (detail level) return true; } else if (key == key_menu_qsave) // F6 (quicksave) { if (gamestate == GS_LEVEL && !demoplayback) { if (!quicksave || quicksave == -1) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &SaveMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, sfx_dorcls); slottextloaded = false; //reload the slot text, when needed quicksave = -1; P_SetMessage(&players[consoleplayer], "CHOOSE A QUICKSAVE SLOT", true); } else { askforquit = true; typeofask = 3; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, sfx_chat); } } return true; } else if (key == key_menu_endgame) // F7 (end game) { if (gamestate == GS_LEVEL && !demoplayback) { S_StartSound(NULL, sfx_chat); SCEndGame(0); } return true; } else if (key == key_menu_messages) // F8 (toggle messages) { SCMessages(0); return true; } else if (key == key_menu_qload) // F9 (quickload) { if (!quickload || quickload == -1) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &LoadMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, sfx_dorcls); slottextloaded = false; //reload the slot text, when needed quickload = -1; P_SetMessage(&players[consoleplayer], "CHOOSE A QUICKLOAD SLOT", true); } else { askforquit = true; if (!netgame && !demoplayback) { paused = true; } typeofask = 4; S_StartSound(NULL, sfx_chat); } return true; } else if (key == key_menu_quit) // F10 (quit) { if (gamestate == GS_LEVEL) { SCQuitGame(0); S_StartSound(NULL, sfx_chat); } return true; } else if (key == key_menu_gamma) // F11 (gamma correction) { usegamma++; if (usegamma > 4) { usegamma = 0; } I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE)); return true; } } if (!MenuActive) { if (key == key_menu_activate || gamestate == GS_DEMOSCREEN || demoplayback) { MN_ActivateMenu(); return (true); } return (false); } if (!FileMenuKeySteal) { item = &CurrentMenu->items[CurrentItPos]; if (key == key_menu_down) // Next menu item { do { if (CurrentItPos + 1 > CurrentMenu->itemCount - 1) { CurrentItPos = 0; } else { CurrentItPos++; } } while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY); S_StartSound(NULL, sfx_switch); return (true); } else if (key == key_menu_up) // Previous menu item { do { if (CurrentItPos == 0) { CurrentItPos = CurrentMenu->itemCount - 1; } else { CurrentItPos--; } } while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY); S_StartSound(NULL, sfx_switch); return (true); } else if (key == key_menu_left) // Slider left { if (item->type == ITT_LRFUNC && item->func != NULL) { item->func(LEFT_DIR); S_StartSound(NULL, sfx_keyup); } return (true); } else if (key == key_menu_right) // Slider right { if (item->type == ITT_LRFUNC && item->func != NULL) { item->func(RIGHT_DIR); S_StartSound(NULL, sfx_keyup); } return (true); } else if (key == key_menu_forward) // Activate item (enter) { if (item->type == ITT_SETMENU) { SetMenu(item->menu); } else if (item->func != NULL) { CurrentMenu->oldItPos = CurrentItPos; if (item->type == ITT_LRFUNC) { item->func(RIGHT_DIR); } else if (item->type == ITT_EFUNC) { if (item->func(item->option)) { if (item->menu != MENU_NONE) { SetMenu(item->menu); } } } } S_StartSound(NULL, sfx_dorcls); return (true); } else if (key == key_menu_activate) // Toggle menu { MN_DeactivateMenu(); return (true); } else if (key == key_menu_back) // Go back to previous menu { S_StartSound(NULL, sfx_switch); if (CurrentMenu->prevMenu == MENU_NONE) { MN_DeactivateMenu(); } else { SetMenu(CurrentMenu->prevMenu); } return (true); } else if (charTyped != 0) { // Jump to menu item based on first letter: for (i = 0; i < CurrentMenu->itemCount; i++) { if (CurrentMenu->items[i].text) { if (toupper(charTyped) == toupper(DEH_String(CurrentMenu->items[i].text)[0])) { CurrentItPos = i; return (true); } } } } return (false); } else { // Editing file names textBuffer = &SlotText[currentSlot][slotptr]; if (key == KEY_BACKSPACE) { if (slotptr) { *textBuffer-- = 0; *textBuffer = ASCII_CURSOR; slotptr--; } return (true); } if (key == KEY_ESCAPE) { memset(SlotText[currentSlot], 0, SLOTTEXTLEN + 2); M_StringCopy(SlotText[currentSlot], oldSlotText, sizeof(SlotText[currentSlot])); SlotStatus[currentSlot]--; MN_DeactivateMenu(); return (true); } if (key == KEY_ENTER) { SlotText[currentSlot][slotptr] = 0; // clear the cursor item = &CurrentMenu->items[CurrentItPos]; CurrentMenu->oldItPos = CurrentItPos; if (item->type == ITT_EFUNC) { item->func(item->option); if (item->menu != MENU_NONE) { SetMenu(item->menu); } } return (true); } if (slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE) { if (isalpha(charTyped)) { *textBuffer++ = toupper(charTyped); *textBuffer = ASCII_CURSOR; slotptr++; return (true); } if (isdigit(charTyped) || charTyped == ' ' || charTyped == ',' || charTyped == '.' || charTyped == '-' || charTyped == '!') { *textBuffer++ = charTyped; *textBuffer = ASCII_CURSOR; slotptr++; return (true); } } return (true); } return (false); } //--------------------------------------------------------------------------- // // PROC MN_ActivateMenu // //--------------------------------------------------------------------------- void MN_ActivateMenu(void) { if (MenuActive) { return; } if (paused) { S_ResumeSound(); } MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &MainMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, sfx_dorcls); slottextloaded = false; //reload the slot text, when needed } //--------------------------------------------------------------------------- // // PROC MN_DeactivateMenu // //--------------------------------------------------------------------------- void MN_DeactivateMenu(void) { if (CurrentMenu != NULL) { CurrentMenu->oldItPos = CurrentItPos; } MenuActive = false; if (!netgame) { paused = false; } S_StartSound(NULL, sfx_dorcls); if (soundchanged) { S_SetMaxVolume(true); //recalc the sound curve soundchanged = false; } players[consoleplayer].message = NULL; players[consoleplayer].messageTics = 1; } //--------------------------------------------------------------------------- // // PROC MN_DrawInfo // //--------------------------------------------------------------------------- void MN_DrawInfo(void) { I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); V_DrawRawScreen(W_CacheLumpNum(W_GetNumForName("TITLE") + InfoType, PU_CACHE)); // V_DrawPatch(0, 0, W_CacheLumpNum(W_GetNumForName("TITLE")+InfoType, // PU_CACHE)); } //--------------------------------------------------------------------------- // // PROC SetMenu // //--------------------------------------------------------------------------- static void SetMenu(MenuType_t menu) { CurrentMenu->oldItPos = CurrentItPos; CurrentMenu = Menus[menu]; CurrentItPos = CurrentMenu->oldItPos; } //--------------------------------------------------------------------------- // // PROC DrawSlider // //--------------------------------------------------------------------------- static void DrawSlider(Menu_t * menu, int item, int width, int slot) { int x; int y; int x2; int count; x = menu->x + 24; y = menu->y + 2 + (item * ITEM_HEIGHT); V_DrawPatch(x - 32, y, W_CacheLumpName(DEH_String("M_SLDLT"), PU_CACHE)); for (x2 = x, count = width; count--; x2 += 8) { V_DrawPatch(x2, y, W_CacheLumpName(DEH_String(count & 1 ? "M_SLDMD1" : "M_SLDMD2"), PU_CACHE)); } V_DrawPatch(x2, y, W_CacheLumpName(DEH_String("M_SLDRT"), PU_CACHE)); V_DrawPatch(x + 4 + slot * 8, y + 7, W_CacheLumpName(DEH_String("M_SLDKB"), PU_CACHE)); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_action.h000066400000000000000000000067631257432200600235000ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // External definitions for action pointer functions. // #ifndef HERETIC_P_ACTION_H #define HERETIC_P_ACTION_H void A_FreeTargMobj(); void A_RestoreSpecialThing1(); void A_RestoreSpecialThing2(); void A_HideThing(); void A_UnHideThing(); void A_RestoreArtifact(); void A_Scream(); void A_Explode(); void A_PodPain(); void A_RemovePod(); void A_MakePod(); void A_InitKeyGizmo(); void A_VolcanoSet(); void A_VolcanoBlast(); void A_BeastPuff(); void A_VolcBallImpact(); void A_SpawnTeleGlitter(); void A_SpawnTeleGlitter2(); void A_AccTeleGlitter(); void A_Light0(); void A_WeaponReady(); void A_Lower(); void A_Raise(); void A_StaffAttackPL1(); void A_ReFire(); void A_StaffAttackPL2(); void A_BeakReady(); void A_BeakRaise(); void A_BeakAttackPL1(); void A_BeakAttackPL2(); void A_GauntletAttack(); void A_FireBlasterPL1(); void A_FireBlasterPL2(); void A_SpawnRippers(); void A_FireMacePL1(); void A_FireMacePL2(); void A_MacePL1Check(); void A_MaceBallImpact(); void A_MaceBallImpact2(); void A_DeathBallImpact(); void A_FireSkullRodPL1(); void A_FireSkullRodPL2(); void A_SkullRodPL2Seek(); void A_AddPlayerRain(); void A_HideInCeiling(); void A_SkullRodStorm(); void A_RainImpact(); void A_FireGoldWandPL1(); void A_FireGoldWandPL2(); void A_FirePhoenixPL1(); void A_InitPhoenixPL2(); void A_FirePhoenixPL2(); void A_ShutdownPhoenixPL2(); void A_PhoenixPuff(); void A_RemovedPhoenixFunc(); void A_FlameEnd(); void A_FloatPuff(); void A_FireCrossbowPL1(); void A_FireCrossbowPL2(); void A_BoltSpark(); void A_Pain(); void A_NoBlocking(); void A_AddPlayerCorpse(); void A_SkullPop(); void A_FlameSnd(); void A_CheckBurnGone(); void A_CheckSkullFloor(); void A_CheckSkullDone(); void A_Feathers(); void A_ChicLook(); void A_ChicChase(); void A_ChicPain(); void A_FaceTarget(); void A_ChicAttack(); void A_Look(); void A_Chase(); void A_MummyAttack(); void A_MummyAttack2(); void A_MummySoul(); void A_ContMobjSound(); void A_MummyFX1Seek(); void A_BeastAttack(); void A_SnakeAttack(); void A_SnakeAttack2(); void A_HeadAttack(); void A_BossDeath(); void A_HeadIceImpact(); void A_HeadFireGrow(); void A_WhirlwindSeek(); void A_ClinkAttack(); void A_WizAtk1(); void A_WizAtk2(); void A_WizAtk3(); void A_GhostOff(); void A_ImpMeAttack(); void A_ImpMsAttack(); void A_ImpMsAttack2(); void A_ImpDeath(); void A_ImpXDeath1(); void A_ImpXDeath2(); void A_ImpExplode(); void A_KnightAttack(); void A_DripBlood(); void A_Sor1Chase(); void A_Sor1Pain(); void A_Srcr1Attack(); void A_SorZap(); void A_SorcererRise(); void A_SorRise(); void A_SorSightSnd(); void A_Srcr2Decide(); void A_Srcr2Attack(); void A_Sor2DthInit(); void A_SorDSph(); void A_Sor2DthLoop(); void A_SorDExp(); void A_SorDBon(); void A_BlueSpark(); void A_GenWizard(); void A_MinotaurAtk1(); void A_MinotaurDecide(); void A_MinotaurAtk2(); void A_MinotaurAtk3(); void A_MinotaurCharge(); void A_MntrFloorFire(); void A_ESound(); #endif /* #ifndef HERETIC_P_ACTION_H */ chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_ceilng.c000066400000000000000000000174731257432200600234570ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" //================================================================== //================================================================== // // CEILINGS // //================================================================== //================================================================== ceiling_t *activeceilings[MAXCEILINGS]; //================================================================== // // T_MoveCeiling // //================================================================== void T_MoveCeiling(ceiling_t * ceiling) { result_e res; switch (ceiling->direction) { case 0: // IN STASIS break; case 1: // UP res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false, 1, ceiling->direction); if (!(leveltime & 7)) S_StartSound(&ceiling->sector->soundorg, sfx_dormov); if (res == pastdest) switch (ceiling->type) { case raiseToHighest: P_RemoveActiveCeiling(ceiling); break; case fastCrushAndRaise: case crushAndRaise: ceiling->direction = -1; break; default: break; } break; case -1: // DOWN res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, 1, ceiling->direction); if (!(leveltime & 7)) S_StartSound(&ceiling->sector->soundorg, sfx_dormov); if (res == pastdest) switch (ceiling->type) { case crushAndRaise: ceiling->speed = CEILSPEED; case fastCrushAndRaise: ceiling->direction = 1; break; case lowerAndCrush: case lowerToFloor: P_RemoveActiveCeiling(ceiling); break; default: break; } else if (res == crushed) switch (ceiling->type) { case crushAndRaise: case lowerAndCrush: ceiling->speed = CEILSPEED / 8; break; default: break; } break; } } //================================================================== // // EV_DoCeiling // Move a ceiling up/down and all around! // //================================================================== int EV_DoCeiling(line_t * line, ceiling_e type) { int secnum, rtn; sector_t *sec; ceiling_t *ceiling; secnum = -1; rtn = 0; // // Reactivate in-stasis ceilings...for certain types. // switch (type) { case fastCrushAndRaise: case crushAndRaise: P_ActivateInStasisCeiling(line); default: break; } while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // // new door thinker // rtn = 1; ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVSPEC, 0); P_AddThinker(&ceiling->thinker); sec->specialdata = ceiling; ceiling->thinker.function = T_MoveCeiling; ceiling->sector = sec; ceiling->crush = false; switch (type) { case fastCrushAndRaise: ceiling->crush = true; ceiling->topheight = sec->ceilingheight; ceiling->bottomheight = sec->floorheight + (8 * FRACUNIT); ceiling->direction = -1; ceiling->speed = CEILSPEED * 2; break; case crushAndRaise: ceiling->crush = true; ceiling->topheight = sec->ceilingheight; case lowerAndCrush: case lowerToFloor: ceiling->bottomheight = sec->floorheight; if (type != lowerToFloor) ceiling->bottomheight += 8 * FRACUNIT; ceiling->direction = -1; ceiling->speed = CEILSPEED; break; case raiseToHighest: ceiling->topheight = P_FindHighestCeilingSurrounding(sec); ceiling->direction = 1; ceiling->speed = CEILSPEED; break; } ceiling->tag = sec->tag; ceiling->type = type; P_AddActiveCeiling(ceiling); } return rtn; } //================================================================== // // Add an active ceiling // //================================================================== void P_AddActiveCeiling(ceiling_t * c) { int i; for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] == NULL) { activeceilings[i] = c; return; } } //================================================================== // // Remove a ceiling's thinker // //================================================================== void P_RemoveActiveCeiling(ceiling_t * c) { int i; for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] == c) { activeceilings[i]->sector->specialdata = NULL; P_RemoveThinker(&activeceilings[i]->thinker); activeceilings[i] = NULL; break; } } //================================================================== // // Restart a ceiling that's in-stasis // //================================================================== void P_ActivateInStasisCeiling(line_t * line) { int i; for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && (activeceilings[i]->direction == 0)) { activeceilings[i]->direction = activeceilings[i]->olddirection; activeceilings[i]->thinker.function = T_MoveCeiling; } } //================================================================== // // EV_CeilingCrushStop // Stop a ceiling from crushing! // //================================================================== int EV_CeilingCrushStop(line_t * line) { int i; int rtn; rtn = 0; for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && (activeceilings[i]->direction != 0)) { activeceilings[i]->olddirection = activeceilings[i]->direction; activeceilings[i]->thinker.function = NULL; activeceilings[i]->direction = 0; // in-stasis rtn = 1; } return rtn; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_doors.c000066400000000000000000000266361257432200600233450ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_doors.c #include "doomdef.h" #include "deh_str.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" //================================================================== //================================================================== // // VERTICAL DOORS // //================================================================== //================================================================== //================================================================== // // T_VerticalDoor // //================================================================== void T_VerticalDoor(vldoor_t * door) { result_e res; switch (door->direction) { case 0: // WAITING if (!--door->topcountdown) switch (door->type) { case vld_normal: door->direction = -1; // time to go back down S_StartSound(&door->sector->soundorg, sfx_doropn); break; case vld_close30ThenOpen: door->direction = 1; S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: break; } break; case 2: // INITIAL WAIT if (!--door->topcountdown) { switch (door->type) { case vld_raiseIn5Mins: door->direction = 1; door->type = vld_normal; S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: break; } } break; case -1: // DOWN res = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction); if (res == pastdest) { switch (door->type) { case vld_normal: case vld_close: door->sector->specialdata = NULL; P_RemoveThinker(&door->thinker); // unlink and free S_StartSound(&door->sector->soundorg, sfx_dorcls); break; case vld_close30ThenOpen: door->direction = 0; door->topcountdown = 35 * 30; break; default: break; } } else if (res == crushed) { switch (door->type) { case vld_close: // DON'T GO BACK UP! break; default: door->direction = 1; S_StartSound(&door->sector->soundorg, sfx_doropn); break; } } break; case 1: // UP res = T_MovePlane(door->sector, door->speed, door->topheight, false, 1, door->direction); if (res == pastdest) { switch (door->type) { case vld_normal: door->direction = 0; // wait at top door->topcountdown = door->topwait; break; case vld_close30ThenOpen: case vld_open: door->sector->specialdata = NULL; P_RemoveThinker(&door->thinker); // unlink and free S_StopSound(&door->sector->soundorg); break; default: break; } } break; } } //---------------------------------------------------------------------------- // // EV_DoDoor // // Move a door up/down // //---------------------------------------------------------------------------- int EV_DoDoor(line_t * line, vldoor_e type, fixed_t speed) { int secnum; int retcode; sector_t *sec; vldoor_t *door; secnum = -1; retcode = 0; while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) { continue; } // Add new door thinker retcode = 1; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function = T_VerticalDoor; door->sector = sec; switch (type) { case vld_close: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; door->direction = -1; S_StartSound(&door->sector->soundorg, sfx_doropn); break; case vld_close30ThenOpen: door->topheight = sec->ceilingheight; door->direction = -1; S_StartSound(&door->sector->soundorg, sfx_doropn); break; case vld_normal: case vld_open: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; if (door->topheight != sec->ceilingheight) { S_StartSound(&door->sector->soundorg, sfx_doropn); } break; default: break; } door->type = type; door->speed = speed; door->topwait = VDOORWAIT; } return (retcode); } //================================================================== // // EV_VerticalDoor : open a door manually, no tag value // //================================================================== void EV_VerticalDoor(line_t * line, mobj_t * thing) { player_t *player; sector_t *sec; vldoor_t *door; int side; side = 0; // only front sides can be used // // Check for locks // player = thing->player; switch (line->special) { case 26: // Blue Lock case 32: if (!player) { return; } if (!player->keys[key_blue]) { P_SetMessage(player, DEH_String(TXT_NEEDBLUEKEY), false); S_StartSound(NULL, sfx_plroof); return; } break; case 27: // Yellow Lock case 34: if (!player) { return; } if (!player->keys[key_yellow]) { P_SetMessage(player, DEH_String(TXT_NEEDYELLOWKEY), false); S_StartSound(NULL, sfx_plroof); return; } break; case 28: // Green Lock case 33: if (!player) { return; } if (!player->keys[key_green]) { P_SetMessage(player, DEH_String(TXT_NEEDGREENKEY), false); S_StartSound(NULL, sfx_plroof); return; } break; } // if the sector has an active thinker, use it sec = sides[line->sidenum[side ^ 1]].sector; if (sec->specialdata) { door = sec->specialdata; switch (line->special) { case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s case 26: case 27: case 28: if (door->direction == -1) { door->direction = 1; // go back up } else { if (!thing->player) { // Monsters don't close doors return; } door->direction = -1; // start going down immediately } return; } } // for proper sound switch (line->special) { case 1: // NORMAL DOOR SOUND case 31: S_StartSound(&sec->soundorg, sfx_doropn); //S_StartSound(&sec->soundorg, sfx_dormov); break; default: // LOCKED DOOR SOUND S_StartSound(&sec->soundorg, sfx_doropn); //S_StartSound(&sec->soundorg, sfx_dormov); break; } // // new door thinker // door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 1; switch (line->special) { case 1: case 26: case 27: case 28: door->type = vld_normal; break; case 31: case 32: case 33: case 34: door->type = vld_open; line->special = 0; break; } door->speed = VDOORSPEED; door->topwait = VDOORWAIT; // // find the top and bottom of the movement range // door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; } //================================================================== // // Spawn a door that closes after 30 seconds // //================================================================== void P_SpawnDoorCloseIn30(sector_t * sec) { vldoor_t *door; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 0; door->type = vld_normal; door->speed = VDOORSPEED; door->topcountdown = 30 * 35; } //================================================================== // // Spawn a door that opens after 5 minutes // //================================================================== void P_SpawnDoorRaiseIn5Mins(sector_t * sec, int secnum) { vldoor_t *door; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 2; door->type = vld_raiseIn5Mins; door->speed = VDOORSPEED; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; door->topwait = VDOORWAIT; door->topcountdown = 5 * 60 * 35; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_enemy.c000066400000000000000000002066411257432200600233300ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_enemy.c #include #include "doomdef.h" #include "i_system.h" #include "i_timer.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" // Macros #define MAX_BOSS_SPOTS 8 // Types typedef struct { fixed_t x; fixed_t y; angle_t angle; } BossSpot_t; // Private Data static int BossSpotCount; static BossSpot_t BossSpots[MAX_BOSS_SPOTS]; //---------------------------------------------------------------------------- // // PROC P_InitMonsters // // Called at level load. // //---------------------------------------------------------------------------- void P_InitMonsters(void) { BossSpotCount = 0; } //---------------------------------------------------------------------------- // // PROC P_AddBossSpot // //---------------------------------------------------------------------------- void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle) { if (BossSpotCount == MAX_BOSS_SPOTS) { I_Error("Too many boss spots."); } BossSpots[BossSpotCount].x = x; BossSpots[BossSpotCount].y = y; BossSpots[BossSpotCount].angle = angle; BossSpotCount++; } //---------------------------------------------------------------------------- // // PROC P_RecursiveSound // //---------------------------------------------------------------------------- mobj_t *soundtarget; void P_RecursiveSound(sector_t * sec, int soundblocks) { int i; line_t *check; sector_t *other; // Wake up all monsters in this sector if (sec->validcount == validcount && sec->soundtraversed <= soundblocks + 1) { // Already flooded return; } sec->validcount = validcount; sec->soundtraversed = soundblocks + 1; sec->soundtarget = soundtarget; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; if (!(check->flags & ML_TWOSIDED)) { continue; } P_LineOpening(check); if (openrange <= 0) { // Closed door continue; } if (sides[check->sidenum[0]].sector == sec) { other = sides[check->sidenum[1]].sector; } else { other = sides[check->sidenum[0]].sector; } if (check->flags & ML_SOUNDBLOCK) { if (!soundblocks) { P_RecursiveSound(other, 1); } } else { P_RecursiveSound(other, soundblocks); } } } //---------------------------------------------------------------------------- // // PROC P_NoiseAlert // // If a monster yells at a player, it will alert other monsters to the // player. // //---------------------------------------------------------------------------- void P_NoiseAlert(mobj_t * target, mobj_t * emmiter) { soundtarget = target; validcount++; P_RecursiveSound(emmiter->subsector->sector, 0); } //---------------------------------------------------------------------------- // // FUNC P_CheckMeleeRange // //---------------------------------------------------------------------------- boolean P_CheckMeleeRange(mobj_t * actor) { mobj_t *mo; fixed_t dist; if (!actor->target) { return (false); } mo = actor->target; dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y); if (dist >= MELEERANGE) { return (false); } if (!P_CheckSight(actor, mo)) { return (false); } if (mo->z > actor->z + actor->height) { // Target is higher than the attacker return (false); } else if (actor->z > mo->z + mo->height) { // Attacker is higher return (false); } return (true); } //---------------------------------------------------------------------------- // // FUNC P_CheckMissileRange // //---------------------------------------------------------------------------- boolean P_CheckMissileRange(mobj_t * actor) { fixed_t dist; if (!P_CheckSight(actor, actor->target)) { return (false); } if (actor->flags & MF_JUSTHIT) { // The target just hit the enemy, so fight back! actor->flags &= ~MF_JUSTHIT; return (true); } if (actor->reactiontime) { // Don't attack yet return (false); } dist = (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) >> FRACBITS) - 64; if (!actor->info->meleestate) { // No melee attack, so fire more frequently dist -= 128; } if (actor->type == MT_IMP) { // Imp's fly attack from far away dist >>= 1; } if (dist > 200) { dist = 200; } if (P_Random() < dist) { return (false); } return (true); } /* ================ = = P_Move = = Move in the current direction = returns false if the move is blocked ================ */ fixed_t xspeed[8] = { FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000, 0, 47000 }; fixed_t yspeed[8] = { 0, 47000, FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000 }; #define MAXSPECIALCROSS 8 extern line_t *spechit[MAXSPECIALCROSS]; extern int numspechit; boolean P_Move(mobj_t * actor) { fixed_t tryx, tryy; line_t *ld; boolean good; if (actor->movedir == DI_NODIR) { return (false); } tryx = actor->x + actor->info->speed * xspeed[actor->movedir]; tryy = actor->y + actor->info->speed * yspeed[actor->movedir]; if (!P_TryMove(actor, tryx, tryy)) { // open any specials if (actor->flags & MF_FLOAT && floatok) { // must adjust height if (actor->z < tmfloorz) { actor->z += FLOATSPEED; } else { actor->z -= FLOATSPEED; } actor->flags |= MF_INFLOAT; return (true); } if (!numspechit) { return false; } actor->movedir = DI_NODIR; good = false; while (numspechit--) { ld = spechit[numspechit]; // if the special isn't a door that can be opened, return false if (P_UseSpecialLine(actor, ld)) { good = true; } } return (good); } else { actor->flags &= ~MF_INFLOAT; } if (!(actor->flags & MF_FLOAT)) { if (actor->z > actor->floorz) { P_HitFloor(actor); } actor->z = actor->floorz; } return (true); } //---------------------------------------------------------------------------- // // FUNC P_TryWalk // // Attempts to move actor in its current (ob->moveangle) direction. // If blocked by either a wall or an actor returns FALSE. // If move is either clear of block only by a door, returns TRUE and sets. // If a door is in the way, an OpenDoor call is made to start it opening. // //---------------------------------------------------------------------------- boolean P_TryWalk(mobj_t * actor) { if (!P_Move(actor)) { return (false); } actor->movecount = P_Random() & 15; return (true); } /* ================ = = P_NewChaseDir = ================ */ dirtype_t opposite[] = { DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR }; dirtype_t diags[] = { DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST }; void P_NewChaseDir(mobj_t * actor) { fixed_t deltax, deltay; dirtype_t d[3]; dirtype_t tdir, olddir, turnaround; if (!actor->target) I_Error("P_NewChaseDir: called with no target"); olddir = actor->movedir; turnaround = opposite[olddir]; deltax = actor->target->x - actor->x; deltay = actor->target->y - actor->y; if (deltax > 10 * FRACUNIT) d[1] = DI_EAST; else if (deltax < -10 * FRACUNIT) d[1] = DI_WEST; else d[1] = DI_NODIR; if (deltay < -10 * FRACUNIT) d[2] = DI_SOUTH; else if (deltay > 10 * FRACUNIT) d[2] = DI_NORTH; else d[2] = DI_NODIR; // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { actor->movedir = diags[((deltay < 0) << 1) + (deltax > 0)]; if (actor->movedir != turnaround && P_TryWalk(actor)) return; } // try other directions if (P_Random() > 200 || abs(deltay) > abs(deltax)) { tdir = d[1]; d[1] = d[2]; d[2] = tdir; } if (d[1] == turnaround) d[1] = DI_NODIR; if (d[2] == turnaround) d[2] = DI_NODIR; if (d[1] != DI_NODIR) { actor->movedir = d[1]; if (P_TryWalk(actor)) return; /*either moved forward or attacked */ } if (d[2] != DI_NODIR) { actor->movedir = d[2]; if (P_TryWalk(actor)) return; } /* there is no direct path to the player, so pick another direction */ if (olddir != DI_NODIR) { actor->movedir = olddir; if (P_TryWalk(actor)) return; } if (P_Random() & 1) /*randomly determine direction of search */ { for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++) { if (tdir != turnaround) { actor->movedir = tdir; if (P_TryWalk(actor)) return; } } } else { // Iterate over all movedirs. tdir = DI_SOUTHEAST; for (;;) { if (tdir != turnaround) { actor->movedir = tdir; if (P_TryWalk(actor)) return; } if (tdir == DI_EAST) { break; } --tdir; } } if (turnaround != DI_NODIR) { actor->movedir = turnaround; if (P_TryWalk(actor)) return; } actor->movedir = DI_NODIR; // can't move } //--------------------------------------------------------------------------- // // FUNC P_LookForMonsters // //--------------------------------------------------------------------------- #define MONS_LOOK_RANGE (20*64*FRACUNIT) #define MONS_LOOK_LIMIT 64 boolean P_LookForMonsters(mobj_t * actor) { int count; mobj_t *mo; thinker_t *think; if (!P_CheckSight(players[0].mo, actor)) { // Player can't see monster return (false); } count = 0; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *) think; if (!(mo->flags & MF_COUNTKILL) || (mo == actor) || (mo->health <= 0)) { // Not a valid monster continue; } if (P_AproxDistance(actor->x - mo->x, actor->y - mo->y) > MONS_LOOK_RANGE) { // Out of range continue; } if (P_Random() < 16) { // Skip continue; } if (count++ > MONS_LOOK_LIMIT) { // Stop searching return (false); } if (!P_CheckSight(actor, mo)) { // Out of sight continue; } // Found a target monster actor->target = mo; return (true); } return (false); } /* ================ = = P_LookForPlayers = = If allaround is false, only look 180 degrees in front = returns true if a player is targeted ================ */ boolean P_LookForPlayers(mobj_t * actor, boolean allaround) { int c; int stop; player_t *player; angle_t an; fixed_t dist; if (!netgame && players[0].health <= 0) { // Single player game and player is dead, look for monsters return (P_LookForMonsters(actor)); } c = 0; stop = (actor->lastlook - 1) & 3; for (;; actor->lastlook = (actor->lastlook + 1) & 3) { if (!playeringame[actor->lastlook]) continue; if (c++ == 2 || actor->lastlook == stop) return false; // done looking player = &players[actor->lastlook]; if (player->health <= 0) continue; // dead if (!P_CheckSight(actor, player->mo)) continue; // out of sight if (!allaround) { an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; if (an > ANG90 && an < ANG270) { dist = P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y); // if real close, react anyway if (dist > MELEERANGE) continue; // behind back } } if (player->mo->flags & MF_SHADOW) { // Player is invisible if ((P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) > 2 * MELEERANGE) && P_AproxDistance(player->mo->momx, player->mo->momy) < 5 * FRACUNIT) { // Player is sneaking - can't detect return (false); } if (P_Random() < 225) { // Player isn't sneaking, but still didn't detect return (false); } } actor->target = player->mo; return (true); } return (false); } /* =============================================================================== ACTION ROUTINES =============================================================================== */ /* ============== = = A_Look = = Stay in state until a player is sighted = ============== */ void A_Look(mobj_t * actor) { mobj_t *targ; actor->threshold = 0; // any shot will wake up targ = actor->subsector->sector->soundtarget; if (targ && (targ->flags & MF_SHOOTABLE)) { actor->target = targ; if (actor->flags & MF_AMBUSH) { if (P_CheckSight(actor, actor->target)) goto seeyou; } else goto seeyou; } if (!P_LookForPlayers(actor, false)) return; // go into chase state seeyou: if (actor->info->seesound) { int sound; /* switch (actor->info->seesound) { case sfx_posit1: case sfx_posit2: case sfx_posit3: sound = sfx_posit1+P_Random()%3; break; case sfx_bgsit1: case sfx_bgsit2: sound = sfx_bgsit1+P_Random()%2; break; default: sound = actor->info->seesound; break; } */ sound = actor->info->seesound; if (actor->flags2 & MF2_BOSS) { // Full volume S_StartSound(NULL, sound); } else { S_StartSound(actor, sound); } } P_SetMobjState(actor, actor->info->seestate); } /* ============== = = A_Chase = = Actor has a melee attack, so it tries to close as fast as possible = ============== */ void A_Chase(mobj_t * actor) { int delta; if (actor->reactiontime) { actor->reactiontime--; } // Modify target threshold if (actor->threshold) { actor->threshold--; } if (gameskill == sk_nightmare) { // Monsters move faster in nightmare mode actor->tics -= actor->tics / 2; if (actor->tics < 3) { actor->tics = 3; } } // // turn towards movement direction if not there yet // if (actor->movedir < 8) { actor->angle &= (7 << 29); delta = actor->angle - (actor->movedir << 29); if (delta > 0) { actor->angle -= ANG90 / 2; } else if (delta < 0) { actor->angle += ANG90 / 2; } } if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { // look for a new target if (P_LookForPlayers(actor, true)) { // got a new target return; } P_SetMobjState(actor, actor->info->spawnstate); return; } // // don't attack twice in a row // if (actor->flags & MF_JUSTATTACKED) { actor->flags &= ~MF_JUSTATTACKED; if (gameskill != sk_nightmare) P_NewChaseDir(actor); return; } // // check for melee attack // if (actor->info->meleestate && P_CheckMeleeRange(actor)) { if (actor->info->attacksound) S_StartSound(actor, actor->info->attacksound); P_SetMobjState(actor, actor->info->meleestate); return; } // // check for missile attack // if (actor->info->missilestate) { if (gameskill < sk_nightmare && actor->movecount) goto nomissile; if (!P_CheckMissileRange(actor)) goto nomissile; P_SetMobjState(actor, actor->info->missilestate); actor->flags |= MF_JUSTATTACKED; return; } nomissile: // // possibly choose another target // if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target)) { if (P_LookForPlayers(actor, true)) return; // got a new target } // // chase towards player // if (--actor->movecount < 0 || !P_Move(actor)) { P_NewChaseDir(actor); } // // make active sound // if (actor->info->activesound && P_Random() < 3) { if (actor->type == MT_WIZARD && P_Random() < 128) { S_StartSound(actor, actor->info->seesound); } else if (actor->type == MT_SORCERER2) { S_StartSound(NULL, actor->info->activesound); } else { S_StartSound(actor, actor->info->activesound); } } } //---------------------------------------------------------------------------- // // PROC A_FaceTarget // //---------------------------------------------------------------------------- void A_FaceTarget(mobj_t * actor) { if (!actor->target) { return; } actor->flags &= ~MF_AMBUSH; actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); if (actor->target->flags & MF_SHADOW) { // Target is a ghost actor->angle += (P_Random() - P_Random()) << 21; } } //---------------------------------------------------------------------------- // // PROC A_Pain // //---------------------------------------------------------------------------- void A_Pain(mobj_t * actor) { if (actor->info->painsound) { S_StartSound(actor, actor->info->painsound); } } //---------------------------------------------------------------------------- // // PROC A_DripBlood // //---------------------------------------------------------------------------- void A_DripBlood(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 11), actor->y + ((P_Random() - P_Random()) << 11), actor->z, MT_BLOOD); mo->momx = (P_Random() - P_Random()) << 10; mo->momy = (P_Random() - P_Random()) << 10; mo->flags2 |= MF2_LOGRAV; } //---------------------------------------------------------------------------- // // PROC A_KnightAttack // //---------------------------------------------------------------------------- void A_KnightAttack(mobj_t * actor) { if (!actor->target) { return; } if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(3)); S_StartSound(actor, sfx_kgtat2); return; } // Throw axe S_StartSound(actor, actor->info->attacksound); if (actor->type == MT_KNIGHTGHOST || P_Random() < 40) { // Red axe P_SpawnMissile(actor, actor->target, MT_REDAXE); return; } // Green axe P_SpawnMissile(actor, actor->target, MT_KNIGHTAXE); } //---------------------------------------------------------------------------- // // PROC A_ImpExplode // //---------------------------------------------------------------------------- void A_ImpExplode(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK1); mo->momx = (P_Random() - P_Random()) << 10; mo->momy = (P_Random() - P_Random()) << 10; mo->momz = 9 * FRACUNIT; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK2); mo->momx = (P_Random() - P_Random()) << 10; mo->momy = (P_Random() - P_Random()) << 10; mo->momz = 9 * FRACUNIT; if (actor->special1.i == 666) { // Extreme death crash P_SetMobjState(actor, S_IMP_XCRASH1); } } //---------------------------------------------------------------------------- // // PROC A_BeastPuff // //---------------------------------------------------------------------------- void A_BeastPuff(mobj_t * actor) { if (P_Random() > 64) { P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10), actor->y + ((P_Random() - P_Random()) << 10), actor->z + ((P_Random() - P_Random()) << 10), MT_PUFFY); } } //---------------------------------------------------------------------------- // // PROC A_ImpMeAttack // //---------------------------------------------------------------------------- void A_ImpMeAttack(mobj_t * actor) { if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, 5 + (P_Random() & 7)); } } //---------------------------------------------------------------------------- // // PROC A_ImpMsAttack // //---------------------------------------------------------------------------- void A_ImpMsAttack(mobj_t * actor) { mobj_t *dest; angle_t an; int dist; if (!actor->target || P_Random() > 64) { P_SetMobjState(actor, actor->info->seestate); return; } dest = actor->target; actor->flags |= MF_SKULLFLY; S_StartSound(actor, actor->info->attacksound); A_FaceTarget(actor); an = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(12 * FRACUNIT, finecosine[an]); actor->momy = FixedMul(12 * FRACUNIT, finesine[an]); dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); dist = dist / (12 * FRACUNIT); if (dist < 1) { dist = 1; } actor->momz = (dest->z + (dest->height >> 1) - actor->z) / dist; } //---------------------------------------------------------------------------- // // PROC A_ImpMsAttack2 // // Fireball attack of the imp leader. // //---------------------------------------------------------------------------- void A_ImpMsAttack2(mobj_t * actor) { if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, 5 + (P_Random() & 7)); return; } P_SpawnMissile(actor, actor->target, MT_IMPBALL); } //---------------------------------------------------------------------------- // // PROC A_ImpDeath // //---------------------------------------------------------------------------- void A_ImpDeath(mobj_t * actor) { actor->flags &= ~MF_SOLID; actor->flags2 |= MF2_FOOTCLIP; if (actor->z <= actor->floorz) { P_SetMobjState(actor, S_IMP_CRASH1); } } //---------------------------------------------------------------------------- // // PROC A_ImpXDeath1 // //---------------------------------------------------------------------------- void A_ImpXDeath1(mobj_t * actor) { actor->flags &= ~MF_SOLID; actor->flags |= MF_NOGRAVITY; actor->flags2 |= MF2_FOOTCLIP; actor->special1.i = 666; // Flag the crash routine } //---------------------------------------------------------------------------- // // PROC A_ImpXDeath2 // //---------------------------------------------------------------------------- void A_ImpXDeath2(mobj_t * actor) { actor->flags &= ~MF_NOGRAVITY; if (actor->z <= actor->floorz) { P_SetMobjState(actor, S_IMP_CRASH1); } } //---------------------------------------------------------------------------- // // FUNC P_UpdateChicken // // Returns true if the chicken morphs. // //---------------------------------------------------------------------------- boolean P_UpdateChicken(mobj_t * actor, int tics) { mobj_t *fog; fixed_t x; fixed_t y; fixed_t z; mobjtype_t moType; mobj_t *mo; mobj_t oldChicken; actor->special1.i -= tics; if (actor->special1.i > 0) { return (false); } moType = actor->special2.i; x = actor->x; y = actor->y; z = actor->z; oldChicken = *actor; P_SetMobjState(actor, S_FREETARGMOBJ); mo = P_SpawnMobj(x, y, z, moType); if (P_TestMobjLocation(mo) == false) { // Didn't fit P_RemoveMobj(mo); mo = P_SpawnMobj(x, y, z, MT_CHICKEN); mo->angle = oldChicken.angle; mo->flags = oldChicken.flags; mo->health = oldChicken.health; mo->target = oldChicken.target; mo->special1.i = 5 * 35; // Next try in 5 seconds mo->special2.i = moType; return (false); } mo->angle = oldChicken.angle; mo->target = oldChicken.target; fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, sfx_telept); return (true); } //---------------------------------------------------------------------------- // // PROC A_ChicAttack // //---------------------------------------------------------------------------- void A_ChicAttack(mobj_t * actor) { if (P_UpdateChicken(actor, 18)) { return; } if (!actor->target) { return; } if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, 1 + (P_Random() & 1)); } } //---------------------------------------------------------------------------- // // PROC A_ChicLook // //---------------------------------------------------------------------------- void A_ChicLook(mobj_t * actor) { if (P_UpdateChicken(actor, 10)) { return; } A_Look(actor); } //---------------------------------------------------------------------------- // // PROC A_ChicChase // //---------------------------------------------------------------------------- void A_ChicChase(mobj_t * actor) { if (P_UpdateChicken(actor, 3)) { return; } A_Chase(actor); } //---------------------------------------------------------------------------- // // PROC A_ChicPain // //---------------------------------------------------------------------------- void A_ChicPain(mobj_t * actor) { if (P_UpdateChicken(actor, 10)) { return; } S_StartSound(actor, actor->info->painsound); } //---------------------------------------------------------------------------- // // PROC A_Feathers // //---------------------------------------------------------------------------- void A_Feathers(mobj_t * actor) { int i; int count; mobj_t *mo; if (actor->health > 0) { // Pain count = P_Random() < 32 ? 2 : 1; } else { // Death count = 5 + (P_Random() & 3); } for (i = 0; i < count; i++) { mo = P_SpawnMobj(actor->x, actor->y, actor->z + 20 * FRACUNIT, MT_FEATHER); mo->target = actor; mo->momx = (P_Random() - P_Random()) << 8; mo->momy = (P_Random() - P_Random()) << 8; mo->momz = FRACUNIT + (P_Random() << 9); P_SetMobjState(mo, S_FEATHER1 + (P_Random() & 7)); } } //---------------------------------------------------------------------------- // // PROC A_MummyAttack // //---------------------------------------------------------------------------- void A_MummyAttack(mobj_t * actor) { if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(2)); S_StartSound(actor, sfx_mumat2); return; } S_StartSound(actor, sfx_mumat1); } //---------------------------------------------------------------------------- // // PROC A_MummyAttack2 // // Mummy leader missile attack. // //---------------------------------------------------------------------------- void A_MummyAttack2(mobj_t * actor) { mobj_t *mo; if (!actor->target) { return; } //S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(2)); return; } mo = P_SpawnMissile(actor, actor->target, MT_MUMMYFX1); //mo = P_SpawnMissile(actor, actor->target, MT_EGGFX); if (mo != NULL) { mo->special1.m = actor->target; } } //---------------------------------------------------------------------------- // // PROC A_MummyFX1Seek // //---------------------------------------------------------------------------- void A_MummyFX1Seek(mobj_t * actor) { P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 20); } //---------------------------------------------------------------------------- // // PROC A_MummySoul // //---------------------------------------------------------------------------- void A_MummySoul(mobj_t * mummy) { mobj_t *mo; mo = P_SpawnMobj(mummy->x, mummy->y, mummy->z + 10 * FRACUNIT, MT_MUMMYSOUL); mo->momz = FRACUNIT; } //---------------------------------------------------------------------------- // // PROC A_Sor1Pain // //---------------------------------------------------------------------------- void A_Sor1Pain(mobj_t * actor) { actor->special1.i = 20; // Number of steps to walk fast A_Pain(actor); } //---------------------------------------------------------------------------- // // PROC A_Sor1Chase // //---------------------------------------------------------------------------- void A_Sor1Chase(mobj_t * actor) { if (actor->special1.i) { actor->special1.i--; actor->tics -= 3; } A_Chase(actor); } //---------------------------------------------------------------------------- // // PROC A_Srcr1Attack // // Sorcerer demon attack. // //---------------------------------------------------------------------------- void A_Srcr1Attack(mobj_t * actor) { mobj_t *mo; fixed_t momz; angle_t angle; if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(8)); return; } if (actor->health > (actor->info->spawnhealth / 3) * 2) { // Spit one fireball P_SpawnMissile(actor, actor->target, MT_SRCRFX1); } else { // Spit three fireballs mo = P_SpawnMissile(actor, actor->target, MT_SRCRFX1); if (mo) { momz = mo->momz; angle = mo->angle; P_SpawnMissileAngle(actor, MT_SRCRFX1, angle - ANG1_X * 3, momz); P_SpawnMissileAngle(actor, MT_SRCRFX1, angle + ANG1_X * 3, momz); } if (actor->health < actor->info->spawnhealth / 3) { // Maybe attack again if (actor->special1.i) { // Just attacked, so don't attack again actor->special1.i = 0; } else { // Set state to attack again actor->special1.i = 1; P_SetMobjState(actor, S_SRCR1_ATK4); } } } } //---------------------------------------------------------------------------- // // PROC A_SorcererRise // //---------------------------------------------------------------------------- void A_SorcererRise(mobj_t * actor) { mobj_t *mo; actor->flags &= ~MF_SOLID; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCERER2); P_SetMobjState(mo, S_SOR2_RISE1); mo->angle = actor->angle; mo->target = actor->target; } //---------------------------------------------------------------------------- // // PROC P_DSparilTeleport // //---------------------------------------------------------------------------- void P_DSparilTeleport(mobj_t * actor) { int i; fixed_t x; fixed_t y; fixed_t prevX; fixed_t prevY; fixed_t prevZ; mobj_t *mo; if (!BossSpotCount) { // No spots return; } i = P_Random(); do { i++; x = BossSpots[i % BossSpotCount].x; y = BossSpots[i % BossSpotCount].y; } while (P_AproxDistance(actor->x - x, actor->y - y) < 128 * FRACUNIT); prevX = actor->x; prevY = actor->y; prevZ = actor->z; if (P_TeleportMove(actor, x, y)) { mo = P_SpawnMobj(prevX, prevY, prevZ, MT_SOR2TELEFADE); S_StartSound(mo, sfx_telept); P_SetMobjState(actor, S_SOR2_TELE1); S_StartSound(actor, sfx_telept); actor->z = actor->floorz; actor->angle = BossSpots[i % BossSpotCount].angle; actor->momx = actor->momy = actor->momz = 0; } } //---------------------------------------------------------------------------- // // PROC A_Srcr2Decide // //---------------------------------------------------------------------------- void A_Srcr2Decide(mobj_t * actor) { static int chance[] = { 192, 120, 120, 120, 64, 64, 32, 16, 0 }; if (!BossSpotCount) { // No spots return; } if (P_Random() < chance[actor->health / (actor->info->spawnhealth / 8)]) { P_DSparilTeleport(actor); } } //---------------------------------------------------------------------------- // // PROC A_Srcr2Attack // //---------------------------------------------------------------------------- void A_Srcr2Attack(mobj_t * actor) { int chance; if (!actor->target) { return; } S_StartSound(NULL, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(20)); return; } chance = actor->health < actor->info->spawnhealth / 2 ? 96 : 48; if (P_Random() < chance) { // Wizard spawners P_SpawnMissileAngle(actor, MT_SOR2FX2, actor->angle - ANG45, FRACUNIT / 2); P_SpawnMissileAngle(actor, MT_SOR2FX2, actor->angle + ANG45, FRACUNIT / 2); } else { // Blue bolt P_SpawnMissile(actor, actor->target, MT_SOR2FX1); } } //---------------------------------------------------------------------------- // // PROC A_BlueSpark // //---------------------------------------------------------------------------- void A_BlueSpark(mobj_t * actor) { int i; mobj_t *mo; for (i = 0; i < 2; i++) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SOR2FXSPARK); mo->momx = (P_Random() - P_Random()) << 9; mo->momy = (P_Random() - P_Random()) << 9; mo->momz = FRACUNIT + (P_Random() << 8); } } //---------------------------------------------------------------------------- // // PROC A_GenWizard // //---------------------------------------------------------------------------- void A_GenWizard(mobj_t * actor) { mobj_t *mo; mobj_t *fog; mo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[MT_WIZARD].height / 2, MT_WIZARD); if (P_TestMobjLocation(mo) == false) { // Didn't fit P_RemoveMobj(mo); return; } actor->momx = actor->momy = actor->momz = 0; P_SetMobjState(actor, mobjinfo[actor->type].deathstate); actor->flags &= ~MF_MISSILE; fog = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TFOG); S_StartSound(fog, sfx_telept); } //---------------------------------------------------------------------------- // // PROC A_Sor2DthInit // //---------------------------------------------------------------------------- void A_Sor2DthInit(mobj_t * actor) { actor->special1.i = 7; // Animation loop counter P_Massacre(); // Kill monsters early } //---------------------------------------------------------------------------- // // PROC A_Sor2DthLoop // //---------------------------------------------------------------------------- void A_Sor2DthLoop(mobj_t * actor) { if (--actor->special1.i) { // Need to loop P_SetMobjState(actor, S_SOR2_DIE4); } } //---------------------------------------------------------------------------- // // D'Sparil Sound Routines // //---------------------------------------------------------------------------- void A_SorZap(mobj_t * actor) { S_StartSound(NULL, sfx_sorzap); } void A_SorRise(mobj_t * actor) { S_StartSound(NULL, sfx_sorrise); } void A_SorDSph(mobj_t * actor) { S_StartSound(NULL, sfx_sordsph); } void A_SorDExp(mobj_t * actor) { S_StartSound(NULL, sfx_sordexp); } void A_SorDBon(mobj_t * actor) { S_StartSound(NULL, sfx_sordbon); } void A_SorSightSnd(mobj_t * actor) { S_StartSound(NULL, sfx_sorsit); } //---------------------------------------------------------------------------- // // PROC A_MinotaurAtk1 // // Melee attack. // //---------------------------------------------------------------------------- void A_MinotaurAtk1(mobj_t * actor) { player_t *player; if (!actor->target) { return; } S_StartSound(actor, sfx_stfpow); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(4)); if ((player = actor->target->player) != NULL) { // Squish the player player->deltaviewheight = -16 * FRACUNIT; } } } //---------------------------------------------------------------------------- // // PROC A_MinotaurDecide // // Choose a missile attack. // //---------------------------------------------------------------------------- #define MNTR_CHARGE_SPEED (13*FRACUNIT) void A_MinotaurDecide(mobj_t * actor) { angle_t angle; mobj_t *target; int dist; target = actor->target; if (!target) { return; } S_StartSound(actor, sfx_minsit); dist = P_AproxDistance(actor->x - target->x, actor->y - target->y); if (target->z + target->height > actor->z && target->z + target->height < actor->z + actor->height && dist < 8 * 64 * FRACUNIT && dist > 1 * 64 * FRACUNIT && P_Random() < 150) { // Charge attack // Don't call the state function right away P_SetMobjStateNF(actor, S_MNTR_ATK4_1); actor->flags |= MF_SKULLFLY; A_FaceTarget(actor); angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]); actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]); actor->special1.i = 35 / 2; // Charge duration } else if (target->z == target->floorz && dist < 9 * 64 * FRACUNIT && P_Random() < 220) { // Floor fire attack P_SetMobjState(actor, S_MNTR_ATK3_1); actor->special2.i = 0; } else { // Swing attack A_FaceTarget(actor); // Don't need to call P_SetMobjState because the current state // falls through to the swing attack } } //---------------------------------------------------------------------------- // // PROC A_MinotaurCharge // //---------------------------------------------------------------------------- void A_MinotaurCharge(mobj_t * actor) { mobj_t *puff; if (actor->special1.i) { puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF); puff->momz = 2 * FRACUNIT; actor->special1.i--; } else { actor->flags &= ~MF_SKULLFLY; P_SetMobjState(actor, actor->info->seestate); } } //---------------------------------------------------------------------------- // // PROC A_MinotaurAtk2 // // Swing attack. // //---------------------------------------------------------------------------- void A_MinotaurAtk2(mobj_t * actor) { mobj_t *mo; angle_t angle; fixed_t momz; if (!actor->target) { return; } S_StartSound(actor, sfx_minat2); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(5)); return; } mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1); if (mo) { S_StartSound(mo, sfx_minat2); momz = mo->momz; angle = mo->angle; P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 8), momz); P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 8), momz); P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 16), momz); P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 16), momz); } } //---------------------------------------------------------------------------- // // PROC A_MinotaurAtk3 // // Floor fire attack. // //---------------------------------------------------------------------------- void A_MinotaurAtk3(mobj_t * actor) { mobj_t *mo; player_t *player; if (!actor->target) { return; } if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(5)); if ((player = actor->target->player) != NULL) { // Squish the player player->deltaviewheight = -16 * FRACUNIT; } } else { mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2); if (mo != NULL) { S_StartSound(mo, sfx_minat1); } } if (P_Random() < 192 && actor->special2.i == 0) { P_SetMobjState(actor, S_MNTR_ATK3_4); actor->special2.i = 1; } } //---------------------------------------------------------------------------- // // PROC A_MntrFloorFire // //---------------------------------------------------------------------------- void A_MntrFloorFire(mobj_t * actor) { mobj_t *mo; actor->z = actor->floorz; mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10), actor->y + ((P_Random() - P_Random()) << 10), ONFLOORZ, MT_MNTRFX3); mo->target = actor->target; mo->momx = 1; // Force block checking P_CheckMissileSpawn(mo); } //---------------------------------------------------------------------------- // // PROC A_BeastAttack // //---------------------------------------------------------------------------- void A_BeastAttack(mobj_t * actor) { if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(3)); return; } P_SpawnMissile(actor, actor->target, MT_BEASTBALL); } //---------------------------------------------------------------------------- // // PROC A_HeadAttack // //---------------------------------------------------------------------------- void A_HeadAttack(mobj_t * actor) { int i; mobj_t *fire; mobj_t *baseFire; mobj_t *mo; mobj_t *target; int randAttack; static int atkResolve1[] = { 50, 150 }; static int atkResolve2[] = { 150, 200 }; int dist; // Ice ball (close 20% : far 60%) // Fire column (close 40% : far 20%) // Whirlwind (close 40% : far 20%) // Distance threshold = 8 cells target = actor->target; if (target == NULL) { return; } A_FaceTarget(actor); if (P_CheckMeleeRange(actor)) { P_DamageMobj(target, actor, actor, HITDICE(6)); return; } dist = P_AproxDistance(actor->x - target->x, actor->y - target->y) > 8 * 64 * FRACUNIT; randAttack = P_Random(); if (randAttack < atkResolve1[dist]) { // Ice ball P_SpawnMissile(actor, target, MT_HEADFX1); S_StartSound(actor, sfx_hedat2); } else if (randAttack < atkResolve2[dist]) { // Fire column baseFire = P_SpawnMissile(actor, target, MT_HEADFX3); if (baseFire != NULL) { P_SetMobjState(baseFire, S_HEADFX3_4); // Don't grow for (i = 0; i < 5; i++) { fire = P_SpawnMobj(baseFire->x, baseFire->y, baseFire->z, MT_HEADFX3); if (i == 0) { S_StartSound(actor, sfx_hedat1); } fire->target = baseFire->target; fire->angle = baseFire->angle; fire->momx = baseFire->momx; fire->momy = baseFire->momy; fire->momz = baseFire->momz; fire->damage = 0; fire->health = (i + 1) * 2; P_CheckMissileSpawn(fire); } } } else { // Whirlwind mo = P_SpawnMissile(actor, target, MT_WHIRLWIND); if (mo != NULL) { mo->z -= 32 * FRACUNIT; mo->special1.m = target; mo->special2.i = 50; // Timer for active sound mo->health = 20 * TICRATE; // Duration S_StartSound(actor, sfx_hedat3); } } } //---------------------------------------------------------------------------- // // PROC A_WhirlwindSeek // //---------------------------------------------------------------------------- void A_WhirlwindSeek(mobj_t * actor) { actor->health -= 3; if (actor->health < 0) { actor->momx = actor->momy = actor->momz = 0; P_SetMobjState(actor, mobjinfo[actor->type].deathstate); actor->flags &= ~MF_MISSILE; return; } if ((actor->special2.i -= 3) < 0) { actor->special2.i = 58 + (P_Random() & 31); S_StartSound(actor, sfx_hedat3); } if (actor->special1.m && (((mobj_t *) (actor->special1.m))->flags & MF_SHADOW)) { return; } P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 30); } //---------------------------------------------------------------------------- // // PROC A_HeadIceImpact // //---------------------------------------------------------------------------- void A_HeadIceImpact(mobj_t * ice) { unsigned int i; angle_t angle; mobj_t *shard; for (i = 0; i < 8; i++) { shard = P_SpawnMobj(ice->x, ice->y, ice->z, MT_HEADFX2); angle = i * ANG45; shard->target = ice->target; shard->angle = angle; angle >>= ANGLETOFINESHIFT; shard->momx = FixedMul(shard->info->speed, finecosine[angle]); shard->momy = FixedMul(shard->info->speed, finesine[angle]); shard->momz = (fixed_t)(-.6 * FRACUNIT); P_CheckMissileSpawn(shard); } } //---------------------------------------------------------------------------- // // PROC A_HeadFireGrow // //---------------------------------------------------------------------------- void A_HeadFireGrow(mobj_t * fire) { fire->health--; fire->z += 9 * FRACUNIT; if (fire->health == 0) { fire->damage = fire->info->damage; P_SetMobjState(fire, S_HEADFX3_4); } } //---------------------------------------------------------------------------- // // PROC A_SnakeAttack // //---------------------------------------------------------------------------- void A_SnakeAttack(mobj_t * actor) { if (!actor->target) { P_SetMobjState(actor, S_SNAKE_WALK1); return; } S_StartSound(actor, actor->info->attacksound); A_FaceTarget(actor); P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_A); } //---------------------------------------------------------------------------- // // PROC A_SnakeAttack2 // //---------------------------------------------------------------------------- void A_SnakeAttack2(mobj_t * actor) { if (!actor->target) { P_SetMobjState(actor, S_SNAKE_WALK1); return; } S_StartSound(actor, actor->info->attacksound); A_FaceTarget(actor); P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_B); } //---------------------------------------------------------------------------- // // PROC A_ClinkAttack // //---------------------------------------------------------------------------- void A_ClinkAttack(mobj_t * actor) { int damage; if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { damage = ((P_Random() % 7) + 3); P_DamageMobj(actor->target, actor, actor, damage); } } //---------------------------------------------------------------------------- // // PROC A_GhostOff // //---------------------------------------------------------------------------- void A_GhostOff(mobj_t * actor) { actor->flags &= ~MF_SHADOW; } //---------------------------------------------------------------------------- // // PROC A_WizAtk1 // //---------------------------------------------------------------------------- void A_WizAtk1(mobj_t * actor) { A_FaceTarget(actor); actor->flags &= ~MF_SHADOW; } //---------------------------------------------------------------------------- // // PROC A_WizAtk2 // //---------------------------------------------------------------------------- void A_WizAtk2(mobj_t * actor) { A_FaceTarget(actor); actor->flags |= MF_SHADOW; } //---------------------------------------------------------------------------- // // PROC A_WizAtk3 // //---------------------------------------------------------------------------- void A_WizAtk3(mobj_t * actor) { mobj_t *mo; angle_t angle; fixed_t momz; actor->flags &= ~MF_SHADOW; if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(4)); return; } mo = P_SpawnMissile(actor, actor->target, MT_WIZFX1); if (mo) { momz = mo->momz; angle = mo->angle; P_SpawnMissileAngle(actor, MT_WIZFX1, angle - (ANG45 / 8), momz); P_SpawnMissileAngle(actor, MT_WIZFX1, angle + (ANG45 / 8), momz); } } //---------------------------------------------------------------------------- // // PROC A_Scream // //---------------------------------------------------------------------------- void A_Scream(mobj_t * actor) { switch (actor->type) { case MT_CHICPLAYER: case MT_SORCERER1: case MT_MINOTAUR: // Make boss death sounds full volume S_StartSound(NULL, actor->info->deathsound); break; case MT_PLAYER: // Handle the different player death screams if (actor->special1.i < 10) { // Wimpy death sound S_StartSound(actor, sfx_plrwdth); } else if (actor->health > -50) { // Normal death sound S_StartSound(actor, actor->info->deathsound); } else if (actor->health > -100) { // Crazy death sound S_StartSound(actor, sfx_plrcdth); } else { // Extreme death sound S_StartSound(actor, sfx_gibdth); } break; default: S_StartSound(actor, actor->info->deathsound); break; } } //--------------------------------------------------------------------------- // // PROC P_DropItem // //--------------------------------------------------------------------------- void P_DropItem(mobj_t * source, mobjtype_t type, int special, int chance) { mobj_t *mo; if (P_Random() > chance) { return; } mo = P_SpawnMobj(source->x, source->y, source->z + (source->height >> 1), type); mo->momx = (P_Random() - P_Random()) << 8; mo->momy = (P_Random() - P_Random()) << 8; mo->momz = FRACUNIT * 5 + (P_Random() << 10); mo->flags |= MF_DROPPED; mo->health = special; } //---------------------------------------------------------------------------- // // PROC A_NoBlocking // //---------------------------------------------------------------------------- void A_NoBlocking(mobj_t * actor) { actor->flags &= ~MF_SOLID; // Check for monsters dropping things switch (actor->type) { case MT_MUMMY: case MT_MUMMYLEADER: case MT_MUMMYGHOST: case MT_MUMMYLEADERGHOST: P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84); break; case MT_KNIGHT: case MT_KNIGHTGHOST: P_DropItem(actor, MT_AMCBOWWIMPY, 5, 84); break; case MT_WIZARD: P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84); P_DropItem(actor, MT_ARTITOMEOFPOWER, 0, 4); break; case MT_HEAD: P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84); P_DropItem(actor, MT_ARTIEGG, 0, 51); break; case MT_BEAST: P_DropItem(actor, MT_AMCBOWWIMPY, 10, 84); break; case MT_CLINK: P_DropItem(actor, MT_AMSKRDWIMPY, 20, 84); break; case MT_SNAKE: P_DropItem(actor, MT_AMPHRDWIMPY, 5, 84); break; case MT_MINOTAUR: P_DropItem(actor, MT_ARTISUPERHEAL, 0, 51); P_DropItem(actor, MT_AMPHRDWIMPY, 10, 84); break; default: break; } } //---------------------------------------------------------------------------- // // PROC A_Explode // // Handles a bunch of exploding things. // //---------------------------------------------------------------------------- void A_Explode(mobj_t * actor) { int damage; damage = 128; switch (actor->type) { case MT_FIREBOMB: // Time Bombs actor->z += 32 * FRACUNIT; actor->flags &= ~MF_SHADOW; break; case MT_MNTRFX2: // Minotaur floor fire damage = 24; break; case MT_SOR2FX1: // D'Sparil missile damage = 80 + (P_Random() & 31); break; default: break; } P_RadiusAttack(actor, actor->target, damage); P_HitFloor(actor); } //---------------------------------------------------------------------------- // // PROC A_PodPain // //---------------------------------------------------------------------------- void A_PodPain(mobj_t * actor) { int i; int count; int chance; mobj_t *goo; chance = P_Random(); if (chance < 128) { return; } count = chance > 240 ? 2 : 1; for (i = 0; i < count; i++) { goo = P_SpawnMobj(actor->x, actor->y, actor->z + 48 * FRACUNIT, MT_PODGOO); goo->target = actor; goo->momx = (P_Random() - P_Random()) << 9; goo->momy = (P_Random() - P_Random()) << 9; goo->momz = FRACUNIT / 2 + (P_Random() << 9); } } //---------------------------------------------------------------------------- // // PROC A_RemovePod // //---------------------------------------------------------------------------- void A_RemovePod(mobj_t * actor) { mobj_t *mo; if (actor->special2.m) { mo = (mobj_t *) actor->special2.m; if (mo->special1.i > 0) { mo->special1.i--; } } } //---------------------------------------------------------------------------- // // PROC A_MakePod // //---------------------------------------------------------------------------- #define MAX_GEN_PODS 16 void A_MakePod(mobj_t * actor) { mobj_t *mo; fixed_t x; fixed_t y; if (actor->special1.i == MAX_GEN_PODS) { // Too many generated pods return; } x = actor->x; y = actor->y; mo = P_SpawnMobj(x, y, ONFLOORZ, MT_POD); if (P_CheckPosition(mo, x, y) == false) { // Didn't fit P_RemoveMobj(mo); return; } P_SetMobjState(mo, S_POD_GROW1); P_ThrustMobj(mo, P_Random() << 24, (fixed_t) (4.5 * FRACUNIT)); S_StartSound(mo, sfx_newpod); actor->special1.i++; // Increment generated pod count mo->special2.m = actor; // Link the generator to the pod return; } //---------------------------------------------------------------------------- // // PROC P_Massacre // // Kills all monsters. // //---------------------------------------------------------------------------- void P_Massacre(void) { mobj_t *mo; thinker_t *think; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *) think; if ((mo->flags & MF_COUNTKILL) && (mo->health > 0)) { P_DamageMobj(mo, NULL, NULL, 10000); } } } //---------------------------------------------------------------------------- // // PROC A_BossDeath // // Trigger special effects if all bosses are dead. // //---------------------------------------------------------------------------- void A_BossDeath(mobj_t * actor) { mobj_t *mo; thinker_t *think; line_t dummyLine; static mobjtype_t bossType[6] = { MT_HEAD, MT_MINOTAUR, MT_SORCERER2, MT_HEAD, MT_MINOTAUR, -1 }; if (gamemap != 8) { // Not a boss level return; } if (actor->type != bossType[gameepisode - 1]) { // Not considered a boss in this episode return; } // Make sure all bosses are dead for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *) think; if ((mo != actor) && (mo->type == actor->type) && (mo->health > 0)) { // Found a living boss return; } } if (gameepisode > 1) { // Kill any remaining monsters P_Massacre(); } dummyLine.tag = 666; EV_DoFloor(&dummyLine, lowerFloor); } //---------------------------------------------------------------------------- // // PROC A_ESound // //---------------------------------------------------------------------------- void A_ESound(mobj_t * mo) { int sound = sfx_None; switch (mo->type) { case MT_SOUNDWATERFALL: sound = sfx_waterfl; break; case MT_SOUNDWIND: sound = sfx_wind; break; default: break; } S_StartSound(mo, sound); } //---------------------------------------------------------------------------- // // PROC A_SpawnTeleGlitter // //---------------------------------------------------------------------------- void A_SpawnTeleGlitter(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x + ((P_Random() & 31) - 16) * FRACUNIT, actor->y + ((P_Random() & 31) - 16) * FRACUNIT, actor->subsector->sector->floorheight, MT_TELEGLITTER); mo->momz = FRACUNIT / 4; } //---------------------------------------------------------------------------- // // PROC A_SpawnTeleGlitter2 // //---------------------------------------------------------------------------- void A_SpawnTeleGlitter2(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x + ((P_Random() & 31) - 16) * FRACUNIT, actor->y + ((P_Random() & 31) - 16) * FRACUNIT, actor->subsector->sector->floorheight, MT_TELEGLITTER2); mo->momz = FRACUNIT / 4; } //---------------------------------------------------------------------------- // // PROC A_AccTeleGlitter // //---------------------------------------------------------------------------- void A_AccTeleGlitter(mobj_t * actor) { if (++actor->health > 35) { actor->momz += actor->momz / 2; } } //---------------------------------------------------------------------------- // // PROC A_InitKeyGizmo // //---------------------------------------------------------------------------- void A_InitKeyGizmo(mobj_t * gizmo) { mobj_t *mo; statenum_t state = S_NULL; switch (gizmo->type) { case MT_KEYGIZMOBLUE: state = S_KGZ_BLUEFLOAT1; break; case MT_KEYGIZMOGREEN: state = S_KGZ_GREENFLOAT1; break; case MT_KEYGIZMOYELLOW: state = S_KGZ_YELLOWFLOAT1; break; default: break; } mo = P_SpawnMobj(gizmo->x, gizmo->y, gizmo->z + 60 * FRACUNIT, MT_KEYGIZMOFLOAT); P_SetMobjState(mo, state); } //---------------------------------------------------------------------------- // // PROC A_VolcanoSet // //---------------------------------------------------------------------------- void A_VolcanoSet(mobj_t * volcano) { volcano->tics = 105 + (P_Random() & 127); } //---------------------------------------------------------------------------- // // PROC A_VolcanoBlast // //---------------------------------------------------------------------------- void A_VolcanoBlast(mobj_t * volcano) { int i; int count; mobj_t *blast; angle_t angle; count = 1 + (P_Random() % 3); for (i = 0; i < count; i++) { blast = P_SpawnMobj(volcano->x, volcano->y, volcano->z + 44 * FRACUNIT, MT_VOLCANOBLAST); // MT_VOLCANOBLAST blast->target = volcano; angle = P_Random() << 24; blast->angle = angle; angle >>= ANGLETOFINESHIFT; blast->momx = FixedMul(1 * FRACUNIT, finecosine[angle]); blast->momy = FixedMul(1 * FRACUNIT, finesine[angle]); blast->momz = (fixed_t)(2.5 * FRACUNIT) + (P_Random() << 10); S_StartSound(blast, sfx_volsht); P_CheckMissileSpawn(blast); } } //---------------------------------------------------------------------------- // // PROC A_VolcBallImpact // //---------------------------------------------------------------------------- void A_VolcBallImpact(mobj_t * ball) { unsigned int i; mobj_t *tiny; angle_t angle; if (ball->z <= ball->floorz) { ball->flags |= MF_NOGRAVITY; ball->flags2 &= ~MF2_LOGRAV; ball->z += 28 * FRACUNIT; //ball->momz = 3*FRACUNIT; } P_RadiusAttack(ball, ball->target, 25); for (i = 0; i < 4; i++) { tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_VOLCANOTBLAST); tiny->target = ball; angle = i * ANG90; tiny->angle = angle; angle >>= ANGLETOFINESHIFT; tiny->momx = FixedMul((fixed_t)(FRACUNIT * .7), finecosine[angle]); tiny->momy = FixedMul((fixed_t)(FRACUNIT * .7), finesine[angle]); tiny->momz = FRACUNIT + (P_Random() << 9); P_CheckMissileSpawn(tiny); } } //---------------------------------------------------------------------------- // // PROC A_SkullPop // //---------------------------------------------------------------------------- void A_SkullPop(mobj_t * actor) { mobj_t *mo; player_t *player; actor->flags &= ~MF_SOLID; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 48 * FRACUNIT, MT_BLOODYSKULL); //mo->target = actor; mo->momx = (P_Random() - P_Random()) << 9; mo->momy = (P_Random() - P_Random()) << 9; mo->momz = FRACUNIT * 2 + (P_Random() << 6); // Attach player mobj to bloody skull player = actor->player; actor->player = NULL; mo->player = player; mo->health = actor->health; mo->angle = actor->angle; // fraggle: This check wasn't originally here in the Vanilla Heretic // source, causing crashes if the player respawns before this // function is called. if (player != NULL) { player->mo = mo; player->lookdir = 0; player->damagecount = 32; } } //---------------------------------------------------------------------------- // // PROC A_CheckSkullFloor // //---------------------------------------------------------------------------- void A_CheckSkullFloor(mobj_t * actor) { if (actor->z <= actor->floorz) { P_SetMobjState(actor, S_BLOODYSKULLX1); } } //---------------------------------------------------------------------------- // // PROC A_CheckSkullDone // //---------------------------------------------------------------------------- void A_CheckSkullDone(mobj_t * actor) { if (actor->special2.i == 666) { P_SetMobjState(actor, S_BLOODYSKULLX2); } } //---------------------------------------------------------------------------- // // PROC A_CheckBurnGone // //---------------------------------------------------------------------------- void A_CheckBurnGone(mobj_t * actor) { if (actor->special2.i == 666) { P_SetMobjState(actor, S_PLAY_FDTH20); } } //---------------------------------------------------------------------------- // // PROC A_FreeTargMobj // //---------------------------------------------------------------------------- void A_FreeTargMobj(mobj_t * mo) { mo->momx = mo->momy = mo->momz = 0; mo->z = mo->ceilingz + 4 * FRACUNIT; mo->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_SOLID); mo->flags |= MF_CORPSE | MF_DROPOFF | MF_NOGRAVITY; mo->flags2 &= ~(MF2_PASSMOBJ | MF2_LOGRAV); mo->player = NULL; } //---------------------------------------------------------------------------- // // PROC A_AddPlayerCorpse // //---------------------------------------------------------------------------- #define BODYQUESIZE 32 mobj_t *bodyque[BODYQUESIZE]; int bodyqueslot; void A_AddPlayerCorpse(mobj_t * actor) { if (bodyqueslot >= BODYQUESIZE) { // Too many player corpses - remove an old one P_RemoveMobj(bodyque[bodyqueslot % BODYQUESIZE]); } bodyque[bodyqueslot % BODYQUESIZE] = actor; bodyqueslot++; } //---------------------------------------------------------------------------- // // PROC A_FlameSnd // //---------------------------------------------------------------------------- void A_FlameSnd(mobj_t * actor) { S_StartSound(actor, sfx_hedat1); // Burn sound } //---------------------------------------------------------------------------- // // PROC A_HideThing // //---------------------------------------------------------------------------- void A_HideThing(mobj_t * actor) { //P_UnsetThingPosition(actor); actor->flags2 |= MF2_DONTDRAW; } //---------------------------------------------------------------------------- // // PROC A_UnHideThing // //---------------------------------------------------------------------------- void A_UnHideThing(mobj_t * actor) { //P_SetThingPosition(actor); actor->flags2 &= ~MF2_DONTDRAW; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_floor.c000066400000000000000000000374501257432200600233340ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" //================================================================== //================================================================== // // FLOORS // //================================================================== //================================================================== //================================================================== // // Move a plane (floor or ceiling) and check for crushing // //================================================================== result_e T_MovePlane(sector_t * sector, fixed_t speed, fixed_t dest, boolean crush, int floorOrCeiling, int direction) { boolean flag; fixed_t lastpos; switch (floorOrCeiling) { case 0: // FLOOR switch (direction) { case -1: // DOWN if (sector->floorheight - speed < dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); //return crushed; } return pastdest; } else { lastpos = sector->floorheight; sector->floorheight -= speed; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); return crushed; } } break; case 1: // UP if (sector->floorheight + speed > dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); //return crushed; } return pastdest; } else // COULD GET CRUSHED { lastpos = sector->floorheight; sector->floorheight += speed; flag = P_ChangeSector(sector, crush); if (flag == true) { if (crush == true) return crushed; sector->floorheight = lastpos; P_ChangeSector(sector, crush); return crushed; } } break; } break; case 1: // CEILING switch (direction) { case -1: // DOWN if (sector->ceilingheight - speed < dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); //return crushed; } return pastdest; } else // COULD GET CRUSHED { lastpos = sector->ceilingheight; sector->ceilingheight -= speed; flag = P_ChangeSector(sector, crush); if (flag == true) { if (crush == true) return crushed; sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); return crushed; } } break; case 1: // UP if (sector->ceilingheight + speed > dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); //return crushed; } return pastdest; } else { lastpos = sector->ceilingheight; sector->ceilingheight += speed; flag = P_ChangeSector(sector, crush); #if 0 if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); return crushed; } #endif } break; } break; } return ok; } //================================================================== // // MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN) // //================================================================== void T_MoveFloor(floormove_t * floor) { result_e res; res = T_MovePlane(floor->sector, floor->speed, floor->floordestheight, floor->crush, 0, floor->direction); if (!(leveltime & 7)) { S_StartSound(&floor->sector->soundorg, sfx_dormov); } if (res == pastdest) { floor->sector->specialdata = NULL; if (floor->type == raiseBuildStep) { S_StartSound(&floor->sector->soundorg, sfx_pstop); } if (floor->direction == 1) switch (floor->type) { case donutRaise: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } else if (floor->direction == -1) switch (floor->type) { case lowerAndChange: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } P_RemoveThinker(&floor->thinker); } } //================================================================== // // HANDLE FLOOR TYPES // //================================================================== int EV_DoFloor(line_t * line, floor_e floortype) { int secnum; int rtn; int i; sector_t *sec; floormove_t *floor; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // // new floor thinker // rtn = 1; floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker(&floor->thinker); sec->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = floortype; floor->crush = false; switch (floortype) { case lowerFloor: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindHighestFloorSurrounding(sec); break; case lowerFloorToLowest: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestFloorSurrounding(sec); break; case turboLower: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED * 4; floor->floordestheight = (8 * FRACUNIT) + P_FindHighestFloorSurrounding(sec); break; case raiseFloorCrush: floor->crush = true; case raiseFloor: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestCeilingSurrounding(sec); if (floor->floordestheight > sec->ceilingheight) floor->floordestheight = sec->ceilingheight; floor->floordestheight -= (8 * FRACUNIT) * (floortype == raiseFloorCrush); break; case raiseFloorToNearest: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight); break; case raiseFloor24: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; break; case raiseFloor24AndChange: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; sec->floorpic = line->frontsector->floorpic; sec->special = line->frontsector->special; break; case raiseToTexture: { int minsize = INT_MAX; side_t *side; floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; for (i = 0; i < sec->linecount; i++) if (twoSided(secnum, i)) { side = getSide(secnum, i, 0); if (side->bottomtexture >= 0) if (textureheight[side->bottomtexture] < minsize) minsize = textureheight[side->bottomtexture]; side = getSide(secnum, i, 1); if (side->bottomtexture >= 0) if (textureheight[side->bottomtexture] < minsize) minsize = textureheight[side->bottomtexture]; } floor->floordestheight = floor->sector->floorheight + minsize; } break; case lowerAndChange: floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestFloorSurrounding(sec); floor->texture = sec->floorpic; for (i = 0; i < sec->linecount; i++) if (twoSided(secnum, i)) { if (getSide(secnum, i, 0)->sector - sectors == secnum) { sec = getSector(secnum, i, 1); floor->texture = sec->floorpic; floor->newspecial = sec->special; break; } else { sec = getSector(secnum, i, 0); floor->texture = sec->floorpic; floor->newspecial = sec->special; break; } } default: break; } } return rtn; } //================================================================== // // BUILD A STAIRCASE! // //================================================================== int EV_BuildStairs(line_t * line, fixed_t stepDelta) { int secnum; int height; int i; int newsecnum; int texture; int ok; int rtn; sector_t *sec, *tsec; floormove_t *floor; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // // new floor thinker // rtn = 1; height = sec->floorheight + stepDelta; floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker(&floor->thinker); sec->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = raiseBuildStep; floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = height; texture = sec->floorpic; // // Find next sector to raise // 1. Find 2-sided line with same sector side[0] // 2. Other side is the next sector to raise // do { ok = 0; for (i = 0; i < sec->linecount; i++) { if (!((sec->lines[i])->flags & ML_TWOSIDED)) continue; tsec = (sec->lines[i])->frontsector; newsecnum = tsec - sectors; if (secnum != newsecnum) continue; tsec = (sec->lines[i])->backsector; newsecnum = tsec - sectors; if (tsec->floorpic != texture) continue; height += stepDelta; if (tsec->specialdata) continue; sec = tsec; secnum = newsecnum; floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker(&floor->thinker); sec->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = raiseBuildStep; floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = height; ok = 1; break; } } while (ok); } return (rtn); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_inter.c000066400000000000000000001257161257432200600233370ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_inter.c #include "doomdef.h" #include "deh_str.h" #include "i_system.h" #include "i_timer.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" #define BONUSADD 6 int WeaponValue[] = { 1, // staff 3, // goldwand 4, // crossbow 5, // blaster 6, // skullrod 7, // phoenixrod 8, // mace 2, // gauntlets 0 // beak }; int maxammo[NUMAMMO] = { 100, // gold wand 50, // crossbow 200, // blaster 200, // skull rod 20, // phoenix rod 150 // mace }; int GetWeaponAmmo[NUMWEAPONS] = { 0, // staff 25, // gold wand 10, // crossbow 30, // blaster 50, // skull rod 2, // phoenix rod 50, // mace 0, // gauntlets 0 // beak }; static weapontype_t GetAmmoChange[] = { wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace }; /* static boolean GetAmmoChangePL1[NUMWEAPONS][NUMAMMO] = { // staff {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace}, // gold wand {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace}, // crossbow {-1, -1, wp_blaster, wp_skullrod, -1, -1}, // blaster {-1, -1, -1, -1, -1, -1}, // skull rod {-1, -1, -1, -1, -1, -1}, // phoenix rod {-1, -1, -1, -1, -1, -1}, // mace {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1}, // gauntlets {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace} }; */ /* static boolean GetAmmoChangePL2[NUMWEAPONS][NUMAMMO] = { // staff {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace}, // gold wand {-1, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace}, // crossbow {-1, -1, wp_blaster, wp_skullrod, wp_phoenixrod, -1}, // blaster {-1, -1, -1, wp_skullrod, wp_phoenixrod, -1}, // skull rod {-1, -1, -1, -1, -1, -1}, // phoenix rod {-1, -1, -1, -1, -1, -1}, // mace {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1}, // gauntlets {-1, -1, -1, wp_skullrod, wp_phoenixrod, wp_mace} }; */ //-------------------------------------------------------------------------- // // PROC P_SetMessage // //-------------------------------------------------------------------------- boolean ultimatemsg; void P_SetMessage(player_t * player, char *message, boolean ultmsg) { extern boolean messageson; if ((ultimatemsg || !messageson) && !ultmsg) { return; } player->message = message; player->messageTics = MESSAGETICS; BorderTopRefresh = true; if (ultmsg) { ultimatemsg = true; } } //-------------------------------------------------------------------------- // // FUNC P_GiveAmmo // // Returns true if the player accepted the ammo, false if it was // refused (player has maxammo[ammo]). // //-------------------------------------------------------------------------- boolean P_GiveAmmo(player_t * player, ammotype_t ammo, int count) { int prevAmmo; //weapontype_t changeWeapon; if (ammo == am_noammo) { return (false); } if ((unsigned int) ammo > NUMAMMO) { I_Error("P_GiveAmmo: bad type %i", ammo); } if (player->ammo[ammo] == player->maxammo[ammo]) { return (false); } if (gameskill == sk_baby || gameskill == sk_nightmare) { // extra ammo in baby mode and nightmare mode count += count >> 1; } prevAmmo = player->ammo[ammo]; player->ammo[ammo] += count; if (player->ammo[ammo] > player->maxammo[ammo]) { player->ammo[ammo] = player->maxammo[ammo]; } if (prevAmmo) { // Don't attempt to change weapons if the player already had // ammo of the type just given return (true); } if (player->readyweapon == wp_staff || player->readyweapon == wp_gauntlets) { if (player->weaponowned[GetAmmoChange[ammo]]) { player->pendingweapon = GetAmmoChange[ammo]; } } /* if(player->powers[pw_weaponlevel2]) { changeWeapon = GetAmmoChangePL2[player->readyweapon][ammo]; } else { changeWeapon = GetAmmoChangePL1[player->readyweapon][ammo]; } if(changeWeapon != -1) { if(player->weaponowned[changeWeapon]) { player->pendingweapon = changeWeapon; } } */ return (true); } //-------------------------------------------------------------------------- // // FUNC P_GiveWeapon // // Returns true if the weapon or its ammo was accepted. // //-------------------------------------------------------------------------- boolean P_GiveWeapon(player_t * player, weapontype_t weapon) { boolean gaveAmmo; boolean gaveWeapon; if (netgame && !deathmatch) { // Cooperative net-game if (player->weaponowned[weapon]) { return (false); } player->bonuscount += BONUSADD; player->weaponowned[weapon] = true; P_GiveAmmo(player, wpnlev1info[weapon].ammo, GetWeaponAmmo[weapon]); player->pendingweapon = weapon; if (player == &players[consoleplayer]) { S_StartSound(NULL, sfx_wpnup); } return (false); } gaveAmmo = P_GiveAmmo(player, wpnlev1info[weapon].ammo, GetWeaponAmmo[weapon]); if (player->weaponowned[weapon]) { gaveWeapon = false; } else { gaveWeapon = true; player->weaponowned[weapon] = true; if (WeaponValue[weapon] > WeaponValue[player->readyweapon]) { // Only switch to more powerful weapons player->pendingweapon = weapon; } } return (gaveWeapon || gaveAmmo); } //--------------------------------------------------------------------------- // // FUNC P_GiveBody // // Returns false if the body isn't needed at all. // //--------------------------------------------------------------------------- boolean P_GiveBody(player_t * player, int num) { int max; max = MAXHEALTH; if (player->chickenTics) { max = MAXCHICKENHEALTH; } if (player->health >= max) { return (false); } player->health += num; if (player->health > max) { player->health = max; } player->mo->health = player->health; return (true); } //--------------------------------------------------------------------------- // // FUNC P_GiveArmor // // Returns false if the armor is worse than the current armor. // //--------------------------------------------------------------------------- boolean P_GiveArmor(player_t * player, int armortype) { int hits; hits = armortype * 100; if (player->armorpoints >= hits) { return (false); } player->armortype = armortype; player->armorpoints = hits; return (true); } //--------------------------------------------------------------------------- // // PROC P_GiveKey // //--------------------------------------------------------------------------- void P_GiveKey(player_t * player, keytype_t key) { extern int playerkeys; extern vertex_t KeyPoints[]; if (player->keys[key]) { return; } if (player == &players[consoleplayer]) { playerkeys |= 1 << key; KeyPoints[key].x = 0; KeyPoints[key].y = 0; } player->bonuscount = BONUSADD; player->keys[key] = true; } //--------------------------------------------------------------------------- // // FUNC P_GivePower // // Returns true if power accepted. // //--------------------------------------------------------------------------- boolean P_GivePower(player_t * player, powertype_t power) { if (power == pw_invulnerability) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = INVULNTICS; return (true); } if (power == pw_weaponlevel2) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = WPNLEV2TICS; return (true); } if (power == pw_invisibility) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = INVISTICS; player->mo->flags |= MF_SHADOW; return (true); } if (power == pw_flight) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = FLIGHTTICS; player->mo->flags2 |= MF2_FLY; player->mo->flags |= MF_NOGRAVITY; if (player->mo->z <= player->mo->floorz) { player->flyheight = 10; // thrust the player in the air a bit } return (true); } if (power == pw_infrared) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = INFRATICS; return (true); } /* if(power == pw_ironfeet) { player->powers[power] = IRONTICS; return(true); } if(power == pw_strength) { P_GiveBody(player, 100); player->powers[power] = 1; return(true); } */ if (player->powers[power]) { return (false); // already got it } player->powers[power] = 1; return (true); } //--------------------------------------------------------------------------- // // FUNC P_GiveArtifact // // Returns true if artifact accepted. // //--------------------------------------------------------------------------- boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo) { int i; i = 0; while (player->inventory[i].type != arti && i < player->inventorySlotNum) { i++; } if (i == player->inventorySlotNum) { player->inventory[i].count = 1; player->inventory[i].type = arti; player->inventorySlotNum++; } else { if (player->inventory[i].count >= 16) { // Player already has 16 of this item return (false); } player->inventory[i].count++; } if (player->artifactCount == 0) { player->readyArtifact = arti; } player->artifactCount++; if (mo && (mo->flags & MF_COUNTITEM)) { player->itemcount++; } return (true); } //--------------------------------------------------------------------------- // // PROC P_SetDormantArtifact // // Removes the MF_SPECIAL flag, and initiates the artifact pickup // animation. // //--------------------------------------------------------------------------- void P_SetDormantArtifact(mobj_t * arti) { arti->flags &= ~MF_SPECIAL; if (deathmatch && (arti->type != MT_ARTIINVULNERABILITY) && (arti->type != MT_ARTIINVISIBILITY)) { P_SetMobjState(arti, S_DORMANTARTI1); } else { // Don't respawn P_SetMobjState(arti, S_DEADARTI1); } S_StartSound(arti, sfx_artiup); } //--------------------------------------------------------------------------- // // PROC A_RestoreArtifact // //--------------------------------------------------------------------------- void A_RestoreArtifact(mobj_t * arti) { arti->flags |= MF_SPECIAL; P_SetMobjState(arti, arti->info->spawnstate); S_StartSound(arti, sfx_respawn); } //---------------------------------------------------------------------------- // // PROC P_HideSpecialThing // //---------------------------------------------------------------------------- void P_HideSpecialThing(mobj_t * thing) { thing->flags &= ~MF_SPECIAL; thing->flags2 |= MF2_DONTDRAW; P_SetMobjState(thing, S_HIDESPECIAL1); } //--------------------------------------------------------------------------- // // PROC A_RestoreSpecialThing1 // // Make a special thing visible again. // //--------------------------------------------------------------------------- void A_RestoreSpecialThing1(mobj_t * thing) { if (thing->type == MT_WMACE) { // Do random mace placement P_RepositionMace(thing); } thing->flags2 &= ~MF2_DONTDRAW; S_StartSound(thing, sfx_respawn); } //--------------------------------------------------------------------------- // // PROC A_RestoreSpecialThing2 // //--------------------------------------------------------------------------- void A_RestoreSpecialThing2(mobj_t * thing) { thing->flags |= MF_SPECIAL; P_SetMobjState(thing, thing->info->spawnstate); } //--------------------------------------------------------------------------- // // PROC P_TouchSpecialThing // //--------------------------------------------------------------------------- void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { int i; player_t *player; fixed_t delta; int sound; boolean respawn; delta = special->z - toucher->z; if (delta > toucher->height || delta < -32 * FRACUNIT) { // Out of reach return; } if (toucher->health <= 0) { // Toucher is dead return; } sound = sfx_itemup; player = toucher->player; respawn = true; switch (special->sprite) { // Items case SPR_PTN1: // Item_HealingPotion if (!P_GiveBody(player, 10)) { return; } P_SetMessage(player, DEH_String(TXT_ITEMHEALTH), false); break; case SPR_SHLD: // Item_Shield1 if (!P_GiveArmor(player, 1)) { return; } P_SetMessage(player, DEH_String(TXT_ITEMSHIELD1), false); break; case SPR_SHD2: // Item_Shield2 if (!P_GiveArmor(player, 2)) { return; } P_SetMessage(player, DEH_String(TXT_ITEMSHIELD2), false); break; case SPR_BAGH: // Item_BagOfHolding if (!player->backpack) { for (i = 0; i < NUMAMMO; i++) { player->maxammo[i] *= 2; } player->backpack = true; } P_GiveAmmo(player, am_goldwand, AMMO_GWND_WIMPY); P_GiveAmmo(player, am_blaster, AMMO_BLSR_WIMPY); P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY); P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY); P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY); P_SetMessage(player, DEH_String(TXT_ITEMBAGOFHOLDING), false); break; case SPR_SPMP: // Item_SuperMap if (!P_GivePower(player, pw_allmap)) { return; } P_SetMessage(player, DEH_String(TXT_ITEMSUPERMAP), false); break; // Keys case SPR_BKYY: // Key_Blue if (!player->keys[key_blue]) { P_SetMessage(player, DEH_String(TXT_GOTBLUEKEY), false); } P_GiveKey(player, key_blue); sound = sfx_keyup; if (!netgame) { break; } return; case SPR_CKYY: // Key_Yellow if (!player->keys[key_yellow]) { P_SetMessage(player, DEH_String(TXT_GOTYELLOWKEY), false); } sound = sfx_keyup; P_GiveKey(player, key_yellow); if (!netgame) { break; } return; case SPR_AKYY: // Key_Green if (!player->keys[key_green]) { P_SetMessage(player, DEH_String(TXT_GOTGREENKEY), false); } sound = sfx_keyup; P_GiveKey(player, key_green); if (!netgame) { break; } return; // Artifacts case SPR_PTN2: // Arti_HealingPotion if (P_GiveArtifact(player, arti_health, special)) { P_SetMessage(player, DEH_String(TXT_ARTIHEALTH), false); P_SetDormantArtifact(special); } return; case SPR_SOAR: // Arti_Fly if (P_GiveArtifact(player, arti_fly, special)) { P_SetMessage(player, DEH_String(TXT_ARTIFLY), false); P_SetDormantArtifact(special); } return; case SPR_INVU: // Arti_Invulnerability if (P_GiveArtifact(player, arti_invulnerability, special)) { P_SetMessage(player, DEH_String(TXT_ARTIINVULNERABILITY), false); P_SetDormantArtifact(special); } return; case SPR_PWBK: // Arti_TomeOfPower if (P_GiveArtifact(player, arti_tomeofpower, special)) { P_SetMessage(player, DEH_String(TXT_ARTITOMEOFPOWER), false); P_SetDormantArtifact(special); } return; case SPR_INVS: // Arti_Invisibility if (P_GiveArtifact(player, arti_invisibility, special)) { P_SetMessage(player, DEH_String(TXT_ARTIINVISIBILITY), false); P_SetDormantArtifact(special); } return; case SPR_EGGC: // Arti_Egg if (P_GiveArtifact(player, arti_egg, special)) { P_SetMessage(player, DEH_String(TXT_ARTIEGG), false); P_SetDormantArtifact(special); } return; case SPR_SPHL: // Arti_SuperHealth if (P_GiveArtifact(player, arti_superhealth, special)) { P_SetMessage(player, DEH_String(TXT_ARTISUPERHEALTH), false); P_SetDormantArtifact(special); } return; case SPR_TRCH: // Arti_Torch if (P_GiveArtifact(player, arti_torch, special)) { P_SetMessage(player, DEH_String(TXT_ARTITORCH), false); P_SetDormantArtifact(special); } return; case SPR_FBMB: // Arti_FireBomb if (P_GiveArtifact(player, arti_firebomb, special)) { P_SetMessage(player, DEH_String(TXT_ARTIFIREBOMB), false); P_SetDormantArtifact(special); } return; case SPR_ATLP: // Arti_Teleport if (P_GiveArtifact(player, arti_teleport, special)) { P_SetMessage(player, DEH_String(TXT_ARTITELEPORT), false); P_SetDormantArtifact(special); } return; // Ammo case SPR_AMG1: // Ammo_GoldWandWimpy if (!P_GiveAmmo(player, am_goldwand, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND1), false); break; case SPR_AMG2: // Ammo_GoldWandHefty if (!P_GiveAmmo(player, am_goldwand, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND2), false); break; case SPR_AMM1: // Ammo_MaceWimpy if (!P_GiveAmmo(player, am_mace, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOMACE1), false); break; case SPR_AMM2: // Ammo_MaceHefty if (!P_GiveAmmo(player, am_mace, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOMACE2), false); break; case SPR_AMC1: // Ammo_CrossbowWimpy if (!P_GiveAmmo(player, am_crossbow, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW1), false); break; case SPR_AMC2: // Ammo_CrossbowHefty if (!P_GiveAmmo(player, am_crossbow, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW2), false); break; case SPR_AMB1: // Ammo_BlasterWimpy if (!P_GiveAmmo(player, am_blaster, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOBLASTER1), false); break; case SPR_AMB2: // Ammo_BlasterHefty if (!P_GiveAmmo(player, am_blaster, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOBLASTER2), false); break; case SPR_AMS1: // Ammo_SkullRodWimpy if (!P_GiveAmmo(player, am_skullrod, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD1), false); break; case SPR_AMS2: // Ammo_SkullRodHefty if (!P_GiveAmmo(player, am_skullrod, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD2), false); break; case SPR_AMP1: // Ammo_PhoenixRodWimpy if (!P_GiveAmmo(player, am_phoenixrod, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD1), false); break; case SPR_AMP2: // Ammo_PhoenixRodHefty if (!P_GiveAmmo(player, am_phoenixrod, special->health)) { return; } P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD2), false); break; // Weapons case SPR_WMCE: // Weapon_Mace if (!P_GiveWeapon(player, wp_mace)) { return; } P_SetMessage(player, DEH_String(TXT_WPNMACE), false); sound = sfx_wpnup; break; case SPR_WBOW: // Weapon_Crossbow if (!P_GiveWeapon(player, wp_crossbow)) { return; } P_SetMessage(player, DEH_String(TXT_WPNCROSSBOW), false); sound = sfx_wpnup; break; case SPR_WBLS: // Weapon_Blaster if (!P_GiveWeapon(player, wp_blaster)) { return; } P_SetMessage(player, DEH_String(TXT_WPNBLASTER), false); sound = sfx_wpnup; break; case SPR_WSKL: // Weapon_SkullRod if (!P_GiveWeapon(player, wp_skullrod)) { return; } P_SetMessage(player, DEH_String(TXT_WPNSKULLROD), false); sound = sfx_wpnup; break; case SPR_WPHX: // Weapon_PhoenixRod if (!P_GiveWeapon(player, wp_phoenixrod)) { return; } P_SetMessage(player, DEH_String(TXT_WPNPHOENIXROD), false); sound = sfx_wpnup; break; case SPR_WGNT: // Weapon_Gauntlets if (!P_GiveWeapon(player, wp_gauntlets)) { return; } P_SetMessage(player, DEH_String(TXT_WPNGAUNTLETS), false); sound = sfx_wpnup; break; default: I_Error("P_SpecialThing: Unknown gettable thing"); } if (special->flags & MF_COUNTITEM) { player->itemcount++; } if (deathmatch && respawn && !(special->flags & MF_DROPPED)) { P_HideSpecialThing(special); } else { P_RemoveMobj(special); } player->bonuscount += BONUSADD; if (player == &players[consoleplayer]) { S_StartSound(NULL, sound); SB_PaletteFlash(); } } //--------------------------------------------------------------------------- // // PROC P_KillMobj // //--------------------------------------------------------------------------- void P_KillMobj(mobj_t * source, mobj_t * target) { target->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_NOGRAVITY); target->flags |= MF_CORPSE | MF_DROPOFF; target->flags2 &= ~MF2_PASSMOBJ; target->height >>= 2; if (source && source->player) { if (target->flags & MF_COUNTKILL) { // Count for intermission source->player->killcount++; } if (target->player) { // Frag stuff if (target == source) { // Self-frag target->player->frags[target->player - players]--; } else { source->player->frags[target->player - players]++; if (source->player == &players[consoleplayer]) { S_StartSound(NULL, sfx_gfrag); } if (source->player->chickenTics) { // Make a super chicken P_GivePower(source->player, pw_weaponlevel2); } } } } else if (!netgame && (target->flags & MF_COUNTKILL)) { // Count all monster deaths players[0].killcount++; } if (target->player) { if (!source) { // Self-frag target->player->frags[target->player - players]--; } target->flags &= ~MF_SOLID; target->flags2 &= ~MF2_FLY; target->player->powers[pw_flight] = 0; target->player->powers[pw_weaponlevel2] = 0; target->player->playerstate = PST_DEAD; P_DropWeapon(target->player); if (target->flags2 & MF2_FIREDAMAGE) { // Player flame death P_SetMobjState(target, S_PLAY_FDTH1); //S_StartSound(target, sfx_hedat1); // Burn sound return; } } if (target->health < -(target->info->spawnhealth >> 1) && target->info->xdeathstate) { // Extreme death P_SetMobjState(target, target->info->xdeathstate); } else { // Normal death P_SetMobjState(target, target->info->deathstate); } target->tics -= P_Random() & 3; // I_StartSound(&actor->r, actor->info->deathsound); } //--------------------------------------------------------------------------- // // FUNC P_MinotaurSlam // //--------------------------------------------------------------------------- void P_MinotaurSlam(mobj_t * source, mobj_t * target) { angle_t angle; fixed_t thrust; angle = R_PointToAngle2(source->x, source->y, target->x, target->y); angle >>= ANGLETOFINESHIFT; thrust = 16 * FRACUNIT + (P_Random() << 10); target->momx += FixedMul(thrust, finecosine[angle]); target->momy += FixedMul(thrust, finesine[angle]); P_DamageMobj(target, NULL, NULL, HITDICE(6)); if (target->player) { target->reactiontime = 14 + (P_Random() & 7); } } //--------------------------------------------------------------------------- // // FUNC P_TouchWhirlwind // //--------------------------------------------------------------------------- void P_TouchWhirlwind(mobj_t * target) { int randVal; target->angle += (P_Random() - P_Random()) << 20; target->momx += (P_Random() - P_Random()) << 10; target->momy += (P_Random() - P_Random()) << 10; if (leveltime & 16 && !(target->flags2 & MF2_BOSS)) { randVal = P_Random(); if (randVal > 160) { randVal = 160; } target->momz += randVal << 10; if (target->momz > 12 * FRACUNIT) { target->momz = 12 * FRACUNIT; } } if (!(leveltime & 7)) { P_DamageMobj(target, NULL, NULL, 3); } } //--------------------------------------------------------------------------- // // FUNC P_ChickenMorphPlayer // // Returns true if the player gets turned into a chicken. // //--------------------------------------------------------------------------- boolean P_ChickenMorphPlayer(player_t * player) { mobj_t *pmo; mobj_t *fog; mobj_t *chicken; fixed_t x; fixed_t y; fixed_t z; angle_t angle; int oldFlags2; if (player->chickenTics) { if ((player->chickenTics < CHICKENTICS - TICRATE) && !player->powers[pw_weaponlevel2]) { // Make a super chicken P_GivePower(player, pw_weaponlevel2); } return (false); } if (player->powers[pw_invulnerability]) { // Immune when invulnerable return (false); } pmo = player->mo; x = pmo->x; y = pmo->y; z = pmo->z; angle = pmo->angle; oldFlags2 = pmo->flags2; P_SetMobjState(pmo, S_FREETARGMOBJ); fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, sfx_telept); chicken = P_SpawnMobj(x, y, z, MT_CHICPLAYER); chicken->special1.i = player->readyweapon; chicken->angle = angle; chicken->player = player; player->health = chicken->health = MAXCHICKENHEALTH; player->mo = chicken; player->armorpoints = player->armortype = 0; player->powers[pw_invisibility] = 0; player->powers[pw_weaponlevel2] = 0; if (oldFlags2 & MF2_FLY) { chicken->flags2 |= MF2_FLY; } player->chickenTics = CHICKENTICS; P_ActivateBeak(player); return (true); } //--------------------------------------------------------------------------- // // FUNC P_ChickenMorph // //--------------------------------------------------------------------------- boolean P_ChickenMorph(mobj_t * actor) { mobj_t *fog; mobj_t *chicken; mobj_t *target; mobjtype_t moType; fixed_t x; fixed_t y; fixed_t z; angle_t angle; int ghost; if (actor->player) { return (false); } moType = actor->type; switch (moType) { case MT_POD: case MT_CHICKEN: case MT_HEAD: case MT_MINOTAUR: case MT_SORCERER1: case MT_SORCERER2: return (false); default: break; } x = actor->x; y = actor->y; z = actor->z; angle = actor->angle; ghost = actor->flags & MF_SHADOW; target = actor->target; P_SetMobjState(actor, S_FREETARGMOBJ); fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, sfx_telept); chicken = P_SpawnMobj(x, y, z, MT_CHICKEN); chicken->special2.i = moType; chicken->special1.i = CHICKENTICS + P_Random(); chicken->flags |= ghost; chicken->target = target; chicken->angle = angle; return (true); } //--------------------------------------------------------------------------- // // FUNC P_AutoUseChaosDevice // //--------------------------------------------------------------------------- boolean P_AutoUseChaosDevice(player_t * player) { int i; for (i = 0; i < player->inventorySlotNum; i++) { if (player->inventory[i].type == arti_teleport) { P_PlayerUseArtifact(player, arti_teleport); player->health = player->mo->health = (player->health + 1) / 2; return (true); } } return (false); } //--------------------------------------------------------------------------- // // PROC P_AutoUseHealth // //--------------------------------------------------------------------------- void P_AutoUseHealth(player_t * player, int saveHealth) { int i; int count; int normalCount; int normalSlot; int superCount; int superSlot; normalCount = 0; superCount = 0; normalSlot = 0; superSlot = 0; for (i = 0; i < player->inventorySlotNum; i++) { if (player->inventory[i].type == arti_health) { normalSlot = i; normalCount = player->inventory[i].count; } else if (player->inventory[i].type == arti_superhealth) { superSlot = i; superCount = player->inventory[i].count; } } if ((gameskill == sk_baby) && (normalCount * 25 >= saveHealth)) { // Use quartz flasks count = (saveHealth + 24) / 25; for (i = 0; i < count; i++) { player->health += 25; P_PlayerRemoveArtifact(player, normalSlot); } } else if (superCount * 100 >= saveHealth) { // Use mystic urns count = (saveHealth + 99) / 100; for (i = 0; i < count; i++) { player->health += 100; P_PlayerRemoveArtifact(player, superSlot); } } else if ((gameskill == sk_baby) && (superCount * 100 + normalCount * 25 >= saveHealth)) { // Use mystic urns and quartz flasks count = (saveHealth + 24) / 25; saveHealth -= count * 25; for (i = 0; i < count; i++) { player->health += 25; P_PlayerRemoveArtifact(player, normalSlot); } count = (saveHealth + 99) / 100; for (i = 0; i < count; i++) { player->health += 100; P_PlayerRemoveArtifact(player, normalSlot); } } player->mo->health = player->health; } /* ================= = = P_DamageMobj = = Damages both enemies and players = inflictor is the thing that caused the damage = creature or missile, can be NULL (slime, etc) = source is the thing to target after taking damage = creature or NULL = Source and inflictor are the same for melee attacks = source can be null for barrel explosions and other environmental stuff ================== */ void P_DamageMobj (mobj_t * target, mobj_t * inflictor, mobj_t * source, int damage) { unsigned ang; int saved; player_t *player; fixed_t thrust; int temp; if (!(target->flags & MF_SHOOTABLE)) { // Shouldn't happen return; } if (target->health <= 0) { return; } if (target->flags & MF_SKULLFLY) { if (target->type == MT_MINOTAUR) { // Minotaur is invulnerable during charge attack return; } target->momx = target->momy = target->momz = 0; } player = target->player; if (player && gameskill == sk_baby) { // Take half damage in trainer mode damage >>= 1; } // Special damage types if (inflictor) { switch (inflictor->type) { case MT_EGGFX: if (player) { P_ChickenMorphPlayer(player); } else { P_ChickenMorph(target); } return; // Always return case MT_WHIRLWIND: P_TouchWhirlwind(target); return; case MT_MINOTAUR: if (inflictor->flags & MF_SKULLFLY) { // Slam only when in charge mode P_MinotaurSlam(inflictor, target); return; } break; case MT_MACEFX4: // Death ball if ((target->flags2 & MF2_BOSS) || target->type == MT_HEAD) { // Don't allow cheap boss kills break; } else if (target->player) { // Player specific checks if (target->player->powers[pw_invulnerability]) { // Can't hurt invulnerable players break; } if (P_AutoUseChaosDevice(target->player)) { // Player was saved using chaos device return; } } damage = 10000; // Something's gonna die break; case MT_PHOENIXFX2: // Flame thrower if (target->player && P_Random() < 128) { // Freeze player for a bit target->reactiontime += 4; } break; case MT_RAINPLR1: // Rain missiles case MT_RAINPLR2: case MT_RAINPLR3: case MT_RAINPLR4: if (target->flags2 & MF2_BOSS) { // Decrease damage for bosses damage = (P_Random() & 7) + 1; } break; case MT_HORNRODFX2: case MT_PHOENIXFX1: if (target->type == MT_SORCERER2 && P_Random() < 96) { // D'Sparil teleports away P_DSparilTeleport(target); return; } break; case MT_BLASTERFX1: case MT_RIPPER: if (target->type == MT_HEAD) { // Less damage to Ironlich bosses damage = P_Random() & 1; if (!damage) { return; } } break; default: break; } } // Push the target unless source is using the gauntlets if (inflictor && (!source || !source->player || source->player->readyweapon != wp_gauntlets) && !(inflictor->flags2 & MF2_NODMGTHRUST)) { ang = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y); //thrust = damage*(FRACUNIT>>3)*100/target->info->mass; thrust = damage * (FRACUNIT >> 3) * 150 / target->info->mass; // make fall forwards sometimes if ((damage < 40) && (damage > target->health) && (target->z - inflictor->z > 64 * FRACUNIT) && (P_Random() & 1)) { ang += ANG180; thrust *= 4; } ang >>= ANGLETOFINESHIFT; if (source && source->player && (source == inflictor) && source->player->powers[pw_weaponlevel2] && source->player->readyweapon == wp_staff) { // Staff power level 2 target->momx += FixedMul(10 * FRACUNIT, finecosine[ang]); target->momy += FixedMul(10 * FRACUNIT, finesine[ang]); if (!(target->flags & MF_NOGRAVITY)) { target->momz += 5 * FRACUNIT; } } else { target->momx += FixedMul(thrust, finecosine[ang]); target->momy += FixedMul(thrust, finesine[ang]); } } // // player specific // if (player) { // end of game hell hack //if(target->subsector->sector->special == 11 // && damage >= target->health) //{ // damage = target->health - 1; //} if (damage < 1000 && ((player->cheats & CF_GODMODE) || player->powers[pw_invulnerability])) { return; } if (player->armortype) { if (player->armortype == 1) { saved = damage >> 1; } else { saved = (damage >> 1) + (damage >> 2); } if (player->armorpoints <= saved) { // armor is used up saved = player->armorpoints; player->armortype = 0; } player->armorpoints -= saved; damage -= saved; } if (damage >= player->health && ((gameskill == sk_baby) || deathmatch) && !player->chickenTics) { // Try to use some inventory health P_AutoUseHealth(player, damage - player->health + 1); } player->health -= damage; // mirror mobj health here for Dave if (player->health < 0) { player->health = 0; } player->attacker = source; player->damagecount += damage; // add damage after armor / invuln if (player->damagecount > 100) { player->damagecount = 100; // teleport stomp does 10k points... } temp = damage < 100 ? damage : 100; if (player == &players[consoleplayer]) { I_Tactile(40, 10, 40 + temp * 2); SB_PaletteFlash(); } } // // do the damage // target->health -= damage; if (target->health <= 0) { // Death target->special1.i = damage; if (target->type == MT_POD && source && source->type != MT_POD) { // Make sure players get frags for chain-reaction kills target->target = source; } if (player && inflictor && !player->chickenTics) { // Check for flame death if ((inflictor->flags2 & MF2_FIREDAMAGE) || ((inflictor->type == MT_PHOENIXFX1) && (target->health > -50) && (damage > 25))) { target->flags2 |= MF2_FIREDAMAGE; } } P_KillMobj(source, target); return; } if ((P_Random() < target->info->painchance) && !(target->flags & MF_SKULLFLY)) { target->flags |= MF_JUSTHIT; // fight back! P_SetMobjState(target, target->info->painstate); } target->reactiontime = 0; // we're awake now... if (!target->threshold && source && !(source->flags2 & MF2_BOSS) && !(target->type == MT_SORCERER2 && source->type == MT_WIZARD)) { // Target actor is not intent on another actor, // so make him chase after source target->target = source; target->threshold = BASETHRESHOLD; if (target->state == &states[target->info->spawnstate] && target->info->seestate != S_NULL) { P_SetMobjState(target, target->info->seestate); } } } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_lights.c000066400000000000000000000173101257432200600234760ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "doomdef.h" #include "m_random.h" #include "p_local.h" #include "v_video.h" //================================================================== //================================================================== // // BROKEN LIGHT FLASHING // //================================================================== //================================================================== //================================================================== // // T_LightFlash // // After the map has been loaded, scan each sector for specials // that spawn thinkers // //================================================================== void T_LightFlash(lightflash_t * flash) { if (--flash->count) return; if (flash->sector->lightlevel == flash->maxlight) { flash->sector->lightlevel = flash->minlight; flash->count = (P_Random() & flash->mintime) + 1; } else { flash->sector->lightlevel = flash->maxlight; flash->count = (P_Random() & flash->maxtime) + 1; } } //================================================================== // // P_SpawnLightFlash // // After the map has been loaded, scan each sector for specials that spawn thinkers // //================================================================== void P_SpawnLightFlash(sector_t * sector) { lightflash_t *flash; sector->special = 0; // nothing special about it during gameplay flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0); P_AddThinker(&flash->thinker); flash->thinker.function = T_LightFlash; flash->sector = sector; flash->maxlight = sector->lightlevel; flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); flash->maxtime = 64; flash->mintime = 7; flash->count = (P_Random() & flash->maxtime) + 1; } //================================================================== // // STROBE LIGHT FLASHING // //================================================================== //================================================================== // // T_StrobeFlash // // After the map has been loaded, scan each sector for specials that spawn thinkers // //================================================================== void T_StrobeFlash(strobe_t * flash) { if (--flash->count) return; if (flash->sector->lightlevel == flash->minlight) { flash->sector->lightlevel = flash->maxlight; flash->count = flash->brighttime; } else { flash->sector->lightlevel = flash->minlight; flash->count = flash->darktime; } } //================================================================== // // P_SpawnLightFlash // // After the map has been loaded, scan each sector for specials that spawn thinkers // //================================================================== void P_SpawnStrobeFlash(sector_t * sector, int fastOrSlow, int inSync) { strobe_t *flash; flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0); P_AddThinker(&flash->thinker); flash->sector = sector; flash->darktime = fastOrSlow; flash->brighttime = STROBEBRIGHT; flash->thinker.function = T_StrobeFlash; flash->maxlight = sector->lightlevel; flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); if (flash->minlight == flash->maxlight) flash->minlight = 0; sector->special = 0; // nothing special about it during gameplay if (!inSync) flash->count = (P_Random() & 7) + 1; else flash->count = 1; } //================================================================== // // Start strobing lights (usually from a trigger) // //================================================================== void EV_StartLightStrobing(line_t * line) { int secnum; sector_t *sec; secnum = -1; while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; P_SpawnStrobeFlash(sec, SLOWDARK, 0); } } //================================================================== // // TURN LINE'S TAG LIGHTS OFF // //================================================================== void EV_TurnTagLightsOff(line_t * line) { int i; int j; int min; sector_t *sector; sector_t *tsec; line_t *templine; sector = sectors; for (j = 0; j < numsectors; j++, sector++) if (sector->tag == line->tag) { min = sector->lightlevel; for (i = 0; i < sector->linecount; i++) { templine = sector->lines[i]; tsec = getNextSector(templine, sector); if (!tsec) continue; if (tsec->lightlevel < min) min = tsec->lightlevel; } sector->lightlevel = min; } } //================================================================== // // TURN LINE'S TAG LIGHTS ON // //================================================================== void EV_LightTurnOn(line_t * line, int bright) { int i; int j; sector_t *sector; sector_t *temp; line_t *templine; sector = sectors; for (i = 0; i < numsectors; i++, sector++) if (sector->tag == line->tag) { // // bright = 0 means to search for highest // light level surrounding sector // if (!bright) { for (j = 0; j < sector->linecount; j++) { templine = sector->lines[j]; temp = getNextSector(templine, sector); if (!temp) continue; if (temp->lightlevel > bright) bright = temp->lightlevel; } } sector->lightlevel = bright; } } //================================================================== // // Spawn glowing light // //================================================================== void T_Glow(glow_t * g) { switch (g->direction) { case -1: // DOWN g->sector->lightlevel -= GLOWSPEED; if (g->sector->lightlevel <= g->minlight) { g->sector->lightlevel += GLOWSPEED; g->direction = 1; } break; case 1: // UP g->sector->lightlevel += GLOWSPEED; if (g->sector->lightlevel >= g->maxlight) { g->sector->lightlevel -= GLOWSPEED; g->direction = -1; } break; } } void P_SpawnGlowingLight(sector_t * sector) { glow_t *g; g = Z_Malloc(sizeof(*g), PU_LEVSPEC, 0); P_AddThinker(&g->thinker); g->sector = sector; g->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); g->maxlight = sector->lightlevel; g->thinker.function = T_Glow; g->direction = -1; sector->special = 0; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_local.h000066400000000000000000000204421257432200600233030ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_local.h #ifndef __P_LOCAL__ #define __P_LOCAL__ #ifndef __R_LOCAL__ #include "r_local.h" #endif #define STARTREDPALS 1 #define STARTBONUSPALS 9 #define NUMREDPALS 8 #define NUMBONUSPALS 4 #define FOOTCLIPSIZE 10*FRACUNIT #define TOCENTER -8 #define FLOATSPEED (FRACUNIT*4) #define MAXHEALTH 100 #define MAXCHICKENHEALTH 30 #define VIEWHEIGHT (41*FRACUNIT) // mapblocks are used to check movement against lines and things #define MAPBLOCKUNITS 128 #define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) #define MAPBLOCKSHIFT (FRACBITS+7) #define MAPBMASK (MAPBLOCKSIZE-1) #define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) // player radius for movement checking #define PLAYERRADIUS 16*FRACUNIT // MAXRADIUS is for precalculated sector block boxes // the spider demon is larger, but we don't have any moving sectors // nearby #define MAXRADIUS 32*FRACUNIT #define GRAVITY FRACUNIT #define MAXMOVE (30*FRACUNIT) #define USERANGE (64*FRACUNIT) #define MELEERANGE (64*FRACUNIT) #define MISSILERANGE (32*64*FRACUNIT) typedef enum { DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_NODIR, NUMDIRS } dirtype_t; #define BASETHRESHOLD 100 // follow a player exlusively for 3 seconds // ***** P_TICK ***** extern thinker_t thinkercap; // both the head and tail of the thinker list extern int TimerGame; // tic countdown for deathmatch void P_InitThinkers(void); void P_AddThinker(thinker_t * thinker); void P_RemoveThinker(thinker_t * thinker); // ***** P_PSPR ***** #define USE_GWND_AMMO_1 1 #define USE_GWND_AMMO_2 1 #define USE_CBOW_AMMO_1 1 #define USE_CBOW_AMMO_2 1 #define USE_BLSR_AMMO_1 1 #define USE_BLSR_AMMO_2 5 #define USE_SKRD_AMMO_1 1 #define USE_SKRD_AMMO_2 5 #define USE_PHRD_AMMO_1 1 #define USE_PHRD_AMMO_2 1 #define USE_MACE_AMMO_1 1 #define USE_MACE_AMMO_2 5 void P_OpenWeapons(void); void P_CloseWeapons(void); void P_AddMaceSpot(mapthing_t * mthing); void P_RepositionMace(mobj_t * mo); void P_SetPsprite(player_t * player, int position, statenum_t stnum); void P_SetupPsprites(player_t * curplayer); void P_MovePsprites(player_t * curplayer); void P_DropWeapon(player_t * player); void P_ActivateBeak(player_t * player); void P_PostChickenWeapon(player_t * player, weapontype_t weapon); void P_UpdateBeak(player_t * player, pspdef_t * psp); // ***** P_USER ***** void P_PlayerThink(player_t * player); void P_Thrust(player_t * player, angle_t angle, fixed_t move); void P_PlayerRemoveArtifact(player_t * player, int slot); void P_PlayerUseArtifact(player_t * player, artitype_t arti); boolean P_UseArtifact(player_t * player, artitype_t arti); int P_GetPlayerNum(player_t * player); // ***** P_MOBJ ***** #define FLOOR_SOLID 0 #define FLOOR_WATER 1 #define FLOOR_LAVA 2 #define FLOOR_SLUDGE 3 #define ONFLOORZ INT_MIN #define ONCEILINGZ INT_MAX #define FLOATRANDZ (INT_MAX-1) extern mobjtype_t PuffType; extern mobj_t *MissileMobj; mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); void P_RemoveMobj(mobj_t * th); boolean P_SetMobjState(mobj_t * mobj, statenum_t state); boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state); void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move); int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta); boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax); void P_MobjThinker(mobj_t * mobj); void P_BlasterMobjThinker(mobj_t * mobj); void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z); void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage); void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator); void P_RipperBlood(mobj_t * mo); int P_GetThingFloorType(mobj_t * thing); int P_HitFloor(mobj_t * thing); boolean P_CheckMissileSpawn(mobj_t * missile); mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type); mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type, angle_t angle, fixed_t momz); mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type); mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle); // ***** P_ENEMY ***** void P_NoiseAlert(mobj_t * target, mobj_t * emmiter); void P_InitMonsters(void); void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle); void P_Massacre(void); void P_DSparilTeleport(mobj_t * actor); // ***** P_MAPUTL ***** typedef struct { fixed_t x, y, dx, dy; } divline_t; typedef struct { fixed_t frac; // along trace line boolean isaline; union { mobj_t *thing; line_t *line; } d; } intercept_t; #define MAXINTERCEPTS 128 extern intercept_t intercepts[MAXINTERCEPTS], *intercept_p; typedef boolean(*traverser_t) (intercept_t * in); fixed_t P_AproxDistance(fixed_t dx, fixed_t dy); int P_PointOnLineSide(fixed_t x, fixed_t y, line_t * line); int P_PointOnDivlineSide(fixed_t x, fixed_t y, divline_t * line); void P_MakeDivline(line_t * li, divline_t * dl); fixed_t P_InterceptVector(divline_t * v2, divline_t * v1); int P_BoxOnLineSide(fixed_t * tmbox, line_t * ld); extern fixed_t opentop, openbottom, openrange; extern fixed_t lowfloor; void P_LineOpening(line_t * linedef); boolean P_BlockLinesIterator(int x, int y, boolean(*func) (line_t *)); boolean P_BlockThingsIterator(int x, int y, boolean(*func) (mobj_t *)); #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 #define PT_EARLYOUT 4 extern divline_t trace; boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean(*trav) (intercept_t *)); void P_UnsetThingPosition(mobj_t * thing); void P_SetThingPosition(mobj_t * thing); // ***** P_MAP ***** extern boolean floatok; // if true, move would be ok if extern fixed_t tmfloorz, tmceilingz; // within tmfloorz - tmceilingz extern line_t *ceilingline; boolean P_TestMobjLocation(mobj_t * mobj); boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y); mobj_t *P_CheckOnmobj(mobj_t * thing); void P_FakeZMovement(mobj_t * mo); boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y); boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y); void P_SlideMove(mobj_t * mo); boolean P_CheckSight(mobj_t * t1, mobj_t * t2); void P_UseLines(player_t * player); boolean P_ChangeSector(sector_t * sector, boolean crunch); extern mobj_t *linetarget; // who got hit (or NULL) fixed_t P_AimLineAttack(mobj_t * t1, angle_t angle, fixed_t distance); void P_LineAttack(mobj_t * t1, angle_t angle, fixed_t distance, fixed_t slope, int damage); void P_RadiusAttack(mobj_t * spot, mobj_t * source, int damage); // ***** P_SETUP ***** extern byte *rejectmatrix; // for fast sight rejection extern short *blockmaplump; // offsets in blockmap are from here extern short *blockmap; extern int bmapwidth, bmapheight; // in mapblocks extern fixed_t bmaporgx, bmaporgy; // origin of block map extern mobj_t **blocklinks; // for thing chains // ***** P_INTER ***** extern int maxammo[NUMAMMO]; extern int clipammo[NUMAMMO]; void P_SetMessage(player_t * player, char *message, boolean ultmsg); void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher); void P_DamageMobj(mobj_t * target, mobj_t * inflictor, mobj_t * source, int damage); boolean P_GiveAmmo(player_t * player, ammotype_t ammo, int count); boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo); boolean P_GiveBody(player_t * player, int num); boolean P_GivePower(player_t * player, powertype_t power); boolean P_ChickenMorphPlayer(player_t * player); // ***** AM_MAP ***** boolean AM_Responder(event_t * ev); void AM_Ticker(void); void AM_Drawer(void); // ***** SB_BAR ***** extern int SB_state; extern int ArtifactFlash; void SB_PaletteFlash(void); #include "p_spec.h" #endif // __P_LOCAL__ chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_map.c000066400000000000000000001314301257432200600227610ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_map.c #include #include "doomdef.h" #include "i_system.h" #include "m_bbox.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" /* =============================================================================== NOTES: =============================================================================== */ /* =============================================================================== mobj_t NOTES mobj_ts are used to tell the refresh where to draw an image, tell the world simulation when objects are contacted, and tell the sound driver how to position a sound. The refresh uses the next and prev links to follow lists of things in sectors as they are being drawn. The sprite, frame, and angle elements determine which patch_t is used to draw the sprite if it is visible. The sprite and frame values are allmost allways set from state_t structures. The statescr.exe utility generates the states.h and states.c files that contain the sprite/frame numbers from the statescr.txt source file. The xyz origin point represents a point at the bottom middle of the sprite (between the feet of a biped). This is the default origin position for patch_ts grabbed with lumpy.exe. A walking creature will have its z equal to the floor it is standing on. The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t. The play simulation uses the blocklinks, x,y,z, radius, height to determine when mobj_ts are touching each other, touching lines in the map, or hit by trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has various bit flags used by the simulation. Every mobj_t is linked into a single sector based on it's origin coordinates. The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be found with subsector->sector. The sector links are only used by the rendering code, the play simulation does not care about them at all. Any mobj_t that needs to be acted upon be something else in the play world (block movement, be shot, etc) will also need to be linked into the blockmap. If the thing has the MF_NOBLOCK flag set, it will not use the block links. It can still interact with other things, but only as the instigator (missiles will run into other things, but nothing can run into a missile). Each block in the grid is 128*128 units, and knows about every line_t that it contains a piece of, and every interactable mobj_t that has it's origin contained. A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is linked into a blockmap block or has the MF_NOBLOCKMAP flag set. Links should only be modified by the P_[Un]SetThingPosition () functions. Do not change the MF_NO? flags while a thing is valid. =============================================================================== */ fixed_t tmbbox[4]; mobj_t *tmthing; int tmflags; fixed_t tmx, tmy; boolean floatok; // if true, move would be ok if // within tmfloorz - tmceilingz fixed_t tmfloorz, tmceilingz, tmdropoffz; // keep track of the line that lowers the ceiling, so missiles don't explode // against sky hack walls line_t *ceilingline; // keep track of special lines as they are hit, but don't process them // until the move is proven valid #define MAXSPECIALCROSS 8 line_t *spechit[MAXSPECIALCROSS]; int numspechit; mobj_t *onmobj; //generic global onmobj...used for landing on pods/players /* =============================================================================== TELEPORT MOVE =============================================================================== */ /* ================== = = PIT_StompThing = ================== */ boolean PIT_StompThing(mobj_t * thing) { fixed_t blockdist; if (!(thing->flags & MF_SHOOTABLE)) return true; blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) return true; // didn't hit it if (thing == tmthing) return true; // don't clip against self if (!(tmthing->flags2 & MF2_TELESTOMP)) { // Not allowed to stomp things return (false); } P_DamageMobj(thing, tmthing, tmthing, 10000); return true; } /* =================== = = P_TeleportMove = =================== */ boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y) { int xl, xh, yl, yh, bx, by; subsector_t *newsubsec; // // kill anything occupying the position // tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector(x, y); ceilingline = NULL; // // the base floor / ceiling is from the subsector that contains the // point. Any contacted lines the step closer together will adjust them // tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; validcount++; numspechit = 0; // // stomp on any things contacted // xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockThingsIterator(bx, by, PIT_StompThing)) return false; // // the move is ok, so link the thing into its new position // P_UnsetThingPosition(thing); thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; P_SetThingPosition(thing); return true; } /* =============================================================================== MOVEMENT ITERATOR FUNCTIONS =============================================================================== */ /* ================== = = PIT_CheckLine = = Adjusts tmfloorz and tmceilingz as lines are contacted ================== */ boolean PIT_CheckLine(line_t * ld) { if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { return (true); } if (P_BoxOnLineSide(tmbbox, ld) != -1) { return (true); } // a line has been hit /* = = The moving thing's destination position will cross the given line. = If this should not be allowed, return false. = If the line is special, keep track of it to process later if the move = is proven ok. NOTE: specials are NOT sorted by order, so two special lines = that are only 8 pixels apart could be crossed in either order. */ if (!ld->backsector) { // One sided line if (tmthing->flags & MF_MISSILE) { // Missiles can trigger impact specials if (ld->special) { spechit[numspechit] = ld; numspechit++; } } return false; } if (!(tmthing->flags & MF_MISSILE)) { if (ld->flags & ML_BLOCKING) { // Explicitly blocking everything return (false); } if (!tmthing->player && ld->flags & ML_BLOCKMONSTERS && tmthing->type != MT_POD) { // Block monsters only return (false); } } P_LineOpening(ld); // set openrange, opentop, openbottom // adjust floor / ceiling heights if (opentop < tmceilingz) { tmceilingz = opentop; ceilingline = ld; } if (openbottom > tmfloorz) { tmfloorz = openbottom; } if (lowfloor < tmdropoffz) { tmdropoffz = lowfloor; } if (ld->special) { // Contacted a special line, add it to the list spechit[numspechit] = ld; numspechit++; } return (true); } //--------------------------------------------------------------------------- // // FUNC PIT_CheckThing // //--------------------------------------------------------------------------- boolean PIT_CheckThing(mobj_t * thing) { fixed_t blockdist; boolean solid; int damage; if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE))) { // Can't hit thing return (true); } blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) { // Didn't hit thing return (true); } if (thing == tmthing) { // Don't clip against self return (true); } if (tmthing->flags2 & MF2_PASSMOBJ) { // check if a mobj passed over/under another object if ((tmthing->type == MT_IMP || tmthing->type == MT_WIZARD) && (thing->type == MT_IMP || thing->type == MT_WIZARD)) { // don't let imps/wizards fly over other imps/wizards return false; } if (tmthing->z > thing->z + thing->height && !(thing->flags & MF_SPECIAL)) { return (true); } else if (tmthing->z + tmthing->height < thing->z && !(thing->flags & MF_SPECIAL)) { // under thing return (true); } } // Check for skulls slamming into things if (tmthing->flags & MF_SKULLFLY) { damage = ((P_Random() % 8) + 1) * tmthing->damage; P_DamageMobj(thing, tmthing, tmthing, damage); tmthing->flags &= ~MF_SKULLFLY; tmthing->momx = tmthing->momy = tmthing->momz = 0; P_SetMobjState(tmthing, tmthing->info->seestate); return (false); } // Check for missile if (tmthing->flags & MF_MISSILE) { // Check for passing through a ghost if ((thing->flags & MF_SHADOW) && (tmthing->flags2 & MF2_THRUGHOST)) { return (true); } // Check if it went over / under if (tmthing->z > thing->z + thing->height) { // Over thing return (true); } if (tmthing->z + tmthing->height < thing->z) { // Under thing return (true); } if (tmthing->target && tmthing->target->type == thing->type) { // Don't hit same species as originator if (thing == tmthing->target) { // Don't missile self return (true); } if (thing->type != MT_PLAYER) { // Hit same species as originator, explode, no damage return (false); } } if (!(thing->flags & MF_SHOOTABLE)) { // Didn't do any damage return !(thing->flags & MF_SOLID); } if (tmthing->flags2 & MF2_RIP) { if (!(thing->flags & MF_NOBLOOD)) { // Ok to spawn some blood P_RipperBlood(tmthing); } S_StartSound(tmthing, sfx_ripslop); damage = ((P_Random() & 3) + 2) * tmthing->damage; P_DamageMobj(thing, tmthing, tmthing->target, damage); if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH)) { // Push thing thing->momx += tmthing->momx >> 2; thing->momy += tmthing->momy >> 2; } numspechit = 0; return (true); } // Do damage damage = ((P_Random() % 8) + 1) * tmthing->damage; if (damage) { if (!(thing->flags & MF_NOBLOOD) && P_Random() < 192) { P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing); } P_DamageMobj(thing, tmthing, tmthing->target, damage); } return (false); } if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH)) { // Push thing thing->momx += tmthing->momx >> 2; thing->momy += tmthing->momy >> 2; } // Check for special thing if (thing->flags & MF_SPECIAL) { solid = (thing->flags & MF_SOLID) != 0; if (tmflags & MF_PICKUP) { // Can be picked up by tmthing P_TouchSpecialThing(thing, tmthing); // Can remove thing } return (!solid); } return (!(thing->flags & MF_SOLID)); } //--------------------------------------------------------------------------- // // PIT_CheckOnmobjZ // //--------------------------------------------------------------------------- boolean PIT_CheckOnmobjZ(mobj_t * thing) { fixed_t blockdist; if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE))) { // Can't hit thing return (true); } blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) { // Didn't hit thing return (true); } if (thing == tmthing) { // Don't clip against self return (true); } if (tmthing->z > thing->z + thing->height) { return (true); } else if (tmthing->z + tmthing->height < thing->z) { // under thing return (true); } if (thing->flags & MF_SOLID) { onmobj = thing; } return (!(thing->flags & MF_SOLID)); } /* =============================================================================== MOVEMENT CLIPPING =============================================================================== */ //---------------------------------------------------------------------------- // // FUNC P_TestMobjLocation // // Returns true if the mobj is not blocked by anything at its current // location, otherwise returns false. // //---------------------------------------------------------------------------- boolean P_TestMobjLocation(mobj_t * mobj) { int flags; flags = mobj->flags; mobj->flags &= ~MF_PICKUP; if (P_CheckPosition(mobj, mobj->x, mobj->y)) { // XY is ok, now check Z mobj->flags = flags; if ((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz)) { // Bad Z return (false); } return (true); } mobj->flags = flags; return (false); } /* ================== = = P_CheckPosition = = This is purely informative, nothing is modified (except things picked up) in: a mobj_t (can be valid or invalid) a position to be checked (doesn't need to be related to the mobj_t->x,y) during: special things are touched if MF_PICKUP early out on solid lines? out: newsubsec floorz ceilingz tmdropoffz the lowest point contacted (monsters won't move to a dropoff) speciallines[] numspeciallines ================== */ boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y) { int xl, xh, yl, yh, bx, by; subsector_t *newsubsec; tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector(x, y); ceilingline = NULL; // // the base floor / ceiling is from the subsector that contains the // point. Any contacted lines the step closer together will adjust them // tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; validcount++; numspechit = 0; if (tmflags & MF_NOCLIP) return true; // // check things first, possibly picking things up // the bounding box is extended by MAXRADIUS because mobj_ts are grouped // into mapblocks based on their origin point, and can overlap into adjacent // blocks by up to MAXRADIUS units // xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockThingsIterator(bx, by, PIT_CheckThing)) return false; // // check lines // xl = (tmbbox[BOXLEFT] - bmaporgx) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy) >> MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockLinesIterator(bx, by, PIT_CheckLine)) return false; return true; } //============================================================================= // // P_CheckOnmobj(mobj_t *thing) // // Checks if the new Z position is legal //============================================================================= mobj_t *P_CheckOnmobj(mobj_t * thing) { int xl, xh, yl, yh, bx, by; subsector_t *newsubsec; fixed_t x; fixed_t y; mobj_t oldmo; x = thing->x; y = thing->y; tmthing = thing; tmflags = thing->flags; oldmo = *thing; // save the old mobj before the fake zmovement P_FakeZMovement(tmthing); tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector(x, y); ceilingline = NULL; // // the base floor / ceiling is from the subsector that contains the // point. Any contacted lines the step closer together will adjust them // tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; validcount++; numspechit = 0; if (tmflags & MF_NOCLIP) return NULL; // // check things first, possibly picking things up // the bounding box is extended by MAXRADIUS because mobj_ts are grouped // into mapblocks based on their origin point, and can overlap into adjacent // blocks by up to MAXRADIUS units // xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockThingsIterator(bx, by, PIT_CheckOnmobjZ)) { *tmthing = oldmo; return onmobj; } *tmthing = oldmo; return NULL; } //============================================================================= // // P_FakeZMovement // // Fake the zmovement so that we can check if a move is legal //============================================================================= void P_FakeZMovement(mobj_t * mo) { int dist; int delta; // // adjust height // mo->z += mo->momz; if (mo->flags & MF_FLOAT && mo->target) { // float down towards target if too close if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT)) { dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y); delta = (mo->target->z + (mo->height >> 1)) - mo->z; if (delta < 0 && dist < -(delta * 3)) mo->z -= FLOATSPEED; else if (delta > 0 && dist < (delta * 3)) mo->z += FLOATSPEED; } } if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz) && leveltime & 2) { mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK]; } // // clip movement // if (mo->z <= mo->floorz) { // Hit the floor mo->z = mo->floorz; if (mo->momz < 0) { mo->momz = 0; } if (mo->flags & MF_SKULLFLY) { // The skull slammed into something mo->momz = -mo->momz; } if (mo->info->crashstate && (mo->flags & MF_CORPSE)) { return; } } else if (mo->flags2 & MF2_LOGRAV) { if (mo->momz == 0) mo->momz = -(GRAVITY >> 3) * 2; else mo->momz -= GRAVITY >> 3; } else if (!(mo->flags & MF_NOGRAVITY)) { if (mo->momz == 0) mo->momz = -GRAVITY * 2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // hit the ceiling if (mo->momz > 0) mo->momz = 0; mo->z = mo->ceilingz - mo->height; if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; } } } //========================================================================== // // CheckMissileImpact // //========================================================================== void CheckMissileImpact(mobj_t * mobj) { int i; if (!numspechit || !(mobj->flags & MF_MISSILE) || !mobj->target) { return; } if (!mobj->target->player) { return; } for (i = numspechit - 1; i >= 0; i--) { P_ShootSpecialLine(mobj->target, spechit[i]); } } /* =================== = = P_TryMove = = Attempt to move to a new position, crossing special lines unless MF_TELEPORT = is set = =================== */ boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y) { fixed_t oldx, oldy; int side, oldside; line_t *ld; floatok = false; if (!P_CheckPosition(thing, x, y)) { // Solid wall or thing CheckMissileImpact(thing); return false; } if (!(thing->flags & MF_NOCLIP)) { if (tmceilingz - tmfloorz < thing->height) { // Doesn't fit CheckMissileImpact(thing); return false; } floatok = true; if (!(thing->flags & MF_TELEPORT) && tmceilingz - thing->z < thing->height && !(thing->flags2 & MF2_FLY)) { // mobj must lower itself to fit CheckMissileImpact(thing); return false; } if (thing->flags2 & MF2_FLY) { if (thing->z + thing->height > tmceilingz) { thing->momz = -8 * FRACUNIT; return false; } else if (thing->z < tmfloorz && tmfloorz - tmdropoffz > 24 * FRACUNIT) { thing->momz = 8 * FRACUNIT; return false; } } if (!(thing->flags & MF_TELEPORT) // The Minotaur floor fire (MT_MNTRFX2) can step up any amount && thing->type != MT_MNTRFX2 && tmfloorz - thing->z > 24 * FRACUNIT) { // Too big a step up CheckMissileImpact(thing); return false; } if ((thing->flags & MF_MISSILE) && tmfloorz > thing->z) { CheckMissileImpact(thing); } if (!(thing->flags & (MF_DROPOFF | MF_FLOAT)) && tmfloorz - tmdropoffz > 24 * FRACUNIT) { // Can't move over a dropoff return false; } } // // the move is ok, so link the thing into its new position // P_UnsetThingPosition(thing); oldx = thing->x; oldy = thing->y; thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; P_SetThingPosition(thing); if (thing->flags2 & MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID) { thing->flags2 |= MF2_FEETARECLIPPED; } else if (thing->flags2 & MF2_FEETARECLIPPED) { thing->flags2 &= ~MF2_FEETARECLIPPED; } // // if any special lines were hit, do the effect // if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP))) while (numspechit--) { // see if the line was crossed ld = spechit[numspechit]; side = P_PointOnLineSide(thing->x, thing->y, ld); oldside = P_PointOnLineSide(oldx, oldy, ld); if (side != oldside) { if (ld->special) P_CrossSpecialLine(ld - lines, oldside, thing); } } return true; } /* ================== = = P_ThingHeightClip = = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz, = anf possibly thing->z = = This is called for all nearby monsters whenever a sector changes height = = If the thing doesn't fit, the z will be set to the lowest value and = false will be returned ================== */ boolean P_ThingHeightClip(mobj_t * thing) { boolean onfloor; onfloor = (thing->z == thing->floorz); P_CheckPosition(thing, thing->x, thing->y); // what about stranding a monster partially off an edge? thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; if (onfloor) // walking monsters rise and fall with the floor thing->z = thing->floorz; else { // don't adjust a floating monster unless forced to if (thing->z + thing->height > thing->ceilingz) thing->z = thing->ceilingz - thing->height; } if (thing->ceilingz - thing->floorz < thing->height) return false; return true; } /* ============================================================================== SLIDE MOVE Allows the player to slide along any angled walls ============================================================================== */ fixed_t bestslidefrac, secondslidefrac; line_t *bestslideline, *secondslideline; mobj_t *slidemo; fixed_t tmxmove, tmymove; /* ================== = = P_HitSlideLine = = Adjusts the xmove / ymove so that the next move will slide along the wall ================== */ void P_HitSlideLine(line_t * ld) { int side; angle_t lineangle, moveangle, deltaangle; fixed_t movelen, newlen; if (ld->slopetype == ST_HORIZONTAL) { tmymove = 0; return; } if (ld->slopetype == ST_VERTICAL) { tmxmove = 0; return; } side = P_PointOnLineSide(slidemo->x, slidemo->y, ld); lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy); if (side == 1) lineangle += ANG180; moveangle = R_PointToAngle2(0, 0, tmxmove, tmymove); deltaangle = moveangle - lineangle; if (deltaangle > ANG180) deltaangle += ANG180; // I_Error ("SlideLine: ang>ANG180"); lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; movelen = P_AproxDistance(tmxmove, tmymove); newlen = FixedMul(movelen, finecosine[deltaangle]); tmxmove = FixedMul(newlen, finecosine[lineangle]); tmymove = FixedMul(newlen, finesine[lineangle]); } /* ============== = = PTR_SlideTraverse = ============== */ boolean PTR_SlideTraverse(intercept_t * in) { line_t *li; if (!in->isaline) I_Error("PTR_SlideTraverse: not a line?"); li = in->d.line; if (!(li->flags & ML_TWOSIDED)) { if (P_PointOnLineSide(slidemo->x, slidemo->y, li)) return true; // don't hit the back side goto isblocking; } P_LineOpening(li); // set openrange, opentop, openbottom if (openrange < slidemo->height) goto isblocking; // doesn't fit if (opentop - slidemo->z < slidemo->height) goto isblocking; // mobj is too high if (openbottom - slidemo->z > 24 * FRACUNIT) goto isblocking; // too big a step up return true; // this line doesn't block movement // the line does block movement, see if it is closer than best so far isblocking: if (in->frac < bestslidefrac) { secondslidefrac = bestslidefrac; secondslideline = bestslideline; bestslidefrac = in->frac; bestslideline = li; } return false; // stop } /* ================== = = P_SlideMove = = The momx / momy move is bad, so try to slide along a wall = = Find the first line hit, move flush to it, and slide along it = = This is a kludgy mess. ================== */ void P_SlideMove(mobj_t * mo) { fixed_t leadx, leady; fixed_t trailx, traily; fixed_t newx, newy; int hitcount; slidemo = mo; hitcount = 0; retry: if (++hitcount == 3) goto stairstep; // don't loop forever // // trace along the three leading corners // if (mo->momx > 0) { leadx = mo->x + mo->radius; trailx = mo->x - mo->radius; } else { leadx = mo->x - mo->radius; trailx = mo->x + mo->radius; } if (mo->momy > 0) { leady = mo->y + mo->radius; traily = mo->y - mo->radius; } else { leady = mo->y - mo->radius; traily = mo->y + mo->radius; } bestslidefrac = FRACUNIT + 1; P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy, PT_ADDLINES, PTR_SlideTraverse); P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy, PT_ADDLINES, PTR_SlideTraverse); P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy, PT_ADDLINES, PTR_SlideTraverse); // // move up to the wall // if (bestslidefrac == FRACUNIT + 1) { // the move most have hit the middle, so stairstep stairstep: if (!P_TryMove(mo, mo->x, mo->y + mo->momy)) P_TryMove(mo, mo->x + mo->momx, mo->y); return; } bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit if (bestslidefrac > 0) { newx = FixedMul(mo->momx, bestslidefrac); newy = FixedMul(mo->momy, bestslidefrac); if (!P_TryMove(mo, mo->x + newx, mo->y + newy)) goto stairstep; } // // now continue along the wall // bestslidefrac = FRACUNIT - (bestslidefrac + 0x800); // remainder if (bestslidefrac > FRACUNIT) bestslidefrac = FRACUNIT; if (bestslidefrac <= 0) return; tmxmove = FixedMul(mo->momx, bestslidefrac); tmymove = FixedMul(mo->momy, bestslidefrac); P_HitSlideLine(bestslideline); // clip the moves mo->momx = tmxmove; mo->momy = tmymove; if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove)) { goto retry; } } /* ============================================================================== P_LineAttack ============================================================================== */ mobj_t *linetarget; // who got hit (or NULL) mobj_t *shootthing; fixed_t shootz; // height if not aiming up or down // ???: use slope for monsters? int la_damage; fixed_t attackrange; fixed_t aimslope; extern fixed_t topslope, bottomslope; // slopes to top and bottom of target /* =============================================================================== = = PTR_AimTraverse = = Sets linetaget and aimslope when a target is aimed at =============================================================================== */ boolean PTR_AimTraverse(intercept_t * in) { line_t *li; mobj_t *th; fixed_t slope, thingtopslope, thingbottomslope; fixed_t dist; if (in->isaline) { li = in->d.line; if (!(li->flags & ML_TWOSIDED)) return false; // stop // // crosses a two sided line // a two sided line will restrict the possible target ranges P_LineOpening(li); if (openbottom >= opentop) return false; // stop dist = FixedMul(attackrange, in->frac); if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv(openbottom - shootz, dist); if (slope > bottomslope) bottomslope = slope; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv(opentop - shootz, dist); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop return true; // shot continues } // // shoot a thing // th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags & MF_SHOOTABLE)) return true; // corpse or something if (th->type == MT_POD) { // Can't auto-aim at pods return (true); } // check angles to see if the thing can be aimed at dist = FixedMul(attackrange, in->frac); thingtopslope = FixedDiv(th->z + th->height - shootz, dist); if (thingtopslope < bottomslope) return true; // shot over the thing thingbottomslope = FixedDiv(th->z - shootz, dist); if (thingbottomslope > topslope) return true; // shot under the thing // // this thing can be hit! // if (thingtopslope > topslope) thingtopslope = topslope; if (thingbottomslope < bottomslope) thingbottomslope = bottomslope; aimslope = (thingtopslope + thingbottomslope) / 2; linetarget = th; return false; // don't go any farther } /* ============================================================================== = = PTR_ShootTraverse = ============================================================================== */ boolean PTR_ShootTraverse(intercept_t * in) { fixed_t x, y, z; fixed_t frac; line_t *li; mobj_t *th; fixed_t slope; fixed_t dist; fixed_t thingtopslope, thingbottomslope; mobj_t *mo; if (in->isaline) { li = in->d.line; if (li->special) P_ShootSpecialLine(shootthing, li); if (!(li->flags & ML_TWOSIDED)) goto hitline; // // crosses a two sided line // P_LineOpening(li); dist = FixedMul(attackrange, in->frac); if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv(openbottom - shootz, dist); if (slope > aimslope) goto hitline; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv(opentop - shootz, dist); if (slope < aimslope) goto hitline; } return true; // shot continues // // hit line // hitline: // position a bit closer frac = in->frac - FixedDiv(4 * FRACUNIT, attackrange); x = trace.x + FixedMul(trace.dx, frac); y = trace.y + FixedMul(trace.dy, frac); z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange)); if (li->frontsector->ceilingpic == skyflatnum) { if (z > li->frontsector->ceilingheight) return false; // don't shoot the sky! if (li->backsector && li->backsector->ceilingpic == skyflatnum) return false; // it's a sky hack wall } P_SpawnPuff(x, y, z); return false; // don't go any farther } // // shoot a thing // th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags & MF_SHOOTABLE)) return true; // corpse or something // // check for physical attacks on a ghost // if (th->flags & MF_SHADOW && shootthing->player->readyweapon == wp_staff) { return (true); } // check angles to see if the thing can be aimed at dist = FixedMul(attackrange, in->frac); thingtopslope = FixedDiv(th->z + th->height - shootz, dist); if (thingtopslope < aimslope) return true; // shot over the thing thingbottomslope = FixedDiv(th->z - shootz, dist); if (thingbottomslope > aimslope) return true; // shot under the thing // // hit thing // // position a bit closer frac = in->frac - FixedDiv(10 * FRACUNIT, attackrange); x = trace.x + FixedMul(trace.dx, frac); y = trace.y + FixedMul(trace.dy, frac); z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange)); if (PuffType == MT_BLASTERPUFF1) { // Make blaster big puff mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2); S_StartSound(mo, sfx_blshit); } else { P_SpawnPuff(x, y, z); } if (la_damage) { if (!(in->d.thing->flags & MF_NOBLOOD) && P_Random() < 192) { P_BloodSplatter(x, y, z, in->d.thing); } P_DamageMobj(th, shootthing, shootthing, la_damage); } return (false); // don't go any farther } /* ================= = = P_AimLineAttack = ================= */ fixed_t P_AimLineAttack(mobj_t * t1, angle_t angle, fixed_t distance) { fixed_t x2, y2; angle >>= ANGLETOFINESHIFT; shootthing = t1; x2 = t1->x + (distance >> FRACBITS) * finecosine[angle]; y2 = t1->y + (distance >> FRACBITS) * finesine[angle]; shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT; topslope = 100 * FRACUNIT / 160; // can't shoot outside view angles bottomslope = -100 * FRACUNIT / 160; attackrange = distance; linetarget = NULL; P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS, PTR_AimTraverse); if (linetarget) return aimslope; return 0; } /* ================= = = P_LineAttack = = if damage == 0, it is just a test trace that will leave linetarget set = ================= */ void P_LineAttack(mobj_t * t1, angle_t angle, fixed_t distance, fixed_t slope, int damage) { fixed_t x2, y2; angle >>= ANGLETOFINESHIFT; shootthing = t1; la_damage = damage; x2 = t1->x + (distance >> FRACBITS) * finecosine[angle]; y2 = t1->y + (distance >> FRACBITS) * finesine[angle]; shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT; if (t1->flags2 & MF2_FEETARECLIPPED) { shootz -= FOOTCLIPSIZE; } attackrange = distance; aimslope = slope; P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS, PTR_ShootTraverse); } /* ============================================================================== USE LINES ============================================================================== */ mobj_t *usething; boolean PTR_UseTraverse(intercept_t * in) { if (!in->d.line->special) { P_LineOpening(in->d.line); if (openrange <= 0) { //S_StartSound (usething, sfx_noway); return false; // can't use through a wall } return true; // not a special line, but keep checking } if (P_PointOnLineSide(usething->x, usething->y, in->d.line) == 1) return false; // don't use back sides P_UseSpecialLine(usething, in->d.line); return false; // can't use for than one special line in a row } /* ================ = = P_UseLines = = Looks for special lines in front of the player to activate ================ */ void P_UseLines(player_t * player) { int angle; fixed_t x1, y1, x2, y2; usething = player->mo; angle = player->mo->angle >> ANGLETOFINESHIFT; x1 = player->mo->x; y1 = player->mo->y; x2 = x1 + (USERANGE >> FRACBITS) * finecosine[angle]; y2 = y1 + (USERANGE >> FRACBITS) * finesine[angle]; P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse); } /* ============================================================================== RADIUS ATTACK ============================================================================== */ mobj_t *bombsource; mobj_t *bombspot; int bombdamage; /* ================= = = PIT_RadiusAttack = = Source is the creature that casued the explosion at spot ================= */ boolean PIT_RadiusAttack(mobj_t * thing) { fixed_t dx, dy, dist; if (!(thing->flags & MF_SHOOTABLE)) { return true; } if (thing->type == MT_MINOTAUR || thing->type == MT_SORCERER1 || thing->type == MT_SORCERER2) { // Episode 2 and 3 bosses take no damage from PIT_RadiusAttack return (true); } dx = abs(thing->x - bombspot->x); dy = abs(thing->y - bombspot->y); dist = dx > dy ? dx : dy; dist = (dist - thing->radius) >> FRACBITS; if (dist < 0) { dist = 0; } if (dist >= bombdamage) { // Out of range return true; } if (P_CheckSight(thing, bombspot)) { // OK to damage, target is in direct path P_DamageMobj(thing, bombspot, bombsource, bombdamage - dist); } return (true); } /* ================= = = P_RadiusAttack = = Source is the creature that casued the explosion at spot ================= */ void P_RadiusAttack(mobj_t * spot, mobj_t * source, int damage) { int x, y, xl, xh, yl, yh; fixed_t dist; dist = (damage + MAXRADIUS) << FRACBITS; yh = (spot->y + dist - bmaporgy) >> MAPBLOCKSHIFT; yl = (spot->y - dist - bmaporgy) >> MAPBLOCKSHIFT; xh = (spot->x + dist - bmaporgx) >> MAPBLOCKSHIFT; xl = (spot->x - dist - bmaporgx) >> MAPBLOCKSHIFT; bombspot = spot; if (spot->type == MT_POD && spot->target) { bombsource = spot->target; } else { bombsource = source; } bombdamage = damage; for (y = yl; y <= yh; y++) for (x = xl; x <= xh; x++) P_BlockThingsIterator(x, y, PIT_RadiusAttack); } /* ============================================================================== SECTOR HEIGHT CHANGING = After modifying a sectors floor or ceiling height, call this = routine to adjust the positions of all things that touch the = sector. = = If anything doesn't fit anymore, true will be returned. = If crunch is true, they will take damage as they are being crushed = If Crunch is false, you should set the sector height back the way it = was and call P_ChangeSector again to undo the changes ============================================================================== */ boolean crushchange; boolean nofit; /* =============== = = PIT_ChangeSector = =============== */ boolean PIT_ChangeSector(mobj_t * thing) { mobj_t *mo; if (P_ThingHeightClip(thing)) return true; // keep checking // crunch bodies to giblets if (thing->health <= 0) { //P_SetMobjState (thing, S_GIBS); thing->height = 0; thing->radius = 0; return true; // keep checking } // crunch dropped items if (thing->flags & MF_DROPPED) { P_RemoveMobj(thing); return true; // keep checking } if (!(thing->flags & MF_SHOOTABLE)) return true; // assume it is bloody gibs or something nofit = true; if (crushchange && !(leveltime & 3)) { P_DamageMobj(thing, NULL, NULL, 10); // spray blood in a random direction mo = P_SpawnMobj(thing->x, thing->y, thing->z + thing->height / 2, MT_BLOOD); mo->momx = (P_Random() - P_Random()) << 12; mo->momy = (P_Random() - P_Random()) << 12; } return true; // keep checking (crush other things) } /* =============== = = P_ChangeSector = =============== */ boolean P_ChangeSector(sector_t * sector, boolean crunch) { int x, y; nofit = false; crushchange = crunch; // recheck heights for all things near the moving sector for (x = sector->blockbox[BOXLEFT]; x <= sector->blockbox[BOXRIGHT]; x++) for (y = sector->blockbox[BOXBOTTOM]; y <= sector->blockbox[BOXTOP]; y++) P_BlockThingsIterator(x, y, PIT_ChangeSector); return nofit; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_maputl.c000066400000000000000000000427731257432200600235210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_maputl.c #include #include "doomdef.h" #include "m_bbox.h" #include "p_local.h" /* =================== = = P_AproxDistance = = Gives an estimation of distance (not exact) = =================== */ fixed_t P_AproxDistance(fixed_t dx, fixed_t dy) { dx = abs(dx); dy = abs(dy); if (dx < dy) return dx + dy - (dx >> 1); return dx + dy - (dy >> 1); } /* ================== = = P_PointOnLineSide = = Returns 0 or 1 ================== */ int P_PointOnLineSide(fixed_t x, fixed_t y, line_t * line) { fixed_t dx, dy; fixed_t left, right; if (!line->dx) { if (x <= line->v1->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->v1->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->v1->x); dy = (y - line->v1->y); left = FixedMul(line->dy >> FRACBITS, dx); right = FixedMul(dy, line->dx >> FRACBITS); if (right < left) return 0; // front side return 1; // back side } /* ================= = = P_BoxOnLineSide = = Considers the line to be infinite = Returns side 0 or 1, -1 if box crosses the line ================= */ int P_BoxOnLineSide(fixed_t * tmbox, line_t * ld) { int p1 = 0, p2 = 0; switch (ld->slopetype) { case ST_HORIZONTAL: p1 = tmbox[BOXTOP] > ld->v1->y; p2 = tmbox[BOXBOTTOM] > ld->v1->y; if (ld->dx < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_VERTICAL: p1 = tmbox[BOXRIGHT] < ld->v1->x; p2 = tmbox[BOXLEFT] < ld->v1->x; if (ld->dy < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_POSITIVE: p1 = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld); break; case ST_NEGATIVE: p1 = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld); break; } if (p1 == p2) return p1; return -1; } /* ================== = = P_PointOnDivlineSide = = Returns 0 or 1 ================== */ int P_PointOnDivlineSide(fixed_t x, fixed_t y, divline_t * line) { fixed_t dx, dy; fixed_t left, right; if (!line->dx) { if (x <= line->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->x); dy = (y - line->y); // try to quickly decide by looking at sign bits if ((line->dy ^ line->dx ^ dx ^ dy) & 0x80000000) { if ((line->dy ^ dx) & 0x80000000) return 1; // (left is negative) return 0; } left = FixedMul(line->dy >> 8, dx >> 8); right = FixedMul(dy >> 8, line->dx >> 8); if (right < left) return 0; // front side return 1; // back side } /* ============== = = P_MakeDivline = ============== */ void P_MakeDivline(line_t * li, divline_t * dl) { dl->x = li->v1->x; dl->y = li->v1->y; dl->dx = li->dx; dl->dy = li->dy; } /* =============== = = P_InterceptVector = = Returns the fractional intercept point along the first divline = = This is only called by the addthings and addlines traversers =============== */ fixed_t P_InterceptVector(divline_t * v2, divline_t * v1) { #if 1 fixed_t frac, num, den; den = FixedMul(v1->dy >> 8, v2->dx) - FixedMul(v1->dx >> 8, v2->dy); if (den == 0) return 0; // I_Error ("P_InterceptVector: parallel"); num = FixedMul((v1->x - v2->x) >> 8, v1->dy) + FixedMul((v2->y - v1->y) >> 8, v1->dx); frac = FixedDiv(num, den); return frac; #else float frac, num, den, v1x, v1y, v1dx, v1dy, v2x, v2y, v2dx, v2dy; v1x = (float) v1->x / FRACUNIT; v1y = (float) v1->y / FRACUNIT; v1dx = (float) v1->dx / FRACUNIT; v1dy = (float) v1->dy / FRACUNIT; v2x = (float) v2->x / FRACUNIT; v2y = (float) v2->y / FRACUNIT; v2dx = (float) v2->dx / FRACUNIT; v2dy = (float) v2->dy / FRACUNIT; den = v1dy * v2dx - v1dx * v2dy; if (den == 0) return 0; // parallel num = (v1x - v2x) * v1dy + (v2y - v1y) * v1dx; frac = num / den; return frac * FRACUNIT; #endif } /* ================== = = P_LineOpening = = Sets opentop and openbottom to the window through a two sided line = OPTIMIZE: keep this precalculated ================== */ fixed_t opentop, openbottom, openrange; fixed_t lowfloor; void P_LineOpening(line_t * linedef) { sector_t *front, *back; if (linedef->sidenum[1] == -1) { // single sided line openrange = 0; return; } front = linedef->frontsector; back = linedef->backsector; if (front->ceilingheight < back->ceilingheight) opentop = front->ceilingheight; else opentop = back->ceilingheight; if (front->floorheight > back->floorheight) { openbottom = front->floorheight; lowfloor = back->floorheight; } else { openbottom = back->floorheight; lowfloor = front->floorheight; } openrange = opentop - openbottom; } /* =============================================================================== THING POSITION SETTING =============================================================================== */ /* =================== = = P_UnsetThingPosition = = Unlinks a thing from block map and sectors = =================== */ void P_UnsetThingPosition(mobj_t * thing) { int blockx, blocky; if (!(thing->flags & MF_NOSECTOR)) { // inert things don't need to be in blockmap // unlink from subsector if (thing->snext) thing->snext->sprev = thing->sprev; if (thing->sprev) thing->sprev->snext = thing->snext; else thing->subsector->sector->thinglist = thing->snext; } if (!(thing->flags & MF_NOBLOCKMAP)) { // inert things don't need to be in blockmap // unlink from block map if (thing->bnext) thing->bnext->bprev = thing->bprev; if (thing->bprev) thing->bprev->bnext = thing->bnext; else { blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT; if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight) blocklinks[blocky * bmapwidth + blockx] = thing->bnext; } } } /* =================== = = P_SetThingPosition = = Links a thing into both a block and a subsector based on it's x y = Sets thing->subsector properly = =================== */ void P_SetThingPosition(mobj_t * thing) { subsector_t *ss; sector_t *sec; int blockx, blocky; mobj_t **link; // // link into subsector // ss = R_PointInSubsector(thing->x, thing->y); thing->subsector = ss; if (!(thing->flags & MF_NOSECTOR)) { // invisible things don't go into the sector links sec = ss->sector; thing->sprev = NULL; thing->snext = sec->thinglist; if (sec->thinglist) sec->thinglist->sprev = thing; sec->thinglist = thing; } // // link into blockmap // if (!(thing->flags & MF_NOBLOCKMAP)) { // inert things don't need to be in blockmap blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT; if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight) { link = &blocklinks[blocky * bmapwidth + blockx]; thing->bprev = NULL; thing->bnext = *link; if (*link) (*link)->bprev = thing; *link = thing; } else { // thing is off the map thing->bnext = thing->bprev = NULL; } } } /* =============================================================================== BLOCK MAP ITERATORS For each line/thing in the given mapblock, call the passed function. If the function returns false, exit with false without checking anything else. =============================================================================== */ /* ================== = = P_BlockLinesIterator = = The validcount flags are used to avoid checking lines = that are marked in multiple mapblocks, so increment validcount before = the first call to P_BlockLinesIterator, then make one or more calls to it =================== */ boolean P_BlockLinesIterator(int x, int y, boolean(*func) (line_t *)) { int offset; short *list; line_t *ld; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) return true; offset = y * bmapwidth + x; offset = *(blockmap + offset); for (list = blockmaplump + offset; *list != -1; list++) { ld = &lines[*list]; if (ld->validcount == validcount) continue; // line has already been checked ld->validcount = validcount; if (!func(ld)) return false; } return true; // everything was checked } /* ================== = = P_BlockThingsIterator = ================== */ boolean P_BlockThingsIterator(int x, int y, boolean(*func) (mobj_t *)) { mobj_t *mobj; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) return true; for (mobj = blocklinks[y * bmapwidth + x]; mobj; mobj = mobj->bnext) if (!func(mobj)) return false; return true; } /* =============================================================================== INTERCEPT ROUTINES =============================================================================== */ intercept_t intercepts[MAXINTERCEPTS], *intercept_p; divline_t trace; boolean earlyout; int ptflags; /* ================== = = PIT_AddLineIntercepts = = Looks for lines in the given block that intercept the given trace = to add to the intercepts list = A line is crossed if its endpoints are on opposite sides of the trace = Returns true if earlyout and a solid line hit ================== */ boolean PIT_AddLineIntercepts(line_t * ld) { int s1, s2; fixed_t frac; divline_t dl; // avoid precision problems with two routines if (trace.dx > FRACUNIT * 16 || trace.dy > FRACUNIT * 16 || trace.dx < -FRACUNIT * 16 || trace.dy < -FRACUNIT * 16) { s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace); } else { s1 = P_PointOnLineSide(trace.x, trace.y, ld); s2 = P_PointOnLineSide(trace.x + trace.dx, trace.y + trace.dy, ld); } if (s1 == s2) return true; // line isn't crossed // // hit the line // P_MakeDivline(ld, &dl); frac = P_InterceptVector(&trace, &dl); if (frac < 0) return true; // behind source // try to early out the check if (earlyout && frac < FRACUNIT && !ld->backsector) return false; // stop checking intercept_p->frac = frac; intercept_p->isaline = true; intercept_p->d.line = ld; intercept_p++; return true; // continue } /* ================== = = PIT_AddThingIntercepts = ================== */ boolean PIT_AddThingIntercepts(mobj_t * thing) { fixed_t x1, y1, x2, y2; int s1, s2; boolean tracepositive; divline_t dl; fixed_t frac; tracepositive = (trace.dx ^ trace.dy) > 0; // check a corner to corner crossection for hit if (tracepositive) { x1 = thing->x - thing->radius; y1 = thing->y + thing->radius; x2 = thing->x + thing->radius; y2 = thing->y - thing->radius; } else { x1 = thing->x - thing->radius; y1 = thing->y - thing->radius; x2 = thing->x + thing->radius; y2 = thing->y + thing->radius; } s1 = P_PointOnDivlineSide(x1, y1, &trace); s2 = P_PointOnDivlineSide(x2, y2, &trace); if (s1 == s2) return true; // line isn't crossed dl.x = x1; dl.y = y1; dl.dx = x2 - x1; dl.dy = y2 - y1; frac = P_InterceptVector(&trace, &dl); if (frac < 0) return true; // behind source intercept_p->frac = frac; intercept_p->isaline = false; intercept_p->d.thing = thing; intercept_p++; return true; // keep going } /* ==================== = = P_TraverseIntercepts = = Returns true if the traverser function returns true for all lines ==================== */ boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac) { int count; fixed_t dist; intercept_t *scan, *in; count = intercept_p - intercepts; in = 0; // shut up compiler warning while (count--) { dist = INT_MAX; for (scan = intercepts; scan < intercept_p; scan++) if (scan->frac < dist) { dist = scan->frac; in = scan; } if (dist > maxfrac) return true; // checked everything in range #if 0 { // don't check these yet, ther may be others inserted in = scan = intercepts; for (scan = intercepts; scan < intercept_p; scan++) if (scan->frac > maxfrac) *in++ = *scan; intercept_p = in; return false; } #endif if (!func(in)) return false; // don't bother going farther in->frac = INT_MAX; } return true; // everything was traversed } /* ================== = = P_PathTraverse = = Traces a line from x1,y1 to x2,y2, calling the traverser function for each = Returns true if the traverser function returns true for all lines ================== */ boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean(*trav) (intercept_t *)) { fixed_t xt1, yt1, xt2, yt2; fixed_t xstep, ystep; fixed_t partial; fixed_t xintercept, yintercept; int mapx, mapy, mapxstep, mapystep; int count; earlyout = (flags & PT_EARLYOUT) != 0; validcount++; intercept_p = intercepts; if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0) x1 += FRACUNIT; // don't side exactly on a line if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0) y1 += FRACUNIT; // don't side exactly on a line trace.x = x1; trace.y = y1; trace.dx = x2 - x1; trace.dy = y2 - y1; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = x1 >> MAPBLOCKSHIFT; yt1 = y1 >> MAPBLOCKSHIFT; x2 -= bmaporgx; y2 -= bmaporgy; xt2 = x2 >> MAPBLOCKSHIFT; yt2 = y2 >> MAPBLOCKSHIFT; if (xt2 > xt1) { mapxstep = 1; partial = FRACUNIT - ((x1 >> MAPBTOFRAC) & (FRACUNIT - 1)); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else if (xt2 < xt1) { mapxstep = -1; partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else { mapxstep = 0; partial = FRACUNIT; ystep = 256 * FRACUNIT; } yintercept = (y1 >> MAPBTOFRAC) + FixedMul(partial, ystep); if (yt2 > yt1) { mapystep = 1; partial = FRACUNIT - ((y1 >> MAPBTOFRAC) & (FRACUNIT - 1)); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else if (yt2 < yt1) { mapystep = -1; partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else { mapystep = 0; partial = FRACUNIT; xstep = 256 * FRACUNIT; } xintercept = (x1 >> MAPBTOFRAC) + FixedMul(partial, xstep); // // step through map blocks // Count is present to prevent a round off error from skipping the break mapx = xt1; mapy = yt1; for (count = 0; count < 64; count++) { if (flags & PT_ADDLINES) { if (!P_BlockLinesIterator(mapx, mapy, PIT_AddLineIntercepts)) return false; // early out } if (flags & PT_ADDTHINGS) { if (!P_BlockThingsIterator(mapx, mapy, PIT_AddThingIntercepts)) return false; // early out } if (mapx == xt2 && mapy == yt2) break; if ((yintercept >> FRACBITS) == mapy) { yintercept += ystep; mapx += mapxstep; } else if ((xintercept >> FRACBITS) == mapx) { xintercept += xstep; mapy += mapystep; } } // // go through the sorted list // return P_TraverseIntercepts(trav, FRACUNIT); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_mobj.c000066400000000000000000001260741257432200600231430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_mobj.c #include "doomdef.h" #include "i_system.h" #include "m_random.h" #include "p_local.h" #include "sounds.h" #include "s_sound.h" void G_PlayerReborn(int player); void P_SpawnMapThing(mapthing_t * mthing); mobjtype_t PuffType; mobj_t *MissileMobj; static fixed_t FloatBobOffsets[64] = { 0, 51389, 102283, 152192, 200636, 247147, 291278, 332604, 370727, 405280, 435929, 462380, 484378, 501712, 514213, 521763, 524287, 521763, 514213, 501712, 484378, 462380, 435929, 405280, 370727, 332604, 291278, 247147, 200636, 152192, 102283, 51389, -1, -51390, -102284, -152193, -200637, -247148, -291279, -332605, -370728, -405281, -435930, -462381, -484380, -501713, -514215, -521764, -524288, -521764, -514214, -501713, -484379, -462381, -435930, -405280, -370728, -332605, -291279, -247148, -200637, -152193, -102284, -51389 }; //---------------------------------------------------------------------------- // // FUNC P_SetMobjState // // Returns true if the mobj is still present. // //---------------------------------------------------------------------------- boolean P_SetMobjState(mobj_t * mobj, statenum_t state) { state_t *st; if (state == S_NULL) { // Remove mobj mobj->state = (state_t *) S_NULL; P_RemoveMobj(mobj); return (false); } st = &states[state]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; if (st->action) { // Call action function st->action(mobj); } return (true); } //---------------------------------------------------------------------------- // // FUNC P_SetMobjStateNF // // Same as P_SetMobjState, but does not call the state function. // //---------------------------------------------------------------------------- boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state) { state_t *st; if (state == S_NULL) { // Remove mobj mobj->state = (state_t *) S_NULL; P_RemoveMobj(mobj); return (false); } st = &states[state]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; return (true); } //---------------------------------------------------------------------------- // // PROC P_ExplodeMissile // //---------------------------------------------------------------------------- void P_ExplodeMissile(mobj_t * mo) { if (mo->type == MT_WHIRLWIND) { if (++mo->special2.i < 60) { return; } } mo->momx = mo->momy = mo->momz = 0; P_SetMobjState(mo, mobjinfo[mo->type].deathstate); //mo->tics -= P_Random()&3; mo->flags &= ~MF_MISSILE; if (mo->info->deathsound) { S_StartSound(mo, mo->info->deathsound); } } //---------------------------------------------------------------------------- // // PROC P_FloorBounceMissile // //---------------------------------------------------------------------------- void P_FloorBounceMissile(mobj_t * mo) { mo->momz = -mo->momz; P_SetMobjState(mo, mobjinfo[mo->type].deathstate); } //---------------------------------------------------------------------------- // // PROC P_ThrustMobj // //---------------------------------------------------------------------------- void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move) { angle >>= ANGLETOFINESHIFT; mo->momx += FixedMul(move, finecosine[angle]); mo->momy += FixedMul(move, finesine[angle]); } //---------------------------------------------------------------------------- // // FUNC P_FaceMobj // // Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs // to turn counter clockwise. 'delta' is set to the amount 'source' // needs to turn. // //---------------------------------------------------------------------------- int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta) { angle_t diff; angle_t angle1; angle_t angle2; angle1 = source->angle; angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y); if (angle2 > angle1) { diff = angle2 - angle1; if (diff > ANG180) { *delta = ANG_MAX - diff; return (0); } else { *delta = diff; return (1); } } else { diff = angle1 - angle2; if (diff > ANG180) { *delta = ANG_MAX - diff; return (1); } else { *delta = diff; return (0); } } } //---------------------------------------------------------------------------- // // FUNC P_SeekerMissile // // The missile special1 field must be mobj_t *target. Returns true if // target was tracked, false if not. // //---------------------------------------------------------------------------- boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax) { int dir; int dist; angle_t delta; angle_t angle; mobj_t *target; target = (mobj_t *) actor->special1.m; if (target == NULL) { return (false); } if (!(target->flags & MF_SHOOTABLE)) { // Target died actor->special1.m = NULL; return (false); } dir = P_FaceMobj(actor, target, &delta); if (delta > thresh) { delta >>= 1; if (delta > turnMax) { delta = turnMax; } } if (dir) { // Turn clockwise actor->angle += delta; } else { // Turn counter clockwise actor->angle -= delta; } angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(actor->info->speed, finecosine[angle]); actor->momy = FixedMul(actor->info->speed, finesine[angle]); if (actor->z + actor->height < target->z || target->z + target->height < actor->z) { // Need to seek vertically dist = P_AproxDistance(target->x - actor->x, target->y - actor->y); dist = dist / actor->info->speed; if (dist < 1) { dist = 1; } actor->momz = (target->z - actor->z) / dist; } return (true); } //---------------------------------------------------------------------------- // // PROC P_XYMovement // //---------------------------------------------------------------------------- #define STOPSPEED 0x1000 #define FRICTION_NORMAL 0xe800 #define FRICTION_LOW 0xf900 #define FRICTION_FLY 0xeb00 void P_XYMovement(mobj_t * mo) { fixed_t ptryx, ptryy; player_t *player; fixed_t xmove, ymove; int special; static int windTab[3] = { 2048 * 5, 2048 * 10, 2048 * 25 }; if (!mo->momx && !mo->momy) { if (mo->flags & MF_SKULLFLY) { // A flying mobj slammed into something mo->flags &= ~MF_SKULLFLY; mo->momx = mo->momy = mo->momz = 0; P_SetMobjState(mo, mo->info->seestate); } return; } special = mo->subsector->sector->special; if (mo->flags2 & MF2_WINDTHRUST) { switch (special) { case 40: case 41: case 42: // Wind_East P_ThrustMobj(mo, 0, windTab[special - 40]); break; case 43: case 44: case 45: // Wind_North P_ThrustMobj(mo, ANG90, windTab[special - 43]); break; case 46: case 47: case 48: // Wind_South P_ThrustMobj(mo, ANG270, windTab[special - 46]); break; case 49: case 50: case 51: // Wind_West P_ThrustMobj(mo, ANG180, windTab[special - 49]); break; } } player = mo->player; if (mo->momx > MAXMOVE) { mo->momx = MAXMOVE; } else if (mo->momx < -MAXMOVE) { mo->momx = -MAXMOVE; } if (mo->momy > MAXMOVE) { mo->momy = MAXMOVE; } else if (mo->momy < -MAXMOVE) { mo->momy = -MAXMOVE; } xmove = mo->momx; ymove = mo->momy; do { if (xmove > MAXMOVE / 2 || ymove > MAXMOVE / 2) { ptryx = mo->x + xmove / 2; ptryy = mo->y + ymove / 2; xmove >>= 1; ymove >>= 1; } else { ptryx = mo->x + xmove; ptryy = mo->y + ymove; xmove = ymove = 0; } if (!P_TryMove(mo, ptryx, ptryy)) { // Blocked move if (mo->flags2 & MF2_SLIDE) { // Try to slide along it P_SlideMove(mo); } else if (mo->flags & MF_MISSILE) { // Explode a missile if (ceilingline && ceilingline->backsector && ceilingline->backsector->ceilingpic == skyflatnum) { // Hack to prevent missiles exploding against the sky if (mo->type == MT_BLOODYSKULL) { mo->momx = mo->momy = 0; mo->momz = -FRACUNIT; } else { P_RemoveMobj(mo); } return; } P_ExplodeMissile(mo); } //else if(mo->info->crashstate) //{ // mo->momx = mo->momy = 0; // P_SetMobjState(mo, mo->info->crashstate); // return; //} else { mo->momx = mo->momy = 0; } } } while (xmove || ymove); // Friction if (player && player->cheats & CF_NOMOMENTUM) { // Debug option for no sliding at all mo->momx = mo->momy = 0; return; } if (mo->flags & (MF_MISSILE | MF_SKULLFLY)) { // No friction for missiles return; } if (mo->z > mo->floorz && !(mo->flags2 & MF2_FLY) && !(mo->flags2 & MF2_ONMOBJ)) { // No friction when falling return; } if (mo->flags & MF_CORPSE) { // Don't stop sliding if halfway off a step with some momentum if (mo->momx > FRACUNIT / 4 || mo->momx < -FRACUNIT / 4 || mo->momy > FRACUNIT / 4 || mo->momy < -FRACUNIT / 4) { if (mo->floorz != mo->subsector->sector->floorheight) { return; } } } if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && mo->momy > -STOPSPEED && mo->momy < STOPSPEED && (!player || (player->cmd.forwardmove == 0 && player->cmd.sidemove == 0))) { // If in a walking frame, stop moving if (player) { if (player->chickenTics) { if ((unsigned) ((player->mo->state - states) - S_CHICPLAY_RUN1) < 4) { P_SetMobjState(player->mo, S_CHICPLAY); } } else { if ((unsigned) ((player->mo->state - states) - S_PLAY_RUN1) < 4) { P_SetMobjState(player->mo, S_PLAY); } } } mo->momx = 0; mo->momy = 0; } else { if (mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz) && !(mo->flags2 & MF2_ONMOBJ)) { mo->momx = FixedMul(mo->momx, FRICTION_FLY); mo->momy = FixedMul(mo->momy, FRICTION_FLY); } else if (special == 15) // Friction_Low { mo->momx = FixedMul(mo->momx, FRICTION_LOW); mo->momy = FixedMul(mo->momy, FRICTION_LOW); } else { mo->momx = FixedMul(mo->momx, FRICTION_NORMAL); mo->momy = FixedMul(mo->momy, FRICTION_NORMAL); } } } /* =============== = = P_ZMovement = =============== */ void P_ZMovement(mobj_t * mo) { int dist; int delta; // // check for smooth step up // if (mo->player && mo->z < mo->floorz) { mo->player->viewheight -= mo->floorz - mo->z; mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight) >> 3; } // // adjust height // mo->z += mo->momz; if (mo->flags & MF_FLOAT && mo->target) { // float down towards target if too close if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT)) { dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y); delta = (mo->target->z + (mo->height >> 1)) - mo->z; if (delta < 0 && dist < -(delta * 3)) mo->z -= FLOATSPEED; else if (delta > 0 && dist < (delta * 3)) mo->z += FLOATSPEED; } } if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz) && leveltime & 2) { mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK]; } // // clip movement // if (mo->z <= mo->floorz) { // Hit the floor if (mo->flags & MF_MISSILE) { mo->z = mo->floorz; if (mo->flags2 & MF2_FLOORBOUNCE) { P_FloorBounceMissile(mo); return; } else if (mo->type == MT_MNTRFX2) { // Minotaur floor fire can go up steps return; } else { P_ExplodeMissile(mo); return; } } if (mo->z - mo->momz > mo->floorz) { // Spawn splashes, etc. P_HitFloor(mo); } mo->z = mo->floorz; if (mo->momz < 0) { if (mo->player && mo->momz < -GRAVITY * 8 && !(mo->flags2 & MF2_FLY)) // squat down { mo->player->deltaviewheight = mo->momz >> 3; S_StartSound(mo, sfx_plroof); // haleyjd: removed externdriver crap mo->player->centering = true; } mo->momz = 0; } if (mo->flags & MF_SKULLFLY) { // The skull slammed into something mo->momz = -mo->momz; } if (mo->info->crashstate && (mo->flags & MF_CORPSE)) { P_SetMobjState(mo, mo->info->crashstate); return; } } else if (mo->flags2 & MF2_LOGRAV) { if (mo->momz == 0) mo->momz = -(GRAVITY >> 3) * 2; else mo->momz -= GRAVITY >> 3; } else if (!(mo->flags & MF_NOGRAVITY)) { if (mo->momz == 0) mo->momz = -GRAVITY * 2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // hit the ceiling if (mo->momz > 0) mo->momz = 0; mo->z = mo->ceilingz - mo->height; if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; } if (mo->flags & MF_MISSILE) { if (mo->subsector->sector->ceilingpic == skyflatnum) { if (mo->type == MT_BLOODYSKULL) { mo->momx = mo->momy = 0; mo->momz = -FRACUNIT; } else { P_RemoveMobj(mo); } return; } P_ExplodeMissile(mo); return; } } } /* ================ = = P_NightmareRespawn = ================ */ void P_NightmareRespawn(mobj_t * mobj) { fixed_t x, y, z; subsector_t *ss; mobj_t *mo; mapthing_t *mthing; x = mobj->spawnpoint.x << FRACBITS; y = mobj->spawnpoint.y << FRACBITS; if (!P_CheckPosition(mobj, x, y)) return; // somthing is occupying it's position // spawn a teleport fog at old spot mo = P_SpawnMobj(mobj->x, mobj->y, mobj->subsector->sector->floorheight + TELEFOGHEIGHT, MT_TFOG); S_StartSound(mo, sfx_telept); // spawn a teleport fog at the new spot ss = R_PointInSubsector(x, y); mo = P_SpawnMobj(x, y, ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG); S_StartSound(mo, sfx_telept); // spawn the new monster mthing = &mobj->spawnpoint; // spawn it if (mobj->info->flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mo = P_SpawnMobj(x, y, z, mobj->type); mo->spawnpoint = mobj->spawnpoint; mo->angle = ANG45 * (mthing->angle / 45); if (mthing->options & MTF_AMBUSH) mo->flags |= MF_AMBUSH; mo->reactiontime = 18; // remove the old monster P_RemoveMobj(mobj); } //---------------------------------------------------------------------------- // // PROC P_BlasterMobjThinker // // Thinker for the ultra-fast blaster PL2 ripper-spawning missile. // //---------------------------------------------------------------------------- void P_BlasterMobjThinker(mobj_t * mobj) { int i; fixed_t xfrac; fixed_t yfrac; fixed_t zfrac; fixed_t z; boolean changexy; // Handle movement if (mobj->momx || mobj->momy || (mobj->z != mobj->floorz) || mobj->momz) { xfrac = mobj->momx >> 3; yfrac = mobj->momy >> 3; zfrac = mobj->momz >> 3; changexy = xfrac || yfrac; for (i = 0; i < 8; i++) { if (changexy) { if (!P_TryMove(mobj, mobj->x + xfrac, mobj->y + yfrac)) { // Blocked move P_ExplodeMissile(mobj); return; } } mobj->z += zfrac; if (mobj->z <= mobj->floorz) { // Hit the floor mobj->z = mobj->floorz; P_HitFloor(mobj); P_ExplodeMissile(mobj); return; } if (mobj->z + mobj->height > mobj->ceilingz) { // Hit the ceiling mobj->z = mobj->ceilingz - mobj->height; P_ExplodeMissile(mobj); return; } if (changexy && (P_Random() < 64)) { z = mobj->z - 8 * FRACUNIT; if (z < mobj->floorz) { z = mobj->floorz; } P_SpawnMobj(mobj->x, mobj->y, z, MT_BLASTERSMOKE); } } } // Advance the state if (mobj->tics != -1) { mobj->tics--; while (!mobj->tics) { if (!P_SetMobjState(mobj, mobj->state->nextstate)) { // mobj was removed return; } } } } //---------------------------------------------------------------------------- // // PROC P_MobjThinker // //---------------------------------------------------------------------------- void P_MobjThinker(mobj_t * mobj) { mobj_t *onmo; // Handle X and Y momentums if (mobj->momx || mobj->momy || (mobj->flags & MF_SKULLFLY)) { P_XYMovement(mobj); if (mobj->thinker.function == (think_t) - 1) { // mobj was removed return; } } if (mobj->flags2 & MF2_FLOATBOB) { // Floating item bobbing motion mobj->z = mobj->floorz + FloatBobOffsets[(mobj->health++) & 63]; } else if ((mobj->z != mobj->floorz) || mobj->momz) { // Handle Z momentum and gravity if (mobj->flags2 & MF2_PASSMOBJ) { if (!(onmo = P_CheckOnmobj(mobj))) { P_ZMovement(mobj); } else { if (mobj->player && mobj->momz < 0) { mobj->flags2 |= MF2_ONMOBJ; mobj->momz = 0; } if (mobj->player && (onmo->player || onmo->type == MT_POD)) { mobj->momx = onmo->momx; mobj->momy = onmo->momy; if (onmo->z < onmo->floorz) { mobj->z += onmo->floorz - onmo->z; if (onmo->player) { onmo->player->viewheight -= onmo->floorz - onmo->z; onmo->player->deltaviewheight = (VIEWHEIGHT - onmo->player->viewheight) >> 3; } onmo->z = onmo->floorz; } } } } else { P_ZMovement(mobj); } if (mobj->thinker.function == (think_t) - 1) { // mobj was removed return; } } // // cycle through states, calling action functions at transitions // if (mobj->tics != -1) { mobj->tics--; // you can cycle through multiple states in a tic while (!mobj->tics) { if (!P_SetMobjState(mobj, mobj->state->nextstate)) { // mobj was removed return; } } } else { // Check for monster respawn if (!(mobj->flags & MF_COUNTKILL)) { return; } if (!respawnmonsters) { return; } mobj->movecount++; if (mobj->movecount < 12 * 35) { return; } if (leveltime & 31) { return; } if (P_Random() > 4) { return; } P_NightmareRespawn(mobj); } } /* =============== = = P_SpawnMobj = =============== */ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { mobj_t *mobj; state_t *st; mobjinfo_t *info; fixed_t space; mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL); memset(mobj, 0, sizeof(*mobj)); info = &mobjinfo[type]; mobj->type = type; mobj->info = info; mobj->x = x; mobj->y = y; mobj->radius = info->radius; mobj->height = info->height; mobj->flags = info->flags; mobj->flags2 = info->flags2; mobj->damage = info->damage; mobj->health = info->spawnhealth; if (gameskill != sk_nightmare) { mobj->reactiontime = info->reactiontime; } mobj->lastlook = P_Random() % MAXPLAYERS; // Set the state, but do not use P_SetMobjState, because action // routines can't be called yet. If the spawnstate has an action // routine, it will not be called. st = &states[info->spawnstate]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // Set subsector and/or block links. P_SetThingPosition(mobj); mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; if (z == ONFLOORZ) { mobj->z = mobj->floorz; } else if (z == ONCEILINGZ) { mobj->z = mobj->ceilingz - mobj->info->height; } else if (z == FLOATRANDZ) { space = ((mobj->ceilingz) - (mobj->info->height)) - mobj->floorz; if (space > 48 * FRACUNIT) { space -= 40 * FRACUNIT; mobj->z = ((space * P_Random()) >> 8) + mobj->floorz + 40 * FRACUNIT; } else { mobj->z = mobj->floorz; } } else { mobj->z = z; } if (mobj->flags2 & MF2_FOOTCLIP && P_GetThingFloorType(mobj) != FLOOR_SOLID && mobj->floorz == mobj->subsector->sector->floorheight) { mobj->flags2 |= MF2_FEETARECLIPPED; } else { mobj->flags2 &= ~MF2_FEETARECLIPPED; } mobj->thinker.function = P_MobjThinker; P_AddThinker(&mobj->thinker); return (mobj); } /* =============== = = P_RemoveMobj = =============== */ void P_RemoveMobj(mobj_t * mobj) { // unlink from sector and block lists P_UnsetThingPosition(mobj); // stop any playing sound S_StopSound(mobj); // free block P_RemoveThinker((thinker_t *) mobj); } //============================================================================= /* ============ = = P_SpawnPlayer = = Called when a player is spawned on the level = Most of the player structure stays unchanged between levels ============ */ void P_SpawnPlayer(mapthing_t * mthing) { player_t *p; fixed_t x, y, z; mobj_t *mobj; int i; extern int playerkeys; if (!playeringame[mthing->type - 1]) return; // not playing p = &players[mthing->type - 1]; if (p->playerstate == PST_REBORN) G_PlayerReborn(mthing->type - 1); x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; z = ONFLOORZ; mobj = P_SpawnMobj(x, y, z, MT_PLAYER); if (mthing->type > 1) // set color translations for player sprites mobj->flags |= (mthing->type - 1) << MF_TRANSSHIFT; mobj->angle = ANG45 * (mthing->angle / 45); mobj->player = p; mobj->health = p->health; p->mo = mobj; p->playerstate = PST_LIVE; p->refire = 0; p->message = NULL; p->damagecount = 0; p->bonuscount = 0; p->chickenTics = 0; p->rain1 = NULL; p->rain2 = NULL; p->extralight = 0; p->fixedcolormap = 0; p->viewheight = VIEWHEIGHT; P_SetupPsprites(p); // setup gun psprite if (deathmatch) { // Give all keys in death match mode for (i = 0; i < NUMKEYS; i++) { p->keys[i] = true; if (p == &players[consoleplayer]) { playerkeys = 7; UpdateState |= I_STATBAR; } } } else if (p == &players[consoleplayer]) { playerkeys = 0; UpdateState |= I_STATBAR; } } //---------------------------------------------------------------------------- // // PROC P_SpawnMapThing // // The fields of the mapthing should already be in host byte order. // //---------------------------------------------------------------------------- void P_SpawnMapThing(mapthing_t * mthing) { int i; int bit; mobj_t *mobj; fixed_t x, y, z; // count deathmatch start positions if (mthing->type == 11) { if (deathmatch_p < &deathmatchstarts[10]) { memcpy(deathmatch_p, mthing, sizeof(*mthing)); deathmatch_p++; } return; } // check for players specially if (mthing->type <= 4) { // save spots for respawning in network games playerstarts[mthing->type - 1] = *mthing; if (!deathmatch) { P_SpawnPlayer(mthing); } return; } // Ambient sound sequences if (mthing->type >= 1200 && mthing->type < 1300) { P_AddAmbientSfx(mthing->type - 1200); return; } // Check for boss spots if (mthing->type == 56) // Monster_BossSpot { P_AddBossSpot(mthing->x << FRACBITS, mthing->y << FRACBITS, ANG45 * (mthing->angle / 45)); return; } // check for apropriate skill level if (!netgame && (mthing->options & 16)) return; if (gameskill == sk_baby) bit = 1; else if (gameskill == sk_nightmare) bit = 4; else bit = 1 << (gameskill - 1); if (!(mthing->options & bit)) return; // find which type to spawn for (i = 0; i < NUMMOBJTYPES; i++) if (mthing->type == mobjinfo[i].doomednum) break; if (i == NUMMOBJTYPES) I_Error("P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type, mthing->x, mthing->y); // don't spawn keys and players in deathmatch if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) return; // don't spawn any monsters if -nomonsters if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL)) return; // spawn it switch (i) { // Special stuff case MT_WSKULLROD: case MT_WPHOENIXROD: case MT_AMSKRDWIMPY: case MT_AMSKRDHEFTY: case MT_AMPHRDWIMPY: case MT_AMPHRDHEFTY: case MT_AMMACEWIMPY: case MT_AMMACEHEFTY: case MT_ARTISUPERHEAL: case MT_ARTITELEPORT: case MT_ITEMSHIELD2: if (gamemode == shareware) { // Don't place on map in shareware version return; } break; case MT_WMACE: if (gamemode != shareware) { // Put in the mace spot list P_AddMaceSpot(mthing); return; } return; default: break; } x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (mobjinfo[i].flags & MF_SPAWNCEILING) { z = ONCEILINGZ; } else if (mobjinfo[i].flags2 & MF2_SPAWNFLOAT) { z = FLOATRANDZ; } else { z = ONFLOORZ; } mobj = P_SpawnMobj(x, y, z, i); if (mobj->flags2 & MF2_FLOATBOB) { // Seed random starting index for bobbing motion mobj->health = P_Random(); } if (mobj->tics > 0) { mobj->tics = 1 + (P_Random() % mobj->tics); } if (mobj->flags & MF_COUNTKILL) { totalkills++; mobj->spawnpoint = *mthing; } if (mobj->flags & MF_COUNTITEM) { totalitems++; } mobj->angle = ANG45 * (mthing->angle / 45); if (mthing->options & MTF_AMBUSH) { mobj->flags |= MF_AMBUSH; } } /* =============================================================================== GAME SPAWN FUNCTIONS =============================================================================== */ //--------------------------------------------------------------------------- // // PROC P_SpawnPuff // //--------------------------------------------------------------------------- extern fixed_t attackrange; void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z) { mobj_t *puff; z += ((P_Random() - P_Random()) << 10); puff = P_SpawnMobj(x, y, z, PuffType); if (puff->info->attacksound) { S_StartSound(puff, puff->info->attacksound); } switch (PuffType) { case MT_BEAKPUFF: case MT_STAFFPUFF: puff->momz = FRACUNIT; break; case MT_GAUNTLETPUFF1: case MT_GAUNTLETPUFF2: puff->momz = (fixed_t)(.8 * FRACUNIT); default: break; } } /* ================ = = P_SpawnBlood = ================ */ /* void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage) { mobj_t *th; z += ((P_Random()-P_Random())<<10); th = P_SpawnMobj (x,y,z, MT_BLOOD); th->momz = FRACUNIT*2; th->tics -= P_Random()&3; if (damage <= 12 && damage >= 9) P_SetMobjState (th,S_BLOOD2); else if (damage < 9) P_SetMobjState (th,S_BLOOD3); } */ //--------------------------------------------------------------------------- // // PROC P_BloodSplatter // //--------------------------------------------------------------------------- void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator) { mobj_t *mo; mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER); mo->target = originator; mo->momx = (P_Random() - P_Random()) << 9; mo->momy = (P_Random() - P_Random()) << 9; mo->momz = FRACUNIT * 2; } //--------------------------------------------------------------------------- // // PROC P_RipperBlood // //--------------------------------------------------------------------------- void P_RipperBlood(mobj_t * mo) { mobj_t *th; fixed_t x, y, z; x = mo->x + ((P_Random() - P_Random()) << 12); y = mo->y + ((P_Random() - P_Random()) << 12); z = mo->z + ((P_Random() - P_Random()) << 12); th = P_SpawnMobj(x, y, z, MT_BLOOD); th->flags |= MF_NOGRAVITY; th->momx = mo->momx >> 1; th->momy = mo->momy >> 1; th->tics += P_Random() & 3; } //--------------------------------------------------------------------------- // // FUNC P_GetThingFloorType // //--------------------------------------------------------------------------- int P_GetThingFloorType(mobj_t * thing) { return (TerrainTypes[thing->subsector->sector->floorpic]); /* if(thing->subsector->sector->floorpic == W_GetNumForName("FLTWAWA1")-firstflat) { return(FLOOR_WATER); } else { return(FLOOR_SOLID); } */ } //--------------------------------------------------------------------------- // // FUNC P_HitFloor // //--------------------------------------------------------------------------- int P_HitFloor(mobj_t * thing) { mobj_t *mo; if (thing->floorz != thing->subsector->sector->floorheight) { // don't splash if landing on the edge above water/lava/etc.... return (FLOOR_SOLID); } switch (P_GetThingFloorType(thing)) { case FLOOR_WATER: P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE); mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH); mo->target = thing; mo->momx = (P_Random() - P_Random()) << 8; mo->momy = (P_Random() - P_Random()) << 8; mo->momz = 2 * FRACUNIT + (P_Random() << 8); S_StartSound(mo, sfx_gloop); return (FLOOR_WATER); case FLOOR_LAVA: P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH); mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE); mo->momz = FRACUNIT + (P_Random() << 7); S_StartSound(mo, sfx_burn); return (FLOOR_LAVA); case FLOOR_SLUDGE: P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH); mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK); mo->target = thing; mo->momx = (P_Random() - P_Random()) << 8; mo->momy = (P_Random() - P_Random()) << 8; mo->momz = FRACUNIT + (P_Random() << 8); return (FLOOR_SLUDGE); } return (FLOOR_SOLID); } //--------------------------------------------------------------------------- // // FUNC P_CheckMissileSpawn // // Returns true if the missile is at a valid spawn point, otherwise // explodes it and returns false. // //--------------------------------------------------------------------------- boolean P_CheckMissileSpawn(mobj_t * missile) { //missile->tics -= P_Random()&3; // move a little forward so an angle can be computed if it // immediately explodes missile->x += (missile->momx >> 1); missile->y += (missile->momy >> 1); missile->z += (missile->momz >> 1); if (!P_TryMove(missile, missile->x, missile->y)) { P_ExplodeMissile(missile); return (false); } return (true); } //--------------------------------------------------------------------------- // // FUNC P_SpawnMissile // // Returns NULL if the missile exploded immediately, otherwise returns // a mobj_t pointer to the missile. // //--------------------------------------------------------------------------- mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type) { fixed_t z; mobj_t *th; angle_t an; int dist; switch (type) { case MT_MNTRFX1: // Minotaur swing attack missile z = source->z + 40 * FRACUNIT; break; case MT_MNTRFX2: // Minotaur floor fire missile z = ONFLOORZ; break; case MT_SRCRFX1: // Sorcerer Demon fireball z = source->z + 48 * FRACUNIT; break; case MT_KNIGHTAXE: // Knight normal axe case MT_REDAXE: // Knight red power axe z = source->z + 36 * FRACUNIT; break; default: z = source->z + 32 * FRACUNIT; break; } if (source->flags2 & MF2_FEETARECLIPPED) { z -= FOOTCLIPSIZE; } th = P_SpawnMobj(source->x, source->y, z, type); if (th->info->seesound) { S_StartSound(th, th->info->seesound); } th->target = source; // Originator an = R_PointToAngle2(source->x, source->y, dest->x, dest->y); if (dest->flags & MF_SHADOW) { // Invisible target an += (P_Random() - P_Random()) << 21; } th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(th->info->speed, finecosine[an]); th->momy = FixedMul(th->info->speed, finesine[an]); dist = P_AproxDistance(dest->x - source->x, dest->y - source->y); dist = dist / th->info->speed; if (dist < 1) { dist = 1; } th->momz = (dest->z - source->z) / dist; return (P_CheckMissileSpawn(th) ? th : NULL); } //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileAngle // // Returns NULL if the missile exploded immediately, otherwise returns // a mobj_t pointer to the missile. // //--------------------------------------------------------------------------- mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type, angle_t angle, fixed_t momz) { fixed_t z; mobj_t *mo; switch (type) { case MT_MNTRFX1: // Minotaur swing attack missile z = source->z + 40 * FRACUNIT; break; case MT_MNTRFX2: // Minotaur floor fire missile z = ONFLOORZ; break; case MT_SRCRFX1: // Sorcerer Demon fireball z = source->z + 48 * FRACUNIT; break; default: z = source->z + 32 * FRACUNIT; break; } if (source->flags2 & MF2_FEETARECLIPPED) { z -= FOOTCLIPSIZE; } mo = P_SpawnMobj(source->x, source->y, z, type); if (mo->info->seesound) { S_StartSound(mo, mo->info->seesound); } mo->target = source; // Originator mo->angle = angle; angle >>= ANGLETOFINESHIFT; mo->momx = FixedMul(mo->info->speed, finecosine[angle]); mo->momy = FixedMul(mo->info->speed, finesine[angle]); mo->momz = momz; return (P_CheckMissileSpawn(mo) ? mo : NULL); } /* ================ = = P_SpawnPlayerMissile = = Tries to aim at a nearby monster ================ */ mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type) { angle_t an; fixed_t x, y, z, slope; // Try to find a target an = source->angle; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an += 1 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an -= 2 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); } if (!linetarget) { an = source->angle; slope = ((source->player->lookdir) << FRACBITS) / 173; } } x = source->x; y = source->y; z = source->z + 4 * 8 * FRACUNIT + ((source->player->lookdir) << FRACBITS) / 173; if (source->flags2 & MF2_FEETARECLIPPED) { z -= FOOTCLIPSIZE; } MissileMobj = P_SpawnMobj(x, y, z, type); if (MissileMobj->info->seesound) { S_StartSound(MissileMobj, MissileMobj->info->seesound); } MissileMobj->target = source; MissileMobj->angle = an; MissileMobj->momx = FixedMul(MissileMobj->info->speed, finecosine[an >> ANGLETOFINESHIFT]); MissileMobj->momy = FixedMul(MissileMobj->info->speed, finesine[an >> ANGLETOFINESHIFT]); MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope); if (MissileMobj->type == MT_BLASTERFX1) { // Ultra-fast ripper spawning missile MissileMobj->x += (MissileMobj->momx >> 3); MissileMobj->y += (MissileMobj->momy >> 3); MissileMobj->z += (MissileMobj->momz >> 3); } else { // Normal missile MissileMobj->x += (MissileMobj->momx >> 1); MissileMobj->y += (MissileMobj->momy >> 1); MissileMobj->z += (MissileMobj->momz >> 1); } if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y)) { // Exploded immediately P_ExplodeMissile(MissileMobj); return (NULL); } return (MissileMobj); } //--------------------------------------------------------------------------- // // PROC P_SPMAngle // //--------------------------------------------------------------------------- mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle) { mobj_t *th; angle_t an; fixed_t x, y, z, slope; // // see which target is to be aimed at // an = angle; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an += 1 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an -= 2 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); } if (!linetarget) { an = angle; slope = ((source->player->lookdir) << FRACBITS) / 173; } } x = source->x; y = source->y; z = source->z + 4 * 8 * FRACUNIT + ((source->player->lookdir) << FRACBITS) / 173; if (source->flags2 & MF2_FEETARECLIPPED) { z -= FOOTCLIPSIZE; } th = P_SpawnMobj(x, y, z, type); if (th->info->seesound) { S_StartSound(th, th->info->seesound); } th->target = source; th->angle = an; th->momx = FixedMul(th->info->speed, finecosine[an >> ANGLETOFINESHIFT]); th->momy = FixedMul(th->info->speed, finesine[an >> ANGLETOFINESHIFT]); th->momz = FixedMul(th->info->speed, slope); return (P_CheckMissileSpawn(th) ? th : NULL); } //--------------------------------------------------------------------------- // // PROC A_ContMobjSound // //--------------------------------------------------------------------------- void A_ContMobjSound(mobj_t * actor) { switch (actor->type) { case MT_KNIGHTAXE: S_StartSound(actor, sfx_kgtatk); break; case MT_MUMMYFX1: S_StartSound(actor, sfx_mumhed); break; default: break; } } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_plats.c000066400000000000000000000173471257432200600233410ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_plats.c #include "doomdef.h" #include "i_system.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" plat_t *activeplats[MAXPLATS]; //================================================================== // // Move a plat up and down // //================================================================== void T_PlatRaise(plat_t * plat) { result_e res; switch (plat->status) { case up: res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush, 0, 1); if (!(leveltime & 31)) { S_StartSound(&plat->sector->soundorg, sfx_stnmov); } if (plat->type == raiseAndChange || plat->type == raiseToNearestAndChange) { if (!(leveltime & 7)) { S_StartSound(&plat->sector->soundorg, sfx_stnmov); } } if (res == crushed && (!plat->crush)) { plat->count = plat->wait; plat->status = down; S_StartSound(&plat->sector->soundorg, sfx_pstart); } else if (res == pastdest) { plat->count = plat->wait; plat->status = waiting; S_StartSound(&plat->sector->soundorg, sfx_pstop); switch (plat->type) { case downWaitUpStay: P_RemoveActivePlat(plat); break; case raiseAndChange: P_RemoveActivePlat(plat); break; default: break; } } break; case down: res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1); if (res == pastdest) { plat->count = plat->wait; plat->status = waiting; S_StartSound(&plat->sector->soundorg, sfx_pstop); } else { if (!(leveltime & 31)) { S_StartSound(&plat->sector->soundorg, sfx_stnmov); } } break; case waiting: if (!--plat->count) { if (plat->sector->floorheight == plat->low) plat->status = up; else plat->status = down; S_StartSound(&plat->sector->soundorg, sfx_pstart); } case in_stasis: break; } } //================================================================== // // Do Platforms // "amount" is only used for SOME platforms. // //================================================================== int EV_DoPlat(line_t * line, plattype_e type, int amount) { plat_t *plat; int secnum; int rtn; sector_t *sec; secnum = -1; rtn = 0; // // Activate all plats that are in_stasis // switch (type) { case perpetualRaise: P_ActivateInStasis(line->tag); break; default: break; } while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // // Find lowest & highest floors around sector // rtn = 1; plat = Z_Malloc(sizeof(*plat), PU_LEVSPEC, 0); P_AddThinker(&plat->thinker); plat->type = type; plat->sector = sec; plat->sector->specialdata = plat; plat->thinker.function = T_PlatRaise; plat->crush = false; plat->tag = line->tag; switch (type) { case raiseToNearestAndChange: plat->speed = PLATSPEED / 2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = P_FindNextHighestFloor(sec, sec->floorheight); plat->wait = 0; plat->status = up; sec->special = 0; // NO MORE DAMAGE, IF APPLICABLE S_StartSound(&sec->soundorg, sfx_stnmov); break; case raiseAndChange: plat->speed = PLATSPEED / 2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = sec->floorheight + amount * FRACUNIT; plat->wait = 0; plat->status = up; S_StartSound(&sec->soundorg, sfx_stnmov); break; case downWaitUpStay: plat->speed = PLATSPEED * 4; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = 35 * PLATWAIT; plat->status = down; S_StartSound(&sec->soundorg, sfx_pstart); break; case perpetualRaise: plat->speed = PLATSPEED; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = P_FindHighestFloorSurrounding(sec); if (plat->high < sec->floorheight) plat->high = sec->floorheight; plat->wait = 35 * PLATWAIT; plat->status = P_Random() & 1; S_StartSound(&sec->soundorg, sfx_pstart); break; } P_AddActivePlat(plat); } return rtn; } void P_ActivateInStasis(int tag) { int i; for (i = 0; i < MAXPLATS; i++) if (activeplats[i] && (activeplats[i])->tag == tag && (activeplats[i])->status == in_stasis) { (activeplats[i])->status = (activeplats[i])->oldstatus; (activeplats[i])->thinker.function = T_PlatRaise; } } void EV_StopPlat(line_t * line) { int j; for (j = 0; j < MAXPLATS; j++) if (activeplats[j] && ((activeplats[j])->status != in_stasis) && ((activeplats[j])->tag == line->tag)) { (activeplats[j])->oldstatus = (activeplats[j])->status; (activeplats[j])->status = in_stasis; (activeplats[j])->thinker.function = NULL; } } void P_AddActivePlat(plat_t * plat) { int i; for (i = 0; i < MAXPLATS; i++) if (activeplats[i] == NULL) { activeplats[i] = plat; return; } I_Error("P_AddActivePlat: no more plats!"); } void P_RemoveActivePlat(plat_t * plat) { int i; for (i = 0; i < MAXPLATS; i++) if (plat == activeplats[i]) { (activeplats[i])->sector->specialdata = NULL; P_RemoveThinker(&(activeplats[i])->thinker); activeplats[i] = NULL; return; } I_Error("P_RemoveActivePlat: can't find plat!"); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_pspr.c000066400000000000000000001546671257432200600232110ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_pspr.c #include "doomdef.h" #include "i_system.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" // Macros #define LOWERSPEED FRACUNIT*6 #define RAISESPEED FRACUNIT*6 #define WEAPONBOTTOM 128*FRACUNIT #define WEAPONTOP 32*FRACUNIT #define FLAME_THROWER_TICS 10*35 #define MAGIC_JUNK 1234 #define MAX_MACE_SPOTS 8 static int MaceSpotCount; static struct { fixed_t x; fixed_t y; } MaceSpots[MAX_MACE_SPOTS]; fixed_t bulletslope; static int WeaponAmmoUsePL1[NUMWEAPONS] = { 0, // staff USE_GWND_AMMO_1, // gold wand USE_CBOW_AMMO_1, // crossbow USE_BLSR_AMMO_1, // blaster USE_SKRD_AMMO_1, // skull rod USE_PHRD_AMMO_1, // phoenix rod USE_MACE_AMMO_1, // mace 0, // gauntlets 0 // beak }; static int WeaponAmmoUsePL2[NUMWEAPONS] = { 0, // staff USE_GWND_AMMO_2, // gold wand USE_CBOW_AMMO_2, // crossbow USE_BLSR_AMMO_2, // blaster USE_SKRD_AMMO_2, // skull rod USE_PHRD_AMMO_2, // phoenix rod USE_MACE_AMMO_2, // mace 0, // gauntlets 0 // beak }; weaponinfo_t wpnlev1info[NUMWEAPONS] = { { // Staff am_noammo, // ammo S_STAFFUP, // upstate S_STAFFDOWN, // downstate S_STAFFREADY, // readystate S_STAFFATK1_1, // atkstate S_STAFFATK1_1, // holdatkstate S_NULL // flashstate }, { // Gold wand am_goldwand, // ammo S_GOLDWANDUP, // upstate S_GOLDWANDDOWN, // downstate S_GOLDWANDREADY, // readystate S_GOLDWANDATK1_1, // atkstate S_GOLDWANDATK1_1, // holdatkstate S_NULL // flashstate }, { // Crossbow am_crossbow, // ammo S_CRBOWUP, // upstate S_CRBOWDOWN, // downstate S_CRBOW1, // readystate S_CRBOWATK1_1, // atkstate S_CRBOWATK1_1, // holdatkstate S_NULL // flashstate }, { // Blaster am_blaster, // ammo S_BLASTERUP, // upstate S_BLASTERDOWN, // downstate S_BLASTERREADY, // readystate S_BLASTERATK1_1, // atkstate S_BLASTERATK1_3, // holdatkstate S_NULL // flashstate }, { // Skull rod am_skullrod, // ammo S_HORNRODUP, // upstate S_HORNRODDOWN, // downstate S_HORNRODREADY, // readystae S_HORNRODATK1_1, // atkstate S_HORNRODATK1_1, // holdatkstate S_NULL // flashstate }, { // Phoenix rod am_phoenixrod, // ammo S_PHOENIXUP, // upstate S_PHOENIXDOWN, // downstate S_PHOENIXREADY, // readystate S_PHOENIXATK1_1, // atkstate S_PHOENIXATK1_1, // holdatkstate S_NULL // flashstate }, { // Mace am_mace, // ammo S_MACEUP, // upstate S_MACEDOWN, // downstate S_MACEREADY, // readystate S_MACEATK1_1, // atkstate S_MACEATK1_2, // holdatkstate S_NULL // flashstate }, { // Gauntlets am_noammo, // ammo S_GAUNTLETUP, // upstate S_GAUNTLETDOWN, // downstate S_GAUNTLETREADY, // readystate S_GAUNTLETATK1_1, // atkstate S_GAUNTLETATK1_3, // holdatkstate S_NULL // flashstate }, { // Beak am_noammo, // ammo S_BEAKUP, // upstate S_BEAKDOWN, // downstate S_BEAKREADY, // readystate S_BEAKATK1_1, // atkstate S_BEAKATK1_1, // holdatkstate S_NULL // flashstate } }; weaponinfo_t wpnlev2info[NUMWEAPONS] = { { // Staff am_noammo, // ammo S_STAFFUP2, // upstate S_STAFFDOWN2, // downstate S_STAFFREADY2_1, // readystate S_STAFFATK2_1, // atkstate S_STAFFATK2_1, // holdatkstate S_NULL // flashstate }, { // Gold wand am_goldwand, // ammo S_GOLDWANDUP, // upstate S_GOLDWANDDOWN, // downstate S_GOLDWANDREADY, // readystate S_GOLDWANDATK2_1, // atkstate S_GOLDWANDATK2_1, // holdatkstate S_NULL // flashstate }, { // Crossbow am_crossbow, // ammo S_CRBOWUP, // upstate S_CRBOWDOWN, // downstate S_CRBOW1, // readystate S_CRBOWATK2_1, // atkstate S_CRBOWATK2_1, // holdatkstate S_NULL // flashstate }, { // Blaster am_blaster, // ammo S_BLASTERUP, // upstate S_BLASTERDOWN, // downstate S_BLASTERREADY, // readystate S_BLASTERATK2_1, // atkstate S_BLASTERATK2_3, // holdatkstate S_NULL // flashstate }, { // Skull rod am_skullrod, // ammo S_HORNRODUP, // upstate S_HORNRODDOWN, // downstate S_HORNRODREADY, // readystae S_HORNRODATK2_1, // atkstate S_HORNRODATK2_1, // holdatkstate S_NULL // flashstate }, { // Phoenix rod am_phoenixrod, // ammo S_PHOENIXUP, // upstate S_PHOENIXDOWN, // downstate S_PHOENIXREADY, // readystate S_PHOENIXATK2_1, // atkstate S_PHOENIXATK2_2, // holdatkstate S_NULL // flashstate }, { // Mace am_mace, // ammo S_MACEUP, // upstate S_MACEDOWN, // downstate S_MACEREADY, // readystate S_MACEATK2_1, // atkstate S_MACEATK2_1, // holdatkstate S_NULL // flashstate }, { // Gauntlets am_noammo, // ammo S_GAUNTLETUP2, // upstate S_GAUNTLETDOWN2, // downstate S_GAUNTLETREADY2_1, // readystate S_GAUNTLETATK2_1, // atkstate S_GAUNTLETATK2_3, // holdatkstate S_NULL // flashstate }, { // Beak am_noammo, // ammo S_BEAKUP, // upstate S_BEAKDOWN, // downstate S_BEAKREADY, // readystate S_BEAKATK2_1, // atkstate S_BEAKATK2_1, // holdatkstate S_NULL // flashstate } }; //--------------------------------------------------------------------------- // // PROC P_OpenWeapons // // Called at level load before things are loaded. // //--------------------------------------------------------------------------- void P_OpenWeapons(void) { MaceSpotCount = 0; } //--------------------------------------------------------------------------- // // PROC P_AddMaceSpot // //--------------------------------------------------------------------------- void P_AddMaceSpot(mapthing_t * mthing) { if (MaceSpotCount == MAX_MACE_SPOTS) { I_Error("Too many mace spots."); } MaceSpots[MaceSpotCount].x = mthing->x << FRACBITS; MaceSpots[MaceSpotCount].y = mthing->y << FRACBITS; MaceSpotCount++; } //--------------------------------------------------------------------------- // // PROC P_RepositionMace // // Chooses the next spot to place the mace. // //--------------------------------------------------------------------------- void P_RepositionMace(mobj_t * mo) { int spot; subsector_t *ss; P_UnsetThingPosition(mo); spot = P_Random() % MaceSpotCount; mo->x = MaceSpots[spot].x; mo->y = MaceSpots[spot].y; ss = R_PointInSubsector(mo->x, mo->y); mo->z = mo->floorz = ss->sector->floorheight; mo->ceilingz = ss->sector->ceilingheight; P_SetThingPosition(mo); } //--------------------------------------------------------------------------- // // PROC P_CloseWeapons // // Called at level load after things are loaded. // //--------------------------------------------------------------------------- void P_CloseWeapons(void) { int spot; if (!MaceSpotCount) { // No maces placed return; } if (!deathmatch && P_Random() < 64) { // Sometimes doesn't show up if not in deathmatch return; } spot = P_Random() % MaceSpotCount; P_SpawnMobj(MaceSpots[spot].x, MaceSpots[spot].y, ONFLOORZ, MT_WMACE); } //--------------------------------------------------------------------------- // // PROC P_SetPsprite // //--------------------------------------------------------------------------- void P_SetPsprite(player_t * player, int position, statenum_t stnum) { pspdef_t *psp; state_t *state; psp = &player->psprites[position]; do { if (!stnum) { // Object removed itself. psp->state = NULL; break; } state = &states[stnum]; psp->state = state; psp->tics = state->tics; // could be 0 if (state->misc1) { // Set coordinates. psp->sx = state->misc1 << FRACBITS; psp->sy = state->misc2 << FRACBITS; } if (state->action) { // Call action routine. state->action(player, psp); if (!psp->state) { break; } } stnum = psp->state->nextstate; } while (!psp->tics); // An initial state of 0 could cycle through. } /* ================= = = P_CalcSwing = ================= */ /* fixed_t swingx, swingy; void P_CalcSwing (player_t *player) { fixed_t swing; int angle; // OPTIMIZE: tablify this swing = player->bob; angle = (FINEANGLES/70*leveltime)&FINEMASK; swingx = FixedMul ( swing, finesine[angle]); angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK; swingy = -FixedMul ( swingx, finesine[angle]); } */ //--------------------------------------------------------------------------- // // PROC P_ActivateBeak // //--------------------------------------------------------------------------- void P_ActivateBeak(player_t * player) { player->pendingweapon = wp_nochange; player->readyweapon = wp_beak; player->psprites[ps_weapon].sy = WEAPONTOP; P_SetPsprite(player, ps_weapon, S_BEAKREADY); } //--------------------------------------------------------------------------- // // PROC P_PostChickenWeapon // //--------------------------------------------------------------------------- void P_PostChickenWeapon(player_t * player, weapontype_t weapon) { if (weapon == wp_beak) { // Should never happen weapon = wp_staff; } player->pendingweapon = wp_nochange; player->readyweapon = weapon; player->psprites[ps_weapon].sy = WEAPONBOTTOM; P_SetPsprite(player, ps_weapon, wpnlev1info[weapon].upstate); } //--------------------------------------------------------------------------- // // PROC P_BringUpWeapon // // Starts bringing the pending weapon up from the bottom of the screen. // //--------------------------------------------------------------------------- void P_BringUpWeapon(player_t * player) { statenum_t new; if (player->pendingweapon == wp_nochange) { player->pendingweapon = player->readyweapon; } if (player->pendingweapon == wp_gauntlets) { S_StartSound(player->mo, sfx_gntact); } if (player->powers[pw_weaponlevel2]) { new = wpnlev2info[player->pendingweapon].upstate; } else { new = wpnlev1info[player->pendingweapon].upstate; } player->pendingweapon = wp_nochange; player->psprites[ps_weapon].sy = WEAPONBOTTOM; P_SetPsprite(player, ps_weapon, new); } //--------------------------------------------------------------------------- // // FUNC P_CheckAmmo // // Returns true if there is enough ammo to shoot. If not, selects the // next weapon to use. // //--------------------------------------------------------------------------- boolean P_CheckAmmo(player_t * player) { ammotype_t ammo; int *ammoUse; int count; ammo = wpnlev1info[player->readyweapon].ammo; if (player->powers[pw_weaponlevel2] && !deathmatch) { ammoUse = WeaponAmmoUsePL2; } else { ammoUse = WeaponAmmoUsePL1; } count = ammoUse[player->readyweapon]; if (ammo == am_noammo || player->ammo[ammo] >= count) { return (true); } // out of ammo, pick a weapon to change to do { if (player->weaponowned[wp_skullrod] && player->ammo[am_skullrod] > ammoUse[wp_skullrod]) { player->pendingweapon = wp_skullrod; } else if (player->weaponowned[wp_blaster] && player->ammo[am_blaster] > ammoUse[wp_blaster]) { player->pendingweapon = wp_blaster; } else if (player->weaponowned[wp_crossbow] && player->ammo[am_crossbow] > ammoUse[wp_crossbow]) { player->pendingweapon = wp_crossbow; } else if (player->weaponowned[wp_mace] && player->ammo[am_mace] > ammoUse[wp_mace]) { player->pendingweapon = wp_mace; } else if (player->ammo[am_goldwand] > ammoUse[wp_goldwand]) { player->pendingweapon = wp_goldwand; } else if (player->weaponowned[wp_gauntlets]) { player->pendingweapon = wp_gauntlets; } else if (player->weaponowned[wp_phoenixrod] && player->ammo[am_phoenixrod] > ammoUse[wp_phoenixrod]) { player->pendingweapon = wp_phoenixrod; } else { player->pendingweapon = wp_staff; } } while (player->pendingweapon == wp_nochange); if (player->powers[pw_weaponlevel2]) { P_SetPsprite(player, ps_weapon, wpnlev2info[player->readyweapon].downstate); } else { P_SetPsprite(player, ps_weapon, wpnlev1info[player->readyweapon].downstate); } return (false); } //--------------------------------------------------------------------------- // // PROC P_FireWeapon // //--------------------------------------------------------------------------- void P_FireWeapon(player_t * player) { weaponinfo_t *wpinfo; statenum_t attackState; if (!P_CheckAmmo(player)) { return; } P_SetMobjState(player->mo, S_PLAY_ATK2); wpinfo = player->powers[pw_weaponlevel2] ? &wpnlev2info[0] : &wpnlev1info[0]; attackState = player->refire ? wpinfo[player->readyweapon].holdatkstate : wpinfo[player->readyweapon].atkstate; P_SetPsprite(player, ps_weapon, attackState); P_NoiseAlert(player->mo, player->mo); if (player->readyweapon == wp_gauntlets && !player->refire) { // Play the sound for the initial gauntlet attack S_StartSound(player->mo, sfx_gntuse); } } //--------------------------------------------------------------------------- // // PROC P_DropWeapon // // The player died, so put the weapon away. // //--------------------------------------------------------------------------- void P_DropWeapon(player_t * player) { if (player->powers[pw_weaponlevel2]) { P_SetPsprite(player, ps_weapon, wpnlev2info[player->readyweapon].downstate); } else { P_SetPsprite(player, ps_weapon, wpnlev1info[player->readyweapon].downstate); } } //--------------------------------------------------------------------------- // // PROC A_WeaponReady // // The player can fire the weapon or change to another weapon at this time. // //--------------------------------------------------------------------------- void A_WeaponReady(player_t * player, pspdef_t * psp) { int angle; if (player->chickenTics) { // Change to the chicken beak P_ActivateBeak(player); return; } // Change player from attack state if (player->mo->state == &states[S_PLAY_ATK1] || player->mo->state == &states[S_PLAY_ATK2]) { P_SetMobjState(player->mo, S_PLAY); } // Check for staff PL2 active sound if ((player->readyweapon == wp_staff) && (psp->state == &states[S_STAFFREADY2_1]) && P_Random() < 128) { S_StartSound(player->mo, sfx_stfcrk); } // Put the weapon away if the player has a pending weapon or has // died. if (player->pendingweapon != wp_nochange || !player->health) { if (player->powers[pw_weaponlevel2]) { P_SetPsprite(player, ps_weapon, wpnlev2info[player->readyweapon].downstate); } else { P_SetPsprite(player, ps_weapon, wpnlev1info[player->readyweapon].downstate); } return; } // Check for fire. The phoenix rod does not auto fire. if (player->cmd.buttons & BT_ATTACK) { if (!player->attackdown || (player->readyweapon != wp_phoenixrod)) { player->attackdown = true; P_FireWeapon(player); return; } } else { player->attackdown = false; } // Bob the weapon based on movement speed. angle = (128 * leveltime) & FINEMASK; psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]); angle &= FINEANGLES / 2 - 1; psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); } //--------------------------------------------------------------------------- // // PROC P_UpdateBeak // //--------------------------------------------------------------------------- void P_UpdateBeak(player_t * player, pspdef_t * psp) { psp->sy = WEAPONTOP + (player->chickenPeck << (FRACBITS - 1)); } //--------------------------------------------------------------------------- // // PROC A_BeakReady // //--------------------------------------------------------------------------- void A_BeakReady(player_t * player, pspdef_t * psp) { if (player->cmd.buttons & BT_ATTACK) { // Chicken beak attack player->attackdown = true; P_SetMobjState(player->mo, S_CHICPLAY_ATK1); if (player->powers[pw_weaponlevel2]) { P_SetPsprite(player, ps_weapon, S_BEAKATK2_1); } else { P_SetPsprite(player, ps_weapon, S_BEAKATK1_1); } P_NoiseAlert(player->mo, player->mo); } else { if (player->mo->state == &states[S_CHICPLAY_ATK1]) { // Take out of attack state P_SetMobjState(player->mo, S_CHICPLAY); } player->attackdown = false; } } //--------------------------------------------------------------------------- // // PROC A_ReFire // // The player can re fire the weapon without lowering it entirely. // //--------------------------------------------------------------------------- void A_ReFire(player_t * player, pspdef_t * psp) { if ((player->cmd.buttons & BT_ATTACK) && player->pendingweapon == wp_nochange && player->health) { player->refire++; P_FireWeapon(player); } else { player->refire = 0; P_CheckAmmo(player); } } //--------------------------------------------------------------------------- // // PROC A_Lower // //--------------------------------------------------------------------------- void A_Lower(player_t * player, pspdef_t * psp) { if (player->chickenTics) { psp->sy = WEAPONBOTTOM; } else { psp->sy += LOWERSPEED; } if (psp->sy < WEAPONBOTTOM) { // Not lowered all the way yet return; } if (player->playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon psp->sy = WEAPONBOTTOM; return; } if (!player->health) { // Player is dead, so keep the weapon off screen P_SetPsprite(player, ps_weapon, S_NULL); return; } player->readyweapon = player->pendingweapon; P_BringUpWeapon(player); } //--------------------------------------------------------------------------- // // PROC A_BeakRaise // //--------------------------------------------------------------------------- void A_BeakRaise(player_t * player, pspdef_t * psp) { psp->sy = WEAPONTOP; P_SetPsprite(player, ps_weapon, wpnlev1info[player->readyweapon].readystate); } //--------------------------------------------------------------------------- // // PROC A_Raise // //--------------------------------------------------------------------------- void A_Raise(player_t * player, pspdef_t * psp) { psp->sy -= RAISESPEED; if (psp->sy > WEAPONTOP) { // Not raised all the way yet return; } psp->sy = WEAPONTOP; if (player->powers[pw_weaponlevel2]) { P_SetPsprite(player, ps_weapon, wpnlev2info[player->readyweapon].readystate); } else { P_SetPsprite(player, ps_weapon, wpnlev1info[player->readyweapon].readystate); } } /* =============== = = P_BulletSlope = = Sets a slope so a near miss is at aproximately the height of the = intended target = =============== */ void P_BulletSlope(mobj_t * mo) { angle_t an; // // see which target is to be aimed at // an = mo->angle; bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT); if (!linetarget) { an += 1 << 26; bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT); if (!linetarget) { an -= 2 << 26; bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT); } if (!linetarget) { an += 2 << 26; bulletslope = (mo->player->lookdir << FRACBITS) / 173; } } } //**************************************************************************** // // WEAPON ATTACKS // //**************************************************************************** //---------------------------------------------------------------------------- // // PROC A_BeakAttackPL1 // //---------------------------------------------------------------------------- void A_BeakAttackPL1(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; damage = 1 + (P_Random() & 3); angle = player->mo->angle; slope = P_AimLineAttack(player->mo, angle, MELEERANGE); PuffType = MT_BEAKPUFF; P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); if (linetarget) { player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); } S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3)); player->chickenPeck = 12; psp->tics -= P_Random() & 7; } //---------------------------------------------------------------------------- // // PROC A_BeakAttackPL2 // //---------------------------------------------------------------------------- void A_BeakAttackPL2(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; damage = HITDICE(4); angle = player->mo->angle; slope = P_AimLineAttack(player->mo, angle, MELEERANGE); PuffType = MT_BEAKPUFF; P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); if (linetarget) { player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); } S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3)); player->chickenPeck = 12; psp->tics -= P_Random() & 3; } //---------------------------------------------------------------------------- // // PROC A_StaffAttackPL1 // //---------------------------------------------------------------------------- void A_StaffAttackPL1(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; damage = 5 + (P_Random() & 15); angle = player->mo->angle; angle += (P_Random() - P_Random()) << 18; slope = P_AimLineAttack(player->mo, angle, MELEERANGE); PuffType = MT_STAFFPUFF; P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); if (linetarget) { //S_StartSound(player->mo, sfx_stfhit); // turn to face target player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); } } //---------------------------------------------------------------------------- // // PROC A_StaffAttackPL2 // //---------------------------------------------------------------------------- void A_StaffAttackPL2(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; // P_inter.c:P_DamageMobj() handles target momentums damage = 18 + (P_Random() & 63); angle = player->mo->angle; angle += (P_Random() - P_Random()) << 18; slope = P_AimLineAttack(player->mo, angle, MELEERANGE); PuffType = MT_STAFFPUFF2; P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); if (linetarget) { //S_StartSound(player->mo, sfx_stfpow); // turn to face target player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); } } //---------------------------------------------------------------------------- // // PROC A_FireBlasterPL1 // //---------------------------------------------------------------------------- void A_FireBlasterPL1(player_t * player, pspdef_t * psp) { mobj_t *mo; angle_t angle; int damage; mo = player->mo; S_StartSound(mo, sfx_gldhit); player->ammo[am_blaster] -= USE_BLSR_AMMO_1; P_BulletSlope(mo); damage = HITDICE(4); angle = mo->angle; if (player->refire) { angle += (P_Random() - P_Random()) << 18; } PuffType = MT_BLASTERPUFF1; P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); S_StartSound(player->mo, sfx_blssht); } //---------------------------------------------------------------------------- // // PROC A_FireBlasterPL2 // //---------------------------------------------------------------------------- void A_FireBlasterPL2(player_t * player, pspdef_t * psp) { mobj_t *mo; player->ammo[am_blaster] -= deathmatch ? USE_BLSR_AMMO_1 : USE_BLSR_AMMO_2; mo = P_SpawnPlayerMissile(player->mo, MT_BLASTERFX1); if (mo) { mo->thinker.function = P_BlasterMobjThinker; } S_StartSound(player->mo, sfx_blssht); } //---------------------------------------------------------------------------- // // PROC A_FireGoldWandPL1 // //---------------------------------------------------------------------------- void A_FireGoldWandPL1(player_t * player, pspdef_t * psp) { mobj_t *mo; angle_t angle; int damage; mo = player->mo; player->ammo[am_goldwand] -= USE_GWND_AMMO_1; P_BulletSlope(mo); damage = 7 + (P_Random() & 7); angle = mo->angle; if (player->refire) { angle += (P_Random() - P_Random()) << 18; } PuffType = MT_GOLDWANDPUFF1; P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); S_StartSound(player->mo, sfx_gldhit); } //---------------------------------------------------------------------------- // // PROC A_FireGoldWandPL2 // //---------------------------------------------------------------------------- void A_FireGoldWandPL2(player_t * player, pspdef_t * psp) { int i; mobj_t *mo; angle_t angle; int damage; fixed_t momz; mo = player->mo; player->ammo[am_goldwand] -= deathmatch ? USE_GWND_AMMO_1 : USE_GWND_AMMO_2; PuffType = MT_GOLDWANDPUFF2; P_BulletSlope(mo); momz = FixedMul(mobjinfo[MT_GOLDWANDFX2].speed, bulletslope); P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle - (ANG45 / 8), momz); P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle + (ANG45 / 8), momz); angle = mo->angle - (ANG45 / 8); for (i = 0; i < 5; i++) { damage = 1 + (P_Random() & 7); P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); angle += ((ANG45 / 8) * 2) / 4; } S_StartSound(player->mo, sfx_gldhit); } //---------------------------------------------------------------------------- // // PROC A_FireMacePL1B // //---------------------------------------------------------------------------- void A_FireMacePL1B(player_t * player, pspdef_t * psp) { mobj_t *pmo; mobj_t *ball; angle_t angle; if (player->ammo[am_mace] < USE_MACE_AMMO_1) { return; } player->ammo[am_mace] -= USE_MACE_AMMO_1; pmo = player->mo; // Vanilla bug here: // Original code here looks like: // (pmo->flags2 & MF2_FEETARECLIPPED != 0) // C's operator precedence interprets this as: // (pmo->flags2 & (MF2_FEETARECLIPPED != 0)) // Which simplifies to: // (pmo->flags2 & 1) ball = P_SpawnMobj(pmo->x, pmo->y, pmo->z + 28 * FRACUNIT - FOOTCLIPSIZE * (pmo->flags2 & 1), MT_MACEFX2); ball->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5)); angle = pmo->angle; ball->target = pmo; ball->angle = angle; ball->z += (player->lookdir) << (FRACBITS - 4); angle >>= ANGLETOFINESHIFT; ball->momx = (pmo->momx >> 1) + FixedMul(ball->info->speed, finecosine[angle]); ball->momy = (pmo->momy >> 1) + FixedMul(ball->info->speed, finesine[angle]); S_StartSound(ball, sfx_lobsht); P_CheckMissileSpawn(ball); } //---------------------------------------------------------------------------- // // PROC A_FireMacePL1 // //---------------------------------------------------------------------------- void A_FireMacePL1(player_t * player, pspdef_t * psp) { mobj_t *ball; if (P_Random() < 28) { A_FireMacePL1B(player, psp); return; } if (player->ammo[am_mace] < USE_MACE_AMMO_1) { return; } player->ammo[am_mace] -= USE_MACE_AMMO_1; psp->sx = ((P_Random() & 3) - 2) * FRACUNIT; psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT; ball = P_SPMAngle(player->mo, MT_MACEFX1, player->mo->angle + (((P_Random() & 7) - 4) << 24)); if (ball) { ball->special1.i = 16; // tics till dropoff } } //---------------------------------------------------------------------------- // // PROC A_MacePL1Check // //---------------------------------------------------------------------------- void A_MacePL1Check(mobj_t * ball) { angle_t angle; if (ball->special1.i == 0) { return; } ball->special1.i -= 4; if (ball->special1.i > 0) { return; } ball->special1.i = 0; ball->flags2 |= MF2_LOGRAV; angle = ball->angle >> ANGLETOFINESHIFT; ball->momx = FixedMul(7 * FRACUNIT, finecosine[angle]); ball->momy = FixedMul(7 * FRACUNIT, finesine[angle]); ball->momz -= ball->momz >> 1; } //---------------------------------------------------------------------------- // // PROC A_MaceBallImpact // //---------------------------------------------------------------------------- void A_MaceBallImpact(mobj_t * ball) { if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID)) { // Landed in some sort of liquid P_RemoveMobj(ball); return; } if ((ball->health != MAGIC_JUNK) && (ball->z <= ball->floorz) && ball->momz) { // Bounce ball->health = MAGIC_JUNK; ball->momz = (ball->momz * 192) >> 8; ball->flags2 &= ~MF2_FLOORBOUNCE; P_SetMobjState(ball, ball->info->spawnstate); S_StartSound(ball, sfx_bounce); } else { // Explode ball->flags |= MF_NOGRAVITY; ball->flags2 &= ~MF2_LOGRAV; S_StartSound(ball, sfx_lobhit); } } //---------------------------------------------------------------------------- // // PROC A_MaceBallImpact2 // //---------------------------------------------------------------------------- void A_MaceBallImpact2(mobj_t * ball) { mobj_t *tiny; angle_t angle; if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID)) { // Landed in some sort of liquid P_RemoveMobj(ball); return; } if ((ball->z != ball->floorz) || (ball->momz < 2 * FRACUNIT)) { // Explode ball->momx = ball->momy = ball->momz = 0; ball->flags |= MF_NOGRAVITY; ball->flags2 &= ~(MF2_LOGRAV | MF2_FLOORBOUNCE); } else { // Bounce ball->momz = (ball->momz * 192) >> 8; P_SetMobjState(ball, ball->info->spawnstate); tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3); angle = ball->angle + ANG90; tiny->target = ball->target; tiny->angle = angle; angle >>= ANGLETOFINESHIFT; tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT, finecosine[angle]); tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT, finesine[angle]); tiny->momz = ball->momz; P_CheckMissileSpawn(tiny); tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3); angle = ball->angle - ANG90; tiny->target = ball->target; tiny->angle = angle; angle >>= ANGLETOFINESHIFT; tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT, finecosine[angle]); tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT, finesine[angle]); tiny->momz = ball->momz; P_CheckMissileSpawn(tiny); } } //---------------------------------------------------------------------------- // // PROC A_FireMacePL2 // //---------------------------------------------------------------------------- void A_FireMacePL2(player_t * player, pspdef_t * psp) { mobj_t *mo; player->ammo[am_mace] -= deathmatch ? USE_MACE_AMMO_1 : USE_MACE_AMMO_2; mo = P_SpawnPlayerMissile(player->mo, MT_MACEFX4); if (mo) { mo->momx += player->mo->momx; mo->momy += player->mo->momy; mo->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5)); if (linetarget) { mo->special1.m = linetarget; } } S_StartSound(player->mo, sfx_lobsht); } //---------------------------------------------------------------------------- // // PROC A_DeathBallImpact // //---------------------------------------------------------------------------- void A_DeathBallImpact(mobj_t * ball) { int i; mobj_t *target; angle_t angle; boolean newAngle; if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID)) { // Landed in some sort of liquid P_RemoveMobj(ball); return; } if ((ball->z <= ball->floorz) && ball->momz) { // Bounce newAngle = false; target = (mobj_t *) ball->special1.m; if (target) { if (!(target->flags & MF_SHOOTABLE)) { // Target died ball->special1.m = NULL; } else { // Seek angle = R_PointToAngle2(ball->x, ball->y, target->x, target->y); newAngle = true; } } else { // Find new target angle = 0; for (i = 0; i < 16; i++) { P_AimLineAttack(ball, angle, 10 * 64 * FRACUNIT); if (linetarget && ball->target != linetarget) { ball->special1.m = linetarget; angle = R_PointToAngle2(ball->x, ball->y, linetarget->x, linetarget->y); newAngle = true; break; } angle += ANG45 / 2; } } if (newAngle) { ball->angle = angle; angle >>= ANGLETOFINESHIFT; ball->momx = FixedMul(ball->info->speed, finecosine[angle]); ball->momy = FixedMul(ball->info->speed, finesine[angle]); } P_SetMobjState(ball, ball->info->spawnstate); S_StartSound(ball, sfx_pstop); } else { // Explode ball->flags |= MF_NOGRAVITY; ball->flags2 &= ~MF2_LOGRAV; S_StartSound(ball, sfx_phohit); } } //---------------------------------------------------------------------------- // // PROC A_SpawnRippers // //---------------------------------------------------------------------------- void A_SpawnRippers(mobj_t * actor) { unsigned int i; angle_t angle; mobj_t *ripper; for (i = 0; i < 8; i++) { ripper = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RIPPER); angle = i * ANG45; ripper->target = actor->target; ripper->angle = angle; angle >>= ANGLETOFINESHIFT; ripper->momx = FixedMul(ripper->info->speed, finecosine[angle]); ripper->momy = FixedMul(ripper->info->speed, finesine[angle]); P_CheckMissileSpawn(ripper); } } //---------------------------------------------------------------------------- // // PROC A_FireCrossbowPL1 // //---------------------------------------------------------------------------- void A_FireCrossbowPL1(player_t * player, pspdef_t * psp) { mobj_t *pmo; pmo = player->mo; player->ammo[am_crossbow] -= USE_CBOW_AMMO_1; P_SpawnPlayerMissile(pmo, MT_CRBOWFX1); P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 10)); P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 10)); } //---------------------------------------------------------------------------- // // PROC A_FireCrossbowPL2 // //---------------------------------------------------------------------------- void A_FireCrossbowPL2(player_t * player, pspdef_t * psp) { mobj_t *pmo; pmo = player->mo; player->ammo[am_crossbow] -= deathmatch ? USE_CBOW_AMMO_1 : USE_CBOW_AMMO_2; P_SpawnPlayerMissile(pmo, MT_CRBOWFX2); P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle - (ANG45 / 10)); P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle + (ANG45 / 10)); P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 5)); P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 5)); } //---------------------------------------------------------------------------- // // PROC A_BoltSpark // //---------------------------------------------------------------------------- void A_BoltSpark(mobj_t * bolt) { mobj_t *spark; if (P_Random() > 50) { spark = P_SpawnMobj(bolt->x, bolt->y, bolt->z, MT_CRBOWFX4); spark->x += (P_Random() - P_Random()) << 10; spark->y += (P_Random() - P_Random()) << 10; } } //---------------------------------------------------------------------------- // // PROC A_FireSkullRodPL1 // //---------------------------------------------------------------------------- void A_FireSkullRodPL1(player_t * player, pspdef_t * psp) { mobj_t *mo; if (player->ammo[am_skullrod] < USE_SKRD_AMMO_1) { return; } player->ammo[am_skullrod] -= USE_SKRD_AMMO_1; mo = P_SpawnPlayerMissile(player->mo, MT_HORNRODFX1); // Randomize the first frame if (mo && P_Random() > 128) { P_SetMobjState(mo, S_HRODFX1_2); } } //---------------------------------------------------------------------------- // // PROC A_FireSkullRodPL2 // // The special2 field holds the player number that shot the rain missile. // The special1 field is used for the seeking routines, then as a counter // for the sound looping. // //---------------------------------------------------------------------------- void A_FireSkullRodPL2(player_t * player, pspdef_t * psp) { player->ammo[am_skullrod] -= deathmatch ? USE_SKRD_AMMO_1 : USE_SKRD_AMMO_2; P_SpawnPlayerMissile(player->mo, MT_HORNRODFX2); // Use MissileMobj instead of the return value from // P_SpawnPlayerMissile because we need to give info to the mobj // even if it exploded immediately. if (netgame) { // Multi-player game MissileMobj->special2.i = P_GetPlayerNum(player); } else { // Always use red missiles in single player games MissileMobj->special2.i = 2; } if (linetarget) { MissileMobj->special1.m = linetarget; } S_StartSound(MissileMobj, sfx_hrnpow); } //---------------------------------------------------------------------------- // // PROC A_SkullRodPL2Seek // //---------------------------------------------------------------------------- void A_SkullRodPL2Seek(mobj_t * actor) { P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 30); } //---------------------------------------------------------------------------- // // PROC A_AddPlayerRain // //---------------------------------------------------------------------------- void A_AddPlayerRain(mobj_t * actor) { int playerNum; player_t *player; playerNum = netgame ? actor->special2.i : 0; if (!playeringame[playerNum]) { // Player left the game return; } player = &players[playerNum]; if (player->health <= 0) { // Player is dead return; } if (player->rain1 && player->rain2) { // Terminate an active rain if (player->rain1->health < player->rain2->health) { if (player->rain1->health > 16) { player->rain1->health = 16; } player->rain1 = NULL; } else { if (player->rain2->health > 16) { player->rain2->health = 16; } player->rain2 = NULL; } } // Add rain mobj to list if (player->rain1) { player->rain2 = actor; } else { player->rain1 = actor; } } //---------------------------------------------------------------------------- // // PROC A_SkullRodStorm // //---------------------------------------------------------------------------- void A_SkullRodStorm(mobj_t * actor) { fixed_t x; fixed_t y; mobj_t *mo; int playerNum; player_t *player; if (actor->health-- == 0) { P_SetMobjState(actor, S_NULL); playerNum = netgame ? actor->special2.i : 0; if (!playeringame[playerNum]) { // Player left the game return; } player = &players[playerNum]; if (player->health <= 0) { // Player is dead return; } if (player->rain1 == actor) { player->rain1 = NULL; } else if (player->rain2 == actor) { player->rain2 = NULL; } return; } if (P_Random() < 25) { // Fudge rain frequency return; } x = actor->x + ((P_Random() & 127) - 64) * FRACUNIT; y = actor->y + ((P_Random() & 127) - 64) * FRACUNIT; mo = P_SpawnMobj(x, y, ONCEILINGZ, MT_RAINPLR1 + actor->special2.i); mo->target = actor->target; mo->momx = 1; // Force collision detection mo->momz = -mo->info->speed; mo->special2.i = actor->special2.i; // Transfer player number P_CheckMissileSpawn(mo); if (!(actor->special1.i & 31)) { S_StartSound(actor, sfx_ramrain); } actor->special1.i++; } //---------------------------------------------------------------------------- // // PROC A_RainImpact // //---------------------------------------------------------------------------- void A_RainImpact(mobj_t * actor) { if (actor->z > actor->floorz) { P_SetMobjState(actor, S_RAINAIRXPLR1_1 + actor->special2.i); } else if (P_Random() < 40) { P_HitFloor(actor); } } //---------------------------------------------------------------------------- // // PROC A_HideInCeiling // //---------------------------------------------------------------------------- void A_HideInCeiling(mobj_t * actor) { actor->z = actor->ceilingz + 4 * FRACUNIT; } //---------------------------------------------------------------------------- // // PROC A_FirePhoenixPL1 // //---------------------------------------------------------------------------- void A_FirePhoenixPL1(player_t * player, pspdef_t * psp) { angle_t angle; player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_1; P_SpawnPlayerMissile(player->mo, MT_PHOENIXFX1); //P_SpawnPlayerMissile(player->mo, MT_MNTRFX2); angle = player->mo->angle + ANG180; angle >>= ANGLETOFINESHIFT; player->mo->momx += FixedMul(4 * FRACUNIT, finecosine[angle]); player->mo->momy += FixedMul(4 * FRACUNIT, finesine[angle]); } //---------------------------------------------------------------------------- // // PROC A_PhoenixPuff // //---------------------------------------------------------------------------- void A_PhoenixPuff(mobj_t * actor) { mobj_t *puff; angle_t angle; P_SeekerMissile(actor, ANG1_X * 5, ANG1_X * 10); puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF); angle = actor->angle + ANG90; angle >>= ANGLETOFINESHIFT; puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]); puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]); puff->momz = 0; puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF); angle = actor->angle - ANG90; angle >>= ANGLETOFINESHIFT; puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]); puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]); puff->momz = 0; } // // This function was present in the Heretic 1.0 executable for the // removed "secondary phoenix flash" object (MT_PHOENIXFX_REMOVED). // The purpose of this object is unknown, as is this function. // void A_RemovedPhoenixFunc(mobj_t *actor) { I_Error("Action function invoked for removed Phoenix action!"); } //---------------------------------------------------------------------------- // // PROC A_InitPhoenixPL2 // //---------------------------------------------------------------------------- void A_InitPhoenixPL2(player_t * player, pspdef_t * psp) { player->flamecount = FLAME_THROWER_TICS; } //---------------------------------------------------------------------------- // // PROC A_FirePhoenixPL2 // // Flame thrower effect. // //---------------------------------------------------------------------------- void A_FirePhoenixPL2(player_t * player, pspdef_t * psp) { mobj_t *mo; mobj_t *pmo; angle_t angle; fixed_t x, y, z; fixed_t slope; if (--player->flamecount == 0) { // Out of flame P_SetPsprite(player, ps_weapon, S_PHOENIXATK2_4); player->refire = 0; return; } pmo = player->mo; angle = pmo->angle; x = pmo->x + ((P_Random() - P_Random()) << 9); y = pmo->y + ((P_Random() - P_Random()) << 9); z = pmo->z + 26 * FRACUNIT + ((player->lookdir) << FRACBITS) / 173; if (pmo->flags2 & MF2_FEETARECLIPPED) { z -= FOOTCLIPSIZE; } slope = ((player->lookdir) << FRACBITS) / 173 + (FRACUNIT / 10); mo = P_SpawnMobj(x, y, z, MT_PHOENIXFX2); mo->target = pmo; mo->angle = angle; mo->momx = pmo->momx + FixedMul(mo->info->speed, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = pmo->momy + FixedMul(mo->info->speed, finesine[angle >> ANGLETOFINESHIFT]); mo->momz = FixedMul(mo->info->speed, slope); if (!player->refire || !(leveltime % 38)) { S_StartSound(player->mo, sfx_phopow); } P_CheckMissileSpawn(mo); } //---------------------------------------------------------------------------- // // PROC A_ShutdownPhoenixPL2 // //---------------------------------------------------------------------------- void A_ShutdownPhoenixPL2(player_t * player, pspdef_t * psp) { player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2; } //---------------------------------------------------------------------------- // // PROC A_FlameEnd // //---------------------------------------------------------------------------- void A_FlameEnd(mobj_t * actor) { actor->momz += (fixed_t)(1.5 * FRACUNIT); } //---------------------------------------------------------------------------- // // PROC A_FloatPuff // //---------------------------------------------------------------------------- void A_FloatPuff(mobj_t * puff) { puff->momz += (fixed_t)(1.8 * FRACUNIT); } //--------------------------------------------------------------------------- // // PROC A_GauntletAttack // //--------------------------------------------------------------------------- void A_GauntletAttack(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; int randVal; fixed_t dist; psp->sx = ((P_Random() & 3) - 2) * FRACUNIT; psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT; angle = player->mo->angle; if (player->powers[pw_weaponlevel2]) { damage = HITDICE(2); dist = 4 * MELEERANGE; angle += (P_Random() - P_Random()) << 17; PuffType = MT_GAUNTLETPUFF2; } else { damage = HITDICE(2); dist = MELEERANGE + 1; angle += (P_Random() - P_Random()) << 18; PuffType = MT_GAUNTLETPUFF1; } slope = P_AimLineAttack(player->mo, angle, dist); P_LineAttack(player->mo, angle, dist, slope, damage); if (!linetarget) { if (P_Random() > 64) { player->extralight = !player->extralight; } S_StartSound(player->mo, sfx_gntful); return; } randVal = P_Random(); if (randVal < 64) { player->extralight = 0; } else if (randVal < 160) { player->extralight = 1; } else { player->extralight = 2; } if (player->powers[pw_weaponlevel2]) { P_GiveBody(player, damage >> 1); S_StartSound(player->mo, sfx_gntpow); } else { S_StartSound(player->mo, sfx_gnthit); } // turn to face target angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); if (angle - player->mo->angle > ANG180) { if (angle - player->mo->angle < -ANG90 / 20) player->mo->angle = angle + ANG90 / 21; else player->mo->angle -= ANG90 / 20; } else { if (angle - player->mo->angle > ANG90 / 20) player->mo->angle = angle - ANG90 / 21; else player->mo->angle += ANG90 / 20; } player->mo->flags |= MF_JUSTATTACKED; } void A_Light0(player_t * player, pspdef_t * psp) { player->extralight = 0; } void A_Light1(player_t * player, pspdef_t * psp) { player->extralight = 1; } void A_Light2(player_t * player, pspdef_t * psp) { player->extralight = 2; } //------------------------------------------------------------------------ // // PROC P_SetupPsprites // // Called at start of level for each player // //------------------------------------------------------------------------ void P_SetupPsprites(player_t * player) { int i; // Remove all psprites for (i = 0; i < NUMPSPRITES; i++) { player->psprites[i].state = NULL; } // Spawn the ready weapon player->pendingweapon = player->readyweapon; P_BringUpWeapon(player); } //------------------------------------------------------------------------ // // PROC P_MovePsprites // // Called every tic by player thinking routine // //------------------------------------------------------------------------ void P_MovePsprites(player_t * player) { int i; pspdef_t *psp; state_t *state; psp = &player->psprites[0]; for (i = 0; i < NUMPSPRITES; i++, psp++) { if ((state = psp->state) != 0) // a null state means not active { // drop tic count and possibly change state if (psp->tics != -1) // a -1 tic count never changes { psp->tics--; if (!psp->tics) { P_SetPsprite(player, i, psp->state->nextstate); } } } } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_saveg.c000066400000000000000000001163231257432200600233150ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_tick.c #include #include "doomdef.h" #include "i_swap.h" #include "i_system.h" #include "m_misc.h" #include "p_local.h" #include "v_video.h" #define SVG_RAM 0 #define SVG_FILE 1 static FILE *SaveGameFP; static int SaveGameType; static byte *savebuffer, *save_p; //========================================================================== // // SV_Filename // // Generate the filename to use for a particular savegame slot. // Returns a malloc()'d buffer that must be freed by the caller. // //========================================================================== char *SV_Filename(int slot) { char *filename; size_t filename_len; filename_len = strlen(savegamedir) + strlen(SAVEGAMENAME) + 8; filename = malloc(filename_len); M_snprintf(filename, filename_len, "%s" SAVEGAMENAME "%d.hsg", savegamedir, slot); return filename; } //========================================================================== // // SV_Open // //========================================================================== void SV_Open(char *fileName) { SaveGameType = SVG_FILE; SaveGameFP = fopen(fileName, "wb"); } void SV_OpenRead(char *filename) { SaveGameType = SVG_FILE; SaveGameFP = fopen(filename, "rb"); } //========================================================================== // // SV_Close // //========================================================================== void SV_Close(char *fileName) { int length; SV_WriteByte(SAVE_GAME_TERMINATOR); if (SaveGameType == SVG_RAM) { length = save_p - savebuffer; if (length > SAVEGAMESIZE) { I_Error("Savegame buffer overrun"); } M_WriteFile(fileName, savebuffer, length); Z_Free(savebuffer); } else { // SVG_FILE fclose(SaveGameFP); } } //========================================================================== // // SV_Write // //========================================================================== void SV_Write(void *buffer, int size) { if (SaveGameType == SVG_RAM) { memcpy(save_p, buffer, size); save_p += size; } else { // SVG_FILE fwrite(buffer, size, 1, SaveGameFP); } } void SV_WriteByte(byte val) { SV_Write(&val, sizeof(byte)); } void SV_WriteWord(unsigned short val) { val = SHORT(val); SV_Write(&val, sizeof(unsigned short)); } void SV_WriteLong(unsigned int val) { val = LONG(val); SV_Write(&val, sizeof(int)); } void SV_WritePtr(void *ptr) { long val = (long) ptr; SV_WriteLong(val & 0xffffffff); } //========================================================================== // // SV_Read // //========================================================================== void SV_Read(void *buffer, int size) { if (SaveGameType == SVG_RAM) { memcpy(buffer, save_p, size); save_p += size; } else { // SVG_FILE fread(buffer, size, 1, SaveGameFP); } } byte SV_ReadByte(void) { byte result; SV_Read(&result, sizeof(byte)); return result; } uint16_t SV_ReadWord(void) { uint16_t result; SV_Read(&result, sizeof(unsigned short)); return SHORT(result); } uint32_t SV_ReadLong(void) { uint32_t result; SV_Read(&result, sizeof(int)); return LONG(result); } // // ticcmd_t // static void saveg_read_ticcmd_t(ticcmd_t *str) { // char forwardmove; str->forwardmove = SV_ReadByte(); // char sidemove; str->sidemove = SV_ReadByte(); // short angleturn; str->angleturn = SV_ReadWord(); // short consistancy; str->consistancy = SV_ReadWord(); // byte chatchar; str->chatchar = SV_ReadByte(); // byte buttons; str->buttons = SV_ReadByte(); // byte lookfly; str->lookfly = SV_ReadByte(); // byte arti; str->arti = SV_ReadByte(); } static void saveg_write_ticcmd_t(ticcmd_t *str) { // char forwardmove; SV_WriteByte(str->forwardmove); // char sidemove; SV_WriteByte(str->sidemove); // short angleturn; SV_WriteWord(str->angleturn); // short consistancy; SV_WriteWord(str->consistancy); // byte chatchar; SV_WriteByte(str->chatchar); // byte buttons; SV_WriteByte(str->buttons); // byte lookfly; SV_WriteByte(str->lookfly); // byte arti; SV_WriteByte(str->arti); } // // inventory_t // static void saveg_read_inventory_t(inventory_t *str) { // int type; str->type = SV_ReadLong(); // int count; str->count = SV_ReadLong(); } static void saveg_write_inventory_t(inventory_t *str) { // int type; SV_WriteLong(str->type); // int count; SV_WriteLong(str->count); } // // state_t * // static void saveg_read_state_ptr(state_t **state) { int statenum; statenum = SV_ReadLong(); // We have read a state number, but it is indexed according to the state // table in Vanilla Heretic v1.3. To support v1.0 HHE patches we have // three extra states, so map the state number to our internal state // number. if (statenum >= S_PHOENIXFXIX_1) { statenum = (statenum - S_PHOENIXFXIX_1) + S_PHOENIXPUFF1; } if (statenum == 0) { *state = NULL; } else { *state = &states[statenum]; } } static void saveg_write_state_ptr(state_t *state) { int statenum; // NULL states are just written as zero. if (state == NULL) { SV_WriteLong(0); return; } statenum = state - states; // Our internal state table has three extra states than Vanilla, so map // to the state numbers used by Vanilla Heretic v1.3 for savegame // compatibility. if (statenum >= S_PHOENIXPUFF1) { statenum = (statenum - S_PHOENIXPUFF1) + S_PHOENIXFXIX_1; } else if (statenum >= S_PHOENIXFXIX_1) { // Now we're really in trouble. This state doesn't exist in Vanilla // Heretic v1.3 (but does in v1.0). Map to a frame that might be // vaguely sensible. statenum = S_PHOENIXFXI1_8; } SV_WriteLong(statenum); } // // pspdef_t // static void saveg_read_pspdef_t(pspdef_t *str) { // state_t *state; saveg_read_state_ptr(&str->state); // int tics; str->tics = SV_ReadLong(); // fixed_t sx, sy; str->sx = SV_ReadLong(); str->sy = SV_ReadLong(); } static void saveg_write_pspdef_t(pspdef_t *str) { // state_t *state; saveg_write_state_ptr(str->state); // int tics; SV_WriteLong(str->tics); // fixed_t sx, sy; SV_WriteLong(str->sx); SV_WriteLong(str->sy); } // // player_t // static void saveg_read_player_t(player_t *str) { int i; // mobj_t *mo; SV_ReadLong(); str->mo = NULL; // playerstate_t playerstate; str->playerstate = SV_ReadLong(); // ticcmd_t cmd; saveg_read_ticcmd_t(&str->cmd); // fixed_t viewz; str->viewz = SV_ReadLong(); // fixed_t viewheight; str->viewheight = SV_ReadLong(); // fixed_t deltaviewheight; str->deltaviewheight = SV_ReadLong(); // fixed_t bob; str->bob = SV_ReadLong(); // int flyheight; str->flyheight = SV_ReadLong(); // int lookdir; str->lookdir = SV_ReadLong(); // boolean centering; str->centering = SV_ReadLong(); // int health; str->health = SV_ReadLong(); // int armorpoints, armortype; str->armorpoints = SV_ReadLong(); str->armortype = SV_ReadLong(); // inventory_t inventory[NUMINVENTORYSLOTS]; for (i=0; iinventory[i]); } // artitype_t readyArtifact; str->readyArtifact = SV_ReadLong(); // int artifactCount; str->artifactCount = SV_ReadLong(); // int inventorySlotNum; str->inventorySlotNum = SV_ReadLong(); // int powers[NUMPOWERS]; for (i=0; ipowers[i] = SV_ReadLong(); } // boolean keys[NUMKEYS]; for (i=0; ikeys[i] = SV_ReadLong(); } // boolean backpack; str->backpack = SV_ReadLong(); // signed int frags[MAXPLAYERS]; for (i=0; ifrags[i] = SV_ReadLong(); } // weapontype_t readyweapon; str->readyweapon = SV_ReadLong(); // weapontype_t pendingweapon; str->pendingweapon = SV_ReadLong(); // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i] = SV_ReadLong(); } // int ammo[NUMAMMO]; for (i=0; iammo[i] = SV_ReadLong(); } // int maxammo[NUMAMMO]; for (i=0; imaxammo[i] = SV_ReadLong(); } // int attackdown, usedown; str->attackdown = SV_ReadLong(); str->usedown = SV_ReadLong(); // int cheats; str->cheats = SV_ReadLong(); // int refire; str->refire = SV_ReadLong(); // int killcount, itemcount, secretcount; str->killcount = SV_ReadLong(); str->itemcount = SV_ReadLong(); str->secretcount = SV_ReadLong(); // char *message; SV_ReadLong(); str->message = NULL; // int messageTics; str->messageTics = SV_ReadLong(); // int damagecount, bonuscount; str->damagecount = SV_ReadLong(); str->bonuscount = SV_ReadLong(); // int flamecount; str->flamecount = SV_ReadLong(); // mobj_t *attacker; SV_ReadLong(); str->attacker = NULL; // int extralight; str->extralight = SV_ReadLong(); // int fixedcolormap; str->fixedcolormap = SV_ReadLong(); // int colormap; str->colormap = SV_ReadLong(); // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // boolean didsecret; str->didsecret = SV_ReadLong(); // int chickenTics; str->chickenTics = SV_ReadLong(); // int chickenPeck; str->chickenPeck = SV_ReadLong(); // mobj_t *rain1; SV_ReadLong(); str->rain1 = NULL; // mobj_t *rain2; SV_ReadLong(); str->rain2 = NULL; } static void saveg_write_player_t(player_t *str) { int i; // mobj_t *mo; // pointer will be trashed, but it gets restored on load as // the player number reference is stored in the mo. SV_WritePtr(str->mo); // playerstate_t playerstate; SV_WriteLong(str->playerstate); // ticcmd_t cmd; saveg_write_ticcmd_t(&str->cmd); // fixed_t viewz; SV_WriteLong(str->viewz); // fixed_t viewheight; SV_WriteLong(str->viewheight); // fixed_t deltaviewheight; SV_WriteLong(str->deltaviewheight); // fixed_t bob; SV_WriteLong(str->bob); // int flyheight; SV_WriteLong(str->flyheight); // int lookdir; SV_WriteLong(str->lookdir); // boolean centering; SV_WriteLong(str->centering); // int health; SV_WriteLong(str->health); // int armorpoints, armortype; SV_WriteLong(str->armorpoints); SV_WriteLong(str->armortype); // inventory_t inventory[NUMINVENTORYSLOTS]; for (i=0; iinventory[i]); } // artitype_t readyArtifact; SV_WriteLong(str->readyArtifact); // int artifactCount; SV_WriteLong(str->artifactCount); // int inventorySlotNum; SV_WriteLong(str->inventorySlotNum); // int powers[NUMPOWERS]; for (i=0; ipowers[i]); } // boolean keys[NUMKEYS]; for (i=0; ikeys[i]); } // boolean backpack; SV_WriteLong(str->backpack); // signed int frags[MAXPLAYERS]; for (i=0; ifrags[i]); } // weapontype_t readyweapon; SV_WriteLong(str->readyweapon); // weapontype_t pendingweapon; SV_WriteLong(str->pendingweapon); // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i]); } // int ammo[NUMAMMO]; for (i=0; iammo[i]); } // int maxammo[NUMAMMO]; for (i=0; imaxammo[i]); } // int attackdown, usedown; SV_WriteLong(str->attackdown); SV_WriteLong(str->usedown); // int cheats; SV_WriteLong(str->cheats); // int refire; SV_WriteLong(str->refire); // int killcount, itemcount, secretcount; SV_WriteLong(str->killcount); SV_WriteLong(str->itemcount); SV_WriteLong(str->secretcount); // char *message; SV_WritePtr(str->message); // int messageTics; SV_WriteLong(str->messageTics); // int damagecount, bonuscount; SV_WriteLong(str->damagecount); SV_WriteLong(str->bonuscount); // int flamecount; SV_WriteLong(str->flamecount); // mobj_t *attacker; SV_WritePtr(str->attacker); // int extralight; SV_WriteLong(str->extralight); // int fixedcolormap; SV_WriteLong(str->fixedcolormap); // int colormap; SV_WriteLong(str->colormap); // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // boolean didsecret; SV_WriteLong(str->didsecret); // int chickenTics; SV_WriteLong(str->chickenTics); // int chickenPeck; SV_WriteLong(str->chickenPeck); // mobj_t *rain1; SV_WritePtr(str->rain1); // mobj_t *rain2; SV_WritePtr(str->rain2); } // // mapthing_t // static void saveg_read_mapthing_t(mapthing_t *str) { // short x, y; str->x = SV_ReadWord(); str->y = SV_ReadWord(); // short angle; str->angle = SV_ReadWord(); // short type; str->type = SV_ReadWord(); // short options; str->options = SV_ReadWord(); } static void saveg_write_mapthing_t(mapthing_t *str) { // short x, y; SV_WriteWord(str->x); SV_WriteWord(str->y); // short angle; SV_WriteWord(str->angle); // short type; SV_WriteWord(str->type); // short options; SV_WriteWord(str->options); } // // thinker_t // static void saveg_read_thinker_t(thinker_t *str) { // struct thinker_s *prev, *next; SV_ReadLong(); str->prev = NULL; SV_ReadLong(); str->next = NULL; // think_t function; SV_ReadLong(); str->function = NULL; } static void saveg_write_thinker_t(thinker_t *str) { // struct thinker_s *prev, *next; SV_WritePtr(str->prev); SV_WritePtr(str->next); // think_t function; SV_WritePtr(str->function); } // // specialval_t // static void saveg_read_specialval_t(specialval_t *str) { // This can also be a mobj_t ptr, but we just assume it's // an int. This is probably a really bad assumption that's // likely to end in tears. // int i; str->i = SV_ReadLong(); } static void saveg_write_specialval_t(specialval_t *str) { // int i; SV_WriteLong(str->i); } // // mobj_t // static void saveg_read_mobj_t(mobj_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // fixed_t x, y, z; str->x = SV_ReadLong(); str->y = SV_ReadLong(); str->z = SV_ReadLong(); // struct mobj_s *snext, *sprev; SV_ReadLong(); str->snext = NULL; SV_ReadLong(); str->sprev = NULL; // angle_t angle; str->angle = SV_ReadLong(); // spritenum_t sprite; str->sprite = SV_ReadLong(); // int frame; str->frame = SV_ReadLong(); // struct mobj_s *bnext, *bprev; SV_ReadLong(); str->bnext = NULL; SV_ReadLong(); str->bprev = NULL; // struct subsector_s *subsector; SV_ReadLong(); str->subsector = NULL; // fixed_t floorz, ceilingz; str->floorz = SV_ReadLong(); str->ceilingz = SV_ReadLong(); // fixed_t radius, height; str->radius = SV_ReadLong(); str->height = SV_ReadLong(); // fixed_t momx, momy, momz; str->momx = SV_ReadLong(); str->momy = SV_ReadLong(); str->momz = SV_ReadLong(); // int validcount; str->validcount = SV_ReadLong(); // mobjtype_t type; str->type = SV_ReadLong(); // An extra thing type was added for v1.0 HHE compatibility. // Map from the v1.3 thing type index to the internal one. if (str->type >= MT_PHOENIXFX_REMOVED) { ++str->type; } // mobjinfo_t *info; SV_ReadLong(); str->info = NULL; // int tics; str->tics = SV_ReadLong(); // state_t *state; saveg_read_state_ptr(&str->state); // int damage; str->damage = SV_ReadLong(); // int flags; str->flags = SV_ReadLong(); // int flags2; str->flags2 = SV_ReadLong(); // specialval_t special1; saveg_read_specialval_t(&str->special1); // specialval_t special2; saveg_read_specialval_t(&str->special2); // Now we have a bunch of hacks to try to NULL out special values // where special[12] contained a mobj_t pointer that isn't valid // any more. This isn't in Vanilla but at least it stops the game // from crashing. switch (str->type) { // Gas pods use special2.m to point to the pod generator // that made it. case MT_POD: str->special2.m = NULL; break; // Several thing types use special1.m to mean 'target': case MT_MACEFX4: // A_DeathBallImpact case MT_WHIRLWIND: // A_WhirlwindSeek case MT_MUMMYFX1: // A_MummyFX1Seek case MT_HORNRODFX2: // A_SkullRodPL2Seek case MT_PHOENIXFX1: // A_PhoenixPuff str->special1.m = NULL; break; default: break; } // int health; str->health = SV_ReadLong(); // int movedir; str->movedir = SV_ReadLong(); // int movecount; str->movecount = SV_ReadLong(); // struct mobj_s *target; SV_ReadLong(); str->target = NULL; // int reactiontime; str->reactiontime = SV_ReadLong(); // int threshold; str->threshold = SV_ReadLong(); // struct player_s *player; i = SV_ReadLong(); if (i != 0) { str->player = &players[i - 1]; str->player->mo = str; } else { str->player = NULL; } // int lastlook; str->lastlook = SV_ReadLong(); // mapthing_t spawnpoint; saveg_read_mapthing_t(&str->spawnpoint); } static void saveg_write_mobj_t(mobj_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // fixed_t x, y, z; SV_WriteLong(str->x); SV_WriteLong(str->y); SV_WriteLong(str->z); // struct mobj_s *snext, *sprev; SV_WritePtr(str->snext); SV_WritePtr(str->sprev); // angle_t angle; SV_WriteLong(str->angle); // spritenum_t sprite; SV_WriteLong(str->sprite); // int frame; SV_WriteLong(str->frame); // struct mobj_s *bnext, *bprev; SV_WritePtr(str->bnext); SV_WritePtr(str->bprev); // struct subsector_s *subsector; SV_WritePtr(str->subsector); // fixed_t floorz, ceilingz; SV_WriteLong(str->floorz); SV_WriteLong(str->ceilingz); // fixed_t radius, height; SV_WriteLong(str->radius); SV_WriteLong(str->height); // fixed_t momx, momy, momz; SV_WriteLong(str->momx); SV_WriteLong(str->momy); SV_WriteLong(str->momz); // int validcount; SV_WriteLong(str->validcount); // mobjtype_t type; // Our mobjinfo table has an extra entry, for compatibility with v1.0 // HHE patches. So translate the internal thing type index to the // equivalent for Vanilla Heretic v1.3, for savegame compatibility. if (str->type > MT_PHOENIXFX_REMOVED) { SV_WriteLong(str->type - 1); } else if (str->type == MT_PHOENIXFX_REMOVED) { // This should never happen, but just in case, do something // vaguely sensible ... ? SV_WriteLong(MT_PHOENIXFX1); } else { SV_WriteLong(str->type); } // mobjinfo_t *info; SV_WritePtr(str->info); // int tics; SV_WriteLong(str->tics); // state_t *state; saveg_write_state_ptr(str->state); // int damage; SV_WriteLong(str->damage); // int flags; SV_WriteLong(str->flags); // int flags2; SV_WriteLong(str->flags2); // specialval_t special1; saveg_write_specialval_t(&str->special1); // specialval_t special2; saveg_write_specialval_t(&str->special2); // int health; SV_WriteLong(str->health); // int movedir; SV_WriteLong(str->movedir); // int movecount; SV_WriteLong(str->movecount); // struct mobj_s *target; SV_WritePtr(str->target); // int reactiontime; SV_WriteLong(str->reactiontime); // int threshold; SV_WriteLong(str->threshold); // struct player_s *player; if (str->player != NULL) { SV_WriteLong(str->player - players + 1); } else { SV_WriteLong(0); } // int lastlook; SV_WriteLong(str->lastlook); // mapthing_t spawnpoint; saveg_write_mapthing_t(&str->spawnpoint); } // // ceiling_t // static void saveg_read_ceiling_t(ceiling_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // ceiling_e type; str->type = SV_ReadLong(); // sector_t *sector; i = SV_ReadLong(); str->sector = §ors[i]; // fixed_t bottomheight, topheight; str->bottomheight = SV_ReadLong(); str->topheight = SV_ReadLong(); // fixed_t speed; str->speed = SV_ReadLong(); // boolean crush; str->crush = SV_ReadLong(); // int direction; str->direction = SV_ReadLong(); // int tag; str->tag = SV_ReadLong(); // int olddirection; str->olddirection = SV_ReadLong(); } static void saveg_write_ceiling_t(ceiling_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // ceiling_e type; SV_WriteLong(str->type); // sector_t *sector; SV_WriteLong(str->sector - sectors); // fixed_t bottomheight, topheight; SV_WriteLong(str->bottomheight); SV_WriteLong(str->topheight); // fixed_t speed; SV_WriteLong(str->speed); // boolean crush; SV_WriteLong(str->crush); // int direction; SV_WriteLong(str->direction); // int tag; SV_WriteLong(str->tag); // int olddirection; SV_WriteLong(str->olddirection); } // // vldoor_t // static void saveg_read_vldoor_t(vldoor_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // vldoor_e type; str->type = SV_ReadLong(); // sector_t *sector; i = SV_ReadLong(); str->sector = §ors[i]; // fixed_t topheight; str->topheight = SV_ReadLong(); // fixed_t speed; str->speed = SV_ReadLong(); // int direction; str->direction = SV_ReadLong(); // int topwait; str->topwait = SV_ReadLong(); // int topcountdown; str->topcountdown = SV_ReadLong(); } static void saveg_write_vldoor_t(vldoor_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // vldoor_e type; SV_WriteLong(str->type); // sector_t *sector; SV_WriteLong(str->sector - sectors); // fixed_t topheight; SV_WriteLong(str->topheight); // fixed_t speed; SV_WriteLong(str->speed); // int direction; SV_WriteLong(str->direction); // int topwait; SV_WriteLong(str->topwait); // int topcountdown; SV_WriteLong(str->topcountdown); } // // floormove_t // static void saveg_read_floormove_t(floormove_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // floor_e type; str->type = SV_ReadLong(); // boolean crush; str->crush = SV_ReadLong(); // sector_t *sector; i = SV_ReadLong(); str->sector = §ors[i]; // int direction; str->direction = SV_ReadLong(); // int newspecial; str->newspecial = SV_ReadLong(); // short texture; str->texture = SV_ReadWord(); // fixed_t floordestheight; str->floordestheight = SV_ReadLong(); // fixed_t speed; str->speed = SV_ReadLong(); } static void saveg_write_floormove_t(floormove_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // floor_e type; SV_WriteLong(str->type); // boolean crush; SV_WriteLong(str->crush); // sector_t *sector; SV_WriteLong(str->sector - sectors); // int direction; SV_WriteLong(str->direction); // int newspecial; SV_WriteLong(str->newspecial); // short texture; SV_WriteWord(str->texture); // fixed_t floordestheight; SV_WriteLong(str->floordestheight); // fixed_t speed; SV_WriteLong(str->speed); } // // plat_t // static void saveg_read_plat_t(plat_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t *sector; i = SV_ReadLong(); str->sector = §ors[i]; // fixed_t speed; str->speed = SV_ReadLong(); // fixed_t low; str->low = SV_ReadLong(); // fixed_t high; str->high = SV_ReadLong(); // int wait; str->wait = SV_ReadLong(); // int count; str->count = SV_ReadLong(); // plat_e status; str->status = SV_ReadLong(); // plat_e oldstatus; str->oldstatus = SV_ReadLong(); // boolean crush; str->crush = SV_ReadLong(); // int tag; str->tag = SV_ReadLong(); // plattype_e type; str->type = SV_ReadLong(); } static void saveg_write_plat_t(plat_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t *sector; SV_WriteLong(str->sector - sectors); // fixed_t speed; SV_WriteLong(str->speed); // fixed_t low; SV_WriteLong(str->low); // fixed_t high; SV_WriteLong(str->high); // int wait; SV_WriteLong(str->wait); // int count; SV_WriteLong(str->count); // plat_e status; SV_WriteLong(str->status); // plat_e oldstatus; SV_WriteLong(str->oldstatus); // boolean crush; SV_WriteLong(str->crush); // int tag; SV_WriteLong(str->tag); // plattype_e type; SV_WriteLong(str->type); } // // lightflash_t // static void saveg_read_lightflash_t(lightflash_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t *sector; i = SV_ReadLong(); str->sector = §ors[i]; // int count; str->count = SV_ReadLong(); // int maxlight; str->maxlight = SV_ReadLong(); // int minlight; str->minlight = SV_ReadLong(); // int maxtime; str->maxtime = SV_ReadLong(); // int mintime; str->mintime = SV_ReadLong(); } static void saveg_write_lightflash_t(lightflash_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t *sector; SV_WriteLong(str->sector - sectors); // int count; SV_WriteLong(str->count); // int maxlight; SV_WriteLong(str->maxlight); // int minlight; SV_WriteLong(str->minlight); // int maxtime; SV_WriteLong(str->maxtime); // int mintime; SV_WriteLong(str->mintime); } // // strobe_t // static void saveg_read_strobe_t(strobe_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t *sector; i = SV_ReadLong(); str->sector = §ors[i]; // int count; str->count = SV_ReadLong(); // int minlight; str->minlight = SV_ReadLong(); // int maxlight; str->maxlight = SV_ReadLong(); // int darktime; str->darktime = SV_ReadLong(); // int brighttime; str->brighttime = SV_ReadLong(); } static void saveg_write_strobe_t(strobe_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t *sector; SV_WriteLong(str->sector - sectors); // int count; SV_WriteLong(str->count); // int minlight; SV_WriteLong(str->minlight); // int maxlight; SV_WriteLong(str->maxlight); // int darktime; SV_WriteLong(str->darktime); // int brighttime; SV_WriteLong(str->brighttime); } // // glow_t // static void saveg_read_glow_t(glow_t *str) { int i; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t *sector; i = SV_ReadLong(); str->sector = §ors[i]; // int minlight; str->minlight = SV_ReadLong(); // int maxlight; str->maxlight = SV_ReadLong(); // int direction; str->direction = SV_ReadLong(); } static void saveg_write_glow_t(glow_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t *sector; SV_WriteLong(str->sector - sectors); // int minlight; SV_WriteLong(str->minlight); // int maxlight; SV_WriteLong(str->maxlight); // int direction; SV_WriteLong(str->direction); } /* ==================== = = P_ArchivePlayers = ==================== */ void P_ArchivePlayers(void) { int i; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) { continue; } saveg_write_player_t(&players[i]); } } /* ==================== = = P_UnArchivePlayers = ==================== */ void P_UnArchivePlayers(void) { int i; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; saveg_read_player_t(&players[i]); players[i].mo = NULL; // will be set when unarc thinker players[i].message = NULL; players[i].attacker = NULL; } } //============================================================================= /* ==================== = = P_ArchiveWorld = ==================== */ void P_ArchiveWorld(void) { int i, j; sector_t *sec; line_t *li; side_t *si; // Sectors for (i = 0, sec = sectors; i < numsectors; i++, sec++) { SV_WriteWord(sec->floorheight >> FRACBITS); SV_WriteWord(sec->ceilingheight >> FRACBITS); SV_WriteWord(sec->floorpic); SV_WriteWord(sec->ceilingpic); SV_WriteWord(sec->lightlevel); SV_WriteWord(sec->special); // needed? SV_WriteWord(sec->tag); // needed? } // Lines for (i = 0, li = lines; i < numlines; i++, li++) { SV_WriteWord(li->flags); SV_WriteWord(li->special); SV_WriteWord(li->tag); for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) { continue; } si = &sides[li->sidenum[j]]; SV_WriteWord(si->textureoffset >> FRACBITS); SV_WriteWord(si->rowoffset >> FRACBITS); SV_WriteWord(si->toptexture); SV_WriteWord(si->bottomtexture); SV_WriteWord(si->midtexture); } } } /* ==================== = = P_UnArchiveWorld = ==================== */ void P_UnArchiveWorld(void) { int i, j; sector_t *sec; line_t *li; side_t *si; // // do sectors // for (i = 0, sec = sectors; i < numsectors; i++, sec++) { sec->floorheight = SV_ReadWord() << FRACBITS; sec->ceilingheight = SV_ReadWord() << FRACBITS; sec->floorpic = SV_ReadWord(); sec->ceilingpic = SV_ReadWord(); sec->lightlevel = SV_ReadWord(); sec->special = SV_ReadWord(); // needed? sec->tag = SV_ReadWord(); // needed? sec->specialdata = 0; sec->soundtarget = 0; } // // do lines // for (i = 0, li = lines; i < numlines; i++, li++) { li->flags = SV_ReadWord(); li->special = SV_ReadWord(); li->tag = SV_ReadWord(); for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; si->textureoffset = SV_ReadWord() << FRACBITS; si->rowoffset = SV_ReadWord() << FRACBITS; si->toptexture = SV_ReadWord(); si->bottomtexture = SV_ReadWord(); si->midtexture = SV_ReadWord(); } } } //============================================================================= typedef enum { tc_end, tc_mobj } thinkerclass_t; /* ==================== = = P_ArchiveThinkers = ==================== */ void P_ArchiveThinkers(void) { thinker_t *th; for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == P_MobjThinker) { SV_WriteByte(tc_mobj); saveg_write_mobj_t((mobj_t *) th); } //I_Error("P_ArchiveThinkers: Unknown thinker function"); } // Add a terminating marker SV_WriteByte(tc_end); } /* ==================== = = P_UnArchiveThinkers = ==================== */ void P_UnArchiveThinkers(void) { byte tclass; thinker_t *currentthinker, *next; mobj_t *mobj; // // remove all the current thinkers // currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { next = currentthinker->next; if (currentthinker->function == P_MobjThinker) P_RemoveMobj((mobj_t *) currentthinker); else Z_Free(currentthinker); currentthinker = next; } P_InitThinkers(); // read in saved thinkers while (1) { tclass = SV_ReadByte(); switch (tclass) { case tc_end: return; // end of list case tc_mobj: mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL); saveg_read_mobj_t(mobj); mobj->target = NULL; P_SetThingPosition(mobj); mobj->info = &mobjinfo[mobj->type]; mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; mobj->thinker.function = P_MobjThinker; P_AddThinker(&mobj->thinker); break; default: I_Error("Unknown tclass %i in savegame", tclass); } } } //============================================================================= /* ==================== = = P_ArchiveSpecials = ==================== */ enum { tc_ceiling, tc_door, tc_floor, tc_plat, tc_flash, tc_strobe, tc_glow, tc_endspecials } specials_e; void P_ArchiveSpecials(void) { /* T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list T_VerticalDoor, (vldoor_t: sector_t * swizzle), T_MoveFloor, (floormove_t: sector_t * swizzle), T_LightFlash, (lightflash_t: sector_t * swizzle), T_StrobeFlash, (strobe_t: sector_t *), T_Glow, (glow_t: sector_t *), T_PlatRaise, (plat_t: sector_t *), - active list */ thinker_t *th; for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == T_MoveCeiling) { SV_WriteByte(tc_ceiling); saveg_write_ceiling_t((ceiling_t *) th); } else if (th->function == T_VerticalDoor) { SV_WriteByte(tc_door); saveg_write_vldoor_t((vldoor_t *) th); } else if (th->function == T_MoveFloor) { SV_WriteByte(tc_floor); saveg_write_floormove_t((floormove_t *) th); } else if (th->function == T_PlatRaise) { SV_WriteByte(tc_plat); saveg_write_plat_t((plat_t *) th); } else if (th->function == T_LightFlash) { SV_WriteByte(tc_flash); saveg_write_lightflash_t((lightflash_t *) th); } else if (th->function == T_StrobeFlash) { SV_WriteByte(tc_strobe); saveg_write_strobe_t((strobe_t *) th); } else if (th->function == T_Glow) { SV_WriteByte(tc_glow); saveg_write_glow_t((glow_t *) th); } } // Add a terminating marker SV_WriteByte(tc_endspecials); } /* ==================== = = P_UnArchiveSpecials = ==================== */ void P_UnArchiveSpecials(void) { byte tclass; ceiling_t *ceiling; vldoor_t *door; floormove_t *floor; plat_t *plat; lightflash_t *flash; strobe_t *strobe; glow_t *glow; // read in saved thinkers while (1) { tclass = SV_ReadByte(); switch (tclass) { case tc_endspecials: return; // end of list case tc_ceiling: ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVEL, NULL); saveg_read_ceiling_t(ceiling); ceiling->sector->specialdata = T_MoveCeiling; // ??? ceiling->thinker.function = T_MoveCeiling; P_AddThinker(&ceiling->thinker); P_AddActiveCeiling(ceiling); break; case tc_door: door = Z_Malloc(sizeof(*door), PU_LEVEL, NULL); saveg_read_vldoor_t(door); door->sector->specialdata = door; door->thinker.function = T_VerticalDoor; P_AddThinker(&door->thinker); break; case tc_floor: floor = Z_Malloc(sizeof(*floor), PU_LEVEL, NULL); saveg_read_floormove_t(floor); floor->sector->specialdata = T_MoveFloor; floor->thinker.function = T_MoveFloor; P_AddThinker(&floor->thinker); break; case tc_plat: plat = Z_Malloc(sizeof(*plat), PU_LEVEL, NULL); saveg_read_plat_t(plat); plat->sector->specialdata = T_PlatRaise; // In the original Heretic code this was a conditional "fix" // of the thinker function, but the save code (above) decides // whether to save a T_PlatRaise based on thinker function // anyway, so it can't be NULL. Having the conditional causes // a bug, as our saveg_read_thinker_t sets these to NULL. // if (plat->thinker.function) plat->thinker.function = T_PlatRaise; P_AddThinker(&plat->thinker); P_AddActivePlat(plat); break; case tc_flash: flash = Z_Malloc(sizeof(*flash), PU_LEVEL, NULL); saveg_read_lightflash_t(flash); flash->thinker.function = T_LightFlash; P_AddThinker(&flash->thinker); break; case tc_strobe: strobe = Z_Malloc(sizeof(*strobe), PU_LEVEL, NULL); saveg_read_strobe_t(strobe); strobe->thinker.function = T_StrobeFlash; P_AddThinker(&strobe->thinker); break; case tc_glow: glow = Z_Malloc(sizeof(*glow), PU_LEVEL, NULL); saveg_read_glow_t(glow); glow->thinker.function = T_Glow; P_AddThinker(&glow->thinker); break; default: I_Error("P_UnarchiveSpecials:Unknown tclass %i " "in savegame", tclass); } } } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_setup.c000066400000000000000000000360111257432200600233430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_main.c #include #include #include "doomdef.h" #include "i_swap.h" #include "i_system.h" #include "m_argv.h" #include "m_bbox.h" #include "p_local.h" #include "s_sound.h" void P_SpawnMapThing(mapthing_t * mthing); int numvertexes; vertex_t *vertexes; int numsegs; seg_t *segs; int numsectors; sector_t *sectors; int numsubsectors; subsector_t *subsectors; int numnodes; node_t *nodes; int numlines; line_t *lines; int numsides; side_t *sides; short *blockmaplump; // offsets in blockmap are from here short *blockmap; int bmapwidth, bmapheight; // in mapblocks fixed_t bmaporgx, bmaporgy; // origin of block map mobj_t **blocklinks; // for thing chains byte *rejectmatrix; // for fast sight rejection mapthing_t deathmatchstarts[10], *deathmatch_p; mapthing_t playerstarts[MAXPLAYERS]; /* ================= = = P_LoadVertexes = ================= */ void P_LoadVertexes(int lump) { byte *data; int i; mapvertex_t *ml; vertex_t *li; numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t); vertexes = Z_Malloc(numvertexes * sizeof(vertex_t), PU_LEVEL, 0); data = W_CacheLumpNum(lump, PU_STATIC); ml = (mapvertex_t *) data; li = vertexes; for (i = 0; i < numvertexes; i++, li++, ml++) { li->x = SHORT(ml->x) << FRACBITS; li->y = SHORT(ml->y) << FRACBITS; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSegs = ================= */ void P_LoadSegs(int lump) { byte *data; int i; mapseg_t *ml; seg_t *li; line_t *ldef; int linedef, side; numsegs = W_LumpLength(lump) / sizeof(mapseg_t); segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0); memset(segs, 0, numsegs * sizeof(seg_t)); data = W_CacheLumpNum(lump, PU_STATIC); ml = (mapseg_t *) data; li = segs; for (i = 0; i < numsegs; i++, li++, ml++) { li->v1 = &vertexes[SHORT(ml->v1)]; li->v2 = &vertexes[SHORT(ml->v2)]; li->angle = (SHORT(ml->angle)) << 16; li->offset = (SHORT(ml->offset)) << 16; linedef = SHORT(ml->linedef); ldef = &lines[linedef]; li->linedef = ldef; side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; if (ldef->flags & ML_TWOSIDED) li->backsector = sides[ldef->sidenum[side ^ 1]].sector; else li->backsector = 0; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSubsectors = ================= */ void P_LoadSubsectors(int lump) { byte *data; int i; mapsubsector_t *ms; subsector_t *ss; numsubsectors = W_LumpLength(lump) / sizeof(mapsubsector_t); subsectors = Z_Malloc(numsubsectors * sizeof(subsector_t), PU_LEVEL, 0); data = W_CacheLumpNum(lump, PU_STATIC); ms = (mapsubsector_t *) data; memset(subsectors, 0, numsubsectors * sizeof(subsector_t)); ss = subsectors; for (i = 0; i < numsubsectors; i++, ss++, ms++) { ss->numlines = SHORT(ms->numsegs); ss->firstline = SHORT(ms->firstseg); } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSectors = ================= */ void P_LoadSectors(int lump) { byte *data; int i; mapsector_t *ms; sector_t *ss; numsectors = W_LumpLength(lump) / sizeof(mapsector_t); sectors = Z_Malloc(numsectors * sizeof(sector_t), PU_LEVEL, 0); memset(sectors, 0, numsectors * sizeof(sector_t)); data = W_CacheLumpNum(lump, PU_STATIC); ms = (mapsector_t *) data; ss = sectors; for (i = 0; i < numsectors; i++, ss++, ms++) { ss->floorheight = SHORT(ms->floorheight) << FRACBITS; ss->ceilingheight = SHORT(ms->ceilingheight) << FRACBITS; ss->floorpic = R_FlatNumForName(ms->floorpic); ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); ss->lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); ss->tag = SHORT(ms->tag); ss->thinglist = NULL; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadNodes = ================= */ void P_LoadNodes(int lump) { byte *data; int i, j, k; mapnode_t *mn; node_t *no; numnodes = W_LumpLength(lump) / sizeof(mapnode_t); nodes = Z_Malloc(numnodes * sizeof(node_t), PU_LEVEL, 0); data = W_CacheLumpNum(lump, PU_STATIC); mn = (mapnode_t *) data; no = nodes; for (i = 0; i < numnodes; i++, no++, mn++) { no->x = SHORT(mn->x) << FRACBITS; no->y = SHORT(mn->y) << FRACBITS; no->dx = SHORT(mn->dx) << FRACBITS; no->dy = SHORT(mn->dy) << FRACBITS; for (j = 0; j < 2; j++) { no->children[j] = SHORT(mn->children[j]); for (k = 0; k < 4; k++) no->bbox[j][k] = SHORT(mn->bbox[j][k]) << FRACBITS; } } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadThings = ================= */ void P_LoadThings(int lump) { byte *data; int i; mapthing_t spawnthing; mapthing_t *mt; int numthings; data = W_CacheLumpNum(lump, PU_STATIC); numthings = W_LumpLength(lump) / sizeof(mapthing_t); mt = (mapthing_t *) data; for (i = 0; i < numthings; i++, mt++) { spawnthing.x = SHORT(mt->x); spawnthing.y = SHORT(mt->y); spawnthing.angle = SHORT(mt->angle); spawnthing.type = SHORT(mt->type); spawnthing.options = SHORT(mt->options); P_SpawnMapThing(&spawnthing); } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadLineDefs = = Also counts secret lines for intermissions ================= */ void P_LoadLineDefs(int lump) { byte *data; int i; maplinedef_t *mld; line_t *ld; vertex_t *v1, *v2; numlines = W_LumpLength(lump) / sizeof(maplinedef_t); lines = Z_Malloc(numlines * sizeof(line_t), PU_LEVEL, 0); memset(lines, 0, numlines * sizeof(line_t)); data = W_CacheLumpNum(lump, PU_STATIC); mld = (maplinedef_t *) data; ld = lines; for (i = 0; i < numlines; i++, mld++, ld++) { ld->flags = SHORT(mld->flags); ld->special = SHORT(mld->special); ld->tag = SHORT(mld->tag); v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) ld->slopetype = ST_HORIZONTAL; else { if (FixedDiv(ld->dy, ld->dx) > 0) ld->slopetype = ST_POSITIVE; else ld->slopetype = ST_NEGATIVE; } if (v1->x < v2->x) { ld->bbox[BOXLEFT] = v1->x; ld->bbox[BOXRIGHT] = v2->x; } else { ld->bbox[BOXLEFT] = v2->x; ld->bbox[BOXRIGHT] = v1->x; } if (v1->y < v2->y) { ld->bbox[BOXBOTTOM] = v1->y; ld->bbox[BOXTOP] = v2->y; } else { ld->bbox[BOXBOTTOM] = v2->y; ld->bbox[BOXTOP] = v1->y; } ld->sidenum[0] = SHORT(mld->sidenum[0]); ld->sidenum[1] = SHORT(mld->sidenum[1]); if (ld->sidenum[0] != -1) ld->frontsector = sides[ld->sidenum[0]].sector; else ld->frontsector = 0; if (ld->sidenum[1] != -1) ld->backsector = sides[ld->sidenum[1]].sector; else ld->backsector = 0; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSideDefs = ================= */ void P_LoadSideDefs(int lump) { byte *data; int i; mapsidedef_t *msd; side_t *sd; numsides = W_LumpLength(lump) / sizeof(mapsidedef_t); sides = Z_Malloc(numsides * sizeof(side_t), PU_LEVEL, 0); memset(sides, 0, numsides * sizeof(side_t)); data = W_CacheLumpNum(lump, PU_STATIC); msd = (mapsidedef_t *) data; sd = sides; for (i = 0; i < numsides; i++, msd++, sd++) { sd->textureoffset = SHORT(msd->textureoffset) << FRACBITS; sd->rowoffset = SHORT(msd->rowoffset) << FRACBITS; sd->toptexture = R_TextureNumForName(msd->toptexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->sector = §ors[SHORT(msd->sector)]; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadBlockMap = ================= */ void P_LoadBlockMap(int lump) { int i, count; int lumplen; lumplen = W_LumpLength(lump); blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL); W_ReadLump(lump, blockmaplump); blockmap = blockmaplump + 4; // Swap all short integers to native byte ordering: count = lumplen / 2; for (i = 0; i < count; i++) blockmaplump[i] = SHORT(blockmaplump[i]); bmaporgx = blockmaplump[0] << FRACBITS; bmaporgy = blockmaplump[1] << FRACBITS; bmapwidth = blockmaplump[2]; bmapheight = blockmaplump[3]; // clear out mobj chains count = sizeof(*blocklinks) * bmapwidth * bmapheight; blocklinks = Z_Malloc(count, PU_LEVEL, 0); memset(blocklinks, 0, count); } /* ================= = = P_GroupLines = = Builds sector line lists and subsector sector numbers = Finds block bounding boxes for sectors ================= */ void P_GroupLines(void) { line_t **linebuffer; int i, j, total; line_t *li; sector_t *sector; subsector_t *ss; seg_t *seg; fixed_t bbox[4]; int block; // look up sector number for each subsector ss = subsectors; for (i = 0; i < numsubsectors; i++, ss++) { seg = &segs[ss->firstline]; ss->sector = seg->sidedef->sector; } // count number of lines in each sector li = lines; total = 0; for (i = 0; i < numlines; i++, li++) { total++; li->frontsector->linecount++; if (li->backsector && li->backsector != li->frontsector) { li->backsector->linecount++; total++; } } // build line tables for each sector linebuffer = Z_Malloc(total * sizeof(line_t *), PU_LEVEL, 0); sector = sectors; for (i = 0; i < numsectors; i++, sector++) { M_ClearBox(bbox); sector->lines = linebuffer; li = lines; for (j = 0; j < numlines; j++, li++) { if (li->frontsector == sector || li->backsector == sector) { *linebuffer++ = li; M_AddToBox(bbox, li->v1->x, li->v1->y); M_AddToBox(bbox, li->v2->x, li->v2->y); } } if (linebuffer - sector->lines != sector->linecount) I_Error("P_GroupLines: miscounted"); // set the degenmobj_t to the middle of the bounding box sector->soundorg.x = (bbox[BOXRIGHT] + bbox[BOXLEFT]) / 2; sector->soundorg.y = (bbox[BOXTOP] + bbox[BOXBOTTOM]) / 2; // adjust bounding box to map blocks block = (bbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; block = block >= bmapheight ? bmapheight - 1 : block; sector->blockbox[BOXTOP] = block; block = (bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXBOTTOM] = block; block = (bbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; block = block >= bmapwidth ? bmapwidth - 1 : block; sector->blockbox[BOXRIGHT] = block; block = (bbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXLEFT] = block; } } //============================================================================= /* ================= = = P_SetupLevel = ================= */ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) { int i; int parm; char lumpname[9]; int lumpnum; mobj_t *mobj; totalkills = totalitems = totalsecret = 0; for (i = 0; i < MAXPLAYERS; i++) { players[i].killcount = players[i].secretcount = players[i].itemcount = 0; } players[consoleplayer].viewz = 1; // will be set by player think S_Start(); // make sure all sounds are stopped before Z_FreeTags Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1); P_InitThinkers(); // // look for a regular (development) map first // lumpname[0] = 'E'; lumpname[1] = '0' + episode; lumpname[2] = 'M'; lumpname[3] = '0' + map; lumpname[4] = 0; leveltime = 0; lumpnum = W_GetNumForName(lumpname); // note: most of this ordering is important P_LoadBlockMap(lumpnum + ML_BLOCKMAP); P_LoadVertexes(lumpnum + ML_VERTEXES); P_LoadSectors(lumpnum + ML_SECTORS); P_LoadSideDefs(lumpnum + ML_SIDEDEFS); P_LoadLineDefs(lumpnum + ML_LINEDEFS); P_LoadSubsectors(lumpnum + ML_SSECTORS); P_LoadNodes(lumpnum + ML_NODES); P_LoadSegs(lumpnum + ML_SEGS); rejectmatrix = W_CacheLumpNum(lumpnum + ML_REJECT, PU_LEVEL); P_GroupLines(); bodyqueslot = 0; deathmatch_p = deathmatchstarts; P_InitAmbientSound(); P_InitMonsters(); P_OpenWeapons(); P_LoadThings(lumpnum + ML_THINGS); P_CloseWeapons(); // // if deathmatch, randomly spawn the active players // TimerGame = 0; if (deathmatch) { for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { // must give a player spot before deathmatchspawn mobj = P_SpawnMobj(playerstarts[i].x << 16, playerstarts[i].y << 16, 0, MT_PLAYER); players[i].mo = mobj; G_DeathMatchSpawnPlayer(i); P_RemoveMobj(mobj); } } //! // @arg // @category net // @vanilla // // For multiplayer games: exit each level after n minutes. // parm = M_CheckParmWithArgs("-timer", 1); if (parm) { TimerGame = atoi(myargv[parm + 1]) * 35 * 60; } } // set up world state P_SpawnSpecials(); // build subsector connect matrix // P_ConnectSubsectors (); // preload graphics if (precache) R_PrecacheLevel(); //printf ("free memory: 0x%x\n", Z_FreeMemory()); } /* ================= = = P_Init = ================= */ void P_Init(void) { P_InitSwitchList(); P_InitPicAnims(); P_InitTerrainTypes(); P_InitLava(); R_InitSprites(sprnames); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_sight.c000066400000000000000000000201651257432200600233240ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_sight.c #include #include "doomdef.h" #include "p_local.h" /* ============================================================================== P_CheckSight This uses specialized forms of the maputils routines for optimized performance ============================================================================== */ fixed_t sightzstart; // eye z of looker fixed_t topslope, bottomslope; // slopes to top and bottom of target int sightcounts[3]; /* ============== = = PTR_SightTraverse = ============== */ boolean PTR_SightTraverse(intercept_t * in) { line_t *li; fixed_t slope; li = in->d.line; // // crosses a two sided line // P_LineOpening(li); if (openbottom >= opentop) // quick test for totally closed doors return false; // stop if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv(openbottom - sightzstart, in->frac); if (slope > bottomslope) bottomslope = slope; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv(opentop - sightzstart, in->frac); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop return true; // keep going } /* ================== = = P_SightBlockLinesIterator = =================== */ boolean P_SightBlockLinesIterator(int x, int y) { int offset; short *list; line_t *ld; int s1, s2; divline_t dl; offset = y * bmapwidth + x; offset = *(blockmap + offset); for (list = blockmaplump + offset; *list != -1; list++) { ld = &lines[*list]; if (ld->validcount == validcount) continue; // line has already been checked ld->validcount = validcount; s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace); if (s1 == s2) continue; // line isn't crossed P_MakeDivline(ld, &dl); s1 = P_PointOnDivlineSide(trace.x, trace.y, &dl); s2 = P_PointOnDivlineSide(trace.x + trace.dx, trace.y + trace.dy, &dl); if (s1 == s2) continue; // line isn't crossed // try to early out the check if (!ld->backsector) return false; // stop checking // store the line for later intersection testing intercept_p->d.line = ld; intercept_p++; } return true; // everything was checked } /* ==================== = = P_SightTraverseIntercepts = = Returns true if the traverser function returns true for all lines ==================== */ boolean P_SightTraverseIntercepts(void) { int count; fixed_t dist; intercept_t *scan, *in; divline_t dl; count = intercept_p - intercepts; // // calculate intercept distance // for (scan = intercepts; scan < intercept_p; scan++) { P_MakeDivline(scan->d.line, &dl); scan->frac = P_InterceptVector(&trace, &dl); } // // go through in order // in = 0; // shut up compiler warning while (count--) { dist = INT_MAX; for (scan = intercepts; scan < intercept_p; scan++) if (scan->frac < dist) { dist = scan->frac; in = scan; } if (!PTR_SightTraverse(in)) return false; // don't bother going farther in->frac = INT_MAX; } return true; // everything was traversed } /* ================== = = P_SightPathTraverse = = Traces a line from x1,y1 to x2,y2, calling the traverser function for each = Returns true if the traverser function returns true for all lines ================== */ boolean P_SightPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) { fixed_t xt1, yt1, xt2, yt2; fixed_t xstep, ystep; fixed_t partial; fixed_t xintercept, yintercept; int mapx, mapy, mapxstep, mapystep; int count; validcount++; intercept_p = intercepts; if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0) x1 += FRACUNIT; // don't side exactly on a line if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0) y1 += FRACUNIT; // don't side exactly on a line trace.x = x1; trace.y = y1; trace.dx = x2 - x1; trace.dy = y2 - y1; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = x1 >> MAPBLOCKSHIFT; yt1 = y1 >> MAPBLOCKSHIFT; x2 -= bmaporgx; y2 -= bmaporgy; xt2 = x2 >> MAPBLOCKSHIFT; yt2 = y2 >> MAPBLOCKSHIFT; // points should never be out of bounds, but check once instead of // each block if (xt1 < 0 || yt1 < 0 || xt1 >= bmapwidth || yt1 >= bmapheight || xt2 < 0 || yt2 < 0 || xt2 >= bmapwidth || yt2 >= bmapheight) return false; if (xt2 > xt1) { mapxstep = 1; partial = FRACUNIT - ((x1 >> MAPBTOFRAC) & (FRACUNIT - 1)); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else if (xt2 < xt1) { mapxstep = -1; partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else { mapxstep = 0; partial = FRACUNIT; ystep = 256 * FRACUNIT; } yintercept = (y1 >> MAPBTOFRAC) + FixedMul(partial, ystep); if (yt2 > yt1) { mapystep = 1; partial = FRACUNIT - ((y1 >> MAPBTOFRAC) & (FRACUNIT - 1)); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else if (yt2 < yt1) { mapystep = -1; partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else { mapystep = 0; partial = FRACUNIT; xstep = 256 * FRACUNIT; } xintercept = (x1 >> MAPBTOFRAC) + FixedMul(partial, xstep); // // step through map blocks // Count is present to prevent a round off error from skipping the break mapx = xt1; mapy = yt1; for (count = 0; count < 64; count++) { if (!P_SightBlockLinesIterator(mapx, mapy)) { sightcounts[1]++; return false; // early out } if (mapx == xt2 && mapy == yt2) break; if ((yintercept >> FRACBITS) == mapy) { yintercept += ystep; mapx += mapxstep; } else if ((xintercept >> FRACBITS) == mapx) { xintercept += xstep; mapy += mapystep; } } // // couldn't early out, so go through the sorted list // sightcounts[2]++; return P_SightTraverseIntercepts(); } /* ===================== = = P_CheckSight = = Returns true if a straight line between t1 and t2 is unobstructed = look from eyes of t1 to any part of t2 = ===================== */ boolean P_CheckSight(mobj_t * t1, mobj_t * t2) { int s1, s2; int pnum, bytenum, bitnum; // // check for trivial rejection // s1 = (t1->subsector->sector - sectors); s2 = (t2->subsector->sector - sectors); pnum = s1 * numsectors + s2; bytenum = pnum >> 3; bitnum = 1 << (pnum & 7); if (rejectmatrix[bytenum] & bitnum) { sightcounts[0]++; return false; // can't possibly be connected } // // check precisely // sightzstart = t1->z + t1->height - (t1->height >> 2); topslope = (t2->z + t2->height) - sightzstart; bottomslope = (t2->z) - sightzstart; return P_SightPathTraverse(t1->x, t1->y, t2->x, t2->y); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_spec.c000066400000000000000000001123241257432200600231370ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_Spec.c #include "doomdef.h" #include "deh_str.h" #include "i_system.h" #include "i_timer.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" // Macros #define MAX_AMBIENT_SFX 8 // Per level // Types typedef enum { afxcmd_play, // (sound) afxcmd_playabsvol, // (sound, volume) afxcmd_playrelvol, // (sound, volume) afxcmd_delay, // (ticks) afxcmd_delayrand, // (andbits) afxcmd_end // () } afxcmd_t; // Data int *LevelAmbientSfx[MAX_AMBIENT_SFX]; int *AmbSfxPtr; int AmbSfxCount; int AmbSfxTics; int AmbSfxVolume; int AmbSndSeqInit[] = { // Startup afxcmd_end }; int AmbSndSeq1[] = { // Scream afxcmd_play, sfx_amb1, afxcmd_end }; int AmbSndSeq2[] = { // Squish afxcmd_play, sfx_amb2, afxcmd_end }; int AmbSndSeq3[] = { // Drops afxcmd_play, sfx_amb3, afxcmd_delay, 16, afxcmd_delayrand, 31, afxcmd_play, sfx_amb7, afxcmd_delay, 16, afxcmd_delayrand, 31, afxcmd_play, sfx_amb3, afxcmd_delay, 16, afxcmd_delayrand, 31, afxcmd_play, sfx_amb7, afxcmd_delay, 16, afxcmd_delayrand, 31, afxcmd_play, sfx_amb3, afxcmd_delay, 16, afxcmd_delayrand, 31, afxcmd_play, sfx_amb7, afxcmd_delay, 16, afxcmd_delayrand, 31, afxcmd_end }; int AmbSndSeq4[] = { // SlowFootSteps afxcmd_play, sfx_amb4, afxcmd_delay, 15, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_delay, 15, afxcmd_playrelvol, sfx_amb4, -3, afxcmd_delay, 15, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_delay, 15, afxcmd_playrelvol, sfx_amb4, -3, afxcmd_delay, 15, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_delay, 15, afxcmd_playrelvol, sfx_amb4, -3, afxcmd_delay, 15, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_end }; int AmbSndSeq5[] = { // Heartbeat afxcmd_play, sfx_amb5, afxcmd_delay, 35, afxcmd_play, sfx_amb5, afxcmd_delay, 35, afxcmd_play, sfx_amb5, afxcmd_delay, 35, afxcmd_play, sfx_amb5, afxcmd_end }; int AmbSndSeq6[] = { // Bells afxcmd_play, sfx_amb6, afxcmd_delay, 17, afxcmd_playrelvol, sfx_amb6, -8, afxcmd_delay, 17, afxcmd_playrelvol, sfx_amb6, -8, afxcmd_delay, 17, afxcmd_playrelvol, sfx_amb6, -8, afxcmd_end }; int AmbSndSeq7[] = { // Growl afxcmd_play, sfx_bstsit, afxcmd_end }; int AmbSndSeq8[] = { // Magic afxcmd_play, sfx_amb8, afxcmd_end }; int AmbSndSeq9[] = { // Laughter afxcmd_play, sfx_amb9, afxcmd_delay, 16, afxcmd_playrelvol, sfx_amb9, -4, afxcmd_delay, 16, afxcmd_playrelvol, sfx_amb9, -4, afxcmd_delay, 16, afxcmd_playrelvol, sfx_amb10, -4, afxcmd_delay, 16, afxcmd_playrelvol, sfx_amb10, -4, afxcmd_delay, 16, afxcmd_playrelvol, sfx_amb10, -4, afxcmd_end }; int AmbSndSeq10[] = { // FastFootsteps afxcmd_play, sfx_amb4, afxcmd_delay, 8, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_delay, 8, afxcmd_playrelvol, sfx_amb4, -3, afxcmd_delay, 8, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_delay, 8, afxcmd_playrelvol, sfx_amb4, -3, afxcmd_delay, 8, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_delay, 8, afxcmd_playrelvol, sfx_amb4, -3, afxcmd_delay, 8, afxcmd_playrelvol, sfx_amb11, -3, afxcmd_end }; int *AmbientSfx[] = { AmbSndSeq1, // Scream AmbSndSeq2, // Squish AmbSndSeq3, // Drops AmbSndSeq4, // SlowFootsteps AmbSndSeq5, // Heartbeat AmbSndSeq6, // Bells AmbSndSeq7, // Growl AmbSndSeq8, // Magic AmbSndSeq9, // Laughter AmbSndSeq10 // FastFootsteps }; animdef_t animdefs[] = { // false = flat // true = texture {false, "FLTWAWA3", "FLTWAWA1", 8}, // Water {false, "FLTSLUD3", "FLTSLUD1", 8}, // Sludge {false, "FLTTELE4", "FLTTELE1", 6}, // Teleport {false, "FLTFLWW3", "FLTFLWW1", 9}, // River - West {false, "FLTLAVA4", "FLTLAVA1", 8}, // Lava {false, "FLATHUH4", "FLATHUH1", 8}, // Super Lava {true, "LAVAFL3", "LAVAFL1", 6}, // Texture: Lavaflow {true, "WATRWAL3", "WATRWAL1", 4}, // Texture: Waterfall {-1} }; anim_t anims[MAXANIMS]; anim_t *lastanim; int *TerrainTypes; struct { char *name; int type; } TerrainTypeDefs[] = { { "FLTWAWA1", FLOOR_WATER }, { "FLTFLWW1", FLOOR_WATER }, { "FLTLAVA1", FLOOR_LAVA }, { "FLATHUH1", FLOOR_LAVA }, { "FLTSLUD1", FLOOR_SLUDGE }, { "END", -1 } }; mobj_t LavaInflictor; //---------------------------------------------------------------------------- // // PROC P_InitLava // //---------------------------------------------------------------------------- void P_InitLava(void) { memset(&LavaInflictor, 0, sizeof(mobj_t)); LavaInflictor.type = MT_PHOENIXFX2; LavaInflictor.flags2 = MF2_FIREDAMAGE | MF2_NODMGTHRUST; } //---------------------------------------------------------------------------- // // PROC P_InitTerrainTypes // //---------------------------------------------------------------------------- void P_InitTerrainTypes(void) { int i; int lump; int size; size = (numflats + 1) * sizeof(int); TerrainTypes = Z_Malloc(size, PU_STATIC, 0); memset(TerrainTypes, 0, size); for (i = 0; TerrainTypeDefs[i].type != -1; i++) { lump = W_CheckNumForName(TerrainTypeDefs[i].name); if (lump != -1) { TerrainTypes[lump - firstflat] = TerrainTypeDefs[i].type; } } } //---------------------------------------------------------------------------- // // PROC P_InitPicAnims // //---------------------------------------------------------------------------- void P_InitPicAnims(void) { char *startname; char *endname; int i; lastanim = anims; for (i = 0; animdefs[i].istexture != -1; i++) { startname = DEH_String(animdefs[i].startname); endname = DEH_String(animdefs[i].endname); if (animdefs[i].istexture) { // Texture animation if (R_CheckTextureNumForName(startname) == -1) { // Texture doesn't exist continue; } lastanim->picnum = R_TextureNumForName(endname); lastanim->basepic = R_TextureNumForName(startname); } else { // Flat animation if (W_CheckNumForName(startname) == -1) { // Flat doesn't exist continue; } lastanim->picnum = R_FlatNumForName(endname); lastanim->basepic = R_FlatNumForName(startname); } lastanim->istexture = animdefs[i].istexture; lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; if (lastanim->numpics < 2) { I_Error("P_InitPicAnims: bad cycle from %s to %s", startname, endname); } lastanim->speed = animdefs[i].speed; lastanim++; } } /* ============================================================================== UTILITIES ============================================================================== */ // // Will return a side_t* given the number of the current sector, // the line number, and the side (0/1) that you want. // side_t *getSide(int currentSector, int line, int side) { return &sides[(sectors[currentSector].lines[line])->sidenum[side]]; } // // Will return a sector_t* given the number of the current sector, // the line number and the side (0/1) that you want. // sector_t *getSector(int currentSector, int line, int side) { return sides[(sectors[currentSector].lines[line])->sidenum[side]].sector; } // // Given the sector number and the line number, will tell you whether // the line is two-sided or not. // int twoSided(int sector, int line) { return (sectors[sector].lines[line])->flags & ML_TWOSIDED; } //================================================================== // // Return sector_t * of sector next to current. NULL if not two-sided line // //================================================================== sector_t *getNextSector(line_t * line, sector_t * sec) { if (!(line->flags & ML_TWOSIDED)) return NULL; if (line->frontsector == sec) return line->backsector; return line->frontsector; } //================================================================== // // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS // //================================================================== fixed_t P_FindLowestFloorSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t floor = sec->floorheight; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->floorheight < floor) floor = other->floorheight; } return floor; } //================================================================== // // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS // //================================================================== fixed_t P_FindHighestFloorSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t floor = -500 * FRACUNIT; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->floorheight > floor) floor = other->floorheight; } return floor; } //================================================================== // // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS // //================================================================== fixed_t P_FindNextHighestFloor(sector_t * sec, int currentheight) { int i; int h; fixed_t min; line_t *check; sector_t *other; fixed_t height = currentheight; min = INT_MAX; for (i = 0, h = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (other != NULL && other->floorheight > height) { if (other->floorheight < min) { min = other->floorheight; } ++h; } } // Compatibility note, in case of demo desyncs. if (h > 20) { fprintf(stderr, "P_FindNextHighestFloor: exceeded Vanilla limit\n"); } return min; } //================================================================== // // FIND LOWEST CEILING IN THE SURROUNDING SECTORS // //================================================================== fixed_t P_FindLowestCeilingSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t height = INT_MAX; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->ceilingheight < height) height = other->ceilingheight; } return height; } //================================================================== // // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS // //================================================================== fixed_t P_FindHighestCeilingSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t height = 0; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->ceilingheight > height) height = other->ceilingheight; } return height; } //================================================================== // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO // //================================================================== int P_FindSectorFromLineTag(line_t * line, int start) { int i; for (i = start + 1; i < numsectors; i++) if (sectors[i].tag == line->tag) return i; return -1; } //================================================================== // // Find minimum light from an adjacent sector // //================================================================== int P_FindMinSurroundingLight(sector_t * sector, int max) { int i; int min; line_t *line; sector_t *check; min = max; for (i = 0; i < sector->linecount; i++) { line = sector->lines[i]; check = getNextSector(line, sector); if (!check) continue; if (check->lightlevel < min) min = check->lightlevel; } return min; } /* ============================================================================== EVENTS Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers ============================================================================== */ /* =============================================================================== = = P_CrossSpecialLine - TRIGGER = = Called every time a thing origin is about to cross = a line with a non 0 special = =============================================================================== */ void P_CrossSpecialLine(int linenum, int side, mobj_t * thing) { line_t *line; line = &lines[linenum]; if (!thing->player) { // Check if trigger allowed by non-player mobj switch (line->special) { case 39: // Trigger_TELEPORT case 97: // Retrigger_TELEPORT case 4: // Trigger_Raise_Door //case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER //case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER break; default: return; break; } } switch (line->special) { //==================================================== // TRIGGERS //==================================================== case 2: // Open Door EV_DoDoor(line, vld_open, VDOORSPEED); line->special = 0; break; case 3: // Close Door EV_DoDoor(line, vld_close, VDOORSPEED); line->special = 0; break; case 4: // Raise Door EV_DoDoor(line, vld_normal, VDOORSPEED); line->special = 0; break; case 5: // Raise Floor EV_DoFloor(line, raiseFloor); line->special = 0; break; case 6: // Fast Ceiling Crush & Raise EV_DoCeiling(line, fastCrushAndRaise); line->special = 0; break; case 8: // Trigger_Build_Stairs (8 pixel steps) EV_BuildStairs(line, 8 * FRACUNIT); line->special = 0; break; case 106: // Trigger_Build_Stairs_16 (16 pixel steps) EV_BuildStairs(line, 16 * FRACUNIT); line->special = 0; break; case 10: // PlatDownWaitUp EV_DoPlat(line, downWaitUpStay, 0); line->special = 0; break; case 12: // Light Turn On - brightest near EV_LightTurnOn(line, 0); line->special = 0; break; case 13: // Light Turn On 255 EV_LightTurnOn(line, 255); line->special = 0; break; case 16: // Close Door 30 EV_DoDoor(line, vld_close30ThenOpen, VDOORSPEED); line->special = 0; break; case 17: // Start Light Strobing EV_StartLightStrobing(line); line->special = 0; break; case 19: // Lower Floor EV_DoFloor(line, lowerFloor); line->special = 0; break; case 22: // Raise floor to nearest height and change texture EV_DoPlat(line, raiseToNearestAndChange, 0); line->special = 0; break; case 25: // Ceiling Crush and Raise EV_DoCeiling(line, crushAndRaise); line->special = 0; break; case 30: // Raise floor to shortest texture height // on either side of lines EV_DoFloor(line, raiseToTexture); line->special = 0; break; case 35: // Lights Very Dark EV_LightTurnOn(line, 35); line->special = 0; break; case 36: // Lower Floor (TURBO) EV_DoFloor(line, turboLower); line->special = 0; break; case 37: // LowerAndChange EV_DoFloor(line, lowerAndChange); line->special = 0; break; case 38: // Lower Floor To Lowest EV_DoFloor(line, lowerFloorToLowest); line->special = 0; break; case 39: // TELEPORT! EV_Teleport(line, side, thing); line->special = 0; break; case 40: // RaiseCeilingLowerFloor EV_DoCeiling(line, raiseToHighest); EV_DoFloor(line, lowerFloorToLowest); line->special = 0; break; case 44: // Ceiling Crush EV_DoCeiling(line, lowerAndCrush); line->special = 0; break; case 52: // EXIT! G_ExitLevel(); line->special = 0; break; case 53: // Perpetual Platform Raise EV_DoPlat(line, perpetualRaise, 0); line->special = 0; break; case 54: // Platform Stop EV_StopPlat(line); line->special = 0; break; case 56: // Raise Floor Crush EV_DoFloor(line, raiseFloorCrush); line->special = 0; break; case 57: // Ceiling Crush Stop EV_CeilingCrushStop(line); line->special = 0; break; case 58: // Raise Floor 24 EV_DoFloor(line, raiseFloor24); line->special = 0; break; case 59: // Raise Floor 24 And Change EV_DoFloor(line, raiseFloor24AndChange); line->special = 0; break; case 104: // Turn lights off in sector(tag) EV_TurnTagLightsOff(line); line->special = 0; break; case 105: // Trigger_SecretExit G_SecretExitLevel(); line->special = 0; break; //==================================================== // RE-DOABLE TRIGGERS //==================================================== case 72: // Ceiling Crush EV_DoCeiling(line, lowerAndCrush); break; case 73: // Ceiling Crush and Raise EV_DoCeiling(line, crushAndRaise); break; case 74: // Ceiling Crush Stop EV_CeilingCrushStop(line); break; case 75: // Close Door EV_DoDoor(line, vld_close, VDOORSPEED); break; case 76: // Close Door 30 EV_DoDoor(line, vld_close30ThenOpen, VDOORSPEED); break; case 77: // Fast Ceiling Crush & Raise EV_DoCeiling(line, fastCrushAndRaise); break; case 79: // Lights Very Dark EV_LightTurnOn(line, 35); break; case 80: // Light Turn On - brightest near EV_LightTurnOn(line, 0); break; case 81: // Light Turn On 255 EV_LightTurnOn(line, 255); break; case 82: // Lower Floor To Lowest EV_DoFloor(line, lowerFloorToLowest); break; case 83: // Lower Floor EV_DoFloor(line, lowerFloor); break; case 84: // LowerAndChange EV_DoFloor(line, lowerAndChange); break; case 86: // Open Door EV_DoDoor(line, vld_open, VDOORSPEED); break; case 87: // Perpetual Platform Raise EV_DoPlat(line, perpetualRaise, 0); break; case 88: // PlatDownWaitUp EV_DoPlat(line, downWaitUpStay, 0); break; case 89: // Platform Stop EV_StopPlat(line); break; case 90: // Raise Door EV_DoDoor(line, vld_normal, VDOORSPEED); break; case 100: // Retrigger_Raise_Door_Turbo EV_DoDoor(line, vld_normal, VDOORSPEED * 3); break; case 91: // Raise Floor EV_DoFloor(line, raiseFloor); break; case 92: // Raise Floor 24 EV_DoFloor(line, raiseFloor24); break; case 93: // Raise Floor 24 And Change EV_DoFloor(line, raiseFloor24AndChange); break; case 94: // Raise Floor Crush EV_DoFloor(line, raiseFloorCrush); break; case 95: // Raise floor to nearest height and change texture EV_DoPlat(line, raiseToNearestAndChange, 0); break; case 96: // Raise floor to shortest texture height // on either side of lines EV_DoFloor(line, raiseToTexture); break; case 97: // TELEPORT! EV_Teleport(line, side, thing); break; case 98: // Lower Floor (TURBO) EV_DoFloor(line, turboLower); break; } } //---------------------------------------------------------------------------- // // PROC P_ShootSpecialLine // // Called when a thing shoots a special line. // //---------------------------------------------------------------------------- void P_ShootSpecialLine(mobj_t * thing, line_t * line) { if (!thing->player) { // Check if trigger allowed by non-player mobj switch (line->special) { case 46: // Impact_OpenDoor break; default: return; break; } } switch (line->special) { case 24: // Impact_RaiseFloor EV_DoFloor(line, raiseFloor); P_ChangeSwitchTexture(line, 0); break; case 46: // Impact_OpenDoor EV_DoDoor(line, vld_open, VDOORSPEED); P_ChangeSwitchTexture(line, 1); break; case 47: // Impact_RaiseFloorNear&Change EV_DoPlat(line, raiseToNearestAndChange, 0); P_ChangeSwitchTexture(line, 0); break; } } //---------------------------------------------------------------------------- // // PROC P_PlayerInSpecialSector // // Called every tic frame that the player origin is in a special sector. // //---------------------------------------------------------------------------- void P_PlayerInSpecialSector(player_t * player) { sector_t *sector; static int pushTab[5] = { 2048 * 5, 2048 * 10, 2048 * 25, 2048 * 30, 2048 * 35 }; sector = player->mo->subsector->sector; if (player->mo->z != sector->floorheight) { // Player is not touching the floor return; } switch (sector->special) { case 7: // Damage_Sludge if (!(leveltime & 31)) { P_DamageMobj(player->mo, NULL, NULL, 4); } break; case 5: // Damage_LavaWimpy if (!(leveltime & 15)) { P_DamageMobj(player->mo, &LavaInflictor, NULL, 5); P_HitFloor(player->mo); } break; case 16: // Damage_LavaHefty if (!(leveltime & 15)) { P_DamageMobj(player->mo, &LavaInflictor, NULL, 8); P_HitFloor(player->mo); } break; case 4: // Scroll_EastLavaDamage P_Thrust(player, 0, 2048 * 28); if (!(leveltime & 15)) { P_DamageMobj(player->mo, &LavaInflictor, NULL, 5); P_HitFloor(player->mo); } break; case 9: // SecretArea player->secretcount++; sector->special = 0; break; case 11: // Exit_SuperDamage (DOOM E1M8 finale) /* player->cheats &= ~CF_GODMODE; if(!(leveltime&0x1f)) { P_DamageMobj(player->mo, NULL, NULL, 20); } if(player->health <= 10) { G_ExitLevel(); } */ break; case 25: case 26: case 27: case 28: case 29: // Scroll_North P_Thrust(player, ANG90, pushTab[sector->special - 25]); break; case 20: case 21: case 22: case 23: case 24: // Scroll_East P_Thrust(player, 0, pushTab[sector->special - 20]); break; case 30: case 31: case 32: case 33: case 34: // Scroll_South P_Thrust(player, ANG270, pushTab[sector->special - 30]); break; case 35: case 36: case 37: case 38: case 39: // Scroll_West P_Thrust(player, ANG180, pushTab[sector->special - 35]); break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: // Wind specials are handled in (P_mobj):P_XYMovement break; case 15: // Friction_Low // Only used in (P_mobj):P_XYMovement and (P_user):P_Thrust break; default: I_Error("P_PlayerInSpecialSector: " "unknown special %i", sector->special); } } //---------------------------------------------------------------------------- // // PROC P_UpdateSpecials // // Animate planes, scroll walls, etc. // //---------------------------------------------------------------------------- void P_UpdateSpecials(void) { int i; int pic; anim_t *anim; line_t *line; // Animate flats and textures for (anim = anims; anim < lastanim; anim++) { for (i = anim->basepic; i < anim->basepic + anim->numpics; i++) { pic = anim->basepic + ((leveltime / anim->speed + i) % anim->numpics); if (anim->istexture) { texturetranslation[i] = pic; } else { flattranslation[i] = pic; } } } // Update scrolling texture offsets for (i = 0; i < numlinespecials; i++) { line = linespeciallist[i]; switch (line->special) { case 48: // Effect_Scroll_Left sides[line->sidenum[0]].textureoffset += FRACUNIT; break; case 99: // Effect_Scroll_Right sides[line->sidenum[0]].textureoffset -= FRACUNIT; break; } } // Handle buttons for (i = 0; i < MAXBUTTONS; i++) { if (buttonlist[i].btimer) { buttonlist[i].btimer--; if (!buttonlist[i].btimer) { switch (buttonlist[i].where) { case top: sides[buttonlist[i].line->sidenum[0]].toptexture = buttonlist[i].btexture; break; case middle: sides[buttonlist[i].line->sidenum[0]].midtexture = buttonlist[i].btexture; break; case bottom: sides[buttonlist[i].line->sidenum[0]].bottomtexture = buttonlist[i].btexture; break; } S_StartSound(buttonlist[i].soundorg, sfx_switch); memset(&buttonlist[i], 0, sizeof(button_t)); } } } } //============================================================ // // Special Stuff that can't be categorized // //============================================================ int EV_DoDonut(line_t * line) { sector_t *s1; sector_t *s2; sector_t *s3; int secnum; int rtn; int i; floormove_t *floor; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { s1 = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (s1->specialdata) continue; rtn = 1; s2 = getNextSector(s1->lines[0], s1); for (i = 0; i < s2->linecount; i++) { // Note: This was originally part of the following test: // (!s2->lines[i]->flags & ML_TWOSIDED) || // Due to the apparent mistaken formatting, this can never be // true. if (s2->lines[i]->backsector == s1) continue; s3 = s2->lines[i]->backsector; // // Spawn rising slime // floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker(&floor->thinker); s2->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = donutRaise; floor->crush = false; floor->direction = 1; floor->sector = s2; floor->speed = FLOORSPEED / 2; floor->texture = s3->floorpic; floor->newspecial = 0; floor->floordestheight = s3->floorheight; // // Spawn lowering donut-hole // floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker(&floor->thinker); s1->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = lowerFloor; floor->crush = false; floor->direction = -1; floor->sector = s1; floor->speed = FLOORSPEED / 2; floor->floordestheight = s3->floorheight; break; } } return rtn; } /* ============================================================================== SPECIAL SPAWNING ============================================================================== */ /* ================================================================================ = P_SpawnSpecials = = After the map has been loaded, scan for specials that = spawn thinkers = =============================================================================== */ short numlinespecials; line_t *linespeciallist[MAXLINEANIMS]; void P_SpawnSpecials(void) { sector_t *sector; int i; // // Init special SECTORs // sector = sectors; for (i = 0; i < numsectors; i++, sector++) { if (!sector->special) continue; switch (sector->special) { case 1: // FLICKERING LIGHTS P_SpawnLightFlash(sector); break; case 2: // STROBE FAST P_SpawnStrobeFlash(sector, FASTDARK, 0); break; case 3: // STROBE SLOW P_SpawnStrobeFlash(sector, SLOWDARK, 0); break; case 4: // STROBE FAST/DEATH SLIME P_SpawnStrobeFlash(sector, FASTDARK, 0); sector->special = 4; break; case 8: // GLOWING LIGHT P_SpawnGlowingLight(sector); break; case 9: // SECRET SECTOR totalsecret++; break; case 10: // DOOR CLOSE IN 30 SECONDS P_SpawnDoorCloseIn30(sector); break; case 12: // SYNC STROBE SLOW P_SpawnStrobeFlash(sector, SLOWDARK, 1); break; case 13: // SYNC STROBE FAST P_SpawnStrobeFlash(sector, FASTDARK, 1); break; case 14: // DOOR RAISE IN 5 MINUTES P_SpawnDoorRaiseIn5Mins(sector, i); break; } } // // Init line EFFECTs // numlinespecials = 0; for (i = 0; i < numlines; i++) switch (lines[i].special) { case 48: // Effect_Scroll_Left case 99: // Effect_Scroll_Right linespeciallist[numlinespecials] = &lines[i]; numlinespecials++; break; } // // Init other misc stuff // for (i = 0; i < MAXCEILINGS; i++) activeceilings[i] = NULL; for (i = 0; i < MAXPLATS; i++) activeplats[i] = NULL; for (i = 0; i < MAXBUTTONS; i++) memset(&buttonlist[i], 0, sizeof(button_t)); } //---------------------------------------------------------------------------- // // PROC P_InitAmbientSound // //---------------------------------------------------------------------------- void P_InitAmbientSound(void) { AmbSfxCount = 0; AmbSfxVolume = 0; AmbSfxTics = 10 * TICRATE; AmbSfxPtr = AmbSndSeqInit; } //---------------------------------------------------------------------------- // // PROC P_AddAmbientSfx // // Called by (P_mobj):P_SpawnMapThing during (P_setup):P_SetupLevel. // //---------------------------------------------------------------------------- void P_AddAmbientSfx(int sequence) { if (AmbSfxCount == MAX_AMBIENT_SFX) { I_Error("Too many ambient sound sequences"); } LevelAmbientSfx[AmbSfxCount++] = AmbientSfx[sequence]; } //---------------------------------------------------------------------------- // // PROC P_AmbientSound // // Called every tic by (P_tick):P_Ticker. // //---------------------------------------------------------------------------- void P_AmbientSound(void) { afxcmd_t cmd; int sound; boolean done; if (!AmbSfxCount) { // No ambient sound sequences on current level return; } if (--AmbSfxTics) { return; } done = false; do { cmd = *AmbSfxPtr++; switch (cmd) { case afxcmd_play: AmbSfxVolume = P_Random() >> 2; S_StartSoundAtVolume(NULL, *AmbSfxPtr++, AmbSfxVolume); break; case afxcmd_playabsvol: sound = *AmbSfxPtr++; AmbSfxVolume = *AmbSfxPtr++; S_StartSoundAtVolume(NULL, sound, AmbSfxVolume); break; case afxcmd_playrelvol: sound = *AmbSfxPtr++; AmbSfxVolume += *AmbSfxPtr++; if (AmbSfxVolume < 0) { AmbSfxVolume = 0; } else if (AmbSfxVolume > 127) { AmbSfxVolume = 127; } S_StartSoundAtVolume(NULL, sound, AmbSfxVolume); break; case afxcmd_delay: AmbSfxTics = *AmbSfxPtr++; done = true; break; case afxcmd_delayrand: AmbSfxTics = P_Random() & (*AmbSfxPtr++); done = true; break; case afxcmd_end: AmbSfxTics = 6 * TICRATE + P_Random(); AmbSfxPtr = LevelAmbientSfx[P_Random() % AmbSfxCount]; done = true; break; default: I_Error("P_AmbientSound: Unknown afxcmd %d", cmd); break; } } while (done == false); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_spec.h000066400000000000000000000222331257432200600231430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_spec.h /* =============================================================================== P_SPEC =============================================================================== */ // // Animating textures and planes // typedef struct { boolean istexture; int picnum; int basepic; int numpics; int speed; } anim_t; // // source animation definition // typedef struct { int istexture; // if false, it's a flat char endname[9]; char startname[9]; int speed; } animdef_t; #define MAXANIMS 32 extern anim_t anims[MAXANIMS], *lastanim; extern int *TerrainTypes; // // Animating line specials // #define MAXLINEANIMS 64 extern short numlinespecials; extern line_t *linespeciallist[MAXLINEANIMS]; // Define values for map objects #define MO_TELEPORTMAN 14 // at game start void P_InitPicAnims(void); void P_InitTerrainTypes(void); void P_InitLava(void); // at map load void P_SpawnSpecials(void); void P_InitAmbientSound(void); void P_AddAmbientSfx(int sequence); // every tic void P_UpdateSpecials(void); void P_AmbientSound(void); // when needed boolean P_UseSpecialLine(mobj_t * thing, line_t * line); void P_ShootSpecialLine(mobj_t * thing, line_t * line); void P_CrossSpecialLine(int linenum, int side, mobj_t * thing); void P_PlayerInSpecialSector(player_t * player); int twoSided(int sector, int line); sector_t *getSector(int currentSector, int line, int side); side_t *getSide(int currentSector, int line, int side); fixed_t P_FindLowestFloorSurrounding(sector_t * sec); fixed_t P_FindHighestFloorSurrounding(sector_t * sec); fixed_t P_FindNextHighestFloor(sector_t * sec, int currentheight); fixed_t P_FindLowestCeilingSurrounding(sector_t * sec); fixed_t P_FindHighestCeilingSurrounding(sector_t * sec); int P_FindSectorFromLineTag(line_t * line, int start); int P_FindMinSurroundingLight(sector_t * sector, int max); sector_t *getNextSector(line_t * line, sector_t * sec); // // SPECIAL // int EV_DoDonut(line_t * line); /* =============================================================================== P_LIGHTS =============================================================================== */ typedef struct { thinker_t thinker; sector_t *sector; int count; int maxlight; int minlight; int maxtime; int mintime; } lightflash_t; typedef struct { thinker_t thinker; sector_t *sector; int count; int minlight; int maxlight; int darktime; int brighttime; } strobe_t; typedef struct { thinker_t thinker; sector_t *sector; int minlight; int maxlight; int direction; } glow_t; #define GLOWSPEED 8 #define STROBEBRIGHT 5 #define FASTDARK 15 #define SLOWDARK 35 void T_LightFlash(lightflash_t * flash); void P_SpawnLightFlash(sector_t * sector); void T_StrobeFlash(strobe_t * flash); void P_SpawnStrobeFlash(sector_t * sector, int fastOrSlow, int inSync); void EV_StartLightStrobing(line_t * line); void EV_TurnTagLightsOff(line_t * line); void EV_LightTurnOn(line_t * line, int bright); void T_Glow(glow_t * g); void P_SpawnGlowingLight(sector_t * sector); /* =============================================================================== P_SWITCH =============================================================================== */ typedef struct { char name1[9]; char name2[9]; short episode; } switchlist_t; typedef enum { top, middle, bottom } bwhere_e; typedef struct { line_t *line; bwhere_e where; int btexture; int btimer; void *soundorg; } button_t; #define MAXSWITCHES 50 // max # of wall switches in a level #define MAXBUTTONS 16 // 4 players, 4 buttons each at once, max. #define BUTTONTIME 35 // 1 second extern button_t buttonlist[MAXBUTTONS]; void P_ChangeSwitchTexture(line_t * line, int useAgain); void P_InitSwitchList(void); /* =============================================================================== P_PLATS =============================================================================== */ typedef enum { up, down, waiting, in_stasis } plat_e; typedef enum { perpetualRaise, downWaitUpStay, raiseAndChange, raiseToNearestAndChange } plattype_e; typedef struct { thinker_t thinker; sector_t *sector; fixed_t speed; fixed_t low; fixed_t high; int wait; int count; plat_e status; plat_e oldstatus; boolean crush; int tag; plattype_e type; } plat_t; #define PLATWAIT 3 #define PLATSPEED FRACUNIT #define MAXPLATS 30 extern plat_t *activeplats[MAXPLATS]; void T_PlatRaise(plat_t * plat); int EV_DoPlat(line_t * line, plattype_e type, int amount); void P_AddActivePlat(plat_t * plat); void P_RemoveActivePlat(plat_t * plat); void EV_StopPlat(line_t * line); void P_ActivateInStasis(int tag); /* =============================================================================== P_DOORS =============================================================================== */ typedef enum { vld_normal, vld_close30ThenOpen, vld_close, vld_open, vld_raiseIn5Mins } vldoor_e; typedef struct { thinker_t thinker; vldoor_e type; sector_t *sector; fixed_t topheight; fixed_t speed; int direction; // 1 = up, 0 = waiting at top, -1 = down int topwait; // tics to wait at the top // (keep in case a door going down is reset) int topcountdown; // when it reaches 0, start going down } vldoor_t; #define VDOORSPEED FRACUNIT*2 #define VDOORWAIT 150 void EV_VerticalDoor(line_t * line, mobj_t * thing); int EV_DoDoor(line_t * line, vldoor_e type, fixed_t speed); void T_VerticalDoor(vldoor_t * door); void P_SpawnDoorCloseIn30(sector_t * sec); void P_SpawnDoorRaiseIn5Mins(sector_t * sec, int secnum); /* =============================================================================== P_CEILNG =============================================================================== */ typedef enum { lowerToFloor, raiseToHighest, lowerAndCrush, crushAndRaise, fastCrushAndRaise } ceiling_e; typedef struct { thinker_t thinker; ceiling_e type; sector_t *sector; fixed_t bottomheight, topheight; fixed_t speed; boolean crush; int direction; // 1 = up, 0 = waiting, -1 = down int tag; // ID int olddirection; } ceiling_t; #define CEILSPEED FRACUNIT #define CEILWAIT 150 #define MAXCEILINGS 30 extern ceiling_t *activeceilings[MAXCEILINGS]; int EV_DoCeiling(line_t * line, ceiling_e type); void T_MoveCeiling(ceiling_t * ceiling); void P_AddActiveCeiling(ceiling_t * c); void P_RemoveActiveCeiling(ceiling_t * c); int EV_CeilingCrushStop(line_t * line); void P_ActivateInStasisCeiling(line_t * line); /* =============================================================================== P_FLOOR =============================================================================== */ typedef enum { lowerFloor, // lower floor to highest surrounding floor lowerFloorToLowest, // lower floor to lowest surrounding floor turboLower, // lower floor to highest surrounding floor VERY FAST raiseFloor, // raise floor to lowest surrounding CEILING raiseFloorToNearest, // raise floor to next highest surrounding floor raiseToTexture, // raise floor to shortest height texture around it lowerAndChange, // lower floor to lowest surrounding floor and change // floorpic raiseFloor24, raiseFloor24AndChange, raiseFloorCrush, donutRaise, raiseBuildStep // One step of a staircase } floor_e; typedef struct { thinker_t thinker; floor_e type; boolean crush; sector_t *sector; int direction; int newspecial; short texture; fixed_t floordestheight; fixed_t speed; } floormove_t; #define FLOORSPEED FRACUNIT typedef enum { ok, crushed, pastdest } result_e; result_e T_MovePlane(sector_t * sector, fixed_t speed, fixed_t dest, boolean crush, int floorOrCeiling, int direction); int EV_BuildStairs(line_t * line, fixed_t stepDelta); int EV_DoFloor(line_t * line, floor_e floortype); void T_MoveFloor(floormove_t * floor); /* =============================================================================== P_TELEPT =============================================================================== */ boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle); boolean EV_Teleport(line_t * line, int side, mobj_t * thing); chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_switch.c000066400000000000000000000324211257432200600235050ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "doomdef.h" #include "deh_str.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" //================================================================== // // CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE // //================================================================== switchlist_t alphSwitchList[] = { {"SW1OFF", "SW1ON", 1}, {"SW2OFF", "SW2ON", 1}, /* {"SW1CTY", "SW2CTY", 1}, {"SW1ORGRY", "SW2ORGRY", 1}, {"SW1GRSTN", "SW2GRSTN", 1}, {"SW1SNDP", "SW2SNDP", 1}, {"SW1SPINE", "SW2SPINE", 1}, {"SW1SQPEB", "SW2SQPEB", 1}, {"SW1TRST1", "SW2TRST1", 1}, {"SW1CSTL", "SW2CSTL", 1}, {"SW1MOSS", "SW2MOSS", 1}, {"SW1SNDSQ", "SW2SNDSQ", 1}, {"SW1RED", "SW2RED", 1}, {"SW1WOOD", "SW2WOOD", 1}, {"SW1BROWN", "SW2BROWN", 1}, {"SW1TRST2", "SW2TRST2", 2}, {"SW1MSC", "SW2MSC", 2}, {"SW1MSC2", "SW2MSC2", 2}, {"SW1GRDMD", "SW2GRDMD", 2}, */ #if 0 {"SW1BRCOM", "SW2BRCOM", 1}, {"SW1BRN1", "SW2BRN1", 1}, {"SW1BRN2", "SW2BRN2", 1}, {"SW1BRNGN", "SW2BRNGN", 1}, {"SW1BROWN", "SW2BROWN", 1}, {"SW1COMM", "SW2COMM", 1}, {"SW1COMP", "SW2COMP", 1}, {"SW1DIRT", "SW2DIRT", 1}, {"SW1EXIT", "SW2EXIT", 1}, {"SW1GRAY", "SW2GRAY", 1}, {"SW1GRAY1", "SW2GRAY1", 1}, {"SW1METAL", "SW2METAL", 1}, {"SW1PIPE", "SW2PIPE", 1}, {"SW1SLAD", "SW2SLAD", 1}, {"SW1STARG", "SW2STARG", 1}, {"SW1STON1", "SW2STON1", 1}, {"SW1STON2", "SW2STON2", 1}, {"SW1STONE", "SW2STONE", 1}, {"SW1STRTN", "SW2STRTN", 1}, {"SW1BLUE", "SW2BLUE", 2}, {"SW1CMT", "SW2CMT", 2}, {"SW1GARG", "SW2GARG", 2}, {"SW1GSTON", "SW2GSTON", 2}, {"SW1HOT", "SW2HOT", 2}, {"SW1LION", "SW2LION", 2}, {"SW1SATYR", "SW2SATYR", 2}, {"SW1SKIN", "SW2SKIN", 2}, {"SW1VINE", "SW2VINE", 2}, {"SW1WOOD", "SW2WOOD", 2}, #endif {"\0", "\0", 0} }; int switchlist[MAXSWITCHES * 2]; int numswitches; button_t buttonlist[MAXBUTTONS]; /* =============== = = P_InitSwitchList = = Only called at game initialization = =============== */ void P_InitSwitchList(void) { int i; int index; int episode; episode = 1; if (gamemode != shareware) episode = 2; for (index = 0, i = 0; i < MAXSWITCHES; i++) { if (!alphSwitchList[i].episode) { numswitches = index / 2; switchlist[index] = -1; break; } if (alphSwitchList[i].episode <= episode) { switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name1)); switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name2)); } } } //================================================================== // // Start a button counting down till it turns off. // //================================================================== void P_StartButton(line_t * line, bwhere_e w, int texture, int time) { int i; for (i = 0; i < MAXBUTTONS; i++) if (!buttonlist[i].btimer) { buttonlist[i].line = line; buttonlist[i].where = w; buttonlist[i].btexture = texture; buttonlist[i].btimer = time; buttonlist[i].soundorg = &line->frontsector->soundorg; return; } I_Error("P_StartButton: no button slots left!"); } //================================================================== // // Function that changes wall texture. // Tell it if switch is ok to use again (1=yes, it's a button). // //================================================================== void P_ChangeSwitchTexture(line_t * line, int useAgain) { int texTop; int texMid; int texBot; int i; int sound; if (!useAgain) line->special = 0; texTop = sides[line->sidenum[0]].toptexture; texMid = sides[line->sidenum[0]].midtexture; texBot = sides[line->sidenum[0]].bottomtexture; sound = sfx_switch; //if (line->special == 11) // EXIT SWITCH? // sound = sfx_swtchx; for (i = 0; i < numswitches * 2; i++) if (switchlist[i] == texTop) { S_StartSound(buttonlist->soundorg, sound); sides[line->sidenum[0]].toptexture = switchlist[i ^ 1]; if (useAgain) P_StartButton(line, top, switchlist[i], BUTTONTIME); return; } else if (switchlist[i] == texMid) { S_StartSound(buttonlist->soundorg, sound); sides[line->sidenum[0]].midtexture = switchlist[i ^ 1]; if (useAgain) P_StartButton(line, middle, switchlist[i], BUTTONTIME); return; } else if (switchlist[i] == texBot) { S_StartSound(buttonlist->soundorg, sound); sides[line->sidenum[0]].bottomtexture = switchlist[i ^ 1]; if (useAgain) P_StartButton(line, bottom, switchlist[i], BUTTONTIME); return; } } /* ============================================================================== = = P_UseSpecialLine = = Called when a thing uses a special line = Only the front sides of lines are usable =============================================================================== */ boolean P_UseSpecialLine(mobj_t * thing, line_t * line) { // // Switches that other things can activate // if (!thing->player) { if (line->flags & ML_SECRET) return false; // never open secret doors switch (line->special) { case 1: // MANUAL DOOR RAISE case 32: // MANUAL BLUE case 33: // MANUAL RED case 34: // MANUAL YELLOW break; default: return false; } } // // do something // switch (line->special) { //=============================================== // MANUALS //=============================================== case 1: // Vertical Door case 26: // Blue Door/Locked case 27: // Yellow Door /Locked case 28: // Red Door /Locked case 31: // Manual door open case 32: // Blue locked door open case 33: // Red locked door open case 34: // Yellow locked door open EV_VerticalDoor(line, thing); break; //=============================================== // SWITCHES //=============================================== case 7: // Switch_Build_Stairs (8 pixel steps) if (EV_BuildStairs(line, 8 * FRACUNIT)) { P_ChangeSwitchTexture(line, 0); } break; case 107: // Switch_Build_Stairs_16 (16 pixel steps) if (EV_BuildStairs(line, 16 * FRACUNIT)) { P_ChangeSwitchTexture(line, 0); } break; case 9: // Change Donut if (EV_DoDonut(line)) P_ChangeSwitchTexture(line, 0); break; case 11: // Exit level G_ExitLevel(); P_ChangeSwitchTexture(line, 0); break; case 14: // Raise Floor 32 and change texture if (EV_DoPlat(line, raiseAndChange, 32)) P_ChangeSwitchTexture(line, 0); break; case 15: // Raise Floor 24 and change texture if (EV_DoPlat(line, raiseAndChange, 24)) P_ChangeSwitchTexture(line, 0); break; case 18: // Raise Floor to next highest floor if (EV_DoFloor(line, raiseFloorToNearest)) P_ChangeSwitchTexture(line, 0); break; case 20: // Raise Plat next highest floor and change texture if (EV_DoPlat(line, raiseToNearestAndChange, 0)) P_ChangeSwitchTexture(line, 0); break; case 21: // PlatDownWaitUpStay if (EV_DoPlat(line, downWaitUpStay, 0)) P_ChangeSwitchTexture(line, 0); break; case 23: // Lower Floor to Lowest if (EV_DoFloor(line, lowerFloorToLowest)) P_ChangeSwitchTexture(line, 0); break; case 29: // Raise Door if (EV_DoDoor(line, vld_normal, VDOORSPEED)) P_ChangeSwitchTexture(line, 0); break; case 41: // Lower Ceiling to Floor if (EV_DoCeiling(line, lowerToFloor)) P_ChangeSwitchTexture(line, 0); break; case 71: // Turbo Lower Floor if (EV_DoFloor(line, turboLower)) P_ChangeSwitchTexture(line, 0); break; case 49: // Lower Ceiling And Crush if (EV_DoCeiling(line, lowerAndCrush)) P_ChangeSwitchTexture(line, 0); break; case 50: // Close Door if (EV_DoDoor(line, vld_close, VDOORSPEED)) P_ChangeSwitchTexture(line, 0); break; case 51: // Secret EXIT G_SecretExitLevel(); P_ChangeSwitchTexture(line, 0); break; case 55: // Raise Floor Crush if (EV_DoFloor(line, raiseFloorCrush)) P_ChangeSwitchTexture(line, 0); break; case 101: // Raise Floor if (EV_DoFloor(line, raiseFloor)) P_ChangeSwitchTexture(line, 0); break; case 102: // Lower Floor to Surrounding floor height if (EV_DoFloor(line, lowerFloor)) P_ChangeSwitchTexture(line, 0); break; case 103: // Open Door if (EV_DoDoor(line, vld_open, VDOORSPEED)) P_ChangeSwitchTexture(line, 0); break; //=============================================== // BUTTONS //=============================================== case 42: // Close Door if (EV_DoDoor(line, vld_close, VDOORSPEED)) P_ChangeSwitchTexture(line, 1); break; case 43: // Lower Ceiling to Floor if (EV_DoCeiling(line, lowerToFloor)) P_ChangeSwitchTexture(line, 1); break; case 45: // Lower Floor to Surrounding floor height if (EV_DoFloor(line, lowerFloor)) P_ChangeSwitchTexture(line, 1); break; case 60: // Lower Floor to Lowest if (EV_DoFloor(line, lowerFloorToLowest)) P_ChangeSwitchTexture(line, 1); break; case 61: // Open Door if (EV_DoDoor(line, vld_open, VDOORSPEED)) P_ChangeSwitchTexture(line, 1); break; case 62: // PlatDownWaitUpStay if (EV_DoPlat(line, downWaitUpStay, 1)) P_ChangeSwitchTexture(line, 1); break; case 63: // Raise Door if (EV_DoDoor(line, vld_normal, VDOORSPEED)) P_ChangeSwitchTexture(line, 1); break; case 64: // Raise Floor to ceiling if (EV_DoFloor(line, raiseFloor)) P_ChangeSwitchTexture(line, 1); break; case 66: // Raise Floor 24 and change texture if (EV_DoPlat(line, raiseAndChange, 24)) P_ChangeSwitchTexture(line, 1); break; case 67: // Raise Floor 32 and change texture if (EV_DoPlat(line, raiseAndChange, 32)) P_ChangeSwitchTexture(line, 1); break; case 65: // Raise Floor Crush if (EV_DoFloor(line, raiseFloorCrush)) P_ChangeSwitchTexture(line, 1); break; case 68: // Raise Plat to next highest floor and change texture if (EV_DoPlat(line, raiseToNearestAndChange, 0)) P_ChangeSwitchTexture(line, 1); break; case 69: // Raise Floor to next highest floor if (EV_DoFloor(line, raiseFloorToNearest)) P_ChangeSwitchTexture(line, 1); break; case 70: // Turbo Lower Floor if (EV_DoFloor(line, turboLower)) P_ChangeSwitchTexture(line, 1); break; } return true; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_telept.c000066400000000000000000000113001257432200600234720ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_telept.c #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" //---------------------------------------------------------------------------- // // FUNC P_Teleport // //---------------------------------------------------------------------------- boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle) { fixed_t oldx; fixed_t oldy; fixed_t oldz; fixed_t aboveFloor; fixed_t fogDelta; player_t *player; unsigned an; mobj_t *fog; oldx = thing->x; oldy = thing->y; oldz = thing->z; aboveFloor = thing->z - thing->floorz; if (!P_TeleportMove(thing, x, y)) { return (false); } if (thing->player) { player = thing->player; if (player->powers[pw_flight] && aboveFloor) { thing->z = thing->floorz + aboveFloor; if (thing->z + thing->height > thing->ceilingz) { thing->z = thing->ceilingz - thing->height; } player->viewz = thing->z + player->viewheight; } else { thing->z = thing->floorz; player->viewz = thing->z + player->viewheight; player->lookdir = 0; } } else if (thing->flags & MF_MISSILE) { thing->z = thing->floorz + aboveFloor; if (thing->z + thing->height > thing->ceilingz) { thing->z = thing->ceilingz - thing->height; } } else { thing->z = thing->floorz; } // Spawn teleport fog at source and destination fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; fog = P_SpawnMobj(oldx, oldy, oldz + fogDelta, MT_TFOG); S_StartSound(fog, sfx_telept); an = angle >> ANGLETOFINESHIFT; fog = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an], thing->z + fogDelta, MT_TFOG); S_StartSound(fog, sfx_telept); if (thing->player && !thing->player->powers[pw_weaponlevel2]) { // Freeze player for about .5 sec thing->reactiontime = 18; } thing->angle = angle; if (thing->flags2 & MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID) { thing->flags2 |= MF2_FEETARECLIPPED; } else if (thing->flags2 & MF2_FEETARECLIPPED) { thing->flags2 &= ~MF2_FEETARECLIPPED; } if (thing->flags & MF_MISSILE) { angle >>= ANGLETOFINESHIFT; thing->momx = FixedMul(thing->info->speed, finecosine[angle]); thing->momy = FixedMul(thing->info->speed, finesine[angle]); } else { thing->momx = thing->momy = thing->momz = 0; } return (true); } //---------------------------------------------------------------------------- // // FUNC EV_Teleport // //---------------------------------------------------------------------------- boolean EV_Teleport(line_t * line, int side, mobj_t * thing) { int i; int tag; mobj_t *m; thinker_t *thinker; sector_t *sector; if (thing->flags2 & MF2_NOTELEPORT) { return (false); } if (side == 1) { // Don't teleport when crossing back side return (false); } tag = line->tag; for (i = 0; i < numsectors; i++) { if (sectors[i].tag == tag) { thinker = thinkercap.next; for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { if (thinker->function != P_MobjThinker) { // Not a mobj continue; } m = (mobj_t *) thinker; if (m->type != MT_TELEPORTMAN) { // Not a teleportman continue; } sector = m->subsector->sector; if (sector - sectors != i) { // Wrong sector continue; } return (P_Teleport(thing, m->x, m->y, m->angle)); } } } return (false); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_tick.c000066400000000000000000000065221257432200600231410ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_tick.c #include "doomdef.h" #include "i_system.h" #include "p_local.h" #include "v_video.h" int leveltime; int TimerGame; /* =============================================================================== THINKERS All thinkers should be allocated by Z_Malloc so they can be operated on uniformly. The actual structures will vary in size, but the first element must be thinker_t. =============================================================================== */ thinker_t thinkercap; // both the head and tail of the thinker list /* =============== = = P_InitThinkers = =============== */ void P_InitThinkers(void) { thinkercap.prev = thinkercap.next = &thinkercap; } /* =============== = = P_AddThinker = = Adds a new thinker at the end of the list = =============== */ void P_AddThinker(thinker_t * thinker) { thinkercap.prev->next = thinker; thinker->next = &thinkercap; thinker->prev = thinkercap.prev; thinkercap.prev = thinker; } /* =============== = = P_RemoveThinker = = Deallocation is lazy -- it will not actually be freed until its = thinking turn comes up = =============== */ void P_RemoveThinker(thinker_t * thinker) { thinker->function = (think_t) - 1; } /* =============== = = P_AllocateThinker = = Allocates memory and adds a new thinker at the end of the list = =============== */ void P_AllocateThinker(thinker_t * thinker) { } /* =============== = = P_RunThinkers = =============== */ void P_RunThinkers(void) { thinker_t *currentthinker, *nextthinker; currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { if (currentthinker->function == (think_t) - 1) { // time to remove it nextthinker = currentthinker->next; currentthinker->next->prev = currentthinker->prev; currentthinker->prev->next = currentthinker->next; Z_Free(currentthinker); } else { if (currentthinker->function) currentthinker->function(currentthinker); nextthinker = currentthinker->next; } currentthinker = nextthinker; } } //---------------------------------------------------------------------------- // // PROC P_Ticker // //---------------------------------------------------------------------------- void P_Ticker(void) { int i; if (paused) { return; } for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { P_PlayerThink(&players[i]); } } if (TimerGame) { if (!--TimerGame) { G_ExitLevel(); } } P_RunThinkers(); P_UpdateSpecials(); P_AmbientSound(); leveltime++; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/p_user.c000066400000000000000000000667161257432200600232000ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // P_user.c #include #include "doomdef.h" #include "deh_str.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" void P_PlayerNextArtifact(player_t * player); // Macros #define MAXBOB 0x100000 // 16 pixels of bob // Data boolean onground; int newtorch; // used in the torch flicker effect. int newtorchdelta; boolean WeaponInShareware[] = { true, // Staff true, // Gold wand true, // Crossbow true, // Blaster false, // Skull rod false, // Phoenix rod false, // Mace true, // Gauntlets true // Beak }; /* ================== = = P_Thrust = = moves the given origin along a given angle = ================== */ void P_Thrust(player_t * player, angle_t angle, fixed_t move) { angle >>= ANGLETOFINESHIFT; if (player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz)) { player->mo->momx += FixedMul(move, finecosine[angle]); player->mo->momy += FixedMul(move, finesine[angle]); } else if (player->mo->subsector->sector->special == 15) // Friction_Low { player->mo->momx += FixedMul(move >> 2, finecosine[angle]); player->mo->momy += FixedMul(move >> 2, finesine[angle]); } else { player->mo->momx += FixedMul(move, finecosine[angle]); player->mo->momy += FixedMul(move, finesine[angle]); } } /* ================== = = P_CalcHeight = =Calculate the walking / running height adjustment = ================== */ void P_CalcHeight(player_t * player) { int angle; fixed_t bob; // // regular movement bobbing (needs to be calculated for gun swing even // if not on ground) // OPTIMIZE: tablify angle player->bob = FixedMul(player->mo->momx, player->mo->momx) + FixedMul(player->mo->momy, player->mo->momy); player->bob >>= 2; if (player->bob > MAXBOB) player->bob = MAXBOB; if (player->mo->flags2 & MF2_FLY && !onground) { player->bob = FRACUNIT / 2; } if ((player->cheats & CF_NOMOMENTUM)) { player->viewz = player->mo->z + VIEWHEIGHT; if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT) player->viewz = player->mo->ceilingz - 4 * FRACUNIT; player->viewz = player->mo->z + player->viewheight; return; } angle = (FINEANGLES / 20 * leveltime) & FINEMASK; bob = FixedMul(player->bob / 2, finesine[angle]); // // move viewheight // if (player->playerstate == PST_LIVE) { player->viewheight += player->deltaviewheight; if (player->viewheight > VIEWHEIGHT) { player->viewheight = VIEWHEIGHT; player->deltaviewheight = 0; } if (player->viewheight < VIEWHEIGHT / 2) { player->viewheight = VIEWHEIGHT / 2; if (player->deltaviewheight <= 0) player->deltaviewheight = 1; } if (player->deltaviewheight) { player->deltaviewheight += FRACUNIT / 4; if (!player->deltaviewheight) player->deltaviewheight = 1; } } if (player->chickenTics) { player->viewz = player->mo->z + player->viewheight - (20 * FRACUNIT); } else { player->viewz = player->mo->z + player->viewheight + bob; } if (player->mo->flags2 & MF2_FEETARECLIPPED && player->playerstate != PST_DEAD && player->mo->z <= player->mo->floorz) { player->viewz -= FOOTCLIPSIZE; } if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT) { player->viewz = player->mo->ceilingz - 4 * FRACUNIT; } if (player->viewz < player->mo->floorz + 4 * FRACUNIT) { player->viewz = player->mo->floorz + 4 * FRACUNIT; } } /* ================= = = P_MovePlayer = ================= */ void P_MovePlayer(player_t * player) { int look; int fly; ticcmd_t *cmd; cmd = &player->cmd; player->mo->angle += (cmd->angleturn << 16); onground = (player->mo->z <= player->mo->floorz || (player->mo->flags2 & MF2_ONMOBJ)); if (player->chickenTics) { // Chicken speed if (cmd->forwardmove && (onground || player->mo->flags2 & MF2_FLY)) P_Thrust(player, player->mo->angle, cmd->forwardmove * 2500); if (cmd->sidemove && (onground || player->mo->flags2 & MF2_FLY)) P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2500); } else { // Normal speed if (cmd->forwardmove && (onground || player->mo->flags2 & MF2_FLY)) P_Thrust(player, player->mo->angle, cmd->forwardmove * 2048); if (cmd->sidemove && (onground || player->mo->flags2 & MF2_FLY)) P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2048); } if (cmd->forwardmove || cmd->sidemove) { if (player->chickenTics) { if (player->mo->state == &states[S_CHICPLAY]) { P_SetMobjState(player->mo, S_CHICPLAY_RUN1); } } else { if (player->mo->state == &states[S_PLAY]) { P_SetMobjState(player->mo, S_PLAY_RUN1); } } } look = cmd->lookfly & 15; if (look > 7) { look -= 16; } if (look) { if (look == TOCENTER) { player->centering = true; } else { player->lookdir += 5 * look; if (player->lookdir > 90 || player->lookdir < -110) { player->lookdir -= 5 * look; } } } if (player->centering) { if (player->lookdir > 0) { player->lookdir -= 8; } else if (player->lookdir < 0) { player->lookdir += 8; } if (abs(player->lookdir) < 8) { player->lookdir = 0; player->centering = false; } } fly = cmd->lookfly >> 4; if (fly > 7) { fly -= 16; } if (fly && player->powers[pw_flight]) { if (fly != TOCENTER) { player->flyheight = fly * 2; if (!(player->mo->flags2 & MF2_FLY)) { player->mo->flags2 |= MF2_FLY; player->mo->flags |= MF_NOGRAVITY; } } else { player->mo->flags2 &= ~MF2_FLY; player->mo->flags &= ~MF_NOGRAVITY; } } else if (fly > 0) { P_PlayerUseArtifact(player, arti_fly); } if (player->mo->flags2 & MF2_FLY) { player->mo->momz = player->flyheight * FRACUNIT; if (player->flyheight) { player->flyheight /= 2; } } } /* ================= = = P_DeathThink = ================= */ #define ANG5 (ANG90/18) extern int inv_ptr; extern int curpos; void P_DeathThink(player_t * player) { angle_t angle, delta; int lookDelta; P_MovePsprites(player); onground = (player->mo->z <= player->mo->floorz); if (player->mo->type == MT_BLOODYSKULL) { // Flying bloody skull player->viewheight = 6 * FRACUNIT; player->deltaviewheight = 0; //player->damagecount = 20; if (onground) { if (player->lookdir < 60) { lookDelta = (60 - player->lookdir) / 8; if (lookDelta < 1 && (leveltime & 1)) { lookDelta = 1; } else if (lookDelta > 6) { lookDelta = 6; } player->lookdir += lookDelta; } } } else { // Fall to ground player->deltaviewheight = 0; if (player->viewheight > 6 * FRACUNIT) player->viewheight -= FRACUNIT; if (player->viewheight < 6 * FRACUNIT) player->viewheight = 6 * FRACUNIT; if (player->lookdir > 0) { player->lookdir -= 6; } else if (player->lookdir < 0) { player->lookdir += 6; } if (abs(player->lookdir) < 6) { player->lookdir = 0; } } P_CalcHeight(player); if (player->attacker && player->attacker != player->mo) { angle = R_PointToAngle2(player->mo->x, player->mo->y, player->attacker->x, player->attacker->y); delta = angle - player->mo->angle; if (delta < ANG5 || delta > (unsigned) -ANG5) { // Looking at killer, so fade damage flash down player->mo->angle = angle; if (player->damagecount) { player->damagecount--; } } else if (delta < ANG180) player->mo->angle += ANG5; else player->mo->angle -= ANG5; } else if (player->damagecount) { player->damagecount--; } if (player->cmd.buttons & BT_USE) { if (player == &players[consoleplayer]) { I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE)); inv_ptr = 0; curpos = 0; newtorch = 0; newtorchdelta = 0; } player->playerstate = PST_REBORN; // Let the mobj know the player has entered the reborn state. Some // mobjs need to know when it's ok to remove themselves. player->mo->special2.i = 666; } } //---------------------------------------------------------------------------- // // PROC P_ChickenPlayerThink // //---------------------------------------------------------------------------- void P_ChickenPlayerThink(player_t * player) { mobj_t *pmo; if (player->health > 0) { // Handle beak movement P_UpdateBeak(player, &player->psprites[ps_weapon]); } if (player->chickenTics & 15) { return; } pmo = player->mo; if (!(pmo->momx + pmo->momy) && P_Random() < 160) { // Twitch view angle pmo->angle += (P_Random() - P_Random()) << 19; } if ((pmo->z <= pmo->floorz) && (P_Random() < 32)) { // Jump and noise pmo->momz += FRACUNIT; P_SetMobjState(pmo, S_CHICPLAY_PAIN); return; } if (P_Random() < 48) { // Just noise S_StartSound(pmo, sfx_chicact); } } //---------------------------------------------------------------------------- // // FUNC P_GetPlayerNum // //---------------------------------------------------------------------------- int P_GetPlayerNum(player_t * player) { int i; for (i = 0; i < MAXPLAYERS; i++) { if (player == &players[i]) { return (i); } } return (0); } //---------------------------------------------------------------------------- // // FUNC P_UndoPlayerChicken // //---------------------------------------------------------------------------- boolean P_UndoPlayerChicken(player_t * player) { mobj_t *fog; mobj_t *mo; mobj_t *pmo; fixed_t x; fixed_t y; fixed_t z; angle_t angle; int playerNum; weapontype_t weapon; int oldFlags; int oldFlags2; pmo = player->mo; x = pmo->x; y = pmo->y; z = pmo->z; angle = pmo->angle; weapon = pmo->special1.i; oldFlags = pmo->flags; oldFlags2 = pmo->flags2; P_SetMobjState(pmo, S_FREETARGMOBJ); mo = P_SpawnMobj(x, y, z, MT_PLAYER); if (P_TestMobjLocation(mo) == false) { // Didn't fit P_RemoveMobj(mo); mo = P_SpawnMobj(x, y, z, MT_CHICPLAYER); mo->angle = angle; mo->health = player->health; mo->special1.i = weapon; mo->player = player; mo->flags = oldFlags; mo->flags2 = oldFlags2; player->mo = mo; player->chickenTics = 2 * 35; return (false); } playerNum = P_GetPlayerNum(player); if (playerNum != 0) { // Set color translation mo->flags |= playerNum << MF_TRANSSHIFT; } mo->angle = angle; mo->player = player; mo->reactiontime = 18; if (oldFlags2 & MF2_FLY) { mo->flags2 |= MF2_FLY; mo->flags |= MF_NOGRAVITY; } player->chickenTics = 0; player->powers[pw_weaponlevel2] = 0; player->health = mo->health = MAXHEALTH; player->mo = mo; angle >>= ANGLETOFINESHIFT; fog = P_SpawnMobj(x + 20 * finecosine[angle], y + 20 * finesine[angle], z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, sfx_telept); P_PostChickenWeapon(player, weapon); return (true); } //---------------------------------------------------------------------------- // // PROC P_PlayerThink // //---------------------------------------------------------------------------- void P_PlayerThink(player_t * player) { ticcmd_t *cmd; weapontype_t newweapon; // No-clip cheat if (player->cheats & CF_NOCLIP) { player->mo->flags |= MF_NOCLIP; } else { player->mo->flags &= ~MF_NOCLIP; } cmd = &player->cmd; if (player->mo->flags & MF_JUSTATTACKED) { // Gauntlets attack auto forward motion cmd->angleturn = 0; cmd->forwardmove = 0xc800 / 512; cmd->sidemove = 0; player->mo->flags &= ~MF_JUSTATTACKED; } // messageTics is above the rest of the counters so that messages will // go away, even in death. player->messageTics--; // Can go negative if (!player->messageTics) { // Refresh the screen when a message goes away ultimatemsg = false; // clear out any chat messages. BorderTopRefresh = true; } if (player->playerstate == PST_DEAD) { P_DeathThink(player); return; } if (player->chickenTics) { P_ChickenPlayerThink(player); } // Handle movement if (player->mo->reactiontime) { // Player is frozen player->mo->reactiontime--; } else { P_MovePlayer(player); } P_CalcHeight(player); if (player->mo->subsector->sector->special) { P_PlayerInSpecialSector(player); } if (cmd->arti) { // Use an artifact if (cmd->arti == 0xff) { P_PlayerNextArtifact(player); } else { P_PlayerUseArtifact(player, cmd->arti); } } // Check for weapon change if (cmd->buttons & BT_SPECIAL) { // A special event has no other buttons cmd->buttons = 0; } if (cmd->buttons & BT_CHANGE) { // The actual changing of the weapon is done when the weapon // psprite can do it (A_WeaponReady), so it doesn't happen in // the middle of an attack. newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT; if (newweapon == wp_staff && player->weaponowned[wp_gauntlets] && !(player->readyweapon == wp_gauntlets)) { newweapon = wp_gauntlets; } if (player->weaponowned[newweapon] && newweapon != player->readyweapon) { if (WeaponInShareware[newweapon] || gamemode != shareware) { player->pendingweapon = newweapon; } } } // Check for use if (cmd->buttons & BT_USE) { if (!player->usedown) { P_UseLines(player); player->usedown = true; } } else { player->usedown = false; } // Chicken counter if (player->chickenTics) { if (player->chickenPeck) { // Chicken attack counter player->chickenPeck -= 3; } if (!--player->chickenTics) { // Attempt to undo the chicken P_UndoPlayerChicken(player); } } // Cycle psprites P_MovePsprites(player); // Other Counters if (player->powers[pw_invulnerability]) { player->powers[pw_invulnerability]--; } if (player->powers[pw_invisibility]) { if (!--player->powers[pw_invisibility]) { player->mo->flags &= ~MF_SHADOW; } } if (player->powers[pw_infrared]) { player->powers[pw_infrared]--; } if (player->powers[pw_flight]) { if (!--player->powers[pw_flight]) { // haleyjd: removed externdriver crap if (player->mo->z != player->mo->floorz) { player->centering = true; } player->mo->flags2 &= ~MF2_FLY; player->mo->flags &= ~MF_NOGRAVITY; BorderTopRefresh = true; //make sure the sprite's cleared out } } if (player->powers[pw_weaponlevel2]) { if (!--player->powers[pw_weaponlevel2]) { if ((player->readyweapon == wp_phoenixrod) && (player->psprites[ps_weapon].state != &states[S_PHOENIXREADY]) && (player->psprites[ps_weapon].state != &states[S_PHOENIXUP])) { P_SetPsprite(player, ps_weapon, S_PHOENIXREADY); player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2; player->refire = 0; } else if ((player->readyweapon == wp_gauntlets) || (player->readyweapon == wp_staff)) { player->pendingweapon = player->readyweapon; } BorderTopRefresh = true; } } if (player->damagecount) { player->damagecount--; } if (player->bonuscount) { player->bonuscount--; } // Colormaps if (player->powers[pw_invulnerability]) { if (player->powers[pw_invulnerability] > BLINKTHRESHOLD || (player->powers[pw_invulnerability] & 8)) { player->fixedcolormap = INVERSECOLORMAP; } else { player->fixedcolormap = 0; } } else if (player->powers[pw_infrared]) { if (player->powers[pw_infrared] <= BLINKTHRESHOLD) { if (player->powers[pw_infrared] & 8) { player->fixedcolormap = 0; } else { player->fixedcolormap = 1; } } else if (!(leveltime & 16) && player == &players[consoleplayer]) { if (newtorch) { if (player->fixedcolormap + newtorchdelta > 7 || player->fixedcolormap + newtorchdelta < 1 || newtorch == player->fixedcolormap) { newtorch = 0; } else { player->fixedcolormap += newtorchdelta; } } else { newtorch = (M_Random() & 7) + 1; newtorchdelta = (newtorch == player->fixedcolormap) ? 0 : ((newtorch > player->fixedcolormap) ? 1 : -1); } } } else { player->fixedcolormap = 0; } } //---------------------------------------------------------------------------- // // PROC P_ArtiTele // //---------------------------------------------------------------------------- void P_ArtiTele(player_t * player) { int i; int selections; fixed_t destX; fixed_t destY; angle_t destAngle; if (deathmatch) { selections = deathmatch_p - deathmatchstarts; i = P_Random() % selections; destX = deathmatchstarts[i].x << FRACBITS; destY = deathmatchstarts[i].y << FRACBITS; destAngle = ANG45 * (deathmatchstarts[i].angle / 45); } else { destX = playerstarts[0].x << FRACBITS; destY = playerstarts[0].y << FRACBITS; destAngle = ANG45 * (playerstarts[0].angle / 45); } P_Teleport(player->mo, destX, destY, destAngle); S_StartSound(NULL, sfx_wpnup); // Full volume laugh } //---------------------------------------------------------------------------- // // PROC P_PlayerNextArtifact // //---------------------------------------------------------------------------- void P_PlayerNextArtifact(player_t * player) { if (player == &players[consoleplayer]) { inv_ptr--; if (inv_ptr < 6) { curpos--; if (curpos < 0) { curpos = 0; } } if (inv_ptr < 0) { inv_ptr = player->inventorySlotNum - 1; if (inv_ptr < 6) { curpos = inv_ptr; } else { curpos = 6; } } player->readyArtifact = player->inventory[inv_ptr].type; } } //---------------------------------------------------------------------------- // // PROC P_PlayerRemoveArtifact // //---------------------------------------------------------------------------- void P_PlayerRemoveArtifact(player_t * player, int slot) { int i; player->artifactCount--; if (!(--player->inventory[slot].count)) { // Used last of a type - compact the artifact list player->readyArtifact = arti_none; player->inventory[slot].type = arti_none; for (i = slot + 1; i < player->inventorySlotNum; i++) { player->inventory[i - 1] = player->inventory[i]; } player->inventorySlotNum--; if (player == &players[consoleplayer]) { // Set position markers and get next readyArtifact inv_ptr--; if (inv_ptr < 6) { curpos--; if (curpos < 0) { curpos = 0; } } if (inv_ptr >= player->inventorySlotNum) { inv_ptr = player->inventorySlotNum - 1; } if (inv_ptr < 0) { inv_ptr = 0; } player->readyArtifact = player->inventory[inv_ptr].type; } } } //---------------------------------------------------------------------------- // // PROC P_PlayerUseArtifact // //---------------------------------------------------------------------------- void P_PlayerUseArtifact(player_t * player, artitype_t arti) { int i; for (i = 0; i < player->inventorySlotNum; i++) { if (player->inventory[i].type == arti) { // Found match - try to use if (P_UseArtifact(player, arti)) { // Artifact was used - remove it from inventory P_PlayerRemoveArtifact(player, i); if (player == &players[consoleplayer]) { S_StartSound(NULL, sfx_artiuse); ArtifactFlash = 4; } } else { // Unable to use artifact, advance pointer P_PlayerNextArtifact(player); } break; } } } //---------------------------------------------------------------------------- // // FUNC P_UseArtifact // // Returns true if artifact was used. // //---------------------------------------------------------------------------- boolean P_UseArtifact(player_t * player, artitype_t arti) { mobj_t *mo; angle_t angle; switch (arti) { case arti_invulnerability: if (!P_GivePower(player, pw_invulnerability)) { return (false); } break; case arti_invisibility: if (!P_GivePower(player, pw_invisibility)) { return (false); } break; case arti_health: if (!P_GiveBody(player, 25)) { return (false); } break; case arti_superhealth: if (!P_GiveBody(player, 100)) { return (false); } break; case arti_tomeofpower: if (player->chickenTics) { // Attempt to undo chicken if (P_UndoPlayerChicken(player) == false) { // Failed P_DamageMobj(player->mo, NULL, NULL, 10000); } else { // Succeeded player->chickenTics = 0; S_StartSound(player->mo, sfx_wpnup); } } else { if (!P_GivePower(player, pw_weaponlevel2)) { return (false); } if (player->readyweapon == wp_staff) { P_SetPsprite(player, ps_weapon, S_STAFFREADY2_1); } else if (player->readyweapon == wp_gauntlets) { P_SetPsprite(player, ps_weapon, S_GAUNTLETREADY2_1); } } break; case arti_torch: if (!P_GivePower(player, pw_infrared)) { return (false); } break; case arti_firebomb: angle = player->mo->angle >> ANGLETOFINESHIFT; // Vanilla bug here: // Original code here looks like: // (player->mo->flags2 & MF2_FEETARECLIPPED != 0), // Which under C's operator precedence is: // (player->mo->flags2 & (MF2_FEETARECLIPPED != 0)), // Which simplifies to: // (player->mo->flags2 & 1), mo = P_SpawnMobj(player->mo->x + 24 * finecosine[angle], player->mo->y + 24 * finesine[angle], player->mo->z - 15 * FRACUNIT * (player->mo->flags2 & 1), MT_FIREBOMB); mo->target = player->mo; break; case arti_egg: mo = player->mo; P_SpawnPlayerMissile(mo, MT_EGGFX); P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 6)); P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 6)); P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 3)); P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 3)); break; case arti_fly: if (!P_GivePower(player, pw_flight)) { return (false); } break; case arti_teleport: P_ArtiTele(player); break; default: return (false); } return (true); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_bsp.c000066400000000000000000000270131257432200600227730ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // R_bsp.c #include "doomdef.h" #include "m_bbox.h" #include "r_local.h" seg_t *curline; side_t *sidedef; line_t *linedef; sector_t *frontsector, *backsector; drawseg_t drawsegs[MAXDRAWSEGS], *ds_p; void R_StoreWallRange(int start, int stop); /* ==================== = = R_ClearDrawSegs = ==================== */ void R_ClearDrawSegs(void) { ds_p = drawsegs; } //============================================================================= /* =============================================================================== = = ClipWallSegment = = Clips the given range of columns and includes it in the new clip list =============================================================================== */ typedef struct { int first, last; } cliprange_t; #define MAXSEGS 32 cliprange_t solidsegs[MAXSEGS], *newend; // newend is one past the last valid seg void R_ClipSolidWallSegment(int first, int last) { cliprange_t *next, *start; // find the first range that touches the range (adjacent pixels are touching) start = solidsegs; while (start->last < first - 1) start++; if (first < start->first) { if (last < start->first - 1) { // post is entirely visible (above start), so insert a new clippost R_StoreWallRange(first, last); next = newend; newend++; while (next != start) { *next = *(next - 1); next--; } next->first = first; next->last = last; return; } // there is a fragment above *start R_StoreWallRange(first, start->first - 1); start->first = first; // adjust the clip size } if (last <= start->last) return; // bottom contained in start next = start; while (last >= (next + 1)->first - 1) { // there is a fragment between two posts R_StoreWallRange(next->last + 1, (next + 1)->first - 1); next++; if (last <= next->last) { // bottom is contained in next start->last = next->last; // adjust the clip size goto crunch; } } // there is a fragment after *next R_StoreWallRange(next->last + 1, last); start->last = last; // adjust the clip size // remove start+1 to next from the clip list, // because start now covers their area crunch: if (next == start) return; // post just extended past the bottom of one post while (next++ != newend) // remove a post *++start = *next; newend = start + 1; } /* =============================================================================== = = R_ClipPassWallSegment = = Clips the given range of columns, but does not includes it in the clip list =============================================================================== */ void R_ClipPassWallSegment(int first, int last) { cliprange_t *start; // find the first range that touches the range (adjacent pixels are touching) start = solidsegs; while (start->last < first - 1) start++; if (first < start->first) { if (last < start->first - 1) { // post is entirely visible (above start) R_StoreWallRange(first, last); return; } // there is a fragment above *start R_StoreWallRange(first, start->first - 1); } if (last <= start->last) return; // bottom contained in start while (last >= (start + 1)->first - 1) { // there is a fragment between two posts R_StoreWallRange(start->last + 1, (start + 1)->first - 1); start++; if (last <= start->last) return; } // there is a fragment after *next R_StoreWallRange(start->last + 1, last); } /* ==================== = = R_ClearClipSegs = ==================== */ void R_ClearClipSegs(void) { solidsegs[0].first = -0x7fffffff; solidsegs[0].last = -1; solidsegs[1].first = viewwidth; solidsegs[1].last = 0x7fffffff; newend = solidsegs + 2; } //============================================================================= /* ====================== = = R_AddLine = = Clips the given segment and adds any visible pieces to the line list = ====================== */ void R_AddLine(seg_t * line) { int x1, x2; angle_t angle1, angle2, span, tspan; curline = line; // OPTIMIZE: quickly reject orthogonal back sides angle1 = R_PointToAngle(line->v1->x, line->v1->y); angle2 = R_PointToAngle(line->v2->x, line->v2->y); // // clip to view edges // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW) span = angle1 - angle2; if (span >= ANG180) return; // back side rw_angle1 = angle1; // global angle needed by segcalc angle1 -= viewangle; angle2 -= viewangle; tspan = angle1 + clipangle; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return; // totally off the left edge angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return; // totally off the left edge angle2 = -clipangle; } // // the seg is in the view range, but not necessarily visible // angle1 = (angle1 + ANG90) >> ANGLETOFINESHIFT; angle2 = (angle2 + ANG90) >> ANGLETOFINESHIFT; x1 = viewangletox[angle1]; x2 = viewangletox[angle2]; if (x1 == x2) return; // does not cross a pixel backsector = line->backsector; if (!backsector) goto clipsolid; // single sided line if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) goto clipsolid; // closed door if (backsector->ceilingheight != frontsector->ceilingheight || backsector->floorheight != frontsector->floorheight) goto clippass; // window // reject empty lines used for triggers and special events if (backsector->ceilingpic == frontsector->ceilingpic && backsector->floorpic == frontsector->floorpic && backsector->lightlevel == frontsector->lightlevel && curline->sidedef->midtexture == 0) return; clippass: R_ClipPassWallSegment(x1, x2 - 1); return; clipsolid: R_ClipSolidWallSegment(x1, x2 - 1); } //============================================================================ /* =============================================================================== = = R_CheckBBox = = Returns true if some part of the bbox might be visible = =============================================================================== */ int checkcoord[12][4] = { {3, 0, 2, 1}, {3, 0, 2, 0}, {3, 1, 2, 0}, {0}, {2, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 3, 0}, {0}, {2, 0, 3, 1}, {2, 1, 3, 1}, {2, 1, 3, 0} }; boolean R_CheckBBox(fixed_t * bspcoord) { int boxx, boxy, boxpos; fixed_t x1, y1, x2, y2; angle_t angle1, angle2, span, tspan; cliprange_t *start; int sx1, sx2; // find the corners of the box that define the edges from current viewpoint if (viewx <= bspcoord[BOXLEFT]) boxx = 0; else if (viewx < bspcoord[BOXRIGHT]) boxx = 1; else boxx = 2; if (viewy >= bspcoord[BOXTOP]) boxy = 0; else if (viewy > bspcoord[BOXBOTTOM]) boxy = 1; else boxy = 2; boxpos = (boxy << 2) + boxx; if (boxpos == 5) return true; x1 = bspcoord[checkcoord[boxpos][0]]; y1 = bspcoord[checkcoord[boxpos][1]]; x2 = bspcoord[checkcoord[boxpos][2]]; y2 = bspcoord[checkcoord[boxpos][3]]; // // check clip list for an open space // angle1 = R_PointToAngle(x1, y1) - viewangle; angle2 = R_PointToAngle(x2, y2) - viewangle; span = angle1 - angle2; if (span >= ANG180) return true; // sitting on a line tspan = angle1 + clipangle; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return false; // totally off the left edge angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return false; // totally off the left edge angle2 = -clipangle; } // find the first clippost that touches the source post (adjacent pixels are touching) angle1 = (angle1 + ANG90) >> ANGLETOFINESHIFT; angle2 = (angle2 + ANG90) >> ANGLETOFINESHIFT; sx1 = viewangletox[angle1]; sx2 = viewangletox[angle2]; if (sx1 == sx2) return false; // does not cross a pixel sx2--; start = solidsegs; while (start->last < sx2) start++; if (sx1 >= start->first && sx2 <= start->last) return false; // the clippost contains the new span return true; } /* ================ = = R_Subsector = = Draw one or more segments ================ */ void R_Subsector(int num) { int count; seg_t *line; subsector_t *sub; #ifdef RANGECHECK if (num >= numsubsectors) I_Error("R_Subsector: ss %i with numss = %i", num, numsubsectors); #endif sscount++; sub = &subsectors[num]; frontsector = sub->sector; count = sub->numlines; line = &segs[sub->firstline]; if (frontsector->floorheight < viewz) floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, frontsector->lightlevel, frontsector->special); else floorplane = NULL; if (frontsector->ceilingheight > viewz || frontsector->ceilingpic == skyflatnum) ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, frontsector->lightlevel, 0); else ceilingplane = NULL; R_AddSprites(frontsector); while (count--) { R_AddLine(line); line++; } } /* =============================================================================== = = RenderBSPNode = =============================================================================== */ void R_RenderBSPNode(int bspnum) { node_t *bsp; int side; if (bspnum & NF_SUBSECTOR) { if (bspnum == -1) R_Subsector(0); else R_Subsector(bspnum & (~NF_SUBSECTOR)); return; } bsp = &nodes[bspnum]; // // decide which side the view point is on // side = R_PointOnSide(viewx, viewy, bsp); R_RenderBSPNode(bsp->children[side]); // recursively divide front space if (R_CheckBBox(bsp->bbox[side ^ 1])) // possibly divide back space R_RenderBSPNode(bsp->children[side ^ 1]); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_data.c000066400000000000000000000435771257432200600231350ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // R_data.c #include "doomdef.h" #include "deh_str.h" #include "i_swap.h" #include "i_system.h" #include "m_misc.h" #include "r_local.h" #include "p_local.h" extern void CheckAbortStartup(void); typedef struct { int originx; // block origin (allways UL), which has allready int originy; // accounted for the patch's internal origin int patch; } texpatch_t; // a maptexturedef_t describes a rectangular texture, which is composed of one // or more mappatch_t structures that arrange graphic patches typedef struct { char name[8]; // for switch changing, etc short width; short height; short patchcount; texpatch_t patches[1]; // [patchcount] drawn back to front // into the cached texture } texture_t; int firstflat, lastflat, numflats; int firstpatch, lastpatch, numpatches; int firstspritelump, lastspritelump, numspritelumps; int numtextures; texture_t **textures; int *texturewidthmask; fixed_t *textureheight; // needed for texture pegging int *texturecompositesize; short **texturecolumnlump; unsigned short **texturecolumnofs; byte **texturecomposite; int *flattranslation; // for global animation int *texturetranslation; // for global animation fixed_t *spritewidth; // needed for pre rendering fixed_t *spriteoffset; fixed_t *spritetopoffset; lighttable_t *colormaps; /* ============================================================================== MAPTEXTURE_T CACHING when a texture is first needed, it counts the number of composite columns required in the texture and allocates space for a column directory and any new columns. The directory will simply point inside other patches if there is only one patch in a given column, but any columns with multiple patches will have new column_ts generated. ============================================================================== */ /* =================== = = R_DrawColumnInCache = = Clip and draw a column from a patch into a cached post = =================== */ void R_DrawColumnInCache(column_t * patch, byte * cache, int originy, int cacheheight) { int count, position; byte *source; while (patch->topdelta != 0xff) { source = (byte *) patch + 3; count = patch->length; position = originy + patch->topdelta; if (position < 0) { count += position; position = 0; } if (position + count > cacheheight) count = cacheheight - position; if (count > 0) memcpy(cache + position, source, count); patch = (column_t *) ((byte *) patch + patch->length + 4); } } /* =================== = = R_GenerateComposite = =================== */ void R_GenerateComposite(int texnum) { byte *block; texture_t *texture; texpatch_t *patch; patch_t *realpatch; int x, x1, x2; int i; column_t *patchcol; short *collump; unsigned short *colofs; texture = textures[texnum]; block = Z_Malloc(texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]); collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // // composite the columns together // patch = texture->patches; for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1 < 0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for (; x < x2; x++) { if (collump[x] >= 0) continue; // column does not have multiple patches patchcol = (column_t *) ((byte *) realpatch + LONG(realpatch->columnofs[x - x1])); R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy, texture->height); } } // now that the texture has been built, it is purgable Z_ChangeTag(block, PU_CACHE); } /* =================== = = R_GenerateLookup = =================== */ void R_GenerateLookup(int texnum) { texture_t *texture; byte *patchcount; // [texture->width] texpatch_t *patch; patch_t *realpatch; int x, x1, x2; int i; short *collump; unsigned short *colofs; texture = textures[texnum]; texturecomposite[texnum] = 0; // composited not created yet texturecompositesize[texnum] = 0; collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // // count the number of columns that are covered by more than one patch // fill in the lump / offset, so columns with only a single patch are // all done // patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); memset(patchcount, 0, texture->width); patch = texture->patches; for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1 < 0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for (; x < x2; x++) { patchcount[x]++; collump[x] = patch->patch; colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3; } } for (x = 0; x < texture->width; x++) { if (!patchcount[x]) { printf("R_GenerateLookup: column without a patch (%s)\n", texture->name); return; } // I_Error ("R_GenerateLookup: column without a patch"); if (patchcount[x] > 1) { collump[x] = -1; // use the cached block colofs[x] = texturecompositesize[texnum]; if (texturecompositesize[texnum] > 0x10000 - texture->height) I_Error("R_GenerateLookup: texture %i is >64k", texnum); texturecompositesize[texnum] += texture->height; } } Z_Free(patchcount); } /* ================ = = R_GetColumn = ================ */ byte *R_GetColumn(int tex, int col) { int lump, ofs; col &= texturewidthmask[tex]; lump = texturecolumnlump[tex][col]; ofs = texturecolumnofs[tex][col]; if (lump > 0) return (byte *) W_CacheLumpNum(lump, PU_CACHE) + ofs; if (!texturecomposite[tex]) R_GenerateComposite(tex); return texturecomposite[tex] + ofs; } /* ================== = = R_InitTextures = = Initializes the texture list with the textures from the world map = ================== */ void R_InitTextures(void) { maptexture_t *mtexture; texture_t *texture; mappatch_t *mpatch; texpatch_t *patch; int i, j; int *maptex, *maptex2, *maptex1; char name[9], *names, *name_p; int *patchlookup; int totalwidth; int nummappatches; int offset, maxoff, maxoff2; int numtextures1, numtextures2; int *directory; char *texture1, *texture2, *pnames; texture1 = DEH_String("TEXTURE1"); texture2 = DEH_String("TEXTURE2"); pnames = DEH_String("PNAMES"); // // load the patch names from pnames.lmp // names = W_CacheLumpName(pnames, PU_STATIC); nummappatches = LONG(*((int *) names)); name_p = names + 4; patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL); for (i = 0; i < nummappatches; i++) { M_StringCopy(name, name_p + i * 8, sizeof(name)); patchlookup[i] = W_CheckNumForName(name); } W_ReleaseLumpName(pnames); // // load the map texture definitions from textures.lmp // maptex = maptex1 = W_CacheLumpName(texture1, PU_STATIC); numtextures1 = LONG(*maptex); maxoff = W_LumpLength(W_GetNumForName(texture1)); directory = maptex + 1; if (W_CheckNumForName(texture2) != -1) { maptex2 = W_CacheLumpName(texture2, PU_STATIC); numtextures2 = LONG(*maptex2); maxoff2 = W_LumpLength(W_GetNumForName(texture2)); } else { maptex2 = NULL; numtextures2 = 0; maxoff2 = 0; } numtextures = numtextures1 + numtextures2; // // Init the startup thermometer at this point... // { int start, end; int spramount; start = W_GetNumForName(DEH_String("S_START")); end = W_GetNumForName(DEH_String("S_END")); spramount = end - start + 1; InitThermo(spramount + numtextures + 6); } textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0); texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); texturecolumnofs = Z_Malloc(numtextures * sizeof(unsigned short *), PU_STATIC, 0); texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0); texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); textureheight = Z_Malloc(numtextures * sizeof(fixed_t), PU_STATIC, 0); totalwidth = 0; for (i = 0; i < numtextures; i++, directory++) { #ifdef __NEXT__ if (!(i & 63)) printf("."); #else IncThermo(); #endif if (i == numtextures1) { // start looking in second texture file maptex = maptex2; maxoff = maxoff2; directory = maptex + 1; } offset = LONG(*directory); if (offset > maxoff) I_Error("R_InitTextures: bad texture directory"); mtexture = (maptexture_t *) ((byte *) maptex + offset); texture = textures[i] = Z_Malloc(sizeof(texture_t) + sizeof(texpatch_t) * (SHORT(mtexture->patchcount) - 1), PU_STATIC, 0); texture->width = SHORT(mtexture->width); texture->height = SHORT(mtexture->height); texture->patchcount = SHORT(mtexture->patchcount); memcpy(texture->name, mtexture->name, sizeof(texture->name)); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; for (j = 0; j < texture->patchcount; j++, mpatch++, patch++) { patch->originx = SHORT(mpatch->originx); patch->originy = SHORT(mpatch->originy); patch->patch = patchlookup[SHORT(mpatch->patch)]; if (patch->patch == -1) I_Error("R_InitTextures: Missing patch in texture %s", texture->name); } texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); j = 1; while (j * 2 <= texture->width) j <<= 1; texturewidthmask[i] = j - 1; textureheight[i] = texture->height << FRACBITS; totalwidth += texture->width; } Z_Free(patchlookup); W_ReleaseLumpName(texture1); if (maptex2) { W_ReleaseLumpName(texture2); } // // precalculate whatever possible // for (i = 0; i < numtextures; i++) { R_GenerateLookup(i); CheckAbortStartup(); } // // translation table for global animation // texturetranslation = Z_Malloc((numtextures + 1) * sizeof(int), PU_STATIC, 0); for (i = 0; i < numtextures; i++) texturetranslation[i] = i; } /* ================ = = R_InitFlats = ================= */ void R_InitFlats(void) { int i; firstflat = W_GetNumForName(DEH_String("F_START")) + 1; lastflat = W_GetNumForName(DEH_String("F_END")) - 1; numflats = lastflat - firstflat + 1; // translation table for global animation flattranslation = Z_Malloc((numflats + 1) * sizeof(int), PU_STATIC, 0); for (i = 0; i < numflats; i++) flattranslation[i] = i; } /* ================ = = R_InitSpriteLumps = = Finds the width and hoffset of all sprites in the wad, so the sprite doesn't = need to be cached just for the header during rendering ================= */ void R_InitSpriteLumps(void) { int i; patch_t *patch; firstspritelump = W_GetNumForName(DEH_String("S_START")) + 1; lastspritelump = W_GetNumForName(DEH_String("S_END")) - 1; numspritelumps = lastspritelump - firstspritelump + 1; spritewidth = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); spritetopoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); for (i = 0; i < numspritelumps; i++) { #ifdef __NEXT__ if (!(i & 63)) printf("."); #else IncThermo(); #endif patch = W_CacheLumpNum(firstspritelump + i, PU_CACHE); spritewidth[i] = SHORT(patch->width) << FRACBITS; spriteoffset[i] = SHORT(patch->leftoffset) << FRACBITS; spritetopoffset[i] = SHORT(patch->topoffset) << FRACBITS; } } /* ================ = = R_InitColormaps = ================= */ void R_InitColormaps(void) { int lump, length; // // load in the light tables // 256 byte align tables // lump = W_GetNumForName(DEH_String("COLORMAP")); length = W_LumpLength(lump); colormaps = Z_Malloc(length, PU_STATIC, 0); W_ReadLump(lump, colormaps); } /* ================ = = R_InitData = = Locates all the lumps that will be used by all views = Must be called after W_Init ================= */ void R_InitData(void) { //tprintf("\nR_InitTextures ", 0); R_InitTextures(); printf ("."); //tprintf("R_InitFlats\n", 0); R_InitFlats(); IncThermo(); printf ("."); //tprintf("R_InitSpriteLumps ", 0); R_InitSpriteLumps(); IncThermo(); printf ("."); R_InitColormaps(); } //============================================================================= /* ================ = = R_FlatNumForName = ================ */ int R_FlatNumForName(char *name) { int i; char namet[9]; i = W_CheckNumForName(name); if (i == -1) { namet[8] = 0; memcpy(namet, name, 8); I_Error("R_FlatNumForName: %s not found", namet); } return i - firstflat; } /* ================ = = R_CheckTextureNumForName = ================ */ int R_CheckTextureNumForName(char *name) { int i; if (name[0] == '-') // no texture marker return 0; for (i = 0; i < numtextures; i++) if (!strncasecmp(textures[i]->name, name, 8)) return i; return -1; } /* ================ = = R_TextureNumForName = ================ */ int R_TextureNumForName(char *name) { int i; //char namet[9]; i = R_CheckTextureNumForName(name); if (i == -1) I_Error("R_TextureNumForName: %s not found", name); return i; } /* ================= = = R_PrecacheLevel = = Preloads all relevent graphics for the level ================= */ int flatmemory, texturememory, spritememory; void R_PrecacheLevel(void) { char *flatpresent; char *texturepresent; char *spritepresent; int i, j, k, lump; texture_t *texture; thinker_t *th; spriteframe_t *sf; if (demoplayback) return; // // precache flats // flatpresent = Z_Malloc(numflats, PU_STATIC, NULL); memset(flatpresent, 0, numflats); for (i = 0; i < numsectors; i++) { flatpresent[sectors[i].floorpic] = 1; flatpresent[sectors[i].ceilingpic] = 1; } flatmemory = 0; for (i = 0; i < numflats; i++) if (flatpresent[i]) { lump = firstflat + i; flatmemory += lumpinfo[lump].size; W_CacheLumpNum(lump, PU_CACHE); } Z_Free(flatpresent); // // precache textures // texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL); memset(texturepresent, 0, numtextures); for (i = 0; i < numsides; i++) { texturepresent[sides[i].toptexture] = 1; texturepresent[sides[i].midtexture] = 1; texturepresent[sides[i].bottomtexture] = 1; } texturepresent[skytexture] = 1; texturememory = 0; for (i = 0; i < numtextures; i++) { if (!texturepresent[i]) continue; texture = textures[i]; for (j = 0; j < texture->patchcount; j++) { lump = texture->patches[j].patch; texturememory += lumpinfo[lump].size; W_CacheLumpNum(lump, PU_CACHE); } } Z_Free(texturepresent); // // precache sprites // spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL); memset(spritepresent, 0, numsprites); for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == P_MobjThinker) spritepresent[((mobj_t *) th)->sprite] = 1; } spritememory = 0; for (i = 0; i < numsprites; i++) { if (!spritepresent[i]) continue; for (j = 0; j < sprites[i].numframes; j++) { sf = &sprites[i].spriteframes[j]; for (k = 0; k < 8; k++) { lump = firstspritelump + sf->lump[k]; spritememory += lumpinfo[lump].size; W_CacheLumpNum(lump, PU_CACHE); } } } Z_Free(spritepresent); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_draw.c000066400000000000000000000270711257432200600231500ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // R_draw.c #include "doomdef.h" #include "deh_str.h" #include "r_local.h" #include "i_video.h" #include "v_video.h" /* All drawing to the view buffer is accomplished in this file. The other refresh files only know about ccordinates, not the architecture of the frame buffer. */ byte *viewimage; int viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy; byte *ylookup[MAXHEIGHT]; int columnofs[MAXWIDTH]; byte translations[3][256]; // color tables for different players /* ================== = = R_DrawColumn = = Source is the top of the column to scale = ================== */ lighttable_t *dc_colormap; int dc_x; int dc_yl; int dc_yh; fixed_t dc_iscale; fixed_t dc_texturemid; byte *dc_source; // first pixel in a column (possibly virtual) int dccount; // just for profiling void R_DrawColumn(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } void R_DrawColumnLow(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); // dccount++; #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } // Translucent column draw - blended with background using tinttable. void R_DrawTLColumn(void) { int count; byte *dest; fixed_t frac, fracstep; if (!dc_yl) dc_yl = 1; if (dc_yh == viewheight - 1) dc_yh = viewheight - 2; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = tinttable[((*dest) << 8) + dc_colormap[dc_source[(frac >> FRACBITS) & 127]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } /* ======================== = = R_DrawTranslatedColumn = ======================== */ byte *dc_translation; byte *translationtables; void R_DrawTranslatedColumn(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = dc_colormap[dc_translation[dc_source[frac >> FRACBITS]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } void R_DrawTranslatedTLColumn(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = tinttable[((*dest) << 8) + dc_colormap[dc_translation [dc_source[frac >> FRACBITS]]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } //-------------------------------------------------------------------------- // // PROC R_InitTranslationTables // //-------------------------------------------------------------------------- void R_InitTranslationTables(void) { int i; V_LoadTintTable(); // Allocate translation tables translationtables = Z_Malloc(256 * 3, PU_STATIC, 0); // Fill out the translation tables for (i = 0; i < 256; i++) { if (i >= 225 && i <= 240) { translationtables[i] = 114 + (i - 225); // yellow translationtables[i + 256] = 145 + (i - 225); // red translationtables[i + 512] = 190 + (i - 225); // blue } else { translationtables[i] = translationtables[i + 256] = translationtables[i + 512] = i; } } } /* ================ = = R_DrawSpan = ================ */ int ds_y; int ds_x1; int ds_x2; lighttable_t *ds_colormap; fixed_t ds_xfrac; fixed_t ds_yfrac; fixed_t ds_xstep; fixed_t ds_ystep; byte *ds_source; // start of a 64*64 tile image int dscount; // just for profiling void R_DrawSpan(void) { fixed_t xfrac, yfrac; byte *dest; int count, spot; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned) ds_y > SCREENHEIGHT) I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y); // dscount++; #endif xfrac = ds_xfrac; yfrac = ds_yfrac; dest = ylookup[ds_y] + columnofs[ds_x1]; count = ds_x2 - ds_x1; do { spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63); *dest++ = ds_colormap[ds_source[spot]]; xfrac += ds_xstep; yfrac += ds_ystep; } while (count--); } void R_DrawSpanLow(void) { fixed_t xfrac, yfrac; byte *dest; int count, spot; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned) ds_y > SCREENHEIGHT) I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y); // dscount++; #endif xfrac = ds_xfrac; yfrac = ds_yfrac; dest = ylookup[ds_y] + columnofs[ds_x1]; count = ds_x2 - ds_x1; do { spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63); *dest++ = ds_colormap[ds_source[spot]]; xfrac += ds_xstep; yfrac += ds_ystep; } while (count--); } /* ================ = = R_InitBuffer = ================= */ void R_InitBuffer(int width, int height) { int i; viewwindowx = (SCREENWIDTH - width) >> 1; for (i = 0; i < width; i++) columnofs[i] = viewwindowx + i; if (width == SCREENWIDTH) viewwindowy = 0; else viewwindowy = (SCREENHEIGHT - SBARHEIGHT - height) >> 1; for (i = 0; i < height; i++) ylookup[i] = I_VideoBuffer + (i + viewwindowy) * SCREENWIDTH; } /* ================== = = R_DrawViewBorder = = Draws the border around the view for different size windows ================== */ boolean BorderNeedRefresh; void R_DrawViewBorder(void) { byte *src, *dest; int x, y; if (scaledviewwidth == SCREENWIDTH) return; if (gamemode == shareware) { src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE); } else { src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE); } dest = I_VideoBuffer; for (y = 0; y < SCREENHEIGHT - SBARHEIGHT; y++) { for (x = 0; x < SCREENWIDTH / 64; x++) { memcpy(dest, src + ((y & 63) << 6), 64); dest += 64; } if (SCREENWIDTH & 63) { memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63); dest += (SCREENWIDTH & 63); } } for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16) { V_DrawPatch(x, viewwindowy - 4, W_CacheLumpName(DEH_String("bordt"), PU_CACHE)); V_DrawPatch(x, viewwindowy + viewheight, W_CacheLumpName(DEH_String("bordb"), PU_CACHE)); } for (y = viewwindowy; y < viewwindowy + viewheight; y += 16) { V_DrawPatch(viewwindowx - 4, y, W_CacheLumpName(DEH_String("bordl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, y, W_CacheLumpName(DEH_String("bordr"), PU_CACHE)); } V_DrawPatch(viewwindowx - 4, viewwindowy - 4, W_CacheLumpName(DEH_String("bordtl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, W_CacheLumpName(DEH_String("bordtr"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight, W_CacheLumpName(DEH_String("bordbr"), PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight, W_CacheLumpName(DEH_String("bordbl"), PU_CACHE)); } /* ================== = = R_DrawTopBorder = = Draws the top border around the view for different size windows ================== */ boolean BorderTopRefresh; void R_DrawTopBorder(void) { byte *src, *dest; int x, y; if (scaledviewwidth == SCREENWIDTH) return; if (gamemode == shareware) { src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE); } else { src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE); } dest = I_VideoBuffer; for (y = 0; y < 30; y++) { for (x = 0; x < SCREENWIDTH / 64; x++) { memcpy(dest, src + ((y & 63) << 6), 64); dest += 64; } if (SCREENWIDTH & 63) { memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63); dest += (SCREENWIDTH & 63); } } if (viewwindowy < 25) { for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16) { V_DrawPatch(x, viewwindowy - 4, W_CacheLumpName(DEH_String("bordt"), PU_CACHE)); } V_DrawPatch(viewwindowx - 4, viewwindowy, W_CacheLumpName(DEH_String("bordl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy, W_CacheLumpName(DEH_String("bordr"), PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy + 16, W_CacheLumpName(DEH_String("bordl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16, W_CacheLumpName(DEH_String("bordr"), PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy - 4, W_CacheLumpName(DEH_String("bordtl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, W_CacheLumpName(DEH_String("bordtr"), PU_CACHE)); } } chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_local.h000066400000000000000000000300061257432200600233020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // R_local.h #ifndef __R_LOCAL__ #define __R_LOCAL__ #include "i_video.h" #include "v_patch.h" #define ANGLETOSKYSHIFT 22 // sky map is 256*128*4 maps #define BASEYCENTER 100 #define MAXWIDTH 1120 #define MAXHEIGHT 832 #define PI 3.141592657 #define CENTERY (SCREENHEIGHT/2) #define MINZ (FRACUNIT*4) #define FIELDOFVIEW 2048 // fineangles in the SCREENWIDTH wide window // // lighting constants // #define LIGHTLEVELS 16 #define LIGHTSEGSHIFT 4 #define MAXLIGHTSCALE 48 #define LIGHTSCALESHIFT 12 #define MAXLIGHTZ 128 #define LIGHTZSHIFT 20 #define NUMCOLORMAPS 32 // number of diminishing #define INVERSECOLORMAP 32 /* ============================================================================== INTERNAL MAP TYPES ============================================================================== */ //================ used by play and refresh typedef struct { fixed_t x, y; } vertex_t; struct line_s; typedef struct { fixed_t floorheight, ceilingheight; short floorpic, ceilingpic; short lightlevel; short special, tag; int soundtraversed; // 0 = untraversed, 1,2 = sndlines -1 mobj_t *soundtarget; // thing that made a sound (or null) int blockbox[4]; // mapblock bounding box for height changes degenmobj_t soundorg; // for any sounds played by the sector int validcount; // if == validcount, already checked mobj_t *thinglist; // list of mobjs in sector void *specialdata; // thinker_t for reversable actions int linecount; struct line_s **lines; // [linecount] size } sector_t; typedef struct { fixed_t textureoffset; // add this to the calculated texture col fixed_t rowoffset; // add this to the calculated texture top short toptexture, bottomtexture, midtexture; sector_t *sector; } side_t; typedef enum { ST_HORIZONTAL, ST_VERTICAL, ST_POSITIVE, ST_NEGATIVE } slopetype_t; typedef struct line_s { vertex_t *v1, *v2; fixed_t dx, dy; // v2 - v1 for side checking short flags; short special, tag; short sidenum[2]; // sidenum[1] will be -1 if one sided fixed_t bbox[4]; slopetype_t slopetype; // to aid move clipping sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked void *specialdata; // thinker_t for reversable actions } line_t; typedef struct subsector_s { sector_t *sector; short numlines; short firstline; } subsector_t; typedef struct { vertex_t *v1, *v2; fixed_t offset; angle_t angle; side_t *sidedef; line_t *linedef; sector_t *frontsector; sector_t *backsector; // NULL for one sided lines } seg_t; typedef struct { fixed_t x, y, dx, dy; // partition line fixed_t bbox[2][4]; // bounding box for each child unsigned short children[2]; // if NF_SUBSECTOR its a subsector } node_t; /* ============================================================================== OTHER TYPES ============================================================================== */ typedef byte lighttable_t; // this could be wider for >8 bit display #define MAXVISPLANES 128 #define MAXOPENINGS SCREENWIDTH*64 typedef struct { fixed_t height; int picnum; int lightlevel; int special; int minx, maxx; byte pad1; // leave pads for [minx-1]/[maxx+1] byte top[SCREENWIDTH]; byte pad2; byte pad3; byte bottom[SCREENWIDTH]; byte pad4; } visplane_t; typedef struct drawseg_s { seg_t *curline; int x1, x2; fixed_t scale1, scale2, scalestep; int silhouette; // 0=none, 1=bottom, 2=top, 3=both fixed_t bsilheight; // don't clip sprites above this fixed_t tsilheight; // don't clip sprites below this // pointers to lists for sprite clipping short *sprtopclip; // adjusted so [x1] is first value short *sprbottomclip; // adjusted so [x1] is first value short *maskedtexturecol; // adjusted so [x1] is first value } drawseg_t; #define SIL_NONE 0 #define SIL_BOTTOM 1 #define SIL_TOP 2 #define SIL_BOTH 3 #define MAXDRAWSEGS 256 // A vissprite_t is a thing that will be drawn during a refresh typedef struct vissprite_s { struct vissprite_s *prev, *next; int x1, x2; fixed_t gx, gy; // for line side calculation fixed_t gz, gzt; // global bottom / top for silhouette clipping fixed_t startfrac; // horizontal position of x1 fixed_t scale; fixed_t xiscale; // negative if flipped fixed_t texturemid; int patch; lighttable_t *colormap; int mobjflags; // for color translation and shadow draw boolean psprite; // true if psprite fixed_t footclip; // foot clipping } vissprite_t; extern visplane_t *floorplane, *ceilingplane; // Sprites are patches with a special naming convention so they can be // recognized by R_InitSprites. The sprite and frame specified by a // thing_t is range checked at run time. // a sprite is a patch_t that is assumed to represent a three dimensional // object and may have multiple rotations pre drawn. Horizontal flipping // is used to save space. Some sprites will only have one picture used // for all views. typedef struct { boolean rotate; // if false use 0 for any position short lump[8]; // lump to use for view angles 0-7 byte flip[8]; // flip (1 = flip) to use for view angles 0-7 } spriteframe_t; typedef struct { int numframes; spriteframe_t *spriteframes; } spritedef_t; extern spritedef_t *sprites; extern int numsprites; //============================================================================= extern int numvertexes; extern vertex_t *vertexes; extern int numsegs; extern seg_t *segs; extern int numsectors; extern sector_t *sectors; extern int numsubsectors; extern subsector_t *subsectors; extern int numnodes; extern node_t *nodes; extern int numlines; extern line_t *lines; extern int numsides; extern side_t *sides; extern fixed_t viewx, viewy, viewz; extern angle_t viewangle; extern player_t *viewplayer; extern angle_t clipangle; extern int viewangletox[FINEANGLES / 2]; extern angle_t xtoviewangle[SCREENWIDTH + 1]; extern fixed_t rw_distance; extern angle_t rw_normalangle; // // R_main.c // extern int viewwidth, viewheight, viewwindowx, viewwindowy; extern int scaledviewwidth; extern int centerx, centery; extern int flyheight; extern fixed_t centerxfrac; extern fixed_t centeryfrac; extern fixed_t projection; extern int validcount; extern int sscount, linecount, loopcount; extern lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; extern lighttable_t *scalelightfixed[MAXLIGHTSCALE]; extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; extern int extralight; extern lighttable_t *fixedcolormap; extern fixed_t viewcos, viewsin; extern int detailshift; // 0 = high, 1 = low extern void (*colfunc) (void); extern void (*basecolfunc) (void); extern void (*tlcolfunc) (void); extern void (*spanfunc) (void); int R_PointOnSide(fixed_t x, fixed_t y, node_t * node); int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line); angle_t R_PointToAngle(fixed_t x, fixed_t y); angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); fixed_t R_PointToDist(fixed_t x, fixed_t y); fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); void R_AddPointToBox(int x, int y, fixed_t * box); // // R_bsp.c // extern seg_t *curline; extern side_t *sidedef; extern line_t *linedef; extern sector_t *frontsector, *backsector; extern int rw_x; extern int rw_stopx; extern boolean segtextured; extern boolean markfloor; // false if the back side is the same plane extern boolean markceiling; extern boolean skymap; extern drawseg_t drawsegs[MAXDRAWSEGS], *ds_p; extern lighttable_t **hscalelight, **vscalelight, **dscalelight; typedef void (*drawfunc_t) (int start, int stop); void R_ClearClipSegs(void); void R_ClearDrawSegs(void); void R_InitSkyMap(void); void R_RenderBSPNode(int bspnum); // // R_segs.c // extern int rw_angle1; // angle to line origin void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2); // // R_plane.c // typedef void (*planefunction_t) (int top, int bottom); extern planefunction_t floorfunc, ceilingfunc; extern int skyflatnum; extern short openings[MAXOPENINGS], *lastopening; extern short floorclip[SCREENWIDTH]; extern short ceilingclip[SCREENWIDTH]; extern fixed_t yslope[SCREENHEIGHT]; extern fixed_t distscale[SCREENWIDTH]; void R_InitPlanes(void); void R_ClearPlanes(void); void R_MapPlane(int y, int x1, int x2); void R_MakeSpans(int x, int t1, int b1, int t2, int b2); void R_DrawPlanes(void); visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, int special); visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop); // // R_debug.m // extern int drawbsp; // // R_data.c // extern fixed_t *textureheight; // needed for texture pegging extern fixed_t *spritewidth; // needed for pre rendering (fracs) extern fixed_t *spriteoffset; extern fixed_t *spritetopoffset; extern lighttable_t *colormaps; extern int firstflat; extern int numflats; extern int *flattranslation; // for global animation extern int *texturetranslation; // for global animation extern int firstspritelump, lastspritelump, numspritelumps; byte *R_GetColumn(int tex, int col); void R_InitData(void); void R_PrecacheLevel(void); // // R_things.c // #define MAXVISSPRITES 128 extern vissprite_t vissprites[MAXVISSPRITES], *vissprite_p; extern vissprite_t vsprsortedhead; // constant arrays used for psprite clipping and initializing clipping extern short negonearray[SCREENWIDTH]; extern short screenheightarray[SCREENWIDTH]; // vars for R_DrawMaskedColumn extern short *mfloorclip; extern short *mceilingclip; extern fixed_t spryscale; extern fixed_t sprtopscreen; extern fixed_t sprbotscreen; extern fixed_t pspritescale, pspriteiscale; void R_DrawMaskedColumn(column_t * column, signed int baseclip); void R_SortVisSprites(void); void R_AddSprites(sector_t * sec); void R_AddPSprites(void); void R_DrawSprites(void); void R_InitSprites(char **namelist); void R_ClearSprites(void); void R_DrawMasked(void); void R_ClipVisSprite(vissprite_t * vis, int xl, int xh); //============================================================================= // // R_draw.c // //============================================================================= extern lighttable_t *dc_colormap; extern int dc_x; extern int dc_yl; extern int dc_yh; extern fixed_t dc_iscale; extern fixed_t dc_texturemid; extern byte *dc_source; // first pixel in a column void R_DrawColumn(void); void R_DrawColumnLow(void); void R_DrawTLColumn(void); void R_DrawTLColumnLow(void); void R_DrawTranslatedColumn(void); void R_DrawTranslatedTLColumn(void); void R_DrawTranslatedColumnLow(void); extern int ds_y; extern int ds_x1; extern int ds_x2; extern lighttable_t *ds_colormap; extern fixed_t ds_xfrac; extern fixed_t ds_yfrac; extern fixed_t ds_xstep; extern fixed_t ds_ystep; extern byte *ds_source; // start of a 64*64 tile image extern byte *translationtables; extern byte *dc_translation; void R_DrawSpan(void); void R_DrawSpanLow(void); void R_InitBuffer(int width, int height); void R_InitTranslationTables(void); #endif // __R_LOCAL__ chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_main.c000066400000000000000000000437551257432200600231460ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // R_main.c #include #include #include "doomdef.h" #include "m_bbox.h" #include "r_local.h" #include "tables.h" int viewangleoffset; // haleyjd: removed WATCOMC int validcount = 1; // increment every time a check is made lighttable_t *fixedcolormap; extern lighttable_t **walllights; int centerx, centery; fixed_t centerxfrac, centeryfrac; fixed_t projection; int framecount; // just for profiling purposes int sscount, linecount, loopcount; fixed_t viewx, viewy, viewz; angle_t viewangle; fixed_t viewcos, viewsin; player_t *viewplayer; int detailshift; // 0 = high, 1 = low // // precalculated math tables // angle_t clipangle; // The viewangletox[viewangle + FINEANGLES/4] lookup maps the visible view // angles to screen X coordinates, flattening the arc to a flat projection // plane. There will be many angles mapped to the same X. int viewangletox[FINEANGLES / 2]; // The xtoviewangleangle[] table maps a screen pixel to the lowest viewangle // that maps back to x ranges from clipangle to -clipangle angle_t xtoviewangle[SCREENWIDTH + 1]; lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; lighttable_t *scalelightfixed[MAXLIGHTSCALE]; lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; int extralight; // bumped light from gun blasts void (*colfunc) (void); void (*basecolfunc) (void); void (*tlcolfunc) (void); void (*transcolfunc) (void); void (*spanfunc) (void); /* =================== = = R_AddPointToBox = =================== */ void R_AddPointToBox(int x, int y, fixed_t * box) { if (x < box[BOXLEFT]) box[BOXLEFT] = x; if (x > box[BOXRIGHT]) box[BOXRIGHT] = x; if (y < box[BOXBOTTOM]) box[BOXBOTTOM] = y; if (y > box[BOXTOP]) box[BOXTOP] = y; } /* =============================================================================== = = R_PointOnSide = = Returns side 0 (front) or 1 (back) =============================================================================== */ int R_PointOnSide(fixed_t x, fixed_t y, node_t * node) { fixed_t dx, dy; fixed_t left, right; if (!node->dx) { if (x <= node->x) return node->dy > 0; return node->dy < 0; } if (!node->dy) { if (y <= node->y) return node->dx < 0; return node->dx > 0; } dx = (x - node->x); dy = (y - node->y); // try to quickly decide by looking at sign bits if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000) { if ((node->dy ^ dx) & 0x80000000) return 1; // (left is negative) return 0; } left = FixedMul(node->dy >> FRACBITS, dx); right = FixedMul(dy, node->dx >> FRACBITS); if (right < left) return 0; // front side return 1; // back side } int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line) { fixed_t lx, ly; fixed_t ldx, ldy; fixed_t dx, dy; fixed_t left, right; lx = line->v1->x; ly = line->v1->y; ldx = line->v2->x - lx; ldy = line->v2->y - ly; if (!ldx) { if (x <= lx) return ldy > 0; return ldy < 0; } if (!ldy) { if (y <= ly) return ldx < 0; return ldx > 0; } dx = (x - lx); dy = (y - ly); // try to quickly decide by looking at sign bits if ((ldy ^ ldx ^ dx ^ dy) & 0x80000000) { if ((ldy ^ dx) & 0x80000000) return 1; // (left is negative) return 0; } left = FixedMul(ldy >> FRACBITS, dx); right = FixedMul(dy, ldx >> FRACBITS); if (right < left) return 0; // front side return 1; // back side } /* =============================================================================== = = R_PointToAngle = =============================================================================== */ angle_t R_PointToAngle(fixed_t x, fixed_t y) { x -= viewx; y -= viewy; if ((!x) && (!y)) return 0; if (x >= 0) { // x >=0 if (y >= 0) { // y>= 0 if (x > y) return tantoangle[SlopeDiv(y, x)]; // octant 0 else return ANG90 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 1 } else { // y<0 y = -y; if (x > y) return -tantoangle[SlopeDiv(y, x)]; // octant 8 else return ANG270 + tantoangle[SlopeDiv(x, y)]; // octant 7 } } else { // x<0 x = -x; if (y >= 0) { // y>= 0 if (x > y) return ANG180 - 1 - tantoangle[SlopeDiv(y, x)]; // octant 3 else return ANG90 + tantoangle[SlopeDiv(x, y)]; // octant 2 } else { // y<0 y = -y; if (x > y) return ANG180 + tantoangle[SlopeDiv(y, x)]; // octant 4 else return ANG270 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 5 } } return 0; } angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) { viewx = x1; viewy = y1; return R_PointToAngle(x2, y2); } fixed_t R_PointToDist(fixed_t x, fixed_t y) { int angle; fixed_t dx, dy, temp; fixed_t dist; dx = abs(x - viewx); dy = abs(y - viewy); if (dy > dx) { temp = dx; dx = dy; dy = temp; } angle = (tantoangle[FixedDiv(dy, dx) >> DBITS] + ANG90) >> ANGLETOFINESHIFT; dist = FixedDiv(dx, finesine[angle]); // use as cosine return dist; } /* ================= = = R_InitPointToAngle = ================= */ void R_InitPointToAngle(void) { // now getting from tables.c #if 0 int i; long t; float f; // // slope (tangent) to angle lookup // for (i = 0; i <= SLOPERANGE; i++) { f = atan((float) i / SLOPERANGE) / (3.141592657 * 2); t = 0xffffffff * f; tantoangle[i] = t; } #endif } //============================================================================= /* ================ = = R_ScaleFromGlobalAngle = = Returns the texture mapping scale for the current line at the given angle = rw_distance must be calculated first ================ */ fixed_t R_ScaleFromGlobalAngle(angle_t visangle) { fixed_t scale; int anglea, angleb; int sinea, sineb; fixed_t num, den; #if 0 { fixed_t dist, z; fixed_t sinv, cosv; sinv = finesine[(visangle - rw_normalangle) >> ANGLETOFINESHIFT]; dist = FixedDiv(rw_distance, sinv); cosv = finecosine[(viewangle - visangle) >> ANGLETOFINESHIFT]; z = abs(FixedMul(dist, cosv)); scale = FixedDiv(projection, z); return scale; } #endif anglea = ANG90 + (visangle - viewangle); angleb = ANG90 + (visangle - rw_normalangle); // bothe sines are allways positive sinea = finesine[anglea >> ANGLETOFINESHIFT]; sineb = finesine[angleb >> ANGLETOFINESHIFT]; num = FixedMul(projection, sineb) << detailshift; den = FixedMul(rw_distance, sinea); if (den > num >> 16) { scale = FixedDiv(num, den); if (scale > 64 * FRACUNIT) scale = 64 * FRACUNIT; else if (scale < 256) scale = 256; } else scale = 64 * FRACUNIT; return scale; } /* ================= = = R_InitTables = ================= */ void R_InitTables(void) { // now getting from tables.c #if 0 int i; float a, fv; int t; // // viewangle tangent table // for (i = 0; i < FINEANGLES / 2; i++) { a = (i - FINEANGLES / 4 + 0.5) * PI * 2 / FINEANGLES; fv = FRACUNIT * tan(a); t = fv; finetangent[i] = t; } // // finesine table // for (i = 0; i < 5 * FINEANGLES / 4; i++) { // OPTIMIZE: mirror... a = (i + 0.5) * PI * 2 / FINEANGLES; t = FRACUNIT * sin(a); finesine[i] = t; } #endif } /* ================= = = R_InitTextureMapping = ================= */ void R_InitTextureMapping(void) { int i; int x; int t; fixed_t focallength; // // use tangent table to generate viewangletox // viewangletox will give the next greatest x after the view angle // // calc focallength so FIELDOFVIEW angles covers SCREENWIDTH focallength = FixedDiv(centerxfrac, finetangent[FINEANGLES / 4 + FIELDOFVIEW / 2]); for (i = 0; i < FINEANGLES / 2; i++) { if (finetangent[i] > FRACUNIT * 2) t = -1; else if (finetangent[i] < -FRACUNIT * 2) t = viewwidth + 1; else { t = FixedMul(finetangent[i], focallength); t = (centerxfrac - t + FRACUNIT - 1) >> FRACBITS; if (t < -1) t = -1; else if (t > viewwidth + 1) t = viewwidth + 1; } viewangletox[i] = t; } // // scan viewangletox[] to generate xtoviewangleangle[] // // xtoviewangle will give the smallest view angle that maps to x for (x = 0; x <= viewwidth; x++) { i = 0; while (viewangletox[i] > x) i++; xtoviewangle[x] = (i << ANGLETOFINESHIFT) - ANG90; } // // take out the fencepost cases from viewangletox // for (i = 0; i < FINEANGLES / 2; i++) { t = FixedMul(finetangent[i], focallength); t = centerx - t; if (viewangletox[i] == -1) viewangletox[i] = 0; else if (viewangletox[i] == viewwidth + 1) viewangletox[i] = viewwidth; } clipangle = xtoviewangle[0]; } //============================================================================= /* ==================== = = R_InitLightTables = = Only inits the zlight table, because the scalelight table changes = with view size = ==================== */ #define DISTMAP 2 void R_InitLightTables(void) { int i, j, level, startmap; int scale; // // Calculate the light levels to use for each level / distance combination // for (i = 0; i < LIGHTLEVELS; i++) { startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS; for (j = 0; j < MAXLIGHTZ; j++) { scale = FixedDiv((SCREENWIDTH / 2 * FRACUNIT), (j + 1) << LIGHTZSHIFT); scale >>= LIGHTSCALESHIFT; level = startmap - scale / DISTMAP; if (level < 0) level = 0; if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS - 1; zlight[i][j] = colormaps + level * 256; } } } /* ============== = = R_SetViewSize = = Don't really change anything here, because i might be in the middle of = a refresh. The change will take effect next refresh. = ============== */ boolean setsizeneeded; int setblocks, setdetail; void R_SetViewSize(int blocks, int detail) { setsizeneeded = true; setblocks = blocks; setdetail = detail; } /* ============== = = R_ExecuteSetViewSize = ============== */ void R_ExecuteSetViewSize(void) { fixed_t cosadj, dy; int i, j, level, startmap; setsizeneeded = false; if (setblocks == 11) { scaledviewwidth = SCREENWIDTH; viewheight = SCREENHEIGHT; } else { scaledviewwidth = setblocks * 32; viewheight = (setblocks * 158 / 10); } detailshift = setdetail; viewwidth = scaledviewwidth >> detailshift; centery = viewheight / 2; centerx = viewwidth / 2; centerxfrac = centerx << FRACBITS; centeryfrac = centery << FRACBITS; projection = centerxfrac; if (!detailshift) { colfunc = basecolfunc = R_DrawColumn; tlcolfunc = R_DrawTLColumn; transcolfunc = R_DrawTranslatedColumn; spanfunc = R_DrawSpan; } else { colfunc = basecolfunc = R_DrawColumnLow; tlcolfunc = R_DrawTLColumn; transcolfunc = R_DrawTranslatedColumn; spanfunc = R_DrawSpanLow; } R_InitBuffer(scaledviewwidth, viewheight); R_InitTextureMapping(); // // psprite scales // pspritescale = FRACUNIT * viewwidth / SCREENWIDTH; pspriteiscale = FRACUNIT * SCREENWIDTH / viewwidth; // // thing clipping // for (i = 0; i < viewwidth; i++) screenheightarray[i] = viewheight; // // planes // for (i = 0; i < viewheight; i++) { dy = ((i - viewheight / 2) << FRACBITS) + FRACUNIT / 2; dy = abs(dy); yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT, dy); } for (i = 0; i < viewwidth; i++) { cosadj = abs(finecosine[xtoviewangle[i] >> ANGLETOFINESHIFT]); distscale[i] = FixedDiv(FRACUNIT, cosadj); } // // Calculate the light levels to use for each level / scale combination // for (i = 0; i < LIGHTLEVELS; i++) { startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS; for (j = 0; j < MAXLIGHTSCALE; j++) { level = startmap - j * SCREENWIDTH / (viewwidth << detailshift) / DISTMAP; if (level < 0) level = 0; if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS - 1; scalelight[i][j] = colormaps + level * 256; } } // // draw the border // R_DrawViewBorder(); // erase old menu stuff } /* ============== = = R_Init = ============== */ int detailLevel; int screenblocks = 10; void R_Init(void) { //tprintf("R_InitData ", 1); R_InitData(); printf ("."); //tprintf("R_InitPointToAngle\n", 0); R_InitPointToAngle(); printf ("."); //tprintf("R_InitTables ", 0); R_InitTables(); // viewwidth / viewheight / detailLevel are set by the defaults printf ("."); R_SetViewSize(screenblocks, detailLevel); //tprintf("R_InitPlanes\n", 0); R_InitPlanes(); printf ("."); //tprintf("R_InitLightTables ", 0); R_InitLightTables(); printf ("."); //tprintf("R_InitSkyMap\n", 0); R_InitSkyMap(); printf ("."); R_InitTranslationTables(); framecount = 0; } /* ============== = = R_PointInSubsector = ============== */ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y) { node_t *node; int side, nodenum; if (!numnodes) // single subsector is a special case return subsectors; nodenum = numnodes - 1; while (!(nodenum & NF_SUBSECTOR)) { node = &nodes[nodenum]; side = R_PointOnSide(x, y, node); nodenum = node->children[side]; } return &subsectors[nodenum & ~NF_SUBSECTOR]; } //---------------------------------------------------------------------------- // // PROC R_SetupFrame // //---------------------------------------------------------------------------- void R_SetupFrame(player_t * player) { int i; int tableAngle; int tempCentery; //drawbsp = 1; viewplayer = player; // haleyjd: removed WATCOMC // haleyjd FIXME: viewangleoffset handling? viewangle = player->mo->angle + viewangleoffset; tableAngle = viewangle >> ANGLETOFINESHIFT; if (player->chickenTics && player->chickenPeck) { // Set chicken attack view position viewx = player->mo->x + player->chickenPeck * finecosine[tableAngle]; viewy = player->mo->y + player->chickenPeck * finesine[tableAngle]; } else { // Normal view position viewx = player->mo->x; viewy = player->mo->y; } extralight = player->extralight; viewz = player->viewz; tempCentery = viewheight / 2 + (player->lookdir) * screenblocks / 10; if (centery != tempCentery) { centery = tempCentery; centeryfrac = centery << FRACBITS; for (i = 0; i < viewheight; i++) { yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT, abs(((i - centery) << FRACBITS) + FRACUNIT / 2)); } } viewsin = finesine[tableAngle]; viewcos = finecosine[tableAngle]; sscount = 0; if (player->fixedcolormap) { fixedcolormap = colormaps + player->fixedcolormap * 256 * sizeof(lighttable_t); walllights = scalelightfixed; for (i = 0; i < MAXLIGHTSCALE; i++) { scalelightfixed[i] = fixedcolormap; } } else { fixedcolormap = 0; } framecount++; validcount++; if (BorderNeedRefresh) { if (setblocks < 10) { R_DrawViewBorder(); } BorderNeedRefresh = false; BorderTopRefresh = false; UpdateState |= I_FULLSCRN; } if (BorderTopRefresh) { if (setblocks < 10) { R_DrawTopBorder(); } BorderTopRefresh = false; UpdateState |= I_MESSAGES; } } /* ============== = = R_RenderView = ============== */ void R_RenderPlayerView(player_t * player) { R_SetupFrame(player); R_ClearClipSegs(); R_ClearDrawSegs(); R_ClearPlanes(); R_ClearSprites(); NetUpdate(); // check for new console commands R_RenderBSPNode(numnodes - 1); // the head node is the last node output NetUpdate(); // check for new console commands R_DrawPlanes(); NetUpdate(); // check for new console commands R_DrawMasked(); NetUpdate(); // check for new console commands } chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_plane.c000066400000000000000000000260101257432200600233020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // R_planes.c #include #include "doomdef.h" #include "deh_str.h" #include "i_system.h" #include "r_local.h" planefunction_t floorfunc, ceilingfunc; // // sky mapping // int skyflatnum; int skytexture; int skytexturemid; fixed_t skyiscale; // // opening // visplane_t visplanes[MAXVISPLANES], *lastvisplane; visplane_t *floorplane, *ceilingplane; short openings[MAXOPENINGS], *lastopening; // // clip values are the solid pixel bounding the range // floorclip starts out SCREENHEIGHT // ceilingclip starts out -1 // short floorclip[SCREENWIDTH]; short ceilingclip[SCREENWIDTH]; // // spanstart holds the start of a plane span // initialized to 0 at start // int spanstart[SCREENHEIGHT]; int spanstop[SCREENHEIGHT]; // // texture mapping // lighttable_t **planezlight; fixed_t planeheight; fixed_t yslope[SCREENHEIGHT]; fixed_t distscale[SCREENWIDTH]; fixed_t basexscale, baseyscale; fixed_t cachedheight[SCREENHEIGHT]; fixed_t cacheddistance[SCREENHEIGHT]; fixed_t cachedxstep[SCREENHEIGHT]; fixed_t cachedystep[SCREENHEIGHT]; /* ================ = = R_InitSkyMap = = Called whenever the view size changes = ================ */ void R_InitSkyMap(void) { skyflatnum = R_FlatNumForName(DEH_String("F_SKY1")); skytexturemid = 200 * FRACUNIT; skyiscale = FRACUNIT; } /* ==================== = = R_InitPlanes = = Only at game startup ==================== */ void R_InitPlanes(void) { } /* ================ = = R_MapPlane = global vars: planeheight ds_source basexscale baseyscale viewx viewy BASIC PRIMITIVE ================ */ void R_MapPlane(int y, int x1, int x2) { angle_t angle; fixed_t distance, length; unsigned index; #ifdef RANGECHECK if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned) y > viewheight) I_Error("R_MapPlane: %i, %i at %i", x1, x2, y); #endif if (planeheight != cachedheight[y]) { cachedheight[y] = planeheight; distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale); ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale); } else { distance = cacheddistance[y]; ds_xstep = cachedxstep[y]; ds_ystep = cachedystep[y]; } length = FixedMul(distance, distscale[x1]); angle = (viewangle + xtoviewangle[x1]) >> ANGLETOFINESHIFT; ds_xfrac = viewx + FixedMul(finecosine[angle], length); ds_yfrac = -viewy - FixedMul(finesine[angle], length); if (fixedcolormap) ds_colormap = fixedcolormap; else { index = distance >> LIGHTZSHIFT; if (index >= MAXLIGHTZ) index = MAXLIGHTZ - 1; ds_colormap = planezlight[index]; } ds_y = y; ds_x1 = x1; ds_x2 = x2; spanfunc(); // high or low detail } //============================================================================= /* ==================== = = R_ClearPlanes = = At begining of frame ==================== */ void R_ClearPlanes(void) { int i; angle_t angle; // // opening / clipping determination // for (i = 0; i < viewwidth; i++) { floorclip[i] = viewheight; ceilingclip[i] = -1; } lastvisplane = visplanes; lastopening = openings; // // texture calculation // memset(cachedheight, 0, sizeof(cachedheight)); angle = (viewangle - ANG90) >> ANGLETOFINESHIFT; // left to right mapping // scale will be unit scale at SCREENWIDTH/2 distance basexscale = FixedDiv(finecosine[angle], centerxfrac); baseyscale = -FixedDiv(finesine[angle], centerxfrac); } /* =============== = = R_FindPlane = =============== */ visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, int special) { visplane_t *check; if (picnum == skyflatnum) { // all skies map together height = 0; lightlevel = 0; } for (check = visplanes; check < lastvisplane; check++) { if (height == check->height && picnum == check->picnum && lightlevel == check->lightlevel && special == check->special) break; } if (check < lastvisplane) { return (check); } if (lastvisplane - visplanes == MAXVISPLANES) { I_Error("R_FindPlane: no more visplanes"); } lastvisplane++; check->height = height; check->picnum = picnum; check->lightlevel = lightlevel; check->special = special; check->minx = SCREENWIDTH; check->maxx = -1; memset(check->top, 0xff, sizeof(check->top)); return (check); } /* =============== = = R_CheckPlane = =============== */ visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop) { int intrl, intrh; int unionl, unionh; int x; if (start < pl->minx) { intrl = pl->minx; unionl = start; } else { unionl = pl->minx; intrl = start; } if (stop > pl->maxx) { intrh = pl->maxx; unionh = stop; } else { unionh = pl->maxx; intrh = stop; } for (x = intrl; x <= intrh; x++) if (pl->top[x] != 0xff) break; if (x > intrh) { pl->minx = unionl; pl->maxx = unionh; return pl; // use the same one } // make a new visplane lastvisplane->height = pl->height; lastvisplane->picnum = pl->picnum; lastvisplane->lightlevel = pl->lightlevel; lastvisplane->special = pl->special; pl = lastvisplane++; pl->minx = start; pl->maxx = stop; memset(pl->top, 0xff, sizeof(pl->top)); return pl; } //============================================================================= /* ================ = = R_MakeSpans = ================ */ void R_MakeSpans(int x, int t1, int b1, int t2, int b2) { while (t1 < t2 && t1 <= b1) { R_MapPlane(t1, spanstart[t1], x - 1); t1++; } while (b1 > b2 && b1 >= t1) { R_MapPlane(b1, spanstart[b1], x - 1); b1--; } while (t2 < t1 && t2 <= b2) { spanstart[t2] = x; t2++; } while (b2 > b1 && b2 >= t2) { spanstart[b2] = x; b2--; } } /* ================ = = R_DrawPlanes = = At the end of each frame ================ */ void R_DrawPlanes(void) { visplane_t *pl; int light; int x, stop; int lumpnum; int angle; byte *tempSource; byte *dest; int count; fixed_t frac, fracstep; extern byte *ylookup[MAXHEIGHT]; extern int columnofs[MAXWIDTH]; #ifdef RANGECHECK if (ds_p - drawsegs > MAXDRAWSEGS) I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs); if (lastvisplane - visplanes > MAXVISPLANES) I_Error("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes); if (lastopening - openings > MAXOPENINGS) I_Error("R_DrawPlanes: opening overflow (%i)", lastopening - openings); #endif for (pl = visplanes; pl < lastvisplane; pl++) { if (pl->minx > pl->maxx) continue; // // sky flat // if (pl->picnum == skyflatnum) { dc_iscale = skyiscale; dc_colormap = colormaps; // sky is allways drawn full bright dc_texturemid = skytexturemid; for (x = pl->minx; x <= pl->maxx; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; if (dc_yl <= dc_yh) { angle = (viewangle + xtoviewangle[x]) >> ANGLETOSKYSHIFT; dc_x = x; dc_source = R_GetColumn(skytexture, angle); count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = 1; frac = (dc_texturemid >> FRACBITS) + (dc_yl - centery); do { *dest = dc_source[frac]; dest += SCREENWIDTH; frac += fracstep; } while (count--); // colfunc (); } } continue; } // // regular flat // lumpnum = firstflat + flattranslation[pl->picnum]; tempSource = W_CacheLumpNum(lumpnum, PU_STATIC); switch (pl->special) { case 25: case 26: case 27: case 28: case 29: // Scroll_North ds_source = tempSource; break; case 20: case 21: case 22: case 23: case 24: // Scroll_East ds_source = tempSource + ((63 - ((leveltime >> 1) & 63)) << (pl->special - 20) & 63); //ds_source = tempSource+((leveltime>>1)&63); break; case 30: case 31: case 32: case 33: case 34: // Scroll_South ds_source = tempSource; break; case 35: case 36: case 37: case 38: case 39: // Scroll_West ds_source = tempSource; break; case 4: // Scroll_EastLavaDamage ds_source = tempSource + (((63 - ((leveltime >> 1) & 63)) << 3) & 63); break; default: ds_source = tempSource; } planeheight = abs(pl->height - viewz); light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; if (light >= LIGHTLEVELS) light = LIGHTLEVELS - 1; if (light < 0) light = 0; planezlight = zlight[light]; pl->top[pl->maxx + 1] = 0xff; pl->top[pl->minx - 1] = 0xff; stop = pl->maxx + 1; for (x = pl->minx; x <= stop; x++) R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1], pl->top[x], pl->bottom[x]); W_ReleaseLumpNum(lumpnum); } } chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_segs.c000066400000000000000000000465041257432200600231560ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************** //** //** R_SEGS.C //** //** This version has the tall-sector-crossing-precision-bug fixed. //** //************************************************************************** #include #include "doomdef.h" #include "r_local.h" // OPTIMIZE: closed two sided lines as single sided boolean segtextured; // true if any of the segs textures might be vis boolean markfloor; // false if the back side is the same plane boolean markceiling; boolean maskedtexture; int toptexture, bottomtexture, midtexture; angle_t rw_normalangle; int rw_angle1; // angle to line origin // // wall // int rw_x; int rw_stopx; angle_t rw_centerangle; fixed_t rw_offset; fixed_t rw_distance; fixed_t rw_scale; fixed_t rw_scalestep; fixed_t rw_midtexturemid; fixed_t rw_toptexturemid; fixed_t rw_bottomtexturemid; int worldtop, worldbottom, worldhigh, worldlow; fixed_t pixhigh, pixlow; fixed_t pixhighstep, pixlowstep; fixed_t topfrac, topstep; fixed_t bottomfrac, bottomstep; lighttable_t **walllights; short *maskedtexturecol; /* ================ = = R_RenderMaskedSegRange = ================ */ void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2) { unsigned index; column_t *col; int lightnum; int texnum; // // calculate light table // use different light tables for horizontal / vertical / diagonal // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; frontsector = curline->frontsector; backsector = curline->backsector; texnum = texturetranslation[curline->sidedef->midtexture]; lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight; if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS - 1]; else walllights = scalelight[lightnum]; maskedtexturecol = ds->maskedtexturecol; rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1) * rw_scalestep; mfloorclip = ds->sprbottomclip; mceilingclip = ds->sprtopclip; // // find positioning // if (curline->linedef->flags & ML_DONTPEGBOTTOM) { dc_texturemid = frontsector->floorheight > backsector->floorheight ? frontsector->floorheight : backsector->floorheight; dc_texturemid = dc_texturemid + textureheight[texnum] - viewz; } else { dc_texturemid = frontsector->ceilingheight < backsector->ceilingheight ? frontsector->ceilingheight : backsector->ceilingheight; dc_texturemid = dc_texturemid - viewz; } dc_texturemid += curline->sidedef->rowoffset; if (fixedcolormap) dc_colormap = fixedcolormap; // // draw the columns // for (dc_x = x1; dc_x <= x2; dc_x++) { // calculate lighting if (maskedtexturecol[dc_x] != SHRT_MAX) { if (!fixedcolormap) { index = spryscale >> LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1; dc_colormap = walllights[index]; } sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); dc_iscale = 0xffffffffu / (unsigned) spryscale; // // draw the texture // col = (column_t *) ((byte *) R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); R_DrawMaskedColumn(col, -1); maskedtexturecol[dc_x] = SHRT_MAX; } spryscale += rw_scalestep; } } /* ================ = = R_RenderSegLoop = = Draws zero, one, or two textures (and possibly a masked texture) for walls = Can draw or mark the starting pixel of floor and ceiling textures = = CALLED: CORE LOOPING ROUTINE ================ */ #define HEIGHTBITS 12 #define HEIGHTUNIT (1<> HEIGHTBITS; if (yl < ceilingclip[rw_x] + 1) yl = ceilingclip[rw_x] + 1; // no space above wall if (markceiling) { top = ceilingclip[rw_x] + 1; bottom = yl - 1; if (bottom >= floorclip[rw_x]) bottom = floorclip[rw_x] - 1; if (top <= bottom) { ceilingplane->top[rw_x] = top; ceilingplane->bottom[rw_x] = bottom; } } yh = bottomfrac >> HEIGHTBITS; if (yh >= floorclip[rw_x]) yh = floorclip[rw_x] - 1; if (markfloor) { top = yh + 1; bottom = floorclip[rw_x] - 1; if (top <= ceilingclip[rw_x]) top = ceilingclip[rw_x] + 1; if (top <= bottom) { floorplane->top[rw_x] = top; floorplane->bottom[rw_x] = bottom; } } // // texturecolumn and lighting are independent of wall tiers // if (segtextured) { // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x]) >> ANGLETOFINESHIFT; texturecolumn = rw_offset - FixedMul(finetangent[angle], rw_distance); texturecolumn >>= FRACBITS; // calculate lighting index = rw_scale >> LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1; dc_colormap = walllights[index]; dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned) rw_scale; } // // draw the wall tiers // if (midtexture) { // single sided line dc_yl = yl; dc_yh = yh; dc_texturemid = rw_midtexturemid; dc_source = R_GetColumn(midtexture, texturecolumn); colfunc(); ceilingclip[rw_x] = viewheight; floorclip[rw_x] = -1; } else { // two sided line if (toptexture) { // top wall mid = pixhigh >> HEIGHTBITS; pixhigh += pixhighstep; if (mid >= floorclip[rw_x]) mid = floorclip[rw_x] - 1; if (mid >= yl) { dc_yl = yl; dc_yh = mid; dc_texturemid = rw_toptexturemid; dc_source = R_GetColumn(toptexture, texturecolumn); colfunc(); ceilingclip[rw_x] = mid; } else ceilingclip[rw_x] = yl - 1; } else { // no top wall if (markceiling) ceilingclip[rw_x] = yl - 1; } if (bottomtexture) { // bottom wall mid = (pixlow + HEIGHTUNIT - 1) >> HEIGHTBITS; pixlow += pixlowstep; if (mid <= ceilingclip[rw_x]) mid = ceilingclip[rw_x] + 1; // no space above wall if (mid <= yh) { dc_yl = mid; dc_yh = yh; dc_texturemid = rw_bottomtexturemid; dc_source = R_GetColumn(bottomtexture, texturecolumn); colfunc(); floorclip[rw_x] = mid; } else floorclip[rw_x] = yh + 1; } else { // no bottom wall if (markfloor) floorclip[rw_x] = yh + 1; } if (maskedtexture) { // save texturecol for backdrawing of masked mid texture maskedtexturecol[rw_x] = texturecolumn; } } rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; } } /* ===================== = = R_StoreWallRange = = A wall segment will be drawn between start and stop pixels (inclusive) = ====================== */ void R_StoreWallRange(int start, int stop) { fixed_t hyp; fixed_t sineval; angle_t distangle, offsetangle; fixed_t vtop; int lightnum; if (ds_p == &drawsegs[MAXDRAWSEGS]) return; // don't overflow and crash #ifdef RANGECHECK if (start >= viewwidth || start > stop) I_Error("Bad R_RenderWallRange: %i to %i", start, stop); #endif sidedef = curline->sidedef; linedef = curline->linedef; // mark the segment as visible for auto map linedef->flags |= ML_MAPPED; // // calculate rw_distance for scale calculation // rw_normalangle = curline->angle + ANG90; offsetangle = abs(rw_normalangle - rw_angle1); if (offsetangle > ANG90) offsetangle = ANG90; distangle = ANG90 - offsetangle; hyp = R_PointToDist(curline->v1->x, curline->v1->y); sineval = finesine[distangle >> ANGLETOFINESHIFT]; rw_distance = FixedMul(hyp, sineval); ds_p->x1 = rw_x = start; ds_p->x2 = stop; ds_p->curline = curline; rw_stopx = stop + 1; // // calculate scale at both ends and step // ds_p->scale1 = rw_scale = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[start]); if (stop > start) { ds_p->scale2 = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[stop]); ds_p->scalestep = rw_scalestep = (ds_p->scale2 - rw_scale) / (stop - start); } else { // // try to fix the stretched line bug // #if 0 if (rw_distance < FRACUNIT / 2) { fixed_t trx, try; fixed_t gxt, gyt; trx = curline->v1->x - viewx; try = curline->v1->y - viewy; gxt = FixedMul(trx, viewcos); gyt = -FixedMul(try, viewsin); ds_p->scale1 = FixedDiv(projection, gxt - gyt); } #endif ds_p->scale2 = ds_p->scale1; } // // calculate texture boundaries and decide if floor / ceiling marks // are needed // worldtop = frontsector->ceilingheight - viewz; worldbottom = frontsector->floorheight - viewz; midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; if (!backsector) { // // single sided line // midtexture = texturetranslation[sidedef->midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; if (linedef->flags & ML_DONTPEGBOTTOM) { vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; rw_midtexturemid = vtop - viewz; // bottom of texture at bottom } else rw_midtexturemid = worldtop; // top of texture at top rw_midtexturemid += sidedef->rowoffset; ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->tsilheight = INT_MIN; } else { // // two sided line // ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; if (frontsector->floorheight > backsector->floorheight) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = frontsector->floorheight; } else if (backsector->floorheight > viewz) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT_MAX; // ds_p->sprbottomclip = negonearray; } if (frontsector->ceilingheight < backsector->ceilingheight) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = frontsector->ceilingheight; } else if (backsector->ceilingheight < viewz) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; // ds_p->sprtopclip = screenheightarray; } if (backsector->ceilingheight <= frontsector->floorheight) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (backsector->floorheight >= frontsector->ceilingheight) { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT_MIN; ds_p->silhouette |= SIL_TOP; } worldhigh = backsector->ceilingheight - viewz; worldlow = backsector->floorheight - viewz; // hack to allow height changes in outdoor areas if (frontsector->ceilingpic == skyflatnum && backsector->ceilingpic == skyflatnum) worldtop = worldhigh; if (worldlow != worldbottom || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel) markfloor = true; else markfloor = false; // same plane on both sides if (worldhigh != worldtop || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel) markceiling = true; else markceiling = false; // same plane on both sides if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) markceiling = markfloor = true; // closed door if (worldhigh < worldtop) { // top texture toptexture = texturetranslation[sidedef->toptexture]; if (linedef->flags & ML_DONTPEGTOP) rw_toptexturemid = worldtop; // top of texture at top else { vtop = backsector->ceilingheight + textureheight[sidedef->toptexture]; rw_toptexturemid = vtop - viewz; // bottom of texture } } if (worldlow > worldbottom) { // bottom texture bottomtexture = texturetranslation[sidedef->bottomtexture]; if (linedef->flags & ML_DONTPEGBOTTOM) { // bottom of texture at bottom rw_bottomtexturemid = worldtop; // top of texture at top } else // top of texture at top rw_bottomtexturemid = worldlow; } rw_toptexturemid += sidedef->rowoffset; rw_bottomtexturemid += sidedef->rowoffset; // // allocate space for masked texture tables // if (sidedef->midtexture) { // masked midtexture maskedtexture = true; ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; lastopening += rw_stopx - rw_x; } } // // calculate rw_offset (only needed for textured lines) // segtextured = midtexture | toptexture | bottomtexture | maskedtexture; if (segtextured) { offsetangle = rw_normalangle - rw_angle1; if (offsetangle > ANG180) offsetangle = -offsetangle; if (offsetangle > ANG90) offsetangle = ANG90; sineval = finesine[offsetangle >> ANGLETOFINESHIFT]; rw_offset = FixedMul(hyp, sineval); if (rw_normalangle - rw_angle1 < ANG180) rw_offset = -rw_offset; rw_offset += sidedef->textureoffset + curline->offset; rw_centerangle = ANG90 + viewangle - rw_normalangle; // // calculate light table // use different light tables for horizontal / vertical / diagonal // OPTIMIZE: get rid of LIGHTSEGSHIFT globally if (!fixedcolormap) { lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight; if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS - 1]; else walllights = scalelight[lightnum]; } } // // if a floor / ceiling plane is on the wrong side of the view plane // it is definately invisible and doesn't need to be marked // if (frontsector->floorheight >= viewz) markfloor = false; // above view plane if (frontsector->ceilingheight <= viewz && frontsector->ceilingpic != skyflatnum) markceiling = false; // below view plane // // calculate incremental stepping values for texture edges // worldtop >>= 4; worldbottom >>= 4; topstep = -FixedMul(rw_scalestep, worldtop); topfrac = (centeryfrac >> 4) - FixedMul(worldtop, rw_scale); bottomstep = -FixedMul(rw_scalestep, worldbottom); bottomfrac = (centeryfrac >> 4) - FixedMul(worldbottom, rw_scale); if (backsector) { worldhigh >>= 4; worldlow >>= 4; if (worldhigh < worldtop) { pixhigh = (centeryfrac >> 4) - FixedMul(worldhigh, rw_scale); pixhighstep = -FixedMul(rw_scalestep, worldhigh); } if (worldlow > worldbottom) { pixlow = (centeryfrac >> 4) - FixedMul(worldlow, rw_scale); pixlowstep = -FixedMul(rw_scalestep, worldlow); } } // // render it // if (markceiling) ceilingplane = R_CheckPlane(ceilingplane, rw_x, rw_stopx - 1); if (markfloor) floorplane = R_CheckPlane(floorplane, rw_x, rw_stopx - 1); R_RenderSegLoop(); // // save sprite clipping info // if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) { memcpy(lastopening, ceilingclip + start, 2 * (rw_stopx - start)); ds_p->sprtopclip = lastopening - start; lastopening += rw_stopx - start; } if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) { memcpy(lastopening, floorclip + start, 2 * (rw_stopx - start)); ds_p->sprbottomclip = lastopening - start; lastopening += rw_stopx - start; } if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; } if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; ds_p->bsilheight = INT_MAX; } ds_p++; } chocolate-doom-chocolate-doom-2.2.1/src/heretic/r_things.c000066400000000000000000000620721257432200600235070ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // R_things.c #include #include #include "doomdef.h" #include "deh_str.h" #include "i_swap.h" #include "i_system.h" #include "r_local.h" typedef struct { int x1, x2; int column; int topclip; int bottomclip; } maskdraw_t; /* Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn CLOCKWISE around the axis. This is not the same as the angle, which increases counter clockwise (protractor). There was a lot of stuff grabbed wrong, so I changed it... */ fixed_t pspritescale, pspriteiscale; lighttable_t **spritelights; // constant arrays used for psprite clipping and initializing clipping short negonearray[SCREENWIDTH]; short screenheightarray[SCREENWIDTH]; /* =============================================================================== INITIALIZATION FUNCTIONS =============================================================================== */ // variables used to look up and range check thing_t sprites patches spritedef_t *sprites; int numsprites; spriteframe_t sprtemp[26]; int maxframe; char *spritename; /* ================= = = R_InstallSpriteLump = = Local function for R_InitSprites ================= */ void R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation, boolean flipped) { int r; if (frame >= 26 || rotation > 8) I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump); if ((int) frame > maxframe) maxframe = frame; if (rotation == 0) { // the lump should be used for all rotations if (sprtemp[frame].rotate == false) I_Error("R_InitSprites: Sprite %s frame %c has multip rot=0 lump", spritename, 'A' + frame); if (sprtemp[frame].rotate == true) I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump", spritename, 'A' + frame); sprtemp[frame].rotate = false; for (r = 0; r < 8; r++) { sprtemp[frame].lump[r] = lump - firstspritelump; sprtemp[frame].flip[r] = (byte) flipped; } return; } // the lump is only used for one rotation if (sprtemp[frame].rotate == false) I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump", spritename, 'A' + frame); sprtemp[frame].rotate = true; rotation--; // make 0 based if (sprtemp[frame].lump[rotation] != -1) I_Error ("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it", spritename, 'A' + frame, '1' + rotation); sprtemp[frame].lump[rotation] = lump - firstspritelump; sprtemp[frame].flip[rotation] = (byte) flipped; } /* ================= = = R_InitSpriteDefs = = Pass a null terminated list of sprite names (4 chars exactly) to be used = Builds the sprite rotation matrixes to account for horizontally flipped = sprites. Will report an error if the lumps are inconsistant =Only called at startup = = Sprite lump names are 4 characters for the actor, a letter for the frame, = and a number for the rotation, A sprite that is flippable will have an = additional letter/number appended. The rotation character can be 0 to = signify no rotations ================= */ void R_InitSpriteDefs(char **namelist) { char **check; int i, l, frame, rotation; int start, end; // count the number of sprite names check = namelist; while (*check != NULL) check++; numsprites = check - namelist; if (!numsprites) return; sprites = Z_Malloc(numsprites * sizeof(*sprites), PU_STATIC, NULL); start = firstspritelump - 1; end = lastspritelump + 1; // scan all the lump names for each of the names, noting the highest // frame letter // Just compare 4 characters as ints for (i = 0; i < numsprites; i++) { spritename = DEH_String(namelist[i]); memset(sprtemp, -1, sizeof(sprtemp)); maxframe = -1; // // scan the lumps, filling in the frames for whatever is found // for (l = start + 1; l < end; l++) if (!strncasecmp(lumpinfo[l].name, spritename, 4)) { frame = lumpinfo[l].name[4] - 'A'; rotation = lumpinfo[l].name[5] - '0'; R_InstallSpriteLump(l, frame, rotation, false); if (lumpinfo[l].name[6]) { frame = lumpinfo[l].name[6] - 'A'; rotation = lumpinfo[l].name[7] - '0'; R_InstallSpriteLump(l, frame, rotation, true); } } // // check the frames that were found for completeness // if (maxframe == -1) { //continue; sprites[i].numframes = 0; if (gamemode == shareware) continue; I_Error("R_InitSprites: No lumps found for sprite %s", spritename); } maxframe++; for (frame = 0; frame < maxframe; frame++) { switch ((int) sprtemp[frame].rotate) { case -1: // no rotations were found for that frame at all I_Error("R_InitSprites: No patches found for %s frame %c", spritename, frame + 'A'); case 0: // only the first rotation is needed break; case 1: // must have all 8 frames for (rotation = 0; rotation < 8; rotation++) if (sprtemp[frame].lump[rotation] == -1) I_Error ("R_InitSprites: Sprite %s frame %c is missing rotations", spritename, frame + 'A'); } } // // allocate space for the frames present and copy sprtemp to it // sprites[i].numframes = maxframe; sprites[i].spriteframes = Z_Malloc(maxframe * sizeof(spriteframe_t), PU_STATIC, NULL); memcpy(sprites[i].spriteframes, sprtemp, maxframe * sizeof(spriteframe_t)); } } /* =============================================================================== GAME FUNCTIONS =============================================================================== */ vissprite_t vissprites[MAXVISSPRITES], *vissprite_p; int newvissprite; /* =================== = = R_InitSprites = = Called at program start =================== */ void R_InitSprites(char **namelist) { int i; for (i = 0; i < SCREENWIDTH; i++) { negonearray[i] = -1; } R_InitSpriteDefs(namelist); } /* =================== = = R_ClearSprites = = Called at frame start =================== */ void R_ClearSprites(void) { vissprite_p = vissprites; } /* =================== = = R_NewVisSprite = =================== */ vissprite_t overflowsprite; vissprite_t *R_NewVisSprite(void) { if (vissprite_p == &vissprites[MAXVISSPRITES]) return &overflowsprite; vissprite_p++; return vissprite_p - 1; } /* ================ = = R_DrawMaskedColumn = = Used for sprites and masked mid textures ================ */ short *mfloorclip; short *mceilingclip; fixed_t spryscale; fixed_t sprtopscreen; fixed_t sprbotscreen; void R_DrawMaskedColumn(column_t * column, signed int baseclip) { int topscreen, bottomscreen; fixed_t basetexturemid; basetexturemid = dc_texturemid; for (; column->topdelta != 0xff;) { // calculate unclipped screen coordinates for post topscreen = sprtopscreen + spryscale * column->topdelta; bottomscreen = topscreen + spryscale * column->length; dc_yl = (topscreen + FRACUNIT - 1) >> FRACBITS; dc_yh = (bottomscreen - 1) >> FRACBITS; if (dc_yh >= mfloorclip[dc_x]) dc_yh = mfloorclip[dc_x] - 1; if (dc_yl <= mceilingclip[dc_x]) dc_yl = mceilingclip[dc_x] + 1; if (dc_yh >= baseclip && baseclip != -1) dc_yh = baseclip; if (dc_yl <= dc_yh) { dc_source = (byte *) column + 3; dc_texturemid = basetexturemid - (column->topdelta << FRACBITS); // dc_source = (byte *)column + 3 - column->topdelta; colfunc(); // either R_DrawColumn or R_DrawTLColumn } column = (column_t *) ((byte *) column + column->length + 4); } dc_texturemid = basetexturemid; } /* ================ = = R_DrawVisSprite = = mfloorclip and mceilingclip should also be set ================ */ void R_DrawVisSprite(vissprite_t * vis, int x1, int x2) { column_t *column; int texturecolumn; fixed_t frac; patch_t *patch; fixed_t baseclip; patch = W_CacheLumpNum(vis->patch + firstspritelump, PU_CACHE); dc_colormap = vis->colormap; // if(!dc_colormap) // colfunc = tlcolfunc; // NULL colormap = shadow draw if (vis->mobjflags & MF_SHADOW) { if (vis->mobjflags & MF_TRANSLATION) { colfunc = R_DrawTranslatedTLColumn; dc_translation = translationtables - 256 + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8)); } else { // Draw using shadow column function colfunc = tlcolfunc; } } else if (vis->mobjflags & MF_TRANSLATION) { // Draw using translated column function colfunc = R_DrawTranslatedColumn; dc_translation = translationtables - 256 + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8)); } dc_iscale = abs(vis->xiscale) >> detailshift; dc_texturemid = vis->texturemid; frac = vis->startfrac; spryscale = vis->scale; sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); // check to see if weapon is a vissprite if (vis->psprite) { dc_texturemid += FixedMul(((centery - viewheight / 2) << FRACBITS), vis->xiscale); sprtopscreen += (viewheight / 2 - centery) << FRACBITS; } if (vis->footclip && !vis->psprite) { sprbotscreen = sprtopscreen + FixedMul(SHORT(patch->height) << FRACBITS, spryscale); baseclip = (sprbotscreen - FixedMul(vis->footclip << FRACBITS, spryscale)) >> FRACBITS; } else { baseclip = -1; } for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) { texturecolumn = frac >> FRACBITS; #ifdef RANGECHECK if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) I_Error("R_DrawSpriteRange: bad texturecolumn"); #endif column = (column_t *) ((byte *) patch + LONG(patch->columnofs[texturecolumn])); R_DrawMaskedColumn(column, baseclip); } colfunc = basecolfunc; } /* =================== = = R_ProjectSprite = = Generates a vissprite for a thing if it might be visible = =================== */ void R_ProjectSprite(mobj_t * thing) { fixed_t trx, try; fixed_t gxt, gyt; fixed_t tx, tz; fixed_t xscale; int x1, x2; spritedef_t *sprdef; spriteframe_t *sprframe; int lump; unsigned rot; boolean flip; int index; vissprite_t *vis; angle_t ang; fixed_t iscale; if (thing->flags2 & MF2_DONTDRAW) { // Never make a vissprite when MF2_DONTDRAW is flagged. return; } // // transform the origin point // trx = thing->x - viewx; try = thing->y - viewy; gxt = FixedMul(trx, viewcos); gyt = -FixedMul(try, viewsin); tz = gxt - gyt; if (tz < MINZ) return; // thing is behind view plane xscale = FixedDiv(projection, tz); gxt = -FixedMul(trx, viewsin); gyt = FixedMul(try, viewcos); tx = -(gyt + gxt); if (abs(tx) > (tz << 2)) return; // too far off the side // // decide which patch to use for sprite reletive to player // #ifdef RANGECHECK if ((unsigned) thing->sprite >= numsprites) I_Error("R_ProjectSprite: invalid sprite number %i ", thing->sprite); #endif sprdef = &sprites[thing->sprite]; #ifdef RANGECHECK if ((thing->frame & FF_FRAMEMASK) >= sprdef->numframes) I_Error("R_ProjectSprite: invalid sprite frame %i : %i ", thing->sprite, thing->frame); #endif sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; if (sprframe->rotate) { // choose a different rotation based on player view ang = R_PointToAngle(thing->x, thing->y); rot = (ang - thing->angle + (unsigned) (ANG45 / 2) * 9) >> 29; lump = sprframe->lump[rot]; flip = (boolean) sprframe->flip[rot]; } else { // use single rotation for all views lump = sprframe->lump[0]; flip = (boolean) sprframe->flip[0]; } // // calculate edges of the shape // tx -= spriteoffset[lump]; x1 = (centerxfrac + FixedMul(tx, xscale)) >> FRACBITS; if (x1 > viewwidth) return; // off the right side tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul(tx, xscale)) >> FRACBITS) - 1; if (x2 < 0) return; // off the left side // // store information in a vissprite // vis = R_NewVisSprite(); vis->mobjflags = thing->flags; vis->psprite = false; vis->scale = xscale << detailshift; vis->gx = thing->x; vis->gy = thing->y; vis->gz = thing->z; vis->gzt = thing->z + spritetopoffset[lump]; // foot clipping if (thing->flags2 & MF2_FEETARECLIPPED && thing->z <= thing->subsector->sector->floorheight) { vis->footclip = 10; } else vis->footclip = 0; vis->texturemid = vis->gzt - viewz - (vis->footclip << FRACBITS); vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2; iscale = FixedDiv(FRACUNIT, xscale); if (flip) { vis->startfrac = spritewidth[lump] - 1; vis->xiscale = -iscale; } else { vis->startfrac = 0; vis->xiscale = iscale; } if (vis->x1 > x1) vis->startfrac += vis->xiscale * (vis->x1 - x1); vis->patch = lump; // // get light level // // if (thing->flags & MF_SHADOW) // vis->colormap = NULL; // shadow draw // else ... if (fixedcolormap) vis->colormap = fixedcolormap; // fixed map else if (thing->frame & FF_FULLBRIGHT) vis->colormap = colormaps; // full bright else { // diminished light index = xscale >> (LIGHTSCALESHIFT - detailshift); if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1; vis->colormap = spritelights[index]; } } /* ======================== = = R_AddSprites = ======================== */ void R_AddSprites(sector_t * sec) { mobj_t *thing; int lightnum; if (sec->validcount == validcount) return; // already added sec->validcount = validcount; lightnum = (sec->lightlevel >> LIGHTSEGSHIFT) + extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS - 1]; else spritelights = scalelight[lightnum]; for (thing = sec->thinglist; thing; thing = thing->snext) R_ProjectSprite(thing); } /* ======================== = = R_DrawPSprite = ======================== */ int PSpriteSY[NUMWEAPONS] = { 0, // staff 5 * FRACUNIT, // goldwand 15 * FRACUNIT, // crossbow 15 * FRACUNIT, // blaster 15 * FRACUNIT, // skullrod 15 * FRACUNIT, // phoenix rod 15 * FRACUNIT, // mace 15 * FRACUNIT, // gauntlets 15 * FRACUNIT // beak }; void R_DrawPSprite(pspdef_t * psp) { fixed_t tx; int x1, x2; spritedef_t *sprdef; spriteframe_t *sprframe; int lump; boolean flip; vissprite_t *vis, avis; int tempangle; // // decide which patch to use // #ifdef RANGECHECK if ((unsigned) psp->state->sprite >= numsprites) I_Error("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite); #endif sprdef = &sprites[psp->state->sprite]; #ifdef RANGECHECK if ((psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) I_Error("R_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame); #endif sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK]; lump = sprframe->lump[0]; flip = (boolean) sprframe->flip[0]; // // calculate edges of the shape // tx = psp->sx - 160 * FRACUNIT; tx -= spriteoffset[lump]; if (viewangleoffset) { tempangle = ((centerxfrac / 1024) * (viewangleoffset >> ANGLETOFINESHIFT)); } else { tempangle = 0; } x1 = (centerxfrac + FixedMul(tx, pspritescale) + tempangle) >> FRACBITS; if (x1 > viewwidth) return; // off the right side tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul(tx, pspritescale) + tempangle) >> FRACBITS) - 1; if (x2 < 0) return; // off the left side // // store information in a vissprite // vis = &avis; vis->mobjflags = 0; vis->psprite = true; vis->texturemid = (BASEYCENTER << FRACBITS) + FRACUNIT / 2 - (psp->sy - spritetopoffset[lump]); if (viewheight == SCREENHEIGHT) { vis->texturemid -= PSpriteSY[players[consoleplayer].readyweapon]; } vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2; vis->scale = pspritescale << detailshift; if (flip) { vis->xiscale = -pspriteiscale; vis->startfrac = spritewidth[lump] - 1; } else { vis->xiscale = pspriteiscale; vis->startfrac = 0; } if (vis->x1 > x1) vis->startfrac += vis->xiscale * (vis->x1 - x1); vis->patch = lump; if (viewplayer->powers[pw_invisibility] > 4 * 32 || viewplayer->powers[pw_invisibility] & 8) { // Invisibility vis->colormap = spritelights[MAXLIGHTSCALE - 1]; vis->mobjflags |= MF_SHADOW; } else if (fixedcolormap) { // Fixed color vis->colormap = fixedcolormap; } else if (psp->state->frame & FF_FULLBRIGHT) { // Full bright vis->colormap = colormaps; } else { // local light vis->colormap = spritelights[MAXLIGHTSCALE - 1]; } R_DrawVisSprite(vis, vis->x1, vis->x2); } /* ======================== = = R_DrawPlayerSprites = ======================== */ void R_DrawPlayerSprites(void) { int i, lightnum; pspdef_t *psp; // // get light level // lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) + extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS - 1]; else spritelights = scalelight[lightnum]; // // clip to screen bounds // mfloorclip = screenheightarray; mceilingclip = negonearray; // // add all active psprites // for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; i++, psp++) if (psp->state) R_DrawPSprite(psp); } /* ======================== = = R_SortVisSprites = ======================== */ vissprite_t vsprsortedhead; void R_SortVisSprites(void) { int i, count; vissprite_t *ds, *best; vissprite_t unsorted; fixed_t bestscale; count = vissprite_p - vissprites; unsorted.next = unsorted.prev = &unsorted; if (!count) return; for (ds = vissprites; ds < vissprite_p; ds++) { ds->next = ds + 1; ds->prev = ds - 1; } vissprites[0].prev = &unsorted; unsorted.next = &vissprites[0]; (vissprite_p - 1)->next = &unsorted; unsorted.prev = vissprite_p - 1; // // pull the vissprites out by scale // best = 0; // shut up the compiler warning vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; for (i = 0; i < count; i++) { bestscale = INT_MAX; for (ds = unsorted.next; ds != &unsorted; ds = ds->next) { if (ds->scale < bestscale) { bestscale = ds->scale; best = ds; } } best->next->prev = best->prev; best->prev->next = best->next; best->next = &vsprsortedhead; best->prev = vsprsortedhead.prev; vsprsortedhead.prev->next = best; vsprsortedhead.prev = best; } } /* ======================== = = R_DrawSprite = ======================== */ void R_DrawSprite(vissprite_t * spr) { drawseg_t *ds; short clipbot[SCREENWIDTH], cliptop[SCREENWIDTH]; int x, r1, r2; fixed_t scale, lowscale; int silhouette; for (x = spr->x1; x <= spr->x2; x++) clipbot[x] = cliptop[x] = -2; // // scan drawsegs from end to start for obscuring segs // the first drawseg that has a greater scale is the clip seg // for (ds = ds_p - 1; ds >= drawsegs; ds--) { // // determine if the drawseg obscures the sprite // if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || (!ds->silhouette && !ds->maskedtexturecol)) continue; // doesn't cover sprite r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; if (ds->scale1 > ds->scale2) { lowscale = ds->scale2; scale = ds->scale1; } else { lowscale = ds->scale1; scale = ds->scale2; } if (scale < spr->scale || (lowscale < spr->scale && !R_PointOnSegSide(spr->gx, spr->gy, ds->curline))) { if (ds->maskedtexturecol) // masked mid texture R_RenderMaskedSegRange(ds, r1, r2); continue; // seg is behind sprite } // // clip this piece of the sprite // silhouette = ds->silhouette; if (spr->gz >= ds->bsilheight) silhouette &= ~SIL_BOTTOM; if (spr->gzt <= ds->tsilheight) silhouette &= ~SIL_TOP; if (silhouette == 1) { // bottom sil for (x = r1; x <= r2; x++) if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; } else if (silhouette == 2) { // top sil for (x = r1; x <= r2; x++) if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } else if (silhouette == 3) { // both for (x = r1; x <= r2; x++) { if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } } } // // all clipping has been performed, so draw the sprite // // check for unclipped columns for (x = spr->x1; x <= spr->x2; x++) { if (clipbot[x] == -2) clipbot[x] = viewheight; if (cliptop[x] == -2) cliptop[x] = -1; } mfloorclip = clipbot; mceilingclip = cliptop; R_DrawVisSprite(spr, spr->x1, spr->x2); } /* ======================== = = R_DrawMasked = ======================== */ void R_DrawMasked(void) { vissprite_t *spr; drawseg_t *ds; R_SortVisSprites(); if (vissprite_p > vissprites) { // draw all vissprites back to front for (spr = vsprsortedhead.next; spr != &vsprsortedhead; spr = spr->next) R_DrawSprite(spr); } // // render any remaining masked mid textures // for (ds = ds_p - 1; ds >= drawsegs; ds--) if (ds->maskedtexturecol) R_RenderMaskedSegRange(ds, ds->x1, ds->x2); // // draw the psprites on top of everything // // Added for the sideviewing with an external device if (viewangleoffset <= 1024 << ANGLETOFINESHIFT || viewangleoffset >= -1024 << ANGLETOFINESHIFT) { // don't draw on side views R_DrawPlayerSprites(); } // if (!viewangleoffset) // don't draw on side views // R_DrawPlayerSprites (); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/s_sound.c000066400000000000000000000346301257432200600233430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "doomdef.h" #include "i_system.h" #include "m_random.h" #include "sounds.h" #include "s_sound.h" #include "i_sound.h" #include "r_local.h" #include "p_local.h" #include "sounds.h" #include "w_wad.h" #include "z_zone.h" /* =============================================================================== MUSIC & SFX API =============================================================================== */ void S_ShutDown(void); boolean S_StopSoundID(int sound_id, int priority); static channel_t channel[MAX_CHANNELS]; static void *rs; // Handle for the registered song int mus_song = -1; int mus_lumpnum; void *mus_sndptr; byte *soundCurve; int snd_MaxVolume = 10; int snd_MusicVolume = 10; int snd_Channels = 16; int AmbChan; void S_Start(void) { int i; S_StartSong((gameepisode - 1) * 9 + gamemap - 1, true); //stop all sounds for (i = 0; i < snd_Channels; i++) { if (channel[i].handle) { S_StopSound(channel[i].mo); } } memset(channel, 0, 8 * sizeof(channel_t)); } void S_StartSong(int song, boolean loop) { int mus_len; if (song == mus_song) { // don't replay an old song return; } if (rs != NULL) { I_StopSong(); I_UnRegisterSong(rs); } if (song < mus_e1m1 || song > NUMMUSIC) { return; } mus_lumpnum = W_GetNumForName(S_music[song].name); mus_sndptr = W_CacheLumpNum(mus_lumpnum, PU_MUSIC); mus_len = W_LumpLength(mus_lumpnum); rs = I_RegisterSong(mus_sndptr, mus_len); I_PlaySong(rs, loop); //'true' denotes endless looping. mus_song = song; } static mobj_t *GetSoundListener(void) { static degenmobj_t dummy_listener; // If we are at the title screen, the console player doesn't have an // object yet, so return a pointer to a static dummy listener instead. if (players[consoleplayer].mo != NULL) { return players[consoleplayer].mo; } else { dummy_listener.x = 0; dummy_listener.y = 0; dummy_listener.z = 0; return (mobj_t *) &dummy_listener; } } void S_StartSound(void *_origin, int sound_id) { mobj_t *origin = _origin; mobj_t *listener; int dist, vol; int i; int priority; int sep; int angle; int absx; int absy; static int sndcount = 0; int chan; listener = GetSoundListener(); if (sound_id == 0 || snd_MaxVolume == 0) return; if (origin == NULL) { origin = listener; } // calculate the distance before other stuff so that we can throw out // sounds that are beyond the hearing range. absx = abs(origin->x - listener->x); absy = abs(origin->y - listener->y); dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1); dist >>= FRACBITS; // dist = P_AproxDistance(origin->x-viewx, origin->y-viewy)>>FRACBITS; if (dist >= MAX_SND_DIST) { // dist = MAX_SND_DIST - 1; return; //sound is beyond the hearing range... } if (dist < 0) { dist = 0; } priority = S_sfx[sound_id].priority; priority *= (10 - (dist / 160)); if (!S_StopSoundID(sound_id, priority)) { return; // other sounds have greater priority } for (i = 0; i < snd_Channels; i++) { if (origin->player) { i = snd_Channels; break; // let the player have more than one sound. } if (origin == channel[i].mo) { // only allow other mobjs one sound S_StopSound(channel[i].mo); break; } } if (i >= snd_Channels) { if (sound_id >= sfx_wind) { if (AmbChan != -1 && S_sfx[sound_id].priority <= S_sfx[channel[AmbChan].sound_id].priority) { return; //ambient channel already in use } else { AmbChan = -1; } } for (i = 0; i < snd_Channels; i++) { if (channel[i].mo == NULL) { break; } } if (i >= snd_Channels) { //look for a lower priority sound to replace. sndcount++; if (sndcount >= snd_Channels) { sndcount = 0; } for (chan = 0; chan < snd_Channels; chan++) { i = (sndcount + chan) % snd_Channels; if (priority >= channel[i].priority) { chan = -1; //denote that sound should be replaced. break; } } if (chan != -1) { return; //no free channels. } else //replace the lower priority sound. { if (channel[i].handle) { if (I_SoundIsPlaying(channel[i].handle)) { I_StopSound(channel[i].handle); } if (S_sfx[channel[i].sound_id].usefulness > 0) { S_sfx[channel[i].sound_id].usefulness--; } if (AmbChan == i) { AmbChan = -1; } } } } } if (S_sfx[sound_id].lumpnum == 0) { S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]); } // calculate the volume based upon the distance from the sound origin. // vol = (snd_MaxVolume*16 + dist*(-snd_MaxVolume*16)/MAX_SND_DIST)>>9; vol = soundCurve[dist]; if (origin == listener) { sep = 128; } else { angle = R_PointToAngle2(listener->x, listener->y, origin->x, origin->y); angle = (angle - viewangle) >> 24; sep = angle * 2 - 128; if (sep < 64) sep = -sep; if (sep > 192) sep = 512 - sep; } // TODO: Play pitch-shifted sounds as in Vanilla Heretic channel[i].pitch = (byte) (127 + (M_Random() & 7) - (M_Random() & 7)); channel[i].handle = I_StartSound(&S_sfx[sound_id], i, vol, sep); channel[i].mo = origin; channel[i].sound_id = sound_id; channel[i].priority = priority; if (sound_id >= sfx_wind) { AmbChan = i; } if (S_sfx[sound_id].usefulness == -1) { S_sfx[sound_id].usefulness = 1; } else { S_sfx[sound_id].usefulness++; } } void S_StartSoundAtVolume(void *_origin, int sound_id, int volume) { mobj_t *origin = _origin; mobj_t *listener; int i; listener = GetSoundListener(); if (sound_id == 0 || snd_MaxVolume == 0) return; if (origin == NULL) { origin = listener; } if (volume == 0) { return; } volume = (volume * (snd_MaxVolume + 1) * 8) >> 7; // no priority checking, as ambient sounds would be the LOWEST. for (i = 0; i < snd_Channels; i++) { if (channel[i].mo == NULL) { break; } } if (i >= snd_Channels) { return; } if (S_sfx[sound_id].lumpnum == 0) { S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]); } // TODO: Pitch shifting. channel[i].pitch = (byte) (127 - (M_Random() & 3) + (M_Random() & 3)); channel[i].handle = I_StartSound(&S_sfx[sound_id], i, volume, 128); channel[i].mo = origin; channel[i].sound_id = sound_id; channel[i].priority = 1; //super low priority. if (S_sfx[sound_id].usefulness == -1) { S_sfx[sound_id].usefulness = 1; } else { S_sfx[sound_id].usefulness++; } } boolean S_StopSoundID(int sound_id, int priority) { int i; int lp; //least priority int found; if (S_sfx[sound_id].numchannels == -1) { return (true); } lp = -1; //denote the argument sound_id found = 0; for (i = 0; i < snd_Channels; i++) { if (channel[i].sound_id == sound_id && channel[i].mo) { found++; //found one. Now, should we replace it?? if (priority >= channel[i].priority) { // if we're gonna kill one, then this'll be it lp = i; priority = channel[i].priority; } } } if (found < S_sfx[sound_id].numchannels) { return (true); } else if (lp == -1) { return (false); // don't replace any sounds } if (channel[lp].handle) { if (I_SoundIsPlaying(channel[lp].handle)) { I_StopSound(channel[lp].handle); } if (S_sfx[channel[i].sound_id].usefulness > 0) { S_sfx[channel[i].sound_id].usefulness--; } channel[lp].mo = NULL; } return (true); } void S_StopSound(void *_origin) { mobj_t *origin = _origin; int i; for (i = 0; i < snd_Channels; i++) { if (channel[i].mo == origin) { I_StopSound(channel[i].handle); if (S_sfx[channel[i].sound_id].usefulness > 0) { S_sfx[channel[i].sound_id].usefulness--; } channel[i].handle = 0; channel[i].mo = NULL; if (AmbChan == i) { AmbChan = -1; } } } } void S_SoundLink(mobj_t * oldactor, mobj_t * newactor) { int i; for (i = 0; i < snd_Channels; i++) { if (channel[i].mo == oldactor) channel[i].mo = newactor; } } void S_PauseSound(void) { I_PauseSong(); } void S_ResumeSound(void) { I_ResumeSong(); } void S_UpdateSounds(mobj_t * listener) { int i, dist, vol; int angle; int sep; int priority; int absx; int absy; I_UpdateSound(); listener = GetSoundListener(); if (snd_MaxVolume == 0) { return; } for (i = 0; i < snd_Channels; i++) { if (!channel[i].handle || S_sfx[channel[i].sound_id].usefulness == -1) { continue; } if (!I_SoundIsPlaying(channel[i].handle)) { if (S_sfx[channel[i].sound_id].usefulness > 0) { S_sfx[channel[i].sound_id].usefulness--; } channel[i].handle = 0; channel[i].mo = NULL; channel[i].sound_id = 0; if (AmbChan == i) { AmbChan = -1; } } if (channel[i].mo == NULL || channel[i].sound_id == 0 || channel[i].mo == listener || listener == NULL) { continue; } else { absx = abs(channel[i].mo->x - listener->x); absy = abs(channel[i].mo->y - listener->y); dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1); dist >>= FRACBITS; // dist = P_AproxDistance(channel[i].mo->x-listener->x, channel[i].mo->y-listener->y)>>FRACBITS; if (dist >= MAX_SND_DIST) { S_StopSound(channel[i].mo); continue; } if (dist < 0) dist = 0; // calculate the volume based upon the distance from the sound origin. // vol = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE)+dist)*(snd_MaxVolume*8))>>7; vol = soundCurve[dist]; angle = R_PointToAngle2(listener->x, listener->y, channel[i].mo->x, channel[i].mo->y); angle = (angle - viewangle) >> 24; sep = angle * 2 - 128; if (sep < 64) sep = -sep; if (sep > 192) sep = 512 - sep; // TODO: Pitch shifting. I_UpdateSoundParams(channel[i].handle, vol, sep); priority = S_sfx[channel[i].sound_id].priority; priority *= (10 - (dist >> 8)); channel[i].priority = priority; } } } void S_Init(void) { I_SetOPLDriverVer(opl_v_old); soundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL); if (snd_Channels > 8) { snd_Channels = 8; } I_SetMusicVolume(snd_MusicVolume * 8); S_SetMaxVolume(true); I_AtExit(S_ShutDown, true); I_PrecacheSounds(S_sfx, NUMSFX); } void S_GetChannelInfo(SoundInfo_t * s) { int i; ChanInfo_t *c; s->channelCount = snd_Channels; s->musicVolume = snd_MusicVolume; s->soundVolume = snd_MaxVolume; for (i = 0; i < snd_Channels; i++) { c = &s->chan[i]; c->id = channel[i].sound_id; c->priority = channel[i].priority; c->name = S_sfx[c->id].name; c->mo = channel[i].mo; if (c->mo != NULL) { c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy) >> FRACBITS; } else { c->distance = 0; } } } void S_SetMaxVolume(boolean fullprocess) { int i; if (!fullprocess) { soundCurve[0] = (*((byte *) W_CacheLumpName("SNDCURVE", PU_CACHE)) * (snd_MaxVolume * 8)) >> 7; } else { for (i = 0; i < MAX_SND_DIST; i++) { soundCurve[i] = (*((byte *) W_CacheLumpName("SNDCURVE", PU_CACHE) + i) * (snd_MaxVolume * 8)) >> 7; } } } static boolean musicPaused; void S_SetMusicVolume(void) { I_SetMusicVolume(snd_MusicVolume * 8); if (snd_MusicVolume == 0) { I_PauseSong(); musicPaused = true; } else if (musicPaused) { musicPaused = false; I_ResumeSong(); } } void S_ShutDown(void) { I_StopSong(); I_UnRegisterSong(rs); I_ShutdownSound(); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/s_sound.h000066400000000000000000000022401257432200600233400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // soundst.h #ifndef __SOUNDSTH__ #define __SOUNDSTH__ extern int snd_MaxVolume; extern int snd_MusicVolume; void S_Start(void); void S_StartSound(void *origin, int sound_id); void S_StartSoundAtVolume(void *origin, int sound_id, int volume); void S_StopSound(void *origin); void S_PauseSound(void); void S_ResumeSound(void); void S_UpdateSounds(mobj_t * listener); void S_StartSong(int song, boolean loop); void S_Init(void); void S_GetChannelInfo(SoundInfo_t * s); void S_SetMaxVolume(boolean fullprocess); void S_SetMusicVolume(void); #endif chocolate-doom-chocolate-doom-2.2.1/src/heretic/sb_bar.c000066400000000000000000001047161257432200600231240ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // SB_bar.c #include "doomdef.h" #include "deh_str.h" #include "i_video.h" #include "i_swap.h" #include "m_cheat.h" #include "m_misc.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" // Types typedef struct Cheat_s { void (*func) (player_t * player, struct Cheat_s * cheat); cheatseq_t *seq; } Cheat_t; // Private Functions static void DrawSoundInfo(void); static void ShadeLine(int x, int y, int height, int shade); static void ShadeChain(void); static void DrINumber(signed int val, int x, int y); static void DrBNumber(signed int val, int x, int y); static void DrawCommonBar(void); static void DrawMainBar(void); static void DrawInventoryBar(void); static void DrawFullScreenStuff(void); static boolean HandleCheats(byte key); static void CheatGodFunc(player_t * player, Cheat_t * cheat); static void CheatNoClipFunc(player_t * player, Cheat_t * cheat); static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat); static void CheatPowerFunc(player_t * player, Cheat_t * cheat); static void CheatHealthFunc(player_t * player, Cheat_t * cheat); static void CheatKeysFunc(player_t * player, Cheat_t * cheat); static void CheatSoundFunc(player_t * player, Cheat_t * cheat); static void CheatTickerFunc(player_t * player, Cheat_t * cheat); static void CheatArtifact1Func(player_t * player, Cheat_t * cheat); static void CheatArtifact2Func(player_t * player, Cheat_t * cheat); static void CheatArtifact3Func(player_t * player, Cheat_t * cheat); static void CheatWarpFunc(player_t * player, Cheat_t * cheat); static void CheatChickenFunc(player_t * player, Cheat_t * cheat); static void CheatMassacreFunc(player_t * player, Cheat_t * cheat); static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat); static void CheatIDDQDFunc(player_t * player, Cheat_t * cheat); // Public Data boolean DebugSound; // debug flag for displaying sound info boolean inventory; int curpos; int inv_ptr; int ArtifactFlash; static int DisplayTicker = 0; // Private Data static int HealthMarker; static int ChainWiggle; static player_t *CPlayer; int playpalette; patch_t *PatchLTFACE; patch_t *PatchRTFACE; patch_t *PatchBARBACK; patch_t *PatchCHAIN; patch_t *PatchSTATBAR; patch_t *PatchLIFEGEM; //patch_t *PatchEMPWEAP; //patch_t *PatchLIL4BOX; patch_t *PatchLTFCTOP; patch_t *PatchRTFCTOP; //patch_t *PatchARMORBOX; //patch_t *PatchARTIBOX; patch_t *PatchSELECTBOX; //patch_t *PatchKILLSPIC; //patch_t *PatchMANAPIC; //patch_t *PatchPOWERICN; patch_t *PatchINVLFGEM1; patch_t *PatchINVLFGEM2; patch_t *PatchINVRTGEM1; patch_t *PatchINVRTGEM2; patch_t *PatchINumbers[10]; patch_t *PatchNEGATIVE; patch_t *PatchSmNumbers[10]; patch_t *PatchBLACKSQ; patch_t *PatchINVBAR; patch_t *PatchARMCLEAR; patch_t *PatchCHAINBACK; //byte *ShadeTables; int FontBNumBase; int spinbooklump; int spinflylump; // Toggle god mode cheatseq_t CheatGodSeq = CHEAT("quicken", 0); // Toggle no clipping mode cheatseq_t CheatNoClipSeq = CHEAT("kitty", 0); // Get all weapons and ammo cheatseq_t CheatWeaponsSeq = CHEAT("rambo", 0); // Toggle tome of power cheatseq_t CheatPowerSeq = CHEAT("shazam", 0); // Get full health cheatseq_t CheatHealthSeq = CHEAT("ponce", 0); // Get all keys cheatseq_t CheatKeysSeq = CHEAT("skel", 0); // Toggle sound debug info cheatseq_t CheatSoundSeq = CHEAT("noise", 0); // Toggle ticker cheatseq_t CheatTickerSeq = CHEAT("ticker", 0); // Get an artifact 1st stage (ask for type) cheatseq_t CheatArtifact1Seq = CHEAT("gimme", 0); // Get an artifact 2nd stage (ask for count) cheatseq_t CheatArtifact2Seq = CHEAT("gimme", 1); // Get an artifact final stage cheatseq_t CheatArtifact3Seq = CHEAT("gimme", 2); // Warp to new level cheatseq_t CheatWarpSeq = CHEAT("engage", 2); // Save a screenshot cheatseq_t CheatChickenSeq = CHEAT("cockadoodledoo", 0); // Kill all monsters cheatseq_t CheatMassacreSeq = CHEAT("massacre", 0); cheatseq_t CheatIDKFASeq = CHEAT("idkfa", 0); cheatseq_t CheatIDDQDSeq = CHEAT("iddqd", 0); static Cheat_t Cheats[] = { {CheatGodFunc, &CheatGodSeq}, {CheatNoClipFunc, &CheatNoClipSeq}, {CheatWeaponsFunc, &CheatWeaponsSeq}, {CheatPowerFunc, &CheatPowerSeq}, {CheatHealthFunc, &CheatHealthSeq}, {CheatKeysFunc, &CheatKeysSeq}, {CheatSoundFunc, &CheatSoundSeq}, {CheatTickerFunc, &CheatTickerSeq}, {CheatArtifact1Func, &CheatArtifact1Seq}, {CheatArtifact2Func, &CheatArtifact2Seq}, {CheatArtifact3Func, &CheatArtifact3Seq}, {CheatWarpFunc, &CheatWarpSeq}, {CheatChickenFunc, &CheatChickenSeq}, {CheatMassacreFunc, &CheatMassacreSeq}, {CheatIDKFAFunc, &CheatIDKFASeq}, {CheatIDDQDFunc, &CheatIDDQDSeq}, {NULL, NULL} }; //--------------------------------------------------------------------------- // // PROC SB_Init // //--------------------------------------------------------------------------- void SB_Init(void) { int i; int startLump; PatchLTFACE = W_CacheLumpName(DEH_String("LTFACE"), PU_STATIC); PatchRTFACE = W_CacheLumpName(DEH_String("RTFACE"), PU_STATIC); PatchBARBACK = W_CacheLumpName(DEH_String("BARBACK"), PU_STATIC); PatchINVBAR = W_CacheLumpName(DEH_String("INVBAR"), PU_STATIC); PatchCHAIN = W_CacheLumpName(DEH_String("CHAIN"), PU_STATIC); if (deathmatch) { PatchSTATBAR = W_CacheLumpName(DEH_String("STATBAR"), PU_STATIC); } else { PatchSTATBAR = W_CacheLumpName(DEH_String("LIFEBAR"), PU_STATIC); } if (!netgame) { // single player game uses red life gem PatchLIFEGEM = W_CacheLumpName(DEH_String("LIFEGEM2"), PU_STATIC); } else { PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName(DEH_String("LIFEGEM0")) + consoleplayer, PU_STATIC); } PatchLTFCTOP = W_CacheLumpName(DEH_String("LTFCTOP"), PU_STATIC); PatchRTFCTOP = W_CacheLumpName(DEH_String("RTFCTOP"), PU_STATIC); PatchSELECTBOX = W_CacheLumpName(DEH_String("SELECTBOX"), PU_STATIC); PatchINVLFGEM1 = W_CacheLumpName(DEH_String("INVGEML1"), PU_STATIC); PatchINVLFGEM2 = W_CacheLumpName(DEH_String("INVGEML2"), PU_STATIC); PatchINVRTGEM1 = W_CacheLumpName(DEH_String("INVGEMR1"), PU_STATIC); PatchINVRTGEM2 = W_CacheLumpName(DEH_String("INVGEMR2"), PU_STATIC); PatchBLACKSQ = W_CacheLumpName(DEH_String("BLACKSQ"), PU_STATIC); PatchARMCLEAR = W_CacheLumpName(DEH_String("ARMCLEAR"), PU_STATIC); PatchCHAINBACK = W_CacheLumpName(DEH_String("CHAINBACK"), PU_STATIC); startLump = W_GetNumForName(DEH_String("IN0")); for (i = 0; i < 10; i++) { PatchINumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC); } PatchNEGATIVE = W_CacheLumpName(DEH_String("NEGNUM"), PU_STATIC); FontBNumBase = W_GetNumForName(DEH_String("FONTB16")); startLump = W_GetNumForName(DEH_String("SMALLIN0")); for (i = 0; i < 10; i++) { PatchSmNumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC); } playpalette = W_GetNumForName(DEH_String("PLAYPAL")); spinbooklump = W_GetNumForName(DEH_String("SPINBK0")); spinflylump = W_GetNumForName(DEH_String("SPFLY0")); } //--------------------------------------------------------------------------- // // PROC SB_Ticker // //--------------------------------------------------------------------------- void SB_Ticker(void) { int delta; int curHealth; if (leveltime & 1) { ChainWiggle = P_Random() & 1; } curHealth = players[consoleplayer].mo->health; if (curHealth < 0) { curHealth = 0; } if (curHealth < HealthMarker) { delta = (HealthMarker - curHealth) >> 2; if (delta < 1) { delta = 1; } else if (delta > 8) { delta = 8; } HealthMarker -= delta; } else if (curHealth > HealthMarker) { delta = (curHealth - HealthMarker) >> 2; if (delta < 1) { delta = 1; } else if (delta > 8) { delta = 8; } HealthMarker += delta; } } //--------------------------------------------------------------------------- // // PROC DrINumber // // Draws a three digit number. // //--------------------------------------------------------------------------- static void DrINumber(signed int val, int x, int y) { patch_t *patch; int oldval; oldval = val; if (val < 0) { if (val < -9) { V_DrawPatch(x + 1, y + 1, W_CacheLumpName(DEH_String("LAME"), PU_CACHE)); } else { val = -val; V_DrawPatch(x + 18, y, PatchINumbers[val]); V_DrawPatch(x + 9, y, PatchNEGATIVE); } return; } if (val > 99) { patch = PatchINumbers[val / 100]; V_DrawPatch(x, y, patch); } val = val % 100; if (val > 9 || oldval > 99) { patch = PatchINumbers[val / 10]; V_DrawPatch(x + 9, y, patch); } val = val % 10; patch = PatchINumbers[val]; V_DrawPatch(x + 18, y, patch); } //--------------------------------------------------------------------------- // // PROC DrBNumber // // Draws a three digit number using FontB // //--------------------------------------------------------------------------- static void DrBNumber(signed int val, int x, int y) { patch_t *patch; int xpos; int oldval; oldval = val; xpos = x; if (val < 0) { val = 0; } if (val > 99) { patch = W_CacheLumpNum(FontBNumBase + val / 100, PU_CACHE); V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } val = val % 100; xpos += 12; if (val > 9 || oldval > 99) { patch = W_CacheLumpNum(FontBNumBase + val / 10, PU_CACHE); V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } val = val % 10; xpos += 12; patch = W_CacheLumpNum(FontBNumBase + val, PU_CACHE); V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } //--------------------------------------------------------------------------- // // PROC DrSmallNumber // // Draws a small two digit number. // //--------------------------------------------------------------------------- static void DrSmallNumber(int val, int x, int y) { patch_t *patch; if (val == 1) { return; } if (val > 9) { patch = PatchSmNumbers[val / 10]; V_DrawPatch(x, y, patch); } val = val % 10; patch = PatchSmNumbers[val]; V_DrawPatch(x + 4, y, patch); } //--------------------------------------------------------------------------- // // PROC ShadeLine // //--------------------------------------------------------------------------- static void ShadeLine(int x, int y, int height, int shade) { byte *dest; byte *shades; shades = colormaps + 9 * 256 + shade * 2 * 256; dest = I_VideoBuffer + y * SCREENWIDTH + x; while (height--) { *(dest) = *(shades + *dest); dest += SCREENWIDTH; } } //--------------------------------------------------------------------------- // // PROC ShadeChain // //--------------------------------------------------------------------------- static void ShadeChain(void) { int i; for (i = 0; i < 16; i++) { ShadeLine(277 + i, 190, 10, i / 2); ShadeLine(19 + i, 190, 10, 7 - (i / 2)); } } //--------------------------------------------------------------------------- // // PROC DrawSoundInfo // // Displays sound debugging information. // //--------------------------------------------------------------------------- static void DrawSoundInfo(void) { int i; SoundInfo_t s; ChanInfo_t *c; char text[32]; int x; int y; int xPos[7] = { 1, 75, 112, 156, 200, 230, 260 }; if (leveltime & 16) { MN_DrTextA(DEH_String("*** SOUND DEBUG INFO ***"), xPos[0], 20); } S_GetChannelInfo(&s); if (s.channelCount == 0) { return; } x = 0; MN_DrTextA(DEH_String("NAME"), xPos[x++], 30); MN_DrTextA(DEH_String("MO.T"), xPos[x++], 30); MN_DrTextA(DEH_String("MO.X"), xPos[x++], 30); MN_DrTextA(DEH_String("MO.Y"), xPos[x++], 30); MN_DrTextA(DEH_String("ID"), xPos[x++], 30); MN_DrTextA(DEH_String("PRI"), xPos[x++], 30); MN_DrTextA(DEH_String("DIST"), xPos[x++], 30); for (i = 0; i < s.channelCount; i++) { c = &s.chan[i]; x = 0; y = 40 + i * 10; if (c->mo == NULL) { // Channel is unused MN_DrTextA(DEH_String("------"), xPos[0], y); continue; } M_snprintf(text, sizeof(text), "%s", c->name); M_ForceUppercase(text); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->mo->type); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->mo->x >> FRACBITS); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->mo->y >> FRACBITS); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->id); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->priority); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->distance); MN_DrTextA(text, xPos[x++], y); } UpdateState |= I_FULLSCRN; BorderNeedRefresh = true; } //--------------------------------------------------------------------------- // // PROC SB_Drawer // //--------------------------------------------------------------------------- char patcharti[][10] = { {"ARTIBOX"}, // none {"ARTIINVU"}, // invulnerability {"ARTIINVS"}, // invisibility {"ARTIPTN2"}, // health {"ARTISPHL"}, // superhealth {"ARTIPWBK"}, // tomeofpower {"ARTITRCH"}, // torch {"ARTIFBMB"}, // firebomb {"ARTIEGGC"}, // egg {"ARTISOAR"}, // fly {"ARTIATLP"} // teleport }; char ammopic[][10] = { {"INAMGLD"}, {"INAMBOW"}, {"INAMBST"}, {"INAMRAM"}, {"INAMPNX"}, {"INAMLOB"} }; int SB_state = -1; static int oldarti = 0; static int oldartiCount = 0; static int oldfrags = -9999; static int oldammo = -1; static int oldarmor = -1; static int oldweapon = -1; static int oldhealth = -1; static int oldlife = -1; static int oldkeys = -1; int playerkeys = 0; extern boolean automapactive; void SB_Drawer(void) { int frame; static boolean hitCenterFrame; // Sound info debug stuff if (DebugSound == true) { DrawSoundInfo(); } CPlayer = &players[consoleplayer]; if (viewheight == SCREENHEIGHT && !automapactive) { DrawFullScreenStuff(); SB_state = -1; } else { if (SB_state == -1) { V_DrawPatch(0, 158, PatchBARBACK); if (players[consoleplayer].cheats & CF_GODMODE) { V_DrawPatch(16, 167, W_CacheLumpName(DEH_String("GOD1"), PU_CACHE)); V_DrawPatch(287, 167, W_CacheLumpName(DEH_String("GOD2"), PU_CACHE)); } oldhealth = -1; } DrawCommonBar(); if (!inventory) { if (SB_state != 0) { // Main interface V_DrawPatch(34, 160, PatchSTATBAR); oldarti = 0; oldammo = -1; oldarmor = -1; oldweapon = -1; oldfrags = -9999; //can't use -1, 'cuz of negative frags oldlife = -1; oldkeys = -1; } DrawMainBar(); SB_state = 0; } else { if (SB_state != 1) { V_DrawPatch(34, 160, PatchINVBAR); } DrawInventoryBar(); SB_state = 1; } } SB_PaletteFlash(); // Flight icons if (CPlayer->powers[pw_flight]) { if (CPlayer->powers[pw_flight] > BLINKTHRESHOLD || !(CPlayer->powers[pw_flight] & 16)) { frame = (leveltime / 3) & 15; if (CPlayer->mo->flags2 & MF2_FLY) { if (hitCenterFrame && (frame != 15 && frame != 0)) { V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + 15, PU_CACHE)); } else { V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + frame, PU_CACHE)); hitCenterFrame = false; } } else { if (!hitCenterFrame && (frame != 15 && frame != 0)) { V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + frame, PU_CACHE)); hitCenterFrame = false; } else { V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + 15, PU_CACHE)); hitCenterFrame = true; } } BorderTopRefresh = true; UpdateState |= I_MESSAGES; } else { BorderTopRefresh = true; UpdateState |= I_MESSAGES; } } if (CPlayer->powers[pw_weaponlevel2] && !CPlayer->chickenTics) { if (CPlayer->powers[pw_weaponlevel2] > BLINKTHRESHOLD || !(CPlayer->powers[pw_weaponlevel2] & 16)) { frame = (leveltime / 3) & 15; V_DrawPatch(300, 17, W_CacheLumpNum(spinbooklump + frame, PU_CACHE)); BorderTopRefresh = true; UpdateState |= I_MESSAGES; } else { BorderTopRefresh = true; UpdateState |= I_MESSAGES; } } /* if(CPlayer->powers[pw_weaponlevel2] > BLINKTHRESHOLD || (CPlayer->powers[pw_weaponlevel2]&8)) { V_DrawPatch(291, 0, W_CacheLumpName("ARTIPWBK", PU_CACHE)); } else { BorderTopRefresh = true; } } */ } // sets the new palette based upon current values of player->damagecount // and player->bonuscount void SB_PaletteFlash(void) { static int sb_palette = 0; int palette; byte *pal; CPlayer = &players[consoleplayer]; if (CPlayer->damagecount) { palette = (CPlayer->damagecount + 7) >> 3; if (palette >= NUMREDPALS) { palette = NUMREDPALS - 1; } palette += STARTREDPALS; } else if (CPlayer->bonuscount) { palette = (CPlayer->bonuscount + 7) >> 3; if (palette >= NUMBONUSPALS) { palette = NUMBONUSPALS - 1; } palette += STARTBONUSPALS; } else { palette = 0; } if (palette != sb_palette) { sb_palette = palette; pal = (byte *) W_CacheLumpNum(playpalette, PU_CACHE) + palette * 768; I_SetPalette(pal); } } //--------------------------------------------------------------------------- // // PROC DrawCommonBar // //--------------------------------------------------------------------------- void DrawCommonBar(void) { int chainY; int healthPos; V_DrawPatch(0, 148, PatchLTFCTOP); V_DrawPatch(290, 148, PatchRTFCTOP); if (oldhealth != HealthMarker) { oldhealth = HealthMarker; healthPos = HealthMarker; if (healthPos < 0) { healthPos = 0; } if (healthPos > 100) { healthPos = 100; } healthPos = (healthPos * 256) / 100; chainY = (HealthMarker == CPlayer->mo->health) ? 191 : 191 + ChainWiggle; V_DrawPatch(0, 190, PatchCHAINBACK); V_DrawPatch(2 + (healthPos % 17), chainY, PatchCHAIN); V_DrawPatch(17 + healthPos, chainY, PatchLIFEGEM); V_DrawPatch(0, 190, PatchLTFACE); V_DrawPatch(276, 190, PatchRTFACE); ShadeChain(); UpdateState |= I_STATBAR; } } //--------------------------------------------------------------------------- // // PROC DrawMainBar // //--------------------------------------------------------------------------- void DrawMainBar(void) { int i; int temp; // Ready artifact if (ArtifactFlash) { V_DrawPatch(180, 161, PatchBLACKSQ); temp = W_GetNumForName(DEH_String("useartia")) + ArtifactFlash - 1; V_DrawPatch(182, 161, W_CacheLumpNum(temp, PU_CACHE)); ArtifactFlash--; oldarti = -1; // so that the correct artifact fills in after the flash UpdateState |= I_STATBAR; } else if (oldarti != CPlayer->readyArtifact || oldartiCount != CPlayer->inventory[inv_ptr].count) { V_DrawPatch(180, 161, PatchBLACKSQ); if (CPlayer->readyArtifact > 0) { V_DrawPatch(179, 160, W_CacheLumpName(DEH_String(patcharti[CPlayer->readyArtifact]), PU_CACHE)); DrSmallNumber(CPlayer->inventory[inv_ptr].count, 201, 182); } oldarti = CPlayer->readyArtifact; oldartiCount = CPlayer->inventory[inv_ptr].count; UpdateState |= I_STATBAR; } // Frags if (deathmatch) { temp = 0; for (i = 0; i < MAXPLAYERS; i++) { temp += CPlayer->frags[i]; } if (temp != oldfrags) { V_DrawPatch(57, 171, PatchARMCLEAR); DrINumber(temp, 61, 170); oldfrags = temp; UpdateState |= I_STATBAR; } } else { temp = HealthMarker; if (temp < 0) { temp = 0; } else if (temp > 100) { temp = 100; } if (oldlife != temp) { oldlife = temp; V_DrawPatch(57, 171, PatchARMCLEAR); DrINumber(temp, 61, 170); UpdateState |= I_STATBAR; } } // Keys if (oldkeys != playerkeys) { if (CPlayer->keys[key_yellow]) { V_DrawPatch(153, 164, W_CacheLumpName(DEH_String("ykeyicon"), PU_CACHE)); } if (CPlayer->keys[key_green]) { V_DrawPatch(153, 172, W_CacheLumpName(DEH_String("gkeyicon"), PU_CACHE)); } if (CPlayer->keys[key_blue]) { V_DrawPatch(153, 180, W_CacheLumpName(DEH_String("bkeyicon"), PU_CACHE)); } oldkeys = playerkeys; UpdateState |= I_STATBAR; } // Ammo temp = CPlayer->ammo[wpnlev1info[CPlayer->readyweapon].ammo]; if (oldammo != temp || oldweapon != CPlayer->readyweapon) { V_DrawPatch(108, 161, PatchBLACKSQ); if (temp && CPlayer->readyweapon > 0 && CPlayer->readyweapon < 7) { DrINumber(temp, 109, 162); V_DrawPatch(111, 172, W_CacheLumpName(DEH_String(ammopic[CPlayer->readyweapon - 1]), PU_CACHE)); } oldammo = temp; oldweapon = CPlayer->readyweapon; UpdateState |= I_STATBAR; } // Armor if (oldarmor != CPlayer->armorpoints) { V_DrawPatch(224, 171, PatchARMCLEAR); DrINumber(CPlayer->armorpoints, 228, 170); oldarmor = CPlayer->armorpoints; UpdateState |= I_STATBAR; } } //--------------------------------------------------------------------------- // // PROC DrawInventoryBar // //--------------------------------------------------------------------------- void DrawInventoryBar(void) { char *patch; int i; int x; x = inv_ptr - curpos; UpdateState |= I_STATBAR; V_DrawPatch(34, 160, PatchINVBAR); for (i = 0; i < 7; i++) { //V_DrawPatch(50+i*31, 160, W_CacheLumpName("ARTIBOX", PU_CACHE)); if (CPlayer->inventorySlotNum > x + i && CPlayer->inventory[x + i].type != arti_none) { patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]); V_DrawPatch(50 + i * 31, 160, W_CacheLumpName(patch, PU_CACHE)); DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31, 182); } } V_DrawPatch(50 + curpos * 31, 189, PatchSELECTBOX); if (x != 0) { V_DrawPatch(38, 159, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2); } if (CPlayer->inventorySlotNum - x > 7) { V_DrawPatch(269, 159, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2); } } void DrawFullScreenStuff(void) { char *patch; int i; int x; int temp; UpdateState |= I_FULLSCRN; if (CPlayer->mo->health > 0) { DrBNumber(CPlayer->mo->health, 5, 180); } else { DrBNumber(0, 5, 180); } if (deathmatch) { temp = 0; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { temp += CPlayer->frags[i]; } } DrINumber(temp, 45, 185); } if (!inventory) { if (CPlayer->readyArtifact > 0) { patch = DEH_String(patcharti[CPlayer->readyArtifact]); V_DrawTLPatch(286, 170, W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE)); V_DrawPatch(286, 170, W_CacheLumpName(patch, PU_CACHE)); DrSmallNumber(CPlayer->inventory[inv_ptr].count, 307, 192); } } else { x = inv_ptr - curpos; for (i = 0; i < 7; i++) { V_DrawTLPatch(50 + i * 31, 168, W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE)); if (CPlayer->inventorySlotNum > x + i && CPlayer->inventory[x + i].type != arti_none) { patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]); V_DrawPatch(50 + i * 31, 168, W_CacheLumpName(patch, PU_CACHE)); DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31, 190); } } V_DrawPatch(50 + curpos * 31, 197, PatchSELECTBOX); if (x != 0) { V_DrawPatch(38, 167, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2); } if (CPlayer->inventorySlotNum - x > 7) { V_DrawPatch(269, 167, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2); } } } //-------------------------------------------------------------------------- // // FUNC SB_Responder // //-------------------------------------------------------------------------- boolean SB_Responder(event_t * event) { if (event->type == ev_keydown) { if (HandleCheats(event->data1)) { // Need to eat the key return (true); } } return (false); } //-------------------------------------------------------------------------- // // FUNC HandleCheats // // Returns true if the caller should eat the key. // //-------------------------------------------------------------------------- static boolean HandleCheats(byte key) { int i; boolean eat; if (netgame || gameskill == sk_nightmare) { // Can't cheat in a net-game, or in nightmare mode return (false); } if (players[consoleplayer].health <= 0) { // Dead players can't cheat return (false); } eat = false; for (i = 0; Cheats[i].func != NULL; i++) { if (cht_CheckCheat(Cheats[i].seq, key)) { Cheats[i].func(&players[consoleplayer], &Cheats[i]); S_StartSound(NULL, sfx_dorcls); } } return (eat); } //-------------------------------------------------------------------------- // // CHEAT FUNCTIONS // //-------------------------------------------------------------------------- static void CheatGodFunc(player_t * player, Cheat_t * cheat) { player->cheats ^= CF_GODMODE; if (player->cheats & CF_GODMODE) { P_SetMessage(player, DEH_String(TXT_CHEATGODON), false); } else { P_SetMessage(player, DEH_String(TXT_CHEATGODOFF), false); } SB_state = -1; } static void CheatNoClipFunc(player_t * player, Cheat_t * cheat) { player->cheats ^= CF_NOCLIP; if (player->cheats & CF_NOCLIP) { P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPON), false); } else { P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPOFF), false); } } static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat) { int i; //extern boolean *WeaponInShareware; player->armorpoints = 200; player->armortype = 2; if (!player->backpack) { for (i = 0; i < NUMAMMO; i++) { player->maxammo[i] *= 2; } player->backpack = true; } for (i = 0; i < NUMWEAPONS - 1; i++) { player->weaponowned[i] = true; } if (gamemode == shareware) { player->weaponowned[wp_skullrod] = false; player->weaponowned[wp_phoenixrod] = false; player->weaponowned[wp_mace] = false; } for (i = 0; i < NUMAMMO; i++) { player->ammo[i] = player->maxammo[i]; } P_SetMessage(player, DEH_String(TXT_CHEATWEAPONS), false); } static void CheatPowerFunc(player_t * player, Cheat_t * cheat) { if (player->powers[pw_weaponlevel2]) { player->powers[pw_weaponlevel2] = 0; P_SetMessage(player, DEH_String(TXT_CHEATPOWEROFF), false); } else { P_UseArtifact(player, arti_tomeofpower); P_SetMessage(player, DEH_String(TXT_CHEATPOWERON), false); } } static void CheatHealthFunc(player_t * player, Cheat_t * cheat) { if (player->chickenTics) { player->health = player->mo->health = MAXCHICKENHEALTH; } else { player->health = player->mo->health = MAXHEALTH; } P_SetMessage(player, DEH_String(TXT_CHEATHEALTH), false); } static void CheatKeysFunc(player_t * player, Cheat_t * cheat) { player->keys[key_yellow] = true; player->keys[key_green] = true; player->keys[key_blue] = true; playerkeys = 7; // Key refresh flags P_SetMessage(player, DEH_String(TXT_CHEATKEYS), false); } static void CheatSoundFunc(player_t * player, Cheat_t * cheat) { DebugSound = !DebugSound; if (DebugSound) { P_SetMessage(player, DEH_String(TXT_CHEATSOUNDON), false); } else { P_SetMessage(player, DEH_String(TXT_CHEATSOUNDOFF), false); } } static void CheatTickerFunc(player_t * player, Cheat_t * cheat) { DisplayTicker = !DisplayTicker; if (DisplayTicker) { P_SetMessage(player, DEH_String(TXT_CHEATTICKERON), false); } else { P_SetMessage(player, DEH_String(TXT_CHEATTICKEROFF), false); } I_DisplayFPSDots(DisplayTicker); } static void CheatArtifact1Func(player_t * player, Cheat_t * cheat) { P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS1), false); } static void CheatArtifact2Func(player_t * player, Cheat_t * cheat) { P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS2), false); } static void CheatArtifact3Func(player_t * player, Cheat_t * cheat) { char args[2]; int i; int j; int type; int count; cht_GetParam(cheat->seq, args); type = args[0] - 'a' + 1; count = args[1] - '0'; if (type == 26 && count == 0) { // All artifacts for (i = arti_none + 1; i < NUMARTIFACTS; i++) { if (gamemode == shareware && (i == arti_superhealth || i == arti_teleport)) { continue; } for (j = 0; j < 16; j++) { P_GiveArtifact(player, i, NULL); } } P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false); } else if (type > arti_none && type < NUMARTIFACTS && count > 0 && count < 10) { if (gamemode == shareware && (type == arti_superhealth || type == arti_teleport)) { P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false); return; } for (i = 0; i < count; i++) { P_GiveArtifact(player, type, NULL); } P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false); } else { // Bad input P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false); } } static void CheatWarpFunc(player_t * player, Cheat_t * cheat) { char args[2]; int episode; int map; cht_GetParam(cheat->seq, args); episode = args[0] - '0'; map = args[1] - '0'; if (D_ValidEpisodeMap(heretic, gamemode, episode, map)) { G_DeferedInitNew(gameskill, episode, map); P_SetMessage(player, DEH_String(TXT_CHEATWARP), false); } } static void CheatChickenFunc(player_t * player, Cheat_t * cheat) { extern boolean P_UndoPlayerChicken(player_t * player); if (player->chickenTics) { if (P_UndoPlayerChicken(player)) { P_SetMessage(player, DEH_String(TXT_CHEATCHICKENOFF), false); } } else if (P_ChickenMorphPlayer(player)) { P_SetMessage(player, DEH_String(TXT_CHEATCHICKENON), false); } } static void CheatMassacreFunc(player_t * player, Cheat_t * cheat) { P_Massacre(); P_SetMessage(player, DEH_String(TXT_CHEATMASSACRE), false); } static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat) { int i; if (player->chickenTics) { return; } for (i = 1; i < 8; i++) { player->weaponowned[i] = false; } player->pendingweapon = wp_staff; P_SetMessage(player, DEH_String(TXT_CHEATIDKFA), true); } static void CheatIDDQDFunc(player_t * player, Cheat_t * cheat) { P_DamageMobj(player->mo, NULL, player->mo, 10000); P_SetMessage(player, DEH_String(TXT_CHEATIDDQD), true); } chocolate-doom-chocolate-doom-2.2.1/src/heretic/sounds.c000066400000000000000000000157221257432200600232050ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // sounds.c #include "doomdef.h" #include "i_sound.h" #include "sounds.h" // Music info #define MUSIC(name) \ { name, 0, NULL, NULL } musicinfo_t S_music[] = { MUSIC("MUS_E1M1"), // 1-1 MUSIC("MUS_E1M2"), MUSIC("MUS_E1M3"), MUSIC("MUS_E1M4"), MUSIC("MUS_E1M5"), MUSIC("MUS_E1M6"), MUSIC("MUS_E1M7"), MUSIC("MUS_E1M8"), MUSIC("MUS_E1M9"), MUSIC("MUS_E2M1"), // 2-1 MUSIC("MUS_E2M2"), MUSIC("MUS_E2M3"), MUSIC("MUS_E2M4"), MUSIC("MUS_E1M4"), MUSIC("MUS_E2M6"), MUSIC("MUS_E2M7"), MUSIC("MUS_E2M8"), MUSIC("MUS_E2M9"), MUSIC("MUS_E1M1"), // 3-1 MUSIC("MUS_E3M2"), MUSIC("MUS_E3M3"), MUSIC("MUS_E1M6"), MUSIC("MUS_E1M3"), MUSIC("MUS_E1M2"), MUSIC("MUS_E1M5"), MUSIC("MUS_E1M9"), MUSIC("MUS_E2M6"), MUSIC("MUS_E1M6"), // 4-1 MUSIC("MUS_E1M2"), MUSIC("MUS_E1M3"), MUSIC("MUS_E1M4"), MUSIC("MUS_E1M5"), MUSIC("MUS_E1M1"), MUSIC("MUS_E1M7"), MUSIC("MUS_E1M8"), MUSIC("MUS_E1M9"), MUSIC("MUS_E2M1"), // 5-1 MUSIC("MUS_E2M2"), MUSIC("MUS_E2M3"), MUSIC("MUS_E2M4"), MUSIC("MUS_E1M4"), MUSIC("MUS_E2M6"), MUSIC("MUS_E2M7"), MUSIC("MUS_E2M8"), MUSIC("MUS_E2M9"), MUSIC("MUS_E3M2"), // 6-1 MUSIC("MUS_E3M3"), // 6-2 MUSIC("MUS_E1M6"), // 6-3 MUSIC("MUS_TITL"), MUSIC("MUS_INTR"), MUSIC("MUS_CPTD") }; // Sound info /* Macro for original heretic sfxinfo_t #define SOUND(name, priority, numchannels) \ { name, NULL, priority, -1, NULL, 0, numchannels } #define SOUND_LINK(name, link_id, priority, numchannels) \ { name, &S_sfx[link_id], priority, -1, NULL, 0, numchannels } */ #define SOUND(name, priority, numchannels) \ { NULL, name, priority, NULL, -1, -1, -1, 0, numchannels, NULL } #define SOUND_LINK(name, link_id, priority, numchannels) \ { NULL, name, priority, &S_sfx[link_id], 0, 0, -1, 0, numchannels, NULL } sfxinfo_t S_sfx[] = { SOUND("", 0, 0), SOUND("gldhit", 32, 2), SOUND("gntful", 32, -1), SOUND("gnthit", 32, -1), SOUND("gntpow", 32, -1), SOUND("gntact", 32, -1), SOUND("gntuse", 32, -1), SOUND("phosht", 32, 2), SOUND("phohit", 32, -1), SOUND_LINK("-phopow", sfx_hedat1, 32, 1), SOUND("lobsht", 20, 2), SOUND("lobhit", 20, 2), SOUND("lobpow", 20, 2), SOUND("hrnsht", 32, 2), SOUND("hrnhit", 32, 2), SOUND("hrnpow", 32, 2), SOUND("ramphit", 32, 2), SOUND("ramrain", 10, 2), SOUND("bowsht", 32, 2), SOUND("stfhit", 32, 2), SOUND("stfpow", 32, 2), SOUND("stfcrk", 32, 2), SOUND("impsit", 32, 2), SOUND("impat1", 32, 2), SOUND("impat2", 32, 2), SOUND("impdth", 80, 2), SOUND_LINK("-impact", sfx_impsit, 20, 2), SOUND("imppai", 32, 2), SOUND("mumsit", 32, 2), SOUND("mumat1", 32, 2), SOUND("mumat2", 32, 2), SOUND("mumdth", 80, 2), SOUND_LINK("-mumact", sfx_mumsit, 20, 2), SOUND("mumpai", 32, 2), SOUND("mumhed", 32, 2), SOUND("bstsit", 32, 2), SOUND("bstatk", 32, 2), SOUND("bstdth", 80, 2), SOUND("bstact", 20, 2), SOUND("bstpai", 32, 2), SOUND("clksit", 32, 2), SOUND("clkatk", 32, 2), SOUND("clkdth", 80, 2), SOUND("clkact", 20, 2), SOUND("clkpai", 32, 2), SOUND("snksit", 32, 2), SOUND("snkatk", 32, 2), SOUND("snkdth", 80, 2), SOUND("snkact", 20, 2), SOUND("snkpai", 32, 2), SOUND("kgtsit", 32, 2), SOUND("kgtatk", 32, 2), SOUND("kgtat2", 32, 2), SOUND("kgtdth", 80, 2), SOUND_LINK("-kgtact", sfx_kgtsit, 20, 2), SOUND("kgtpai", 32, 2), SOUND("wizsit", 32, 2), SOUND("wizatk", 32, 2), SOUND("wizdth", 80, 2), SOUND("wizact", 20, 2), SOUND("wizpai", 32, 2), SOUND("minsit", 32, 2), SOUND("minat1", 32, 2), SOUND("minat2", 32, 2), SOUND("minat3", 32, 2), SOUND("mindth", 80, 2), SOUND("minact", 20, 2), SOUND("minpai", 32, 2), SOUND("hedsit", 32, 2), SOUND("hedat1", 32, 2), SOUND("hedat2", 32, 2), SOUND("hedat3", 32, 2), SOUND("heddth", 80, 2), SOUND("hedact", 20, 2), SOUND("hedpai", 32, 2), SOUND("sorzap", 32, 2), SOUND("sorrise", 32, 2), SOUND("sorsit", 200, 2), SOUND("soratk", 32, 2), SOUND("soract", 200, 2), SOUND("sorpai", 200, 2), SOUND("sordsph", 200, 2), SOUND("sordexp", 200, 2), SOUND("sordbon", 200, 2), SOUND_LINK("-sbtsit", sfx_bstsit, 32, 2), SOUND_LINK("-sbtatk", sfx_bstatk, 32, 2), SOUND("sbtdth", 80, 2), SOUND("sbtact", 20, 2), SOUND("sbtpai", 32, 2), SOUND("plroof", 32, 2), SOUND("plrpai", 32, 2), SOUND("plrdth", 80, 2), SOUND("gibdth", 100, 2), SOUND("plrwdth", 80, 2), SOUND("plrcdth", 100, 2), SOUND("itemup", 32, 2), SOUND("wpnup", 32, 2), SOUND("telept", 50, 2), SOUND("doropn", 40, 2), SOUND("dorcls", 40, 2), SOUND("dormov", 40, 2), SOUND("artiup", 32, 2), SOUND("switch", 40, 2), SOUND("pstart", 40, 2), SOUND("pstop", 40, 2), SOUND("stnmov", 40, 2), SOUND("chicpai", 32, 2), SOUND("chicatk", 32, 2), SOUND("chicdth", 40, 2), SOUND("chicact", 32, 2), SOUND("chicpk1", 32, 2), SOUND("chicpk2", 32, 2), SOUND("chicpk3", 32, 2), SOUND("keyup", 50, 2), SOUND("ripslop", 16, 2), SOUND("newpod", 16, -1), SOUND("podexp", 40, -1), SOUND("bounce", 16, 2), SOUND_LINK("-volsht", sfx_bstatk, 16, 2), SOUND_LINK("-volhit", sfx_lobhit, 16, 2), SOUND("burn", 10, 2), SOUND("splash", 10, 1), SOUND("gloop", 10, 2), SOUND("respawn", 10, 1), SOUND("blssht", 32, 2), SOUND("blshit", 32, 2), SOUND("chat", 100, 1), SOUND("artiuse", 32, 1), SOUND("gfrag", 100, 1), SOUND("waterfl", 16, 2), // Monophonic sounds SOUND("wind", 16, 1), SOUND("amb1", 1, 1), SOUND("amb2", 1, 1), SOUND("amb3", 1, 1), SOUND("amb4", 1, 1), SOUND("amb5", 1, 1), SOUND("amb6", 1, 1), SOUND("amb7", 1, 1), SOUND("amb8", 1, 1), SOUND("amb9", 1, 1), SOUND("amb10", 1, 1), SOUND("amb11", 1, 0) }; chocolate-doom-chocolate-doom-2.2.1/src/heretic/sounds.h000066400000000000000000000114141257432200600232040ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // sounds.h #ifndef __SOUNDSH__ #define __SOUNDSH__ #include "i_sound.h" #define MAX_SND_DIST 1600 #define MAX_CHANNELS 16 // Music identifiers typedef enum { mus_e1m1, mus_e1m2, mus_e1m3, mus_e1m4, mus_e1m5, mus_e1m6, mus_e1m7, mus_e1m8, mus_e1m9, mus_e2m1, mus_e2m2, mus_e2m3, mus_e2m4, mus_e2m5, mus_e2m6, mus_e2m7, mus_e2m8, mus_e2m9, mus_e3m1, mus_e3m2, mus_e3m3, mus_e3m4, mus_e3m5, mus_e3m6, mus_e3m7, mus_e3m8, mus_e3m9, mus_e4m1, mus_e4m2, mus_e4m3, mus_e4m4, mus_e4m5, mus_e4m6, mus_e4m7, mus_e4m8, mus_e4m9, mus_e5m1, mus_e5m2, mus_e5m3, mus_e5m4, mus_e5m5, mus_e5m6, mus_e5m7, mus_e5m8, mus_e5m9, mus_e6m1, mus_e6m2, mus_e6m3, mus_titl, mus_intr, mus_cptd, NUMMUSIC } musicenum_t; #if 0 typedef struct { char name[8]; } musicinfo_t; typedef struct sfxinfo_s { char name[8]; struct sfxinfo_s *link; // Make alias for another sound unsigned short priority; // Higher priority takes precendence int usefulness; // Determines when a sound should be cached out void *snd_ptr; int lumpnum; int numchannels; // total number of channels a sound type may occupy } sfxinfo_t; #endif typedef struct { mobj_t *mo; int sound_id; int handle; int pitch; int priority; } channel_t; typedef struct { int id; unsigned short priority; char *name; mobj_t *mo; int distance; } ChanInfo_t; typedef struct { int channelCount; int musicVolume; int soundVolume; ChanInfo_t chan[8]; } SoundInfo_t; // Sound identifiers typedef enum { sfx_None, sfx_gldhit, sfx_gntful, sfx_gnthit, sfx_gntpow, sfx_gntact, sfx_gntuse, sfx_phosht, sfx_phohit, sfx_phopow, sfx_lobsht, sfx_lobhit, sfx_lobpow, sfx_hrnsht, sfx_hrnhit, sfx_hrnpow, sfx_ramphit, sfx_ramrain, sfx_bowsht, sfx_stfhit, sfx_stfpow, sfx_stfcrk, sfx_impsit, sfx_impat1, sfx_impat2, sfx_impdth, sfx_impact, sfx_imppai, sfx_mumsit, sfx_mumat1, sfx_mumat2, sfx_mumdth, sfx_mumact, sfx_mumpai, sfx_mumhed, sfx_bstsit, sfx_bstatk, sfx_bstdth, sfx_bstact, sfx_bstpai, sfx_clksit, sfx_clkatk, sfx_clkdth, sfx_clkact, sfx_clkpai, sfx_snksit, sfx_snkatk, sfx_snkdth, sfx_snkact, sfx_snkpai, sfx_kgtsit, sfx_kgtatk, sfx_kgtat2, sfx_kgtdth, sfx_kgtact, sfx_kgtpai, sfx_wizsit, sfx_wizatk, sfx_wizdth, sfx_wizact, sfx_wizpai, sfx_minsit, sfx_minat1, sfx_minat2, sfx_minat3, sfx_mindth, sfx_minact, sfx_minpai, sfx_hedsit, sfx_hedat1, sfx_hedat2, sfx_hedat3, sfx_heddth, sfx_hedact, sfx_hedpai, sfx_sorzap, sfx_sorrise, sfx_sorsit, sfx_soratk, sfx_soract, sfx_sorpai, sfx_sordsph, sfx_sordexp, sfx_sordbon, sfx_sbtsit, sfx_sbtatk, sfx_sbtdth, sfx_sbtact, sfx_sbtpai, sfx_plroof, sfx_plrpai, sfx_plrdth, // Normal sfx_gibdth, // Extreme sfx_plrwdth, // Wimpy sfx_plrcdth, // Crazy sfx_itemup, sfx_wpnup, sfx_telept, sfx_doropn, sfx_dorcls, sfx_dormov, sfx_artiup, sfx_switch, sfx_pstart, sfx_pstop, sfx_stnmov, sfx_chicpai, sfx_chicatk, sfx_chicdth, sfx_chicact, sfx_chicpk1, sfx_chicpk2, sfx_chicpk3, sfx_keyup, sfx_ripslop, sfx_newpod, sfx_podexp, sfx_bounce, sfx_volsht, sfx_volhit, sfx_burn, sfx_splash, sfx_gloop, sfx_respawn, sfx_blssht, sfx_blshit, sfx_chat, sfx_artiuse, sfx_gfrag, sfx_waterfl, // Monophonic sounds sfx_wind, sfx_amb1, sfx_amb2, sfx_amb3, sfx_amb4, sfx_amb5, sfx_amb6, sfx_amb7, sfx_amb8, sfx_amb9, sfx_amb10, sfx_amb11, NUMSFX } sfxenum_t; extern sfxinfo_t S_sfx[]; extern musicinfo_t S_music[]; #endif chocolate-doom-chocolate-doom-2.2.1/src/hexen.appdata.xml.in000066400000000000000000000033431257432200600237460ustar00rootroot00000000000000 @PROGRAM_PREFIX@hexen.desktop CC0-1.0 GPL-2.0+ @PACKAGE_MAINTAINER@ @PACKAGE_URL@ @PACKAGE_ISSUES@

@PACKAGE_SHORTNAME@ Hexen is a conservative, historically-accurate Hexen source port, which is compatible with mods and levels that were made before the Hexen source code was released. Unlike other source ports, the goal is to preserve the original look, feel, limitations, and bugs of the original DOS executable.

Full support for single- and multi-player games is provided. Unlike the original executable, network play is implemented on the IP network stack, allowing it to function on modern LANs and the Internet.

http://www.chocolate-doom.org/wiki/images/0/0f/GNOME_Hexen_Guardian_of_Fire.png Level "Guardian of Fire" http://www.chocolate-doom.org/wiki/images/5/5c/GNOME_Hexen_Effluvium.png Level "Effluvium" http://www.chocolate-doom.org/wiki/images/c/c1/GNOME_Hexen_Dragon_Chapel.png Level "Dragon Chapel" http://www.chocolate-doom.org/wiki/images/a/a7/GNOME_Hexen_Darkmere.png Level "Darkmere"
chocolate-doom-chocolate-doom-2.2.1/src/hexen.desktop.in000066400000000000000000000003311257432200600232000ustar00rootroot00000000000000[Desktop Entry] Name=@PACKAGE_SHORTNAME@ Hexen Exec=@PROGRAM_PREFIX@hexen Icon=@PROGRAM_PREFIX@doom Type=Application Comment=@PACKAGE_SHORTDESC@ Categories=Game;ActionGame; Keywords=first;person;shooter;doom;vanilla; chocolate-doom-chocolate-doom-2.2.1/src/hexen/000077500000000000000000000000001257432200600212035ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/src/hexen/.gitignore000066400000000000000000000000451257432200600231720ustar00rootroot00000000000000Makefile Makefile.in .deps tags TAGS chocolate-doom-chocolate-doom-2.2.1/src/hexen/Makefile.am000066400000000000000000000044341257432200600232440ustar00rootroot00000000000000AM_CFLAGS=-I$(top_srcdir)/src @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@ noinst_LIBRARIES=libhexen.a SOURCE_FILES= \ a_action.c \ am_data.h \ am_map.c am_map.h \ ct_chat.c \ ct_chat.h \ d_net.c \ f_finale.c \ g_game.c \ h2def.h \ h2_main.c \ info.c info.h \ in_lude.c \ m_random.c m_random.h \ mn_menu.c \ p_acs.c \ p_anim.c \ p_ceilng.c \ p_doors.c \ p_enemy.c \ p_floor.c \ p_inter.c \ p_lights.c \ p_local.h \ p_map.c \ p_maputl.c \ p_mobj.c \ po_man.c \ p_plats.c \ p_pspr.c \ p_setup.c \ p_sight.c \ p_spec.c p_spec.h \ p_switch.c \ p_telept.c \ p_things.c \ p_tick.c \ p_user.c \ r_bsp.c \ r_data.c \ r_draw.c \ r_local.h \ r_main.c \ r_plane.c \ r_segs.c \ r_things.c \ s_sound.c s_sound.h \ sb_bar.c \ sc_man.c \ sn_sonix.c \ sounds.c sounds.h \ st_start.c st_start.h \ sv_save.c \ textdefs.h \ xddefs.h libhexen_a_SOURCES=$(SOURCE_FILES) chocolate-doom-chocolate-doom-2.2.1/src/hexen/a_action.c000066400000000000000000001137211257432200600231310ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern fixed_t FloatBobOffsets[64]; // PUBLIC DATA DEFINITIONS ------------------------------------------------- int orbitTableX[256] = { 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490, 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025, 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310, 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690, 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725, 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010, 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010, 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745, -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420, -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135, -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230, -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105, -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925, -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845, -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235, -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740, -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490, -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025, -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310, -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690, -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725, -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010, -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010, -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745, 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420, 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135, 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230, 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105, 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925, 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845, 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235, 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740 }; int orbitTableY[256] = { 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420, 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135, 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230, 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105, 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925, 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845, 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235, 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740, 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490, 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025, 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310, 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690, 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725, 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010, 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010, 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745, -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420, -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135, -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230, -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105, -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925, -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845, -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235, -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740, -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490, -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025, -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310, -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690, -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725, -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010, -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010, -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745 }; // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- //-------------------------------------------------------------------------- // // Environmental Action routines // //-------------------------------------------------------------------------- //========================================================================== // // A_DripBlood // //========================================================================== /* void A_DripBlood(mobj_t *actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11), actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD); mo->momx = (P_Random()-P_Random())<<10; mo->momy = (P_Random()-P_Random())<<10; mo->flags2 |= MF2_LOGRAV; } */ //============================================================================ // // A_PotteryExplode // //============================================================================ void A_PotteryExplode(mobj_t * actor) { mobj_t *mo = NULL; int i; for (i = (P_Random() & 3) + 3; i; i--) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_POTTERYBIT1); P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 5)); if (mo) { mo->momz = ((P_Random() & 7) + 5) * (3 * FRACUNIT / 4); mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6); mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6); } } S_StartSound(mo, SFX_POTTERY_EXPLODE); if (actor->args[0]) { // Spawn an item if (!nomonsters || !(mobjinfo[TranslateThingType[actor->args[0]]]. flags & MF_COUNTKILL)) { // Only spawn monsters if not -nomonsters P_SpawnMobj(actor->x, actor->y, actor->z, TranslateThingType[actor->args[0]]); } } P_RemoveMobj(actor); } //============================================================================ // // A_PotteryChooseBit // //============================================================================ void A_PotteryChooseBit(mobj_t * actor) { P_SetMobjState(actor, actor->info->deathstate + (P_Random() % 5) + 1); actor->tics = 256 + (P_Random() << 1); } //============================================================================ // // A_PotteryCheck // //============================================================================ void A_PotteryCheck(mobj_t * actor) { int i; mobj_t *pmo; if (!netgame) { pmo = players[consoleplayer].mo; if (P_CheckSight(actor, pmo) && (abs(R_PointToAngle2(pmo->x, pmo->y, actor->x, actor->y) - pmo->angle) <= ANG45)) { // Previous state (pottery bit waiting state) P_SetMobjState(actor, actor->state - &states[0] - 1); } else { return; } } else { for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) { continue; } pmo = players[i].mo; if (P_CheckSight(actor, pmo) && (abs(R_PointToAngle2(pmo->x, pmo->y, actor->x, actor->y) - pmo->angle) <= ANG45)) { // Previous state (pottery bit waiting state) P_SetMobjState(actor, actor->state - &states[0] - 1); return; } } } } //============================================================================ // // A_CorpseBloodDrip // //============================================================================ void A_CorpseBloodDrip(mobj_t * actor) { if (P_Random() > 128) { return; } P_SpawnMobj(actor->x, actor->y, actor->z + actor->height / 2, MT_CORPSEBLOODDRIP); } //============================================================================ // // A_CorpseExplode // //============================================================================ void A_CorpseExplode(mobj_t * actor) { mobj_t *mo; int i; for (i = (P_Random() & 3) + 3; i; i--) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT); P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3)); if (mo) { mo->momz = ((P_Random() & 7) + 5) * (3 * FRACUNIT / 4); mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6); mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6); } } // Spawn a skull mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT); P_SetMobjState(mo, S_CORPSEBIT_4); if (mo) { mo->momz = ((P_Random() & 7) + 5) * (3 * FRACUNIT / 4); mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6); mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6); S_StartSound(mo, SFX_FIRED_DEATH); } P_RemoveMobj(actor); } //============================================================================ // // A_LeafSpawn // //============================================================================ void A_LeafSpawn(mobj_t * actor) { mobj_t *mo; int i; for (i = (P_Random() & 3) + 1; i; i--) { // Official release of Hexen's source code relies on unspecified behavior // the in order of function's argument evaluation, // see ISO-IEC 9899-1999, [6.5.2.2.10] mobjtype_t type = MT_LEAF1 + (P_Random() & 1); fixed_t z = actor->z + (P_Random() << 14); fixed_t y = actor->y + ((P_Random() - P_Random()) << 14); fixed_t x = actor->x + ((P_Random() - P_Random()) << 14); mo = P_SpawnMobj(x, y, z, type); if (mo) { P_ThrustMobj(mo, actor->angle, (P_Random() << 9) + 3 * FRACUNIT); mo->target = actor; mo->special1.i = 0; } } } //============================================================================ // // A_LeafThrust // //============================================================================ void A_LeafThrust(mobj_t * actor) { if (P_Random() > 96) { return; } actor->momz += (P_Random() << 9) + FRACUNIT; } //============================================================================ // // A_LeafCheck // //============================================================================ void A_LeafCheck(mobj_t * actor) { actor->special1.i++; if (actor->special1.i >= 20) { P_SetMobjState(actor, S_NULL); return; } if (P_Random() > 64) { if (!actor->momx && !actor->momy) { P_ThrustMobj(actor, actor->target->angle, (P_Random() << 9) + FRACUNIT); } return; } P_SetMobjState(actor, S_LEAF1_8); actor->momz = (P_Random() << 9) + FRACUNIT; P_ThrustMobj(actor, actor->target->angle, (P_Random() << 9) + 2 * FRACUNIT); actor->flags |= MF_MISSILE; } /* #define ORBIT_RADIUS (15*FRACUNIT) void GenerateOrbitTable(void) { int angle; for (angle=0; angle<256; angle++) { orbitTableX[angle] = FixedMul(ORBIT_RADIUS, finecosine[angle<<5]); orbitTableY[angle] = FixedMul(ORBIT_RADIUS, finesine[angle<<5]); } printf("int orbitTableX[256]=\n{\n"); for (angle=0; angle<256; angle+=8) { printf("%d, %d, %d, %d, %d, %d, %d, %d,\n", orbitTableX[angle], orbitTableX[angle+1], orbitTableX[angle+2], orbitTableX[angle+3], orbitTableX[angle+4], orbitTableX[angle+5], orbitTableX[angle+6], orbitTableX[angle+7]); } printf("};\n\n"); printf("int orbitTableY[256]=\n{\n"); for (angle=0; angle<256; angle+=8) { printf("%d, %d, %d, %d, %d, %d, %d, %d,\n", orbitTableY[angle], orbitTableY[angle+1], orbitTableY[angle+2], orbitTableY[angle+3], orbitTableY[angle+4], orbitTableY[angle+5], orbitTableY[angle+6], orbitTableY[angle+7]); } printf("};\n"); } */ // New bridge stuff // Parent // special1 true == removing from world // // Child // target pointer to center mobj // args[0] angle of ball void A_BridgeOrbit(mobj_t * actor) { if (actor->target->special1.i) { P_SetMobjState(actor, S_NULL); } actor->args[0] += 3; actor->x = actor->target->x + orbitTableX[actor->args[0]]; actor->y = actor->target->y + orbitTableY[actor->args[0]]; actor->z = actor->target->z; } void A_BridgeInit(mobj_t * actor) { byte startangle; mobj_t *ball1, *ball2, *ball3; fixed_t cx, cy, cz; // GenerateOrbitTable(); cx = actor->x; cy = actor->y; cz = actor->z; startangle = P_Random(); actor->special1.i = 0; // Spawn triad into world ball1 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL); ball1->args[0] = startangle; ball1->target = actor; ball2 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL); ball2->args[0] = (startangle + 85) & 255; ball2->target = actor; ball3 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL); ball3->args[0] = (startangle + 170) & 255; ball3->target = actor; A_BridgeOrbit(ball1); A_BridgeOrbit(ball2); A_BridgeOrbit(ball3); } void A_BridgeRemove(mobj_t * actor) { actor->special1.i = true; // Removing the bridge actor->flags &= ~MF_SOLID; P_SetMobjState(actor, S_FREE_BRIDGE1); } //========================================================================== // // A_GhostOn // //========================================================================== /* void A_GhostOn(mobj_t *actor) { actor->flags |= MF_SHADOW; } */ //========================================================================== // // A_GhostOff // //========================================================================== /* void A_GhostOff(mobj_t *actor) { actor->flags &= ~MF_SHADOW; } */ //========================================================================== // // A_HideThing // //========================================================================== void A_HideThing(mobj_t * actor) { actor->flags2 |= MF2_DONTDRAW; } //========================================================================== // // A_UnHideThing // //========================================================================== void A_UnHideThing(mobj_t * actor) { actor->flags2 &= ~MF2_DONTDRAW; } //========================================================================== // // A_SetShootable // //========================================================================== void A_SetShootable(mobj_t * actor) { actor->flags2 &= ~MF2_NONSHOOTABLE; actor->flags |= MF_SHOOTABLE; } //========================================================================== // // A_UnSetShootable // //========================================================================== void A_UnSetShootable(mobj_t * actor) { actor->flags2 |= MF2_NONSHOOTABLE; actor->flags &= ~MF_SHOOTABLE; } //========================================================================== // // A_SetAltShadow // //========================================================================== void A_SetAltShadow(mobj_t * actor) { actor->flags &= ~MF_SHADOW; actor->flags |= MF_ALTSHADOW; } //========================================================================== // // A_UnSetAltShadow // //========================================================================== /* void A_UnSetAltShadow(mobj_t *actor) { actor->flags &= ~MF_ALTSHADOW; } */ //-------------------------------------------------------------------------- // // Sound Action Routines // //-------------------------------------------------------------------------- //========================================================================== // // A_ContMobjSound // //========================================================================== void A_ContMobjSound(mobj_t * actor) { switch (actor->type) { case MT_SERPENTFX: S_StartSound(actor, SFX_SERPENTFX_CONTINUOUS); break; case MT_HAMMER_MISSILE: S_StartSound(actor, SFX_FIGHTER_HAMMER_CONTINUOUS); break; case MT_QUAKE_FOCUS: S_StartSound(actor, SFX_EARTHQUAKE); break; default: break; } } //========================================================================== // // PROC A_ESound // //========================================================================== void A_ESound(mobj_t * mo) { int sound; switch (mo->type) { case MT_SOUNDWIND: sound = SFX_WIND; break; default: sound = SFX_NONE; break; } S_StartSound(mo, sound); } //========================================================================== // Summon Minotaur -- see p_enemy for variable descriptions //========================================================================== void A_Summon(mobj_t * actor) { mobj_t *mo; mobj_t *master; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINOTAUR); if (mo) { if (P_TestMobjLocation(mo) == false || !actor->special1.m) { // Didn't fit - change back to artifact P_SetMobjState(mo, S_NULL); mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SUMMONMAULATOR); if (mo) mo->flags2 |= MF2_DROPPED; return; } // Store leveltime into mo->args. This must be stored in little- // endian format for Vanilla savegame compatibility. mo->args[0] = leveltime & 0xff; mo->args[1] = (leveltime >> 8) & 0xff; mo->args[2] = (leveltime >> 16) & 0xff; mo->args[3] = (leveltime >> 24) & 0xff; master = actor->special1.m; if (master->flags & MF_CORPSE) { // Master dead mo->special1.m = NULL; // No master } else { mo->special1.m = actor->special1.m; // Pointer to master (mobj_t *) P_GivePower(master->player, pw_minotaur); } // Make smoke puff P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE); S_StartSound(actor, SFX_MAULATOR_ACTIVE); } } //========================================================================== // Fog Variables: // // args[0] Speed (0..10) of fog // args[1] Angle of spread (0..128) // args[2] Frequency of spawn (1..10) // args[3] Lifetime countdown // args[4] Boolean: fog moving? // special1 Internal: Counter for spawn frequency // special2 Internal: Index into floatbob table // //========================================================================== void A_FogSpawn(mobj_t * actor) { mobj_t *mo = NULL; angle_t delta; if (actor->special1.i-- > 0) return; actor->special1.i = actor->args[2]; // Reset frequency count switch (P_Random() % 3) { case 0: mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHS); break; case 1: mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHM); break; case 2: mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHL); break; } if (mo) { delta = actor->args[1]; if (delta == 0) delta = 1; mo->angle = actor->angle + (((P_Random() % delta) - (delta >> 1)) << 24); mo->target = actor; if (actor->args[0] < 1) actor->args[0] = 1; mo->args[0] = (P_Random() % (actor->args[0])) + 1; // Random speed mo->args[3] = actor->args[3]; // Set lifetime mo->args[4] = 1; // Set to moving mo->special2.i = P_Random() & 63; } } void A_FogMove(mobj_t * actor) { int speed = actor->args[0] << FRACBITS; angle_t angle; int weaveindex; if (!(actor->args[4])) return; if (actor->args[3]-- <= 0) { P_SetMobjStateNF(actor, actor->info->deathstate); return; } if ((actor->args[3] % 4) == 0) { weaveindex = actor->special2.i; actor->z += FloatBobOffsets[weaveindex] >> 1; actor->special2.i = (weaveindex + 1) & 63; } angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(speed, finecosine[angle]); actor->momy = FixedMul(speed, finesine[angle]); } //=========================================================================== // // A_PoisonBagInit // //=========================================================================== void A_PoisonBagInit(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 28 * FRACUNIT, MT_POISONCLOUD); if (!mo) { return; } mo->momx = 1; // missile objects must move to impact other objects mo->special1.i = 24 + (P_Random() & 7); mo->special2.i = 0; mo->target = actor->target; mo->radius = 20 * FRACUNIT; mo->height = 30 * FRACUNIT; mo->flags &= ~MF_NOCLIP; } //=========================================================================== // // A_PoisonBagCheck // //=========================================================================== void A_PoisonBagCheck(mobj_t * actor) { if (!--actor->special1.i) { P_SetMobjState(actor, S_POISONCLOUD_X1); } else { return; } } //=========================================================================== // // A_PoisonBagDamage // //=========================================================================== void A_PoisonBagDamage(mobj_t * actor) { int bobIndex; extern void A_Explode(mobj_t * actor); A_Explode(actor); bobIndex = actor->special2.i; actor->z += FloatBobOffsets[bobIndex] >> 4; actor->special2.i = (bobIndex + 1) & 63; } //=========================================================================== // // A_PoisonShroom // //=========================================================================== void A_PoisonShroom(mobj_t * actor) { actor->tics = 128 + (P_Random() << 1); } //=========================================================================== // // A_CheckThrowBomb // //=========================================================================== void A_CheckThrowBomb(mobj_t * actor) { if (abs(actor->momx) < 1.5 * FRACUNIT && abs(actor->momy) < 1.5 * FRACUNIT && actor->momz < 2 * FRACUNIT && actor->state == &states[S_THROWINGBOMB6]) { P_SetMobjState(actor, S_THROWINGBOMB7); actor->z = actor->floorz; actor->momz = 0; actor->flags2 &= ~MF2_FLOORBOUNCE; actor->flags &= ~MF_MISSILE; } if (!--actor->health) { P_SetMobjState(actor, actor->info->deathstate); } } //=========================================================================== // Quake variables // // args[0] Intensity on richter scale (2..9) // args[1] Duration in tics // args[2] Radius for damage // args[3] Radius for tremor // args[4] TID of map thing for focus of quake // //=========================================================================== //=========================================================================== // // A_LocalQuake // //=========================================================================== boolean A_LocalQuake(byte * args, mobj_t * actor) { mobj_t *focus, *target; int lastfound = 0; int success = false; // Find all quake foci do { target = P_FindMobjFromTID(args[4], &lastfound); if (target) { focus = P_SpawnMobj(target->x, target->y, target->z, MT_QUAKE_FOCUS); if (focus) { focus->args[0] = args[0]; focus->args[1] = args[1] >> 1; // decremented every 2 tics focus->args[2] = args[2]; focus->args[3] = args[3]; focus->args[4] = args[4]; success = true; } } } while (target != NULL); return (success); } //=========================================================================== // // A_Quake // //=========================================================================== int localQuakeHappening[MAXPLAYERS]; void A_Quake(mobj_t * actor) { angle_t an; player_t *player; mobj_t *victim; int richters = actor->args[0]; int playnum; fixed_t dist; if (actor->args[1]-- > 0) { for (playnum = 0; playnum < maxplayers; playnum++) { player = &players[playnum]; if (!playeringame[playnum]) continue; victim = player->mo; dist = P_AproxDistance(actor->x - victim->x, actor->y - victim->y) >> (FRACBITS + 6); // Tested in tile units (64 pixels) if (dist < actor->args[3]) // In tremor radius { localQuakeHappening[playnum] = richters; } // Check if in damage radius if ((dist < actor->args[2]) && (victim->z <= victim->floorz)) { if (P_Random() < 50) { P_DamageMobj(victim, NULL, NULL, HITDICE(1)); } // Thrust player around an = victim->angle + ANG1 * P_Random(); P_ThrustMobj(victim, an, richters << (FRACBITS - 1)); } } } else { for (playnum = 0; playnum < maxplayers; playnum++) { localQuakeHappening[playnum] = false; } P_SetMobjState(actor, S_NULL); } } //=========================================================================== // // Teleport other stuff // //=========================================================================== #define TELEPORT_LIFE 1 void A_TeloSpawnA(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX2); if (mo) { mo->special1.i = TELEPORT_LIFE; // Lifetime countdown mo->angle = actor->angle; mo->target = actor->target; mo->momx = actor->momx >> 1; mo->momy = actor->momy >> 1; mo->momz = actor->momz >> 1; } } void A_TeloSpawnB(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX3); if (mo) { mo->special1.i = TELEPORT_LIFE; // Lifetime countdown mo->angle = actor->angle; mo->target = actor->target; mo->momx = actor->momx >> 1; mo->momy = actor->momy >> 1; mo->momz = actor->momz >> 1; } } void A_TeloSpawnC(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX4); if (mo) { mo->special1.i = TELEPORT_LIFE; // Lifetime countdown mo->angle = actor->angle; mo->target = actor->target; mo->momx = actor->momx >> 1; mo->momy = actor->momy >> 1; mo->momz = actor->momz >> 1; } } void A_TeloSpawnD(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX5); if (mo) { mo->special1.i = TELEPORT_LIFE; // Lifetime countdown mo->angle = actor->angle; mo->target = actor->target; mo->momx = actor->momx >> 1; mo->momy = actor->momy >> 1; mo->momz = actor->momz >> 1; } } void A_CheckTeleRing(mobj_t * actor) { if (actor->special1.i-- <= 0) { P_SetMobjState(actor, actor->info->deathstate); } } // Dirt stuff void P_SpawnDirt(mobj_t * actor, fixed_t radius) { fixed_t x, y, z; int dtype = 0; mobj_t *mo; angle_t angle; angle = P_Random() << 5; // <<24 >>19 x = actor->x + FixedMul(radius, finecosine[angle]); y = actor->y + FixedMul(radius, finesine[angle]); // x = actor->x + ((P_Random()-P_Random())%radius)<y + ((P_Random()-P_Random()<z + (P_Random() << 9) + FRACUNIT; switch (P_Random() % 6) { case 0: dtype = MT_DIRT1; break; case 1: dtype = MT_DIRT2; break; case 2: dtype = MT_DIRT3; break; case 3: dtype = MT_DIRT4; break; case 4: dtype = MT_DIRT5; break; case 5: dtype = MT_DIRT6; break; } mo = P_SpawnMobj(x, y, z, dtype); if (mo) { mo->momz = P_Random() << 10; } } //=========================================================================== // // Thrust floor stuff // // Thrust Spike Variables // special1 pointer to dirt clump mobj // special2 speed of raise // args[0] 0 = lowered, 1 = raised // args[1] 0 = normal, 1 = bloody //=========================================================================== void A_ThrustInitUp(mobj_t * actor) { actor->special2.i = 5; // Raise speed actor->args[0] = 1; // Mark as up actor->floorclip = 0; actor->flags = MF_SOLID; actor->flags2 = MF2_NOTELEPORT | MF2_FLOORCLIP; actor->special1.m = NULL; } void A_ThrustInitDn(mobj_t * actor) { mobj_t *mo; actor->special2.i = 5; // Raise speed actor->args[0] = 0; // Mark as down actor->floorclip = actor->info->height; actor->flags = 0; actor->flags2 = MF2_NOTELEPORT | MF2_FLOORCLIP | MF2_DONTDRAW; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_DIRTCLUMP); actor->special1.m = mo; } void A_ThrustRaise(mobj_t * actor) { if (A_RaiseMobj(actor)) { // Reached it's target height actor->args[0] = 1; if (actor->args[1]) P_SetMobjStateNF(actor, S_BTHRUSTINIT2_1); else P_SetMobjStateNF(actor, S_THRUSTINIT2_1); } // Lose the dirt clump if ((actor->floorclip < actor->height) && actor->special1.m) { P_RemoveMobj(actor->special1.m); actor->special1.m = NULL; } // Spawn some dirt if (P_Random() < 40) P_SpawnDirt(actor, actor->radius); actor->special2.i++; // Increase raise speed } void A_ThrustLower(mobj_t * actor) { if (A_SinkMobj(actor)) { actor->args[0] = 0; if (actor->args[1]) P_SetMobjStateNF(actor, S_BTHRUSTINIT1_1); else P_SetMobjStateNF(actor, S_THRUSTINIT1_1); } } void A_ThrustBlock(mobj_t * actor) { actor->flags |= MF_SOLID; } void A_ThrustImpale(mobj_t * actor) { // Impale all shootables in radius PIT_ThrustSpike(actor); } //=========================================================================== // // A_SoAExplode - Suit of Armor Explode // //=========================================================================== void A_SoAExplode(mobj_t * actor) { mobj_t *mo; int i; for (i = 0; i < 10; i++) { mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12), actor->y + ((P_Random() - 128) << 12), actor->z + (P_Random() * actor->height / 256), MT_ZARMORCHUNK); P_SetMobjState(mo, mo->info->spawnstate + i); if (mo) { mo->momz = ((P_Random() & 7) + 5) * FRACUNIT; mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6); mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6); } } if (actor->args[0]) { // Spawn an item if (!nomonsters || !(mobjinfo[TranslateThingType[actor->args[0]]]. flags & MF_COUNTKILL)) { // Only spawn monsters if not -nomonsters P_SpawnMobj(actor->x, actor->y, actor->z, TranslateThingType[actor->args[0]]); } } S_StartSound(mo, SFX_SUITOFARMOR_BREAK); P_RemoveMobj(actor); } //=========================================================================== // // A_BellReset1 // //=========================================================================== void A_BellReset1(mobj_t * actor) { actor->flags |= MF_NOGRAVITY; actor->height <<= 2; } //=========================================================================== // // A_BellReset2 // //=========================================================================== void A_BellReset2(mobj_t * actor) { actor->flags |= MF_SHOOTABLE; actor->flags &= ~MF_CORPSE; actor->health = 5; } //=========================================================================== // // A_FlameCheck // //=========================================================================== void A_FlameCheck(mobj_t * actor) { if (!actor->args[0]--) // Called every 8 tics { P_SetMobjState(actor, S_NULL); } } //=========================================================================== // Bat Spawner Variables // special1 frequency counter // special2 // args[0] frequency of spawn (1=fastest, 10=slowest) // args[1] spread angle (0..255) // args[2] // args[3] duration of bats (in octics) // args[4] turn amount per move (in degrees) // // Bat Variables // special2 lifetime counter // args[4] turn amount per move (in degrees) //=========================================================================== void A_BatSpawnInit(mobj_t * actor) { actor->special1.i = 0; // Frequency count } void A_BatSpawn(mobj_t * actor) { mobj_t *mo; int delta; angle_t angle; // Countdown until next spawn if (actor->special1.i-- > 0) return; actor->special1.i = actor->args[0]; // Reset frequency count delta = actor->args[1]; if (delta == 0) delta = 1; angle = actor->angle + (((P_Random() % delta) - (delta >> 1)) << 24); mo = P_SpawnMissileAngle(actor, MT_BAT, angle, 0); if (mo) { mo->args[0] = P_Random() & 63; // floatbob index mo->args[4] = actor->args[4]; // turn degrees mo->special2.i = actor->args[3] << 3; // Set lifetime mo->target = actor; } } void A_BatMove(mobj_t * actor) { angle_t newangle; fixed_t speed; if (actor->special2.i < 0) { P_SetMobjState(actor, actor->info->deathstate); } actor->special2.i -= 2; // Called every 2 tics if (P_Random() < 128) { newangle = actor->angle + ANG1 * actor->args[4]; } else { newangle = actor->angle - ANG1 * actor->args[4]; } // Adjust momentum vector to new direction newangle >>= ANGLETOFINESHIFT; speed = FixedMul(actor->info->speed, P_Random() << 10); actor->momx = FixedMul(speed, finecosine[newangle]); actor->momy = FixedMul(speed, finesine[newangle]); if (P_Random() < 15) S_StartSound(actor, SFX_BAT_SCREAM); // Handle Z movement actor->z = actor->target->z + 2 * FloatBobOffsets[actor->args[0]]; actor->args[0] = (actor->args[0] + 3) & 63; } //=========================================================================== // // A_TreeDeath // //=========================================================================== void A_TreeDeath(mobj_t * actor) { if (!(actor->flags2 & MF2_FIREDAMAGE)) { actor->height <<= 2; actor->flags |= MF_SHOOTABLE; actor->flags &= ~(MF_CORPSE + MF_DROPOFF); actor->health = 35; return; } else { P_SetMobjState(actor, actor->info->meleestate); } } //=========================================================================== // // A_NoGravity // //=========================================================================== void A_NoGravity(mobj_t * actor) { actor->flags |= MF_NOGRAVITY; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/am_data.h000066400000000000000000000067711257432200600227550ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __AMDATA_H__ #define __AMDATA_H__ // a line drawing of the player pointing right, starting from the middle. #define R ((8*PLAYERRADIUS)/7) mline_t player_arrow[] = { { { -R+R/4, 0 }, { 0, 0} }, // center line. { { -R+R/4, R/8 }, { R, 0} }, // blade { { -R+R/4, -R/8 }, { R, 0 } }, { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece { { -R+R/8, -R/4 }, { -R+R/8, R/4 } }, { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors { { -R+R/8, R/4 }, { -R+R/4, R/4} }, { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel { { -R-R/4, R/8 }, { -R+R/8, R/8 } }, { { -R-R/4, -R/8}, { -R+R/8, -R/8 } } }; /* mline_t keysquare[] = { { { 0, 0 }, { R/4, -R/2 } }, { { R/4, -R/2 }, { R/2, -R/2 } }, { { R/2, -R/2 }, { R/2, R/2 } }, { { R/2, R/2 }, { R/4, R/2 } }, { { R/4, R/2 }, { 0, 0 } }, // handle part type thing { { 0, 0 }, { -R, 0 } }, // stem { { -R, 0 }, { -R, -R/2 } }, // end lockpick part { { -3*R/4, 0 }, { -3*R/4, -R/4 } } }; */ /*mline_t player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; */ #undef R #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) #define NUMKEYSQUARELINES (sizeof(keysquare)/sizeof(mline_t)) /* #define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/6 } }, // -----> { { R, 0 }, { R-R/2, -R/6 } }, { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >-----> { { -R+R/8, 0 }, { -R-R/8, -R/6 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>-----> { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } }, { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d---> { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } }, { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } }, { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd--> { { -R/6, -R/6 }, { 0, -R/6 } }, { { 0, -R/6 }, { 0, R/4 } }, { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt-> { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } }; #undef R #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) */ /* #define R (FRACUNIT) mline_t triangle_guy[] = { { { -.867*R, -.5*R }, { .867*R, -.5*R } }, { { .867*R, -.5*R } , { 0, R } }, { { 0, R }, { -.867*R, -.5*R } } }; #undef R #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) */ #define R (FRACUNIT) mline_t thintriangle_guy[] = { { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } }, { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } }, { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } }; #undef R #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) #endif chocolate-doom-chocolate-doom-2.2.1/src/hexen/am_map.c000066400000000000000000001201371257432200600226050ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "h2def.h" #include "doomkeys.h" #include "i_video.h" #include "i_swap.h" #include "m_controls.h" #include "m_misc.h" #include "p_local.h" #include "am_map.h" #include "am_data.h" #include "v_video.h" #define NUMALIAS 3 // Number of antialiased lines. int cheating = 0; static int grid = 0; static int leveljuststarted = 1; // kluge until AM_LevelInit() is called boolean automapactive = false; static int finit_width = SCREENWIDTH; static int finit_height = SCREENHEIGHT - SBARHEIGHT - 3; static int f_x, f_y; // location of window on screen static int f_w, f_h; // size of window on screen static int lightlev; // used for funky strobing effect static byte *fb; // pseudo-frame buffer static int amclock; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords) static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords) static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords) // width/height of window on map (map coords) static fixed_t m_w, m_h; static fixed_t min_x, min_y; // based on level size static fixed_t max_x, max_y; // based on level size static fixed_t max_w, max_h; // max_x-min_x, max_y-min_y static fixed_t min_w, min_h; // based on player size static fixed_t min_scale_mtof; // used to tell when to stop zooming out static fixed_t max_scale_mtof; // used to tell when to stop zooming in // old stuff for recovery later static fixed_t old_m_w, old_m_h; static fixed_t old_m_x, old_m_y; // old location used by the Follower routine static mpoint_t f_oldloc; // used by MTOF to scale from map-to-frame-buffer coords static fixed_t scale_mtof = INITSCALEMTOF; // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow static vertex_t oldplr; //static patch_t *marknums[10]; // numbers used for marking by the automap //static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are //static int markpointnum = 0; // next point to be assigned static int followplayer = 1; // specifies whether to follow the player around static char cheat_kills[] = { 'k', 'i', 'l', 'l', 's' }; static boolean ShowKills = 0; static unsigned ShowKillsCount = 0; extern boolean viewactive; static byte antialias[NUMALIAS][8] = { {83, 84, 85, 86, 87, 88, 89, 90}, {96, 96, 95, 94, 93, 92, 91, 90}, {107, 108, 109, 110, 111, 112, 89, 90} }; /* static byte *aliasmax[NUMALIAS] = { &antialias[0][7], &antialias[1][7], &antialias[2][7] };*/ static byte *maplump; // pointer to the raw data for the automap background. static short mapystart = 0; // y-value for the start of the map bitmap...used in //the parallax stuff. static short mapxstart = 0; //x-value for the bitmap. //byte screens[][SCREENWIDTH*SCREENHEIGHT]; //void V_MarkRect (int x, int y, int width, int height); // Functions void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor, int NumLevels, unsigned short IntensityBits); void AM_DrawDeathmatchStats(void); static void DrawWorldTimer(void); // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so // that it can be used with the brain-dead drawing stuff. // Ripped out for Heretic /* void AM_getIslope(mline_t *ml, islope_t *is) { int dx, dy; dy = ml->a.y - ml->b.y; dx = ml->b.x - ml->a.x; if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX); else is->islp = FixedDiv(dx, dy); if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX); else is->slp = FixedDiv(dy, dx); } */ void AM_activateNewScale(void) { m_x += m_w / 2; m_y += m_h / 2; m_w = FTOM(f_w); m_h = FTOM(f_h); m_x -= m_w / 2; m_y -= m_h / 2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } void AM_saveScaleAndLoc(void) { old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; } void AM_restoreScaleAndLoc(void) { m_w = old_m_w; m_h = old_m_h; if (!followplayer) { m_x = old_m_x; m_y = old_m_y; } else { m_x = plr->mo->x - m_w / 2; m_y = plr->mo->y - m_h / 2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; // Change the scaling multipliers scale_mtof = FixedDiv(f_w << FRACBITS, m_w); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } // adds a marker at the current location /* void AM_addMark(void) { markpoints[markpointnum].x = m_x + m_w/2; markpoints[markpointnum].y = m_y + m_h/2; markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS; } */ void AM_findMinMaxBoundaries(void) { int i; fixed_t a, b; min_x = min_y = INT_MAX; max_x = max_y = -INT_MAX; for (i = 0; i < numvertexes; i++) { if (vertexes[i].x < min_x) min_x = vertexes[i].x; else if (vertexes[i].x > max_x) max_x = vertexes[i].x; if (vertexes[i].y < min_y) min_y = vertexes[i].y; else if (vertexes[i].y > max_y) max_y = vertexes[i].y; } max_w = max_x - min_x; max_h = max_y - min_y; min_w = 2 * PLAYERRADIUS; min_h = 2 * PLAYERRADIUS; a = FixedDiv(f_w << FRACBITS, max_w); b = FixedDiv(f_h << FRACBITS, max_h); min_scale_mtof = a < b ? a : b; max_scale_mtof = FixedDiv(f_h << FRACBITS, 2 * PLAYERRADIUS); } void AM_changeWindowLoc(void) { if (m_paninc.x || m_paninc.y) { followplayer = 0; f_oldloc.x = INT_MAX; } m_x += m_paninc.x; m_y += m_paninc.y; if (m_x + m_w / 2 > max_x) { m_x = max_x - m_w / 2; m_paninc.x = 0; } else if (m_x + m_w / 2 < min_x) { m_x = min_x - m_w / 2; m_paninc.x = 0; } if (m_y + m_h / 2 > max_y) { m_y = max_y - m_h / 2; m_paninc.y = 0; } else if (m_y + m_h / 2 < min_y) { m_y = min_y - m_h / 2; m_paninc.y = 0; } // The following code was commented out in the released Hexen source, // but I believe we need to do this here to stop the background moving // when we reach the map boundaries. (In the released source it's done // in AM_clearFB). mapxstart += MTOF(m_paninc.x+FRACUNIT/2); mapystart -= MTOF(m_paninc.y+FRACUNIT/2); if(mapxstart >= finit_width) mapxstart -= finit_width; if(mapxstart < 0) mapxstart += finit_width; if(mapystart >= finit_height) mapystart -= finit_height; if(mapystart < 0) mapystart += finit_height; // - end of code that was commented-out m_x2 = m_x + m_w; m_y2 = m_y + m_h; } void AM_initVariables(void) { int pnum; thinker_t *think; //static event_t st_notify = { ev_keyup, AM_MSGENTERED }; automapactive = true; fb = I_VideoBuffer; f_oldloc.x = INT_MAX; amclock = 0; lightlev = 0; m_paninc.x = m_paninc.y = 0; ftom_zoommul = FRACUNIT; mtof_zoommul = FRACUNIT; m_w = FTOM(f_w); m_h = FTOM(f_h); // find player to center on initially if (!playeringame[pnum = consoleplayer]) for (pnum = 0; pnum < maxplayers; pnum++) if (playeringame[pnum]) break; plr = &players[pnum]; oldplr.x = plr->mo->x; oldplr.y = plr->mo->y; m_x = plr->mo->x - m_w / 2; m_y = plr->mo->y - m_h / 2; AM_changeWindowLoc(); // for saving & restoring old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; // load in the location of keys, if in baby mode // memset(KeyPoints, 0, sizeof(vertex_t)*3); if (gameskill == sk_baby) { for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { //not a mobj continue; } } } // inform the status bar of the change //c ST_Responder(&st_notify); } void AM_loadPics(void) { maplump = W_CacheLumpName("AUTOPAGE", PU_STATIC); } /* void AM_clearMarks(void) { int i; for (i=0;i max_scale_mtof) scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } static boolean stopped = true; void AM_Stop(void) { //static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED }; // AM_unloadPics(); automapactive = false; // ST_Responder(&st_notify); stopped = true; BorderNeedRefresh = true; } void AM_Start(void) { static int lastlevel = -1, lastepisode = -1; if (!stopped) AM_Stop(); stopped = false; if (gamestate != GS_LEVEL) { return; // don't show automap if we aren't in a game! } if (lastlevel != gamemap || lastepisode != gameepisode) { AM_LevelInit(); lastlevel = gamemap; lastepisode = gameepisode; } AM_initVariables(); AM_loadPics(); } // set the window scale to the maximum size void AM_minOutWindowScale(void) { scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // set the window scale to the minimum size void AM_maxOutWindowScale(void) { scale_mtof = max_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } boolean AM_Responder(event_t * ev) { int rc; int key; static int bigstate = 0; key = ev->data1; rc = false; if (!automapactive) { if (ev->type == ev_keydown && key == key_map_toggle && gamestate == GS_LEVEL) { AM_Start(); SB_state = -1; viewactive = false; rc = true; } } else if (ev->type == ev_keydown) { rc = true; if (key == key_map_east) // pan right { if (!followplayer) m_paninc.x = FTOM(F_PANINC); else rc = false; } else if (key == key_map_west) // pan left { if (!followplayer) m_paninc.x = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_north) // pan up { if (!followplayer) m_paninc.y = FTOM(F_PANINC); else rc = false; } else if (key == key_map_south) // pan down { if (!followplayer) m_paninc.y = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_zoomout) // zoom out { mtof_zoommul = M_ZOOMOUT; ftom_zoommul = M_ZOOMIN; } else if (key == key_map_zoomin) // zoom in { mtof_zoommul = M_ZOOMIN; ftom_zoommul = M_ZOOMOUT; } else if (key == key_map_toggle) { bigstate = 0; viewactive = true; AM_Stop(); SB_state = -1; } else if (key == key_map_maxzoom) { bigstate = !bigstate; if (bigstate) { AM_saveScaleAndLoc(); AM_minOutWindowScale(); } else AM_restoreScaleAndLoc(); } else if (key == key_map_follow) { followplayer = !followplayer; f_oldloc.x = INT_MAX; P_SetMessage(plr, followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF, true); } else { rc = false; } if (cheat_kills[ShowKillsCount] == ev->data1 && netgame && deathmatch) { ShowKillsCount++; if (ShowKillsCount == 5) { ShowKillsCount = 0; rc = false; ShowKills ^= 1; } } else { ShowKillsCount = 0; } } else if (ev->type == ev_keyup) { rc = false; if (key == key_map_east) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_west) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_north) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_south) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_zoomin || key == key_map_zoomout) { mtof_zoommul = FRACUNIT; ftom_zoommul = FRACUNIT; } } return rc; } void AM_changeWindowScale(void) { // Change the scaling multipliers scale_mtof = FixedMul(scale_mtof, mtof_zoommul); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); if (scale_mtof < min_scale_mtof) AM_minOutWindowScale(); else if (scale_mtof > max_scale_mtof) AM_maxOutWindowScale(); else AM_activateNewScale(); } void AM_doFollowPlayer(void) { if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) { // m_x = FTOM(MTOF(plr->mo->x - m_w/2)); // m_y = FTOM(MTOF(plr->mo->y - m_h/2)); // m_x = plr->mo->x - m_w/2; // m_y = plr->mo->y - m_h/2; m_x = FTOM(MTOF(plr->mo->x)) - m_w / 2; m_y = FTOM(MTOF(plr->mo->y)) - m_h / 2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; // do the parallax parchment scrolling. /* dmapx = (MTOF(plr->mo->x)-MTOF(f_oldloc.x)); //fixed point dmapy = (MTOF(f_oldloc.y)-MTOF(plr->mo->y)); if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first dmapx=0; //goes into the automap. mapxstart += dmapx; mapystart += dmapy; while(mapxstart >= finit_width) mapxstart -= finit_width; while(mapxstart < 0) mapxstart += finit_width; while(mapystart >= finit_height) mapystart -= finit_height; while(mapystart < 0) mapystart += finit_height; */ f_oldloc.x = plr->mo->x; f_oldloc.y = plr->mo->y; } } // Ripped out for Heretic /* void AM_updateLightLev(void) { static nexttic = 0; //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 }; static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 }; static int litelevelscnt = 0; // Change light level if (amclock>nexttic) { lightlev = litelevels[litelevelscnt++]; if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0; nexttic = amclock + 6 - (amclock % 6); } } */ void AM_Ticker(void) { if (!automapactive) return; amclock++; if (followplayer) AM_doFollowPlayer(); // Change the zoom if necessary if (ftom_zoommul != FRACUNIT) AM_changeWindowScale(); // Change x,y location if (m_paninc.x || m_paninc.y) AM_changeWindowLoc(); // Update light level // AM_updateLightLev(); } void AM_clearFB(int color) { int i, j; int dmapx; int dmapy; if (followplayer) { dmapx = (MTOF(plr->mo->x) - MTOF(oldplr.x)); //fixed point dmapy = (MTOF(oldplr.y) - MTOF(plr->mo->y)); oldplr.x = plr->mo->x; oldplr.y = plr->mo->y; // if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first // dmapx=0; //goes into the automap. mapxstart += dmapx >> 1; mapystart += dmapy >> 1; while (mapxstart >= finit_width) mapxstart -= finit_width; while (mapxstart < 0) mapxstart += finit_width; while (mapystart >= finit_height) mapystart -= finit_height; while (mapystart < 0) mapystart += finit_height; } else { // The released Hexen source does this here, but this causes a bug // where the map background keeps moving when we reach the map // boundaries. This is instead done in AM_changeWindowLoc. /* mapxstart += (MTOF(m_paninc.x) >> 1); mapystart -= (MTOF(m_paninc.y) >> 1); if (mapxstart >= finit_width) mapxstart -= finit_width; if (mapxstart < 0) mapxstart += finit_width; if (mapystart >= finit_height) mapystart -= finit_height; if (mapystart < 0) mapystart += finit_height; */ } //blit the automap background to the screen. j = mapystart * finit_width; for (i = 0; i < SCREENHEIGHT - SBARHEIGHT; i++) { memcpy(I_VideoBuffer + i * finit_width, maplump + j + mapxstart, finit_width - mapxstart); memcpy(I_VideoBuffer + i * finit_width + finit_width - mapxstart, maplump + j, mapxstart); j += finit_width; if (j >= finit_height * finit_width) j = 0; } // memcpy(I_VideoBuffer, maplump, finit_width*finit_height); // memset(fb, color, f_w*f_h); } // Based on Cohen-Sutherland clipping algorithm but with a slightly // faster reject and precalculated slopes. If I need the speed, will // hash algorithm to the common cases. boolean AM_clipMline(mline_t * ml, fline_t * fl) { enum { LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 }; int outcode1 = 0, outcode2 = 0, outside; fpoint_t tmp = { 0, 0 }; int dx, dy; #define DOOUTCODE(oc, mx, my) \ (oc) = 0; \ if ((my) < 0) (oc) |= TOP; \ else if ((my) >= f_h) (oc) |= BOTTOM; \ if ((mx) < 0) (oc) |= LEFT; \ else if ((mx) >= f_w) (oc) |= RIGHT // do trivial rejects and outcodes if (ml->a.y > m_y2) outcode1 = TOP; else if (ml->a.y < m_y) outcode1 = BOTTOM; if (ml->b.y > m_y2) outcode2 = TOP; else if (ml->b.y < m_y) outcode2 = BOTTOM; if (outcode1 & outcode2) return false; // trivially outside if (ml->a.x < m_x) outcode1 |= LEFT; else if (ml->a.x > m_x2) outcode1 |= RIGHT; if (ml->b.x < m_x) outcode2 |= LEFT; else if (ml->b.x > m_x2) outcode2 |= RIGHT; if (outcode1 & outcode2) return false; // trivially outside // transform to frame-buffer coordinates. fl->a.x = CXMTOF(ml->a.x); fl->a.y = CYMTOF(ml->a.y); fl->b.x = CXMTOF(ml->b.x); fl->b.y = CYMTOF(ml->b.y); DOOUTCODE(outcode1, fl->a.x, fl->a.y); DOOUTCODE(outcode2, fl->b.x, fl->b.y); if (outcode1 & outcode2) return false; while (outcode1 | outcode2) { // may be partially inside box // find an outside point if (outcode1) outside = outcode1; else outside = outcode2; // clip to each side if (outside & TOP) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx * (fl->a.y)) / dy; tmp.y = 0; } else if (outside & BOTTOM) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx * (fl->a.y - f_h)) / dy; tmp.y = f_h - 1; } else if (outside & RIGHT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy * (f_w - 1 - fl->a.x)) / dx; tmp.x = f_w - 1; } else if (outside & LEFT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy * (-fl->a.x)) / dx; tmp.x = 0; } if (outside == outcode1) { fl->a = tmp; DOOUTCODE(outcode1, fl->a.x, fl->a.y); } else { fl->b = tmp; DOOUTCODE(outcode2, fl->b.x, fl->b.y); } if (outcode1 & outcode2) return false; // trivially outside } return true; } #undef DOOUTCODE // Classic Bresenham w/ whatever optimizations I need for speed void AM_drawFline(fline_t * fl, int color) { register int x, y, dx, dy, sx, sy, ax, ay, d; //static fuck = 0; switch (color) { case WALLCOLORS: DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[0][0], 8, 3); break; case FDWALLCOLORS: DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[1][0], 8, 3); break; case CDWALLCOLORS: DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[2][0], 8, 3); break; default: { // For debugging only if (fl->a.x < 0 || fl->a.x >= f_w || fl->a.y < 0 || fl->a.y >= f_h || fl->b.x < 0 || fl->b.x >= f_w || fl->b.y < 0 || fl->b.y >= f_h) { //fprintf(stderr, "fuck %d \r", fuck++); return; } #define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO! dx = fl->b.x - fl->a.x; ax = 2 * (dx < 0 ? -dx : dx); sx = dx < 0 ? -1 : 1; dy = fl->b.y - fl->a.y; ay = 2 * (dy < 0 ? -dy : dy); sy = dy < 0 ? -1 : 1; x = fl->a.x; y = fl->a.y; if (ax > ay) { d = ay - ax / 2; while (1) { DOT(x, y, color); if (x == fl->b.x) return; if (d >= 0) { y += sy; d -= ax; } x += sx; d += ay; } } else { d = ax - ay / 2; while (1) { DOT(x, y, color); if (y == fl->b.y) return; if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; } } } } } /* Wu antialiased line drawer. * (X0,Y0),(X1,Y1) = line to draw * BaseColor = color # of first color in block used for antialiasing, the * 100% intensity version of the drawing color * NumLevels = size of color block, with BaseColor+NumLevels-1 being the * 0% intensity version of the drawing color * IntensityBits = log base 2 of NumLevels; the # of bits used to describe * the intensity of the drawing color. 2**IntensityBits==NumLevels */ void PUTDOT(short xx, short yy, byte * cc, byte * cm) { static int oldyy; static int oldyyshifted; byte *oldcc = cc; if (xx < 32) cc += 7 - (xx >> 2); else if (xx > (finit_width - 32)) cc += 7 - ((finit_width - xx) >> 2); // if(cc==oldcc) //make sure that we don't double fade the corners. // { if (yy < 32) cc += 7 - (yy >> 2); else if (yy > (finit_height - 32)) cc += 7 - ((finit_height - yy) >> 2); // } if (cc > cm && cm != NULL) { cc = cm; } else if (cc > oldcc + 6) // don't let the color escape from the fade table... { cc = oldcc + 6; } if (yy == oldyy + 1) { oldyy++; oldyyshifted += 320; } else if (yy == oldyy - 1) { oldyy--; oldyyshifted -= 320; } else if (yy != oldyy) { oldyy = yy; oldyyshifted = yy * 320; } fb[oldyyshifted + xx] = *(cc); // fb[(yy)*f_w+(xx)]=*(cc); } void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor, int NumLevels, unsigned short IntensityBits) { unsigned short IntensityShift, ErrorAdj, ErrorAcc; unsigned short ErrorAccTemp, Weighting, WeightingComplementMask; short DeltaX, DeltaY, Temp, XDir; /* Make sure the line runs top to bottom */ if (Y0 > Y1) { Temp = Y0; Y0 = Y1; Y1 = Temp; Temp = X0; X0 = X1; X1 = Temp; } /* Draw the initial pixel, which is always exactly intersected by the line and so needs no weighting */ PUTDOT(X0, Y0, &BaseColor[0], NULL); if ((DeltaX = X1 - X0) >= 0) { XDir = 1; } else { XDir = -1; DeltaX = -DeltaX; /* make DeltaX positive */ } /* Special-case horizontal, vertical, and diagonal lines, which require no weighting because they go right through the center of every pixel */ if ((DeltaY = Y1 - Y0) == 0) { /* Horizontal line */ while (DeltaX-- != 0) { X0 += XDir; PUTDOT(X0, Y0, &BaseColor[0], NULL); } return; } if (DeltaX == 0) { /* Vertical line */ do { Y0++; PUTDOT(X0, Y0, &BaseColor[0], NULL); } while (--DeltaY != 0); return; } //diagonal line. if (DeltaX == DeltaY) { do { X0 += XDir; Y0++; PUTDOT(X0, Y0, &BaseColor[0], NULL); } while (--DeltaY != 0); return; } /* Line is not horizontal, diagonal, or vertical */ ErrorAcc = 0; /* initialize the line error accumulator to 0 */ /* # of bits by which to shift ErrorAcc to get intensity level */ IntensityShift = 16 - IntensityBits; /* Mask used to flip all bits in an intensity weighting, producing the result (1 - intensity weighting) */ WeightingComplementMask = NumLevels - 1; /* Is this an X-major or Y-major line? */ if (DeltaY > DeltaX) { /* Y-major line; calculate 16-bit fixed-point fractional part of a pixel that X advances each time Y advances 1 pixel, truncating the result so that we won't overrun the endpoint along the X axis */ ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY; /* Draw all pixels other than the first and last */ while (--DeltaY) { ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ ErrorAcc += ErrorAdj; /* calculate error for next pixel */ if (ErrorAcc <= ErrorAccTemp) { /* The error accumulator turned over, so advance the X coord */ X0 += XDir; } Y0++; /* Y-major, so always advance Y */ /* The IntensityBits most significant bits of ErrorAcc give us the intensity weighting for this pixel, and the complement of the weighting for the paired pixel */ Weighting = ErrorAcc >> IntensityShift; PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]); PUTDOT(X0 + XDir, Y0, &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]); } /* Draw the final pixel, which is always exactly intersected by the line and so needs no weighting */ PUTDOT(X1, Y1, &BaseColor[0], NULL); return; } /* It's an X-major line; calculate 16-bit fixed-point fractional part of a pixel that Y advances each time X advances 1 pixel, truncating the result to avoid overrunning the endpoint along the X axis */ ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX; /* Draw all pixels other than the first and last */ while (--DeltaX) { ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ ErrorAcc += ErrorAdj; /* calculate error for next pixel */ if (ErrorAcc <= ErrorAccTemp) { /* The error accumulator turned over, so advance the Y coord */ Y0++; } X0 += XDir; /* X-major, so always advance X */ /* The IntensityBits most significant bits of ErrorAcc give us the intensity weighting for this pixel, and the complement of the weighting for the paired pixel */ Weighting = ErrorAcc >> IntensityShift; PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]); PUTDOT(X0, Y0 + 1, &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]); } /* Draw the final pixel, which is always exactly intersected by the line and so needs no weighting */ PUTDOT(X1, Y1, &BaseColor[0], NULL); } void AM_drawMline(mline_t * ml, int color) { static fline_t fl; if (AM_clipMline(ml, &fl)) AM_drawFline(&fl, color); // draws it on frame buffer using fb coords } void AM_drawGrid(int color) { fixed_t x, y; fixed_t start, end; mline_t ml; // Figure out start of vertical gridlines start = m_x; if ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS)) start += (MAPBLOCKUNITS << FRACBITS) - ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS)); end = m_x + m_w; // draw vertical gridlines ml.a.y = m_y; ml.b.y = m_y + m_h; for (x = start; x < end; x += (MAPBLOCKUNITS << FRACBITS)) { ml.a.x = x; ml.b.x = x; AM_drawMline(&ml, color); } // Figure out start of horizontal gridlines start = m_y; if ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS)) start += (MAPBLOCKUNITS << FRACBITS) - ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS)); end = m_y + m_h; // draw horizontal gridlines ml.a.x = m_x; ml.b.x = m_x + m_w; for (y = start; y < end; y += (MAPBLOCKUNITS << FRACBITS)) { ml.a.y = y; ml.b.y = y; AM_drawMline(&ml, color); } } void AM_drawWalls(void) { int i; static mline_t l; for (i = 0; i < numlines; i++) { l.a.x = lines[i].v1->x; l.a.y = lines[i].v1->y; l.b.x = lines[i].v2->x; l.b.y = lines[i].v2->y; if (cheating || (lines[i].flags & ML_MAPPED)) { if ((lines[i].flags & LINE_NEVERSEE) && !cheating) continue; if (!lines[i].backsector) { AM_drawMline(&l, WALLCOLORS + lightlev); } else { if (lines[i].flags & ML_SECRET) // secret door { if (cheating) AM_drawMline(&l, 0); else AM_drawMline(&l, WALLCOLORS + lightlev); } else if (lines[i].special == 13 || lines[i].special == 83) { // Locked door line -- all locked doors are greed AM_drawMline(&l, GREENKEY); } else if (lines[i].special == 70 || lines[i].special == 71) { // intra-level teleports are blue AM_drawMline(&l, BLUEKEY); } else if (lines[i].special == 74 || lines[i].special == 75) { // inter-level teleport/game-winning exit -- both are red AM_drawMline(&l, BLOODRED); } else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight) { AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change } else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight) { AM_drawMline(&l, CDWALLCOLORS + lightlev); // ceiling level change } else if (cheating) { AM_drawMline(&l, TSWALLCOLORS + lightlev); } } } else if (plr->powers[pw_allmap]) { if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS + 3); } } } void AM_rotate(fixed_t * x, fixed_t * y, angle_t a) { fixed_t tmpx; tmpx = FixedMul(*x, finecosine[a >> ANGLETOFINESHIFT]) - FixedMul(*y, finesine[a >> ANGLETOFINESHIFT]); *y = FixedMul(*x, finesine[a >> ANGLETOFINESHIFT]) + FixedMul(*y, finecosine[a >> ANGLETOFINESHIFT]); *x = tmpx; } void AM_drawLineCharacter(mline_t * lineguy, int lineguylines, fixed_t scale, angle_t angle, int color, fixed_t x, fixed_t y) { int i; mline_t l; for (i = 0; i < lineguylines; i++) { l.a.x = lineguy[i].a.x; l.a.y = lineguy[i].a.y; if (scale) { l.a.x = FixedMul(scale, l.a.x); l.a.y = FixedMul(scale, l.a.y); } if (angle) AM_rotate(&l.a.x, &l.a.y, angle); l.a.x += x; l.a.y += y; l.b.x = lineguy[i].b.x; l.b.y = lineguy[i].b.y; if (scale) { l.b.x = FixedMul(scale, l.b.x); l.b.y = FixedMul(scale, l.b.y); } if (angle) AM_rotate(&l.b.x, &l.b.y, angle); l.b.x += x; l.b.y += y; AM_drawMline(&l, color); } } void AM_drawPlayers(void) { int i; player_t *p; static int their_colors[] = { AM_PLR1_COLOR, AM_PLR2_COLOR, AM_PLR3_COLOR, AM_PLR4_COLOR, AM_PLR5_COLOR, AM_PLR6_COLOR, AM_PLR7_COLOR, AM_PLR8_COLOR }; int their_color = -1; int color; if (!netgame) { AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y); return; } for (i = 0; i < maxplayers; i++) { their_color++; p = &players[i]; if (deathmatch && !singledemo && p != plr) { continue; } if (!playeringame[i]) continue; color = their_colors[their_color]; AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle, color, p->mo->x, p->mo->y); } } void AM_drawThings(int colors, int colorrange) { int i; mobj_t *t; for (i = 0; i < numsectors; i++) { t = sectors[i].thinglist; while (t) { AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16 << FRACBITS, t->angle, colors + lightlev, t->x, t->y); t = t->snext; } } } /* void AM_drawMarks(void) { int i, fx, fy, w, h; for (i=0;iwidth); h = SHORT(marknums[i]->height); fx = CXMTOF(markpoints[i].x); fy = CYMTOF(markpoints[i].y); if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h) V_DrawPatch(fx, fy, marknums[i]); } } } */ /* void AM_drawkeys(void) { if(KeyPoints[0].x != 0 || KeyPoints[0].y != 0) { AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, YELLOWKEY, KeyPoints[0].x, KeyPoints[0].y); } if(KeyPoints[1].x != 0 || KeyPoints[1].y != 0) { AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, GREENKEY, KeyPoints[1].x, KeyPoints[1].y); } if(KeyPoints[2].x != 0 || KeyPoints[2].y != 0) { AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, BLUEKEY, KeyPoints[2].x, KeyPoints[2].y); } } */ /* void AM_drawCrosshair(int color) { fb[(f_w*(f_h+1))/2] = color; // single point for now } */ void AM_Drawer(void) { if (!automapactive) return; UpdateState |= I_FULLSCRN; AM_clearFB(BACKGROUND); if (grid) AM_drawGrid(GRIDCOLORS); AM_drawWalls(); AM_drawPlayers(); DrawWorldTimer(); if (cheating == 2) AM_drawThings(THINGCOLORS, THINGRANGE); // AM_drawCrosshair(XHAIRCOLORS); // AM_drawMarks(); // if(gameskill == sk_baby) AM_drawkeys(); MN_DrTextA(P_GetMapName(gamemap), 38, 144); if (ShowKills && netgame && deathmatch) { AM_DrawDeathmatchStats(); } // I_Update(); // V_MarkRect(f_x, f_y, f_w, f_h); } //=========================================================================== // // AM_DrawDeathmatchStats // //=========================================================================== // 8-player note: Proper player color names here, too char *PlayerColorText[MAXPLAYERS] = { "BLUE:", "RED:", "YELLOW:", "GREEN:", "JADE:", "WHITE:", "HAZEL:", "PURPLE:" }; void AM_DrawDeathmatchStats(void) { int i, j, k, m; int fragCount[MAXPLAYERS]; int order[MAXPLAYERS]; char textBuffer[80]; int yPosition; for (i = 0; i < maxplayers; i++) { fragCount[i] = 0; order[i] = -1; } for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) { continue; } else { for (j = 0; j < maxplayers; j++) { if (playeringame[j]) { fragCount[i] += players[i].frags[j]; } } for (k = 0; k < maxplayers; k++) { if (order[k] == -1) { order[k] = i; break; } else if (fragCount[i] > fragCount[order[k]]) { for (m = maxplayers - 1; m > k; m--) { order[m] = order[m - 1]; } order[k] = i; break; } } } } yPosition = 15; for (i = 0; i < maxplayers; i++) { if (!playeringame[order[i]]) { continue; } else { MN_DrTextA(PlayerColorText[order[i]], 8, yPosition); M_snprintf(textBuffer, sizeof(textBuffer), "%d", fragCount[order[i]]); MN_DrTextA(textBuffer, 80, yPosition); yPosition += 10; } } } //=========================================================================== // // DrawWorldTimer // //=========================================================================== static void DrawWorldTimer(void) { int days; int hours; int minutes; int seconds; int worldTimer; char timeBuffer[15]; char dayBuffer[20]; worldTimer = players[consoleplayer].worldTimer; worldTimer /= 35; days = worldTimer / 86400; worldTimer -= days * 86400; hours = worldTimer / 3600; worldTimer -= hours * 3600; minutes = worldTimer / 60; worldTimer -= minutes * 60; seconds = worldTimer; M_snprintf(timeBuffer, sizeof(timeBuffer), "%.2d : %.2d : %.2d", hours, minutes, seconds); MN_DrTextA(timeBuffer, 240, 8); if (days) { if (days == 1) { M_snprintf(dayBuffer, sizeof(dayBuffer), "%.2d DAY", days); } else { M_snprintf(dayBuffer, sizeof(dayBuffer), "%.2d DAYS", days); } MN_DrTextA(dayBuffer, 240, 20); if (days >= 5) { MN_DrTextA("YOU FREAK!!!", 230, 35); } } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/am_map.h000066400000000000000000000062631257432200600226150ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __AMMAP_H__ #define __AMMAP_H__ // For use if I do walls with outsides/insides #define REDS 12*8 #define REDRANGE 1 //16 #define BLUES (256-4*16+8) #define BLUERANGE 1 //8 #define GREENS (33*8) #define GREENRANGE 1 //16 #define GRAYS (5*8) #define GRAYSRANGE 1 //16 #define BROWNS (14*8) #define BROWNRANGE 1 //16 #define YELLOWS 10*8 #define YELLOWRANGE 1 #define BLACK 0 #define WHITE 4*8 #define PARCH 13*8-1 #define BLOODRED 177 #define BLUEKEY 157 #define YELLOWKEY 137 #define GREENKEY 198 // Automap colors #define AM_PLR1_COLOR 157 // Blue #define AM_PLR2_COLOR 177 // Red #define AM_PLR3_COLOR 137 // Yellow #define AM_PLR4_COLOR 198 // Green #define AM_PLR5_COLOR 215 // Jade #define AM_PLR6_COLOR 32 // White #define AM_PLR7_COLOR 106 // Hazel #define AM_PLR8_COLOR 234 // Purple #define BACKGROUND PARCH #define YOURCOLORS WHITE #define YOURRANGE 0 #define WALLCOLORS REDS #define WALLRANGE REDRANGE #define TSWALLCOLORS GRAYS #define TSWALLRANGE GRAYSRANGE #define FDWALLCOLORS BROWNS #define FDWALLRANGE BROWNRANGE #define CDWALLCOLORS YELLOWS #define CDWALLRANGE YELLOWRANGE #define THINGCOLORS GREENS #define THINGRANGE GREENRANGE #define SECRETWALLCOLORS WALLCOLORS #define SECRETWALLRANGE WALLRANGE #define GRIDCOLORS (GRAYS + GRAYSRANGE/2) #define GRIDRANGE 0 #define XHAIRCOLORS GRAYS // drawing stuff #define AM_NUMMARKPOINTS 10 #define AM_MSGHEADER (('a'<<24)+('m'<<16)) #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) #define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) #define INITSCALEMTOF (.2*FRACUNIT) // scale on entry // how much the automap moves window per tic in frame-buffer coordinates #define F_PANINC 4 // moves 140 pixels in 1 second // how much zoom-in per tic #define M_ZOOMIN ((int) (1.02*FRACUNIT)) // goes to 2x in 1 second // how much zoom-out per tic #define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // pulls out to 0.5x in 1 second // translates between frame-buffer and map distances #define FTOM(x) FixedMul(((x)<<16),scale_ftom) #define MTOF(x) (FixedMul((x),scale_mtof)>>16) // translates between frame-buffer and map coordinates #define CXMTOF(x) (f_x + MTOF((x)-m_x)) #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) // the following is crap #define LINE_NEVERSEE ML_DONTDRAW typedef struct { int x, y; } fpoint_t; typedef struct { fpoint_t a, b; } fline_t; typedef vertex_t mpoint_t; typedef struct { mpoint_t a, b; } mline_t; typedef struct { fixed_t slp, islp; } islope_t; // extern int f_x, f_y, f_w, f_h; #endif chocolate-doom-chocolate-doom-2.2.1/src/hexen/ct_chat.c000066400000000000000000000304701257432200600227600ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "h2def.h" #include "s_sound.h" #include "doomkeys.h" #include "m_controls.h" #include "m_misc.h" #include "p_local.h" #include "v_video.h" #define NUMKEYS 256 #define QUEUESIZE 128 #define MESSAGESIZE 128 #define MESSAGELEN 265 // 8-player note: Change this stuff (CT_PLR_*, and the key mappings) enum { CT_PLR_BLUE = 1, CT_PLR_RED, CT_PLR_YELLOW, CT_PLR_GREEN, CT_PLR_PLAYER5, CT_PLR_PLAYER6, CT_PLR_PLAYER7, CT_PLR_PLAYER8, CT_PLR_ALL }; #define CT_ESCAPE 6 // Public data boolean chatmodeon; // Private data void CT_queueChatChar(char ch); void CT_ClearChatMessage(int player); void CT_AddChar(int player, char c); void CT_BackSpace(int player); int head; int tail; byte ChatQueue[QUEUESIZE]; int chat_dest[MAXPLAYERS]; char chat_msg[MAXPLAYERS][MESSAGESIZE]; char plr_lastmsg[MAXPLAYERS][MESSAGESIZE + 9]; int msgptr[MAXPLAYERS]; int msglen[MAXPLAYERS]; boolean cheated; static int FontABaseLump; char *CT_FromPlrText[MAXPLAYERS] = { "BLUE: ", "RED: ", "YELLOW: ", "GREEN: ", "JADE: ", "WHITE: ", "HAZEL: ", "PURPLE: " }; char *chat_macros[10] = { HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, HUSTR_CHATMACRO2, HUSTR_CHATMACRO3, HUSTR_CHATMACRO4, HUSTR_CHATMACRO5, HUSTR_CHATMACRO6, HUSTR_CHATMACRO7, HUSTR_CHATMACRO8, HUSTR_CHATMACRO9, }; boolean altdown; boolean shiftdown; extern boolean usearti; //=========================================================================== // // CT_Init // // Initialize chat mode data //=========================================================================== void CT_Init(void) { int i; head = 0; //initialize the queue index tail = 0; chatmodeon = false; memset(ChatQueue, 0, QUEUESIZE); for (i = 0; i < maxplayers; i++) { chat_dest[i] = 0; msgptr[i] = 0; memset(plr_lastmsg[i], 0, MESSAGESIZE); memset(chat_msg[i], 0, MESSAGESIZE); } FontABaseLump = W_GetNumForName("FONTA_S") + 1; return; } //=========================================================================== // // CT_Stop // //=========================================================================== void CT_Stop(void) { chatmodeon = false; return; } // These keys are allowed by Vanilla Heretic: static boolean ValidChatChar(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '!' || c == '?' || c == ' ' || c == '\'' || c == ',' || c == '.' || c == '-' || c == '='; } //=========================================================================== // // CT_Responder // //=========================================================================== boolean CT_Responder(event_t * ev) { char *macro; int sendto; if (!netgame) { return false; } if (ev->data1 == KEY_RALT) { altdown = (ev->type == ev_keydown); return false; } if (ev->data1 == KEY_RSHIFT) { shiftdown = (ev->type == ev_keydown); return false; } if (gamestate != GS_LEVEL || ev->type != ev_keydown) { return false; } if (!chatmodeon) { sendto = 0; if (ev->data1 == key_multi_msg) { sendto = CT_PLR_ALL; } else if (ev->data1 == key_multi_msgplayer[0]) { sendto = CT_PLR_BLUE; } else if (ev->data1 == key_multi_msgplayer[1]) { sendto = CT_PLR_RED; } else if (ev->data1 == key_multi_msgplayer[2]) { sendto = CT_PLR_YELLOW; } else if (ev->data1 == key_multi_msgplayer[3]) { sendto = CT_PLR_GREEN; } else if (ev->data1 == key_multi_msgplayer[4]) { sendto = CT_PLR_PLAYER5; } else if (ev->data1 == key_multi_msgplayer[5]) { sendto = CT_PLR_PLAYER6; } else if (ev->data1 == key_multi_msgplayer[6]) { sendto = CT_PLR_PLAYER7; } else if (ev->data1 == key_multi_msgplayer[7]) { sendto = CT_PLR_PLAYER8; } if (sendto == 0 || (sendto != CT_PLR_ALL && !playeringame[sendto - 1]) || sendto == consoleplayer + 1) { return false; } CT_queueChatChar(sendto); chatmodeon = true; return true; } else { if (altdown) { if (ev->data1 >= '0' && ev->data1 <= '9') { if (ev->data1 == '0') { // macro 0 comes after macro 9 ev->data1 = '9' + 1; } macro = chat_macros[ev->data1 - '1']; CT_queueChatChar(KEY_ENTER); //send old message CT_queueChatChar(chat_dest[consoleplayer]); // chose the dest. while (*macro) { CT_queueChatChar(toupper(*macro++)); } CT_queueChatChar(KEY_ENTER); //send it off... CT_Stop(); return true; } } if (ev->data1 == KEY_ENTER) { CT_queueChatChar(KEY_ENTER); usearti = false; CT_Stop(); return true; } else if (ev->data1 == KEY_ESCAPE) { CT_queueChatChar(CT_ESCAPE); CT_Stop(); return true; } else if (ev->data1 == KEY_BACKSPACE) { CT_queueChatChar(KEY_BACKSPACE); return true; } else if (ValidChatChar(ev->data2)) { CT_queueChatChar(toupper(ev->data2)); return true; } } return false; } //=========================================================================== // // CT_Ticker // //=========================================================================== void CT_Ticker(void) { int i; int j; char c; int numplayers; for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) { continue; } if ((c = players[i].cmd.chatchar) != 0) { if (c <= CT_PLR_ALL) { chat_dest[i] = c; continue; } else if (c == CT_ESCAPE) { CT_ClearChatMessage(i); } else if (c == KEY_ENTER) { numplayers = 0; for (j = 0; j < maxplayers; j++) { numplayers += playeringame[j]; } CT_AddChar(i, 0); // set the end of message character if (numplayers > 2) { M_StringCopy(plr_lastmsg[i], CT_FromPlrText[i], sizeof(plr_lastmsg[i])); M_StringConcat(plr_lastmsg[i], chat_msg[i], sizeof(plr_lastmsg[i])); } else { M_StringCopy(plr_lastmsg[i], chat_msg[i], sizeof(plr_lastmsg[i])); } if (i != consoleplayer && (chat_dest[i] == consoleplayer + 1 || chat_dest[i] == CT_PLR_ALL) && *chat_msg[i]) { P_SetMessage(&players[consoleplayer], plr_lastmsg[i], true); S_StartSound(NULL, SFX_CHAT); } else if (i == consoleplayer && (*chat_msg[i])) { if (numplayers <= 1) { P_SetMessage(&players[consoleplayer], "THERE ARE NO OTHER PLAYERS IN THE GAME!", true); S_StartSound(NULL, SFX_CHAT); } } CT_ClearChatMessage(i); } else if (c == KEY_BACKSPACE) { CT_BackSpace(i); } else { CT_AddChar(i, c); } } } return; } //=========================================================================== // // CT_Drawer // //=========================================================================== void CT_Drawer(void) { int i; int x; patch_t *patch; if (chatmodeon) { x = 25; for (i = 0; i < msgptr[consoleplayer]; i++) { if (chat_msg[consoleplayer][i] < 33) { x += 6; } else { patch = W_CacheLumpNum(FontABaseLump + chat_msg[consoleplayer][i] - 33, PU_CACHE); V_DrawPatch(x, 10, patch); x += patch->width; } } V_DrawPatch(x, 10, W_CacheLumpName("FONTA59", PU_CACHE)); BorderTopRefresh = true; UpdateState |= I_MESSAGES; } } //=========================================================================== // // CT_queueChatChar // //=========================================================================== void CT_queueChatChar(char ch) { if (((tail + 1) & (QUEUESIZE - 1)) == head) { // the queue is full return; } ChatQueue[tail] = ch; tail = (tail + 1) & (QUEUESIZE - 1); } //=========================================================================== // // CT_dequeueChatChar // //=========================================================================== char CT_dequeueChatChar(void) { byte temp; if (head == tail) { // queue is empty return 0; } temp = ChatQueue[head]; head = (head + 1) & (QUEUESIZE - 1); return temp; } //=========================================================================== // // CT_AddChar // //=========================================================================== void CT_AddChar(int player, char c) { patch_t *patch; if (msgptr[player] + 1 >= MESSAGESIZE || msglen[player] >= MESSAGELEN) { // full. return; } chat_msg[player][msgptr[player]] = c; msgptr[player]++; if (c < 33) { msglen[player] += 6; } else { patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); msglen[player] += patch->width; } } //=========================================================================== // // CT_BackSpace // // Backs up a space, when the user hits (obviously) backspace //=========================================================================== void CT_BackSpace(int player) { patch_t *patch; char c; if (msgptr[player] == 0) { // message is already blank return; } msgptr[player]--; c = chat_msg[player][msgptr[player]]; if (c < 33) { msglen[player] -= 6; } else { patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); msglen[player] -= patch->width; } chat_msg[player][msgptr[player]] = 0; } //=========================================================================== // // CT_ClearChatMessage // // Clears out the data for the chat message, but the player's message // is still saved in plrmsg. //=========================================================================== void CT_ClearChatMessage(int player) { memset(chat_msg[player], 0, MESSAGESIZE); msgptr[player] = 0; msglen[player] = 0; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/ct_chat.h000066400000000000000000000017341257432200600227660ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Chat mode stuff // #ifndef HEXEN_CT_CHAT_H #define HEXEN_CT_CHAT_H #define CT_PLR_GREEN 1 #define CT_PLR_YELLOW 2 #define CT_PLR_RED 3 #define CT_PLR_BLUE 4 #define CT_PLR_ALL 5 #define CT_KEY_GREEN 'g' #define CT_KEY_YELLOW 'y' #define CT_KEY_RED 'r' #define CT_KEY_BLUE 'b' #define CT_KEY_ALL 't' extern char *chat_macros[10]; #endif chocolate-doom-chocolate-doom-2.2.1/src/hexen/d_net.c000066400000000000000000000144421257432200600224450ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM Network game communication and protocol, // all OS independend parts. // #include #include "doomfeatures.h" #include "m_argv.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "i_videohr.h" #include "h2def.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" #include "w_checksum.h" #include "deh_main.h" #include "d_loop.h" ticcmd_t *netcmds; extern void H2_DoAdvanceDemo(void); extern void H2_ProcessEvents(void); extern void G_BuildTiccmd(ticcmd_t *cmd, int maketic); extern boolean G_CheckDemoStatus(void); extern boolean demorecording; // Called when a player leaves the game static void PlayerQuitGame(player_t *player) { static char exitmsg[80]; unsigned int player_num; player_num = player - players; M_StringCopy(exitmsg, "PLAYER 1 LEFT THE GAME", sizeof(exitmsg)); exitmsg[7] += player_num; P_SetMessage(&players[consoleplayer], exitmsg, true); S_StartSound(NULL, SFX_CHAT); playeringame[player_num] = false; // TODO: check if it is sensible to do this: if (demorecording) { G_CheckDemoStatus (); } } static void RunTic(ticcmd_t *cmds, boolean *ingame) { extern boolean advancedemo; unsigned int i; // Check for player quits. for (i = 0; i < maxplayers; ++i) { if (!demoplayback && playeringame[i] && !ingame[i]) { PlayerQuitGame(&players[i]); } } netcmds = cmds; // check that there are players in the game. if not, we cannot // run a tic. if (advancedemo) H2_DoAdvanceDemo (); G_Ticker (); } static loop_interface_t hexen_loop_interface = { H2_ProcessEvents, G_BuildTiccmd, RunTic, MN_Ticker }; // Load game settings from the specified structure and // set global variables. static void LoadGameSettings(net_gamesettings_t *settings) { unsigned int i; deathmatch = settings->deathmatch; ticdup = settings->ticdup; startepisode = settings->episode; startmap = settings->map; startskill = settings->skill; // TODO startloadgame = settings->loadgame; nomonsters = settings->nomonsters; respawnparm = settings->respawn_monsters; consoleplayer = settings->consoleplayer; for (i=0; inum_players; PlayerClass[i] = settings->player_classes[i]; if (PlayerClass[i] >= NUMCLASSES) { PlayerClass[i] = PCLASS_FIGHTER; } } } // Save the game settings from global variables to the specified // game settings structure. static void SaveGameSettings(net_gamesettings_t *settings) { // jhaley 20120715: Some parts of the structure are being left // uninitialized. If -class is not used on the command line, this // can lead to a crash in SB_Init due to player class == 0xCCCCCCCC. memset(settings, 0, sizeof(*settings)); // Fill in game settings structure with appropriate parameters // for the new game settings->deathmatch = deathmatch; settings->episode = startepisode; settings->map = startmap; settings->skill = startskill; // TODO settings->loadgame = startloadgame; settings->gameversion = exe_hexen_1_1; settings->nomonsters = nomonsters; settings->respawn_monsters = respawnparm; settings->timelimit = 0; settings->lowres_turn = false; } static void InitConnectData(net_connect_data_t *connect_data) { int i; // // Connect data // // Game type fields: connect_data->gamemode = gamemode; connect_data->gamemission = hexen; connect_data->lowres_turn = false; connect_data->drone = false; connect_data->max_players = maxplayers; //! // @category net // @arg // // Specify player class: 0=fighter, 1=cleric, 2=mage, 3=pig. // i = M_CheckParmWithArgs("-class", 1); if (i > 0) { connect_data->player_class = atoi(myargv[i + 1]); } else { connect_data->player_class = PCLASS_FIGHTER; } // Read checksums of our WAD directory and dehacked information W_Checksum(connect_data->wad_sha1sum); memset(connect_data->deh_sha1sum, 0, sizeof(sha1_digest_t)); connect_data->is_freedoom = 0; } void D_ConnectNetGame(void) { net_connect_data_t connect_data; InitConnectData(&connect_data); netgame = D_InitNetGame(&connect_data); //! // @category net // // Start the game playing as though in a netgame with a single // player. This can also be used to play back single player netgame // demos. // if (M_CheckParm("-solo-net") > 0) { netgame = true; } } static boolean StartupProgress(int now_ready, int total) { static int ready = 0; while (ready < now_ready) { ST_NetProgress(); ++ready; } ready = now_ready; // Allow the user to hit escape during netgame startup to abort. return !I_CheckAbortHR(); } // // D_CheckNetGame // Works out player numbers among the net participants // void D_CheckNetGame(void) { net_gamesettings_t settings; D_RegisterLoopCallbacks(&hexen_loop_interface); if (netgame) { autostart = true; } SaveGameSettings(&settings); D_StartNetGame(&settings, StartupProgress); LoadGameSettings(&settings); // Finish netgame progress on startup screen. if (netgame) { StartupProgress(settings.num_players, settings.num_players); ST_NetDone(); } } //========================================================================== // // NET_SendFrags // //========================================================================== void NET_SendFrags(player_t * player) { // Not sure what this is intended for. Unused? } chocolate-doom-chocolate-doom-2.2.1/src/hexen/f_finale.c000066400000000000000000000244371257432200600231240ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "i_system.h" #include "i_video.h" #include "p_local.h" #include "s_sound.h" #include #include "v_video.h" #include "i_swap.h" // MACROS ------------------------------------------------------------------ #define TEXTSPEED 3 #define TEXTWAIT 250 // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void TextWrite(void); static void DrawPic(void); static void InitializeFade(boolean fadeIn); static void DeInitializeFade(void); static void FadePic(void); static char *GetFinaleText(int sequence); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern boolean automapactive; extern boolean viewactive; // PUBLIC DATA DECLARATIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int FinaleStage; static int FinaleCount; static int FinaleEndCount; static int FinaleLumpNum; static int FontABaseLump; static char *FinaleText; static fixed_t *Palette; static fixed_t *PaletteDelta; static byte *RealPalette; // CODE -------------------------------------------------------------------- //=========================================================================== // // F_StartFinale // //=========================================================================== void F_StartFinale(void) { gameaction = ga_nothing; gamestate = GS_FINALE; viewactive = false; automapactive = false; P_ClearMessage(&players[consoleplayer]); FinaleStage = 0; FinaleCount = 0; FinaleText = GetFinaleText(0); FinaleEndCount = 70; FinaleLumpNum = W_GetNumForName("FINALE1"); FontABaseLump = W_GetNumForName("FONTA_S") + 1; InitializeFade(1); // S_ChangeMusic(mus_victor, true); S_StartSongName("hall", false); // don't loop the song } //=========================================================================== // // F_Responder // //=========================================================================== boolean F_Responder(event_t * event) { return false; } //=========================================================================== // // F_Ticker // //=========================================================================== void F_Ticker(void) { FinaleCount++; if (FinaleStage < 5 && FinaleCount >= FinaleEndCount) { FinaleCount = 0; FinaleStage++; switch (FinaleStage) { case 1: // Text 1 FinaleEndCount = strlen(FinaleText) * TEXTSPEED + TEXTWAIT; break; case 2: // Pic 2, Text 2 FinaleText = GetFinaleText(1); FinaleEndCount = strlen(FinaleText) * TEXTSPEED + TEXTWAIT; FinaleLumpNum = W_GetNumForName("FINALE2"); S_StartSongName("orb", false); break; case 3: // Pic 2 -- Fade out FinaleEndCount = 70; DeInitializeFade(); InitializeFade(0); break; case 4: // Pic 3 -- Fade in FinaleLumpNum = W_GetNumForName("FINALE3"); FinaleEndCount = 71; DeInitializeFade(); InitializeFade(1); S_StartSongName("chess", true); break; case 5: // Pic 3 , Text 3 FinaleText = GetFinaleText(2); DeInitializeFade(); break; default: break; } return; } if (FinaleStage == 0 || FinaleStage == 3 || FinaleStage == 4) { FadePic(); } } //=========================================================================== // // TextWrite // //=========================================================================== static void TextWrite(void) { int count; char *ch; int c; int cx, cy; patch_t *w; memcpy(I_VideoBuffer, W_CacheLumpNum(FinaleLumpNum, PU_CACHE), SCREENWIDTH * SCREENHEIGHT); if (FinaleStage == 5) { // Chess pic, draw the correct character graphic if (netgame) { V_DrawPatch(20, 0, W_CacheLumpName("chessall", PU_CACHE)); } else if (PlayerClass[consoleplayer]) { V_DrawPatch(60, 0, W_CacheLumpNum(W_GetNumForName("chessc") + PlayerClass[consoleplayer] - 1, PU_CACHE)); } } // Draw the actual text if (FinaleStage == 5) { cy = 135; } else { cy = 5; } cx = 20; ch = FinaleText; count = (FinaleCount - 10) / TEXTSPEED; if (count < 0) { count = 0; } for (; count; count--) { c = *ch++; if (!c) { break; } if (c == '\n') { cx = 20; cy += 9; continue; } if (c < 32) { continue; } c = toupper(c); if (c == 32) { cx += 5; continue; } w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); if (cx + SHORT(w->width) > SCREENWIDTH) { break; } V_DrawPatch(cx, cy, w); cx += SHORT(w->width); } } //=========================================================================== // // InitializeFade // //=========================================================================== static void InitializeFade(boolean fadeIn) { unsigned i; Palette = Z_Malloc(768 * sizeof(fixed_t), PU_STATIC, 0); PaletteDelta = Z_Malloc(768 * sizeof(fixed_t), PU_STATIC, 0); RealPalette = Z_Malloc(768 * sizeof(byte), PU_STATIC, 0); if (fadeIn) { memset(RealPalette, 0, 768 * sizeof(byte)); for (i = 0; i < 768; i++) { Palette[i] = 0; PaletteDelta[i] = FixedDiv((*((byte *) W_CacheLumpName("playpal", PU_CACHE) + i)) << FRACBITS, 70 * FRACUNIT); } } else { for (i = 0; i < 768; i++) { RealPalette[i] = *((byte *) W_CacheLumpName("playpal", PU_CACHE) + i); Palette[i] = RealPalette[i] << FRACBITS; PaletteDelta[i] = FixedDiv(Palette[i], -70 * FRACUNIT); } } I_SetPalette(RealPalette); } //=========================================================================== // // DeInitializeFade // //=========================================================================== static void DeInitializeFade(void) { Z_Free(Palette); Z_Free(PaletteDelta); Z_Free(RealPalette); } //=========================================================================== // // FadePic // //=========================================================================== static void FadePic(void) { unsigned i; for (i = 0; i < 768; i++) { Palette[i] += PaletteDelta[i]; RealPalette[i] = Palette[i] >> FRACBITS; } I_SetPalette(RealPalette); } //=========================================================================== // // DrawPic // //=========================================================================== static void DrawPic(void) { memcpy(I_VideoBuffer, W_CacheLumpNum(FinaleLumpNum, PU_CACHE), SCREENWIDTH * SCREENHEIGHT); if (FinaleStage == 4 || FinaleStage == 5) { // Chess pic, draw the correct character graphic if (netgame) { V_DrawPatch(20, 0, W_CacheLumpName("chessall", PU_CACHE)); } else if (PlayerClass[consoleplayer]) { V_DrawPatch(60, 0, W_CacheLumpNum(W_GetNumForName("chessc") + PlayerClass[consoleplayer] - 1, PU_CACHE)); } } } //=========================================================================== // // F_Drawer // //=========================================================================== void F_Drawer(void) { switch (FinaleStage) { case 0: // Fade in initial finale screen DrawPic(); break; case 1: case 2: TextWrite(); break; case 3: // Fade screen out DrawPic(); break; case 4: // Fade in chess screen DrawPic(); break; case 5: TextWrite(); break; } UpdateState |= I_FULLSCRN; } //========================================================================== // // GetFinaleText // //========================================================================== static char *GetFinaleText(int sequence) { char *msgLumpName; int msgSize; int msgLump; static char *winMsgLumpNames[] = { "win1msg", "win2msg", "win3msg" }; msgLumpName = winMsgLumpNames[sequence]; msgLump = W_GetNumForName(msgLumpName); msgSize = W_LumpLength(msgLump); if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE) { I_Error("Finale message too long (%s)", msgLumpName); } W_ReadLump(msgLump, ClusterMessage); ClusterMessage[msgSize] = 0; // Append terminator return ClusterMessage; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/g_game.c000066400000000000000000001347271257432200600226040ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "m_random.h" #include "h2def.h" #include "s_sound.h" #include "doomkeys.h" #include "i_video.h" #include "i_system.h" #include "i_timer.h" #include "m_controls.h" #include "m_misc.h" #include "p_local.h" #include "v_video.h" #define AM_STARTKEY 9 // External functions extern void R_InitSky(int map); extern void P_PlayerNextArtifact(player_t * player); // Functions boolean G_CheckDemoStatus(void); void G_ReadDemoTiccmd(ticcmd_t * cmd); void G_WriteDemoTiccmd(ticcmd_t * cmd); void G_DoReborn(int playernum); void G_DoLoadLevel(void); void G_DoInitNew(void); void G_DoNewGame(void); void G_DoPlayDemo(void); void G_DoTeleportNewMap(void); void G_DoCompleted(void); void G_DoVictory(void); void G_DoWorldDone(void); void G_DoSaveGame(void); void G_DoSingleReborn(void); void H2_PageTicker(void); void H2_AdvanceDemo(void); extern boolean mn_SuicideConsole; gameaction_t gameaction; gamestate_t gamestate; skill_t gameskill; //boolean respawnmonsters; int gameepisode; int gamemap; int prevmap; boolean paused; boolean sendpause; // send a pause event next tic boolean sendsave; // send a save event next tic boolean usergame; // ok to save / end game boolean timingdemo; // if true, exit with report on completion int starttime; // for comparative timing purposes boolean viewactive; boolean deathmatch; // only if started as net death boolean netgame; // only true if packets are broadcast boolean playeringame[MAXPLAYERS]; player_t players[MAXPLAYERS]; pclass_t PlayerClass[MAXPLAYERS]; // Position indicator for cooperative net-play reborn int RebornPosition; int consoleplayer; // player taking events and displaying int displayplayer; // view being displayed int levelstarttic; // gametic at level start char demoname[32]; boolean demorecording; boolean demoplayback; byte *demobuffer, *demo_p; boolean singledemo; // quit after playing a demo from cmdline boolean precache = true; // if true, load all graphics at start // TODO: Hexen uses 16-bit shorts for consistancy? byte consistancy[MAXPLAYERS][BACKUPTICS]; int mouseSensitivity = 5; int LeaveMap; static int LeavePosition; //#define MAXPLMOVE 0x32 // Old Heretic Max move fixed_t MaxPlayerMove[NUMCLASSES] = { 0x3C, 0x32, 0x2D, 0x31 }; fixed_t forwardmove[NUMCLASSES][2] = { {0x1D, 0x3C}, {0x19, 0x32}, {0x16, 0x2E}, {0x18, 0x31} }; fixed_t sidemove[NUMCLASSES][2] = { {0x1B, 0x3B}, {0x18, 0x28}, {0x15, 0x25}, {0x17, 0x27} }; fixed_t angleturn[3] = { 640, 1280, 320 }; // + slow turn static int *weapon_keys[] = { &key_weapon1, &key_weapon2, &key_weapon3, &key_weapon4, }; static int next_weapon = 0; #define SLOWTURNTICS 6 #define NUMKEYS 256 boolean gamekeydown[NUMKEYS]; int turnheld; // for accelerative turning int lookheld; boolean mousearray[MAX_MOUSE_BUTTONS + 1]; boolean *mousebuttons = &mousearray[1]; // allow [-1] int mousex, mousey; // mouse values are used once int dclicktime, dclickstate, dclicks; int dclicktime2, dclickstate2, dclicks2; #define MAX_JOY_BUTTONS 20 int joyxmove, joyymove; // joystick values are repeated int joystrafemove; boolean joyarray[MAX_JOY_BUTTONS + 1]; boolean *joybuttons = &joyarray[1]; // allow [-1] int savegameslot; char savedescription[32]; int inventoryTics; // haleyjd: removed externdriver crap static skill_t TempSkill; static int TempEpisode; static int TempMap; boolean testcontrols = false; int testcontrols_mousespeed; //============================================================================= /* ==================== = = G_BuildTiccmd = = Builds a ticcmd from all of the available inputs or reads it from the = demo buffer. = If recording a demo, write it out ==================== */ extern boolean inventory; boolean usearti = true; void G_BuildTiccmd(ticcmd_t *cmd, int maketic) { int i; boolean strafe, bstrafe; int speed, tspeed, lspeed; int forward, side; int look, arti; int flyheight; int pClass; extern boolean artiskip; // haleyjd: removed externdriver crap pClass = players[consoleplayer].class; memset(cmd, 0, sizeof(*cmd)); // cmd->consistancy = // consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS]; cmd->consistancy = consistancy[consoleplayer][maketic % BACKUPTICS]; //printf ("cons: %i\n",cmd->consistancy); strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; // Allow joybspeed hack. speed = key_speed >= NUMKEYS || joybspeed >= MAX_JOY_BUTTONS || gamekeydown[key_speed] || joybuttons[joybspeed]; // haleyjd: removed externdriver crap forward = side = look = arti = flyheight = 0; // // use two stage accelerative turning on the keyboard and joystick // if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left]) turnheld += ticdup; else turnheld = 0; if (turnheld < SLOWTURNTICS) tspeed = 2; // slow turn else tspeed = speed; if (gamekeydown[key_lookdown] || gamekeydown[key_lookup]) { lookheld += ticdup; } else { lookheld = 0; } if (lookheld < SLOWTURNTICS) { lspeed = 1; // 3; } else { lspeed = 2; // 5; } // // let movement keys cancel each other out // if (strafe) { if (gamekeydown[key_right]) { side += sidemove[pClass][speed]; } if (gamekeydown[key_left]) { side -= sidemove[pClass][speed]; } if (joyxmove > 0) { side += sidemove[pClass][speed]; } if (joyxmove < 0) { side -= sidemove[pClass][speed]; } } else { if (gamekeydown[key_right]) cmd->angleturn -= angleturn[tspeed]; if (gamekeydown[key_left]) cmd->angleturn += angleturn[tspeed]; if (joyxmove > 0) cmd->angleturn -= angleturn[tspeed]; if (joyxmove < 0) cmd->angleturn += angleturn[tspeed]; } if (gamekeydown[key_up]) { forward += forwardmove[pClass][speed]; } if (gamekeydown[key_down]) { forward -= forwardmove[pClass][speed]; } if (joyymove < 0) { forward += forwardmove[pClass][speed]; } if (joyymove > 0) { forward -= forwardmove[pClass][speed]; } if (gamekeydown[key_straferight] || joystrafemove > 0 || joybuttons[joybstraferight]) { side += sidemove[pClass][speed]; } if (gamekeydown[key_strafeleft] || joystrafemove < 0 || joybuttons[joybstrafeleft]) { side -= sidemove[pClass][speed]; } // Look up/down/center keys if (gamekeydown[key_lookup]) { look = lspeed; } if (gamekeydown[key_lookdown]) { look = -lspeed; } // haleyjd: removed externdriver crap if (gamekeydown[key_lookcenter]) { look = TOCENTER; } // haleyjd: removed externdriver crap // Fly up/down/drop keys if (gamekeydown[key_flyup]) { flyheight = 5; // note that the actual flyheight will be twice this } if (gamekeydown[key_flydown]) { flyheight = -5; } if (gamekeydown[key_flycenter]) { flyheight = TOCENTER; // haleyjd: removed externdriver crap look = TOCENTER; } // Use artifact key if (gamekeydown[key_useartifact]) { if (gamekeydown[key_speed] && artiskip) { if (players[consoleplayer].inventory[inv_ptr].type != arti_none) { // Skip an artifact gamekeydown[key_useartifact] = false; P_PlayerNextArtifact(&players[consoleplayer]); } } else { if (inventory) { players[consoleplayer].readyArtifact = players[consoleplayer].inventory[inv_ptr].type; inventory = false; cmd->arti = 0; usearti = false; } else if (usearti) { cmd->arti |= players[consoleplayer].inventory[inv_ptr]. type & AFLAG_MASK; usearti = false; } } } if (gamekeydown[key_jump] || mousebuttons[mousebjump] || joybuttons[joybjump]) { cmd->arti |= AFLAG_JUMP; } if (mn_SuicideConsole) { cmd->arti |= AFLAG_SUICIDE; mn_SuicideConsole = false; } // Artifact hot keys if (gamekeydown[key_arti_all] && !cmd->arti) { gamekeydown[key_arti_all] = false; // Use one of each artifact cmd->arti = NUMARTIFACTS; } else if (gamekeydown[key_arti_health] && !cmd->arti && (players[consoleplayer].mo->health < MAXHEALTH)) { gamekeydown[key_arti_health] = false; cmd->arti = arti_health; } else if (gamekeydown[key_arti_poisonbag] && !cmd->arti) { gamekeydown[key_arti_poisonbag] = false; cmd->arti = arti_poisonbag; } else if (gamekeydown[key_arti_blastradius] && !cmd->arti) { gamekeydown[key_arti_blastradius] = false; cmd->arti = arti_blastradius; } else if (gamekeydown[key_arti_teleport] && !cmd->arti) { gamekeydown[key_arti_teleport] = false; cmd->arti = arti_teleport; } else if (gamekeydown[key_arti_teleportother] && !cmd->arti) { gamekeydown[key_arti_teleportother] = false; cmd->arti = arti_teleportother; } else if (gamekeydown[key_arti_egg] && !cmd->arti) { gamekeydown[key_arti_egg] = false; cmd->arti = arti_egg; } else if (gamekeydown[key_arti_invulnerability] && !cmd->arti && !players[consoleplayer].powers[pw_invulnerability]) { gamekeydown[key_arti_invulnerability] = false; cmd->arti = arti_invulnerability; } // // buttons // cmd->chatchar = CT_dequeueChatChar(); if (gamekeydown[key_fire] || mousebuttons[mousebfire] || joybuttons[joybfire]) cmd->buttons |= BT_ATTACK; if (gamekeydown[key_use] || joybuttons[joybuse] || mousebuttons[mousebuse]) { cmd->buttons |= BT_USE; dclicks = 0; // clear double clicks if hit use button } // Weapon cycling. Switch to previous or next weapon. // (Disabled when player is a pig). if (gamestate == GS_LEVEL && players[consoleplayer].morphTics == 0 && next_weapon != 0) { int start_i; if (players[consoleplayer].pendingweapon == WP_NOCHANGE) { i = players[consoleplayer].readyweapon; } else { i = players[consoleplayer].pendingweapon; } // Don't loop forever. start_i = i; do { i = (i + next_weapon + NUMWEAPONS) % NUMWEAPONS; } while (i != start_i && !players[consoleplayer].weaponowned[i]); cmd->buttons |= BT_CHANGE; cmd->buttons |= i << BT_WEAPONSHIFT; } else { for (i=0; ibuttons |= BT_CHANGE; cmd->buttons |= i< 1) { dclickstate = mousebuttons[mousebforward]; if (dclickstate) dclicks++; if (dclicks == 2) { cmd->buttons |= BT_USE; dclicks = 0; } else dclicktime = 0; } else { dclicktime += ticdup; if (dclicktime > 20) { dclicks = 0; dclickstate = 0; } } // // strafe double click // bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; if (bstrafe != dclickstate2 && dclicktime2 > 1) { dclickstate2 = bstrafe; if (dclickstate2) dclicks2++; if (dclicks2 == 2) { cmd->buttons |= BT_USE; dclicks2 = 0; } else dclicktime2 = 0; } else { dclicktime2 += ticdup; if (dclicktime2 > 20) { dclicks2 = 0; dclickstate2 = 0; } } if (strafe) { side += mousex * 2; } else { cmd->angleturn -= mousex * 0x8; } if (mousex == 0) { testcontrols_mousespeed = 0; } forward += mousey; mousex = mousey = 0; if (forward > MaxPlayerMove[pClass]) { forward = MaxPlayerMove[pClass]; } else if (forward < -MaxPlayerMove[pClass]) { forward = -MaxPlayerMove[pClass]; } if (side > MaxPlayerMove[pClass]) { side = MaxPlayerMove[pClass]; } else if (side < -MaxPlayerMove[pClass]) { side = -MaxPlayerMove[pClass]; } if (players[consoleplayer].powers[pw_speed] && !players[consoleplayer].morphTics) { // Adjust for a player with a speed artifact forward = (3 * forward) >> 1; side = (3 * side) >> 1; } cmd->forwardmove += forward; cmd->sidemove += side; if (players[consoleplayer].playerstate == PST_LIVE) { if (look < 0) { look += 16; } cmd->lookfly = look; } if (flyheight < 0) { flyheight += 16; } cmd->lookfly |= flyheight << 4; // // special buttons // if (sendpause) { sendpause = false; cmd->buttons = BT_SPECIAL | BTS_PAUSE; } if (sendsave) { sendsave = false; cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot << BTS_SAVESHIFT); } } /* ============== = = G_DoLoadLevel = ============== */ void G_DoLoadLevel(void) { int i; levelstarttic = gametic; // for time calculation gamestate = GS_LEVEL; for (i = 0; i < maxplayers; i++) { if (playeringame[i] && players[i].playerstate == PST_DEAD) players[i].playerstate = PST_REBORN; memset(players[i].frags, 0, sizeof(players[i].frags)); } SN_StopAllSequences(); P_SetupLevel(gameepisode, gamemap, 0, gameskill); displayplayer = consoleplayer; // view the guy you are playing starttime = I_GetTime(); gameaction = ga_nothing; Z_CheckHeap(); // // clear cmd building stuff // memset(gamekeydown, 0, sizeof(gamekeydown)); joyxmove = joyymove = joystrafemove = 0; mousex = mousey = 0; sendpause = sendsave = paused = false; memset(mousearray, 0, sizeof(mousearray)); memset(joyarray, 0, sizeof(joyarray)); if (testcontrols) { P_SetMessage(&players[consoleplayer], "PRESS ESCAPE TO QUIT.", false); } } static void SetJoyButtons(unsigned int buttons_mask) { int i; for (i=0; itype == ev_keyup && ev->data1 == key_useartifact) { // flag to denote that it's okay to use an artifact if (!inventory) { plr->readyArtifact = plr->inventory[inv_ptr].type; } usearti = true; } // Check for spy mode player cycle if (gamestate == GS_LEVEL && ev->type == ev_keydown && ev->data1 == key_spy && !deathmatch) { // Cycle the display player do { displayplayer++; if (displayplayer == maxplayers) { displayplayer = 0; } } while (!playeringame[displayplayer] && displayplayer != consoleplayer); return (true); } if (CT_Responder(ev)) { // Chat ate the event return (true); } if (gamestate == GS_LEVEL) { if (SB_Responder(ev)) { // Status bar ate the event return (true); } if (AM_Responder(ev)) { // Automap ate the event return (true); } } if (ev->type == ev_mouse) { testcontrols_mousespeed = abs(ev->data2); } if (ev->type == ev_keydown && ev->data1 == key_prevweapon) { next_weapon = -1; } else if (ev->type == ev_keydown && ev->data1 == key_nextweapon) { next_weapon = 1; } switch (ev->type) { case ev_keydown: if (ev->data1 == key_invleft) { inventoryTics = 5 * 35; if (!inventory) { inventory = true; break; } inv_ptr--; if (inv_ptr < 0) { inv_ptr = 0; } else { curpos--; if (curpos < 0) { curpos = 0; } } return (true); } if (ev->data1 == key_invright) { inventoryTics = 5 * 35; if (!inventory) { inventory = true; break; } inv_ptr++; if (inv_ptr >= plr->inventorySlotNum) { inv_ptr--; if (inv_ptr < 0) inv_ptr = 0; } else { curpos++; if (curpos > 6) { curpos = 6; } } return (true); } if (ev->data1 == key_pause && !MenuActive) { sendpause = true; return (true); } if (ev->data1 < NUMKEYS) { gamekeydown[ev->data1] = true; } return (true); // eat key down events case ev_keyup: if (ev->data1 < NUMKEYS) { gamekeydown[ev->data1] = false; } return (false); // always let key up events filter down case ev_mouse: SetMouseButtons(ev->data1); mousex = ev->data2 * (mouseSensitivity + 5) / 10; mousey = ev->data3 * (mouseSensitivity + 5) / 10; return (true); // eat events case ev_joystick: SetJoyButtons(ev->data1); joyxmove = ev->data2; joyymove = ev->data3; joystrafemove = ev->data4; return (true); // eat events default: break; } return (false); } //========================================================================== // // G_Ticker // //========================================================================== void G_Ticker(void) { int i, buf; ticcmd_t *cmd = NULL; // // do player reborns if needed // for (i = 0; i < maxplayers; i++) if (playeringame[i] && players[i].playerstate == PST_REBORN) G_DoReborn(i); // // do things to change the game state // while (gameaction != ga_nothing) { switch (gameaction) { case ga_loadlevel: G_DoLoadLevel(); break; case ga_initnew: G_DoInitNew(); break; case ga_newgame: G_DoNewGame(); break; case ga_loadgame: Draw_LoadIcon(); G_DoLoadGame(); break; case ga_savegame: Draw_SaveIcon(); G_DoSaveGame(); break; case ga_singlereborn: G_DoSingleReborn(); break; case ga_playdemo: G_DoPlayDemo(); break; case ga_screenshot: V_ScreenShot("HEXEN%02i.%s"); P_SetMessage(&players[consoleplayer], "SCREEN SHOT", false); gameaction = ga_nothing; break; case ga_leavemap: Draw_TeleportIcon(); G_DoTeleportNewMap(); break; case ga_completed: G_DoCompleted(); break; case ga_worlddone: G_DoWorldDone(); break; case ga_victory: F_StartFinale(); break; default: break; } } // // get commands, check consistancy, and build new consistancy check // //buf = gametic%BACKUPTICS; buf = (gametic / ticdup) % BACKUPTICS; for (i = 0; i < maxplayers; i++) if (playeringame[i]) { cmd = &players[i].cmd; memcpy(cmd, &netcmds[i], sizeof(ticcmd_t)); if (demoplayback) G_ReadDemoTiccmd(cmd); if (demorecording) G_WriteDemoTiccmd(cmd); if (netgame && !(gametic % ticdup)) { if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy) { I_Error("consistency failure (%i should be %i)", cmd->consistancy, consistancy[i][buf]); } if (players[i].mo) consistancy[i][buf] = players[i].mo->x; else consistancy[i][buf] = rndindex; } } // // check for special buttons // for (i = 0; i < maxplayers; i++) if (playeringame[i]) { if (players[i].cmd.buttons & BT_SPECIAL) { switch (players[i].cmd.buttons & BT_SPECIALMASK) { case BTS_PAUSE: paused ^= 1; if (paused) { S_PauseSound(); } else { S_ResumeSound(); } break; case BTS_SAVEGAME: if (!savedescription[0]) { if (netgame) { M_StringCopy(savedescription, "NET GAME", sizeof(savedescription)); } else { M_StringCopy(savedescription, "SAVE GAME", sizeof(savedescription)); } } savegameslot = (players[i].cmd. buttons & BTS_SAVEMASK) >> BTS_SAVESHIFT; gameaction = ga_savegame; break; } } } // turn inventory off after a certain amount of time if (inventory && !(--inventoryTics)) { players[consoleplayer].readyArtifact = players[consoleplayer].inventory[inv_ptr].type; inventory = false; cmd->arti = 0; } // // do main actions // // // do main actions // switch (gamestate) { case GS_LEVEL: P_Ticker(); SB_Ticker(); AM_Ticker(); CT_Ticker(); break; case GS_INTERMISSION: IN_Ticker(); break; case GS_FINALE: F_Ticker(); break; case GS_DEMOSCREEN: H2_PageTicker(); break; } } /* ============================================================================== PLAYER STRUCTURE FUNCTIONS also see P_SpawnPlayer in P_Things ============================================================================== */ //========================================================================== // // G_PlayerExitMap // // Called when the player leaves a map. // //========================================================================== void G_PlayerExitMap(int playerNumber) { int i; player_t *player; int flightPower; player = &players[playerNumber]; // if(deathmatch) // { // // Strip all but one of each type of artifact // for(i = 0; i < player->inventorySlotNum; i++) // { // player->inventory[i].count = 1; // } // player->artifactCount = player->inventorySlotNum; // } // else // Strip all current powers (retain flight) flightPower = player->powers[pw_flight]; memset(player->powers, 0, sizeof(player->powers)); player->powers[pw_flight] = flightPower; if (deathmatch) { player->powers[pw_flight] = 0; } else { if (P_GetMapCluster(gamemap) != P_GetMapCluster(LeaveMap)) { // Entering new cluster // Strip all keys player->keys = 0; // Strip flight artifact for (i = 0; i < 25; i++) { player->powers[pw_flight] = 0; P_PlayerUseArtifact(player, arti_fly); } player->powers[pw_flight] = 0; } } if (player->morphTics) { player->readyweapon = player->mo->special1.i; // Restore weapon player->morphTics = 0; } player->messageTics = 0; player->lookdir = 0; player->mo->flags &= ~MF_SHADOW; // Remove invisibility player->extralight = 0; // Remove weapon flashes player->fixedcolormap = 0; // Remove torch player->damagecount = 0; // No palette changes player->bonuscount = 0; player->poisoncount = 0; if (player == &players[consoleplayer]) { SB_state = -1; // refresh the status bar viewangleoffset = 0; } } //========================================================================== // // G_PlayerReborn // // Called after a player dies. Almost everything is cleared and // initialized. // //========================================================================== void G_PlayerReborn(int player) { player_t *p; int frags[MAXPLAYERS]; int killcount, itemcount, secretcount; unsigned int worldTimer; memcpy(frags, players[player].frags, sizeof(frags)); killcount = players[player].killcount; itemcount = players[player].itemcount; secretcount = players[player].secretcount; worldTimer = players[player].worldTimer; p = &players[player]; memset(p, 0, sizeof(*p)); memcpy(players[player].frags, frags, sizeof(players[player].frags)); players[player].killcount = killcount; players[player].itemcount = itemcount; players[player].secretcount = secretcount; players[player].worldTimer = worldTimer; players[player].class = PlayerClass[player]; p->usedown = p->attackdown = true; // don't do anything immediately p->playerstate = PST_LIVE; p->health = MAXHEALTH; p->readyweapon = p->pendingweapon = WP_FIRST; p->weaponowned[WP_FIRST] = true; p->messageTics = 0; p->lookdir = 0; localQuakeHappening[player] = false; if (p == &players[consoleplayer]) { SB_state = -1; // refresh the status bar inv_ptr = 0; // reset the inventory pointer curpos = 0; viewangleoffset = 0; } } /* ==================== = = G_CheckSpot = = Returns false if the player cannot be respawned at the given mapthing_t spot = because something is occupying it ==================== */ void P_SpawnPlayer(mapthing_t * mthing); boolean G_CheckSpot(int playernum, mapthing_t * mthing) { fixed_t x, y; subsector_t *ss; unsigned an; mobj_t *mo; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; players[playernum].mo->flags2 &= ~MF2_PASSMOBJ; if (!P_CheckPosition(players[playernum].mo, x, y)) { players[playernum].mo->flags2 |= MF2_PASSMOBJ; return false; } players[playernum].mo->flags2 |= MF2_PASSMOBJ; // spawn a teleport fog ss = R_PointInSubsector(x, y); an = ((unsigned) ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT; mo = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an], ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG); if (players[consoleplayer].viewz != 1) S_StartSound(mo, SFX_TELEPORT); // don't start sound on first frame return true; } /* ==================== = = G_DeathMatchSpawnPlayer = = Spawns a player at one of the random death match spots = called at level load and each death ==================== */ void G_DeathMatchSpawnPlayer(int playernum) { int i, j; int selections; selections = deathmatch_p - deathmatchstarts; // This check has been moved to p_setup.c:P_LoadThings() //if (selections < 8) // I_Error ("Only %i deathmatch spots, 8 required", selections); for (j = 0; j < 20; j++) { i = P_Random() % selections; if (G_CheckSpot(playernum, &deathmatchstarts[i])) { deathmatchstarts[i].type = playernum + 1; P_SpawnPlayer(&deathmatchstarts[i]); return; } } // no good spot, so the player will probably get stuck P_SpawnPlayer(&playerstarts[0][playernum]); } //========================================================================== // // G_DoReborn // //========================================================================== void G_DoReborn(int playernum) { int i; boolean oldWeaponowned[NUMWEAPONS]; int oldKeys; int oldPieces; boolean foundSpot; int bestWeapon; if (G_CheckDemoStatus()) { return; } if (!netgame) { if (SV_RebornSlotAvailable()) { // Use the reborn code if the slot is available gameaction = ga_singlereborn; } else { // Start a new game if there's no reborn info gameaction = ga_newgame; } } else { // Net-game players[playernum].mo->player = NULL; // Dissassociate the corpse if (deathmatch) { // Spawn at random spot if in death match G_DeathMatchSpawnPlayer(playernum); return; } // Cooperative net-play, retain keys and weapons oldKeys = players[playernum].keys; oldPieces = players[playernum].pieces; for (i = 0; i < NUMWEAPONS; i++) { oldWeaponowned[i] = players[playernum].weaponowned[i]; } foundSpot = false; if (G_CheckSpot(playernum, &playerstarts[RebornPosition][playernum])) { // Appropriate player start spot is open P_SpawnPlayer(&playerstarts[RebornPosition][playernum]); foundSpot = true; } else { // Try to spawn at one of the other player start spots for (i = 0; i < maxplayers; i++) { if (G_CheckSpot(playernum, &playerstarts[RebornPosition][i])) { // Found an open start spot // Fake as other player playerstarts[RebornPosition][i].type = playernum + 1; P_SpawnPlayer(&playerstarts[RebornPosition][i]); // Restore proper player type playerstarts[RebornPosition][i].type = i + 1; foundSpot = true; break; } } } if (foundSpot == false) { // Player's going to be inside something P_SpawnPlayer(&playerstarts[RebornPosition][playernum]); } // Restore keys and weapons players[playernum].keys = oldKeys; players[playernum].pieces = oldPieces; for (bestWeapon = 0, i = 0; i < NUMWEAPONS; i++) { if (oldWeaponowned[i]) { bestWeapon = i; players[playernum].weaponowned[i] = true; } } players[playernum].mana[MANA_1] = 25; players[playernum].mana[MANA_2] = 25; if (bestWeapon) { // Bring up the best weapon players[playernum].pendingweapon = bestWeapon; } } } void G_ScreenShot(void) { gameaction = ga_screenshot; } //========================================================================== // // G_StartNewInit // //========================================================================== void G_StartNewInit(void) { SV_InitBaseSlot(); SV_ClearRebornSlot(); P_ACSInitNewGame(); // Default the player start spot group to 0 RebornPosition = 0; } //========================================================================== // // G_StartNewGame // //========================================================================== void G_StartNewGame(skill_t skill) { int realMap; G_StartNewInit(); realMap = P_TranslateMap(1); if (realMap == -1) { realMap = 1; } G_InitNew(TempSkill, 1, realMap); } //========================================================================== // // G_TeleportNewMap // // Only called by the warp cheat code. Works just like normal map to map // teleporting, but doesn't do any interlude stuff. // //========================================================================== void G_TeleportNewMap(int map, int position) { gameaction = ga_leavemap; LeaveMap = map; LeavePosition = position; } //========================================================================== // // G_DoTeleportNewMap // //========================================================================== void G_DoTeleportNewMap(void) { SV_MapTeleport(LeaveMap, LeavePosition); gamestate = GS_LEVEL; gameaction = ga_nothing; RebornPosition = LeavePosition; } /* boolean secretexit; void G_ExitLevel (void) { secretexit = false; gameaction = ga_completed; } void G_SecretExitLevel (void) { secretexit = true; gameaction = ga_completed; } */ //========================================================================== // // G_Completed // // Starts intermission routine, which is used only during hub exits, // and DeathMatch games. //========================================================================== void G_Completed(int map, int position) { if (gamemode == shareware && map > 4) { P_SetMessage(&players[consoleplayer], "ACCESS DENIED -- DEMO", true); S_StartSound(NULL, SFX_CHAT); return; } gameaction = ga_completed; LeaveMap = map; LeavePosition = position; } void G_DoCompleted(void) { int i; gameaction = ga_nothing; if (G_CheckDemoStatus()) { return; } for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { G_PlayerExitMap(i); } } if (LeaveMap == -1 && LeavePosition == -1) { gameaction = ga_victory; return; } else { gamestate = GS_INTERMISSION; IN_Start(); } /* int i; static int afterSecret[3] = { 7, 5, 5 }; gameaction = ga_nothing; if(G_CheckDemoStatus()) { return; } for(i = 0; i < maxplayers; i++) { if(playeringame[i]) { G_PlayerFinishLevel(i); } } prevmap = gamemap; if(secretexit == true) { gamemap = 9; } else if(gamemap == 9) { // Finished secret level gamemap = afterSecret[gameepisode-1]; } else if(gamemap == 8) { gameaction = ga_victory; return; } else { gamemap++; } gamestate = GS_INTERMISSION; IN_Start(); */ } //============================================================================ // // G_WorldDone // //============================================================================ void G_WorldDone(void) { gameaction = ga_worlddone; } //============================================================================ // // G_DoWorldDone // //============================================================================ void G_DoWorldDone(void) { gamestate = GS_LEVEL; G_DoLoadLevel(); gameaction = ga_nothing; viewactive = true; } //========================================================================== // // G_DoSingleReborn // // Called by G_Ticker based on gameaction. Loads a game from the reborn // save slot. // //========================================================================== void G_DoSingleReborn(void) { gameaction = ga_nothing; SV_LoadGame(SV_GetRebornSlot()); SB_SetClassData(); } //========================================================================== // // G_LoadGame // // Can be called by the startup code or the menu task. // //========================================================================== static int GameLoadSlot; void G_LoadGame(int slot) { GameLoadSlot = slot; gameaction = ga_loadgame; } //========================================================================== // // G_DoLoadGame // // Called by G_Ticker based on gameaction. // //========================================================================== void G_DoLoadGame(void) { gameaction = ga_nothing; SV_LoadGame(GameLoadSlot); if (!netgame) { // Copy the base slot to the reborn slot SV_UpdateRebornSlot(); } SB_SetClassData(); } //========================================================================== // // G_SaveGame // // Called by the menu task. is a 24 byte text string. // //========================================================================== void G_SaveGame(int slot, char *description) { savegameslot = slot; M_StringCopy(savedescription, description, sizeof(savedescription)); sendsave = true; } //========================================================================== // // G_DoSaveGame // // Called by G_Ticker based on gameaction. // //========================================================================== void G_DoSaveGame(void) { SV_SaveGame(savegameslot, savedescription); gameaction = ga_nothing; savedescription[0] = 0; P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true); } //========================================================================== // // G_DeferredNewGame // //========================================================================== void G_DeferredNewGame(skill_t skill) { TempSkill = skill; gameaction = ga_newgame; } //========================================================================== // // G_DoNewGame // //========================================================================== void G_DoNewGame(void) { G_StartNewGame(TempSkill); gameaction = ga_nothing; } /* ==================== = = G_InitNew = = Can be called by the startup code or the menu task = consoleplayer, displayplayer, playeringame[] should be set ==================== */ void G_DeferedInitNew(skill_t skill, int episode, int map) { TempSkill = skill; TempEpisode = episode; TempMap = map; gameaction = ga_initnew; } void G_DoInitNew(void) { SV_InitBaseSlot(); G_InitNew(TempSkill, TempEpisode, TempMap); gameaction = ga_nothing; } void G_InitNew(skill_t skill, int episode, int map) { int i; if (paused) { paused = false; S_ResumeSound(); } if (skill < sk_baby) { skill = sk_baby; } if (skill > sk_nightmare) { skill = sk_nightmare; } if (map < 1) { map = 1; } if (map > 99) { map = 99; } M_ClearRandom(); // Force players to be initialized upon first level load for (i = 0; i < maxplayers; i++) { players[i].playerstate = PST_REBORN; players[i].worldTimer = 0; } // Set up a bunch of globals usergame = true; // will be set false if a demo paused = false; demorecording = false; demoplayback = false; viewactive = true; gameepisode = episode; gamemap = map; gameskill = skill; BorderNeedRefresh = true; // Initialize the sky R_InitSky(map); // Give one null ticcmd_t //gametic = 0; //maketic = 1; //for (i=0 ; iforwardmove = ((signed char) *demo_p++); cmd->sidemove = ((signed char) *demo_p++); cmd->angleturn = ((unsigned char) *demo_p++) << 8; cmd->buttons = (unsigned char) *demo_p++; cmd->lookfly = (unsigned char) *demo_p++; cmd->arti = (unsigned char) *demo_p++; } void G_WriteDemoTiccmd(ticcmd_t * cmd) { if (gamekeydown['q']) // press q to end demo recording G_CheckDemoStatus(); *demo_p++ = cmd->forwardmove; *demo_p++ = cmd->sidemove; *demo_p++ = cmd->angleturn >> 8; *demo_p++ = cmd->buttons; *demo_p++ = cmd->lookfly; *demo_p++ = cmd->arti; demo_p -= 6; G_ReadDemoTiccmd(cmd); // make SURE it is exactly the same } /* =================== = = G_RecordDemo = =================== */ void G_RecordDemo(skill_t skill, int numplayers, int episode, int map, char *name) { int i; G_InitNew(skill, episode, map); usergame = false; M_StringCopy(demoname, name, sizeof(demoname)); M_StringConcat(demoname, ".lmp", sizeof(demoname)); demobuffer = demo_p = Z_Malloc(0x20000, PU_STATIC, NULL); *demo_p++ = skill; *demo_p++ = episode; *demo_p++ = map; for (i = 0; i < maxplayers; i++) { *demo_p++ = playeringame[i]; *demo_p++ = PlayerClass[i]; } demorecording = true; } /* =================== = = G_PlayDemo = =================== */ char *defdemoname; void G_DeferedPlayDemo(char *name) { defdemoname = name; gameaction = ga_playdemo; } void G_DoPlayDemo(void) { skill_t skill; int i, episode, map; gameaction = ga_nothing; demobuffer = demo_p = W_CacheLumpName(defdemoname, PU_STATIC); skill = *demo_p++; episode = *demo_p++; map = *demo_p++; for (i = 0; i < maxplayers; i++) { playeringame[i] = *demo_p++; PlayerClass[i] = *demo_p++; } // Initialize world info, etc. G_StartNewInit(); precache = false; // don't spend a lot of time in loadlevel G_InitNew(skill, episode, map); precache = true; usergame = false; demoplayback = true; } /* =================== = = G_TimeDemo = =================== */ void G_TimeDemo(char *name) { skill_t skill; int episode, map, i; demobuffer = demo_p = W_CacheLumpName(name, PU_STATIC); skill = *demo_p++; episode = *demo_p++; map = *demo_p++; for (i = 0; i < maxplayers; i++) { playeringame[i] = *demo_p++; PlayerClass[i] = *demo_p++; } G_InitNew(skill, episode, map); usergame = false; demoplayback = true; timingdemo = true; singletics = true; } /* =================== = = G_CheckDemoStatus = = Called after a death or level completion to allow demos to be cleaned up = Returns true if a new demo loop action will take place =================== */ boolean G_CheckDemoStatus(void) { int endtime, realtics; if (timingdemo) { float fps; endtime = I_GetTime(); realtics = endtime - starttime; fps = ((float) gametic * TICRATE) / realtics; I_Error("timed %i gametics in %i realtics (%f fps)", gametic, realtics, fps); } if (demoplayback) { if (singledemo) I_Quit(); W_ReleaseLumpName(defdemoname); demoplayback = false; H2_AdvanceDemo(); return true; } if (demorecording) { *demo_p++ = DEMOMARKER; M_WriteFile(demoname, demobuffer, demo_p - demobuffer); Z_Free(demobuffer); demorecording = false; I_Error("Demo %s recorded", demoname); } return false; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/h2_main.c000066400000000000000000000614721257432200600226760ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ // haleyjd: removed WATCOMC #include #include #include #include "config.h" #include "doomfeatures.h" #include "h2def.h" #include "ct_chat.h" #include "d_iwad.h" #include "d_mode.h" #include "m_misc.h" #include "s_sound.h" #include "i_joystick.h" #include "i_system.h" #include "i_timer.h" #include "m_argv.h" #include "m_config.h" #include "m_controls.h" #include "net_client.h" #include "p_local.h" #include "v_video.h" #include "w_main.h" // MACROS ------------------------------------------------------------------ #define MAXWADFILES 20 #define CT_KEY_BLUE 'b' #define CT_KEY_RED 'r' #define CT_KEY_YELLOW 'y' #define CT_KEY_GREEN 'g' #define CT_KEY_PLAYER5 'j' // Jade #define CT_KEY_PLAYER6 'w' // White #define CT_KEY_PLAYER7 'h' // Hazel #define CT_KEY_PLAYER8 'p' // Purple #define CT_KEY_ALL 't' // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void R_ExecuteSetViewSize(void); void D_ConnectNetGame(void); void D_CheckNetGame(void); boolean F_Responder(event_t * ev); void I_StartupKeyboard(void); void I_StartupJoystick(void); void I_ShutdownKeyboard(void); void S_InitScript(void); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- void H2_ProcessEvents(void); void H2_DoAdvanceDemo(void); void H2_AdvanceDemo(void); void H2_StartTitle(void); void H2_PageTicker(void); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void DrawMessage(void); static void PageDrawer(void); static void HandleArgs(void); static void CheckRecordFrom(void); static void DrawAndBlit(void); static void CreateSavePath(void); static void WarpCheck(void); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern boolean automapactive; extern boolean MenuActive; extern boolean askforquit; // PUBLIC DATA DEFINITIONS ------------------------------------------------- GameMode_t gamemode; char *gamedescription; char *iwadfile; static char demolumpname[9]; // Demo lump to start playing. boolean nomonsters; // checkparm of -nomonsters boolean respawnparm; // checkparm of -respawn boolean randomclass; // checkparm of -randclass boolean debugmode; // checkparm of -debug boolean ravpic; // checkparm of -ravpic boolean cdrom = false; // true if cd-rom mode active boolean cmdfrag; // true if a CMD_FRAG packet should be sent out boolean artiskip; // whether shift-enter skips an artifact int maxzone = 0x800000; // Maximum allocated for zone heap (8meg default) skill_t startskill; int startepisode; int startmap; boolean autostart; boolean advancedemo; FILE *debugfile; int UpdateState; int maxplayers = MAXPLAYERS; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int WarpMap; static int demosequence; static int pagetic; static char *pagename; // CODE -------------------------------------------------------------------- void D_BindVariables(void) { int i; M_ApplyPlatformDefaults(); I_BindVideoVariables(); I_BindJoystickVariables(); I_BindSoundVariables(); M_BindBaseControls(); M_BindMapControls(); M_BindMenuControls(); M_BindWeaponControls(); M_BindChatControls(MAXPLAYERS); M_BindHereticControls(); M_BindHexenControls(); key_multi_msgplayer[0] = CT_KEY_BLUE; key_multi_msgplayer[1] = CT_KEY_RED; key_multi_msgplayer[2] = CT_KEY_YELLOW; key_multi_msgplayer[3] = CT_KEY_GREEN; key_multi_msgplayer[4] = CT_KEY_PLAYER5; key_multi_msgplayer[5] = CT_KEY_PLAYER6; key_multi_msgplayer[6] = CT_KEY_PLAYER7; key_multi_msgplayer[7] = CT_KEY_PLAYER8; M_BindIntVariable("graphical_startup", &graphical_startup); M_BindIntVariable("mouse_sensitivity", &mouseSensitivity); M_BindIntVariable("sfx_volume", &snd_MaxVolume); M_BindIntVariable("music_volume", &snd_MusicVolume); M_BindIntVariable("messageson", &messageson); M_BindIntVariable("screenblocks", &screenblocks); M_BindIntVariable("snd_channels", &snd_Channels); M_BindStringVariable("savedir", &SavePath); // Multiplayer chat macros for (i=0; i<10; ++i) { char buf[12]; M_snprintf(buf, sizeof(buf), "chatmacro%i", i); M_BindStringVariable(buf, &chat_macros[i]); } } // Set the default directory where hub savegames are saved. static void D_SetDefaultSavePath(void) { SavePath = M_GetSaveGameDir("hexen.wad"); // If we are not using a savegame path (probably because we are on // Windows and not using a config dir), behave like Vanilla Hexen // and use hexndata/: if (!strcmp(SavePath, "")) { SavePath = malloc(10); M_snprintf(SavePath, 10, "hexndata%c", DIR_SEPARATOR); } } // The Mac version of the Hexen IWAD is different to the "normal" DOS // version - it doesn't include lumps used by the DOS DMX library. // This means that we can't do GUS or OPL emulation and need to apply // a workaround. static void AdjustForMacIWAD(void) { boolean adjust_music = false; switch (snd_musicdevice) { case SNDDEVICE_ADLIB: case SNDDEVICE_SB: adjust_music = W_CheckNumForName("GENMIDI") < 0; break; case SNDDEVICE_GUS: adjust_music = W_CheckNumForName("DMXGUS") < 0; break; default: break; } if (adjust_music) { printf("** Note: You appear to be using the Mac version of the Hexen\n" "** IWAD file. This is missing the lumps required for OPL or\n" "** GUS emulation. Your music configuration is being adjusted\n" "** to a different setting that won't cause the game to " "crash.\n"); snd_musicdevice = SNDDEVICE_GENMIDI; } } // // D_GrabMouseCallback // // Called to determine whether to grab the mouse pointer // static boolean D_GrabMouseCallback(void) { // when menu is active or game is paused, release the mouse if (MenuActive || paused) return false; // only grab mouse when playing levels (but not demos) return (gamestate == GS_LEVEL) && !advancedemo && !demoplayback; } // Message displayed when quitting Hexen static void D_HexenQuitMessage(void) { printf("\nHexen: Beyond Heretic\n"); } static void D_AddFile(char *filename) { printf(" adding %s\n", filename); W_AddFile(filename); } // Find out what version of Hexen is playing. void D_IdentifyVersion(void) { // The Hexen Shareware, ne 4 Level Demo Version, is missing the SKY1 lump // and uses the SKY2 lump instead. Let's use this fact and the missing // levels from MAP05 onward to identify it and set gamemode accordingly. if (W_CheckNumForName("SKY1") == -1 && W_CheckNumForName("MAP05") == -1 ) { gamemode = shareware; maxplayers = 4; } // The v1.0 IWAD file is missing a bunch of lumps that can cause the game // to crash, so we exit with an error if the user tries to play with it. // But we provide an override command line flag if they really want to // do it. //! // If provided, the check for the v1.0 IWAD file is disabled, even though // it will almost certainly cause the game to crash. // // @category compat // if (!M_ParmExists("-v10override") && gamemode != shareware && W_CheckNumForName("CLUS1MSG") < 0) { I_Error( "You are trying to use the Hexen v1.0 IWAD. This isn't\n" "supported by " PACKAGE_NAME ". Please upgrade to the v1.1\n" "IWAD file. See here for more information:\n" " http://www.doomworld.com/classicdoom/info/patches.php"); } } // Set the gamedescription string. void D_SetGameDescription(void) { /* NB: The 4 Level Demo Version actually prints a four-lined banner (and indeed waits for a keypress): Hexen: Beyond Heretic 4 Level Demo Version Press any key to continue. */ if (gamemode == shareware) { gamedescription = "Hexen: 4 Level Demo Version"; } else { gamedescription = "Hexen"; } } //========================================================================== // // H2_Main // //========================================================================== void InitMapMusicInfo(void); void D_DoomMain(void) { GameMission_t gamemission; int p; I_AtExit(D_HexenQuitMessage, false); startepisode = 1; autostart = false; startskill = sk_medium; startmap = 1; gamemode = commercial; I_PrintBanner(PACKAGE_STRING); // Initialize subsystems ST_Message("V_Init: allocate screens.\n"); V_Init(); // Load defaults before initing other systems ST_Message("M_LoadDefaults: Load system defaults.\n"); D_BindVariables(); #ifdef _WIN32 //! // @platform windows // @vanilla // // Save configuration data and savegames in c:\hexndata, // allowing play from CD. // cdrom = M_ParmExists("-cdrom"); #endif if (cdrom) { M_SetConfigDir("c:\\hexndata\\"); } else { M_SetConfigDir(NULL); } D_SetDefaultSavePath(); M_SetConfigFilenames("hexen.cfg", PROGRAM_PREFIX "hexen.cfg"); M_LoadDefaults(); I_AtExit(M_SaveDefaults, false); // Now that the savedir is loaded from .CFG, make sure it exists CreateSavePath(); ST_Message("Z_Init: Init zone memory allocation daemon.\n"); Z_Init(); // haleyjd: removed WATCOMC ST_Message("W_Init: Init WADfiles.\n"); iwadfile = D_FindIWAD(IWAD_MASK_HEXEN, &gamemission); if (iwadfile == NULL) { I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n" "one with the '-iwad' command line parameter."); } D_AddFile(iwadfile); W_CheckCorrectIWAD(hexen); D_IdentifyVersion(); D_SetGameDescription(); AdjustForMacIWAD(); HandleArgs(); I_PrintStartupBanner(gamedescription); ST_Message("MN_Init: Init menu system.\n"); MN_Init(); ST_Message("CT_Init: Init chat mode data.\n"); CT_Init(); InitMapMusicInfo(); // Init music fields in mapinfo ST_Message("S_InitScript\n"); S_InitScript(); ST_Message("SN_InitSequenceScript: Registering sound sequences.\n"); SN_InitSequenceScript(); ST_Message("I_Init: Setting up machine state.\n"); I_CheckIsScreensaver(); I_InitTimer(); I_InitJoystick(); I_InitSound(false); I_InitMusic(); #ifdef FEATURE_MULTIPLAYER ST_Message("NET_Init: Init networking subsystem.\n"); NET_Init(); #endif D_ConnectNetGame(); S_Init(); S_Start(); ST_Message("ST_Init: Init startup screen.\n"); ST_Init(); // Show version message now, so it's visible during R_Init() ST_Message("R_Init: Init Hexen refresh daemon"); R_Init(); ST_Message("\n"); //if (M_CheckParm("-net")) // ST_NetProgress(); // Console player found ST_Message("P_Init: Init Playloop state.\n"); P_Init(); // Check for command line warping. Follows P_Init() because the // MAPINFO.TXT script must be already processed. WarpCheck(); ST_Message("D_CheckNetGame: Checking network game status.\n"); D_CheckNetGame(); ST_Message("SB_Init: Loading patches.\n"); SB_Init(); ST_Done(); if (autostart) { ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n", WarpMap, P_GetMapName(startmap), startmap, startskill + 1); } CheckRecordFrom(); p = M_CheckParm("-record"); if (p && p < myargc - 1) { G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]); H2_GameLoop(); // Never returns } p = M_CheckParmWithArgs("-playdemo", 1); if (p) { singledemo = true; // Quit after one demo G_DeferedPlayDemo(demolumpname); H2_GameLoop(); // Never returns } p = M_CheckParmWithArgs("-timedemo", 1); if (p) { G_TimeDemo(demolumpname); H2_GameLoop(); // Never returns } //! // @arg // @vanilla // // Load the game in savegame slot s. // p = M_CheckParmWithArgs("-loadgame", 1); if (p) { G_LoadGame(atoi(myargv[p + 1])); } if (gameaction != ga_loadgame) { UpdateState |= I_FULLSCRN; BorderNeedRefresh = true; if (autostart || netgame) { G_StartNewInit(); G_InitNew(startskill, startepisode, startmap); } else { H2_StartTitle(); } } H2_GameLoop(); // Never returns } //========================================================================== // // HandleArgs // //========================================================================== static void HandleArgs(void) { int p; //! // @vanilla // // Disable monsters. // nomonsters = M_ParmExists("-nomonsters"); //! // @vanilla // // Monsters respawn after being killed. // respawnparm = M_ParmExists("-respawn"); //! // @vanilla // @category net // // In deathmatch mode, change a player's class each time the // player respawns. // randomclass = M_ParmExists("-randclass"); //! // @vanilla // // Take screenshots when F1 is pressed. // ravpic = M_ParmExists("-ravpic"); //! // @vanilla // // Don't allow artifacts to be used when the run key is held down. // artiskip = M_ParmExists("-artiskip"); debugmode = M_ParmExists("-debug"); //! // @vanilla // @category net // // Start a deathmatch game. // deathmatch = M_ParmExists("-deathmatch"); // currently broken or unused: cmdfrag = M_ParmExists("-cmdfrag"); // Check WAD file command line options W_ParseCommandLine(); //! // @vanilla // @arg // // Development option to specify path to level scripts. // p = M_CheckParmWithArgs("-scripts", 1); if (p) { sc_FileScripts = true; sc_ScriptsDir = myargv[p+1]; } //! // @arg // @vanilla // // Set the game skill, 1-5 (1: easiest, 5: hardest). A skill of // 0 disables all monsters. // p = M_CheckParmWithArgs("-skill", 1); if (p) { startskill = myargv[p+1][0] - '1'; autostart = true; } //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp. // p = M_CheckParmWithArgs("-playdemo", 1); if (!p) { //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp, determining the framerate // of the screen. // p = M_CheckParmWithArgs("-timedemo", 1); } if (p) { char *uc_filename; char file[256]; M_StringCopy(file, myargv[p+1], sizeof(file)); // With Vanilla Hexen you have to specify the file without // extension, but make that optional. uc_filename = strdup(myargv[p + 1]); M_ForceUppercase(uc_filename); if (!M_StringEndsWith(uc_filename, ".LMP")) { M_StringConcat(file, ".lmp", sizeof(file)); } free(uc_filename); if (W_AddFile(file) != NULL) { M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name, sizeof(demolumpname)); } else { // The file failed to load, but copy the original arg as a // demo name to make tricks like -playdemo demo1 possible. M_StringCopy(demolumpname, myargv[p+1], sizeof(demolumpname)); } ST_Message("Playing demo %s.\n", myargv[p+1]); } if (M_ParmExists("-testcontrols")) { autostart = true; testcontrols = true; } } //========================================================================== // // WarpCheck // //========================================================================== static void WarpCheck(void) { int p; int map; p = M_CheckParm("-warp"); if (p && p < myargc - 1) { WarpMap = atoi(myargv[p + 1]); map = P_TranslateMap(WarpMap); if (map == -1) { // Couldn't find real map number startmap = 1; ST_Message("-WARP: Invalid map number.\n"); } else { // Found a valid startmap startmap = map; autostart = true; } } else { WarpMap = 1; startmap = P_TranslateMap(1); if (startmap == -1) { startmap = 1; } } } //========================================================================== // // H2_GameLoop // //========================================================================== void H2_GameLoop(void) { if (M_CheckParm("-debugfile")) { char filename[20]; M_snprintf(filename, sizeof(filename), "debug%i.txt", consoleplayer); debugfile = fopen(filename, "w"); } I_SetWindowTitle(gamedescription); I_GraphicsCheckCommandLine(); I_SetGrabMouseCallback(D_GrabMouseCallback); I_InitGraphics(); while (1) { // Frame syncronous IO operations I_StartFrame(); // Process one or more tics // Will run at least one tic TryRunTics(); // Move positional sounds S_UpdateSounds(players[displayplayer].mo); DrawAndBlit(); } } //========================================================================== // // H2_ProcessEvents // // Send all the events of the given timestamp down the responder chain. // //========================================================================== void H2_ProcessEvents(void) { event_t *ev; for (;;) { ev = D_PopEvent(); if (ev == NULL) { break; } if (F_Responder(ev)) { continue; } if (MN_Responder(ev)) { continue; } G_Responder(ev); } } //========================================================================== // // DrawAndBlit // //========================================================================== static void DrawAndBlit(void) { // Change the view size if needed if (setsizeneeded) { R_ExecuteSetViewSize(); } // Do buffered drawing switch (gamestate) { case GS_LEVEL: if (!gametic) { break; } if (automapactive) { AM_Drawer(); } else { R_RenderPlayerView(&players[displayplayer]); } CT_Drawer(); UpdateState |= I_FULLVIEW; SB_Drawer(); break; case GS_INTERMISSION: IN_Drawer(); break; case GS_FINALE: F_Drawer(); break; case GS_DEMOSCREEN: PageDrawer(); break; } if (testcontrols) { V_DrawMouseSpeedBox(testcontrols_mousespeed); } if (paused && !MenuActive && !askforquit) { if (!netgame) { V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName("PAUSED", PU_CACHE)); } else { V_DrawPatch(160, 70, W_CacheLumpName("PAUSED", PU_CACHE)); } } // Draw current message DrawMessage(); // Draw Menu MN_Drawer(); // Send out any new accumulation NetUpdate(); // Flush buffered stuff to screen I_FinishUpdate(); } //========================================================================== // // DrawMessage // //========================================================================== static void DrawMessage(void) { player_t *player; player = &players[consoleplayer]; if (player->messageTics <= 0) { // No message return; } if (player->yellowMessage) { MN_DrTextAYellow(player->message, 160 - MN_TextAWidth(player->message) / 2, 1); } else { MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message) / 2, 1); } } //========================================================================== // // H2_PageTicker // //========================================================================== void H2_PageTicker(void) { if (--pagetic < 0) { H2_AdvanceDemo(); } } //========================================================================== // // PageDrawer // //========================================================================== static void PageDrawer(void) { V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE)); if (demosequence == 1) { V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE)); } UpdateState |= I_FULLSCRN; } //========================================================================== // // H2_AdvanceDemo // // Called after each demo or intro demosequence finishes. // //========================================================================== void H2_AdvanceDemo(void) { advancedemo = true; } //========================================================================== // // H2_DoAdvanceDemo // //========================================================================== void H2_DoAdvanceDemo(void) { players[consoleplayer].playerstate = PST_LIVE; // don't reborn advancedemo = false; usergame = false; // can't save/end game here paused = false; gameaction = ga_nothing; demosequence = (demosequence + 1) % 7; switch (demosequence) { case 0: pagetic = 280; gamestate = GS_DEMOSCREEN; pagename = "TITLE"; S_StartSongName("hexen", true); break; case 1: pagetic = 210; gamestate = GS_DEMOSCREEN; pagename = "TITLE"; break; case 2: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; G_DeferedPlayDemo("demo1"); break; case 3: pagetic = 200; gamestate = GS_DEMOSCREEN; pagename = "CREDIT"; break; case 4: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; G_DeferedPlayDemo("demo2"); break; case 5: pagetic = 200; gamestate = GS_DEMOSCREEN; pagename = "CREDIT"; break; case 6: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; G_DeferedPlayDemo("demo3"); break; } } //========================================================================== // // H2_StartTitle // //========================================================================== void H2_StartTitle(void) { gameaction = ga_nothing; demosequence = -1; H2_AdvanceDemo(); } //========================================================================== // // CheckRecordFrom // // -recordfrom // //========================================================================== static void CheckRecordFrom(void) { int p; p = M_CheckParm("-recordfrom"); if (!p || p > myargc - 2) { // Bad args return; } G_LoadGame(atoi(myargv[p + 1])); G_DoLoadGame(); // Load the gameskill etc info from savegame G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]); H2_GameLoop(); // Never returns } // haleyjd: removed WATCOMC /* void CleanExit(void) { union REGS regs; I_ShutdownKeyboard(); regs.x.eax = 0x3; int386(0x10, ®s, ®s); printf("Exited from HEXEN: Beyond Heretic.\n"); exit(1); } */ //========================================================================== // // CreateSavePath // //========================================================================== static void CreateSavePath(void) { M_MakeDirectory(SavePath); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/h2def.h000066400000000000000000000703231257432200600223510ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __H2DEF__ #define __H2DEF__ #include #include #include //#include #include "st_start.h" // haleyjd: removed WATCOMC // ticcmd: #include "d_ticcmd.h" // events #include "d_event.h" // gamemode/mission #include "d_mode.h" // for fixed_t: #include "m_fixed.h" // angle definitions: #include "tables.h" #include "d_loop.h" #include "net_defs.h" #define HEXEN_VERSION 110 #define HEXEN_VERSION_TEXT "v1.1" // if rangecheck is undefined, most parameter validation debugging code // will not be compiled #ifndef NORANGECHECKING #define RANGECHECK #endif // Past distributions #ifndef VER_ID #define VER_ID "DVL" #endif //#define HEXEN_VERSIONTEXT "ID V1.2" //#define HEXEN_VERSIONTEXT "RETAIL STORE BETA" // 9/26/95 //#define HEXEN_VERSIONTEXT "DVL BETA 10 05 95" // Used for GT for testing //#define HEXEN_VERSIONTEXT "DVL BETA 10 07 95" // Just an update for Romero //#define HEXEN_VERSIONTEXT "FINAL 1.0 (10 13 95)" // Just an update for Romero #ifdef RANGECHECK #define HEXEN_VERSIONTEXT "Version 1.1 +R "__DATE__" ("VER_ID")" #else #define HEXEN_VERSIONTEXT "Version 1.1 "__DATE__" ("VER_ID")" #endif // all exterior data is defined here #include "xddefs.h" // all important printed strings #include "textdefs.h" // header generated by multigen utility #include "info.h" /* =============================================================================== GLOBAL TYPES =============================================================================== */ //#define NUMARTIFCTS 28 #define MAXPLAYERS 8 #define BT_ATTACK 1 #define BT_USE 2 #define BT_CHANGE 4 // if true, the next 3 bits hold weapon num #define BT_WEAPONMASK (8+16+32) #define BT_WEAPONSHIFT 3 #define BT_SPECIAL 128 // game events, not really buttons #define BTS_SAVEMASK (4+8+16) #define BTS_SAVESHIFT 2 #define BT_SPECIALMASK 3 #define BTS_PAUSE 1 // pause the game #define BTS_SAVEGAME 2 // save the game at each console // savegame slot numbers occupy the second byte of buttons // The top 3 bits of the artifact field in the ticcmd_t struct are used // as additional flags #define AFLAG_MASK 0x3F #define AFLAG_SUICIDE 0x40 #define AFLAG_JUMP 0x80 typedef enum { GS_LEVEL, GS_INTERMISSION, GS_FINALE, GS_DEMOSCREEN } gamestate_t; typedef enum { ga_nothing, ga_loadlevel, ga_initnew, ga_newgame, ga_loadgame, ga_savegame, ga_playdemo, ga_completed, ga_leavemap, ga_singlereborn, ga_victory, ga_worlddone, ga_screenshot } gameaction_t; typedef enum { wipe_0, wipe_1, wipe_2, wipe_3, wipe_4, NUMWIPES, wipe_random } wipe_t; /* =============================================================================== MAPOBJ DATA =============================================================================== */ // think_t is a function pointer to a routine to handle an actor typedef void (*think_t) (); typedef struct thinker_s { struct thinker_s *prev, *next; think_t function; } thinker_t; struct player_s; typedef union { int i; struct mobj_s *m; struct player_s *p; } specialval_t; typedef struct mobj_s { thinker_t thinker; // thinker node // info for drawing fixed_t x, y, z; struct mobj_s *snext, *sprev; // links in sector (if needed) angle_t angle; spritenum_t sprite; // used to find patch_t and flip value int frame; // might be ord with FF_FULLBRIGHT // interaction info struct mobj_s *bnext, *bprev; // links in blocks (if needed) struct subsector_s *subsector; fixed_t floorz, ceilingz; // closest together of contacted secs fixed_t floorpic; // contacted sec floorpic fixed_t radius, height; // for movement checking fixed_t momx, momy, momz; // momentums int validcount; // if == validcount, already checked mobjtype_t type; mobjinfo_t *info; // &mobjinfo[mobj->type] int tics; // state tic counter state_t *state; int damage; // For missiles int flags; int flags2; // Heretic flags specialval_t special1; // Special info specialval_t special2; // Special info int health; int movedir; // 0-7 int movecount; // when 0, select a new dir struct mobj_s *target; // thing being chased/attacked (or NULL) // also the originator for missiles int reactiontime; // if non 0, don't attack yet // used by player to freeze a bit after // teleporting int threshold; // if > 0, the target will be chased // no matter what (even if shot) struct player_s *player; // only valid if type == MT_PLAYER int lastlook; // player number last looked for fixed_t floorclip; // value to use for floor clipping int archiveNum; // Identity during archive short tid; // thing identifier byte special; // special byte args[5]; // special arguments } mobj_t; // each sector has a degenmobj_t in it's center for sound origin purposes typedef struct { thinker_t thinker; // not used for anything fixed_t x, y, z; } degenmobj_t; // // frame flags // #define FF_FULLBRIGHT 0x8000 // flag in thing->frame #define FF_FRAMEMASK 0x7fff // --- mobj.flags --- #define MF_SPECIAL 1 // call P_SpecialThing when touched #define MF_SOLID 2 #define MF_SHOOTABLE 4 #define MF_NOSECTOR 8 // don't use the sector links // (invisible but touchable) #define MF_NOBLOCKMAP 16 // don't use the blocklinks // (inert but displayable) #define MF_AMBUSH 32 #define MF_JUSTHIT 64 // try to attack right back #define MF_JUSTATTACKED 128 // take at least one step before attacking #define MF_SPAWNCEILING 256 // hang from ceiling instead of floor #define MF_NOGRAVITY 512 // don't apply gravity every tic // movement flags #define MF_DROPOFF 0x400 // allow jumps from high places #define MF_PICKUP 0x800 // for players to pick up items #define MF_NOCLIP 0x1000 // player cheat #define MF_SLIDE 0x2000 // keep info about sliding along walls #define MF_FLOAT 0x4000 // allow moves to any height, no gravity #define MF_TELEPORT 0x8000 // don't cross lines or look at heights #define MF_MISSILE 0x10000 // don't hit same species, explode on block #define MF_ALTSHADOW 0x20000 // alternate translucent draw #define MF_SHADOW 0x40000 // use translucent draw (shadow demons / invis) #define MF_NOBLOOD 0x80000 // don't bleed when shot (use puff) #define MF_CORPSE 0x100000 // don't stop moving halfway off a step #define MF_INFLOAT 0x200000 // floating to a height for a move, don't // auto float to target's height #define MF_COUNTKILL 0x400000 // count towards intermission kill total #define MF_ICECORPSE 0x800000 // a frozen corpse (for blasting) #define MF_SKULLFLY 0x1000000 // skull in flight #define MF_NOTDMATCH 0x2000000 // don't spawn in death match (key cards) //#define MF_TRANSLATION 0xc000000 // if 0x4 0x8 or 0xc, use a translation #define MF_TRANSLATION 0x1c000000 // use a translation table (>>MF_TRANSHIFT) #define MF_TRANSSHIFT 26 // table for player colormaps // --- mobj.flags2 --- #define MF2_LOGRAV 0x00000001 // alternate gravity setting #define MF2_WINDTHRUST 0x00000002 // gets pushed around by the wind // specials #define MF2_FLOORBOUNCE 0x00000004 // bounces off the floor #define MF2_BLASTED 0x00000008 // missile will pass through ghosts #define MF2_FLY 0x00000010 // fly mode is active #define MF2_FLOORCLIP 0x00000020 // if feet are allowed to be clipped #define MF2_SPAWNFLOAT 0x00000040 // spawn random float z #define MF2_NOTELEPORT 0x00000080 // does not teleport #define MF2_RIP 0x00000100 // missile rips through solid // targets #define MF2_PUSHABLE 0x00000200 // can be pushed by other moving // mobjs #define MF2_SLIDE 0x00000400 // slides against walls #define MF2_ONMOBJ 0x00000800 // mobj is resting on top of another // mobj #define MF2_PASSMOBJ 0x00001000 // Enable z block checking. If on, // this flag will allow the mobj to // pass over/under other mobjs. #define MF2_CANNOTPUSH 0x00002000 // cannot push other pushable mobjs #define MF2_DROPPED 0x00004000 // dropped by a demon #define MF2_BOSS 0x00008000 // mobj is a major boss #define MF2_FIREDAMAGE 0x00010000 // does fire damage #define MF2_NODMGTHRUST 0x00020000 // does not thrust target when // damaging #define MF2_TELESTOMP 0x00040000 // mobj can stomp another #define MF2_FLOATBOB 0x00080000 // use float bobbing z movement #define MF2_DONTDRAW 0x00100000 // don't generate a vissprite #define MF2_IMPACT 0x00200000 // an MF_MISSILE mobj can activate // SPAC_IMPACT #define MF2_PUSHWALL 0x00400000 // mobj can push walls #define MF2_MCROSS 0x00800000 // can activate monster cross lines #define MF2_PCROSS 0x01000000 // can activate projectile cross lines #define MF2_CANTLEAVEFLOORPIC 0x02000000 // stay within a certain floor type #define MF2_NONSHOOTABLE 0x04000000 // mobj is totally non-shootable, // but still considered solid #define MF2_INVULNERABLE 0x08000000 // mobj is invulnerable #define MF2_DORMANT 0x10000000 // thing is dormant #define MF2_ICEDAMAGE 0x20000000 // does ice damage #define MF2_SEEKERMISSILE 0x40000000 // is a seeker (for reflection) #define MF2_REFLECTIVE 0x80000000 // reflects missiles //============================================================================= // ===== Player Class Types ===== typedef enum { PCLASS_FIGHTER, PCLASS_CLERIC, PCLASS_MAGE, PCLASS_PIG, NUMCLASSES } pclass_t; typedef enum { PST_LIVE, // playing PST_DEAD, // dead on the ground PST_REBORN // ready to restart } playerstate_t; // psprites are scaled shapes directly on the view screen // coordinates are given for a 320*200 view screen typedef enum { ps_weapon, ps_flash, NUMPSPRITES } psprnum_t; typedef struct { state_t *state; // a NULL state means not active int tics; fixed_t sx, sy; } pspdef_t; /* Old Heretic key type typedef enum { key_yellow, key_green, key_blue, NUMKEYS } keytype_t; */ typedef enum { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_A, KEY_B, NUMKEYS } keytype_t; typedef enum { ARMOR_ARMOR, ARMOR_SHIELD, ARMOR_HELMET, ARMOR_AMULET, NUMARMOR } armortype_t; typedef enum { WP_FIRST, WP_SECOND, WP_THIRD, WP_FOURTH, NUMWEAPONS, WP_NOCHANGE } weapontype_t; typedef enum { MANA_1, MANA_2, NUMMANA, MANA_BOTH, MANA_NONE } manatype_t; #define MAX_MANA 200 #define WPIECE1 1 #define WPIECE2 2 #define WPIECE3 4 typedef struct { manatype_t mana; int upstate; int downstate; int readystate; int atkstate; int holdatkstate; int flashstate; } weaponinfo_t; extern weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES]; typedef enum { arti_none, arti_invulnerability, arti_health, arti_superhealth, arti_healingradius, arti_summon, arti_torch, arti_egg, arti_fly, arti_blastradius, arti_poisonbag, arti_teleportother, arti_speed, arti_boostmana, arti_boostarmor, arti_teleport, // Puzzle artifacts arti_firstpuzzitem, arti_puzzskull = arti_firstpuzzitem, arti_puzzgembig, arti_puzzgemred, arti_puzzgemgreen1, arti_puzzgemgreen2, arti_puzzgemblue1, arti_puzzgemblue2, arti_puzzbook1, arti_puzzbook2, arti_puzzskull2, arti_puzzfweapon, arti_puzzcweapon, arti_puzzmweapon, arti_puzzgear1, arti_puzzgear2, arti_puzzgear3, arti_puzzgear4, NUMARTIFACTS } artitype_t; typedef enum { pw_None, pw_invulnerability, pw_allmap, pw_infrared, pw_flight, pw_shield, pw_health2, pw_speed, pw_minotaur, NUMPOWERS } powertype_t; #define INVULNTICS (30*35) #define INVISTICS (60*35) #define INFRATICS (120*35) #define IRONTICS (60*35) #define WPNLEV2TICS (40*35) #define FLIGHTTICS (60*35) #define SPEEDTICS (45*35) #define MORPHTICS (40*35) #define MAULATORTICS (25*35) #define MESSAGETICS (4*35) #define BLINKTHRESHOLD (4*35) #define NUMINVENTORYSLOTS NUMARTIFACTS typedef struct { int type; int count; } inventory_t; /* ================ = = player_t = ================ */ typedef struct player_s { mobj_t *mo; playerstate_t playerstate; ticcmd_t cmd; pclass_t class; // player class type fixed_t viewz; // focal origin above r.z fixed_t viewheight; // base height above floor for viewz fixed_t deltaviewheight; // squat speed fixed_t bob; // bounded/scaled total momentum int flyheight; int lookdir; boolean centering; int health; // only used between levels, mo->health // is used during levels int armorpoints[NUMARMOR]; inventory_t inventory[NUMINVENTORYSLOTS]; artitype_t readyArtifact; int artifactCount; int inventorySlotNum; int powers[NUMPOWERS]; int keys; int pieces; // Fourth Weapon pieces signed int frags[MAXPLAYERS]; // kills of other players weapontype_t readyweapon; weapontype_t pendingweapon; // wp_nochange if not changing boolean weaponowned[NUMWEAPONS]; int mana[NUMMANA]; int attackdown, usedown; // true if button down last tic int cheats; // bit flags int refire; // refired shots are less accurate int killcount, itemcount, secretcount; // for intermission char message[80]; // hint messages int messageTics; // counter for showing messages short ultimateMessage; short yellowMessage; int damagecount, bonuscount; // for screen flashing int poisoncount; // screen flash for poison damage mobj_t *poisoner; // NULL for non-player mobjs mobj_t *attacker; // who did damage (NULL for floors) int extralight; // so gun flashes light up areas int fixedcolormap; // can be set to REDCOLORMAP, etc int colormap; // 0-3 for which color to draw player pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc) int morphTics; // player is a pig if > 0 unsigned int jumpTics; // delay the next jump for a moment unsigned int worldTimer; // total time the player's been playing } player_t; #define CF_NOCLIP 1 #define CF_GODMODE 2 #define CF_NOMOMENTUM 4 // not really a cheat, just a debug aid #define SBARHEIGHT 39 // status bar height at bottom of screen void NET_SendFrags(player_t * player); /* =============================================================================== GLOBAL VARIABLES =============================================================================== */ #define TELEFOGHEIGHT (32*FRACUNIT) extern GameMode_t gamemode; // Always commercial extern gameaction_t gameaction; extern boolean paused; extern boolean DevMaps; // true = map development mode extern char *DevMapsDir; // development maps directory extern boolean nomonsters; // checkparm of -nomonsters extern boolean respawnparm; // checkparm of -respawn extern boolean randomclass; // checkparm of -randclass extern boolean debugmode; // checkparm of -debug extern boolean usergame; // ok to save / end game extern boolean ravpic; // checkparm of -ravpic extern boolean altpal; // checkparm to use an alternate palette routine extern boolean cdrom; // true if cd-rom mode active ("-cdrom") extern boolean deathmatch; // only if started as net death extern boolean netgame; // only true if >1 player extern boolean cmdfrag; // true if a CMD_FRAG packet should be sent out every // kill extern boolean playeringame[MAXPLAYERS]; extern pclass_t PlayerClass[MAXPLAYERS]; extern int consoleplayer; // player taking events and displaying extern int displayplayer; extern int viewangleoffset; // ANG90 = left side, ANG270 = right extern player_t players[MAXPLAYERS]; extern boolean DebugSound; // debug flag for displaying sound info extern boolean demoplayback; extern int maxzone; // Maximum chunk allocated for zone heap extern int Sky1Texture; extern int Sky2Texture; extern gamestate_t gamestate; extern skill_t gameskill; //extern boolean respawnmonsters; extern int gameepisode; extern int gamemap; extern int prevmap; extern int levelstarttic; // gametic at level start extern int leveltime; // tics in game play for par extern ticcmd_t *netcmds; #define MAXDEATHMATCHSTARTS 16 extern mapthing_t *deathmatch_p; extern mapthing_t deathmatchstarts[MAXDEATHMATCHSTARTS]; // Position indicator for cooperative net-play reborn extern int RebornPosition; #define MAX_PLAYER_STARTS 8 extern mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS]; extern int maxplayers; extern int mouseSensitivity; extern boolean precache; // if true, load all graphics at level load extern byte *screen; // off screen work buffer, from V_video.c extern boolean singledemo; // quit after playing a demo from cmdline extern int bodyqueslot; extern skill_t startskill; extern int startepisode; extern int startmap; extern boolean autostart; extern boolean testcontrols; extern int testcontrols_mousespeed; /* =============================================================================== GLOBAL FUNCTIONS =============================================================================== */ #include "w_wad.h" #include "z_zone.h" //---------- //BASE LEVEL //---------- void H2_Main(void); // not a globally visible function, just included for source reference // calls all startup code // parses command line options // if not overrided, calls N_AdvanceDemo void H2_GameLoop(void); // not a globally visible function, just included for source reference // called by H2_Main, never exits // manages timing and IO // calls all ?_Responder, ?_Ticker, and ?_Drawer functions // calls I_GetTime, I_StartFrame, and I_StartTic //--------- //SYSTEM IO //--------- byte *I_AllocLow(int length); // allocates from low memory under dos, just mallocs under unix // haleyjd: was WATCOMC, again preserved for historical interest as in Heretic #if 0 extern boolean useexterndriver; #define EBT_FIRE 1 #define EBT_OPENDOOR 2 #define EBT_SPEED 4 #define EBT_STRAFE 8 #define EBT_MAP 0x10 #define EBT_INVENTORYLEFT 0x20 #define EBT_INVENTORYRIGHT 0x40 #define EBT_USEARTIFACT 0x80 #define EBT_FLYDROP 0x100 #define EBT_CENTERVIEW 0x200 #define EBT_PAUSE 0x400 #define EBT_WEAPONCYCLE 0x800 #define EBT_JUMP 0x1000 typedef struct { short vector; // Interrupt vector signed char moveForward; // forward/backward (maxes at 50) signed char moveSideways; // strafe (maxes at 24) short angleTurn; // turning speed (640 [slow] 1280 [fast]) short angleHead; // head angle (+2080 [left] : 0 [center] : -2048 [right]) signed char pitch; // look up/down (-110 : +90) signed char flyDirection; // flyheight (+1/-1) unsigned short buttons; // EBT_* flags } externdata_t; #endif //---- //GAME //---- void G_DeathMatchSpawnPlayer(int playernum); void G_InitNew(skill_t skill, int episode, int map); void G_DeferedInitNew(skill_t skill, int episode, int map); // can be called by the startup code or M_Responder // a normal game starts at map 1, but a warp test can start elsewhere void G_DeferredNewGame(skill_t skill); void G_DeferedPlayDemo(char *demo); void G_LoadGame(int slot); // can be called by the startup code or M_Responder // calls P_SetupLevel or W_EnterWorld void G_DoLoadGame(void); void G_SaveGame(int slot, char *description); // called by M_Responder void G_RecordDemo(skill_t skill, int numplayers, int episode, int map, char *name); // only called by startup code void G_PlayDemo(char *name); void G_TimeDemo(char *name); void G_TeleportNewMap(int map, int position); void G_Completed(int map, int position); //void G_ExitLevel (void); //void G_SecretExitLevel (void); void G_StartNewGame(skill_t skill); void G_StartNewInit(void); void G_WorldDone(void); void G_Ticker(void); boolean G_Responder(event_t * ev); void G_ScreenShot(void); //------- //SV_SAVE //------- #define HXS_VERSION_TEXT "HXS Ver 2.37" #define HXS_VERSION_TEXT_LENGTH 16 #define HXS_DESCRIPTION_LENGTH 24 extern char *SavePath; void SV_SaveGame(int slot, char *description); void SV_SaveMap(boolean savePlayers); void SV_LoadGame(int slot); void SV_MapTeleport(int map, int position); void SV_LoadMap(void); void SV_InitBaseSlot(void); void SV_UpdateRebornSlot(void); void SV_ClearRebornSlot(void); boolean SV_RebornSlotAvailable(void); int SV_GetRebornSlot(void); //----- //PLAY //----- void P_Ticker(void); // called by C_Ticker // can call G_PlayerExited // carries out all thinking of monsters and players void P_SetupLevel(int episode, int map, int playermask, skill_t skill); // called by W_Ticker void P_Init(void); // called by startup code int P_GetMapCluster(int map); int P_TranslateMap(int map); int P_GetMapCDTrack(int map); int P_GetMapWarpTrans(int map); int P_GetMapNextMap(int map); int P_GetMapSky1Texture(int map); int P_GetMapSky2Texture(int map); char *P_GetMapName(int map); fixed_t P_GetMapSky1ScrollDelta(int map); fixed_t P_GetMapSky2ScrollDelta(int map); boolean P_GetMapDoubleSky(int map); boolean P_GetMapLightning(int map); boolean P_GetMapFadeTable(int map); char *P_GetMapSongLump(int map); void P_PutMapSongLump(int map, char *lumpName); int P_GetCDStartTrack(void); int P_GetCDEnd1Track(void); int P_GetCDEnd2Track(void); int P_GetCDEnd3Track(void); int P_GetCDIntermissionTrack(void); int P_GetCDTitleTrack(void); //------- //REFRESH //------- extern boolean setsizeneeded; extern boolean BorderNeedRefresh; extern boolean BorderTopRefresh; extern int UpdateState; // define the different areas for the dirty map #define I_NOUPDATE 0 #define I_FULLVIEW 1 #define I_STATBAR 2 #define I_MESSAGES 4 #define I_FULLSCRN 8 void R_RenderPlayerView(player_t * player); // called by G_Drawer void R_Init(void); // called by startup code void R_DrawViewBorder(void); void R_DrawTopBorder(void); // if the view size is not full screen, draws a border around it void R_SetViewSize(int blocks, int detail); // called by M_Responder int R_FlatNumForName(char *name); int R_TextureNumForName(char *name); int R_CheckTextureNumForName(char *name); // called by P_Ticker for switches and animations // returns the texture number for the texture name //---- //MISC //---- extern int localQuakeHappening[MAXPLAYERS]; int M_DrawText(int x, int y, boolean direct, char *string); //------------------------------ // SC_man.c //------------------------------ void SC_Open(char *name); void SC_OpenLump(char *name); void SC_OpenFile(char *name); void SC_Close(void); boolean SC_GetString(void); void SC_MustGetString(void); void SC_MustGetStringName(char *name); boolean SC_GetNumber(void); void SC_MustGetNumber(void); void SC_UnGet(void); //boolean SC_Check(void); boolean SC_Compare(char *text); int SC_MatchString(char **strings); int SC_MustMatchString(char **strings); void SC_ScriptError(char *message); extern char *sc_String; extern int sc_Number; extern int sc_Line; extern boolean sc_End; extern boolean sc_Crossed; extern boolean sc_FileScripts; extern char *sc_ScriptsDir; //------------------------------ // SN_sonix.c //------------------------------ enum { SEQ_PLATFORM, SEQ_PLATFORM_HEAVY, // same script as a normal platform SEQ_PLATFORM_METAL, SEQ_PLATFORM_CREAK, // same script as a normal platform SEQ_PLATFORM_SILENCE, SEQ_PLATFORM_LAVA, SEQ_PLATFORM_WATER, SEQ_PLATFORM_ICE, SEQ_PLATFORM_EARTH, SEQ_PLATFORM_METAL2, SEQ_DOOR_STONE, SEQ_DOOR_HEAVY, SEQ_DOOR_METAL, SEQ_DOOR_CREAK, SEQ_DOOR_SILENCE, SEQ_DOOR_LAVA, SEQ_DOOR_WATER, SEQ_DOOR_ICE, SEQ_DOOR_EARTH, SEQ_DOOR_METAL2, SEQ_ESOUND_WIND, SEQ_NUMSEQ }; typedef enum { SEQTYPE_STONE, SEQTYPE_HEAVY, SEQTYPE_METAL, SEQTYPE_CREAK, SEQTYPE_SILENCE, SEQTYPE_LAVA, SEQTYPE_WATER, SEQTYPE_ICE, SEQTYPE_EARTH, SEQTYPE_METAL2, SEQTYPE_NUMSEQ } seqtype_t; void SN_InitSequenceScript(void); void SN_StartSequence(mobj_t * mobj, int sequence); void SN_StartSequenceName(mobj_t * mobj, char *name); void SN_StopSequence(mobj_t * mobj); void SN_UpdateActiveSequences(void); void SN_StopAllSequences(void); int SN_GetSequenceOffset(int sequence, int *sequencePtr); void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume, int currentSoundID); typedef struct seqnode_s seqnode_t; struct seqnode_s { int *sequencePtr; int sequence; mobj_t *mobj; int currentSoundID; int delayTics; int volume; int stopSound; seqnode_t *prev; seqnode_t *next; }; extern int ActiveSequences; extern seqnode_t *SequenceListHead; //---------------------- // Interlude (IN_lude.c) //---------------------- #define MAX_INTRMSN_MESSAGE_SIZE 1024 extern boolean intermission; extern char ClusterMessage[MAX_INTRMSN_MESSAGE_SIZE]; void IN_Start(void); void IN_Ticker(void); void IN_Drawer(void); //---------------------- // Chat mode (CT_chat.c) //---------------------- void CT_Init(void); void CT_Drawer(void); boolean CT_Responder(event_t * ev); void CT_Ticker(void); char CT_dequeueChatChar(void); extern boolean chatmodeon; //-------------------- // Finale (F_finale.c) //-------------------- void F_Drawer(void); void F_Ticker(void); void F_StartFinale(void); //---------------------- // STATUS BAR (SB_bar.c) //---------------------- extern int inv_ptr; extern int curpos; void SB_Init(void); void SB_SetClassData(void); boolean SB_Responder(event_t * event); void SB_Ticker(void); void SB_Drawer(void); void Draw_TeleportIcon(void); void Draw_SaveIcon(void); void Draw_LoadIcon(void); //----------------- // MENU (MN_menu.c) //----------------- void MN_Init(void); void MN_ActivateMenu(void); void MN_DeactivateMenu(void); boolean MN_Responder(event_t * event); void MN_Ticker(void); void MN_Drawer(void); void MN_DrTextA(char *text, int x, int y); void MN_DrTextAYellow(char *text, int x, int y); int MN_TextAWidth(char *text); void MN_DrTextB(char *text, int x, int y); int MN_TextBWidth(char *text); extern int messageson; #include "sounds.h" #endif // __H2DEF__ chocolate-doom-chocolate-doom-2.2.1/src/hexen/in_lude.c000066400000000000000000000363201257432200600227720ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "h2def.h" #include "s_sound.h" #include "i_system.h" #include "i_video.h" #include "m_misc.h" #include "p_local.h" #include "v_video.h" #include "i_swap.h" // MACROS ------------------------------------------------------------------ #define TEXTSPEED 3 #define TEXTWAIT 140 // TYPES ------------------------------------------------------------------- typedef enum { SINGLE, COOPERATIVE, DEATHMATCH } gametype_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void WaitStop(void); static void Stop(void); static void LoadPics(void); static void UnloadPics(void); static void CheckForSkip(void); static void InitStats(void); static void DrDeathTally(void); static void DrNumber(int val, int x, int y, int wrapThresh); static void DrNumberBold(int val, int x, int y, int wrapThresh); static void DrawHubText(void); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DECLARATIONS ------------------------------------------------ boolean intermission; char ClusterMessage[MAX_INTRMSN_MESSAGE_SIZE]; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static boolean skipintermission; static int interstate = 0; static int intertime = -1; static gametype_t gametype; static int cnt; static int slaughterboy; // in DM, the player with the most kills static patch_t *patchINTERPIC; static patch_t *FontBNumbers[10]; static patch_t *FontBNegative; static patch_t *FontBSlash; static patch_t *FontBPercent; static int FontABaseLump; static int FontBLump; static int FontBLumpBase; static signed int totalFrags[MAXPLAYERS]; static int HubCount; static char *HubText; // CODE -------------------------------------------------------------------- //======================================================================== // // IN_Start // //======================================================================== extern void AM_Stop(void); void IN_Start(void) { int i; I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); InitStats(); LoadPics(); intermission = true; interstate = 0; skipintermission = false; intertime = 0; AM_Stop(); for (i = 0; i < maxplayers; i++) { players[i].messageTics = 0; players[i].message[0] = 0; } SN_StopAllSequences(); } //======================================================================== // // WaitStop // //======================================================================== void WaitStop(void) { if (!--cnt) { Stop(); // gamestate = GS_LEVEL; // G_DoLoadLevel(); gameaction = ga_leavemap; // G_WorldDone(); } } //======================================================================== // // Stop // //======================================================================== static void Stop(void) { intermission = false; UnloadPics(); SB_state = -1; BorderNeedRefresh = true; } //======================================================================== // // InitStats // // Initializes the stats for single player mode //======================================================================== static char *ClusMsgLumpNames[] = { "clus1msg", "clus2msg", "clus3msg", "clus4msg", "clus5msg" }; static void InitStats(void) { int i; int j; int oldCluster; signed int slaughterfrags; int posnum; int slaughtercount; int playercount; char *msgLumpName; int msgSize; int msgLump; extern int LeaveMap; if (!deathmatch) { gametype = SINGLE; HubCount = 0; oldCluster = P_GetMapCluster(gamemap); if (oldCluster != P_GetMapCluster(LeaveMap)) { if (oldCluster >= 1 && oldCluster <= 5) { msgLumpName = ClusMsgLumpNames[oldCluster - 1]; msgLump = W_GetNumForName(msgLumpName); msgSize = W_LumpLength(msgLump); if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE) { I_Error("Cluster message too long (%s)", msgLumpName); } W_ReadLump(msgLump, ClusterMessage); ClusterMessage[msgSize] = 0; // Append terminator HubText = ClusterMessage; HubCount = strlen(HubText) * TEXTSPEED + TEXTWAIT; S_StartSongName("hub", true); } } } else { gametype = DEATHMATCH; slaughterboy = 0; slaughterfrags = -9999; posnum = 0; playercount = 0; slaughtercount = 0; for (i = 0; i < maxplayers; i++) { totalFrags[i] = 0; if (playeringame[i]) { playercount++; for (j = 0; j < maxplayers; j++) { if (playeringame[j]) { totalFrags[i] += players[i].frags[j]; } } posnum++; } if (totalFrags[i] > slaughterfrags) { slaughterboy = 1 << i; slaughterfrags = totalFrags[i]; slaughtercount = 1; } else if (totalFrags[i] == slaughterfrags) { slaughterboy |= 1 << i; slaughtercount++; } } if (playercount == slaughtercount) { // don't do the slaughter stuff if everyone is equal slaughterboy = 0; } S_StartSongName("hub", true); } } //======================================================================== // // LoadPics // //======================================================================== static void LoadPics(void) { int i; if (HubCount || gametype == DEATHMATCH) { patchINTERPIC = W_CacheLumpName("INTERPIC", PU_STATIC); FontBLumpBase = W_GetNumForName("FONTB16"); for (i = 0; i < 10; i++) { FontBNumbers[i] = W_CacheLumpNum(FontBLumpBase + i, PU_STATIC); } FontBLump = W_GetNumForName("FONTB_S") + 1; FontBNegative = W_CacheLumpName("FONTB13", PU_STATIC); FontABaseLump = W_GetNumForName("FONTA_S") + 1; FontBSlash = W_CacheLumpName("FONTB15", PU_STATIC); FontBPercent = W_CacheLumpName("FONTB05", PU_STATIC); } } //======================================================================== // // UnloadPics // //======================================================================== static void UnloadPics(void) { int i; if (HubCount || gametype == DEATHMATCH) { W_ReleaseLumpName("INTERPIC"); patchINTERPIC = W_CacheLumpName("INTERPIC", PU_STATIC); FontBLumpBase = W_GetNumForName("FONTB16"); for (i = 0; i < 10; i++) { W_ReleaseLumpNum(FontBLumpBase + i); } W_ReleaseLumpName("FONTB13"); W_ReleaseLumpName("FONTB15"); W_ReleaseLumpName("FONTB05"); } } //======================================================================== // // IN_Ticker // //======================================================================== void IN_Ticker(void) { if (!intermission) { return; } if (interstate) { WaitStop(); return; } skipintermission = false; CheckForSkip(); intertime++; if (skipintermission || (gametype == SINGLE && !HubCount)) { interstate = 1; cnt = 10; skipintermission = false; //S_StartSound(NULL, sfx_dorcls); } } //======================================================================== // // CheckForSkip // // Check to see if any player hit a key //======================================================================== static void CheckForSkip(void) { int i; player_t *player; static boolean triedToSkip; for (i = 0, player = players; i < maxplayers; i++, player++) { if (playeringame[i]) { if (player->cmd.buttons & BT_ATTACK) { if (!player->attackdown) { skipintermission = 1; } player->attackdown = true; } else { player->attackdown = false; } if (player->cmd.buttons & BT_USE) { if (!player->usedown) { skipintermission = 1; } player->usedown = true; } else { player->usedown = false; } } } if (deathmatch && intertime < 140) { // wait for 4 seconds before allowing a skip if (skipintermission == 1) { triedToSkip = true; skipintermission = 0; } } else { if (triedToSkip) { skipintermission = 1; triedToSkip = false; } } } //======================================================================== // // IN_Drawer // //======================================================================== void IN_Drawer(void) { if (!intermission) { return; } if (interstate) { return; } UpdateState |= I_FULLSCRN; memcpy(I_VideoBuffer, (byte *) patchINTERPIC, SCREENWIDTH * SCREENHEIGHT); if (gametype == SINGLE) { if (HubCount) { DrawHubText(); } } else { DrDeathTally(); } } //======================================================================== // // DrDeathTally // //======================================================================== #define TALLY_EFFECT_TICKS 20 #define TALLY_FINAL_X_DELTA (23*FRACUNIT) #define TALLY_FINAL_Y_DELTA (13*FRACUNIT) #define TALLY_START_XPOS (178*FRACUNIT) #define TALLY_STOP_XPOS (90*FRACUNIT) #define TALLY_START_YPOS (132*FRACUNIT) #define TALLY_STOP_YPOS (83*FRACUNIT) #define TALLY_TOP_X 85 #define TALLY_TOP_Y 9 #define TALLY_LEFT_X 7 #define TALLY_LEFT_Y 71 #define TALLY_TOTALS_X 291 static void DrDeathTally(void) { int i, j; fixed_t xPos, yPos; fixed_t xDelta, yDelta; fixed_t xStart, scale; int x, y; boolean bold; static boolean showTotals; int temp; V_DrawPatch(TALLY_TOP_X, TALLY_TOP_Y, W_CacheLumpName("tallytop", PU_CACHE)); V_DrawPatch(TALLY_LEFT_X, TALLY_LEFT_Y, W_CacheLumpName("tallylft", PU_CACHE)); if (intertime < TALLY_EFFECT_TICKS) { showTotals = false; scale = (intertime * FRACUNIT) / TALLY_EFFECT_TICKS; xDelta = FixedMul(scale, TALLY_FINAL_X_DELTA); yDelta = FixedMul(scale, TALLY_FINAL_Y_DELTA); xStart = TALLY_START_XPOS - FixedMul(scale, TALLY_START_XPOS - TALLY_STOP_XPOS); yPos = TALLY_START_YPOS - FixedMul(scale, TALLY_START_YPOS - TALLY_STOP_YPOS); } else { xDelta = TALLY_FINAL_X_DELTA; yDelta = TALLY_FINAL_Y_DELTA; xStart = TALLY_STOP_XPOS; yPos = TALLY_STOP_YPOS; } if (intertime >= TALLY_EFFECT_TICKS && showTotals == false) { showTotals = true; S_StartSound(NULL, SFX_PLATFORM_STOP); } y = yPos >> FRACBITS; for (i = 0; i < maxplayers; i++) { xPos = xStart; for (j = 0; j < maxplayers; j++, xPos += xDelta) { x = xPos >> FRACBITS; bold = (i == consoleplayer || j == consoleplayer); if (playeringame[i] && playeringame[j]) { if (bold) { DrNumberBold(players[i].frags[j], x, y, 100); } else { DrNumber(players[i].frags[j], x, y, 100); } } else { temp = MN_TextAWidth("--") / 2; if (bold) { MN_DrTextAYellow("--", x - temp, y); } else { MN_DrTextA("--", x - temp, y); } } } if (showTotals && playeringame[i] && !((slaughterboy & (1 << i)) && !(intertime & 16))) { DrNumber(totalFrags[i], TALLY_TOTALS_X, y, 1000); } yPos += yDelta; y = yPos >> FRACBITS; } } //========================================================================== // // DrNumber // //========================================================================== static void DrNumber(int val, int x, int y, int wrapThresh) { char buff[8] = "XX"; if (!(val < -9 && wrapThresh < 1000)) { M_snprintf(buff, sizeof(buff), "%d", val >= wrapThresh ? val % wrapThresh : val); } MN_DrTextA(buff, x - MN_TextAWidth(buff) / 2, y); } //========================================================================== // // DrNumberBold // //========================================================================== static void DrNumberBold(int val, int x, int y, int wrapThresh) { char buff[8] = "XX"; if (!(val < -9 && wrapThresh < 1000)) { M_snprintf(buff, sizeof(buff), "%d", val >= wrapThresh ? val % wrapThresh : val); } MN_DrTextAYellow(buff, x - MN_TextAWidth(buff) / 2, y); } //=========================================================================== // // DrawHubText // //=========================================================================== static void DrawHubText(void) { int count; char *ch; int c; int cx, cy; patch_t *w; cy = 5; cx = 10; ch = HubText; count = (intertime - 10) / TEXTSPEED; if (count < 0) { count = 0; } for (; count; count--) { c = *ch++; if (!c) { break; } if (c == '\n') { cx = 10; cy += 9; continue; } if (c < 32) { continue; } c = toupper(c); if (c == 32) { cx += 5; continue; } w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); if (cx + SHORT(w->width) > SCREENWIDTH) { break; } V_DrawPatch(cx, cy, w); cx += SHORT(w->width); } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/info.c000066400000000000000000024557711257432200600223270ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_swap.h" // generated by stateco char *sprnames[] = { "MAN1","ACLO","TLGL","FBL1","XPL1","ARRW","DART","RIPP","CFCF","BLAD", "SHRD","FFSM","FFLG","PTN1","PTN2","SOAR","INVU","SUMN","TSPK","TELO", "TRNG","ROCK","FOGS","FOGM","FOGL","SGSA","SGSB","PORK","EGGM","FHFX", "SPHL","STWN","GMPD","ASKU","ABGM","AGMR","AGMG","AGG2","AGMB","AGB2", "ABK1","ABK2","ASK2","AFWP","ACWP","AMWP","AGER","AGR2","AGR3","AGR4", "TRCH","PSBG","ATLP","THRW","SPED","BMAN","BRAC","BLST","HRAD","SPSH", "LVAS","SLDG","STTW","RCK1","RCK2","RCK3","RCK4","CDLR","TRE1","TRDT", "TRE2","TRE3","STM1","STM2","STM3","STM4","MSH1","MSH2","MSH3","MSH4", "MSH5","MSH6","MSH7","MSH8","SGMP","SGM1","SGM2","SGM3","SLC1","SLC2", "SLC3","MSS1","MSS2","SWMV","CPS1","CPS2","TMS1","TMS2","TMS3","TMS4", "TMS5","TMS6","TMS7","CPS3","STT2","STT3","STT4","STT5","GAR1","GAR2", "GAR3","GAR4","GAR5","GAR6","GAR7","GAR8","GAR9","BNR1","TRE4","TRE5", "TRE6","TRE7","LOGG","ICT1","ICT2","ICT3","ICT4","ICM1","ICM2","ICM3", "ICM4","RKBL","RKBS","RKBK","RBL1","RBL2","RBL3","VASE","POT1","POT2", "POT3","PBIT","CPS4","CPS5","CPS6","CPB1","CPB2","CPB3","CPB4","BDRP", "BDSH","BDPL","CNDL","LEF1","LEF3","LEF2","TWTR","WLTR","BARL","SHB1", "SHB2","BCKT","SHRM","FBUL","FSKL","BRTR","SUIT","BBLL","CAND","IRON", "XMAS","CDRN","CHNS","TST1","TST2","TST3","TST4","TST5","TST6","TST7", "TST8","TST9","TST0","TELE","TSMK","FPCH","WFAX","FAXE","WFHM","FHMR", "FSRD","FSFX","CMCE","WCSS","CSSF","WCFM","CFLM","CFFX","CHLY","SPIR", "MWND","WMLG","MLNG","MLFX","MLF2","MSTF","MSP1","MSP2","WFR1","WFR2", "WFR3","WCH1","WCH2","WCH3","WMS1","WMS2","WMS3","WPIG","WMCS","CONE", "SHEX","BLOD","GIBS","PLAY","FDTH","BSKL","ICEC","CLER","MAGE","PIGY", "CENT","CTXD","CTFX","CTDP","DEMN","DEMA","DEMB","DEMC","DEMD","DEME", "DMFX","DEM2","DMBA","DMBB","DMBC","DMBD","DMBE","D2FX","WRTH","WRT2", "WRBL","MNTR","FX12","FX13","MNSM","SSPT","SSDV","SSXD","SSFX","BISH", "BPFX","DRAG","DRFX","ARM1","ARM2","ARM3","ARM4","MAN2","MAN3","KEY1", "KEY2","KEY3","KEY4","KEY5","KEY6","KEY7","KEY8","KEY9","KEYA","KEYB", "ETTN","ETTB","FDMN","FDMB","ICEY","ICPR","ICWS","SORC","SBMP","SBS4", "SBMB","SBS3","SBMG","SBS1","SBS2","SBFX","RADE","WATR","KORX","ABAT", NULL }; void A_FreeTargMobj(); void A_FlameCheck(); void A_HideThing(); void A_UnHideThing(); void A_RestoreSpecialThing1(); void A_RestoreSpecialThing2(); void A_RestoreArtifact(); void A_Summon(); void A_ThrustInitUp(); void A_ThrustInitDn(); void A_ThrustRaise(); void A_ThrustBlock(); void A_ThrustImpale(); void A_ThrustLower(); void A_TeloSpawnC(); void A_TeloSpawnB(); void A_TeloSpawnA(); void A_TeloSpawnD(); void A_CheckTeleRing(); void A_FogSpawn(); void A_FogMove(); void A_Quake(); void A_ContMobjSound(); void A_Scream(); void A_Explode(); void A_PoisonBagInit(); void A_PoisonBagDamage(); void A_PoisonBagCheck(); void A_CheckThrowBomb(); void A_NoGravity(); void A_PotteryExplode(); void A_PotteryChooseBit(); void A_PotteryCheck(); void A_CorpseBloodDrip(); void A_CorpseExplode(); void A_LeafSpawn(); void A_LeafThrust(); void A_LeafCheck(); void A_BridgeInit(); void A_BridgeOrbit(); void A_TreeDeath(); void A_PoisonShroom(); void A_Pain(); void A_SoAExplode(); void A_BellReset1(); void A_BellReset2(); void A_NoBlocking(); void A_Light0(); void A_WeaponReady(); void A_Lower(); void A_Raise(); void A_FPunchAttack(); void A_ReFire(); void A_FAxeAttack(); void A_FHammerAttack(); void A_FHammerThrow(); void A_FSwordAttack(); void A_FSwordFlames(); void A_CMaceAttack(); void A_CStaffInitBlink(); void A_CStaffCheckBlink(); void A_CStaffCheck(); void A_CStaffAttack(); void A_CStaffMissileSlither(); void A_CFlameAttack(); void A_CFlameRotate(); void A_CFlamePuff(); void A_CFlameMissile(); void A_CHolyAttack(); void A_CHolyPalette(); void A_CHolySeek(); void A_CHolyCheckScream(); void A_CHolyTail(); void A_CHolySpawnPuff(); void A_CHolyAttack2(); void A_MWandAttack(); void A_LightningReady(); void A_MLightningAttack(); void A_LightningZap(); void A_LightningClip(); void A_LightningRemove(); void A_LastZap(); void A_ZapMimic(); void A_MStaffAttack(); void A_MStaffPalette(); void A_MStaffWeave(); void A_MStaffTrack(); void A_SnoutAttack(); void A_FireConePL1(); void A_ShedShard(); void A_AddPlayerCorpse(); void A_SkullPop(); void A_FreezeDeath(); void A_FreezeDeathChunks(); void A_CheckBurnGone(); void A_CheckSkullFloor(); void A_CheckSkullDone(); void A_SpeedFade(); void A_IceSetTics(); void A_IceCheckHeadDone(); void A_PigPain(); void A_PigLook(); void A_PigChase(); void A_FaceTarget(); void A_PigAttack(); void A_QueueCorpse(); void A_Look(); void A_Chase(); void A_CentaurAttack(); void A_CentaurAttack2(); void A_SetReflective(); void A_CentaurDefend(); void A_UnSetReflective(); void A_CentaurDropStuff(); void A_CheckFloor(); void A_DemonAttack1(); void A_DemonAttack2(); void A_DemonDeath(); void A_Demon2Death(); void A_WraithRaiseInit(); void A_WraithRaise(); void A_WraithInit(); void A_WraithLook(); void A_WraithChase(); void A_WraithFX3(); void A_WraithMelee(); void A_WraithMissile(); void A_WraithFX2(); void A_MinotaurFade1(); void A_MinotaurFade2(); void A_MinotaurLook(); void A_MinotaurChase(); void A_MinotaurRoam(); void A_MinotaurAtk1(); void A_MinotaurDecide(); void A_MinotaurAtk2(); void A_MinotaurAtk3(); void A_MinotaurCharge(); void A_SmokePuffExit(); void A_MinotaurFade0(); void A_MntrFloorFire(); void A_SerpentChase(); void A_SerpentHumpDecide(); void A_SerpentUnHide(); void A_SerpentRaiseHump(); void A_SerpentLowerHump(); void A_SerpentHide(); void A_SerpentBirthScream(); void A_SetShootable(); void A_SerpentCheckForAttack(); void A_UnSetShootable(); void A_SerpentDiveSound(); void A_SerpentWalk(); void A_SerpentChooseAttack(); void A_SerpentMeleeAttack(); void A_SerpentMissileAttack(); void A_SerpentHeadPop(); void A_SerpentSpawnGibs(); void A_SerpentHeadCheck(); void A_FloatGib(); void A_DelayGib(); void A_SinkGib(); void A_BishopDecide(); void A_BishopDoBlur(); void A_BishopSpawnBlur(); void A_BishopChase(); void A_BishopAttack(); void A_BishopAttack2(); void A_BishopPainBlur(); void A_BishopPuff(); void A_SetAltShadow(); void A_BishopMissileWeave(); void A_BishopMissileSeek(); void A_DragonInitFlight(); void A_DragonFlap(); void A_DragonFlight(); void A_DragonAttack(); void A_DragonPain(); void A_DragonCheckCrash(); void A_DragonFX2(); void A_ESound(); void A_EttinAttack(); void A_DropMace(); void A_FiredRocks(); void A_UnSetInvulnerable(); void A_FiredChase(); void A_FiredAttack(); void A_FiredSplotch(); void A_SmBounce(); void A_IceGuyLook(); void A_IceGuyChase(); void A_IceGuyAttack(); void A_IceGuyDie(); void A_IceGuyMissilePuff(); void A_IceGuyMissileExplode(); void A_ClassBossHealth(); void A_FastChase(); void A_FighterAttack(); void A_ClericAttack(); void A_MageAttack(); void A_SorcSpinBalls(); void A_SpeedBalls(); void A_SpawnFizzle(); void A_SorcBossAttack(); void A_SorcBallOrbit(); void A_SorcBallPop(); void A_BounceCheck(); void A_SorcFX1Seek(); void A_SorcFX2Split(); void A_SorcFX2Orbit(); void A_SorcererBishopEntry(); void A_SpawnBishop(); void A_SorcFX4Check(); void A_KoraxStep2(); void A_KoraxChase(); void A_KoraxStep(); void A_KoraxDecide(); void A_KoraxMissile(); void A_KoraxCommand(); void A_KoraxBonePop(); void A_KSpiritRoam(); void A_KBoltRaise(); void A_KBolt(); void A_BatSpawnInit(); void A_BatSpawn(); void A_BatMove(); state_t states[NUMSTATES] = { {SPR_MAN1, 0, -1, NULL, S_NULL, 0, 0}, // S_NULL {SPR_ACLO, 4, 1050, A_FreeTargMobj, S_NULL, 0, 0}, // S_FREETARGMOBJ {SPR_TLGL, 0, -1, NULL, S_NULL, 0, 0}, // S_MAPSPOT {SPR_FBL1, 32768, 4, NULL, S_FIREBALL1_2, 0, 0}, // S_FIREBALL1_1 {SPR_FBL1, 32769, 4, NULL, S_FIREBALL1_1, 0, 0}, // S_FIREBALL1_2 {SPR_XPL1, 32768, 4, NULL, S_FIREBALL1_X2, 0, 0}, // S_FIREBALL1_X1 {SPR_XPL1, 32769, 4, NULL, S_FIREBALL1_X3, 0, 0}, // S_FIREBALL1_X2 {SPR_XPL1, 32770, 4, NULL, S_FIREBALL1_X4, 0, 0}, // S_FIREBALL1_X3 {SPR_XPL1, 32771, 4, NULL, S_FIREBALL1_X5, 0, 0}, // S_FIREBALL1_X4 {SPR_XPL1, 32772, 4, NULL, S_FIREBALL1_X6, 0, 0}, // S_FIREBALL1_X5 {SPR_XPL1, 32773, 4, NULL, S_NULL, 0, 0}, // S_FIREBALL1_X6 {SPR_ARRW, 0, -1, NULL, S_NULL, 0, 0}, // S_ARROW_1 {SPR_ARRW, 0, 1, NULL, S_NULL, 0, 0}, // S_ARROW_X1 {SPR_DART, 0, -1, NULL, S_NULL, 0, 0}, // S_DART_1 {SPR_DART, 0, 1, NULL, S_NULL, 0, 0}, // S_DART_X1 {SPR_DART, 0, -1, NULL, S_NULL, 0, 0}, // S_POISONDART_1 {SPR_DART, 0, 1, NULL, S_NULL, 0, 0}, // S_POISONDART_X1 {SPR_RIPP, 0, 3, NULL, S_RIPPERBALL_2, 0, 0}, // S_RIPPERBALL_1 {SPR_RIPP, 1, 3, NULL, S_RIPPERBALL_3, 0, 0}, // S_RIPPERBALL_2 {SPR_RIPP, 2, 3, NULL, S_RIPPERBALL_1, 0, 0}, // S_RIPPERBALL_3 {SPR_CFCF, 32784, 4, NULL, S_RIPPERBALL_X2, 0, 0}, // S_RIPPERBALL_X1 {SPR_CFCF, 32785, 3, NULL, S_RIPPERBALL_X3, 0, 0}, // S_RIPPERBALL_X2 {SPR_CFCF, 32786, 4, NULL, S_RIPPERBALL_X4, 0, 0}, // S_RIPPERBALL_X3 {SPR_CFCF, 32787, 3, NULL, S_RIPPERBALL_X5, 0, 0}, // S_RIPPERBALL_X4 {SPR_CFCF, 32788, 4, NULL, S_RIPPERBALL_X6, 0, 0}, // S_RIPPERBALL_X5 {SPR_CFCF, 32789, 3, NULL, S_RIPPERBALL_X7, 0, 0}, // S_RIPPERBALL_X6 {SPR_CFCF, 32790, 4, NULL, S_RIPPERBALL_X8, 0, 0}, // S_RIPPERBALL_X7 {SPR_CFCF, 32791, 3, NULL, S_RIPPERBALL_X9, 0, 0}, // S_RIPPERBALL_X8 {SPR_CFCF, 32792, 4, NULL, S_RIPPERBALL_X10, 0, 0}, // S_RIPPERBALL_X9 {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_RIPPERBALL_X10 {SPR_BLAD, 0, -1, NULL, S_NULL, 0, 0}, // S_PRJ_BLADE1 {SPR_BLAD, 0, 1, NULL, S_NULL, 0, 0}, // S_PRJ_BLADE_X1 {SPR_SHRD, 32768, 3, NULL, S_ICESHARD2, 0, 0}, // S_ICESHARD1 {SPR_SHRD, 32769, 3, NULL, S_ICESHARD3, 0, 0}, // S_ICESHARD2 {SPR_SHRD, 32770, 3, NULL, S_ICESHARD1, 0, 0}, // S_ICESHARD3 {SPR_FFSM, 32768, 3, NULL, S_FLAME_TSMALL2, 0, 0}, // S_FLAME_TSMALL1 {SPR_FFSM, 32769, 3, NULL, S_FLAME_TSMALL3, 0, 0}, // S_FLAME_TSMALL2 {SPR_FFSM, 32770, 2, A_FlameCheck, S_FLAME_TSMALL4, 0, 0}, // S_FLAME_TSMALL3 {SPR_FFSM, 32770, 2, NULL, S_FLAME_TSMALL5, 0, 0}, // S_FLAME_TSMALL4 {SPR_FFSM, 32771, 3, NULL, S_FLAME_TSMALL6, 0, 0}, // S_FLAME_TSMALL5 {SPR_FFSM, 32772, 3, A_FlameCheck, S_FLAME_TSMALL1, 0, 0}, // S_FLAME_TSMALL6 {SPR_FFLG, 32768, 4, NULL, S_FLAME_TLARGE2, 0, 0}, // S_FLAME_TLARGE1 {SPR_FFLG, 32769, 4, A_FlameCheck, S_FLAME_TLARGE3, 0, 0}, // S_FLAME_TLARGE2 {SPR_FFLG, 32770, 4, NULL, S_FLAME_TLARGE4, 0, 0}, // S_FLAME_TLARGE3 {SPR_FFLG, 32771, 4, A_FlameCheck, S_FLAME_TLARGE5, 0, 0}, // S_FLAME_TLARGE4 {SPR_FFLG, 32772, 4, NULL, S_FLAME_TLARGE6, 0, 0}, // S_FLAME_TLARGE5 {SPR_FFLG, 32773, 4, A_FlameCheck, S_FLAME_TLARGE7, 0, 0}, // S_FLAME_TLARGE6 {SPR_FFLG, 32774, 4, NULL, S_FLAME_TLARGE8, 0, 0}, // S_FLAME_TLARGE7 {SPR_FFLG, 32775, 4, A_FlameCheck, S_FLAME_TLARGE9, 0, 0}, // S_FLAME_TLARGE8 {SPR_FFLG, 32776, 4, NULL, S_FLAME_TLARGE10, 0, 0}, // S_FLAME_TLARGE9 {SPR_FFLG, 32777, 4, A_FlameCheck, S_FLAME_TLARGE11, 0, 0}, // S_FLAME_TLARGE10 {SPR_FFLG, 32778, 4, NULL, S_FLAME_TLARGE12, 0, 0}, // S_FLAME_TLARGE11 {SPR_FFLG, 32779, 4, A_FlameCheck, S_FLAME_TLARGE13, 0, 0}, // S_FLAME_TLARGE12 {SPR_FFLG, 32780, 4, NULL, S_FLAME_TLARGE14, 0, 0}, // S_FLAME_TLARGE13 {SPR_FFLG, 32781, 4, A_FlameCheck, S_FLAME_TLARGE15, 0, 0}, // S_FLAME_TLARGE14 {SPR_FFLG, 32782, 4, NULL, S_FLAME_TLARGE16, 0, 0}, // S_FLAME_TLARGE15 {SPR_FFLG, 32783, 4, A_FlameCheck, S_FLAME_TLARGE5, 0, 0}, // S_FLAME_TLARGE16 {SPR_FFSM, 0, 2, NULL, S_FLAME_SDORM2, 0, 0}, // S_FLAME_SDORM1 {SPR_FFSM, 1, 2, A_HideThing, S_FLAME_SDORM3, 0, 0}, // S_FLAME_SDORM2 {SPR_FFSM, 2, 200, NULL, S_FLAME_SDORM3, 0, 0}, // S_FLAME_SDORM3 {SPR_FFSM, 32768, 3, NULL, S_FLAME_SMALL2, 0, 0}, // S_FLAME_SMALL1 {SPR_FFSM, 32768, 3, A_UnHideThing, S_FLAME_SMALL3, 0, 0}, // S_FLAME_SMALL2 {SPR_FFSM, 32768, 3, NULL, S_FLAME_SMALL4, 0, 0}, // S_FLAME_SMALL3 {SPR_FFSM, 32769, 3, NULL, S_FLAME_SMALL5, 0, 0}, // S_FLAME_SMALL4 {SPR_FFSM, 32770, 3, NULL, S_FLAME_SMALL6, 0, 0}, // S_FLAME_SMALL5 {SPR_FFSM, 32771, 3, NULL, S_FLAME_SMALL7, 0, 0}, // S_FLAME_SMALL6 {SPR_FFSM, 32772, 3, NULL, S_FLAME_SMALL3, 0, 0}, // S_FLAME_SMALL7 {SPR_FFLG, 3, 2, NULL, S_FLAME_LDORM2, 0, 0}, // S_FLAME_LDORM1 {SPR_FFLG, 2, 2, NULL, S_FLAME_LDORM3, 0, 0}, // S_FLAME_LDORM2 {SPR_FFLG, 1, 2, NULL, S_FLAME_LDORM4, 0, 0}, // S_FLAME_LDORM3 {SPR_FFLG, 0, 2, A_HideThing, S_FLAME_LDORM5, 0, 0}, // S_FLAME_LDORM4 {SPR_FFLG, 0, 200, NULL, S_FLAME_LDORM5, 0, 0}, // S_FLAME_LDORM5 {SPR_FFLG, 32768, 2, NULL, S_FLAME_LARGE2, 0, 0}, // S_FLAME_LARGE1 {SPR_FFLG, 32768, 2, A_UnHideThing, S_FLAME_LARGE3, 0, 0}, // S_FLAME_LARGE2 {SPR_FFLG, 32768, 4, NULL, S_FLAME_LARGE4, 0, 0}, // S_FLAME_LARGE3 {SPR_FFLG, 32769, 4, NULL, S_FLAME_LARGE5, 0, 0}, // S_FLAME_LARGE4 {SPR_FFLG, 32770, 4, NULL, S_FLAME_LARGE6, 0, 0}, // S_FLAME_LARGE5 {SPR_FFLG, 32771, 4, NULL, S_FLAME_LARGE7, 0, 0}, // S_FLAME_LARGE6 {SPR_FFLG, 32772, 4, NULL, S_FLAME_LARGE8, 0, 0}, // S_FLAME_LARGE7 {SPR_FFLG, 32773, 4, NULL, S_FLAME_LARGE9, 0, 0}, // S_FLAME_LARGE8 {SPR_FFLG, 32774, 4, NULL, S_FLAME_LARGE10, 0, 0}, // S_FLAME_LARGE9 {SPR_FFLG, 32775, 4, NULL, S_FLAME_LARGE11, 0, 0}, // S_FLAME_LARGE10 {SPR_FFLG, 32776, 4, NULL, S_FLAME_LARGE12, 0, 0}, // S_FLAME_LARGE11 {SPR_FFLG, 32777, 4, NULL, S_FLAME_LARGE13, 0, 0}, // S_FLAME_LARGE12 {SPR_FFLG, 32778, 4, NULL, S_FLAME_LARGE14, 0, 0}, // S_FLAME_LARGE13 {SPR_FFLG, 32779, 4, NULL, S_FLAME_LARGE15, 0, 0}, // S_FLAME_LARGE14 {SPR_FFLG, 32780, 4, NULL, S_FLAME_LARGE16, 0, 0}, // S_FLAME_LARGE15 {SPR_FFLG, 32781, 4, NULL, S_FLAME_LARGE17, 0, 0}, // S_FLAME_LARGE16 {SPR_FFLG, 32782, 4, NULL, S_FLAME_LARGE18, 0, 0}, // S_FLAME_LARGE17 {SPR_FFLG, 32783, 4, NULL, S_FLAME_LARGE7, 0, 0}, // S_FLAME_LARGE18 {SPR_PTN1, 0, 3, NULL, S_ITEM_PTN1_2, 0, 0}, // S_ITEM_PTN1_1 {SPR_PTN1, 1, 3, NULL, S_ITEM_PTN1_3, 0, 0}, // S_ITEM_PTN1_2 {SPR_PTN1, 2, 3, NULL, S_ITEM_PTN1_1, 0, 0}, // S_ITEM_PTN1_3 {SPR_ACLO, 4, 1400, NULL, S_HIDESPECIAL2, 0, 0}, // S_HIDESPECIAL1 {SPR_ACLO, 0, 4, A_RestoreSpecialThing1, S_HIDESPECIAL3, 0, 0}, // S_HIDESPECIAL2 {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL4, 0, 0}, // S_HIDESPECIAL3 {SPR_ACLO, 0, 4, NULL, S_HIDESPECIAL5, 0, 0}, // S_HIDESPECIAL4 {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL6, 0, 0}, // S_HIDESPECIAL5 {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL7, 0, 0}, // S_HIDESPECIAL6 {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL8, 0, 0}, // S_HIDESPECIAL7 {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL9, 0, 0}, // S_HIDESPECIAL8 {SPR_ACLO, 3, 4, NULL, S_HIDESPECIAL10, 0, 0}, // S_HIDESPECIAL9 {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL11, 0, 0}, // S_HIDESPECIAL10 {SPR_ACLO, 3, 4, A_RestoreSpecialThing2, S_NULL, 0, 0}, // S_HIDESPECIAL11 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI1_2, 0, 0}, // S_DORMANTARTI1_1 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_3, 0, 0}, // S_DORMANTARTI1_2 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI1_4, 0, 0}, // S_DORMANTARTI1_3 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_5, 0, 0}, // S_DORMANTARTI1_4 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_6, 0, 0}, // S_DORMANTARTI1_5 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_7, 0, 0}, // S_DORMANTARTI1_6 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_8, 0, 0}, // S_DORMANTARTI1_7 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI1_9, 0, 0}, // S_DORMANTARTI1_8 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_10, 0, 0}, // S_DORMANTARTI1_9 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI1_11, 0, 0}, // S_DORMANTARTI1_10 {SPR_ACLO, 0, 1400, A_HideThing, S_DORMANTARTI1_12, 0, 0}, // S_DORMANTARTI1_11 {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI1_13, 0, 0}, // S_DORMANTARTI1_12 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_14, 0, 0}, // S_DORMANTARTI1_13 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI1_15, 0, 0}, // S_DORMANTARTI1_14 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_16, 0, 0}, // S_DORMANTARTI1_15 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_17, 0, 0}, // S_DORMANTARTI1_16 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_18, 0, 0}, // S_DORMANTARTI1_17 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_19, 0, 0}, // S_DORMANTARTI1_18 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI1_20, 0, 0}, // S_DORMANTARTI1_19 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_21, 0, 0}, // S_DORMANTARTI1_20 {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI1_21 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2_2, 0, 0}, // S_DORMANTARTI2_1 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_3, 0, 0}, // S_DORMANTARTI2_2 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2_4, 0, 0}, // S_DORMANTARTI2_3 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_5, 0, 0}, // S_DORMANTARTI2_4 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_6, 0, 0}, // S_DORMANTARTI2_5 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_7, 0, 0}, // S_DORMANTARTI2_6 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_8, 0, 0}, // S_DORMANTARTI2_7 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI2_9, 0, 0}, // S_DORMANTARTI2_8 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_10, 0, 0}, // S_DORMANTARTI2_9 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI2_11, 0, 0}, // S_DORMANTARTI2_10 {SPR_ACLO, 0, 4200, A_HideThing, S_DORMANTARTI2_12, 0, 0}, // S_DORMANTARTI2_11 {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI2_13, 0, 0}, // S_DORMANTARTI2_12 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_14, 0, 0}, // S_DORMANTARTI2_13 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI2_15, 0, 0}, // S_DORMANTARTI2_14 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_16, 0, 0}, // S_DORMANTARTI2_15 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_17, 0, 0}, // S_DORMANTARTI2_16 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_18, 0, 0}, // S_DORMANTARTI2_17 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_19, 0, 0}, // S_DORMANTARTI2_18 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2_20, 0, 0}, // S_DORMANTARTI2_19 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_21, 0, 0}, // S_DORMANTARTI2_20 {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI2_21 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI3_2, 0, 0}, // S_DORMANTARTI3_1 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_3, 0, 0}, // S_DORMANTARTI3_2 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI3_4, 0, 0}, // S_DORMANTARTI3_3 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_5, 0, 0}, // S_DORMANTARTI3_4 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_6, 0, 0}, // S_DORMANTARTI3_5 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_7, 0, 0}, // S_DORMANTARTI3_6 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_8, 0, 0}, // S_DORMANTARTI3_7 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI3_9, 0, 0}, // S_DORMANTARTI3_8 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_10, 0, 0}, // S_DORMANTARTI3_9 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI3_11, 0, 0}, // S_DORMANTARTI3_10 {SPR_ACLO, 0, 21000, A_HideThing, S_DORMANTARTI3_12, 0, 0}, // S_DORMANTARTI3_11 {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI3_13, 0, 0}, // S_DORMANTARTI3_12 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_14, 0, 0}, // S_DORMANTARTI3_13 {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI3_15, 0, 0}, // S_DORMANTARTI3_14 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_16, 0, 0}, // S_DORMANTARTI3_15 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_17, 0, 0}, // S_DORMANTARTI3_16 {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_18, 0, 0}, // S_DORMANTARTI3_17 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_19, 0, 0}, // S_DORMANTARTI3_18 {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI3_20, 0, 0}, // S_DORMANTARTI3_19 {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_21, 0, 0}, // S_DORMANTARTI3_20 {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI3_21 {SPR_ACLO, 3, 3, NULL, S_DEADARTI2, 0, 0}, // S_DEADARTI1 {SPR_ACLO, 2, 3, NULL, S_DEADARTI3, 0, 0}, // S_DEADARTI2 {SPR_ACLO, 3, 3, NULL, S_DEADARTI4, 0, 0}, // S_DEADARTI3 {SPR_ACLO, 2, 3, NULL, S_DEADARTI5, 0, 0}, // S_DEADARTI4 {SPR_ACLO, 1, 3, NULL, S_DEADARTI6, 0, 0}, // S_DEADARTI5 {SPR_ACLO, 2, 3, NULL, S_DEADARTI7, 0, 0}, // S_DEADARTI6 {SPR_ACLO, 1, 3, NULL, S_DEADARTI8, 0, 0}, // S_DEADARTI7 {SPR_ACLO, 0, 3, NULL, S_DEADARTI9, 0, 0}, // S_DEADARTI8 {SPR_ACLO, 1, 3, NULL, S_DEADARTI10, 0, 0}, // S_DEADARTI9 {SPR_ACLO, 0, 3, NULL, S_NULL, 0, 0}, // S_DEADARTI10 {SPR_PTN2, 0, 4, NULL, S_ARTI_PTN2_2, 0, 0}, // S_ARTI_PTN2_1 {SPR_PTN2, 1, 4, NULL, S_ARTI_PTN2_3, 0, 0}, // S_ARTI_PTN2_2 {SPR_PTN2, 2, 4, NULL, S_ARTI_PTN2_1, 0, 0}, // S_ARTI_PTN2_3 {SPR_SOAR, 0, 5, NULL, S_ARTI_SOAR2, 0, 0}, // S_ARTI_SOAR1 {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR3, 0, 0}, // S_ARTI_SOAR2 {SPR_SOAR, 2, 5, NULL, S_ARTI_SOAR4, 0, 0}, // S_ARTI_SOAR3 {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR1, 0, 0}, // S_ARTI_SOAR4 {SPR_INVU, 0, 3, NULL, S_ARTI_INVU2, 0, 0}, // S_ARTI_INVU1 {SPR_INVU, 1, 3, NULL, S_ARTI_INVU3, 0, 0}, // S_ARTI_INVU2 {SPR_INVU, 2, 3, NULL, S_ARTI_INVU4, 0, 0}, // S_ARTI_INVU3 {SPR_INVU, 3, 3, NULL, S_ARTI_INVU1, 0, 0}, // S_ARTI_INVU4 {SPR_SUMN, 0, 350, NULL, S_ARTI_SUMMON, 0, 0}, // S_ARTI_SUMMON {SPR_SUMN, 0, 4, NULL, S_SUMMON_FX1_1, 0, 0}, // S_SUMMON_FX1_1 {SPR_SUMN, 0, 4, NULL, S_SUMMON_FX2_2, 0, 0}, // S_SUMMON_FX2_1 {SPR_SUMN, 0, 4, NULL, S_SUMMON_FX2_3, 0, 0}, // S_SUMMON_FX2_2 {SPR_SUMN, 0, 4, A_Summon, S_NULL, 0, 0}, // S_SUMMON_FX2_3 {SPR_TSPK, 0, 3, NULL, S_THRUSTINIT2_2, 0, 0}, // S_THRUSTINIT2_1 {SPR_TSPK, 0, 4, A_ThrustInitUp, S_THRUSTBLOCK, 0, 0}, // S_THRUSTINIT2_2 {SPR_TSPK, 1, 3, NULL, S_BTHRUSTINIT2_2, 0, 0}, // S_BTHRUSTINIT2_1 {SPR_TSPK, 1, 4, A_ThrustInitUp, S_BTHRUSTBLOCK, 0, 0}, // S_BTHRUSTINIT2_2 {SPR_TSPK, 0, 3, NULL, S_THRUSTINIT1_2, 0, 0}, // S_THRUSTINIT1_1 {SPR_TSPK, 0, 4, A_ThrustInitDn, S_THRUSTSTAY, 0, 0}, // S_THRUSTINIT1_2 {SPR_TSPK, 1, 3, NULL, S_BTHRUSTINIT1_2, 0, 0}, // S_BTHRUSTINIT1_1 {SPR_TSPK, 1, 4, A_ThrustInitDn, S_BTHRUSTSTAY, 0, 0}, // S_BTHRUSTINIT1_2 {SPR_TSPK, 0, 8, A_ThrustRaise, S_THRUSTRAISE2, 0, 0}, // S_THRUSTRAISE1 {SPR_TSPK, 0, 6, A_ThrustRaise, S_THRUSTRAISE3, 0, 0}, // S_THRUSTRAISE2 {SPR_TSPK, 0, 4, A_ThrustRaise, S_THRUSTRAISE4, 0, 0}, // S_THRUSTRAISE3 {SPR_TSPK, 0, 3, A_ThrustBlock, S_THRUSTIMPALE, 0, 0}, // S_THRUSTRAISE4 {SPR_TSPK, 1, 8, A_ThrustRaise, S_BTHRUSTRAISE2, 0, 0}, // S_BTHRUSTRAISE1 {SPR_TSPK, 1, 6, A_ThrustRaise, S_BTHRUSTRAISE3, 0, 0}, // S_BTHRUSTRAISE2 {SPR_TSPK, 1, 4, A_ThrustRaise, S_BTHRUSTRAISE4, 0, 0}, // S_BTHRUSTRAISE3 {SPR_TSPK, 1, 3, A_ThrustBlock, S_BTHRUSTIMPALE, 0, 0}, // S_BTHRUSTRAISE4 {SPR_TSPK, 0, 2, A_ThrustImpale, S_THRUSTRAISE, 0, 0}, // S_THRUSTIMPALE {SPR_TSPK, 1, 2, A_ThrustImpale, S_BTHRUSTRAISE, 0, 0}, // S_BTHRUSTIMPALE {SPR_TSPK, 0, 2, A_ThrustRaise, S_THRUSTRAISE, 0, 0}, // S_THRUSTRAISE {SPR_TSPK, 1, 2, A_ThrustRaise, S_BTHRUSTRAISE, 0, 0}, // S_BTHRUSTRAISE {SPR_TSPK, 0, 10, NULL, S_THRUSTBLOCK, 0, 0}, // S_THRUSTBLOCK {SPR_TSPK, 1, 10, NULL, S_BTHRUSTBLOCK, 0, 0}, // S_BTHRUSTBLOCK {SPR_TSPK, 0, 2, A_ThrustLower, S_THRUSTLOWER, 0, 0}, // S_THRUSTLOWER {SPR_TSPK, 1, 2, A_ThrustLower, S_BTHRUSTLOWER, 0, 0}, // S_BTHRUSTLOWER {SPR_TSPK, 0, -1, NULL, S_THRUSTSTAY, 0, 0}, // S_THRUSTSTAY {SPR_TSPK, 1, -1, NULL, S_BTHRUSTSTAY, 0, 0}, // S_BTHRUSTSTAY {SPR_TELO, 0, 5, NULL, S_ARTI_TELOTHER2, 0, 0}, // S_ARTI_TELOTHER1 {SPR_TELO, 1, 5, NULL, S_ARTI_TELOTHER3, 0, 0}, // S_ARTI_TELOTHER2 {SPR_TELO, 2, 5, NULL, S_ARTI_TELOTHER4, 0, 0}, // S_ARTI_TELOTHER3 {SPR_TELO, 3, 5, NULL, S_ARTI_TELOTHER1, 0, 0}, // S_ARTI_TELOTHER4 {SPR_TRNG, 32772, 5, NULL, S_TELO_FX2, 0, 0}, // S_TELO_FX1 {SPR_TRNG, 32771, 4, NULL, S_TELO_FX3, 0, 0}, // S_TELO_FX2 {SPR_TRNG, 32770, 3, A_TeloSpawnC, S_TELO_FX4, 0, 0}, // S_TELO_FX3 {SPR_TRNG, 32769, 3, A_TeloSpawnB, S_TELO_FX5, 0, 0}, // S_TELO_FX4 {SPR_TRNG, 32768, 3, A_TeloSpawnA, S_TELO_FX6, 0, 0}, // S_TELO_FX5 {SPR_TRNG, 32769, 3, A_TeloSpawnB, S_TELO_FX7, 0, 0}, // S_TELO_FX6 {SPR_TRNG, 32770, 3, A_TeloSpawnC, S_TELO_FX8, 0, 0}, // S_TELO_FX7 {SPR_TRNG, 32771, 3, A_TeloSpawnD, S_TELO_FX3, 0, 0}, // S_TELO_FX8 {SPR_TRNG, 32772, 3, NULL, S_NULL, 0, 0}, // S_TELO_FX9 {SPR_TRNG, 32769, 4, NULL, S_TELO_FX2_2, 0, 0}, // S_TELO_FX2_1 {SPR_TRNG, 32770, 4, NULL, S_TELO_FX2_3, 0, 0}, // S_TELO_FX2_2 {SPR_TRNG, 32771, 4, NULL, S_TELO_FX2_4, 0, 0}, // S_TELO_FX2_3 {SPR_TRNG, 32770, 4, NULL, S_TELO_FX2_5, 0, 0}, // S_TELO_FX2_4 {SPR_TRNG, 32769, 4, NULL, S_TELO_FX2_6, 0, 0}, // S_TELO_FX2_5 {SPR_TRNG, 32768, 4, A_CheckTeleRing, S_TELO_FX2_1, 0, 0}, // S_TELO_FX2_6 {SPR_TRNG, 32770, 4, NULL, S_TELO_FX3_2, 0, 0}, // S_TELO_FX3_1 {SPR_TRNG, 32771, 4, NULL, S_TELO_FX3_3, 0, 0}, // S_TELO_FX3_2 {SPR_TRNG, 32770, 4, NULL, S_TELO_FX3_4, 0, 0}, // S_TELO_FX3_3 {SPR_TRNG, 32769, 4, NULL, S_TELO_FX3_5, 0, 0}, // S_TELO_FX3_4 {SPR_TRNG, 32768, 4, NULL, S_TELO_FX3_6, 0, 0}, // S_TELO_FX3_5 {SPR_TRNG, 32769, 4, A_CheckTeleRing, S_TELO_FX3_1, 0, 0}, // S_TELO_FX3_6 {SPR_TRNG, 32771, 4, NULL, S_TELO_FX4_2, 0, 0}, // S_TELO_FX4_1 {SPR_TRNG, 32770, 4, NULL, S_TELO_FX4_3, 0, 0}, // S_TELO_FX4_2 {SPR_TRNG, 32769, 4, NULL, S_TELO_FX4_4, 0, 0}, // S_TELO_FX4_3 {SPR_TRNG, 32768, 4, NULL, S_TELO_FX4_5, 0, 0}, // S_TELO_FX4_4 {SPR_TRNG, 32769, 4, NULL, S_TELO_FX4_6, 0, 0}, // S_TELO_FX4_5 {SPR_TRNG, 32770, 4, A_CheckTeleRing, S_TELO_FX4_1, 0, 0}, // S_TELO_FX4_6 {SPR_TRNG, 32770, 4, NULL, S_TELO_FX5_2, 0, 0}, // S_TELO_FX5_1 {SPR_TRNG, 32769, 4, NULL, S_TELO_FX5_3, 0, 0}, // S_TELO_FX5_2 {SPR_TRNG, 32768, 4, NULL, S_TELO_FX5_4, 0, 0}, // S_TELO_FX5_3 {SPR_TRNG, 32769, 4, NULL, S_TELO_FX5_5, 0, 0}, // S_TELO_FX5_4 {SPR_TRNG, 32770, 4, NULL, S_TELO_FX5_6, 0, 0}, // S_TELO_FX5_5 {SPR_TRNG, 32771, 4, A_CheckTeleRing, S_TELO_FX5_1, 0, 0}, // S_TELO_FX5_6 {SPR_ROCK, 3, 20, NULL, S_DIRT1_1, 0, 0}, // S_DIRT1_1 {SPR_ROCK, 3, 10, NULL, S_NULL, 0, 0}, // S_DIRT1_D {SPR_ROCK, 4, 20, NULL, S_DIRT2_1, 0, 0}, // S_DIRT2_1 {SPR_ROCK, 4, 10, NULL, S_NULL, 0, 0}, // S_DIRT2_D {SPR_ROCK, 5, 20, NULL, S_DIRT3_1, 0, 0}, // S_DIRT3_1 {SPR_ROCK, 5, 10, NULL, S_NULL, 0, 0}, // S_DIRT3_D {SPR_ROCK, 6, 20, NULL, S_DIRT4_1, 0, 0}, // S_DIRT4_1 {SPR_ROCK, 6, 10, NULL, S_NULL, 0, 0}, // S_DIRT4_D {SPR_ROCK, 7, 20, NULL, S_DIRT5_1, 0, 0}, // S_DIRT5_1 {SPR_ROCK, 7, 10, NULL, S_NULL, 0, 0}, // S_DIRT5_D {SPR_ROCK, 8, 20, NULL, S_DIRT6_1, 0, 0}, // S_DIRT6_1 {SPR_ROCK, 8, 10, NULL, S_NULL, 0, 0}, // S_DIRT6_D {SPR_TSPK, 2, 20, NULL, S_DIRTCLUMP1, 0, 0}, // S_DIRTCLUMP1 {SPR_ROCK, 0, 20, NULL, S_ROCK1_1, 0, 0}, // S_ROCK1_1 {SPR_ROCK, 0, 10, NULL, S_NULL, 0, 0}, // S_ROCK1_D {SPR_ROCK, 1, 20, NULL, S_ROCK2_1, 0, 0}, // S_ROCK2_1 {SPR_ROCK, 1, 10, NULL, S_NULL, 0, 0}, // S_ROCK2_D {SPR_ROCK, 2, 20, NULL, S_ROCK3_1, 0, 0}, // S_ROCK3_1 {SPR_ROCK, 2, 10, NULL, S_NULL, 0, 0}, // S_ROCK3_D {SPR_MAN1, 0, 20, A_FogSpawn, S_SPAWNFOG1, 0, 0}, // S_SPAWNFOG1 {SPR_FOGS, 0, 7, A_FogMove, S_FOGPATCHS2, 0, 0}, // S_FOGPATCHS1 {SPR_FOGS, 1, 7, A_FogMove, S_FOGPATCHS3, 0, 0}, // S_FOGPATCHS2 {SPR_FOGS, 2, 7, A_FogMove, S_FOGPATCHS4, 0, 0}, // S_FOGPATCHS3 {SPR_FOGS, 3, 7, A_FogMove, S_FOGPATCHS5, 0, 0}, // S_FOGPATCHS4 {SPR_FOGS, 4, 7, A_FogMove, S_FOGPATCHS1, 0, 0}, // S_FOGPATCHS5 {SPR_FOGS, 4, 5, NULL, S_NULL, 0, 0}, // S_FOGPATCHS0 {SPR_FOGM, 0, 7, A_FogMove, S_FOGPATCHM2, 0, 0}, // S_FOGPATCHM1 {SPR_FOGM, 1, 7, A_FogMove, S_FOGPATCHM3, 0, 0}, // S_FOGPATCHM2 {SPR_FOGM, 2, 7, A_FogMove, S_FOGPATCHM4, 0, 0}, // S_FOGPATCHM3 {SPR_FOGM, 3, 7, A_FogMove, S_FOGPATCHM5, 0, 0}, // S_FOGPATCHM4 {SPR_FOGM, 4, 7, A_FogMove, S_FOGPATCHM1, 0, 0}, // S_FOGPATCHM5 {SPR_FOGS, 0, 5, NULL, S_FOGPATCHMA, 0, 0}, // S_FOGPATCHM0 {SPR_FOGS, 1, 5, NULL, S_FOGPATCHMB, 0, 0}, // S_FOGPATCHMA {SPR_FOGS, 2, 5, NULL, S_FOGPATCHMC, 0, 0}, // S_FOGPATCHMB {SPR_FOGS, 3, 5, NULL, S_FOGPATCHMD, 0, 0}, // S_FOGPATCHMC {SPR_FOGS, 4, 5, NULL, S_FOGPATCHS0, 0, 0}, // S_FOGPATCHMD {SPR_FOGL, 0, 7, A_FogMove, S_FOGPATCHL2, 0, 0}, // S_FOGPATCHL1 {SPR_FOGL, 1, 7, A_FogMove, S_FOGPATCHL3, 0, 0}, // S_FOGPATCHL2 {SPR_FOGL, 2, 7, A_FogMove, S_FOGPATCHL4, 0, 0}, // S_FOGPATCHL3 {SPR_FOGL, 3, 7, A_FogMove, S_FOGPATCHL5, 0, 0}, // S_FOGPATCHL4 {SPR_FOGL, 4, 7, A_FogMove, S_FOGPATCHL1, 0, 0}, // S_FOGPATCHL5 {SPR_FOGM, 0, 4, NULL, S_FOGPATCHLA, 0, 0}, // S_FOGPATCHL0 {SPR_FOGM, 1, 4, NULL, S_FOGPATCHLB, 0, 0}, // S_FOGPATCHLA {SPR_FOGM, 2, 4, NULL, S_FOGPATCHLC, 0, 0}, // S_FOGPATCHLB {SPR_FOGM, 3, 4, NULL, S_FOGPATCHLD, 0, 0}, // S_FOGPATCHLC {SPR_FOGM, 4, 4, NULL, S_FOGPATCHM0, 0, 0}, // S_FOGPATCHLD {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE2, 0, 0}, // S_QUAKE_ACTIVE1 {SPR_MAN1, 0, 1, A_ContMobjSound, S_QUAKE_ACTIVE3, 0, 0}, // S_QUAKE_ACTIVE2 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE4, 0, 0}, // S_QUAKE_ACTIVE3 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE5, 0, 0}, // S_QUAKE_ACTIVE4 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE6, 0, 0}, // S_QUAKE_ACTIVE5 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE7, 0, 0}, // S_QUAKE_ACTIVE6 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE8, 0, 0}, // S_QUAKE_ACTIVE7 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE9, 0, 0}, // S_QUAKE_ACTIVE8 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE0, 0, 0}, // S_QUAKE_ACTIVE9 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEA, 0, 0}, // S_QUAKE_ACTIVE0 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEB, 0, 0}, // S_QUAKE_ACTIVEA {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEC, 0, 0}, // S_QUAKE_ACTIVEB {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVED, 0, 0}, // S_QUAKE_ACTIVEC {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEE, 0, 0}, // S_QUAKE_ACTIVED {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEF, 0, 0}, // S_QUAKE_ACTIVEE {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEG, 0, 0}, // S_QUAKE_ACTIVEF {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEH, 0, 0}, // S_QUAKE_ACTIVEG {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEI, 0, 0}, // S_QUAKE_ACTIVEH {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEJ, 0, 0}, // S_QUAKE_ACTIVEI {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEK, 0, 0}, // S_QUAKE_ACTIVEJ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEL, 0, 0}, // S_QUAKE_ACTIVEK {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEM, 0, 0}, // S_QUAKE_ACTIVEL {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEN, 0, 0}, // S_QUAKE_ACTIVEM {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEO, 0, 0}, // S_QUAKE_ACTIVEN {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEP, 0, 0}, // S_QUAKE_ACTIVEO {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEQ, 0, 0}, // S_QUAKE_ACTIVEP {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVER, 0, 0}, // S_QUAKE_ACTIVEQ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVES, 0, 0}, // S_QUAKE_ACTIVER {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVET, 0, 0}, // S_QUAKE_ACTIVES {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEU, 0, 0}, // S_QUAKE_ACTIVET {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEV, 0, 0}, // S_QUAKE_ACTIVEU {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEW, 0, 0}, // S_QUAKE_ACTIVEV {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEX, 0, 0}, // S_QUAKE_ACTIVEW {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEY, 0, 0}, // S_QUAKE_ACTIVEX {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEZ, 0, 0}, // S_QUAKE_ACTIVEY {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT1, 0, 0}, // S_QUAKE_ACTIVEZ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT2, 0, 0}, // S_QUAKE_ACT1 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT3, 0, 0}, // S_QUAKE_ACT2 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT4, 0, 0}, // S_QUAKE_ACT3 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT5, 0, 0}, // S_QUAKE_ACT4 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT6, 0, 0}, // S_QUAKE_ACT5 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT7, 0, 0}, // S_QUAKE_ACT6 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT8, 0, 0}, // S_QUAKE_ACT7 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT9, 0, 0}, // S_QUAKE_ACT8 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT0, 0, 0}, // S_QUAKE_ACT9 {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE1, 0, 0}, // S_QUAKE_ACT0 {SPR_SGSA, 0, 4, NULL, S_SGSHARD1_2, 0, 0}, // S_SGSHARD1_1 {SPR_SGSA, 1, 4, NULL, S_SGSHARD1_3, 0, 0}, // S_SGSHARD1_2 {SPR_SGSA, 2, 4, NULL, S_SGSHARD1_4, 0, 0}, // S_SGSHARD1_3 {SPR_SGSA, 3, 4, NULL, S_SGSHARD1_5, 0, 0}, // S_SGSHARD1_4 {SPR_SGSA, 4, 4, NULL, S_SGSHARD1_1, 0, 0}, // S_SGSHARD1_5 {SPR_SGSA, 4, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD1_D {SPR_SGSA, 5, 4, NULL, S_SGSHARD2_2, 0, 0}, // S_SGSHARD2_1 {SPR_SGSA, 6, 4, NULL, S_SGSHARD2_3, 0, 0}, // S_SGSHARD2_2 {SPR_SGSA, 7, 4, NULL, S_SGSHARD2_4, 0, 0}, // S_SGSHARD2_3 {SPR_SGSA, 8, 4, NULL, S_SGSHARD2_5, 0, 0}, // S_SGSHARD2_4 {SPR_SGSA, 9, 4, NULL, S_SGSHARD2_1, 0, 0}, // S_SGSHARD2_5 {SPR_SGSA, 9, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD2_D {SPR_SGSA, 10, 4, NULL, S_SGSHARD3_2, 0, 0}, // S_SGSHARD3_1 {SPR_SGSA, 11, 4, NULL, S_SGSHARD3_3, 0, 0}, // S_SGSHARD3_2 {SPR_SGSA, 12, 4, NULL, S_SGSHARD3_4, 0, 0}, // S_SGSHARD3_3 {SPR_SGSA, 13, 4, NULL, S_SGSHARD3_5, 0, 0}, // S_SGSHARD3_4 {SPR_SGSA, 14, 4, NULL, S_SGSHARD3_1, 0, 0}, // S_SGSHARD3_5 {SPR_SGSA, 14, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD3_D {SPR_SGSA, 15, 4, NULL, S_SGSHARD4_2, 0, 0}, // S_SGSHARD4_1 {SPR_SGSA, 16, 4, NULL, S_SGSHARD4_3, 0, 0}, // S_SGSHARD4_2 {SPR_SGSA, 17, 4, NULL, S_SGSHARD4_4, 0, 0}, // S_SGSHARD4_3 {SPR_SGSA, 18, 4, NULL, S_SGSHARD4_5, 0, 0}, // S_SGSHARD4_4 {SPR_SGSA, 19, 4, NULL, S_SGSHARD4_1, 0, 0}, // S_SGSHARD4_5 {SPR_SGSA, 19, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD4_D {SPR_SGSA, 20, 4, NULL, S_SGSHARD5_2, 0, 0}, // S_SGSHARD5_1 {SPR_SGSA, 21, 4, NULL, S_SGSHARD5_3, 0, 0}, // S_SGSHARD5_2 {SPR_SGSA, 22, 4, NULL, S_SGSHARD5_4, 0, 0}, // S_SGSHARD5_3 {SPR_SGSA, 23, 4, NULL, S_SGSHARD5_5, 0, 0}, // S_SGSHARD5_4 {SPR_SGSA, 24, 4, NULL, S_SGSHARD5_1, 0, 0}, // S_SGSHARD5_5 {SPR_SGSA, 24, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD5_D {SPR_SGSB, 0, 4, NULL, S_SGSHARD6_1, 0, 0}, // S_SGSHARD6_1 {SPR_SGSB, 0, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD6_D {SPR_SGSB, 1, 4, NULL, S_SGSHARD7_1, 0, 0}, // S_SGSHARD7_1 {SPR_SGSB, 1, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD7_D {SPR_SGSB, 2, 4, NULL, S_SGSHARD8_1, 0, 0}, // S_SGSHARD8_1 {SPR_SGSB, 2, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD8_D {SPR_SGSB, 3, 4, NULL, S_SGSHARD9_1, 0, 0}, // S_SGSHARD9_1 {SPR_SGSB, 3, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD9_D {SPR_SGSB, 4, 4, NULL, S_SGSHARD0_1, 0, 0}, // S_SGSHARD0_1 {SPR_SGSB, 4, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD0_D {SPR_PORK, 0, 5, NULL, S_ARTI_EGGC2, 0, 0}, // S_ARTI_EGGC1 {SPR_PORK, 1, 5, NULL, S_ARTI_EGGC3, 0, 0}, // S_ARTI_EGGC2 {SPR_PORK, 2, 5, NULL, S_ARTI_EGGC4, 0, 0}, // S_ARTI_EGGC3 {SPR_PORK, 3, 5, NULL, S_ARTI_EGGC5, 0, 0}, // S_ARTI_EGGC4 {SPR_PORK, 4, 5, NULL, S_ARTI_EGGC6, 0, 0}, // S_ARTI_EGGC5 {SPR_PORK, 5, 5, NULL, S_ARTI_EGGC7, 0, 0}, // S_ARTI_EGGC6 {SPR_PORK, 6, 5, NULL, S_ARTI_EGGC8, 0, 0}, // S_ARTI_EGGC7 {SPR_PORK, 7, 5, NULL, S_ARTI_EGGC1, 0, 0}, // S_ARTI_EGGC8 {SPR_EGGM, 0, 4, NULL, S_EGGFX2, 0, 0}, // S_EGGFX1 {SPR_EGGM, 1, 4, NULL, S_EGGFX3, 0, 0}, // S_EGGFX2 {SPR_EGGM, 2, 4, NULL, S_EGGFX4, 0, 0}, // S_EGGFX3 {SPR_EGGM, 3, 4, NULL, S_EGGFX5, 0, 0}, // S_EGGFX4 {SPR_EGGM, 4, 4, NULL, S_EGGFX1, 0, 0}, // S_EGGFX5 {SPR_FHFX, 32776, 3, NULL, S_EGGFXI1_2, 0, 0}, // S_EGGFXI1_1 {SPR_FHFX, 32777, 3, NULL, S_EGGFXI1_3, 0, 0}, // S_EGGFXI1_2 {SPR_FHFX, 32778, 3, NULL, S_EGGFXI1_4, 0, 0}, // S_EGGFXI1_3 {SPR_FHFX, 32779, 3, NULL, S_NULL, 0, 0}, // S_EGGFXI1_4 {SPR_SPHL, 0, 350, NULL, S_ARTI_SPHL1, 0, 0}, // S_ARTI_SPHL1 {SPR_STWN, 0, -1, NULL, S_NULL, 0, 0}, // S_ZWINGEDSTATUENOSKULL {SPR_STWN, 1, -1, NULL, S_NULL, 0, 0}, // S_ZWINGEDSTATUENOSKULL2 {SPR_GMPD, 0, -1, NULL, S_NULL, 0, 0}, // S_ZGEMPEDESTAL1 {SPR_GMPD, 1, -1, NULL, S_NULL, 0, 0}, // S_ZGEMPEDESTAL2 {SPR_ASKU, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZSKULL {SPR_ABGM, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMBIG {SPR_AGMR, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMRED {SPR_AGMG, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMGREEN1 {SPR_AGG2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMGREEN2 {SPR_AGMB, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMBLUE1 {SPR_AGB2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMBLUE2 {SPR_ABK1, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZBOOK1 {SPR_ABK2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZBOOK2 {SPR_ASK2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZSKULL2 {SPR_AFWP, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZFWEAPON {SPR_ACWP, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZCWEAPON {SPR_AMWP, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZMWEAPON {SPR_AGER, 32768, 4, NULL, S_ARTIPUZZGEAR_2, 0, 0}, // S_ARTIPUZZGEAR_1 {SPR_AGER, 32769, 4, NULL, S_ARTIPUZZGEAR_3, 0, 0}, // S_ARTIPUZZGEAR_2 {SPR_AGER, 32770, 4, NULL, S_ARTIPUZZGEAR_4, 0, 0}, // S_ARTIPUZZGEAR_3 {SPR_AGER, 32771, 4, NULL, S_ARTIPUZZGEAR_5, 0, 0}, // S_ARTIPUZZGEAR_4 {SPR_AGER, 32772, 4, NULL, S_ARTIPUZZGEAR_6, 0, 0}, // S_ARTIPUZZGEAR_5 {SPR_AGER, 32773, 4, NULL, S_ARTIPUZZGEAR_7, 0, 0}, // S_ARTIPUZZGEAR_6 {SPR_AGER, 32774, 4, NULL, S_ARTIPUZZGEAR_8, 0, 0}, // S_ARTIPUZZGEAR_7 {SPR_AGER, 32775, 4, NULL, S_ARTIPUZZGEAR_1, 0, 0}, // S_ARTIPUZZGEAR_8 {SPR_AGR2, 32768, 4, NULL, S_ARTIPUZZGEAR2_2, 0, 0}, // S_ARTIPUZZGEAR2_1 {SPR_AGR2, 32769, 4, NULL, S_ARTIPUZZGEAR2_3, 0, 0}, // S_ARTIPUZZGEAR2_2 {SPR_AGR2, 32770, 4, NULL, S_ARTIPUZZGEAR2_4, 0, 0}, // S_ARTIPUZZGEAR2_3 {SPR_AGR2, 32771, 4, NULL, S_ARTIPUZZGEAR2_5, 0, 0}, // S_ARTIPUZZGEAR2_4 {SPR_AGR2, 32772, 4, NULL, S_ARTIPUZZGEAR2_6, 0, 0}, // S_ARTIPUZZGEAR2_5 {SPR_AGR2, 32773, 4, NULL, S_ARTIPUZZGEAR2_7, 0, 0}, // S_ARTIPUZZGEAR2_6 {SPR_AGR2, 32774, 4, NULL, S_ARTIPUZZGEAR2_8, 0, 0}, // S_ARTIPUZZGEAR2_7 {SPR_AGR2, 32775, 4, NULL, S_ARTIPUZZGEAR2_1, 0, 0}, // S_ARTIPUZZGEAR2_8 {SPR_AGR3, 32768, 4, NULL, S_ARTIPUZZGEAR3_2, 0, 0}, // S_ARTIPUZZGEAR3_1 {SPR_AGR3, 32769, 4, NULL, S_ARTIPUZZGEAR3_3, 0, 0}, // S_ARTIPUZZGEAR3_2 {SPR_AGR3, 32770, 4, NULL, S_ARTIPUZZGEAR3_4, 0, 0}, // S_ARTIPUZZGEAR3_3 {SPR_AGR3, 32771, 4, NULL, S_ARTIPUZZGEAR3_5, 0, 0}, // S_ARTIPUZZGEAR3_4 {SPR_AGR3, 32772, 4, NULL, S_ARTIPUZZGEAR3_6, 0, 0}, // S_ARTIPUZZGEAR3_5 {SPR_AGR3, 32773, 4, NULL, S_ARTIPUZZGEAR3_7, 0, 0}, // S_ARTIPUZZGEAR3_6 {SPR_AGR3, 32774, 4, NULL, S_ARTIPUZZGEAR3_8, 0, 0}, // S_ARTIPUZZGEAR3_7 {SPR_AGR3, 32775, 4, NULL, S_ARTIPUZZGEAR3_1, 0, 0}, // S_ARTIPUZZGEAR3_8 {SPR_AGR4, 32768, 4, NULL, S_ARTIPUZZGEAR4_2, 0, 0}, // S_ARTIPUZZGEAR4_1 {SPR_AGR4, 32769, 4, NULL, S_ARTIPUZZGEAR4_3, 0, 0}, // S_ARTIPUZZGEAR4_2 {SPR_AGR4, 32770, 4, NULL, S_ARTIPUZZGEAR4_4, 0, 0}, // S_ARTIPUZZGEAR4_3 {SPR_AGR4, 32771, 4, NULL, S_ARTIPUZZGEAR4_5, 0, 0}, // S_ARTIPUZZGEAR4_4 {SPR_AGR4, 32772, 4, NULL, S_ARTIPUZZGEAR4_6, 0, 0}, // S_ARTIPUZZGEAR4_5 {SPR_AGR4, 32773, 4, NULL, S_ARTIPUZZGEAR4_7, 0, 0}, // S_ARTIPUZZGEAR4_6 {SPR_AGR4, 32774, 4, NULL, S_ARTIPUZZGEAR4_8, 0, 0}, // S_ARTIPUZZGEAR4_7 {SPR_AGR4, 32775, 4, NULL, S_ARTIPUZZGEAR4_1, 0, 0}, // S_ARTIPUZZGEAR4_8 {SPR_TRCH, 32768, 3, NULL, S_ARTI_TRCH2, 0, 0}, // S_ARTI_TRCH1 {SPR_TRCH, 32769, 3, NULL, S_ARTI_TRCH3, 0, 0}, // S_ARTI_TRCH2 {SPR_TRCH, 32770, 3, NULL, S_ARTI_TRCH1, 0, 0}, // S_ARTI_TRCH3 {SPR_PSBG, 0, 20, NULL, S_FIREBOMB2, 0, 0}, // S_FIREBOMB1 {SPR_PSBG, 0, 10, NULL, S_FIREBOMB3, 0, 0}, // S_FIREBOMB2 {SPR_PSBG, 0, 10, NULL, S_FIREBOMB4, 0, 0}, // S_FIREBOMB3 {SPR_PSBG, 1, 4, NULL, S_FIREBOMB5, 0, 0}, // S_FIREBOMB4 {SPR_PSBG, 2, 4, A_Scream, S_FIREBOMB6, 0, 0}, // S_FIREBOMB5 {SPR_XPL1, 32768, 4, A_Explode, S_FIREBOMB7, 0, 0}, // S_FIREBOMB6 {SPR_XPL1, 32769, 4, NULL, S_FIREBOMB8, 0, 0}, // S_FIREBOMB7 {SPR_XPL1, 32770, 4, NULL, S_FIREBOMB9, 0, 0}, // S_FIREBOMB8 {SPR_XPL1, 32771, 4, NULL, S_FIREBOMB10, 0, 0}, // S_FIREBOMB9 {SPR_XPL1, 32772, 4, NULL, S_FIREBOMB11, 0, 0}, // S_FIREBOMB10 {SPR_XPL1, 32773, 4, NULL, S_NULL, 0, 0}, // S_FIREBOMB11 {SPR_ATLP, 0, 4, NULL, S_ARTI_ATLP2, 0, 0}, // S_ARTI_ATLP1 {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP3, 0, 0}, // S_ARTI_ATLP2 {SPR_ATLP, 2, 4, NULL, S_ARTI_ATLP4, 0, 0}, // S_ARTI_ATLP3 {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP1, 0, 0}, // S_ARTI_ATLP4 {SPR_PSBG, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTI_PSBG1 {SPR_PSBG, 32768, 18, NULL, S_POISONBAG2, 0, 0}, // S_POISONBAG1 {SPR_PSBG, 32769, 4, NULL, S_POISONBAG3, 0, 0}, // S_POISONBAG2 {SPR_PSBG, 2, 3, NULL, S_POISONBAG4, 0, 0}, // S_POISONBAG3 {SPR_PSBG, 2, 1, A_PoisonBagInit, S_NULL, 0, 0}, // S_POISONBAG4 {SPR_PSBG, 3, 1, NULL, S_POISONCLOUD2, 0, 0}, // S_POISONCLOUD1 {SPR_PSBG, 3, 1, A_Scream, S_POISONCLOUD3, 0, 0}, // S_POISONCLOUD2 {SPR_PSBG, 3, 2, A_PoisonBagDamage, S_POISONCLOUD4, 0, 0}, // S_POISONCLOUD3 {SPR_PSBG, 4, 2, A_PoisonBagDamage, S_POISONCLOUD5, 0, 0}, // S_POISONCLOUD4 {SPR_PSBG, 4, 2, A_PoisonBagDamage, S_POISONCLOUD6, 0, 0}, // S_POISONCLOUD5 {SPR_PSBG, 4, 2, A_PoisonBagDamage, S_POISONCLOUD7, 0, 0}, // S_POISONCLOUD6 {SPR_PSBG, 5, 2, A_PoisonBagDamage, S_POISONCLOUD8, 0, 0}, // S_POISONCLOUD7 {SPR_PSBG, 5, 2, A_PoisonBagDamage, S_POISONCLOUD9, 0, 0}, // S_POISONCLOUD8 {SPR_PSBG, 5, 2, A_PoisonBagDamage, S_POISONCLOUD10, 0, 0}, // S_POISONCLOUD9 {SPR_PSBG, 6, 2, A_PoisonBagDamage, S_POISONCLOUD11, 0, 0}, // S_POISONCLOUD10 {SPR_PSBG, 6, 2, A_PoisonBagDamage, S_POISONCLOUD12, 0, 0}, // S_POISONCLOUD11 {SPR_PSBG, 6, 2, A_PoisonBagDamage, S_POISONCLOUD13, 0, 0}, // S_POISONCLOUD12 {SPR_PSBG, 7, 2, A_PoisonBagDamage, S_POISONCLOUD14, 0, 0}, // S_POISONCLOUD13 {SPR_PSBG, 7, 2, A_PoisonBagDamage, S_POISONCLOUD15, 0, 0}, // S_POISONCLOUD14 {SPR_PSBG, 7, 2, A_PoisonBagDamage, S_POISONCLOUD16, 0, 0}, // S_POISONCLOUD15 {SPR_PSBG, 8, 2, A_PoisonBagDamage, S_POISONCLOUD17, 0, 0}, // S_POISONCLOUD16 {SPR_PSBG, 8, 1, A_PoisonBagDamage, S_POISONCLOUD18, 0, 0}, // S_POISONCLOUD17 {SPR_PSBG, 8, 1, A_PoisonBagCheck, S_POISONCLOUD4, 0, 0}, // S_POISONCLOUD18 {SPR_PSBG, 7, 7, NULL, S_POISONCLOUD_X2, 0, 0}, // S_POISONCLOUD_X1 {SPR_PSBG, 6, 7, NULL, S_POISONCLOUD_X3, 0, 0}, // S_POISONCLOUD_X2 {SPR_PSBG, 5, 6, NULL, S_POISONCLOUD_X4, 0, 0}, // S_POISONCLOUD_X3 {SPR_PSBG, 3, 6, NULL, S_NULL, 0, 0}, // S_POISONCLOUD_X4 {SPR_THRW, 0, 4, A_CheckThrowBomb, S_THROWINGBOMB2, 0, 0}, // S_THROWINGBOMB1 {SPR_THRW, 1, 3, A_CheckThrowBomb, S_THROWINGBOMB3, 0, 0}, // S_THROWINGBOMB2 {SPR_THRW, 2, 3, A_CheckThrowBomb, S_THROWINGBOMB4, 0, 0}, // S_THROWINGBOMB3 {SPR_THRW, 3, 3, A_CheckThrowBomb, S_THROWINGBOMB5, 0, 0}, // S_THROWINGBOMB4 {SPR_THRW, 4, 3, A_CheckThrowBomb, S_THROWINGBOMB6, 0, 0}, // S_THROWINGBOMB5 {SPR_THRW, 5, 3, A_CheckThrowBomb, S_THROWINGBOMB1, 0, 0}, // S_THROWINGBOMB6 {SPR_THRW, 6, 6, A_CheckThrowBomb, S_THROWINGBOMB8, 0, 0}, // S_THROWINGBOMB7 {SPR_THRW, 5, 4, A_CheckThrowBomb, S_THROWINGBOMB9, 0, 0}, // S_THROWINGBOMB8 {SPR_THRW, 7, 6, A_CheckThrowBomb, S_THROWINGBOMB10, 0, 0}, // S_THROWINGBOMB9 {SPR_THRW, 5, 4, A_CheckThrowBomb, S_THROWINGBOMB11, 0, 0}, // S_THROWINGBOMB10 {SPR_THRW, 6, 6, A_CheckThrowBomb, S_THROWINGBOMB12, 0, 0}, // S_THROWINGBOMB11 {SPR_THRW, 5, 3, A_CheckThrowBomb, S_THROWINGBOMB12, 0, 0}, // S_THROWINGBOMB12 {SPR_CFCF, 32784, 4, A_NoGravity, S_THROWINGBOMB_X2, 0, 0}, // S_THROWINGBOMB_X1 {SPR_CFCF, 32785, 3, A_Scream, S_THROWINGBOMB_X3, 0, 0}, // S_THROWINGBOMB_X2 {SPR_CFCF, 32786, 4, A_Explode, S_THROWINGBOMB_X4, 0, 0}, // S_THROWINGBOMB_X3 {SPR_CFCF, 32787, 3, NULL, S_THROWINGBOMB_X5, 0, 0}, // S_THROWINGBOMB_X4 {SPR_CFCF, 32788, 4, NULL, S_THROWINGBOMB_X6, 0, 0}, // S_THROWINGBOMB_X5 {SPR_CFCF, 32790, 3, NULL, S_THROWINGBOMB_X7, 0, 0}, // S_THROWINGBOMB_X6 {SPR_CFCF, 32791, 4, NULL, S_THROWINGBOMB_X8, 0, 0}, // S_THROWINGBOMB_X7 {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_THROWINGBOMB_X8 {SPR_SPED, 32768, 3, NULL, S_ARTI_BOOTS2, 0, 0}, // S_ARTI_BOOTS1 {SPR_SPED, 32769, 3, NULL, S_ARTI_BOOTS3, 0, 0}, // S_ARTI_BOOTS2 {SPR_SPED, 32770, 3, NULL, S_ARTI_BOOTS4, 0, 0}, // S_ARTI_BOOTS3 {SPR_SPED, 32771, 3, NULL, S_ARTI_BOOTS5, 0, 0}, // S_ARTI_BOOTS4 {SPR_SPED, 32772, 3, NULL, S_ARTI_BOOTS6, 0, 0}, // S_ARTI_BOOTS5 {SPR_SPED, 32773, 3, NULL, S_ARTI_BOOTS7, 0, 0}, // S_ARTI_BOOTS6 {SPR_SPED, 32774, 3, NULL, S_ARTI_BOOTS8, 0, 0}, // S_ARTI_BOOTS7 {SPR_SPED, 32775, 3, NULL, S_ARTI_BOOTS1, 0, 0}, // S_ARTI_BOOTS8 {SPR_BMAN, 32768, -1, NULL, S_NULL, 0, 0}, // S_ARTI_MANA {SPR_BRAC, 32768, 4, NULL, S_ARTI_ARMOR2, 0, 0}, // S_ARTI_ARMOR1 {SPR_BRAC, 32769, 4, NULL, S_ARTI_ARMOR3, 0, 0}, // S_ARTI_ARMOR2 {SPR_BRAC, 32770, 4, NULL, S_ARTI_ARMOR4, 0, 0}, // S_ARTI_ARMOR3 {SPR_BRAC, 32771, 4, NULL, S_ARTI_ARMOR5, 0, 0}, // S_ARTI_ARMOR4 {SPR_BRAC, 32772, 4, NULL, S_ARTI_ARMOR6, 0, 0}, // S_ARTI_ARMOR5 {SPR_BRAC, 32773, 4, NULL, S_ARTI_ARMOR7, 0, 0}, // S_ARTI_ARMOR6 {SPR_BRAC, 32774, 4, NULL, S_ARTI_ARMOR8, 0, 0}, // S_ARTI_ARMOR7 {SPR_BRAC, 32775, 4, NULL, S_ARTI_ARMOR1, 0, 0}, // S_ARTI_ARMOR8 {SPR_BLST, 32768, 4, NULL, S_ARTI_BLAST2, 0, 0}, // S_ARTI_BLAST1 {SPR_BLST, 32769, 4, NULL, S_ARTI_BLAST3, 0, 0}, // S_ARTI_BLAST2 {SPR_BLST, 32770, 4, NULL, S_ARTI_BLAST4, 0, 0}, // S_ARTI_BLAST3 {SPR_BLST, 32771, 4, NULL, S_ARTI_BLAST5, 0, 0}, // S_ARTI_BLAST4 {SPR_BLST, 32772, 4, NULL, S_ARTI_BLAST6, 0, 0}, // S_ARTI_BLAST5 {SPR_BLST, 32773, 4, NULL, S_ARTI_BLAST7, 0, 0}, // S_ARTI_BLAST6 {SPR_BLST, 32774, 4, NULL, S_ARTI_BLAST8, 0, 0}, // S_ARTI_BLAST7 {SPR_BLST, 32775, 4, NULL, S_ARTI_BLAST1, 0, 0}, // S_ARTI_BLAST8 {SPR_HRAD, 32768, 4, NULL, S_ARTI_HEALRAD2, 0, 0}, // S_ARTI_HEALRAD1 {SPR_HRAD, 32769, 4, NULL, S_ARTI_HEALRAD3, 0, 0}, // S_ARTI_HEALRAD2 {SPR_HRAD, 32770, 4, NULL, S_ARTI_HEALRAD4, 0, 0}, // S_ARTI_HEALRAD3 {SPR_HRAD, 32771, 4, NULL, S_ARTI_HEALRAD5, 0, 0}, // S_ARTI_HEALRAD4 {SPR_HRAD, 32772, 4, NULL, S_ARTI_HEALRAD6, 0, 0}, // S_ARTI_HEALRAD5 {SPR_HRAD, 32773, 4, NULL, S_ARTI_HEALRAD7, 0, 0}, // S_ARTI_HEALRAD6 {SPR_HRAD, 32774, 4, NULL, S_ARTI_HEALRAD8, 0, 0}, // S_ARTI_HEALRAD7 {SPR_HRAD, 32775, 4, NULL, S_ARTI_HEALRAD9, 0, 0}, // S_ARTI_HEALRAD8 {SPR_HRAD, 32776, 4, NULL, S_ARTI_HEALRAD0, 0, 0}, // S_ARTI_HEALRAD9 {SPR_HRAD, 32777, 4, NULL, S_ARTI_HEALRADA, 0, 0}, // S_ARTI_HEALRAD0 {SPR_HRAD, 32778, 4, NULL, S_ARTI_HEALRADB, 0, 0}, // S_ARTI_HEALRADA {SPR_HRAD, 32779, 4, NULL, S_ARTI_HEALRADC, 0, 0}, // S_ARTI_HEALRADB {SPR_HRAD, 32780, 4, NULL, S_ARTI_HEALRADD, 0, 0}, // S_ARTI_HEALRADC {SPR_HRAD, 32781, 4, NULL, S_ARTI_HEALRADE, 0, 0}, // S_ARTI_HEALRADD {SPR_HRAD, 32782, 4, NULL, S_ARTI_HEALRADF, 0, 0}, // S_ARTI_HEALRADE {SPR_HRAD, 32783, 4, NULL, S_ARTI_HEALRAD1, 0, 0}, // S_ARTI_HEALRADF {SPR_SPSH, 0, 8, NULL, S_SPLASH2, 0, 0}, // S_SPLASH1 {SPR_SPSH, 1, 8, NULL, S_SPLASH3, 0, 0}, // S_SPLASH2 {SPR_SPSH, 2, 8, NULL, S_SPLASH4, 0, 0}, // S_SPLASH3 {SPR_SPSH, 3, 16, NULL, S_NULL, 0, 0}, // S_SPLASH4 {SPR_SPSH, 3, 10, NULL, S_NULL, 0, 0}, // S_SPLASHX {SPR_SPSH, 4, 5, NULL, S_SPLASHBASE2, 0, 0}, // S_SPLASHBASE1 {SPR_SPSH, 5, 5, NULL, S_SPLASHBASE3, 0, 0}, // S_SPLASHBASE2 {SPR_SPSH, 6, 5, NULL, S_SPLASHBASE4, 0, 0}, // S_SPLASHBASE3 {SPR_SPSH, 7, 5, NULL, S_SPLASHBASE5, 0, 0}, // S_SPLASHBASE4 {SPR_SPSH, 8, 5, NULL, S_SPLASHBASE6, 0, 0}, // S_SPLASHBASE5 {SPR_SPSH, 9, 5, NULL, S_SPLASHBASE7, 0, 0}, // S_SPLASHBASE6 {SPR_SPSH, 10, 5, NULL, S_NULL, 0, 0}, // S_SPLASHBASE7 {SPR_LVAS, 32768, 5, NULL, S_LAVASPLASH2, 0, 0}, // S_LAVASPLASH1 {SPR_LVAS, 32769, 5, NULL, S_LAVASPLASH3, 0, 0}, // S_LAVASPLASH2 {SPR_LVAS, 32770, 5, NULL, S_LAVASPLASH4, 0, 0}, // S_LAVASPLASH3 {SPR_LVAS, 32771, 5, NULL, S_LAVASPLASH5, 0, 0}, // S_LAVASPLASH4 {SPR_LVAS, 32772, 5, NULL, S_LAVASPLASH6, 0, 0}, // S_LAVASPLASH5 {SPR_LVAS, 32773, 5, NULL, S_NULL, 0, 0}, // S_LAVASPLASH6 {SPR_LVAS, 32774, 5, NULL, S_LAVASMOKE2, 0, 0}, // S_LAVASMOKE1 {SPR_LVAS, 32775, 5, NULL, S_LAVASMOKE3, 0, 0}, // S_LAVASMOKE2 {SPR_LVAS, 32776, 5, NULL, S_LAVASMOKE4, 0, 0}, // S_LAVASMOKE3 {SPR_LVAS, 32777, 5, NULL, S_LAVASMOKE5, 0, 0}, // S_LAVASMOKE4 {SPR_LVAS, 32778, 5, NULL, S_NULL, 0, 0}, // S_LAVASMOKE5 {SPR_SLDG, 0, 8, NULL, S_SLUDGECHUNK2, 0, 0}, // S_SLUDGECHUNK1 {SPR_SLDG, 1, 8, NULL, S_SLUDGECHUNK3, 0, 0}, // S_SLUDGECHUNK2 {SPR_SLDG, 2, 8, NULL, S_SLUDGECHUNK4, 0, 0}, // S_SLUDGECHUNK3 {SPR_SLDG, 3, 8, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNK4 {SPR_SLDG, 3, 6, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNKX {SPR_SLDG, 4, 6, NULL, S_SLUDGESPLASH2, 0, 0}, // S_SLUDGESPLASH1 {SPR_SLDG, 5, 6, NULL, S_SLUDGESPLASH3, 0, 0}, // S_SLUDGESPLASH2 {SPR_SLDG, 6, 6, NULL, S_SLUDGESPLASH4, 0, 0}, // S_SLUDGESPLASH3 {SPR_SLDG, 7, 6, NULL, S_NULL, 0, 0}, // S_SLUDGESPLASH4 {SPR_STTW, 0, -1, NULL, S_NULL, 0, 0}, // S_ZWINGEDSTATUE1 {SPR_RCK1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK1_1 {SPR_RCK2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK2_1 {SPR_RCK3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK3_1 {SPR_RCK4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK4_1 {SPR_CDLR, 0, 4, NULL, S_ZCHANDELIER2, 0, 0}, // S_ZCHANDELIER1 {SPR_CDLR, 1, 4, NULL, S_ZCHANDELIER3, 0, 0}, // S_ZCHANDELIER2 {SPR_CDLR, 2, 4, NULL, S_ZCHANDELIER1, 0, 0}, // S_ZCHANDELIER3 {SPR_CDLR, 3, -1, NULL, S_NULL, 0, 0}, // S_ZCHANDELIER_U {SPR_TRE1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDEAD1 {SPR_TRE1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREE {SPR_TRDT, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDESTRUCTIBLE1 {SPR_TRDT, 1, 5, NULL, S_ZTREEDES_D2, 0, 0}, // S_ZTREEDES_D1 {SPR_TRDT, 2, 5, A_Scream, S_ZTREEDES_D3, 0, 0}, // S_ZTREEDES_D2 {SPR_TRDT, 3, 5, NULL, S_ZTREEDES_D4, 0, 0}, // S_ZTREEDES_D3 {SPR_TRDT, 4, 5, NULL, S_ZTREEDES_D5, 0, 0}, // S_ZTREEDES_D4 {SPR_TRDT, 5, 5, NULL, S_ZTREEDES_D6, 0, 0}, // S_ZTREEDES_D5 {SPR_TRDT, 6, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDES_D6 {SPR_TRDT, 32775, 5, NULL, S_ZTREEDES_X2, 0, 0}, // S_ZTREEDES_X1 {SPR_TRDT, 32776, 5, NULL, S_ZTREEDES_X3, 0, 0}, // S_ZTREEDES_X2 {SPR_TRDT, 32777, 5, NULL, S_ZTREEDES_X4, 0, 0}, // S_ZTREEDES_X3 {SPR_TRDT, 32778, 5, NULL, S_ZTREEDES_X5, 0, 0}, // S_ZTREEDES_X4 {SPR_TRDT, 32779, 5, NULL, S_ZTREEDES_X6, 0, 0}, // S_ZTREEDES_X5 {SPR_TRDT, 32780, 5, A_Explode, S_ZTREEDES_X7, 0, 0}, // S_ZTREEDES_X6 {SPR_TRDT, 32781, 5, NULL, S_ZTREEDES_X8, 0, 0}, // S_ZTREEDES_X7 {SPR_TRDT, 14, 5, NULL, S_ZTREEDES_X9, 0, 0}, // S_ZTREEDES_X8 {SPR_TRDT, 15, 5, NULL, S_ZTREEDES_X10, 0, 0}, // S_ZTREEDES_X9 {SPR_TRDT, 16, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDES_X10 {SPR_TRE2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREESWAMP182_1 {SPR_TRE3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREESWAMP172_1 {SPR_STM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPBURNED1 {SPR_STM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPBARE1 {SPR_STM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPSWAMP1_1 {SPR_STM4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPSWAMP2_1 {SPR_MSH1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMLARGE1_1 {SPR_MSH2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMLARGE2_1 {SPR_MSH3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMLARGE3_1 {SPR_MSH4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL1_1 {SPR_MSH5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL2_1 {SPR_MSH6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL3_1 {SPR_MSH7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL4_1 {SPR_MSH8, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL5_1 {SPR_SGMP, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEPILLAR1 {SPR_SGM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITELARGE1 {SPR_SGM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEMEDIUM1 {SPR_SGM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITESMALL1 {SPR_SLC1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITELARGE1 {SPR_SLC2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEMEDIUM1 {SPR_SLC3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITESMALL1 {SPR_MSS1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZMOSSCEILING1_1 {SPR_MSS2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZMOSSCEILING2_1 {SPR_SWMV, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSWAMPVINE1 {SPR_CPS1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSEKABOB1 {SPR_CPS2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSESLEEPING1 {SPR_TMS1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONERIP1 {SPR_TMS2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONESHANE1 {SPR_TMS3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONEBIGCROSS1 {SPR_TMS4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONEBRIANR1 {SPR_TMS5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONECROSSCIRCLE1 {SPR_TMS6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONESMALLCROSS1 {SPR_TMS7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONEBRIANP1 {SPR_CPS3, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEHANGING_1 {SPR_STT2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEGREENTALL_1 {SPR_STT3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEBLUETALL_1 {SPR_STT4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEGREENSHORT_1 {SPR_STT5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEBLUESHORT_1 {SPR_GAR1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLESTRIPETALL_1 {SPR_GAR2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEDARKREDTALL_1 {SPR_GAR3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEREDTALL_1 {SPR_GAR4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLETANTALL_1 {SPR_GAR5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLERUSTTALL_1 {SPR_GAR6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEDARKREDSHORT_1 {SPR_GAR7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEREDSHORT_1 {SPR_GAR8, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLETANSHORT_1 {SPR_GAR9, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLERUSTSHORT_1 {SPR_BNR1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZBANNERTATTERED_1 {SPR_TRE4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREELARGE1 {SPR_TRE5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREELARGE2 {SPR_TRE6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEGNARLED1 {SPR_TRE7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEGNARLED2 {SPR_LOGG, 0, -1, NULL, S_NULL, 0, 0}, // S_ZLOG {SPR_ICT1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICELARGE {SPR_ICT2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICEMEDIUM {SPR_ICT3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICESMALL {SPR_ICT4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICETINY {SPR_ICM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICELARGE {SPR_ICM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICEMEDIUM {SPR_ICM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICESMALL {SPR_ICM4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICETINY {SPR_RKBL, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCKBROWN1 {SPR_RKBS, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCKBROWN2 {SPR_RKBK, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCKBLACK {SPR_RBL1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZRUBBLE1 {SPR_RBL2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZRUBBLE2 {SPR_RBL3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZRUBBLE3 {SPR_VASE, 0, -1, NULL, S_NULL, 0, 0}, // S_ZVASEPILLAR {SPR_POT1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZPOTTERY1 {SPR_POT2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZPOTTERY2 {SPR_POT3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZPOTTERY3 {SPR_POT1, 0, 0, A_PotteryExplode, S_NULL, 0, 0}, // S_ZPOTTERY_EXPLODE {SPR_PBIT, 0, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_1 {SPR_PBIT, 1, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_2 {SPR_PBIT, 2, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_3 {SPR_PBIT, 3, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_4 {SPR_PBIT, 4, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_5 {SPR_PBIT, 5, 0, A_PotteryChooseBit, S_NULL, 0, 0}, // S_POTTERYBIT_EX0 {SPR_PBIT, 5, 140, NULL, S_POTTERYBIT_EX1_2, 0, 0}, // S_POTTERYBIT_EX1 {SPR_PBIT, 5, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX1_2 {SPR_PBIT, 6, 140, NULL, S_POTTERYBIT_EX2_2, 0, 0}, // S_POTTERYBIT_EX2 {SPR_PBIT, 6, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX2_2 {SPR_PBIT, 7, 140, NULL, S_POTTERYBIT_EX3_2, 0, 0}, // S_POTTERYBIT_EX3 {SPR_PBIT, 7, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX3_2 {SPR_PBIT, 8, 140, NULL, S_POTTERYBIT_EX4_2, 0, 0}, // S_POTTERYBIT_EX4 {SPR_PBIT, 8, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX4_2 {SPR_PBIT, 9, 140, NULL, S_POTTERYBIT_EX5_2, 0, 0}, // S_POTTERYBIT_EX5 {SPR_PBIT, 9, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX5_2 {SPR_CPS4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSELYNCHED1 {SPR_CPS5, 0, 140, A_CorpseBloodDrip, S_ZCORPSELYNCHED2, 0, 0}, // S_ZCORPSELYNCHED2 {SPR_CPS6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSESITTING {SPR_CPS6, 0, 1, A_CorpseExplode, S_NULL, 0, 0}, // S_ZCORPSESITTING_X {SPR_CPB1, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_1 {SPR_CPB2, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_2 {SPR_CPB3, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_3 {SPR_CPB4, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_4 {SPR_BDRP, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBLOODDRIP {SPR_BDSH, 0, 3, NULL, S_CORPSEBLOODDRIP_X2, 0, 0}, // S_CORPSEBLOODDRIP_X1 {SPR_BDSH, 1, 3, NULL, S_CORPSEBLOODDRIP_X3, 0, 0}, // S_CORPSEBLOODDRIP_X2 {SPR_BDSH, 2, 2, NULL, S_CORPSEBLOODDRIP_X4, 0, 0}, // S_CORPSEBLOODDRIP_X3 {SPR_BDSH, 3, 2, NULL, S_NULL, 0, 0}, // S_CORPSEBLOODDRIP_X4 {SPR_BDPL, 0, -1, NULL, S_NULL, 0, 0}, // S_BLOODPOOL {SPR_CNDL, 32768, 4, NULL, S_ZCANDLE2, 0, 0}, // S_ZCANDLE1 {SPR_CNDL, 32769, 4, NULL, S_ZCANDLE3, 0, 0}, // S_ZCANDLE2 {SPR_CNDL, 32770, 4, NULL, S_ZCANDLE1, 0, 0}, // S_ZCANDLE3 {SPR_MAN1, 0, 20, A_LeafSpawn, S_ZLEAFSPAWNER, 0, 0}, // S_ZLEAFSPAWNER {SPR_LEF1, 0, 4, NULL, S_LEAF1_2, 0, 0}, // S_LEAF1_1 {SPR_LEF1, 1, 4, NULL, S_LEAF1_3, 0, 0}, // S_LEAF1_2 {SPR_LEF1, 2, 4, NULL, S_LEAF1_4, 0, 0}, // S_LEAF1_3 {SPR_LEF1, 3, 4, A_LeafThrust, S_LEAF1_5, 0, 0}, // S_LEAF1_4 {SPR_LEF1, 4, 4, NULL, S_LEAF1_6, 0, 0}, // S_LEAF1_5 {SPR_LEF1, 5, 4, NULL, S_LEAF1_7, 0, 0}, // S_LEAF1_6 {SPR_LEF1, 6, 4, NULL, S_LEAF1_8, 0, 0}, // S_LEAF1_7 {SPR_LEF1, 7, 4, A_LeafThrust, S_LEAF1_9, 0, 0}, // S_LEAF1_8 {SPR_LEF1, 8, 4, NULL, S_LEAF1_10, 0, 0}, // S_LEAF1_9 {SPR_LEF1, 0, 4, NULL, S_LEAF1_11, 0, 0}, // S_LEAF1_10 {SPR_LEF1, 1, 4, NULL, S_LEAF1_12, 0, 0}, // S_LEAF1_11 {SPR_LEF1, 2, 4, A_LeafThrust, S_LEAF1_13, 0, 0}, // S_LEAF1_12 {SPR_LEF1, 3, 4, NULL, S_LEAF1_14, 0, 0}, // S_LEAF1_13 {SPR_LEF1, 4, 4, NULL, S_LEAF1_15, 0, 0}, // S_LEAF1_14 {SPR_LEF1, 5, 4, NULL, S_LEAF1_16, 0, 0}, // S_LEAF1_15 {SPR_LEF1, 6, 4, A_LeafThrust, S_LEAF1_17, 0, 0}, // S_LEAF1_16 {SPR_LEF1, 7, 4, NULL, S_LEAF1_18, 0, 0}, // S_LEAF1_17 {SPR_LEF1, 8, 4, NULL, S_NULL, 0, 0}, // S_LEAF1_18 {SPR_LEF3, 3, 10, A_LeafCheck, S_LEAF_X1, 0, 0}, // S_LEAF_X1 {SPR_LEF2, 0, 4, NULL, S_LEAF2_2, 0, 0}, // S_LEAF2_1 {SPR_LEF2, 1, 4, NULL, S_LEAF2_3, 0, 0}, // S_LEAF2_2 {SPR_LEF2, 2, 4, NULL, S_LEAF2_4, 0, 0}, // S_LEAF2_3 {SPR_LEF2, 3, 4, A_LeafThrust, S_LEAF2_5, 0, 0}, // S_LEAF2_4 {SPR_LEF2, 4, 4, NULL, S_LEAF2_6, 0, 0}, // S_LEAF2_5 {SPR_LEF2, 5, 4, NULL, S_LEAF2_7, 0, 0}, // S_LEAF2_6 {SPR_LEF2, 6, 4, NULL, S_LEAF2_8, 0, 0}, // S_LEAF2_7 {SPR_LEF2, 7, 4, A_LeafThrust, S_LEAF2_9, 0, 0}, // S_LEAF2_8 {SPR_LEF2, 8, 4, NULL, S_LEAF2_10, 0, 0}, // S_LEAF2_9 {SPR_LEF2, 0, 4, NULL, S_LEAF2_11, 0, 0}, // S_LEAF2_10 {SPR_LEF2, 1, 4, NULL, S_LEAF2_12, 0, 0}, // S_LEAF2_11 {SPR_LEF2, 2, 4, A_LeafThrust, S_LEAF2_13, 0, 0}, // S_LEAF2_12 {SPR_LEF2, 3, 4, NULL, S_LEAF2_14, 0, 0}, // S_LEAF2_13 {SPR_LEF2, 4, 4, NULL, S_LEAF2_15, 0, 0}, // S_LEAF2_14 {SPR_LEF2, 5, 4, NULL, S_LEAF2_16, 0, 0}, // S_LEAF2_15 {SPR_LEF2, 6, 4, A_LeafThrust, S_LEAF2_17, 0, 0}, // S_LEAF2_16 {SPR_LEF2, 7, 4, NULL, S_LEAF2_18, 0, 0}, // S_LEAF2_17 {SPR_LEF2, 8, 4, NULL, S_NULL, 0, 0}, // S_LEAF2_18 {SPR_TWTR, 32768, 4, NULL, S_ZTWINEDTORCH_2, 0, 0}, // S_ZTWINEDTORCH_1 {SPR_TWTR, 32769, 4, NULL, S_ZTWINEDTORCH_3, 0, 0}, // S_ZTWINEDTORCH_2 {SPR_TWTR, 32770, 4, NULL, S_ZTWINEDTORCH_4, 0, 0}, // S_ZTWINEDTORCH_3 {SPR_TWTR, 32771, 4, NULL, S_ZTWINEDTORCH_5, 0, 0}, // S_ZTWINEDTORCH_4 {SPR_TWTR, 32772, 4, NULL, S_ZTWINEDTORCH_6, 0, 0}, // S_ZTWINEDTORCH_5 {SPR_TWTR, 32773, 4, NULL, S_ZTWINEDTORCH_7, 0, 0}, // S_ZTWINEDTORCH_6 {SPR_TWTR, 32774, 4, NULL, S_ZTWINEDTORCH_8, 0, 0}, // S_ZTWINEDTORCH_7 {SPR_TWTR, 32775, 4, NULL, S_ZTWINEDTORCH_1, 0, 0}, // S_ZTWINEDTORCH_8 {SPR_TWTR, 8, -1, NULL, S_NULL, 0, 0}, // S_ZTWINEDTORCH_UNLIT {SPR_TLGL, 0, 2, NULL, S_BRIDGE2, 0, 0}, // S_BRIDGE1 {SPR_TLGL, 0, 2, A_BridgeInit, S_BRIDGE3, 0, 0}, // S_BRIDGE2 {SPR_TLGL, 0, -1, NULL, S_NULL, 0, 0}, // S_BRIDGE3 {SPR_TLGL, 0, 2, NULL, S_FREE_BRIDGE2, 0, 0}, // S_FREE_BRIDGE1 {SPR_TLGL, 0, 300, NULL, S_NULL, 0, 0}, // S_FREE_BRIDGE2 {SPR_TLGL, 0, 2, NULL, S_BBALL2, 0, 0}, // S_BBALL1 {SPR_TLGL, 0, 5, A_BridgeOrbit, S_BBALL2, 0, 0}, // S_BBALL2 {SPR_WLTR, 32768, 5, NULL, S_ZWALLTORCH2, 0, 0}, // S_ZWALLTORCH1 {SPR_WLTR, 32769, 5, NULL, S_ZWALLTORCH3, 0, 0}, // S_ZWALLTORCH2 {SPR_WLTR, 32770, 5, NULL, S_ZWALLTORCH4, 0, 0}, // S_ZWALLTORCH3 {SPR_WLTR, 32771, 5, NULL, S_ZWALLTORCH5, 0, 0}, // S_ZWALLTORCH4 {SPR_WLTR, 32772, 5, NULL, S_ZWALLTORCH6, 0, 0}, // S_ZWALLTORCH5 {SPR_WLTR, 32773, 5, NULL, S_ZWALLTORCH7, 0, 0}, // S_ZWALLTORCH6 {SPR_WLTR, 32774, 5, NULL, S_ZWALLTORCH8, 0, 0}, // S_ZWALLTORCH7 {SPR_WLTR, 32775, 5, NULL, S_ZWALLTORCH1, 0, 0}, // S_ZWALLTORCH8 {SPR_WLTR, 8, -1, NULL, S_NULL, 0, 0}, // S_ZWALLTORCH_U {SPR_BARL, 0, -1, NULL, S_NULL, 0, 0}, // S_ZBARREL1 {SPR_SHB1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHRUB1 {SPR_SHB1, 0, 1, A_TreeDeath, S_ZSHRUB1, 0, 0}, // S_ZSHRUB1_DIE {SPR_SHB1, 32769, 7, NULL, S_ZSHRUB1_X2, 0, 0}, // S_ZSHRUB1_X1 {SPR_SHB1, 32770, 6, A_Scream, S_ZSHRUB1_X3, 0, 0}, // S_ZSHRUB1_X2 {SPR_SHB1, 32771, 5, NULL, S_NULL, 0, 0}, // S_ZSHRUB1_X3 {SPR_SHB2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHRUB2 {SPR_SHB2, 0, 1, A_TreeDeath, S_ZSHRUB2, 0, 0}, // S_ZSHRUB2_DIE {SPR_SHB2, 32769, 7, NULL, S_ZSHRUB2_X2, 0, 0}, // S_ZSHRUB2_X1 {SPR_SHB2, 32770, 6, A_Scream, S_ZSHRUB2_X3, 0, 0}, // S_ZSHRUB2_X2 {SPR_SHB2, 32771, 5, A_Explode, S_ZSHRUB2_X4, 0, 0}, // S_ZSHRUB2_X3 {SPR_SHB2, 32772, 5, NULL, S_NULL, 0, 0}, // S_ZSHRUB2_X4 {SPR_BCKT, 0, -1, NULL, S_NULL, 0, 0}, // S_ZBUCKET1 {SPR_SHRM, 0, 5, A_PoisonShroom, S_ZPOISONSHROOM_P2, 0, 0}, // S_ZPOISONSHROOM1 {SPR_SHRM, 0, 6, NULL, S_ZPOISONSHROOM_P2, 0, 0}, // S_ZPOISONSHROOM_P1 {SPR_SHRM, 1, 8, A_Pain, S_ZPOISONSHROOM1, 0, 0}, // S_ZPOISONSHROOM_P2 {SPR_SHRM, 2, 5, NULL, S_ZPOISONSHROOM_X2, 0, 0}, // S_ZPOISONSHROOM_X1 {SPR_SHRM, 3, 5, NULL, S_ZPOISONSHROOM_X3, 0, 0}, // S_ZPOISONSHROOM_X2 {SPR_SHRM, 4, 5, A_PoisonBagInit, S_ZPOISONSHROOM_X4, 0, 0}, // S_ZPOISONSHROOM_X3 {SPR_SHRM, 5, -1, NULL, S_NULL, 0, 0}, // S_ZPOISONSHROOM_X4 {SPR_FBUL, 32768, 4, NULL, S_ZFIREBULL2, 0, 0}, // S_ZFIREBULL1 {SPR_FBUL, 32769, 4, NULL, S_ZFIREBULL3, 0, 0}, // S_ZFIREBULL2 {SPR_FBUL, 32770, 4, NULL, S_ZFIREBULL4, 0, 0}, // S_ZFIREBULL3 {SPR_FBUL, 32771, 4, NULL, S_ZFIREBULL5, 0, 0}, // S_ZFIREBULL4 {SPR_FBUL, 32772, 4, NULL, S_ZFIREBULL6, 0, 0}, // S_ZFIREBULL5 {SPR_FBUL, 32773, 4, NULL, S_ZFIREBULL7, 0, 0}, // S_ZFIREBULL6 {SPR_FBUL, 32774, 4, NULL, S_ZFIREBULL1, 0, 0}, // S_ZFIREBULL7 {SPR_FBUL, 32777, 4, NULL, S_ZFIREBULL_DEATH2, 0, 0}, // S_ZFIREBULL_DEATH {SPR_FBUL, 32776, 4, NULL, S_ZFIREBULL_U, 0, 0}, // S_ZFIREBULL_DEATH2 {SPR_FBUL, 7, -1, NULL, S_NULL, 0, 0}, // S_ZFIREBULL_U {SPR_FBUL, 32776, 4, NULL, S_ZFIREBULL_BIRTH2, 0, 0}, // S_ZFIREBULL_BIRTH {SPR_FBUL, 32777, 4, NULL, S_ZFIREBULL1, 0, 0}, // S_ZFIREBULL_BIRTH2 {SPR_FSKL, 32768, 4, NULL, S_ZFIRETHING2, 0, 0}, // S_ZFIRETHING1 {SPR_FSKL, 32769, 3, NULL, S_ZFIRETHING3, 0, 0}, // S_ZFIRETHING2 {SPR_FSKL, 32770, 4, NULL, S_ZFIRETHING4, 0, 0}, // S_ZFIRETHING3 {SPR_FSKL, 32771, 3, NULL, S_ZFIRETHING5, 0, 0}, // S_ZFIRETHING4 {SPR_FSKL, 32772, 4, NULL, S_ZFIRETHING6, 0, 0}, // S_ZFIRETHING5 {SPR_FSKL, 32773, 3, NULL, S_ZFIRETHING7, 0, 0}, // S_ZFIRETHING6 {SPR_FSKL, 32774, 4, NULL, S_ZFIRETHING8, 0, 0}, // S_ZFIRETHING7 {SPR_FSKL, 32775, 3, NULL, S_ZFIRETHING9, 0, 0}, // S_ZFIRETHING8 {SPR_FSKL, 32776, 4, NULL, S_ZFIRETHING1, 0, 0}, // S_ZFIRETHING9 {SPR_BRTR, 32768, 4, NULL, S_ZBRASSTORCH2, 0, 0}, // S_ZBRASSTORCH1 {SPR_BRTR, 32769, 4, NULL, S_ZBRASSTORCH3, 0, 0}, // S_ZBRASSTORCH2 {SPR_BRTR, 32770, 4, NULL, S_ZBRASSTORCH4, 0, 0}, // S_ZBRASSTORCH3 {SPR_BRTR, 32771, 4, NULL, S_ZBRASSTORCH5, 0, 0}, // S_ZBRASSTORCH4 {SPR_BRTR, 32772, 4, NULL, S_ZBRASSTORCH6, 0, 0}, // S_ZBRASSTORCH5 {SPR_BRTR, 32773, 4, NULL, S_ZBRASSTORCH7, 0, 0}, // S_ZBRASSTORCH6 {SPR_BRTR, 32774, 4, NULL, S_ZBRASSTORCH8, 0, 0}, // S_ZBRASSTORCH7 {SPR_BRTR, 32775, 4, NULL, S_ZBRASSTORCH9, 0, 0}, // S_ZBRASSTORCH8 {SPR_BRTR, 32776, 4, NULL, S_ZBRASSTORCH10, 0, 0}, // S_ZBRASSTORCH9 {SPR_BRTR, 32777, 4, NULL, S_ZBRASSTORCH11, 0, 0}, // S_ZBRASSTORCH10 {SPR_BRTR, 32778, 4, NULL, S_ZBRASSTORCH12, 0, 0}, // S_ZBRASSTORCH11 {SPR_BRTR, 32779, 4, NULL, S_ZBRASSTORCH13, 0, 0}, // S_ZBRASSTORCH12 {SPR_BRTR, 32780, 4, NULL, S_ZBRASSTORCH1, 0, 0}, // S_ZBRASSTORCH13 {SPR_SUIT, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSUITOFARMOR {SPR_SUIT, 0, 1, A_SoAExplode, S_NULL, 0, 0}, // S_ZSUITOFARMOR_X1 {SPR_SUIT, 1, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK1 {SPR_SUIT, 2, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK2 {SPR_SUIT, 3, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK3 {SPR_SUIT, 4, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK4 {SPR_SUIT, 5, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK5 {SPR_SUIT, 6, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK6 {SPR_SUIT, 7, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK7 {SPR_SUIT, 8, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK8 {SPR_SUIT, 9, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK9 {SPR_SUIT, 10, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK10 {SPR_BBLL, 5, -1, NULL, S_NULL, 0, 0}, // S_ZBELL {SPR_BBLL, 0, 4, A_BellReset1, S_ZBELL_X2, 0, 0}, // S_ZBELL_X1 {SPR_BBLL, 1, 4, NULL, S_ZBELL_X3, 0, 0}, // S_ZBELL_X2 {SPR_BBLL, 2, 4, NULL, S_ZBELL_X4, 0, 0}, // S_ZBELL_X3 {SPR_BBLL, 3, 5, A_Scream, S_ZBELL_X5, 0, 0}, // S_ZBELL_X4 {SPR_BBLL, 2, 4, NULL, S_ZBELL_X6, 0, 0}, // S_ZBELL_X5 {SPR_BBLL, 1, 4, NULL, S_ZBELL_X7, 0, 0}, // S_ZBELL_X6 {SPR_BBLL, 0, 3, NULL, S_ZBELL_X8, 0, 0}, // S_ZBELL_X7 {SPR_BBLL, 4, 4, NULL, S_ZBELL_X9, 0, 0}, // S_ZBELL_X8 {SPR_BBLL, 5, 5, NULL, S_ZBELL_X10, 0, 0}, // S_ZBELL_X9 {SPR_BBLL, 6, 6, A_Scream, S_ZBELL_X11, 0, 0}, // S_ZBELL_X10 {SPR_BBLL, 5, 5, NULL, S_ZBELL_X12, 0, 0}, // S_ZBELL_X11 {SPR_BBLL, 4, 4, NULL, S_ZBELL_X13, 0, 0}, // S_ZBELL_X12 {SPR_BBLL, 0, 4, NULL, S_ZBELL_X14, 0, 0}, // S_ZBELL_X13 {SPR_BBLL, 1, 5, NULL, S_ZBELL_X15, 0, 0}, // S_ZBELL_X14 {SPR_BBLL, 2, 5, NULL, S_ZBELL_X16, 0, 0}, // S_ZBELL_X15 {SPR_BBLL, 3, 6, A_Scream, S_ZBELL_X17, 0, 0}, // S_ZBELL_X16 {SPR_BBLL, 2, 5, NULL, S_ZBELL_X18, 0, 0}, // S_ZBELL_X17 {SPR_BBLL, 1, 5, NULL, S_ZBELL_X19, 0, 0}, // S_ZBELL_X18 {SPR_BBLL, 0, 4, NULL, S_ZBELL_X20, 0, 0}, // S_ZBELL_X19 {SPR_BBLL, 4, 5, NULL, S_ZBELL_X21, 0, 0}, // S_ZBELL_X20 {SPR_BBLL, 5, 5, NULL, S_ZBELL_X22, 0, 0}, // S_ZBELL_X21 {SPR_BBLL, 6, 7, A_Scream, S_ZBELL_X23, 0, 0}, // S_ZBELL_X22 {SPR_BBLL, 5, 5, NULL, S_ZBELL_X24, 0, 0}, // S_ZBELL_X23 {SPR_BBLL, 4, 5, NULL, S_ZBELL_X25, 0, 0}, // S_ZBELL_X24 {SPR_BBLL, 0, 5, NULL, S_ZBELL_X26, 0, 0}, // S_ZBELL_X25 {SPR_BBLL, 1, 6, NULL, S_ZBELL_X27, 0, 0}, // S_ZBELL_X26 {SPR_BBLL, 2, 6, NULL, S_ZBELL_X28, 0, 0}, // S_ZBELL_X27 {SPR_BBLL, 3, 7, A_Scream, S_ZBELL_X29, 0, 0}, // S_ZBELL_X28 {SPR_BBLL, 2, 6, NULL, S_ZBELL_X30, 0, 0}, // S_ZBELL_X29 {SPR_BBLL, 1, 6, NULL, S_ZBELL_X31, 0, 0}, // S_ZBELL_X30 {SPR_BBLL, 0, 5, NULL, S_ZBELL_X32, 0, 0}, // S_ZBELL_X31 {SPR_BBLL, 4, 6, NULL, S_ZBELL_X33, 0, 0}, // S_ZBELL_X32 {SPR_BBLL, 5, 6, NULL, S_ZBELL_X34, 0, 0}, // S_ZBELL_X33 {SPR_BBLL, 6, 7, A_Scream, S_ZBELL_X35, 0, 0}, // S_ZBELL_X34 {SPR_BBLL, 5, 6, NULL, S_ZBELL_X36, 0, 0}, // S_ZBELL_X35 {SPR_BBLL, 4, 6, NULL, S_ZBELL_X37, 0, 0}, // S_ZBELL_X36 {SPR_BBLL, 0, 6, NULL, S_ZBELL_X38, 0, 0}, // S_ZBELL_X37 {SPR_BBLL, 1, 6, NULL, S_ZBELL_X39, 0, 0}, // S_ZBELL_X38 {SPR_BBLL, 2, 6, NULL, S_ZBELL_X40, 0, 0}, // S_ZBELL_X39 {SPR_BBLL, 1, 7, NULL, S_ZBELL_X41, 0, 0}, // S_ZBELL_X40 {SPR_BBLL, 0, 8, NULL, S_ZBELL_X42, 0, 0}, // S_ZBELL_X41 {SPR_BBLL, 4, 12, NULL, S_ZBELL_X43, 0, 0}, // S_ZBELL_X42 {SPR_BBLL, 0, 10, NULL, S_ZBELL_X44, 0, 0}, // S_ZBELL_X43 {SPR_BBLL, 1, 12, NULL, S_ZBELL_X45, 0, 0}, // S_ZBELL_X44 {SPR_BBLL, 0, 12, NULL, S_ZBELL_X46, 0, 0}, // S_ZBELL_X45 {SPR_BBLL, 4, 14, NULL, S_ZBELL_X47, 0, 0}, // S_ZBELL_X46 {SPR_BBLL, 0, 1, A_BellReset2, S_ZBELL, 0, 0}, // S_ZBELL_X47 {SPR_CAND, 32768, 5, NULL, S_ZBLUE_CANDLE2, 0, 0}, // S_ZBLUE_CANDLE1 {SPR_CAND, 32769, 5, NULL, S_ZBLUE_CANDLE3, 0, 0}, // S_ZBLUE_CANDLE2 {SPR_CAND, 32770, 5, NULL, S_ZBLUE_CANDLE4, 0, 0}, // S_ZBLUE_CANDLE3 {SPR_CAND, 32771, 5, NULL, S_ZBLUE_CANDLE5, 0, 0}, // S_ZBLUE_CANDLE4 {SPR_CAND, 32772, 5, NULL, S_ZBLUE_CANDLE1, 0, 0}, // S_ZBLUE_CANDLE5 {SPR_IRON, 0, -1, NULL, S_NULL, 0, 0}, // S_ZIRON_MAIDEN {SPR_XMAS, 0, -1, NULL, S_NULL, 0, 0}, // S_ZXMAS_TREE {SPR_XMAS, 0, 4, A_TreeDeath, S_ZXMAS_TREE, 0, 0}, // S_ZXMAS_TREE_DIE {SPR_XMAS, 32769, 6, NULL, S_ZXMAS_TREE_X2, 0, 0}, // S_ZXMAS_TREE_X1 {SPR_XMAS, 32770, 6, A_Scream, S_ZXMAS_TREE_X3, 0, 0}, // S_ZXMAS_TREE_X2 {SPR_XMAS, 32771, 5, NULL, S_ZXMAS_TREE_X4, 0, 0}, // S_ZXMAS_TREE_X3 {SPR_XMAS, 32772, 5, A_Explode, S_ZXMAS_TREE_X5, 0, 0}, // S_ZXMAS_TREE_X4 {SPR_XMAS, 32773, 5, NULL, S_ZXMAS_TREE_X6, 0, 0}, // S_ZXMAS_TREE_X5 {SPR_XMAS, 32774, 4, NULL, S_ZXMAS_TREE_X7, 0, 0}, // S_ZXMAS_TREE_X6 {SPR_XMAS, 7, 5, NULL, S_ZXMAS_TREE_X8, 0, 0}, // S_ZXMAS_TREE_X7 {SPR_XMAS, 8, 4, A_NoBlocking, S_ZXMAS_TREE_X9, 0, 0}, // S_ZXMAS_TREE_X8 {SPR_XMAS, 9, 4, NULL, S_ZXMAS_TREE_X10, 0, 0}, // S_ZXMAS_TREE_X9 {SPR_XMAS, 10, -1, NULL, S_NULL, 0, 0}, // S_ZXMAS_TREE_X10 {SPR_CDRN, 32769, 4, NULL, S_ZCAULDRON2, 0, 0}, // S_ZCAULDRON1 {SPR_CDRN, 32770, 4, NULL, S_ZCAULDRON3, 0, 0}, // S_ZCAULDRON2 {SPR_CDRN, 32771, 4, NULL, S_ZCAULDRON4, 0, 0}, // S_ZCAULDRON3 {SPR_CDRN, 32772, 4, NULL, S_ZCAULDRON5, 0, 0}, // S_ZCAULDRON4 {SPR_CDRN, 32773, 4, NULL, S_ZCAULDRON6, 0, 0}, // S_ZCAULDRON5 {SPR_CDRN, 32774, 4, NULL, S_ZCAULDRON7, 0, 0}, // S_ZCAULDRON6 {SPR_CDRN, 32775, 4, NULL, S_ZCAULDRON1, 0, 0}, // S_ZCAULDRON7 {SPR_CDRN, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCAULDRON_U {SPR_CHNS, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINBIT32 {SPR_CHNS, 1, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINBIT64 {SPR_CHNS, 2, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_HEART {SPR_CHNS, 3, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_HOOK1 {SPR_CHNS, 4, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_HOOK2 {SPR_CHNS, 5, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_SPIKE {SPR_CHNS, 6, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_SKULL {SPR_TST1, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT1 {SPR_TST2, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT2 {SPR_TST3, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT3 {SPR_TST4, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT4 {SPR_TST5, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT5 {SPR_TST6, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT6 {SPR_TST7, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT7 {SPR_TST8, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT8 {SPR_TST9, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT9 {SPR_TST0, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT10 {SPR_TELE, 32768, 6, NULL, S_TFOG2, 0, 0}, // S_TFOG1 {SPR_TELE, 32769, 6, NULL, S_TFOG3, 0, 0}, // S_TFOG2 {SPR_TELE, 32770, 6, NULL, S_TFOG4, 0, 0}, // S_TFOG3 {SPR_TELE, 32771, 6, NULL, S_TFOG5, 0, 0}, // S_TFOG4 {SPR_TELE, 32772, 6, NULL, S_TFOG6, 0, 0}, // S_TFOG5 {SPR_TELE, 32773, 6, NULL, S_TFOG7, 0, 0}, // S_TFOG6 {SPR_TELE, 32774, 6, NULL, S_TFOG8, 0, 0}, // S_TFOG7 {SPR_TELE, 32775, 6, NULL, S_TFOG9, 0, 0}, // S_TFOG8 {SPR_TELE, 32774, 6, NULL, S_TFOG10, 0, 0}, // S_TFOG9 {SPR_TELE, 32773, 6, NULL, S_TFOG11, 0, 0}, // S_TFOG10 {SPR_TELE, 32772, 6, NULL, S_TFOG12, 0, 0}, // S_TFOG11 {SPR_TELE, 32771, 6, NULL, S_TFOG13, 0, 0}, // S_TFOG12 {SPR_TELE, 32770, 6, NULL, S_NULL, 0, 0}, // S_TFOG13 {SPR_TSMK, 0, 4, NULL, S_TELESMOKE2, 0, 0}, // S_TELESMOKE1 {SPR_TSMK, 1, 3, NULL, S_TELESMOKE3, 0, 0}, // S_TELESMOKE2 {SPR_TSMK, 2, 4, NULL, S_TELESMOKE4, 0, 0}, // S_TELESMOKE3 {SPR_TSMK, 3, 3, NULL, S_TELESMOKE5, 0, 0}, // S_TELESMOKE4 {SPR_TSMK, 4, 4, NULL, S_TELESMOKE6, 0, 0}, // S_TELESMOKE5 {SPR_TSMK, 5, 3, NULL, S_TELESMOKE7, 0, 0}, // S_TELESMOKE6 {SPR_TSMK, 6, 4, NULL, S_TELESMOKE8, 0, 0}, // S_TELESMOKE7 {SPR_TSMK, 7, 3, NULL, S_TELESMOKE9, 0, 0}, // S_TELESMOKE8 {SPR_TSMK, 8, 4, NULL, S_TELESMOKE10, 0, 0}, // S_TELESMOKE9 {SPR_TSMK, 9, 3, NULL, S_TELESMOKE11, 0, 0}, // S_TELESMOKE10 {SPR_TSMK, 10, 4, NULL, S_TELESMOKE12, 0, 0}, // S_TELESMOKE11 {SPR_TSMK, 11, 3, NULL, S_TELESMOKE13, 0, 0}, // S_TELESMOKE12 {SPR_TSMK, 12, 4, NULL, S_TELESMOKE14, 0, 0}, // S_TELESMOKE13 {SPR_TSMK, 13, 3, NULL, S_TELESMOKE15, 0, 0}, // S_TELESMOKE14 {SPR_TSMK, 14, 4, NULL, S_TELESMOKE16, 0, 0}, // S_TELESMOKE15 {SPR_TSMK, 15, 3, NULL, S_TELESMOKE17, 0, 0}, // S_TELESMOKE16 {SPR_TSMK, 16, 4, NULL, S_TELESMOKE18, 0, 0}, // S_TELESMOKE17 {SPR_TSMK, 17, 3, NULL, S_TELESMOKE19, 0, 0}, // S_TELESMOKE18 {SPR_TSMK, 18, 4, NULL, S_TELESMOKE20, 0, 0}, // S_TELESMOKE19 {SPR_TSMK, 19, 3, NULL, S_TELESMOKE21, 0, 0}, // S_TELESMOKE20 {SPR_TSMK, 20, 4, NULL, S_TELESMOKE22, 0, 0}, // S_TELESMOKE21 {SPR_TSMK, 21, 3, NULL, S_TELESMOKE23, 0, 0}, // S_TELESMOKE22 {SPR_TSMK, 22, 4, NULL, S_TELESMOKE24, 0, 0}, // S_TELESMOKE23 {SPR_TSMK, 23, 3, NULL, S_TELESMOKE25, 0, 0}, // S_TELESMOKE24 {SPR_TSMK, 24, 4, NULL, S_TELESMOKE26, 0, 0}, // S_TELESMOKE25 {SPR_TSMK, 25, 3, NULL, S_TELESMOKE1, 0, 0}, // S_TELESMOKE26 {SPR_FPCH, 0, 0, A_Light0, S_NULL, 0, 0}, // S_LIGHTDONE {SPR_FPCH, 0, 1, A_WeaponReady, S_PUNCHREADY, 0, 0}, // S_PUNCHREADY {SPR_FPCH, 0, 1, A_Lower, S_PUNCHDOWN, 0, 0}, // S_PUNCHDOWN {SPR_FPCH, 0, 1, A_Raise, S_PUNCHUP, 0, 0}, // S_PUNCHUP {SPR_FPCH, 1, 5, NULL, S_PUNCHATK1_2, 5, 40}, // S_PUNCHATK1_1 {SPR_FPCH, 2, 4, NULL, S_PUNCHATK1_3, 5, 40}, // S_PUNCHATK1_2 {SPR_FPCH, 3, 4, A_FPunchAttack, S_PUNCHATK1_4, 5, 40}, // S_PUNCHATK1_3 {SPR_FPCH, 2, 4, NULL, S_PUNCHATK1_5, 5, 40}, // S_PUNCHATK1_4 {SPR_FPCH, 1, 5, A_ReFire, S_PUNCHREADY, 5, 40}, // S_PUNCHATK1_5 {SPR_FPCH, 3, 4, NULL, S_PUNCHATK2_2, 5, 40}, // S_PUNCHATK2_1 {SPR_FPCH, 4, 4, NULL, S_PUNCHATK2_3, 5, 40}, // S_PUNCHATK2_2 {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_4, 15, 50}, // S_PUNCHATK2_3 {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_5, 25, 60}, // S_PUNCHATK2_4 {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_6, 35, 70}, // S_PUNCHATK2_5 {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_7, 45, 80}, // S_PUNCHATK2_6 {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_8, 55, 90}, // S_PUNCHATK2_7 {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_9, 65, 100}, // S_PUNCHATK2_8 {SPR_FPCH, 4, 10, NULL, S_PUNCHREADY, 0, 150}, // S_PUNCHATK2_9 {SPR_FHFX, 18, 4, NULL, S_PUNCHPUFF2, 0, 0}, // S_PUNCHPUFF1 {SPR_FHFX, 19, 4, NULL, S_PUNCHPUFF3, 0, 0}, // S_PUNCHPUFF2 {SPR_FHFX, 20, 4, NULL, S_PUNCHPUFF4, 0, 0}, // S_PUNCHPUFF3 {SPR_FHFX, 21, 4, NULL, S_PUNCHPUFF5, 0, 0}, // S_PUNCHPUFF4 {SPR_FHFX, 22, 4, NULL, S_NULL, 0, 0}, // S_PUNCHPUFF5 {SPR_WFAX, 0, -1, NULL, S_NULL, 0, 0}, // S_AXE {SPR_FAXE, 0, 1, A_WeaponReady, S_FAXEREADY, 0, 0}, // S_FAXEREADY {SPR_FAXE, 0, 1, A_Lower, S_FAXEDOWN, 0, 0}, // S_FAXEDOWN {SPR_FAXE, 0, 1, A_Raise, S_FAXEUP, 0, 0}, // S_FAXEUP {SPR_FAXE, 1, 4, NULL, S_FAXEATK_2, 15, 32}, // S_FAXEATK_1 {SPR_FAXE, 2, 3, NULL, S_FAXEATK_3, 15, 32}, // S_FAXEATK_2 {SPR_FAXE, 3, 2, NULL, S_FAXEATK_4, 15, 32}, // S_FAXEATK_3 {SPR_FAXE, 3, 1, A_FAxeAttack, S_FAXEATK_5, -5, 70}, // S_FAXEATK_4 {SPR_FAXE, 3, 2, NULL, S_FAXEATK_6, -25, 90}, // S_FAXEATK_5 {SPR_FAXE, 4, 1, NULL, S_FAXEATK_7, 15, 32}, // S_FAXEATK_6 {SPR_FAXE, 4, 2, NULL, S_FAXEATK_8, 10, 54}, // S_FAXEATK_7 {SPR_FAXE, 4, 7, NULL, S_FAXEATK_9, 10, 150}, // S_FAXEATK_8 {SPR_FAXE, 0, 1, A_ReFire, S_FAXEATK_10, 0, 60}, // S_FAXEATK_9 {SPR_FAXE, 0, 1, NULL, S_FAXEATK_11, 0, 52}, // S_FAXEATK_10 {SPR_FAXE, 0, 1, NULL, S_FAXEATK_12, 0, 44}, // S_FAXEATK_11 {SPR_FAXE, 0, 1, NULL, S_FAXEATK_13, 0, 36}, // S_FAXEATK_12 {SPR_FAXE, 0, 1, NULL, S_FAXEREADY, 0, 0}, // S_FAXEATK_13 {SPR_FAXE, 11, 1, A_WeaponReady, S_FAXEREADY_G1, 0, 0}, // S_FAXEREADY_G {SPR_FAXE, 11, 1, A_WeaponReady, S_FAXEREADY_G2, 0, 0}, // S_FAXEREADY_G1 {SPR_FAXE, 11, 1, A_WeaponReady, S_FAXEREADY_G3, 0, 0}, // S_FAXEREADY_G2 {SPR_FAXE, 12, 1, A_WeaponReady, S_FAXEREADY_G4, 0, 0}, // S_FAXEREADY_G3 {SPR_FAXE, 12, 1, A_WeaponReady, S_FAXEREADY_G5, 0, 0}, // S_FAXEREADY_G4 {SPR_FAXE, 12, 1, A_WeaponReady, S_FAXEREADY_G, 0, 0}, // S_FAXEREADY_G5 {SPR_FAXE, 11, 1, A_Lower, S_FAXEDOWN_G, 0, 0}, // S_FAXEDOWN_G {SPR_FAXE, 11, 1, A_Raise, S_FAXEUP_G, 0, 0}, // S_FAXEUP_G {SPR_FAXE, 13, 4, NULL, S_FAXEATK_G2, 15, 32}, // S_FAXEATK_G1 {SPR_FAXE, 14, 3, NULL, S_FAXEATK_G3, 15, 32}, // S_FAXEATK_G2 {SPR_FAXE, 15, 2, NULL, S_FAXEATK_G4, 15, 32}, // S_FAXEATK_G3 {SPR_FAXE, 15, 1, A_FAxeAttack, S_FAXEATK_G5, -5, 70}, // S_FAXEATK_G4 {SPR_FAXE, 15, 2, NULL, S_FAXEATK_G6, -25, 90}, // S_FAXEATK_G5 {SPR_FAXE, 16, 1, NULL, S_FAXEATK_G7, 15, 32}, // S_FAXEATK_G6 {SPR_FAXE, 16, 2, NULL, S_FAXEATK_G8, 10, 54}, // S_FAXEATK_G7 {SPR_FAXE, 16, 7, NULL, S_FAXEATK_G9, 10, 150}, // S_FAXEATK_G8 {SPR_FAXE, 0, 1, A_ReFire, S_FAXEATK_G10, 0, 60}, // S_FAXEATK_G9 {SPR_FAXE, 0, 1, NULL, S_FAXEATK_G11, 0, 52}, // S_FAXEATK_G10 {SPR_FAXE, 0, 1, NULL, S_FAXEATK_G12, 0, 44}, // S_FAXEATK_G11 {SPR_FAXE, 0, 1, NULL, S_FAXEATK_G13, 0, 36}, // S_FAXEATK_G12 {SPR_FAXE, 0, 1, NULL, S_FAXEREADY_G, 0, 0}, // S_FAXEATK_G13 {SPR_FAXE, 32785, 4, NULL, S_AXEPUFF_GLOW2, 0, 0}, // S_AXEPUFF_GLOW1 {SPR_FAXE, 32786, 4, NULL, S_AXEPUFF_GLOW3, 0, 0}, // S_AXEPUFF_GLOW2 {SPR_FAXE, 32787, 4, NULL, S_AXEPUFF_GLOW4, 0, 0}, // S_AXEPUFF_GLOW3 {SPR_FAXE, 32788, 4, NULL, S_AXEPUFF_GLOW5, 0, 0}, // S_AXEPUFF_GLOW4 {SPR_FAXE, 32789, 4, NULL, S_AXEPUFF_GLOW6, 0, 0}, // S_AXEPUFF_GLOW5 {SPR_FAXE, 32790, 4, NULL, S_AXEPUFF_GLOW7, 0, 0}, // S_AXEPUFF_GLOW6 {SPR_FAXE, 32791, 4, NULL, S_NULL, 0, 0}, // S_AXEPUFF_GLOW7 {SPR_FAXE, 5, 3, NULL, S_AXEBLOOD2, 0, 0}, // S_AXEBLOOD1 {SPR_FAXE, 6, 3, NULL, S_AXEBLOOD3, 0, 0}, // S_AXEBLOOD2 {SPR_FAXE, 7, 3, NULL, S_AXEBLOOD4, 0, 0}, // S_AXEBLOOD3 {SPR_FAXE, 8, 3, NULL, S_AXEBLOOD5, 0, 0}, // S_AXEBLOOD4 {SPR_FAXE, 9, 3, NULL, S_AXEBLOOD6, 0, 0}, // S_AXEBLOOD5 {SPR_FAXE, 10, 3, NULL, S_NULL, 0, 0}, // S_AXEBLOOD6 {SPR_WFHM, 0, -1, NULL, S_NULL, 0, 0}, // S_HAMM {SPR_FHMR, 0, 1, A_WeaponReady, S_FHAMMERREADY, 0, 0}, // S_FHAMMERREADY {SPR_FHMR, 0, 1, A_Lower, S_FHAMMERDOWN, 0, 0}, // S_FHAMMERDOWN {SPR_FHMR, 0, 1, A_Raise, S_FHAMMERUP, 0, 0}, // S_FHAMMERUP {SPR_FHMR, 1, 6, NULL, S_FHAMMERATK_2, 5, 0}, // S_FHAMMERATK_1 {SPR_FHMR, 2, 3, A_FHammerAttack, S_FHAMMERATK_3, 5, 0}, // S_FHAMMERATK_2 {SPR_FHMR, 3, 3, NULL, S_FHAMMERATK_4, 5, 0}, // S_FHAMMERATK_3 {SPR_FHMR, 4, 2, NULL, S_FHAMMERATK_5, 5, 0}, // S_FHAMMERATK_4 {SPR_FHMR, 4, 10, A_FHammerThrow, S_FHAMMERATK_6, 5, 150}, // S_FHAMMERATK_5 {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_7, 0, 60}, // S_FHAMMERATK_6 {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_8, 0, 55}, // S_FHAMMERATK_7 {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_9, 0, 50}, // S_FHAMMERATK_8 {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_10, 0, 45}, // S_FHAMMERATK_9 {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_11, 0, 40}, // S_FHAMMERATK_10 {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_12, 0, 35}, // S_FHAMMERATK_11 {SPR_FHMR, 0, 1, NULL, S_FHAMMERREADY, 0, 0}, // S_FHAMMERATK_12 {SPR_FHFX, 32768, 2, NULL, S_HAMMER_MISSILE_2, 0, 0}, // S_HAMMER_MISSILE_1 {SPR_FHFX, 32769, 2, A_ContMobjSound, S_HAMMER_MISSILE_3, 0, 0}, // S_HAMMER_MISSILE_2 {SPR_FHFX, 32770, 2, NULL, S_HAMMER_MISSILE_4, 0, 0}, // S_HAMMER_MISSILE_3 {SPR_FHFX, 32771, 2, NULL, S_HAMMER_MISSILE_5, 0, 0}, // S_HAMMER_MISSILE_4 {SPR_FHFX, 32772, 2, NULL, S_HAMMER_MISSILE_6, 0, 0}, // S_HAMMER_MISSILE_5 {SPR_FHFX, 32773, 2, NULL, S_HAMMER_MISSILE_7, 0, 0}, // S_HAMMER_MISSILE_6 {SPR_FHFX, 32774, 2, NULL, S_HAMMER_MISSILE_8, 0, 0}, // S_HAMMER_MISSILE_7 {SPR_FHFX, 32775, 2, NULL, S_HAMMER_MISSILE_1, 0, 0}, // S_HAMMER_MISSILE_8 {SPR_FHFX, 32776, 3, NULL, S_HAMMER_MISSILE_X2, 0, 0}, // S_HAMMER_MISSILE_X1 {SPR_FHFX, 32777, 3, NULL, S_HAMMER_MISSILE_X3, 0, 0}, // S_HAMMER_MISSILE_X2 {SPR_FHFX, 32778, 3, A_Explode, S_HAMMER_MISSILE_X4, 0, 0}, // S_HAMMER_MISSILE_X3 {SPR_FHFX, 32779, 3, NULL, S_HAMMER_MISSILE_X5, 0, 0}, // S_HAMMER_MISSILE_X4 {SPR_FHFX, 32780, 3, NULL, S_HAMMER_MISSILE_X6, 0, 0}, // S_HAMMER_MISSILE_X5 {SPR_FHFX, 13, 3, NULL, S_HAMMER_MISSILE_X7, 0, 0}, // S_HAMMER_MISSILE_X6 {SPR_FHFX, 32782, 3, NULL, S_HAMMER_MISSILE_X8, 0, 0}, // S_HAMMER_MISSILE_X7 {SPR_FHFX, 32783, 3, NULL, S_HAMMER_MISSILE_X9, 0, 0}, // S_HAMMER_MISSILE_X8 {SPR_FHFX, 32784, 3, NULL, S_HAMMER_MISSILE_X10, 0, 0}, // S_HAMMER_MISSILE_X9 {SPR_FHFX, 32785, 3, NULL, S_NULL, 0, 0}, // S_HAMMER_MISSILE_X10 {SPR_FHFX, 18, 4, NULL, S_HAMMERPUFF2, 0, 0}, // S_HAMMERPUFF1 {SPR_FHFX, 19, 4, NULL, S_HAMMERPUFF3, 0, 0}, // S_HAMMERPUFF2 {SPR_FHFX, 20, 4, NULL, S_HAMMERPUFF4, 0, 0}, // S_HAMMERPUFF3 {SPR_FHFX, 21, 4, NULL, S_HAMMERPUFF5, 0, 0}, // S_HAMMERPUFF4 {SPR_FHFX, 22, 4, NULL, S_NULL, 0, 0}, // S_HAMMERPUFF5 {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY1, 0, 0}, // S_FSWORDREADY {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY2, 0, 0}, // S_FSWORDREADY1 {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY3, 0, 0}, // S_FSWORDREADY2 {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY4, 0, 0}, // S_FSWORDREADY3 {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY5, 0, 0}, // S_FSWORDREADY4 {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY6, 0, 0}, // S_FSWORDREADY5 {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY7, 0, 0}, // S_FSWORDREADY6 {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY8, 0, 0}, // S_FSWORDREADY7 {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY9, 0, 0}, // S_FSWORDREADY8 {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY10, 0, 0}, // S_FSWORDREADY9 {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY11, 0, 0}, // S_FSWORDREADY10 {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY, 0, 0}, // S_FSWORDREADY11 {SPR_FSRD, 32768, 1, A_Lower, S_FSWORDDOWN, 0, 0}, // S_FSWORDDOWN {SPR_FSRD, 32768, 1, A_Raise, S_FSWORDUP, 0, 0}, // S_FSWORDUP {SPR_FSRD, 32771, 3, NULL, S_FSWORDATK_2, 5, 36}, // S_FSWORDATK_1 {SPR_FSRD, 32772, 3, NULL, S_FSWORDATK_3, 5, 36}, // S_FSWORDATK_2 {SPR_FSRD, 32773, 2, NULL, S_FSWORDATK_4, 5, 36}, // S_FSWORDATK_3 {SPR_FSRD, 32774, 3, A_FSwordAttack, S_FSWORDATK_5, 5, 36}, // S_FSWORDATK_4 {SPR_FSRD, 32775, 2, NULL, S_FSWORDATK_6, 5, 36}, // S_FSWORDATK_5 {SPR_FSRD, 32776, 2, NULL, S_FSWORDATK_7, 5, 36}, // S_FSWORDATK_6 {SPR_FSRD, 32776, 10, NULL, S_FSWORDATK_8, 5, 150}, // S_FSWORDATK_7 {SPR_FSRD, 32768, 1, NULL, S_FSWORDATK_9, 5, 60}, // S_FSWORDATK_8 {SPR_FSRD, 32769, 1, NULL, S_FSWORDATK_10, 5, 55}, // S_FSWORDATK_9 {SPR_FSRD, 32770, 1, NULL, S_FSWORDATK_11, 5, 50}, // S_FSWORDATK_10 {SPR_FSRD, 32768, 1, NULL, S_FSWORDATK_12, 5, 45}, // S_FSWORDATK_11 {SPR_FSRD, 32769, 1, NULL, S_FSWORDREADY, 5, 40}, // S_FSWORDATK_12 {SPR_FSFX, 32768, 3, NULL, S_FSWORD_MISSILE2, 0, 0}, // S_FSWORD_MISSILE1 {SPR_FSFX, 32769, 3, NULL, S_FSWORD_MISSILE3, 0, 0}, // S_FSWORD_MISSILE2 {SPR_FSFX, 32770, 3, NULL, S_FSWORD_MISSILE1, 0, 0}, // S_FSWORD_MISSILE3 {SPR_FSFX, 32771, 4, NULL, S_FSWORD_MISSILE_X2, 0, 0}, // S_FSWORD_MISSILE_X1 {SPR_FSFX, 32772, 3, A_FSwordFlames, S_FSWORD_MISSILE_X3, 0, 0}, // S_FSWORD_MISSILE_X2 {SPR_FSFX, 32773, 4, A_Explode, S_FSWORD_MISSILE_X4, 0, 0}, // S_FSWORD_MISSILE_X3 {SPR_FSFX, 32774, 3, NULL, S_FSWORD_MISSILE_X5, 0, 0}, // S_FSWORD_MISSILE_X4 {SPR_FSFX, 32775, 4, NULL, S_FSWORD_MISSILE_X6, 0, 0}, // S_FSWORD_MISSILE_X5 {SPR_FSFX, 32776, 3, NULL, S_FSWORD_MISSILE_X7, 0, 0}, // S_FSWORD_MISSILE_X6 {SPR_FSFX, 32777, 4, NULL, S_FSWORD_MISSILE_X8, 0, 0}, // S_FSWORD_MISSILE_X7 {SPR_FSFX, 32778, 3, NULL, S_FSWORD_MISSILE_X9, 0, 0}, // S_FSWORD_MISSILE_X8 {SPR_FSFX, 32779, 3, NULL, S_FSWORD_MISSILE_X10, 0, 0}, // S_FSWORD_MISSILE_X9 {SPR_FSFX, 32780, 3, NULL, S_NULL, 0, 0}, // S_FSWORD_MISSILE_X10 {SPR_FSFX, 32781, 3, NULL, S_FSWORD_FLAME2, 0, 0}, // S_FSWORD_FLAME1 {SPR_FSFX, 32782, 3, NULL, S_FSWORD_FLAME3, 0, 0}, // S_FSWORD_FLAME2 {SPR_FSFX, 32783, 3, NULL, S_FSWORD_FLAME4, 0, 0}, // S_FSWORD_FLAME3 {SPR_FSFX, 32784, 3, NULL, S_FSWORD_FLAME5, 0, 0}, // S_FSWORD_FLAME4 {SPR_FSFX, 32785, 3, NULL, S_FSWORD_FLAME6, 0, 0}, // S_FSWORD_FLAME5 {SPR_FSFX, 32786, 3, NULL, S_FSWORD_FLAME7, 0, 0}, // S_FSWORD_FLAME6 {SPR_FSFX, 32787, 3, NULL, S_FSWORD_FLAME8, 0, 0}, // S_FSWORD_FLAME7 {SPR_FSFX, 32788, 3, NULL, S_FSWORD_FLAME9, 0, 0}, // S_FSWORD_FLAME8 {SPR_FSFX, 32789, 3, NULL, S_FSWORD_FLAME10, 0, 0}, // S_FSWORD_FLAME9 {SPR_FSFX, 32790, 3, NULL, S_NULL, 0, 0}, // S_FSWORD_FLAME10 {SPR_CMCE, 0, 1, A_WeaponReady, S_CMACEREADY, 0, 0}, // S_CMACEREADY {SPR_CMCE, 0, 1, A_Lower, S_CMACEDOWN, 0, 0}, // S_CMACEDOWN {SPR_CMCE, 0, 1, A_Raise, S_CMACEUP, 0, 0}, // S_CMACEUP {SPR_CMCE, 1, 2, NULL, S_CMACEATK_2, 60, 20}, // S_CMACEATK_1 {SPR_CMCE, 1, 1, NULL, S_CMACEATK_3, 30, 33}, // S_CMACEATK_2 {SPR_CMCE, 1, 2, NULL, S_CMACEATK_4, 8, 45}, // S_CMACEATK_3 {SPR_CMCE, 2, 1, NULL, S_CMACEATK_5, 8, 45}, // S_CMACEATK_4 {SPR_CMCE, 3, 1, NULL, S_CMACEATK_6, 8, 45}, // S_CMACEATK_5 {SPR_CMCE, 4, 1, NULL, S_CMACEATK_7, 8, 45}, // S_CMACEATK_6 {SPR_CMCE, 4, 1, A_CMaceAttack, S_CMACEATK_8, -11, 58}, // S_CMACEATK_7 {SPR_CMCE, 5, 1, NULL, S_CMACEATK_9, 8, 45}, // S_CMACEATK_8 {SPR_CMCE, 5, 2, NULL, S_CMACEATK_10, -8, 74}, // S_CMACEATK_9 {SPR_CMCE, 5, 1, NULL, S_CMACEATK_11, -20, 96}, // S_CMACEATK_10 {SPR_CMCE, 5, 8, NULL, S_CMACEATK_12, -33, 160}, // S_CMACEATK_11 {SPR_CMCE, 0, 2, A_ReFire, S_CMACEATK_13, 8, 75}, // S_CMACEATK_12 {SPR_CMCE, 0, 1, NULL, S_CMACEATK_14, 8, 65}, // S_CMACEATK_13 {SPR_CMCE, 0, 2, NULL, S_CMACEATK_15, 8, 60}, // S_CMACEATK_14 {SPR_CMCE, 0, 1, NULL, S_CMACEATK_16, 8, 55}, // S_CMACEATK_15 {SPR_CMCE, 0, 2, NULL, S_CMACEATK_17, 8, 50}, // S_CMACEATK_16 {SPR_CMCE, 0, 1, NULL, S_CMACEREADY, 8, 45}, // S_CMACEATK_17 {SPR_WCSS, 0, -1, NULL, S_NULL, 0, 0}, // S_CSTAFF {SPR_CSSF, 2, 4, NULL, S_CSTAFFREADY1, 0, 0}, // S_CSTAFFREADY {SPR_CSSF, 1, 3, A_CStaffInitBlink, S_CSTAFFREADY2, 0, 0}, // S_CSTAFFREADY1 {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY3, 0, 0}, // S_CSTAFFREADY2 {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY4, 0, 0}, // S_CSTAFFREADY3 {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY5, 0, 0}, // S_CSTAFFREADY4 {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY6, 0, 0}, // S_CSTAFFREADY5 {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY7, 0, 0}, // S_CSTAFFREADY6 {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY8, 0, 0}, // S_CSTAFFREADY7 {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY9, 0, 0}, // S_CSTAFFREADY8 {SPR_CSSF, 0, 1, A_CStaffCheckBlink, S_CSTAFFREADY2, 0, 0}, // S_CSTAFFREADY9 {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK2, 0, 0}, // S_CSTAFFBLINK1 {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK3, 0, 0}, // S_CSTAFFBLINK2 {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK4, 0, 0}, // S_CSTAFFBLINK3 {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK5, 0, 0}, // S_CSTAFFBLINK4 {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK6, 0, 0}, // S_CSTAFFBLINK5 {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK7, 0, 0}, // S_CSTAFFBLINK6 {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK8, 0, 0}, // S_CSTAFFBLINK7 {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK9, 0, 0}, // S_CSTAFFBLINK8 {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK10, 0, 0}, // S_CSTAFFBLINK9 {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK11, 0, 0}, // S_CSTAFFBLINK10 {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFREADY2, 0, 0}, // S_CSTAFFBLINK11 {SPR_CSSF, 1, 3, NULL, S_CSTAFFDOWN2, 0, 0}, // S_CSTAFFDOWN {SPR_CSSF, 2, 4, NULL, S_CSTAFFDOWN3, 0, 0}, // S_CSTAFFDOWN2 {SPR_CSSF, 2, 1, A_Lower, S_CSTAFFDOWN3, 0, 0}, // S_CSTAFFDOWN3 {SPR_CSSF, 2, 1, A_Raise, S_CSTAFFUP, 0, 0}, // S_CSTAFFUP {SPR_CSSF, 0, 1, A_CStaffCheck, S_CSTAFFATK_2, 0, 45}, // S_CSTAFFATK_1 {SPR_CSSF, 9, 1, A_CStaffAttack, S_CSTAFFATK_3, 0, 50}, // S_CSTAFFATK_2 {SPR_CSSF, 9, 2, NULL, S_CSTAFFATK_4, 0, 50}, // S_CSTAFFATK_3 {SPR_CSSF, 9, 2, NULL, S_CSTAFFATK_5, 0, 45}, // S_CSTAFFATK_4 {SPR_CSSF, 0, 2, NULL, S_CSTAFFATK_6, 0, 40}, // S_CSTAFFATK_5 {SPR_CSSF, 0, 2, NULL, S_CSTAFFREADY2, 0, 36}, // S_CSTAFFATK_6 {SPR_CSSF, 10, 10, NULL, S_CSTAFFREADY2, 0, 36}, // S_CSTAFFATK2_1 {SPR_CSSF, 32771, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE2, 0, 0}, // S_CSTAFF_MISSILE1 {SPR_CSSF, 32771, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE3, 0, 0}, // S_CSTAFF_MISSILE2 {SPR_CSSF, 32772, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE4, 0, 0}, // S_CSTAFF_MISSILE3 {SPR_CSSF, 32772, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE1, 0, 0}, // S_CSTAFF_MISSILE4 {SPR_CSSF, 32773, 4, NULL, S_CSTAFF_MISSILE_X2, 0, 0}, // S_CSTAFF_MISSILE_X1 {SPR_CSSF, 32774, 4, NULL, S_CSTAFF_MISSILE_X3, 0, 0}, // S_CSTAFF_MISSILE_X2 {SPR_CSSF, 32775, 3, NULL, S_CSTAFF_MISSILE_X4, 0, 0}, // S_CSTAFF_MISSILE_X3 {SPR_CSSF, 32776, 3, NULL, S_NULL, 0, 0}, // S_CSTAFF_MISSILE_X4 {SPR_FHFX, 18, 4, NULL, S_CSTAFFPUFF2, 0, 0}, // S_CSTAFFPUFF1 {SPR_FHFX, 19, 4, NULL, S_CSTAFFPUFF3, 0, 0}, // S_CSTAFFPUFF2 {SPR_FHFX, 20, 4, NULL, S_CSTAFFPUFF4, 0, 0}, // S_CSTAFFPUFF3 {SPR_FHFX, 21, 4, NULL, S_CSTAFFPUFF5, 0, 0}, // S_CSTAFFPUFF4 {SPR_FHFX, 22, 4, NULL, S_NULL, 0, 0}, // S_CSTAFFPUFF5 {SPR_WCFM, 32768, 4, NULL, S_CFLAME2, 0, 0}, // S_CFLAME1 {SPR_WCFM, 32769, 4, NULL, S_CFLAME3, 0, 0}, // S_CFLAME2 {SPR_WCFM, 32770, 4, NULL, S_CFLAME4, 0, 0}, // S_CFLAME3 {SPR_WCFM, 32771, 4, NULL, S_CFLAME5, 0, 0}, // S_CFLAME4 {SPR_WCFM, 32772, 4, NULL, S_CFLAME6, 0, 0}, // S_CFLAME5 {SPR_WCFM, 32773, 4, NULL, S_CFLAME7, 0, 0}, // S_CFLAME6 {SPR_WCFM, 32774, 4, NULL, S_CFLAME8, 0, 0}, // S_CFLAME7 {SPR_WCFM, 32775, 4, NULL, S_CFLAME1, 0, 0}, // S_CFLAME8 {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY2, 0, 0}, // S_CFLAMEREADY1 {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY3, 0, 0}, // S_CFLAMEREADY2 {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY4, 0, 0}, // S_CFLAMEREADY3 {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY5, 0, 0}, // S_CFLAMEREADY4 {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY6, 0, 0}, // S_CFLAMEREADY5 {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY7, 0, 0}, // S_CFLAMEREADY6 {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY8, 0, 0}, // S_CFLAMEREADY7 {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY9, 0, 0}, // S_CFLAMEREADY8 {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY10, 0, 0}, // S_CFLAMEREADY9 {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY11, 0, 0}, // S_CFLAMEREADY10 {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY12, 0, 0}, // S_CFLAMEREADY11 {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY1, 0, 0}, // S_CFLAMEREADY12 {SPR_CFLM, 0, 1, A_Lower, S_CFLAMEDOWN, 0, 0}, // S_CFLAMEDOWN {SPR_CFLM, 0, 1, A_Raise, S_CFLAMEUP, 0, 0}, // S_CFLAMEUP {SPR_CFLM, 0, 2, NULL, S_CFLAMEATK_2, 0, 40}, // S_CFLAMEATK_1 {SPR_CFLM, 3, 2, NULL, S_CFLAMEATK_3, 0, 50}, // S_CFLAMEATK_2 {SPR_CFLM, 3, 2, NULL, S_CFLAMEATK_4, 0, 36}, // S_CFLAMEATK_3 {SPR_CFLM, 32772, 4, NULL, S_CFLAMEATK_5, 0, 0}, // S_CFLAMEATK_4 {SPR_CFLM, 32773, 4, A_CFlameAttack, S_CFLAMEATK_6, 0, 0}, // S_CFLAMEATK_5 {SPR_CFLM, 32772, 4, NULL, S_CFLAMEATK_7, 0, 0}, // S_CFLAMEATK_6 {SPR_CFLM, 6, 2, NULL, S_CFLAMEATK_8, 0, 40}, // S_CFLAMEATK_7 {SPR_CFLM, 6, 2, NULL, S_CFLAMEREADY1, 0, 0}, // S_CFLAMEATK_8 {SPR_CFFX, 32781, 5, NULL, S_CFLAMEFLOOR2, 0, 0}, // S_CFLAMEFLOOR1 {SPR_CFFX, 32782, 4, NULL, S_CFLAMEFLOOR3, 0, 0}, // S_CFLAMEFLOOR2 {SPR_CFFX, 32783, 3, NULL, S_NULL, 0, 0}, // S_CFLAMEFLOOR3 {SPR_CFFX, 32768, 3, NULL, S_FLAMEPUFF2, 0, 0}, // S_FLAMEPUFF1 {SPR_CFFX, 32769, 3, NULL, S_FLAMEPUFF3, 0, 0}, // S_FLAMEPUFF2 {SPR_CFFX, 32770, 3, NULL, S_FLAMEPUFF4, 0, 0}, // S_FLAMEPUFF3 {SPR_CFFX, 32771, 4, NULL, S_FLAMEPUFF5, 0, 0}, // S_FLAMEPUFF4 {SPR_CFFX, 32772, 3, NULL, S_FLAMEPUFF6, 0, 0}, // S_FLAMEPUFF5 {SPR_CFFX, 32773, 4, NULL, S_FLAMEPUFF7, 0, 0}, // S_FLAMEPUFF6 {SPR_CFFX, 32774, 3, NULL, S_FLAMEPUFF8, 0, 0}, // S_FLAMEPUFF7 {SPR_CFFX, 32775, 4, NULL, S_FLAMEPUFF9, 0, 0}, // S_FLAMEPUFF8 {SPR_CFFX, 32776, 3, NULL, S_FLAMEPUFF10, 0, 0}, // S_FLAMEPUFF9 {SPR_CFFX, 32777, 4, NULL, S_FLAMEPUFF11, 0, 0}, // S_FLAMEPUFF10 {SPR_CFFX, 32778, 3, NULL, S_FLAMEPUFF12, 0, 0}, // S_FLAMEPUFF11 {SPR_CFFX, 32779, 4, NULL, S_FLAMEPUFF13, 0, 0}, // S_FLAMEPUFF12 {SPR_CFFX, 32780, 3, NULL, S_NULL, 0, 0}, // S_FLAMEPUFF13 {SPR_CFFX, 32768, 3, NULL, S_FLAMEPUFF2_2, 0, 0}, // S_FLAMEPUFF2_1 {SPR_CFFX, 32769, 3, NULL, S_FLAMEPUFF2_3, 0, 0}, // S_FLAMEPUFF2_2 {SPR_CFFX, 32770, 3, NULL, S_FLAMEPUFF2_4, 0, 0}, // S_FLAMEPUFF2_3 {SPR_CFFX, 32771, 4, NULL, S_FLAMEPUFF2_5, 0, 0}, // S_FLAMEPUFF2_4 {SPR_CFFX, 32772, 3, NULL, S_FLAMEPUFF2_6, 0, 0}, // S_FLAMEPUFF2_5 {SPR_CFFX, 32773, 4, NULL, S_FLAMEPUFF2_7, 0, 0}, // S_FLAMEPUFF2_6 {SPR_CFFX, 32774, 3, NULL, S_FLAMEPUFF2_8, 0, 0}, // S_FLAMEPUFF2_7 {SPR_CFFX, 32775, 4, NULL, S_FLAMEPUFF2_9, 0, 0}, // S_FLAMEPUFF2_8 {SPR_CFFX, 32776, 3, NULL, S_FLAMEPUFF2_10, 0, 0}, // S_FLAMEPUFF2_9 {SPR_CFFX, 32770, 3, NULL, S_FLAMEPUFF2_11, 0, 0}, // S_FLAMEPUFF2_10 {SPR_CFFX, 32771, 4, NULL, S_FLAMEPUFF2_12, 0, 0}, // S_FLAMEPUFF2_11 {SPR_CFFX, 32772, 3, NULL, S_FLAMEPUFF2_13, 0, 0}, // S_FLAMEPUFF2_12 {SPR_CFFX, 32773, 4, NULL, S_FLAMEPUFF2_14, 0, 0}, // S_FLAMEPUFF2_13 {SPR_CFFX, 32774, 3, NULL, S_FLAMEPUFF2_15, 0, 0}, // S_FLAMEPUFF2_14 {SPR_CFFX, 32775, 4, NULL, S_FLAMEPUFF2_16, 0, 0}, // S_FLAMEPUFF2_15 {SPR_CFFX, 32776, 3, NULL, S_FLAMEPUFF2_17, 0, 0}, // S_FLAMEPUFF2_16 {SPR_CFFX, 32777, 4, NULL, S_FLAMEPUFF2_18, 0, 0}, // S_FLAMEPUFF2_17 {SPR_CFFX, 32778, 3, NULL, S_FLAMEPUFF2_19, 0, 0}, // S_FLAMEPUFF2_18 {SPR_CFFX, 32779, 4, NULL, S_FLAMEPUFF2_20, 0, 0}, // S_FLAMEPUFF2_19 {SPR_CFFX, 32780, 3, NULL, S_NULL, 0, 0}, // S_FLAMEPUFF2_20 {SPR_CFCF, 32768, 4, NULL, S_CIRCLE_FLAME2, 0, 0}, // S_CIRCLE_FLAME1 {SPR_CFCF, 32769, 2, A_CFlameRotate, S_CIRCLE_FLAME3, 0, 0}, // S_CIRCLE_FLAME2 {SPR_CFCF, 32770, 2, NULL, S_CIRCLE_FLAME4, 0, 0}, // S_CIRCLE_FLAME3 {SPR_CFCF, 32771, 1, NULL, S_CIRCLE_FLAME5, 0, 0}, // S_CIRCLE_FLAME4 {SPR_CFCF, 32772, 2, NULL, S_CIRCLE_FLAME6, 0, 0}, // S_CIRCLE_FLAME5 {SPR_CFCF, 32773, 2, A_CFlameRotate, S_CIRCLE_FLAME7, 0, 0}, // S_CIRCLE_FLAME6 {SPR_CFCF, 32774, 1, NULL, S_CIRCLE_FLAME8, 0, 0}, // S_CIRCLE_FLAME7 {SPR_CFCF, 32775, 2, NULL, S_CIRCLE_FLAME9, 0, 0}, // S_CIRCLE_FLAME8 {SPR_CFCF, 32776, 2, NULL, S_CIRCLE_FLAME10, 0, 0}, // S_CIRCLE_FLAME9 {SPR_CFCF, 32777, 1, A_CFlameRotate, S_CIRCLE_FLAME11, 0, 0}, // S_CIRCLE_FLAME10 {SPR_CFCF, 32778, 2, NULL, S_CIRCLE_FLAME12, 0, 0}, // S_CIRCLE_FLAME11 {SPR_CFCF, 32779, 3, NULL, S_CIRCLE_FLAME13, 0, 0}, // S_CIRCLE_FLAME12 {SPR_CFCF, 32780, 3, NULL, S_CIRCLE_FLAME14, 0, 0}, // S_CIRCLE_FLAME13 {SPR_CFCF, 32781, 2, A_CFlameRotate, S_CIRCLE_FLAME15, 0, 0}, // S_CIRCLE_FLAME14 {SPR_CFCF, 32782, 3, NULL, S_CIRCLE_FLAME16, 0, 0}, // S_CIRCLE_FLAME15 {SPR_CFCF, 32783, 2, NULL, S_NULL, 0, 0}, // S_CIRCLE_FLAME16 {SPR_CFCF, 32784, 3, NULL, S_CIRCLE_FLAME_X2, 0, 0}, // S_CIRCLE_FLAME_X1 {SPR_CFCF, 32785, 3, NULL, S_CIRCLE_FLAME_X3, 0, 0}, // S_CIRCLE_FLAME_X2 {SPR_CFCF, 32786, 3, A_Explode, S_CIRCLE_FLAME_X4, 0, 0}, // S_CIRCLE_FLAME_X3 {SPR_CFCF, 32787, 3, NULL, S_CIRCLE_FLAME_X5, 0, 0}, // S_CIRCLE_FLAME_X4 {SPR_CFCF, 32788, 3, NULL, S_CIRCLE_FLAME_X6, 0, 0}, // S_CIRCLE_FLAME_X5 {SPR_CFCF, 32789, 3, NULL, S_CIRCLE_FLAME_X7, 0, 0}, // S_CIRCLE_FLAME_X6 {SPR_CFCF, 32790, 3, NULL, S_CIRCLE_FLAME_X8, 0, 0}, // S_CIRCLE_FLAME_X7 {SPR_CFCF, 32791, 3, NULL, S_CIRCLE_FLAME_X9, 0, 0}, // S_CIRCLE_FLAME_X8 {SPR_CFCF, 32792, 3, NULL, S_CIRCLE_FLAME_X10, 0, 0}, // S_CIRCLE_FLAME_X9 {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_CIRCLE_FLAME_X10 {SPR_CFFX, 32768, 4, NULL, S_CFLAME_MISSILE2, 0, 0}, // S_CFLAME_MISSILE1 {SPR_CFFX, 0, 1, A_CFlamePuff, S_FLAMEPUFF1, 0, 0}, // S_CFLAME_MISSILE2 {SPR_CFFX, 32768, 1, A_CFlameMissile, S_FLAMEPUFF1, 0, 0}, // S_CFLAME_MISSILE_X {SPR_CHLY, 0, 1, A_WeaponReady, S_CHOLYREADY, 0, 0}, // S_CHOLYREADY {SPR_CHLY, 0, 1, A_Lower, S_CHOLYDOWN, 0, 0}, // S_CHOLYDOWN {SPR_CHLY, 0, 1, A_Raise, S_CHOLYUP, 0, 0}, // S_CHOLYUP {SPR_CHLY, 32768, 1, NULL, S_CHOLYATK_2, 0, 40}, // S_CHOLYATK_1 {SPR_CHLY, 32769, 1, NULL, S_CHOLYATK_3, 0, 40}, // S_CHOLYATK_2 {SPR_CHLY, 32770, 2, NULL, S_CHOLYATK_4, 0, 43}, // S_CHOLYATK_3 {SPR_CHLY, 32771, 2, NULL, S_CHOLYATK_5, 0, 43}, // S_CHOLYATK_4 {SPR_CHLY, 32772, 2, NULL, S_CHOLYATK_6, 0, 45}, // S_CHOLYATK_5 {SPR_CHLY, 32773, 6, A_CHolyAttack, S_CHOLYATK_7, 0, 48}, // S_CHOLYATK_6 {SPR_CHLY, 32774, 2, A_CHolyPalette, S_CHOLYATK_8, 0, 40}, // S_CHOLYATK_7 {SPR_CHLY, 32774, 2, A_CHolyPalette, S_CHOLYATK_9, 0, 40}, // S_CHOLYATK_8 {SPR_CHLY, 32774, 2, A_CHolyPalette, S_CHOLYREADY, 0, 36}, // S_CHOLYATK_9 {SPR_SPIR, 0, 2, A_CHolySeek, S_HOLY_FX2, 0, 0}, // S_HOLY_FX1 {SPR_SPIR, 0, 2, A_CHolySeek, S_HOLY_FX3, 0, 0}, // S_HOLY_FX2 {SPR_SPIR, 1, 2, A_CHolySeek, S_HOLY_FX4, 0, 0}, // S_HOLY_FX3 {SPR_SPIR, 1, 2, A_CHolyCheckScream, S_HOLY_FX1, 0, 0}, // S_HOLY_FX4 {SPR_SPIR, 3, 4, NULL, S_HOLY_FX_X2, 0, 0}, // S_HOLY_FX_X1 {SPR_SPIR, 4, 4, A_Scream, S_HOLY_FX_X3, 0, 0}, // S_HOLY_FX_X2 {SPR_SPIR, 5, 4, NULL, S_HOLY_FX_X4, 0, 0}, // S_HOLY_FX_X3 {SPR_SPIR, 6, 4, NULL, S_HOLY_FX_X5, 0, 0}, // S_HOLY_FX_X4 {SPR_SPIR, 7, 4, NULL, S_HOLY_FX_X6, 0, 0}, // S_HOLY_FX_X5 {SPR_SPIR, 8, 4, NULL, S_NULL, 0, 0}, // S_HOLY_FX_X6 {SPR_SPIR, 2, 1, A_CHolyTail, S_HOLY_TAIL1, 0, 0}, // S_HOLY_TAIL1 {SPR_SPIR, 3, -1, NULL, S_NULL, 0, 0}, // S_HOLY_TAIL2 {SPR_SPIR, 10, 3, NULL, S_HOLY_PUFF2, 0, 0}, // S_HOLY_PUFF1 {SPR_SPIR, 11, 3, NULL, S_HOLY_PUFF3, 0, 0}, // S_HOLY_PUFF2 {SPR_SPIR, 12, 3, NULL, S_HOLY_PUFF4, 0, 0}, // S_HOLY_PUFF3 {SPR_SPIR, 13, 3, NULL, S_HOLY_PUFF5, 0, 0}, // S_HOLY_PUFF4 {SPR_SPIR, 14, 3, NULL, S_NULL, 0, 0}, // S_HOLY_PUFF5 {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE2, 0, 0}, // S_HOLY_MISSILE1 {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE3, 0, 0}, // S_HOLY_MISSILE2 {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE4, 0, 0}, // S_HOLY_MISSILE3 {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE_X, 0, 0}, // S_HOLY_MISSILE4 {SPR_SPIR, 32783, 1, A_CHolyAttack2, S_NULL, 0, 0}, // S_HOLY_MISSILE_X {SPR_SPIR, 16, 3, NULL, S_HOLY_MISSILE_P2, 0, 0}, // S_HOLY_MISSILE_P1 {SPR_SPIR, 17, 3, NULL, S_HOLY_MISSILE_P3, 0, 0}, // S_HOLY_MISSILE_P2 {SPR_SPIR, 18, 3, NULL, S_HOLY_MISSILE_P4, 0, 0}, // S_HOLY_MISSILE_P3 {SPR_SPIR, 19, 3, NULL, S_HOLY_MISSILE_P5, 0, 0}, // S_HOLY_MISSILE_P4 {SPR_SPIR, 20, 3, NULL, S_NULL, 0, 0}, // S_HOLY_MISSILE_P5 {SPR_MWND, 0, 1, A_WeaponReady, S_MWANDREADY, 0, 0}, // S_MWANDREADY {SPR_MWND, 0, 1, A_Lower, S_MWANDDOWN, 0, 0}, // S_MWANDDOWN {SPR_MWND, 0, 1, A_Raise, S_MWANDUP, 0, 0}, // S_MWANDUP {SPR_MWND, 0, 6, NULL, S_MWANDATK_2, 0, 0}, // S_MWANDATK_1 {SPR_MWND, 32769, 6, A_MWandAttack, S_MWANDATK_3, 0, 48}, // S_MWANDATK_2 {SPR_MWND, 0, 3, NULL, S_MWANDATK_4, 0, 40}, // S_MWANDATK_3 {SPR_MWND, 0, 3, A_ReFire, S_MWANDREADY, 0, 36}, // S_MWANDATK_4 {SPR_MWND, 32772, 4, NULL, S_MWANDPUFF2, 0, 0}, // S_MWANDPUFF1 {SPR_MWND, 32773, 3, NULL, S_MWANDPUFF3, 0, 0}, // S_MWANDPUFF2 {SPR_MWND, 32774, 4, NULL, S_MWANDPUFF4, 0, 0}, // S_MWANDPUFF3 {SPR_MWND, 32775, 3, NULL, S_MWANDPUFF5, 0, 0}, // S_MWANDPUFF4 {SPR_MWND, 32776, 4, NULL, S_NULL, 0, 0}, // S_MWANDPUFF5 {SPR_MWND, 2, 4, NULL, S_MWANDSMOKE2, 0, 0}, // S_MWANDSMOKE1 {SPR_MWND, 3, 4, NULL, S_MWANDSMOKE3, 0, 0}, // S_MWANDSMOKE2 {SPR_MWND, 2, 4, NULL, S_MWANDSMOKE4, 0, 0}, // S_MWANDSMOKE3 {SPR_MWND, 3, 4, NULL, S_NULL, 0, 0}, // S_MWANDSMOKE4 {SPR_MWND, 32770, 4, NULL, S_MWAND_MISSILE2, 0, 0}, // S_MWAND_MISSILE1 {SPR_MWND, 32771, 4, NULL, S_MWAND_MISSILE1, 0, 0}, // S_MWAND_MISSILE2 {SPR_WMLG, 32768, 4, NULL, S_MW_LIGHTNING2, 0, 0}, // S_MW_LIGHTNING1 {SPR_WMLG, 32769, 4, NULL, S_MW_LIGHTNING3, 0, 0}, // S_MW_LIGHTNING2 {SPR_WMLG, 32770, 4, NULL, S_MW_LIGHTNING4, 0, 0}, // S_MW_LIGHTNING3 {SPR_WMLG, 32771, 4, NULL, S_MW_LIGHTNING5, 0, 0}, // S_MW_LIGHTNING4 {SPR_WMLG, 32772, 4, NULL, S_MW_LIGHTNING6, 0, 0}, // S_MW_LIGHTNING5 {SPR_WMLG, 32773, 4, NULL, S_MW_LIGHTNING7, 0, 0}, // S_MW_LIGHTNING6 {SPR_WMLG, 32774, 4, NULL, S_MW_LIGHTNING8, 0, 0}, // S_MW_LIGHTNING7 {SPR_WMLG, 32775, 4, NULL, S_MW_LIGHTNING1, 0, 0}, // S_MW_LIGHTNING8 {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY2, 0, 0}, // S_MLIGHTNINGREADY {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY3, 0, 0}, // S_MLIGHTNINGREADY2 {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY4, 0, 0}, // S_MLIGHTNINGREADY3 {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY5, 0, 0}, // S_MLIGHTNINGREADY4 {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY6, 0, 0}, // S_MLIGHTNINGREADY5 {SPR_MLNG, 32768, 1, A_LightningReady, S_MLIGHTNINGREADY7, 0, 0}, // S_MLIGHTNINGREADY6 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY8, 0, 0}, // S_MLIGHTNINGREADY7 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY9, 0, 0}, // S_MLIGHTNINGREADY8 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY10, 0, 0}, // S_MLIGHTNINGREADY9 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY11, 0, 0}, // S_MLIGHTNINGREADY10 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY12, 0, 0}, // S_MLIGHTNINGREADY11 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY13, 0, 0}, // S_MLIGHTNINGREADY12 {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY14, 0, 0}, // S_MLIGHTNINGREADY13 {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY15, 0, 0}, // S_MLIGHTNINGREADY14 {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY16, 0, 0}, // S_MLIGHTNINGREADY15 {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY17, 0, 0}, // S_MLIGHTNINGREADY16 {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY18, 0, 0}, // S_MLIGHTNINGREADY17 {SPR_MLNG, 32770, 1, A_LightningReady, S_MLIGHTNINGREADY19, 0, 0}, // S_MLIGHTNINGREADY18 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY20, 0, 0}, // S_MLIGHTNINGREADY19 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY21, 0, 0}, // S_MLIGHTNINGREADY20 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY22, 0, 0}, // S_MLIGHTNINGREADY21 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY23, 0, 0}, // S_MLIGHTNINGREADY22 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY24, 0, 0}, // S_MLIGHTNINGREADY23 {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY, 0, 0}, // S_MLIGHTNINGREADY24 {SPR_MLNG, 32768, 1, A_Lower, S_MLIGHTNINGDOWN, 0, 0}, // S_MLIGHTNINGDOWN {SPR_MLNG, 32768, 1, A_Raise, S_MLIGHTNINGUP, 0, 0}, // S_MLIGHTNINGUP {SPR_MLNG, 32771, 3, NULL, S_MLIGHTNINGATK_2, 0, 0}, // S_MLIGHTNINGATK_1 {SPR_MLNG, 32772, 3, NULL, S_MLIGHTNINGATK_3, 0, 0}, // S_MLIGHTNINGATK_2 {SPR_MLNG, 32773, 4, A_MLightningAttack, S_MLIGHTNINGATK_4, 0, 0}, // S_MLIGHTNINGATK_3 {SPR_MLNG, 32774, 4, NULL, S_MLIGHTNINGATK_5, 0, 0}, // S_MLIGHTNINGATK_4 {SPR_MLNG, 32775, 3, NULL, S_MLIGHTNINGATK_6, 0, 0}, // S_MLIGHTNINGATK_5 {SPR_MLNG, 32776, 3, NULL, S_MLIGHTNINGATK_7, 0, 0}, // S_MLIGHTNINGATK_6 {SPR_MLNG, 32776, 6, NULL, S_MLIGHTNINGATK_8, 0, 199}, // S_MLIGHTNINGATK_7 {SPR_MLNG, 32770, 2, NULL, S_MLIGHTNINGATK_9, 0, 55}, // S_MLIGHTNINGATK_8 {SPR_MLNG, 32769, 2, NULL, S_MLIGHTNINGATK_10, 0, 50}, // S_MLIGHTNINGATK_9 {SPR_MLNG, 32769, 2, NULL, S_MLIGHTNINGATK_11, 0, 45}, // S_MLIGHTNINGATK_10 {SPR_MLNG, 32769, 2, NULL, S_MLIGHTNINGREADY, 0, 40}, // S_MLIGHTNINGATK_11 {SPR_MLFX, 32768, 2, A_LightningZap, S_LIGHTNING_CEILING2, 0, 0}, // S_LIGHTNING_CEILING1 {SPR_MLFX, 32769, 2, A_LightningClip, S_LIGHTNING_CEILING3, 0, 0}, // S_LIGHTNING_CEILING2 {SPR_MLFX, 32770, 2, A_LightningClip, S_LIGHTNING_CEILING4, 0, 0}, // S_LIGHTNING_CEILING3 {SPR_MLFX, 32771, 2, A_LightningClip, S_LIGHTNING_CEILING1, 0, 0}, // S_LIGHTNING_CEILING4 {SPR_MLF2, 32768, 2, A_LightningRemove, S_LIGHTNING_C_X2, 0, 0}, // S_LIGHTNING_C_X1 {SPR_MLF2, 32769, 3, NULL, S_LIGHTNING_C_X3, 0, 0}, // S_LIGHTNING_C_X2 {SPR_MLF2, 32770, 3, NULL, S_LIGHTNING_C_X4, 0, 0}, // S_LIGHTNING_C_X3 {SPR_MLF2, 32771, 3, NULL, S_LIGHTNING_C_X5, 0, 0}, // S_LIGHTNING_C_X4 {SPR_MLF2, 32772, 3, NULL, S_LIGHTNING_C_X6, 0, 0}, // S_LIGHTNING_C_X5 {SPR_MLF2, 32778, 3, NULL, S_LIGHTNING_C_X7, 0, 0}, // S_LIGHTNING_C_X6 {SPR_MLF2, 32779, 3, NULL, S_LIGHTNING_C_X8, 0, 0}, // S_LIGHTNING_C_X7 {SPR_MLF2, 32780, 3, NULL, S_LIGHTNING_C_X9, 0, 0}, // S_LIGHTNING_C_X8 {SPR_ACLO, 4, 35, NULL, S_LIGHTNING_C_X10, 0, 0}, // S_LIGHTNING_C_X9 {SPR_MLF2, 32781, 3, NULL, S_LIGHTNING_C_X11, 0, 0}, // S_LIGHTNING_C_X10 {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_C_X12, 0, 0}, // S_LIGHTNING_C_X11 {SPR_MLF2, 32783, 4, NULL, S_LIGHTNING_C_X13, 0, 0}, // S_LIGHTNING_C_X12 {SPR_MLF2, 32784, 3, NULL, S_LIGHTNING_C_X14, 0, 0}, // S_LIGHTNING_C_X13 {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_C_X15, 0, 0}, // S_LIGHTNING_C_X14 {SPR_MLF2, 32784, 4, NULL, S_LIGHTNING_C_X16, 0, 0}, // S_LIGHTNING_C_X15 {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_C_X17, 0, 0}, // S_LIGHTNING_C_X16 {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_C_X18, 0, 0}, // S_LIGHTNING_C_X17 {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_C_X19, 0, 0}, // S_LIGHTNING_C_X18 {SPR_MLF2, 32783, 1, A_HideThing, S_FREETARGMOBJ, 0, 0}, // S_LIGHTNING_C_X19 {SPR_MLFX, 32772, 2, A_LightningZap, S_LIGHTNING_FLOOR2, 0, 0}, // S_LIGHTNING_FLOOR1 {SPR_MLFX, 32773, 2, A_LightningClip, S_LIGHTNING_FLOOR3, 0, 0}, // S_LIGHTNING_FLOOR2 {SPR_MLFX, 32774, 2, A_LightningClip, S_LIGHTNING_FLOOR4, 0, 0}, // S_LIGHTNING_FLOOR3 {SPR_MLFX, 32775, 2, A_LightningClip, S_LIGHTNING_FLOOR1, 0, 0}, // S_LIGHTNING_FLOOR4 {SPR_MLF2, 32773, 2, A_LightningRemove, S_LIGHTNING_F_X2, 0, 0}, // S_LIGHTNING_F_X1 {SPR_MLF2, 32774, 3, NULL, S_LIGHTNING_F_X3, 0, 0}, // S_LIGHTNING_F_X2 {SPR_MLF2, 32775, 3, NULL, S_LIGHTNING_F_X4, 0, 0}, // S_LIGHTNING_F_X3 {SPR_MLF2, 32776, 3, NULL, S_LIGHTNING_F_X5, 0, 0}, // S_LIGHTNING_F_X4 {SPR_MLF2, 32777, 3, NULL, S_LIGHTNING_F_X6, 0, 0}, // S_LIGHTNING_F_X5 {SPR_MLF2, 32778, 3, NULL, S_LIGHTNING_F_X7, 0, 0}, // S_LIGHTNING_F_X6 {SPR_MLF2, 32779, 3, NULL, S_LIGHTNING_F_X8, 0, 0}, // S_LIGHTNING_F_X7 {SPR_MLF2, 32780, 3, NULL, S_LIGHTNING_F_X9, 0, 0}, // S_LIGHTNING_F_X8 {SPR_ACLO, 4, 20, NULL, S_LIGHTNING_F_X10, 0, 0}, // S_LIGHTNING_F_X9 {SPR_MLF2, 32781, 3, NULL, S_LIGHTNING_F_X11, 0, 0}, // S_LIGHTNING_F_X10 {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_F_X12, 0, 0}, // S_LIGHTNING_F_X11 {SPR_MLF2, 32783, 4, NULL, S_LIGHTNING_F_X13, 0, 0}, // S_LIGHTNING_F_X12 {SPR_MLF2, 32784, 3, NULL, S_LIGHTNING_F_X14, 0, 0}, // S_LIGHTNING_F_X13 {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_F_X15, 0, 0}, // S_LIGHTNING_F_X14 {SPR_MLF2, 32784, 4, A_LastZap, S_LIGHTNING_F_X16, 0, 0}, // S_LIGHTNING_F_X15 {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_F_X17, 0, 0}, // S_LIGHTNING_F_X16 {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_F_X18, 0, 0}, // S_LIGHTNING_F_X17 {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_F_X19, 0, 0}, // S_LIGHTNING_F_X18 {SPR_MLF2, 32783, 1, A_HideThing, S_FREETARGMOBJ, 0, 0}, // S_LIGHTNING_F_X19 {SPR_MLFX, 32776, 2, A_ZapMimic, S_LIGHTNING_ZAP2, 0, 0}, // S_LIGHTNING_ZAP1 {SPR_MLFX, 32777, 2, A_ZapMimic, S_LIGHTNING_ZAP3, 0, 0}, // S_LIGHTNING_ZAP2 {SPR_MLFX, 32778, 2, A_ZapMimic, S_LIGHTNING_ZAP4, 0, 0}, // S_LIGHTNING_ZAP3 {SPR_MLFX, 32779, 2, A_ZapMimic, S_LIGHTNING_ZAP5, 0, 0}, // S_LIGHTNING_ZAP4 {SPR_MLFX, 32780, 2, A_ZapMimic, S_LIGHTNING_ZAP1, 0, 0}, // S_LIGHTNING_ZAP5 {SPR_MLFX, 32781, 2, NULL, S_LIGHTNING_ZAP_X2, 0, 0}, // S_LIGHTNING_ZAP_X1 {SPR_MLFX, 32782, 2, NULL, S_LIGHTNING_ZAP_X3, 0, 0}, // S_LIGHTNING_ZAP_X2 {SPR_MLFX, 32783, 2, NULL, S_LIGHTNING_ZAP_X4, 0, 0}, // S_LIGHTNING_ZAP_X3 {SPR_MLFX, 32784, 2, NULL, S_LIGHTNING_ZAP_X5, 0, 0}, // S_LIGHTNING_ZAP_X4 {SPR_MLFX, 32785, 2, NULL, S_LIGHTNING_ZAP_X6, 0, 0}, // S_LIGHTNING_ZAP_X5 {SPR_MLFX, 32786, 2, NULL, S_LIGHTNING_ZAP_X7, 0, 0}, // S_LIGHTNING_ZAP_X6 {SPR_MLFX, 32787, 2, NULL, S_LIGHTNING_ZAP_X8, 0, 0}, // S_LIGHTNING_ZAP_X7 {SPR_MLFX, 32788, 2, NULL, S_NULL, 0, 0}, // S_LIGHTNING_ZAP_X8 {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY2, 0, 0}, // S_MSTAFFREADY {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY3, 0, 0}, // S_MSTAFFREADY2 {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY4, 0, 0}, // S_MSTAFFREADY3 {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY5, 0, 0}, // S_MSTAFFREADY4 {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY6, 0, 0}, // S_MSTAFFREADY5 {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY7, 0, 0}, // S_MSTAFFREADY6 {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY8, 0, 0}, // S_MSTAFFREADY7 {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY9, 0, 0}, // S_MSTAFFREADY8 {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY10, 0, 0}, // S_MSTAFFREADY9 {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY11, 0, 0}, // S_MSTAFFREADY10 {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY12, 0, 0}, // S_MSTAFFREADY11 {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY13, 0, 0}, // S_MSTAFFREADY12 {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY14, 0, 0}, // S_MSTAFFREADY13 {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY15, 0, 0}, // S_MSTAFFREADY14 {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY16, 0, 0}, // S_MSTAFFREADY15 {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY17, 0, 0}, // S_MSTAFFREADY16 {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY18, 0, 0}, // S_MSTAFFREADY17 {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY19, 0, 0}, // S_MSTAFFREADY18 {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY20, 0, 0}, // S_MSTAFFREADY19 {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY21, 0, 0}, // S_MSTAFFREADY20 {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY22, 0, 0}, // S_MSTAFFREADY21 {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY23, 0, 0}, // S_MSTAFFREADY22 {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY24, 0, 0}, // S_MSTAFFREADY23 {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY25, 0, 0}, // S_MSTAFFREADY24 {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY26, 0, 0}, // S_MSTAFFREADY25 {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY27, 0, 0}, // S_MSTAFFREADY26 {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY28, 0, 0}, // S_MSTAFFREADY27 {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY29, 0, 0}, // S_MSTAFFREADY28 {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY30, 0, 0}, // S_MSTAFFREADY29 {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY31, 0, 0}, // S_MSTAFFREADY30 {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY32, 0, 0}, // S_MSTAFFREADY31 {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY33, 0, 0}, // S_MSTAFFREADY32 {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY34, 0, 0}, // S_MSTAFFREADY33 {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY35, 0, 0}, // S_MSTAFFREADY34 {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY, 0, 0}, // S_MSTAFFREADY35 {SPR_MSTF, 0, 1, A_Lower, S_MSTAFFDOWN, 0, 0}, // S_MSTAFFDOWN {SPR_MSTF, 0, 1, A_Raise, S_MSTAFFUP, 0, 0}, // S_MSTAFFUP {SPR_MSTF, 6, 4, NULL, S_MSTAFFATK_2, 0, 40}, // S_MSTAFFATK_1 {SPR_MSTF, 32775, 4, A_MStaffAttack, S_MSTAFFATK_3, 0, 48}, // S_MSTAFFATK_2 {SPR_MSTF, 32775, 2, A_MStaffPalette, S_MSTAFFATK_4, 0, 48}, // S_MSTAFFATK_3 {SPR_MSTF, 8, 2, A_MStaffPalette, S_MSTAFFATK_5, 0, 48}, // S_MSTAFFATK_4 {SPR_MSTF, 8, 2, A_MStaffPalette, S_MSTAFFATK_6, 0, 48}, // S_MSTAFFATK_5 {SPR_MSTF, 8, 1, NULL, S_MSTAFFATK_7, 0, 40}, // S_MSTAFFATK_6 {SPR_MSTF, 9, 5, NULL, S_MSTAFFREADY, 0, 36}, // S_MSTAFFATK_7 {SPR_MSP1, 32768, 3, A_MStaffWeave, S_MSTAFF_FX1_2, 0, 0}, // S_MSTAFF_FX1_1 {SPR_MSP1, 32769, 3, A_MStaffWeave, S_MSTAFF_FX1_3, 0, 0}, // S_MSTAFF_FX1_2 {SPR_MSP1, 32770, 3, A_MStaffWeave, S_MSTAFF_FX1_4, 0, 0}, // S_MSTAFF_FX1_3 {SPR_MSP1, 32771, 3, A_MStaffWeave, S_MSTAFF_FX1_5, 0, 0}, // S_MSTAFF_FX1_4 {SPR_MSP1, 32772, 3, A_MStaffWeave, S_MSTAFF_FX1_6, 0, 0}, // S_MSTAFF_FX1_5 {SPR_MSP1, 32773, 3, A_MStaffWeave, S_MSTAFF_FX1_1, 0, 0}, // S_MSTAFF_FX1_6 {SPR_MSP1, 32774, 4, NULL, S_MSTAFF_FX_X2, 0, 0}, // S_MSTAFF_FX_X1 {SPR_MSP1, 32775, 5, A_Explode, S_MSTAFF_FX_X3, 0, 0}, // S_MSTAFF_FX_X2 {SPR_MSP1, 32776, 4, NULL, S_MSTAFF_FX_X4, 0, 0}, // S_MSTAFF_FX_X3 {SPR_MSP1, 32777, 5, NULL, S_MSTAFF_FX_X5, 0, 0}, // S_MSTAFF_FX_X4 {SPR_MSP1, 32778, 4, NULL, S_MSTAFF_FX_X6, 0, 0}, // S_MSTAFF_FX_X5 {SPR_MSP1, 32779, 5, NULL, S_MSTAFF_FX_X7, 0, 0}, // S_MSTAFF_FX_X6 {SPR_MSP1, 32780, 4, NULL, S_MSTAFF_FX_X8, 0, 0}, // S_MSTAFF_FX_X7 {SPR_MSP1, 32781, 5, NULL, S_MSTAFF_FX_X9, 0, 0}, // S_MSTAFF_FX_X8 {SPR_MSP1, 32782, 4, NULL, S_MSTAFF_FX_X10, 0, 0}, // S_MSTAFF_FX_X9 {SPR_MSP1, 32783, 4, NULL, S_NULL, 0, 0}, // S_MSTAFF_FX_X10 {SPR_MSP2, 32768, 2, A_MStaffTrack, S_MSTAFF_FX2_2, 0, 0}, // S_MSTAFF_FX2_1 {SPR_MSP2, 32769, 2, A_MStaffTrack, S_MSTAFF_FX2_3, 0, 0}, // S_MSTAFF_FX2_2 {SPR_MSP2, 32770, 2, A_MStaffTrack, S_MSTAFF_FX2_4, 0, 0}, // S_MSTAFF_FX2_3 {SPR_MSP2, 32771, 2, A_MStaffTrack, S_MSTAFF_FX2_1, 0, 0}, // S_MSTAFF_FX2_4 {SPR_MSP2, 32772, 4, NULL, S_MSTAFF_FX2_X2, 0, 0}, // S_MSTAFF_FX2_X1 {SPR_MSP2, 32773, 5, A_Explode, S_MSTAFF_FX2_X3, 0, 0}, // S_MSTAFF_FX2_X2 {SPR_MSP2, 32774, 5, NULL, S_MSTAFF_FX2_X4, 0, 0}, // S_MSTAFF_FX2_X3 {SPR_MSP2, 32775, 5, NULL, S_MSTAFF_FX2_X5, 0, 0}, // S_MSTAFF_FX2_X4 {SPR_MSP2, 32776, 4, NULL, S_NULL, 0, 0}, // S_MSTAFF_FX2_X5 {SPR_WFR1, 32768, -1, NULL, S_NULL, 0, 0}, // S_FSWORD1 {SPR_WFR2, 32768, -1, NULL, S_NULL, 0, 0}, // S_FSWORD2 {SPR_WFR3, 32768, -1, NULL, S_NULL, 0, 0}, // S_FSWORD3 {SPR_WCH1, 32768, -1, NULL, S_NULL, 0, 0}, // S_CHOLY1 {SPR_WCH2, 32768, -1, NULL, S_NULL, 0, 0}, // S_CHOLY2 {SPR_WCH3, 32768, -1, NULL, S_NULL, 0, 0}, // S_CHOLY3 {SPR_WMS1, 32768, -1, NULL, S_NULL, 0, 0}, // S_MSTAFF1 {SPR_WMS2, 32768, -1, NULL, S_NULL, 0, 0}, // S_MSTAFF2 {SPR_WMS3, 32768, -1, NULL, S_NULL, 0, 0}, // S_MSTAFF3 {SPR_WPIG, 0, 1, A_WeaponReady, S_SNOUTREADY, 0, 0}, // S_SNOUTREADY {SPR_WPIG, 0, 1, A_Lower, S_SNOUTDOWN, 0, 0}, // S_SNOUTDOWN {SPR_WPIG, 0, 1, A_Raise, S_SNOUTUP, 0, 0}, // S_SNOUTUP {SPR_WPIG, 0, 4, A_SnoutAttack, S_SNOUTATK2, 0, 0}, // S_SNOUTATK1 {SPR_WPIG, 1, 8, A_SnoutAttack, S_SNOUTREADY, 0, 0}, // S_SNOUTATK2 {SPR_WMCS, 32768, 8, NULL, S_COS2, 0, 0}, // S_COS1 {SPR_WMCS, 32769, 8, NULL, S_COS3, 0, 0}, // S_COS2 {SPR_WMCS, 32770, 8, NULL, S_COS1, 0, 0}, // S_COS3 {SPR_CONE, 0, 1, A_WeaponReady, S_CONEREADY, 0, 0}, // S_CONEREADY {SPR_CONE, 0, 1, A_Lower, S_CONEDOWN, 0, 0}, // S_CONEDOWN {SPR_CONE, 0, 1, A_Raise, S_CONEUP, 0, 0}, // S_CONEUP {SPR_CONE, 1, 3, NULL, S_CONEATK1_2, 0, 0}, // S_CONEATK1_1 {SPR_CONE, 2, 4, NULL, S_CONEATK1_3, 0, 0}, // S_CONEATK1_2 {SPR_CONE, 3, 3, NULL, S_CONEATK1_4, 0, 0}, // S_CONEATK1_3 {SPR_CONE, 4, 5, NULL, S_CONEATK1_5, 0, 0}, // S_CONEATK1_4 {SPR_CONE, 5, 3, A_FireConePL1, S_CONEATK1_6, 0, 0}, // S_CONEATK1_5 {SPR_CONE, 6, 3, NULL, S_CONEATK1_7, 0, 0}, // S_CONEATK1_6 {SPR_CONE, 0, 9, NULL, S_CONEATK1_8, 0, 0}, // S_CONEATK1_7 {SPR_CONE, 0, 10, A_ReFire, S_CONEREADY, 0, 0}, // S_CONEATK1_8 {SPR_SHRD, 32768, 2, NULL, S_SHARDFX1_2, 0, 0}, // S_SHARDFX1_1 {SPR_SHRD, 32768, 3, A_ShedShard, S_SHARDFX1_3, 0, 0}, // S_SHARDFX1_2 {SPR_SHRD, 32769, 3, NULL, S_SHARDFX1_4, 0, 0}, // S_SHARDFX1_3 {SPR_SHRD, 32770, 3, NULL, S_SHARDFX1_1, 0, 0}, // S_SHARDFX1_4 {SPR_SHEX, 32768, 5, NULL, S_SHARDFXE1_2, 0, 0}, // S_SHARDFXE1_1 {SPR_SHEX, 32769, 5, NULL, S_SHARDFXE1_3, 0, 0}, // S_SHARDFXE1_2 {SPR_SHEX, 32770, 5, NULL, S_SHARDFXE1_4, 0, 0}, // S_SHARDFXE1_3 {SPR_SHEX, 32771, 5, NULL, S_SHARDFXE1_5, 0, 0}, // S_SHARDFXE1_4 {SPR_SHEX, 32772, 5, NULL, S_NULL, 0, 0}, // S_SHARDFXE1_5 {SPR_BLOD, 2, 8, NULL, S_BLOOD2, 0, 0}, // S_BLOOD1 {SPR_BLOD, 1, 8, NULL, S_BLOOD3, 0, 0}, // S_BLOOD2 {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOOD3 {SPR_BLOD, 2, 8, NULL, S_BLOODSPLATTER2, 0, 0}, // S_BLOODSPLATTER1 {SPR_BLOD, 1, 8, NULL, S_BLOODSPLATTER3, 0, 0}, // S_BLOODSPLATTER2 {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTER3 {SPR_BLOD, 0, 6, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTERX {SPR_GIBS, 0, -1, NULL, S_NULL, 0, 0}, // S_GIBS1 {SPR_PLAY, 0, -1, NULL, S_NULL, 0, 0}, // S_FPLAY {SPR_PLAY, 0, 4, NULL, S_FPLAY_RUN2, 0, 0}, // S_FPLAY_RUN1 {SPR_PLAY, 1, 4, NULL, S_FPLAY_RUN3, 0, 0}, // S_FPLAY_RUN2 {SPR_PLAY, 2, 4, NULL, S_FPLAY_RUN4, 0, 0}, // S_FPLAY_RUN3 {SPR_PLAY, 3, 4, NULL, S_FPLAY_RUN1, 0, 0}, // S_FPLAY_RUN4 {SPR_PLAY, 4, 8, NULL, S_FPLAY_ATK2, 0, 0}, // S_FPLAY_ATK1 {SPR_PLAY, 5, 8, NULL, S_FPLAY, 0, 0}, // S_FPLAY_ATK2 {SPR_PLAY, 6, 4, NULL, S_FPLAY_PAIN2, 0, 0}, // S_FPLAY_PAIN {SPR_PLAY, 6, 4, A_Pain, S_FPLAY, 0, 0}, // S_FPLAY_PAIN2 {SPR_PLAY, 7, 6, NULL, S_FPLAY_DIE2, 0, 0}, // S_FPLAY_DIE1 {SPR_PLAY, 8, 6, A_Scream, S_FPLAY_DIE3, 0, 0}, // S_FPLAY_DIE2 {SPR_PLAY, 9, 6, NULL, S_FPLAY_DIE4, 0, 0}, // S_FPLAY_DIE3 {SPR_PLAY, 10, 6, NULL, S_FPLAY_DIE5, 0, 0}, // S_FPLAY_DIE4 {SPR_PLAY, 11, 6, A_NoBlocking, S_FPLAY_DIE6, 0, 0}, // S_FPLAY_DIE5 {SPR_PLAY, 12, 6, NULL, S_FPLAY_DIE7, 0, 0}, // S_FPLAY_DIE6 {SPR_PLAY, 13, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_FPLAY_DIE7 {SPR_PLAY, 14, 5, A_Scream, S_FPLAY_XDIE2, 0, 0}, // S_FPLAY_XDIE1 {SPR_PLAY, 15, 5, A_SkullPop, S_FPLAY_XDIE3, 0, 0}, // S_FPLAY_XDIE2 {SPR_PLAY, 17, 5, A_NoBlocking, S_FPLAY_XDIE4, 0, 0}, // S_FPLAY_XDIE3 {SPR_PLAY, 18, 5, NULL, S_FPLAY_XDIE5, 0, 0}, // S_FPLAY_XDIE4 {SPR_PLAY, 19, 5, NULL, S_FPLAY_XDIE6, 0, 0}, // S_FPLAY_XDIE5 {SPR_PLAY, 20, 5, NULL, S_FPLAY_XDIE7, 0, 0}, // S_FPLAY_XDIE6 {SPR_PLAY, 21, 5, NULL, S_FPLAY_XDIE8, 0, 0}, // S_FPLAY_XDIE7 {SPR_PLAY, 22, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_FPLAY_XDIE8 {SPR_PLAY, 23, 5, A_FreezeDeath, S_FPLAY_ICE2, 0, 0}, // S_FPLAY_ICE {SPR_PLAY, 23, 1, A_FreezeDeathChunks, S_FPLAY_ICE2, 0, 0}, // S_FPLAY_ICE2 {SPR_FDTH, 32768, 5, NULL, S_PLAY_F_FDTH2, 0, 0}, // S_PLAY_F_FDTH1 {SPR_FDTH, 32769, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_F_FDTH2 {SPR_FDTH, 32770, 5, NULL, S_PLAY_C_FDTH2, 0, 0}, // S_PLAY_C_FDTH1 {SPR_FDTH, 32771, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_C_FDTH2 {SPR_FDTH, 32772, 5, NULL, S_PLAY_M_FDTH2, 0, 0}, // S_PLAY_M_FDTH1 {SPR_FDTH, 32773, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_M_FDTH2 {SPR_FDTH, 32774, 5, NULL, S_PLAY_FDTH4, 0, 0}, // S_PLAY_FDTH3 {SPR_FDTH, 32775, 4, A_Scream, S_PLAY_FDTH5, 0, 0}, // S_PLAY_FDTH4 {SPR_FDTH, 32776, 5, NULL, S_PLAY_FDTH6, 0, 0}, // S_PLAY_FDTH5 {SPR_FDTH, 32777, 4, NULL, S_PLAY_FDTH7, 0, 0}, // S_PLAY_FDTH6 {SPR_FDTH, 32778, 5, NULL, S_PLAY_FDTH8, 0, 0}, // S_PLAY_FDTH7 {SPR_FDTH, 32779, 4, NULL, S_PLAY_FDTH9, 0, 0}, // S_PLAY_FDTH8 {SPR_FDTH, 32780, 5, NULL, S_PLAY_FDTH10, 0, 0}, // S_PLAY_FDTH9 {SPR_FDTH, 32781, 4, NULL, S_PLAY_FDTH11, 0, 0}, // S_PLAY_FDTH10 {SPR_FDTH, 32782, 5, NULL, S_PLAY_FDTH12, 0, 0}, // S_PLAY_FDTH11 {SPR_FDTH, 32783, 4, NULL, S_PLAY_FDTH13, 0, 0}, // S_PLAY_FDTH12 {SPR_FDTH, 32784, 5, NULL, S_PLAY_FDTH14, 0, 0}, // S_PLAY_FDTH13 {SPR_FDTH, 32785, 4, NULL, S_PLAY_FDTH15, 0, 0}, // S_PLAY_FDTH14 {SPR_FDTH, 32786, 5, A_NoBlocking, S_PLAY_FDTH16, 0, 0}, // S_PLAY_FDTH15 {SPR_FDTH, 32787, 4, NULL, S_PLAY_FDTH17, 0, 0}, // S_PLAY_FDTH16 {SPR_FDTH, 32788, 5, NULL, S_PLAY_FDTH18, 0, 0}, // S_PLAY_FDTH17 {SPR_FDTH, 32789, 4, NULL, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH18 {SPR_ACLO, 4, 35, A_CheckBurnGone, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH19 {SPR_ACLO, 4, 8, NULL, S_NULL, 0, 0}, // S_PLAY_FDTH20 {SPR_BSKL, 0, 5, A_CheckSkullFloor, S_BLOODYSKULL2, 0, 0}, // S_BLOODYSKULL1 {SPR_BSKL, 1, 5, A_CheckSkullFloor, S_BLOODYSKULL3, 0, 0}, // S_BLOODYSKULL2 {SPR_BSKL, 2, 5, A_CheckSkullFloor, S_BLOODYSKULL4, 0, 0}, // S_BLOODYSKULL3 {SPR_BSKL, 3, 5, A_CheckSkullFloor, S_BLOODYSKULL5, 0, 0}, // S_BLOODYSKULL4 {SPR_BSKL, 5, 5, A_CheckSkullFloor, S_BLOODYSKULL6, 0, 0}, // S_BLOODYSKULL5 {SPR_BSKL, 6, 5, A_CheckSkullFloor, S_BLOODYSKULL7, 0, 0}, // S_BLOODYSKULL6 {SPR_BSKL, 7, 5, A_CheckSkullFloor, S_BLOODYSKULL1, 0, 0}, // S_BLOODYSKULL7 {SPR_BSKL, 8, 16, A_CheckSkullDone, S_BLOODYSKULLX1, 0, 0}, // S_BLOODYSKULLX1 {SPR_BSKL, 8, 1050, NULL, S_NULL, 0, 0}, // S_BLOODYSKULLX2 {SPR_PLAY, 0, 5, NULL, S_PLAYER_SPEED2, 0, 0}, // S_PLAYER_SPEED1 {SPR_PLAY, 0, 3, A_SpeedFade, S_NULL, 0, 0}, // S_PLAYER_SPEED2 {SPR_ICEC, 0, 10, NULL, S_ICECHUNK2, 0, 0}, // S_ICECHUNK1 {SPR_ICEC, 1, 10, A_IceSetTics, S_ICECHUNK3, 0, 0}, // S_ICECHUNK2 {SPR_ICEC, 2, 10, A_IceSetTics, S_ICECHUNK4, 0, 0}, // S_ICECHUNK3 {SPR_ICEC, 3, 10, A_IceSetTics, S_NULL, 0, 0}, // S_ICECHUNK4 {SPR_ICEC, 0, 10, A_IceCheckHeadDone, S_ICECHUNK_HEAD, 0, 0}, // S_ICECHUNK_HEAD {SPR_ICEC, 0, 1050, NULL, S_NULL, 0, 0}, // S_ICECHUNK_HEAD2 {SPR_CLER, 0, -1, NULL, S_NULL, 0, 0}, // S_CPLAY {SPR_CLER, 0, 4, NULL, S_CPLAY_RUN2, 0, 0}, // S_CPLAY_RUN1 {SPR_CLER, 1, 4, NULL, S_CPLAY_RUN3, 0, 0}, // S_CPLAY_RUN2 {SPR_CLER, 2, 4, NULL, S_CPLAY_RUN4, 0, 0}, // S_CPLAY_RUN3 {SPR_CLER, 3, 4, NULL, S_CPLAY_RUN1, 0, 0}, // S_CPLAY_RUN4 {SPR_CLER, 4, 6, NULL, S_CPLAY_ATK2, 0, 0}, // S_CPLAY_ATK1 {SPR_CLER, 5, 6, NULL, S_CPLAY_ATK3, 0, 0}, // S_CPLAY_ATK2 {SPR_CLER, 6, 6, NULL, S_CPLAY, 0, 0}, // S_CPLAY_ATK3 {SPR_CLER, 7, 4, NULL, S_CPLAY_PAIN2, 0, 0}, // S_CPLAY_PAIN {SPR_CLER, 7, 4, A_Pain, S_CPLAY, 0, 0}, // S_CPLAY_PAIN2 {SPR_CLER, 8, 6, NULL, S_CPLAY_DIE2, 0, 0}, // S_CPLAY_DIE1 {SPR_CLER, 10, 6, A_Scream, S_CPLAY_DIE3, 0, 0}, // S_CPLAY_DIE2 {SPR_CLER, 11, 6, NULL, S_CPLAY_DIE4, 0, 0}, // S_CPLAY_DIE3 {SPR_CLER, 11, 6, NULL, S_CPLAY_DIE5, 0, 0}, // S_CPLAY_DIE4 {SPR_CLER, 12, 6, A_NoBlocking, S_CPLAY_DIE6, 0, 0}, // S_CPLAY_DIE5 {SPR_CLER, 13, 6, NULL, S_CPLAY_DIE7, 0, 0}, // S_CPLAY_DIE6 {SPR_CLER, 14, 6, NULL, S_CPLAY_DIE8, 0, 0}, // S_CPLAY_DIE7 {SPR_CLER, 15, 6, NULL, S_CPLAY_DIE9, 0, 0}, // S_CPLAY_DIE8 {SPR_CLER, 16, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_CPLAY_DIE9 {SPR_CLER, 17, 5, A_Scream, S_CPLAY_XDIE2, 0, 0}, // S_CPLAY_XDIE1 {SPR_CLER, 18, 5, NULL, S_CPLAY_XDIE3, 0, 0}, // S_CPLAY_XDIE2 {SPR_CLER, 19, 5, A_NoBlocking, S_CPLAY_XDIE4, 0, 0}, // S_CPLAY_XDIE3 {SPR_CLER, 20, 5, NULL, S_CPLAY_XDIE5, 0, 0}, // S_CPLAY_XDIE4 {SPR_CLER, 21, 5, NULL, S_CPLAY_XDIE6, 0, 0}, // S_CPLAY_XDIE5 {SPR_CLER, 22, 5, NULL, S_CPLAY_XDIE7, 0, 0}, // S_CPLAY_XDIE6 {SPR_CLER, 23, 5, NULL, S_CPLAY_XDIE8, 0, 0}, // S_CPLAY_XDIE7 {SPR_CLER, 24, 5, NULL, S_CPLAY_XDIE9, 0, 0}, // S_CPLAY_XDIE8 {SPR_CLER, 25, 5, NULL, S_CPLAY_XDIE10, 0, 0}, // S_CPLAY_XDIE9 {SPR_CLER, 26, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_CPLAY_XDIE10 {SPR_CLER, 27, 5, A_FreezeDeath, S_CPLAY_ICE2, 0, 0}, // S_CPLAY_ICE {SPR_CLER, 27, 1, A_FreezeDeathChunks, S_CPLAY_ICE2, 0, 0}, // S_CPLAY_ICE2 {SPR_MAGE, 0, -1, NULL, S_NULL, 0, 0}, // S_MPLAY {SPR_MAGE, 0, 4, NULL, S_MPLAY_RUN2, 0, 0}, // S_MPLAY_RUN1 {SPR_MAGE, 1, 4, NULL, S_MPLAY_RUN3, 0, 0}, // S_MPLAY_RUN2 {SPR_MAGE, 2, 4, NULL, S_MPLAY_RUN4, 0, 0}, // S_MPLAY_RUN3 {SPR_MAGE, 3, 4, NULL, S_MPLAY_RUN1, 0, 0}, // S_MPLAY_RUN4 {SPR_MAGE, 4, 8, NULL, S_MPLAY_ATK2, 0, 0}, // S_MPLAY_ATK1 {SPR_MAGE, 32773, 8, NULL, S_MPLAY, 0, 0}, // S_MPLAY_ATK2 {SPR_MAGE, 6, 4, NULL, S_MPLAY_PAIN2, 0, 0}, // S_MPLAY_PAIN {SPR_MAGE, 6, 4, A_Pain, S_MPLAY, 0, 0}, // S_MPLAY_PAIN2 {SPR_MAGE, 7, 6, NULL, S_MPLAY_DIE2, 0, 0}, // S_MPLAY_DIE1 {SPR_MAGE, 8, 6, A_Scream, S_MPLAY_DIE3, 0, 0}, // S_MPLAY_DIE2 {SPR_MAGE, 9, 6, NULL, S_MPLAY_DIE4, 0, 0}, // S_MPLAY_DIE3 {SPR_MAGE, 10, 6, NULL, S_MPLAY_DIE5, 0, 0}, // S_MPLAY_DIE4 {SPR_MAGE, 11, 6, A_NoBlocking, S_MPLAY_DIE6, 0, 0}, // S_MPLAY_DIE5 {SPR_MAGE, 12, 6, NULL, S_MPLAY_DIE7, 0, 0}, // S_MPLAY_DIE6 {SPR_MAGE, 13, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_MPLAY_DIE7 {SPR_MAGE, 14, 5, A_Scream, S_MPLAY_XDIE2, 0, 0}, // S_MPLAY_XDIE1 {SPR_MAGE, 15, 5, NULL, S_MPLAY_XDIE3, 0, 0}, // S_MPLAY_XDIE2 {SPR_MAGE, 17, 5, A_NoBlocking, S_MPLAY_XDIE4, 0, 0}, // S_MPLAY_XDIE3 {SPR_MAGE, 18, 5, NULL, S_MPLAY_XDIE5, 0, 0}, // S_MPLAY_XDIE4 {SPR_MAGE, 19, 5, NULL, S_MPLAY_XDIE6, 0, 0}, // S_MPLAY_XDIE5 {SPR_MAGE, 20, 5, NULL, S_MPLAY_XDIE7, 0, 0}, // S_MPLAY_XDIE6 {SPR_MAGE, 21, 5, NULL, S_MPLAY_XDIE8, 0, 0}, // S_MPLAY_XDIE7 {SPR_MAGE, 22, 5, NULL, S_MPLAY_XDIE9, 0, 0}, // S_MPLAY_XDIE8 {SPR_MAGE, 23, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_MPLAY_XDIE9 {SPR_MAGE, 24, 5, A_FreezeDeath, S_MPLAY_ICE2, 0, 0}, // S_MPLAY_ICE {SPR_MAGE, 24, 1, A_FreezeDeathChunks, S_MPLAY_ICE2, 0, 0}, // S_MPLAY_ICE2 {SPR_PIGY, 0, -1, NULL, S_NULL, 0, 0}, // S_PIGPLAY {SPR_PIGY, 0, 3, NULL, S_PIGPLAY_RUN2, 0, 0}, // S_PIGPLAY_RUN1 {SPR_PIGY, 1, 3, NULL, S_PIGPLAY_RUN3, 0, 0}, // S_PIGPLAY_RUN2 {SPR_PIGY, 2, 3, NULL, S_PIGPLAY_RUN4, 0, 0}, // S_PIGPLAY_RUN3 {SPR_PIGY, 3, 3, NULL, S_PIGPLAY_RUN1, 0, 0}, // S_PIGPLAY_RUN4 {SPR_PIGY, 0, 12, NULL, S_PIGPLAY, 0, 0}, // S_PIGPLAY_ATK1 {SPR_PIGY, 3, 4, A_PigPain, S_PIGPLAY, 0, 0}, // S_PIGPLAY_PAIN {SPR_PIGY, 1, 10, A_PigLook, S_PIG_LOOK1, 0, 0}, // S_PIG_LOOK1 {SPR_PIGY, 0, 3, A_PigChase, S_PIG_WALK2, 0, 0}, // S_PIG_WALK1 {SPR_PIGY, 1, 3, A_PigChase, S_PIG_WALK3, 0, 0}, // S_PIG_WALK2 {SPR_PIGY, 2, 3, A_PigChase, S_PIG_WALK4, 0, 0}, // S_PIG_WALK3 {SPR_PIGY, 3, 3, A_PigChase, S_PIG_WALK1, 0, 0}, // S_PIG_WALK4 {SPR_PIGY, 3, 4, A_PigPain, S_PIG_WALK1, 0, 0}, // S_PIG_PAIN {SPR_PIGY, 0, 5, A_FaceTarget, S_PIG_ATK2, 0, 0}, // S_PIG_ATK1 {SPR_PIGY, 0, 10, A_PigAttack, S_PIG_WALK1, 0, 0}, // S_PIG_ATK2 {SPR_PIGY, 4, 4, A_Scream, S_PIG_DIE2, 0, 0}, // S_PIG_DIE1 {SPR_PIGY, 5, 3, A_NoBlocking, S_PIG_DIE3, 0, 0}, // S_PIG_DIE2 {SPR_PIGY, 6, 4, A_QueueCorpse, S_PIG_DIE4, 0, 0}, // S_PIG_DIE3 {SPR_PIGY, 7, 3, NULL, S_PIG_DIE5, 0, 0}, // S_PIG_DIE4 {SPR_PIGY, 8, 4, NULL, S_PIG_DIE6, 0, 0}, // S_PIG_DIE5 {SPR_PIGY, 9, 4, NULL, S_PIG_DIE7, 0, 0}, // S_PIG_DIE6 {SPR_PIGY, 10, 4, NULL, S_PIG_DIE8, 0, 0}, // S_PIG_DIE7 {SPR_PIGY, 11, -1, NULL, S_NULL, 0, 0}, // S_PIG_DIE8 {SPR_PIGY, 12, 5, A_FreezeDeath, S_PIG_ICE2, 0, 0}, // S_PIG_ICE {SPR_PIGY, 12, 1, A_FreezeDeathChunks, S_PIG_ICE2, 0, 0}, // S_PIG_ICE2 {SPR_CENT, 0, 10, A_Look, S_CENTAUR_LOOK2, 0, 0}, // S_CENTAUR_LOOK1 {SPR_CENT, 1, 10, A_Look, S_CENTAUR_LOOK1, 0, 0}, // S_CENTAUR_LOOK2 {SPR_CENT, 0, 4, A_Chase, S_CENTAUR_WALK2, 0, 0}, // S_CENTAUR_WALK1 {SPR_CENT, 1, 4, A_Chase, S_CENTAUR_WALK3, 0, 0}, // S_CENTAUR_WALK2 {SPR_CENT, 2, 4, A_Chase, S_CENTAUR_WALK4, 0, 0}, // S_CENTAUR_WALK3 {SPR_CENT, 3, 4, A_Chase, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_WALK4 {SPR_CENT, 7, 5, A_FaceTarget, S_CENTAUR_ATK2, 0, 0}, // S_CENTAUR_ATK1 {SPR_CENT, 8, 4, A_FaceTarget, S_CENTAUR_ATK3, 0, 0}, // S_CENTAUR_ATK2 {SPR_CENT, 9, 7, A_CentaurAttack, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_ATK3 {SPR_CENT, 4, 10, A_FaceTarget, S_CENTAUR_MISSILE2, 0, 0}, // S_CENTAUR_MISSILE1 {SPR_CENT, 32773, 8, A_CentaurAttack2, S_CENTAUR_MISSILE3, 0, 0}, // S_CENTAUR_MISSILE2 {SPR_CENT, 4, 10, A_FaceTarget, S_CENTAUR_MISSILE4, 0, 0}, // S_CENTAUR_MISSILE3 {SPR_CENT, 32773, 8, A_CentaurAttack2, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_MISSILE4 {SPR_CENT, 6, 6, A_Pain, S_CENTAUR_PAIN2, 0, 0}, // S_CENTAUR_PAIN1 {SPR_CENT, 6, 6, A_SetReflective, S_CENTAUR_PAIN3, 0, 0}, // S_CENTAUR_PAIN2 {SPR_CENT, 4, 15, A_CentaurDefend, S_CENTAUR_PAIN4, 0, 0}, // S_CENTAUR_PAIN3 {SPR_CENT, 4, 15, A_CentaurDefend, S_CENTAUR_PAIN5, 0, 0}, // S_CENTAUR_PAIN4 {SPR_CENT, 4, 15, A_CentaurDefend, S_CENTAUR_PAIN6, 0, 0}, // S_CENTAUR_PAIN5 {SPR_CENT, 4, 1, A_UnSetReflective, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_PAIN6 {SPR_CENT, 10, 4, NULL, S_CENTAUR_DEATH2, 0, 0}, // S_CENTAUR_DEATH1 {SPR_CENT, 11, 4, A_Scream, S_CENTAUR_DEATH3, 0, 0}, // S_CENTAUR_DEATH2 {SPR_CENT, 12, 4, NULL, S_CENTAUR_DEATH4, 0, 0}, // S_CENTAUR_DEATH3 {SPR_CENT, 13, 4, NULL, S_CENTAUR_DEATH5, 0, 0}, // S_CENTAUR_DEATH4 {SPR_CENT, 14, 4, A_NoBlocking, S_CENTAUR_DEATH6, 0, 0}, // S_CENTAUR_DEATH5 {SPR_CENT, 15, 4, NULL, S_CENTAUR_DEATH7, 0, 0}, // S_CENTAUR_DEATH6 {SPR_CENT, 16, 4, NULL, S_CENTAUR_DEATH8, 0, 0}, // S_CENTAUR_DEATH7 {SPR_CENT, 17, 4, A_QueueCorpse, S_CENTAUR_DEATH9, 0, 0}, // S_CENTAUR_DEATH8 {SPR_CENT, 18, 4, NULL, S_CENTAUR_DEATH0, 0, 0}, // S_CENTAUR_DEATH9 {SPR_CENT, 19, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_DEATH0 {SPR_CTXD, 0, 4, NULL, S_CENTAUR_DEATH_X2, 0, 0}, // S_CENTAUR_DEATH_X1 {SPR_CTXD, 1, 4, A_NoBlocking, S_CENTAUR_DEATH_X3, 0, 0}, // S_CENTAUR_DEATH_X2 {SPR_CTXD, 2, 4, A_CentaurDropStuff, S_CENTAUR_DEATH_X4, 0, 0}, // S_CENTAUR_DEATH_X3 {SPR_CTXD, 3, 3, A_Scream, S_CENTAUR_DEATH_X5, 0, 0}, // S_CENTAUR_DEATH_X4 {SPR_CTXD, 4, 4, A_QueueCorpse, S_CENTAUR_DEATH_X6, 0, 0}, // S_CENTAUR_DEATH_X5 {SPR_CTXD, 5, 3, NULL, S_CENTAUR_DEATH_X7, 0, 0}, // S_CENTAUR_DEATH_X6 {SPR_CTXD, 6, 4, NULL, S_CENTAUR_DEATH_X8, 0, 0}, // S_CENTAUR_DEATH_X7 {SPR_CTXD, 7, 3, NULL, S_CENTAUR_DEATH_X9, 0, 0}, // S_CENTAUR_DEATH_X8 {SPR_CTXD, 8, 4, NULL, S_CENTAUR_DEATH_X10, 0, 0}, // S_CENTAUR_DEATH_X9 {SPR_CTXD, 9, 3, NULL, S_CENTAUR_DEATH_X11, 0, 0}, // S_CENTAUR_DEATH_X10 {SPR_CTXD, 10, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_DEATH_X11 {SPR_CENT, 20, 5, A_FreezeDeath, S_CENTAUR_ICE2, 0, 0}, // S_CENTAUR_ICE {SPR_CENT, 20, 1, A_FreezeDeathChunks, S_CENTAUR_ICE2, 0, 0}, // S_CENTAUR_ICE2 {SPR_CTFX, 32768, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_FX1 {SPR_CTFX, 32769, 4, NULL, S_CENTAUR_FX_X2, 0, 0}, // S_CENTAUR_FX_X1 {SPR_CTFX, 32770, 3, NULL, S_CENTAUR_FX_X3, 0, 0}, // S_CENTAUR_FX_X2 {SPR_CTFX, 32771, 4, NULL, S_CENTAUR_FX_X4, 0, 0}, // S_CENTAUR_FX_X3 {SPR_CTFX, 32772, 3, NULL, S_CENTAUR_FX_X5, 0, 0}, // S_CENTAUR_FX_X4 {SPR_CTFX, 32773, 2, NULL, S_NULL, 0, 0}, // S_CENTAUR_FX_X5 {SPR_CTDP, 0, 3, A_CheckFloor, S_CENTAUR_SHIELD2, 0, 0}, // S_CENTAUR_SHIELD1 {SPR_CTDP, 1, 3, A_CheckFloor, S_CENTAUR_SHIELD3, 0, 0}, // S_CENTAUR_SHIELD2 {SPR_CTDP, 2, 3, A_CheckFloor, S_CENTAUR_SHIELD4, 0, 0}, // S_CENTAUR_SHIELD3 {SPR_CTDP, 3, 3, A_CheckFloor, S_CENTAUR_SHIELD5, 0, 0}, // S_CENTAUR_SHIELD4 {SPR_CTDP, 4, 3, A_CheckFloor, S_CENTAUR_SHIELD6, 0, 0}, // S_CENTAUR_SHIELD5 {SPR_CTDP, 5, 3, A_CheckFloor, S_CENTAUR_SHIELD3, 0, 0}, // S_CENTAUR_SHIELD6 {SPR_CTDP, 6, 4, NULL, S_CENTAUR_SHIELD_X2, 0, 0}, // S_CENTAUR_SHIELD_X1 {SPR_CTDP, 7, 4, A_QueueCorpse, S_CENTAUR_SHIELD_X3, 0, 0}, // S_CENTAUR_SHIELD_X2 {SPR_CTDP, 8, 4, NULL, S_CENTAUR_SHIELD_X4, 0, 0}, // S_CENTAUR_SHIELD_X3 {SPR_CTDP, 9, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_SHIELD_X4 {SPR_CTDP, 10, 3, A_CheckFloor, S_CENTAUR_SWORD2, 0, 0}, // S_CENTAUR_SWORD1 {SPR_CTDP, 11, 3, A_CheckFloor, S_CENTAUR_SWORD3, 0, 0}, // S_CENTAUR_SWORD2 {SPR_CTDP, 12, 3, A_CheckFloor, S_CENTAUR_SWORD4, 0, 0}, // S_CENTAUR_SWORD3 {SPR_CTDP, 13, 3, A_CheckFloor, S_CENTAUR_SWORD5, 0, 0}, // S_CENTAUR_SWORD4 {SPR_CTDP, 14, 3, A_CheckFloor, S_CENTAUR_SWORD6, 0, 0}, // S_CENTAUR_SWORD5 {SPR_CTDP, 15, 3, A_CheckFloor, S_CENTAUR_SWORD7, 0, 0}, // S_CENTAUR_SWORD6 {SPR_CTDP, 16, 3, A_CheckFloor, S_CENTAUR_SWORD3, 0, 0}, // S_CENTAUR_SWORD7 {SPR_CTDP, 17, 4, NULL, S_CENTAUR_SWORD_X2, 0, 0}, // S_CENTAUR_SWORD_X1 {SPR_CTDP, 18, 4, A_QueueCorpse, S_CENTAUR_SWORD_X3, 0, 0}, // S_CENTAUR_SWORD_X2 {SPR_CTDP, 19, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_SWORD_X3 {SPR_DEMN, 0, 10, A_Look, S_DEMN_LOOK2, 0, 0}, // S_DEMN_LOOK1 {SPR_DEMN, 0, 10, A_Look, S_DEMN_LOOK1, 0, 0}, // S_DEMN_LOOK2 {SPR_DEMN, 0, 4, A_Chase, S_DEMN_CHASE2, 0, 0}, // S_DEMN_CHASE1 {SPR_DEMN, 1, 4, A_Chase, S_DEMN_CHASE3, 0, 0}, // S_DEMN_CHASE2 {SPR_DEMN, 2, 4, A_Chase, S_DEMN_CHASE4, 0, 0}, // S_DEMN_CHASE3 {SPR_DEMN, 3, 4, A_Chase, S_DEMN_CHASE1, 0, 0}, // S_DEMN_CHASE4 {SPR_DEMN, 4, 6, A_FaceTarget, S_DEMN_ATK1_2, 0, 0}, // S_DEMN_ATK1_1 {SPR_DEMN, 5, 8, A_FaceTarget, S_DEMN_ATK1_3, 0, 0}, // S_DEMN_ATK1_2 {SPR_DEMN, 6, 6, A_DemonAttack1, S_DEMN_CHASE1, 0, 0}, // S_DEMN_ATK1_3 {SPR_DEMN, 4, 5, A_FaceTarget, S_DEMN_ATK2_2, 0, 0}, // S_DEMN_ATK2_1 {SPR_DEMN, 5, 6, A_FaceTarget, S_DEMN_ATK2_3, 0, 0}, // S_DEMN_ATK2_2 {SPR_DEMN, 6, 5, A_DemonAttack2, S_DEMN_CHASE1, 0, 0}, // S_DEMN_ATK2_3 {SPR_DEMN, 4, 4, NULL, S_DEMN_PAIN2, 0, 0}, // S_DEMN_PAIN1 {SPR_DEMN, 4, 4, A_Pain, S_DEMN_CHASE1, 0, 0}, // S_DEMN_PAIN2 {SPR_DEMN, 7, 6, NULL, S_DEMN_DEATH2, 0, 0}, // S_DEMN_DEATH1 {SPR_DEMN, 8, 6, NULL, S_DEMN_DEATH3, 0, 0}, // S_DEMN_DEATH2 {SPR_DEMN, 9, 6, A_Scream, S_DEMN_DEATH4, 0, 0}, // S_DEMN_DEATH3 {SPR_DEMN, 10, 6, A_NoBlocking, S_DEMN_DEATH5, 0, 0}, // S_DEMN_DEATH4 {SPR_DEMN, 11, 6, A_QueueCorpse, S_DEMN_DEATH6, 0, 0}, // S_DEMN_DEATH5 {SPR_DEMN, 12, 6, NULL, S_DEMN_DEATH7, 0, 0}, // S_DEMN_DEATH6 {SPR_DEMN, 13, 6, NULL, S_DEMN_DEATH8, 0, 0}, // S_DEMN_DEATH7 {SPR_DEMN, 14, 6, NULL, S_DEMN_DEATH9, 0, 0}, // S_DEMN_DEATH8 {SPR_DEMN, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN_DEATH9 {SPR_DEMN, 7, 6, NULL, S_DEMN_XDEATH2, 0, 0}, // S_DEMN_XDEATH1 {SPR_DEMN, 8, 6, A_DemonDeath, S_DEMN_XDEATH3, 0, 0}, // S_DEMN_XDEATH2 {SPR_DEMN, 9, 6, A_Scream, S_DEMN_XDEATH4, 0, 0}, // S_DEMN_XDEATH3 {SPR_DEMN, 10, 6, A_NoBlocking, S_DEMN_XDEATH5, 0, 0}, // S_DEMN_XDEATH4 {SPR_DEMN, 11, 6, A_QueueCorpse, S_DEMN_XDEATH6, 0, 0}, // S_DEMN_XDEATH5 {SPR_DEMN, 12, 6, NULL, S_DEMN_XDEATH7, 0, 0}, // S_DEMN_XDEATH6 {SPR_DEMN, 13, 6, NULL, S_DEMN_XDEATH8, 0, 0}, // S_DEMN_XDEATH7 {SPR_DEMN, 14, 6, NULL, S_DEMN_XDEATH9, 0, 0}, // S_DEMN_XDEATH8 {SPR_DEMN, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN_XDEATH9 {SPR_DEMN, 16, 5, A_FreezeDeath, S_DEMON_ICE2, 0, 0}, // S_DEMON_ICE {SPR_DEMN, 16, 1, A_FreezeDeathChunks, S_DEMON_ICE2, 0, 0}, // S_DEMON_ICE2 {SPR_DEMA, 0, 4, NULL, S_DEMONCHUNK1_2, 0, 0}, // S_DEMONCHUNK1_1 {SPR_DEMA, 0, 10, A_QueueCorpse, S_DEMONCHUNK1_3, 0, 0}, // S_DEMONCHUNK1_2 {SPR_DEMA, 0, 20, NULL, S_DEMONCHUNK1_3, 0, 0}, // S_DEMONCHUNK1_3 {SPR_DEMA, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK1_4 {SPR_DEMB, 0, 4, NULL, S_DEMONCHUNK2_2, 0, 0}, // S_DEMONCHUNK2_1 {SPR_DEMB, 0, 10, A_QueueCorpse, S_DEMONCHUNK2_3, 0, 0}, // S_DEMONCHUNK2_2 {SPR_DEMB, 0, 20, NULL, S_DEMONCHUNK2_3, 0, 0}, // S_DEMONCHUNK2_3 {SPR_DEMB, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK2_4 {SPR_DEMC, 0, 4, NULL, S_DEMONCHUNK3_2, 0, 0}, // S_DEMONCHUNK3_1 {SPR_DEMC, 0, 10, A_QueueCorpse, S_DEMONCHUNK3_3, 0, 0}, // S_DEMONCHUNK3_2 {SPR_DEMC, 0, 20, NULL, S_DEMONCHUNK3_3, 0, 0}, // S_DEMONCHUNK3_3 {SPR_DEMC, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK3_4 {SPR_DEMD, 0, 4, NULL, S_DEMONCHUNK4_2, 0, 0}, // S_DEMONCHUNK4_1 {SPR_DEMD, 0, 10, A_QueueCorpse, S_DEMONCHUNK4_3, 0, 0}, // S_DEMONCHUNK4_2 {SPR_DEMD, 0, 20, NULL, S_DEMONCHUNK4_3, 0, 0}, // S_DEMONCHUNK4_3 {SPR_DEMD, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK4_4 {SPR_DEME, 0, 4, NULL, S_DEMONCHUNK5_2, 0, 0}, // S_DEMONCHUNK5_1 {SPR_DEME, 0, 10, A_QueueCorpse, S_DEMONCHUNK5_3, 0, 0}, // S_DEMONCHUNK5_2 {SPR_DEME, 0, 20, NULL, S_DEMONCHUNK5_3, 0, 0}, // S_DEMONCHUNK5_3 {SPR_DEME, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK5_4 {SPR_DMFX, 32768, 4, NULL, S_DEMONFX_MOVE2, 0, 0}, // S_DEMONFX_MOVE1 {SPR_DMFX, 32769, 4, NULL, S_DEMONFX_MOVE3, 0, 0}, // S_DEMONFX_MOVE2 {SPR_DMFX, 32770, 4, NULL, S_DEMONFX_MOVE1, 0, 0}, // S_DEMONFX_MOVE3 {SPR_DMFX, 32771, 4, NULL, S_DEMONFX_BOOM2, 0, 0}, // S_DEMONFX_BOOM1 {SPR_DMFX, 32772, 4, NULL, S_DEMONFX_BOOM3, 0, 0}, // S_DEMONFX_BOOM2 {SPR_DMFX, 32773, 3, NULL, S_DEMONFX_BOOM4, 0, 0}, // S_DEMONFX_BOOM3 {SPR_DMFX, 32774, 3, NULL, S_DEMONFX_BOOM5, 0, 0}, // S_DEMONFX_BOOM4 {SPR_DMFX, 32775, 3, NULL, S_NULL, 0, 0}, // S_DEMONFX_BOOM5 {SPR_DEM2, 0, 10, A_Look, S_DEMN2_LOOK2, 0, 0}, // S_DEMN2_LOOK1 {SPR_DEM2, 0, 10, A_Look, S_DEMN2_LOOK1, 0, 0}, // S_DEMN2_LOOK2 {SPR_DEM2, 0, 4, A_Chase, S_DEMN2_CHASE2, 0, 0}, // S_DEMN2_CHASE1 {SPR_DEM2, 1, 4, A_Chase, S_DEMN2_CHASE3, 0, 0}, // S_DEMN2_CHASE2 {SPR_DEM2, 2, 4, A_Chase, S_DEMN2_CHASE4, 0, 0}, // S_DEMN2_CHASE3 {SPR_DEM2, 3, 4, A_Chase, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_CHASE4 {SPR_DEM2, 4, 6, A_FaceTarget, S_DEMN2_ATK1_2, 0, 0}, // S_DEMN2_ATK1_1 {SPR_DEM2, 5, 8, A_FaceTarget, S_DEMN2_ATK1_3, 0, 0}, // S_DEMN2_ATK1_2 {SPR_DEM2, 6, 6, A_DemonAttack1, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_ATK1_3 {SPR_DEM2, 4, 5, A_FaceTarget, S_DEMN2_ATK2_2, 0, 0}, // S_DEMN2_ATK2_1 {SPR_DEM2, 5, 6, A_FaceTarget, S_DEMN2_ATK2_3, 0, 0}, // S_DEMN2_ATK2_2 {SPR_DEM2, 6, 5, A_DemonAttack2, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_ATK2_3 {SPR_DEM2, 4, 4, NULL, S_DEMN2_PAIN2, 0, 0}, // S_DEMN2_PAIN1 {SPR_DEM2, 4, 4, A_Pain, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_PAIN2 {SPR_DEM2, 7, 6, NULL, S_DEMN2_DEATH2, 0, 0}, // S_DEMN2_DEATH1 {SPR_DEM2, 8, 6, NULL, S_DEMN2_DEATH3, 0, 0}, // S_DEMN2_DEATH2 {SPR_DEM2, 9, 6, A_Scream, S_DEMN2_DEATH4, 0, 0}, // S_DEMN2_DEATH3 {SPR_DEM2, 10, 6, A_NoBlocking, S_DEMN2_DEATH5, 0, 0}, // S_DEMN2_DEATH4 {SPR_DEM2, 11, 6, A_QueueCorpse, S_DEMN2_DEATH6, 0, 0}, // S_DEMN2_DEATH5 {SPR_DEM2, 12, 6, NULL, S_DEMN2_DEATH7, 0, 0}, // S_DEMN2_DEATH6 {SPR_DEM2, 13, 6, NULL, S_DEMN2_DEATH8, 0, 0}, // S_DEMN2_DEATH7 {SPR_DEM2, 14, 6, NULL, S_DEMN2_DEATH9, 0, 0}, // S_DEMN2_DEATH8 {SPR_DEM2, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN2_DEATH9 {SPR_DEM2, 7, 6, NULL, S_DEMN2_XDEATH2, 0, 0}, // S_DEMN2_XDEATH1 {SPR_DEM2, 8, 6, A_Demon2Death, S_DEMN2_XDEATH3, 0, 0}, // S_DEMN2_XDEATH2 {SPR_DEM2, 9, 6, A_Scream, S_DEMN2_XDEATH4, 0, 0}, // S_DEMN2_XDEATH3 {SPR_DEM2, 10, 6, A_NoBlocking, S_DEMN2_XDEATH5, 0, 0}, // S_DEMN2_XDEATH4 {SPR_DEM2, 11, 6, A_QueueCorpse, S_DEMN2_XDEATH6, 0, 0}, // S_DEMN2_XDEATH5 {SPR_DEM2, 12, 6, NULL, S_DEMN2_XDEATH7, 0, 0}, // S_DEMN2_XDEATH6 {SPR_DEM2, 13, 6, NULL, S_DEMN2_XDEATH8, 0, 0}, // S_DEMN2_XDEATH7 {SPR_DEM2, 14, 6, NULL, S_DEMN2_XDEATH9, 0, 0}, // S_DEMN2_XDEATH8 {SPR_DEM2, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN2_XDEATH9 {SPR_DMBA, 0, 4, NULL, S_DEMON2CHUNK1_2, 0, 0}, // S_DEMON2CHUNK1_1 {SPR_DMBA, 0, 10, A_QueueCorpse, S_DEMON2CHUNK1_3, 0, 0}, // S_DEMON2CHUNK1_2 {SPR_DMBA, 0, 20, NULL, S_DEMON2CHUNK1_3, 0, 0}, // S_DEMON2CHUNK1_3 {SPR_DMBA, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK1_4 {SPR_DMBB, 0, 4, NULL, S_DEMON2CHUNK2_2, 0, 0}, // S_DEMON2CHUNK2_1 {SPR_DMBB, 0, 10, A_QueueCorpse, S_DEMON2CHUNK2_3, 0, 0}, // S_DEMON2CHUNK2_2 {SPR_DMBB, 0, 20, NULL, S_DEMON2CHUNK2_3, 0, 0}, // S_DEMON2CHUNK2_3 {SPR_DMBB, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK2_4 {SPR_DMBC, 0, 4, NULL, S_DEMON2CHUNK3_2, 0, 0}, // S_DEMON2CHUNK3_1 {SPR_DMBC, 0, 10, A_QueueCorpse, S_DEMON2CHUNK3_3, 0, 0}, // S_DEMON2CHUNK3_2 {SPR_DMBC, 0, 20, NULL, S_DEMON2CHUNK3_3, 0, 0}, // S_DEMON2CHUNK3_3 {SPR_DMBC, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK3_4 {SPR_DMBD, 0, 4, NULL, S_DEMON2CHUNK4_2, 0, 0}, // S_DEMON2CHUNK4_1 {SPR_DMBD, 0, 10, A_QueueCorpse, S_DEMON2CHUNK4_3, 0, 0}, // S_DEMON2CHUNK4_2 {SPR_DMBD, 0, 20, NULL, S_DEMON2CHUNK4_3, 0, 0}, // S_DEMON2CHUNK4_3 {SPR_DMBD, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK4_4 {SPR_DMBE, 0, 4, NULL, S_DEMON2CHUNK5_2, 0, 0}, // S_DEMON2CHUNK5_1 {SPR_DMBE, 0, 10, NULL, S_DEMON2CHUNK5_3, 0, 0}, // S_DEMON2CHUNK5_2 {SPR_DMBE, 0, 20, NULL, S_DEMON2CHUNK5_3, 0, 0}, // S_DEMON2CHUNK5_3 {SPR_DMBE, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK5_4 {SPR_D2FX, 32768, 4, NULL, S_DEMON2FX_MOVE2, 0, 0}, // S_DEMON2FX_MOVE1 {SPR_D2FX, 32769, 4, NULL, S_DEMON2FX_MOVE3, 0, 0}, // S_DEMON2FX_MOVE2 {SPR_D2FX, 32770, 4, NULL, S_DEMON2FX_MOVE4, 0, 0}, // S_DEMON2FX_MOVE3 {SPR_D2FX, 32771, 4, NULL, S_DEMON2FX_MOVE5, 0, 0}, // S_DEMON2FX_MOVE4 {SPR_D2FX, 32772, 4, NULL, S_DEMON2FX_MOVE6, 0, 0}, // S_DEMON2FX_MOVE5 {SPR_D2FX, 32773, 4, NULL, S_DEMON2FX_MOVE1, 0, 0}, // S_DEMON2FX_MOVE6 {SPR_D2FX, 32774, 4, NULL, S_DEMON2FX_BOOM2, 0, 0}, // S_DEMON2FX_BOOM1 {SPR_D2FX, 32775, 4, NULL, S_DEMON2FX_BOOM3, 0, 0}, // S_DEMON2FX_BOOM2 {SPR_D2FX, 32776, 4, NULL, S_DEMON2FX_BOOM4, 0, 0}, // S_DEMON2FX_BOOM3 {SPR_D2FX, 32777, 4, NULL, S_DEMON2FX_BOOM5, 0, 0}, // S_DEMON2FX_BOOM4 {SPR_D2FX, 32778, 3, NULL, S_DEMON2FX_BOOM6, 0, 0}, // S_DEMON2FX_BOOM5 {SPR_D2FX, 32779, 3, NULL, S_NULL, 0, 0}, // S_DEMON2FX_BOOM6 {SPR_WRTH, 0, 2, A_WraithRaiseInit, S_WRAITH_RAISE2, 0, 0}, // S_WRAITH_RAISE1 {SPR_WRTH, 0, 2, A_WraithRaise, S_WRAITH_RAISE3, 0, 0}, // S_WRAITH_RAISE2 {SPR_WRTH, 0, 2, A_FaceTarget, S_WRAITH_RAISE4, 0, 0}, // S_WRAITH_RAISE3 {SPR_WRTH, 1, 2, A_WraithRaise, S_WRAITH_RAISE5, 0, 0}, // S_WRAITH_RAISE4 {SPR_WRTH, 1, 2, A_WraithRaise, S_WRAITH_RAISE2, 0, 0}, // S_WRAITH_RAISE5 {SPR_WRTH, 0, 10, NULL, S_WRAITH_INIT2, 0, 0}, // S_WRAITH_INIT1 {SPR_WRTH, 1, 5, A_WraithInit, S_WRAITH_LOOK1, 0, 0}, // S_WRAITH_INIT2 {SPR_WRTH, 0, 15, A_WraithLook, S_WRAITH_LOOK2, 0, 0}, // S_WRAITH_LOOK1 {SPR_WRTH, 1, 15, A_WraithLook, S_WRAITH_LOOK1, 0, 0}, // S_WRAITH_LOOK2 {SPR_WRTH, 0, 4, A_WraithChase, S_WRAITH_CHASE2, 0, 0}, // S_WRAITH_CHASE1 {SPR_WRTH, 1, 4, A_WraithChase, S_WRAITH_CHASE3, 0, 0}, // S_WRAITH_CHASE2 {SPR_WRTH, 2, 4, A_WraithChase, S_WRAITH_CHASE4, 0, 0}, // S_WRAITH_CHASE3 {SPR_WRTH, 3, 4, A_WraithChase, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_CHASE4 {SPR_WRTH, 4, 6, A_FaceTarget, S_WRAITH_ATK1_2, 0, 0}, // S_WRAITH_ATK1_1 {SPR_WRTH, 5, 6, A_WraithFX3, S_WRAITH_ATK1_3, 0, 0}, // S_WRAITH_ATK1_2 {SPR_WRTH, 6, 6, A_WraithMelee, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_ATK1_3 {SPR_WRTH, 4, 6, A_FaceTarget, S_WRAITH_ATK2_2, 0, 0}, // S_WRAITH_ATK2_1 {SPR_WRTH, 5, 6, NULL, S_WRAITH_ATK2_3, 0, 0}, // S_WRAITH_ATK2_2 {SPR_WRTH, 6, 6, A_WraithMissile, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_ATK2_3 {SPR_WRTH, 0, 2, NULL, S_WRAITH_PAIN2, 0, 0}, // S_WRAITH_PAIN1 {SPR_WRTH, 7, 6, A_Pain, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_PAIN2 {SPR_WRTH, 8, 4, NULL, S_WRAITH_DEATH1_2, 0, 0}, // S_WRAITH_DEATH1_1 {SPR_WRTH, 9, 4, A_Scream, S_WRAITH_DEATH1_3, 0, 0}, // S_WRAITH_DEATH1_2 {SPR_WRTH, 10, 4, NULL, S_WRAITH_DEATH1_4, 0, 0}, // S_WRAITH_DEATH1_3 {SPR_WRTH, 11, 4, NULL, S_WRAITH_DEATH1_5, 0, 0}, // S_WRAITH_DEATH1_4 {SPR_WRTH, 12, 4, A_NoBlocking, S_WRAITH_DEATH1_6, 0, 0}, // S_WRAITH_DEATH1_5 {SPR_WRTH, 13, 4, A_QueueCorpse, S_WRAITH_DEATH1_7, 0, 0}, // S_WRAITH_DEATH1_6 {SPR_WRTH, 14, 4, NULL, S_WRAITH_DEATH1_8, 0, 0}, // S_WRAITH_DEATH1_7 {SPR_WRTH, 15, 5, NULL, S_WRAITH_DEATH1_9, 0, 0}, // S_WRAITH_DEATH1_8 {SPR_WRTH, 16, 5, NULL, S_WRAITH_DEATH1_0, 0, 0}, // S_WRAITH_DEATH1_9 {SPR_WRTH, 17, -1, NULL, S_NULL, 0, 0}, // S_WRAITH_DEATH1_0 {SPR_WRT2, 0, 5, NULL, S_WRAITH_DEATH2_2, 0, 0}, // S_WRAITH_DEATH2_1 {SPR_WRT2, 1, 5, A_Scream, S_WRAITH_DEATH2_3, 0, 0}, // S_WRAITH_DEATH2_2 {SPR_WRT2, 2, 5, NULL, S_WRAITH_DEATH2_4, 0, 0}, // S_WRAITH_DEATH2_3 {SPR_WRT2, 3, 5, NULL, S_WRAITH_DEATH2_5, 0, 0}, // S_WRAITH_DEATH2_4 {SPR_WRT2, 4, 5, A_NoBlocking, S_WRAITH_DEATH2_6, 0, 0}, // S_WRAITH_DEATH2_5 {SPR_WRT2, 5, 5, A_QueueCorpse, S_WRAITH_DEATH2_7, 0, 0}, // S_WRAITH_DEATH2_6 {SPR_WRT2, 6, 5, NULL, S_WRAITH_DEATH2_8, 0, 0}, // S_WRAITH_DEATH2_7 {SPR_WRT2, 7, -1, NULL, S_NULL, 0, 0}, // S_WRAITH_DEATH2_8 {SPR_WRT2, 8, 5, A_FreezeDeath, S_WRAITH_ICE2, 0, 0}, // S_WRAITH_ICE {SPR_WRT2, 8, 1, A_FreezeDeathChunks, S_WRAITH_ICE2, 0, 0}, // S_WRAITH_ICE2 {SPR_WRBL, 32768, 3, NULL, S_WRTHFX_MOVE2, 0, 0}, // S_WRTHFX_MOVE1 {SPR_WRBL, 32769, 3, A_WraithFX2, S_WRTHFX_MOVE3, 0, 0}, // S_WRTHFX_MOVE2 {SPR_WRBL, 32770, 3, NULL, S_WRTHFX_MOVE1, 0, 0}, // S_WRTHFX_MOVE3 {SPR_WRBL, 32771, 4, NULL, S_WRTHFX_BOOM2, 0, 0}, // S_WRTHFX_BOOM1 {SPR_WRBL, 32772, 4, A_WraithFX2, S_WRTHFX_BOOM3, 0, 0}, // S_WRTHFX_BOOM2 {SPR_WRBL, 32773, 4, NULL, S_WRTHFX_BOOM4, 0, 0}, // S_WRTHFX_BOOM3 {SPR_WRBL, 32774, 3, A_WraithFX2, S_WRTHFX_BOOM5, 0, 0}, // S_WRTHFX_BOOM4 {SPR_WRBL, 32775, 3, A_WraithFX2, S_WRTHFX_BOOM6, 0, 0}, // S_WRTHFX_BOOM5 {SPR_WRBL, 32776, 3, NULL, S_NULL, 0, 0}, // S_WRTHFX_BOOM6 {SPR_WRBL, 32777, 4, NULL, S_WRTHFX_SIZZLE2, 0, 0}, // S_WRTHFX_SIZZLE1 {SPR_WRBL, 32778, 4, NULL, S_WRTHFX_SIZZLE3, 0, 0}, // S_WRTHFX_SIZZLE2 {SPR_WRBL, 32779, 4, NULL, S_WRTHFX_SIZZLE4, 0, 0}, // S_WRTHFX_SIZZLE3 {SPR_WRBL, 32780, 4, NULL, S_WRTHFX_SIZZLE5, 0, 0}, // S_WRTHFX_SIZZLE4 {SPR_WRBL, 32781, 4, NULL, S_WRTHFX_SIZZLE6, 0, 0}, // S_WRTHFX_SIZZLE5 {SPR_WRBL, 32782, 4, NULL, S_WRTHFX_SIZZLE7, 0, 0}, // S_WRTHFX_SIZZLE6 {SPR_WRBL, 32783, 4, NULL, S_NULL, 0, 0}, // S_WRTHFX_SIZZLE7 {SPR_WRBL, 32784, 4, NULL, S_WRTHFX_DROP2, 0, 0}, // S_WRTHFX_DROP1 {SPR_WRBL, 32785, 4, NULL, S_WRTHFX_DROP3, 0, 0}, // S_WRTHFX_DROP2 {SPR_WRBL, 32786, 4, NULL, S_WRTHFX_DROP1, 0, 0}, // S_WRTHFX_DROP3 {SPR_WRBL, 32786, 4, NULL, S_NULL, 0, 0}, // S_WRTHFX_DEAD1 {SPR_WRBL, 19, 4, NULL, S_WRTHFX_ADROP2, 0, 0}, // S_WRTHFX_ADROP1 {SPR_WRBL, 20, 4, NULL, S_WRTHFX_ADROP3, 0, 0}, // S_WRTHFX_ADROP2 {SPR_WRBL, 21, 4, NULL, S_WRTHFX_ADROP4, 0, 0}, // S_WRTHFX_ADROP3 {SPR_WRBL, 22, 4, NULL, S_WRTHFX_ADROP1, 0, 0}, // S_WRTHFX_ADROP4 {SPR_WRBL, 22, 10, NULL, S_NULL, 0, 0}, // S_WRTHFX_ADEAD1 {SPR_WRBL, 23, 7, NULL, S_WRTHFX_BDROP2, 0, 0}, // S_WRTHFX_BDROP1 {SPR_WRBL, 24, 7, NULL, S_WRTHFX_BDROP3, 0, 0}, // S_WRTHFX_BDROP2 {SPR_WRBL, 25, 7, NULL, S_WRTHFX_BDROP1, 0, 0}, // S_WRTHFX_BDROP3 {SPR_WRBL, 25, 35, NULL, S_NULL, 0, 0}, // S_WRTHFX_BDEAD1 {SPR_MNTR, 0, 15, NULL, S_MNTR_SPAWN2, 0, 0}, // S_MNTR_SPAWN1 {SPR_MNTR, 0, 15, A_MinotaurFade1, S_MNTR_SPAWN3, 0, 0}, // S_MNTR_SPAWN2 {SPR_MNTR, 0, 3, A_MinotaurFade2, S_MNTR_LOOK1, 0, 0}, // S_MNTR_SPAWN3 {SPR_MNTR, 0, 10, A_MinotaurLook, S_MNTR_LOOK2, 0, 0}, // S_MNTR_LOOK1 {SPR_MNTR, 1, 10, A_MinotaurLook, S_MNTR_LOOK1, 0, 0}, // S_MNTR_LOOK2 {SPR_MNTR, 0, 5, A_MinotaurChase, S_MNTR_WALK2, 0, 0}, // S_MNTR_WALK1 {SPR_MNTR, 1, 5, A_MinotaurChase, S_MNTR_WALK3, 0, 0}, // S_MNTR_WALK2 {SPR_MNTR, 2, 5, A_MinotaurChase, S_MNTR_WALK4, 0, 0}, // S_MNTR_WALK3 {SPR_MNTR, 3, 5, A_MinotaurChase, S_MNTR_WALK1, 0, 0}, // S_MNTR_WALK4 {SPR_MNTR, 0, 5, A_MinotaurRoam, S_MNTR_ROAM2, 0, 0}, // S_MNTR_ROAM1 {SPR_MNTR, 1, 5, A_MinotaurRoam, S_MNTR_ROAM3, 0, 0}, // S_MNTR_ROAM2 {SPR_MNTR, 2, 5, A_MinotaurRoam, S_MNTR_ROAM4, 0, 0}, // S_MNTR_ROAM3 {SPR_MNTR, 3, 5, A_MinotaurRoam, S_MNTR_ROAM1, 0, 0}, // S_MNTR_ROAM4 {SPR_MNTR, 6, 10, A_FaceTarget, S_MNTR_ATK1_2, 0, 0}, // S_MNTR_ATK1_1 {SPR_MNTR, 7, 7, A_FaceTarget, S_MNTR_ATK1_3, 0, 0}, // S_MNTR_ATK1_2 {SPR_MNTR, 8, 12, A_MinotaurAtk1, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK1_3 {SPR_MNTR, 6, 10, A_MinotaurDecide, S_MNTR_ATK2_2, 0, 0}, // S_MNTR_ATK2_1 {SPR_MNTR, 9, 4, A_FaceTarget, S_MNTR_ATK2_3, 0, 0}, // S_MNTR_ATK2_2 {SPR_MNTR, 10, 9, A_MinotaurAtk2, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK2_3 {SPR_MNTR, 6, 10, A_FaceTarget, S_MNTR_ATK3_2, 0, 0}, // S_MNTR_ATK3_1 {SPR_MNTR, 7, 7, A_FaceTarget, S_MNTR_ATK3_3, 0, 0}, // S_MNTR_ATK3_2 {SPR_MNTR, 8, 12, A_MinotaurAtk3, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK3_3 {SPR_MNTR, 8, 12, NULL, S_MNTR_ATK3_1, 0, 0}, // S_MNTR_ATK3_4 {SPR_MNTR, 5, 2, A_MinotaurCharge, S_MNTR_ATK4_1, 0, 0}, // S_MNTR_ATK4_1 {SPR_MNTR, 4, 3, NULL, S_MNTR_PAIN2, 0, 0}, // S_MNTR_PAIN1 {SPR_MNTR, 4, 6, A_Pain, S_MNTR_WALK1, 0, 0}, // S_MNTR_PAIN2 {SPR_MNTR, 4, 6, NULL, S_MNTR_DIE2, 0, 0}, // S_MNTR_DIE1 {SPR_MNTR, 4, 2, A_Scream, S_MNTR_DIE3, 0, 0}, // S_MNTR_DIE2 {SPR_MNTR, 4, 5, A_SmokePuffExit, S_MNTR_DIE4, 0, 0}, // S_MNTR_DIE3 {SPR_MNTR, 4, 5, NULL, S_MNTR_DIE5, 0, 0}, // S_MNTR_DIE4 {SPR_MNTR, 4, 5, A_NoBlocking, S_MNTR_DIE6, 0, 0}, // S_MNTR_DIE5 {SPR_MNTR, 4, 5, NULL, S_MNTR_DIE7, 0, 0}, // S_MNTR_DIE6 {SPR_MNTR, 4, 5, A_MinotaurFade1, S_MNTR_DIE8, 0, 0}, // S_MNTR_DIE7 {SPR_MNTR, 4, 5, A_MinotaurFade0, S_MNTR_DIE9, 0, 0}, // S_MNTR_DIE8 {SPR_MNTR, 4, 10, NULL, S_NULL, 0, 0}, // S_MNTR_DIE9 {SPR_FX12, 32768, 6, NULL, S_MNTRFX1_2, 0, 0}, // S_MNTRFX1_1 {SPR_FX12, 32769, 6, NULL, S_MNTRFX1_1, 0, 0}, // S_MNTRFX1_2 {SPR_FX12, 32770, 5, NULL, S_MNTRFXI1_2, 0, 0}, // S_MNTRFXI1_1 {SPR_FX12, 32771, 5, NULL, S_MNTRFXI1_3, 0, 0}, // S_MNTRFXI1_2 {SPR_FX12, 32772, 5, NULL, S_MNTRFXI1_4, 0, 0}, // S_MNTRFXI1_3 {SPR_FX12, 32773, 5, NULL, S_MNTRFXI1_5, 0, 0}, // S_MNTRFXI1_4 {SPR_FX12, 32774, 5, NULL, S_MNTRFXI1_6, 0, 0}, // S_MNTRFXI1_5 {SPR_FX12, 32775, 5, NULL, S_NULL, 0, 0}, // S_MNTRFXI1_6 {SPR_FX13, 0, 2, A_MntrFloorFire, S_MNTRFX2_1, 0, 0}, // S_MNTRFX2_1 {SPR_FX13, 32776, 4, A_Explode, S_MNTRFXI2_2, 0, 0}, // S_MNTRFXI2_1 {SPR_FX13, 32777, 4, NULL, S_MNTRFXI2_3, 0, 0}, // S_MNTRFXI2_2 {SPR_FX13, 32778, 4, NULL, S_MNTRFXI2_4, 0, 0}, // S_MNTRFXI2_3 {SPR_FX13, 32779, 4, NULL, S_MNTRFXI2_5, 0, 0}, // S_MNTRFXI2_4 {SPR_FX13, 32780, 4, NULL, S_NULL, 0, 0}, // S_MNTRFXI2_5 {SPR_FX13, 32771, 4, NULL, S_MNTRFX3_2, 0, 0}, // S_MNTRFX3_1 {SPR_FX13, 32770, 4, NULL, S_MNTRFX3_3, 0, 0}, // S_MNTRFX3_2 {SPR_FX13, 32769, 5, NULL, S_MNTRFX3_4, 0, 0}, // S_MNTRFX3_3 {SPR_FX13, 32770, 5, NULL, S_MNTRFX3_5, 0, 0}, // S_MNTRFX3_4 {SPR_FX13, 32771, 5, NULL, S_MNTRFX3_6, 0, 0}, // S_MNTRFX3_5 {SPR_FX13, 32772, 5, NULL, S_MNTRFX3_7, 0, 0}, // S_MNTRFX3_6 {SPR_FX13, 32773, 4, NULL, S_MNTRFX3_8, 0, 0}, // S_MNTRFX3_7 {SPR_FX13, 32774, 4, NULL, S_MNTRFX3_9, 0, 0}, // S_MNTRFX3_8 {SPR_FX13, 32775, 4, NULL, S_NULL, 0, 0}, // S_MNTRFX3_9 {SPR_MNSM, 0, 3, NULL, S_MINOSMOKE2, 0, 0}, // S_MINOSMOKE1 {SPR_MNSM, 1, 3, NULL, S_MINOSMOKE3, 0, 0}, // S_MINOSMOKE2 {SPR_MNSM, 2, 3, NULL, S_MINOSMOKE4, 0, 0}, // S_MINOSMOKE3 {SPR_MNSM, 3, 3, NULL, S_MINOSMOKE5, 0, 0}, // S_MINOSMOKE4 {SPR_MNSM, 4, 3, NULL, S_MINOSMOKE6, 0, 0}, // S_MINOSMOKE5 {SPR_MNSM, 5, 3, NULL, S_MINOSMOKE7, 0, 0}, // S_MINOSMOKE6 {SPR_MNSM, 6, 3, NULL, S_MINOSMOKE8, 0, 0}, // S_MINOSMOKE7 {SPR_MNSM, 7, 3, NULL, S_MINOSMOKE9, 0, 0}, // S_MINOSMOKE8 {SPR_MNSM, 8, 3, NULL, S_MINOSMOKE0, 0, 0}, // S_MINOSMOKE9 {SPR_MNSM, 9, 3, NULL, S_MINOSMOKEA, 0, 0}, // S_MINOSMOKE0 {SPR_MNSM, 10, 3, NULL, S_MINOSMOKEB, 0, 0}, // S_MINOSMOKEA {SPR_MNSM, 11, 3, NULL, S_MINOSMOKEC, 0, 0}, // S_MINOSMOKEB {SPR_MNSM, 12, 3, NULL, S_MINOSMOKED, 0, 0}, // S_MINOSMOKEC {SPR_MNSM, 13, 3, NULL, S_MINOSMOKEE, 0, 0}, // S_MINOSMOKED {SPR_MNSM, 14, 3, NULL, S_MINOSMOKEF, 0, 0}, // S_MINOSMOKEE {SPR_MNSM, 15, 3, NULL, S_MINOSMOKEG, 0, 0}, // S_MINOSMOKEF {SPR_MNSM, 16, 3, NULL, S_NULL, 0, 0}, // S_MINOSMOKEG {SPR_MNSM, 0, 3, NULL, S_MINOSMOKEX2, 0, 0}, // S_MINOSMOKEX1 {SPR_MNSM, 1, 3, NULL, S_MINOSMOKEX3, 0, 0}, // S_MINOSMOKEX2 {SPR_MNSM, 2, 3, NULL, S_MINOSMOKEX4, 0, 0}, // S_MINOSMOKEX3 {SPR_MNSM, 3, 3, NULL, S_MINOSMOKEX5, 0, 0}, // S_MINOSMOKEX4 {SPR_MNSM, 4, 3, NULL, S_MINOSMOKEX6, 0, 0}, // S_MINOSMOKEX5 {SPR_MNSM, 5, 3, NULL, S_MINOSMOKEX7, 0, 0}, // S_MINOSMOKEX6 {SPR_MNSM, 6, 3, NULL, S_MINOSMOKEX8, 0, 0}, // S_MINOSMOKEX7 {SPR_MNSM, 7, 3, NULL, S_MINOSMOKEX9, 0, 0}, // S_MINOSMOKEX8 {SPR_MNSM, 8, 3, NULL, S_MINOSMOKEX0, 0, 0}, // S_MINOSMOKEX9 {SPR_MNSM, 9, 3, NULL, S_MINOSMOKEXA, 0, 0}, // S_MINOSMOKEX0 {SPR_MNSM, 8, 3, NULL, S_MINOSMOKEXB, 0, 0}, // S_MINOSMOKEXA {SPR_MNSM, 7, 3, NULL, S_MINOSMOKEXC, 0, 0}, // S_MINOSMOKEXB {SPR_MNSM, 6, 3, NULL, S_MINOSMOKEXD, 0, 0}, // S_MINOSMOKEXC {SPR_MNSM, 5, 3, NULL, S_MINOSMOKEXE, 0, 0}, // S_MINOSMOKEXD {SPR_MNSM, 4, 3, NULL, S_MINOSMOKEXF, 0, 0}, // S_MINOSMOKEXE {SPR_MNSM, 3, 3, NULL, S_MINOSMOKEXG, 0, 0}, // S_MINOSMOKEXF {SPR_MNSM, 2, 3, NULL, S_MINOSMOKEXH, 0, 0}, // S_MINOSMOKEXG {SPR_MNSM, 1, 3, NULL, S_MINOSMOKEXI, 0, 0}, // S_MINOSMOKEXH {SPR_MNSM, 0, 3, NULL, S_NULL, 0, 0}, // S_MINOSMOKEXI {SPR_SSPT, 7, 10, A_Look, S_SERPENT_LOOK1, 0, 0}, // S_SERPENT_LOOK1 {SPR_SSPT, 7, 1, A_SerpentChase, S_SERPENT_SWIM2, 0, 0}, // S_SERPENT_SWIM1 {SPR_SSPT, 7, 1, A_SerpentChase, S_SERPENT_SWIM3, 0, 0}, // S_SERPENT_SWIM2 {SPR_SSPT, 7, 2, A_SerpentHumpDecide, S_SERPENT_SWIM1, 0, 0}, // S_SERPENT_SWIM3 {SPR_SSPT, 7, 3, A_SerpentUnHide, S_SERPENT_HUMP2, 0, 0}, // S_SERPENT_HUMP1 {SPR_SSPT, 4, 3, A_SerpentRaiseHump, S_SERPENT_HUMP3, 0, 0}, // S_SERPENT_HUMP2 {SPR_SSPT, 5, 3, A_SerpentRaiseHump, S_SERPENT_HUMP4, 0, 0}, // S_SERPENT_HUMP3 {SPR_SSPT, 6, 3, A_SerpentRaiseHump, S_SERPENT_HUMP5, 0, 0}, // S_SERPENT_HUMP4 {SPR_SSPT, 4, 3, A_SerpentRaiseHump, S_SERPENT_HUMP6, 0, 0}, // S_SERPENT_HUMP5 {SPR_SSPT, 5, 3, A_SerpentRaiseHump, S_SERPENT_HUMP7, 0, 0}, // S_SERPENT_HUMP6 {SPR_SSPT, 6, 3, NULL, S_SERPENT_HUMP8, 0, 0}, // S_SERPENT_HUMP7 {SPR_SSPT, 4, 3, NULL, S_SERPENT_HUMP9, 0, 0}, // S_SERPENT_HUMP8 {SPR_SSPT, 5, 3, NULL, S_SERPENT_HUMP10, 0, 0}, // S_SERPENT_HUMP9 {SPR_SSPT, 6, 3, A_SerpentLowerHump, S_SERPENT_HUMP11, 0, 0}, // S_SERPENT_HUMP10 {SPR_SSPT, 4, 3, A_SerpentLowerHump, S_SERPENT_HUMP12, 0, 0}, // S_SERPENT_HUMP11 {SPR_SSPT, 5, 3, A_SerpentLowerHump, S_SERPENT_HUMP13, 0, 0}, // S_SERPENT_HUMP12 {SPR_SSPT, 6, 3, A_SerpentLowerHump, S_SERPENT_HUMP14, 0, 0}, // S_SERPENT_HUMP13 {SPR_SSPT, 4, 3, A_SerpentLowerHump, S_SERPENT_HUMP15, 0, 0}, // S_SERPENT_HUMP14 {SPR_SSPT, 5, 3, A_SerpentHide, S_SERPENT_SWIM1, 0, 0}, // S_SERPENT_HUMP15 {SPR_SSPT, 0, 1, A_UnHideThing, S_SERPENT_SURFACE2, 0, 0}, // S_SERPENT_SURFACE1 {SPR_SSPT, 0, 1, A_SerpentBirthScream, S_SERPENT_SURFACE3, 0, 0}, // S_SERPENT_SURFACE2 {SPR_SSPT, 1, 3, A_SetShootable, S_SERPENT_SURFACE4, 0, 0}, // S_SERPENT_SURFACE3 {SPR_SSPT, 2, 3, NULL, S_SERPENT_SURFACE5, 0, 0}, // S_SERPENT_SURFACE4 {SPR_SSPT, 3, 4, A_SerpentCheckForAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_SURFACE5 {SPR_SSDV, 0, 4, NULL, S_SERPENT_DIVE2, 0, 0}, // S_SERPENT_DIVE1 {SPR_SSDV, 1, 4, NULL, S_SERPENT_DIVE3, 0, 0}, // S_SERPENT_DIVE2 {SPR_SSDV, 2, 4, NULL, S_SERPENT_DIVE4, 0, 0}, // S_SERPENT_DIVE3 {SPR_SSDV, 3, 4, A_UnSetShootable, S_SERPENT_DIVE5, 0, 0}, // S_SERPENT_DIVE4 {SPR_SSDV, 4, 3, A_SerpentDiveSound, S_SERPENT_DIVE6, 0, 0}, // S_SERPENT_DIVE5 {SPR_SSDV, 5, 3, NULL, S_SERPENT_DIVE7, 0, 0}, // S_SERPENT_DIVE6 {SPR_SSDV, 6, 4, NULL, S_SERPENT_DIVE8, 0, 0}, // S_SERPENT_DIVE7 {SPR_SSDV, 7, 4, NULL, S_SERPENT_DIVE9, 0, 0}, // S_SERPENT_DIVE8 {SPR_SSDV, 8, 3, NULL, S_SERPENT_DIVE10, 0, 0}, // S_SERPENT_DIVE9 {SPR_SSDV, 9, 3, A_SerpentHide, S_SERPENT_SWIM1, 0, 0}, // S_SERPENT_DIVE10 {SPR_SSPT, 8, 5, A_SerpentWalk, S_SERPENT_WALK2, 0, 0}, // S_SERPENT_WALK1 {SPR_SSPT, 9, 5, A_SerpentWalk, S_SERPENT_WALK3, 0, 0}, // S_SERPENT_WALK2 {SPR_SSPT, 8, 5, A_SerpentWalk, S_SERPENT_WALK4, 0, 0}, // S_SERPENT_WALK3 {SPR_SSPT, 9, 5, A_SerpentCheckForAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_WALK4 {SPR_SSPT, 11, 5, NULL, S_SERPENT_PAIN2, 0, 0}, // S_SERPENT_PAIN1 {SPR_SSPT, 11, 5, A_Pain, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_PAIN2 {SPR_SSPT, 10, 6, A_FaceTarget, S_SERPENT_ATK2, 0, 0}, // S_SERPENT_ATK1 {SPR_SSPT, 11, 5, A_SerpentChooseAttack, S_SERPENT_MELEE1, 0, 0}, // S_SERPENT_ATK2 {SPR_SSPT, 13, 5, A_SerpentMeleeAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_MELEE1 {SPR_SSPT, 13, 5, A_SerpentMissileAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_MISSILE1 {SPR_SSPT, 14, 4, NULL, S_SERPENT_DIE2, 0, 0}, // S_SERPENT_DIE1 {SPR_SSPT, 15, 4, A_Scream, S_SERPENT_DIE3, 0, 0}, // S_SERPENT_DIE2 {SPR_SSPT, 16, 4, A_NoBlocking, S_SERPENT_DIE4, 0, 0}, // S_SERPENT_DIE3 {SPR_SSPT, 17, 4, NULL, S_SERPENT_DIE5, 0, 0}, // S_SERPENT_DIE4 {SPR_SSPT, 18, 4, NULL, S_SERPENT_DIE6, 0, 0}, // S_SERPENT_DIE5 {SPR_SSPT, 19, 4, NULL, S_SERPENT_DIE7, 0, 0}, // S_SERPENT_DIE6 {SPR_SSPT, 20, 4, NULL, S_SERPENT_DIE8, 0, 0}, // S_SERPENT_DIE7 {SPR_SSPT, 21, 4, NULL, S_SERPENT_DIE9, 0, 0}, // S_SERPENT_DIE8 {SPR_SSPT, 22, 4, NULL, S_SERPENT_DIE10, 0, 0}, // S_SERPENT_DIE9 {SPR_SSPT, 23, 4, NULL, S_SERPENT_DIE11, 0, 0}, // S_SERPENT_DIE10 {SPR_SSPT, 24, 4, NULL, S_SERPENT_DIE12, 0, 0}, // S_SERPENT_DIE11 {SPR_SSPT, 25, 4, NULL, S_NULL, 0, 0}, // S_SERPENT_DIE12 {SPR_SSXD, 0, 4, NULL, S_SERPENT_XDIE2, 0, 0}, // S_SERPENT_XDIE1 {SPR_SSXD, 1, 4, A_SerpentHeadPop, S_SERPENT_XDIE3, 0, 0}, // S_SERPENT_XDIE2 {SPR_SSXD, 2, 4, A_NoBlocking, S_SERPENT_XDIE4, 0, 0}, // S_SERPENT_XDIE3 {SPR_SSXD, 3, 4, NULL, S_SERPENT_XDIE5, 0, 0}, // S_SERPENT_XDIE4 {SPR_SSXD, 4, 4, NULL, S_SERPENT_XDIE6, 0, 0}, // S_SERPENT_XDIE5 {SPR_SSXD, 5, 3, NULL, S_SERPENT_XDIE7, 0, 0}, // S_SERPENT_XDIE6 {SPR_SSXD, 6, 3, NULL, S_SERPENT_XDIE8, 0, 0}, // S_SERPENT_XDIE7 {SPR_SSXD, 7, 3, A_SerpentSpawnGibs, S_NULL, 0, 0}, // S_SERPENT_XDIE8 {SPR_SSPT, 26, 5, A_FreezeDeath, S_SERPENT_ICE2, 0, 0}, // S_SERPENT_ICE {SPR_SSPT, 26, 1, A_FreezeDeathChunks, S_SERPENT_ICE2, 0, 0}, // S_SERPENT_ICE2 {SPR_SSFX, 32768, 3, A_ContMobjSound, S_SERPENT_FX2, 0, 0}, // S_SERPENT_FX1 {SPR_SSFX, 32769, 3, NULL, S_SERPENT_FX3, 0, 0}, // S_SERPENT_FX2 {SPR_SSFX, 32768, 3, NULL, S_SERPENT_FX4, 0, 0}, // S_SERPENT_FX3 {SPR_SSFX, 32769, 3, NULL, S_SERPENT_FX1, 0, 0}, // S_SERPENT_FX4 {SPR_SSFX, 32770, 4, NULL, S_SERPENT_FX_X2, 0, 0}, // S_SERPENT_FX_X1 {SPR_SSFX, 32771, 4, NULL, S_SERPENT_FX_X3, 0, 0}, // S_SERPENT_FX_X2 {SPR_SSFX, 32772, 4, NULL, S_SERPENT_FX_X4, 0, 0}, // S_SERPENT_FX_X3 {SPR_SSFX, 32773, 4, NULL, S_SERPENT_FX_X5, 0, 0}, // S_SERPENT_FX_X4 {SPR_SSFX, 32774, 4, NULL, S_SERPENT_FX_X6, 0, 0}, // S_SERPENT_FX_X5 {SPR_SSFX, 32775, 4, NULL, S_NULL, 0, 0}, // S_SERPENT_FX_X6 {SPR_SSXD, 8, 4, A_SerpentHeadCheck, S_SERPENT_HEAD2, 0, 0}, // S_SERPENT_HEAD1 {SPR_SSXD, 9, 4, A_SerpentHeadCheck, S_SERPENT_HEAD3, 0, 0}, // S_SERPENT_HEAD2 {SPR_SSXD, 10, 4, A_SerpentHeadCheck, S_SERPENT_HEAD4, 0, 0}, // S_SERPENT_HEAD3 {SPR_SSXD, 11, 4, A_SerpentHeadCheck, S_SERPENT_HEAD5, 0, 0}, // S_SERPENT_HEAD4 {SPR_SSXD, 12, 4, A_SerpentHeadCheck, S_SERPENT_HEAD6, 0, 0}, // S_SERPENT_HEAD5 {SPR_SSXD, 13, 4, A_SerpentHeadCheck, S_SERPENT_HEAD7, 0, 0}, // S_SERPENT_HEAD6 {SPR_SSXD, 14, 4, A_SerpentHeadCheck, S_SERPENT_HEAD8, 0, 0}, // S_SERPENT_HEAD7 {SPR_SSXD, 15, 4, A_SerpentHeadCheck, S_SERPENT_HEAD1, 0, 0}, // S_SERPENT_HEAD8 {SPR_SSXD, 18, -1, NULL, S_SERPENT_HEAD_X1, 0, 0}, // S_SERPENT_HEAD_X1 {SPR_SSXD, 16, 6, NULL, S_SERPENT_GIB1_2, 0, 0}, // S_SERPENT_GIB1_1 {SPR_SSXD, 16, 6, A_FloatGib, S_SERPENT_GIB1_3, 0, 0}, // S_SERPENT_GIB1_2 {SPR_SSXD, 16, 8, A_FloatGib, S_SERPENT_GIB1_4, 0, 0}, // S_SERPENT_GIB1_3 {SPR_SSXD, 16, 8, A_FloatGib, S_SERPENT_GIB1_5, 0, 0}, // S_SERPENT_GIB1_4 {SPR_SSXD, 16, 12, A_FloatGib, S_SERPENT_GIB1_6, 0, 0}, // S_SERPENT_GIB1_5 {SPR_SSXD, 16, 12, A_FloatGib, S_SERPENT_GIB1_7, 0, 0}, // S_SERPENT_GIB1_6 {SPR_SSXD, 16, 232, A_DelayGib, S_SERPENT_GIB1_8, 0, 0}, // S_SERPENT_GIB1_7 {SPR_SSXD, 16, 12, A_SinkGib, S_SERPENT_GIB1_9, 0, 0}, // S_SERPENT_GIB1_8 {SPR_SSXD, 16, 12, A_SinkGib, S_SERPENT_GIB1_10, 0, 0}, // S_SERPENT_GIB1_9 {SPR_SSXD, 16, 8, A_SinkGib, S_SERPENT_GIB1_11, 0, 0}, // S_SERPENT_GIB1_10 {SPR_SSXD, 16, 8, A_SinkGib, S_SERPENT_GIB1_12, 0, 0}, // S_SERPENT_GIB1_11 {SPR_SSXD, 16, 8, A_SinkGib, S_NULL, 0, 0}, // S_SERPENT_GIB1_12 {SPR_SSXD, 17, 6, NULL, S_SERPENT_GIB2_2, 0, 0}, // S_SERPENT_GIB2_1 {SPR_SSXD, 17, 6, A_FloatGib, S_SERPENT_GIB2_3, 0, 0}, // S_SERPENT_GIB2_2 {SPR_SSXD, 17, 8, A_FloatGib, S_SERPENT_GIB2_4, 0, 0}, // S_SERPENT_GIB2_3 {SPR_SSXD, 17, 8, A_FloatGib, S_SERPENT_GIB2_5, 0, 0}, // S_SERPENT_GIB2_4 {SPR_SSXD, 17, 12, A_FloatGib, S_SERPENT_GIB2_6, 0, 0}, // S_SERPENT_GIB2_5 {SPR_SSXD, 17, 12, A_FloatGib, S_SERPENT_GIB2_7, 0, 0}, // S_SERPENT_GIB2_6 {SPR_SSXD, 17, 232, A_DelayGib, S_SERPENT_GIB2_8, 0, 0}, // S_SERPENT_GIB2_7 {SPR_SSXD, 17, 12, A_SinkGib, S_SERPENT_GIB2_9, 0, 0}, // S_SERPENT_GIB2_8 {SPR_SSXD, 17, 12, A_SinkGib, S_SERPENT_GIB2_10, 0, 0}, // S_SERPENT_GIB2_9 {SPR_SSXD, 17, 8, A_SinkGib, S_SERPENT_GIB2_11, 0, 0}, // S_SERPENT_GIB2_10 {SPR_SSXD, 17, 8, A_SinkGib, S_SERPENT_GIB2_12, 0, 0}, // S_SERPENT_GIB2_11 {SPR_SSXD, 17, 8, A_SinkGib, S_NULL, 0, 0}, // S_SERPENT_GIB2_12 {SPR_SSXD, 19, 6, NULL, S_SERPENT_GIB3_2, 0, 0}, // S_SERPENT_GIB3_1 {SPR_SSXD, 19, 6, A_FloatGib, S_SERPENT_GIB3_3, 0, 0}, // S_SERPENT_GIB3_2 {SPR_SSXD, 19, 8, A_FloatGib, S_SERPENT_GIB3_4, 0, 0}, // S_SERPENT_GIB3_3 {SPR_SSXD, 19, 8, A_FloatGib, S_SERPENT_GIB3_5, 0, 0}, // S_SERPENT_GIB3_4 {SPR_SSXD, 19, 12, A_FloatGib, S_SERPENT_GIB3_6, 0, 0}, // S_SERPENT_GIB3_5 {SPR_SSXD, 19, 12, A_FloatGib, S_SERPENT_GIB3_7, 0, 0}, // S_SERPENT_GIB3_6 {SPR_SSXD, 19, 232, A_DelayGib, S_SERPENT_GIB3_8, 0, 0}, // S_SERPENT_GIB3_7 {SPR_SSXD, 19, 12, A_SinkGib, S_SERPENT_GIB3_9, 0, 0}, // S_SERPENT_GIB3_8 {SPR_SSXD, 19, 12, A_SinkGib, S_SERPENT_GIB3_10, 0, 0}, // S_SERPENT_GIB3_9 {SPR_SSXD, 19, 8, A_SinkGib, S_SERPENT_GIB3_11, 0, 0}, // S_SERPENT_GIB3_10 {SPR_SSXD, 19, 8, A_SinkGib, S_SERPENT_GIB3_12, 0, 0}, // S_SERPENT_GIB3_11 {SPR_SSXD, 19, 8, A_SinkGib, S_NULL, 0, 0}, // S_SERPENT_GIB3_12 {SPR_BISH, 0, 10, A_Look, S_BISHOP_LOOK1, 0, 0}, // S_BISHOP_LOOK1 {SPR_BISH, 0, 1, A_BishopDecide, S_BISHOP_WALK1, 0, 0}, // S_BISHOP_DECIDE {SPR_BISH, 0, 2, A_BishopDoBlur, S_BISHOP_BLUR2, 0, 0}, // S_BISHOP_BLUR1 {SPR_BISH, 0, 4, A_BishopSpawnBlur, S_BISHOP_BLUR2, 0, 0}, // S_BISHOP_BLUR2 {SPR_BISH, 0, 2, A_Chase, S_BISHOP_WALK2, 0, 0}, // S_BISHOP_WALK1 {SPR_BISH, 0, 2, A_BishopChase, S_BISHOP_WALK3, 0, 0}, // S_BISHOP_WALK2 {SPR_BISH, 0, 2, NULL, S_BISHOP_WALK4, 0, 0}, // S_BISHOP_WALK3 {SPR_BISH, 1, 2, A_BishopChase, S_BISHOP_WALK5, 0, 0}, // S_BISHOP_WALK4 {SPR_BISH, 1, 2, A_Chase, S_BISHOP_WALK6, 0, 0}, // S_BISHOP_WALK5 {SPR_BISH, 1, 2, A_BishopChase, S_BISHOP_DECIDE, 0, 0}, // S_BISHOP_WALK6 {SPR_BISH, 0, 3, A_FaceTarget, S_BISHOP_ATK2, 0, 0}, // S_BISHOP_ATK1 {SPR_BISH, 32771, 3, A_FaceTarget, S_BISHOP_ATK3, 0, 0}, // S_BISHOP_ATK2 {SPR_BISH, 32772, 3, A_FaceTarget, S_BISHOP_ATK4, 0, 0}, // S_BISHOP_ATK3 {SPR_BISH, 32773, 3, A_BishopAttack, S_BISHOP_ATK5, 0, 0}, // S_BISHOP_ATK4 {SPR_BISH, 32773, 5, A_BishopAttack2, S_BISHOP_ATK5, 0, 0}, // S_BISHOP_ATK5 {SPR_BISH, 2, 6, A_Pain, S_BISHOP_PAIN2, 0, 0}, // S_BISHOP_PAIN1 {SPR_BISH, 2, 6, A_BishopPainBlur, S_BISHOP_PAIN3, 0, 0}, // S_BISHOP_PAIN2 {SPR_BISH, 2, 6, A_BishopPainBlur, S_BISHOP_PAIN4, 0, 0}, // S_BISHOP_PAIN3 {SPR_BISH, 2, 6, A_BishopPainBlur, S_BISHOP_PAIN5, 0, 0}, // S_BISHOP_PAIN4 {SPR_BISH, 2, 0, NULL, S_BISHOP_WALK1, 0, 0}, // S_BISHOP_PAIN5 {SPR_BISH, 6, 6, NULL, S_BISHOP_DEATH2, 0, 0}, // S_BISHOP_DEATH1 {SPR_BISH, 32775, 6, A_Scream, S_BISHOP_DEATH3, 0, 0}, // S_BISHOP_DEATH2 {SPR_BISH, 32776, 5, A_NoBlocking, S_BISHOP_DEATH4, 0, 0}, // S_BISHOP_DEATH3 {SPR_BISH, 32777, 5, A_Explode, S_BISHOP_DEATH5, 0, 0}, // S_BISHOP_DEATH4 {SPR_BISH, 32778, 5, NULL, S_BISHOP_DEATH6, 0, 0}, // S_BISHOP_DEATH5 {SPR_BISH, 32779, 4, NULL, S_BISHOP_DEATH7, 0, 0}, // S_BISHOP_DEATH6 {SPR_BISH, 32780, 4, NULL, S_BISHOP_DEATH8, 0, 0}, // S_BISHOP_DEATH7 {SPR_BISH, 13, 4, A_BishopPuff, S_BISHOP_DEATH9, 0, 0}, // S_BISHOP_DEATH8 {SPR_BISH, 14, 4, A_QueueCorpse, S_BISHOP_DEATH10, 0, 0}, // S_BISHOP_DEATH9 {SPR_BISH, 15, -1, NULL, S_NULL, 0, 0}, // S_BISHOP_DEATH10 {SPR_BISH, 23, 5, A_FreezeDeath, S_BISHOP_ICE2, 0, 0}, // S_BISHOP_ICE {SPR_BISH, 23, 1, A_FreezeDeathChunks, S_BISHOP_ICE2, 0, 0}, // S_BISHOP_ICE2 {SPR_BISH, 16, 5, NULL, S_BISHOP_PUFF2, 0, 0}, // S_BISHOP_PUFF1 {SPR_BISH, 17, 5, NULL, S_BISHOP_PUFF3, 0, 0}, // S_BISHOP_PUFF2 {SPR_BISH, 18, 5, NULL, S_BISHOP_PUFF4, 0, 0}, // S_BISHOP_PUFF3 {SPR_BISH, 19, 5, NULL, S_BISHOP_PUFF5, 0, 0}, // S_BISHOP_PUFF4 {SPR_BISH, 20, 6, NULL, S_BISHOP_PUFF6, 0, 0}, // S_BISHOP_PUFF5 {SPR_BISH, 21, 6, NULL, S_BISHOP_PUFF7, 0, 0}, // S_BISHOP_PUFF6 {SPR_BISH, 22, 5, NULL, S_NULL, 0, 0}, // S_BISHOP_PUFF7 {SPR_BISH, 0, 16, NULL, S_BISHOPBLUR2, 0, 0}, // S_BISHOPBLUR1 {SPR_BISH, 0, 8, A_SetAltShadow, S_NULL, 0, 0}, // S_BISHOPBLUR2 {SPR_BISH, 2, 8, NULL, S_NULL, 0, 0}, // S_BISHOPPAINBLUR1 {SPR_BPFX, 32768, 1, A_BishopMissileWeave, S_BISHFX1_2, 0, 0}, // S_BISHFX1_1 {SPR_BPFX, 32769, 1, A_BishopMissileWeave, S_BISHFX1_3, 0, 0}, // S_BISHFX1_2 {SPR_BPFX, 32768, 1, A_BishopMissileWeave, S_BISHFX1_4, 0, 0}, // S_BISHFX1_3 {SPR_BPFX, 32769, 1, A_BishopMissileWeave, S_BISHFX1_5, 0, 0}, // S_BISHFX1_4 {SPR_BPFX, 32769, 0, A_BishopMissileSeek, S_BISHFX1_1, 0, 0}, // S_BISHFX1_5 {SPR_BPFX, 32770, 4, NULL, S_BISHFXI1_2, 0, 0}, // S_BISHFXI1_1 {SPR_BPFX, 32771, 4, NULL, S_BISHFXI1_3, 0, 0}, // S_BISHFXI1_2 {SPR_BPFX, 32772, 4, NULL, S_BISHFXI1_4, 0, 0}, // S_BISHFXI1_3 {SPR_BPFX, 32773, 4, NULL, S_BISHFXI1_5, 0, 0}, // S_BISHFXI1_4 {SPR_BPFX, 32774, 3, NULL, S_BISHFXI1_6, 0, 0}, // S_BISHFXI1_5 {SPR_BPFX, 32775, 3, NULL, S_NULL, 0, 0}, // S_BISHFXI1_6 {SPR_DRAG, 3, 10, A_Look, S_DRAGON_LOOK1, 0, 0}, // S_DRAGON_LOOK1 {SPR_DRAG, 2, 5, NULL, S_DRAGON_INIT2, 0, 0}, // S_DRAGON_INIT {SPR_DRAG, 1, 5, NULL, S_DRAGON_INIT3, 0, 0}, // S_DRAGON_INIT2 {SPR_DRAG, 0, 5, A_DragonInitFlight, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_INIT3 {SPR_DRAG, 1, 3, A_DragonFlap, S_DRAGON_WALK2, 0, 0}, // S_DRAGON_WALK1 {SPR_DRAG, 1, 3, A_DragonFlight, S_DRAGON_WALK3, 0, 0}, // S_DRAGON_WALK2 {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK4, 0, 0}, // S_DRAGON_WALK3 {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK5, 0, 0}, // S_DRAGON_WALK4 {SPR_DRAG, 3, 3, A_DragonFlight, S_DRAGON_WALK6, 0, 0}, // S_DRAGON_WALK5 {SPR_DRAG, 3, 3, A_DragonFlight, S_DRAGON_WALK7, 0, 0}, // S_DRAGON_WALK6 {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK8, 0, 0}, // S_DRAGON_WALK7 {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK9, 0, 0}, // S_DRAGON_WALK8 {SPR_DRAG, 1, 3, A_DragonFlight, S_DRAGON_WALK10, 0, 0}, // S_DRAGON_WALK9 {SPR_DRAG, 1, 3, A_DragonFlight, S_DRAGON_WALK11, 0, 0}, // S_DRAGON_WALK10 {SPR_DRAG, 0, 3, A_DragonFlight, S_DRAGON_WALK12, 0, 0}, // S_DRAGON_WALK11 {SPR_DRAG, 0, 3, A_DragonFlight, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_WALK12 {SPR_DRAG, 4, 8, A_DragonAttack, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_ATK1 {SPR_DRAG, 5, 10, A_DragonPain, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_PAIN1 {SPR_DRAG, 6, 5, A_Scream, S_DRAGON_DEATH2, 0, 0}, // S_DRAGON_DEATH1 {SPR_DRAG, 7, 4, A_NoBlocking, S_DRAGON_DEATH3, 0, 0}, // S_DRAGON_DEATH2 {SPR_DRAG, 8, 4, NULL, S_DRAGON_DEATH4, 0, 0}, // S_DRAGON_DEATH3 {SPR_DRAG, 9, 4, A_DragonCheckCrash, S_DRAGON_DEATH4, 0, 0}, // S_DRAGON_DEATH4 {SPR_DRAG, 10, 5, NULL, S_DRAGON_CRASH2, 0, 0}, // S_DRAGON_CRASH1 {SPR_DRAG, 11, 5, NULL, S_DRAGON_CRASH3, 0, 0}, // S_DRAGON_CRASH2 {SPR_DRAG, 12, -1, NULL, S_NULL, 0, 0}, // S_DRAGON_CRASH3 {SPR_DRFX, 32768, 4, NULL, S_DRAGON_FX1_2, 0, 0}, // S_DRAGON_FX1_1 {SPR_DRFX, 32769, 4, NULL, S_DRAGON_FX1_3, 0, 0}, // S_DRAGON_FX1_2 {SPR_DRFX, 32770, 4, NULL, S_DRAGON_FX1_4, 0, 0}, // S_DRAGON_FX1_3 {SPR_DRFX, 32771, 4, NULL, S_DRAGON_FX1_5, 0, 0}, // S_DRAGON_FX1_4 {SPR_DRFX, 32772, 4, NULL, S_DRAGON_FX1_6, 0, 0}, // S_DRAGON_FX1_5 {SPR_DRFX, 32773, 4, NULL, S_DRAGON_FX1_1, 0, 0}, // S_DRAGON_FX1_6 {SPR_DRFX, 32774, 4, NULL, S_DRAGON_FX1_X2, 0, 0}, // S_DRAGON_FX1_X1 {SPR_DRFX, 32775, 4, NULL, S_DRAGON_FX1_X3, 0, 0}, // S_DRAGON_FX1_X2 {SPR_DRFX, 32776, 4, NULL, S_DRAGON_FX1_X4, 0, 0}, // S_DRAGON_FX1_X3 {SPR_DRFX, 32777, 4, A_DragonFX2, S_DRAGON_FX1_X5, 0, 0}, // S_DRAGON_FX1_X4 {SPR_DRFX, 32778, 3, NULL, S_DRAGON_FX1_X6, 0, 0}, // S_DRAGON_FX1_X5 {SPR_DRFX, 32779, 3, NULL, S_NULL, 0, 0}, // S_DRAGON_FX1_X6 {SPR_CFCF, 32784, 1, NULL, S_DRAGON_FX2_2, 0, 0}, // S_DRAGON_FX2_1 {SPR_CFCF, 32784, 4, A_UnHideThing, S_DRAGON_FX2_3, 0, 0}, // S_DRAGON_FX2_2 {SPR_CFCF, 32785, 3, A_Scream, S_DRAGON_FX2_4, 0, 0}, // S_DRAGON_FX2_3 {SPR_CFCF, 32786, 4, NULL, S_DRAGON_FX2_5, 0, 0}, // S_DRAGON_FX2_4 {SPR_CFCF, 32787, 3, A_Explode, S_DRAGON_FX2_6, 0, 0}, // S_DRAGON_FX2_5 {SPR_CFCF, 32788, 4, NULL, S_DRAGON_FX2_7, 0, 0}, // S_DRAGON_FX2_6 {SPR_CFCF, 32789, 3, NULL, S_DRAGON_FX2_8, 0, 0}, // S_DRAGON_FX2_7 {SPR_CFCF, 32790, 4, NULL, S_DRAGON_FX2_9, 0, 0}, // S_DRAGON_FX2_8 {SPR_CFCF, 32791, 3, NULL, S_DRAGON_FX2_10, 0, 0}, // S_DRAGON_FX2_9 {SPR_CFCF, 32792, 4, NULL, S_DRAGON_FX2_11, 0, 0}, // S_DRAGON_FX2_10 {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_DRAGON_FX2_11 {SPR_ARM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_1 {SPR_ARM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_2 {SPR_ARM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_3 {SPR_ARM4, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_4 {SPR_MAN1, 32768, 4, NULL, S_MANA1_2, 0, 0}, // S_MANA1_1 {SPR_MAN1, 32769, 4, NULL, S_MANA1_3, 0, 0}, // S_MANA1_2 {SPR_MAN1, 32770, 4, NULL, S_MANA1_4, 0, 0}, // S_MANA1_3 {SPR_MAN1, 32771, 4, NULL, S_MANA1_5, 0, 0}, // S_MANA1_4 {SPR_MAN1, 32772, 4, NULL, S_MANA1_6, 0, 0}, // S_MANA1_5 {SPR_MAN1, 32773, 4, NULL, S_MANA1_7, 0, 0}, // S_MANA1_6 {SPR_MAN1, 32774, 4, NULL, S_MANA1_8, 0, 0}, // S_MANA1_7 {SPR_MAN1, 32775, 4, NULL, S_MANA1_9, 0, 0}, // S_MANA1_8 {SPR_MAN1, 32776, 4, NULL, S_MANA1_1, 0, 0}, // S_MANA1_9 {SPR_MAN2, 32768, 4, NULL, S_MANA2_2, 0, 0}, // S_MANA2_1 {SPR_MAN2, 32769, 4, NULL, S_MANA2_3, 0, 0}, // S_MANA2_2 {SPR_MAN2, 32770, 4, NULL, S_MANA2_4, 0, 0}, // S_MANA2_3 {SPR_MAN2, 32771, 4, NULL, S_MANA2_5, 0, 0}, // S_MANA2_4 {SPR_MAN2, 32772, 4, NULL, S_MANA2_6, 0, 0}, // S_MANA2_5 {SPR_MAN2, 32773, 4, NULL, S_MANA2_7, 0, 0}, // S_MANA2_6 {SPR_MAN2, 32774, 4, NULL, S_MANA2_8, 0, 0}, // S_MANA2_7 {SPR_MAN2, 32775, 4, NULL, S_MANA2_9, 0, 0}, // S_MANA2_8 {SPR_MAN2, 32776, 4, NULL, S_MANA2_10, 0, 0}, // S_MANA2_9 {SPR_MAN2, 32777, 4, NULL, S_MANA2_11, 0, 0}, // S_MANA2_10 {SPR_MAN2, 32778, 4, NULL, S_MANA2_12, 0, 0}, // S_MANA2_11 {SPR_MAN2, 32779, 4, NULL, S_MANA2_13, 0, 0}, // S_MANA2_12 {SPR_MAN2, 32780, 4, NULL, S_MANA2_14, 0, 0}, // S_MANA2_13 {SPR_MAN2, 32781, 4, NULL, S_MANA2_15, 0, 0}, // S_MANA2_14 {SPR_MAN2, 32782, 4, NULL, S_MANA2_16, 0, 0}, // S_MANA2_15 {SPR_MAN2, 32783, 4, NULL, S_MANA2_1, 0, 0}, // S_MANA2_16 {SPR_MAN3, 32768, 4, NULL, S_MANA3_2, 0, 0}, // S_MANA3_1 {SPR_MAN3, 32769, 4, NULL, S_MANA3_3, 0, 0}, // S_MANA3_2 {SPR_MAN3, 32770, 4, NULL, S_MANA3_4, 0, 0}, // S_MANA3_3 {SPR_MAN3, 32771, 4, NULL, S_MANA3_5, 0, 0}, // S_MANA3_4 {SPR_MAN3, 32772, 4, NULL, S_MANA3_6, 0, 0}, // S_MANA3_5 {SPR_MAN3, 32773, 4, NULL, S_MANA3_7, 0, 0}, // S_MANA3_6 {SPR_MAN3, 32774, 4, NULL, S_MANA3_8, 0, 0}, // S_MANA3_7 {SPR_MAN3, 32775, 4, NULL, S_MANA3_9, 0, 0}, // S_MANA3_8 {SPR_MAN3, 32776, 4, NULL, S_MANA3_10, 0, 0}, // S_MANA3_9 {SPR_MAN3, 32777, 4, NULL, S_MANA3_11, 0, 0}, // S_MANA3_10 {SPR_MAN3, 32778, 4, NULL, S_MANA3_12, 0, 0}, // S_MANA3_11 {SPR_MAN3, 32779, 4, NULL, S_MANA3_13, 0, 0}, // S_MANA3_12 {SPR_MAN3, 32780, 4, NULL, S_MANA3_14, 0, 0}, // S_MANA3_13 {SPR_MAN3, 32781, 4, NULL, S_MANA3_15, 0, 0}, // S_MANA3_14 {SPR_MAN3, 32782, 4, NULL, S_MANA3_16, 0, 0}, // S_MANA3_15 {SPR_MAN3, 32783, 4, NULL, S_MANA3_1, 0, 0}, // S_MANA3_16 {SPR_KEY1, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY1 {SPR_KEY2, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY2 {SPR_KEY3, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY3 {SPR_KEY4, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY4 {SPR_KEY5, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY5 {SPR_KEY6, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY6 {SPR_KEY7, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY7 {SPR_KEY8, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY8 {SPR_KEY9, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY9 {SPR_KEYA, 0, -1, NULL, S_NULL, 0, 0}, // S_KEYA {SPR_KEYB, 0, -1, NULL, S_NULL, 0, 0}, // S_KEYB {SPR_TLGL, 0, 1, NULL, S_SND_WIND2, 0, 0}, // S_SND_WIND1 {SPR_TLGL, 0, 200, A_ESound, S_SND_WIND2, 0, 0}, // S_SND_WIND2 {SPR_TLGL, 0, 85, A_ESound, S_SND_WATERFALL, 0, 0}, // S_SND_WATERFALL {SPR_ETTN, 0, 10, A_Look, S_ETTIN_LOOK2, 0, 0}, // S_ETTIN_LOOK1 {SPR_ETTN, 0, 10, A_Look, S_ETTIN_LOOK1, 0, 0}, // S_ETTIN_LOOK2 {SPR_ETTN, 0, 5, A_Chase, S_ETTIN_CHASE2, 0, 0}, // S_ETTIN_CHASE1 {SPR_ETTN, 1, 5, A_Chase, S_ETTIN_CHASE3, 0, 0}, // S_ETTIN_CHASE2 {SPR_ETTN, 2, 5, A_Chase, S_ETTIN_CHASE4, 0, 0}, // S_ETTIN_CHASE3 {SPR_ETTN, 3, 5, A_Chase, S_ETTIN_CHASE1, 0, 0}, // S_ETTIN_CHASE4 {SPR_ETTN, 7, 7, A_Pain, S_ETTIN_CHASE1, 0, 0}, // S_ETTIN_PAIN1 {SPR_ETTN, 4, 6, A_FaceTarget, S_ETTIN_ATK1_2, 0, 0}, // S_ETTIN_ATK1_1 {SPR_ETTN, 5, 6, A_FaceTarget, S_ETTIN_ATK1_3, 0, 0}, // S_ETTIN_ATK1_2 {SPR_ETTN, 6, 8, A_EttinAttack, S_ETTIN_CHASE1, 0, 0}, // S_ETTIN_ATK1_3 {SPR_ETTN, 8, 4, NULL, S_ETTIN_DEATH1_2, 0, 0}, // S_ETTIN_DEATH1_1 {SPR_ETTN, 9, 4, NULL, S_ETTIN_DEATH1_3, 0, 0}, // S_ETTIN_DEATH1_2 {SPR_ETTN, 10, 4, A_Scream, S_ETTIN_DEATH1_4, 0, 0}, // S_ETTIN_DEATH1_3 {SPR_ETTN, 11, 4, A_NoBlocking, S_ETTIN_DEATH1_5, 0, 0}, // S_ETTIN_DEATH1_4 {SPR_ETTN, 12, 4, A_QueueCorpse, S_ETTIN_DEATH1_6, 0, 0}, // S_ETTIN_DEATH1_5 {SPR_ETTN, 13, 4, NULL, S_ETTIN_DEATH1_7, 0, 0}, // S_ETTIN_DEATH1_6 {SPR_ETTN, 14, 4, NULL, S_ETTIN_DEATH1_8, 0, 0}, // S_ETTIN_DEATH1_7 {SPR_ETTN, 15, 4, NULL, S_ETTIN_DEATH1_9, 0, 0}, // S_ETTIN_DEATH1_8 {SPR_ETTN, 16, -1, NULL, S_NULL, 0, 0}, // S_ETTIN_DEATH1_9 {SPR_ETTB, 0, 4, NULL, S_ETTIN_DEATH2_2, 0, 0}, // S_ETTIN_DEATH2_1 {SPR_ETTB, 1, 4, A_NoBlocking, S_ETTIN_DEATH2_3, 0, 0}, // S_ETTIN_DEATH2_2 {SPR_ETTB, 2, 4, A_DropMace, S_ETTIN_DEATH2_4, 0, 0}, // S_ETTIN_DEATH2_3 {SPR_ETTB, 3, 4, A_Scream, S_ETTIN_DEATH2_5, 0, 0}, // S_ETTIN_DEATH2_4 {SPR_ETTB, 4, 4, A_QueueCorpse, S_ETTIN_DEATH2_6, 0, 0}, // S_ETTIN_DEATH2_5 {SPR_ETTB, 5, 4, NULL, S_ETTIN_DEATH2_7, 0, 0}, // S_ETTIN_DEATH2_6 {SPR_ETTB, 6, 4, NULL, S_ETTIN_DEATH2_8, 0, 0}, // S_ETTIN_DEATH2_7 {SPR_ETTB, 7, 4, NULL, S_ETTIN_DEATH2_9, 0, 0}, // S_ETTIN_DEATH2_8 {SPR_ETTB, 8, 4, NULL, S_ETTIN_DEATH2_0, 0, 0}, // S_ETTIN_DEATH2_9 {SPR_ETTB, 9, 4, NULL, S_ETTIN_DEATH2_A, 0, 0}, // S_ETTIN_DEATH2_0 {SPR_ETTB, 10, 4, NULL, S_ETTIN_DEATH2_B, 0, 0}, // S_ETTIN_DEATH2_A {SPR_ETTB, 11, -1, NULL, S_NULL, 0, 0}, // S_ETTIN_DEATH2_B {SPR_ETTN, 17, 5, A_FreezeDeath, S_ETTIN_ICE2, 0, 0}, // S_ETTIN_ICE1 {SPR_ETTN, 17, 1, A_FreezeDeathChunks, S_ETTIN_ICE2, 0, 0}, // S_ETTIN_ICE2 {SPR_ETTB, 12, 5, A_CheckFloor, S_ETTIN_MACE2, 0, 0}, // S_ETTIN_MACE1 {SPR_ETTB, 13, 5, A_CheckFloor, S_ETTIN_MACE3, 0, 0}, // S_ETTIN_MACE2 {SPR_ETTB, 14, 5, A_CheckFloor, S_ETTIN_MACE4, 0, 0}, // S_ETTIN_MACE3 {SPR_ETTB, 15, 5, A_CheckFloor, S_ETTIN_MACE1, 0, 0}, // S_ETTIN_MACE4 {SPR_ETTB, 16, 5, NULL, S_ETTIN_MACE6, 0, 0}, // S_ETTIN_MACE5 {SPR_ETTB, 17, 5, A_QueueCorpse, S_ETTIN_MACE7, 0, 0}, // S_ETTIN_MACE6 {SPR_ETTB, 18, -1, NULL, S_NULL, 0, 0}, // S_ETTIN_MACE7 {SPR_FDMN, 32791, 5, NULL, S_FIRED_LOOK1, 0, 0}, // S_FIRED_SPAWN1 {SPR_FDMN, 32772, 10, A_Look, S_FIRED_LOOK2, 0, 0}, // S_FIRED_LOOK1 {SPR_FDMN, 32773, 10, A_Look, S_FIRED_LOOK3, 0, 0}, // S_FIRED_LOOK2 {SPR_FDMN, 32774, 10, A_Look, S_FIRED_LOOK1, 0, 0}, // S_FIRED_LOOK3 {SPR_FDMN, 32772, 8, NULL, S_FIRED_LOOK5, 0, 0}, // S_FIRED_LOOK4 {SPR_FDMN, 32773, 6, NULL, S_FIRED_LOOK6, 0, 0}, // S_FIRED_LOOK5 {SPR_FDMN, 32774, 5, NULL, S_FIRED_LOOK7, 0, 0}, // S_FIRED_LOOK6 {SPR_FDMN, 32773, 8, NULL, S_FIRED_LOOK8, 0, 0}, // S_FIRED_LOOK7 {SPR_FDMN, 32772, 6, NULL, S_FIRED_LOOK9, 0, 0}, // S_FIRED_LOOK8 {SPR_FDMN, 32773, 7, A_FiredRocks, S_FIRED_LOOK0, 0, 0}, // S_FIRED_LOOK9 {SPR_FDMN, 32775, 5, NULL, S_FIRED_LOOKA, 0, 0}, // S_FIRED_LOOK0 {SPR_FDMN, 32776, 5, NULL, S_FIRED_LOOKB, 0, 0}, // S_FIRED_LOOKA {SPR_FDMN, 32777, 5, A_UnSetInvulnerable, S_FIRED_WALK1, 0, 0}, // S_FIRED_LOOKB {SPR_FDMN, 32768, 5, A_FiredChase, S_FIRED_WALK2, 0, 0}, // S_FIRED_WALK1 {SPR_FDMN, 32769, 5, A_FiredChase, S_FIRED_WALK3, 0, 0}, // S_FIRED_WALK2 {SPR_FDMN, 32770, 5, A_FiredChase, S_FIRED_WALK1, 0, 0}, // S_FIRED_WALK3 {SPR_FDMN, 32771, 6, A_Pain, S_FIRED_WALK1, 0, 0}, // S_FIRED_PAIN1 {SPR_FDMN, 32778, 3, A_FaceTarget, S_FIRED_ATTACK2, 0, 0}, // S_FIRED_ATTACK1 {SPR_FDMN, 32778, 5, A_FiredAttack, S_FIRED_ATTACK3, 0, 0}, // S_FIRED_ATTACK2 {SPR_FDMN, 32778, 5, A_FiredAttack, S_FIRED_ATTACK4, 0, 0}, // S_FIRED_ATTACK3 {SPR_FDMN, 32778, 5, A_FiredAttack, S_FIRED_WALK1, 0, 0}, // S_FIRED_ATTACK4 {SPR_FDMN, 32771, 4, A_FaceTarget, S_FIRED_DEATH2, 0, 0}, // S_FIRED_DEATH1 {SPR_FDMN, 32779, 4, A_Scream, S_FIRED_DEATH3, 0, 0}, // S_FIRED_DEATH2 {SPR_FDMN, 32779, 4, A_NoBlocking, S_FIRED_DEATH4, 0, 0}, // S_FIRED_DEATH3 {SPR_FDMN, 32779, 200, NULL, S_NULL, 0, 0}, // S_FIRED_DEATH4 {SPR_FDMN, 12, 5, A_FaceTarget, S_FIRED_XDEATH2, 0, 0}, // S_FIRED_XDEATH1 {SPR_FDMN, 13, 5, A_NoBlocking, S_FIRED_XDEATH3, 0, 0}, // S_FIRED_XDEATH2 {SPR_FDMN, 14, 5, A_FiredSplotch, S_NULL, 0, 0}, // S_FIRED_XDEATH3 {SPR_FDMN, 17, 5, A_FreezeDeath, S_FIRED_ICE2, 0, 0}, // S_FIRED_ICE1 {SPR_FDMN, 17, 1, A_FreezeDeathChunks, S_FIRED_ICE2, 0, 0}, // S_FIRED_ICE2 {SPR_FDMN, 15, 3, NULL, S_FIRED_CORPSE2, 0, 0}, // S_FIRED_CORPSE1 {SPR_FDMN, 15, 6, A_QueueCorpse, S_FIRED_CORPSE3, 0, 0}, // S_FIRED_CORPSE2 {SPR_FDMN, 24, -1, NULL, S_NULL, 0, 0}, // S_FIRED_CORPSE3 {SPR_FDMN, 16, 3, NULL, S_FIRED_CORPSE5, 0, 0}, // S_FIRED_CORPSE4 {SPR_FDMN, 16, 6, A_QueueCorpse, S_FIRED_CORPSE6, 0, 0}, // S_FIRED_CORPSE5 {SPR_FDMN, 25, -1, NULL, S_NULL, 0, 0}, // S_FIRED_CORPSE6 {SPR_FDMN, 18, 4, NULL, S_FIRED_RDROP1, 0, 0}, // S_FIRED_RDROP1 {SPR_FDMN, 18, 5, A_SmBounce, S_FIRED_RDEAD1_2, 0, 0}, // S_FIRED_RDEAD1_1 {SPR_FDMN, 18, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD1_2 {SPR_FDMN, 19, 4, NULL, S_FIRED_RDROP2, 0, 0}, // S_FIRED_RDROP2 {SPR_FDMN, 19, 5, A_SmBounce, S_FIRED_RDEAD2_2, 0, 0}, // S_FIRED_RDEAD2_1 {SPR_FDMN, 19, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD2_2 {SPR_FDMN, 20, 4, NULL, S_FIRED_RDROP3, 0, 0}, // S_FIRED_RDROP3 {SPR_FDMN, 20, 5, A_SmBounce, S_FIRED_RDEAD3_2, 0, 0}, // S_FIRED_RDEAD3_1 {SPR_FDMN, 20, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD3_2 {SPR_FDMN, 21, 4, NULL, S_FIRED_RDROP4, 0, 0}, // S_FIRED_RDROP4 {SPR_FDMN, 21, 5, A_SmBounce, S_FIRED_RDEAD4_2, 0, 0}, // S_FIRED_RDEAD4_1 {SPR_FDMN, 21, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD4_2 {SPR_FDMN, 22, 4, NULL, S_FIRED_RDROP5, 0, 0}, // S_FIRED_RDROP5 {SPR_FDMN, 22, 5, A_SmBounce, S_FIRED_RDEAD5_2, 0, 0}, // S_FIRED_RDEAD5_1 {SPR_FDMN, 22, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD5_2 {SPR_FDMB, 32768, 5, NULL, S_FIRED_FX6_1, 0, 0}, // S_FIRED_FX6_1 {SPR_FDMB, 32769, 5, NULL, S_FIRED_FX6_3, 0, 0}, // S_FIRED_FX6_2 {SPR_FDMB, 32770, 5, NULL, S_FIRED_FX6_4, 0, 0}, // S_FIRED_FX6_3 {SPR_FDMB, 32771, 5, NULL, S_FIRED_FX6_5, 0, 0}, // S_FIRED_FX6_4 {SPR_FDMB, 32772, 5, NULL, S_NULL, 0, 0}, // S_FIRED_FX6_5 {SPR_ICEY, 0, 10, A_IceGuyLook, S_ICEGUY_LOOK, 0, 0}, // S_ICEGUY_LOOK {SPR_ICEY, 0, -1, NULL, S_ICEGUY_LOOK, 0, 0}, // S_ICEGUY_DORMANT {SPR_ICEY, 0, 4, A_Chase, S_ICEGUY_WALK2, 0, 0}, // S_ICEGUY_WALK1 {SPR_ICEY, 1, 4, A_IceGuyChase, S_ICEGUY_WALK3, 0, 0}, // S_ICEGUY_WALK2 {SPR_ICEY, 2, 4, A_Chase, S_ICEGUY_WALK4, 0, 0}, // S_ICEGUY_WALK3 {SPR_ICEY, 3, 4, A_Chase, S_ICEGUY_WALK1, 0, 0}, // S_ICEGUY_WALK4 {SPR_ICEY, 4, 3, A_FaceTarget, S_ICEGUY_ATK2, 0, 0}, // S_ICEGUY_ATK1 {SPR_ICEY, 5, 3, A_FaceTarget, S_ICEGUY_ATK3, 0, 0}, // S_ICEGUY_ATK2 {SPR_ICEY, 32774, 8, A_IceGuyAttack, S_ICEGUY_ATK4, 0, 0}, // S_ICEGUY_ATK3 {SPR_ICEY, 5, 4, A_FaceTarget, S_ICEGUY_WALK1, 0, 0}, // S_ICEGUY_ATK4 {SPR_ICEY, 0, 1, A_Pain, S_ICEGUY_WALK1, 0, 0}, // S_ICEGUY_PAIN1 {SPR_ICEY, 0, 1, A_IceGuyDie, S_NULL, 0, 0}, // S_ICEGUY_DEATH {SPR_ICPR, 32768, 3, A_IceGuyMissilePuff, S_ICEGUY_FX2, 0, 0}, // S_ICEGUY_FX1 {SPR_ICPR, 32769, 3, A_IceGuyMissilePuff, S_ICEGUY_FX3, 0, 0}, // S_ICEGUY_FX2 {SPR_ICPR, 32770, 3, A_IceGuyMissilePuff, S_ICEGUY_FX1, 0, 0}, // S_ICEGUY_FX3 {SPR_ICPR, 32771, 4, NULL, S_ICEGUY_FX_X2, 0, 0}, // S_ICEGUY_FX_X1 {SPR_ICPR, 32772, 4, A_IceGuyMissileExplode, S_ICEGUY_FX_X3, 0, 0}, // S_ICEGUY_FX_X2 {SPR_ICPR, 32773, 4, NULL, S_ICEGUY_FX_X4, 0, 0}, // S_ICEGUY_FX_X3 {SPR_ICPR, 32774, 4, NULL, S_ICEGUY_FX_X5, 0, 0}, // S_ICEGUY_FX_X4 {SPR_ICPR, 32775, 3, NULL, S_NULL, 0, 0}, // S_ICEGUY_FX_X5 {SPR_ICPR, 8, 3, NULL, S_ICEFX_PUFF2, 0, 0}, // S_ICEFX_PUFF1 {SPR_ICPR, 9, 3, NULL, S_ICEFX_PUFF3, 0, 0}, // S_ICEFX_PUFF2 {SPR_ICPR, 10, 3, NULL, S_ICEFX_PUFF4, 0, 0}, // S_ICEFX_PUFF3 {SPR_ICPR, 11, 2, NULL, S_ICEFX_PUFF5, 0, 0}, // S_ICEFX_PUFF4 {SPR_ICPR, 12, 2, NULL, S_NULL, 0, 0}, // S_ICEFX_PUFF5 {SPR_ICPR, 32781, 3, NULL, S_ICEGUY_FX2_2, 0, 0}, // S_ICEGUY_FX2_1 {SPR_ICPR, 32782, 3, NULL, S_ICEGUY_FX2_3, 0, 0}, // S_ICEGUY_FX2_2 {SPR_ICPR, 32783, 3, NULL, S_ICEGUY_FX2_1, 0, 0}, // S_ICEGUY_FX2_3 {SPR_ICPR, 32784, 50, NULL, S_NULL, 0, 0}, // S_ICEGUY_BIT1 {SPR_ICPR, 32785, 50, NULL, S_NULL, 0, 0}, // S_ICEGUY_BIT2 {SPR_ICWS, 0, 2, NULL, S_ICEGUY_WISP1_2, 0, 0}, // S_ICEGUY_WISP1_1 {SPR_ICWS, 1, 2, NULL, S_ICEGUY_WISP1_3, 0, 0}, // S_ICEGUY_WISP1_2 {SPR_ICWS, 2, 2, NULL, S_ICEGUY_WISP1_4, 0, 0}, // S_ICEGUY_WISP1_3 {SPR_ICWS, 3, 2, NULL, S_ICEGUY_WISP1_5, 0, 0}, // S_ICEGUY_WISP1_4 {SPR_ICWS, 4, 2, NULL, S_ICEGUY_WISP1_6, 0, 0}, // S_ICEGUY_WISP1_5 {SPR_ICWS, 5, 2, NULL, S_ICEGUY_WISP1_7, 0, 0}, // S_ICEGUY_WISP1_6 {SPR_ICWS, 6, 2, NULL, S_ICEGUY_WISP1_8, 0, 0}, // S_ICEGUY_WISP1_7 {SPR_ICWS, 7, 2, NULL, S_ICEGUY_WISP1_9, 0, 0}, // S_ICEGUY_WISP1_8 {SPR_ICWS, 8, 2, NULL, S_NULL, 0, 0}, // S_ICEGUY_WISP1_9 {SPR_ICWS, 9, 2, NULL, S_ICEGUY_WISP2_2, 0, 0}, // S_ICEGUY_WISP2_1 {SPR_ICWS, 10, 2, NULL, S_ICEGUY_WISP2_3, 0, 0}, // S_ICEGUY_WISP2_2 {SPR_ICWS, 11, 2, NULL, S_ICEGUY_WISP2_4, 0, 0}, // S_ICEGUY_WISP2_3 {SPR_ICWS, 12, 2, NULL, S_ICEGUY_WISP2_5, 0, 0}, // S_ICEGUY_WISP2_4 {SPR_ICWS, 13, 2, NULL, S_ICEGUY_WISP2_6, 0, 0}, // S_ICEGUY_WISP2_5 {SPR_ICWS, 14, 2, NULL, S_ICEGUY_WISP2_7, 0, 0}, // S_ICEGUY_WISP2_6 {SPR_ICWS, 15, 2, NULL, S_ICEGUY_WISP2_8, 0, 0}, // S_ICEGUY_WISP2_7 {SPR_ICWS, 16, 2, NULL, S_ICEGUY_WISP2_9, 0, 0}, // S_ICEGUY_WISP2_8 {SPR_ICWS, 17, 2, NULL, S_NULL, 0, 0}, // S_ICEGUY_WISP2_9 {SPR_PLAY, 0, 2, NULL, S_FIGHTER2, 0, 0}, // S_FIGHTER {SPR_PLAY, 0, 3, A_ClassBossHealth, S_FIGHTERLOOK, 0, 0}, // S_FIGHTER2 {SPR_PLAY, 0, 5, A_Look, S_FIGHTERLOOK, 0, 0}, // S_FIGHTERLOOK {SPR_PLAY, 0, 4, A_FastChase, S_FIGHTER_RUN2, 0, 0}, // S_FIGHTER_RUN1 {SPR_PLAY, 1, 4, A_FastChase, S_FIGHTER_RUN3, 0, 0}, // S_FIGHTER_RUN2 {SPR_PLAY, 2, 4, A_FastChase, S_FIGHTER_RUN4, 0, 0}, // S_FIGHTER_RUN3 {SPR_PLAY, 3, 4, A_FastChase, S_FIGHTER_RUN1, 0, 0}, // S_FIGHTER_RUN4 {SPR_PLAY, 4, 8, A_FaceTarget, S_FIGHTER_ATK2, 0, 0}, // S_FIGHTER_ATK1 {SPR_PLAY, 5, 8, A_FighterAttack, S_FIGHTER_RUN1, 0, 0}, // S_FIGHTER_ATK2 {SPR_PLAY, 6, 4, NULL, S_FIGHTER_PAIN2, 0, 0}, // S_FIGHTER_PAIN {SPR_PLAY, 6, 4, A_Pain, S_FIGHTER_RUN1, 0, 0}, // S_FIGHTER_PAIN2 {SPR_PLAY, 7, 6, NULL, S_FIGHTER_DIE2, 0, 0}, // S_FIGHTER_DIE1 {SPR_PLAY, 8, 6, A_Scream, S_FIGHTER_DIE3, 0, 0}, // S_FIGHTER_DIE2 {SPR_PLAY, 9, 6, NULL, S_FIGHTER_DIE4, 0, 0}, // S_FIGHTER_DIE3 {SPR_PLAY, 10, 6, NULL, S_FIGHTER_DIE5, 0, 0}, // S_FIGHTER_DIE4 {SPR_PLAY, 11, 6, A_NoBlocking, S_FIGHTER_DIE6, 0, 0}, // S_FIGHTER_DIE5 {SPR_PLAY, 12, 6, NULL, S_FIGHTER_DIE7, 0, 0}, // S_FIGHTER_DIE6 {SPR_PLAY, 13, -1, NULL, S_NULL, 0, 0}, // S_FIGHTER_DIE7 {SPR_PLAY, 14, 5, A_Scream, S_FIGHTER_XDIE2, 0, 0}, // S_FIGHTER_XDIE1 {SPR_PLAY, 15, 5, A_SkullPop, S_FIGHTER_XDIE3, 0, 0}, // S_FIGHTER_XDIE2 {SPR_PLAY, 17, 5, A_NoBlocking, S_FIGHTER_XDIE4, 0, 0}, // S_FIGHTER_XDIE3 {SPR_PLAY, 18, 5, NULL, S_FIGHTER_XDIE5, 0, 0}, // S_FIGHTER_XDIE4 {SPR_PLAY, 19, 5, NULL, S_FIGHTER_XDIE6, 0, 0}, // S_FIGHTER_XDIE5 {SPR_PLAY, 20, 5, NULL, S_FIGHTER_XDIE7, 0, 0}, // S_FIGHTER_XDIE6 {SPR_PLAY, 21, 5, NULL, S_FIGHTER_XDIE8, 0, 0}, // S_FIGHTER_XDIE7 {SPR_PLAY, 22, -1, NULL, S_NULL, 0, 0}, // S_FIGHTER_XDIE8 {SPR_PLAY, 23, 5, A_FreezeDeath, S_FIGHTER_ICE2, 0, 0}, // S_FIGHTER_ICE {SPR_PLAY, 23, 1, A_FreezeDeathChunks, S_FIGHTER_ICE2, 0, 0}, // S_FIGHTER_ICE2 {SPR_CLER, 0, 2, NULL, S_CLERIC2, 0, 0}, // S_CLERIC {SPR_CLER, 0, 3, A_ClassBossHealth, S_CLERICLOOK, 0, 0}, // S_CLERIC2 {SPR_CLER, 0, 5, A_Look, S_CLERICLOOK, 0, 0}, // S_CLERICLOOK {SPR_CLER, 0, 4, A_FastChase, S_CLERIC_RUN2, 0, 0}, // S_CLERIC_RUN1 {SPR_CLER, 1, 4, A_FastChase, S_CLERIC_RUN3, 0, 0}, // S_CLERIC_RUN2 {SPR_CLER, 2, 4, A_FastChase, S_CLERIC_RUN4, 0, 0}, // S_CLERIC_RUN3 {SPR_CLER, 3, 4, A_FastChase, S_CLERIC_RUN1, 0, 0}, // S_CLERIC_RUN4 {SPR_CLER, 4, 8, A_FaceTarget, S_CLERIC_ATK2, 0, 0}, // S_CLERIC_ATK1 {SPR_CLER, 5, 8, A_FaceTarget, S_CLERIC_ATK3, 0, 0}, // S_CLERIC_ATK2 {SPR_CLER, 6, 10, A_ClericAttack, S_CLERIC_RUN1, 0, 0}, // S_CLERIC_ATK3 {SPR_CLER, 7, 4, NULL, S_CLERIC_PAIN2, 0, 0}, // S_CLERIC_PAIN {SPR_CLER, 7, 4, A_Pain, S_CLERIC_RUN1, 0, 0}, // S_CLERIC_PAIN2 {SPR_CLER, 8, 6, NULL, S_CLERIC_DIE2, 0, 0}, // S_CLERIC_DIE1 {SPR_CLER, 10, 6, A_Scream, S_CLERIC_DIE3, 0, 0}, // S_CLERIC_DIE2 {SPR_CLER, 11, 6, NULL, S_CLERIC_DIE4, 0, 0}, // S_CLERIC_DIE3 {SPR_CLER, 11, 6, NULL, S_CLERIC_DIE5, 0, 0}, // S_CLERIC_DIE4 {SPR_CLER, 12, 6, A_NoBlocking, S_CLERIC_DIE6, 0, 0}, // S_CLERIC_DIE5 {SPR_CLER, 13, 6, NULL, S_CLERIC_DIE7, 0, 0}, // S_CLERIC_DIE6 {SPR_CLER, 14, 6, NULL, S_CLERIC_DIE8, 0, 0}, // S_CLERIC_DIE7 {SPR_CLER, 15, 6, NULL, S_CLERIC_DIE9, 0, 0}, // S_CLERIC_DIE8 {SPR_CLER, 16, -1, NULL, S_NULL, 0, 0}, // S_CLERIC_DIE9 {SPR_CLER, 17, 5, A_Scream, S_CLERIC_XDIE2, 0, 0}, // S_CLERIC_XDIE1 {SPR_CLER, 18, 5, NULL, S_CLERIC_XDIE3, 0, 0}, // S_CLERIC_XDIE2 {SPR_CLER, 19, 5, A_NoBlocking, S_CLERIC_XDIE4, 0, 0}, // S_CLERIC_XDIE3 {SPR_CLER, 20, 5, NULL, S_CLERIC_XDIE5, 0, 0}, // S_CLERIC_XDIE4 {SPR_CLER, 21, 5, NULL, S_CLERIC_XDIE6, 0, 0}, // S_CLERIC_XDIE5 {SPR_CLER, 22, 5, NULL, S_CLERIC_XDIE7, 0, 0}, // S_CLERIC_XDIE6 {SPR_CLER, 23, 5, NULL, S_CLERIC_XDIE8, 0, 0}, // S_CLERIC_XDIE7 {SPR_CLER, 24, 5, NULL, S_CLERIC_XDIE9, 0, 0}, // S_CLERIC_XDIE8 {SPR_CLER, 25, 5, NULL, S_CLERIC_XDIE10, 0, 0}, // S_CLERIC_XDIE9 {SPR_CLER, 26, -1, NULL, S_NULL, 0, 0}, // S_CLERIC_XDIE10 {SPR_CLER, 27, 5, A_FreezeDeath, S_CLERIC_ICE2, 0, 0}, // S_CLERIC_ICE {SPR_CLER, 27, 1, A_FreezeDeathChunks, S_CLERIC_ICE2, 0, 0}, // S_CLERIC_ICE2 {SPR_MAGE, 0, 2, NULL, S_MAGE2, 0, 0}, // S_MAGE {SPR_MAGE, 0, 3, A_ClassBossHealth, S_MAGELOOK, 0, 0}, // S_MAGE2 {SPR_MAGE, 0, 5, A_Look, S_MAGELOOK, 0, 0}, // S_MAGELOOK {SPR_MAGE, 0, 4, A_FastChase, S_MAGE_RUN2, 0, 0}, // S_MAGE_RUN1 {SPR_MAGE, 1, 4, A_FastChase, S_MAGE_RUN3, 0, 0}, // S_MAGE_RUN2 {SPR_MAGE, 2, 4, A_FastChase, S_MAGE_RUN4, 0, 0}, // S_MAGE_RUN3 {SPR_MAGE, 3, 4, A_FastChase, S_MAGE_RUN1, 0, 0}, // S_MAGE_RUN4 {SPR_MAGE, 4, 8, A_FaceTarget, S_MAGE_ATK2, 0, 0}, // S_MAGE_ATK1 {SPR_MAGE, 32773, 8, A_MageAttack, S_MAGE_RUN1, 0, 0}, // S_MAGE_ATK2 {SPR_MAGE, 6, 4, NULL, S_MAGE_PAIN2, 0, 0}, // S_MAGE_PAIN {SPR_MAGE, 6, 4, A_Pain, S_MAGE_RUN1, 0, 0}, // S_MAGE_PAIN2 {SPR_MAGE, 7, 6, NULL, S_MAGE_DIE2, 0, 0}, // S_MAGE_DIE1 {SPR_MAGE, 8, 6, A_Scream, S_MAGE_DIE3, 0, 0}, // S_MAGE_DIE2 {SPR_MAGE, 9, 6, NULL, S_MAGE_DIE4, 0, 0}, // S_MAGE_DIE3 {SPR_MAGE, 10, 6, NULL, S_MAGE_DIE5, 0, 0}, // S_MAGE_DIE4 {SPR_MAGE, 11, 6, A_NoBlocking, S_MAGE_DIE6, 0, 0}, // S_MAGE_DIE5 {SPR_MAGE, 12, 6, NULL, S_MAGE_DIE7, 0, 0}, // S_MAGE_DIE6 {SPR_MAGE, 13, -1, NULL, S_NULL, 0, 0}, // S_MAGE_DIE7 {SPR_MAGE, 14, 5, A_Scream, S_MAGE_XDIE2, 0, 0}, // S_MAGE_XDIE1 {SPR_MAGE, 15, 5, NULL, S_MAGE_XDIE3, 0, 0}, // S_MAGE_XDIE2 {SPR_MAGE, 17, 5, A_NoBlocking, S_MAGE_XDIE4, 0, 0}, // S_MAGE_XDIE3 {SPR_MAGE, 18, 5, NULL, S_MAGE_XDIE5, 0, 0}, // S_MAGE_XDIE4 {SPR_MAGE, 19, 5, NULL, S_MAGE_XDIE6, 0, 0}, // S_MAGE_XDIE5 {SPR_MAGE, 20, 5, NULL, S_MAGE_XDIE7, 0, 0}, // S_MAGE_XDIE6 {SPR_MAGE, 21, 5, NULL, S_MAGE_XDIE8, 0, 0}, // S_MAGE_XDIE7 {SPR_MAGE, 22, 5, NULL, S_MAGE_XDIE9, 0, 0}, // S_MAGE_XDIE8 {SPR_MAGE, 23, -1, NULL, S_NULL, 0, 0}, // S_MAGE_XDIE9 {SPR_MAGE, 24, 5, A_FreezeDeath, S_MAGE_ICE2, 0, 0}, // S_MAGE_ICE {SPR_MAGE, 24, 1, A_FreezeDeathChunks, S_MAGE_ICE2, 0, 0}, // S_MAGE_ICE2 {SPR_SORC, 0, 3, NULL, S_SORC_SPAWN2, 0, 0}, // S_SORC_SPAWN1 {SPR_SORC, 0, 2, A_SorcSpinBalls, S_SORC_LOOK1, 0, 0}, // S_SORC_SPAWN2 {SPR_SORC, 0, 10, A_Look, S_SORC_LOOK1, 0, 0}, // S_SORC_LOOK1 {SPR_SORC, 0, 5, A_Chase, S_SORC_WALK2, 0, 0}, // S_SORC_WALK1 {SPR_SORC, 1, 5, A_Chase, S_SORC_WALK3, 0, 0}, // S_SORC_WALK2 {SPR_SORC, 2, 5, A_Chase, S_SORC_WALK4, 0, 0}, // S_SORC_WALK3 {SPR_SORC, 3, 5, A_Chase, S_SORC_WALK1, 0, 0}, // S_SORC_WALK4 {SPR_SORC, 6, 8, NULL, S_SORC_PAIN2, 0, 0}, // S_SORC_PAIN1 {SPR_SORC, 6, 8, A_Pain, S_SORC_WALK1, 0, 0}, // S_SORC_PAIN2 {SPR_SORC, 32773, 6, A_FaceTarget, S_SORC_ATK2_2, 0, 0}, // S_SORC_ATK2_1 {SPR_SORC, 32773, 6, A_SpeedBalls, S_SORC_ATK2_3, 0, 0}, // S_SORC_ATK2_2 {SPR_SORC, 32773, 6, A_FaceTarget, S_SORC_ATK2_3, 0, 0}, // S_SORC_ATK2_3 {SPR_SORC, 32772, 6, NULL, S_SORC_ATTACK2, 0, 0}, // S_SORC_ATTACK1 {SPR_SORC, 32772, 6, A_SpawnFizzle, S_SORC_ATTACK3, 0, 0}, // S_SORC_ATTACK2 {SPR_SORC, 32772, 5, A_FaceTarget, S_SORC_ATTACK2, 0, 0}, // S_SORC_ATTACK3 {SPR_SORC, 32772, 2, NULL, S_SORC_ATTACK5, 0, 0}, // S_SORC_ATTACK4 {SPR_SORC, 32772, 2, A_SorcBossAttack, S_SORC_WALK1, 0, 0}, // S_SORC_ATTACK5 {SPR_SORC, 32775, 5, NULL, S_SORC_DIE2, 0, 0}, // S_SORC_DIE1 {SPR_SORC, 32776, 5, A_FaceTarget, S_SORC_DIE3, 0, 0}, // S_SORC_DIE2 {SPR_SORC, 32777, 5, A_Scream, S_SORC_DIE4, 0, 0}, // S_SORC_DIE3 {SPR_SORC, 32778, 5, NULL, S_SORC_DIE5, 0, 0}, // S_SORC_DIE4 {SPR_SORC, 32779, 5, NULL, S_SORC_DIE6, 0, 0}, // S_SORC_DIE5 {SPR_SORC, 32780, 5, NULL, S_SORC_DIE7, 0, 0}, // S_SORC_DIE6 {SPR_SORC, 32781, 5, NULL, S_SORC_DIE8, 0, 0}, // S_SORC_DIE7 {SPR_SORC, 32782, 5, NULL, S_SORC_DIE9, 0, 0}, // S_SORC_DIE8 {SPR_SORC, 32783, 5, NULL, S_SORC_DIE0, 0, 0}, // S_SORC_DIE9 {SPR_SORC, 32784, 5, NULL, S_SORC_DIEA, 0, 0}, // S_SORC_DIE0 {SPR_SORC, 32785, 5, NULL, S_SORC_DIEB, 0, 0}, // S_SORC_DIEA {SPR_SORC, 32786, 5, NULL, S_SORC_DIEC, 0, 0}, // S_SORC_DIEB {SPR_SORC, 32787, 5, NULL, S_SORC_DIED, 0, 0}, // S_SORC_DIEC {SPR_SORC, 32788, 5, A_NoBlocking, S_SORC_DIEE, 0, 0}, // S_SORC_DIED {SPR_SORC, 32789, 5, NULL, S_SORC_DIEF, 0, 0}, // S_SORC_DIEE {SPR_SORC, 32790, 5, NULL, S_SORC_DIEG, 0, 0}, // S_SORC_DIEF {SPR_SORC, 32791, 5, NULL, S_SORC_DIEH, 0, 0}, // S_SORC_DIEG {SPR_SORC, 32792, 5, NULL, S_SORC_DIEI, 0, 0}, // S_SORC_DIEH {SPR_SORC, 32793, -1, NULL, S_NULL, 0, 0}, // S_SORC_DIEI {SPR_SBMP, 0, 2, A_SorcBallOrbit, S_SORCBALL1_2, 0, 0}, // S_SORCBALL1_1 {SPR_SBMP, 1, 2, A_SorcBallOrbit, S_SORCBALL1_3, 0, 0}, // S_SORCBALL1_2 {SPR_SBMP, 2, 2, A_SorcBallOrbit, S_SORCBALL1_4, 0, 0}, // S_SORCBALL1_3 {SPR_SBMP, 3, 2, A_SorcBallOrbit, S_SORCBALL1_5, 0, 0}, // S_SORCBALL1_4 {SPR_SBMP, 4, 2, A_SorcBallOrbit, S_SORCBALL1_6, 0, 0}, // S_SORCBALL1_5 {SPR_SBMP, 5, 2, A_SorcBallOrbit, S_SORCBALL1_7, 0, 0}, // S_SORCBALL1_6 {SPR_SBMP, 6, 2, A_SorcBallOrbit, S_SORCBALL1_8, 0, 0}, // S_SORCBALL1_7 {SPR_SBMP, 7, 2, A_SorcBallOrbit, S_SORCBALL1_9, 0, 0}, // S_SORCBALL1_8 {SPR_SBMP, 8, 2, A_SorcBallOrbit, S_SORCBALL1_0, 0, 0}, // S_SORCBALL1_9 {SPR_SBMP, 9, 2, A_SorcBallOrbit, S_SORCBALL1_A, 0, 0}, // S_SORCBALL1_0 {SPR_SBMP, 10, 2, A_SorcBallOrbit, S_SORCBALL1_B, 0, 0}, // S_SORCBALL1_A {SPR_SBMP, 11, 2, A_SorcBallOrbit, S_SORCBALL1_C, 0, 0}, // S_SORCBALL1_B {SPR_SBMP, 12, 2, A_SorcBallOrbit, S_SORCBALL1_D, 0, 0}, // S_SORCBALL1_C {SPR_SBMP, 13, 2, A_SorcBallOrbit, S_SORCBALL1_E, 0, 0}, // S_SORCBALL1_D {SPR_SBMP, 14, 2, A_SorcBallOrbit, S_SORCBALL1_F, 0, 0}, // S_SORCBALL1_E {SPR_SBMP, 15, 2, A_SorcBallOrbit, S_SORCBALL1_1, 0, 0}, // S_SORCBALL1_F {SPR_SBMP, 0, 5, A_SorcBallPop, S_SORCBALL1_D2, 0, 0}, // S_SORCBALL1_D1 {SPR_SBMP, 1, 2, A_BounceCheck, S_SORCBALL1_D2, 0, 0}, // S_SORCBALL1_D2 {SPR_SBS4, 3, 5, A_Explode, S_SORCBALL1_D6, 0, 0}, // S_SORCBALL1_D5 {SPR_SBS4, 4, 5, NULL, S_SORCBALL1_D7, 0, 0}, // S_SORCBALL1_D6 {SPR_SBS4, 5, 6, NULL, S_SORCBALL1_D8, 0, 0}, // S_SORCBALL1_D7 {SPR_SBS4, 6, 6, NULL, S_SORCBALL1_D9, 0, 0}, // S_SORCBALL1_D8 {SPR_SBS4, 7, 6, NULL, S_NULL, 0, 0}, // S_SORCBALL1_D9 {SPR_SBMB, 0, 2, A_SorcBallOrbit, S_SORCBALL2_2, 0, 0}, // S_SORCBALL2_1 {SPR_SBMB, 1, 2, A_SorcBallOrbit, S_SORCBALL2_3, 0, 0}, // S_SORCBALL2_2 {SPR_SBMB, 2, 2, A_SorcBallOrbit, S_SORCBALL2_4, 0, 0}, // S_SORCBALL2_3 {SPR_SBMB, 3, 2, A_SorcBallOrbit, S_SORCBALL2_5, 0, 0}, // S_SORCBALL2_4 {SPR_SBMB, 4, 2, A_SorcBallOrbit, S_SORCBALL2_6, 0, 0}, // S_SORCBALL2_5 {SPR_SBMB, 5, 2, A_SorcBallOrbit, S_SORCBALL2_7, 0, 0}, // S_SORCBALL2_6 {SPR_SBMB, 6, 2, A_SorcBallOrbit, S_SORCBALL2_8, 0, 0}, // S_SORCBALL2_7 {SPR_SBMB, 7, 2, A_SorcBallOrbit, S_SORCBALL2_9, 0, 0}, // S_SORCBALL2_8 {SPR_SBMB, 8, 2, A_SorcBallOrbit, S_SORCBALL2_0, 0, 0}, // S_SORCBALL2_9 {SPR_SBMB, 9, 2, A_SorcBallOrbit, S_SORCBALL2_A, 0, 0}, // S_SORCBALL2_0 {SPR_SBMB, 10, 2, A_SorcBallOrbit, S_SORCBALL2_B, 0, 0}, // S_SORCBALL2_A {SPR_SBMB, 11, 2, A_SorcBallOrbit, S_SORCBALL2_C, 0, 0}, // S_SORCBALL2_B {SPR_SBMB, 12, 2, A_SorcBallOrbit, S_SORCBALL2_D, 0, 0}, // S_SORCBALL2_C {SPR_SBMB, 13, 2, A_SorcBallOrbit, S_SORCBALL2_E, 0, 0}, // S_SORCBALL2_D {SPR_SBMB, 14, 2, A_SorcBallOrbit, S_SORCBALL2_F, 0, 0}, // S_SORCBALL2_E {SPR_SBMB, 15, 2, A_SorcBallOrbit, S_SORCBALL2_1, 0, 0}, // S_SORCBALL2_F {SPR_SBMB, 0, 5, A_SorcBallPop, S_SORCBALL2_D2, 0, 0}, // S_SORCBALL2_D1 {SPR_SBMB, 1, 2, A_BounceCheck, S_SORCBALL2_D2, 0, 0}, // S_SORCBALL2_D2 {SPR_SBS3, 3, 5, A_Explode, S_SORCBALL2_D6, 0, 0}, // S_SORCBALL2_D5 {SPR_SBS3, 4, 5, NULL, S_SORCBALL2_D7, 0, 0}, // S_SORCBALL2_D6 {SPR_SBS3, 5, 6, NULL, S_SORCBALL2_D8, 0, 0}, // S_SORCBALL2_D7 {SPR_SBS3, 6, 6, NULL, S_SORCBALL2_D9, 0, 0}, // S_SORCBALL2_D8 {SPR_SBS3, 7, 6, NULL, S_NULL, 0, 0}, // S_SORCBALL2_D9 {SPR_SBMG, 0, 2, A_SorcBallOrbit, S_SORCBALL3_2, 0, 0}, // S_SORCBALL3_1 {SPR_SBMG, 1, 2, A_SorcBallOrbit, S_SORCBALL3_3, 0, 0}, // S_SORCBALL3_2 {SPR_SBMG, 2, 2, A_SorcBallOrbit, S_SORCBALL3_4, 0, 0}, // S_SORCBALL3_3 {SPR_SBMG, 3, 2, A_SorcBallOrbit, S_SORCBALL3_5, 0, 0}, // S_SORCBALL3_4 {SPR_SBMG, 4, 2, A_SorcBallOrbit, S_SORCBALL3_6, 0, 0}, // S_SORCBALL3_5 {SPR_SBMG, 5, 2, A_SorcBallOrbit, S_SORCBALL3_7, 0, 0}, // S_SORCBALL3_6 {SPR_SBMG, 6, 2, A_SorcBallOrbit, S_SORCBALL3_8, 0, 0}, // S_SORCBALL3_7 {SPR_SBMG, 7, 2, A_SorcBallOrbit, S_SORCBALL3_9, 0, 0}, // S_SORCBALL3_8 {SPR_SBMG, 8, 2, A_SorcBallOrbit, S_SORCBALL3_0, 0, 0}, // S_SORCBALL3_9 {SPR_SBMG, 9, 2, A_SorcBallOrbit, S_SORCBALL3_A, 0, 0}, // S_SORCBALL3_0 {SPR_SBMG, 10, 2, A_SorcBallOrbit, S_SORCBALL3_B, 0, 0}, // S_SORCBALL3_A {SPR_SBMG, 11, 2, A_SorcBallOrbit, S_SORCBALL3_C, 0, 0}, // S_SORCBALL3_B {SPR_SBMG, 12, 2, A_SorcBallOrbit, S_SORCBALL3_D, 0, 0}, // S_SORCBALL3_C {SPR_SBMG, 13, 2, A_SorcBallOrbit, S_SORCBALL3_E, 0, 0}, // S_SORCBALL3_D {SPR_SBMG, 14, 2, A_SorcBallOrbit, S_SORCBALL3_F, 0, 0}, // S_SORCBALL3_E {SPR_SBMG, 15, 2, A_SorcBallOrbit, S_SORCBALL3_1, 0, 0}, // S_SORCBALL3_F {SPR_SBMG, 0, 5, A_SorcBallPop, S_SORCBALL3_D2, 0, 0}, // S_SORCBALL3_D1 {SPR_SBMG, 1, 2, A_BounceCheck, S_SORCBALL3_D2, 0, 0}, // S_SORCBALL3_D2 {SPR_SBS3, 3, 5, A_Explode, S_SORCBALL3_D6, 0, 0}, // S_SORCBALL3_D5 {SPR_SBS3, 4, 5, NULL, S_SORCBALL3_D7, 0, 0}, // S_SORCBALL3_D6 {SPR_SBS3, 5, 6, NULL, S_SORCBALL3_D8, 0, 0}, // S_SORCBALL3_D7 {SPR_SBS3, 6, 6, NULL, S_SORCBALL3_D9, 0, 0}, // S_SORCBALL3_D8 {SPR_SBS3, 7, 6, NULL, S_NULL, 0, 0}, // S_SORCBALL3_D9 {SPR_SBS1, 32768, 2, NULL, S_SORCFX1_2, 0, 0}, // S_SORCFX1_1 {SPR_SBS1, 32769, 3, A_SorcFX1Seek, S_SORCFX1_3, 0, 0}, // S_SORCFX1_2 {SPR_SBS1, 32770, 3, A_SorcFX1Seek, S_SORCFX1_4, 0, 0}, // S_SORCFX1_3 {SPR_SBS1, 32771, 3, A_SorcFX1Seek, S_SORCFX1_1, 0, 0}, // S_SORCFX1_4 {SPR_FHFX, 32786, 2, A_Explode, S_SORCFX1_D2, 0, 0}, // S_SORCFX1_D1 {SPR_FHFX, 32786, 6, NULL, S_SORCFX1_D3, 0, 0}, // S_SORCFX1_D2 {SPR_FHFX, 32786, 6, NULL, S_NULL, 0, 0}, // S_SORCFX1_D3 {SPR_SBS2, 32768, 3, A_SorcFX2Split, S_SORCFX2_SPLIT1, 0, 0}, // S_SORCFX2_SPLIT1 {SPR_SBS2, 32768, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT2, 0, 0}, // S_SORCFX2_ORBIT1 {SPR_SBS2, 32769, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT3, 0, 0}, // S_SORCFX2_ORBIT2 {SPR_SBS2, 32770, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT4, 0, 0}, // S_SORCFX2_ORBIT3 {SPR_SBS2, 32771, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT5, 0, 0}, // S_SORCFX2_ORBIT4 {SPR_SBS2, 32772, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT6, 0, 0}, // S_SORCFX2_ORBIT5 {SPR_SBS2, 32773, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT7, 0, 0}, // S_SORCFX2_ORBIT6 {SPR_SBS2, 32774, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT8, 0, 0}, // S_SORCFX2_ORBIT7 {SPR_SBS2, 32775, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT9, 0, 0}, // S_SORCFX2_ORBIT8 {SPR_SBS2, 32776, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT0, 0, 0}, // S_SORCFX2_ORBIT9 {SPR_SBS2, 32777, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITA, 0, 0}, // S_SORCFX2_ORBIT0 {SPR_SBS2, 32778, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITB, 0, 0}, // S_SORCFX2_ORBITA {SPR_SBS2, 32779, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITC, 0, 0}, // S_SORCFX2_ORBITB {SPR_SBS2, 32780, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITD, 0, 0}, // S_SORCFX2_ORBITC {SPR_SBS2, 32781, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITE, 0, 0}, // S_SORCFX2_ORBITD {SPR_SBS2, 32782, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITF, 0, 0}, // S_SORCFX2_ORBITE {SPR_SBS2, 32783, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT1, 0, 0}, // S_SORCFX2_ORBITF {SPR_SBS2, 0, 10, NULL, S_NULL, 0, 0}, // S_SORCFX2T1 {SPR_SBS3, 32768, 2, NULL, S_SORCFX3_2, 0, 0}, // S_SORCFX3_1 {SPR_SBS3, 32769, 2, NULL, S_SORCFX3_3, 0, 0}, // S_SORCFX3_2 {SPR_SBS3, 32770, 2, NULL, S_SORCFX3_1, 0, 0}, // S_SORCFX3_3 {SPR_SBS3, 32768, 4, NULL, S_BISHMORPHA, 0, 0}, // S_BISHMORPH1 {SPR_BISH, 15, 4, A_SorcererBishopEntry, S_BISHMORPHB, 0, 0}, // S_BISHMORPHA {SPR_BISH, 14, 4, NULL, S_BISHMORPHC, 0, 0}, // S_BISHMORPHB {SPR_BISH, 13, 4, NULL, S_BISHMORPHD, 0, 0}, // S_BISHMORPHC {SPR_BISH, 12, 3, NULL, S_BISHMORPHE, 0, 0}, // S_BISHMORPHD {SPR_BISH, 11, 3, NULL, S_BISHMORPHF, 0, 0}, // S_BISHMORPHE {SPR_BISH, 10, 3, NULL, S_BISHMORPHG, 0, 0}, // S_BISHMORPHF {SPR_BISH, 9, 3, NULL, S_BISHMORPHH, 0, 0}, // S_BISHMORPHG {SPR_BISH, 8, 3, NULL, S_BISHMORPHI, 0, 0}, // S_BISHMORPHH {SPR_BISH, 7, 3, NULL, S_BISHMORPHJ, 0, 0}, // S_BISHMORPHI {SPR_BISH, 6, 3, A_SpawnBishop, S_NULL, 0, 0}, // S_BISHMORPHJ {SPR_SBS3, 3, 3, NULL, S_SORCFX3_EXP2, 0, 0}, // S_SORCFX3_EXP1 {SPR_SBS3, 4, 3, NULL, S_SORCFX3_EXP3, 0, 0}, // S_SORCFX3_EXP2 {SPR_SBS3, 5, 3, NULL, S_SORCFX3_EXP4, 0, 0}, // S_SORCFX3_EXP3 {SPR_SBS3, 6, 3, NULL, S_SORCFX3_EXP5, 0, 0}, // S_SORCFX3_EXP4 {SPR_SBS3, 7, 3, NULL, S_NULL, 0, 0}, // S_SORCFX3_EXP5 {SPR_SBS4, 32768, 2, A_SorcFX4Check, S_SORCFX4_2, 0, 0}, // S_SORCFX4_1 {SPR_SBS4, 32769, 2, A_SorcFX4Check, S_SORCFX4_3, 0, 0}, // S_SORCFX4_2 {SPR_SBS4, 32770, 2, A_SorcFX4Check, S_SORCFX4_1, 0, 0}, // S_SORCFX4_3 {SPR_SBS4, 32771, 2, NULL, S_SORCFX4_D2, 0, 0}, // S_SORCFX4_D1 {SPR_SBS4, 32772, 2, A_Explode, S_SORCFX4_D3, 0, 0}, // S_SORCFX4_D2 {SPR_SBS4, 32773, 2, NULL, S_SORCFX4_D4, 0, 0}, // S_SORCFX4_D3 {SPR_SBS4, 32774, 2, NULL, S_SORCFX4_D5, 0, 0}, // S_SORCFX4_D4 {SPR_SBS4, 32775, 2, NULL, S_NULL, 0, 0}, // S_SORCFX4_D5 {SPR_SBFX, 32768, 4, NULL, S_SORCSPARK2, 0, 0}, // S_SORCSPARK1 {SPR_SBFX, 32769, 4, NULL, S_SORCSPARK3, 0, 0}, // S_SORCSPARK2 {SPR_SBFX, 32770, 4, NULL, S_SORCSPARK4, 0, 0}, // S_SORCSPARK3 {SPR_SBFX, 32771, 4, NULL, S_SORCSPARK5, 0, 0}, // S_SORCSPARK4 {SPR_SBFX, 32772, 4, NULL, S_SORCSPARK6, 0, 0}, // S_SORCSPARK5 {SPR_SBFX, 32773, 4, NULL, S_SORCSPARK7, 0, 0}, // S_SORCSPARK6 {SPR_SBFX, 32774, 4, NULL, S_NULL, 0, 0}, // S_SORCSPARK7 {SPR_RADE, 0, 4, NULL, S_BLASTEFFECT2, 0, 0}, // S_BLASTEFFECT1 {SPR_RADE, 1, 4, NULL, S_BLASTEFFECT3, 0, 0}, // S_BLASTEFFECT2 {SPR_RADE, 2, 4, NULL, S_BLASTEFFECT4, 0, 0}, // S_BLASTEFFECT3 {SPR_RADE, 3, 4, NULL, S_BLASTEFFECT5, 0, 0}, // S_BLASTEFFECT4 {SPR_RADE, 4, 4, NULL, S_BLASTEFFECT6, 0, 0}, // S_BLASTEFFECT5 {SPR_RADE, 5, 4, NULL, S_BLASTEFFECT7, 0, 0}, // S_BLASTEFFECT6 {SPR_RADE, 6, 4, NULL, S_BLASTEFFECT8, 0, 0}, // S_BLASTEFFECT7 {SPR_RADE, 7, 4, NULL, S_BLASTEFFECT9, 0, 0}, // S_BLASTEFFECT8 {SPR_RADE, 8, 4, NULL, S_NULL, 0, 0}, // S_BLASTEFFECT9 {SPR_WATR, 0, 5, NULL, S_WATERDRIP1, 0, 0}, // S_WATERDRIP1 {SPR_KORX, 0, 5, A_Look, S_KORAX_LOOK1, 0, 0}, // S_KORAX_LOOK1 {SPR_KORX, 0, 3, A_KoraxStep2, S_KORAX_CHASE2, 0, 0}, // S_KORAX_CHASE1 {SPR_KORX, 0, 3, A_KoraxChase, S_KORAX_CHASE3, 0, 0}, // S_KORAX_CHASE2 {SPR_KORX, 0, 3, A_KoraxChase, S_KORAX_CHASE4, 0, 0}, // S_KORAX_CHASE3 {SPR_KORX, 0, 3, A_KoraxChase, S_KORAX_CHASE5, 0, 0}, // S_KORAX_CHASE4 {SPR_KORX, 1, 3, A_KoraxStep, S_KORAX_CHASE6, 0, 0}, // S_KORAX_CHASE5 {SPR_KORX, 1, 3, A_KoraxChase, S_KORAX_CHASE7, 0, 0}, // S_KORAX_CHASE6 {SPR_KORX, 1, 3, A_KoraxChase, S_KORAX_CHASE8, 0, 0}, // S_KORAX_CHASE7 {SPR_KORX, 1, 3, A_KoraxChase, S_KORAX_CHASE9, 0, 0}, // S_KORAX_CHASE8 {SPR_KORX, 2, 3, A_KoraxStep2, S_KORAX_CHASE0, 0, 0}, // S_KORAX_CHASE9 {SPR_KORX, 2, 3, A_KoraxChase, S_KORAX_CHASEA, 0, 0}, // S_KORAX_CHASE0 {SPR_KORX, 2, 3, A_KoraxChase, S_KORAX_CHASEB, 0, 0}, // S_KORAX_CHASEA {SPR_KORX, 2, 3, A_KoraxChase, S_KORAX_CHASEC, 0, 0}, // S_KORAX_CHASEB {SPR_KORX, 3, 3, A_KoraxStep, S_KORAX_CHASED, 0, 0}, // S_KORAX_CHASEC {SPR_KORX, 3, 3, A_KoraxChase, S_KORAX_CHASEE, 0, 0}, // S_KORAX_CHASED {SPR_KORX, 3, 3, A_KoraxChase, S_KORAX_CHASEF, 0, 0}, // S_KORAX_CHASEE {SPR_KORX, 3, 3, A_KoraxChase, S_KORAX_CHASE1, 0, 0}, // S_KORAX_CHASEF {SPR_KORX, 7, 5, A_Pain, S_KORAX_PAIN2, 0, 0}, // S_KORAX_PAIN1 {SPR_KORX, 7, 5, NULL, S_KORAX_CHASE2, 0, 0}, // S_KORAX_PAIN2 {SPR_KORX, 32772, 2, A_FaceTarget, S_KORAX_ATTACK2, 0, 0}, // S_KORAX_ATTACK1 {SPR_KORX, 32772, 5, A_KoraxDecide, S_KORAX_ATTACK2, 0, 0}, // S_KORAX_ATTACK2 {SPR_KORX, 32772, 4, A_FaceTarget, S_KORAX_MISSILE2, 0, 0}, // S_KORAX_MISSILE1 {SPR_KORX, 32773, 8, A_KoraxMissile, S_KORAX_MISSILE3, 0, 0}, // S_KORAX_MISSILE2 {SPR_KORX, 32772, 8, NULL, S_KORAX_CHASE2, 0, 0}, // S_KORAX_MISSILE3 {SPR_KORX, 32772, 5, A_FaceTarget, S_KORAX_COMMAND2, 0, 0}, // S_KORAX_COMMAND1 {SPR_KORX, 32790, 10, A_FaceTarget, S_KORAX_COMMAND3, 0, 0}, // S_KORAX_COMMAND2 {SPR_KORX, 32774, 15, A_KoraxCommand, S_KORAX_COMMAND4, 0, 0}, // S_KORAX_COMMAND3 {SPR_KORX, 32790, 10, NULL, S_KORAX_COMMAND5, 0, 0}, // S_KORAX_COMMAND4 {SPR_KORX, 32772, 5, NULL, S_KORAX_CHASE2, 0, 0}, // S_KORAX_COMMAND5 {SPR_KORX, 8, 5, NULL, S_KORAX_DEATH2, 0, 0}, // S_KORAX_DEATH1 {SPR_KORX, 9, 5, A_FaceTarget, S_KORAX_DEATH3, 0, 0}, // S_KORAX_DEATH2 {SPR_KORX, 10, 5, A_Scream, S_KORAX_DEATH4, 0, 0}, // S_KORAX_DEATH3 {SPR_KORX, 11, 5, NULL, S_KORAX_DEATH5, 0, 0}, // S_KORAX_DEATH4 {SPR_KORX, 12, 5, NULL, S_KORAX_DEATH6, 0, 0}, // S_KORAX_DEATH5 {SPR_KORX, 13, 5, NULL, S_KORAX_DEATH7, 0, 0}, // S_KORAX_DEATH6 {SPR_KORX, 14, 5, NULL, S_KORAX_DEATH8, 0, 0}, // S_KORAX_DEATH7 {SPR_KORX, 15, 5, NULL, S_KORAX_DEATH9, 0, 0}, // S_KORAX_DEATH8 {SPR_KORX, 16, 10, NULL, S_KORAX_DEATH0, 0, 0}, // S_KORAX_DEATH9 {SPR_KORX, 17, 5, A_KoraxBonePop, S_KORAX_DEATHA, 0, 0}, // S_KORAX_DEATH0 {SPR_KORX, 18, 5, A_NoBlocking, S_KORAX_DEATHB, 0, 0}, // S_KORAX_DEATHA {SPR_KORX, 19, 5, NULL, S_KORAX_DEATHC, 0, 0}, // S_KORAX_DEATHB {SPR_KORX, 20, 5, NULL, S_KORAX_DEATHD, 0, 0}, // S_KORAX_DEATHC {SPR_KORX, 21, -1, NULL, S_NULL, 0, 0}, // S_KORAX_DEATHD {SPR_SPIR, 0, 5, A_KSpiritRoam, S_KSPIRIT_ROAM2, 0, 0}, // S_KSPIRIT_ROAM1 {SPR_SPIR, 1, 5, A_KSpiritRoam, S_KSPIRIT_ROAM1, 0, 0}, // S_KSPIRIT_ROAM2 {SPR_SPIR, 3, 5, NULL, S_KSPIRIT_DEATH2, 0, 0}, // S_KSPIRIT_DEATH1 {SPR_SPIR, 4, 5, NULL, S_KSPIRIT_DEATH3, 0, 0}, // S_KSPIRIT_DEATH2 {SPR_SPIR, 5, 5, NULL, S_KSPIRIT_DEATH4, 0, 0}, // S_KSPIRIT_DEATH3 {SPR_SPIR, 6, 5, NULL, S_KSPIRIT_DEATH5, 0, 0}, // S_KSPIRIT_DEATH4 {SPR_SPIR, 7, 5, NULL, S_KSPIRIT_DEATH6, 0, 0}, // S_KSPIRIT_DEATH5 {SPR_SPIR, 8, 5, NULL, S_NULL, 0, 0}, // S_KSPIRIT_DEATH6 {SPR_MLFX, 32776, 2, NULL, S_KBOLT2, 0, 0}, // S_KBOLT1 {SPR_MLFX, 32777, 2, A_KBoltRaise, S_KBOLT3, 0, 0}, // S_KBOLT2 {SPR_MLFX, 32776, 2, A_KBolt, S_KBOLT4, 0, 0}, // S_KBOLT3 {SPR_MLFX, 32777, 2, A_KBolt, S_KBOLT5, 0, 0}, // S_KBOLT4 {SPR_MLFX, 32778, 2, A_KBolt, S_KBOLT6, 0, 0}, // S_KBOLT5 {SPR_MLFX, 32779, 2, A_KBolt, S_KBOLT7, 0, 0}, // S_KBOLT6 {SPR_MLFX, 32780, 2, A_KBolt, S_KBOLT3, 0, 0}, // S_KBOLT7 {SPR_MAN1, 0, 2, NULL, S_SPAWNBATS2, 0, 0}, // S_SPAWNBATS1 {SPR_MAN1, 0, 2, A_BatSpawnInit, S_SPAWNBATS3, 0, 0}, // S_SPAWNBATS2 {SPR_MAN1, 0, 2, A_BatSpawn, S_SPAWNBATS3, 0, 0}, // S_SPAWNBATS3 {SPR_MAN1, 0, -1, NULL, S_NULL, 0, 0}, // S_SPAWNBATS_OFF {SPR_ABAT, 0, 2, A_BatMove, S_BAT2, 0, 0}, // S_BAT1 {SPR_ABAT, 1, 2, A_BatMove, S_BAT3, 0, 0}, // S_BAT2 {SPR_ABAT, 2, 2, A_BatMove, S_BAT1, 0, 0}, // S_BAT3 {SPR_ABAT, 0, 2, NULL, S_NULL, 0, 0} // S_BAT_DEATH }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = { { // MT_MAPSPOT 9001, // doomednum S_MAPSPOT, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MAPSPOTGRAVITY 9013, // doomednum S_MAPSPOT, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags MF2_DONTDRAW // flags2 }, { // MT_FIREBALL1 -1, // doomednum S_FIREBALL1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FIREBALL1_X1, // deathstate S_NULL, // xdeathstate SFX_FIREBALL, // deathsound 2 * FRACUNIT, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_ARROW -1, // doomednum S_ARROW_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ARROW_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 6 * FRACUNIT, // speed 8 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_DART -1, // doomednum S_DART_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DART_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 6 * FRACUNIT, // speed 8 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 2, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_POISONDART -1, // doomednum S_POISONDART_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_POISONDART_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 6 * FRACUNIT, // speed 8 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 2, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_RIPPERBALL -1, // doomednum S_RIPPERBALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_RIPPERBALL_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 6 * FRACUNIT, // speed 8 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 2, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_RIP // flags2 }, { // MT_PROJECTILE_BLADE -1, // doomednum S_PRJ_BLADE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_PRJ_BLADE_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 6 * FRACUNIT, // speed 6 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 3, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_ICESHARD -1, // doomednum S_ICESHARD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SHARDFXE1_1, // deathstate S_NULL, // xdeathstate SFX_MAGE_SHARDS_EXPLODE, // deathsound 25 * FRACUNIT, // speed 13 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 1, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_ICEDAMAGE // flags2 }, { // MT_FLAME_SMALL_TEMP 10500, // doomednum S_FLAME_TSMALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags MF2_NOTELEPORT // flags2 }, { // MT_FLAME_LARGE_TEMP 10502, // doomednum S_FLAME_TLARGE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags MF2_NOTELEPORT // flags2 }, { // MT_FLAME_SMALL 10501, // doomednum S_FLAME_SMALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags MF2_NOTELEPORT | MF2_DONTDRAW // flags2 }, { // MT_FLAME_LARGE 10503, // doomednum S_FLAME_LARGE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags MF2_NOTELEPORT | MF2_DONTDRAW // flags2 }, { // MT_HEALINGBOTTLE 81, // doomednum S_ITEM_PTN1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_HEALTHFLASK 82, // doomednum S_ARTI_PTN2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTIFLY 83, // doomednum S_ARTI_SOAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTIINVULNERABILITY 84, // doomednum S_ARTI_INVU1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_SUMMONMAULATOR 86, // doomednum S_ARTI_SUMMON, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_SUMMON_FX -1, // doomednum S_SUMMON_FX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SUMMON_FX2_1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 20 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_MISSILE | MF_DROPOFF | MF_NOBLOCKMAP, // flags MF2_NOTELEPORT // flags2 }, { // MT_THRUSTFLOOR_UP 10091, // doomednum S_THRUSTINIT2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 128 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_THRUSTFLOOR_DOWN 10090, // doomednum S_THRUSTINIT1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 128 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags MF2_NOTELEPORT | MF2_FLOORCLIP | MF2_DONTDRAW // flags2 }, { // MT_TELEPORTOTHER 10040, // doomednum S_ARTI_TELOTHER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_TELOTHER_FX1 -1, // doomednum S_TELO_FX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_TELO_FX9, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 20 * FRACUNIT, // speed 16 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 10001, // damage SFX_NONE, // activesound MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags MF2_NOTELEPORT // flags2 }, { // MT_TELOTHER_FX2 -1, // doomednum S_TELO_FX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_TELO_FX9, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 16 * FRACUNIT, // speed 16 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 10001, // damage SFX_NONE, // activesound MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags MF2_NOTELEPORT // flags2 }, { // MT_TELOTHER_FX3 -1, // doomednum S_TELO_FX3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_TELO_FX9, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 16 * FRACUNIT, // speed 16 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 10001, // damage SFX_NONE, // activesound MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags MF2_NOTELEPORT // flags2 }, { // MT_TELOTHER_FX4 -1, // doomednum S_TELO_FX4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_TELO_FX9, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 16 * FRACUNIT, // speed 16 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 10001, // damage SFX_NONE, // activesound MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags MF2_NOTELEPORT // flags2 }, { // MT_TELOTHER_FX5 -1, // doomednum S_TELO_FX5_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_TELO_FX9, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 16 * FRACUNIT, // speed 16 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 10001, // damage SFX_NONE, // activesound MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags MF2_NOTELEPORT // flags2 }, { // MT_DIRT1 -1, // doomednum S_DIRT1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DIRT1_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_DIRT2 -1, // doomednum S_DIRT2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DIRT2_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_DIRT3 -1, // doomednum S_DIRT3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DIRT3_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_DIRT4 -1, // doomednum S_DIRT4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DIRT4_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_LOGRAV // flags2 }, { // MT_DIRT5 -1, // doomednum S_DIRT5_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DIRT5_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_LOGRAV // flags2 }, { // MT_DIRT6 -1, // doomednum S_DIRT6_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DIRT6_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_LOGRAV // flags2 }, { // MT_DIRTCLUMP -1, // doomednum S_DIRTCLUMP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags MF2_NOTELEPORT // flags2 }, { // MT_ROCK1 -1, // doomednum S_ROCK1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ROCK1_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_ROCK2 -1, // doomednum S_ROCK2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ROCK2_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_ROCK3 -1, // doomednum S_ROCK3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ROCK3_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_FOGSPAWNER 10000, // doomednum S_SPAWNFOG1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags MF2_DONTDRAW | MF2_FLOATBOB // flags2 }, { // MT_FOGPATCHS 10001, // doomednum S_FOGPATCHS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FOGPATCHS0, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_FLOAT | MF_NOGRAVITY | MF_SHADOW | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_FOGPATCHM 10002, // doomednum S_FOGPATCHM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FOGPATCHM0, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_FLOAT | MF_NOGRAVITY | MF_SHADOW | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_FOGPATCHL 10003, // doomednum S_FOGPATCHL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FOGPATCHL0, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_FLOAT | MF_NOGRAVITY | MF_SHADOW | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_QUAKE_FOCUS -1, // doomednum S_QUAKE_ACTIVE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags MF2_DONTDRAW // flags2 }, { // MT_SGSHARD1 -1, // doomednum S_SGSHARD1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD1_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD2 -1, // doomednum S_SGSHARD2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD2_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD3 -1, // doomednum S_SGSHARD3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD3_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD4 -1, // doomednum S_SGSHARD4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD4_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD5 -1, // doomednum S_SGSHARD5_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD5_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD6 -1, // doomednum S_SGSHARD6_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD6_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD7 -1, // doomednum S_SGSHARD7_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD7_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD8 -1, // doomednum S_SGSHARD8_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD8_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD9 -1, // doomednum S_SGSHARD9_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD9_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SGSHARD0 -1, // doomednum S_SGSHARD0_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SGSHARD0_D, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_ARTIEGG 30, // doomednum S_ARTI_EGGC1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_EGGFX -1, // doomednum S_EGGFX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_EGGFXI1_1, // deathstate S_NULL, // xdeathstate 0, // deathsound 18 * FRACUNIT, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 1, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_ARTISUPERHEAL 32, // doomednum S_ARTI_SPHL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_ZWINGEDSTATUENOSKULL 9011, // doomednum S_ZWINGEDSTATUENOSKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZGEMPEDESTAL 9012, // doomednum S_ZGEMPEDESTAL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 40 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ARTIPUZZSKULL 9002, // doomednum S_ARTIPUZZSKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEMBIG 9003, // doomednum S_ARTIPUZZGEMBIG, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEMRED 9004, // doomednum S_ARTIPUZZGEMRED, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEMGREEN1 9005, // doomednum S_ARTIPUZZGEMGREEN1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEMGREEN2 9009, // doomednum S_ARTIPUZZGEMGREEN2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEMBLUE1 9006, // doomednum S_ARTIPUZZGEMBLUE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEMBLUE2 9010, // doomednum S_ARTIPUZZGEMBLUE2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZBOOK1 9007, // doomednum S_ARTIPUZZBOOK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZBOOK2 9008, // doomednum S_ARTIPUZZBOOK2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZSKULL2 9014, // doomednum S_ARTIPUZZSKULL2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZFWEAPON 9015, // doomednum S_ARTIPUZZFWEAPON, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZCWEAPON 9016, // doomednum S_ARTIPUZZCWEAPON, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZMWEAPON 9017, // doomednum S_ARTIPUZZMWEAPON, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEAR 9018, // doomednum S_ARTIPUZZGEAR_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEAR2 9019, // doomednum S_ARTIPUZZGEAR2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEAR3 9020, // doomednum S_ARTIPUZZGEAR3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTIPUZZGEAR4 9021, // doomednum S_ARTIPUZZGEAR4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARTITORCH 33, // doomednum S_ARTI_TRCH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_FIREBOMB -1, // doomednum S_FIREBOMB1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_FLECHETTE_EXPLODE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOGRAVITY | MF_ALTSHADOW, // flags MF2_FIREDAMAGE // flags2 }, { // MT_ARTITELEPORT 36, // doomednum S_ARTI_ATLP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_ARTIPOISONBAG 8000, // doomednum S_ARTI_PSBG1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_POISONBAG -1, // doomednum S_POISONBAG1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOGRAVITY | MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_POISONCLOUD -1, // doomednum S_POISONCLOUD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_POISONSHROOM_DEATH, // deathsound 0, // speed 1, // radius 1, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_NOGRAVITY | MF_NOBLOCKMAP | MF_SHADOW | MF_NOCLIP | MF_DROPOFF, // flags MF2_NODMGTHRUST // flags2 }, { // MT_THROWINGBOMB -1, // doomednum S_THROWINGBOMB1, // spawnstate 48, // spawnhealth S_NULL, // seestate SFX_FLECHETTE_BOUNCE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_THROWINGBOMB_X1, // deathstate S_NULL, // xdeathstate SFX_FLECHETTE_EXPLODE, // deathsound 12 * FRACUNIT, // speed 8 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_FLOORBOUNCE | MF2_FIREDAMAGE // flags2 }, { // MT_SPEEDBOOTS 8002, // doomednum S_ARTI_BOOTS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_BOOSTMANA 8003, // doomednum S_ARTI_MANA, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_BOOSTARMOR 8041, // doomednum S_ARTI_ARMOR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_BLASTRADIUS 10110, // doomednum S_ARTI_BLAST1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_HEALRADIUS 10120, // doomednum S_ARTI_HEALRAD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_SPLASH -1, // doomednum S_SPLASH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SPLASHX, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2 }, { // MT_SPLASHBASE -1, // doomednum S_SPLASHBASE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_LAVASPLASH -1, // doomednum S_LAVASPLASH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_LAVASMOKE -1, // doomednum S_LAVASMOKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_SLUDGECHUNK -1, // doomednum S_SLUDGECHUNK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SLUDGECHUNKX, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2 }, { // MT_SLUDGESPLASH -1, // doomednum S_SLUDGESPLASH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_MISC0 5, // doomednum S_ZWINGEDSTATUE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC1 6, // doomednum S_ZROCK1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC2 7, // doomednum S_ZROCK2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC3 9, // doomednum S_ZROCK3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC4 15, // doomednum S_ZROCK4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC5 17, // doomednum S_ZCHANDELIER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 60 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC6 8063, // doomednum S_ZCHANDELIER_U, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 60 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC7 24, // doomednum S_ZTREEDEAD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 96 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC8 25, // doomednum S_ZTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 128 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_TREEDESTRUCTIBLE 8062, // doomednum S_ZTREEDESTRUCTIBLE1, // spawnstate 70, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZTREEDES_D1, // deathstate S_NULL, // xdeathstate SFX_TREE_BREAK, // deathsound 0, // speed 15 * FRACUNIT, // radius 180 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags 0 // flags2 }, { // MT_MISC9 26, // doomednum S_ZTREESWAMP182_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 150 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC10 27, // doomednum S_ZTREESWAMP172_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 120 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC11 28, // doomednum S_ZSTUMPBURNED1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 12 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC12 29, // doomednum S_ZSTUMPBARE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 12 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC13 37, // doomednum S_ZSTUMPSWAMP1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC14 38, // doomednum S_ZSTUMPSWAMP2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC15 39, // doomednum S_ZSHROOMLARGE1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC16 40, // doomednum S_ZSHROOMLARGE2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC17 41, // doomednum S_ZSHROOMLARGE3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC18 42, // doomednum S_ZSHROOMSMALL1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC19 44, // doomednum S_ZSHROOMSMALL2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC20 45, // doomednum S_ZSHROOMSMALL3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC21 46, // doomednum S_ZSHROOMSMALL4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC22 47, // doomednum S_ZSHROOMSMALL5_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC23 48, // doomednum S_ZSTALAGMITEPILLAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 138 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC24 49, // doomednum S_ZSTALAGMITELARGE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 48 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC25 50, // doomednum S_ZSTALAGMITEMEDIUM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 6 * FRACUNIT, // radius 40 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC26 51, // doomednum S_ZSTALAGMITESMALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 36 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC27 52, // doomednum S_ZSTALACTITELARGE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 66 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC28 56, // doomednum S_ZSTALACTITEMEDIUM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 6 * FRACUNIT, // radius 50 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC29 57, // doomednum S_ZSTALACTITESMALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 40 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC30 58, // doomednum S_ZMOSSCEILING1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC31 59, // doomednum S_ZMOSSCEILING2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 24 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC32 60, // doomednum S_ZSWAMPVINE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 52 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC33 61, // doomednum S_ZCORPSEKABOB1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 92 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC34 62, // doomednum S_ZCORPSESLEEPING1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC35 63, // doomednum S_ZTOMBSTONERIP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 46 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC36 64, // doomednum S_ZTOMBSTONESHANE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 46 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC37 65, // doomednum S_ZTOMBSTONEBIGCROSS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 46 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC38 66, // doomednum S_ZTOMBSTONEBRIANR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 52 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC39 67, // doomednum S_ZTOMBSTONECROSSCIRCLE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 52 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC40 68, // doomednum S_ZTOMBSTONESMALLCROSS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 46 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC41 69, // doomednum S_ZTOMBSTONEBRIANP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 46 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC42 71, // doomednum S_CORPSEHANGING_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 6 * FRACUNIT, // radius 75 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC43 72, // doomednum S_ZSTATUEGARGOYLEGREENTALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 108 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC44 73, // doomednum S_ZSTATUEGARGOYLEBLUETALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 108 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC45 74, // doomednum S_ZSTATUEGARGOYLEGREENSHORT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC46 76, // doomednum S_ZSTATUEGARGOYLEBLUESHORT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC47 8044, // doomednum S_ZSTATUEGARGOYLESTRIPETALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 108 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC48 8045, // doomednum S_ZSTATUEGARGOYLEDARKREDTALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 108 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC49 8046, // doomednum S_ZSTATUEGARGOYLEREDTALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 108 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC50 8047, // doomednum S_ZSTATUEGARGOYLETANTALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 108 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC51 8048, // doomednum S_ZSTATUEGARGOYLERUSTTALL_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 108 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC52 8049, // doomednum S_ZSTATUEGARGOYLEDARKREDSHORT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC53 8050, // doomednum S_ZSTATUEGARGOYLEREDSHORT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC54 8051, // doomednum S_ZSTATUEGARGOYLETANSHORT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC55 8052, // doomednum S_ZSTATUEGARGOYLERUSTSHORT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 14 * FRACUNIT, // radius 62 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC56 77, // doomednum S_ZBANNERTATTERED_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 120 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC57 78, // doomednum S_ZTREELARGE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZTREELARGE1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 180 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC58 79, // doomednum S_ZTREELARGE2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZTREELARGE2, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 180 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC59 80, // doomednum S_ZTREEGNARLED1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 22 * FRACUNIT, // radius 100 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC60 87, // doomednum S_ZTREEGNARLED2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 22 * FRACUNIT, // radius 100 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC61 88, // doomednum S_ZLOG, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 25 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC62 89, // doomednum S_ZSTALACTITEICELARGE, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 66 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC63 90, // doomednum S_ZSTALACTITEICEMEDIUM, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 50 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC64 91, // doomednum S_ZSTALACTITEICESMALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC65 92, // doomednum S_ZSTALACTITEICETINY, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC66 93, // doomednum S_ZSTALAGMITEICELARGE, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 66 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC67 94, // doomednum S_ZSTALAGMITEICEMEDIUM, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 50 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC68 95, // doomednum S_ZSTALAGMITEICESMALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC69 96, // doomednum S_ZSTALAGMITEICETINY, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC70 97, // doomednum S_ZROCKBROWN1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 17 * FRACUNIT, // radius 72 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC71 98, // doomednum S_ZROCKBROWN2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 50 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC72 99, // doomednum S_ZROCKBLACK, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 40 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_MISC73 100, // doomednum S_ZRUBBLE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC74 101, // doomednum S_ZRUBBLE2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC75 102, // doomednum S_ZRUBBLE3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_MISC76 103, // doomednum S_ZVASEPILLAR, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 12 * FRACUNIT, // radius 54 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_POTTERY1 104, // doomednum S_ZPOTTERY1, // spawnstate 15, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZPOTTERY_EXPLODE, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_DROPOFF, // flags MF2_SLIDE | MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ // flags2 }, { // MT_POTTERY2 105, // doomednum S_ZPOTTERY2, // spawnstate 15, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZPOTTERY_EXPLODE, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 25 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_DROPOFF, // flags MF2_SLIDE | MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ // flags2 }, { // MT_POTTERY3 106, // doomednum S_ZPOTTERY3, // spawnstate 15, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZPOTTERY_EXPLODE, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 25 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_DROPOFF, // flags MF2_SLIDE | MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ // flags2 }, { // MT_POTTERYBIT1 -1, // doomednum S_POTTERYBIT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_POTTERYBIT_EX0, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_MISC77 108, // doomednum S_ZCORPSELYNCHED1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 11 * FRACUNIT, // radius 95 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ZLYNCHED_NOHEART 109, // doomednum S_ZCORPSELYNCHED2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 100 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC78 110, // doomednum S_ZCORPSESITTING, // spawnstate 30, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZCORPSESITTING_X, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 35 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags 0 // flags2 }, { // MT_CORPSEBIT -1, // doomednum S_CORPSEBIT_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags MF2_TELESTOMP // flags2 }, { // MT_CORPSEBLOODDRIP -1, // doomednum S_CORPSEBLOODDRIP, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CORPSEBLOODDRIP_X1, // deathstate S_NULL, // xdeathstate SFX_DRIP, // deathsound 0, // speed FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_MISSILE, // flags MF2_LOGRAV // flags2 }, { // MT_BLOODPOOL 111, // doomednum S_BLOODPOOL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_MISC79 119, // doomednum S_ZCANDLE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC80 113, // doomednum S_ZLEAFSPAWNER, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags MF2_DONTDRAW // flags2 }, { // MT_LEAF1 -1, // doomednum S_LEAF1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_LEAF_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_LOGRAV // flags2 }, { // MT_LEAF2 -1, // doomednum S_LEAF2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_LEAF_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_LOGRAV // flags2 }, { // MT_ZTWINEDTORCH 116, // doomednum S_ZTWINEDTORCH_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZTWINEDTORCH_UNLIT 117, // doomednum S_ZTWINEDTORCH_UNLIT, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 10 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_BRIDGE 118, // doomednum S_BRIDGE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 32 * FRACUNIT, // radius 2 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_NOGRAVITY, // flags MF2_DONTDRAW // flags2 }, { // MT_BRIDGEBALL -1, // doomednum S_BBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_ZWALLTORCH 54, // doomednum S_ZWALLTORCH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ZWALLTORCH_UNLIT 55, // doomednum S_ZWALLTORCH_U, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ZBARREL 8100, // doomednum S_ZBARREL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZSHRUB1 8101, // doomednum S_ZSHRUB1, // spawnstate 20, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_ZSHRUB1_X1, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZSHRUB1_DIE, // deathstate S_NULL, // xdeathstate SFX_TREE_EXPLODE, // deathsound 0, // speed 8 * FRACUNIT, // radius 24 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags 0 // flags2 }, { // MT_ZSHRUB2 8102, // doomednum S_ZSHRUB2, // spawnstate 10, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_ZSHRUB2_X1, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZSHRUB2_DIE, // deathstate S_NULL, // xdeathstate SFX_TREE_EXPLODE, // deathsound 0, // speed 16 * FRACUNIT, // radius 40 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags 0 // flags2 }, { // MT_ZBUCKET 8103, // doomednum S_ZBUCKET1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 72 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ZPOISONSHROOM 8104, // doomednum S_ZPOISONSHROOM1, // spawnstate 30, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_ZPOISONSHROOM_P1, // painstate 255, // painchance SFX_POISONSHROOM_PAIN, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZPOISONSHROOM_X1, // deathstate S_NULL, // xdeathstate SFX_POISONSHROOM_DEATH, // deathsound 0, // speed 6 * FRACUNIT, // radius 20 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SHOOTABLE | MF_SOLID | MF_NOBLOOD, // flags 0 // flags2 }, { // MT_ZFIREBULL 8042, // doomednum S_ZFIREBULL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 80 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZFIREBULL_UNLIT 8043, // doomednum S_ZFIREBULL_U, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 80 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_FIRETHING 8060, // doomednum S_ZFIRETHING1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_BRASSTORCH 8061, // doomednum S_ZBRASSTORCH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 6 * FRACUNIT, // radius 35 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZSUITOFARMOR 8064, // doomednum S_ZSUITOFARMOR, // spawnstate 60, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZSUITOFARMOR_X1, // deathstate S_NULL, // xdeathstate SFX_SUITOFARMOR_BREAK, // deathsound 0, // speed 16 * FRACUNIT, // radius 72 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags 0 // flags2 }, { // MT_ZARMORCHUNK -1, // doomednum S_ZARMORCHUNK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound 0, // flags 0 // flags2 }, { // MT_ZBELL 8065, // doomednum S_ZBELL, // spawnstate 5, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZBELL_X1, // deathstate S_NULL, // xdeathstate SFX_BELLRING, // deathsound 0, // speed 56 * FRACUNIT, // radius 120 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_ZBLUE_CANDLE 8066, // doomednum S_ZBLUE_CANDLE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_ZIRON_MAIDEN 8067, // doomednum S_ZIRON_MAIDEN, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 12 * FRACUNIT, // radius 60 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZXMAS_TREE 8068, // doomednum S_ZXMAS_TREE, // spawnstate 20, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_ZXMAS_TREE_X1, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZXMAS_TREE_DIE, // deathstate S_NULL, // xdeathstate SFX_TREE_EXPLODE, // deathsound 0, // speed 11 * FRACUNIT, // radius 130 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags 0 // flags2 }, { // MT_ZCAULDRON 8069, // doomednum S_ZCAULDRON1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 12 * FRACUNIT, // radius 26 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZCAULDRON_UNLIT 8070, // doomednum S_ZCAULDRON_U, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 12 * FRACUNIT, // radius 26 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID, // flags 0 // flags2 }, { // MT_ZCHAINBIT32 8071, // doomednum S_ZCHAINBIT32, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_ZCHAINBIT64 8072, // doomednum S_ZCHAINBIT64, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_ZCHAINEND_HEART 8073, // doomednum S_ZCHAINEND_HEART, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_ZCHAINEND_HOOK1 8074, // doomednum S_ZCHAINEND_HOOK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_ZCHAINEND_HOOK2 8075, // doomednum S_ZCHAINEND_HOOK2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_ZCHAINEND_SPIKE 8076, // doomednum S_ZCHAINEND_SPIKE, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_ZCHAINEND_SKULL 8077, // doomednum S_ZCHAINEND_SKULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 32 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags 0 // flags2 }, { // MT_TABLE_SHIT1 8500, // doomednum S_TABLE_SHIT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT2 8501, // doomednum S_TABLE_SHIT2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT3 8502, // doomednum S_TABLE_SHIT3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT4 8503, // doomednum S_TABLE_SHIT4, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT5 8504, // doomednum S_TABLE_SHIT5, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT6 8505, // doomednum S_TABLE_SHIT6, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT7 8506, // doomednum S_TABLE_SHIT7, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT8 8507, // doomednum S_TABLE_SHIT8, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT9 8508, // doomednum S_TABLE_SHIT9, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TABLE_SHIT10 8509, // doomednum S_TABLE_SHIT10, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_TFOG -1, // doomednum S_TFOG1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MISC81 140, // doomednum S_TELESMOKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_TELEPORTMAN 14, // doomednum S_NULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_PUNCHPUFF -1, // doomednum S_PUNCHPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_FIGHTER_PUNCH_HITTHING, // seesound 8, // reactiontime SFX_FIGHTER_PUNCH_HITWALL, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_FW_AXE 8010, // doomednum S_AXE, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_AXEPUFF -1, // doomednum S_HAMMERPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_FIGHTER_AXE_HITTHING, // seesound 8, // reactiontime SFX_FIGHTER_HAMMER_HITWALL, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_AXEPUFF_GLOW -1, // doomednum S_AXEPUFF_GLOW1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_FIGHTER_AXE_HITTHING, // seesound 8, // reactiontime SFX_FIGHTER_HAMMER_HITWALL, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_AXEBLOOD -1, // doomednum S_AXEBLOOD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_AXEBLOOD6, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2 }, { // MT_FW_HAMMER 123, // doomednum S_HAMM, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_HAMMER_MISSILE -1, // doomednum S_HAMMER_MISSILE_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HAMMER_MISSILE_X1, // deathstate S_NULL, // xdeathstate SFX_FIGHTER_HAMMER_EXPLODE, // deathsound 25 * FRACUNIT, // speed 14 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 10, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FIREDAMAGE // flags2 }, { // MT_HAMMERPUFF -1, // doomednum S_HAMMERPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_FIGHTER_HAMMER_HITTHING, // seesound 8, // reactiontime SFX_FIGHTER_HAMMER_HITWALL, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_FSWORD_MISSILE -1, // doomednum S_FSWORD_MISSILE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FSWORD_MISSILE_X1, // deathstate S_NULL, // xdeathstate SFX_FIGHTER_SWORD_EXPLODE, // deathsound 30 * FRACUNIT, // speed 16 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 8, // damage SFX_NONE, // activesound MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2 }, { // MT_FSWORD_FLAME -1, // doomednum S_FSWORD_FLAME1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_CW_SERPSTAFF 10, // doomednum S_CSTAFF, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_CSTAFF_MISSILE -1, // doomednum S_CSTAFF_MISSILE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CSTAFF_MISSILE_X1, // deathstate S_NULL, // xdeathstate SFX_CLERIC_CSTAFF_EXPLODE, // deathsound 22 * FRACUNIT, // speed 12 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 5, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2 }, { // MT_CSTAFFPUFF -1, // doomednum S_CSTAFFPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_CLERIC_CSTAFF_HITTHING, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_CW_FLAME 8009, // doomednum S_CFLAME1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_CFLAMEFLOOR -1, // doomednum S_CFLAMEFLOOR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_FLAMEPUFF -1, // doomednum S_FLAMEPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_CLERIC_FLAME_EXPLODE, // seesound 8, // reactiontime SFX_CLERIC_FLAME_EXPLODE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed FRACUNIT, // radius FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_FLAMEPUFF2 -1, // doomednum S_FLAMEPUFF2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_CLERIC_FLAME_EXPLODE, // seesound 8, // reactiontime SFX_CLERIC_FLAME_EXPLODE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed FRACUNIT, // radius FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_CIRCLEFLAME -1, // doomednum S_CIRCLE_FLAME1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CIRCLE_FLAME_X1, // deathstate S_NULL, // xdeathstate SFX_CLERIC_FLAME_CIRCLE, // deathsound 0, // speed 6 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 2, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_CFLAME_MISSILE -1, // doomednum S_CFLAME_MISSILE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CFLAME_MISSILE_X, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 200 * FRACUNIT, // speed 14 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 8, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_DONTDRAW | MF2_FIREDAMAGE // flags2 }, { // MT_HOLY_FX -1, // doomednum S_HOLY_FX1, // spawnstate 105, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HOLY_FX_X1, // deathstate S_NULL, // xdeathstate SFX_SPIRIT_DIE, // deathsound 12 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 3, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_SEEKERMISSILE | MF2_RIP | MF2_IMPACT | MF2_PCROSS // flags2 }, { // MT_HOLY_TAIL -1, // doomednum S_HOLY_TAIL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed FRACUNIT, // radius FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_NOCLIP | MF_ALTSHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_HOLY_PUFF -1, // doomednum S_HOLY_PUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_HOLY_MISSILE -1, // doomednum S_HOLY_MISSILE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_HOLY_MISSILE_X, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 30 * FRACUNIT, // speed 15 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_HOLY_MISSILE_PUFF -1, // doomednum S_HOLY_MISSILE_P1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_MWANDPUFF -1, // doomednum S_MWANDPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH | MF2_NODMGTHRUST // flags2 }, { // MT_MWANDSMOKE -1, // doomednum S_MWANDSMOKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH | MF2_NODMGTHRUST // flags2 }, { // MT_MWAND_MISSILE -1, // doomednum S_MWAND_MISSILE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MWANDPUFF1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 184 * FRACUNIT, // speed 12 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 2, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_RIP | MF2_IMPACT | MF2_PCROSS | MF2_NODMGTHRUST | MF2_CANNOTPUSH // flags2 }, { // MT_MW_LIGHTNING 8040, // doomednum S_MW_LIGHTNING1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_LIGHTNING_CEILING -1, // doomednum S_LIGHTNING_CEILING1, // spawnstate 144, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_LIGHTNING_C_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 25 * FRACUNIT, // speed 16 * FRACUNIT, // radius 40 * FRACUNIT, // height 100, // mass 8, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2 }, { // MT_LIGHTNING_FLOOR -1, // doomednum S_LIGHTNING_FLOOR1, // spawnstate 144, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_LIGHTNING_F_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 25 * FRACUNIT, // speed 16 * FRACUNIT, // radius 40 * FRACUNIT, // height 100, // mass 8, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2 }, { // MT_LIGHTNING_ZAP -1, // doomednum S_LIGHTNING_ZAP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_LIGHTNING_ZAP_X8, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 35 * FRACUNIT, // height 100, // mass 2, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags 0 // flags2 }, { // MT_MSTAFF_FX -1, // doomednum S_MSTAFF_FX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MSTAFF_FX_X1, // deathstate S_NULL, // xdeathstate SFX_MAGE_STAFF_EXPLODE, // deathsound 20 * FRACUNIT, // speed 16 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 6, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE | MF2_RIP | MF2_IMPACT | MF2_PCROSS // flags2 }, { // MT_MSTAFF_FX2 -1, // doomednum S_MSTAFF_FX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MSTAFF_FX2_X1, // deathstate S_NULL, // xdeathstate SFX_MAGE_STAFF_EXPLODE, // deathsound 17 * FRACUNIT, // speed 20 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE | MF2_IMPACT | MF2_PCROSS | MF2_SEEKERMISSILE // flags2 }, { // MT_FW_SWORD1 12, // doomednum S_FSWORD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_FW_SWORD2 13, // doomednum S_FSWORD2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_FW_SWORD3 16, // doomednum S_FSWORD3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_CW_HOLY1 18, // doomednum S_CHOLY1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_CW_HOLY2 19, // doomednum S_CHOLY2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_CW_HOLY3 20, // doomednum S_CHOLY3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_MW_STAFF1 21, // doomednum S_MSTAFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_MW_STAFF2 22, // doomednum S_MSTAFF2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_MW_STAFF3 23, // doomednum S_MSTAFF3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_SNOUTPUFF -1, // doomednum S_PUNCHPUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_MW_CONE 53, // doomednum S_COS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_SHARDFX1 -1, // doomednum S_SHARDFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SHARDFXE1_1, // deathstate S_NULL, // xdeathstate SFX_MAGE_SHARDS_EXPLODE, // deathsound 25 * FRACUNIT, // speed 13 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 1, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_ICEDAMAGE // flags2 }, { // MT_BLOOD -1, // doomednum S_BLOOD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags 0 // flags2 }, { // MT_BLOODSPLATTER -1, // doomednum S_BLOODSPLATTER1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BLOODSPLATTERX, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 2 * FRACUNIT, // radius 4 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2 }, { // MT_GIBS -1, // doomednum S_GIBS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT // flags2 }, { // MT_PLAYER_FIGHTER -1, // doomednum S_FPLAY, // spawnstate 100, // spawnhealth S_FPLAY_RUN1, // seestate SFX_NONE, // seesound 0, // reactiontime SFX_NONE, // attacksound S_FPLAY_PAIN, // painstate 255, // painchance SFX_PLAYER_FIGHTER_PAIN, // painsound S_NULL, // meleestate S_FPLAY_ATK1, // missilestate S_NULL, // crashstate S_FPLAY_DIE1, // deathstate S_FPLAY_XDIE1, // xdeathstate SFX_NONE, // deathsound 0, // speed 16 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL // flags2 }, { // MT_BLOODYSKULL -1, // doomednum S_BLOODYSKULL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 4 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF, // flags MF2_LOGRAV | MF2_CANNOTPUSH // flags2 }, { // MT_PLAYER_SPEED -1, // doomednum S_PLAYER_SPEED1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_ALTSHADOW, // flags 0 // flags2 }, { // MT_ICECHUNK -1, // doomednum S_ICECHUNK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF, // flags MF2_LOGRAV | MF2_CANNOTPUSH | MF2_FLOORCLIP // flags2 }, { // MT_PLAYER_CLERIC -1, // doomednum S_CPLAY, // spawnstate 100, // spawnhealth S_CPLAY_RUN1, // seestate SFX_NONE, // seesound 0, // reactiontime SFX_NONE, // attacksound S_CPLAY_PAIN, // painstate 255, // painchance SFX_PLAYER_CLERIC_PAIN, // painsound S_NULL, // meleestate S_CPLAY_ATK1, // missilestate S_NULL, // crashstate S_CPLAY_DIE1, // deathstate S_CPLAY_XDIE1, // xdeathstate SFX_NONE, // deathsound 0, // speed 16 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL // flags2 }, { // MT_PLAYER_MAGE -1, // doomednum S_MPLAY, // spawnstate 100, // spawnhealth S_MPLAY_RUN1, // seestate SFX_NONE, // seesound 0, // reactiontime SFX_NONE, // attacksound S_MPLAY_PAIN, // painstate 255, // painchance SFX_PLAYER_MAGE_PAIN, // painsound S_NULL, // meleestate S_MPLAY_ATK1, // missilestate S_NULL, // crashstate S_MPLAY_DIE1, // deathstate S_MPLAY_XDIE1, // xdeathstate SFX_NONE, // deathsound 0, // speed 16 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL // flags2 }, { // MT_PIGPLAYER -1, // doomednum S_PIGPLAY, // spawnstate 100, // spawnhealth S_PIGPLAY_RUN1, // seestate SFX_NONE, // seesound 0, // reactiontime SFX_NONE, // attacksound S_PIGPLAY_PAIN, // painstate 255, // painchance SFX_PIG_PAIN, // painsound S_NULL, // meleestate S_PIGPLAY_ATK1, // missilestate S_NULL, // crashstate S_PIG_DIE1, // deathstate S_NULL, // xdeathstate SFX_PIG_DEATH, // deathsound 0, // speed 16 * FRACUNIT, // radius 24 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_NOTDMATCH, // flags MF2_WINDTHRUST | MF2_SLIDE | MF2_PASSMOBJ | MF2_FLOORCLIP | MF2_TELESTOMP | MF2_PUSHWALL // flags2 }, { // MT_PIG -1, // doomednum S_PIG_LOOK1, // spawnstate 25, // spawnhealth S_PIG_WALK1, // seestate SFX_PIG_ACTIVE1, // seesound 8, // reactiontime SFX_NONE, // attacksound S_PIG_PAIN, // painstate 128, // painchance SFX_PIG_PAIN, // painsound S_PIG_ATK1, // meleestate 0, // missilestate S_NULL, // crashstate S_PIG_DIE1, // deathstate S_NULL, // xdeathstate SFX_PIG_DEATH, // deathsound 10, // speed 12 * FRACUNIT, // radius 22 * FRACUNIT, // height 60, // mass 0, // damage SFX_PIG_ACTIVE1, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2 }, { // MT_CENTAUR 107, // doomednum S_CENTAUR_LOOK1, // spawnstate 200, // spawnhealth S_CENTAUR_WALK1, // seestate SFX_CENTAUR_SIGHT, // seesound 8, // reactiontime SFX_CENTAUR_ATTACK, // attacksound S_CENTAUR_PAIN1, // painstate 135, // painchance SFX_CENTAUR_PAIN, // painsound S_CENTAUR_ATK1, // meleestate 0, // missilestate S_NULL, // crashstate S_CENTAUR_DEATH1, // deathstate S_CENTAUR_DEATH_X1, // xdeathstate SFX_CENTAUR_DEATH, // deathsound 13, // speed 20 * FRACUNIT, // radius 64 * FRACUNIT, // height 120, // mass 0, // damage SFX_CENTAUR_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP // flags2 }, { // MT_CENTAURLEADER 115, // doomednum S_CENTAUR_LOOK1, // spawnstate 250, // spawnhealth S_CENTAUR_WALK1, // seestate SFX_CENTAUR_SIGHT, // seesound 8, // reactiontime SFX_CENTAUR_ATTACK, // attacksound S_CENTAUR_PAIN1, // painstate 96, // painchance SFX_CENTAUR_PAIN, // painsound S_CENTAUR_ATK1, // meleestate S_CENTAUR_MISSILE1, // missilestate S_NULL, // crashstate S_CENTAUR_DEATH1, // deathstate S_CENTAUR_DEATH_X1, // xdeathstate SFX_CENTAUR_DEATH, // deathsound 10, // speed 20 * FRACUNIT, // radius 64 * FRACUNIT, // height 120, // mass 0, // damage SFX_CENTAUR_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP // flags2 }, { // MT_CENTAUR_FX -1, // doomednum S_CENTAUR_FX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CENTAUR_FX_X1, // deathstate S_NULL, // xdeathstate SFX_CENTAUR_MISSILE_EXPLODE, // deathsound 20 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2 }, { // MT_CENTAUR_SHIELD -1, // doomednum S_CENTAUR_SHIELD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CENTAUR_SHIELD_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT // flags2 }, { // MT_CENTAUR_SWORD -1, // doomednum S_CENTAUR_SWORD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_CENTAUR_SWORD_X1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT // flags2 }, { // MT_DEMON 31, // doomednum S_DEMN_LOOK1, // spawnstate 250, // spawnhealth S_DEMN_CHASE1, // seestate SFX_DEMON_SIGHT, // seesound 8, // reactiontime SFX_DEMON_ATTACK, // attacksound S_DEMN_PAIN1, // painstate 50, // painchance SFX_DEMON_PAIN, // painsound S_DEMN_ATK1_1, // meleestate S_DEMN_ATK2_1, // missilestate S_NULL, // crashstate S_DEMN_DEATH1, // deathstate S_DEMN_XDEATH1, // xdeathstate SFX_DEMON_DEATH, // deathsound 13, // speed 32 * FRACUNIT, // radius 64 * FRACUNIT, // height 220, // mass 0, // damage SFX_DEMON_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_TELESTOMP // flags2 }, { // MT_DEMONCHUNK1 -1, // doomednum S_DEMONCHUNK1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMONCHUNK1_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMONCHUNK2 -1, // doomednum S_DEMONCHUNK2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMONCHUNK2_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMONCHUNK3 -1, // doomednum S_DEMONCHUNK3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMONCHUNK3_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMONCHUNK4 -1, // doomednum S_DEMONCHUNK4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMONCHUNK4_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMONCHUNK5 -1, // doomednum S_DEMONCHUNK5_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMONCHUNK5_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMONFX1 -1, // doomednum S_DEMONFX_MOVE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMONFX_BOOM1, // deathstate S_NULL, // xdeathstate SFX_DEMON_MISSILE_EXPLODE, // deathsound 15 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 5, // damage SFX_NONE, // activesound MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FIREDAMAGE // flags2 }, { // MT_DEMON2 8080, // doomednum S_DEMN2_LOOK1, // spawnstate 250, // spawnhealth S_DEMN2_CHASE1, // seestate SFX_DEMON_SIGHT, // seesound 8, // reactiontime SFX_DEMON_ATTACK, // attacksound S_DEMN2_PAIN1, // painstate 50, // painchance SFX_DEMON_PAIN, // painsound S_DEMN2_ATK1_1, // meleestate S_DEMN2_ATK2_1, // missilestate S_NULL, // crashstate S_DEMN2_DEATH1, // deathstate S_DEMN2_XDEATH1, // xdeathstate SFX_DEMON_DEATH, // deathsound 13, // speed 32 * FRACUNIT, // radius 64 * FRACUNIT, // height 220, // mass 0, // damage SFX_DEMON_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_TELESTOMP // flags2 }, { // MT_DEMON2CHUNK1 -1, // doomednum S_DEMON2CHUNK1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMON2CHUNK1_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMON2CHUNK2 -1, // doomednum S_DEMON2CHUNK2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMON2CHUNK2_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMON2CHUNK3 -1, // doomednum S_DEMON2CHUNK3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMON2CHUNK3_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMON2CHUNK4 -1, // doomednum S_DEMON2CHUNK4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMON2CHUNK4_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMON2CHUNK5 -1, // doomednum S_DEMON2CHUNK5_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMON2CHUNK5_4, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_DEMON2FX1 -1, // doomednum S_DEMON2FX_MOVE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DEMON2FX_BOOM1, // deathstate S_NULL, // xdeathstate SFX_DEMON_MISSILE_EXPLODE, // deathsound 15 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 5, // damage SFX_NONE, // activesound MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FIREDAMAGE // flags2 }, { // MT_WRAITHB 10011, // doomednum S_WRAITH_LOOK1, // spawnstate 150, // spawnhealth S_WRAITH_RAISE1, // seestate SFX_WRAITH_SIGHT, // seesound 8, // reactiontime SFX_WRAITH_ATTACK, // attacksound S_WRAITH_PAIN1, // painstate 25, // painchance SFX_WRAITH_PAIN, // painsound S_WRAITH_ATK1_1, // meleestate S_WRAITH_ATK2_1, // missilestate S_NULL, // crashstate S_WRAITH_DEATH1_1, // deathstate S_WRAITH_DEATH2_1, // xdeathstate SFX_WRAITH_DEATH, // deathsound 11, // speed 20 * FRACUNIT, // radius 68 * FRACUNIT, // height 75, // mass 10, // damage SFX_WRAITH_ACTIVE, // activesound MF_DROPOFF | MF_NOGRAVITY | MF_FLOAT | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP | MF2_DONTDRAW // flags2 }, { // MT_WRAITH 34, // doomednum S_WRAITH_INIT1, // spawnstate 150, // spawnhealth S_WRAITH_CHASE1, // seestate SFX_WRAITH_SIGHT, // seesound 8, // reactiontime SFX_WRAITH_ATTACK, // attacksound S_WRAITH_PAIN1, // painstate 25, // painchance SFX_WRAITH_PAIN, // painsound S_WRAITH_ATK1_1, // meleestate S_WRAITH_ATK2_1, // missilestate S_NULL, // crashstate S_WRAITH_DEATH1_1, // deathstate S_WRAITH_DEATH2_1, // xdeathstate SFX_WRAITH_DEATH, // deathsound 11, // speed 20 * FRACUNIT, // radius 55 * FRACUNIT, // height 75, // mass 10, // damage SFX_WRAITH_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF | MF_NOGRAVITY | MF_FLOAT, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2 }, { // MT_WRAITHFX1 -1, // doomednum S_WRTHFX_MOVE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_WRTHFX_BOOM1, // deathstate S_NULL, // xdeathstate SFX_WRAITH_MISSILE_EXPLODE, // deathsound 14 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 5, // mass 5, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FLOORCLIP | MF2_FIREDAMAGE // flags2 }, { // MT_WRAITHFX2 -1, // doomednum S_WRTHFX_SIZZLE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 2 * FRACUNIT, // radius 5 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_WRAITHFX3 -1, // doomednum S_WRTHFX_DROP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_WRTHFX_DEAD1, // deathstate S_NULL, // xdeathstate SFX_DRIP, // deathsound 0, // speed 2 * FRACUNIT, // radius 5 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_WRAITHFX4 -1, // doomednum S_WRTHFX_ADROP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_WRTHFX_ADEAD1, // deathstate S_NULL, // xdeathstate SFX_DRIP, // deathsound 0, // speed 2 * FRACUNIT, // radius 5 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_WRAITHFX5 -1, // doomednum S_WRTHFX_BDROP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_WRTHFX_BDEAD1, // deathstate S_NULL, // xdeathstate SFX_DRIP, // deathsound 0, // speed 2 * FRACUNIT, // radius 5 * FRACUNIT, // height 5, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_MINOTAUR 9, // doomednum S_MNTR_SPAWN1, // spawnstate 2500, // spawnhealth S_MNTR_WALK1, // seestate SFX_MAULATOR_SIGHT, // seesound 8, // reactiontime SFX_MAULATOR_HAMMER_SWING, // attacksound S_MNTR_PAIN1, // painstate 25, // painchance SFX_MAULATOR_PAIN, // painsound S_MNTR_ATK1_1, // meleestate S_MNTR_ATK2_1, // missilestate S_NULL, // crashstate S_MNTR_DIE1, // deathstate S_NULL, // xdeathstate SFX_MAULATOR_DEATH, // deathsound 16, // speed 28 * FRACUNIT, // radius 100 * FRACUNIT, // height 800, // mass 7, // damage SFX_MAULATOR_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2 }, { // MT_MNTRFX1 -1, // doomednum S_MNTRFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MNTRFXI1_1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 20 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 3, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_MNTRFX2 -1, // doomednum S_MNTRFX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MNTRFXI2_1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 14 * FRACUNIT, // speed 5 * FRACUNIT, // radius 12 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_MNTRFX3 -1, // doomednum S_MNTRFX3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_MNTRFXI2_1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_MNTRSMOKE -1, // doomednum S_MINOSMOKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_MNTRSMOKEEXIT -1, // doomednum S_MINOSMOKEX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_SERPENT 121, // doomednum S_SERPENT_LOOK1, // spawnstate 90, // spawnhealth S_SERPENT_SWIM1, // seestate SFX_SERPENT_SIGHT, // seesound 8, // reactiontime SFX_SERPENT_ATTACK, // attacksound S_SERPENT_PAIN1, // painstate 96, // painchance SFX_SERPENT_PAIN, // painsound S_SERPENT_SURFACE1, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SERPENT_DIE1, // deathstate S_SERPENT_XDIE1, // xdeathstate SFX_SERPENT_DEATH, // deathsound 12, // speed 32 * FRACUNIT, // radius 70 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_COUNTKILL | MF_NOBLOOD, // flags MF2_PASSMOBJ | MF2_DONTDRAW | MF2_CANTLEAVEFLOORPIC | MF2_NONSHOOTABLE | MF2_MCROSS // flags2 }, { // MT_SERPENTLEADER 120, // doomednum S_SERPENT_LOOK1, // spawnstate 90, // spawnhealth S_SERPENT_SWIM1, // seestate SFX_SERPENT_SIGHT, // seesound 8, // reactiontime SFX_SERPENT_ATTACK, // attacksound S_SERPENT_PAIN1, // painstate 96, // painchance SFX_SERPENT_PAIN, // painsound S_SERPENT_SURFACE1, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SERPENT_DIE1, // deathstate S_SERPENT_XDIE1, // xdeathstate SFX_SERPENT_DEATH, // deathsound 12, // speed 32 * FRACUNIT, // radius 70 * FRACUNIT, // height 200, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_COUNTKILL | MF_NOBLOOD, // flags MF2_PASSMOBJ | MF2_DONTDRAW | MF2_CANTLEAVEFLOORPIC | MF2_NONSHOOTABLE | MF2_MCROSS // flags2 }, { // MT_SERPENTFX -1, // doomednum S_SERPENT_FX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate 0, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SERPENT_FX_X1, // deathstate S_NULL, // xdeathstate SFX_SERPENTFX_HIT, // deathsound 15 * FRACUNIT, // speed 8 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 4, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_SERPENT_HEAD -1, // doomednum S_SERPENT_HEAD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags MF2_LOGRAV // flags2 }, { // MT_SERPENT_GIB1 -1, // doomednum S_SERPENT_GIB1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 3 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_SERPENT_GIB2 -1, // doomednum S_SERPENT_GIB2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 3 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_SERPENT_GIB3 -1, // doomednum S_SERPENT_GIB3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 3 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_BISHOP 114, // doomednum S_BISHOP_LOOK1, // spawnstate 130, // spawnhealth S_BISHOP_WALK1, // seestate SFX_BISHOP_SIGHT, // seesound 8, // reactiontime SFX_BISHOP_ATTACK, // attacksound S_BISHOP_PAIN1, // painstate 110, // painchance SFX_BISHOP_PAIN, // painsound 0, // meleestate S_BISHOP_ATK1, // missilestate S_NULL, // crashstate S_BISHOP_DEATH1, // deathstate S_NULL, // xdeathstate SFX_BISHOP_DEATH, // deathsound 10, // speed 22 * FRACUNIT, // radius 65 * FRACUNIT, // height 100, // mass 0, // damage SFX_BISHOP_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_FLOAT | MF_NOGRAVITY | MF_NOBLOOD, // flags MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2 }, { // MT_BISHOP_PUFF -1, // doomednum S_BISHOP_PUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SHADOW | MF_NOBLOCKMAP | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_BISHOPBLUR -1, // doomednum S_BISHOPBLUR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_BISHOPPAINBLUR -1, // doomednum S_BISHOPPAINBLUR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags 0 // flags2 }, { // MT_BISH_FX -1, // doomednum S_BISHFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BISHFXI1_1, // deathstate S_NULL, // xdeathstate SFX_BISHOP_MISSILE_EXPLODE, // deathsound 10 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 100, // mass 1, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_SEEKERMISSILE // flags2 }, { // MT_DRAGON 254, // doomednum S_DRAGON_LOOK1, // spawnstate 640, // spawnhealth S_DRAGON_INIT, // seestate SFX_DRAGON_SIGHT, // seesound 8, // reactiontime SFX_DRAGON_ATTACK, // attacksound S_DRAGON_PAIN1, // painstate 128, // painchance SFX_DRAGON_PAIN, // painsound S_NULL, // meleestate S_DRAGON_ATK1, // missilestate S_NULL, // crashstate S_DRAGON_DEATH1, // deathstate S_NULL, // xdeathstate SFX_DRAGON_DEATH, // deathsound 10 * FRACUNIT, // speed 20 * FRACUNIT, // radius 65 * FRACUNIT, // height INT_MAX, // mass 0, // damage SFX_DRAGON_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_FLOAT | MF_NOGRAVITY | MF_NOBLOOD, // flags MF2_PASSMOBJ | MF2_BOSS // flags2 }, { // MT_DRAGON_FX -1, // doomednum S_DRAGON_FX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_DRAGON_FX1_X1, // deathstate S_NULL, // xdeathstate SFX_DRAGON_FIREBALL_EXPLODE, // deathsound 24 * FRACUNIT, // speed 12 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 6, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2 }, { // MT_DRAGON_FX2 -1, // doomednum S_DRAGON_FX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_DRAGON_FIREBALL_EXPLODE, // deathsound 0, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP, // flags MF2_NOTELEPORT | MF2_FIREDAMAGE | MF2_DONTDRAW // flags2 }, { // MT_ARMOR_1 8005, // doomednum S_ARMOR_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARMOR_2 8006, // doomednum S_ARMOR_2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARMOR_3 8007, // doomednum S_ARMOR_3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_ARMOR_4 8008, // doomednum S_ARMOR_4, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL | MF_NOGRAVITY, // flags 0 // flags2 }, { // MT_MANA1 122, // doomednum S_MANA1_1, // spawnstate 10, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_MANA2 124, // doomednum S_MANA2_1, // spawnstate 10, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_MANA3 8004, // doomednum S_MANA3_1, // spawnstate 20, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 8 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags MF2_FLOATBOB // flags2 }, { // MT_KEY1 8030, // doomednum S_KEY1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY2 8031, // doomednum S_KEY2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY3 8032, // doomednum S_KEY3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY4 8033, // doomednum S_KEY4, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY5 8034, // doomednum S_KEY5, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY6 8035, // doomednum S_KEY6, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY7 8036, // doomednum S_KEY7, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY8 8037, // doomednum S_KEY8, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEY9 8038, // doomednum S_KEY9, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEYA 8039, // doomednum S_KEYA, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_KEYB 8200, // doomednum S_KEYB, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 8 * FRACUNIT, // radius 20 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SPECIAL, // flags 0 // flags2 }, { // MT_SOUNDWIND 1410, // doomednum S_SND_WIND1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_SOUNDWATERFALL 41, // doomednum S_SND_WATERFALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR, // flags 0 // flags2 }, { // MT_ETTIN 10030, // doomednum S_ETTIN_LOOK1, // spawnstate 175, // spawnhealth S_ETTIN_CHASE1, // seestate SFX_ETTIN_SIGHT, // seesound 8, // reactiontime SFX_ETTIN_ATTACK, // attacksound S_ETTIN_PAIN1, // painstate 60, // painchance SFX_ETTIN_PAIN, // painsound S_ETTIN_ATK1_1, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ETTIN_DEATH1_1, // deathstate S_ETTIN_DEATH2_1, // xdeathstate SFX_ETTIN_DEATH, // deathsound 13, // speed 25 * FRACUNIT, // radius 68 * FRACUNIT, // height 175, // mass 3, // damage SFX_ETTIN_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP // flags2 }, { // MT_ETTIN_MACE -1, // doomednum S_ETTIN_MACE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ETTIN_MACE5, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_FIREDEMON 10060, // doomednum S_FIRED_SPAWN1, // spawnstate 80, // spawnhealth S_FIRED_LOOK4, // seestate SFX_FIRED_SPAWN, // seesound 8, // reactiontime SFX_NONE, // attacksound S_FIRED_PAIN1, // painstate 1, // painchance SFX_FIRED_PAIN, // painsound S_NULL, // meleestate S_FIRED_ATTACK1, // missilestate S_FIRED_XDEATH1, // crashstate S_FIRED_DEATH1, // deathstate S_FIRED_XDEATH1, // xdeathstate SFX_FIRED_DEATH, // deathsound 13, // speed 20 * FRACUNIT, // radius 68 * FRACUNIT, // height 75, // mass 1, // damage SFX_FIRED_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF | MF_NOGRAVITY | MF_FLOAT, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_INVULNERABLE | MF2_MCROSS | MF2_TELESTOMP // flags2 }, { // MT_FIREDEMON_SPLOTCH1 -1, // doomednum S_FIRED_CORPSE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_FIREDEMON_SPLOTCH2 -1, // doomednum S_FIRED_CORPSE4, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_DROPOFF | MF_CORPSE, // flags MF2_NOTELEPORT | MF2_FLOORCLIP // flags2 }, { // MT_FIREDEMON_FX1 -1, // doomednum S_FIRED_RDROP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FIRED_RDEAD1_1, // deathstate S_FIRED_RDEAD1_2, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 5 * FRACUNIT, // height 16, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_FIREDEMON_FX2 -1, // doomednum S_FIRED_RDROP2, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FIRED_RDEAD2_1, // deathstate S_FIRED_RDEAD2_2, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 5 * FRACUNIT, // height 16, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_FIREDEMON_FX3 -1, // doomednum S_FIRED_RDROP3, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FIRED_RDEAD3_1, // deathstate S_FIRED_RDEAD3_2, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 5 * FRACUNIT, // height 16, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_FIREDEMON_FX4 -1, // doomednum S_FIRED_RDROP4, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FIRED_RDEAD4_1, // deathstate S_FIRED_RDEAD4_2, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 5 * FRACUNIT, // height 16, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_FIREDEMON_FX5 -1, // doomednum S_FIRED_RDROP5, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FIRED_RDEAD5_1, // deathstate S_FIRED_RDEAD5_2, // xdeathstate SFX_NONE, // deathsound 0, // speed 3 * FRACUNIT, // radius 5 * FRACUNIT, // height 16, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_FIREDEMON_FX6 -1, // doomednum S_FIRED_FX6_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_FIRED_FX6_2, // deathstate S_NULL, // xdeathstate SFX_FIRED_MISSILE_HIT, // deathsound 10 * FRACUNIT, // speed 10 * FRACUNIT, // radius 6 * FRACUNIT, // height 15, // mass 1, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FLOORCLIP | MF2_FIREDAMAGE // flags2 }, { // MT_ICEGUY 8020, // doomednum S_ICEGUY_LOOK, // spawnstate 120, // spawnhealth S_ICEGUY_WALK1, // seestate SFX_ICEGUY_SIGHT, // seesound 8, // reactiontime SFX_ICEGUY_ATTACK, // attacksound S_ICEGUY_PAIN1, // painstate 144, // painchance SFX_NONE, // painsound 0, // meleestate S_ICEGUY_ATK1, // missilestate S_NULL, // crashstate S_ICEGUY_DEATH, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 14, // speed 22 * FRACUNIT, // radius 75 * FRACUNIT, // height 150, // mass 0, // damage SFX_ICEGUY_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags MF2_PASSMOBJ | MF2_PUSHWALL | MF2_ICEDAMAGE | MF2_MCROSS | MF2_TELESTOMP // flags2 }, { // MT_ICEGUY_FX -1, // doomednum S_ICEGUY_FX1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ICEGUY_FX_X1, // deathstate S_NULL, // xdeathstate SFX_ICEGUY_FX_EXPLODE, // deathsound 14 * FRACUNIT, // speed 8 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 1, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags MF2_NOTELEPORT | MF2_ICEDAMAGE // flags2 }, { // MT_ICEFX_PUFF -1, // doomednum S_ICEFX_PUFF1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed FRACUNIT, // radius FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW | MF_DROPOFF, // flags MF2_NOTELEPORT // flags2 }, { // MT_ICEGUY_FX2 -1, // doomednum S_ICEGUY_FX2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 10 * FRACUNIT, // speed 4 * FRACUNIT, // radius 4 * FRACUNIT, // height 100, // mass 1, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_LOGRAV | MF2_ICEDAMAGE // flags2 }, { // MT_ICEGUY_BIT -1, // doomednum S_ICEGUY_BIT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed FRACUNIT, // radius FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV // flags2 }, { // MT_ICEGUY_WISP1 -1, // doomednum S_ICEGUY_WISP1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_ICEGUY_WISP2 -1, // doomednum S_ICEGUY_WISP2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_FIGHTER_BOSS 10100, // doomednum S_FIGHTER, // spawnstate 800, // spawnhealth S_FIGHTER_RUN1, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_FIGHTER_PAIN, // painstate 50, // painchance SFX_PLAYER_FIGHTER_PAIN, // painsound S_FIGHTER_ATK1, // meleestate S_FIGHTER_ATK1, // missilestate S_NULL, // crashstate S_FIGHTER_DIE1, // deathstate S_FIGHTER_XDIE1, // xdeathstate SFX_PLAYER_FIGHTER_CRAZY_DEATH, // deathsound 25, // speed 16 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL | MF2_MCROSS // flags2 }, { // MT_CLERIC_BOSS 10101, // doomednum S_CLERIC, // spawnstate 800, // spawnhealth S_CLERIC_RUN1, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_CLERIC_PAIN, // painstate 50, // painchance SFX_PLAYER_CLERIC_PAIN, // painsound S_CLERIC_ATK1, // meleestate S_CLERIC_ATK1, // missilestate S_NULL, // crashstate S_CLERIC_DIE1, // deathstate S_CLERIC_XDIE1, // xdeathstate SFX_PLAYER_CLERIC_CRAZY_DEATH, // deathsound 25, // speed 16 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL | MF2_MCROSS // flags2 }, { // MT_MAGE_BOSS 10102, // doomednum S_MAGE, // spawnstate 800, // spawnhealth S_MAGE_RUN1, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_MAGE_PAIN, // painstate 50, // painchance SFX_PLAYER_MAGE_PAIN, // painsound S_MAGE_ATK1, // meleestate S_MAGE_ATK1, // missilestate S_NULL, // crashstate S_MAGE_DIE1, // deathstate S_MAGE_XDIE1, // xdeathstate SFX_PLAYER_MAGE_CRAZY_DEATH, // deathsound 25, // speed 16 * FRACUNIT, // radius 64 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL | MF2_MCROSS // flags2 }, { // MT_SORCBOSS 10080, // doomednum S_SORC_SPAWN1, // spawnstate 5000, // spawnhealth S_SORC_WALK1, // seestate SFX_SORCERER_SIGHT, // seesound 8, // reactiontime SFX_NONE, // attacksound S_SORC_PAIN1, // painstate 10, // painchance SFX_SORCERER_PAIN, // painsound S_NULL, // meleestate S_SORC_ATK2_1, // missilestate S_NULL, // crashstate S_SORC_DIE1, // deathstate S_NULL, // xdeathstate SFX_SORCERER_DEATHSCREAM, // deathsound 16, // speed 40 * FRACUNIT, // radius 110 * FRACUNIT, // height 500, // mass 9, // damage SFX_SORCERER_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_BOSS | MF2_MCROSS // flags2 }, { // MT_SORCBALL1 -1, // doomednum S_SORCBALL1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_SORCERER_BALLBOUNCE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_SORCBALL1_D1, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SORCBALL1_D5, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 10 * FRACUNIT, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SORCBALL2 -1, // doomednum S_SORCBALL2_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_SORCERER_BALLBOUNCE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_SORCBALL2_D1, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SORCBALL2_D5, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 10 * FRACUNIT, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SORCBALL3 -1, // doomednum S_SORCBALL3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_SORCERER_BALLBOUNCE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_SORCBALL3_D1, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SORCBALL3_D5, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 10 * FRACUNIT, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SORCFX1 -1, // doomednum S_SORCFX1_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_SORCERER_BALLBOUNCE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SORCFX1_D1, // deathstate S_SORCFX1_D1, // xdeathstate SFX_NONE, // deathsound 7 * FRACUNIT, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE, // flags MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2 }, { // MT_SORCFX2 -1, // doomednum S_SORCFX2_SPLIT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SORCFX2T1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 15 * FRACUNIT, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_SORCFX2_T1 -1, // doomednum S_SORCFX2T1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_ALTSHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_SORCFX3 -1, // doomednum S_SORCFX3_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_SORCERER_BISHOPSPAWN, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BISHMORPH1, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 15 * FRACUNIT, // speed 22 * FRACUNIT, // radius 65 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE, // flags MF2_NOTELEPORT // flags2 }, { // MT_SORCFX3_EXPLOSION -1, // doomednum S_SORCFX3_EXP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_ALTSHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_SORCFX4 -1, // doomednum S_SORCFX4_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_SORCFX4_D1, // deathstate S_NULL, // xdeathstate SFX_SORCERER_BALLEXPLODE, // deathsound 12 * FRACUNIT, // speed 10 * FRACUNIT, // radius 10 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_MISSILE | MF_NOGRAVITY, // flags MF2_NOTELEPORT // flags2 }, { // MT_SORCSPARK1 -1, // doomednum S_SORCSPARK1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 5 * FRACUNIT, // radius 5 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF, // flags MF2_NOTELEPORT | MF2_LOGRAV // flags2 }, { // MT_BLASTEFFECT -1, // doomednum S_BLASTEFFECT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_NOCLIP | MF_ALTSHADOW, // flags MF2_NOTELEPORT // flags2 }, { // MT_WATER_DRIP -1, // doomednum S_WATERDRIP1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_DRIP, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 1, // mass 0, // damage SFX_NONE, // activesound MF_MISSILE, // flags MF2_LOGRAV | MF2_NOTELEPORT // flags2 }, { // MT_KORAX 10200, // doomednum S_KORAX_LOOK1, // spawnstate 5000, // spawnhealth S_KORAX_CHASE2, // seestate SFX_KORAX_SIGHT, // seesound 8, // reactiontime SFX_KORAX_ATTACK, // attacksound S_KORAX_PAIN1, // painstate 20, // painchance SFX_KORAX_PAIN, // painsound S_NULL, // meleestate S_KORAX_ATTACK1, // missilestate S_NULL, // crashstate S_KORAX_DEATH1, // deathstate S_NULL, // xdeathstate SFX_KORAX_DEATH, // deathsound 10, // speed 65 * FRACUNIT, // radius 115 * FRACUNIT, // height 2000, // mass 15, // damage SFX_KORAX_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags MF2_FLOORCLIP | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP | MF2_BOSS // flags2 }, { // MT_KORAX_SPIRIT1 -1, // doomednum S_KSPIRIT_ROAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 8 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_KORAX_SPIRIT2 -1, // doomednum S_KSPIRIT_ROAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 8 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_KORAX_SPIRIT3 -1, // doomednum S_KSPIRIT_ROAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 8 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_KORAX_SPIRIT4 -1, // doomednum S_KSPIRIT_ROAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 8 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_KORAX_SPIRIT5 -1, // doomednum S_KSPIRIT_ROAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 8 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_KORAX_SPIRIT6 -1, // doomednum S_KSPIRIT_ROAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 8 * FRACUNIT, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags MF2_NOTELEPORT // flags2 }, { // MT_DEMON_MASH -1, // doomednum S_DEMN_LOOK1, // spawnstate 250, // spawnhealth S_DEMN_CHASE1, // seestate SFX_DEMON_SIGHT, // seesound 8, // reactiontime SFX_DEMON_ATTACK, // attacksound S_DEMN_PAIN1, // painstate 50, // painchance SFX_DEMON_PAIN, // painsound S_DEMN_ATK1_1, // meleestate S_DEMN_ATK2_1, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_DEMON_DEATH, // deathsound 13, // speed 32 * FRACUNIT, // radius 64 * FRACUNIT, // height 220, // mass 0, // damage SFX_DEMON_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2 }, { // MT_DEMON2_MASH -1, // doomednum S_DEMN2_LOOK1, // spawnstate 250, // spawnhealth S_DEMN2_CHASE1, // seestate SFX_DEMON_SIGHT, // seesound 8, // reactiontime SFX_DEMON_ATTACK, // attacksound S_DEMN2_PAIN1, // painstate 50, // painchance SFX_DEMON_PAIN, // painsound S_DEMN2_ATK1_1, // meleestate S_DEMN2_ATK2_1, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_DEMON_DEATH, // deathsound 13, // speed 32 * FRACUNIT, // radius 64 * FRACUNIT, // height 220, // mass 0, // damage SFX_DEMON_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2 }, { // MT_ETTIN_MASH -1, // doomednum S_ETTIN_LOOK1, // spawnstate 175, // spawnhealth S_ETTIN_CHASE1, // seestate SFX_ETTIN_SIGHT, // seesound 8, // reactiontime SFX_ETTIN_ATTACK, // attacksound S_ETTIN_PAIN1, // painstate 60, // painchance SFX_ETTIN_PAIN, // painsound S_ETTIN_ATK1_1, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_ETTIN_DEATH, // deathsound 13, // speed 25 * FRACUNIT, // radius 68 * FRACUNIT, // height 175, // mass 3, // damage SFX_ETTIN_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2 }, { // MT_CENTAUR_MASH -1, // doomednum S_CENTAUR_LOOK1, // spawnstate 200, // spawnhealth S_CENTAUR_WALK1, // seestate SFX_CENTAUR_SIGHT, // seesound 8, // reactiontime SFX_CENTAUR_ATTACK, // attacksound S_CENTAUR_PAIN1, // painstate 135, // painchance SFX_CENTAUR_PAIN, // painsound S_CENTAUR_ATK1, // meleestate 0, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_CENTAUR_DEATH, // deathsound 13, // speed 20 * FRACUNIT, // radius 64 * FRACUNIT, // height 120, // mass 0, // damage SFX_CENTAUR_ACTIVE, // activesound MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2 }, { // MT_KORAX_BOLT -1, // doomednum S_KBOLT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 15 * FRACUNIT, // radius 35 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags MF2_NOTELEPORT // flags2 }, { // MT_BAT_SPAWNER 10225, // doomednum S_SPAWNBATS1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 0, // speed 20 * FRACUNIT, // radius 16 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOSECTOR | MF_NOGRAVITY, // flags MF2_DONTDRAW // flags2 }, { // MT_BAT -1, // doomednum S_BAT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_BAT_DEATH, // deathstate S_NULL, // xdeathstate SFX_NONE, // deathsound 5 * FRACUNIT, // speed 3 * FRACUNIT, // radius 3 * FRACUNIT, // height 100, // mass 0, // damage SFX_NONE, // activesound MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags MF2_PASSMOBJ | MF2_NOTELEPORT // flags2 } }; chocolate-doom-chocolate-doom-2.2.1/src/hexen/info.h000066400000000000000000002071551257432200600223210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // generated by stateco typedef enum { SPR_MAN1, SPR_ACLO, SPR_TLGL, SPR_FBL1, SPR_XPL1, SPR_ARRW, SPR_DART, SPR_RIPP, SPR_CFCF, SPR_BLAD, SPR_SHRD, SPR_FFSM, SPR_FFLG, SPR_PTN1, SPR_PTN2, SPR_SOAR, SPR_INVU, SPR_SUMN, SPR_TSPK, SPR_TELO, SPR_TRNG, SPR_ROCK, SPR_FOGS, SPR_FOGM, SPR_FOGL, SPR_SGSA, SPR_SGSB, SPR_PORK, SPR_EGGM, SPR_FHFX, SPR_SPHL, SPR_STWN, SPR_GMPD, SPR_ASKU, SPR_ABGM, SPR_AGMR, SPR_AGMG, SPR_AGG2, SPR_AGMB, SPR_AGB2, SPR_ABK1, SPR_ABK2, SPR_ASK2, SPR_AFWP, SPR_ACWP, SPR_AMWP, SPR_AGER, SPR_AGR2, SPR_AGR3, SPR_AGR4, SPR_TRCH, SPR_PSBG, SPR_ATLP, SPR_THRW, SPR_SPED, SPR_BMAN, SPR_BRAC, SPR_BLST, SPR_HRAD, SPR_SPSH, SPR_LVAS, SPR_SLDG, SPR_STTW, SPR_RCK1, SPR_RCK2, SPR_RCK3, SPR_RCK4, SPR_CDLR, SPR_TRE1, SPR_TRDT, SPR_TRE2, SPR_TRE3, SPR_STM1, SPR_STM2, SPR_STM3, SPR_STM4, SPR_MSH1, SPR_MSH2, SPR_MSH3, SPR_MSH4, SPR_MSH5, SPR_MSH6, SPR_MSH7, SPR_MSH8, SPR_SGMP, SPR_SGM1, SPR_SGM2, SPR_SGM3, SPR_SLC1, SPR_SLC2, SPR_SLC3, SPR_MSS1, SPR_MSS2, SPR_SWMV, SPR_CPS1, SPR_CPS2, SPR_TMS1, SPR_TMS2, SPR_TMS3, SPR_TMS4, SPR_TMS5, SPR_TMS6, SPR_TMS7, SPR_CPS3, SPR_STT2, SPR_STT3, SPR_STT4, SPR_STT5, SPR_GAR1, SPR_GAR2, SPR_GAR3, SPR_GAR4, SPR_GAR5, SPR_GAR6, SPR_GAR7, SPR_GAR8, SPR_GAR9, SPR_BNR1, SPR_TRE4, SPR_TRE5, SPR_TRE6, SPR_TRE7, SPR_LOGG, SPR_ICT1, SPR_ICT2, SPR_ICT3, SPR_ICT4, SPR_ICM1, SPR_ICM2, SPR_ICM3, SPR_ICM4, SPR_RKBL, SPR_RKBS, SPR_RKBK, SPR_RBL1, SPR_RBL2, SPR_RBL3, SPR_VASE, SPR_POT1, SPR_POT2, SPR_POT3, SPR_PBIT, SPR_CPS4, SPR_CPS5, SPR_CPS6, SPR_CPB1, SPR_CPB2, SPR_CPB3, SPR_CPB4, SPR_BDRP, SPR_BDSH, SPR_BDPL, SPR_CNDL, SPR_LEF1, SPR_LEF3, SPR_LEF2, SPR_TWTR, SPR_WLTR, SPR_BARL, SPR_SHB1, SPR_SHB2, SPR_BCKT, SPR_SHRM, SPR_FBUL, SPR_FSKL, SPR_BRTR, SPR_SUIT, SPR_BBLL, SPR_CAND, SPR_IRON, SPR_XMAS, SPR_CDRN, SPR_CHNS, SPR_TST1, SPR_TST2, SPR_TST3, SPR_TST4, SPR_TST5, SPR_TST6, SPR_TST7, SPR_TST8, SPR_TST9, SPR_TST0, SPR_TELE, SPR_TSMK, SPR_FPCH, SPR_WFAX, SPR_FAXE, SPR_WFHM, SPR_FHMR, SPR_FSRD, SPR_FSFX, SPR_CMCE, SPR_WCSS, SPR_CSSF, SPR_WCFM, SPR_CFLM, SPR_CFFX, SPR_CHLY, SPR_SPIR, SPR_MWND, SPR_WMLG, SPR_MLNG, SPR_MLFX, SPR_MLF2, SPR_MSTF, SPR_MSP1, SPR_MSP2, SPR_WFR1, SPR_WFR2, SPR_WFR3, SPR_WCH1, SPR_WCH2, SPR_WCH3, SPR_WMS1, SPR_WMS2, SPR_WMS3, SPR_WPIG, SPR_WMCS, SPR_CONE, SPR_SHEX, SPR_BLOD, SPR_GIBS, SPR_PLAY, SPR_FDTH, SPR_BSKL, SPR_ICEC, SPR_CLER, SPR_MAGE, SPR_PIGY, SPR_CENT, SPR_CTXD, SPR_CTFX, SPR_CTDP, SPR_DEMN, SPR_DEMA, SPR_DEMB, SPR_DEMC, SPR_DEMD, SPR_DEME, SPR_DMFX, SPR_DEM2, SPR_DMBA, SPR_DMBB, SPR_DMBC, SPR_DMBD, SPR_DMBE, SPR_D2FX, SPR_WRTH, SPR_WRT2, SPR_WRBL, SPR_MNTR, SPR_FX12, SPR_FX13, SPR_MNSM, SPR_SSPT, SPR_SSDV, SPR_SSXD, SPR_SSFX, SPR_BISH, SPR_BPFX, SPR_DRAG, SPR_DRFX, SPR_ARM1, SPR_ARM2, SPR_ARM3, SPR_ARM4, SPR_MAN2, SPR_MAN3, SPR_KEY1, SPR_KEY2, SPR_KEY3, SPR_KEY4, SPR_KEY5, SPR_KEY6, SPR_KEY7, SPR_KEY8, SPR_KEY9, SPR_KEYA, SPR_KEYB, SPR_ETTN, SPR_ETTB, SPR_FDMN, SPR_FDMB, SPR_ICEY, SPR_ICPR, SPR_ICWS, SPR_SORC, SPR_SBMP, SPR_SBS4, SPR_SBMB, SPR_SBS3, SPR_SBMG, SPR_SBS1, SPR_SBS2, SPR_SBFX, SPR_RADE, SPR_WATR, SPR_KORX, SPR_ABAT, NUMSPRITES } spritenum_t; typedef enum { S_NULL, S_FREETARGMOBJ, S_MAPSPOT, S_FIREBALL1_1, S_FIREBALL1_2, S_FIREBALL1_X1, S_FIREBALL1_X2, S_FIREBALL1_X3, S_FIREBALL1_X4, S_FIREBALL1_X5, S_FIREBALL1_X6, S_ARROW_1, S_ARROW_X1, S_DART_1, S_DART_X1, S_POISONDART_1, S_POISONDART_X1, S_RIPPERBALL_1, S_RIPPERBALL_2, S_RIPPERBALL_3, S_RIPPERBALL_X1, S_RIPPERBALL_X2, S_RIPPERBALL_X3, S_RIPPERBALL_X4, S_RIPPERBALL_X5, S_RIPPERBALL_X6, S_RIPPERBALL_X7, S_RIPPERBALL_X8, S_RIPPERBALL_X9, S_RIPPERBALL_X10, S_PRJ_BLADE1, S_PRJ_BLADE_X1, S_ICESHARD1, S_ICESHARD2, S_ICESHARD3, S_FLAME_TSMALL1, S_FLAME_TSMALL2, S_FLAME_TSMALL3, S_FLAME_TSMALL4, S_FLAME_TSMALL5, S_FLAME_TSMALL6, S_FLAME_TLARGE1, S_FLAME_TLARGE2, S_FLAME_TLARGE3, S_FLAME_TLARGE4, S_FLAME_TLARGE5, S_FLAME_TLARGE6, S_FLAME_TLARGE7, S_FLAME_TLARGE8, S_FLAME_TLARGE9, S_FLAME_TLARGE10, S_FLAME_TLARGE11, S_FLAME_TLARGE12, S_FLAME_TLARGE13, S_FLAME_TLARGE14, S_FLAME_TLARGE15, S_FLAME_TLARGE16, S_FLAME_SDORM1, S_FLAME_SDORM2, S_FLAME_SDORM3, S_FLAME_SMALL1, S_FLAME_SMALL2, S_FLAME_SMALL3, S_FLAME_SMALL4, S_FLAME_SMALL5, S_FLAME_SMALL6, S_FLAME_SMALL7, S_FLAME_LDORM1, S_FLAME_LDORM2, S_FLAME_LDORM3, S_FLAME_LDORM4, S_FLAME_LDORM5, S_FLAME_LARGE1, S_FLAME_LARGE2, S_FLAME_LARGE3, S_FLAME_LARGE4, S_FLAME_LARGE5, S_FLAME_LARGE6, S_FLAME_LARGE7, S_FLAME_LARGE8, S_FLAME_LARGE9, S_FLAME_LARGE10, S_FLAME_LARGE11, S_FLAME_LARGE12, S_FLAME_LARGE13, S_FLAME_LARGE14, S_FLAME_LARGE15, S_FLAME_LARGE16, S_FLAME_LARGE17, S_FLAME_LARGE18, S_ITEM_PTN1_1, S_ITEM_PTN1_2, S_ITEM_PTN1_3, S_HIDESPECIAL1, S_HIDESPECIAL2, S_HIDESPECIAL3, S_HIDESPECIAL4, S_HIDESPECIAL5, S_HIDESPECIAL6, S_HIDESPECIAL7, S_HIDESPECIAL8, S_HIDESPECIAL9, S_HIDESPECIAL10, S_HIDESPECIAL11, S_DORMANTARTI1_1, S_DORMANTARTI1_2, S_DORMANTARTI1_3, S_DORMANTARTI1_4, S_DORMANTARTI1_5, S_DORMANTARTI1_6, S_DORMANTARTI1_7, S_DORMANTARTI1_8, S_DORMANTARTI1_9, S_DORMANTARTI1_10, S_DORMANTARTI1_11, S_DORMANTARTI1_12, S_DORMANTARTI1_13, S_DORMANTARTI1_14, S_DORMANTARTI1_15, S_DORMANTARTI1_16, S_DORMANTARTI1_17, S_DORMANTARTI1_18, S_DORMANTARTI1_19, S_DORMANTARTI1_20, S_DORMANTARTI1_21, S_DORMANTARTI2_1, S_DORMANTARTI2_2, S_DORMANTARTI2_3, S_DORMANTARTI2_4, S_DORMANTARTI2_5, S_DORMANTARTI2_6, S_DORMANTARTI2_7, S_DORMANTARTI2_8, S_DORMANTARTI2_9, S_DORMANTARTI2_10, S_DORMANTARTI2_11, S_DORMANTARTI2_12, S_DORMANTARTI2_13, S_DORMANTARTI2_14, S_DORMANTARTI2_15, S_DORMANTARTI2_16, S_DORMANTARTI2_17, S_DORMANTARTI2_18, S_DORMANTARTI2_19, S_DORMANTARTI2_20, S_DORMANTARTI2_21, S_DORMANTARTI3_1, S_DORMANTARTI3_2, S_DORMANTARTI3_3, S_DORMANTARTI3_4, S_DORMANTARTI3_5, S_DORMANTARTI3_6, S_DORMANTARTI3_7, S_DORMANTARTI3_8, S_DORMANTARTI3_9, S_DORMANTARTI3_10, S_DORMANTARTI3_11, S_DORMANTARTI3_12, S_DORMANTARTI3_13, S_DORMANTARTI3_14, S_DORMANTARTI3_15, S_DORMANTARTI3_16, S_DORMANTARTI3_17, S_DORMANTARTI3_18, S_DORMANTARTI3_19, S_DORMANTARTI3_20, S_DORMANTARTI3_21, S_DEADARTI1, S_DEADARTI2, S_DEADARTI3, S_DEADARTI4, S_DEADARTI5, S_DEADARTI6, S_DEADARTI7, S_DEADARTI8, S_DEADARTI9, S_DEADARTI10, S_ARTI_PTN2_1, S_ARTI_PTN2_2, S_ARTI_PTN2_3, S_ARTI_SOAR1, S_ARTI_SOAR2, S_ARTI_SOAR3, S_ARTI_SOAR4, S_ARTI_INVU1, S_ARTI_INVU2, S_ARTI_INVU3, S_ARTI_INVU4, S_ARTI_SUMMON, S_SUMMON_FX1_1, S_SUMMON_FX2_1, S_SUMMON_FX2_2, S_SUMMON_FX2_3, S_THRUSTINIT2_1, S_THRUSTINIT2_2, S_BTHRUSTINIT2_1, S_BTHRUSTINIT2_2, S_THRUSTINIT1_1, S_THRUSTINIT1_2, S_BTHRUSTINIT1_1, S_BTHRUSTINIT1_2, S_THRUSTRAISE1, S_THRUSTRAISE2, S_THRUSTRAISE3, S_THRUSTRAISE4, S_BTHRUSTRAISE1, S_BTHRUSTRAISE2, S_BTHRUSTRAISE3, S_BTHRUSTRAISE4, S_THRUSTIMPALE, S_BTHRUSTIMPALE, S_THRUSTRAISE, S_BTHRUSTRAISE, S_THRUSTBLOCK, S_BTHRUSTBLOCK, S_THRUSTLOWER, S_BTHRUSTLOWER, S_THRUSTSTAY, S_BTHRUSTSTAY, S_ARTI_TELOTHER1, S_ARTI_TELOTHER2, S_ARTI_TELOTHER3, S_ARTI_TELOTHER4, S_TELO_FX1, S_TELO_FX2, S_TELO_FX3, S_TELO_FX4, S_TELO_FX5, S_TELO_FX6, S_TELO_FX7, S_TELO_FX8, S_TELO_FX9, S_TELO_FX2_1, S_TELO_FX2_2, S_TELO_FX2_3, S_TELO_FX2_4, S_TELO_FX2_5, S_TELO_FX2_6, S_TELO_FX3_1, S_TELO_FX3_2, S_TELO_FX3_3, S_TELO_FX3_4, S_TELO_FX3_5, S_TELO_FX3_6, S_TELO_FX4_1, S_TELO_FX4_2, S_TELO_FX4_3, S_TELO_FX4_4, S_TELO_FX4_5, S_TELO_FX4_6, S_TELO_FX5_1, S_TELO_FX5_2, S_TELO_FX5_3, S_TELO_FX5_4, S_TELO_FX5_5, S_TELO_FX5_6, S_DIRT1_1, S_DIRT1_D, S_DIRT2_1, S_DIRT2_D, S_DIRT3_1, S_DIRT3_D, S_DIRT4_1, S_DIRT4_D, S_DIRT5_1, S_DIRT5_D, S_DIRT6_1, S_DIRT6_D, S_DIRTCLUMP1, S_ROCK1_1, S_ROCK1_D, S_ROCK2_1, S_ROCK2_D, S_ROCK3_1, S_ROCK3_D, S_SPAWNFOG1, S_FOGPATCHS1, S_FOGPATCHS2, S_FOGPATCHS3, S_FOGPATCHS4, S_FOGPATCHS5, S_FOGPATCHS0, S_FOGPATCHM1, S_FOGPATCHM2, S_FOGPATCHM3, S_FOGPATCHM4, S_FOGPATCHM5, S_FOGPATCHM0, S_FOGPATCHMA, S_FOGPATCHMB, S_FOGPATCHMC, S_FOGPATCHMD, S_FOGPATCHL1, S_FOGPATCHL2, S_FOGPATCHL3, S_FOGPATCHL4, S_FOGPATCHL5, S_FOGPATCHL0, S_FOGPATCHLA, S_FOGPATCHLB, S_FOGPATCHLC, S_FOGPATCHLD, S_QUAKE_ACTIVE1, S_QUAKE_ACTIVE2, S_QUAKE_ACTIVE3, S_QUAKE_ACTIVE4, S_QUAKE_ACTIVE5, S_QUAKE_ACTIVE6, S_QUAKE_ACTIVE7, S_QUAKE_ACTIVE8, S_QUAKE_ACTIVE9, S_QUAKE_ACTIVE0, S_QUAKE_ACTIVEA, S_QUAKE_ACTIVEB, S_QUAKE_ACTIVEC, S_QUAKE_ACTIVED, S_QUAKE_ACTIVEE, S_QUAKE_ACTIVEF, S_QUAKE_ACTIVEG, S_QUAKE_ACTIVEH, S_QUAKE_ACTIVEI, S_QUAKE_ACTIVEJ, S_QUAKE_ACTIVEK, S_QUAKE_ACTIVEL, S_QUAKE_ACTIVEM, S_QUAKE_ACTIVEN, S_QUAKE_ACTIVEO, S_QUAKE_ACTIVEP, S_QUAKE_ACTIVEQ, S_QUAKE_ACTIVER, S_QUAKE_ACTIVES, S_QUAKE_ACTIVET, S_QUAKE_ACTIVEU, S_QUAKE_ACTIVEV, S_QUAKE_ACTIVEW, S_QUAKE_ACTIVEX, S_QUAKE_ACTIVEY, S_QUAKE_ACTIVEZ, S_QUAKE_ACT1, S_QUAKE_ACT2, S_QUAKE_ACT3, S_QUAKE_ACT4, S_QUAKE_ACT5, S_QUAKE_ACT6, S_QUAKE_ACT7, S_QUAKE_ACT8, S_QUAKE_ACT9, S_QUAKE_ACT0, S_SGSHARD1_1, S_SGSHARD1_2, S_SGSHARD1_3, S_SGSHARD1_4, S_SGSHARD1_5, S_SGSHARD1_D, S_SGSHARD2_1, S_SGSHARD2_2, S_SGSHARD2_3, S_SGSHARD2_4, S_SGSHARD2_5, S_SGSHARD2_D, S_SGSHARD3_1, S_SGSHARD3_2, S_SGSHARD3_3, S_SGSHARD3_4, S_SGSHARD3_5, S_SGSHARD3_D, S_SGSHARD4_1, S_SGSHARD4_2, S_SGSHARD4_3, S_SGSHARD4_4, S_SGSHARD4_5, S_SGSHARD4_D, S_SGSHARD5_1, S_SGSHARD5_2, S_SGSHARD5_3, S_SGSHARD5_4, S_SGSHARD5_5, S_SGSHARD5_D, S_SGSHARD6_1, S_SGSHARD6_D, S_SGSHARD7_1, S_SGSHARD7_D, S_SGSHARD8_1, S_SGSHARD8_D, S_SGSHARD9_1, S_SGSHARD9_D, S_SGSHARD0_1, S_SGSHARD0_D, S_ARTI_EGGC1, S_ARTI_EGGC2, S_ARTI_EGGC3, S_ARTI_EGGC4, S_ARTI_EGGC5, S_ARTI_EGGC6, S_ARTI_EGGC7, S_ARTI_EGGC8, S_EGGFX1, S_EGGFX2, S_EGGFX3, S_EGGFX4, S_EGGFX5, S_EGGFXI1_1, S_EGGFXI1_2, S_EGGFXI1_3, S_EGGFXI1_4, S_ARTI_SPHL1, S_ZWINGEDSTATUENOSKULL, S_ZWINGEDSTATUENOSKULL2, S_ZGEMPEDESTAL1, S_ZGEMPEDESTAL2, S_ARTIPUZZSKULL, S_ARTIPUZZGEMBIG, S_ARTIPUZZGEMRED, S_ARTIPUZZGEMGREEN1, S_ARTIPUZZGEMGREEN2, S_ARTIPUZZGEMBLUE1, S_ARTIPUZZGEMBLUE2, S_ARTIPUZZBOOK1, S_ARTIPUZZBOOK2, S_ARTIPUZZSKULL2, S_ARTIPUZZFWEAPON, S_ARTIPUZZCWEAPON, S_ARTIPUZZMWEAPON, S_ARTIPUZZGEAR_1, S_ARTIPUZZGEAR_2, S_ARTIPUZZGEAR_3, S_ARTIPUZZGEAR_4, S_ARTIPUZZGEAR_5, S_ARTIPUZZGEAR_6, S_ARTIPUZZGEAR_7, S_ARTIPUZZGEAR_8, S_ARTIPUZZGEAR2_1, S_ARTIPUZZGEAR2_2, S_ARTIPUZZGEAR2_3, S_ARTIPUZZGEAR2_4, S_ARTIPUZZGEAR2_5, S_ARTIPUZZGEAR2_6, S_ARTIPUZZGEAR2_7, S_ARTIPUZZGEAR2_8, S_ARTIPUZZGEAR3_1, S_ARTIPUZZGEAR3_2, S_ARTIPUZZGEAR3_3, S_ARTIPUZZGEAR3_4, S_ARTIPUZZGEAR3_5, S_ARTIPUZZGEAR3_6, S_ARTIPUZZGEAR3_7, S_ARTIPUZZGEAR3_8, S_ARTIPUZZGEAR4_1, S_ARTIPUZZGEAR4_2, S_ARTIPUZZGEAR4_3, S_ARTIPUZZGEAR4_4, S_ARTIPUZZGEAR4_5, S_ARTIPUZZGEAR4_6, S_ARTIPUZZGEAR4_7, S_ARTIPUZZGEAR4_8, S_ARTI_TRCH1, S_ARTI_TRCH2, S_ARTI_TRCH3, S_FIREBOMB1, S_FIREBOMB2, S_FIREBOMB3, S_FIREBOMB4, S_FIREBOMB5, S_FIREBOMB6, S_FIREBOMB7, S_FIREBOMB8, S_FIREBOMB9, S_FIREBOMB10, S_FIREBOMB11, S_ARTI_ATLP1, S_ARTI_ATLP2, S_ARTI_ATLP3, S_ARTI_ATLP4, S_ARTI_PSBG1, S_POISONBAG1, S_POISONBAG2, S_POISONBAG3, S_POISONBAG4, S_POISONCLOUD1, S_POISONCLOUD2, S_POISONCLOUD3, S_POISONCLOUD4, S_POISONCLOUD5, S_POISONCLOUD6, S_POISONCLOUD7, S_POISONCLOUD8, S_POISONCLOUD9, S_POISONCLOUD10, S_POISONCLOUD11, S_POISONCLOUD12, S_POISONCLOUD13, S_POISONCLOUD14, S_POISONCLOUD15, S_POISONCLOUD16, S_POISONCLOUD17, S_POISONCLOUD18, S_POISONCLOUD_X1, S_POISONCLOUD_X2, S_POISONCLOUD_X3, S_POISONCLOUD_X4, S_THROWINGBOMB1, S_THROWINGBOMB2, S_THROWINGBOMB3, S_THROWINGBOMB4, S_THROWINGBOMB5, S_THROWINGBOMB6, S_THROWINGBOMB7, S_THROWINGBOMB8, S_THROWINGBOMB9, S_THROWINGBOMB10, S_THROWINGBOMB11, S_THROWINGBOMB12, S_THROWINGBOMB_X1, S_THROWINGBOMB_X2, S_THROWINGBOMB_X3, S_THROWINGBOMB_X4, S_THROWINGBOMB_X5, S_THROWINGBOMB_X6, S_THROWINGBOMB_X7, S_THROWINGBOMB_X8, S_ARTI_BOOTS1, S_ARTI_BOOTS2, S_ARTI_BOOTS3, S_ARTI_BOOTS4, S_ARTI_BOOTS5, S_ARTI_BOOTS6, S_ARTI_BOOTS7, S_ARTI_BOOTS8, S_ARTI_MANA, S_ARTI_ARMOR1, S_ARTI_ARMOR2, S_ARTI_ARMOR3, S_ARTI_ARMOR4, S_ARTI_ARMOR5, S_ARTI_ARMOR6, S_ARTI_ARMOR7, S_ARTI_ARMOR8, S_ARTI_BLAST1, S_ARTI_BLAST2, S_ARTI_BLAST3, S_ARTI_BLAST4, S_ARTI_BLAST5, S_ARTI_BLAST6, S_ARTI_BLAST7, S_ARTI_BLAST8, S_ARTI_HEALRAD1, S_ARTI_HEALRAD2, S_ARTI_HEALRAD3, S_ARTI_HEALRAD4, S_ARTI_HEALRAD5, S_ARTI_HEALRAD6, S_ARTI_HEALRAD7, S_ARTI_HEALRAD8, S_ARTI_HEALRAD9, S_ARTI_HEALRAD0, S_ARTI_HEALRADA, S_ARTI_HEALRADB, S_ARTI_HEALRADC, S_ARTI_HEALRADD, S_ARTI_HEALRADE, S_ARTI_HEALRADF, S_SPLASH1, S_SPLASH2, S_SPLASH3, S_SPLASH4, S_SPLASHX, S_SPLASHBASE1, S_SPLASHBASE2, S_SPLASHBASE3, S_SPLASHBASE4, S_SPLASHBASE5, S_SPLASHBASE6, S_SPLASHBASE7, S_LAVASPLASH1, S_LAVASPLASH2, S_LAVASPLASH3, S_LAVASPLASH4, S_LAVASPLASH5, S_LAVASPLASH6, S_LAVASMOKE1, S_LAVASMOKE2, S_LAVASMOKE3, S_LAVASMOKE4, S_LAVASMOKE5, S_SLUDGECHUNK1, S_SLUDGECHUNK2, S_SLUDGECHUNK3, S_SLUDGECHUNK4, S_SLUDGECHUNKX, S_SLUDGESPLASH1, S_SLUDGESPLASH2, S_SLUDGESPLASH3, S_SLUDGESPLASH4, S_ZWINGEDSTATUE1, S_ZROCK1_1, S_ZROCK2_1, S_ZROCK3_1, S_ZROCK4_1, S_ZCHANDELIER1, S_ZCHANDELIER2, S_ZCHANDELIER3, S_ZCHANDELIER_U, S_ZTREEDEAD1, S_ZTREE, S_ZTREEDESTRUCTIBLE1, S_ZTREEDES_D1, S_ZTREEDES_D2, S_ZTREEDES_D3, S_ZTREEDES_D4, S_ZTREEDES_D5, S_ZTREEDES_D6, S_ZTREEDES_X1, S_ZTREEDES_X2, S_ZTREEDES_X3, S_ZTREEDES_X4, S_ZTREEDES_X5, S_ZTREEDES_X6, S_ZTREEDES_X7, S_ZTREEDES_X8, S_ZTREEDES_X9, S_ZTREEDES_X10, S_ZTREESWAMP182_1, S_ZTREESWAMP172_1, S_ZSTUMPBURNED1, S_ZSTUMPBARE1, S_ZSTUMPSWAMP1_1, S_ZSTUMPSWAMP2_1, S_ZSHROOMLARGE1_1, S_ZSHROOMLARGE2_1, S_ZSHROOMLARGE3_1, S_ZSHROOMSMALL1_1, S_ZSHROOMSMALL2_1, S_ZSHROOMSMALL3_1, S_ZSHROOMSMALL4_1, S_ZSHROOMSMALL5_1, S_ZSTALAGMITEPILLAR1, S_ZSTALAGMITELARGE1, S_ZSTALAGMITEMEDIUM1, S_ZSTALAGMITESMALL1, S_ZSTALACTITELARGE1, S_ZSTALACTITEMEDIUM1, S_ZSTALACTITESMALL1, S_ZMOSSCEILING1_1, S_ZMOSSCEILING2_1, S_ZSWAMPVINE1, S_ZCORPSEKABOB1, S_ZCORPSESLEEPING1, S_ZTOMBSTONERIP1, S_ZTOMBSTONESHANE1, S_ZTOMBSTONEBIGCROSS1, S_ZTOMBSTONEBRIANR1, S_ZTOMBSTONECROSSCIRCLE1, S_ZTOMBSTONESMALLCROSS1, S_ZTOMBSTONEBRIANP1, S_CORPSEHANGING_1, S_ZSTATUEGARGOYLEGREENTALL_1, S_ZSTATUEGARGOYLEBLUETALL_1, S_ZSTATUEGARGOYLEGREENSHORT_1, S_ZSTATUEGARGOYLEBLUESHORT_1, S_ZSTATUEGARGOYLESTRIPETALL_1, S_ZSTATUEGARGOYLEDARKREDTALL_1, S_ZSTATUEGARGOYLEREDTALL_1, S_ZSTATUEGARGOYLETANTALL_1, S_ZSTATUEGARGOYLERUSTTALL_1, S_ZSTATUEGARGOYLEDARKREDSHORT_1, S_ZSTATUEGARGOYLEREDSHORT_1, S_ZSTATUEGARGOYLETANSHORT_1, S_ZSTATUEGARGOYLERUSTSHORT_1, S_ZBANNERTATTERED_1, S_ZTREELARGE1, S_ZTREELARGE2, S_ZTREEGNARLED1, S_ZTREEGNARLED2, S_ZLOG, S_ZSTALACTITEICELARGE, S_ZSTALACTITEICEMEDIUM, S_ZSTALACTITEICESMALL, S_ZSTALACTITEICETINY, S_ZSTALAGMITEICELARGE, S_ZSTALAGMITEICEMEDIUM, S_ZSTALAGMITEICESMALL, S_ZSTALAGMITEICETINY, S_ZROCKBROWN1, S_ZROCKBROWN2, S_ZROCKBLACK, S_ZRUBBLE1, S_ZRUBBLE2, S_ZRUBBLE3, S_ZVASEPILLAR, S_ZPOTTERY1, S_ZPOTTERY2, S_ZPOTTERY3, S_ZPOTTERY_EXPLODE, S_POTTERYBIT_1, S_POTTERYBIT_2, S_POTTERYBIT_3, S_POTTERYBIT_4, S_POTTERYBIT_5, S_POTTERYBIT_EX0, S_POTTERYBIT_EX1, S_POTTERYBIT_EX1_2, S_POTTERYBIT_EX2, S_POTTERYBIT_EX2_2, S_POTTERYBIT_EX3, S_POTTERYBIT_EX3_2, S_POTTERYBIT_EX4, S_POTTERYBIT_EX4_2, S_POTTERYBIT_EX5, S_POTTERYBIT_EX5_2, S_ZCORPSELYNCHED1, S_ZCORPSELYNCHED2, S_ZCORPSESITTING, S_ZCORPSESITTING_X, S_CORPSEBIT_1, S_CORPSEBIT_2, S_CORPSEBIT_3, S_CORPSEBIT_4, S_CORPSEBLOODDRIP, S_CORPSEBLOODDRIP_X1, S_CORPSEBLOODDRIP_X2, S_CORPSEBLOODDRIP_X3, S_CORPSEBLOODDRIP_X4, S_BLOODPOOL, S_ZCANDLE1, S_ZCANDLE2, S_ZCANDLE3, S_ZLEAFSPAWNER, S_LEAF1_1, S_LEAF1_2, S_LEAF1_3, S_LEAF1_4, S_LEAF1_5, S_LEAF1_6, S_LEAF1_7, S_LEAF1_8, S_LEAF1_9, S_LEAF1_10, S_LEAF1_11, S_LEAF1_12, S_LEAF1_13, S_LEAF1_14, S_LEAF1_15, S_LEAF1_16, S_LEAF1_17, S_LEAF1_18, S_LEAF_X1, S_LEAF2_1, S_LEAF2_2, S_LEAF2_3, S_LEAF2_4, S_LEAF2_5, S_LEAF2_6, S_LEAF2_7, S_LEAF2_8, S_LEAF2_9, S_LEAF2_10, S_LEAF2_11, S_LEAF2_12, S_LEAF2_13, S_LEAF2_14, S_LEAF2_15, S_LEAF2_16, S_LEAF2_17, S_LEAF2_18, S_ZTWINEDTORCH_1, S_ZTWINEDTORCH_2, S_ZTWINEDTORCH_3, S_ZTWINEDTORCH_4, S_ZTWINEDTORCH_5, S_ZTWINEDTORCH_6, S_ZTWINEDTORCH_7, S_ZTWINEDTORCH_8, S_ZTWINEDTORCH_UNLIT, S_BRIDGE1, S_BRIDGE2, S_BRIDGE3, S_FREE_BRIDGE1, S_FREE_BRIDGE2, S_BBALL1, S_BBALL2, S_ZWALLTORCH1, S_ZWALLTORCH2, S_ZWALLTORCH3, S_ZWALLTORCH4, S_ZWALLTORCH5, S_ZWALLTORCH6, S_ZWALLTORCH7, S_ZWALLTORCH8, S_ZWALLTORCH_U, S_ZBARREL1, S_ZSHRUB1, S_ZSHRUB1_DIE, S_ZSHRUB1_X1, S_ZSHRUB1_X2, S_ZSHRUB1_X3, S_ZSHRUB2, S_ZSHRUB2_DIE, S_ZSHRUB2_X1, S_ZSHRUB2_X2, S_ZSHRUB2_X3, S_ZSHRUB2_X4, S_ZBUCKET1, S_ZPOISONSHROOM1, S_ZPOISONSHROOM_P1, S_ZPOISONSHROOM_P2, S_ZPOISONSHROOM_X1, S_ZPOISONSHROOM_X2, S_ZPOISONSHROOM_X3, S_ZPOISONSHROOM_X4, S_ZFIREBULL1, S_ZFIREBULL2, S_ZFIREBULL3, S_ZFIREBULL4, S_ZFIREBULL5, S_ZFIREBULL6, S_ZFIREBULL7, S_ZFIREBULL_DEATH, S_ZFIREBULL_DEATH2, S_ZFIREBULL_U, S_ZFIREBULL_BIRTH, S_ZFIREBULL_BIRTH2, S_ZFIRETHING1, S_ZFIRETHING2, S_ZFIRETHING3, S_ZFIRETHING4, S_ZFIRETHING5, S_ZFIRETHING6, S_ZFIRETHING7, S_ZFIRETHING8, S_ZFIRETHING9, S_ZBRASSTORCH1, S_ZBRASSTORCH2, S_ZBRASSTORCH3, S_ZBRASSTORCH4, S_ZBRASSTORCH5, S_ZBRASSTORCH6, S_ZBRASSTORCH7, S_ZBRASSTORCH8, S_ZBRASSTORCH9, S_ZBRASSTORCH10, S_ZBRASSTORCH11, S_ZBRASSTORCH12, S_ZBRASSTORCH13, S_ZSUITOFARMOR, S_ZSUITOFARMOR_X1, S_ZARMORCHUNK1, S_ZARMORCHUNK2, S_ZARMORCHUNK3, S_ZARMORCHUNK4, S_ZARMORCHUNK5, S_ZARMORCHUNK6, S_ZARMORCHUNK7, S_ZARMORCHUNK8, S_ZARMORCHUNK9, S_ZARMORCHUNK10, S_ZBELL, S_ZBELL_X1, S_ZBELL_X2, S_ZBELL_X3, S_ZBELL_X4, S_ZBELL_X5, S_ZBELL_X6, S_ZBELL_X7, S_ZBELL_X8, S_ZBELL_X9, S_ZBELL_X10, S_ZBELL_X11, S_ZBELL_X12, S_ZBELL_X13, S_ZBELL_X14, S_ZBELL_X15, S_ZBELL_X16, S_ZBELL_X17, S_ZBELL_X18, S_ZBELL_X19, S_ZBELL_X20, S_ZBELL_X21, S_ZBELL_X22, S_ZBELL_X23, S_ZBELL_X24, S_ZBELL_X25, S_ZBELL_X26, S_ZBELL_X27, S_ZBELL_X28, S_ZBELL_X29, S_ZBELL_X30, S_ZBELL_X31, S_ZBELL_X32, S_ZBELL_X33, S_ZBELL_X34, S_ZBELL_X35, S_ZBELL_X36, S_ZBELL_X37, S_ZBELL_X38, S_ZBELL_X39, S_ZBELL_X40, S_ZBELL_X41, S_ZBELL_X42, S_ZBELL_X43, S_ZBELL_X44, S_ZBELL_X45, S_ZBELL_X46, S_ZBELL_X47, S_ZBLUE_CANDLE1, S_ZBLUE_CANDLE2, S_ZBLUE_CANDLE3, S_ZBLUE_CANDLE4, S_ZBLUE_CANDLE5, S_ZIRON_MAIDEN, S_ZXMAS_TREE, S_ZXMAS_TREE_DIE, S_ZXMAS_TREE_X1, S_ZXMAS_TREE_X2, S_ZXMAS_TREE_X3, S_ZXMAS_TREE_X4, S_ZXMAS_TREE_X5, S_ZXMAS_TREE_X6, S_ZXMAS_TREE_X7, S_ZXMAS_TREE_X8, S_ZXMAS_TREE_X9, S_ZXMAS_TREE_X10, S_ZCAULDRON1, S_ZCAULDRON2, S_ZCAULDRON3, S_ZCAULDRON4, S_ZCAULDRON5, S_ZCAULDRON6, S_ZCAULDRON7, S_ZCAULDRON_U, S_ZCHAINBIT32, S_ZCHAINBIT64, S_ZCHAINEND_HEART, S_ZCHAINEND_HOOK1, S_ZCHAINEND_HOOK2, S_ZCHAINEND_SPIKE, S_ZCHAINEND_SKULL, S_TABLE_SHIT1, S_TABLE_SHIT2, S_TABLE_SHIT3, S_TABLE_SHIT4, S_TABLE_SHIT5, S_TABLE_SHIT6, S_TABLE_SHIT7, S_TABLE_SHIT8, S_TABLE_SHIT9, S_TABLE_SHIT10, S_TFOG1, S_TFOG2, S_TFOG3, S_TFOG4, S_TFOG5, S_TFOG6, S_TFOG7, S_TFOG8, S_TFOG9, S_TFOG10, S_TFOG11, S_TFOG12, S_TFOG13, S_TELESMOKE1, S_TELESMOKE2, S_TELESMOKE3, S_TELESMOKE4, S_TELESMOKE5, S_TELESMOKE6, S_TELESMOKE7, S_TELESMOKE8, S_TELESMOKE9, S_TELESMOKE10, S_TELESMOKE11, S_TELESMOKE12, S_TELESMOKE13, S_TELESMOKE14, S_TELESMOKE15, S_TELESMOKE16, S_TELESMOKE17, S_TELESMOKE18, S_TELESMOKE19, S_TELESMOKE20, S_TELESMOKE21, S_TELESMOKE22, S_TELESMOKE23, S_TELESMOKE24, S_TELESMOKE25, S_TELESMOKE26, S_LIGHTDONE, S_PUNCHREADY, S_PUNCHDOWN, S_PUNCHUP, S_PUNCHATK1_1, S_PUNCHATK1_2, S_PUNCHATK1_3, S_PUNCHATK1_4, S_PUNCHATK1_5, S_PUNCHATK2_1, S_PUNCHATK2_2, S_PUNCHATK2_3, S_PUNCHATK2_4, S_PUNCHATK2_5, S_PUNCHATK2_6, S_PUNCHATK2_7, S_PUNCHATK2_8, S_PUNCHATK2_9, S_PUNCHPUFF1, S_PUNCHPUFF2, S_PUNCHPUFF3, S_PUNCHPUFF4, S_PUNCHPUFF5, S_AXE, S_FAXEREADY, S_FAXEDOWN, S_FAXEUP, S_FAXEATK_1, S_FAXEATK_2, S_FAXEATK_3, S_FAXEATK_4, S_FAXEATK_5, S_FAXEATK_6, S_FAXEATK_7, S_FAXEATK_8, S_FAXEATK_9, S_FAXEATK_10, S_FAXEATK_11, S_FAXEATK_12, S_FAXEATK_13, S_FAXEREADY_G, S_FAXEREADY_G1, S_FAXEREADY_G2, S_FAXEREADY_G3, S_FAXEREADY_G4, S_FAXEREADY_G5, S_FAXEDOWN_G, S_FAXEUP_G, S_FAXEATK_G1, S_FAXEATK_G2, S_FAXEATK_G3, S_FAXEATK_G4, S_FAXEATK_G5, S_FAXEATK_G6, S_FAXEATK_G7, S_FAXEATK_G8, S_FAXEATK_G9, S_FAXEATK_G10, S_FAXEATK_G11, S_FAXEATK_G12, S_FAXEATK_G13, S_AXEPUFF_GLOW1, S_AXEPUFF_GLOW2, S_AXEPUFF_GLOW3, S_AXEPUFF_GLOW4, S_AXEPUFF_GLOW5, S_AXEPUFF_GLOW6, S_AXEPUFF_GLOW7, S_AXEBLOOD1, S_AXEBLOOD2, S_AXEBLOOD3, S_AXEBLOOD4, S_AXEBLOOD5, S_AXEBLOOD6, S_HAMM, S_FHAMMERREADY, S_FHAMMERDOWN, S_FHAMMERUP, S_FHAMMERATK_1, S_FHAMMERATK_2, S_FHAMMERATK_3, S_FHAMMERATK_4, S_FHAMMERATK_5, S_FHAMMERATK_6, S_FHAMMERATK_7, S_FHAMMERATK_8, S_FHAMMERATK_9, S_FHAMMERATK_10, S_FHAMMERATK_11, S_FHAMMERATK_12, S_HAMMER_MISSILE_1, S_HAMMER_MISSILE_2, S_HAMMER_MISSILE_3, S_HAMMER_MISSILE_4, S_HAMMER_MISSILE_5, S_HAMMER_MISSILE_6, S_HAMMER_MISSILE_7, S_HAMMER_MISSILE_8, S_HAMMER_MISSILE_X1, S_HAMMER_MISSILE_X2, S_HAMMER_MISSILE_X3, S_HAMMER_MISSILE_X4, S_HAMMER_MISSILE_X5, S_HAMMER_MISSILE_X6, S_HAMMER_MISSILE_X7, S_HAMMER_MISSILE_X8, S_HAMMER_MISSILE_X9, S_HAMMER_MISSILE_X10, S_HAMMERPUFF1, S_HAMMERPUFF2, S_HAMMERPUFF3, S_HAMMERPUFF4, S_HAMMERPUFF5, S_FSWORDREADY, S_FSWORDREADY1, S_FSWORDREADY2, S_FSWORDREADY3, S_FSWORDREADY4, S_FSWORDREADY5, S_FSWORDREADY6, S_FSWORDREADY7, S_FSWORDREADY8, S_FSWORDREADY9, S_FSWORDREADY10, S_FSWORDREADY11, S_FSWORDDOWN, S_FSWORDUP, S_FSWORDATK_1, S_FSWORDATK_2, S_FSWORDATK_3, S_FSWORDATK_4, S_FSWORDATK_5, S_FSWORDATK_6, S_FSWORDATK_7, S_FSWORDATK_8, S_FSWORDATK_9, S_FSWORDATK_10, S_FSWORDATK_11, S_FSWORDATK_12, S_FSWORD_MISSILE1, S_FSWORD_MISSILE2, S_FSWORD_MISSILE3, S_FSWORD_MISSILE_X1, S_FSWORD_MISSILE_X2, S_FSWORD_MISSILE_X3, S_FSWORD_MISSILE_X4, S_FSWORD_MISSILE_X5, S_FSWORD_MISSILE_X6, S_FSWORD_MISSILE_X7, S_FSWORD_MISSILE_X8, S_FSWORD_MISSILE_X9, S_FSWORD_MISSILE_X10, S_FSWORD_FLAME1, S_FSWORD_FLAME2, S_FSWORD_FLAME3, S_FSWORD_FLAME4, S_FSWORD_FLAME5, S_FSWORD_FLAME6, S_FSWORD_FLAME7, S_FSWORD_FLAME8, S_FSWORD_FLAME9, S_FSWORD_FLAME10, S_CMACEREADY, S_CMACEDOWN, S_CMACEUP, S_CMACEATK_1, S_CMACEATK_2, S_CMACEATK_3, S_CMACEATK_4, S_CMACEATK_5, S_CMACEATK_6, S_CMACEATK_7, S_CMACEATK_8, S_CMACEATK_9, S_CMACEATK_10, S_CMACEATK_11, S_CMACEATK_12, S_CMACEATK_13, S_CMACEATK_14, S_CMACEATK_15, S_CMACEATK_16, S_CMACEATK_17, S_CSTAFF, S_CSTAFFREADY, S_CSTAFFREADY1, S_CSTAFFREADY2, S_CSTAFFREADY3, S_CSTAFFREADY4, S_CSTAFFREADY5, S_CSTAFFREADY6, S_CSTAFFREADY7, S_CSTAFFREADY8, S_CSTAFFREADY9, S_CSTAFFBLINK1, S_CSTAFFBLINK2, S_CSTAFFBLINK3, S_CSTAFFBLINK4, S_CSTAFFBLINK5, S_CSTAFFBLINK6, S_CSTAFFBLINK7, S_CSTAFFBLINK8, S_CSTAFFBLINK9, S_CSTAFFBLINK10, S_CSTAFFBLINK11, S_CSTAFFDOWN, S_CSTAFFDOWN2, S_CSTAFFDOWN3, S_CSTAFFUP, S_CSTAFFATK_1, S_CSTAFFATK_2, S_CSTAFFATK_3, S_CSTAFFATK_4, S_CSTAFFATK_5, S_CSTAFFATK_6, S_CSTAFFATK2_1, S_CSTAFF_MISSILE1, S_CSTAFF_MISSILE2, S_CSTAFF_MISSILE3, S_CSTAFF_MISSILE4, S_CSTAFF_MISSILE_X1, S_CSTAFF_MISSILE_X2, S_CSTAFF_MISSILE_X3, S_CSTAFF_MISSILE_X4, S_CSTAFFPUFF1, S_CSTAFFPUFF2, S_CSTAFFPUFF3, S_CSTAFFPUFF4, S_CSTAFFPUFF5, S_CFLAME1, S_CFLAME2, S_CFLAME3, S_CFLAME4, S_CFLAME5, S_CFLAME6, S_CFLAME7, S_CFLAME8, S_CFLAMEREADY1, S_CFLAMEREADY2, S_CFLAMEREADY3, S_CFLAMEREADY4, S_CFLAMEREADY5, S_CFLAMEREADY6, S_CFLAMEREADY7, S_CFLAMEREADY8, S_CFLAMEREADY9, S_CFLAMEREADY10, S_CFLAMEREADY11, S_CFLAMEREADY12, S_CFLAMEDOWN, S_CFLAMEUP, S_CFLAMEATK_1, S_CFLAMEATK_2, S_CFLAMEATK_3, S_CFLAMEATK_4, S_CFLAMEATK_5, S_CFLAMEATK_6, S_CFLAMEATK_7, S_CFLAMEATK_8, S_CFLAMEFLOOR1, S_CFLAMEFLOOR2, S_CFLAMEFLOOR3, S_FLAMEPUFF1, S_FLAMEPUFF2, S_FLAMEPUFF3, S_FLAMEPUFF4, S_FLAMEPUFF5, S_FLAMEPUFF6, S_FLAMEPUFF7, S_FLAMEPUFF8, S_FLAMEPUFF9, S_FLAMEPUFF10, S_FLAMEPUFF11, S_FLAMEPUFF12, S_FLAMEPUFF13, S_FLAMEPUFF2_1, S_FLAMEPUFF2_2, S_FLAMEPUFF2_3, S_FLAMEPUFF2_4, S_FLAMEPUFF2_5, S_FLAMEPUFF2_6, S_FLAMEPUFF2_7, S_FLAMEPUFF2_8, S_FLAMEPUFF2_9, S_FLAMEPUFF2_10, S_FLAMEPUFF2_11, S_FLAMEPUFF2_12, S_FLAMEPUFF2_13, S_FLAMEPUFF2_14, S_FLAMEPUFF2_15, S_FLAMEPUFF2_16, S_FLAMEPUFF2_17, S_FLAMEPUFF2_18, S_FLAMEPUFF2_19, S_FLAMEPUFF2_20, S_CIRCLE_FLAME1, S_CIRCLE_FLAME2, S_CIRCLE_FLAME3, S_CIRCLE_FLAME4, S_CIRCLE_FLAME5, S_CIRCLE_FLAME6, S_CIRCLE_FLAME7, S_CIRCLE_FLAME8, S_CIRCLE_FLAME9, S_CIRCLE_FLAME10, S_CIRCLE_FLAME11, S_CIRCLE_FLAME12, S_CIRCLE_FLAME13, S_CIRCLE_FLAME14, S_CIRCLE_FLAME15, S_CIRCLE_FLAME16, S_CIRCLE_FLAME_X1, S_CIRCLE_FLAME_X2, S_CIRCLE_FLAME_X3, S_CIRCLE_FLAME_X4, S_CIRCLE_FLAME_X5, S_CIRCLE_FLAME_X6, S_CIRCLE_FLAME_X7, S_CIRCLE_FLAME_X8, S_CIRCLE_FLAME_X9, S_CIRCLE_FLAME_X10, S_CFLAME_MISSILE1, S_CFLAME_MISSILE2, S_CFLAME_MISSILE_X, S_CHOLYREADY, S_CHOLYDOWN, S_CHOLYUP, S_CHOLYATK_1, S_CHOLYATK_2, S_CHOLYATK_3, S_CHOLYATK_4, S_CHOLYATK_5, S_CHOLYATK_6, S_CHOLYATK_7, S_CHOLYATK_8, S_CHOLYATK_9, S_HOLY_FX1, S_HOLY_FX2, S_HOLY_FX3, S_HOLY_FX4, S_HOLY_FX_X1, S_HOLY_FX_X2, S_HOLY_FX_X3, S_HOLY_FX_X4, S_HOLY_FX_X5, S_HOLY_FX_X6, S_HOLY_TAIL1, S_HOLY_TAIL2, S_HOLY_PUFF1, S_HOLY_PUFF2, S_HOLY_PUFF3, S_HOLY_PUFF4, S_HOLY_PUFF5, S_HOLY_MISSILE1, S_HOLY_MISSILE2, S_HOLY_MISSILE3, S_HOLY_MISSILE4, S_HOLY_MISSILE_X, S_HOLY_MISSILE_P1, S_HOLY_MISSILE_P2, S_HOLY_MISSILE_P3, S_HOLY_MISSILE_P4, S_HOLY_MISSILE_P5, S_MWANDREADY, S_MWANDDOWN, S_MWANDUP, S_MWANDATK_1, S_MWANDATK_2, S_MWANDATK_3, S_MWANDATK_4, S_MWANDPUFF1, S_MWANDPUFF2, S_MWANDPUFF3, S_MWANDPUFF4, S_MWANDPUFF5, S_MWANDSMOKE1, S_MWANDSMOKE2, S_MWANDSMOKE3, S_MWANDSMOKE4, S_MWAND_MISSILE1, S_MWAND_MISSILE2, S_MW_LIGHTNING1, S_MW_LIGHTNING2, S_MW_LIGHTNING3, S_MW_LIGHTNING4, S_MW_LIGHTNING5, S_MW_LIGHTNING6, S_MW_LIGHTNING7, S_MW_LIGHTNING8, S_MLIGHTNINGREADY, S_MLIGHTNINGREADY2, S_MLIGHTNINGREADY3, S_MLIGHTNINGREADY4, S_MLIGHTNINGREADY5, S_MLIGHTNINGREADY6, S_MLIGHTNINGREADY7, S_MLIGHTNINGREADY8, S_MLIGHTNINGREADY9, S_MLIGHTNINGREADY10, S_MLIGHTNINGREADY11, S_MLIGHTNINGREADY12, S_MLIGHTNINGREADY13, S_MLIGHTNINGREADY14, S_MLIGHTNINGREADY15, S_MLIGHTNINGREADY16, S_MLIGHTNINGREADY17, S_MLIGHTNINGREADY18, S_MLIGHTNINGREADY19, S_MLIGHTNINGREADY20, S_MLIGHTNINGREADY21, S_MLIGHTNINGREADY22, S_MLIGHTNINGREADY23, S_MLIGHTNINGREADY24, S_MLIGHTNINGDOWN, S_MLIGHTNINGUP, S_MLIGHTNINGATK_1, S_MLIGHTNINGATK_2, S_MLIGHTNINGATK_3, S_MLIGHTNINGATK_4, S_MLIGHTNINGATK_5, S_MLIGHTNINGATK_6, S_MLIGHTNINGATK_7, S_MLIGHTNINGATK_8, S_MLIGHTNINGATK_9, S_MLIGHTNINGATK_10, S_MLIGHTNINGATK_11, S_LIGHTNING_CEILING1, S_LIGHTNING_CEILING2, S_LIGHTNING_CEILING3, S_LIGHTNING_CEILING4, S_LIGHTNING_C_X1, S_LIGHTNING_C_X2, S_LIGHTNING_C_X3, S_LIGHTNING_C_X4, S_LIGHTNING_C_X5, S_LIGHTNING_C_X6, S_LIGHTNING_C_X7, S_LIGHTNING_C_X8, S_LIGHTNING_C_X9, S_LIGHTNING_C_X10, S_LIGHTNING_C_X11, S_LIGHTNING_C_X12, S_LIGHTNING_C_X13, S_LIGHTNING_C_X14, S_LIGHTNING_C_X15, S_LIGHTNING_C_X16, S_LIGHTNING_C_X17, S_LIGHTNING_C_X18, S_LIGHTNING_C_X19, S_LIGHTNING_FLOOR1, S_LIGHTNING_FLOOR2, S_LIGHTNING_FLOOR3, S_LIGHTNING_FLOOR4, S_LIGHTNING_F_X1, S_LIGHTNING_F_X2, S_LIGHTNING_F_X3, S_LIGHTNING_F_X4, S_LIGHTNING_F_X5, S_LIGHTNING_F_X6, S_LIGHTNING_F_X7, S_LIGHTNING_F_X8, S_LIGHTNING_F_X9, S_LIGHTNING_F_X10, S_LIGHTNING_F_X11, S_LIGHTNING_F_X12, S_LIGHTNING_F_X13, S_LIGHTNING_F_X14, S_LIGHTNING_F_X15, S_LIGHTNING_F_X16, S_LIGHTNING_F_X17, S_LIGHTNING_F_X18, S_LIGHTNING_F_X19, S_LIGHTNING_ZAP1, S_LIGHTNING_ZAP2, S_LIGHTNING_ZAP3, S_LIGHTNING_ZAP4, S_LIGHTNING_ZAP5, S_LIGHTNING_ZAP_X1, S_LIGHTNING_ZAP_X2, S_LIGHTNING_ZAP_X3, S_LIGHTNING_ZAP_X4, S_LIGHTNING_ZAP_X5, S_LIGHTNING_ZAP_X6, S_LIGHTNING_ZAP_X7, S_LIGHTNING_ZAP_X8, S_MSTAFFREADY, S_MSTAFFREADY2, S_MSTAFFREADY3, S_MSTAFFREADY4, S_MSTAFFREADY5, S_MSTAFFREADY6, S_MSTAFFREADY7, S_MSTAFFREADY8, S_MSTAFFREADY9, S_MSTAFFREADY10, S_MSTAFFREADY11, S_MSTAFFREADY12, S_MSTAFFREADY13, S_MSTAFFREADY14, S_MSTAFFREADY15, S_MSTAFFREADY16, S_MSTAFFREADY17, S_MSTAFFREADY18, S_MSTAFFREADY19, S_MSTAFFREADY20, S_MSTAFFREADY21, S_MSTAFFREADY22, S_MSTAFFREADY23, S_MSTAFFREADY24, S_MSTAFFREADY25, S_MSTAFFREADY26, S_MSTAFFREADY27, S_MSTAFFREADY28, S_MSTAFFREADY29, S_MSTAFFREADY30, S_MSTAFFREADY31, S_MSTAFFREADY32, S_MSTAFFREADY33, S_MSTAFFREADY34, S_MSTAFFREADY35, S_MSTAFFDOWN, S_MSTAFFUP, S_MSTAFFATK_1, S_MSTAFFATK_2, S_MSTAFFATK_3, S_MSTAFFATK_4, S_MSTAFFATK_5, S_MSTAFFATK_6, S_MSTAFFATK_7, S_MSTAFF_FX1_1, S_MSTAFF_FX1_2, S_MSTAFF_FX1_3, S_MSTAFF_FX1_4, S_MSTAFF_FX1_5, S_MSTAFF_FX1_6, S_MSTAFF_FX_X1, S_MSTAFF_FX_X2, S_MSTAFF_FX_X3, S_MSTAFF_FX_X4, S_MSTAFF_FX_X5, S_MSTAFF_FX_X6, S_MSTAFF_FX_X7, S_MSTAFF_FX_X8, S_MSTAFF_FX_X9, S_MSTAFF_FX_X10, S_MSTAFF_FX2_1, S_MSTAFF_FX2_2, S_MSTAFF_FX2_3, S_MSTAFF_FX2_4, S_MSTAFF_FX2_X1, S_MSTAFF_FX2_X2, S_MSTAFF_FX2_X3, S_MSTAFF_FX2_X4, S_MSTAFF_FX2_X5, S_FSWORD1, S_FSWORD2, S_FSWORD3, S_CHOLY1, S_CHOLY2, S_CHOLY3, S_MSTAFF1, S_MSTAFF2, S_MSTAFF3, S_SNOUTREADY, S_SNOUTDOWN, S_SNOUTUP, S_SNOUTATK1, S_SNOUTATK2, S_COS1, S_COS2, S_COS3, S_CONEREADY, S_CONEDOWN, S_CONEUP, S_CONEATK1_1, S_CONEATK1_2, S_CONEATK1_3, S_CONEATK1_4, S_CONEATK1_5, S_CONEATK1_6, S_CONEATK1_7, S_CONEATK1_8, S_SHARDFX1_1, S_SHARDFX1_2, S_SHARDFX1_3, S_SHARDFX1_4, S_SHARDFXE1_1, S_SHARDFXE1_2, S_SHARDFXE1_3, S_SHARDFXE1_4, S_SHARDFXE1_5, S_BLOOD1, S_BLOOD2, S_BLOOD3, S_BLOODSPLATTER1, S_BLOODSPLATTER2, S_BLOODSPLATTER3, S_BLOODSPLATTERX, S_GIBS1, S_FPLAY, S_FPLAY_RUN1, S_FPLAY_RUN2, S_FPLAY_RUN3, S_FPLAY_RUN4, S_FPLAY_ATK1, S_FPLAY_ATK2, S_FPLAY_PAIN, S_FPLAY_PAIN2, S_FPLAY_DIE1, S_FPLAY_DIE2, S_FPLAY_DIE3, S_FPLAY_DIE4, S_FPLAY_DIE5, S_FPLAY_DIE6, S_FPLAY_DIE7, S_FPLAY_XDIE1, S_FPLAY_XDIE2, S_FPLAY_XDIE3, S_FPLAY_XDIE4, S_FPLAY_XDIE5, S_FPLAY_XDIE6, S_FPLAY_XDIE7, S_FPLAY_XDIE8, S_FPLAY_ICE, S_FPLAY_ICE2, S_PLAY_F_FDTH1, S_PLAY_F_FDTH2, S_PLAY_C_FDTH1, S_PLAY_C_FDTH2, S_PLAY_M_FDTH1, S_PLAY_M_FDTH2, S_PLAY_FDTH3, S_PLAY_FDTH4, S_PLAY_FDTH5, S_PLAY_FDTH6, S_PLAY_FDTH7, S_PLAY_FDTH8, S_PLAY_FDTH9, S_PLAY_FDTH10, S_PLAY_FDTH11, S_PLAY_FDTH12, S_PLAY_FDTH13, S_PLAY_FDTH14, S_PLAY_FDTH15, S_PLAY_FDTH16, S_PLAY_FDTH17, S_PLAY_FDTH18, S_PLAY_FDTH19, S_PLAY_FDTH20, S_BLOODYSKULL1, S_BLOODYSKULL2, S_BLOODYSKULL3, S_BLOODYSKULL4, S_BLOODYSKULL5, S_BLOODYSKULL6, S_BLOODYSKULL7, S_BLOODYSKULLX1, S_BLOODYSKULLX2, S_PLAYER_SPEED1, S_PLAYER_SPEED2, S_ICECHUNK1, S_ICECHUNK2, S_ICECHUNK3, S_ICECHUNK4, S_ICECHUNK_HEAD, S_ICECHUNK_HEAD2, S_CPLAY, S_CPLAY_RUN1, S_CPLAY_RUN2, S_CPLAY_RUN3, S_CPLAY_RUN4, S_CPLAY_ATK1, S_CPLAY_ATK2, S_CPLAY_ATK3, S_CPLAY_PAIN, S_CPLAY_PAIN2, S_CPLAY_DIE1, S_CPLAY_DIE2, S_CPLAY_DIE3, S_CPLAY_DIE4, S_CPLAY_DIE5, S_CPLAY_DIE6, S_CPLAY_DIE7, S_CPLAY_DIE8, S_CPLAY_DIE9, S_CPLAY_XDIE1, S_CPLAY_XDIE2, S_CPLAY_XDIE3, S_CPLAY_XDIE4, S_CPLAY_XDIE5, S_CPLAY_XDIE6, S_CPLAY_XDIE7, S_CPLAY_XDIE8, S_CPLAY_XDIE9, S_CPLAY_XDIE10, S_CPLAY_ICE, S_CPLAY_ICE2, S_MPLAY, S_MPLAY_RUN1, S_MPLAY_RUN2, S_MPLAY_RUN3, S_MPLAY_RUN4, S_MPLAY_ATK1, S_MPLAY_ATK2, S_MPLAY_PAIN, S_MPLAY_PAIN2, S_MPLAY_DIE1, S_MPLAY_DIE2, S_MPLAY_DIE3, S_MPLAY_DIE4, S_MPLAY_DIE5, S_MPLAY_DIE6, S_MPLAY_DIE7, S_MPLAY_XDIE1, S_MPLAY_XDIE2, S_MPLAY_XDIE3, S_MPLAY_XDIE4, S_MPLAY_XDIE5, S_MPLAY_XDIE6, S_MPLAY_XDIE7, S_MPLAY_XDIE8, S_MPLAY_XDIE9, S_MPLAY_ICE, S_MPLAY_ICE2, S_PIGPLAY, S_PIGPLAY_RUN1, S_PIGPLAY_RUN2, S_PIGPLAY_RUN3, S_PIGPLAY_RUN4, S_PIGPLAY_ATK1, S_PIGPLAY_PAIN, S_PIG_LOOK1, S_PIG_WALK1, S_PIG_WALK2, S_PIG_WALK3, S_PIG_WALK4, S_PIG_PAIN, S_PIG_ATK1, S_PIG_ATK2, S_PIG_DIE1, S_PIG_DIE2, S_PIG_DIE3, S_PIG_DIE4, S_PIG_DIE5, S_PIG_DIE6, S_PIG_DIE7, S_PIG_DIE8, S_PIG_ICE, S_PIG_ICE2, S_CENTAUR_LOOK1, S_CENTAUR_LOOK2, S_CENTAUR_WALK1, S_CENTAUR_WALK2, S_CENTAUR_WALK3, S_CENTAUR_WALK4, S_CENTAUR_ATK1, S_CENTAUR_ATK2, S_CENTAUR_ATK3, S_CENTAUR_MISSILE1, S_CENTAUR_MISSILE2, S_CENTAUR_MISSILE3, S_CENTAUR_MISSILE4, S_CENTAUR_PAIN1, S_CENTAUR_PAIN2, S_CENTAUR_PAIN3, S_CENTAUR_PAIN4, S_CENTAUR_PAIN5, S_CENTAUR_PAIN6, S_CENTAUR_DEATH1, S_CENTAUR_DEATH2, S_CENTAUR_DEATH3, S_CENTAUR_DEATH4, S_CENTAUR_DEATH5, S_CENTAUR_DEATH6, S_CENTAUR_DEATH7, S_CENTAUR_DEATH8, S_CENTAUR_DEATH9, S_CENTAUR_DEATH0, S_CENTAUR_DEATH_X1, S_CENTAUR_DEATH_X2, S_CENTAUR_DEATH_X3, S_CENTAUR_DEATH_X4, S_CENTAUR_DEATH_X5, S_CENTAUR_DEATH_X6, S_CENTAUR_DEATH_X7, S_CENTAUR_DEATH_X8, S_CENTAUR_DEATH_X9, S_CENTAUR_DEATH_X10, S_CENTAUR_DEATH_X11, S_CENTAUR_ICE, S_CENTAUR_ICE2, S_CENTAUR_FX1, S_CENTAUR_FX_X1, S_CENTAUR_FX_X2, S_CENTAUR_FX_X3, S_CENTAUR_FX_X4, S_CENTAUR_FX_X5, S_CENTAUR_SHIELD1, S_CENTAUR_SHIELD2, S_CENTAUR_SHIELD3, S_CENTAUR_SHIELD4, S_CENTAUR_SHIELD5, S_CENTAUR_SHIELD6, S_CENTAUR_SHIELD_X1, S_CENTAUR_SHIELD_X2, S_CENTAUR_SHIELD_X3, S_CENTAUR_SHIELD_X4, S_CENTAUR_SWORD1, S_CENTAUR_SWORD2, S_CENTAUR_SWORD3, S_CENTAUR_SWORD4, S_CENTAUR_SWORD5, S_CENTAUR_SWORD6, S_CENTAUR_SWORD7, S_CENTAUR_SWORD_X1, S_CENTAUR_SWORD_X2, S_CENTAUR_SWORD_X3, S_DEMN_LOOK1, S_DEMN_LOOK2, S_DEMN_CHASE1, S_DEMN_CHASE2, S_DEMN_CHASE3, S_DEMN_CHASE4, S_DEMN_ATK1_1, S_DEMN_ATK1_2, S_DEMN_ATK1_3, S_DEMN_ATK2_1, S_DEMN_ATK2_2, S_DEMN_ATK2_3, S_DEMN_PAIN1, S_DEMN_PAIN2, S_DEMN_DEATH1, S_DEMN_DEATH2, S_DEMN_DEATH3, S_DEMN_DEATH4, S_DEMN_DEATH5, S_DEMN_DEATH6, S_DEMN_DEATH7, S_DEMN_DEATH8, S_DEMN_DEATH9, S_DEMN_XDEATH1, S_DEMN_XDEATH2, S_DEMN_XDEATH3, S_DEMN_XDEATH4, S_DEMN_XDEATH5, S_DEMN_XDEATH6, S_DEMN_XDEATH7, S_DEMN_XDEATH8, S_DEMN_XDEATH9, S_DEMON_ICE, S_DEMON_ICE2, S_DEMONCHUNK1_1, S_DEMONCHUNK1_2, S_DEMONCHUNK1_3, S_DEMONCHUNK1_4, S_DEMONCHUNK2_1, S_DEMONCHUNK2_2, S_DEMONCHUNK2_3, S_DEMONCHUNK2_4, S_DEMONCHUNK3_1, S_DEMONCHUNK3_2, S_DEMONCHUNK3_3, S_DEMONCHUNK3_4, S_DEMONCHUNK4_1, S_DEMONCHUNK4_2, S_DEMONCHUNK4_3, S_DEMONCHUNK4_4, S_DEMONCHUNK5_1, S_DEMONCHUNK5_2, S_DEMONCHUNK5_3, S_DEMONCHUNK5_4, S_DEMONFX_MOVE1, S_DEMONFX_MOVE2, S_DEMONFX_MOVE3, S_DEMONFX_BOOM1, S_DEMONFX_BOOM2, S_DEMONFX_BOOM3, S_DEMONFX_BOOM4, S_DEMONFX_BOOM5, S_DEMN2_LOOK1, S_DEMN2_LOOK2, S_DEMN2_CHASE1, S_DEMN2_CHASE2, S_DEMN2_CHASE3, S_DEMN2_CHASE4, S_DEMN2_ATK1_1, S_DEMN2_ATK1_2, S_DEMN2_ATK1_3, S_DEMN2_ATK2_1, S_DEMN2_ATK2_2, S_DEMN2_ATK2_3, S_DEMN2_PAIN1, S_DEMN2_PAIN2, S_DEMN2_DEATH1, S_DEMN2_DEATH2, S_DEMN2_DEATH3, S_DEMN2_DEATH4, S_DEMN2_DEATH5, S_DEMN2_DEATH6, S_DEMN2_DEATH7, S_DEMN2_DEATH8, S_DEMN2_DEATH9, S_DEMN2_XDEATH1, S_DEMN2_XDEATH2, S_DEMN2_XDEATH3, S_DEMN2_XDEATH4, S_DEMN2_XDEATH5, S_DEMN2_XDEATH6, S_DEMN2_XDEATH7, S_DEMN2_XDEATH8, S_DEMN2_XDEATH9, S_DEMON2CHUNK1_1, S_DEMON2CHUNK1_2, S_DEMON2CHUNK1_3, S_DEMON2CHUNK1_4, S_DEMON2CHUNK2_1, S_DEMON2CHUNK2_2, S_DEMON2CHUNK2_3, S_DEMON2CHUNK2_4, S_DEMON2CHUNK3_1, S_DEMON2CHUNK3_2, S_DEMON2CHUNK3_3, S_DEMON2CHUNK3_4, S_DEMON2CHUNK4_1, S_DEMON2CHUNK4_2, S_DEMON2CHUNK4_3, S_DEMON2CHUNK4_4, S_DEMON2CHUNK5_1, S_DEMON2CHUNK5_2, S_DEMON2CHUNK5_3, S_DEMON2CHUNK5_4, S_DEMON2FX_MOVE1, S_DEMON2FX_MOVE2, S_DEMON2FX_MOVE3, S_DEMON2FX_MOVE4, S_DEMON2FX_MOVE5, S_DEMON2FX_MOVE6, S_DEMON2FX_BOOM1, S_DEMON2FX_BOOM2, S_DEMON2FX_BOOM3, S_DEMON2FX_BOOM4, S_DEMON2FX_BOOM5, S_DEMON2FX_BOOM6, S_WRAITH_RAISE1, S_WRAITH_RAISE2, S_WRAITH_RAISE3, S_WRAITH_RAISE4, S_WRAITH_RAISE5, S_WRAITH_INIT1, S_WRAITH_INIT2, S_WRAITH_LOOK1, S_WRAITH_LOOK2, S_WRAITH_CHASE1, S_WRAITH_CHASE2, S_WRAITH_CHASE3, S_WRAITH_CHASE4, S_WRAITH_ATK1_1, S_WRAITH_ATK1_2, S_WRAITH_ATK1_3, S_WRAITH_ATK2_1, S_WRAITH_ATK2_2, S_WRAITH_ATK2_3, S_WRAITH_PAIN1, S_WRAITH_PAIN2, S_WRAITH_DEATH1_1, S_WRAITH_DEATH1_2, S_WRAITH_DEATH1_3, S_WRAITH_DEATH1_4, S_WRAITH_DEATH1_5, S_WRAITH_DEATH1_6, S_WRAITH_DEATH1_7, S_WRAITH_DEATH1_8, S_WRAITH_DEATH1_9, S_WRAITH_DEATH1_0, S_WRAITH_DEATH2_1, S_WRAITH_DEATH2_2, S_WRAITH_DEATH2_3, S_WRAITH_DEATH2_4, S_WRAITH_DEATH2_5, S_WRAITH_DEATH2_6, S_WRAITH_DEATH2_7, S_WRAITH_DEATH2_8, S_WRAITH_ICE, S_WRAITH_ICE2, S_WRTHFX_MOVE1, S_WRTHFX_MOVE2, S_WRTHFX_MOVE3, S_WRTHFX_BOOM1, S_WRTHFX_BOOM2, S_WRTHFX_BOOM3, S_WRTHFX_BOOM4, S_WRTHFX_BOOM5, S_WRTHFX_BOOM6, S_WRTHFX_SIZZLE1, S_WRTHFX_SIZZLE2, S_WRTHFX_SIZZLE3, S_WRTHFX_SIZZLE4, S_WRTHFX_SIZZLE5, S_WRTHFX_SIZZLE6, S_WRTHFX_SIZZLE7, S_WRTHFX_DROP1, S_WRTHFX_DROP2, S_WRTHFX_DROP3, S_WRTHFX_DEAD1, S_WRTHFX_ADROP1, S_WRTHFX_ADROP2, S_WRTHFX_ADROP3, S_WRTHFX_ADROP4, S_WRTHFX_ADEAD1, S_WRTHFX_BDROP1, S_WRTHFX_BDROP2, S_WRTHFX_BDROP3, S_WRTHFX_BDEAD1, S_MNTR_SPAWN1, S_MNTR_SPAWN2, S_MNTR_SPAWN3, S_MNTR_LOOK1, S_MNTR_LOOK2, S_MNTR_WALK1, S_MNTR_WALK2, S_MNTR_WALK3, S_MNTR_WALK4, S_MNTR_ROAM1, S_MNTR_ROAM2, S_MNTR_ROAM3, S_MNTR_ROAM4, S_MNTR_ATK1_1, S_MNTR_ATK1_2, S_MNTR_ATK1_3, S_MNTR_ATK2_1, S_MNTR_ATK2_2, S_MNTR_ATK2_3, S_MNTR_ATK3_1, S_MNTR_ATK3_2, S_MNTR_ATK3_3, S_MNTR_ATK3_4, S_MNTR_ATK4_1, S_MNTR_PAIN1, S_MNTR_PAIN2, S_MNTR_DIE1, S_MNTR_DIE2, S_MNTR_DIE3, S_MNTR_DIE4, S_MNTR_DIE5, S_MNTR_DIE6, S_MNTR_DIE7, S_MNTR_DIE8, S_MNTR_DIE9, S_MNTRFX1_1, S_MNTRFX1_2, S_MNTRFXI1_1, S_MNTRFXI1_2, S_MNTRFXI1_3, S_MNTRFXI1_4, S_MNTRFXI1_5, S_MNTRFXI1_6, S_MNTRFX2_1, S_MNTRFXI2_1, S_MNTRFXI2_2, S_MNTRFXI2_3, S_MNTRFXI2_4, S_MNTRFXI2_5, S_MNTRFX3_1, S_MNTRFX3_2, S_MNTRFX3_3, S_MNTRFX3_4, S_MNTRFX3_5, S_MNTRFX3_6, S_MNTRFX3_7, S_MNTRFX3_8, S_MNTRFX3_9, S_MINOSMOKE1, S_MINOSMOKE2, S_MINOSMOKE3, S_MINOSMOKE4, S_MINOSMOKE5, S_MINOSMOKE6, S_MINOSMOKE7, S_MINOSMOKE8, S_MINOSMOKE9, S_MINOSMOKE0, S_MINOSMOKEA, S_MINOSMOKEB, S_MINOSMOKEC, S_MINOSMOKED, S_MINOSMOKEE, S_MINOSMOKEF, S_MINOSMOKEG, S_MINOSMOKEX1, S_MINOSMOKEX2, S_MINOSMOKEX3, S_MINOSMOKEX4, S_MINOSMOKEX5, S_MINOSMOKEX6, S_MINOSMOKEX7, S_MINOSMOKEX8, S_MINOSMOKEX9, S_MINOSMOKEX0, S_MINOSMOKEXA, S_MINOSMOKEXB, S_MINOSMOKEXC, S_MINOSMOKEXD, S_MINOSMOKEXE, S_MINOSMOKEXF, S_MINOSMOKEXG, S_MINOSMOKEXH, S_MINOSMOKEXI, S_SERPENT_LOOK1, S_SERPENT_SWIM1, S_SERPENT_SWIM2, S_SERPENT_SWIM3, S_SERPENT_HUMP1, S_SERPENT_HUMP2, S_SERPENT_HUMP3, S_SERPENT_HUMP4, S_SERPENT_HUMP5, S_SERPENT_HUMP6, S_SERPENT_HUMP7, S_SERPENT_HUMP8, S_SERPENT_HUMP9, S_SERPENT_HUMP10, S_SERPENT_HUMP11, S_SERPENT_HUMP12, S_SERPENT_HUMP13, S_SERPENT_HUMP14, S_SERPENT_HUMP15, S_SERPENT_SURFACE1, S_SERPENT_SURFACE2, S_SERPENT_SURFACE3, S_SERPENT_SURFACE4, S_SERPENT_SURFACE5, S_SERPENT_DIVE1, S_SERPENT_DIVE2, S_SERPENT_DIVE3, S_SERPENT_DIVE4, S_SERPENT_DIVE5, S_SERPENT_DIVE6, S_SERPENT_DIVE7, S_SERPENT_DIVE8, S_SERPENT_DIVE9, S_SERPENT_DIVE10, S_SERPENT_WALK1, S_SERPENT_WALK2, S_SERPENT_WALK3, S_SERPENT_WALK4, S_SERPENT_PAIN1, S_SERPENT_PAIN2, S_SERPENT_ATK1, S_SERPENT_ATK2, S_SERPENT_MELEE1, S_SERPENT_MISSILE1, S_SERPENT_DIE1, S_SERPENT_DIE2, S_SERPENT_DIE3, S_SERPENT_DIE4, S_SERPENT_DIE5, S_SERPENT_DIE6, S_SERPENT_DIE7, S_SERPENT_DIE8, S_SERPENT_DIE9, S_SERPENT_DIE10, S_SERPENT_DIE11, S_SERPENT_DIE12, S_SERPENT_XDIE1, S_SERPENT_XDIE2, S_SERPENT_XDIE3, S_SERPENT_XDIE4, S_SERPENT_XDIE5, S_SERPENT_XDIE6, S_SERPENT_XDIE7, S_SERPENT_XDIE8, S_SERPENT_ICE, S_SERPENT_ICE2, S_SERPENT_FX1, S_SERPENT_FX2, S_SERPENT_FX3, S_SERPENT_FX4, S_SERPENT_FX_X1, S_SERPENT_FX_X2, S_SERPENT_FX_X3, S_SERPENT_FX_X4, S_SERPENT_FX_X5, S_SERPENT_FX_X6, S_SERPENT_HEAD1, S_SERPENT_HEAD2, S_SERPENT_HEAD3, S_SERPENT_HEAD4, S_SERPENT_HEAD5, S_SERPENT_HEAD6, S_SERPENT_HEAD7, S_SERPENT_HEAD8, S_SERPENT_HEAD_X1, S_SERPENT_GIB1_1, S_SERPENT_GIB1_2, S_SERPENT_GIB1_3, S_SERPENT_GIB1_4, S_SERPENT_GIB1_5, S_SERPENT_GIB1_6, S_SERPENT_GIB1_7, S_SERPENT_GIB1_8, S_SERPENT_GIB1_9, S_SERPENT_GIB1_10, S_SERPENT_GIB1_11, S_SERPENT_GIB1_12, S_SERPENT_GIB2_1, S_SERPENT_GIB2_2, S_SERPENT_GIB2_3, S_SERPENT_GIB2_4, S_SERPENT_GIB2_5, S_SERPENT_GIB2_6, S_SERPENT_GIB2_7, S_SERPENT_GIB2_8, S_SERPENT_GIB2_9, S_SERPENT_GIB2_10, S_SERPENT_GIB2_11, S_SERPENT_GIB2_12, S_SERPENT_GIB3_1, S_SERPENT_GIB3_2, S_SERPENT_GIB3_3, S_SERPENT_GIB3_4, S_SERPENT_GIB3_5, S_SERPENT_GIB3_6, S_SERPENT_GIB3_7, S_SERPENT_GIB3_8, S_SERPENT_GIB3_9, S_SERPENT_GIB3_10, S_SERPENT_GIB3_11, S_SERPENT_GIB3_12, S_BISHOP_LOOK1, S_BISHOP_DECIDE, S_BISHOP_BLUR1, S_BISHOP_BLUR2, S_BISHOP_WALK1, S_BISHOP_WALK2, S_BISHOP_WALK3, S_BISHOP_WALK4, S_BISHOP_WALK5, S_BISHOP_WALK6, S_BISHOP_ATK1, S_BISHOP_ATK2, S_BISHOP_ATK3, S_BISHOP_ATK4, S_BISHOP_ATK5, S_BISHOP_PAIN1, S_BISHOP_PAIN2, S_BISHOP_PAIN3, S_BISHOP_PAIN4, S_BISHOP_PAIN5, S_BISHOP_DEATH1, S_BISHOP_DEATH2, S_BISHOP_DEATH3, S_BISHOP_DEATH4, S_BISHOP_DEATH5, S_BISHOP_DEATH6, S_BISHOP_DEATH7, S_BISHOP_DEATH8, S_BISHOP_DEATH9, S_BISHOP_DEATH10, S_BISHOP_ICE, S_BISHOP_ICE2, S_BISHOP_PUFF1, S_BISHOP_PUFF2, S_BISHOP_PUFF3, S_BISHOP_PUFF4, S_BISHOP_PUFF5, S_BISHOP_PUFF6, S_BISHOP_PUFF7, S_BISHOPBLUR1, S_BISHOPBLUR2, S_BISHOPPAINBLUR1, S_BISHFX1_1, S_BISHFX1_2, S_BISHFX1_3, S_BISHFX1_4, S_BISHFX1_5, S_BISHFXI1_1, S_BISHFXI1_2, S_BISHFXI1_3, S_BISHFXI1_4, S_BISHFXI1_5, S_BISHFXI1_6, S_DRAGON_LOOK1, S_DRAGON_INIT, S_DRAGON_INIT2, S_DRAGON_INIT3, S_DRAGON_WALK1, S_DRAGON_WALK2, S_DRAGON_WALK3, S_DRAGON_WALK4, S_DRAGON_WALK5, S_DRAGON_WALK6, S_DRAGON_WALK7, S_DRAGON_WALK8, S_DRAGON_WALK9, S_DRAGON_WALK10, S_DRAGON_WALK11, S_DRAGON_WALK12, S_DRAGON_ATK1, S_DRAGON_PAIN1, S_DRAGON_DEATH1, S_DRAGON_DEATH2, S_DRAGON_DEATH3, S_DRAGON_DEATH4, S_DRAGON_CRASH1, S_DRAGON_CRASH2, S_DRAGON_CRASH3, S_DRAGON_FX1_1, S_DRAGON_FX1_2, S_DRAGON_FX1_3, S_DRAGON_FX1_4, S_DRAGON_FX1_5, S_DRAGON_FX1_6, S_DRAGON_FX1_X1, S_DRAGON_FX1_X2, S_DRAGON_FX1_X3, S_DRAGON_FX1_X4, S_DRAGON_FX1_X5, S_DRAGON_FX1_X6, S_DRAGON_FX2_1, S_DRAGON_FX2_2, S_DRAGON_FX2_3, S_DRAGON_FX2_4, S_DRAGON_FX2_5, S_DRAGON_FX2_6, S_DRAGON_FX2_7, S_DRAGON_FX2_8, S_DRAGON_FX2_9, S_DRAGON_FX2_10, S_DRAGON_FX2_11, S_ARMOR_1, S_ARMOR_2, S_ARMOR_3, S_ARMOR_4, S_MANA1_1, S_MANA1_2, S_MANA1_3, S_MANA1_4, S_MANA1_5, S_MANA1_6, S_MANA1_7, S_MANA1_8, S_MANA1_9, S_MANA2_1, S_MANA2_2, S_MANA2_3, S_MANA2_4, S_MANA2_5, S_MANA2_6, S_MANA2_7, S_MANA2_8, S_MANA2_9, S_MANA2_10, S_MANA2_11, S_MANA2_12, S_MANA2_13, S_MANA2_14, S_MANA2_15, S_MANA2_16, S_MANA3_1, S_MANA3_2, S_MANA3_3, S_MANA3_4, S_MANA3_5, S_MANA3_6, S_MANA3_7, S_MANA3_8, S_MANA3_9, S_MANA3_10, S_MANA3_11, S_MANA3_12, S_MANA3_13, S_MANA3_14, S_MANA3_15, S_MANA3_16, S_KEY1, S_KEY2, S_KEY3, S_KEY4, S_KEY5, S_KEY6, S_KEY7, S_KEY8, S_KEY9, S_KEYA, S_KEYB, S_SND_WIND1, S_SND_WIND2, S_SND_WATERFALL, S_ETTIN_LOOK1, S_ETTIN_LOOK2, S_ETTIN_CHASE1, S_ETTIN_CHASE2, S_ETTIN_CHASE3, S_ETTIN_CHASE4, S_ETTIN_PAIN1, S_ETTIN_ATK1_1, S_ETTIN_ATK1_2, S_ETTIN_ATK1_3, S_ETTIN_DEATH1_1, S_ETTIN_DEATH1_2, S_ETTIN_DEATH1_3, S_ETTIN_DEATH1_4, S_ETTIN_DEATH1_5, S_ETTIN_DEATH1_6, S_ETTIN_DEATH1_7, S_ETTIN_DEATH1_8, S_ETTIN_DEATH1_9, S_ETTIN_DEATH2_1, S_ETTIN_DEATH2_2, S_ETTIN_DEATH2_3, S_ETTIN_DEATH2_4, S_ETTIN_DEATH2_5, S_ETTIN_DEATH2_6, S_ETTIN_DEATH2_7, S_ETTIN_DEATH2_8, S_ETTIN_DEATH2_9, S_ETTIN_DEATH2_0, S_ETTIN_DEATH2_A, S_ETTIN_DEATH2_B, S_ETTIN_ICE1, S_ETTIN_ICE2, S_ETTIN_MACE1, S_ETTIN_MACE2, S_ETTIN_MACE3, S_ETTIN_MACE4, S_ETTIN_MACE5, S_ETTIN_MACE6, S_ETTIN_MACE7, S_FIRED_SPAWN1, S_FIRED_LOOK1, S_FIRED_LOOK2, S_FIRED_LOOK3, S_FIRED_LOOK4, S_FIRED_LOOK5, S_FIRED_LOOK6, S_FIRED_LOOK7, S_FIRED_LOOK8, S_FIRED_LOOK9, S_FIRED_LOOK0, S_FIRED_LOOKA, S_FIRED_LOOKB, S_FIRED_WALK1, S_FIRED_WALK2, S_FIRED_WALK3, S_FIRED_PAIN1, S_FIRED_ATTACK1, S_FIRED_ATTACK2, S_FIRED_ATTACK3, S_FIRED_ATTACK4, S_FIRED_DEATH1, S_FIRED_DEATH2, S_FIRED_DEATH3, S_FIRED_DEATH4, S_FIRED_XDEATH1, S_FIRED_XDEATH2, S_FIRED_XDEATH3, S_FIRED_ICE1, S_FIRED_ICE2, S_FIRED_CORPSE1, S_FIRED_CORPSE2, S_FIRED_CORPSE3, S_FIRED_CORPSE4, S_FIRED_CORPSE5, S_FIRED_CORPSE6, S_FIRED_RDROP1, S_FIRED_RDEAD1_1, S_FIRED_RDEAD1_2, S_FIRED_RDROP2, S_FIRED_RDEAD2_1, S_FIRED_RDEAD2_2, S_FIRED_RDROP3, S_FIRED_RDEAD3_1, S_FIRED_RDEAD3_2, S_FIRED_RDROP4, S_FIRED_RDEAD4_1, S_FIRED_RDEAD4_2, S_FIRED_RDROP5, S_FIRED_RDEAD5_1, S_FIRED_RDEAD5_2, S_FIRED_FX6_1, S_FIRED_FX6_2, S_FIRED_FX6_3, S_FIRED_FX6_4, S_FIRED_FX6_5, S_ICEGUY_LOOK, S_ICEGUY_DORMANT, S_ICEGUY_WALK1, S_ICEGUY_WALK2, S_ICEGUY_WALK3, S_ICEGUY_WALK4, S_ICEGUY_ATK1, S_ICEGUY_ATK2, S_ICEGUY_ATK3, S_ICEGUY_ATK4, S_ICEGUY_PAIN1, S_ICEGUY_DEATH, S_ICEGUY_FX1, S_ICEGUY_FX2, S_ICEGUY_FX3, S_ICEGUY_FX_X1, S_ICEGUY_FX_X2, S_ICEGUY_FX_X3, S_ICEGUY_FX_X4, S_ICEGUY_FX_X5, S_ICEFX_PUFF1, S_ICEFX_PUFF2, S_ICEFX_PUFF3, S_ICEFX_PUFF4, S_ICEFX_PUFF5, S_ICEGUY_FX2_1, S_ICEGUY_FX2_2, S_ICEGUY_FX2_3, S_ICEGUY_BIT1, S_ICEGUY_BIT2, S_ICEGUY_WISP1_1, S_ICEGUY_WISP1_2, S_ICEGUY_WISP1_3, S_ICEGUY_WISP1_4, S_ICEGUY_WISP1_5, S_ICEGUY_WISP1_6, S_ICEGUY_WISP1_7, S_ICEGUY_WISP1_8, S_ICEGUY_WISP1_9, S_ICEGUY_WISP2_1, S_ICEGUY_WISP2_2, S_ICEGUY_WISP2_3, S_ICEGUY_WISP2_4, S_ICEGUY_WISP2_5, S_ICEGUY_WISP2_6, S_ICEGUY_WISP2_7, S_ICEGUY_WISP2_8, S_ICEGUY_WISP2_9, S_FIGHTER, S_FIGHTER2, S_FIGHTERLOOK, S_FIGHTER_RUN1, S_FIGHTER_RUN2, S_FIGHTER_RUN3, S_FIGHTER_RUN4, S_FIGHTER_ATK1, S_FIGHTER_ATK2, S_FIGHTER_PAIN, S_FIGHTER_PAIN2, S_FIGHTER_DIE1, S_FIGHTER_DIE2, S_FIGHTER_DIE3, S_FIGHTER_DIE4, S_FIGHTER_DIE5, S_FIGHTER_DIE6, S_FIGHTER_DIE7, S_FIGHTER_XDIE1, S_FIGHTER_XDIE2, S_FIGHTER_XDIE3, S_FIGHTER_XDIE4, S_FIGHTER_XDIE5, S_FIGHTER_XDIE6, S_FIGHTER_XDIE7, S_FIGHTER_XDIE8, S_FIGHTER_ICE, S_FIGHTER_ICE2, S_CLERIC, S_CLERIC2, S_CLERICLOOK, S_CLERIC_RUN1, S_CLERIC_RUN2, S_CLERIC_RUN3, S_CLERIC_RUN4, S_CLERIC_ATK1, S_CLERIC_ATK2, S_CLERIC_ATK3, S_CLERIC_PAIN, S_CLERIC_PAIN2, S_CLERIC_DIE1, S_CLERIC_DIE2, S_CLERIC_DIE3, S_CLERIC_DIE4, S_CLERIC_DIE5, S_CLERIC_DIE6, S_CLERIC_DIE7, S_CLERIC_DIE8, S_CLERIC_DIE9, S_CLERIC_XDIE1, S_CLERIC_XDIE2, S_CLERIC_XDIE3, S_CLERIC_XDIE4, S_CLERIC_XDIE5, S_CLERIC_XDIE6, S_CLERIC_XDIE7, S_CLERIC_XDIE8, S_CLERIC_XDIE9, S_CLERIC_XDIE10, S_CLERIC_ICE, S_CLERIC_ICE2, S_MAGE, S_MAGE2, S_MAGELOOK, S_MAGE_RUN1, S_MAGE_RUN2, S_MAGE_RUN3, S_MAGE_RUN4, S_MAGE_ATK1, S_MAGE_ATK2, S_MAGE_PAIN, S_MAGE_PAIN2, S_MAGE_DIE1, S_MAGE_DIE2, S_MAGE_DIE3, S_MAGE_DIE4, S_MAGE_DIE5, S_MAGE_DIE6, S_MAGE_DIE7, S_MAGE_XDIE1, S_MAGE_XDIE2, S_MAGE_XDIE3, S_MAGE_XDIE4, S_MAGE_XDIE5, S_MAGE_XDIE6, S_MAGE_XDIE7, S_MAGE_XDIE8, S_MAGE_XDIE9, S_MAGE_ICE, S_MAGE_ICE2, S_SORC_SPAWN1, S_SORC_SPAWN2, S_SORC_LOOK1, S_SORC_WALK1, S_SORC_WALK2, S_SORC_WALK3, S_SORC_WALK4, S_SORC_PAIN1, S_SORC_PAIN2, S_SORC_ATK2_1, S_SORC_ATK2_2, S_SORC_ATK2_3, S_SORC_ATTACK1, S_SORC_ATTACK2, S_SORC_ATTACK3, S_SORC_ATTACK4, S_SORC_ATTACK5, S_SORC_DIE1, S_SORC_DIE2, S_SORC_DIE3, S_SORC_DIE4, S_SORC_DIE5, S_SORC_DIE6, S_SORC_DIE7, S_SORC_DIE8, S_SORC_DIE9, S_SORC_DIE0, S_SORC_DIEA, S_SORC_DIEB, S_SORC_DIEC, S_SORC_DIED, S_SORC_DIEE, S_SORC_DIEF, S_SORC_DIEG, S_SORC_DIEH, S_SORC_DIEI, S_SORCBALL1_1, S_SORCBALL1_2, S_SORCBALL1_3, S_SORCBALL1_4, S_SORCBALL1_5, S_SORCBALL1_6, S_SORCBALL1_7, S_SORCBALL1_8, S_SORCBALL1_9, S_SORCBALL1_0, S_SORCBALL1_A, S_SORCBALL1_B, S_SORCBALL1_C, S_SORCBALL1_D, S_SORCBALL1_E, S_SORCBALL1_F, S_SORCBALL1_D1, S_SORCBALL1_D2, S_SORCBALL1_D5, S_SORCBALL1_D6, S_SORCBALL1_D7, S_SORCBALL1_D8, S_SORCBALL1_D9, S_SORCBALL2_1, S_SORCBALL2_2, S_SORCBALL2_3, S_SORCBALL2_4, S_SORCBALL2_5, S_SORCBALL2_6, S_SORCBALL2_7, S_SORCBALL2_8, S_SORCBALL2_9, S_SORCBALL2_0, S_SORCBALL2_A, S_SORCBALL2_B, S_SORCBALL2_C, S_SORCBALL2_D, S_SORCBALL2_E, S_SORCBALL2_F, S_SORCBALL2_D1, S_SORCBALL2_D2, S_SORCBALL2_D5, S_SORCBALL2_D6, S_SORCBALL2_D7, S_SORCBALL2_D8, S_SORCBALL2_D9, S_SORCBALL3_1, S_SORCBALL3_2, S_SORCBALL3_3, S_SORCBALL3_4, S_SORCBALL3_5, S_SORCBALL3_6, S_SORCBALL3_7, S_SORCBALL3_8, S_SORCBALL3_9, S_SORCBALL3_0, S_SORCBALL3_A, S_SORCBALL3_B, S_SORCBALL3_C, S_SORCBALL3_D, S_SORCBALL3_E, S_SORCBALL3_F, S_SORCBALL3_D1, S_SORCBALL3_D2, S_SORCBALL3_D5, S_SORCBALL3_D6, S_SORCBALL3_D7, S_SORCBALL3_D8, S_SORCBALL3_D9, S_SORCFX1_1, S_SORCFX1_2, S_SORCFX1_3, S_SORCFX1_4, S_SORCFX1_D1, S_SORCFX1_D2, S_SORCFX1_D3, S_SORCFX2_SPLIT1, S_SORCFX2_ORBIT1, S_SORCFX2_ORBIT2, S_SORCFX2_ORBIT3, S_SORCFX2_ORBIT4, S_SORCFX2_ORBIT5, S_SORCFX2_ORBIT6, S_SORCFX2_ORBIT7, S_SORCFX2_ORBIT8, S_SORCFX2_ORBIT9, S_SORCFX2_ORBIT0, S_SORCFX2_ORBITA, S_SORCFX2_ORBITB, S_SORCFX2_ORBITC, S_SORCFX2_ORBITD, S_SORCFX2_ORBITE, S_SORCFX2_ORBITF, S_SORCFX2T1, S_SORCFX3_1, S_SORCFX3_2, S_SORCFX3_3, S_BISHMORPH1, S_BISHMORPHA, S_BISHMORPHB, S_BISHMORPHC, S_BISHMORPHD, S_BISHMORPHE, S_BISHMORPHF, S_BISHMORPHG, S_BISHMORPHH, S_BISHMORPHI, S_BISHMORPHJ, S_SORCFX3_EXP1, S_SORCFX3_EXP2, S_SORCFX3_EXP3, S_SORCFX3_EXP4, S_SORCFX3_EXP5, S_SORCFX4_1, S_SORCFX4_2, S_SORCFX4_3, S_SORCFX4_D1, S_SORCFX4_D2, S_SORCFX4_D3, S_SORCFX4_D4, S_SORCFX4_D5, S_SORCSPARK1, S_SORCSPARK2, S_SORCSPARK3, S_SORCSPARK4, S_SORCSPARK5, S_SORCSPARK6, S_SORCSPARK7, S_BLASTEFFECT1, S_BLASTEFFECT2, S_BLASTEFFECT3, S_BLASTEFFECT4, S_BLASTEFFECT5, S_BLASTEFFECT6, S_BLASTEFFECT7, S_BLASTEFFECT8, S_BLASTEFFECT9, S_WATERDRIP1, S_KORAX_LOOK1, S_KORAX_CHASE1, S_KORAX_CHASE2, S_KORAX_CHASE3, S_KORAX_CHASE4, S_KORAX_CHASE5, S_KORAX_CHASE6, S_KORAX_CHASE7, S_KORAX_CHASE8, S_KORAX_CHASE9, S_KORAX_CHASE0, S_KORAX_CHASEA, S_KORAX_CHASEB, S_KORAX_CHASEC, S_KORAX_CHASED, S_KORAX_CHASEE, S_KORAX_CHASEF, S_KORAX_PAIN1, S_KORAX_PAIN2, S_KORAX_ATTACK1, S_KORAX_ATTACK2, S_KORAX_MISSILE1, S_KORAX_MISSILE2, S_KORAX_MISSILE3, S_KORAX_COMMAND1, S_KORAX_COMMAND2, S_KORAX_COMMAND3, S_KORAX_COMMAND4, S_KORAX_COMMAND5, S_KORAX_DEATH1, S_KORAX_DEATH2, S_KORAX_DEATH3, S_KORAX_DEATH4, S_KORAX_DEATH5, S_KORAX_DEATH6, S_KORAX_DEATH7, S_KORAX_DEATH8, S_KORAX_DEATH9, S_KORAX_DEATH0, S_KORAX_DEATHA, S_KORAX_DEATHB, S_KORAX_DEATHC, S_KORAX_DEATHD, S_KSPIRIT_ROAM1, S_KSPIRIT_ROAM2, S_KSPIRIT_DEATH1, S_KSPIRIT_DEATH2, S_KSPIRIT_DEATH3, S_KSPIRIT_DEATH4, S_KSPIRIT_DEATH5, S_KSPIRIT_DEATH6, S_KBOLT1, S_KBOLT2, S_KBOLT3, S_KBOLT4, S_KBOLT5, S_KBOLT6, S_KBOLT7, S_SPAWNBATS1, S_SPAWNBATS2, S_SPAWNBATS3, S_SPAWNBATS_OFF, S_BAT1, S_BAT2, S_BAT3, S_BAT_DEATH, NUMSTATES } statenum_t; typedef struct { spritenum_t sprite; int frame; int tics; void (*action) (); statenum_t nextstate; int misc1, misc2; } state_t; extern state_t states[NUMSTATES]; extern char *sprnames[]; typedef enum { MT_MAPSPOT, MT_MAPSPOTGRAVITY, MT_FIREBALL1, MT_ARROW, MT_DART, MT_POISONDART, MT_RIPPERBALL, MT_PROJECTILE_BLADE, MT_ICESHARD, MT_FLAME_SMALL_TEMP, MT_FLAME_LARGE_TEMP, MT_FLAME_SMALL, MT_FLAME_LARGE, MT_HEALINGBOTTLE, MT_HEALTHFLASK, MT_ARTIFLY, MT_ARTIINVULNERABILITY, MT_SUMMONMAULATOR, MT_SUMMON_FX, MT_THRUSTFLOOR_UP, MT_THRUSTFLOOR_DOWN, MT_TELEPORTOTHER, MT_TELOTHER_FX1, MT_TELOTHER_FX2, MT_TELOTHER_FX3, MT_TELOTHER_FX4, MT_TELOTHER_FX5, MT_DIRT1, MT_DIRT2, MT_DIRT3, MT_DIRT4, MT_DIRT5, MT_DIRT6, MT_DIRTCLUMP, MT_ROCK1, MT_ROCK2, MT_ROCK3, MT_FOGSPAWNER, MT_FOGPATCHS, MT_FOGPATCHM, MT_FOGPATCHL, MT_QUAKE_FOCUS, MT_SGSHARD1, MT_SGSHARD2, MT_SGSHARD3, MT_SGSHARD4, MT_SGSHARD5, MT_SGSHARD6, MT_SGSHARD7, MT_SGSHARD8, MT_SGSHARD9, MT_SGSHARD0, MT_ARTIEGG, MT_EGGFX, MT_ARTISUPERHEAL, MT_ZWINGEDSTATUENOSKULL, MT_ZGEMPEDESTAL, MT_ARTIPUZZSKULL, MT_ARTIPUZZGEMBIG, MT_ARTIPUZZGEMRED, MT_ARTIPUZZGEMGREEN1, MT_ARTIPUZZGEMGREEN2, MT_ARTIPUZZGEMBLUE1, MT_ARTIPUZZGEMBLUE2, MT_ARTIPUZZBOOK1, MT_ARTIPUZZBOOK2, MT_ARTIPUZZSKULL2, MT_ARTIPUZZFWEAPON, MT_ARTIPUZZCWEAPON, MT_ARTIPUZZMWEAPON, MT_ARTIPUZZGEAR, MT_ARTIPUZZGEAR2, MT_ARTIPUZZGEAR3, MT_ARTIPUZZGEAR4, MT_ARTITORCH, MT_FIREBOMB, MT_ARTITELEPORT, MT_ARTIPOISONBAG, MT_POISONBAG, MT_POISONCLOUD, MT_THROWINGBOMB, MT_SPEEDBOOTS, MT_BOOSTMANA, MT_BOOSTARMOR, MT_BLASTRADIUS, MT_HEALRADIUS, MT_SPLASH, MT_SPLASHBASE, MT_LAVASPLASH, MT_LAVASMOKE, MT_SLUDGECHUNK, MT_SLUDGESPLASH, MT_MISC0, MT_MISC1, MT_MISC2, MT_MISC3, MT_MISC4, MT_MISC5, MT_MISC6, MT_MISC7, MT_MISC8, MT_TREEDESTRUCTIBLE, MT_MISC9, MT_MISC10, MT_MISC11, MT_MISC12, MT_MISC13, MT_MISC14, MT_MISC15, MT_MISC16, MT_MISC17, MT_MISC18, MT_MISC19, MT_MISC20, MT_MISC21, MT_MISC22, MT_MISC23, MT_MISC24, MT_MISC25, MT_MISC26, MT_MISC27, MT_MISC28, MT_MISC29, MT_MISC30, MT_MISC31, MT_MISC32, MT_MISC33, MT_MISC34, MT_MISC35, MT_MISC36, MT_MISC37, MT_MISC38, MT_MISC39, MT_MISC40, MT_MISC41, MT_MISC42, MT_MISC43, MT_MISC44, MT_MISC45, MT_MISC46, MT_MISC47, MT_MISC48, MT_MISC49, MT_MISC50, MT_MISC51, MT_MISC52, MT_MISC53, MT_MISC54, MT_MISC55, MT_MISC56, MT_MISC57, MT_MISC58, MT_MISC59, MT_MISC60, MT_MISC61, MT_MISC62, MT_MISC63, MT_MISC64, MT_MISC65, MT_MISC66, MT_MISC67, MT_MISC68, MT_MISC69, MT_MISC70, MT_MISC71, MT_MISC72, MT_MISC73, MT_MISC74, MT_MISC75, MT_MISC76, MT_POTTERY1, MT_POTTERY2, MT_POTTERY3, MT_POTTERYBIT1, MT_MISC77, MT_ZLYNCHED_NOHEART, MT_MISC78, MT_CORPSEBIT, MT_CORPSEBLOODDRIP, MT_BLOODPOOL, MT_MISC79, MT_MISC80, MT_LEAF1, MT_LEAF2, MT_ZTWINEDTORCH, MT_ZTWINEDTORCH_UNLIT, MT_BRIDGE, MT_BRIDGEBALL, MT_ZWALLTORCH, MT_ZWALLTORCH_UNLIT, MT_ZBARREL, MT_ZSHRUB1, MT_ZSHRUB2, MT_ZBUCKET, MT_ZPOISONSHROOM, MT_ZFIREBULL, MT_ZFIREBULL_UNLIT, MT_FIRETHING, MT_BRASSTORCH, MT_ZSUITOFARMOR, MT_ZARMORCHUNK, MT_ZBELL, MT_ZBLUE_CANDLE, MT_ZIRON_MAIDEN, MT_ZXMAS_TREE, MT_ZCAULDRON, MT_ZCAULDRON_UNLIT, MT_ZCHAINBIT32, MT_ZCHAINBIT64, MT_ZCHAINEND_HEART, MT_ZCHAINEND_HOOK1, MT_ZCHAINEND_HOOK2, MT_ZCHAINEND_SPIKE, MT_ZCHAINEND_SKULL, MT_TABLE_SHIT1, MT_TABLE_SHIT2, MT_TABLE_SHIT3, MT_TABLE_SHIT4, MT_TABLE_SHIT5, MT_TABLE_SHIT6, MT_TABLE_SHIT7, MT_TABLE_SHIT8, MT_TABLE_SHIT9, MT_TABLE_SHIT10, MT_TFOG, MT_MISC81, MT_TELEPORTMAN, MT_PUNCHPUFF, MT_FW_AXE, MT_AXEPUFF, MT_AXEPUFF_GLOW, MT_AXEBLOOD, MT_FW_HAMMER, MT_HAMMER_MISSILE, MT_HAMMERPUFF, MT_FSWORD_MISSILE, MT_FSWORD_FLAME, MT_CW_SERPSTAFF, MT_CSTAFF_MISSILE, MT_CSTAFFPUFF, MT_CW_FLAME, MT_CFLAMEFLOOR, MT_FLAMEPUFF, MT_FLAMEPUFF2, MT_CIRCLEFLAME, MT_CFLAME_MISSILE, MT_HOLY_FX, MT_HOLY_TAIL, MT_HOLY_PUFF, MT_HOLY_MISSILE, MT_HOLY_MISSILE_PUFF, MT_MWANDPUFF, MT_MWANDSMOKE, MT_MWAND_MISSILE, MT_MW_LIGHTNING, MT_LIGHTNING_CEILING, MT_LIGHTNING_FLOOR, MT_LIGHTNING_ZAP, MT_MSTAFF_FX, MT_MSTAFF_FX2, MT_FW_SWORD1, MT_FW_SWORD2, MT_FW_SWORD3, MT_CW_HOLY1, MT_CW_HOLY2, MT_CW_HOLY3, MT_MW_STAFF1, MT_MW_STAFF2, MT_MW_STAFF3, MT_SNOUTPUFF, MT_MW_CONE, MT_SHARDFX1, MT_BLOOD, MT_BLOODSPLATTER, MT_GIBS, MT_PLAYER_FIGHTER, MT_BLOODYSKULL, MT_PLAYER_SPEED, MT_ICECHUNK, MT_PLAYER_CLERIC, MT_PLAYER_MAGE, MT_PIGPLAYER, MT_PIG, MT_CENTAUR, MT_CENTAURLEADER, MT_CENTAUR_FX, MT_CENTAUR_SHIELD, MT_CENTAUR_SWORD, MT_DEMON, MT_DEMONCHUNK1, MT_DEMONCHUNK2, MT_DEMONCHUNK3, MT_DEMONCHUNK4, MT_DEMONCHUNK5, MT_DEMONFX1, MT_DEMON2, MT_DEMON2CHUNK1, MT_DEMON2CHUNK2, MT_DEMON2CHUNK3, MT_DEMON2CHUNK4, MT_DEMON2CHUNK5, MT_DEMON2FX1, MT_WRAITHB, MT_WRAITH, MT_WRAITHFX1, MT_WRAITHFX2, MT_WRAITHFX3, MT_WRAITHFX4, MT_WRAITHFX5, MT_MINOTAUR, MT_MNTRFX1, MT_MNTRFX2, MT_MNTRFX3, MT_MNTRSMOKE, MT_MNTRSMOKEEXIT, MT_SERPENT, MT_SERPENTLEADER, MT_SERPENTFX, MT_SERPENT_HEAD, MT_SERPENT_GIB1, MT_SERPENT_GIB2, MT_SERPENT_GIB3, MT_BISHOP, MT_BISHOP_PUFF, MT_BISHOPBLUR, MT_BISHOPPAINBLUR, MT_BISH_FX, MT_DRAGON, MT_DRAGON_FX, MT_DRAGON_FX2, MT_ARMOR_1, MT_ARMOR_2, MT_ARMOR_3, MT_ARMOR_4, MT_MANA1, MT_MANA2, MT_MANA3, MT_KEY1, MT_KEY2, MT_KEY3, MT_KEY4, MT_KEY5, MT_KEY6, MT_KEY7, MT_KEY8, MT_KEY9, MT_KEYA, MT_KEYB, MT_SOUNDWIND, MT_SOUNDWATERFALL, MT_ETTIN, MT_ETTIN_MACE, MT_FIREDEMON, MT_FIREDEMON_SPLOTCH1, MT_FIREDEMON_SPLOTCH2, MT_FIREDEMON_FX1, MT_FIREDEMON_FX2, MT_FIREDEMON_FX3, MT_FIREDEMON_FX4, MT_FIREDEMON_FX5, MT_FIREDEMON_FX6, MT_ICEGUY, MT_ICEGUY_FX, MT_ICEFX_PUFF, MT_ICEGUY_FX2, MT_ICEGUY_BIT, MT_ICEGUY_WISP1, MT_ICEGUY_WISP2, MT_FIGHTER_BOSS, MT_CLERIC_BOSS, MT_MAGE_BOSS, MT_SORCBOSS, MT_SORCBALL1, MT_SORCBALL2, MT_SORCBALL3, MT_SORCFX1, MT_SORCFX2, MT_SORCFX2_T1, MT_SORCFX3, MT_SORCFX3_EXPLOSION, MT_SORCFX4, MT_SORCSPARK1, MT_BLASTEFFECT, MT_WATER_DRIP, MT_KORAX, MT_KORAX_SPIRIT1, MT_KORAX_SPIRIT2, MT_KORAX_SPIRIT3, MT_KORAX_SPIRIT4, MT_KORAX_SPIRIT5, MT_KORAX_SPIRIT6, MT_DEMON_MASH, MT_DEMON2_MASH, MT_ETTIN_MASH, MT_CENTAUR_MASH, MT_KORAX_BOLT, MT_BAT_SPAWNER, MT_BAT, NUMMOBJTYPES } mobjtype_t; typedef struct { int doomednum; int spawnstate; int spawnhealth; int seestate; int seesound; int reactiontime; int attacksound; int painstate; int painchance; int painsound; int meleestate; int missilestate; int crashstate; int deathstate; int xdeathstate; int deathsound; int speed; int radius; int height; int mass; int damage; int activesound; int flags; int flags2; } mobjinfo_t; extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; chocolate-doom-chocolate-doom-2.2.1/src/hexen/m_random.c000066400000000000000000000046011257432200600231440ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "m_random.h" // This is the new flat distribution table static const unsigned char rndtable[256] = { 201, 1, 243, 19, 18, 42, 183, 203, 101, 123, 154, 137, 34, 118, 10, 216, 135, 246, 0, 107, 133, 229, 35, 113, 177, 211, 110, 17, 139, 84, 251, 235, 182, 166, 161, 230, 143, 91, 24, 81, 22, 94, 7, 51, 232, 104, 122, 248, 175, 138, 127, 171, 222, 213, 44, 16, 9, 33, 88, 102, 170, 150, 136, 114, 62, 3, 142, 237, 6, 252, 249, 56, 74, 30, 13, 21, 180, 199, 32, 132, 187, 234, 78, 210, 46, 131, 197, 8, 206, 244, 73, 4, 236, 178, 195, 70, 121, 97, 167, 217, 103, 40, 247, 186, 105, 39, 95, 163, 99, 149, 253, 29, 119, 83, 254, 26, 202, 65, 130, 155, 60, 64, 184, 106, 221, 93, 164, 196, 112, 108, 179, 141, 54, 109, 11, 126, 75, 165, 191, 227, 87, 225, 156, 15, 98, 162, 116, 79, 169, 140, 190, 205, 168, 194, 41, 250, 27, 20, 14, 241, 50, 214, 72, 192, 220, 233, 67, 148, 96, 185, 176, 181, 215, 207, 172, 85, 89, 90, 209, 128, 124, 2, 55, 173, 66, 152, 47, 129, 59, 43, 159, 240, 239, 12, 189, 212, 144, 28, 200, 77, 219, 198, 134, 228, 45, 92, 125, 151, 5, 53, 255, 52, 68, 245, 160, 158, 61, 86, 58, 82, 117, 37, 242, 145, 69, 188, 115, 76, 63, 100, 49, 111, 153, 80, 38, 57, 174, 224, 71, 231, 23, 25, 48, 218, 120, 147, 208, 36, 226, 223, 193, 238, 157, 204, 146, 31 }; int rndindex = 0; int prndindex = 0; /* =============== = = M_Random = = Returns a 0-255 number = =============== */ int P_Random(void) { prndindex = (prndindex + 1) & 0xff; return rndtable[prndindex]; } int M_Random(void) { rndindex = (rndindex + 1) & 0xff; return rndtable[rndindex]; } void M_ClearRandom(void) { rndindex = prndindex = 0; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/m_random.h000066400000000000000000000017441257432200600231560ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef HEXEN_M_RANDOM_H #define HEXEN_M_RANDOM_H // Most damage defined using HITDICE #define HITDICE(a) ((1+(P_Random()&7))*a) int M_Random(void); // returns a number from 0 to 255 int P_Random(void); // as M_Random, but used only by the play simulation void M_ClearRandom(void); // fix randoms for demos extern int rndindex; #endif // HEXEN_M_RANDOM_H chocolate-doom-chocolate-doom-2.2.1/src/hexen/mn_menu.c000066400000000000000000001340771257432200600230210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include #include "h2def.h" #include "doomkeys.h" #include "i_system.h" #include "i_swap.h" #include "i_video.h" #include "m_controls.h" #include "m_misc.h" #include "p_local.h" #include "r_local.h" #include "s_sound.h" #include "v_video.h" // MACROS ------------------------------------------------------------------ #define LEFT_DIR 0 #define RIGHT_DIR 1 #define ITEM_HEIGHT 20 #define SELECTOR_XOFFSET (-28) #define SELECTOR_YOFFSET (-1) #define SLOTTEXTLEN 16 #define ASCII_CURSOR '[' // TYPES ------------------------------------------------------------------- typedef enum { ITT_EMPTY, ITT_EFUNC, ITT_LRFUNC, ITT_SETMENU, ITT_INERT } ItemType_t; typedef enum { MENU_MAIN, MENU_CLASS, MENU_SKILL, MENU_OPTIONS, MENU_OPTIONS2, MENU_FILES, MENU_LOAD, MENU_SAVE, MENU_NONE } MenuType_t; typedef struct { ItemType_t type; char *text; void (*func) (int option); int option; MenuType_t menu; } MenuItem_t; typedef struct { int x; int y; void (*drawFunc) (void); int itemCount; MenuItem_t *items; int oldItPos; MenuType_t prevMenu; } Menu_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void InitFonts(void); static void SetMenu(MenuType_t menu); static void SCQuitGame(int option); static void SCClass(int option); static void SCSkill(int option); static void SCMouseSensi(int option); static void SCSfxVolume(int option); static void SCMusicVolume(int option); static void SCScreenSize(int option); static boolean SCNetCheck(int option); static void SCNetCheck2(int option); static void SCLoadGame(int option); static void SCSaveGame(int option); static void SCMessages(int option); static void SCEndGame(int option); static void SCInfo(int option); static void DrawMainMenu(void); static void DrawClassMenu(void); static void DrawSkillMenu(void); static void DrawOptionsMenu(void); static void DrawOptions2Menu(void); static void DrawFileSlots(Menu_t * menu); static void DrawFilesMenu(void); static void MN_DrawInfo(void); static void DrawLoadMenu(void); static void DrawSaveMenu(void); static void DrawSlider(Menu_t * menu, int item, int width, int slot); void MN_LoadSlotText(void); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern int detailLevel; extern boolean gamekeydown[256]; // The NUMKEYS macro is local to g_game // PUBLIC DATA DEFINITIONS ------------------------------------------------- boolean MenuActive; int InfoType; int messageson = true; boolean mn_SuicideConsole; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int FontABaseLump; static int FontAYellowBaseLump; static int FontBBaseLump; static int MauloBaseLump; static Menu_t *CurrentMenu; static int CurrentItPos; static int MenuPClass; static int MenuTime; static boolean soundchanged; boolean askforquit; static int typeofask; static boolean FileMenuKeySteal; static boolean slottextloaded; static char SlotText[6][SLOTTEXTLEN + 2]; static char oldSlotText[SLOTTEXTLEN + 2]; static int SlotStatus[6]; static int slotptr; static int currentSlot; static int quicksave; static int quickload; static MenuItem_t MainItems[] = { {ITT_SETMENU, "NEW GAME", SCNetCheck2, 1, MENU_CLASS}, {ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS}, {ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES}, {ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE}, {ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE} }; static Menu_t MainMenu = { 110, 56, DrawMainMenu, 5, MainItems, 0, MENU_NONE }; static MenuItem_t ClassItems[] = { {ITT_EFUNC, "FIGHTER", SCClass, 0, MENU_NONE}, {ITT_EFUNC, "CLERIC", SCClass, 1, MENU_NONE}, {ITT_EFUNC, "MAGE", SCClass, 2, MENU_NONE} }; static Menu_t ClassMenu = { 66, 66, DrawClassMenu, 3, ClassItems, 0, MENU_MAIN }; static MenuItem_t FilesItems[] = { {ITT_SETMENU, "LOAD GAME", SCNetCheck2, 2, MENU_LOAD}, {ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE} }; static Menu_t FilesMenu = { 110, 60, DrawFilesMenu, 2, FilesItems, 0, MENU_MAIN }; static MenuItem_t LoadItems[] = { {ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE}, {ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE} }; static Menu_t LoadMenu = { 70, 30, DrawLoadMenu, 6, LoadItems, 0, MENU_FILES }; static MenuItem_t SaveItems[] = { {ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE}, {ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE} }; static Menu_t SaveMenu = { 70, 30, DrawSaveMenu, 6, SaveItems, 0, MENU_FILES }; static MenuItem_t SkillItems[] = { {ITT_EFUNC, NULL, SCSkill, sk_baby, MENU_NONE}, {ITT_EFUNC, NULL, SCSkill, sk_easy, MENU_NONE}, {ITT_EFUNC, NULL, SCSkill, sk_medium, MENU_NONE}, {ITT_EFUNC, NULL, SCSkill, sk_hard, MENU_NONE}, {ITT_EFUNC, NULL, SCSkill, sk_nightmare, MENU_NONE} }; static Menu_t SkillMenu = { 120, 44, DrawSkillMenu, 5, SkillItems, 2, MENU_CLASS }; static MenuItem_t OptionsItems[] = { {ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE}, {ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE}, {ITT_LRFUNC, "MOUSE SENSITIVITY", SCMouseSensi, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}, {ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2} }; static Menu_t OptionsMenu = { 88, 30, DrawOptionsMenu, 5, OptionsItems, 0, MENU_MAIN }; static MenuItem_t Options2Items[] = { {ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}, {ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}, {ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE}, {ITT_EMPTY, NULL, NULL, 0, MENU_NONE} }; static Menu_t Options2Menu = { 90, 20, DrawOptions2Menu, 6, Options2Items, 0, MENU_OPTIONS }; static Menu_t *Menus[] = { &MainMenu, &ClassMenu, &SkillMenu, &OptionsMenu, &Options2Menu, &FilesMenu, &LoadMenu, &SaveMenu }; static char *GammaText[] = { TXT_GAMMA_LEVEL_OFF, TXT_GAMMA_LEVEL_1, TXT_GAMMA_LEVEL_2, TXT_GAMMA_LEVEL_3, TXT_GAMMA_LEVEL_4 }; // CODE -------------------------------------------------------------------- //--------------------------------------------------------------------------- // // PROC MN_Init // //--------------------------------------------------------------------------- void MN_Init(void) { InitFonts(); MenuActive = false; // messageson = true; // Set by defaults in .CFG MauloBaseLump = W_GetNumForName("FBULA0"); // ("M_SKL00"); } //--------------------------------------------------------------------------- // // PROC InitFonts // //--------------------------------------------------------------------------- static void InitFonts(void) { FontABaseLump = W_GetNumForName("FONTA_S") + 1; FontAYellowBaseLump = W_GetNumForName("FONTAY_S") + 1; FontBBaseLump = W_GetNumForName("FONTB_S") + 1; } //--------------------------------------------------------------------------- // // PROC MN_DrTextA // // Draw text using font A. // //--------------------------------------------------------------------------- void MN_DrTextA(char *text, int x, int y) { char c; patch_t *p; while ((c = *text++) != 0) { if (c < 33) { x += 5; } else { p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); V_DrawPatch(x, y, p); x += SHORT(p->width) - 1; } } } //========================================================================== // // MN_DrTextAYellow // //========================================================================== void MN_DrTextAYellow(char *text, int x, int y) { char c; patch_t *p; while ((c = *text++) != 0) { if (c < 33) { x += 5; } else { p = W_CacheLumpNum(FontAYellowBaseLump + c - 33, PU_CACHE); V_DrawPatch(x, y, p); x += SHORT(p->width) - 1; } } } //--------------------------------------------------------------------------- // // FUNC MN_TextAWidth // // Returns the pixel width of a string using font A. // //--------------------------------------------------------------------------- int MN_TextAWidth(char *text) { char c; int width; patch_t *p; width = 0; while ((c = *text++) != 0) { if (c < 33) { width += 5; } else { p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE); width += SHORT(p->width) - 1; } } return (width); } //--------------------------------------------------------------------------- // // PROC MN_DrTextB // // Draw text using font B. // //--------------------------------------------------------------------------- void MN_DrTextB(char *text, int x, int y) { char c; patch_t *p; while ((c = *text++) != 0) { if (c < 33) { x += 8; } else { p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE); V_DrawPatch(x, y, p); x += SHORT(p->width) - 1; } } } //--------------------------------------------------------------------------- // // FUNC MN_TextBWidth // // Returns the pixel width of a string using font B. // //--------------------------------------------------------------------------- int MN_TextBWidth(char *text) { char c; int width; patch_t *p; width = 0; while ((c = *text++) != 0) { if (c < 33) { width += 5; } else { p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE); width += SHORT(p->width) - 1; } } return (width); } //--------------------------------------------------------------------------- // // PROC MN_Ticker // //--------------------------------------------------------------------------- void MN_Ticker(void) { if (MenuActive == false) { return; } MenuTime++; } //--------------------------------------------------------------------------- // // PROC MN_Drawer // //--------------------------------------------------------------------------- char *QuitEndMsg[] = { "ARE YOU SURE YOU WANT TO QUIT?", "ARE YOU SURE YOU WANT TO END THE GAME?", "DO YOU WANT TO QUICKSAVE THE GAME NAMED", "DO YOU WANT TO QUICKLOAD THE GAME NAMED", "ARE YOU SURE YOU WANT TO SUICIDE?" }; void MN_Drawer(void) { int i; int x; int y; MenuItem_t *item; char *selName; if (MenuActive == false) { if (askforquit) { MN_DrTextA(QuitEndMsg[typeofask - 1], 160 - MN_TextAWidth(QuitEndMsg[typeofask - 1]) / 2, 80); if (typeofask == 3) { MN_DrTextA(SlotText[quicksave - 1], 160 - MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90); MN_DrTextA("?", 160 + MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90); } if (typeofask == 4) { MN_DrTextA(SlotText[quickload - 1], 160 - MN_TextAWidth(SlotText[quickload - 1]) / 2, 90); MN_DrTextA("?", 160 + MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90); } UpdateState |= I_FULLSCRN; } return; } else { UpdateState |= I_FULLSCRN; if (InfoType) { MN_DrawInfo(); return; } if (screenblocks < 10) { BorderNeedRefresh = true; } if (CurrentMenu->drawFunc != NULL) { CurrentMenu->drawFunc(); } x = CurrentMenu->x; y = CurrentMenu->y; item = CurrentMenu->items; for (i = 0; i < CurrentMenu->itemCount; i++) { if (item->type != ITT_EMPTY && item->text) { MN_DrTextB(item->text, x, y); } y += ITEM_HEIGHT; item++; } y = CurrentMenu->y + (CurrentItPos * ITEM_HEIGHT) + SELECTOR_YOFFSET; selName = MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2"; V_DrawPatch(x + SELECTOR_XOFFSET, y, W_CacheLumpName(selName, PU_CACHE)); } } //--------------------------------------------------------------------------- // // PROC DrawMainMenu // //--------------------------------------------------------------------------- static void DrawMainMenu(void) { int frame; frame = (MenuTime / 5) % 7; V_DrawPatch(88, 0, W_CacheLumpName("M_HTIC", PU_CACHE)); // Old Gold skull positions: (40, 10) and (232, 10) V_DrawPatch(37, 80, W_CacheLumpNum(MauloBaseLump + (frame + 2) % 7, PU_CACHE)); V_DrawPatch(278, 80, W_CacheLumpNum(MauloBaseLump + frame, PU_CACHE)); } //========================================================================== // // DrawClassMenu // //========================================================================== static void DrawClassMenu(void) { pclass_t class; static char *boxLumpName[3] = { "m_fbox", "m_cbox", "m_mbox" }; static char *walkLumpName[3] = { "m_fwalk1", "m_cwalk1", "m_mwalk1" }; MN_DrTextB("CHOOSE CLASS:", 34, 24); class = (pclass_t) CurrentMenu->items[CurrentItPos].option; V_DrawPatch(174, 8, W_CacheLumpName(boxLumpName[class], PU_CACHE)); V_DrawPatch(174 + 24, 8 + 12, W_CacheLumpNum(W_GetNumForName(walkLumpName[class]) + ((MenuTime >> 3) & 3), PU_CACHE)); } //--------------------------------------------------------------------------- // // PROC DrawSkillMenu // //--------------------------------------------------------------------------- static void DrawSkillMenu(void) { MN_DrTextB("CHOOSE SKILL LEVEL:", 74, 16); } //--------------------------------------------------------------------------- // // PROC DrawFilesMenu // //--------------------------------------------------------------------------- static void DrawFilesMenu(void) { // clear out the quicksave/quickload stuff quicksave = 0; quickload = 0; P_ClearMessage(&players[consoleplayer]); } //--------------------------------------------------------------------------- // // PROC DrawLoadMenu // //--------------------------------------------------------------------------- static void DrawLoadMenu(void) { MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME") / 2, 10); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&LoadMenu); } //--------------------------------------------------------------------------- // // PROC DrawSaveMenu // //--------------------------------------------------------------------------- static void DrawSaveMenu(void) { MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME") / 2, 10); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&SaveMenu); } static boolean ReadDescriptionForSlot(int slot, char *description) { FILE *fp; boolean found; char name[100]; char versionText[HXS_VERSION_TEXT_LENGTH]; M_snprintf(name, sizeof(name), "%shex%d.hxs", SavePath, slot); fp = fopen(name, "rb"); if (fp == NULL) { return false; } found = fread(description, HXS_DESCRIPTION_LENGTH, 1, fp) == 1 && fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp) == 1; found = found && strcmp(versionText, HXS_VERSION_TEXT) == 0; fclose(fp); return found; } //=========================================================================== // // MN_LoadSlotText // // For each slot, looks for save games and reads the description field. // //=========================================================================== void MN_LoadSlotText(void) { char description[HXS_DESCRIPTION_LENGTH]; int slot; for (slot = 0; slot < 6; slot++) { if (ReadDescriptionForSlot(slot, description)) { memcpy(SlotText[slot], description, SLOTTEXTLEN); SlotStatus[slot] = 1; } else { memset(SlotText[slot], 0, SLOTTEXTLEN); SlotStatus[slot] = 0; } } slottextloaded = true; } //--------------------------------------------------------------------------- // // PROC DrawFileSlots // //--------------------------------------------------------------------------- static void DrawFileSlots(Menu_t * menu) { int i; int x; int y; x = menu->x; y = menu->y; for (i = 0; i < 6; i++) { V_DrawPatch(x, y, W_CacheLumpName("M_FSLOT", PU_CACHE)); if (SlotStatus[i]) { MN_DrTextA(SlotText[i], x + 5, y + 5); } y += ITEM_HEIGHT; } } //--------------------------------------------------------------------------- // // PROC DrawOptionsMenu // //--------------------------------------------------------------------------- static void DrawOptionsMenu(void) { if (messageson) { MN_DrTextB("ON", 196, 50); } else { MN_DrTextB("OFF", 196, 50); } DrawSlider(&OptionsMenu, 3, 10, mouseSensitivity); } //--------------------------------------------------------------------------- // // PROC DrawOptions2Menu // //--------------------------------------------------------------------------- static void DrawOptions2Menu(void) { DrawSlider(&Options2Menu, 1, 9, screenblocks - 3); DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume); DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume); } //--------------------------------------------------------------------------- // // PROC SCQuitGame // //--------------------------------------------------------------------------- static void SCQuitGame(int option) { MenuActive = false; askforquit = true; typeofask = 1; //quit game if (!netgame && !demoplayback) { paused = true; } } //--------------------------------------------------------------------------- // // PROC SCEndGame // //--------------------------------------------------------------------------- static void SCEndGame(int option) { if (demoplayback) { return; } if (SCNetCheck(3)) { MenuActive = false; askforquit = true; typeofask = 2; //endgame if (!netgame && !demoplayback) { paused = true; } } } //--------------------------------------------------------------------------- // // PROC SCMessages // //--------------------------------------------------------------------------- static void SCMessages(int option) { messageson ^= 1; if (messageson) { P_SetMessage(&players[consoleplayer], "MESSAGES ON", true); } else { P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true); } S_StartSound(NULL, SFX_CHAT); } //=========================================================================== // // SCNetCheck // //=========================================================================== static boolean SCNetCheck(int option) { if (!netgame) { return true; } switch (option) { case 1: // new game P_SetMessage(&players[consoleplayer], "YOU CAN'T START A NEW GAME IN NETPLAY!", true); break; case 2: // load game P_SetMessage(&players[consoleplayer], "YOU CAN'T LOAD A GAME IN NETPLAY!", true); break; case 3: // end game P_SetMessage(&players[consoleplayer], "YOU CAN'T END A GAME IN NETPLAY!", true); break; } MenuActive = false; S_StartSound(NULL, SFX_CHAT); return false; } //=========================================================================== // // SCNetCheck2 // //=========================================================================== static void SCNetCheck2(int option) { SCNetCheck(option); return; } //--------------------------------------------------------------------------- // // PROC SCLoadGame // //--------------------------------------------------------------------------- static void SCLoadGame(int option) { if (!SlotStatus[option]) { // Don't try to load from an empty slot return; } G_LoadGame(option); MN_DeactivateMenu(); BorderNeedRefresh = true; if (quickload == -1) { quickload = option + 1; P_ClearMessage(&players[consoleplayer]); } } //--------------------------------------------------------------------------- // // PROC SCSaveGame // //--------------------------------------------------------------------------- static void SCSaveGame(int option) { char *ptr; if (!FileMenuKeySteal) { FileMenuKeySteal = true; M_StringCopy(oldSlotText, SlotText[option], sizeof(oldSlotText)); ptr = SlotText[option]; while (*ptr) { ptr++; } *ptr = '['; *(ptr + 1) = 0; SlotStatus[option]++; currentSlot = option; slotptr = ptr - SlotText[option]; return; } else { G_SaveGame(option, SlotText[option]); FileMenuKeySteal = false; MN_DeactivateMenu(); } BorderNeedRefresh = true; if (quicksave == -1) { quicksave = option + 1; P_ClearMessage(&players[consoleplayer]); } } //========================================================================== // // SCClass // //========================================================================== static void SCClass(int option) { if (netgame) { P_SetMessage(&players[consoleplayer], "YOU CAN'T START A NEW GAME FROM WITHIN A NETGAME!", true); return; } MenuPClass = option; switch (MenuPClass) { case PCLASS_FIGHTER: SkillMenu.x = 120; SkillItems[0].text = "SQUIRE"; SkillItems[1].text = "KNIGHT"; SkillItems[2].text = "WARRIOR"; SkillItems[3].text = "BERSERKER"; SkillItems[4].text = "TITAN"; break; case PCLASS_CLERIC: SkillMenu.x = 116; SkillItems[0].text = "ALTAR BOY"; SkillItems[1].text = "ACOLYTE"; SkillItems[2].text = "PRIEST"; SkillItems[3].text = "CARDINAL"; SkillItems[4].text = "POPE"; break; case PCLASS_MAGE: SkillMenu.x = 112; SkillItems[0].text = "APPRENTICE"; SkillItems[1].text = "ENCHANTER"; SkillItems[2].text = "SORCERER"; SkillItems[3].text = "WARLOCK"; SkillItems[4].text = "ARCHIMAGE"; break; } SetMenu(MENU_SKILL); } //--------------------------------------------------------------------------- // // PROC SCSkill // //--------------------------------------------------------------------------- static void SCSkill(int option) { PlayerClass[consoleplayer] = MenuPClass; G_DeferredNewGame(option); SB_SetClassData(); SB_state = -1; MN_DeactivateMenu(); } //--------------------------------------------------------------------------- // // PROC SCMouseSensi // //--------------------------------------------------------------------------- static void SCMouseSensi(int option) { if (option == RIGHT_DIR) { if (mouseSensitivity < 9) { mouseSensitivity++; } } else if (mouseSensitivity) { mouseSensitivity--; } } //--------------------------------------------------------------------------- // // PROC SCSfxVolume // //--------------------------------------------------------------------------- static void SCSfxVolume(int option) { if (option == RIGHT_DIR) { if (snd_MaxVolume < 15) { snd_MaxVolume++; } } else if (snd_MaxVolume) { snd_MaxVolume--; } soundchanged = true; // we'll set it when we leave the menu } //--------------------------------------------------------------------------- // // PROC SCMusicVolume // //--------------------------------------------------------------------------- static void SCMusicVolume(int option) { if (option == RIGHT_DIR) { if (snd_MusicVolume < 15) { snd_MusicVolume++; } } else if (snd_MusicVolume) { snd_MusicVolume--; } S_SetMusicVolume(); } //--------------------------------------------------------------------------- // // PROC SCScreenSize // //--------------------------------------------------------------------------- static void SCScreenSize(int option) { if (option == RIGHT_DIR) { if (screenblocks < 11) { screenblocks++; } } else if (screenblocks > 3) { screenblocks--; } R_SetViewSize(screenblocks, detailLevel); } //--------------------------------------------------------------------------- // // PROC SCInfo // //--------------------------------------------------------------------------- static void SCInfo(int option) { InfoType = 1; S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); if (!netgame && !demoplayback) { paused = true; } } //--------------------------------------------------------------------------- // // FUNC MN_Responder // //--------------------------------------------------------------------------- boolean MN_Responder(event_t * event) { int key; int charTyped; int i; MenuItem_t *item; extern boolean automapactive; extern void H2_StartTitle(void); extern void G_CheckDemoStatus(void); char *textBuffer; // In testcontrols mode, none of the function keys should do anything // - the only key is escape to quit. if (testcontrols) { if (event->type == ev_quit || (event->type == ev_keydown && (event->data1 == key_menu_activate || event->data1 == key_menu_quit))) { I_Quit(); return true; } return false; } // "close" button pressed on window? if (event->type == ev_quit) { // First click on close = bring up quit confirm message. // Second click = confirm quit. if (!MenuActive && askforquit && typeofask == 1) { G_CheckDemoStatus(); I_Quit(); } else { SCQuitGame(0); S_StartSound(NULL, SFX_CHAT); } return true; } // Allow the menu to be activated from a joystick button if a button // is bound for joybmenu. if (event->type == ev_joystick) { if (joybmenu >= 0 && (event->data1 & (1 << joybmenu)) != 0) { MN_ActivateMenu(); return true; } } // Only care about keypresses beyond this point. if (event->type != ev_keydown) { return false; } key = event->data1; charTyped = event->data2; if (InfoType) { /* The 4-Level Demo Version also has 3 Info pages if (gamemode == shareware) { InfoType = (InfoType + 1) % 5; } else */ { InfoType = (InfoType + 1) % 4; } if (key == KEY_ESCAPE) { InfoType = 0; } if (!InfoType) { if (!netgame && !demoplayback) { paused = false; } MN_DeactivateMenu(); SB_state = -1; //refresh the statbar BorderNeedRefresh = true; } S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); return (true); //make the info screen eat the keypress } if ((ravpic && key == KEY_F1) || (key != 0 && key == key_menu_screenshot)) { G_ScreenShot(); return (true); } if (askforquit) { if (key == key_menu_confirm) { switch (typeofask) { case 1: G_CheckDemoStatus(); I_Quit(); return false; case 2: P_ClearMessage(&players[consoleplayer]); askforquit = false; typeofask = 0; paused = false; I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); H2_StartTitle(); // go to intro/demo mode. return false; case 3: P_SetMessage(&players[consoleplayer], "QUICKSAVING....", false); FileMenuKeySteal = true; SCSaveGame(quicksave - 1); BorderNeedRefresh = true; break; case 4: P_SetMessage(&players[consoleplayer], "QUICKLOADING....", false); SCLoadGame(quickload - 1); BorderNeedRefresh = true; break; case 5: BorderNeedRefresh = true; mn_SuicideConsole = true; break; default: break; } askforquit = false; typeofask = 0; return true; } else if (key == key_menu_abort || key == KEY_ESCAPE) { players[consoleplayer].messageTics = 0; askforquit = false; typeofask = 0; paused = false; UpdateState |= I_FULLSCRN; BorderNeedRefresh = true; return true; } return false; // don't let the keys filter thru } if (!MenuActive && !chatmodeon) { if (key == key_menu_decscreen) { if (automapactive) { // Don't screen size in automap return (false); } SCScreenSize(LEFT_DIR); S_StartSound(NULL, SFX_PICKUP_KEY); BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; return (true); } else if (key == key_menu_incscreen) { if (automapactive) { // Don't screen size in automap return (false); } SCScreenSize(RIGHT_DIR); S_StartSound(NULL, SFX_PICKUP_KEY); BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; return (true); } else if (key == key_menu_help) // F1 (help screen) { SCInfo(0); // start up info screens MenuActive = true; return (true); } else if (key == key_menu_save) // F2 (save game) { if (gamestate == GS_LEVEL && !demoplayback) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &SaveMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); slottextloaded = false; //reload the slot text, when needed } return true; } else if (key == key_menu_load) // F3 (load game) { if (SCNetCheck(2)) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &LoadMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); slottextloaded = false; //reload the slot text, when needed } return true; } else if (key == key_menu_volume) // F4 (volume) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &Options2Menu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); slottextloaded = false; //reload the slot text, when needed return true; } else if (key == key_menu_detail) // F5 (suicide) { MenuActive = false; askforquit = true; typeofask = 5; // suicide return true; } else if (key == key_menu_qsave) // F6 (quicksave) { if (gamestate == GS_LEVEL && !demoplayback) { if (!quicksave || quicksave == -1) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &SaveMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); slottextloaded = false; //reload the slot text quicksave = -1; P_SetMessage(&players[consoleplayer], "CHOOSE A QUICKSAVE SLOT", true); } else { askforquit = true; typeofask = 3; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, SFX_CHAT); } } return true; } else if (key == key_menu_endgame) // F7 (end game) { if (SCNetCheck(3)) { if (gamestate == GS_LEVEL && !demoplayback) { S_StartSound(NULL, SFX_CHAT); SCEndGame(0); } } return true; } else if (key == key_menu_messages) // F8 (toggle messages) { SCMessages(0); return true; } else if (key == key_menu_qload) // F9 (quickload) { if (SCNetCheck(2)) { if (!quickload || quickload == -1) { MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &LoadMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); slottextloaded = false; // reload the slot text quickload = -1; P_SetMessage(&players[consoleplayer], "CHOOSE A QUICKLOAD SLOT", true); } else { askforquit = true; if (!netgame && !demoplayback) { paused = true; } typeofask = 4; S_StartSound(NULL, SFX_CHAT); } } return true; } else if (key == key_menu_quit) // F10 (quit) { if (gamestate == GS_LEVEL || gamestate == GS_FINALE) { SCQuitGame(0); S_StartSound(NULL, SFX_CHAT); } return true; } else if (key == key_menu_gamma) // F11 (gamma correction) { usegamma++; if (usegamma > 4) { usegamma = 0; } SB_PaletteFlash(true); // force change P_SetMessage(&players[consoleplayer], GammaText[usegamma], false); return true; } else if (key == KEY_F12) // F12 (???) { // F12 - reload current map (devmaps mode) if (netgame) { return false; } if (gamekeydown[key_speed]) { // Monsters ON nomonsters = false; } if (gamekeydown[key_strafe]) { // Monsters OFF nomonsters = true; } G_DeferedInitNew(gameskill, gameepisode, gamemap); P_SetMessage(&players[consoleplayer], TXT_CHEATWARP, false); return true; } } if (!MenuActive) { if (key == key_menu_activate || gamestate == GS_DEMOSCREEN || demoplayback) { MN_ActivateMenu(); return (true); } return (false); } if (!FileMenuKeySteal) { item = &CurrentMenu->items[CurrentItPos]; if (key == key_menu_down) // Next menu item { do { if (CurrentItPos + 1 > CurrentMenu->itemCount - 1) { CurrentItPos = 0; } else { CurrentItPos++; } } while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY); S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL); return (true); } else if (key == key_menu_up) // Previous menu item { do { if (CurrentItPos == 0) { CurrentItPos = CurrentMenu->itemCount - 1; } else { CurrentItPos--; } } while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY); S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL); return (true); } else if (key == key_menu_left) // Slider left { if (item->type == ITT_LRFUNC && item->func != NULL) { item->func(LEFT_DIR); S_StartSound(NULL, SFX_PICKUP_KEY); } return (true); } else if (key == key_menu_right) // Slider right { if (item->type == ITT_LRFUNC && item->func != NULL) { item->func(RIGHT_DIR); S_StartSound(NULL, SFX_PICKUP_KEY); } return (true); } else if (key == key_menu_forward) // Activate item (enter) { if (item->type == ITT_SETMENU) { if (item->func != NULL) { item->func(item->option); } SetMenu(item->menu); } else if (item->func != NULL) { CurrentMenu->oldItPos = CurrentItPos; if (item->type == ITT_LRFUNC) { item->func(RIGHT_DIR); } else if (item->type == ITT_EFUNC) { item->func(item->option); } } S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE); return (true); } else if (key == key_menu_activate) { MN_DeactivateMenu(); return (true); } else if (key == key_menu_back) { S_StartSound(NULL, SFX_PICKUP_KEY); if (CurrentMenu->prevMenu == MENU_NONE) { MN_DeactivateMenu(); } else { SetMenu(CurrentMenu->prevMenu); } return (true); } else if (charTyped != 0) { for (i = 0; i < CurrentMenu->itemCount; i++) { if (CurrentMenu->items[i].text) { if (toupper(charTyped) == toupper(CurrentMenu->items[i].text[0])) { CurrentItPos = i; return (true); } } } } return (false); } else { // Editing file names textBuffer = &SlotText[currentSlot][slotptr]; if (key == KEY_BACKSPACE) { if (slotptr) { *textBuffer-- = 0; *textBuffer = ASCII_CURSOR; slotptr--; } return (true); } if (key == KEY_ESCAPE) { M_StringCopy(SlotText[currentSlot], oldSlotText, sizeof(SlotText[currentSlot])); SlotStatus[currentSlot]--; MN_DeactivateMenu(); return (true); } if (key == KEY_ENTER) { SlotText[currentSlot][slotptr] = 0; // clear the cursor item = &CurrentMenu->items[CurrentItPos]; CurrentMenu->oldItPos = CurrentItPos; if (item->type == ITT_EFUNC) { item->func(item->option); if (item->menu != MENU_NONE) { SetMenu(item->menu); } } return (true); } if (slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE) { if (isalpha(charTyped)) { *textBuffer++ = toupper(charTyped); *textBuffer = ASCII_CURSOR; slotptr++; return (true); } if (isdigit(charTyped) || charTyped == ' ' || charTyped == ',' || charTyped == '.' || charTyped == '-' || charTyped == '!') { *textBuffer++ = charTyped; *textBuffer = ASCII_CURSOR; slotptr++; return (true); } } return (true); } return (false); } //--------------------------------------------------------------------------- // // PROC MN_ActivateMenu // //--------------------------------------------------------------------------- void MN_ActivateMenu(void) { if (MenuActive) { return; } if (paused) { S_ResumeSound(); } MenuActive = true; FileMenuKeySteal = false; MenuTime = 0; CurrentMenu = &MainMenu; CurrentItPos = CurrentMenu->oldItPos; if (!netgame && !demoplayback) { paused = true; } S_StartSound(NULL, SFX_PLATFORM_STOP); slottextloaded = false; //reload the slot text, when needed } //--------------------------------------------------------------------------- // // PROC MN_DeactivateMenu // //--------------------------------------------------------------------------- void MN_DeactivateMenu(void) { if (CurrentMenu != NULL) { CurrentMenu->oldItPos = CurrentItPos; } MenuActive = false; if (!netgame) { paused = false; } S_StartSound(NULL, SFX_PLATFORM_STOP); P_ClearMessage(&players[consoleplayer]); } //--------------------------------------------------------------------------- // // PROC MN_DrawInfo // //--------------------------------------------------------------------------- void MN_DrawInfo(void) { I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); memcpy(I_VideoBuffer, (byte *) W_CacheLumpNum(W_GetNumForName("TITLE") + InfoType, PU_CACHE), SCREENWIDTH * SCREENHEIGHT); // V_DrawPatch(0, 0, W_CacheLumpNum(W_GetNumForName("TITLE")+InfoType, // PU_CACHE)); } //--------------------------------------------------------------------------- // // PROC SetMenu // //--------------------------------------------------------------------------- static void SetMenu(MenuType_t menu) { CurrentMenu->oldItPos = CurrentItPos; CurrentMenu = Menus[menu]; CurrentItPos = CurrentMenu->oldItPos; } //--------------------------------------------------------------------------- // // PROC DrawSlider // //--------------------------------------------------------------------------- static void DrawSlider(Menu_t * menu, int item, int width, int slot) { int x; int y; int x2; int count; x = menu->x + 24; y = menu->y + 2 + (item * ITEM_HEIGHT); V_DrawPatch(x - 32, y, W_CacheLumpName("M_SLDLT", PU_CACHE)); for (x2 = x, count = width; count--; x2 += 8) { V_DrawPatch(x2, y, W_CacheLumpName(count & 1 ? "M_SLDMD1" : "M_SLDMD2", PU_CACHE)); } V_DrawPatch(x2, y, W_CacheLumpName("M_SLDRT", PU_CACHE)); V_DrawPatch(x + 4 + slot * 8, y + 7, W_CacheLumpName("M_SLDKB", PU_CACHE)); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_acs.c000066400000000000000000001225211257432200600224370ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "m_misc.h" #include "m_random.h" #include "s_sound.h" #include "i_swap.h" #include "i_system.h" #include "p_local.h" // MACROS ------------------------------------------------------------------ #define MAX_SCRIPT_ARGS 3 #define SCRIPT_CONTINUE 0 #define SCRIPT_STOP 1 #define SCRIPT_TERMINATE 2 #define OPEN_SCRIPTS_BASE 1000 #define PRINT_BUFFER_SIZE 256 #define GAME_SINGLE_PLAYER 0 #define GAME_NET_COOPERATIVE 1 #define GAME_NET_DEATHMATCH 2 #define TEXTURE_TOP 0 #define TEXTURE_MIDDLE 1 #define TEXTURE_BOTTOM 2 #define S_DROP ACScript->stackPtr-- #define S_POP ACScript->stack[--ACScript->stackPtr] #define S_PUSH(x) ACScript->stack[ACScript->stackPtr++] = x // TYPES ------------------------------------------------------------------- typedef struct { int marker; int infoOffset; int code; } PACKEDATTR acsHeader_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void StartOpenACS(int number, int infoIndex, int *address); static void ScriptFinished(int number); static boolean TagBusy(int tag); static boolean AddToACSStore(int map, int number, byte * args); static int GetACSIndex(int number); static void Push(int value); static int Pop(void); static int Top(void); static void Drop(void); static int CmdNOP(void); static int CmdTerminate(void); static int CmdSuspend(void); static int CmdPushNumber(void); static int CmdLSpec1(void); static int CmdLSpec2(void); static int CmdLSpec3(void); static int CmdLSpec4(void); static int CmdLSpec5(void); static int CmdLSpec1Direct(void); static int CmdLSpec2Direct(void); static int CmdLSpec3Direct(void); static int CmdLSpec4Direct(void); static int CmdLSpec5Direct(void); static int CmdAdd(void); static int CmdSubtract(void); static int CmdMultiply(void); static int CmdDivide(void); static int CmdModulus(void); static int CmdEQ(void); static int CmdNE(void); static int CmdLT(void); static int CmdGT(void); static int CmdLE(void); static int CmdGE(void); static int CmdAssignScriptVar(void); static int CmdAssignMapVar(void); static int CmdAssignWorldVar(void); static int CmdPushScriptVar(void); static int CmdPushMapVar(void); static int CmdPushWorldVar(void); static int CmdAddScriptVar(void); static int CmdAddMapVar(void); static int CmdAddWorldVar(void); static int CmdSubScriptVar(void); static int CmdSubMapVar(void); static int CmdSubWorldVar(void); static int CmdMulScriptVar(void); static int CmdMulMapVar(void); static int CmdMulWorldVar(void); static int CmdDivScriptVar(void); static int CmdDivMapVar(void); static int CmdDivWorldVar(void); static int CmdModScriptVar(void); static int CmdModMapVar(void); static int CmdModWorldVar(void); static int CmdIncScriptVar(void); static int CmdIncMapVar(void); static int CmdIncWorldVar(void); static int CmdDecScriptVar(void); static int CmdDecMapVar(void); static int CmdDecWorldVar(void); static int CmdGoto(void); static int CmdIfGoto(void); static int CmdDrop(void); static int CmdDelay(void); static int CmdDelayDirect(void); static int CmdRandom(void); static int CmdRandomDirect(void); static int CmdThingCount(void); static int CmdThingCountDirect(void); static int CmdTagWait(void); static int CmdTagWaitDirect(void); static int CmdPolyWait(void); static int CmdPolyWaitDirect(void); static int CmdChangeFloor(void); static int CmdChangeFloorDirect(void); static int CmdChangeCeiling(void); static int CmdChangeCeilingDirect(void); static int CmdRestart(void); static int CmdAndLogical(void); static int CmdOrLogical(void); static int CmdAndBitwise(void); static int CmdOrBitwise(void); static int CmdEorBitwise(void); static int CmdNegateLogical(void); static int CmdLShift(void); static int CmdRShift(void); static int CmdUnaryMinus(void); static int CmdIfNotGoto(void); static int CmdLineSide(void); static int CmdScriptWait(void); static int CmdScriptWaitDirect(void); static int CmdClearLineSpecial(void); static int CmdCaseGoto(void); static int CmdBeginPrint(void); static int CmdEndPrint(void); static int CmdPrintString(void); static int CmdPrintNumber(void); static int CmdPrintCharacter(void); static int CmdPlayerCount(void); static int CmdGameType(void); static int CmdGameSkill(void); static int CmdTimer(void); static int CmdSectorSound(void); static int CmdAmbientSound(void); static int CmdSoundSequence(void); static int CmdSetLineTexture(void); static int CmdSetLineBlocking(void); static int CmdSetLineSpecial(void); static int CmdThingSound(void); static int CmdEndPrintBold(void); static void ThingCount(int type, int tid); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- int ACScriptCount; byte *ActionCodeBase; acsInfo_t *ACSInfo; int MapVars[MAX_ACS_MAP_VARS]; int WorldVars[MAX_ACS_WORLD_VARS]; acsstore_t ACSStore[MAX_ACS_STORE + 1]; // +1 for termination marker // PRIVATE DATA DEFINITIONS ------------------------------------------------ static acs_t *ACScript; static int *PCodePtr; static byte SpecArgs[8]; static int ACStringCount; static char **ACStrings; static char PrintBuffer[PRINT_BUFFER_SIZE]; static acs_t *NewScript; static int (*PCodeCmds[]) (void) = { CmdNOP, CmdTerminate, CmdSuspend, CmdPushNumber, CmdLSpec1, CmdLSpec2, CmdLSpec3, CmdLSpec4, CmdLSpec5, CmdLSpec1Direct, CmdLSpec2Direct, CmdLSpec3Direct, CmdLSpec4Direct, CmdLSpec5Direct, CmdAdd, CmdSubtract, CmdMultiply, CmdDivide, CmdModulus, CmdEQ, CmdNE, CmdLT, CmdGT, CmdLE, CmdGE, CmdAssignScriptVar, CmdAssignMapVar, CmdAssignWorldVar, CmdPushScriptVar, CmdPushMapVar, CmdPushWorldVar, CmdAddScriptVar, CmdAddMapVar, CmdAddWorldVar, CmdSubScriptVar, CmdSubMapVar, CmdSubWorldVar, CmdMulScriptVar, CmdMulMapVar, CmdMulWorldVar, CmdDivScriptVar, CmdDivMapVar, CmdDivWorldVar, CmdModScriptVar, CmdModMapVar, CmdModWorldVar, CmdIncScriptVar, CmdIncMapVar, CmdIncWorldVar, CmdDecScriptVar, CmdDecMapVar, CmdDecWorldVar, CmdGoto, CmdIfGoto, CmdDrop, CmdDelay, CmdDelayDirect, CmdRandom, CmdRandomDirect, CmdThingCount, CmdThingCountDirect, CmdTagWait, CmdTagWaitDirect, CmdPolyWait, CmdPolyWaitDirect, CmdChangeFloor, CmdChangeFloorDirect, CmdChangeCeiling, CmdChangeCeilingDirect, CmdRestart, CmdAndLogical, CmdOrLogical, CmdAndBitwise, CmdOrBitwise, CmdEorBitwise, CmdNegateLogical, CmdLShift, CmdRShift, CmdUnaryMinus, CmdIfNotGoto, CmdLineSide, CmdScriptWait, CmdScriptWaitDirect, CmdClearLineSpecial, CmdCaseGoto, CmdBeginPrint, CmdEndPrint, CmdPrintString, CmdPrintNumber, CmdPrintCharacter, CmdPlayerCount, CmdGameType, CmdGameSkill, CmdTimer, CmdSectorSound, CmdAmbientSound, CmdSoundSequence, CmdSetLineTexture, CmdSetLineBlocking, CmdSetLineSpecial, CmdThingSound, CmdEndPrintBold, }; // CODE -------------------------------------------------------------------- //========================================================================== // // P_LoadACScripts // //========================================================================== void P_LoadACScripts(int lump) { int i; int *buffer; acsHeader_t *header; acsInfo_t *info; header = W_CacheLumpNum(lump, PU_LEVEL); ActionCodeBase = (byte *) header; buffer = (int *) ((byte *) header + LONG(header->infoOffset)); ACScriptCount = LONG(*buffer); ++buffer; if (ACScriptCount == 0) { // Empty behavior lump return; } ACSInfo = Z_Malloc(ACScriptCount * sizeof(acsInfo_t), PU_LEVEL, 0); memset(ACSInfo, 0, ACScriptCount * sizeof(acsInfo_t)); for (i = 0, info = ACSInfo; i < ACScriptCount; i++, info++) { info->number = LONG(*buffer); ++buffer; info->address = (int *) ((byte *) ActionCodeBase + LONG(*buffer)); ++buffer; info->argCount = LONG(*buffer); ++buffer; if (info->argCount > MAX_SCRIPT_ARGS) { fprintf(stderr, "Warning: ACS script #%i has %i arguments, more " "than the maximum of %i. Enforcing limit.\n" "If you are seeing this message, please report " "the name of the WAD where you saw it.\n", i, info->argCount, MAX_SCRIPT_ARGS); info->argCount = MAX_SCRIPT_ARGS; } if (info->number >= OPEN_SCRIPTS_BASE) { // Auto-activate info->number -= OPEN_SCRIPTS_BASE; StartOpenACS(info->number, i, info->address); info->state = ASTE_RUNNING; } else { info->state = ASTE_INACTIVE; } } ACStringCount = LONG(*buffer); ++buffer; ACStrings = Z_Malloc(ACStringCount * sizeof(char *), PU_LEVEL, NULL); for (i=0; inumber = number; // World objects are allotted 1 second for initialization script->delayCount = 35; script->infoIndex = infoIndex; script->ip = address; script->thinker.function = T_InterpretACS; P_AddThinker(&script->thinker); } //========================================================================== // // P_CheckACSStore // // Scans the ACS store and executes all scripts belonging to the current // map. // //========================================================================== void P_CheckACSStore(void) { acsstore_t *store; for (store = ACSStore; store->map != 0; store++) { if (store->map == gamemap) { P_StartACS(store->script, 0, store->args, NULL, NULL, 0); if (NewScript) { NewScript->delayCount = 35; } store->map = -1; } } } //========================================================================== // // P_StartACS // // Start an ACS script. The 'args' array should be at least MAX_SCRIPT_ARGS // elements in length. // //========================================================================== static char ErrorMsg[128]; boolean P_StartACS(int number, int map, byte * args, mobj_t * activator, line_t * line, int side) { int i; acs_t *script; int infoIndex; aste_t *statePtr; NewScript = NULL; if (map && map != gamemap) { // Add to the script store return AddToACSStore(map, number, args); } infoIndex = GetACSIndex(number); if (infoIndex == -1) { // Script not found //I_Error("P_StartACS: Unknown script number %d", number); M_snprintf(ErrorMsg, sizeof(ErrorMsg), "P_STARTACS ERROR: UNKNOWN SCRIPT %d", number); P_SetMessage(&players[consoleplayer], ErrorMsg, true); } statePtr = &ACSInfo[infoIndex].state; if (*statePtr == ASTE_SUSPENDED) { // Resume a suspended script *statePtr = ASTE_RUNNING; return true; } if (*statePtr != ASTE_INACTIVE) { // Script is already executing return false; } script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0); memset(script, 0, sizeof(acs_t)); script->number = number; script->infoIndex = infoIndex; script->activator = activator; script->line = line; script->side = side; script->ip = ACSInfo[infoIndex].address; script->thinker.function = T_InterpretACS; for (i = 0; i < MAX_SCRIPT_ARGS && i < ACSInfo[infoIndex].argCount; i++) { script->vars[i] = args[i]; } *statePtr = ASTE_RUNNING; P_AddThinker(&script->thinker); NewScript = script; return true; } //========================================================================== // // AddToACSStore // //========================================================================== static boolean AddToACSStore(int map, int number, byte * args) { int i; int index; index = -1; for (i = 0; ACSStore[i].map != 0; i++) { if (ACSStore[i].script == number && ACSStore[i].map == map) { // Don't allow duplicates return false; } if (index == -1 && ACSStore[i].map == -1) { // Remember first empty slot index = i; } } if (index == -1) { // Append required if (i == MAX_ACS_STORE) { I_Error("AddToACSStore: MAX_ACS_STORE (%d) exceeded.", MAX_ACS_STORE); } index = i; ACSStore[index + 1].map = 0; } ACSStore[index].map = map; ACSStore[index].script = number; memcpy(ACSStore[index].args, args, MAX_SCRIPT_ARGS); return true; } //========================================================================== // // P_StartLockedACS // //========================================================================== boolean P_StartLockedACS(line_t * line, byte * args, mobj_t * mo, int side) { int i; int lock; byte newArgs[5]; char LockedBuffer[80]; extern char *TextKeyMessages[11]; lock = args[4]; if (!mo->player) { return false; } if (lock) { if (!(mo->player->keys & (1 << (lock - 1)))) { M_snprintf(LockedBuffer, sizeof(LockedBuffer), "YOU NEED THE %s\n", TextKeyMessages[lock - 1]); P_SetMessage(mo->player, LockedBuffer, true); S_StartSound(mo, SFX_DOOR_LOCKED); return false; } } for (i = 0; i < 4; i++) { newArgs[i] = args[i]; } newArgs[4] = 0; return P_StartACS(newArgs[0], newArgs[1], &newArgs[2], mo, line, side); } //========================================================================== // // P_TerminateACS // //========================================================================== boolean P_TerminateACS(int number, int map) { int infoIndex; infoIndex = GetACSIndex(number); if (infoIndex == -1) { // Script not found return false; } if (ACSInfo[infoIndex].state == ASTE_INACTIVE || ACSInfo[infoIndex].state == ASTE_TERMINATING) { // States that disallow termination return false; } ACSInfo[infoIndex].state = ASTE_TERMINATING; return true; } //========================================================================== // // P_SuspendACS // //========================================================================== boolean P_SuspendACS(int number, int map) { int infoIndex; infoIndex = GetACSIndex(number); if (infoIndex == -1) { // Script not found return false; } if (ACSInfo[infoIndex].state == ASTE_INACTIVE || ACSInfo[infoIndex].state == ASTE_SUSPENDED || ACSInfo[infoIndex].state == ASTE_TERMINATING) { // States that disallow suspension return false; } ACSInfo[infoIndex].state = ASTE_SUSPENDED; return true; } //========================================================================== // // P_Init // //========================================================================== void P_ACSInitNewGame(void) { memset(WorldVars, 0, sizeof(WorldVars)); memset(ACSStore, 0, sizeof(ACSStore)); } //========================================================================== // // T_InterpretACS // //========================================================================== void T_InterpretACS(acs_t * script) { int cmd; int action; if (ACSInfo[script->infoIndex].state == ASTE_TERMINATING) { ACSInfo[script->infoIndex].state = ASTE_INACTIVE; ScriptFinished(ACScript->number); P_RemoveThinker(&ACScript->thinker); return; } if (ACSInfo[script->infoIndex].state != ASTE_RUNNING) { return; } if (script->delayCount) { script->delayCount--; return; } ACScript = script; PCodePtr = ACScript->ip; do { cmd = LONG(*PCodePtr); ++PCodePtr; action = PCodeCmds[cmd] (); } while (action == SCRIPT_CONTINUE); ACScript->ip = PCodePtr; if (action == SCRIPT_TERMINATE) { ACSInfo[script->infoIndex].state = ASTE_INACTIVE; ScriptFinished(ACScript->number); P_RemoveThinker(&ACScript->thinker); } } //========================================================================== // // P_TagFinished // //========================================================================== void P_TagFinished(int tag) { int i; if (TagBusy(tag) == true) { return; } for (i = 0; i < ACScriptCount; i++) { if (ACSInfo[i].state == ASTE_WAITINGFORTAG && ACSInfo[i].waitValue == tag) { ACSInfo[i].state = ASTE_RUNNING; } } } //========================================================================== // // P_PolyobjFinished // //========================================================================== void P_PolyobjFinished(int po) { int i; if (PO_Busy(po) == true) { return; } for (i = 0; i < ACScriptCount; i++) { if (ACSInfo[i].state == ASTE_WAITINGFORPOLY && ACSInfo[i].waitValue == po) { ACSInfo[i].state = ASTE_RUNNING; } } } //========================================================================== // // ScriptFinished // //========================================================================== static void ScriptFinished(int number) { int i; for (i = 0; i < ACScriptCount; i++) { if (ACSInfo[i].state == ASTE_WAITINGFORSCRIPT && ACSInfo[i].waitValue == number) { ACSInfo[i].state = ASTE_RUNNING; } } } //========================================================================== // // TagBusy // //========================================================================== static boolean TagBusy(int tag) { int sectorIndex; sectorIndex = -1; while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0) { if (sectors[sectorIndex].specialdata) { return true; } } return false; } //========================================================================== // // GetACSIndex // // Returns the index of a script number. Returns -1 if the script number // is not found. // //========================================================================== static int GetACSIndex(int number) { int i; for (i = 0; i < ACScriptCount; i++) { if (ACSInfo[i].number == number) { return i; } } return -1; } //========================================================================== // // Push // //========================================================================== static void Push(int value) { ACScript->stack[ACScript->stackPtr++] = value; } //========================================================================== // // Pop // //========================================================================== static int Pop(void) { return ACScript->stack[--ACScript->stackPtr]; } //========================================================================== // // Top // //========================================================================== static int Top(void) { return ACScript->stack[ACScript->stackPtr - 1]; } //========================================================================== // // Drop // //========================================================================== static void Drop(void) { ACScript->stackPtr--; } //========================================================================== // // P-Code Commands // //========================================================================== static int CmdNOP(void) { return SCRIPT_CONTINUE; } static int CmdTerminate(void) { return SCRIPT_TERMINATE; } static int CmdSuspend(void) { ACSInfo[ACScript->infoIndex].state = ASTE_SUSPENDED; return SCRIPT_STOP; } static int CmdPushNumber(void) { Push(LONG(*PCodePtr)); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdLSpec1(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[0] = Pop(); P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec2(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[1] = Pop(); SpecArgs[0] = Pop(); P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec3(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[2] = Pop(); SpecArgs[1] = Pop(); SpecArgs[0] = Pop(); P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec4(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[3] = Pop(); SpecArgs[2] = Pop(); SpecArgs[1] = Pop(); SpecArgs[0] = Pop(); P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec5(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[4] = Pop(); SpecArgs[3] = Pop(); SpecArgs[2] = Pop(); SpecArgs[1] = Pop(); SpecArgs[0] = Pop(); P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec1Direct(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[0] = LONG(*PCodePtr); ++PCodePtr; P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec2Direct(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[0] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[1] = LONG(*PCodePtr); ++PCodePtr; P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec3Direct(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[0] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[1] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[2] = LONG(*PCodePtr); ++PCodePtr; P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec4Direct(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[0] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[1] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[2] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[3] = LONG(*PCodePtr); ++PCodePtr; P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdLSpec5Direct(void) { int special; special = LONG(*PCodePtr); ++PCodePtr; SpecArgs[0] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[1] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[2] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[3] = LONG(*PCodePtr); ++PCodePtr; SpecArgs[4] = LONG(*PCodePtr); ++PCodePtr; P_ExecuteLineSpecial(special, SpecArgs, ACScript->line, ACScript->side, ACScript->activator); return SCRIPT_CONTINUE; } static int CmdAdd(void) { Push(Pop() + Pop()); return SCRIPT_CONTINUE; } static int CmdSubtract(void) { int operand2; operand2 = Pop(); Push(Pop() - operand2); return SCRIPT_CONTINUE; } static int CmdMultiply(void) { Push(Pop() * Pop()); return SCRIPT_CONTINUE; } static int CmdDivide(void) { int operand2; operand2 = Pop(); Push(Pop() / operand2); return SCRIPT_CONTINUE; } static int CmdModulus(void) { int operand2; operand2 = Pop(); Push(Pop() % operand2); return SCRIPT_CONTINUE; } static int CmdEQ(void) { Push(Pop() == Pop()); return SCRIPT_CONTINUE; } static int CmdNE(void) { Push(Pop() != Pop()); return SCRIPT_CONTINUE; } static int CmdLT(void) { int operand2; operand2 = Pop(); Push(Pop() < operand2); return SCRIPT_CONTINUE; } static int CmdGT(void) { int operand2; operand2 = Pop(); Push(Pop() > operand2); return SCRIPT_CONTINUE; } static int CmdLE(void) { int operand2; operand2 = Pop(); Push(Pop() <= operand2); return SCRIPT_CONTINUE; } static int CmdGE(void) { int operand2; operand2 = Pop(); Push(Pop() >= operand2); return SCRIPT_CONTINUE; } static int CmdAssignScriptVar(void) { ACScript->vars[LONG(*PCodePtr)] = Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdAssignMapVar(void) { MapVars[LONG(*PCodePtr)] = Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdAssignWorldVar(void) { WorldVars[LONG(*PCodePtr)] = Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdPushScriptVar(void) { Push(ACScript->vars[LONG(*PCodePtr)]); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdPushMapVar(void) { Push(MapVars[LONG(*PCodePtr)]); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdPushWorldVar(void) { Push(WorldVars[LONG(*PCodePtr)]); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdAddScriptVar(void) { ACScript->vars[LONG(*PCodePtr)] += Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdAddMapVar(void) { MapVars[LONG(*PCodePtr)] += Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdAddWorldVar(void) { WorldVars[LONG(*PCodePtr)] += Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdSubScriptVar(void) { ACScript->vars[LONG(*PCodePtr)] -= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdSubMapVar(void) { MapVars[LONG(*PCodePtr)] -= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdSubWorldVar(void) { WorldVars[LONG(*PCodePtr)] -= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdMulScriptVar(void) { ACScript->vars[LONG(*PCodePtr)] *= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdMulMapVar(void) { MapVars[LONG(*PCodePtr)] *= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdMulWorldVar(void) { WorldVars[LONG(*PCodePtr)] *= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdDivScriptVar(void) { ACScript->vars[LONG(*PCodePtr)] /= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdDivMapVar(void) { MapVars[LONG(*PCodePtr)] /= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdDivWorldVar(void) { WorldVars[LONG(*PCodePtr)] /= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdModScriptVar(void) { ACScript->vars[LONG(*PCodePtr)] %= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdModMapVar(void) { MapVars[LONG(*PCodePtr)] %= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdModWorldVar(void) { WorldVars[LONG(*PCodePtr)] %= Pop(); ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdIncScriptVar(void) { ++ACScript->vars[LONG(*PCodePtr)]; ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdIncMapVar(void) { ++MapVars[LONG(*PCodePtr)]; ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdIncWorldVar(void) { ++WorldVars[LONG(*PCodePtr)]; ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdDecScriptVar(void) { --ACScript->vars[LONG(*PCodePtr)]; ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdDecMapVar(void) { --MapVars[LONG(*PCodePtr)]; ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdDecWorldVar(void) { --WorldVars[LONG(*PCodePtr)]; ++PCodePtr; return SCRIPT_CONTINUE; } static int CmdGoto(void) { PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr)); return SCRIPT_CONTINUE; } static int CmdIfGoto(void) { if (Pop() != 0) { PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr)); } else { ++PCodePtr; } return SCRIPT_CONTINUE; } static int CmdDrop(void) { Drop(); return SCRIPT_CONTINUE; } static int CmdDelay(void) { ACScript->delayCount = Pop(); return SCRIPT_STOP; } static int CmdDelayDirect(void) { ACScript->delayCount = LONG(*PCodePtr); ++PCodePtr; return SCRIPT_STOP; } static int CmdRandom(void) { int low; int high; high = Pop(); low = Pop(); Push(low + (P_Random() % (high - low + 1))); return SCRIPT_CONTINUE; } static int CmdRandomDirect(void) { int low; int high; low = LONG(*PCodePtr); ++PCodePtr; high = LONG(*PCodePtr); ++PCodePtr; Push(low + (P_Random() % (high - low + 1))); return SCRIPT_CONTINUE; } static int CmdThingCount(void) { int tid; tid = Pop(); ThingCount(Pop(), tid); return SCRIPT_CONTINUE; } static int CmdThingCountDirect(void) { int type; type = LONG(*PCodePtr); ++PCodePtr; ThingCount(type, LONG(*PCodePtr)); ++PCodePtr; return SCRIPT_CONTINUE; } static void ThingCount(int type, int tid) { int count; int searcher; mobj_t *mobj; mobjtype_t moType; thinker_t *think; if (!(type + tid)) { // Nothing to count return; } moType = TranslateThingType[type]; count = 0; searcher = -1; if (tid) { // Count TID things while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { if (type == 0) { // Just count TIDs count++; } else if (moType == mobj->type) { if (mobj->flags & MF_COUNTKILL && mobj->health <= 0) { // Don't count dead monsters continue; } count++; } } } else { // Count only types for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mobj = (mobj_t *) think; if (mobj->type != moType) { // Doesn't match continue; } if (mobj->flags & MF_COUNTKILL && mobj->health <= 0) { // Don't count dead monsters continue; } count++; } } Push(count); } static int CmdTagWait(void) { ACSInfo[ACScript->infoIndex].waitValue = Pop(); ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG; return SCRIPT_STOP; } static int CmdTagWaitDirect(void) { ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr); ++PCodePtr; ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG; return SCRIPT_STOP; } static int CmdPolyWait(void) { ACSInfo[ACScript->infoIndex].waitValue = Pop(); ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY; return SCRIPT_STOP; } static int CmdPolyWaitDirect(void) { ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr); ++PCodePtr; ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY; return SCRIPT_STOP; } static int CmdChangeFloor(void) { int tag; int flat; int sectorIndex; flat = R_FlatNumForName(ACStrings[Pop()]); tag = Pop(); sectorIndex = -1; while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0) { sectors[sectorIndex].floorpic = flat; } return SCRIPT_CONTINUE; } static int CmdChangeFloorDirect(void) { int tag; int flat; int sectorIndex; tag = LONG(*PCodePtr); ++PCodePtr; flat = R_FlatNumForName(ACStrings[LONG(*PCodePtr)]); ++PCodePtr; sectorIndex = -1; while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0) { sectors[sectorIndex].floorpic = flat; } return SCRIPT_CONTINUE; } static int CmdChangeCeiling(void) { int tag; int flat; int sectorIndex; flat = R_FlatNumForName(ACStrings[Pop()]); tag = Pop(); sectorIndex = -1; while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0) { sectors[sectorIndex].ceilingpic = flat; } return SCRIPT_CONTINUE; } static int CmdChangeCeilingDirect(void) { int tag; int flat; int sectorIndex; tag = LONG(*PCodePtr); ++PCodePtr; flat = R_FlatNumForName(ACStrings[LONG(*PCodePtr)]); ++PCodePtr; sectorIndex = -1; while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0) { sectors[sectorIndex].ceilingpic = flat; } return SCRIPT_CONTINUE; } static int CmdRestart(void) { PCodePtr = ACSInfo[ACScript->infoIndex].address; return SCRIPT_CONTINUE; } static int CmdAndLogical(void) { Push(Pop() && Pop()); return SCRIPT_CONTINUE; } static int CmdOrLogical(void) { Push(Pop() || Pop()); return SCRIPT_CONTINUE; } static int CmdAndBitwise(void) { Push(Pop() & Pop()); return SCRIPT_CONTINUE; } static int CmdOrBitwise(void) { Push(Pop() | Pop()); return SCRIPT_CONTINUE; } static int CmdEorBitwise(void) { Push(Pop() ^ Pop()); return SCRIPT_CONTINUE; } static int CmdNegateLogical(void) { Push(!Pop()); return SCRIPT_CONTINUE; } static int CmdLShift(void) { int operand2; operand2 = Pop(); Push(Pop() << operand2); return SCRIPT_CONTINUE; } static int CmdRShift(void) { int operand2; operand2 = Pop(); Push(Pop() >> operand2); return SCRIPT_CONTINUE; } static int CmdUnaryMinus(void) { Push(-Pop()); return SCRIPT_CONTINUE; } static int CmdIfNotGoto(void) { if (Pop() != 0) { ++PCodePtr; } else { PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr)); } return SCRIPT_CONTINUE; } static int CmdLineSide(void) { Push(ACScript->side); return SCRIPT_CONTINUE; } static int CmdScriptWait(void) { ACSInfo[ACScript->infoIndex].waitValue = Pop(); ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT; return SCRIPT_STOP; } static int CmdScriptWaitDirect(void) { ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr); ++PCodePtr; ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT; return SCRIPT_STOP; } static int CmdClearLineSpecial(void) { if (ACScript->line) { ACScript->line->special = 0; } return SCRIPT_CONTINUE; } static int CmdCaseGoto(void) { int value; value = LONG(*PCodePtr); ++PCodePtr; if (Top() == value) { PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr)); Drop(); } else { ++PCodePtr; } return SCRIPT_CONTINUE; } static int CmdBeginPrint(void) { *PrintBuffer = 0; return SCRIPT_CONTINUE; } static int CmdEndPrint(void) { player_t *player; if (ACScript->activator && ACScript->activator->player) { player = ACScript->activator->player; } else { player = &players[consoleplayer]; } P_SetMessage(player, PrintBuffer, true); return SCRIPT_CONTINUE; } static int CmdEndPrintBold(void) { int i; for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { P_SetYellowMessage(&players[i], PrintBuffer, true); } } return SCRIPT_CONTINUE; } static int CmdPrintString(void) { M_StringConcat(PrintBuffer, ACStrings[Pop()], sizeof(PrintBuffer)); return SCRIPT_CONTINUE; } static int CmdPrintNumber(void) { char tempStr[16]; M_snprintf(tempStr, sizeof(tempStr), "%d", Pop()); M_StringConcat(PrintBuffer, tempStr, sizeof(PrintBuffer)); return SCRIPT_CONTINUE; } static int CmdPrintCharacter(void) { char *bufferEnd; bufferEnd = PrintBuffer + strlen(PrintBuffer); *bufferEnd++ = Pop(); *bufferEnd = 0; return SCRIPT_CONTINUE; } static int CmdPlayerCount(void) { int i; int count; count = 0; for (i = 0; i < maxplayers; i++) { count += playeringame[i]; } Push(count); return SCRIPT_CONTINUE; } static int CmdGameType(void) { int gametype; if (netgame == false) { gametype = GAME_SINGLE_PLAYER; } else if (deathmatch) { gametype = GAME_NET_DEATHMATCH; } else { gametype = GAME_NET_COOPERATIVE; } Push(gametype); return SCRIPT_CONTINUE; } static int CmdGameSkill(void) { Push(gameskill); return SCRIPT_CONTINUE; } static int CmdTimer(void) { Push(leveltime); return SCRIPT_CONTINUE; } static int CmdSectorSound(void) { int volume; mobj_t *mobj; mobj = NULL; if (ACScript->line) { mobj = (mobj_t *) & ACScript->line->frontsector->soundorg; } volume = Pop(); S_StartSoundAtVolume(mobj, S_GetSoundID(ACStrings[Pop()]), volume); return SCRIPT_CONTINUE; } static int CmdThingSound(void) { int tid; int sound; int volume; mobj_t *mobj; int searcher; volume = Pop(); sound = S_GetSoundID(ACStrings[Pop()]); tid = Pop(); searcher = -1; while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { S_StartSoundAtVolume(mobj, sound, volume); } return SCRIPT_CONTINUE; } static int CmdAmbientSound(void) { int volume; volume = Pop(); S_StartSoundAtVolume(NULL, S_GetSoundID(ACStrings[Pop()]), volume); return SCRIPT_CONTINUE; } static int CmdSoundSequence(void) { mobj_t *mobj; mobj = NULL; if (ACScript->line) { mobj = (mobj_t *) & ACScript->line->frontsector->soundorg; } SN_StartSequenceName(mobj, ACStrings[Pop()]); return SCRIPT_CONTINUE; } static int CmdSetLineTexture(void) { line_t *line; int lineTag; int side; int position; int texture; int searcher; texture = R_TextureNumForName(ACStrings[Pop()]); position = Pop(); side = Pop(); lineTag = Pop(); searcher = -1; while ((line = P_FindLine(lineTag, &searcher)) != NULL) { if (position == TEXTURE_MIDDLE) { sides[line->sidenum[side]].midtexture = texture; } else if (position == TEXTURE_BOTTOM) { sides[line->sidenum[side]].bottomtexture = texture; } else { // TEXTURE_TOP sides[line->sidenum[side]].toptexture = texture; } } return SCRIPT_CONTINUE; } static int CmdSetLineBlocking(void) { line_t *line; int lineTag; boolean blocking; int searcher; blocking = Pop()? ML_BLOCKING : 0; lineTag = Pop(); searcher = -1; while ((line = P_FindLine(lineTag, &searcher)) != NULL) { line->flags = (line->flags & ~ML_BLOCKING) | blocking; } return SCRIPT_CONTINUE; } static int CmdSetLineSpecial(void) { line_t *line; int lineTag; int special, arg1, arg2, arg3, arg4, arg5; int searcher; arg5 = Pop(); arg4 = Pop(); arg3 = Pop(); arg2 = Pop(); arg1 = Pop(); special = Pop(); lineTag = Pop(); searcher = -1; while ((line = P_FindLine(lineTag, &searcher)) != NULL) { line->special = special; line->arg1 = arg1; line->arg2 = arg2; line->arg3 = arg3; line->arg4 = arg4; line->arg5 = arg5; } return SCRIPT_CONTINUE; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_anim.c000066400000000000000000000321101257432200600226070ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "m_random.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" // MACROS ------------------------------------------------------------------ #define ANIM_SCRIPT_NAME "ANIMDEFS" #define MAX_ANIM_DEFS 20 #define MAX_FRAME_DEFS 96 #define ANIM_FLAT 0 #define ANIM_TEXTURE 1 #define SCI_FLAT "flat" #define SCI_TEXTURE "texture" #define SCI_PIC "pic" #define SCI_TICS "tics" #define SCI_RAND "rand" #define LIGHTNING_SPECIAL 198 #define LIGHTNING_SPECIAL2 199 #define SKYCHANGE_SPECIAL 200 // TYPES ------------------------------------------------------------------- typedef struct { int index; int tics; } frameDef_t; typedef struct { int type; int index; int tics; int currentFrameDef; int startFrameDef; int endFrameDef; } animDef_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void P_LightningFlash(void); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern fixed_t Sky1ColumnOffset; extern fixed_t Sky2ColumnOffset; extern boolean DoubleSky; // PUBLIC DATA DEFINITIONS ------------------------------------------------- fixed_t Sky1ScrollDelta; fixed_t Sky2ScrollDelta; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static animDef_t AnimDefs[MAX_ANIM_DEFS]; static frameDef_t FrameDefs[MAX_FRAME_DEFS]; static int AnimDefCount; static boolean LevelHasLightning; static int NextLightningFlash; static int LightningFlash; static int *LightningLightLevels; // CODE -------------------------------------------------------------------- //========================================================================== // // P_AnimateSurfaces // //========================================================================== void P_AnimateSurfaces(void) { int i; animDef_t *ad; line_t *line; // Animate flats and textures for (i = 0; i < AnimDefCount; i++) { ad = &AnimDefs[i]; ad->tics--; if (ad->tics == 0) { if (ad->currentFrameDef == ad->endFrameDef) { ad->currentFrameDef = ad->startFrameDef; } else { ad->currentFrameDef++; } ad->tics = FrameDefs[ad->currentFrameDef].tics; if (ad->tics > 255) { // Random tics ad->tics = (ad->tics >> 16) + P_Random() % ((ad->tics & 0xff00) >> 8); } if (ad->type == ANIM_FLAT) { flattranslation[ad->index] = FrameDefs[ad->currentFrameDef].index; } else { // Texture texturetranslation[ad->index] = FrameDefs[ad->currentFrameDef].index; } } } // Update scrolling textures for (i = 0; i < numlinespecials; i++) { line = linespeciallist[i]; switch (line->special) { case 100: // Scroll_Texture_Left sides[line->sidenum[0]].textureoffset += line->arg1 << 10; break; case 101: // Scroll_Texture_Right sides[line->sidenum[0]].textureoffset -= line->arg1 << 10; break; case 102: // Scroll_Texture_Up sides[line->sidenum[0]].rowoffset += line->arg1 << 10; break; case 103: // Scroll_Texture_Down sides[line->sidenum[0]].rowoffset -= line->arg1 << 10; break; } } // Update sky column offsets Sky1ColumnOffset += Sky1ScrollDelta; Sky2ColumnOffset += Sky2ScrollDelta; if (LevelHasLightning) { if (!NextLightningFlash || LightningFlash) { P_LightningFlash(); } else { NextLightningFlash--; } } } //========================================================================== // // P_LightningFlash // //========================================================================== static void P_LightningFlash(void) { int i; sector_t *tempSec; int *tempLight; boolean foundSec; int flashLight; if (LightningFlash) { LightningFlash--; if (LightningFlash) { tempLight = LightningLightLevels; tempSec = sectors; for (i = 0; i < numsectors; i++, tempSec++) { if (tempSec->ceilingpic == skyflatnum || tempSec->special == LIGHTNING_SPECIAL || tempSec->special == LIGHTNING_SPECIAL2) { if (*tempLight < tempSec->lightlevel - 4) { tempSec->lightlevel -= 4; } tempLight++; } } } else { // remove the alternate lightning flash special tempLight = LightningLightLevels; tempSec = sectors; for (i = 0; i < numsectors; i++, tempSec++) { if (tempSec->ceilingpic == skyflatnum || tempSec->special == LIGHTNING_SPECIAL || tempSec->special == LIGHTNING_SPECIAL2) { tempSec->lightlevel = *tempLight; tempLight++; } } Sky1Texture = P_GetMapSky1Texture(gamemap); } return; } LightningFlash = (P_Random() & 7) + 8; flashLight = 200 + (P_Random() & 31); tempSec = sectors; tempLight = LightningLightLevels; foundSec = false; for (i = 0; i < numsectors; i++, tempSec++) { if (tempSec->ceilingpic == skyflatnum || tempSec->special == LIGHTNING_SPECIAL || tempSec->special == LIGHTNING_SPECIAL2) { *tempLight = tempSec->lightlevel; if (tempSec->special == LIGHTNING_SPECIAL) { tempSec->lightlevel += 64; if (tempSec->lightlevel > flashLight) { tempSec->lightlevel = flashLight; } } else if (tempSec->special == LIGHTNING_SPECIAL2) { tempSec->lightlevel += 32; if (tempSec->lightlevel > flashLight) { tempSec->lightlevel = flashLight; } } else { tempSec->lightlevel = flashLight; } if (tempSec->lightlevel < *tempLight) { tempSec->lightlevel = *tempLight; } tempLight++; foundSec = true; } } if (foundSec) { Sky1Texture = P_GetMapSky2Texture(gamemap); // set alternate sky S_StartSound(NULL, SFX_THUNDER_CRASH); } // Calculate the next lighting flash if (!NextLightningFlash) { if (P_Random() < 50) { // Immediate Quick flash NextLightningFlash = (P_Random() & 15) + 16; } else { if (P_Random() < 128 && !(leveltime & 32)) { NextLightningFlash = ((P_Random() & 7) + 2) * 35; } else { NextLightningFlash = ((P_Random() & 15) + 5) * 35; } } } } //========================================================================== // // P_ForceLightning // //========================================================================== void P_ForceLightning(void) { NextLightningFlash = 0; } //========================================================================== // // P_InitLightning // //========================================================================== void P_InitLightning(void) { int i; int secCount; if (!P_GetMapLightning(gamemap)) { LevelHasLightning = false; LightningFlash = 0; return; } LightningFlash = 0; secCount = 0; for (i = 0; i < numsectors; i++) { if (sectors[i].ceilingpic == skyflatnum || sectors[i].special == LIGHTNING_SPECIAL || sectors[i].special == LIGHTNING_SPECIAL2) { secCount++; } } if (secCount) { LevelHasLightning = true; } else { LevelHasLightning = false; return; } LightningLightLevels = (int *) Z_Malloc(secCount * sizeof(int), PU_LEVEL, NULL); NextLightningFlash = ((P_Random() & 15) + 5) * 35; // don't flash at level start } //========================================================================== // // P_InitFTAnims // // Initialize flat and texture animation lists. // //========================================================================== void P_InitFTAnims(void) { int base; int mod; int fd; animDef_t *ad; boolean ignore; boolean done; fd = 0; ad = AnimDefs; AnimDefCount = 0; SC_Open(ANIM_SCRIPT_NAME); while (SC_GetString()) { if (AnimDefCount == MAX_ANIM_DEFS) { I_Error("P_InitFTAnims: too many AnimDefs."); } if (SC_Compare(SCI_FLAT)) { ad->type = ANIM_FLAT; } else if (SC_Compare(SCI_TEXTURE)) { ad->type = ANIM_TEXTURE; } else { SC_ScriptError(NULL); } SC_MustGetString(); // Name ignore = false; if (ad->type == ANIM_FLAT) { if (W_CheckNumForName(sc_String) == -1) { ignore = true; } else { ad->index = R_FlatNumForName(sc_String); } } else { // Texture if (R_CheckTextureNumForName(sc_String) == -1) { ignore = true; } else { ad->index = R_TextureNumForName(sc_String); } } ad->startFrameDef = fd; done = false; while (done == false) { if (SC_GetString()) { if (SC_Compare(SCI_PIC)) { if (fd == MAX_FRAME_DEFS) { I_Error("P_InitFTAnims: too many FrameDefs."); } SC_MustGetNumber(); if (ignore == false) { FrameDefs[fd].index = ad->index + sc_Number - 1; } SC_MustGetString(); if (SC_Compare(SCI_TICS)) { SC_MustGetNumber(); if (ignore == false) { FrameDefs[fd].tics = sc_Number; fd++; } } else if (SC_Compare(SCI_RAND)) { SC_MustGetNumber(); base = sc_Number; SC_MustGetNumber(); if (ignore == false) { mod = sc_Number - base + 1; FrameDefs[fd].tics = (base << 16) + (mod << 8); fd++; } } else { SC_ScriptError(NULL); } } else { SC_UnGet(); done = true; } } else { done = true; } } if ((ignore == false) && (fd - ad->startFrameDef < 2)) { I_Error("P_InitFTAnims: AnimDef has framecount < 2."); } if (ignore == false) { ad->endFrameDef = fd - 1; ad->currentFrameDef = ad->endFrameDef; ad->tics = 1; // Force 1st game tic to animate AnimDefCount++; ad++; } } SC_Close(); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_ceilng.c000066400000000000000000000227571257432200600231440ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "p_local.h" //================================================================== //================================================================== // // CEILINGS // //================================================================== //================================================================== ceiling_t *activeceilings[MAXCEILINGS]; //================================================================== // // T_MoveCeiling // //================================================================== void T_MoveCeiling(ceiling_t * ceiling) { result_e res; switch (ceiling->direction) { // case 0: // IN STASIS // break; case 1: // UP res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false, 1, ceiling->direction); if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *) & ceiling->sector->soundorg); switch (ceiling->type) { case CLEV_CRUSHANDRAISE: ceiling->direction = -1; ceiling->speed = ceiling->speed * 2; break; default: P_RemoveActiveCeiling(ceiling); break; } } break; case -1: // DOWN res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, 1, ceiling->direction); if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *) & ceiling->sector->soundorg); switch (ceiling->type) { case CLEV_CRUSHANDRAISE: case CLEV_CRUSHRAISEANDSTAY: ceiling->direction = 1; ceiling->speed = ceiling->speed / 2; break; default: P_RemoveActiveCeiling(ceiling); break; } } else if (res == RES_CRUSHED) { switch (ceiling->type) { case CLEV_CRUSHANDRAISE: case CLEV_LOWERANDCRUSH: case CLEV_CRUSHRAISEANDSTAY: //ceiling->speed = ceiling->speed/4; break; default: break; } } break; } } //================================================================== // // EV_DoCeiling // Move a ceiling up/down and all around! // //================================================================== int EV_DoCeiling(line_t * line, byte * arg, ceiling_e type) { int secnum, rtn; sector_t *sec; ceiling_t *ceiling; secnum = -1; rtn = 0; /* Old Ceiling stasis code // // Reactivate in-stasis ceilings...for certain types. // switch(type) { case CLEV_CRUSHANDRAISE: P_ActivateInStasisCeiling(line); default: break; } */ while ((secnum = P_FindSectorFromTag(arg[0], secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // // new door thinker // rtn = 1; ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVSPEC, 0); P_AddThinker(&ceiling->thinker); sec->specialdata = ceiling; ceiling->thinker.function = T_MoveCeiling; ceiling->sector = sec; ceiling->crush = 0; ceiling->speed = arg[1] * (FRACUNIT / 8); switch (type) { case CLEV_CRUSHRAISEANDSTAY: ceiling->crush = arg[2]; // arg[2] = crushing value ceiling->topheight = sec->ceilingheight; ceiling->bottomheight = sec->floorheight + (8 * FRACUNIT); ceiling->direction = -1; break; case CLEV_CRUSHANDRAISE: ceiling->topheight = sec->ceilingheight; case CLEV_LOWERANDCRUSH: ceiling->crush = arg[2]; // arg[2] = crushing value case CLEV_LOWERTOFLOOR: ceiling->bottomheight = sec->floorheight; if (type != CLEV_LOWERTOFLOOR) { ceiling->bottomheight += 8 * FRACUNIT; } ceiling->direction = -1; break; case CLEV_RAISETOHIGHEST: ceiling->topheight = P_FindHighestCeilingSurrounding(sec); ceiling->direction = 1; break; case CLEV_LOWERBYVALUE: ceiling->bottomheight = sec->ceilingheight - arg[2] * FRACUNIT; ceiling->direction = -1; break; case CLEV_RAISEBYVALUE: ceiling->topheight = sec->ceilingheight + arg[2] * FRACUNIT; ceiling->direction = 1; break; case CLEV_MOVETOVALUETIMES8: { int destHeight = arg[2] * FRACUNIT * 8; if (arg[3]) { destHeight = -destHeight; } if (sec->ceilingheight <= destHeight) { ceiling->direction = 1; ceiling->topheight = destHeight; if (sec->ceilingheight == destHeight) { rtn = 0; } } else if (sec->ceilingheight > destHeight) { ceiling->direction = -1; ceiling->bottomheight = destHeight; } break; } default: rtn = 0; break; } ceiling->tag = sec->tag; ceiling->type = type; P_AddActiveCeiling(ceiling); if (rtn) { SN_StartSequence((mobj_t *) & ceiling->sector->soundorg, SEQ_PLATFORM + ceiling->sector->seqType); } } return rtn; } //================================================================== // // Add an active ceiling // //================================================================== void P_AddActiveCeiling(ceiling_t * c) { int i; for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] == NULL) { activeceilings[i] = c; return; } } //================================================================== // // Remove a ceiling's thinker // //================================================================== void P_RemoveActiveCeiling(ceiling_t * c) { int i; for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] == c) { activeceilings[i]->sector->specialdata = NULL; P_RemoveThinker(&activeceilings[i]->thinker); P_TagFinished(activeceilings[i]->sector->tag); activeceilings[i] = NULL; break; } } #if 0 //================================================================== // // Restart a ceiling that's in-stasis // //================================================================== void P_ActivateInStasisCeiling(line_t * line) { int i; for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] && (activeceilings[i]->tag == line->arg1) && (activeceilings[i]->direction == 0)) { activeceilings[i]->direction = activeceilings[i]->olddirection; activeceilings[i]->thinker.function = T_MoveCeiling; SN_StartSequence((mobj_t *) & activeceilings[i]->sector->soundorg, SEQ_PLATFORM + activeceilings[i]->sector->seqType); } } #endif //================================================================== // // EV_CeilingCrushStop // Stop a ceiling from crushing! // //================================================================== int EV_CeilingCrushStop(line_t * line, byte * args) { int i; int rtn; rtn = 0; for (i = 0; i < MAXCEILINGS; i++) { if (activeceilings[i] && activeceilings[i]->tag == args[0]) { rtn = 1; SN_StopSequence((mobj_t *) & activeceilings[i]->sector->soundorg); activeceilings[i]->sector->specialdata = NULL; P_RemoveThinker(&activeceilings[i]->thinker); P_TagFinished(activeceilings[i]->sector->tag); activeceilings[i] = NULL; break; } } return rtn; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_doors.c000066400000000000000000000226221257432200600230200ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "p_local.h" //================================================================== //================================================================== // // VERTICAL DOORS // //================================================================== //================================================================== //================================================================== // // T_VerticalDoor // //================================================================== void T_VerticalDoor(vldoor_t * door) { result_e res; switch (door->direction) { case 0: // WAITING if (!--door->topcountdown) switch (door->type) { case DREV_NORMAL: door->direction = -1; // time to go back down SN_StartSequence((mobj_t *) & door->sector->soundorg, SEQ_DOOR_STONE + door->sector->seqType); break; case DREV_CLOSE30THENOPEN: door->direction = 1; break; default: break; } break; case 2: // INITIAL WAIT if (!--door->topcountdown) { switch (door->type) { case DREV_RAISEIN5MINS: door->direction = 1; door->type = DREV_NORMAL; break; default: break; } } break; case -1: // DOWN res = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction); if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *) & door->sector->soundorg); switch (door->type) { case DREV_NORMAL: case DREV_CLOSE: door->sector->specialdata = NULL; P_TagFinished(door->sector->tag); P_RemoveThinker(&door->thinker); // unlink and free break; case DREV_CLOSE30THENOPEN: door->direction = 0; door->topcountdown = 35 * 30; break; default: break; } } else if (res == RES_CRUSHED) { switch (door->type) { case DREV_CLOSE: // DON'T GO BACK UP! break; default: door->direction = 1; break; } } break; case 1: // UP res = T_MovePlane(door->sector, door->speed, door->topheight, false, 1, door->direction); if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *) & door->sector->soundorg); switch (door->type) { case DREV_NORMAL: door->direction = 0; // wait at top door->topcountdown = door->topwait; break; case DREV_CLOSE30THENOPEN: case DREV_OPEN: door->sector->specialdata = NULL; P_TagFinished(door->sector->tag); P_RemoveThinker(&door->thinker); // unlink and free break; default: break; } } break; } } //---------------------------------------------------------------------------- // // EV_DoDoor // // Move a door up/down // //---------------------------------------------------------------------------- int EV_DoDoor(line_t * line, byte * args, vldoor_e type) { int secnum; int retcode; sector_t *sec; vldoor_t *door; fixed_t speed; speed = args[1] * FRACUNIT / 8; secnum = -1; retcode = 0; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) { continue; } // Add new door thinker retcode = 1; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function = T_VerticalDoor; door->sector = sec; switch (type) { case DREV_CLOSE: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; door->direction = -1; break; case DREV_CLOSE30THENOPEN: door->topheight = sec->ceilingheight; door->direction = -1; break; case DREV_NORMAL: case DREV_OPEN: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; break; default: break; } door->type = type; door->speed = speed; door->topwait = args[2]; // line->arg3 SN_StartSequence((mobj_t *) & door->sector->soundorg, SEQ_DOOR_STONE + door->sector->seqType); } return (retcode); } //================================================================== // // EV_VerticalDoor : open a door manually, no tag value // //================================================================== boolean EV_VerticalDoor(line_t * line, mobj_t * thing) { sector_t *sec; vldoor_t *door; int side; side = 0; // only front sides can be used // if the sector has an active thinker, use it sec = sides[line->sidenum[side ^ 1]].sector; if (sec->specialdata) { return false; /* door = sec->specialdata; switch(line->special) { // only for raise doors case 12: if(door->direction == -1) { door->direction = 1; // go back up } else { if(!thing->player) { // Monsters don't close doors return; } door->direction = -1; // start going down immediately } return; } */ } // // new door thinker // door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 1; switch (line->special) { case 11: door->type = DREV_OPEN; line->special = 0; break; case 12: case 13: door->type = DREV_NORMAL; break; default: door->type = DREV_NORMAL; break; } door->speed = line->arg2 * (FRACUNIT / 8); door->topwait = line->arg3; // // find the top and bottom of the movement range // door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; SN_StartSequence((mobj_t *) & door->sector->soundorg, SEQ_DOOR_STONE + door->sector->seqType); return true; } //================================================================== // // Spawn a door that closes after 30 seconds // //================================================================== /* void P_SpawnDoorCloseIn30(sector_t *sec) { vldoor_t *door; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 0; door->type = DREV_NORMAL; door->speed = VDOORSPEED; door->topcountdown = 30*35; } */ //================================================================== // // Spawn a door that opens after 5 minutes // //================================================================== /* void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum) { vldoor_t *door; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 2; door->type = DREV_RAISEIN5MINS; door->speed = VDOORSPEED; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->topwait = VDOORWAIT; door->topcountdown = 5*60*35; } */ chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_enemy.c000066400000000000000000004264641257432200600230230ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "m_random.h" #include "i_system.h" #include "i_swap.h" #include "p_local.h" #include "s_sound.h" // Macros // Types // Private Data // External Data extern fixed_t FloatBobOffsets[64]; //---------------------------------------------------------------------------- // // PROC P_RecursiveSound // //---------------------------------------------------------------------------- mobj_t *soundtarget; void P_RecursiveSound(sector_t * sec, int soundblocks) { int i; line_t *check; sector_t *other; // Wake up all monsters in this sector if (sec->validcount == validcount && sec->soundtraversed <= soundblocks + 1) { // Already flooded return; } sec->validcount = validcount; sec->soundtraversed = soundblocks + 1; sec->soundtarget = soundtarget; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; if (!(check->flags & ML_TWOSIDED)) { continue; } P_LineOpening(check); if (openrange <= 0) { // Closed door continue; } if (sides[check->sidenum[0]].sector == sec) { other = sides[check->sidenum[1]].sector; } else { other = sides[check->sidenum[0]].sector; } if (check->flags & ML_SOUNDBLOCK) { if (!soundblocks) { P_RecursiveSound(other, 1); } } else { P_RecursiveSound(other, soundblocks); } } } //---------------------------------------------------------------------------- // // PROC P_NoiseAlert // // If a monster yells at a player, it will alert other monsters to the // player. // //---------------------------------------------------------------------------- void P_NoiseAlert(mobj_t * target, mobj_t * emmiter) { soundtarget = target; validcount++; P_RecursiveSound(emmiter->subsector->sector, 0); } //---------------------------------------------------------------------------- // // FUNC P_CheckMeleeRange // //---------------------------------------------------------------------------- boolean P_CheckMeleeRange(mobj_t * actor) { mobj_t *mo; fixed_t dist; if (!actor->target) { return (false); } mo = actor->target; dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y); if (dist >= MELEERANGE) { return (false); } if (!P_CheckSight(actor, mo)) { return (false); } if (mo->z > actor->z + actor->height) { // Target is higher than the attacker return (false); } else if (actor->z > mo->z + mo->height) { // Attacker is higher return (false); } return (true); } //---------------------------------------------------------------------------- // // FUNC P_CheckMeleeRange2 // //---------------------------------------------------------------------------- boolean P_CheckMeleeRange2(mobj_t * actor) { mobj_t *mo; fixed_t dist; if (!actor->target) { return (false); } mo = actor->target; dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y); if (dist >= MELEERANGE * 2 || dist < MELEERANGE) { return (false); } if (!P_CheckSight(actor, mo)) { return (false); } if (mo->z > actor->z + actor->height) { // Target is higher than the attacker return (false); } else if (actor->z > mo->z + mo->height) { // Attacker is higher return (false); } return (true); } //---------------------------------------------------------------------------- // // FUNC P_CheckMissileRange // //---------------------------------------------------------------------------- boolean P_CheckMissileRange(mobj_t * actor) { fixed_t dist; if (!P_CheckSight(actor, actor->target)) { return (false); } if (actor->flags & MF_JUSTHIT) { // The target just hit the enemy, so fight back! actor->flags &= ~MF_JUSTHIT; return (true); } if (actor->reactiontime) { // Don't attack yet return (false); } dist = (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) >> FRACBITS) - 64; if (!actor->info->meleestate) { // No melee attack, so fire more frequently dist -= 128; } if (dist > 200) { dist = 200; } if (P_Random() < dist) { return (false); } return (true); } /* ================ = = P_Move = = Move in the current direction = returns false if the move is blocked ================ */ fixed_t xspeed[8] = { FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000, 0, 47000 }; fixed_t yspeed[8] = { 0, 47000, FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000 }; #define MAXSPECIALCROSS 8 extern line_t *spechit[MAXSPECIALCROSS]; extern int numspechit; boolean P_Move(mobj_t * actor) { fixed_t tryx, tryy; line_t *ld; boolean good; if (actor->flags2 & MF2_BLASTED) return (true); if (actor->movedir == DI_NODIR) { return (false); } tryx = actor->x + actor->info->speed * xspeed[actor->movedir]; tryy = actor->y + actor->info->speed * yspeed[actor->movedir]; if (!P_TryMove(actor, tryx, tryy)) { // open any specials if (actor->flags & MF_FLOAT && floatok) { // must adjust height if (actor->z < tmfloorz) { actor->z += FLOATSPEED; } else { actor->z -= FLOATSPEED; } actor->flags |= MF_INFLOAT; return (true); } if (!numspechit) { return false; } actor->movedir = DI_NODIR; good = false; while (numspechit--) { ld = spechit[numspechit]; // if the special isn't a door that can be opened, return false if (P_ActivateLine(ld, actor, 0, SPAC_USE)) { good = true; } /* Old version before use/cross/impact specials were combined if(P_UseSpecialLine(actor, ld)) { good = true; } */ } return (good); } else { actor->flags &= ~MF_INFLOAT; } if (!(actor->flags & MF_FLOAT)) { if (actor->z > actor->floorz) { P_HitFloor(actor); } actor->z = actor->floorz; } return (true); } //---------------------------------------------------------------------------- // // FUNC P_TryWalk // // Attempts to move actor in its current (ob->moveangle) direction. // If blocked by either a wall or an actor returns FALSE. // If move is either clear of block only by a door, returns TRUE and sets. // If a door is in the way, an OpenDoor call is made to start it opening. // //---------------------------------------------------------------------------- boolean P_TryWalk(mobj_t * actor) { if (!P_Move(actor)) { return (false); } actor->movecount = P_Random() & 15; return (true); } /* ================ = = P_NewChaseDir = ================ */ dirtype_t opposite[] = { DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR }; dirtype_t diags[] = { DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST }; void P_NewChaseDir(mobj_t * actor) { fixed_t deltax, deltay; dirtype_t d[3]; dirtype_t tdir, olddir, turnaround; if (!actor->target) I_Error("P_NewChaseDir: called with no target"); olddir = actor->movedir; turnaround = opposite[olddir]; deltax = actor->target->x - actor->x; deltay = actor->target->y - actor->y; if (deltax > 10 * FRACUNIT) d[1] = DI_EAST; else if (deltax < -10 * FRACUNIT) d[1] = DI_WEST; else d[1] = DI_NODIR; if (deltay < -10 * FRACUNIT) d[2] = DI_SOUTH; else if (deltay > 10 * FRACUNIT) d[2] = DI_NORTH; else d[2] = DI_NODIR; // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { actor->movedir = diags[((deltay < 0) << 1) + (deltax > 0)]; if (actor->movedir != turnaround && P_TryWalk(actor)) return; } // try other directions if (P_Random() > 200 || abs(deltay) > abs(deltax)) { tdir = d[1]; d[1] = d[2]; d[2] = tdir; } if (d[1] == turnaround) d[1] = DI_NODIR; if (d[2] == turnaround) d[2] = DI_NODIR; if (d[1] != DI_NODIR) { actor->movedir = d[1]; if (P_TryWalk(actor)) return; /*either moved forward or attacked */ } if (d[2] != DI_NODIR) { actor->movedir = d[2]; if (P_TryWalk(actor)) return; } /* there is no direct path to the player, so pick another direction */ if (olddir != DI_NODIR) { actor->movedir = olddir; if (P_TryWalk(actor)) return; } if (P_Random() & 1) /*randomly determine direction of search */ { for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++) { if (tdir != turnaround) { actor->movedir = tdir; if (P_TryWalk(actor)) return; } } } else { tdir = DI_SOUTHEAST; for (;;) { if (tdir != turnaround) { actor->movedir = tdir; if (P_TryWalk(actor)) return; } if (tdir == DI_EAST) { break; } --tdir; } } if (turnaround != DI_NODIR) { actor->movedir = turnaround; if (P_TryWalk(actor)) return; } actor->movedir = DI_NODIR; // can't move } //--------------------------------------------------------------------------- // // FUNC P_LookForMonsters // //--------------------------------------------------------------------------- #define MONS_LOOK_RANGE (16*64*FRACUNIT) #define MONS_LOOK_LIMIT 64 boolean P_LookForMonsters(mobj_t * actor) { int count; mobj_t *mo; thinker_t *think; if (!P_CheckSight(players[0].mo, actor)) { // Player can't see monster return (false); } count = 0; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *) think; if (!(mo->flags & MF_COUNTKILL) || (mo == actor) || (mo->health <= 0)) { // Not a valid monster continue; } if (P_AproxDistance(actor->x - mo->x, actor->y - mo->y) > MONS_LOOK_RANGE) { // Out of range continue; } if (P_Random() < 16) { // Skip continue; } if (count++ > MONS_LOOK_LIMIT) { // Stop searching return (false); } if (!P_CheckSight(actor, mo)) { // Out of sight continue; } if (actor->type == MT_MINOTAUR) { if ((mo->type == MT_MINOTAUR) && (mo->target != actor->special1.p->mo)) { continue; } } // Found a target monster actor->target = mo; return (true); } return (false); } /* ================ = = P_LookForPlayers = = If allaround is false, only look 180 degrees in front = returns true if a player is targeted ================ */ boolean P_LookForPlayers(mobj_t * actor, boolean allaround) { int c; int stop; player_t *player; angle_t an; fixed_t dist; if (!netgame && players[0].health <= 0) { // Single player game and player is dead, look for monsters return (P_LookForMonsters(actor)); } c = 0; // NOTE: This behavior has been changed from the Vanilla behavior, where // an infinite loop can occur if players 0-3 all quit the game. Although // technically this is not what Vanilla does, fixing this is highly // desirable, and having the game simply lock up is not acceptable. // stop = (actor->lastlook - 1) & 3; // for (;; actor->lastlook = (actor->lastlook + 1) & 3) stop = (actor->lastlook + maxplayers - 1) % maxplayers; for (;; actor->lastlook = (actor->lastlook + 1) % maxplayers) { if (!playeringame[actor->lastlook]) continue; if (c++ == 2 || actor->lastlook == stop) return false; // done looking player = &players[actor->lastlook]; if (player->health <= 0) continue; // dead if (!P_CheckSight(actor, player->mo)) continue; // out of sight if (!allaround) { an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; if (an > ANG90 && an < ANG270) { dist = P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y); // if real close, react anyway if (dist > MELEERANGE) continue; // behind back } } if (player->mo->flags & MF_SHADOW) { // Player is invisible if ((P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) > 2 * MELEERANGE) && P_AproxDistance(player->mo->momx, player->mo->momy) < 5 * FRACUNIT) { // Player is sneaking - can't detect return (false); } if (P_Random() < 225) { // Player isn't sneaking, but still didn't detect return (false); } } if (actor->type == MT_MINOTAUR) { if (actor->special1.p == player) { continue; // Don't target master } } actor->target = player->mo; return (true); } return (false); } /* =============================================================================== ACTION ROUTINES =============================================================================== */ /* ============== = = A_Look = = Stay in state until a player is sighted = ============== */ void A_Look(mobj_t * actor) { mobj_t *targ; actor->threshold = 0; // any shot will wake up targ = actor->subsector->sector->soundtarget; if (targ && (targ->flags & MF_SHOOTABLE)) { actor->target = targ; if (actor->flags & MF_AMBUSH) { if (P_CheckSight(actor, actor->target)) goto seeyou; } else goto seeyou; } if (!P_LookForPlayers(actor, false)) return; // go into chase state seeyou: if (actor->info->seesound) { int sound; sound = actor->info->seesound; if (actor->flags2 & MF2_BOSS) { // Full volume S_StartSound(NULL, sound); } else { S_StartSound(actor, sound); } } P_SetMobjState(actor, actor->info->seestate); } /* ============== = = A_Chase = = Actor has a melee attack, so it tries to close as fast as possible = ============== */ void A_Chase(mobj_t * actor) { int delta; if (actor->reactiontime) { actor->reactiontime--; } // Modify target threshold if (actor->threshold) { actor->threshold--; } if (gameskill == sk_nightmare) { // Monsters move faster in nightmare mode actor->tics -= actor->tics / 2; if (actor->tics < 3) { actor->tics = 3; } } // // turn towards movement direction if not there yet // if (actor->movedir < 8) { actor->angle &= (7 << 29); delta = actor->angle - (actor->movedir << 29); if (delta > 0) { actor->angle -= ANG90 / 2; } else if (delta < 0) { actor->angle += ANG90 / 2; } } if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { // look for a new target if (P_LookForPlayers(actor, true)) { // got a new target return; } P_SetMobjState(actor, actor->info->spawnstate); return; } // // don't attack twice in a row // if (actor->flags & MF_JUSTATTACKED) { actor->flags &= ~MF_JUSTATTACKED; if (gameskill != sk_nightmare) P_NewChaseDir(actor); return; } // // check for melee attack // if (actor->info->meleestate && P_CheckMeleeRange(actor)) { if (actor->info->attacksound) { S_StartSound(actor, actor->info->attacksound); } P_SetMobjState(actor, actor->info->meleestate); return; } // // check for missile attack // if (actor->info->missilestate) { if (gameskill < sk_nightmare && actor->movecount) goto nomissile; if (!P_CheckMissileRange(actor)) goto nomissile; P_SetMobjState(actor, actor->info->missilestate); actor->flags |= MF_JUSTATTACKED; return; } nomissile: // // possibly choose another target // if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target)) { if (P_LookForPlayers(actor, true)) return; // got a new target } // // chase towards player // if (--actor->movecount < 0 || !P_Move(actor)) { P_NewChaseDir(actor); } // // make active sound // if (actor->info->activesound && P_Random() < 3) { if (actor->type == MT_BISHOP && P_Random() < 128) { S_StartSound(actor, actor->info->seesound); } else if (actor->type == MT_PIG) { S_StartSound(actor, SFX_PIG_ACTIVE1 + (P_Random() & 1)); } else if (actor->flags2 & MF2_BOSS) { S_StartSound(NULL, actor->info->activesound); } else { S_StartSound(actor, actor->info->activesound); } } } //---------------------------------------------------------------------------- // // PROC A_FaceTarget // //---------------------------------------------------------------------------- void A_FaceTarget(mobj_t * actor) { if (!actor->target) { return; } actor->flags &= ~MF_AMBUSH; actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); if (actor->target->flags & MF_SHADOW) { // Target is a ghost actor->angle += (P_Random() - P_Random()) << 21; } } //---------------------------------------------------------------------------- // // PROC A_Pain // //---------------------------------------------------------------------------- void A_Pain(mobj_t * actor) { if (actor->info->painsound) { S_StartSound(actor, actor->info->painsound); } } //============================================================================ // // A_SetInvulnerable // //============================================================================ void A_SetInvulnerable(mobj_t * actor) { actor->flags2 |= MF2_INVULNERABLE; } //============================================================================ // // A_UnSetInvulnerable // //============================================================================ void A_UnSetInvulnerable(mobj_t * actor) { actor->flags2 &= ~MF2_INVULNERABLE; } //============================================================================ // // A_SetReflective // //============================================================================ void A_SetReflective(mobj_t * actor) { actor->flags2 |= MF2_REFLECTIVE; if ((actor->type == MT_CENTAUR) || (actor->type == MT_CENTAURLEADER)) { A_SetInvulnerable(actor); } } //============================================================================ // // A_UnSetReflective // //============================================================================ void A_UnSetReflective(mobj_t * actor) { actor->flags2 &= ~MF2_REFLECTIVE; if ((actor->type == MT_CENTAUR) || (actor->type == MT_CENTAURLEADER)) { A_UnSetInvulnerable(actor); } } //---------------------------------------------------------------------------- // // FUNC P_UpdateMorphedMonster // // Returns true if the pig morphs. // //---------------------------------------------------------------------------- boolean P_UpdateMorphedMonster(mobj_t * actor, int tics) { mobj_t *fog; fixed_t x; fixed_t y; fixed_t z; mobjtype_t moType; mobj_t *mo; mobj_t oldMonster; actor->special1.i -= tics; if (actor->special1.i > 0) { return (false); } moType = actor->special2.i; switch (moType) { case MT_WRAITHB: // These must remain morphed case MT_SERPENT: case MT_SERPENTLEADER: case MT_MINOTAUR: return (false); default: break; } x = actor->x; y = actor->y; z = actor->z; oldMonster = *actor; // Save pig vars P_RemoveMobjFromTIDList(actor); P_SetMobjState(actor, S_FREETARGMOBJ); mo = P_SpawnMobj(x, y, z, moType); if (P_TestMobjLocation(mo) == false) { // Didn't fit P_RemoveMobj(mo); mo = P_SpawnMobj(x, y, z, oldMonster.type); mo->angle = oldMonster.angle; mo->flags = oldMonster.flags; mo->health = oldMonster.health; mo->target = oldMonster.target; mo->special = oldMonster.special; mo->special1.i = 5 * 35; // Next try in 5 seconds mo->special2.i = moType; mo->tid = oldMonster.tid; memcpy(mo->args, oldMonster.args, 5); P_InsertMobjIntoTIDList(mo, oldMonster.tid); return (false); } mo->angle = oldMonster.angle; mo->target = oldMonster.target; mo->tid = oldMonster.tid; mo->special = oldMonster.special; memcpy(mo->args, oldMonster.args, 5); P_InsertMobjIntoTIDList(mo, oldMonster.tid); fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, SFX_TELEPORT); return (true); } //---------------------------------------------------------------------------- // // PROC A_PigLook // //---------------------------------------------------------------------------- void A_PigLook(mobj_t * actor) { if (P_UpdateMorphedMonster(actor, 10)) { return; } A_Look(actor); } //---------------------------------------------------------------------------- // // PROC A_PigChase // //---------------------------------------------------------------------------- void A_PigChase(mobj_t * actor) { if (P_UpdateMorphedMonster(actor, 3)) { return; } A_Chase(actor); } //============================================================================ // // A_PigAttack // //============================================================================ void A_PigAttack(mobj_t * actor) { if (P_UpdateMorphedMonster(actor, 18)) { return; } if (!actor->target) { return; } if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, 2 + (P_Random() & 1)); S_StartSound(actor, SFX_PIG_ATTACK); } } //============================================================================ // // A_PigPain // //============================================================================ void A_PigPain(mobj_t * actor) { A_Pain(actor); if (actor->z <= actor->floorz) { actor->momz = 3.5 * FRACUNIT; } } void FaceMovementDirection(mobj_t * actor) { switch (actor->movedir) { case DI_EAST: actor->angle = 0 << 24; break; case DI_NORTHEAST: actor->angle = 32 << 24; break; case DI_NORTH: actor->angle = 64 << 24; break; case DI_NORTHWEST: actor->angle = 96 << 24; break; case DI_WEST: actor->angle = 128 << 24; break; case DI_SOUTHWEST: actor->angle = 160 << 24; break; case DI_SOUTH: actor->angle = 192 << 24; break; case DI_SOUTHEAST: actor->angle = 224 << 24; break; } } //---------------------------------------------------------------------------- // // Minotaur variables // // special1 pointer to player that spawned it (mobj_t) // special2 internal to minotaur AI // args[0] args[0]-args[3] together make up minotaur start time // args[1] | // args[2] | // args[3] V // args[4] charge duration countdown //---------------------------------------------------------------------------- void A_MinotaurFade0(mobj_t * actor) { actor->flags &= ~MF_ALTSHADOW; actor->flags |= MF_SHADOW; } void A_MinotaurFade1(mobj_t * actor) { // Second level of transparency actor->flags &= ~MF_SHADOW; actor->flags |= MF_ALTSHADOW; } void A_MinotaurFade2(mobj_t * actor) { // Make fully visible actor->flags &= ~MF_SHADOW; actor->flags &= ~MF_ALTSHADOW; } //---------------------------------------------------------------------------- // // A_MinotaurRoam - // // //---------------------------------------------------------------------------- void A_MinotaurLook(mobj_t * actor); // Check the age of the minotaur and stomp it after MAULATORTICS of time // have passed. Returns false if killed. static boolean CheckMinotaurAge(mobj_t *mo) { unsigned int starttime; // The start time is stored in the mobj_t structure, but it is stored // in little endian format. For Vanilla savegame compatibility we must // swap it to the native endianness. memcpy(&starttime, mo->args, sizeof(unsigned int)); if (leveltime - LONG(starttime) >= MAULATORTICS) { P_DamageMobj(mo, NULL, NULL, 10000); return false; } return true; } void A_MinotaurRoam(mobj_t * actor) { actor->flags &= ~MF_SHADOW; // In case pain caused him to actor->flags &= ~MF_ALTSHADOW; // skip his fade in. if (!CheckMinotaurAge(actor)) { return; } if (P_Random() < 30) A_MinotaurLook(actor); // adjust to closest target if (P_Random() < 6) { //Choose new direction actor->movedir = P_Random() % 8; FaceMovementDirection(actor); } if (!P_Move(actor)) { // Turn if (P_Random() & 1) actor->movedir = (actor->movedir + 1) % 8; else actor->movedir = (actor->movedir + 7) % 8; FaceMovementDirection(actor); } } //---------------------------------------------------------------------------- // // PROC A_MinotaurLook // // Look for enemy of player //---------------------------------------------------------------------------- #define MINOTAUR_LOOK_DIST (16*54*FRACUNIT) void A_MinotaurLook(mobj_t * actor) { mobj_t *mo = NULL; player_t *player; thinker_t *think; fixed_t dist; int i; mobj_t *master = actor->special1.m; actor->target = NULL; if (deathmatch) // Quick search for players { for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) continue; player = &players[i]; mo = player->mo; if (mo == master) continue; if (mo->health <= 0) continue; dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y); if (dist > MINOTAUR_LOOK_DIST) continue; actor->target = mo; break; } } if (!actor->target) // Near player monster search { if (master && (master->health > 0) && (master->player)) mo = P_RoughMonsterSearch(master, 20); else mo = P_RoughMonsterSearch(actor, 20); actor->target = mo; } if (!actor->target) // Normal monster search { for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) continue; mo = (mobj_t *) think; if (!(mo->flags & MF_COUNTKILL)) continue; if (mo->health <= 0) continue; if (!(mo->flags & MF_SHOOTABLE)) continue; dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y); if (dist > MINOTAUR_LOOK_DIST) continue; if ((mo == master) || (mo == actor)) continue; if ((mo->type == MT_MINOTAUR) && (mo->special1.m == actor->special1.m)) continue; actor->target = mo; break; // Found mobj to attack } } if (actor->target) { P_SetMobjStateNF(actor, S_MNTR_WALK1); } else { P_SetMobjStateNF(actor, S_MNTR_ROAM1); } } void A_MinotaurChase(mobj_t * actor) { actor->flags &= ~MF_SHADOW; // In case pain caused him to actor->flags &= ~MF_ALTSHADOW; // skip his fade in. if (!CheckMinotaurAge(actor)) { return; } if (P_Random() < 30) A_MinotaurLook(actor); // adjust to closest target if (!actor->target || (actor->target->health <= 0) || !(actor->target->flags & MF_SHOOTABLE)) { // look for a new target P_SetMobjState(actor, S_MNTR_LOOK1); return; } FaceMovementDirection(actor); actor->reactiontime = 0; // Melee attack if (actor->info->meleestate && P_CheckMeleeRange(actor)) { if (actor->info->attacksound) { S_StartSound(actor, actor->info->attacksound); } P_SetMobjState(actor, actor->info->meleestate); return; } // Missile attack if (actor->info->missilestate && P_CheckMissileRange(actor)) { P_SetMobjState(actor, actor->info->missilestate); return; } // chase towards target if (!P_Move(actor)) { P_NewChaseDir(actor); } // Active sound if (actor->info->activesound && P_Random() < 6) { S_StartSound(actor, actor->info->activesound); } } //---------------------------------------------------------------------------- // // PROC A_MinotaurAtk1 // // Melee attack. // //---------------------------------------------------------------------------- void A_MinotaurAtk1(mobj_t * actor) { if (!actor->target) return; S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(4)); } } //---------------------------------------------------------------------------- // // PROC A_MinotaurDecide // // Choose a missile attack. // //---------------------------------------------------------------------------- #define MNTR_CHARGE_SPEED (23*FRACUNIT) void A_MinotaurDecide(mobj_t * actor) { angle_t angle; mobj_t *target = actor->target; int dist; if (!target) return; dist = P_AproxDistance(actor->x - target->x, actor->y - target->y); if (target->z + target->height > actor->z && target->z + target->height < actor->z + actor->height && dist < 16 * 64 * FRACUNIT && dist > 1 * 64 * FRACUNIT && P_Random() < 230) { // Charge attack // Don't call the state function right away P_SetMobjStateNF(actor, S_MNTR_ATK4_1); actor->flags |= MF_SKULLFLY; A_FaceTarget(actor); angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]); actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]); actor->args[4] = 35 / 2; // Charge duration } else if (target->z == target->floorz && dist < 9 * 64 * FRACUNIT && P_Random() < 100) { // Floor fire attack P_SetMobjState(actor, S_MNTR_ATK3_1); actor->special2.i = 0; } else { // Swing attack A_FaceTarget(actor); // Don't need to call P_SetMobjState because the current state // falls through to the swing attack } } //---------------------------------------------------------------------------- // // PROC A_MinotaurCharge // //---------------------------------------------------------------------------- void A_MinotaurCharge(mobj_t * actor) { mobj_t *puff; if (!actor->target) return; if (actor->args[4] > 0) { puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PUNCHPUFF); puff->momz = 2 * FRACUNIT; actor->args[4]--; } else { actor->flags &= ~MF_SKULLFLY; P_SetMobjState(actor, actor->info->seestate); } } //---------------------------------------------------------------------------- // // PROC A_MinotaurAtk2 // // Swing attack. // //---------------------------------------------------------------------------- void A_MinotaurAtk2(mobj_t * actor) { mobj_t *mo; angle_t angle; fixed_t momz; if (!actor->target) return; S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(3)); return; } mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1); if (mo) { //S_StartSound(mo, sfx_minat2); momz = mo->momz; angle = mo->angle; P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 8), momz); P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 8), momz); P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 16), momz); P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 16), momz); } } //---------------------------------------------------------------------------- // // PROC A_MinotaurAtk3 // // Floor fire attack. // //---------------------------------------------------------------------------- void A_MinotaurAtk3(mobj_t * actor) { mobj_t *mo; player_t *player; if (!actor->target) { return; } if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(3)); if ((player = actor->target->player) != NULL) { // Squish the player player->deltaviewheight = -16 * FRACUNIT; } } else { mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2); if (mo != NULL) { S_StartSound(mo, SFX_MAULATOR_HAMMER_HIT); } } if (P_Random() < 192 && actor->special2.i == 0) { P_SetMobjState(actor, S_MNTR_ATK3_4); actor->special2.i = 1; } } //---------------------------------------------------------------------------- // // PROC A_MntrFloorFire // //---------------------------------------------------------------------------- void A_MntrFloorFire(mobj_t * actor) { mobj_t *mo; actor->z = actor->floorz; mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10), actor->y + ((P_Random() - P_Random()) << 10), ONFLOORZ, MT_MNTRFX3); mo->target = actor->target; mo->momx = 1; // Force block checking P_CheckMissileSpawn(mo); } //---------------------------------------------------------------------------- // // PROC A_Scream // //---------------------------------------------------------------------------- void A_Scream(mobj_t * actor) { int sound; S_StopSound(actor); if (actor->player) { if (actor->player->morphTics) { S_StartSound(actor, actor->info->deathsound); } else { // Handle the different player death screams if (actor->momz <= -39 * FRACUNIT) { // Falling splat sound = SFX_PLAYER_FALLING_SPLAT; } else if (actor->health > -50) { // Normal death sound switch (actor->player->class) { case PCLASS_FIGHTER: sound = SFX_PLAYER_FIGHTER_NORMAL_DEATH; break; case PCLASS_CLERIC: sound = SFX_PLAYER_CLERIC_NORMAL_DEATH; break; case PCLASS_MAGE: sound = SFX_PLAYER_MAGE_NORMAL_DEATH; break; default: sound = SFX_NONE; break; } } else if (actor->health > -100) { // Crazy death sound switch (actor->player->class) { case PCLASS_FIGHTER: sound = SFX_PLAYER_FIGHTER_CRAZY_DEATH; break; case PCLASS_CLERIC: sound = SFX_PLAYER_CLERIC_CRAZY_DEATH; break; case PCLASS_MAGE: sound = SFX_PLAYER_MAGE_CRAZY_DEATH; break; default: sound = SFX_NONE; break; } } else { // Extreme death sound switch (actor->player->class) { case PCLASS_FIGHTER: sound = SFX_PLAYER_FIGHTER_EXTREME1_DEATH; break; case PCLASS_CLERIC: sound = SFX_PLAYER_CLERIC_EXTREME1_DEATH; break; case PCLASS_MAGE: sound = SFX_PLAYER_MAGE_EXTREME1_DEATH; break; default: sound = SFX_NONE; break; } sound += P_Random() % 3; // Three different extreme deaths } S_StartSound(actor, sound); } } else { S_StartSound(actor, actor->info->deathsound); } } //--------------------------------------------------------------------------- // // PROC P_DropItem // //--------------------------------------------------------------------------- /* void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance) { mobj_t *mo; if(P_Random() > chance) { return; } mo = P_SpawnMobj(source->x, source->y, source->z+(source->height>>1), type); mo->momx = (P_Random()-P_Random())<<8; mo->momy = (P_Random()-P_Random())<<8; mo->momz = FRACUNIT*5+(P_Random()<<10); mo->flags2 |= MF2_DROPPED; mo->health = special; } */ //---------------------------------------------------------------------------- // // PROC A_NoBlocking // //---------------------------------------------------------------------------- void A_NoBlocking(mobj_t * actor) { actor->flags &= ~MF_SOLID; // Check for monsters dropping things /* switch(actor->type) { // Add the monster dropped items here case MT_MUMMYLEADERGHOST: P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84); break; default: break; } */ } //---------------------------------------------------------------------------- // // PROC A_Explode // // Handles a bunch of exploding things. // //---------------------------------------------------------------------------- void A_Explode(mobj_t * actor) { int damage; int distance; boolean damageSelf; damage = 128; distance = 128; damageSelf = true; switch (actor->type) { case MT_FIREBOMB: // Time Bombs actor->z += 32 * FRACUNIT; actor->flags &= ~MF_SHADOW; break; case MT_MNTRFX2: // Minotaur floor fire damage = 24; break; case MT_BISHOP: // Bishop radius death damage = 25 + (P_Random() & 15); break; case MT_HAMMER_MISSILE: // Fighter Hammer damage = 128; damageSelf = false; break; case MT_FSWORD_MISSILE: // Fighter Runesword damage = 64; damageSelf = false; break; case MT_CIRCLEFLAME: // Cleric Flame secondary flames damage = 20; damageSelf = false; break; case MT_SORCBALL1: // Sorcerer balls case MT_SORCBALL2: case MT_SORCBALL3: distance = 255; damage = 255; actor->args[0] = 1; // don't play bounce break; case MT_SORCFX1: // Sorcerer spell 1 damage = 30; break; case MT_SORCFX4: // Sorcerer spell 4 damage = 20; break; case MT_TREEDESTRUCTIBLE: damage = 10; break; case MT_DRAGON_FX2: damage = 80; damageSelf = false; break; case MT_MSTAFF_FX: damage = 64; distance = 192; damageSelf = false; break; case MT_MSTAFF_FX2: damage = 80; distance = 192; damageSelf = false; break; case MT_POISONCLOUD: damage = 4; distance = 40; break; case MT_ZXMAS_TREE: case MT_ZSHRUB2: damage = 30; distance = 64; break; default: break; } P_RadiusAttack(actor, actor->target, damage, distance, damageSelf); if (actor->z <= actor->floorz + (distance << FRACBITS) && actor->type != MT_POISONCLOUD) { P_HitFloor(actor); } } //---------------------------------------------------------------------------- // // PROC P_Massacre // // Kills all monsters. // //---------------------------------------------------------------------------- int P_Massacre(void) { int count; mobj_t *mo; thinker_t *think; count = 0; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *) think; if ((mo->flags & MF_COUNTKILL) && (mo->health > 0)) { mo->flags2 &= ~(MF2_NONSHOOTABLE + MF2_INVULNERABLE); mo->flags |= MF_SHOOTABLE; P_DamageMobj(mo, NULL, NULL, 10000); count++; } } return count; } //---------------------------------------------------------------------------- // // PROC A_SkullPop // //---------------------------------------------------------------------------- void A_SkullPop(mobj_t * actor) { mobj_t *mo; player_t *player; if (!actor->player) { return; } actor->flags &= ~MF_SOLID; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 48 * FRACUNIT, MT_BLOODYSKULL); //mo->target = actor; mo->momx = (P_Random() - P_Random()) << 9; mo->momy = (P_Random() - P_Random()) << 9; mo->momz = FRACUNIT * 2 + (P_Random() << 6); // Attach player mobj to bloody skull player = actor->player; actor->player = NULL; actor->special1.i = player->class; mo->player = player; mo->health = actor->health; mo->angle = actor->angle; player->mo = mo; player->lookdir = 0; player->damagecount = 32; } //---------------------------------------------------------------------------- // // PROC A_CheckSkullFloor // //---------------------------------------------------------------------------- void A_CheckSkullFloor(mobj_t * actor) { if (actor->z <= actor->floorz) { P_SetMobjState(actor, S_BLOODYSKULLX1); S_StartSound(actor, SFX_DRIP); } } //---------------------------------------------------------------------------- // // PROC A_CheckSkullDone // //---------------------------------------------------------------------------- void A_CheckSkullDone(mobj_t * actor) { if (actor->special2.i == 666) { P_SetMobjState(actor, S_BLOODYSKULLX2); } } //---------------------------------------------------------------------------- // // PROC A_CheckBurnGone // //---------------------------------------------------------------------------- void A_CheckBurnGone(mobj_t * actor) { if (actor->special2.i == 666) { P_SetMobjState(actor, S_PLAY_FDTH20); } } //---------------------------------------------------------------------------- // // PROC A_FreeTargMobj // //---------------------------------------------------------------------------- void A_FreeTargMobj(mobj_t * mo) { mo->momx = mo->momy = mo->momz = 0; mo->z = mo->ceilingz + 4 * FRACUNIT; mo->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_SOLID | MF_COUNTKILL); mo->flags |= MF_CORPSE | MF_DROPOFF | MF_NOGRAVITY; mo->flags2 &= ~(MF2_PASSMOBJ | MF2_LOGRAV); mo->flags2 |= MF2_DONTDRAW; mo->player = NULL; mo->health = -1000; // Don't resurrect } //---------------------------------------------------------------------------- // // CorpseQueue Routines // //---------------------------------------------------------------------------- // Corpse queue for monsters - this should be saved out #define CORPSEQUEUESIZE 64 mobj_t *corpseQueue[CORPSEQUEUESIZE]; int corpseQueueSlot; // throw another corpse on the queue void A_QueueCorpse(mobj_t * actor) { mobj_t *corpse; if (corpseQueueSlot >= CORPSEQUEUESIZE) { // Too many corpses - remove an old one corpse = corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE]; if (corpse) P_RemoveMobj(corpse); } corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE] = actor; corpseQueueSlot++; } // Remove a mobj from the queue (for resurrection) void A_DeQueueCorpse(mobj_t * actor) { int slot; for (slot = 0; slot < CORPSEQUEUESIZE; slot++) { if (corpseQueue[slot] == actor) { corpseQueue[slot] = NULL; break; } } } void P_InitCreatureCorpseQueue(boolean corpseScan) { thinker_t *think; mobj_t *mo; // Initialize queue corpseQueueSlot = 0; memset(corpseQueue, 0, sizeof(mobj_t *) * CORPSEQUEUESIZE); if (!corpseScan) return; // Search mobj list for corpses and place them in this queue for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) continue; mo = (mobj_t *) think; if (!(mo->flags & MF_CORPSE)) continue; // Must be a corpse if (mo->flags & MF_ICECORPSE) continue; // Not ice corpses // Only corpses that call A_QueueCorpse from death routine switch (mo->type) { case MT_CENTAUR: case MT_CENTAURLEADER: case MT_DEMON: case MT_DEMON2: case MT_WRAITH: case MT_WRAITHB: case MT_BISHOP: case MT_ETTIN: case MT_PIG: case MT_CENTAUR_SHIELD: case MT_CENTAUR_SWORD: case MT_DEMONCHUNK1: case MT_DEMONCHUNK2: case MT_DEMONCHUNK3: case MT_DEMONCHUNK4: case MT_DEMONCHUNK5: case MT_DEMON2CHUNK1: case MT_DEMON2CHUNK2: case MT_DEMON2CHUNK3: case MT_DEMON2CHUNK4: case MT_DEMON2CHUNK5: case MT_FIREDEMON_SPLOTCH1: case MT_FIREDEMON_SPLOTCH2: A_QueueCorpse(mo); // Add corpse to queue break; default: break; } } } //---------------------------------------------------------------------------- // // PROC A_AddPlayerCorpse // //---------------------------------------------------------------------------- #define BODYQUESIZE 32 mobj_t *bodyque[BODYQUESIZE]; int bodyqueslot; void A_AddPlayerCorpse(mobj_t * actor) { if (bodyqueslot >= BODYQUESIZE) { // Too many player corpses - remove an old one P_RemoveMobj(bodyque[bodyqueslot % BODYQUESIZE]); } bodyque[bodyqueslot % BODYQUESIZE] = actor; bodyqueslot++; } //============================================================================ // // A_SerpentUnHide // //============================================================================ void A_SerpentUnHide(mobj_t * actor) { actor->flags2 &= ~MF2_DONTDRAW; actor->floorclip = 24 * FRACUNIT; } //============================================================================ // // A_SerpentHide // //============================================================================ void A_SerpentHide(mobj_t * actor) { actor->flags2 |= MF2_DONTDRAW; actor->floorclip = 0; } //============================================================================ // // A_SerpentChase // //============================================================================ void A_SerpentChase(mobj_t * actor) { int delta; int oldX, oldY, oldFloor; if (actor->reactiontime) { actor->reactiontime--; } // Modify target threshold if (actor->threshold) { actor->threshold--; } if (gameskill == sk_nightmare) { // Monsters move faster in nightmare mode actor->tics -= actor->tics / 2; if (actor->tics < 3) { actor->tics = 3; } } // // turn towards movement direction if not there yet // if (actor->movedir < 8) { actor->angle &= (7 << 29); delta = actor->angle - (actor->movedir << 29); if (delta > 0) { actor->angle -= ANG90 / 2; } else if (delta < 0) { actor->angle += ANG90 / 2; } } if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { // look for a new target if (P_LookForPlayers(actor, true)) { // got a new target return; } P_SetMobjState(actor, actor->info->spawnstate); return; } // // don't attack twice in a row // if (actor->flags & MF_JUSTATTACKED) { actor->flags &= ~MF_JUSTATTACKED; if (gameskill != sk_nightmare) P_NewChaseDir(actor); return; } // // check for melee attack // if (actor->info->meleestate && P_CheckMeleeRange(actor)) { if (actor->info->attacksound) { S_StartSound(actor, actor->info->attacksound); } P_SetMobjState(actor, actor->info->meleestate); return; } // // possibly choose another target // if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target)) { if (P_LookForPlayers(actor, true)) return; // got a new target } // // chase towards player // oldX = actor->x; oldY = actor->y; oldFloor = actor->subsector->sector->floorpic; if (--actor->movecount < 0 || !P_Move(actor)) { P_NewChaseDir(actor); } if (actor->subsector->sector->floorpic != oldFloor) { P_TryMove(actor, oldX, oldY); P_NewChaseDir(actor); } // // make active sound // if (actor->info->activesound && P_Random() < 3) { S_StartSound(actor, actor->info->activesound); } } //============================================================================ // // A_SerpentRaiseHump // // Raises the hump above the surface by raising the floorclip level //============================================================================ void A_SerpentRaiseHump(mobj_t * actor) { actor->floorclip -= 4 * FRACUNIT; } //============================================================================ // // A_SerpentLowerHump // //============================================================================ void A_SerpentLowerHump(mobj_t * actor) { actor->floorclip += 4 * FRACUNIT; } //============================================================================ // // A_SerpentHumpDecide // // Decided whether to hump up, or if the mobj is a serpent leader, // to missile attack //============================================================================ void A_SerpentHumpDecide(mobj_t * actor) { if (actor->type == MT_SERPENTLEADER) { if (P_Random() > 30) { return; } else if (P_Random() < 40) { // Missile attack P_SetMobjState(actor, S_SERPENT_SURFACE1); return; } } else if (P_Random() > 3) { return; } if (!P_CheckMeleeRange(actor)) { // The hump shouldn't occur when within melee range if (actor->type == MT_SERPENTLEADER && P_Random() < 128) { P_SetMobjState(actor, S_SERPENT_SURFACE1); } else { P_SetMobjState(actor, S_SERPENT_HUMP1); S_StartSound(actor, SFX_SERPENT_ACTIVE); } } } //============================================================================ // // A_SerpentBirthScream // //============================================================================ void A_SerpentBirthScream(mobj_t * actor) { S_StartSound(actor, SFX_SERPENT_BIRTH); } //============================================================================ // // A_SerpentDiveSound // //============================================================================ void A_SerpentDiveSound(mobj_t * actor) { S_StartSound(actor, SFX_SERPENT_ACTIVE); } //============================================================================ // // A_SerpentWalk // // Similar to A_Chase, only has a hardcoded entering of meleestate //============================================================================ void A_SerpentWalk(mobj_t * actor) { int delta; if (actor->reactiontime) { actor->reactiontime--; } // Modify target threshold if (actor->threshold) { actor->threshold--; } if (gameskill == sk_nightmare) { // Monsters move faster in nightmare mode actor->tics -= actor->tics / 2; if (actor->tics < 3) { actor->tics = 3; } } // // turn towards movement direction if not there yet // if (actor->movedir < 8) { actor->angle &= (7 << 29); delta = actor->angle - (actor->movedir << 29); if (delta > 0) { actor->angle -= ANG90 / 2; } else if (delta < 0) { actor->angle += ANG90 / 2; } } if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { // look for a new target if (P_LookForPlayers(actor, true)) { // got a new target return; } P_SetMobjState(actor, actor->info->spawnstate); return; } // // don't attack twice in a row // if (actor->flags & MF_JUSTATTACKED) { actor->flags &= ~MF_JUSTATTACKED; if (gameskill != sk_nightmare) P_NewChaseDir(actor); return; } // // check for melee attack // if (actor->info->meleestate && P_CheckMeleeRange(actor)) { if (actor->info->attacksound) { S_StartSound(actor, actor->info->attacksound); } P_SetMobjState(actor, S_SERPENT_ATK1); return; } // // possibly choose another target // if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target)) { if (P_LookForPlayers(actor, true)) return; // got a new target } // // chase towards player // if (--actor->movecount < 0 || !P_Move(actor)) { P_NewChaseDir(actor); } } //============================================================================ // // A_SerpentCheckForAttack // //============================================================================ void A_SerpentCheckForAttack(mobj_t * actor) { if (!actor->target) { return; } if (actor->type == MT_SERPENTLEADER) { if (!P_CheckMeleeRange(actor)) { P_SetMobjState(actor, S_SERPENT_ATK1); return; } } if (P_CheckMeleeRange2(actor)) { P_SetMobjState(actor, S_SERPENT_WALK1); } else if (P_CheckMeleeRange(actor)) { if (P_Random() < 32) { P_SetMobjState(actor, S_SERPENT_WALK1); } else { P_SetMobjState(actor, S_SERPENT_ATK1); } } } //============================================================================ // // A_SerpentChooseAttack // //============================================================================ void A_SerpentChooseAttack(mobj_t * actor) { if (!actor->target || P_CheckMeleeRange(actor)) { return; } if (actor->type == MT_SERPENTLEADER) { P_SetMobjState(actor, S_SERPENT_MISSILE1); } } //============================================================================ // // A_SerpentMeleeAttack // //============================================================================ void A_SerpentMeleeAttack(mobj_t * actor) { if (!actor->target) { return; } if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(5)); S_StartSound(actor, SFX_SERPENT_MELEEHIT); } if (P_Random() < 96) { A_SerpentCheckForAttack(actor); } } //============================================================================ // // A_SerpentMissileAttack // //============================================================================ void A_SerpentMissileAttack(mobj_t * actor) { if (!actor->target) { return; } P_SpawnMissile(actor, actor->target, MT_SERPENTFX); } //============================================================================ // // A_SerpentHeadPop // //============================================================================ void A_SerpentHeadPop(mobj_t * actor) { P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_SERPENT_HEAD); } //============================================================================ // // A_SerpentSpawnGibs // //============================================================================ void A_SerpentSpawnGibs(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12), actor->y + ((P_Random() - 128) << 12), actor->floorz + FRACUNIT, MT_SERPENT_GIB1); if (mo) { mo->momx = (P_Random() - 128) << 6; mo->momy = (P_Random() - 128) << 6; mo->floorclip = 6 * FRACUNIT; } mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12), actor->y + ((P_Random() - 128) << 12), actor->floorz + FRACUNIT, MT_SERPENT_GIB2); if (mo) { mo->momx = (P_Random() - 128) << 6; mo->momy = (P_Random() - 128) << 6; mo->floorclip = 6 * FRACUNIT; } mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12), actor->y + ((P_Random() - 128) << 12), actor->floorz + FRACUNIT, MT_SERPENT_GIB3); if (mo) { mo->momx = (P_Random() - 128) << 6; mo->momy = (P_Random() - 128) << 6; mo->floorclip = 6 * FRACUNIT; } } //============================================================================ // // A_FloatGib // //============================================================================ void A_FloatGib(mobj_t * actor) { actor->floorclip -= FRACUNIT; } //============================================================================ // // A_SinkGib // //============================================================================ void A_SinkGib(mobj_t * actor) { actor->floorclip += FRACUNIT; } //============================================================================ // // A_DelayGib // //============================================================================ void A_DelayGib(mobj_t * actor) { actor->tics -= P_Random() >> 2; } //============================================================================ // // A_SerpentHeadCheck // //============================================================================ void A_SerpentHeadCheck(mobj_t * actor) { if (actor->z <= actor->floorz) { if (P_GetThingFloorType(actor) >= FLOOR_LIQUID) { P_HitFloor(actor); P_SetMobjState(actor, S_NULL); } else { P_SetMobjState(actor, S_SERPENT_HEAD_X1); } } } //============================================================================ // // A_CentaurAttack // //============================================================================ void A_CentaurAttack(mobj_t * actor) { if (!actor->target) { return; } if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, P_Random() % 7 + 3); } } //============================================================================ // // A_CentaurAttack2 // //============================================================================ void A_CentaurAttack2(mobj_t * actor) { if (!actor->target) { return; } P_SpawnMissile(actor, actor->target, MT_CENTAUR_FX); S_StartSound(actor, SFX_CENTAURLEADER_ATTACK); } //============================================================================ // // A_CentaurDropStuff // // Spawn shield/sword sprites when the centaur pulps //============================================================================ void A_CentaurDropStuff(mobj_t * actor) { mobj_t *mo; angle_t angle; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_CENTAUR_SHIELD); if (mo) { angle = actor->angle + ANG90; mo->momz = FRACUNIT * 8 + (P_Random() << 10); mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_CENTAUR_SWORD); if (mo) { angle = actor->angle - ANG90; mo->momz = FRACUNIT * 8 + (P_Random() << 10); mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } } //============================================================================ // // A_CentaurDefend // //============================================================================ void A_CentaurDefend(mobj_t * actor) { A_FaceTarget(actor); if (P_CheckMeleeRange(actor) && P_Random() < 32) { A_UnSetInvulnerable(actor); P_SetMobjState(actor, actor->info->meleestate); } } //============================================================================ // // A_BishopAttack // //============================================================================ void A_BishopAttack(mobj_t * actor) { if (!actor->target) { return; } S_StartSound(actor, actor->info->attacksound); if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(4)); return; } actor->special1.i = (P_Random() & 3) + 5; } //============================================================================ // // A_BishopAttack2 // // Spawns one of a string of bishop missiles //============================================================================ void A_BishopAttack2(mobj_t * actor) { mobj_t *mo; if (!actor->target || !actor->special1.i) { actor->special1.i = 0; P_SetMobjState(actor, S_BISHOP_WALK1); return; } mo = P_SpawnMissile(actor, actor->target, MT_BISH_FX); if (mo) { mo->special1.m = actor->target; mo->special2.i = 16; // High word == x/y, Low word == z } actor->special1.i--; } //============================================================================ // // A_BishopMissileWeave // //============================================================================ void A_BishopMissileWeave(mobj_t * actor) { fixed_t newX, newY; int weaveXY, weaveZ; int angle; weaveXY = actor->special2.i >> 16; weaveZ = actor->special2.i & 0xFFFF; angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT; newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 1); newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 1); weaveXY = (weaveXY + 2) & 63; newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 1); newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 1); P_TryMove(actor, newX, newY); actor->z -= FloatBobOffsets[weaveZ]; weaveZ = (weaveZ + 2) & 63; actor->z += FloatBobOffsets[weaveZ]; actor->special2.i = weaveZ + (weaveXY << 16); } //============================================================================ // // A_BishopMissileSeek // //============================================================================ void A_BishopMissileSeek(mobj_t * actor) { P_SeekerMissile(actor, ANG1 * 2, ANG1 * 3); } //============================================================================ // // A_BishopDecide // //============================================================================ void A_BishopDecide(mobj_t * actor) { if (P_Random() < 220) { return; } else { P_SetMobjState(actor, S_BISHOP_BLUR1); } } //============================================================================ // // A_BishopDoBlur // //============================================================================ void A_BishopDoBlur(mobj_t * actor) { actor->special1.i = (P_Random() & 3) + 3; // Random number of blurs if (P_Random() < 120) { P_ThrustMobj(actor, actor->angle + ANG90, 11 * FRACUNIT); } else if (P_Random() > 125) { P_ThrustMobj(actor, actor->angle - ANG90, 11 * FRACUNIT); } else { // Thrust forward P_ThrustMobj(actor, actor->angle, 11 * FRACUNIT); } S_StartSound(actor, SFX_BISHOP_BLUR); } //============================================================================ // // A_BishopSpawnBlur // //============================================================================ void A_BishopSpawnBlur(mobj_t * actor) { mobj_t *mo; if (!--actor->special1.i) { actor->momx = 0; actor->momy = 0; if (P_Random() > 96) { P_SetMobjState(actor, S_BISHOP_WALK1); } else { P_SetMobjState(actor, S_BISHOP_ATK1); } } mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOPBLUR); if (mo) { mo->angle = actor->angle; } } //============================================================================ // // A_BishopChase // //============================================================================ void A_BishopChase(mobj_t * actor) { actor->z -= FloatBobOffsets[actor->special2.i] >> 1; actor->special2.i = (actor->special2.i + 4) & 63; actor->z += FloatBobOffsets[actor->special2.i] >> 1; } //============================================================================ // // A_BishopPuff // //============================================================================ void A_BishopPuff(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 40 * FRACUNIT, MT_BISHOP_PUFF); if (mo) { mo->momz = FRACUNIT / 2; } } //============================================================================ // // A_BishopPainBlur // //============================================================================ void A_BishopPainBlur(mobj_t * actor) { mobj_t *mo; if (P_Random() < 64) { P_SetMobjState(actor, S_BISHOP_BLUR1); return; } mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 12), actor->y + ((P_Random() - P_Random()) << 12), actor->z + ((P_Random() - P_Random()) << 11), MT_BISHOPPAINBLUR); if (mo) { mo->angle = actor->angle; } } //============================================================================ // // DragonSeek // //============================================================================ static void DragonSeek(mobj_t * actor, angle_t thresh, angle_t turnMax) { int dir; int dist; angle_t delta; angle_t angle; mobj_t *target; int search; int i; int bestArg; angle_t bestAngle; angle_t angleToSpot, angleToTarget; mobj_t *mo; target = actor->special1.m; if (target == NULL) { return; } dir = P_FaceMobj(actor, target, &delta); if (delta > thresh) { delta >>= 1; if (delta > turnMax) { delta = turnMax; } } if (dir) { // Turn clockwise actor->angle += delta; } else { // Turn counter clockwise actor->angle -= delta; } angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(actor->info->speed, finecosine[angle]); actor->momy = FixedMul(actor->info->speed, finesine[angle]); if (actor->z + actor->height < target->z || target->z + target->height < actor->z) { dist = P_AproxDistance(target->x - actor->x, target->y - actor->y); dist = dist / actor->info->speed; if (dist < 1) { dist = 1; } actor->momz = (target->z - actor->z) / dist; } else { dist = P_AproxDistance(target->x - actor->x, target->y - actor->y); dist = dist / actor->info->speed; } if (target->flags & MF_SHOOTABLE && P_Random() < 64) { // attack the destination mobj if it's attackable mobj_t *oldTarget; if (abs(actor->angle - R_PointToAngle2(actor->x, actor->y, target->x, target->y)) < ANG45 / 2) { oldTarget = actor->target; actor->target = target; if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(10)); S_StartSound(actor, SFX_DRAGON_ATTACK); } else if (P_Random() < 128 && P_CheckMissileRange(actor)) { P_SpawnMissile(actor, target, MT_DRAGON_FX); S_StartSound(actor, SFX_DRAGON_ATTACK); } actor->target = oldTarget; } } if (dist < 4) { // Hit the target thing if (actor->target && P_Random() < 200) { bestArg = -1; bestAngle = ANG_MAX; angleToTarget = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); for (i = 0; i < 5; i++) { if (!target->args[i]) { continue; } search = -1; mo = P_FindMobjFromTID(target->args[i], &search); angleToSpot = R_PointToAngle2(actor->x, actor->y, mo->x, mo->y); if (abs(angleToSpot - angleToTarget) < bestAngle) { bestAngle = abs(angleToSpot - angleToTarget); bestArg = i; } } if (bestArg != -1) { search = -1; actor->special1.m = P_FindMobjFromTID(target->args[bestArg], &search); } } else { do { i = (P_Random() >> 2) % 5; } while (!target->args[i]); search = -1; actor->special1.m = P_FindMobjFromTID(target->args[i], &search); } } } //============================================================================ // // A_DragonInitFlight // //============================================================================ void A_DragonInitFlight(mobj_t * actor) { int search; search = -1; do { // find the first tid identical to the dragon's tid actor->special1.m = P_FindMobjFromTID(actor->tid, &search); if (search == -1) { P_SetMobjState(actor, actor->info->spawnstate); return; } } while (actor->special1.m == actor); P_RemoveMobjFromTIDList(actor); } //============================================================================ // // A_DragonFlight // //============================================================================ void A_DragonFlight(mobj_t * actor) { angle_t angle; DragonSeek(actor, 4 * ANG1, 8 * ANG1); if (actor->target) { if (!(actor->target->flags & MF_SHOOTABLE)) { // target died actor->target = NULL; return; } angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); if (abs(actor->angle - angle) < ANG45 / 2 && P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(8)); S_StartSound(actor, SFX_DRAGON_ATTACK); } else if (abs(actor->angle - angle) <= ANG1 * 20) { P_SetMobjState(actor, actor->info->missilestate); S_StartSound(actor, SFX_DRAGON_ATTACK); } } else { P_LookForPlayers(actor, true); } } //============================================================================ // // A_DragonFlap // //============================================================================ void A_DragonFlap(mobj_t * actor) { A_DragonFlight(actor); if (P_Random() < 240) { S_StartSound(actor, SFX_DRAGON_WINGFLAP); } else { S_StartSound(actor, actor->info->activesound); } } //============================================================================ // // A_DragonAttack // //============================================================================ void A_DragonAttack(mobj_t * actor) { P_SpawnMissile(actor, actor->target, MT_DRAGON_FX); } //============================================================================ // // A_DragonFX2 // //============================================================================ void A_DragonFX2(mobj_t * actor) { mobj_t *mo; int i; int delay; delay = 16 + (P_Random() >> 3); for (i = 1 + (P_Random() & 3); i; i--) { mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 14), actor->y + ((P_Random() - 128) << 14), actor->z + ((P_Random() - 128) << 12), MT_DRAGON_FX2); if (mo) { mo->tics = delay + (P_Random() & 3) * i * 2; mo->target = actor->target; } } } //============================================================================ // // A_DragonPain // //============================================================================ void A_DragonPain(mobj_t * actor) { A_Pain(actor); if (!actor->special1.i) { // no destination spot yet P_SetMobjState(actor, S_DRAGON_INIT); } } //============================================================================ // // A_DragonCheckCrash // //============================================================================ void A_DragonCheckCrash(mobj_t * actor) { if (actor->z <= actor->floorz) { P_SetMobjState(actor, S_DRAGON_CRASH1); } } //============================================================================ // Demon AI //============================================================================ // // A_DemonAttack1 (melee) // void A_DemonAttack1(mobj_t * actor) { if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(2)); } } // // A_DemonAttack2 (missile) // void A_DemonAttack2(mobj_t * actor) { mobj_t *mo; int fireBall; if (actor->type == MT_DEMON) { fireBall = MT_DEMONFX1; } else { fireBall = MT_DEMON2FX1; } mo = P_SpawnMissile(actor, actor->target, fireBall); if (mo) { mo->z += 30 * FRACUNIT; S_StartSound(actor, SFX_DEMON_MISSILE_FIRE); } } // // A_DemonDeath // void A_DemonDeath(mobj_t * actor) { mobj_t *mo; angle_t angle; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMONCHUNK1); if (mo) { angle = actor->angle + ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMONCHUNK2); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMONCHUNK3); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMONCHUNK4); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMONCHUNK5); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } } //=========================================================================== // // A_Demon2Death // //=========================================================================== void A_Demon2Death(mobj_t * actor) { mobj_t *mo; angle_t angle; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMON2CHUNK1); if (mo) { angle = actor->angle + ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMON2CHUNK2); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMON2CHUNK3); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMON2CHUNK4); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT, MT_DEMON2CHUNK5); if (mo) { angle = actor->angle - ANG90; mo->momz = 8 * FRACUNIT; mo->momx = FixedMul((P_Random() << 10) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 10) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; } } // // A_SinkMobj // Sink a mobj incrementally into the floor // boolean A_SinkMobj(mobj_t * actor) { if (actor->floorclip < actor->info->height) { switch (actor->type) { case MT_THRUSTFLOOR_DOWN: case MT_THRUSTFLOOR_UP: actor->floorclip += 6 * FRACUNIT; break; default: actor->floorclip += FRACUNIT; break; } return false; } return true; } // // A_RaiseMobj // Raise a mobj incrementally from the floor to // boolean A_RaiseMobj(mobj_t * actor) { int done = true; // Raise a mobj from the ground if (actor->floorclip > 0) { switch (actor->type) { case MT_WRAITHB: actor->floorclip -= 2 * FRACUNIT; break; case MT_THRUSTFLOOR_DOWN: case MT_THRUSTFLOOR_UP: actor->floorclip -= actor->special2.i * FRACUNIT; break; default: actor->floorclip -= 2 * FRACUNIT; break; } if (actor->floorclip <= 0) { actor->floorclip = 0; done = true; } else { done = false; } } return done; // Reached target height } //============================================================================ // Wraith Variables // // special1 Internal index into floatbob // special2 //============================================================================ // // A_WraithInit // void A_WraithInit(mobj_t * actor) { actor->z += 48 << FRACBITS; actor->special1.i = 0; // index into floatbob } void A_WraithRaiseInit(mobj_t * actor) { actor->flags2 &= ~MF2_DONTDRAW; actor->flags2 &= ~MF2_NONSHOOTABLE; actor->flags |= MF_SHOOTABLE | MF_SOLID; actor->floorclip = actor->info->height; } void A_WraithRaise(mobj_t * actor) { if (A_RaiseMobj(actor)) { // Reached it's target height P_SetMobjState(actor, S_WRAITH_CHASE1); } P_SpawnDirt(actor, actor->radius); } void A_WraithMelee(mobj_t * actor) { int amount; // Steal health from target and give to player if (P_CheckMeleeRange(actor) && (P_Random() < 220)) { amount = HITDICE(2); P_DamageMobj(actor->target, actor, actor, amount); actor->health += amount; } } void A_WraithMissile(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMissile(actor, actor->target, MT_WRAITHFX1); if (mo) { S_StartSound(actor, SFX_WRAITH_MISSILE_FIRE); } } // // A_WraithFX2 - spawns sparkle tail of missile // void A_WraithFX2(mobj_t * actor) { mobj_t *mo; angle_t angle; int i; for (i = 0; i < 2; i++) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX2); if (mo) { if (P_Random() < 128) { angle = actor->angle + (P_Random() << 22); } else { angle = actor->angle - (P_Random() << 22); } mo->momz = 0; mo->momx = FixedMul((P_Random() << 7) + FRACUNIT, finecosine[angle >> ANGLETOFINESHIFT]); mo->momy = FixedMul((P_Random() << 7) + FRACUNIT, finesine[angle >> ANGLETOFINESHIFT]); mo->target = actor; mo->floorclip = 10 * FRACUNIT; } } } // Spawn an FX3 around the actor during attacks void A_WraithFX3(mobj_t * actor) { mobj_t *mo; int numdropped = P_Random() % 15; int i; for (i = 0; i < numdropped; i++) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX3); if (mo) { mo->x += (P_Random() - 128) << 11; mo->y += (P_Random() - 128) << 11; mo->z += (P_Random() << 10); mo->target = actor; } } } // Spawn an FX4 during movement void A_WraithFX4(mobj_t * actor) { mobj_t *mo; int chance = P_Random(); int spawn4, spawn5; if (chance < 10) { spawn4 = true; spawn5 = false; } else if (chance < 20) { spawn4 = false; spawn5 = true; } else if (chance < 25) { spawn4 = true; spawn5 = true; } else { spawn4 = false; spawn5 = false; } if (spawn4) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX4); if (mo) { mo->x += (P_Random() - 128) << 12; mo->y += (P_Random() - 128) << 12; mo->z += (P_Random() << 10); mo->target = actor; } } if (spawn5) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX5); if (mo) { mo->x += (P_Random() - 128) << 11; mo->y += (P_Random() - 128) << 11; mo->z += (P_Random() << 10); mo->target = actor; } } } void A_WraithLook(mobj_t * actor) { // A_WraithFX4(actor); // too expensive A_Look(actor); } void A_WraithChase(mobj_t * actor) { int weaveindex = actor->special1.i; actor->z += FloatBobOffsets[weaveindex]; actor->special1.i = (weaveindex + 2) & 63; // if (actor->floorclip > 0) // { // P_SetMobjState(actor, S_WRAITH_RAISE2); // return; // } A_Chase(actor); A_WraithFX4(actor); } //============================================================================ // Ettin AI //============================================================================ void A_EttinAttack(mobj_t * actor) { if (P_CheckMeleeRange(actor)) { P_DamageMobj(actor->target, actor, actor, HITDICE(2)); } } void A_DropMace(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height >> 1), MT_ETTIN_MACE); if (mo) { mo->momx = (P_Random() - 128) << 11; mo->momy = (P_Random() - 128) << 11; mo->momz = FRACUNIT * 10 + (P_Random() << 10); mo->target = actor; } } //============================================================================ // Fire Demon AI // // special1 index into floatbob // special2 whether strafing or not //============================================================================ void A_FiredSpawnRock(mobj_t * actor) { mobj_t *mo; int x, y, z; int rtype = 0; switch (P_Random() % 5) { case 0: rtype = MT_FIREDEMON_FX1; break; case 1: rtype = MT_FIREDEMON_FX2; break; case 2: rtype = MT_FIREDEMON_FX3; break; case 3: rtype = MT_FIREDEMON_FX4; break; case 4: rtype = MT_FIREDEMON_FX5; break; } x = actor->x + ((P_Random() - 128) << 12); y = actor->y + ((P_Random() - 128) << 12); z = actor->z + ((P_Random()) << 11); mo = P_SpawnMobj(x, y, z, rtype); if (mo) { mo->target = actor; mo->momx = (P_Random() - 128) << 10; mo->momy = (P_Random() - 128) << 10; mo->momz = (P_Random() << 10); mo->special1.i = 2; // Number bounces } // Initialize fire demon actor->special2.i = 0; actor->flags &= ~MF_JUSTATTACKED; } void A_FiredRocks(mobj_t * actor) { A_FiredSpawnRock(actor); A_FiredSpawnRock(actor); A_FiredSpawnRock(actor); A_FiredSpawnRock(actor); A_FiredSpawnRock(actor); } void A_FiredAttack(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMissile(actor, actor->target, MT_FIREDEMON_FX6); if (mo) S_StartSound(actor, SFX_FIRED_ATTACK); } void A_SmBounce(mobj_t * actor) { // give some more momentum (x,y,&z) actor->z = actor->floorz + FRACUNIT; actor->momz = (2 * FRACUNIT) + (P_Random() << 10); actor->momx = P_Random() % 3 << FRACBITS; actor->momy = P_Random() % 3 << FRACBITS; } #define FIREDEMON_ATTACK_RANGE 64*8*FRACUNIT void A_FiredChase(mobj_t * actor) { int weaveindex = actor->special1.i; mobj_t *target = actor->target; angle_t ang; fixed_t dist; if (actor->reactiontime) actor->reactiontime--; if (actor->threshold) actor->threshold--; // Float up and down actor->z += FloatBobOffsets[weaveindex]; actor->special1.i = (weaveindex + 2) & 63; // Insure it stays above certain height if (actor->z < actor->floorz + (64 * FRACUNIT)) { actor->z += 2 * FRACUNIT; } if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { // Invalid target P_LookForPlayers(actor, true); return; } // Strafe if (actor->special2.i > 0) { actor->special2.i--; } else { actor->special2.i = 0; actor->momx = actor->momy = 0; dist = P_AproxDistance(actor->x - target->x, actor->y - target->y); if (dist < FIREDEMON_ATTACK_RANGE) { if (P_Random() < 30) { ang = R_PointToAngle2(actor->x, actor->y, target->x, target->y); if (P_Random() < 128) ang += ANG90; else ang -= ANG90; ang >>= ANGLETOFINESHIFT; actor->momx = FixedMul(8 * FRACUNIT, finecosine[ang]); actor->momy = FixedMul(8 * FRACUNIT, finesine[ang]); actor->special2.i = 3; // strafe time } } } FaceMovementDirection(actor); // Normal movement if (!actor->special2.i) { if (--actor->movecount < 0 || !P_Move(actor)) { P_NewChaseDir(actor); } } // Do missile attack if (!(actor->flags & MF_JUSTATTACKED)) { if (P_CheckMissileRange(actor) && (P_Random() < 20)) { P_SetMobjState(actor, actor->info->missilestate); actor->flags |= MF_JUSTATTACKED; return; } } else { actor->flags &= ~MF_JUSTATTACKED; } // make active sound if (actor->info->activesound && P_Random() < 3) { S_StartSound(actor, actor->info->activesound); } } void A_FiredSplotch(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH1); if (mo) { mo->momx = (P_Random() - 128) << 11; mo->momy = (P_Random() - 128) << 11; mo->momz = FRACUNIT * 3 + (P_Random() << 10); } mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH2); if (mo) { mo->momx = (P_Random() - 128) << 11; mo->momy = (P_Random() - 128) << 11; mo->momz = FRACUNIT * 3 + (P_Random() << 10); } } //============================================================================ // // A_IceGuyLook // //============================================================================ void A_IceGuyLook(mobj_t * actor) { fixed_t dist; fixed_t an; A_Look(actor); if (P_Random() < 64) { dist = ((P_Random() - 128) * actor->radius) >> 7; an = (actor->angle + ANG90) >> ANGLETOFINESHIFT; P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]), actor->y + FixedMul(dist, finesine[an]), actor->z + 60 * FRACUNIT, MT_ICEGUY_WISP1 + (P_Random() & 1)); } } //============================================================================ // // A_IceGuyChase // //============================================================================ void A_IceGuyChase(mobj_t * actor) { fixed_t dist; fixed_t an; mobj_t *mo; A_Chase(actor); if (P_Random() < 128) { dist = ((P_Random() - 128) * actor->radius) >> 7; an = (actor->angle + ANG90) >> ANGLETOFINESHIFT; mo = P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]), actor->y + FixedMul(dist, finesine[an]), actor->z + 60 * FRACUNIT, MT_ICEGUY_WISP1 + (P_Random() & 1)); if (mo) { mo->momx = actor->momx; mo->momy = actor->momy; mo->momz = actor->momz; mo->target = actor; } } } //============================================================================ // // A_IceGuyAttack // //============================================================================ void A_IceGuyAttack(mobj_t * actor) { fixed_t an; if (!actor->target) { return; } an = (actor->angle + ANG90) >> ANGLETOFINESHIFT; P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1, finecosine[an]), actor->y + FixedMul(actor->radius >> 1, finesine[an]), actor->z + 40 * FRACUNIT, actor, actor->target, MT_ICEGUY_FX); an = (actor->angle - ANG90) >> ANGLETOFINESHIFT; P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1, finecosine[an]), actor->y + FixedMul(actor->radius >> 1, finesine[an]), actor->z + 40 * FRACUNIT, actor, actor->target, MT_ICEGUY_FX); S_StartSound(actor, actor->info->attacksound); } //============================================================================ // // A_IceGuyMissilePuff // //============================================================================ void A_IceGuyMissilePuff(mobj_t * actor) { P_SpawnMobj(actor->x, actor->y, actor->z + 2 * FRACUNIT, MT_ICEFX_PUFF); } //============================================================================ // // A_IceGuyDie // //============================================================================ void A_IceGuyDie(mobj_t * actor) { void A_FreezeDeathChunks(mobj_t * actor); actor->momx = 0; actor->momy = 0; actor->momz = 0; actor->height <<= 2; A_FreezeDeathChunks(actor); } //============================================================================ // // A_IceGuyMissileExplode // //============================================================================ void A_IceGuyMissileExplode(mobj_t * actor) { mobj_t *mo; unsigned int i; for (i = 0; i < 8; i++) { mo = P_SpawnMissileAngle(actor, MT_ICEGUY_FX2, i * ANG45, -0.3 * FRACUNIT); if (mo) { mo->target = actor->target; } } } //============================================================================ // // Sorcerer stuff // // Sorcerer Variables // special1 Angle of ball 1 (all others relative to that) // special2 which ball to stop at in stop mode (MT_???) // args[0] Denfense time // args[1] Number of full rotations since stopping mode // args[2] Target orbit speed for acceleration/deceleration // args[3] Movement mode (see SORC_ macros) // args[4] Current ball orbit speed // Sorcerer Ball Variables // special1 Previous angle of ball (for woosh) // special2 Countdown of rapid fire (FX4) // args[0] If set, don't play the bounce sound when bouncing //============================================================================ #define SORCBALL_INITIAL_SPEED 7 #define SORCBALL_TERMINAL_SPEED 25 #define SORCBALL_SPEED_ROTATIONS 5 #define SORC_DEFENSE_TIME 255 #define SORC_DEFENSE_HEIGHT 45 #define BOUNCE_TIME_UNIT (35/2) #define SORCFX4_RAPIDFIRE_TIME (6*3) // 3 seconds #define SORCFX4_SPREAD_ANGLE 20 #define SORC_DECELERATE 0 #define SORC_ACCELERATE 1 #define SORC_STOPPING 2 #define SORC_FIRESPELL 3 #define SORC_STOPPED 4 #define SORC_NORMAL 5 #define SORC_FIRING_SPELL 6 #define BALL1_ANGLEOFFSET 0 #define BALL2_ANGLEOFFSET (ANG_MAX/3) #define BALL3_ANGLEOFFSET ((ANG_MAX/3)*2) void A_SorcBallOrbit(mobj_t * actor); void A_SorcSpinBalls(mobj_t * actor); void A_SpeedBalls(mobj_t * actor); void A_SlowBalls(mobj_t * actor); void A_StopBalls(mobj_t * actor); void A_AccelBalls(mobj_t * actor); void A_DecelBalls(mobj_t * actor); void A_SorcBossAttack(mobj_t * actor); void A_SpawnFizzle(mobj_t * actor); void A_CastSorcererSpell(mobj_t * actor); void A_SorcUpdateBallAngle(mobj_t * actor); void A_BounceCheck(mobj_t * actor); void A_SorcFX1Seek(mobj_t * actor); void A_SorcOffense1(mobj_t * actor); void A_SorcOffense2(mobj_t * actor); // Spawn spinning balls above head - actor is sorcerer void A_SorcSpinBalls(mobj_t * actor) { mobj_t *mo; fixed_t z; A_SlowBalls(actor); actor->args[0] = 0; // Currently no defense actor->args[3] = SORC_NORMAL; actor->args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed actor->special1.i = ANG1; z = actor->z - actor->floorclip + actor->info->height; mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL1); if (mo) { mo->target = actor; mo->special2.i = SORCFX4_RAPIDFIRE_TIME; } mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL2); if (mo) mo->target = actor; mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL3); if (mo) mo->target = actor; } // // A_SorcBallOrbit() ========================================== // void A_SorcBallOrbit(mobj_t * actor) { int x, y; angle_t angle, baseangle; int mode = actor->target->args[3]; mobj_t *parent = (mobj_t *) actor->target; int dist = parent->radius - (actor->radius << 1); angle_t prevangle = actor->special1.i; if (actor->target->health <= 0) P_SetMobjState(actor, actor->info->painstate); baseangle = (angle_t) parent->special1.i; switch (actor->type) { case MT_SORCBALL1: angle = baseangle + BALL1_ANGLEOFFSET; break; case MT_SORCBALL2: angle = baseangle + BALL2_ANGLEOFFSET; break; case MT_SORCBALL3: angle = baseangle + BALL3_ANGLEOFFSET; break; default: I_Error("corrupted sorcerer"); return; } actor->angle = angle; angle >>= ANGLETOFINESHIFT; switch (mode) { case SORC_NORMAL: // Balls rotating normally A_SorcUpdateBallAngle(actor); break; case SORC_DECELERATE: // Balls decelerating A_DecelBalls(actor); A_SorcUpdateBallAngle(actor); break; case SORC_ACCELERATE: // Balls accelerating A_AccelBalls(actor); A_SorcUpdateBallAngle(actor); break; case SORC_STOPPING: // Balls stopping if ((parent->special2.i == actor->type) && (parent->args[1] > SORCBALL_SPEED_ROTATIONS) && (abs(angle - (parent->angle >> ANGLETOFINESHIFT)) < (30 << 5))) { // Can stop now actor->target->args[3] = SORC_FIRESPELL; actor->target->args[4] = 0; // Set angle so ball angle == sorcerer angle switch (actor->type) { case MT_SORCBALL1: parent->special1.i = (int) (parent->angle - BALL1_ANGLEOFFSET); break; case MT_SORCBALL2: parent->special1.i = (int) (parent->angle - BALL2_ANGLEOFFSET); break; case MT_SORCBALL3: parent->special1.i = (int) (parent->angle - BALL3_ANGLEOFFSET); break; default: break; } } else { A_SorcUpdateBallAngle(actor); } break; case SORC_FIRESPELL: // Casting spell if (parent->special2.i == actor->type) { // Put sorcerer into special throw spell anim if (parent->health > 0) P_SetMobjStateNF(parent, S_SORC_ATTACK1); if (actor->type == MT_SORCBALL1 && P_Random() < 200) { S_StartSound(NULL, SFX_SORCERER_SPELLCAST); actor->special2.i = SORCFX4_RAPIDFIRE_TIME; actor->args[4] = 128; parent->args[3] = SORC_FIRING_SPELL; } else { A_CastSorcererSpell(actor); parent->args[3] = SORC_STOPPED; } } break; case SORC_FIRING_SPELL: if (parent->special2.i == actor->type) { if (actor->special2.i-- <= 0) { // Done rapid firing parent->args[3] = SORC_STOPPED; // Back to orbit balls if (parent->health > 0) P_SetMobjStateNF(parent, S_SORC_ATTACK4); } else { // Do rapid fire spell A_SorcOffense2(actor); } } break; case SORC_STOPPED: // Balls stopped default: break; } if ((angle < prevangle) && (parent->args[4] == SORCBALL_TERMINAL_SPEED)) { parent->args[1]++; // Bump rotation counter // Completed full rotation - make woosh sound S_StartSound(actor, SFX_SORCERER_BALLWOOSH); } actor->special1.i = angle; // Set previous angle x = parent->x + FixedMul(dist, finecosine[angle]); y = parent->y + FixedMul(dist, finesine[angle]); actor->x = x; actor->y = y; actor->z = parent->z - parent->floorclip + parent->info->height; } // // Set balls to speed mode - actor is sorcerer // void A_SpeedBalls(mobj_t * actor) { actor->args[3] = SORC_ACCELERATE; // speed mode actor->args[2] = SORCBALL_TERMINAL_SPEED; // target speed } // // Set balls to slow mode - actor is sorcerer // void A_SlowBalls(mobj_t * actor) { actor->args[3] = SORC_DECELERATE; // slow mode actor->args[2] = SORCBALL_INITIAL_SPEED; // target speed } // // Instant stop when rotation gets to ball in special2 // actor is sorcerer // void A_StopBalls(mobj_t * actor) { int chance = P_Random(); actor->args[3] = SORC_STOPPING; // stopping mode actor->args[1] = 0; // Reset rotation counter if ((actor->args[0] <= 0) && (chance < 200)) { actor->special2.i = MT_SORCBALL2; // Blue } else if ((actor->health < (actor->info->spawnhealth >> 1)) && (chance < 200)) { actor->special2.i = MT_SORCBALL3; // Green } else { actor->special2.i = MT_SORCBALL1; // Yellow } } // // Increase ball orbit speed - actor is ball // void A_AccelBalls(mobj_t * actor) { mobj_t *sorc = actor->target; if (sorc->args[4] < sorc->args[2]) { sorc->args[4]++; } else { sorc->args[3] = SORC_NORMAL; if (sorc->args[4] >= SORCBALL_TERMINAL_SPEED) { // Reached terminal velocity - stop balls A_StopBalls(sorc); } } } // Decrease ball orbit speed - actor is ball void A_DecelBalls(mobj_t * actor) { mobj_t *sorc = actor->target; if (sorc->args[4] > sorc->args[2]) { sorc->args[4]--; } else { sorc->args[3] = SORC_NORMAL; } } // Update angle if first ball - actor is ball void A_SorcUpdateBallAngle(mobj_t * actor) { if (actor->type == MT_SORCBALL1) { actor->target->special1.i += ANG1 * actor->target->args[4]; } } // actor is ball void A_CastSorcererSpell(mobj_t * actor) { mobj_t *mo; int spell = actor->type; angle_t ang1, ang2; fixed_t z; mobj_t *parent = actor->target; S_StartSound(NULL, SFX_SORCERER_SPELLCAST); // Put sorcerer into throw spell animation if (parent->health > 0) P_SetMobjStateNF(parent, S_SORC_ATTACK4); switch (spell) { case MT_SORCBALL1: // Offensive A_SorcOffense1(actor); break; case MT_SORCBALL2: // Defensive z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT * FRACUNIT; mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCFX2); parent->flags2 |= MF2_REFLECTIVE | MF2_INVULNERABLE; parent->args[0] = SORC_DEFENSE_TIME; if (mo) mo->target = parent; break; case MT_SORCBALL3: // Reinforcements ang1 = actor->angle - ANG45; ang2 = actor->angle + ANG45; if (actor->health < (actor->info->spawnhealth / 3)) { // Spawn 2 at a time mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4 * FRACUNIT); if (mo) mo->target = parent; mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang2, 4 * FRACUNIT); if (mo) mo->target = parent; } else { if (P_Random() < 128) ang1 = ang2; mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4 * FRACUNIT); if (mo) mo->target = parent; } break; default: break; } } /* void A_SpawnReinforcements(mobj_t *actor) { mobj_t *parent = actor->target; mobj_t *mo; angle_t ang; ang = ANG1 * P_Random(); mo = P_SpawnMissileAngle(actor, MT_SORCFX3, ang, 5*FRACUNIT); if (mo) mo->target = parent; } */ // actor is ball void A_SorcOffense1(mobj_t * actor) { mobj_t *mo; angle_t ang1, ang2; mobj_t *parent = (mobj_t *) actor->target; ang1 = actor->angle + ANG1 * 70; ang2 = actor->angle - ANG1 * 70; mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang1, 0); if (mo) { mo->target = parent; mo->special1.m = parent->target; mo->args[4] = BOUNCE_TIME_UNIT; mo->args[3] = 15; // Bounce time in seconds } mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang2, 0); if (mo) { mo->target = parent; mo->special1.m = parent->target; mo->args[4] = BOUNCE_TIME_UNIT; mo->args[3] = 15; // Bounce time in seconds } } // Actor is ball void A_SorcOffense2(mobj_t * actor) { angle_t ang1; mobj_t *mo; int delta, index; mobj_t *parent = actor->target; mobj_t *dest = parent->target; int dist; index = actor->args[4] << 5; actor->args[4] += 15; delta = (finesine[index]) * SORCFX4_SPREAD_ANGLE; delta = (delta >> FRACBITS) * ANG1; ang1 = actor->angle + delta; mo = P_SpawnMissileAngle(parent, MT_SORCFX4, ang1, 0); if (mo) { mo->special2.i = 35 * 5 / 2; // 5 seconds dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y); dist = dist / mo->info->speed; if (dist < 1) dist = 1; mo->momz = (dest->z - mo->z) / dist; } } // Resume ball spinning void A_SorcBossAttack(mobj_t * actor) { actor->args[3] = SORC_ACCELERATE; actor->args[2] = SORCBALL_INITIAL_SPEED; } // spell cast magic fizzle void A_SpawnFizzle(mobj_t * actor) { fixed_t x, y, z; fixed_t dist = 5 * FRACUNIT; angle_t angle = actor->angle >> ANGLETOFINESHIFT; fixed_t speed = actor->info->speed; angle_t rangle; mobj_t *mo; int ix; x = actor->x + FixedMul(dist, finecosine[angle]); y = actor->y + FixedMul(dist, finesine[angle]); z = actor->z - actor->floorclip + (actor->height >> 1); for (ix = 0; ix < 5; ix++) { mo = P_SpawnMobj(x, y, z, MT_SORCSPARK1); if (mo) { rangle = angle + ((P_Random() % 5) << 1); mo->momx = FixedMul(P_Random() % speed, finecosine[rangle]); mo->momy = FixedMul(P_Random() % speed, finesine[rangle]); mo->momz = FRACUNIT * 2; } } } //============================================================================ // Yellow spell - offense //============================================================================ void A_SorcFX1Seek(mobj_t * actor) { A_BounceCheck(actor); P_SeekerMissile(actor, ANG1 * 2, ANG1 * 6); } //============================================================================ // Blue spell - defense //============================================================================ // // FX2 Variables // special1 current angle // special2 // args[0] 0 = CW, 1 = CCW // args[1] //============================================================================ // Split ball in two void A_SorcFX2Split(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2); if (mo) { mo->target = actor->target; mo->args[0] = 0; // CW mo->special1.i = actor->angle; // Set angle P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1); } mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2); if (mo) { mo->target = actor->target; mo->args[0] = 1; // CCW mo->special1.i = actor->angle; // Set angle P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1); } P_SetMobjStateNF(actor, S_NULL); } // Orbit FX2 about sorcerer void A_SorcFX2Orbit(mobj_t * actor) { angle_t angle; fixed_t x, y, z; mobj_t *parent = actor->target; fixed_t dist = parent->info->radius; if ((parent->health <= 0) || // Sorcerer is dead (!parent->args[0])) // Time expired { P_SetMobjStateNF(actor, actor->info->deathstate); parent->args[0] = 0; parent->flags2 &= ~MF2_REFLECTIVE; parent->flags2 &= ~MF2_INVULNERABLE; } if (actor->args[0] && (parent->args[0]-- <= 0)) // Time expired { P_SetMobjStateNF(actor, actor->info->deathstate); parent->args[0] = 0; parent->flags2 &= ~MF2_REFLECTIVE; } // Move to new position based on angle if (actor->args[0]) // Counter clock-wise { actor->special1.i += ANG1 * 10; angle = ((angle_t) actor->special1.i) >> ANGLETOFINESHIFT; x = parent->x + FixedMul(dist, finecosine[angle]); y = parent->y + FixedMul(dist, finesine[angle]); z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT * FRACUNIT; z += FixedMul(15 * FRACUNIT, finecosine[angle]); // Spawn trailer P_SpawnMobj(x, y, z, MT_SORCFX2_T1); } else // Clock wise { actor->special1.i -= ANG1 * 10; angle = ((angle_t) actor->special1.i) >> ANGLETOFINESHIFT; x = parent->x + FixedMul(dist, finecosine[angle]); y = parent->y + FixedMul(dist, finesine[angle]); z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT * FRACUNIT; z += FixedMul(20 * FRACUNIT, finesine[angle]); // Spawn trailer P_SpawnMobj(x, y, z, MT_SORCFX2_T1); } actor->x = x; actor->y = y; actor->z = z; } //============================================================================ // Green spell - spawn bishops //============================================================================ void A_SpawnBishop(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOP); if (mo) { if (!P_TestMobjLocation(mo)) { P_SetMobjState(mo, S_NULL); } } P_SetMobjState(actor, S_NULL); } /* void A_SmokePuffEntry(mobj_t *actor) { P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE); } */ void A_SmokePuffExit(mobj_t * actor) { P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKEEXIT); } void A_SorcererBishopEntry(mobj_t * actor) { P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX3_EXPLOSION); S_StartSound(actor, actor->info->seesound); } //============================================================================ // FX4 - rapid fire balls //============================================================================ void A_SorcFX4Check(mobj_t * actor) { if (actor->special2.i-- <= 0) { P_SetMobjStateNF(actor, actor->info->deathstate); } } //============================================================================ // Ball death - spawn stuff //============================================================================ void A_SorcBallPop(mobj_t * actor) { S_StartSound(NULL, SFX_SORCERER_BALLPOP); actor->flags &= ~MF_NOGRAVITY; actor->flags2 |= MF2_LOGRAV; actor->momx = ((P_Random() % 10) - 5) << FRACBITS; actor->momy = ((P_Random() % 10) - 5) << FRACBITS; actor->momz = (2 + (P_Random() % 3)) << FRACBITS; actor->special2.i = 4 * FRACUNIT; // Initial bounce factor actor->args[4] = BOUNCE_TIME_UNIT; // Bounce time unit actor->args[3] = 5; // Bounce time in seconds } void A_BounceCheck(mobj_t * actor) { if (actor->args[4]-- <= 0) { if (actor->args[3]-- <= 0) { P_SetMobjState(actor, actor->info->deathstate); switch (actor->type) { case MT_SORCBALL1: case MT_SORCBALL2: case MT_SORCBALL3: S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE); break; case MT_SORCFX1: S_StartSound(NULL, SFX_SORCERER_HEADSCREAM); break; default: break; } } else { actor->args[4] = BOUNCE_TIME_UNIT; } } } //============================================================================ // Class Bosses //============================================================================ #define CLASS_BOSS_STRAFE_RANGE 64*10*FRACUNIT void A_FastChase(mobj_t * actor) { int delta; fixed_t dist; angle_t ang; mobj_t *target; if (actor->reactiontime) { actor->reactiontime--; } // Modify target threshold if (actor->threshold) { actor->threshold--; } if (gameskill == sk_nightmare) { // Monsters move faster in nightmare mode actor->tics -= actor->tics / 2; if (actor->tics < 3) { actor->tics = 3; } } // // turn towards movement direction if not there yet // if (actor->movedir < 8) { actor->angle &= (7 << 29); delta = actor->angle - (actor->movedir << 29); if (delta > 0) { actor->angle -= ANG90 / 2; } else if (delta < 0) { actor->angle += ANG90 / 2; } } if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { // look for a new target if (P_LookForPlayers(actor, true)) { // got a new target return; } P_SetMobjState(actor, actor->info->spawnstate); return; } // // don't attack twice in a row // if (actor->flags & MF_JUSTATTACKED) { actor->flags &= ~MF_JUSTATTACKED; if (gameskill != sk_nightmare) P_NewChaseDir(actor); return; } // Strafe if (actor->special2.i > 0) { actor->special2.i--; } else { target = actor->target; actor->special2.i = 0; actor->momx = actor->momy = 0; dist = P_AproxDistance(actor->x - target->x, actor->y - target->y); if (dist < CLASS_BOSS_STRAFE_RANGE) { if (P_Random() < 100) { ang = R_PointToAngle2(actor->x, actor->y, target->x, target->y); if (P_Random() < 128) ang += ANG90; else ang -= ANG90; ang >>= ANGLETOFINESHIFT; actor->momx = FixedMul(13 * FRACUNIT, finecosine[ang]); actor->momy = FixedMul(13 * FRACUNIT, finesine[ang]); actor->special2.i = 3; // strafe time } } } // // check for missile attack // if (actor->info->missilestate) { if (gameskill < sk_nightmare && actor->movecount) goto nomissile; if (!P_CheckMissileRange(actor)) goto nomissile; P_SetMobjState(actor, actor->info->missilestate); actor->flags |= MF_JUSTATTACKED; return; } nomissile: // // possibly choose another target // if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target)) { if (P_LookForPlayers(actor, true)) return; // got a new target } // // chase towards player // if (!actor->special2.i) { if (--actor->movecount < 0 || !P_Move(actor)) { P_NewChaseDir(actor); } } } void A_FighterAttack(mobj_t * actor) { extern void A_FSwordAttack2(mobj_t * actor); if (!actor->target) return; A_FSwordAttack2(actor); } void A_ClericAttack(mobj_t * actor) { extern void A_CHolyAttack3(mobj_t * actor); if (!actor->target) return; A_CHolyAttack3(actor); } void A_MageAttack(mobj_t * actor) { extern void A_MStaffAttack2(mobj_t * actor); if (!actor->target) return; A_MStaffAttack2(actor); } void A_ClassBossHealth(mobj_t * actor) { if (netgame && !deathmatch) // co-op only { if (!actor->special1.i) { actor->health *= 5; actor->special1.i = true; // has been initialized } } } //=========================================================================== // // A_CheckFloor - Checks if an object hit the floor // //=========================================================================== void A_CheckFloor(mobj_t * actor) { if (actor->z <= actor->floorz) { actor->z = actor->floorz; actor->flags2 &= ~MF2_LOGRAV; P_SetMobjState(actor, actor->info->deathstate); } } //============================================================================ // // A_FreezeDeath // //============================================================================ void A_FreezeDeath(mobj_t * actor) { actor->tics = 75 + P_Random() + P_Random(); actor->flags |= MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD; actor->flags2 |= MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ | MF2_SLIDE; actor->height <<= 2; S_StartSound(actor, SFX_FREEZE_DEATH); if (actor->player) { actor->player->damagecount = 0; actor->player->poisoncount = 0; actor->player->bonuscount = 0; if (actor->player == &players[consoleplayer]) { SB_PaletteFlash(false); } } else if (actor->flags & MF_COUNTKILL && actor->special) { // Initiate monster death actions. P_ExecuteLineSpecial(actor->special, actor->args, NULL, 0, actor); } } //============================================================================ // // A_IceSetTics // //============================================================================ void A_IceSetTics(mobj_t * actor) { int floor; actor->tics = 70 + (P_Random() & 63); floor = P_GetThingFloorType(actor); if (floor == FLOOR_LAVA) { actor->tics >>= 2; } else if (floor == FLOOR_ICE) { actor->tics <<= 1; } } //============================================================================ // // A_IceCheckHeadDone // //============================================================================ void A_IceCheckHeadDone(mobj_t * actor) { if (actor->special2.i == 666) { P_SetMobjState(actor, S_ICECHUNK_HEAD2); } } //============================================================================ // // A_FreezeDeathChunks // //============================================================================ void A_FreezeDeathChunks(mobj_t * actor) { int i; mobj_t *mo; if (actor->momx || actor->momy || actor->momz) { actor->tics = 105; return; } S_StartSound(actor, SFX_FREEZE_SHATTER); for (i = 12 + (P_Random() & 15); i >= 0; i--) { mo = P_SpawnMobj(actor->x + (((P_Random() - 128) * actor->radius) >> 7), actor->y + (((P_Random() - 128) * actor->radius) >> 7), actor->z + (P_Random() * actor->height / 255), MT_ICECHUNK); P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3)); if (mo) { mo->momz = FixedDiv(mo->z - actor->z, actor->height) << 2; mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7); mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7); A_IceSetTics(mo); // set a random tic wait } } for (i = 12 + (P_Random() & 15); i >= 0; i--) { mo = P_SpawnMobj(actor->x + (((P_Random() - 128) * actor->radius) >> 7), actor->y + (((P_Random() - 128) * actor->radius) >> 7), actor->z + (P_Random() * actor->height / 255), MT_ICECHUNK); P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3)); if (mo) { mo->momz = FixedDiv(mo->z - actor->z, actor->height) << 2; mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7); mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7); A_IceSetTics(mo); // set a random tic wait } } if (actor->player) { // attach the player's view to a chunk of ice mo = P_SpawnMobj(actor->x, actor->y, actor->z + VIEWHEIGHT, MT_ICECHUNK); P_SetMobjState(mo, S_ICECHUNK_HEAD); mo->momz = FixedDiv(mo->z - actor->z, actor->height) << 2; mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7); mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7); mo->flags2 |= MF2_ICEDAMAGE; // used to force blue palette mo->flags2 &= ~MF2_FLOORCLIP; mo->player = actor->player; actor->player = NULL; mo->health = actor->health; mo->angle = actor->angle; mo->player->mo = mo; mo->player->lookdir = 0; } P_RemoveMobjFromTIDList(actor); P_SetMobjState(actor, S_FREETARGMOBJ); actor->flags2 |= MF2_DONTDRAW; } //=========================================================================== // Korax Variables // special1 last teleport destination // special2 set if "below half" script not yet run // // Korax Scripts (reserved) // 249 Tell scripts that we are below half health // 250-254 Control scripts // 255 Death script // // Korax TIDs (reserved) // 245 Reserved for Korax himself // 248 Initial teleport destination // 249 Teleport destination // 250-254 For use in respective control scripts // 255 For use in death script (spawn spots) //=========================================================================== #define KORAX_SPIRIT_LIFETIME (5*(35/5)) // 5 seconds #define KORAX_COMMAND_HEIGHT (120*FRACUNIT) #define KORAX_COMMAND_OFFSET (27*FRACUNIT) void KoraxFire1(mobj_t * actor, int type); void KoraxFire2(mobj_t * actor, int type); void KoraxFire3(mobj_t * actor, int type); void KoraxFire4(mobj_t * actor, int type); void KoraxFire5(mobj_t * actor, int type); void KoraxFire6(mobj_t * actor, int type); void KSpiritInit(mobj_t * spirit, mobj_t * korax); #define KORAX_TID (245) #define KORAX_FIRST_TELEPORT_TID (248) #define KORAX_TELEPORT_TID (249) void A_KoraxChase(mobj_t * actor) { mobj_t *spot; int lastfound; byte args[3] = {0, 0, 0}; if ((!actor->special2.i) && (actor->health <= (actor->info->spawnhealth / 2))) { lastfound = 0; spot = P_FindMobjFromTID(KORAX_FIRST_TELEPORT_TID, &lastfound); if (spot) { P_Teleport(actor, spot->x, spot->y, spot->angle, true); } P_StartACS(249, 0, args, actor, NULL, 0); actor->special2.i = 1; // Don't run again return; } if (!actor->target) return; if (P_Random() < 30) { P_SetMobjState(actor, actor->info->missilestate); } else if (P_Random() < 30) { S_StartSound(NULL, SFX_KORAX_ACTIVE); } // Teleport away if (actor->health < (actor->info->spawnhealth >> 1)) { if (P_Random() < 10) { lastfound = actor->special1.i; spot = P_FindMobjFromTID(KORAX_TELEPORT_TID, &lastfound); actor->special1.i = lastfound; if (spot) { P_Teleport(actor, spot->x, spot->y, spot->angle, true); } } } } void A_KoraxStep(mobj_t * actor) { A_Chase(actor); } void A_KoraxStep2(mobj_t * actor) { S_StartSound(NULL, SFX_KORAX_STEP); A_Chase(actor); } void A_KoraxBonePop(mobj_t * actor) { mobj_t *mo; byte args[5]; args[0] = args[1] = args[2] = args[3] = args[4] = 0; // Spawn 6 spirits equalangularly mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT1, ANG60 * 0, 5 * FRACUNIT); if (mo) KSpiritInit(mo, actor); mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT2, ANG60 * 1, 5 * FRACUNIT); if (mo) KSpiritInit(mo, actor); mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT3, ANG60 * 2, 5 * FRACUNIT); if (mo) KSpiritInit(mo, actor); mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT4, ANG60 * 3, 5 * FRACUNIT); if (mo) KSpiritInit(mo, actor); mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT5, ANG60 * 4, 5 * FRACUNIT); if (mo) KSpiritInit(mo, actor); mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT6, ANG60 * 5, 5 * FRACUNIT); if (mo) KSpiritInit(mo, actor); P_StartACS(255, 0, args, actor, NULL, 0); // Death script } void KSpiritInit(mobj_t * spirit, mobj_t * korax) { int i; mobj_t *tail, *next; spirit->health = KORAX_SPIRIT_LIFETIME; spirit->special1.m = korax; // Swarm around korax spirit->special2.i = 32 + (P_Random() & 7); // Float bob index spirit->args[0] = 10; // initial turn value spirit->args[1] = 0; // initial look angle // Spawn a tail for spirit tail = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL); tail->special2.m = spirit; // parent for (i = 1; i < 3; i++) { next = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL); P_SetMobjState(next, next->info->spawnstate + 1); tail->special1.m = next; tail = next; } tail->special1.m = NULL; // last tail bit } void A_KoraxDecide(mobj_t * actor) { if (P_Random() < 220) { P_SetMobjState(actor, S_KORAX_MISSILE1); } else { P_SetMobjState(actor, S_KORAX_COMMAND1); } } void A_KoraxMissile(mobj_t * actor) { int type = P_Random() % 6; int sound = 0; S_StartSound(actor, SFX_KORAX_ATTACK); switch (type) { case 0: type = MT_WRAITHFX1; sound = SFX_WRAITH_MISSILE_FIRE; break; case 1: type = MT_DEMONFX1; sound = SFX_DEMON_MISSILE_FIRE; break; case 2: type = MT_DEMON2FX1; sound = SFX_DEMON_MISSILE_FIRE; break; case 3: type = MT_FIREDEMON_FX6; sound = SFX_FIRED_ATTACK; break; case 4: type = MT_CENTAUR_FX; sound = SFX_CENTAURLEADER_ATTACK; break; case 5: type = MT_SERPENTFX; sound = SFX_CENTAURLEADER_ATTACK; break; } // Fire all 6 missiles at once S_StartSound(NULL, sound); KoraxFire1(actor, type); KoraxFire2(actor, type); KoraxFire3(actor, type); KoraxFire4(actor, type); KoraxFire5(actor, type); KoraxFire6(actor, type); } // Call action code scripts (250-254) void A_KoraxCommand(mobj_t * actor) { byte args[5]; fixed_t x, y, z; angle_t ang; int numcommands; S_StartSound(actor, SFX_KORAX_COMMAND); // Shoot stream of lightning to ceiling ang = (actor->angle - ANG90) >> ANGLETOFINESHIFT; x = actor->x + FixedMul(KORAX_COMMAND_OFFSET, finecosine[ang]); y = actor->y + FixedMul(KORAX_COMMAND_OFFSET, finesine[ang]); z = actor->z + KORAX_COMMAND_HEIGHT; P_SpawnMobj(x, y, z, MT_KORAX_BOLT); args[0] = args[1] = args[2] = args[3] = args[4] = 0; if (actor->health <= (actor->info->spawnhealth >> 1)) { numcommands = 5; } else { numcommands = 4; } switch (P_Random() % numcommands) { case 0: P_StartACS(250, 0, args, actor, NULL, 0); break; case 1: P_StartACS(251, 0, args, actor, NULL, 0); break; case 2: P_StartACS(252, 0, args, actor, NULL, 0); break; case 3: P_StartACS(253, 0, args, actor, NULL, 0); break; case 4: P_StartACS(254, 0, args, actor, NULL, 0); break; } } #define KORAX_DELTAANGLE (85*ANG1) #define KORAX_ARM_EXTENSION_SHORT (40*FRACUNIT) #define KORAX_ARM_EXTENSION_LONG (55*FRACUNIT) #define KORAX_ARM1_HEIGHT (108*FRACUNIT) #define KORAX_ARM2_HEIGHT (82*FRACUNIT) #define KORAX_ARM3_HEIGHT (54*FRACUNIT) #define KORAX_ARM4_HEIGHT (104*FRACUNIT) #define KORAX_ARM5_HEIGHT (86*FRACUNIT) #define KORAX_ARM6_HEIGHT (53*FRACUNIT) // Arm projectiles // arm positions numbered: // 1 top left // 2 middle left // 3 lower left // 4 top right // 5 middle right // 6 lower right // Arm 1 projectile void KoraxFire1(mobj_t * actor, int type) { angle_t ang; fixed_t x, y, z; ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT; x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]); y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]); z = actor->z - actor->floorclip + KORAX_ARM1_HEIGHT; P_SpawnKoraxMissile(x, y, z, actor, actor->target, type); } // Arm 2 projectile void KoraxFire2(mobj_t * actor, int type) { angle_t ang; fixed_t x, y, z; ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT; x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]); y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]); z = actor->z - actor->floorclip + KORAX_ARM2_HEIGHT; P_SpawnKoraxMissile(x, y, z, actor, actor->target, type); } // Arm 3 projectile void KoraxFire3(mobj_t * actor, int type) { angle_t ang; fixed_t x, y, z; ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT; x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]); y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]); z = actor->z - actor->floorclip + KORAX_ARM3_HEIGHT; P_SpawnKoraxMissile(x, y, z, actor, actor->target, type); } // Arm 4 projectile void KoraxFire4(mobj_t * actor, int type) { angle_t ang; fixed_t x, y, z; ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT; x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]); y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]); z = actor->z - actor->floorclip + KORAX_ARM4_HEIGHT; P_SpawnKoraxMissile(x, y, z, actor, actor->target, type); } // Arm 5 projectile void KoraxFire5(mobj_t * actor, int type) { angle_t ang; fixed_t x, y, z; ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT; x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]); y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]); z = actor->z - actor->floorclip + KORAX_ARM5_HEIGHT; P_SpawnKoraxMissile(x, y, z, actor, actor->target, type); } // Arm 6 projectile void KoraxFire6(mobj_t * actor, int type) { angle_t ang; fixed_t x, y, z; ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT; x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]); y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]); z = actor->z - actor->floorclip + KORAX_ARM6_HEIGHT; P_SpawnKoraxMissile(x, y, z, actor, actor->target, type); } void A_KSpiritWeave(mobj_t * actor) { fixed_t newX, newY; int weaveXY, weaveZ; int angle; weaveXY = actor->special2.i >> 16; weaveZ = actor->special2.i & 0xFFFF; angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT; newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2); newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2); weaveXY = (weaveXY + (P_Random() % 5)) & 63; newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2); newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2); P_TryMove(actor, newX, newY); actor->z -= FloatBobOffsets[weaveZ] << 1; weaveZ = (weaveZ + (P_Random() % 5)) & 63; actor->z += FloatBobOffsets[weaveZ] << 1; actor->special2.i = weaveZ + (weaveXY << 16); } void A_KSpiritSeeker(mobj_t * actor, angle_t thresh, angle_t turnMax) { int dir; int dist; angle_t delta; angle_t angle; mobj_t *target; fixed_t newZ; fixed_t deltaZ; target = actor->special1.m; if (target == NULL) { return; } dir = P_FaceMobj(actor, target, &delta); if (delta > thresh) { delta >>= 1; if (delta > turnMax) { delta = turnMax; } } if (dir) { // Turn clockwise actor->angle += delta; } else { // Turn counter clockwise actor->angle -= delta; } angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(actor->info->speed, finecosine[angle]); actor->momy = FixedMul(actor->info->speed, finesine[angle]); if (!(leveltime & 15) || actor->z > target->z + (target->info->height) || actor->z + actor->height < target->z) { newZ = target->z + ((P_Random() * target->info->height) >> 8); deltaZ = newZ - actor->z; if (abs(deltaZ) > 15 * FRACUNIT) { if (deltaZ > 0) { deltaZ = 15 * FRACUNIT; } else { deltaZ = -15 * FRACUNIT; } } dist = P_AproxDistance(target->x - actor->x, target->y - actor->y); dist = dist / actor->info->speed; if (dist < 1) { dist = 1; } actor->momz = deltaZ / dist; } return; } void A_KSpiritRoam(mobj_t * actor) { if (actor->health-- <= 0) { S_StartSound(actor, SFX_SPIRIT_DIE); P_SetMobjState(actor, S_KSPIRIT_DEATH1); } else { if (actor->special1.m) { A_KSpiritSeeker(actor, actor->args[0] * ANG1, actor->args[0] * ANG1 * 2); } A_KSpiritWeave(actor); if (P_Random() < 50) { S_StartSound(NULL, SFX_SPIRIT_ACTIVE); } } } void A_KBolt(mobj_t * actor) { // Countdown lifetime if (actor->special1.i-- <= 0) { P_SetMobjState(actor, S_NULL); } } #define KORAX_BOLT_HEIGHT 48*FRACUNIT #define KORAX_BOLT_LIFETIME 3 void A_KBoltRaise(mobj_t * actor) { mobj_t *mo; fixed_t z; // Spawn a child upward z = actor->z + KORAX_BOLT_HEIGHT; if ((z + KORAX_BOLT_HEIGHT) < actor->ceilingz) { mo = P_SpawnMobj(actor->x, actor->y, z, MT_KORAX_BOLT); if (mo) { mo->special1.i = KORAX_BOLT_LIFETIME; } } else { // Maybe cap it off here } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_floor.c000066400000000000000000000735541257432200600230250ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_system.h" #include "p_local.h" extern fixed_t FloatBobOffsets[64]; //================================================================== //================================================================== // // FLOORS // //================================================================== //================================================================== //================================================================== // // Move a plane (floor or ceiling) and check for crushing // //================================================================== result_e T_MovePlane(sector_t * sector, fixed_t speed, fixed_t dest, int crush, int floorOrCeiling, int direction) { boolean flag; fixed_t lastpos; switch (floorOrCeiling) { case 0: // FLOOR switch (direction) { case -1: // DOWN if (sector->floorheight - speed < dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else { lastpos = sector->floorheight; sector->floorheight -= speed; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } } break; case 1: // UP if (sector->floorheight + speed > dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else // COULD GET CRUSHED { lastpos = sector->floorheight; sector->floorheight += speed; flag = P_ChangeSector(sector, crush); if (flag == true) { //if (crush == true) //{ // return RES_CRUSHED; //} sector->floorheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } } break; } break; case 1: // CEILING switch (direction) { case -1: // DOWN if (sector->ceilingheight - speed < dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else // COULD GET CRUSHED { lastpos = sector->ceilingheight; sector->ceilingheight -= speed; flag = P_ChangeSector(sector, crush); if (flag == true) { //if (crush == true) //{ // return RES_CRUSHED; //} sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } } break; case 1: // UP if (sector->ceilingheight + speed > dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else { lastpos = sector->ceilingheight; sector->ceilingheight += speed; flag = P_ChangeSector(sector, crush); #if 0 if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } #endif } break; } break; } return RES_OK; } //================================================================== // // MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN) // //================================================================== void T_MoveFloor(floormove_t * floor) { result_e res; if (floor->resetDelayCount) { floor->resetDelayCount--; if (!floor->resetDelayCount) { floor->floordestheight = floor->resetHeight; floor->direction = -floor->direction; floor->resetDelay = 0; floor->delayCount = 0; floor->delayTotal = 0; } } if (floor->delayCount) { floor->delayCount--; if (!floor->delayCount && floor->textureChange) { floor->sector->floorpic += floor->textureChange; } return; } res = T_MovePlane(floor->sector, floor->speed, floor->floordestheight, floor->crush, 0, floor->direction); if (floor->type == FLEV_RAISEBUILDSTEP) { if ((floor->direction == 1 && floor->sector->floorheight >= floor->stairsDelayHeight) || (floor->direction == -1 && floor->sector->floorheight <= floor->stairsDelayHeight)) { floor->delayCount = floor->delayTotal; floor->stairsDelayHeight += floor->stairsDelayHeightDelta; } } if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *) & floor->sector->soundorg); if (floor->delayTotal) { floor->delayTotal = 0; } if (floor->resetDelay) { // floor->resetDelayCount = floor->resetDelay; // floor->resetDelay = 0; return; } floor->sector->specialdata = NULL; /* if (floor->direction == 1) switch(floor->type) { case donutRaise: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } else if (floor->direction == -1) switch(floor->type) { case lowerAndChange: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } */ if (floor->textureChange) { floor->sector->floorpic -= floor->textureChange; } P_TagFinished(floor->sector->tag); P_RemoveThinker(&floor->thinker); } } //================================================================== // // HANDLE FLOOR TYPES // //================================================================== int EV_DoFloor(line_t * line, byte * args, floor_e floortype) { int secnum; int rtn; sector_t *sec; floormove_t *floor = NULL; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // // new floor thinker // rtn = 1; floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0); memset(floor, 0, sizeof(*floor)); P_AddThinker(&floor->thinker); sec->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = floortype; floor->crush = 0; floor->speed = args[1] * (FRACUNIT / 8); if (floortype == FLEV_LOWERTIMES8INSTANT || floortype == FLEV_RAISETIMES8INSTANT) { floor->speed = 2000 << FRACBITS; } switch (floortype) { case FLEV_LOWERFLOOR: floor->direction = -1; floor->sector = sec; floor->floordestheight = P_FindHighestFloorSurrounding(sec); break; case FLEV_LOWERFLOORTOLOWEST: floor->direction = -1; floor->sector = sec; floor->floordestheight = P_FindLowestFloorSurrounding(sec); break; case FLEV_LOWERFLOORBYVALUE: floor->direction = -1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight - args[2] * FRACUNIT; break; case FLEV_LOWERTIMES8INSTANT: case FLEV_LOWERBYVALUETIMES8: floor->direction = -1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight - args[2] * FRACUNIT * 8; break; case FLEV_RAISEFLOORCRUSH: floor->crush = args[2]; // arg[2] = crushing value floor->direction = 1; floor->sector = sec; floor->floordestheight = sec->ceilingheight - 8 * FRACUNIT; break; case FLEV_RAISEFLOOR: floor->direction = 1; floor->sector = sec; floor->floordestheight = P_FindLowestCeilingSurrounding(sec); if (floor->floordestheight > sec->ceilingheight) floor->floordestheight = sec->ceilingheight; break; case FLEV_RAISEFLOORTONEAREST: floor->direction = 1; floor->sector = sec; floor->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight); break; case FLEV_RAISEFLOORBYVALUE: floor->direction = 1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight + args[2] * FRACUNIT; break; case FLEV_RAISETIMES8INSTANT: case FLEV_RAISEBYVALUETIMES8: floor->direction = 1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight + args[2] * FRACUNIT * 8; break; case FLEV_MOVETOVALUETIMES8: floor->sector = sec; floor->floordestheight = args[2] * FRACUNIT * 8; if (args[3]) { floor->floordestheight = -floor->floordestheight; } if (floor->floordestheight > floor->sector->floorheight) { floor->direction = 1; } else if (floor->floordestheight < floor->sector->floorheight) { floor->direction = -1; } else { // already at lowest position rtn = 0; } break; default: rtn = 0; break; } } if (rtn) { SN_StartSequence((mobj_t *) & floor->sector->soundorg, SEQ_PLATFORM + floor->sector->seqType); } return rtn; } //============================================================================ // // EV_DoFloorAndCeiling // //============================================================================ int EV_DoFloorAndCeiling(line_t * line, byte * args, boolean raise) { boolean floor, ceiling; int secnum; sector_t *sec; if (raise) { floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE); secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; sec->specialdata = NULL; } ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE); } else { floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE); secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; sec->specialdata = NULL; } ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE); } return (floor | ceiling); } // ===== Build Stairs Private Data ===== #define STAIR_SECTOR_TYPE 26 #define STAIR_QUEUE_SIZE 32 struct { sector_t *sector; int type; int height; } StairQueue[STAIR_QUEUE_SIZE]; static int QueueHead; static int QueueTail; static int StepDelta; static int Direction; static int Speed; static int Texture; static int StartDelay; static int StartDelayDelta; static int TextureChange; static int StartHeight; //========================================================================== // // QueueStairSector // //========================================================================== static void QueueStairSector(sector_t * sec, int type, int height) { if ((QueueTail + 1) % STAIR_QUEUE_SIZE == QueueHead) { I_Error("BuildStairs: Too many branches located.\n"); } StairQueue[QueueTail].sector = sec; StairQueue[QueueTail].type = type; StairQueue[QueueTail].height = height; QueueTail = (QueueTail + 1) % STAIR_QUEUE_SIZE; } //========================================================================== // // DequeueStairSector // //========================================================================== static sector_t *DequeueStairSector(int *type, int *height) { sector_t *sec; if (QueueHead == QueueTail) { // queue is empty return NULL; } *type = StairQueue[QueueHead].type; *height = StairQueue[QueueHead].height; sec = StairQueue[QueueHead].sector; QueueHead = (QueueHead + 1) % STAIR_QUEUE_SIZE; return sec; } //========================================================================== // // ProcessStairSector // //========================================================================== static void ProcessStairSector(sector_t * sec, int type, int height, stairs_e stairsType, int delay, int resetDelay) { int i; sector_t *tsec; floormove_t *floor; // // new floor thinker // height += StepDelta; floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0); memset(floor, 0, sizeof(*floor)); P_AddThinker(&floor->thinker); sec->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = FLEV_RAISEBUILDSTEP; floor->direction = Direction; floor->sector = sec; floor->floordestheight = height; switch (stairsType) { case STAIRS_NORMAL: floor->speed = Speed; if (delay) { floor->delayTotal = delay; floor->stairsDelayHeight = sec->floorheight + StepDelta; floor->stairsDelayHeightDelta = StepDelta; } floor->resetDelay = resetDelay; floor->resetDelayCount = resetDelay; floor->resetHeight = sec->floorheight; break; case STAIRS_SYNC: floor->speed = FixedMul(Speed, FixedDiv(height - StartHeight, StepDelta)); floor->resetDelay = delay; //arg4 floor->resetDelayCount = delay; floor->resetHeight = sec->floorheight; break; /* case STAIRS_PHASED: floor->floordestheight = sec->floorheight+StepDelta; floor->speed = Speed; floor->delayCount = StartDelay; StartDelay += StartDelayDelta; floor->textureChange = TextureChange; floor->resetDelayCount = StartDelay; break; */ default: break; } SN_StartSequence((mobj_t *) & sec->soundorg, SEQ_PLATFORM + sec->seqType); // // Find next sector to raise // Find nearby sector with sector special equal to type // for (i = 0; i < sec->linecount; i++) { if (!((sec->lines[i])->flags & ML_TWOSIDED)) { continue; } tsec = (sec->lines[i])->frontsector; if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata && tsec->floorpic == Texture && tsec->validcount != validcount) { QueueStairSector(tsec, type ^ 1, height); tsec->validcount = validcount; //tsec->special = 0; } tsec = (sec->lines[i])->backsector; if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata && tsec->floorpic == Texture && tsec->validcount != validcount) { QueueStairSector(tsec, type ^ 1, height); tsec->validcount = validcount; //tsec->special = 0; } } } //================================================================== // // BUILD A STAIRCASE! // // Direction is either positive or negative, denoting build stairs // up or down. //================================================================== int EV_BuildStairs(line_t * line, byte * args, int direction, stairs_e stairsType) { int secnum; int height; int delay; int resetDelay; sector_t *sec; sector_t *qSec; int type; // Set global stairs variables TextureChange = 0; Direction = direction; StepDelta = Direction * (args[2] * FRACUNIT); Speed = args[1] * (FRACUNIT / 8); resetDelay = args[4]; delay = args[3]; if (stairsType == STAIRS_PHASED) { StartDelayDelta = args[3]; StartDelay = StartDelayDelta; resetDelay = StartDelayDelta; delay = 0; TextureChange = args[4]; } secnum = -1; validcount++; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; Texture = sec->floorpic; StartHeight = sec->floorheight; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; QueueStairSector(sec, 0, sec->floorheight); sec->special = 0; } while ((qSec = DequeueStairSector(&type, &height)) != NULL) { ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay); } return (1); } //========================================================================= // // T_BuildPillar // //========================================================================= void T_BuildPillar(pillar_t * pillar) { result_e res1; result_e res2; // First, raise the floor res1 = T_MovePlane(pillar->sector, pillar->floorSpeed, pillar->floordest, pillar->crush, 0, pillar->direction); // floorOrCeiling, direction // Then, lower the ceiling res2 = T_MovePlane(pillar->sector, pillar->ceilingSpeed, pillar->ceilingdest, pillar->crush, 1, -pillar->direction); if (res1 == RES_PASTDEST && res2 == RES_PASTDEST) { pillar->sector->specialdata = NULL; SN_StopSequence((mobj_t *) & pillar->sector->soundorg); P_TagFinished(pillar->sector->tag); P_RemoveThinker(&pillar->thinker); } } //========================================================================= // // EV_BuildPillar // //========================================================================= int EV_BuildPillar(line_t * line, byte * args, boolean crush) { int secnum; sector_t *sec; pillar_t *pillar; int newHeight; int rtn; rtn = 0; secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // already moving if (sec->floorheight == sec->ceilingheight) { // pillar is already closed continue; } rtn = 1; if (!args[2]) { newHeight = sec->floorheight + ((sec->ceilingheight - sec->floorheight) / 2); } else { newHeight = sec->floorheight + (args[2] << FRACBITS); } pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0); sec->specialdata = pillar; P_AddThinker(&pillar->thinker); pillar->thinker.function = T_BuildPillar; pillar->sector = sec; if (!args[2]) { pillar->ceilingSpeed = pillar->floorSpeed = args[1] * (FRACUNIT / 8); } else if (newHeight - sec->floorheight > sec->ceilingheight - newHeight) { pillar->floorSpeed = args[1] * (FRACUNIT / 8); pillar->ceilingSpeed = FixedMul(sec->ceilingheight - newHeight, FixedDiv(pillar->floorSpeed, newHeight - sec->floorheight)); } else { pillar->ceilingSpeed = args[1] * (FRACUNIT / 8); pillar->floorSpeed = FixedMul(newHeight - sec->floorheight, FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - newHeight)); } pillar->floordest = newHeight; pillar->ceilingdest = newHeight; pillar->direction = 1; pillar->crush = crush * args[3]; SN_StartSequence((mobj_t *) & pillar->sector->soundorg, SEQ_PLATFORM + pillar->sector->seqType); } return rtn; } //========================================================================= // // EV_OpenPillar // //========================================================================= int EV_OpenPillar(line_t * line, byte * args) { int secnum; sector_t *sec; pillar_t *pillar; int rtn; rtn = 0; secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // already moving if (sec->floorheight != sec->ceilingheight) { // pillar isn't closed continue; } rtn = 1; pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0); sec->specialdata = pillar; P_AddThinker(&pillar->thinker); pillar->thinker.function = T_BuildPillar; pillar->sector = sec; if (!args[2]) { pillar->floordest = P_FindLowestFloorSurrounding(sec); } else { pillar->floordest = sec->floorheight - (args[2] << FRACBITS); } if (!args[3]) { pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec); } else { pillar->ceilingdest = sec->ceilingheight + (args[3] << FRACBITS); } if (sec->floorheight - pillar->floordest >= pillar->ceilingdest - sec->ceilingheight) { pillar->floorSpeed = args[1] * (FRACUNIT / 8); pillar->ceilingSpeed = FixedMul(sec->ceilingheight - pillar->ceilingdest, FixedDiv(pillar->floorSpeed, pillar->floordest - sec->floorheight)); } else { pillar->ceilingSpeed = args[1] * (FRACUNIT / 8); pillar->floorSpeed = FixedMul(pillar->floordest - sec->floorheight, FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - pillar->ceilingdest)); } pillar->direction = -1; // open the pillar SN_StartSequence((mobj_t *) & pillar->sector->soundorg, SEQ_PLATFORM + pillar->sector->seqType); } return rtn; } //========================================================================= // // EV_FloorCrushStop // //========================================================================= int EV_FloorCrushStop(line_t * line, byte * args) { thinker_t *think; floormove_t *floor; boolean rtn; rtn = 0; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != T_MoveFloor) { continue; } floor = (floormove_t *) think; if (floor->type != FLEV_RAISEFLOORCRUSH) { continue; } // Completely remove the crushing floor SN_StopSequence((mobj_t *) & floor->sector->soundorg); floor->sector->specialdata = NULL; P_TagFinished(floor->sector->tag); P_RemoveThinker(&floor->thinker); rtn = 1; } return rtn; } //========================================================================== // // T_FloorWaggle // //========================================================================== #define WGLSTATE_EXPAND 1 #define WGLSTATE_STABLE 2 #define WGLSTATE_REDUCE 3 void T_FloorWaggle(floorWaggle_t * waggle) { switch (waggle->state) { case WGLSTATE_EXPAND: if ((waggle->scale += waggle->scaleDelta) >= waggle->targetScale) { waggle->scale = waggle->targetScale; waggle->state = WGLSTATE_STABLE; } break; case WGLSTATE_REDUCE: if ((waggle->scale -= waggle->scaleDelta) <= 0) { // Remove waggle->sector->floorheight = waggle->originalHeight; P_ChangeSector(waggle->sector, true); waggle->sector->specialdata = NULL; P_TagFinished(waggle->sector->tag); P_RemoveThinker(&waggle->thinker); return; } break; case WGLSTATE_STABLE: if (waggle->ticker != -1) { if (!--waggle->ticker) { waggle->state = WGLSTATE_REDUCE; } } break; } waggle->accumulator += waggle->accDelta; waggle->sector->floorheight = waggle->originalHeight + FixedMul(FloatBobOffsets[(waggle->accumulator >> FRACBITS) & 63], waggle->scale); P_ChangeSector(waggle->sector, true); } //========================================================================== // // EV_StartFloorWaggle // //========================================================================== boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset, int timer) { int sectorIndex; sector_t *sector; floorWaggle_t *waggle; boolean retCode; retCode = false; sectorIndex = -1; while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0) { sector = §ors[sectorIndex]; if (sector->specialdata) { // Already busy with another thinker continue; } retCode = true; waggle = Z_Malloc(sizeof(*waggle), PU_LEVSPEC, 0); sector->specialdata = waggle; waggle->thinker.function = T_FloorWaggle; waggle->sector = sector; waggle->originalHeight = sector->floorheight; waggle->accumulator = offset * FRACUNIT; waggle->accDelta = speed << 10; waggle->scale = 0; waggle->targetScale = height << 10; waggle->scaleDelta = waggle->targetScale / (35 + ((3 * 35) * height) / 255); waggle->ticker = timer ? timer * 35 : -1; waggle->state = WGLSTATE_EXPAND; P_AddThinker(&waggle->thinker); } return retCode; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_inter.c000066400000000000000000002010431257432200600230070ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "m_misc.h" #include "m_random.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" #define BONUSADD 6 int ArmorIncrement[NUMCLASSES][NUMARMOR] = { {25 * FRACUNIT, 20 * FRACUNIT, 15 * FRACUNIT, 5 * FRACUNIT}, {10 * FRACUNIT, 25 * FRACUNIT, 5 * FRACUNIT, 20 * FRACUNIT}, {5 * FRACUNIT, 15 * FRACUNIT, 10 * FRACUNIT, 25 * FRACUNIT}, {0, 0, 0, 0} }; int AutoArmorSave[NUMCLASSES] = { 15 * FRACUNIT, 10 * FRACUNIT, 5 * FRACUNIT, 0 }; char *TextKeyMessages[] = { TXT_KEY_STEEL, TXT_KEY_CAVE, TXT_KEY_AXE, TXT_KEY_FIRE, TXT_KEY_EMERALD, TXT_KEY_DUNGEON, TXT_KEY_SILVER, TXT_KEY_RUSTED, TXT_KEY_HORN, TXT_KEY_SWAMP, TXT_KEY_CASTLE }; static void SetDormantArtifact(mobj_t * arti); static void TryPickupArtifact(player_t * player, artitype_t artifactType, mobj_t * artifact); static void TryPickupWeapon(player_t * player, pclass_t weaponClass, weapontype_t weaponType, mobj_t * weapon, char *message); static void TryPickupWeaponPiece(player_t * player, pclass_t matchClass, int pieceValue, mobj_t * pieceMobj); //-------------------------------------------------------------------------- // // PROC P_SetMessage // //-------------------------------------------------------------------------- void P_SetMessage(player_t * player, char *message, boolean ultmsg) { if ((player->ultimateMessage || !messageson) && !ultmsg) { return; } M_StringCopy(player->message, message, sizeof(player->message)); // strupr(player->message); player->messageTics = MESSAGETICS; player->yellowMessage = false; if (ultmsg) { player->ultimateMessage = true; } if (player == &players[consoleplayer]) { BorderTopRefresh = true; } } //========================================================================== // // P_SetYellowMessage // //========================================================================== void P_SetYellowMessage(player_t * player, char *message, boolean ultmsg) { if ((player->ultimateMessage || !messageson) && !ultmsg) { return; } M_StringCopy(player->message, message, sizeof(player->message)); player->messageTics = 5 * MESSAGETICS; // Bold messages last longer player->yellowMessage = true; if (ultmsg) { player->ultimateMessage = true; } if (player == &players[consoleplayer]) { BorderTopRefresh = true; } } //========================================================================== // // P_ClearMessage // //========================================================================== void P_ClearMessage(player_t * player) { player->messageTics = 0; if (player == &players[consoleplayer]) { BorderTopRefresh = true; } } //---------------------------------------------------------------------------- // // PROC P_HideSpecialThing // //---------------------------------------------------------------------------- void P_HideSpecialThing(mobj_t * thing) { thing->flags &= ~MF_SPECIAL; thing->flags2 |= MF2_DONTDRAW; P_SetMobjState(thing, S_HIDESPECIAL1); } //-------------------------------------------------------------------------- // // FUNC P_GiveMana // // Returns true if the player accepted the mana, false if it was // refused (player has MAX_MANA). // //-------------------------------------------------------------------------- boolean P_GiveMana(player_t * player, manatype_t mana, int count) { int prevMana; //weapontype_t changeWeapon; if (mana == MANA_NONE || mana == MANA_BOTH) { return (false); } if ((unsigned int) mana > NUMMANA) { I_Error("P_GiveMana: bad type %i", mana); } if (player->mana[mana] == MAX_MANA) { return (false); } if (gameskill == sk_baby || gameskill == sk_nightmare) { // extra mana in baby mode and nightmare mode count += count >> 1; } prevMana = player->mana[mana]; player->mana[mana] += count; if (player->mana[mana] > MAX_MANA) { player->mana[mana] = MAX_MANA; } if (player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND && mana == MANA_1 && prevMana <= 0) { P_SetPsprite(player, ps_weapon, S_FAXEREADY_G); } return (true); } //========================================================================== // // TryPickupWeapon // //========================================================================== static void TryPickupWeapon(player_t * player, pclass_t weaponClass, weapontype_t weaponType, mobj_t * weapon, char *message) { boolean remove; boolean gaveMana; boolean gaveWeapon; remove = true; if (player->class != weaponClass) { // Wrong class, but try to pick up for mana if (netgame && !deathmatch) { // Can't pick up weapons for other classes in coop netplay return; } if (weaponType == WP_SECOND) { if (!P_GiveMana(player, MANA_1, 25)) { return; } } else { if (!P_GiveMana(player, MANA_2, 25)) { return; } } } else if (netgame && !deathmatch) { // Cooperative net-game if (player->weaponowned[weaponType]) { return; } player->weaponowned[weaponType] = true; if (weaponType == WP_SECOND) { P_GiveMana(player, MANA_1, 25); } else { P_GiveMana(player, MANA_2, 25); } player->pendingweapon = weaponType; remove = false; } else { // Deathmatch or single player game if (weaponType == WP_SECOND) { gaveMana = P_GiveMana(player, MANA_1, 25); } else { gaveMana = P_GiveMana(player, MANA_2, 25); } if (player->weaponowned[weaponType]) { gaveWeapon = false; } else { gaveWeapon = true; player->weaponowned[weaponType] = true; if (weaponType > player->readyweapon) { // Only switch to more powerful weapons player->pendingweapon = weaponType; } } if (!(gaveWeapon || gaveMana)) { // Player didn't need the weapon or any mana return; } } P_SetMessage(player, message, false); if (weapon->special) { P_ExecuteLineSpecial(weapon->special, weapon->args, NULL, 0, player->mo); weapon->special = 0; } if (remove) { if (deathmatch && !(weapon->flags2 & MF2_DROPPED)) { P_HideSpecialThing(weapon); } else { P_RemoveMobj(weapon); } } player->bonuscount += BONUSADD; if (player == &players[consoleplayer]) { S_StartSound(NULL, SFX_PICKUP_WEAPON); SB_PaletteFlash(false); } } //-------------------------------------------------------------------------- // // FUNC P_GiveWeapon // // Returns true if the weapon or its mana was accepted. // //-------------------------------------------------------------------------- /* boolean P_GiveWeapon(player_t *player, pclass_t class, weapontype_t weapon) { boolean gaveMana; boolean gaveWeapon; if(player->class != class) { // player cannot use this weapon, take it anyway, and get mana if(netgame && !deathmatch) { // Can't pick up weapons for other classes in coop netplay return false; } if(weapon == WP_SECOND) { return P_GiveMana(player, MANA_1, 25); } else { return P_GiveMana(player, MANA_2, 25); } } if(netgame && !deathmatch) { // Cooperative net-game if(player->weaponowned[weapon]) { return(false); } player->bonuscount += BONUSADD; player->weaponowned[weapon] = true; if(weapon == WP_SECOND) { P_GiveMana(player, MANA_1, 25); } else { P_GiveMana(player, MANA_2, 25); } player->pendingweapon = weapon; if(player == &players[consoleplayer]) { S_StartSound(NULL, SFX_PICKUP_WEAPON); } return(false); } if(weapon == WP_SECOND) { gaveMana = P_GiveMana(player, MANA_1, 25); } else { gaveMana = P_GiveMana(player, MANA_2, 25); } if(player->weaponowned[weapon]) { gaveWeapon = false; } else { gaveWeapon = true; player->weaponowned[weapon] = true; if(weapon > player->readyweapon) { // Only switch to more powerful weapons player->pendingweapon = weapon; } } return(gaveWeapon || gaveMana); } */ //=========================================================================== // // P_GiveWeaponPiece // //=========================================================================== /* boolean P_GiveWeaponPiece(player_t *player, pclass_t class, int piece) { P_GiveMana(player, MANA_1, 20); P_GiveMana(player, MANA_2, 20); if(player->class != class) { return true; } else if(player->pieces&piece) { // player already has that weapon piece return true; } player->pieces |= piece; if(player->pieces == 7) { // player has built the fourth weapon! P_GiveWeapon(player, class, WP_FOURTH); S_StartSound(player->mo, SFX_WEAPON_BUILD); } return true; } */ //========================================================================== // // TryPickupWeaponPiece // //========================================================================== static void TryPickupWeaponPiece(player_t * player, pclass_t matchClass, int pieceValue, mobj_t * pieceMobj) { boolean remove; boolean checkAssembled; boolean gaveWeapon; int gaveMana; static char *fourthWeaponText[] = { TXT_WEAPON_F4, TXT_WEAPON_C4, TXT_WEAPON_M4 }; static char *weaponPieceText[] = { TXT_QUIETUS_PIECE, TXT_WRAITHVERGE_PIECE, TXT_BLOODSCOURGE_PIECE }; static int pieceValueTrans[] = { 0, // 0: never WPIECE1 | WPIECE2 | WPIECE3, // WPIECE1 (1) WPIECE2 | WPIECE3, // WPIECE2 (2) 0, // 3: never WPIECE3 // WPIECE3 (4) }; remove = true; checkAssembled = true; gaveWeapon = false; if (player->class != matchClass) { // Wrong class, but try to pick up for mana if (netgame && !deathmatch) { // Can't pick up wrong-class weapons in coop netplay return; } checkAssembled = false; gaveMana = P_GiveMana(player, MANA_1, 20) + P_GiveMana(player, MANA_2, 20); if (!gaveMana) { // Didn't need the mana, so don't pick it up return; } } else if (netgame && !deathmatch) { // Cooperative net-game if (player->pieces & pieceValue) { // Already has the piece return; } pieceValue = pieceValueTrans[pieceValue]; P_GiveMana(player, MANA_1, 20); P_GiveMana(player, MANA_2, 20); remove = false; } else { // Deathmatch or single player game gaveMana = P_GiveMana(player, MANA_1, 20) + P_GiveMana(player, MANA_2, 20); if (player->pieces & pieceValue) { // Already has the piece, check if mana needed if (!gaveMana) { // Didn't need the mana, so don't pick it up return; } checkAssembled = false; } } // Pick up the weapon piece if (pieceMobj->special) { P_ExecuteLineSpecial(pieceMobj->special, pieceMobj->args, NULL, 0, player->mo); pieceMobj->special = 0; } if (remove) { if (deathmatch && !(pieceMobj->flags2 & MF2_DROPPED)) { P_HideSpecialThing(pieceMobj); } else { P_RemoveMobj(pieceMobj); } } player->bonuscount += BONUSADD; if (player == &players[consoleplayer]) { SB_PaletteFlash(false); } // Check if fourth weapon assembled if (checkAssembled) { player->pieces |= pieceValue; if (player->pieces == (WPIECE1 | WPIECE2 | WPIECE3)) { gaveWeapon = true; player->weaponowned[WP_FOURTH] = true; player->pendingweapon = WP_FOURTH; } } if (gaveWeapon) { P_SetMessage(player, fourthWeaponText[matchClass], false); // Play the build-sound full volume for all players S_StartSound(NULL, SFX_WEAPON_BUILD); } else { P_SetMessage(player, weaponPieceText[matchClass], false); if (player == &players[consoleplayer]) { S_StartSound(NULL, SFX_PICKUP_WEAPON); } } } //--------------------------------------------------------------------------- // // FUNC P_GiveBody // // Returns false if the body isn't needed at all. // //--------------------------------------------------------------------------- boolean P_GiveBody(player_t * player, int num) { int max; max = MAXHEALTH; if (player->morphTics) { max = MAXMORPHHEALTH; } if (player->health >= max) { return (false); } player->health += num; if (player->health > max) { player->health = max; } player->mo->health = player->health; return (true); } //--------------------------------------------------------------------------- // // FUNC P_GiveArmor // // Returns false if the armor is worse than the current armor. // //--------------------------------------------------------------------------- boolean P_GiveArmor(player_t * player, armortype_t armortype, int amount) { int hits; int totalArmor; extern int ArmorMax[NUMCLASSES]; if (amount == -1) { hits = ArmorIncrement[player->class][armortype]; if (player->armorpoints[armortype] >= hits) { return false; } else { player->armorpoints[armortype] = hits; } } else { hits = amount * 5 * FRACUNIT; totalArmor = player->armorpoints[ARMOR_ARMOR] + player->armorpoints[ARMOR_SHIELD] + player->armorpoints[ARMOR_HELMET] + player->armorpoints[ARMOR_AMULET] + AutoArmorSave[player->class]; if (totalArmor < ArmorMax[player->class] * 5 * FRACUNIT) { player->armorpoints[armortype] += hits; } else { return false; } } return true; } //--------------------------------------------------------------------------- // // PROC P_GiveKey // //--------------------------------------------------------------------------- int P_GiveKey(player_t * player, keytype_t key) { if (player->keys & (1 << key)) { return false; } player->bonuscount += BONUSADD; player->keys |= 1 << key; return true; } //--------------------------------------------------------------------------- // // FUNC P_GivePower // // Returns true if power accepted. // //--------------------------------------------------------------------------- boolean P_GivePower(player_t * player, powertype_t power) { if (power == pw_invulnerability) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = INVULNTICS; player->mo->flags2 |= MF2_INVULNERABLE; if (player->class == PCLASS_MAGE) { player->mo->flags2 |= MF2_REFLECTIVE; } return (true); } if (power == pw_flight) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = FLIGHTTICS; player->mo->flags2 |= MF2_FLY; player->mo->flags |= MF_NOGRAVITY; if (player->mo->z <= player->mo->floorz) { player->flyheight = 10; // thrust the player in the air a bit } return (true); } if (power == pw_infrared) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = INFRATICS; return (true); } if (power == pw_speed) { if (player->powers[power] > BLINKTHRESHOLD) { // Already have it return (false); } player->powers[power] = SPEEDTICS; return (true); } if (power == pw_minotaur) { // Doesn't matter if already have power, renew ticker player->powers[power] = MAULATORTICS; return (true); } /* if(power == pw_ironfeet) { player->powers[power] = IRONTICS; return(true); } if(power == pw_strength) { P_GiveBody(player, 100); player->powers[power] = 1; return(true); } */ if (player->powers[power]) { return (false); // already got it } player->powers[power] = 1; return (true); } //========================================================================== // // TryPickupArtifact // //========================================================================== static void TryPickupArtifact(player_t * player, artitype_t artifactType, mobj_t * artifact) { static char *artifactMessages[NUMARTIFACTS] = { NULL, TXT_ARTIINVULNERABILITY, TXT_ARTIHEALTH, TXT_ARTISUPERHEALTH, TXT_ARTIHEALINGRADIUS, TXT_ARTISUMMON, TXT_ARTITORCH, TXT_ARTIEGG, TXT_ARTIFLY, TXT_ARTIBLASTRADIUS, TXT_ARTIPOISONBAG, TXT_ARTITELEPORTOTHER, TXT_ARTISPEED, TXT_ARTIBOOSTMANA, TXT_ARTIBOOSTARMOR, TXT_ARTITELEPORT, TXT_ARTIPUZZSKULL, TXT_ARTIPUZZGEMBIG, TXT_ARTIPUZZGEMRED, TXT_ARTIPUZZGEMGREEN1, TXT_ARTIPUZZGEMGREEN2, TXT_ARTIPUZZGEMBLUE1, TXT_ARTIPUZZGEMBLUE2, TXT_ARTIPUZZBOOK1, TXT_ARTIPUZZBOOK2, TXT_ARTIPUZZSKULL2, TXT_ARTIPUZZFWEAPON, TXT_ARTIPUZZCWEAPON, TXT_ARTIPUZZMWEAPON, TXT_ARTIPUZZGEAR, // All gear pickups use the same text TXT_ARTIPUZZGEAR, TXT_ARTIPUZZGEAR, TXT_ARTIPUZZGEAR }; if (gamemode == shareware) { artifactMessages[arti_blastradius] = TXT_ARTITELEPORT; artifactMessages[arti_teleport] = TXT_ARTIBLASTRADIUS; } if (P_GiveArtifact(player, artifactType, artifact)) { if (artifact->special) { P_ExecuteLineSpecial(artifact->special, artifact->args, NULL, 0, NULL); artifact->special = 0; } player->bonuscount += BONUSADD; if (artifactType < arti_firstpuzzitem) { SetDormantArtifact(artifact); S_StartSound(artifact, SFX_PICKUP_ARTIFACT); P_SetMessage(player, artifactMessages[artifactType], false); } else { // Puzzle item S_StartSound(NULL, SFX_PICKUP_ITEM); P_SetMessage(player, artifactMessages[artifactType], true); if (!netgame || deathmatch) { // Remove puzzle items if not cooperative netplay P_RemoveMobj(artifact); } } } } //--------------------------------------------------------------------------- // // FUNC P_GiveArtifact // // Returns true if artifact accepted. // //--------------------------------------------------------------------------- boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo) { int i; int j; boolean slidePointer; slidePointer = false; i = 0; while (player->inventory[i].type != arti && i < player->inventorySlotNum) { i++; } if (i == player->inventorySlotNum) { if (arti < arti_firstpuzzitem) { i = 0; while (player->inventory[i].type < arti_firstpuzzitem && i < player->inventorySlotNum) { i++; } if (i != player->inventorySlotNum) { for (j = player->inventorySlotNum; j > i; j--) { player->inventory[j].count = player->inventory[j - 1].count; player->inventory[j].type = player->inventory[j - 1].type; slidePointer = true; } } } player->inventory[i].count = 1; player->inventory[i].type = arti; player->inventorySlotNum++; } else { if (arti >= arti_firstpuzzitem && netgame && !deathmatch) { // Can't carry more than 1 puzzle item in coop netplay return false; } if (player->inventory[i].count >= 25) { // Player already has 25 of this item return false; } player->inventory[i].count++; } if (!player->artifactCount) { player->readyArtifact = arti; } else if (player == &players[consoleplayer] && slidePointer && i <= inv_ptr) { inv_ptr++; curpos++; if (curpos > 6) { curpos = 6; } } player->artifactCount++; return (true); } //========================================================================== // // SetDormantArtifact // // Removes the MF_SPECIAL flag and initiates the artifact pickup // animation. // //========================================================================== static void SetDormantArtifact(mobj_t * arti) { arti->flags &= ~MF_SPECIAL; if (deathmatch && !(arti->flags2 & MF2_DROPPED)) { if (arti->type == MT_ARTIINVULNERABILITY) { P_SetMobjState(arti, S_DORMANTARTI3_1); } else if (arti->type == MT_SUMMONMAULATOR || arti->type == MT_ARTIFLY) { P_SetMobjState(arti, S_DORMANTARTI2_1); } else { P_SetMobjState(arti, S_DORMANTARTI1_1); } } else { // Don't respawn P_SetMobjState(arti, S_DEADARTI1); } } //--------------------------------------------------------------------------- // // PROC A_RestoreArtifact // //--------------------------------------------------------------------------- void A_RestoreArtifact(mobj_t * arti) { arti->flags |= MF_SPECIAL; P_SetMobjState(arti, arti->info->spawnstate); S_StartSound(arti, SFX_RESPAWN); } //--------------------------------------------------------------------------- // // PROC A_RestoreSpecialThing1 // // Make a special thing visible again. // //--------------------------------------------------------------------------- void A_RestoreSpecialThing1(mobj_t * thing) { thing->flags2 &= ~MF2_DONTDRAW; S_StartSound(thing, SFX_RESPAWN); } //--------------------------------------------------------------------------- // // PROC A_RestoreSpecialThing2 // //--------------------------------------------------------------------------- void A_RestoreSpecialThing2(mobj_t * thing) { thing->flags |= MF_SPECIAL; P_SetMobjState(thing, thing->info->spawnstate); } //--------------------------------------------------------------------------- // // PROC P_TouchSpecialThing // //--------------------------------------------------------------------------- void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { player_t *player; fixed_t delta; int sound; boolean respawn; delta = special->z - toucher->z; if (delta > toucher->height || delta < -32 * FRACUNIT) { // Out of reach return; } if (toucher->health <= 0) { // Toucher is dead return; } sound = SFX_PICKUP_ITEM; player = toucher->player; respawn = true; switch (special->sprite) { // Items case SPR_PTN1: // Item_HealingPotion if (!P_GiveBody(player, 10)) { return; } P_SetMessage(player, TXT_ITEMHEALTH, false); break; case SPR_ARM1: if (!P_GiveArmor(player, ARMOR_ARMOR, -1)) { return; } P_SetMessage(player, TXT_ARMOR1, false); break; case SPR_ARM2: if (!P_GiveArmor(player, ARMOR_SHIELD, -1)) { return; } P_SetMessage(player, TXT_ARMOR2, false); break; case SPR_ARM3: if (!P_GiveArmor(player, ARMOR_HELMET, -1)) { return; } P_SetMessage(player, TXT_ARMOR3, false); break; case SPR_ARM4: if (!P_GiveArmor(player, ARMOR_AMULET, -1)) { return; } P_SetMessage(player, TXT_ARMOR4, false); break; // Keys case SPR_KEY1: case SPR_KEY2: case SPR_KEY3: case SPR_KEY4: case SPR_KEY5: case SPR_KEY6: case SPR_KEY7: case SPR_KEY8: case SPR_KEY9: case SPR_KEYA: case SPR_KEYB: if (!P_GiveKey(player, special->sprite - SPR_KEY1)) { return; } P_SetMessage(player, TextKeyMessages[special->sprite - SPR_KEY1], true); sound = SFX_PICKUP_KEY; // Check and process the special now in case the key doesn't // get removed for coop netplay if (special->special) { P_ExecuteLineSpecial(special->special, special->args, NULL, 0, toucher); special->special = 0; } if (!netgame) { // Only remove keys in single player game break; } player->bonuscount += BONUSADD; if (player == &players[consoleplayer]) { S_StartSound(NULL, sound); SB_PaletteFlash(false); } return; // Artifacts case SPR_PTN2: TryPickupArtifact(player, arti_health, special); return; case SPR_SOAR: TryPickupArtifact(player, arti_fly, special); return; case SPR_INVU: TryPickupArtifact(player, arti_invulnerability, special); return; case SPR_SUMN: TryPickupArtifact(player, arti_summon, special); return; case SPR_PORK: TryPickupArtifact(player, arti_egg, special); return; case SPR_SPHL: TryPickupArtifact(player, arti_superhealth, special); return; case SPR_HRAD: TryPickupArtifact(player, arti_healingradius, special); return; case SPR_TRCH: TryPickupArtifact(player, arti_torch, special); return; case SPR_ATLP: TryPickupArtifact(player, arti_teleport, special); return; case SPR_TELO: TryPickupArtifact(player, arti_teleportother, special); return; case SPR_PSBG: TryPickupArtifact(player, arti_poisonbag, special); return; case SPR_SPED: TryPickupArtifact(player, arti_speed, special); return; case SPR_BMAN: TryPickupArtifact(player, arti_boostmana, special); return; case SPR_BRAC: TryPickupArtifact(player, arti_boostarmor, special); return; case SPR_BLST: TryPickupArtifact(player, arti_blastradius, special); return; // Puzzle artifacts case SPR_ASKU: TryPickupArtifact(player, arti_puzzskull, special); return; case SPR_ABGM: TryPickupArtifact(player, arti_puzzgembig, special); return; case SPR_AGMR: TryPickupArtifact(player, arti_puzzgemred, special); return; case SPR_AGMG: TryPickupArtifact(player, arti_puzzgemgreen1, special); return; case SPR_AGG2: TryPickupArtifact(player, arti_puzzgemgreen2, special); return; case SPR_AGMB: TryPickupArtifact(player, arti_puzzgemblue1, special); return; case SPR_AGB2: TryPickupArtifact(player, arti_puzzgemblue2, special); return; case SPR_ABK1: TryPickupArtifact(player, arti_puzzbook1, special); return; case SPR_ABK2: TryPickupArtifact(player, arti_puzzbook2, special); return; case SPR_ASK2: TryPickupArtifact(player, arti_puzzskull2, special); return; case SPR_AFWP: TryPickupArtifact(player, arti_puzzfweapon, special); return; case SPR_ACWP: TryPickupArtifact(player, arti_puzzcweapon, special); return; case SPR_AMWP: TryPickupArtifact(player, arti_puzzmweapon, special); return; case SPR_AGER: TryPickupArtifact(player, arti_puzzgear1, special); return; case SPR_AGR2: TryPickupArtifact(player, arti_puzzgear2, special); return; case SPR_AGR3: TryPickupArtifact(player, arti_puzzgear3, special); return; case SPR_AGR4: TryPickupArtifact(player, arti_puzzgear4, special); return; // Mana case SPR_MAN1: if (!P_GiveMana(player, MANA_1, 15)) { return; } P_SetMessage(player, TXT_MANA_1, false); break; case SPR_MAN2: if (!P_GiveMana(player, MANA_2, 15)) { return; } P_SetMessage(player, TXT_MANA_2, false); break; case SPR_MAN3: // Double Mana Dodecahedron if (!P_GiveMana(player, MANA_1, 20)) { if (!P_GiveMana(player, MANA_2, 20)) { return; } } else { P_GiveMana(player, MANA_2, 20); } P_SetMessage(player, TXT_MANA_BOTH, false); break; // 2nd and 3rd Mage Weapons case SPR_WMCS: // Frost Shards TryPickupWeapon(player, PCLASS_MAGE, WP_SECOND, special, TXT_WEAPON_M2); return; case SPR_WMLG: // Arc of Death TryPickupWeapon(player, PCLASS_MAGE, WP_THIRD, special, TXT_WEAPON_M3); return; // 2nd and 3rd Fighter Weapons case SPR_WFAX: // Timon's Axe TryPickupWeapon(player, PCLASS_FIGHTER, WP_SECOND, special, TXT_WEAPON_F2); return; case SPR_WFHM: // Hammer of Retribution TryPickupWeapon(player, PCLASS_FIGHTER, WP_THIRD, special, TXT_WEAPON_F3); return; // 2nd and 3rd Cleric Weapons case SPR_WCSS: // Serpent Staff TryPickupWeapon(player, PCLASS_CLERIC, WP_SECOND, special, TXT_WEAPON_C2); return; case SPR_WCFM: // Firestorm TryPickupWeapon(player, PCLASS_CLERIC, WP_THIRD, special, TXT_WEAPON_C3); return; // Fourth Weapon Pieces case SPR_WFR1: TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE1, special); return; case SPR_WFR2: TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE2, special); return; case SPR_WFR3: TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE3, special); return; case SPR_WCH1: TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE1, special); return; case SPR_WCH2: TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE2, special); return; case SPR_WCH3: TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE3, special); return; case SPR_WMS1: TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE1, special); return; case SPR_WMS2: TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE2, special); return; case SPR_WMS3: TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE3, special); return; default: I_Error("P_SpecialThing: Unknown gettable thing"); } if (special->special) { P_ExecuteLineSpecial(special->special, special->args, NULL, 0, toucher); special->special = 0; } if (deathmatch && respawn && !(special->flags2 & MF2_DROPPED)) { P_HideSpecialThing(special); } else { P_RemoveMobj(special); } player->bonuscount += BONUSADD; if (player == &players[consoleplayer]) { S_StartSound(NULL, sound); SB_PaletteFlash(false); } } // Search thinker list for minotaur mobj_t *ActiveMinotaur(player_t * master) { mobj_t *mo; player_t *plr; thinker_t *think; unsigned int *starttime; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) continue; mo = (mobj_t *) think; if (mo->type != MT_MINOTAUR) continue; if (mo->health <= 0) continue; if (!(mo->flags & MF_COUNTKILL)) continue; // for morphed minotaurs if (mo->flags & MF_CORPSE) continue; starttime = (unsigned int *) mo->args; if ((leveltime - *starttime) >= MAULATORTICS) continue; plr = mo->special1.m->player; if (plr == master) return (mo); } return (NULL); } //--------------------------------------------------------------------------- // // PROC P_KillMobj // //--------------------------------------------------------------------------- void P_KillMobj(mobj_t * source, mobj_t * target) { byte dummyArgs[3] = {0, 0, 0}; mobj_t *master; target->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_NOGRAVITY); target->flags |= MF_CORPSE | MF_DROPOFF; target->flags2 &= ~MF2_PASSMOBJ; target->height >>= 2; if ((target->flags & MF_COUNTKILL || target->type == MT_ZBELL) && target->special) { // Initiate monster death actions if (target->type == MT_SORCBOSS) { P_StartACS(target->special, 0, dummyArgs, target, NULL, 0); } else { P_ExecuteLineSpecial(target->special, target->args, NULL, 0, target); } } if (source && source->player) { // Check for frag changes if (target->player) { if (target == source) { // Self-frag target->player->frags[target->player - players]--; if (cmdfrag && netgame && source->player == &players[consoleplayer]) { // Send out a frag count packet NET_SendFrags(source->player); } } else { source->player->frags[target->player - players]++; if (cmdfrag && netgame && source->player == &players[consoleplayer]) { // Send out a frag count packet NET_SendFrags(source->player); } } } } if (target->player) { // Player death if (!source) { // Self-frag target->player->frags[target->player - players]--; if (cmdfrag && netgame && target->player == &players[consoleplayer]) { // Send out a frag count packet NET_SendFrags(target->player); } } target->flags &= ~MF_SOLID; target->flags2 &= ~MF2_FLY; target->player->powers[pw_flight] = 0; target->player->playerstate = PST_DEAD; P_DropWeapon(target->player); if (target->flags2 & MF2_FIREDAMAGE) { // Player flame death switch (target->player->class) { case PCLASS_FIGHTER: S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH); P_SetMobjState(target, S_PLAY_F_FDTH1); return; case PCLASS_CLERIC: S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH); P_SetMobjState(target, S_PLAY_C_FDTH1); return; case PCLASS_MAGE: S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH); P_SetMobjState(target, S_PLAY_M_FDTH1); return; default: break; } } if (target->flags2 & MF2_ICEDAMAGE) { // Player ice death target->flags &= ~(7 << MF_TRANSSHIFT); //no translation target->flags |= MF_ICECORPSE; switch (target->player->class) { case PCLASS_FIGHTER: P_SetMobjState(target, S_FPLAY_ICE); return; case PCLASS_CLERIC: P_SetMobjState(target, S_CPLAY_ICE); return; case PCLASS_MAGE: P_SetMobjState(target, S_MPLAY_ICE); return; case PCLASS_PIG: P_SetMobjState(target, S_PIG_ICE); return; default: break; } } } if (target->flags2 & MF2_FIREDAMAGE) { if (target->type == MT_FIGHTER_BOSS || target->type == MT_CLERIC_BOSS || target->type == MT_MAGE_BOSS) { switch (target->type) { case MT_FIGHTER_BOSS: S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH); P_SetMobjState(target, S_PLAY_F_FDTH1); return; case MT_CLERIC_BOSS: S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH); P_SetMobjState(target, S_PLAY_C_FDTH1); return; case MT_MAGE_BOSS: S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH); P_SetMobjState(target, S_PLAY_M_FDTH1); return; default: break; } } else if (target->type == MT_TREEDESTRUCTIBLE) { P_SetMobjState(target, S_ZTREEDES_X1); target->height = 24 * FRACUNIT; S_StartSound(target, SFX_TREE_EXPLODE); return; } } if (target->flags2 & MF2_ICEDAMAGE) { target->flags |= MF_ICECORPSE; switch (target->type) { case MT_BISHOP: P_SetMobjState(target, S_BISHOP_ICE); return; case MT_CENTAUR: case MT_CENTAURLEADER: P_SetMobjState(target, S_CENTAUR_ICE); return; case MT_DEMON: case MT_DEMON2: P_SetMobjState(target, S_DEMON_ICE); return; case MT_SERPENT: case MT_SERPENTLEADER: P_SetMobjState(target, S_SERPENT_ICE); return; case MT_WRAITH: case MT_WRAITHB: P_SetMobjState(target, S_WRAITH_ICE); return; case MT_ETTIN: P_SetMobjState(target, S_ETTIN_ICE1); return; case MT_FIREDEMON: P_SetMobjState(target, S_FIRED_ICE1); return; case MT_FIGHTER_BOSS: P_SetMobjState(target, S_FIGHTER_ICE); return; case MT_CLERIC_BOSS: P_SetMobjState(target, S_CLERIC_ICE); return; case MT_MAGE_BOSS: P_SetMobjState(target, S_MAGE_ICE); return; case MT_PIG: P_SetMobjState(target, S_PIG_ICE); return; default: target->flags &= ~MF_ICECORPSE; break; } } if (target->type == MT_MINOTAUR) { master = target->special1.m; if (master->health > 0) { if (!ActiveMinotaur(master->player)) { master->player->powers[pw_minotaur] = 0; } } } else if (target->type == MT_TREEDESTRUCTIBLE) { target->height = 24 * FRACUNIT; } if (target->health < -(target->info->spawnhealth >> 1) && target->info->xdeathstate) { // Extreme death P_SetMobjState(target, target->info->xdeathstate); } else { // Normal death if ((target->type == MT_FIREDEMON) && (target->z <= target->floorz + 2 * FRACUNIT) && (target->info->xdeathstate)) { // This is to fix the imps' staying in fall state P_SetMobjState(target, target->info->xdeathstate); } else { P_SetMobjState(target, target->info->deathstate); } } target->tics -= P_Random() & 3; // I_StartSound(&actor->r, actor->info->deathsound); } //--------------------------------------------------------------------------- // // FUNC P_MinotaurSlam // //--------------------------------------------------------------------------- void P_MinotaurSlam(mobj_t * source, mobj_t * target) { angle_t angle; fixed_t thrust; angle = R_PointToAngle2(source->x, source->y, target->x, target->y); angle >>= ANGLETOFINESHIFT; thrust = 16 * FRACUNIT + (P_Random() << 10); target->momx += FixedMul(thrust, finecosine[angle]); target->momy += FixedMul(thrust, finesine[angle]); P_DamageMobj(target, NULL, source, HITDICE(4)); if (target->player) { target->reactiontime = 14 + (P_Random() & 7); } source->args[0] = 0; // Stop charging } //--------------------------------------------------------------------------- // // FUNC P_MorphPlayer // // Returns true if the player gets turned into a pig // //--------------------------------------------------------------------------- boolean P_MorphPlayer(player_t * player) { mobj_t *pmo; mobj_t *fog; mobj_t *beastMo; fixed_t x; fixed_t y; fixed_t z; angle_t angle; int oldFlags2; if (player->powers[pw_invulnerability]) { // Immune when invulnerable return (false); } if (player->morphTics) { // Player is already a beast return false; } pmo = player->mo; x = pmo->x; y = pmo->y; z = pmo->z; angle = pmo->angle; oldFlags2 = pmo->flags2; P_SetMobjState(pmo, S_FREETARGMOBJ); fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, SFX_TELEPORT); beastMo = P_SpawnMobj(x, y, z, MT_PIGPLAYER); beastMo->special1.i = player->readyweapon; beastMo->angle = angle; beastMo->player = player; player->health = beastMo->health = MAXMORPHHEALTH; player->mo = beastMo; memset(&player->armorpoints[0], 0, NUMARMOR * sizeof(int)); player->class = PCLASS_PIG; if (oldFlags2 & MF2_FLY) { beastMo->flags2 |= MF2_FLY; } player->morphTics = MORPHTICS; P_ActivateMorphWeapon(player); return (true); } //--------------------------------------------------------------------------- // // FUNC P_MorphMonster // //--------------------------------------------------------------------------- boolean P_MorphMonster(mobj_t * actor) { mobj_t *master, *monster, *fog; mobjtype_t moType; fixed_t x; fixed_t y; fixed_t z; mobj_t oldMonster; if (actor->player) return (false); if (!(actor->flags & MF_COUNTKILL)) return false; if (actor->flags2 & MF2_BOSS) return false; moType = actor->type; switch (moType) { case MT_PIG: return (false); case MT_FIGHTER_BOSS: case MT_CLERIC_BOSS: case MT_MAGE_BOSS: return (false); default: break; } oldMonster = *actor; x = oldMonster.x; y = oldMonster.y; z = oldMonster.z; P_RemoveMobjFromTIDList(actor); P_SetMobjState(actor, S_FREETARGMOBJ); fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, SFX_TELEPORT); monster = P_SpawnMobj(x, y, z, MT_PIG); monster->special2.i = moType; monster->special1.i = MORPHTICS + P_Random(); monster->flags |= (oldMonster.flags & MF_SHADOW); monster->target = oldMonster.target; monster->angle = oldMonster.angle; monster->tid = oldMonster.tid; monster->special = oldMonster.special; P_InsertMobjIntoTIDList(monster, oldMonster.tid); memcpy(monster->args, oldMonster.args, 5); // check for turning off minotaur power for active icon if (moType == MT_MINOTAUR) { master = oldMonster.special1.m; if (master->health > 0) { if (!ActiveMinotaur(master->player)) { master->player->powers[pw_minotaur] = 0; } } } return (true); } //--------------------------------------------------------------------------- // // PROC P_AutoUseHealth // //--------------------------------------------------------------------------- void P_AutoUseHealth(player_t * player, int saveHealth) { int i; int count; int normalCount; int normalSlot = 0; int superCount; int superSlot = 0; normalCount = superCount = 0; for (i = 0; i < player->inventorySlotNum; i++) { if (player->inventory[i].type == arti_health) { normalSlot = i; normalCount = player->inventory[i].count; } else if (player->inventory[i].type == arti_superhealth) { superSlot = i; superCount = player->inventory[i].count; } } if ((gameskill == sk_baby) && (normalCount * 25 >= saveHealth)) { // Use quartz flasks count = (saveHealth + 24) / 25; for (i = 0; i < count; i++) { player->health += 25; P_PlayerRemoveArtifact(player, normalSlot); } } else if (superCount * 100 >= saveHealth) { // Use mystic urns count = (saveHealth + 99) / 100; for (i = 0; i < count; i++) { player->health += 100; P_PlayerRemoveArtifact(player, superSlot); } } else if ((gameskill == sk_baby) && (superCount * 100 + normalCount * 25 >= saveHealth)) { // Use mystic urns and quartz flasks count = (saveHealth + 24) / 25; saveHealth -= count * 25; for (i = 0; i < count; i++) { player->health += 25; P_PlayerRemoveArtifact(player, normalSlot); } count = (saveHealth + 99) / 100; for (i = 0; i < count; i++) { player->health += 100; P_PlayerRemoveArtifact(player, normalSlot); } } player->mo->health = player->health; } /* ================= = = P_DamageMobj = = Damages both enemies and players = inflictor is the thing that caused the damage = creature or missile, can be NULL (slime, etc) = source is the thing to target after taking damage = creature or NULL = Source and inflictor are the same for melee attacks = source can be null for barrel explosions and other environmental stuff ================== */ void P_DamageMobj (mobj_t * target, mobj_t * inflictor, mobj_t * source, int damage) { unsigned ang; int saved; fixed_t savedPercent; player_t *player; mobj_t *master; fixed_t thrust; int temp; int i; if (!(target->flags & MF_SHOOTABLE)) { // Shouldn't happen return; } if (target->health <= 0) { if (inflictor && inflictor->flags2 & MF2_ICEDAMAGE) { return; } else if (target->flags & MF_ICECORPSE) // frozen { target->tics = 1; target->momx = target->momy = 0; } return; } if ((target->flags2 & MF2_INVULNERABLE) && damage < 10000) { // mobj is invulnerable if (target->player) return; // for player, no exceptions if (inflictor) { switch (inflictor->type) { // These inflictors aren't foiled by invulnerability case MT_HOLY_FX: case MT_POISONCLOUD: case MT_FIREBOMB: break; default: return; } } else { return; } } if (target->player) { if (damage < 1000 && ((target->player->cheats & CF_GODMODE) || target->player->powers[pw_invulnerability])) { return; } } if (target->flags & MF_SKULLFLY) { target->momx = target->momy = target->momz = 0; } if (target->flags2 & MF2_DORMANT) { // Invulnerable, and won't wake up return; } player = target->player; if (player && gameskill == sk_baby) { // Take half damage in trainer mode damage >>= 1; } // Special damage types if (inflictor) { switch (inflictor->type) { case MT_EGGFX: if (player) { P_MorphPlayer(player); } else { P_MorphMonster(target); } return; // Always return case MT_TELOTHER_FX1: case MT_TELOTHER_FX2: case MT_TELOTHER_FX3: case MT_TELOTHER_FX4: case MT_TELOTHER_FX5: if ((target->flags & MF_COUNTKILL) && (target->type != MT_SERPENT) && (target->type != MT_SERPENTLEADER) && (!(target->flags2 & MF2_BOSS))) { P_TeleportOther(target); } return; case MT_MINOTAUR: if (inflictor->flags & MF_SKULLFLY) { // Slam only when in charge mode P_MinotaurSlam(inflictor, target); return; } break; case MT_BISH_FX: // Bishops are just too nasty damage >>= 1; break; case MT_SHARDFX1: switch (inflictor->special2.i) { case 3: damage <<= 3; break; case 2: damage <<= 2; break; case 1: damage <<= 1; break; default: break; } break; case MT_CSTAFF_MISSILE: // Cleric Serpent Staff does poison damage if (target->player) { P_PoisonPlayer(target->player, source, 20); damage >>= 1; } break; case MT_ICEGUY_FX2: damage >>= 1; break; case MT_POISONDART: if (target->player) { P_PoisonPlayer(target->player, source, 20); damage >>= 1; } break; case MT_POISONCLOUD: if (target->player) { if (target->player->poisoncount < 4) { P_PoisonDamage(target->player, source, 15 + (P_Random() & 15), false); // Don't play painsound P_PoisonPlayer(target->player, source, 50); S_StartSound(target, SFX_PLAYER_POISONCOUGH); } return; } else if (!(target->flags & MF_COUNTKILL)) { // only damage monsters/players with the poison cloud return; } break; case MT_FSWORD_MISSILE: if (target->player) { damage -= damage >> 2; } break; default: break; } } // Push the target unless source is using the gauntlets if (inflictor && (!source || !source->player) && !(inflictor->flags2 & MF2_NODMGTHRUST)) { ang = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y); //thrust = damage*(FRACUNIT>>3)*100/target->info->mass; thrust = damage * (FRACUNIT >> 3) * 150 / target->info->mass; // make fall forwards sometimes if ((damage < 40) && (damage > target->health) && (target->z - inflictor->z > 64 * FRACUNIT) && (P_Random() & 1)) { ang += ANG180; thrust *= 4; } ang >>= ANGLETOFINESHIFT; target->momx += FixedMul(thrust, finecosine[ang]); target->momy += FixedMul(thrust, finesine[ang]); } // // player specific // if (player) { savedPercent = AutoArmorSave[player->class] + player->armorpoints[ARMOR_ARMOR] + player->armorpoints[ARMOR_SHIELD] + player->armorpoints[ARMOR_HELMET] + player->armorpoints[ARMOR_AMULET]; if (savedPercent) { // armor absorbed some damage if (savedPercent > 100 * FRACUNIT) { savedPercent = 100 * FRACUNIT; } for (i = 0; i < NUMARMOR; i++) { if (player->armorpoints[i]) { player->armorpoints[i] -= FixedDiv(FixedMul(damage << FRACBITS, ArmorIncrement[player->class][i]), 300 * FRACUNIT); if (player->armorpoints[i] < 2 * FRACUNIT) { player->armorpoints[i] = 0; } } } saved = FixedDiv(FixedMul(damage << FRACBITS, savedPercent), 100 * FRACUNIT); if (saved > savedPercent * 2) { saved = savedPercent * 2; } damage -= saved >> FRACBITS; } if (damage >= player->health && ((gameskill == sk_baby) || deathmatch) && !player->morphTics) { // Try to use some inventory health P_AutoUseHealth(player, damage - player->health + 1); } player->health -= damage; // mirror mobj health here for Dave if (player->health < 0) { player->health = 0; } player->attacker = source; player->damagecount += damage; // add damage after armor / invuln if (player->damagecount > 100) { player->damagecount = 100; // teleport stomp does 10k points... } temp = damage < 100 ? damage : 100; if (player == &players[consoleplayer]) { I_Tactile(40, 10, 40 + temp * 2); SB_PaletteFlash(false); } } // // do the damage // target->health -= damage; if (target->health <= 0) { // Death if (inflictor) { // check for special fire damage or ice damage deaths if (inflictor->flags2 & MF2_FIREDAMAGE) { if (player && !player->morphTics) { // Check for flame death if (target->health > -50 && damage > 25) { target->flags2 |= MF2_FIREDAMAGE; } } else { target->flags2 |= MF2_FIREDAMAGE; } } else if (inflictor->flags2 & MF2_ICEDAMAGE) { target->flags2 |= MF2_ICEDAMAGE; } } if (source && (source->type == MT_MINOTAUR)) { // Minotaur's kills go to his master master = source->special1.m; // Make sure still alive and not a pointer to fighter head if (master->player && (master->player->mo == master)) { source = master; } } if (source && (source->player) && (source->player->readyweapon == WP_FOURTH)) { // Always extreme death from fourth weapon target->health = -5000; } P_KillMobj(source, target); return; } if ((P_Random() < target->info->painchance) && !(target->flags & MF_SKULLFLY)) { if (inflictor && (inflictor->type >= MT_LIGHTNING_FLOOR && inflictor->type <= MT_LIGHTNING_ZAP)) { if (P_Random() < 96) { target->flags |= MF_JUSTHIT; // fight back! P_SetMobjState(target, target->info->painstate); } else { // "electrocute" the target target->frame |= FF_FULLBRIGHT; if (target->flags & MF_COUNTKILL && P_Random() < 128 && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT)) { if ((target->type == MT_CENTAUR) || (target->type == MT_CENTAURLEADER) || (target->type == MT_ETTIN)) { S_StartSound(target, SFX_PUPPYBEAT); } } } } else { target->flags |= MF_JUSTHIT; // fight back! P_SetMobjState(target, target->info->painstate); if (inflictor && inflictor->type == MT_POISONCLOUD) { if (target->flags & MF_COUNTKILL && P_Random() < 128 && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT)) { if ((target->type == MT_CENTAUR) || (target->type == MT_CENTAURLEADER) || (target->type == MT_ETTIN)) { S_StartSound(target, SFX_PUPPYBEAT); } } } } } target->reactiontime = 0; // we're awake now... if (!target->threshold && source && !(source->flags2 & MF2_BOSS) && !(target->type == MT_BISHOP) && !(target->type == MT_MINOTAUR)) { // Target actor is not intent on another actor, // so make him chase after source if ((target->type == MT_CENTAUR && source->type == MT_CENTAURLEADER) || (target->type == MT_CENTAURLEADER && source->type == MT_CENTAUR)) { return; } target->target = source; target->threshold = BASETHRESHOLD; if (target->state == &states[target->info->spawnstate] && target->info->seestate != S_NULL) { P_SetMobjState(target, target->info->seestate); } } } //========================================================================== // // P_FallingDamage // //========================================================================== void P_FallingDamage(player_t * player) { int damage; int mom; int dist; mom = abs(player->mo->momz); dist = FixedMul(mom, 16 * FRACUNIT / 23); if (mom >= 63 * FRACUNIT) { // automatic death P_DamageMobj(player->mo, NULL, NULL, 10000); return; } damage = ((FixedMul(dist, dist) / 10) >> FRACBITS) - 24; if (player->mo->momz > -39 * FRACUNIT && damage > player->mo->health && player->mo->health != 1) { // No-death threshold damage = player->mo->health - 1; } S_StartSound(player->mo, SFX_PLAYER_LAND); P_DamageMobj(player->mo, NULL, NULL, damage); } //========================================================================== // // P_PoisonPlayer - Sets up all data concerning poisoning // //========================================================================== void P_PoisonPlayer(player_t * player, mobj_t * poisoner, int poison) { if ((player->cheats & CF_GODMODE) || player->powers[pw_invulnerability]) { return; } player->poisoncount += poison; player->poisoner = poisoner; if (player->poisoncount > 100) { player->poisoncount = 100; } } //========================================================================== // // P_PoisonDamage - Similar to P_DamageMobj // //========================================================================== void P_PoisonDamage(player_t * player, mobj_t * source, int damage, boolean playPainSound) { mobj_t *target; mobj_t *inflictor; target = player->mo; inflictor = source; if (target->health <= 0) { return; } if (target->flags2 & MF2_INVULNERABLE && damage < 10000) { // mobj is invulnerable return; } if (player && gameskill == sk_baby) { // Take half damage in trainer mode damage >>= 1; } if (damage < 1000 && ((player->cheats & CF_GODMODE) || player->powers[pw_invulnerability])) { return; } if (damage >= player->health && ((gameskill == sk_baby) || deathmatch) && !player->morphTics) { // Try to use some inventory health P_AutoUseHealth(player, damage - player->health + 1); } player->health -= damage; // mirror mobj health here for Dave if (player->health < 0) { player->health = 0; } player->attacker = source; // // do the damage // target->health -= damage; if (target->health <= 0) { // Death target->special1.i = damage; if (player && inflictor && !player->morphTics) { // Check for flame death if ((inflictor->flags2 & MF2_FIREDAMAGE) && (target->health > -50) && (damage > 25)) { target->flags2 |= MF2_FIREDAMAGE; } if (inflictor->flags2 & MF2_ICEDAMAGE) { target->flags2 |= MF2_ICEDAMAGE; } } P_KillMobj(source, target); return; } if (!(leveltime & 63) && playPainSound) { P_SetMobjState(target, target->info->painstate); } /* if((P_Random() < target->info->painchance) && !(target->flags&MF_SKULLFLY)) { target->flags |= MF_JUSTHIT; // fight back! P_SetMobjState(target, target->info->painstate); } */ } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_lights.c000066400000000000000000000250041257432200600231610ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "m_random.h" #include "p_local.h" //============================================================================ // // T_Light // //============================================================================ void T_Light(light_t * light) { if (light->count) { light->count--; return; } switch (light->type) { case LITE_FADE: light->sector->lightlevel = ((light->sector->lightlevel << FRACBITS) + light->value2) >> FRACBITS; if (light->tics2 == 1) { if (light->sector->lightlevel >= light->value1) { light->sector->lightlevel = light->value1; P_RemoveThinker(&light->thinker); } } else if (light->sector->lightlevel <= light->value1) { light->sector->lightlevel = light->value1; P_RemoveThinker(&light->thinker); } break; case LITE_GLOW: light->sector->lightlevel = ((light->sector->lightlevel << FRACBITS) + light->tics1) >> FRACBITS; if (light->tics2 == 1) { if (light->sector->lightlevel >= light->value1) { light->sector->lightlevel = light->value1; light->tics1 = -light->tics1; light->tics2 = -1; // reverse direction } } else if (light->sector->lightlevel <= light->value2) { light->sector->lightlevel = light->value2; light->tics1 = -light->tics1; light->tics2 = 1; // reverse direction } break; case LITE_FLICKER: if (light->sector->lightlevel == light->value1) { light->sector->lightlevel = light->value2; light->count = (P_Random() & 7) + 1; } else { light->sector->lightlevel = light->value1; light->count = (P_Random() & 31) + 1; } break; case LITE_STROBE: if (light->sector->lightlevel == light->value1) { light->sector->lightlevel = light->value2; light->count = light->tics2; } else { light->sector->lightlevel = light->value1; light->count = light->tics1; } break; default: break; } } //============================================================================ // // EV_SpawnLight // //============================================================================ boolean EV_SpawnLight(line_t * line, byte * arg, lighttype_t type) { light_t *light; sector_t *sec; int secNum; int arg1, arg2, arg3, arg4; boolean think; boolean rtn; /* Original code; redundant considering that a byte value is always in the range 0-255: arg1 = arg[1] > 255 ? 255 : arg[1]; arg1 = arg1 < 0 ? 0 : arg1; arg2 = arg[2] > 255 ? 255 : arg[2]; arg2 = arg2 < 0 ? 0 : arg2; arg3 = arg[3] > 255 ? 255 : arg[3]; arg3 = arg3 < 0 ? 0 : arg3; arg4 = arg[4] > 255 ? 255 : arg[4]; arg4 = arg4 < 0 ? 0 : arg4; */ arg1 = arg[1]; arg2 = arg[2]; arg3 = arg[3]; arg4 = arg[4]; secNum = -1; rtn = false; think = false; while ((secNum = P_FindSectorFromTag(arg[0], secNum)) >= 0) { think = false; sec = §ors[secNum]; light = (light_t *) Z_Malloc(sizeof(light_t), PU_LEVSPEC, 0); light->type = type; light->sector = sec; light->count = 0; rtn = true; switch (type) { case LITE_RAISEBYVALUE: sec->lightlevel += arg1; if (sec->lightlevel > 255) { sec->lightlevel = 255; } break; case LITE_LOWERBYVALUE: sec->lightlevel -= arg1; if (sec->lightlevel < 0) { sec->lightlevel = 0; } break; case LITE_CHANGETOVALUE: sec->lightlevel = arg1; if (sec->lightlevel < 0) { sec->lightlevel = 0; } else if (sec->lightlevel > 255) { sec->lightlevel = 255; } break; case LITE_FADE: think = true; light->value1 = arg1; // destination lightlevel light->value2 = FixedDiv((arg1 - sec->lightlevel) << FRACBITS, arg2 << FRACBITS); // delta lightlevel if (sec->lightlevel <= arg1) { light->tics2 = 1; // get brighter } else { light->tics2 = -1; } break; case LITE_GLOW: think = true; light->value1 = arg1; // upper lightlevel light->value2 = arg2; // lower lightlevel light->tics1 = FixedDiv((arg1 - sec->lightlevel) << FRACBITS, arg3 << FRACBITS); // lightlevel delta if (sec->lightlevel <= arg1) { light->tics2 = 1; // get brighter } else { light->tics2 = -1; } break; case LITE_FLICKER: think = true; light->value1 = arg1; // upper lightlevel light->value2 = arg2; // lower lightlevel sec->lightlevel = light->value1; light->count = (P_Random() & 64) + 1; break; case LITE_STROBE: think = true; light->value1 = arg1; // upper lightlevel light->value2 = arg2; // lower lightlevel light->tics1 = arg3; // upper tics light->tics2 = arg4; // lower tics light->count = arg3; sec->lightlevel = light->value1; break; default: rtn = false; break; } if (think) { P_AddThinker(&light->thinker); light->thinker.function = T_Light; } else { Z_Free(light); } } return rtn; } //============================================================================ // // T_Phase // //============================================================================ int PhaseTable[64] = { 128, 112, 96, 80, 64, 48, 32, 32, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 32, 32, 48, 64, 80, 96, 112, 128 }; void T_Phase(phase_t * phase) { phase->index = (phase->index + 1) & 63; phase->sector->lightlevel = phase->base + PhaseTable[phase->index]; } //========================================================================== // // P_SpawnPhasedLight // //========================================================================== void P_SpawnPhasedLight(sector_t * sector, int base, int index) { phase_t *phase; phase = Z_Malloc(sizeof(*phase), PU_LEVSPEC, 0); P_AddThinker(&phase->thinker); phase->sector = sector; if (index == -1) { // sector->lightlevel as the index phase->index = sector->lightlevel & 63; } else { phase->index = index & 63; } phase->base = base & 255; sector->lightlevel = phase->base + PhaseTable[phase->index]; phase->thinker.function = T_Phase; sector->special = 0; } //========================================================================== // // P_SpawnLightSequence // //========================================================================== void P_SpawnLightSequence(sector_t * sector, int indexStep) { sector_t *sec; sector_t *nextSec; sector_t *tempSec; int seqSpecial; int i; int count; fixed_t index; fixed_t indexDelta; int base; seqSpecial = LIGHT_SEQUENCE; // look for Light_Sequence, first sec = sector; count = 1; do { nextSec = NULL; sec->special = LIGHT_SEQUENCE_START; // make sure that the search doesn't back up. for (i = 0; i < sec->linecount; i++) { tempSec = getNextSector(sec->lines[i], sec); if (!tempSec) { continue; } if (tempSec->special == seqSpecial) { if (seqSpecial == LIGHT_SEQUENCE) { seqSpecial = LIGHT_SEQUENCE_ALT; } else { seqSpecial = LIGHT_SEQUENCE; } nextSec = tempSec; count++; } } sec = nextSec; } while (sec); sec = sector; count *= indexStep; index = 0; indexDelta = FixedDiv(64 * FRACUNIT, count * FRACUNIT); base = sector->lightlevel; do { nextSec = NULL; if (sec->lightlevel) { base = sec->lightlevel; } P_SpawnPhasedLight(sec, base, index >> FRACBITS); index += indexDelta; for (i = 0; i < sec->linecount; i++) { tempSec = getNextSector(sec->lines[i], sec); if (!tempSec) { continue; } if (tempSec->special == LIGHT_SEQUENCE_START) { nextSec = tempSec; } } sec = nextSec; } while (sec); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_local.h000066400000000000000000000270051257432200600227710ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __P_LOCAL__ #define __P_LOCAL__ #ifndef __R_LOCAL__ #include "r_local.h" #endif #define STARTREDPALS 1 #define STARTBONUSPALS 9 #define STARTPOISONPALS 13 #define STARTICEPAL 21 #define STARTHOLYPAL 22 #define STARTSCOURGEPAL 25 #define NUMREDPALS 8 #define NUMBONUSPALS 4 #define NUMPOISONPALS 8 #define TOCENTER -8 #define FLOATSPEED (FRACUNIT*4) #define MAXHEALTH 100 #define MAXMORPHHEALTH 30 #define VIEWHEIGHT (48*FRACUNIT) // mapblocks are used to check movement against lines and things #define MAPBLOCKUNITS 128 #define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) #define MAPBLOCKSHIFT (FRACBITS+7) #define MAPBMASK (MAPBLOCKSIZE-1) #define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) // player radius for movement checking #define PLAYERRADIUS 16*FRACUNIT // MAXRADIUS is for precalculated sector block boxes // the spider demon is larger, but we don't have any moving sectors // nearby #define MAXRADIUS 32*FRACUNIT #define GRAVITY FRACUNIT #define MAXMOVE (30*FRACUNIT) #define USERANGE (64*FRACUNIT) #define MELEERANGE (64*FRACUNIT) #define MISSILERANGE (32*64*FRACUNIT) typedef enum { DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_NODIR, NUMDIRS } dirtype_t; #define BASETHRESHOLD 100 // follow a player exlusively for 3 seconds // ***** P_TICK ***** extern thinker_t thinkercap; // both the head and tail of the thinker list extern int TimerGame; // tic countdown for deathmatch void P_InitThinkers(void); void P_AddThinker(thinker_t * thinker); void P_RemoveThinker(thinker_t * thinker); // ***** P_PSPR ***** #define USE_MANA1 1 #define USE_MANA2 1 void P_SetPsprite(player_t * player, int position, statenum_t stnum); void P_SetPspriteNF(player_t * player, int position, statenum_t stnum); void P_SetupPsprites(player_t * curplayer); void P_MovePsprites(player_t * curplayer); void P_DropWeapon(player_t * player); void P_ActivateMorphWeapon(player_t * player); void P_PostMorphWeapon(player_t * player, weapontype_t weapon); // ***** P_USER ***** extern int PStateNormal[NUMCLASSES]; extern int PStateRun[NUMCLASSES]; extern int PStateAttack[NUMCLASSES]; extern int PStateAttackEnd[NUMCLASSES]; void P_PlayerThink(player_t * player); void P_Thrust(player_t * player, angle_t angle, fixed_t move); void P_PlayerRemoveArtifact(player_t * player, int slot); void P_PlayerUseArtifact(player_t * player, artitype_t arti); boolean P_UseArtifact(player_t * player, artitype_t arti); int P_GetPlayerNum(player_t * player); void P_TeleportOther(mobj_t * victim); void ResetBlasted(mobj_t * mo); // ***** P_MOBJ ***** // Any floor type >= FLOOR_LIQUID will floorclip sprites enum { FLOOR_SOLID, FLOOR_ICE, FLOOR_LIQUID, FLOOR_WATER, FLOOR_LAVA, FLOOR_SLUDGE }; #define ONFLOORZ INT_MIN #define ONCEILINGZ INT_MAX #define FLOATRANDZ (INT_MAX-1) #define FROMCEILINGZ128 (INT_MAX-2) extern mobjtype_t PuffType; extern mobj_t *MissileMobj; mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); void P_RemoveMobj(mobj_t * th); boolean P_SetMobjState(mobj_t * mobj, statenum_t state); boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state); void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move); int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta); boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax); void P_MobjThinker(mobj_t * mobj); void P_BlasterMobjThinker(mobj_t * mobj); void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z); void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage); void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator); void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator); void P_RipperBlood(mobj_t * mo); int P_GetThingFloorType(mobj_t * thing); int P_HitFloor(mobj_t * thing); boolean P_CheckMissileSpawn(mobj_t * missile); mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type); mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z, mobj_t * source, mobj_t * dest, mobjtype_t type); mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type, angle_t angle, fixed_t momz); mobj_t *P_SpawnMissileAngleSpeed(mobj_t * source, mobjtype_t type, angle_t angle, fixed_t momz, fixed_t speed); mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type); mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle); mobj_t *P_SPMAngleXYZ(mobj_t * source, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, angle_t angle); void P_CreateTIDList(void); void P_RemoveMobjFromTIDList(mobj_t * mobj); void P_InsertMobjIntoTIDList(mobj_t * mobj, int tid); mobj_t *P_FindMobjFromTID(int tid, int *searchPosition); mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z, mobj_t * source, mobj_t * dest, mobjtype_t type); // ***** P_ENEMY ***** void P_NoiseAlert(mobj_t * target, mobj_t * emmiter); int P_Massacre(void); boolean A_RaiseMobj(mobj_t * actor); boolean A_SinkMobj(mobj_t * actor); void A_NoBlocking(mobj_t * actor); boolean P_LookForMonsters(mobj_t * actor); void P_InitCreatureCorpseQueue(boolean corpseScan); void A_DeQueueCorpse(mobj_t * actor); // ***** P_MAPUTL ***** typedef struct { fixed_t x, y, dx, dy; } divline_t; typedef struct { fixed_t frac; // along trace line boolean isaline; union { mobj_t *thing; line_t *line; } d; } intercept_t; #define MAXINTERCEPTS 128 extern intercept_t intercepts[MAXINTERCEPTS], *intercept_p; typedef boolean(*traverser_t) (intercept_t * in); fixed_t P_AproxDistance(fixed_t dx, fixed_t dy); int P_PointOnLineSide(fixed_t x, fixed_t y, line_t * line); int P_PointOnDivlineSide(fixed_t x, fixed_t y, divline_t * line); void P_MakeDivline(line_t * li, divline_t * dl); fixed_t P_InterceptVector(divline_t * v2, divline_t * v1); int P_BoxOnLineSide(fixed_t * tmbox, line_t * ld); extern fixed_t opentop, openbottom, openrange; extern fixed_t lowfloor; void P_LineOpening(line_t * linedef); boolean P_BlockLinesIterator(int x, int y, boolean(*func) (line_t *)); boolean P_BlockThingsIterator(int x, int y, boolean(*func) (mobj_t *)); #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 #define PT_EARLYOUT 4 extern divline_t trace; boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean(*trav) (intercept_t *)); void P_UnsetThingPosition(mobj_t * thing); void P_SetThingPosition(mobj_t * thing); mobj_t *P_RoughMonsterSearch(mobj_t * mo, int distance); // ***** P_MAP ***** extern boolean floatok; // if true, move would be ok if extern fixed_t tmfloorz, tmceilingz; // within tmfloorz - tmceilingz extern int tmfloorpic; extern mobj_t *BlockingMobj; extern line_t *ceilingline; boolean P_TestMobjLocation(mobj_t * mobj); boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y); mobj_t *P_CheckOnmobj(mobj_t * thing); void P_FakeZMovement(mobj_t * mo); boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y); boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y); void P_SlideMove(mobj_t * mo); void P_BounceWall(mobj_t * mo); boolean P_CheckSight(mobj_t * t1, mobj_t * t2); void P_UseLines(player_t * player); boolean P_UsePuzzleItem(player_t * player, int itemType); void PIT_ThrustSpike(mobj_t * actor); boolean P_ChangeSector(sector_t * sector, int crunch); extern mobj_t *PuffSpawned; // true if a puff was spawned extern mobj_t *linetarget; // who got hit (or NULL) fixed_t P_AimLineAttack(mobj_t * t1, angle_t angle, fixed_t distance); void P_LineAttack(mobj_t * t1, angle_t angle, fixed_t distance, fixed_t slope, int damage); void P_RadiusAttack(mobj_t * spot, mobj_t * source, int damage, int distance, boolean damageSource); // ***** P_SETUP ***** extern byte *rejectmatrix; // for fast sight rejection extern short *blockmaplump; // offsets in blockmap are from here extern short *blockmap; extern int bmapwidth, bmapheight; // in mapblocks extern fixed_t bmaporgx, bmaporgy; // origin of block map extern mobj_t **blocklinks; // for thing chains // ***** P_INTER ***** extern int clipmana[NUMMANA]; void P_SetMessage(player_t * player, char *message, boolean ultmsg); void P_SetYellowMessage(player_t * player, char *message, boolean ultmsg); void P_ClearMessage(player_t * player); void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher); void P_DamageMobj(mobj_t * target, mobj_t * inflictor, mobj_t * source, int damage); void P_FallingDamage(player_t * player); void P_PoisonPlayer(player_t * player, mobj_t * poisoner, int poison); void P_PoisonDamage(player_t * player, mobj_t * source, int damage, boolean playPainSound); boolean P_GiveMana(player_t * player, manatype_t mana, int count); boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo); boolean P_GiveArmor(player_t * player, armortype_t armortype, int amount); boolean P_GiveBody(player_t * player, int num); boolean P_GivePower(player_t * player, powertype_t power); boolean P_MorphPlayer(player_t * player); // ***** AM_MAP ***** boolean AM_Responder(event_t * ev); void AM_Ticker(void); void AM_Drawer(void); // ***** A_ACTION ***** boolean A_LocalQuake(byte * args, mobj_t * victim); void P_SpawnDirt(mobj_t * actor, fixed_t radius); void A_BridgeRemove(mobj_t * actor); // ***** SB_BAR ***** extern int SB_state; extern int ArtifactFlash; void SB_PaletteFlash(boolean forceChange); // ===== PO_MAN ===== typedef enum { PODOOR_NONE, PODOOR_SLIDE, PODOOR_SWING, } podoortype_t; typedef struct { thinker_t thinker; int polyobj; int speed; unsigned int dist; int angle; fixed_t xSpeed; // for sliding walls fixed_t ySpeed; } polyevent_t; typedef struct { thinker_t thinker; int polyobj; int speed; int dist; int totalDist; int direction; fixed_t xSpeed, ySpeed; int tics; int waitTics; podoortype_t type; boolean close; } polydoor_t; enum { PO_ANCHOR_TYPE = 3000, PO_SPAWN_TYPE, PO_SPAWNCRUSH_TYPE }; #define PO_LINE_START 1 // polyobj line start special #define PO_LINE_EXPLICIT 5 extern polyobj_t *polyobjs; // list of all poly-objects on the level extern int po_NumPolyobjs; void T_PolyDoor(polydoor_t * pd); void T_RotatePoly(polyevent_t * pe); boolean EV_RotatePoly(line_t * line, byte * args, int direction, boolean overRide); void T_MovePoly(polyevent_t * pe); boolean EV_MovePoly(line_t * line, byte * args, boolean timesEight, boolean overRide); boolean EV_OpenPolyDoor(line_t * line, byte * args, podoortype_t type); boolean PO_MovePolyobj(int num, int x, int y); boolean PO_RotatePolyobj(int num, angle_t angle); void PO_Init(int lump); boolean PO_Busy(int polyobj); #include "p_spec.h" #endif // __P_LOCAL__ chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_map.c000066400000000000000000002041311257432200600224440ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "m_random.h" #include "i_system.h" #include "m_bbox.h" #include "p_local.h" #include "s_sound.h" static void CheckForPushSpecial(line_t * line, int side, mobj_t * mobj); /* =============================================================================== NOTES: =============================================================================== */ /* =============================================================================== mobj_t NOTES mobj_ts are used to tell the refresh where to draw an image, tell the world simulation when objects are contacted, and tell the sound driver how to position a sound. The refresh uses the next and prev links to follow lists of things in sectors as they are being drawn. The sprite, frame, and angle elements determine which patch_t is used to draw the sprite if it is visible. The sprite and frame values are allmost allways set from state_t structures. The statescr.exe utility generates the states.h and states.c files that contain the sprite/frame numbers from the statescr.txt source file. The xyz origin point represents a point at the bottom middle of the sprite (between the feet of a biped). This is the default origin position for patch_ts grabbed with lumpy.exe. A walking creature will have its z equal to the floor it is standing on. The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t. The play simulation uses the blocklinks, x,y,z, radius, height to determine when mobj_ts are touching each other, touching lines in the map, or hit by trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has various bit flags used by the simulation. Every mobj_t is linked into a single sector based on it's origin coordinates. The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be found with subsector->sector. The sector links are only used by the rendering code, the play simulation does not care about them at all. Any mobj_t that needs to be acted upon be something else in the play world (block movement, be shot, etc) will also need to be linked into the blockmap. If the thing has the MF_NOBLOCK flag set, it will not use the block links. It can still interact with other things, but only as the instigator (missiles will run into other things, but nothing can run into a missile). Each block in the grid is 128*128 units, and knows about every line_t that it contains a piece of, and every interactable mobj_t that has it's origin contained. A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is linked into a blockmap block or has the MF_NOBLOCKMAP flag set. Links should only be modified by the P_[Un]SetThingPosition () functions. Do not change the MF_NO? flags while a thing is valid. =============================================================================== */ fixed_t tmbbox[4]; mobj_t *tmthing; mobj_t *tsthing; int tmflags; fixed_t tmx, tmy; boolean floatok; // if true, move would be ok if // within tmfloorz - tmceilingz fixed_t tmfloorz, tmceilingz, tmdropoffz; int tmfloorpic; // keep track of the line that lowers the ceiling, so missiles don't explode // against sky hack walls line_t *ceilingline; // keep track of special lines as they are hit, but don't process them // until the move is proven valid #define MAXSPECIALCROSS 8 line_t *spechit[MAXSPECIALCROSS]; int numspechit; mobj_t *onmobj; // generic global onmobj...used for landing on pods/players mobj_t *BlockingMobj; /* =============================================================================== TELEPORT MOVE =============================================================================== */ /* ================== = = PIT_StompThing = ================== */ boolean PIT_StompThing(mobj_t * thing) { fixed_t blockdist; if (!(thing->flags & MF_SHOOTABLE)) return true; blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) return true; // didn't hit it if (thing == tmthing) return true; // don't clip against self if (!(tmthing->flags2 & MF2_TELESTOMP)) { // Not allowed to stomp things return (false); } P_DamageMobj(thing, tmthing, tmthing, 10000); return true; } /* =================== = = P_TeleportMove = =================== */ boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y) { int xl, xh, yl, yh, bx, by; subsector_t *newsubsec; // // kill anything occupying the position // tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector(x, y); ceilingline = NULL; // // the base floor / ceiling is from the subsector that contains the // point. Any contacted lines the step closer together will adjust them // tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; tmfloorpic = newsubsec->sector->floorpic; validcount++; numspechit = 0; // // stomp on any things contacted // xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockThingsIterator(bx, by, PIT_StompThing)) return false; // // the move is ok, so link the thing into its new position // P_UnsetThingPosition(thing); thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; P_SetThingPosition(thing); return true; } boolean PIT_ThrustStompThing(mobj_t * thing) { fixed_t blockdist; if (!(thing->flags & MF_SHOOTABLE)) return true; blockdist = thing->radius + tsthing->radius; if (abs(thing->x - tsthing->x) >= blockdist || abs(thing->y - tsthing->y) >= blockdist || (thing->z > tsthing->z + tsthing->height)) return true; // didn't hit it if (thing == tsthing) return true; // don't clip against self P_DamageMobj(thing, tsthing, tsthing, 10001); tsthing->args[1] = 1; // Mark thrust thing as bloody return true; } void PIT_ThrustSpike(mobj_t * actor) { int xl, xh, yl, yh, bx, by; int x0, x2, y0, y2; tsthing = actor; x0 = actor->x - actor->info->radius; x2 = actor->x + actor->info->radius; y0 = actor->y - actor->info->radius; y2 = actor->y + actor->info->radius; xl = (x0 - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; xh = (x2 - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; yl = (y0 - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; yh = (y2 - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; // stomp on any things contacted for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) P_BlockThingsIterator(bx, by, PIT_ThrustStompThing); } /* =============================================================================== MOVEMENT ITERATOR FUNCTIONS =============================================================================== */ /* ================== = = PIT_CheckLine = = Adjusts tmfloorz and tmceilingz as lines are contacted ================== */ boolean PIT_CheckLine(line_t * ld) { if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { return (true); } if (P_BoxOnLineSide(tmbbox, ld) != -1) { return (true); } // a line has been hit /* = = The moving thing's destination position will cross the given line. = If this should not be allowed, return false. = If the line is special, keep track of it to process later if the move = is proven ok. NOTE: specials are NOT sorted by order, so two special lines = that are only 8 pixels apart could be crossed in either order. */ if (!ld->backsector) { // One sided line if (tmthing->flags2 & MF2_BLASTED) { P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5); } CheckForPushSpecial(ld, 0, tmthing); return (false); } if (!(tmthing->flags & MF_MISSILE)) { if (ld->flags & ML_BLOCKING) { // Explicitly blocking everything if (tmthing->flags2 & MF2_BLASTED) { P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5); } CheckForPushSpecial(ld, 0, tmthing); return (false); } if (!tmthing->player && ld->flags & ML_BLOCKMONSTERS) { // Block monsters only if (tmthing->flags2 & MF2_BLASTED) { P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5); } return (false); } } P_LineOpening(ld); // set openrange, opentop, openbottom // adjust floor / ceiling heights if (opentop < tmceilingz) { tmceilingz = opentop; ceilingline = ld; } if (openbottom > tmfloorz) { tmfloorz = openbottom; } if (lowfloor < tmdropoffz) { tmdropoffz = lowfloor; } if (ld->special) { // Contacted a special line, add it to the list spechit[numspechit] = ld; numspechit++; } return (true); } //--------------------------------------------------------------------------- // // FUNC PIT_CheckThing // //--------------------------------------------------------------------------- boolean PIT_CheckThing(mobj_t * thing) { fixed_t blockdist; boolean solid; int damage; if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE))) { // Can't hit thing return (true); } blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) { // Didn't hit thing return (true); } if (thing == tmthing) { // Don't clip against self return (true); } BlockingMobj = thing; if (tmthing->flags2 & MF2_PASSMOBJ) { // check if a mobj passed over/under another object if (tmthing->type == MT_BISHOP && thing->type == MT_BISHOP) { // don't let bishops fly over other bishops return false; } if (tmthing->z >= thing->z + thing->height && !(thing->flags & MF_SPECIAL)) { return (true); } else if (tmthing->z + tmthing->height < thing->z && !(thing->flags & MF_SPECIAL)) { // under thing return (true); } } // Check for skulls slamming into things if (tmthing->flags & MF_SKULLFLY) { if (tmthing->type == MT_MINOTAUR) { // Slamming minotaurs shouldn't move non-creatures if (!(thing->flags & MF_COUNTKILL)) { return (false); } } else if (tmthing->type == MT_HOLY_FX) { if (thing->flags & MF_SHOOTABLE && thing != tmthing->target) { if (netgame && !deathmatch && thing->player) { // don't attack other co-op players return true; } if (thing->flags2 & MF2_REFLECTIVE && (thing->player || thing->flags2 & MF2_BOSS)) { tmthing->special1.m = tmthing->target; tmthing->target = thing; return true; } if (thing->flags & MF_COUNTKILL || thing->player) { tmthing->special1.m = thing; } if (P_Random() < 96) { damage = 12; if (thing->player || thing->flags2 & MF2_BOSS) { damage = 3; // ghost burns out faster when attacking players/bosses tmthing->health -= 6; } P_DamageMobj(thing, tmthing, tmthing->target, damage); if (P_Random() < 128) { P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z, MT_HOLY_PUFF); S_StartSound(tmthing, SFX_SPIRIT_ATTACK); if (thing->flags & MF_COUNTKILL && P_Random() < 128 && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT)) { if ((thing->type == MT_CENTAUR) || (thing->type == MT_CENTAURLEADER) || (thing->type == MT_ETTIN)) { S_StartSound(thing, SFX_PUPPYBEAT); } } } } if (thing->health <= 0) { tmthing->special1.i = 0; } } return true; } damage = ((P_Random() % 8) + 1) * tmthing->damage; P_DamageMobj(thing, tmthing, tmthing, damage); tmthing->flags &= ~MF_SKULLFLY; tmthing->momx = tmthing->momy = tmthing->momz = 0; P_SetMobjState(tmthing, tmthing->info->seestate); return (false); } // Check for blasted thing running into another if (tmthing->flags2 & MF2_BLASTED && thing->flags & MF_SHOOTABLE) { if (!(thing->flags2 & MF2_BOSS) && (thing->flags & MF_COUNTKILL)) { thing->momx += tmthing->momx; thing->momy += tmthing->momy; if ((thing->momx + thing->momy) > 3 * FRACUNIT) { damage = (tmthing->info->mass / 100) + 1; P_DamageMobj(thing, tmthing, tmthing, damage); damage = (thing->info->mass / 100) + 1; P_DamageMobj(tmthing, thing, thing, damage >> 2); } return (false); } } // Check for missile if (tmthing->flags & MF_MISSILE) { // Check for a non-shootable mobj if (thing->flags2 & MF2_NONSHOOTABLE) { return true; } // Check if it went over / under if (tmthing->z > thing->z + thing->height) { // Over thing return (true); } if (tmthing->z + tmthing->height < thing->z) { // Under thing return (true); } if (tmthing->flags2 & MF2_FLOORBOUNCE) { if (tmthing->target == thing || !(thing->flags & MF_SOLID)) { return true; } else { return false; } } if (tmthing->type == MT_LIGHTNING_FLOOR || tmthing->type == MT_LIGHTNING_CEILING) { if (thing->flags & MF_SHOOTABLE && thing != tmthing->target) { if (thing->info->mass != INT_MAX) { thing->momx += tmthing->momx >> 4; thing->momy += tmthing->momy >> 4; } if ((!thing->player && !(thing->flags2 & MF2_BOSS)) || !(leveltime & 1)) { if (thing->type == MT_CENTAUR || thing->type == MT_CENTAURLEADER) { // Lightning does more damage to centaurs P_DamageMobj(thing, tmthing, tmthing->target, 9); } else { P_DamageMobj(thing, tmthing, tmthing->target, 3); } if (!(S_GetSoundPlayingInfo(tmthing, SFX_MAGE_LIGHTNING_ZAP))) { S_StartSound(tmthing, SFX_MAGE_LIGHTNING_ZAP); } if (thing->flags & MF_COUNTKILL && P_Random() < 64 && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT)) { if ((thing->type == MT_CENTAUR) || (thing->type == MT_CENTAURLEADER) || (thing->type == MT_ETTIN)) { S_StartSound(thing, SFX_PUPPYBEAT); } } } tmthing->health--; if (tmthing->health <= 0 || thing->health <= 0) { return false; } if (tmthing->type == MT_LIGHTNING_FLOOR) { if (tmthing->special2.m && !tmthing->special2.m->special1.m) { tmthing->special2.m->special1.m = thing; } } else if (!tmthing->special1.m) { tmthing->special1.m = thing; } } return true; // lightning zaps through all sprites } else if (tmthing->type == MT_LIGHTNING_ZAP) { mobj_t *lmo; if (thing->flags & MF_SHOOTABLE && thing != tmthing->target) { lmo = tmthing->special2.m; if (lmo) { if (lmo->type == MT_LIGHTNING_FLOOR) { if (lmo->special2.m && !lmo->special2.m->special1.m) { lmo->special2.m->special1.m = thing; } } else if (!lmo->special1.m) { lmo->special1.m = thing; } if (!(leveltime & 3)) { lmo->health--; } } } } else if (tmthing->type == MT_MSTAFF_FX2 && thing != tmthing->target) { if (!thing->player && !(thing->flags2 & MF2_BOSS)) { switch (thing->type) { case MT_FIGHTER_BOSS: // these not flagged boss case MT_CLERIC_BOSS: // so they can be blasted case MT_MAGE_BOSS: break; default: P_DamageMobj(thing, tmthing, tmthing->target, 10); return true; break; } } } if (tmthing->target && tmthing->target->type == thing->type) { // Don't hit same species as originator if (thing == tmthing->target) { // Don't missile self return (true); } if (!thing->player) { // Hit same species as originator, explode, no damage return (false); } } if (!(thing->flags & MF_SHOOTABLE)) { // Didn't do any damage return !(thing->flags & MF_SOLID); } if (tmthing->flags2 & MF2_RIP) { if (!(thing->flags & MF_NOBLOOD) && !(thing->flags2 & MF2_REFLECTIVE) && !(thing->flags2 & MF2_INVULNERABLE)) { // Ok to spawn some blood P_RipperBlood(tmthing); } //S_StartSound(tmthing, sfx_ripslop); damage = ((P_Random() & 3) + 2) * tmthing->damage; P_DamageMobj(thing, tmthing, tmthing->target, damage); if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH)) { // Push thing thing->momx += tmthing->momx >> 2; thing->momy += tmthing->momy >> 2; } numspechit = 0; return (true); } // Do damage damage = ((P_Random() % 8) + 1) * tmthing->damage; if (damage) { if (!(thing->flags & MF_NOBLOOD) && !(thing->flags2 & MF2_REFLECTIVE) && !(thing->flags2 & MF2_INVULNERABLE) && !(tmthing->type == MT_TELOTHER_FX1) && !(tmthing->type == MT_TELOTHER_FX2) && !(tmthing->type == MT_TELOTHER_FX3) && !(tmthing->type == MT_TELOTHER_FX4) && !(tmthing->type == MT_TELOTHER_FX5) && (P_Random() < 192)) { P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing); } P_DamageMobj(thing, tmthing, tmthing->target, damage); } return (false); } if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH)) { // Push thing thing->momx += tmthing->momx >> 2; thing->momy += tmthing->momy >> 2; } // Check for special thing if (thing->flags & MF_SPECIAL) { solid = (thing->flags & MF_SOLID) != 0; if (tmflags & MF_PICKUP) { // Can be picked up by tmthing P_TouchSpecialThing(thing, tmthing); // Can remove thing } return (!solid); } return (!(thing->flags & MF_SOLID)); } //--------------------------------------------------------------------------- // // PIT_CheckOnmobjZ // //--------------------------------------------------------------------------- boolean PIT_CheckOnmobjZ(mobj_t * thing) { fixed_t blockdist; if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE))) { // Can't hit thing return (true); } blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) { // Didn't hit thing return (true); } if (thing == tmthing) { // Don't clip against self return (true); } if (tmthing->z > thing->z + thing->height) { return (true); } else if (tmthing->z + tmthing->height < thing->z) { // under thing return (true); } if (thing->flags & MF_SOLID) { onmobj = thing; } return (!(thing->flags & MF_SOLID)); } /* =============================================================================== MOVEMENT CLIPPING =============================================================================== */ //---------------------------------------------------------------------------- // // FUNC P_TestMobjLocation // // Returns true if the mobj is not blocked by anything at its current // location, otherwise returns false. // //---------------------------------------------------------------------------- boolean P_TestMobjLocation(mobj_t * mobj) { int flags; flags = mobj->flags; mobj->flags &= ~MF_PICKUP; if (P_CheckPosition(mobj, mobj->x, mobj->y)) { // XY is ok, now check Z mobj->flags = flags; if ((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz)) { // Bad Z return (false); } return (true); } mobj->flags = flags; return (false); } /* ================== = = P_CheckPosition = = This is purely informative, nothing is modified (except things picked up) in: a mobj_t (can be valid or invalid) a position to be checked (doesn't need to be related to the mobj_t->x,y) during: special things are touched if MF_PICKUP early out on solid lines? out: newsubsec floorz ceilingz tmdropoffz = the lowest point contacted (monsters won't move to a dropoff) speciallines[] numspeciallines mobj_t *BlockingMobj = pointer to thing that blocked position (NULL if not blocked, or blocked by a line). ================== */ boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y) { int xl, xh, yl, yh, bx, by; subsector_t *newsubsec; tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector(x, y); ceilingline = NULL; // // the base floor / ceiling is from the subsector that contains the // point. Any contacted lines the step closer together will adjust them // tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; tmfloorpic = newsubsec->sector->floorpic; validcount++; numspechit = 0; if (tmflags & MF_NOCLIP && !(tmflags & MF_SKULLFLY)) { return true; } // // check things first, possibly picking things up // the bounding box is extended by MAXRADIUS because mobj_ts are grouped // into mapblocks based on their origin point, and can overlap into adjacent // blocks by up to MAXRADIUS units // xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; BlockingMobj = NULL; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockThingsIterator(bx, by, PIT_CheckThing)) return false; // // check lines // if (tmflags & MF_NOCLIP) { return true; } BlockingMobj = NULL; xl = (tmbbox[BOXLEFT] - bmaporgx) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy) >> MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockLinesIterator(bx, by, PIT_CheckLine)) return false; return true; } //============================================================================= // // P_CheckOnmobj(mobj_t *thing) // // Checks if the new Z position is legal //============================================================================= mobj_t *P_CheckOnmobj(mobj_t * thing) { int xl, xh, yl, yh, bx, by; subsector_t *newsubsec; fixed_t x; fixed_t y; mobj_t oldmo; x = thing->x; y = thing->y; tmthing = thing; tmflags = thing->flags; oldmo = *thing; // save the old mobj before the fake zmovement P_FakeZMovement(tmthing); tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector(x, y); ceilingline = NULL; // // the base floor / ceiling is from the subsector that contains the // point. Any contacted lines the step closer together will adjust them // tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; tmfloorpic = newsubsec->sector->floorpic; validcount++; numspechit = 0; if (tmflags & MF_NOCLIP) return NULL; // // check things first, possibly picking things up // the bounding box is extended by MAXRADIUS because mobj_ts are grouped // into mapblocks based on their origin point, and can overlap into adjacent // blocks by up to MAXRADIUS units // xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockThingsIterator(bx, by, PIT_CheckOnmobjZ)) { *tmthing = oldmo; return onmobj; } *tmthing = oldmo; return NULL; } //============================================================================= // // P_FakeZMovement // // Fake the zmovement so that we can check if a move is legal //============================================================================= void P_FakeZMovement(mobj_t * mo) { int dist; int delta; // // adjust height // mo->z += mo->momz; if (mo->flags & MF_FLOAT && mo->target) { // float down towards target if too close if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT)) { dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y); delta = (mo->target->z + (mo->height >> 1)) - mo->z; if (delta < 0 && dist < -(delta * 3)) mo->z -= FLOATSPEED; else if (delta > 0 && dist < (delta * 3)) mo->z += FLOATSPEED; } } if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz) && leveltime & 2) { mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK]; } // // clip movement // if (mo->z <= mo->floorz) { // Hit the floor mo->z = mo->floorz; if (mo->momz < 0) { mo->momz = 0; } if (mo->flags & MF_SKULLFLY) { // The skull slammed into something mo->momz = -mo->momz; } if (mo->info->crashstate && (mo->flags & MF_CORPSE)) { return; } } else if (mo->flags2 & MF2_LOGRAV) { if (mo->momz == 0) mo->momz = -(GRAVITY >> 3) * 2; else mo->momz -= GRAVITY >> 3; } else if (!(mo->flags & MF_NOGRAVITY)) { if (mo->momz == 0) mo->momz = -GRAVITY * 2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // hit the ceiling if (mo->momz > 0) mo->momz = 0; mo->z = mo->ceilingz - mo->height; if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; } } } //=========================================================================== // // CheckForPushSpecial // //=========================================================================== static void CheckForPushSpecial(line_t * line, int side, mobj_t * mobj) { if (line->special) { if (mobj->flags2 & MF2_PUSHWALL) { P_ActivateLine(line, mobj, side, SPAC_PUSH); } else if (mobj->flags2 & MF2_IMPACT) { P_ActivateLine(line, mobj, side, SPAC_IMPACT); } } } /* =================== = = P_TryMove = = Attempt to move to a new position, crossing special lines unless MF_TELEPORT = is set = =================== */ boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y) { fixed_t oldx, oldy; int side, oldside; line_t *ld; floatok = false; if (!P_CheckPosition(thing, x, y)) { // Solid wall or thing if (!BlockingMobj || BlockingMobj->player || !thing->player) { goto pushline; } else if (BlockingMobj->z + BlockingMobj->height - thing->z > 24 * FRACUNIT || (BlockingMobj->subsector->sector->ceilingheight - (BlockingMobj->z + BlockingMobj->height) < thing->height) || (tmceilingz - (BlockingMobj->z + BlockingMobj->height) < thing->height)) { goto pushline; } } if (!(thing->flags & MF_NOCLIP)) { if (tmceilingz - tmfloorz < thing->height) { // Doesn't fit goto pushline; } floatok = true; if (!(thing->flags & MF_TELEPORT) && tmceilingz - thing->z < thing->height && thing->type != MT_LIGHTNING_CEILING && !(thing->flags2 & MF2_FLY)) { // mobj must lower itself to fit goto pushline; } if (thing->flags2 & MF2_FLY) { if (thing->z + thing->height > tmceilingz) { thing->momz = -8 * FRACUNIT; goto pushline; } else if (thing->z < tmfloorz && tmfloorz - tmdropoffz > 24 * FRACUNIT) { thing->momz = 8 * FRACUNIT; goto pushline; } } if (!(thing->flags & MF_TELEPORT) // The Minotaur floor fire (MT_MNTRFX2) can step up any amount && thing->type != MT_MNTRFX2 && thing->type != MT_LIGHTNING_FLOOR && tmfloorz - thing->z > 24 * FRACUNIT) { goto pushline; } if (!(thing->flags & (MF_DROPOFF | MF_FLOAT)) && (tmfloorz - tmdropoffz > 24 * FRACUNIT) && !(thing->flags2 & MF2_BLASTED)) { // Can't move over a dropoff unless it's been blasted return (false); } if (thing->flags2 & MF2_CANTLEAVEFLOORPIC && (tmfloorpic != thing->subsector->sector->floorpic || tmfloorz - thing->z != 0)) { // must stay within a sector of a certain floor type return false; } } // // the move is ok, so link the thing into its new position // P_UnsetThingPosition(thing); oldx = thing->x; oldy = thing->y; thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->floorpic = tmfloorpic; thing->x = x; thing->y = y; P_SetThingPosition(thing); if (thing->flags2 & MF2_FLOORCLIP) { if (thing->z == thing->subsector->sector->floorheight && P_GetThingFloorType(thing) >= FLOOR_LIQUID) { thing->floorclip = 10 * FRACUNIT; } else { thing->floorclip = 0; } } // // if any special lines were hit, do the effect // if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP))) { while (numspechit > 0) { numspechit--; // see if the line was crossed ld = spechit[numspechit]; side = P_PointOnLineSide(thing->x, thing->y, ld); oldside = P_PointOnLineSide(oldx, oldy, ld); if (side != oldside) { if (ld->special) { if (thing->player) { P_ActivateLine(ld, thing, oldside, SPAC_CROSS); } else if (thing->flags2 & MF2_MCROSS) { P_ActivateLine(ld, thing, oldside, SPAC_MCROSS); } else if (thing->flags2 & MF2_PCROSS) { P_ActivateLine(ld, thing, oldside, SPAC_PCROSS); } } } } } return true; pushline: if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP))) { int numSpecHitTemp; if (tmthing->flags2 & MF2_BLASTED) { P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5); } numSpecHitTemp = numspechit; while (numSpecHitTemp > 0) { numSpecHitTemp--; // see if the line was crossed ld = spechit[numSpecHitTemp]; side = P_PointOnLineSide(thing->x, thing->y, ld); CheckForPushSpecial(ld, side, thing); } } return false; } /* ================== = = P_ThingHeightClip = = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz, = anf possibly thing->z = = This is called for all nearby monsters whenever a sector changes height = = If the thing doesn't fit, the z will be set to the lowest value and = false will be returned ================== */ boolean P_ThingHeightClip(mobj_t * thing) { boolean onfloor; onfloor = (thing->z == thing->floorz); P_CheckPosition(thing, thing->x, thing->y); // what about stranding a monster partially off an edge? thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->floorpic = tmfloorpic; if (onfloor) { // walking monsters rise and fall with the floor if ((thing->z - thing->floorz < 9 * FRACUNIT) || (thing->flags & MF_NOGRAVITY)) { thing->z = thing->floorz; } } else { // don't adjust a floating monster unless forced to if (thing->z + thing->height > thing->ceilingz) thing->z = thing->ceilingz - thing->height; } if (thing->ceilingz - thing->floorz < thing->height) return false; return true; } /* ============================================================================== SLIDE MOVE Allows the player to slide along any angled walls ============================================================================== */ fixed_t bestslidefrac, secondslidefrac; line_t *bestslideline, *secondslideline; mobj_t *slidemo; fixed_t tmxmove, tmymove; /* ================== = = P_HitSlideLine = = Adjusts the xmove / ymove so that the next move will slide along the wall ================== */ void P_HitSlideLine(line_t * ld) { int side; angle_t lineangle, moveangle, deltaangle; fixed_t movelen, newlen; if (ld->slopetype == ST_HORIZONTAL) { tmymove = 0; return; } if (ld->slopetype == ST_VERTICAL) { tmxmove = 0; return; } side = P_PointOnLineSide(slidemo->x, slidemo->y, ld); lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy); if (side == 1) lineangle += ANG180; moveangle = R_PointToAngle2(0, 0, tmxmove, tmymove); deltaangle = moveangle - lineangle; if (deltaangle > ANG180) deltaangle += ANG180; // I_Error ("SlideLine: ang>ANG180"); lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; movelen = P_AproxDistance(tmxmove, tmymove); newlen = FixedMul(movelen, finecosine[deltaangle]); tmxmove = FixedMul(newlen, finecosine[lineangle]); tmymove = FixedMul(newlen, finesine[lineangle]); } /* ============== = = PTR_SlideTraverse = ============== */ boolean PTR_SlideTraverse(intercept_t * in) { line_t *li; if (!in->isaline) I_Error("PTR_SlideTraverse: not a line?"); li = in->d.line; if (!(li->flags & ML_TWOSIDED)) { if (P_PointOnLineSide(slidemo->x, slidemo->y, li)) return true; // don't hit the back side goto isblocking; } P_LineOpening(li); // set openrange, opentop, openbottom if (openrange < slidemo->height) goto isblocking; // doesn't fit if (opentop - slidemo->z < slidemo->height) goto isblocking; // mobj is too high if (openbottom - slidemo->z > 24 * FRACUNIT) goto isblocking; // too big a step up return true; // this line doesn't block movement // the line does block movement, see if it is closer than best so far isblocking: if (in->frac < bestslidefrac) { secondslidefrac = bestslidefrac; secondslideline = bestslideline; bestslidefrac = in->frac; bestslideline = li; } return false; // stop } /* ================== = = P_SlideMove = = The momx / momy move is bad, so try to slide along a wall = = Find the first line hit, move flush to it, and slide along it = = This is a kludgy mess. ================== */ void P_SlideMove(mobj_t * mo) { fixed_t leadx, leady; fixed_t trailx, traily; fixed_t newx, newy; int hitcount; slidemo = mo; hitcount = 0; retry: if (++hitcount == 3) goto stairstep; // don't loop forever // // trace along the three leading corners // if (mo->momx > 0) { leadx = mo->x + mo->radius; trailx = mo->x - mo->radius; } else { leadx = mo->x - mo->radius; trailx = mo->x + mo->radius; } if (mo->momy > 0) { leady = mo->y + mo->radius; traily = mo->y - mo->radius; } else { leady = mo->y - mo->radius; traily = mo->y + mo->radius; } bestslidefrac = FRACUNIT + 1; P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy, PT_ADDLINES, PTR_SlideTraverse); P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy, PT_ADDLINES, PTR_SlideTraverse); P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy, PT_ADDLINES, PTR_SlideTraverse); // // move up to the wall // if (bestslidefrac == FRACUNIT + 1) { // the move must have hit the middle, so stairstep stairstep: if (!P_TryMove(mo, mo->x, mo->y + mo->momy)) { P_TryMove(mo, mo->x + mo->momx, mo->y); } return; } bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit if (bestslidefrac > 0) { newx = FixedMul(mo->momx, bestslidefrac); newy = FixedMul(mo->momy, bestslidefrac); if (!P_TryMove(mo, mo->x + newx, mo->y + newy)) goto stairstep; } // // now continue along the wall // bestslidefrac = FRACUNIT - (bestslidefrac + 0x800); // remainder if (bestslidefrac > FRACUNIT) bestslidefrac = FRACUNIT; if (bestslidefrac <= 0) return; tmxmove = FixedMul(mo->momx, bestslidefrac); tmymove = FixedMul(mo->momy, bestslidefrac); P_HitSlideLine(bestslideline); // clip the moves mo->momx = tmxmove; mo->momy = tmymove; if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove)) { goto retry; } } //============================================================================ // // PTR_BounceTraverse // //============================================================================ boolean PTR_BounceTraverse(intercept_t * in) { line_t *li; if (!in->isaline) I_Error("PTR_BounceTraverse: not a line?"); li = in->d.line; if (!(li->flags & ML_TWOSIDED)) { if (P_PointOnLineSide(slidemo->x, slidemo->y, li)) return true; // don't hit the back side goto bounceblocking; } P_LineOpening(li); // set openrange, opentop, openbottom if (openrange < slidemo->height) goto bounceblocking; // doesn't fit if (opentop - slidemo->z < slidemo->height) goto bounceblocking; // mobj is too high return true; // this line doesn't block movement // the line does block movement, see if it is closer than best so far bounceblocking: if (in->frac < bestslidefrac) { secondslidefrac = bestslidefrac; secondslideline = bestslideline; bestslidefrac = in->frac; bestslideline = li; } return false; // stop } //============================================================================ // // P_BounceWall // //============================================================================ void P_BounceWall(mobj_t * mo) { fixed_t leadx, leady; int side; angle_t lineangle, moveangle, deltaangle; fixed_t movelen; slidemo = mo; // // trace along the three leading corners // if (mo->momx > 0) { leadx = mo->x + mo->radius; } else { leadx = mo->x - mo->radius; } if (mo->momy > 0) { leady = mo->y + mo->radius; } else { leady = mo->y - mo->radius; } bestslidefrac = FRACUNIT + 1; P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy, PT_ADDLINES, PTR_BounceTraverse); side = P_PointOnLineSide(mo->x, mo->y, bestslideline); lineangle = R_PointToAngle2(0, 0, bestslideline->dx, bestslideline->dy); if (side == 1) lineangle += ANG180; moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); deltaangle = (2 * lineangle) - moveangle; // if (deltaangle > ANG180) // deltaangle += ANG180; // I_Error ("SlideLine: ang>ANG180"); lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; movelen = P_AproxDistance(mo->momx, mo->momy); movelen = FixedMul(movelen, 0.75 * FRACUNIT); // friction if (movelen < FRACUNIT) movelen = 2 * FRACUNIT; mo->momx = FixedMul(movelen, finecosine[deltaangle]); mo->momy = FixedMul(movelen, finesine[deltaangle]); } /* ============================================================================== P_LineAttack ============================================================================== */ mobj_t *PuffSpawned; mobj_t *linetarget; // who got hit (or NULL) mobj_t *shootthing; fixed_t shootz; // height if not aiming up or down // ???: use slope for monsters? int la_damage; fixed_t attackrange; fixed_t aimslope; extern fixed_t topslope, bottomslope; // slopes to top and bottom of target /* =============================================================================== = = PTR_AimTraverse = = Sets linetaget and aimslope when a target is aimed at =============================================================================== */ boolean PTR_AimTraverse(intercept_t * in) { line_t *li; mobj_t *th; fixed_t slope, thingtopslope, thingbottomslope; fixed_t dist; if (in->isaline) { li = in->d.line; if (!(li->flags & ML_TWOSIDED)) return false; // stop // // crosses a two sided line // a two sided line will restrict the possible target ranges P_LineOpening(li); if (openbottom >= opentop) return false; // stop dist = FixedMul(attackrange, in->frac); if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv(openbottom - shootz, dist); if (slope > bottomslope) bottomslope = slope; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv(opentop - shootz, dist); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop return true; // shot continues } // // shoot a thing // th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags & MF_SHOOTABLE)) { // corpse or something return true; } if (th->player && netgame && !deathmatch) { // don't aim at fellow co-op players return true; } // check angles to see if the thing can be aimed at dist = FixedMul(attackrange, in->frac); thingtopslope = FixedDiv(th->z + th->height - shootz, dist); if (thingtopslope < bottomslope) return true; // shot over the thing thingbottomslope = FixedDiv(th->z - shootz, dist); if (thingbottomslope > topslope) return true; // shot under the thing // // this thing can be hit! // if (thingtopslope > topslope) thingtopslope = topslope; if (thingbottomslope < bottomslope) thingbottomslope = bottomslope; aimslope = (thingtopslope + thingbottomslope) / 2; linetarget = th; return false; // don't go any farther } /* ============================================================================== = = PTR_ShootTraverse = ============================================================================== */ boolean PTR_ShootTraverse(intercept_t * in) { fixed_t x, y, z; fixed_t frac; line_t *li; mobj_t *th; fixed_t slope; fixed_t dist; fixed_t thingtopslope, thingbottomslope; extern mobj_t LavaInflictor; if (in->isaline) { li = in->d.line; if (li->special) { P_ActivateLine(li, shootthing, 0, SPAC_IMPACT); // P_ShootSpecialLine (shootthing, li); } if (!(li->flags & ML_TWOSIDED)) goto hitline; // // crosses a two sided line // P_LineOpening(li); dist = FixedMul(attackrange, in->frac); if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv(openbottom - shootz, dist); if (slope > aimslope) goto hitline; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv(opentop - shootz, dist); if (slope < aimslope) goto hitline; } return true; // shot continues // // hit line // hitline: // position a bit closer frac = in->frac - FixedDiv(4 * FRACUNIT, attackrange); x = trace.x + FixedMul(trace.dx, frac); y = trace.y + FixedMul(trace.dy, frac); z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange)); if (li->frontsector->ceilingpic == skyflatnum) { if (z > li->frontsector->ceilingheight) return false; // don't shoot the sky! if (li->backsector && li->backsector->ceilingpic == skyflatnum) return false; // it's a sky hack wall } P_SpawnPuff(x, y, z); return false; // don't go any farther } // // shoot a thing // th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags & MF_SHOOTABLE)) return true; // corpse or something // // check for physical attacks on a ghost // /* FIX: Impliment Heretic 2 weapons here if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff) { return(true); } */ // check angles to see if the thing can be aimed at dist = FixedMul(attackrange, in->frac); thingtopslope = FixedDiv(th->z + th->height - shootz, dist); if (thingtopslope < aimslope) return true; // shot over the thing thingbottomslope = FixedDiv(th->z - shootz, dist); if (thingbottomslope > aimslope) return true; // shot under the thing // // hit thing // // position a bit closer frac = in->frac - FixedDiv(10 * FRACUNIT, attackrange); x = trace.x + FixedMul(trace.dx, frac); y = trace.y + FixedMul(trace.dy, frac); z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange)); P_SpawnPuff(x, y, z); if (la_damage) { if (!(in->d.thing->flags & MF_NOBLOOD) && !(in->d.thing->flags2 & MF2_INVULNERABLE)) { if (PuffType == MT_AXEPUFF || PuffType == MT_AXEPUFF_GLOW) { P_BloodSplatter2(x, y, z, in->d.thing); } if (P_Random() < 192) { P_BloodSplatter(x, y, z, in->d.thing); } } if (PuffType == MT_FLAMEPUFF2) { // Cleric FlameStrike does fire damage P_DamageMobj(th, &LavaInflictor, shootthing, la_damage); } else { P_DamageMobj(th, shootthing, shootthing, la_damage); } } return (false); // don't go any farther } /* ================= = = P_AimLineAttack = ================= */ fixed_t P_AimLineAttack(mobj_t * t1, angle_t angle, fixed_t distance) { fixed_t x2, y2; angle >>= ANGLETOFINESHIFT; shootthing = t1; x2 = t1->x + (distance >> FRACBITS) * finecosine[angle]; y2 = t1->y + (distance >> FRACBITS) * finesine[angle]; shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT; topslope = 100 * FRACUNIT / 160; // can't shoot outside view angles bottomslope = -100 * FRACUNIT / 160; attackrange = distance; linetarget = NULL; P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS, PTR_AimTraverse); if (linetarget) return aimslope; return 0; } /* ================= = = P_LineAttack = = if damage == 0, it is just a test trace that will leave linetarget set = ================= */ void P_LineAttack(mobj_t * t1, angle_t angle, fixed_t distance, fixed_t slope, int damage) { fixed_t x2, y2; angle >>= ANGLETOFINESHIFT; shootthing = t1; la_damage = damage; x2 = t1->x + (distance >> FRACBITS) * finecosine[angle]; y2 = t1->y + (distance >> FRACBITS) * finesine[angle]; shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT; shootz -= t1->floorclip; attackrange = distance; aimslope = slope; if (P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS, PTR_ShootTraverse)) { switch (PuffType) { case MT_PUNCHPUFF: S_StartSound(t1, SFX_FIGHTER_PUNCH_MISS); break; case MT_HAMMERPUFF: case MT_AXEPUFF: case MT_AXEPUFF_GLOW: S_StartSound(t1, SFX_FIGHTER_HAMMER_MISS); break; case MT_FLAMEPUFF: P_SpawnPuff(x2, y2, shootz + FixedMul(slope, distance)); break; default: break; } } } /* ============================================================================== USE LINES ============================================================================== */ mobj_t *usething; boolean PTR_UseTraverse(intercept_t * in) { int sound; fixed_t pheight; if (!in->d.line->special) { P_LineOpening(in->d.line); if (openrange <= 0) { if (usething->player) { switch (usething->player->class) { case PCLASS_FIGHTER: sound = SFX_PLAYER_FIGHTER_FAILED_USE; break; case PCLASS_CLERIC: sound = SFX_PLAYER_CLERIC_FAILED_USE; break; case PCLASS_MAGE: sound = SFX_PLAYER_MAGE_FAILED_USE; break; case PCLASS_PIG: sound = SFX_PIG_ACTIVE1; break; default: sound = SFX_NONE; break; } S_StartSound(usething, sound); } return false; // can't use through a wall } if (usething->player) { pheight = usething->z + (usething->height / 2); if ((opentop < pheight) || (openbottom > pheight)) { switch (usething->player->class) { case PCLASS_FIGHTER: sound = SFX_PLAYER_FIGHTER_FAILED_USE; break; case PCLASS_CLERIC: sound = SFX_PLAYER_CLERIC_FAILED_USE; break; case PCLASS_MAGE: sound = SFX_PLAYER_MAGE_FAILED_USE; break; case PCLASS_PIG: sound = SFX_PIG_ACTIVE1; break; default: sound = SFX_NONE; break; } S_StartSound(usething, sound); } } return true; // not a special line, but keep checking } if (P_PointOnLineSide(usething->x, usething->y, in->d.line) == 1) return false; // don't use back sides // P_UseSpecialLine (usething, in->d.line); P_ActivateLine(in->d.line, usething, 0, SPAC_USE); return false; // can't use for than one special line in a row } /* ================ = = P_UseLines = = Looks for special lines in front of the player to activate ================ */ void P_UseLines(player_t * player) { int angle; fixed_t x1, y1, x2, y2; usething = player->mo; angle = player->mo->angle >> ANGLETOFINESHIFT; x1 = player->mo->x; y1 = player->mo->y; x2 = x1 + (USERANGE >> FRACBITS) * finecosine[angle]; y2 = y1 + (USERANGE >> FRACBITS) * finesine[angle]; P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse); } //========================================================================== // // PTR_PuzzleItemTraverse // //========================================================================== #define USE_PUZZLE_ITEM_SPECIAL 129 static mobj_t *PuzzleItemUser; static int PuzzleItemType; static boolean PuzzleActivated; boolean PTR_PuzzleItemTraverse(intercept_t * in) { mobj_t *mobj; byte args[3]; int sound; if (in->isaline) { // Check line if (in->d.line->special != USE_PUZZLE_ITEM_SPECIAL) { P_LineOpening(in->d.line); if (openrange <= 0) { sound = SFX_NONE; if (PuzzleItemUser->player) { switch (PuzzleItemUser->player->class) { case PCLASS_FIGHTER: sound = SFX_PUZZLE_FAIL_FIGHTER; break; case PCLASS_CLERIC: sound = SFX_PUZZLE_FAIL_CLERIC; break; case PCLASS_MAGE: sound = SFX_PUZZLE_FAIL_MAGE; break; default: sound = SFX_NONE; break; } } S_StartSound(PuzzleItemUser, sound); return false; // can't use through a wall } return true; // Continue searching } if (P_PointOnLineSide(PuzzleItemUser->x, PuzzleItemUser->y, in->d.line) == 1) { // Don't use back sides return false; } if (PuzzleItemType != in->d.line->arg1) { // Item type doesn't match return false; } // Construct an args[] array that would contain the values from // the line that would be passed by Vanilla Hexen. args[0] = in->d.line->arg3; args[1] = in->d.line->arg4; args[2] = in->d.line->arg5; P_StartACS(in->d.line->arg2, 0, args, PuzzleItemUser, in->d.line, 0); in->d.line->special = 0; PuzzleActivated = true; return false; // Stop searching } // Check thing mobj = in->d.thing; if (mobj->special != USE_PUZZLE_ITEM_SPECIAL) { // Wrong special return true; } if (PuzzleItemType != mobj->args[0]) { // Item type doesn't match return true; } P_StartACS(mobj->args[1], 0, &mobj->args[2], PuzzleItemUser, NULL, 0); mobj->special = 0; PuzzleActivated = true; return false; // Stop searching } //========================================================================== // // P_UsePuzzleItem // // Returns true if the puzzle item was used on a line or a thing. // //========================================================================== boolean P_UsePuzzleItem(player_t * player, int itemType) { int angle; fixed_t x1, y1, x2, y2; PuzzleItemType = itemType; PuzzleItemUser = player->mo; PuzzleActivated = false; angle = player->mo->angle >> ANGLETOFINESHIFT; x1 = player->mo->x; y1 = player->mo->y; x2 = x1 + (USERANGE >> FRACBITS) * finecosine[angle]; y2 = y1 + (USERANGE >> FRACBITS) * finesine[angle]; P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES | PT_ADDTHINGS, PTR_PuzzleItemTraverse); return PuzzleActivated; } /* ============================================================================== RADIUS ATTACK ============================================================================== */ mobj_t *bombsource; mobj_t *bombspot; int bombdamage; int bombdistance; boolean DamageSource; /* ================= = = PIT_RadiusAttack = = Source is the creature that casued the explosion at spot ================= */ boolean PIT_RadiusAttack(mobj_t * thing) { fixed_t dx, dy, dist; int damage; if (!(thing->flags & MF_SHOOTABLE)) { return true; } // if(thing->flags2&MF2_BOSS) // { // Bosses take no damage from PIT_RadiusAttack // return(true); // } if (!DamageSource && thing == bombsource) { // don't damage the source of the explosion return true; } if (abs((thing->z - bombspot->z) >> FRACBITS) > 2 * bombdistance) { // too high/low return true; } dx = abs(thing->x - bombspot->x); dy = abs(thing->y - bombspot->y); dist = dx > dy ? dx : dy; dist = (dist - thing->radius) >> FRACBITS; if (dist < 0) { dist = 0; } if (dist >= bombdistance) { // Out of range return true; } if (P_CheckSight(thing, bombspot)) { // OK to damage, target is in direct path damage = (bombdamage * (bombdistance - dist) / bombdistance) + 1; if (thing->player) { damage >>= 2; } P_DamageMobj(thing, bombspot, bombsource, damage); } return (true); } /* ================= = = P_RadiusAttack = = Source is the creature that caused the explosion at spot ================= */ void P_RadiusAttack(mobj_t * spot, mobj_t * source, int damage, int distance, boolean damageSource) { int x, y, xl, xh, yl, yh; fixed_t dist; dist = (distance + MAXRADIUS) << FRACBITS; yh = (spot->y + dist - bmaporgy) >> MAPBLOCKSHIFT; yl = (spot->y - dist - bmaporgy) >> MAPBLOCKSHIFT; xh = (spot->x + dist - bmaporgx) >> MAPBLOCKSHIFT; xl = (spot->x - dist - bmaporgx) >> MAPBLOCKSHIFT; bombspot = spot; bombsource = source; bombdamage = damage; bombdistance = distance; DamageSource = damageSource; for (y = yl; y <= yh; y++) { for (x = xl; x <= xh; x++) { P_BlockThingsIterator(x, y, PIT_RadiusAttack); } } } /* ============================================================================== SECTOR HEIGHT CHANGING = After modifying a sectors floor or ceiling height, call this = routine to adjust the positions of all things that touch the = sector. = = If anything doesn't fit anymore, true will be returned. = If crunch is true, they will take damage as they are being crushed = If Crunch is false, you should set the sector height back the way it = was and call P_ChangeSector again to undo the changes ============================================================================== */ int crushchange; boolean nofit; /* =============== = = PIT_ChangeSector = =============== */ boolean PIT_ChangeSector(mobj_t * thing) { mobj_t *mo; if (P_ThingHeightClip(thing)) return true; // keep checking // crunch bodies to giblets if ((thing->flags & MF_CORPSE) && (thing->health <= 0)) { if (thing->flags & MF_NOBLOOD) { P_RemoveMobj(thing); } else { if (thing->state != &states[S_GIBS1]) { P_SetMobjState(thing, S_GIBS1); thing->height = 0; thing->radius = 0; S_StartSound(thing, SFX_PLAYER_FALLING_SPLAT); } } return true; // keep checking } // crunch dropped items if (thing->flags2 & MF2_DROPPED) { P_RemoveMobj(thing); return true; // keep checking } if (!(thing->flags & MF_SHOOTABLE)) return true; // assume it is bloody gibs or something nofit = true; if (crushchange && !(leveltime & 3)) { P_DamageMobj(thing, NULL, NULL, crushchange); // spray blood in a random direction if ((!(thing->flags & MF_NOBLOOD)) && (!(thing->flags2 & MF2_INVULNERABLE))) { mo = P_SpawnMobj(thing->x, thing->y, thing->z + thing->height / 2, MT_BLOOD); mo->momx = (P_Random() - P_Random()) << 12; mo->momy = (P_Random() - P_Random()) << 12; } } return true; // keep checking (crush other things) } /* =============== = = P_ChangeSector = =============== */ boolean P_ChangeSector(sector_t * sector, int crunch) { int x, y; nofit = false; crushchange = crunch; // recheck heights for all things near the moving sector for (x = sector->blockbox[BOXLEFT]; x <= sector->blockbox[BOXRIGHT]; x++) for (y = sector->blockbox[BOXBOTTOM]; y <= sector->blockbox[BOXTOP]; y++) P_BlockThingsIterator(x, y, PIT_ChangeSector); return nofit; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_maputl.c000066400000000000000000000637101257432200600231770ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_system.h" #include "m_bbox.h" #include "p_local.h" static mobj_t *RoughBlockCheck(mobj_t * mo, int index); /* =================== = = P_AproxDistance = = Gives an estimation of distance (not exact) = =================== */ fixed_t P_AproxDistance(fixed_t dx, fixed_t dy) { dx = abs(dx); dy = abs(dy); if (dx < dy) return dx + dy - (dx >> 1); return dx + dy - (dy >> 1); } /* ================== = = P_PointOnLineSide = = Returns 0 or 1 ================== */ int P_PointOnLineSide(fixed_t x, fixed_t y, line_t * line) { fixed_t dx, dy; fixed_t left, right; if (!line->dx) { if (x <= line->v1->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->v1->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->v1->x); dy = (y - line->v1->y); left = FixedMul(line->dy >> FRACBITS, dx); right = FixedMul(dy, line->dx >> FRACBITS); if (right < left) return 0; // front side return 1; // back side } /* ================= = = P_BoxOnLineSide = = Considers the line to be infinite = Returns side 0 or 1, -1 if box crosses the line ================= */ int P_BoxOnLineSide(fixed_t * tmbox, line_t * ld) { int p1 = 0, p2 = 0; switch (ld->slopetype) { case ST_HORIZONTAL: p1 = tmbox[BOXTOP] > ld->v1->y; p2 = tmbox[BOXBOTTOM] > ld->v1->y; if (ld->dx < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_VERTICAL: p1 = tmbox[BOXRIGHT] < ld->v1->x; p2 = tmbox[BOXLEFT] < ld->v1->x; if (ld->dy < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_POSITIVE: p1 = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld); break; case ST_NEGATIVE: p1 = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld); break; } if (p1 == p2) return p1; return -1; } /* ================== = = P_PointOnDivlineSide = = Returns 0 or 1 ================== */ int P_PointOnDivlineSide(fixed_t x, fixed_t y, divline_t * line) { fixed_t dx, dy; fixed_t left, right; if (!line->dx) { if (x <= line->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->x); dy = (y - line->y); // try to quickly decide by looking at sign bits if ((line->dy ^ line->dx ^ dx ^ dy) & 0x80000000) { if ((line->dy ^ dx) & 0x80000000) return 1; // (left is negative) return 0; } left = FixedMul(line->dy >> 8, dx >> 8); right = FixedMul(dy >> 8, line->dx >> 8); if (right < left) return 0; // front side return 1; // back side } /* ============== = = P_MakeDivline = ============== */ void P_MakeDivline(line_t * li, divline_t * dl) { dl->x = li->v1->x; dl->y = li->v1->y; dl->dx = li->dx; dl->dy = li->dy; } /* =============== = = P_InterceptVector = = Returns the fractional intercept point along the first divline = = This is only called by the addthings and addlines traversers =============== */ fixed_t P_InterceptVector(divline_t * v2, divline_t * v1) { #if 1 fixed_t frac, num, den; den = FixedMul(v1->dy >> 8, v2->dx) - FixedMul(v1->dx >> 8, v2->dy); if (den == 0) return 0; // I_Error ("P_InterceptVector: parallel"); num = FixedMul((v1->x - v2->x) >> 8, v1->dy) + FixedMul((v2->y - v1->y) >> 8, v1->dx); frac = FixedDiv(num, den); return frac; #else float frac, num, den, v1x, v1y, v1dx, v1dy, v2x, v2y, v2dx, v2dy; v1x = (float) v1->x / FRACUNIT; v1y = (float) v1->y / FRACUNIT; v1dx = (float) v1->dx / FRACUNIT; v1dy = (float) v1->dy / FRACUNIT; v2x = (float) v2->x / FRACUNIT; v2y = (float) v2->y / FRACUNIT; v2dx = (float) v2->dx / FRACUNIT; v2dy = (float) v2->dy / FRACUNIT; den = v1dy * v2dx - v1dx * v2dy; if (den == 0) return 0; // parallel num = (v1x - v2x) * v1dy + (v2y - v1y) * v1dx; frac = num / den; return frac * FRACUNIT; #endif } /* ================== = = P_LineOpening = = Sets opentop and openbottom to the window through a two sided line = OPTIMIZE: keep this precalculated ================== */ fixed_t opentop, openbottom, openrange; fixed_t lowfloor; void P_LineOpening(line_t * linedef) { sector_t *front, *back; if (linedef->sidenum[1] == -1) { // single sided line openrange = 0; return; } front = linedef->frontsector; back = linedef->backsector; if (front->ceilingheight < back->ceilingheight) opentop = front->ceilingheight; else opentop = back->ceilingheight; if (front->floorheight > back->floorheight) { openbottom = front->floorheight; lowfloor = back->floorheight; tmfloorpic = front->floorpic; } else { openbottom = back->floorheight; lowfloor = front->floorheight; tmfloorpic = back->floorpic; } openrange = opentop - openbottom; } /* =============================================================================== THING POSITION SETTING =============================================================================== */ /* =================== = = P_UnsetThingPosition = = Unlinks a thing from block map and sectors = =================== */ void P_UnsetThingPosition(mobj_t * thing) { int blockx, blocky; if (!(thing->flags & MF_NOSECTOR)) { // inert things don't need to be in blockmap // unlink from subsector if (thing->snext) thing->snext->sprev = thing->sprev; if (thing->sprev) thing->sprev->snext = thing->snext; else thing->subsector->sector->thinglist = thing->snext; } if (!(thing->flags & MF_NOBLOCKMAP)) { // inert things don't need to be in blockmap // unlink from block map if (thing->bnext) thing->bnext->bprev = thing->bprev; if (thing->bprev) thing->bprev->bnext = thing->bnext; else { blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT; if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight) blocklinks[blocky * bmapwidth + blockx] = thing->bnext; } } } /* =================== = = P_SetThingPosition = = Links a thing into both a block and a subsector based on it's x y = Sets thing->subsector properly = =================== */ void P_SetThingPosition(mobj_t * thing) { subsector_t *ss; sector_t *sec; int blockx, blocky; mobj_t **link; // // link into subsector // ss = R_PointInSubsector(thing->x, thing->y); thing->subsector = ss; if (!(thing->flags & MF_NOSECTOR)) { // invisible things don't go into the sector links sec = ss->sector; thing->sprev = NULL; thing->snext = sec->thinglist; if (sec->thinglist) sec->thinglist->sprev = thing; sec->thinglist = thing; } // // link into blockmap // if (!(thing->flags & MF_NOBLOCKMAP)) { // inert things don't need to be in blockmap blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT; if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight) { link = &blocklinks[blocky * bmapwidth + blockx]; thing->bprev = NULL; thing->bnext = *link; if (*link) (*link)->bprev = thing; *link = thing; } else { // thing is off the map thing->bnext = thing->bprev = NULL; } } } /* =============================================================================== BLOCK MAP ITERATORS For each line/thing in the given mapblock, call the passed function. If the function returns false, exit with false without checking anything else. =============================================================================== */ /* ================== = = P_BlockLinesIterator = = The validcount flags are used to avoid checking lines = that are marked in multiple mapblocks, so increment validcount before = the first call to P_BlockLinesIterator, then make one or more calls to it =================== */ boolean P_BlockLinesIterator(int x, int y, boolean(*func) (line_t *)) { int offset; short *list; line_t *ld; int i; polyblock_t *polyLink; seg_t **tempSeg; extern polyblock_t **PolyBlockMap; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) return true; offset = y * bmapwidth + x; polyLink = PolyBlockMap[offset]; while (polyLink) { if (polyLink->polyobj) { if (polyLink->polyobj->validcount != validcount) { polyLink->polyobj->validcount = validcount; tempSeg = polyLink->polyobj->segs; for (i = 0; i < polyLink->polyobj->numsegs; i++, tempSeg++) { if ((*tempSeg)->linedef->validcount == validcount) { continue; } (*tempSeg)->linedef->validcount = validcount; if (!func((*tempSeg)->linedef)) { return false; } } } } polyLink = polyLink->next; } offset = *(blockmap + offset); for (list = blockmaplump + offset; *list != -1; list++) { ld = &lines[*list]; if (ld->validcount == validcount) continue; // line has already been checked ld->validcount = validcount; if (!func(ld)) return false; } return true; // everything was checked } /* ================== = = P_BlockThingsIterator = ================== */ boolean P_BlockThingsIterator(int x, int y, boolean(*func) (mobj_t *)) { mobj_t *mobj; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) return true; for (mobj = blocklinks[y * bmapwidth + x]; mobj; mobj = mobj->bnext) if (!func(mobj)) return false; return true; } /* =============================================================================== INTERCEPT ROUTINES =============================================================================== */ intercept_t intercepts[MAXINTERCEPTS], *intercept_p; divline_t trace; boolean earlyout; int ptflags; /* ================== = = PIT_AddLineIntercepts = = Looks for lines in the given block that intercept the given trace = to add to the intercepts list = A line is crossed if its endpoints are on opposite sides of the trace = Returns true if earlyout and a solid line hit ================== */ boolean PIT_AddLineIntercepts(line_t * ld) { int s1, s2; fixed_t frac; divline_t dl; // avoid precision problems with two routines if (trace.dx > FRACUNIT * 16 || trace.dy > FRACUNIT * 16 || trace.dx < -FRACUNIT * 16 || trace.dy < -FRACUNIT * 16) { s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace); } else { s1 = P_PointOnLineSide(trace.x, trace.y, ld); s2 = P_PointOnLineSide(trace.x + trace.dx, trace.y + trace.dy, ld); } if (s1 == s2) return true; // line isn't crossed // // hit the line // P_MakeDivline(ld, &dl); frac = P_InterceptVector(&trace, &dl); if (frac < 0) return true; // behind source // try to early out the check if (earlyout && frac < FRACUNIT && !ld->backsector) return false; // stop checking intercept_p->frac = frac; intercept_p->isaline = true; intercept_p->d.line = ld; intercept_p++; return true; // continue } /* ================== = = PIT_AddThingIntercepts = ================== */ boolean PIT_AddThingIntercepts(mobj_t * thing) { fixed_t x1, y1, x2, y2; int s1, s2; boolean tracepositive; divline_t dl; fixed_t frac; tracepositive = (trace.dx ^ trace.dy) > 0; // check a corner to corner crossection for hit if (tracepositive) { x1 = thing->x - thing->radius; y1 = thing->y + thing->radius; x2 = thing->x + thing->radius; y2 = thing->y - thing->radius; } else { x1 = thing->x - thing->radius; y1 = thing->y - thing->radius; x2 = thing->x + thing->radius; y2 = thing->y + thing->radius; } s1 = P_PointOnDivlineSide(x1, y1, &trace); s2 = P_PointOnDivlineSide(x2, y2, &trace); if (s1 == s2) return true; // line isn't crossed dl.x = x1; dl.y = y1; dl.dx = x2 - x1; dl.dy = y2 - y1; frac = P_InterceptVector(&trace, &dl); if (frac < 0) return true; // behind source intercept_p->frac = frac; intercept_p->isaline = false; intercept_p->d.thing = thing; intercept_p++; return true; // keep going } /* ==================== = = P_TraverseIntercepts = = Returns true if the traverser function returns true for all lines ==================== */ boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac) { int count; fixed_t dist; intercept_t *scan, *in; count = intercept_p - intercepts; in = 0; // shut up compiler warning while (count--) { dist = INT_MAX; for (scan = intercepts; scan < intercept_p; scan++) if (scan->frac < dist) { dist = scan->frac; in = scan; } if (dist > maxfrac) return true; // checked everything in range #if 0 { // don't check these yet, ther may be others inserted in = scan = intercepts; for (scan = intercepts; scan < intercept_p; scan++) if (scan->frac > maxfrac) *in++ = *scan; intercept_p = in; return false; } #endif if (!func(in)) return false; // don't bother going farther in->frac = INT_MAX; } return true; // everything was traversed } /* ================== = = P_PathTraverse = = Traces a line from x1,y1 to x2,y2, calling the traverser function for each = Returns true if the traverser function returns true for all lines ================== */ boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean(*trav) (intercept_t *)) { fixed_t xt1, yt1, xt2, yt2; fixed_t xstep, ystep; fixed_t partial; fixed_t xintercept, yintercept; int mapx, mapy, mapxstep, mapystep; int count; earlyout = (flags & PT_EARLYOUT) != 0; validcount++; intercept_p = intercepts; if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0) x1 += FRACUNIT; // don't side exactly on a line if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0) y1 += FRACUNIT; // don't side exactly on a line trace.x = x1; trace.y = y1; trace.dx = x2 - x1; trace.dy = y2 - y1; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = x1 >> MAPBLOCKSHIFT; yt1 = y1 >> MAPBLOCKSHIFT; x2 -= bmaporgx; y2 -= bmaporgy; xt2 = x2 >> MAPBLOCKSHIFT; yt2 = y2 >> MAPBLOCKSHIFT; if (xt2 > xt1) { mapxstep = 1; partial = FRACUNIT - ((x1 >> MAPBTOFRAC) & (FRACUNIT - 1)); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else if (xt2 < xt1) { mapxstep = -1; partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else { mapxstep = 0; partial = FRACUNIT; ystep = 256 * FRACUNIT; } yintercept = (y1 >> MAPBTOFRAC) + FixedMul(partial, ystep); if (yt2 > yt1) { mapystep = 1; partial = FRACUNIT - ((y1 >> MAPBTOFRAC) & (FRACUNIT - 1)); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else if (yt2 < yt1) { mapystep = -1; partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else { mapystep = 0; partial = FRACUNIT; xstep = 256 * FRACUNIT; } xintercept = (x1 >> MAPBTOFRAC) + FixedMul(partial, xstep); // // step through map blocks // Count is present to prevent a round off error from skipping the break mapx = xt1; mapy = yt1; for (count = 0; count < 64; count++) { if (flags & PT_ADDLINES) { if (!P_BlockLinesIterator(mapx, mapy, PIT_AddLineIntercepts)) return false; // early out } if (flags & PT_ADDTHINGS) { if (!P_BlockThingsIterator(mapx, mapy, PIT_AddThingIntercepts)) return false; // early out } if (mapx == xt2 && mapy == yt2) break; if ((yintercept >> FRACBITS) == mapy) { yintercept += ystep; mapx += mapxstep; } else if ((xintercept >> FRACBITS) == mapx) { xintercept += xstep; mapy += mapystep; } } // // go through the sorted list // return P_TraverseIntercepts(trav, FRACUNIT); } //=========================================================================== // // P_RoughMonsterSearch // // Searches though the surrounding mapblocks for monsters/players // distance is in MAPBLOCKUNITS //=========================================================================== mobj_t *P_RoughMonsterSearch(mobj_t * mo, int distance) { int blockX; int blockY; int startX, startY; int blockIndex; int firstStop; int secondStop; int thirdStop; int finalStop; int count; mobj_t *target; startX = (mo->x - bmaporgx) >> MAPBLOCKSHIFT; startY = (mo->y - bmaporgy) >> MAPBLOCKSHIFT; if (startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight) { target = RoughBlockCheck(mo, startY * bmapwidth + startX); if (target != NULL) { // found a target right away return target; } } for (count = 1; count <= distance; count++) { blockX = startX - count; blockY = startY - count; if (blockY < 0) { blockY = 0; } else if (blockY >= bmapheight) { blockY = bmapheight - 1; } if (blockX < 0) { blockX = 0; } else if (blockX >= bmapwidth) { blockX = bmapwidth - 1; } blockIndex = blockY * bmapwidth + blockX; firstStop = startX + count; if (firstStop < 0) { continue; } if (firstStop >= bmapwidth) { firstStop = bmapwidth - 1; } secondStop = startY + count; if (secondStop < 0) { continue; } if (secondStop >= bmapheight) { secondStop = bmapheight - 1; } thirdStop = secondStop * bmapwidth + blockX; secondStop = secondStop * bmapwidth + firstStop; firstStop += blockY * bmapwidth; finalStop = blockIndex; // Trace the first block section (along the top) for (; blockIndex <= firstStop; blockIndex++) { target = RoughBlockCheck(mo, blockIndex); if (target != NULL) { return target; } } // Trace the second block section (right edge) for (blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth) { target = RoughBlockCheck(mo, blockIndex); if (target != NULL) { return target; } } // Trace the third block section (bottom edge) for (blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--) { target = RoughBlockCheck(mo, blockIndex); if (target != NULL) { return target; } } // Trace the final block section (left edge) for (blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth) { target = RoughBlockCheck(mo, blockIndex); if (target != NULL) { return target; } } } return NULL; } //=========================================================================== // // RoughBlockCheck // //=========================================================================== static mobj_t *RoughBlockCheck(mobj_t * mo, int index) { mobj_t *link; mobj_t *master; angle_t angle; link = blocklinks[index]; while (link) { if (mo->player) // Minotaur looking around player { if ((link->flags & MF_COUNTKILL) || (link->player && (link != mo))) { if (!(link->flags & MF_SHOOTABLE)) { link = link->bnext; continue; } if (link->flags2 & MF2_DORMANT) { link = link->bnext; continue; } if ((link->type == MT_MINOTAUR) && (link->special1.m == mo)) { link = link->bnext; continue; } if (netgame && !deathmatch && link->player) { link = link->bnext; continue; } if (P_CheckSight(mo, link)) { return link; } } link = link->bnext; } else if (mo->type == MT_MINOTAUR) // looking around minotaur { master = mo->special1.m; if ((link->flags & MF_COUNTKILL) || (link->player && (link != master))) { if (!(link->flags & MF_SHOOTABLE)) { link = link->bnext; continue; } if (link->flags2 & MF2_DORMANT) { link = link->bnext; continue; } if ((link->type == MT_MINOTAUR) && (link->special1.m == mo->special1.m)) { link = link->bnext; continue; } if (netgame && !deathmatch && link->player) { link = link->bnext; continue; } if (P_CheckSight(mo, link)) { return link; } } link = link->bnext; } else if (mo->type == MT_MSTAFF_FX2) // bloodscourge { if ((link->flags & MF_COUNTKILL || (link->player && link != mo->target)) && !(link->flags2 & MF2_DORMANT)) { if (!(link->flags & MF_SHOOTABLE)) { link = link->bnext; continue; } if (netgame && !deathmatch && link->player) { link = link->bnext; continue; } else if (P_CheckSight(mo, link)) { master = mo->target; angle = R_PointToAngle2(master->x, master->y, link->x, link->y) - master->angle; angle >>= 24; if (angle > 226 || angle < 30) { return link; } } } link = link->bnext; } else // spirits { if ((link->flags & MF_COUNTKILL || (link->player && link != mo->target)) && !(link->flags2 & MF2_DORMANT)) { if (!(link->flags & MF_SHOOTABLE)) { link = link->bnext; continue; } if (netgame && !deathmatch && link->player) { link = link->bnext; continue; } if (link == mo->target) { link = link->bnext; continue; } else if (P_CheckSight(mo, link)) { return link; } } link = link->bnext; } } return NULL; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_mobj.c000066400000000000000000002124701257432200600226230ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "m_random.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" #include "sounds.h" // MACROS ------------------------------------------------------------------ #define MAX_TID_COUNT 200 // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void G_PlayerReborn(int player); void P_MarkAsLeaving(mobj_t * corpse); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- void P_SpawnMapThing(mapthing_t * mthing); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void PlayerLandedOnThing(mobj_t * mo, mobj_t * onmobj); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern mobj_t LavaInflictor; // PUBLIC DATA DEFINITIONS ------------------------------------------------- mobjtype_t PuffType; mobj_t *MissileMobj; fixed_t FloatBobOffsets[64] = { 0, 51389, 102283, 152192, 200636, 247147, 291278, 332604, 370727, 405280, 435929, 462380, 484378, 501712, 514213, 521763, 524287, 521763, 514213, 501712, 484378, 462380, 435929, 405280, 370727, 332604, 291278, 247147, 200636, 152192, 102283, 51389, -1, -51390, -102284, -152193, -200637, -247148, -291279, -332605, -370728, -405281, -435930, -462381, -484380, -501713, -514215, -521764, -524288, -521764, -514214, -501713, -484379, -462381, -435930, -405280, -370728, -332605, -291279, -247148, -200637, -152193, -102284, -51389 }; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int TIDList[MAX_TID_COUNT + 1]; // +1 for termination marker static mobj_t *TIDMobj[MAX_TID_COUNT]; // CODE -------------------------------------------------------------------- //========================================================================== // // P_SetMobjState // // Returns true if the mobj is still present. // //========================================================================== boolean P_SetMobjState(mobj_t * mobj, statenum_t state) { state_t *st; if (state == S_NULL) { // Remove mobj mobj->state = (state_t *) S_NULL; P_RemoveMobj(mobj); return (false); } st = &states[state]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; if (st->action) { // Call action function st->action(mobj); } return (true); } //========================================================================== // // P_SetMobjStateNF // // Same as P_SetMobjState, but does not call the state function. // //========================================================================== boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state) { state_t *st; if (state == S_NULL) { // Remove mobj mobj->state = (state_t *) S_NULL; P_RemoveMobj(mobj); return (false); } st = &states[state]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; return (true); } //---------------------------------------------------------------------------- // // PROC P_ExplodeMissile // //---------------------------------------------------------------------------- void P_ExplodeMissile(mobj_t * mo) { mo->momx = mo->momy = mo->momz = 0; P_SetMobjState(mo, mobjinfo[mo->type].deathstate); //mo->tics -= P_Random()&3; mo->flags &= ~MF_MISSILE; switch (mo->type) { case MT_SORCBALL1: case MT_SORCBALL2: case MT_SORCBALL3: S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE); break; case MT_SORCFX1: S_StartSound(NULL, SFX_SORCERER_HEADSCREAM); break; default: if (mo->info->deathsound) { S_StartSound(mo, mo->info->deathsound); } break; } } //---------------------------------------------------------------------------- // // PROC P_FloorBounceMissile // //---------------------------------------------------------------------------- void P_FloorBounceMissile(mobj_t * mo) { if (P_HitFloor(mo) >= FLOOR_LIQUID) { switch (mo->type) { case MT_SORCFX1: case MT_SORCBALL1: case MT_SORCBALL2: case MT_SORCBALL3: break; default: P_RemoveMobj(mo); return; } } switch (mo->type) { case MT_SORCFX1: mo->momz = -mo->momz; // no energy absorbed break; case MT_SGSHARD1: case MT_SGSHARD2: case MT_SGSHARD3: case MT_SGSHARD4: case MT_SGSHARD5: case MT_SGSHARD6: case MT_SGSHARD7: case MT_SGSHARD8: case MT_SGSHARD9: case MT_SGSHARD0: mo->momz = FixedMul(mo->momz, -0.3 * FRACUNIT); if (abs(mo->momz) < (FRACUNIT / 2)) { P_SetMobjState(mo, S_NULL); return; } break; default: mo->momz = FixedMul(mo->momz, -0.7 * FRACUNIT); break; } mo->momx = 2 * mo->momx / 3; mo->momy = 2 * mo->momy / 3; if (mo->info->seesound) { switch (mo->type) { case MT_SORCBALL1: case MT_SORCBALL2: case MT_SORCBALL3: if (!mo->args[0]) S_StartSound(mo, mo->info->seesound); break; default: S_StartSound(mo, mo->info->seesound); break; } S_StartSound(mo, mo->info->seesound); } // P_SetMobjState(mo, mobjinfo[mo->type].deathstate); } //---------------------------------------------------------------------------- // // PROC P_ThrustMobj // //---------------------------------------------------------------------------- void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move) { angle >>= ANGLETOFINESHIFT; mo->momx += FixedMul(move, finecosine[angle]); mo->momy += FixedMul(move, finesine[angle]); } //---------------------------------------------------------------------------- // // FUNC P_FaceMobj // // Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs // to turn counter clockwise. 'delta' is set to the amount 'source' // needs to turn. // //---------------------------------------------------------------------------- int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta) { angle_t diff; angle_t angle1; angle_t angle2; angle1 = source->angle; angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y); if (angle2 > angle1) { diff = angle2 - angle1; if (diff > ANG180) { *delta = ANG_MAX - diff; return (0); } else { *delta = diff; return (1); } } else { diff = angle1 - angle2; if (diff > ANG180) { *delta = ANG_MAX - diff; return (1); } else { *delta = diff; return (0); } } } //---------------------------------------------------------------------------- // // // The missile special1 field must be mobj_t *target. Returns true if // target was tracked, false if not. // //---------------------------------------------------------------------------- boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax) { int dir; int dist; angle_t delta; angle_t angle; mobj_t *target; target = actor->special1.m; if (target == NULL) { return (false); } if (!(target->flags & MF_SHOOTABLE)) { // Target died actor->special1.m = NULL; return (false); } dir = P_FaceMobj(actor, target, &delta); if (delta > thresh) { delta >>= 1; if (delta > turnMax) { delta = turnMax; } } if (dir) { // Turn clockwise actor->angle += delta; } else { // Turn counter clockwise actor->angle -= delta; } angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(actor->info->speed, finecosine[angle]); actor->momy = FixedMul(actor->info->speed, finesine[angle]); if (actor->z + actor->height < target->z || target->z + target->height < actor->z) { // Need to seek vertically dist = P_AproxDistance(target->x - actor->x, target->y - actor->y); dist = dist / actor->info->speed; if (dist < 1) { dist = 1; } actor->momz = (target->z + (target->height >> 1) - (actor->z + (actor->height >> 1))) / dist; } return (true); } //---------------------------------------------------------------------------- // // PROC P_XYMovement // //---------------------------------------------------------------------------- #define STOPSPEED 0x1000 #define FRICTION_NORMAL 0xe800 #define FRICTION_LOW 0xf900 #define FRICTION_FLY 0xeb00 void P_XYMovement(mobj_t * mo) { fixed_t ptryx, ptryy; player_t *player; fixed_t xmove, ymove; int special; angle_t angle; static int windTab[3] = { 2048 * 5, 2048 * 10, 2048 * 25 }; if (!mo->momx && !mo->momy) { if (mo->flags & MF_SKULLFLY) { // A flying mobj slammed into something mo->flags &= ~MF_SKULLFLY; mo->momx = mo->momy = mo->momz = 0; P_SetMobjState(mo, mo->info->seestate); } return; } special = mo->subsector->sector->special; if (mo->flags2 & MF2_WINDTHRUST) { switch (special) { case 40: case 41: case 42: // Wind_East P_ThrustMobj(mo, 0, windTab[special - 40]); break; case 43: case 44: case 45: // Wind_North P_ThrustMobj(mo, ANG90, windTab[special - 43]); break; case 46: case 47: case 48: // Wind_South P_ThrustMobj(mo, ANG270, windTab[special - 46]); break; case 49: case 50: case 51: // Wind_West P_ThrustMobj(mo, ANG180, windTab[special - 49]); break; } } player = mo->player; if (mo->momx > MAXMOVE) { mo->momx = MAXMOVE; } else if (mo->momx < -MAXMOVE) { mo->momx = -MAXMOVE; } if (mo->momy > MAXMOVE) { mo->momy = MAXMOVE; } else if (mo->momy < -MAXMOVE) { mo->momy = -MAXMOVE; } xmove = mo->momx; ymove = mo->momy; do { if (xmove > MAXMOVE / 2 || ymove > MAXMOVE / 2) { ptryx = mo->x + xmove / 2; ptryy = mo->y + ymove / 2; xmove >>= 1; ymove >>= 1; } else { ptryx = mo->x + xmove; ptryy = mo->y + ymove; xmove = ymove = 0; } if (!P_TryMove(mo, ptryx, ptryy)) { // Blocked move if (mo->flags2 & MF2_SLIDE) { // Try to slide along it if (BlockingMobj == NULL) { // Slide against wall P_SlideMove(mo); } else { // Slide against mobj //if(P_TryMove(mo, mo->x, mo->y+mo->momy)) if (P_TryMove(mo, mo->x, ptryy)) { mo->momx = 0; } //else if(P_TryMove(mo, mo->x+mo->momx, mo->y)) else if (P_TryMove(mo, ptryx, mo->y)) { mo->momy = 0; } else { mo->momx = mo->momy = 0; } } } else if (mo->flags & MF_MISSILE) { if (mo->flags2 & MF2_FLOORBOUNCE) { if (BlockingMobj) { if ((BlockingMobj->flags2 & MF2_REFLECTIVE) || ((!BlockingMobj->player) && (!(BlockingMobj->flags & MF_COUNTKILL)))) { fixed_t speed; angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y) + ANG1 * ((P_Random() % 16) - 8); speed = P_AproxDistance(mo->momx, mo->momy); speed = FixedMul(speed, 0.75 * FRACUNIT); mo->angle = angle; angle >>= ANGLETOFINESHIFT; mo->momx = FixedMul(speed, finecosine[angle]); mo->momy = FixedMul(speed, finesine[angle]); if (mo->info->seesound) { S_StartSound(mo, mo->info->seesound); } return; } else { // Struck a player/creature P_ExplodeMissile(mo); } } else { // Struck a wall P_BounceWall(mo); switch (mo->type) { case MT_SORCBALL1: case MT_SORCBALL2: case MT_SORCBALL3: case MT_SORCFX1: break; default: if (mo->info->seesound) { S_StartSound(mo, mo->info->seesound); } break; } return; } } if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE)) { angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); // Change angle for delflection/reflection switch (BlockingMobj->type) { case MT_CENTAUR: case MT_CENTAURLEADER: if (abs(angle - BlockingMobj->angle) >> 24 > 45) goto explode; if (mo->type == MT_HOLY_FX) goto explode; // Drop through to sorcerer full reflection case MT_SORCBOSS: // Deflection if (P_Random() < 128) angle += ANG45; else angle -= ANG45; break; default: // Reflection angle += ANG1 * ((P_Random() % 16) - 8); break; } // Reflect the missile along angle mo->angle = angle; angle >>= ANGLETOFINESHIFT; mo->momx = FixedMul(mo->info->speed >> 1, finecosine[angle]); mo->momy = FixedMul(mo->info->speed >> 1, finesine[angle]); // mo->momz = -mo->momz; if (mo->flags2 & MF2_SEEKERMISSILE) { mo->special1.m = mo->target; } mo->target = BlockingMobj; return; } explode: // Explode a missile if (ceilingline && ceilingline->backsector && ceilingline->backsector->ceilingpic == skyflatnum) { // Hack to prevent missiles exploding against the sky if (mo->type == MT_BLOODYSKULL) { mo->momx = mo->momy = 0; mo->momz = -FRACUNIT; } else if (mo->type == MT_HOLY_FX) { P_ExplodeMissile(mo); } else { P_RemoveMobj(mo); } return; } P_ExplodeMissile(mo); } //else if(mo->info->crashstate) //{ // mo->momx = mo->momy = 0; // P_SetMobjState(mo, mo->info->crashstate); // return; //} else { mo->momx = mo->momy = 0; } } } while (xmove || ymove); // Friction if (player && player->cheats & CF_NOMOMENTUM) { // Debug option for no sliding at all mo->momx = mo->momy = 0; return; } if (mo->flags & (MF_MISSILE | MF_SKULLFLY)) { // No friction for missiles return; } if (mo->z > mo->floorz && !(mo->flags2 & MF2_FLY) && !(mo->flags2 & MF2_ONMOBJ)) { // No friction when falling if (mo->type != MT_BLASTEFFECT) return; } if (mo->flags & MF_CORPSE) { // Don't stop sliding if halfway off a step with some momentum if (mo->momx > FRACUNIT / 4 || mo->momx < -FRACUNIT / 4 || mo->momy > FRACUNIT / 4 || mo->momy < -FRACUNIT / 4) { if (mo->floorz != mo->subsector->sector->floorheight) { return; } } } if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && mo->momy > -STOPSPEED && mo->momy < STOPSPEED && (!player || (player->cmd.forwardmove == 0 && player->cmd.sidemove == 0))) { // If in a walking frame, stop moving if (player) { if ((unsigned) ((player->mo->state - states) - PStateRun[player->class]) < 4) { P_SetMobjState(player->mo, PStateNormal[player->class]); } } mo->momx = 0; mo->momy = 0; } else { if (mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz) && !(mo->flags2 & MF2_ONMOBJ)) { mo->momx = FixedMul(mo->momx, FRICTION_FLY); mo->momy = FixedMul(mo->momy, FRICTION_FLY); } else if (P_GetThingFloorType(mo) == FLOOR_ICE) { mo->momx = FixedMul(mo->momx, FRICTION_LOW); mo->momy = FixedMul(mo->momy, FRICTION_LOW); } else { mo->momx = FixedMul(mo->momx, FRICTION_NORMAL); mo->momy = FixedMul(mo->momy, FRICTION_NORMAL); } } } // Move this to p_inter *** void P_MonsterFallingDamage(mobj_t * mo) { int damage; int mom; mom = abs(mo->momz); if (mom > 35 * FRACUNIT) { // automatic death damage = 10000; } else { damage = ((mom - (23 * FRACUNIT)) * 6) >> FRACBITS; } damage = 10000; // always kill 'em P_DamageMobj(mo, NULL, NULL, damage); } /* =============== = = P_ZMovement = =============== */ void P_ZMovement(mobj_t * mo) { int dist; int delta; // // check for smooth step up // if (mo->player && mo->z < mo->floorz) { mo->player->viewheight -= mo->floorz - mo->z; mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight) >> 3; } // // adjust height // mo->z += mo->momz; if (mo->flags & MF_FLOAT && mo->target) { // float down towards target if too close if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT)) { dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y); delta = (mo->target->z + (mo->height >> 1)) - mo->z; if (delta < 0 && dist < -(delta * 3)) mo->z -= FLOATSPEED; else if (delta > 0 && dist < (delta * 3)) mo->z += FLOATSPEED; } } if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz) && leveltime & 2) { mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK]; } // // clip movement // if (mo->z <= mo->floorz) { // Hit the floor if (mo->flags & MF_MISSILE) { mo->z = mo->floorz; if (mo->flags2 & MF2_FLOORBOUNCE) { P_FloorBounceMissile(mo); return; } else if (mo->type == MT_HOLY_FX) { // The spirit struck the ground mo->momz = 0; P_HitFloor(mo); return; } else if (mo->type == MT_MNTRFX2 || mo->type == MT_LIGHTNING_FLOOR) { // Minotaur floor fire can go up steps return; } else { P_HitFloor(mo); P_ExplodeMissile(mo); return; } } if (mo->flags & MF_COUNTKILL) // Blasted mobj falling { if (mo->momz < -(23 * FRACUNIT)) { P_MonsterFallingDamage(mo); } } if (mo->z - mo->momz > mo->floorz) { // Spawn splashes, etc. P_HitFloor(mo); } mo->z = mo->floorz; if (mo->momz < 0) { if (mo->flags2 & MF2_ICEDAMAGE && mo->momz < -GRAVITY * 8) { mo->tics = 1; mo->momx = 0; mo->momy = 0; mo->momz = 0; return; } if (mo->player) { mo->player->jumpTics = 7; // delay any jumping for a short time if (mo->momz < -GRAVITY * 8 && !(mo->flags2 & MF2_FLY)) { // squat down mo->player->deltaviewheight = mo->momz >> 3; if (mo->momz < -23 * FRACUNIT) { P_FallingDamage(mo->player); P_NoiseAlert(mo, mo); } else if (mo->momz < -GRAVITY * 12 && !mo->player->morphTics) { S_StartSound(mo, SFX_PLAYER_LAND); switch (mo->player->class) { case PCLASS_FIGHTER: S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT); break; case PCLASS_CLERIC: S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT); break; case PCLASS_MAGE: S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT); break; default: break; } } else if ((P_GetThingFloorType(mo) < FLOOR_LIQUID) && (!mo->player->morphTics)) { S_StartSound(mo, SFX_PLAYER_LAND); } // haleyjd: removed externdriver crap mo->player->centering = true; } } else if (mo->type >= MT_POTTERY1 && mo->type <= MT_POTTERY3) { P_DamageMobj(mo, NULL, NULL, 25); } else if (mo->flags & MF_COUNTKILL) { if (mo->momz < -23 * FRACUNIT) { // Doesn't get here } } mo->momz = 0; } if (mo->flags & MF_SKULLFLY) { // The skull slammed into something mo->momz = -mo->momz; } if (mo->info->crashstate && (mo->flags & MF_CORPSE) && !(mo->flags2 & MF2_ICEDAMAGE)) { P_SetMobjState(mo, mo->info->crashstate); return; } } else if (mo->flags2 & MF2_LOGRAV) { if (mo->momz == 0) mo->momz = -(GRAVITY >> 3) * 2; else mo->momz -= GRAVITY >> 3; } else if (!(mo->flags & MF_NOGRAVITY)) { if (mo->momz == 0) mo->momz = -GRAVITY * 2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // hit the ceiling if (mo->momz > 0) mo->momz = 0; mo->z = mo->ceilingz - mo->height; if (mo->flags2 & MF2_FLOORBOUNCE) { // Maybe reverse momentum here for ceiling bounce // Currently won't happen if (mo->info->seesound) { S_StartSound(mo, mo->info->seesound); } return; } if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; } if (mo->flags & MF_MISSILE) { if (mo->type == MT_LIGHTNING_CEILING) { return; } if (mo->subsector->sector->ceilingpic == skyflatnum) { if (mo->type == MT_BLOODYSKULL) { mo->momx = mo->momy = 0; mo->momz = -FRACUNIT; } else if (mo->type == MT_HOLY_FX) { P_ExplodeMissile(mo); } else { P_RemoveMobj(mo); } return; } P_ExplodeMissile(mo); return; } } } //---------------------------------------------------------------------------- // // PROC P_BlasterMobjThinker // // //---------------------------------------------------------------------------- void P_BlasterMobjThinker(mobj_t * mobj) { int i; fixed_t xfrac; fixed_t yfrac; fixed_t zfrac; fixed_t z; boolean changexy; mobj_t *mo; // Handle movement if (mobj->momx || mobj->momy || (mobj->z != mobj->floorz) || mobj->momz) { xfrac = mobj->momx >> 3; yfrac = mobj->momy >> 3; zfrac = mobj->momz >> 3; changexy = xfrac || yfrac; for (i = 0; i < 8; i++) { if (changexy) { if (!P_TryMove(mobj, mobj->x + xfrac, mobj->y + yfrac)) { // Blocked move P_ExplodeMissile(mobj); return; } } mobj->z += zfrac; if (mobj->z <= mobj->floorz) { // Hit the floor mobj->z = mobj->floorz; P_HitFloor(mobj); P_ExplodeMissile(mobj); return; } if (mobj->z + mobj->height > mobj->ceilingz) { // Hit the ceiling mobj->z = mobj->ceilingz - mobj->height; P_ExplodeMissile(mobj); return; } if (changexy) { if (mobj->type == MT_MWAND_MISSILE && (P_Random() < 128)) { z = mobj->z - 8 * FRACUNIT; if (z < mobj->floorz) { z = mobj->floorz; } P_SpawnMobj(mobj->x, mobj->y, z, MT_MWANDSMOKE); } else if (!--mobj->special1.i) { mobj->special1.i = 4; z = mobj->z - 12 * FRACUNIT; if (z < mobj->floorz) { z = mobj->floorz; } mo = P_SpawnMobj(mobj->x, mobj->y, z, MT_CFLAMEFLOOR); if (mo) { mo->angle = mobj->angle; } } } } } // Advance the state if (mobj->tics != -1) { mobj->tics--; while (!mobj->tics) { if (!P_SetMobjState(mobj, mobj->state->nextstate)) { // mobj was removed return; } } } } //=========================================================================== // // PlayerLandedOnThing // //=========================================================================== static void PlayerLandedOnThing(mobj_t * mo, mobj_t * onmobj) { mo->player->deltaviewheight = mo->momz >> 3; if (mo->momz < -23 * FRACUNIT) { P_FallingDamage(mo->player); P_NoiseAlert(mo, mo); } else if (mo->momz < -GRAVITY * 12 && !mo->player->morphTics) { S_StartSound(mo, SFX_PLAYER_LAND); switch (mo->player->class) { case PCLASS_FIGHTER: S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT); break; case PCLASS_CLERIC: S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT); break; case PCLASS_MAGE: S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT); break; default: break; } } else if (!mo->player->morphTics) { S_StartSound(mo, SFX_PLAYER_LAND); } // haleyjd: removed externdriver crap mo->player->centering = true; } //---------------------------------------------------------------------------- // // PROC P_MobjThinker // //---------------------------------------------------------------------------- void P_MobjThinker(mobj_t * mobj) { mobj_t *onmo; /* // Reset to not blasted when momentums are gone if((mobj->flags2&MF2_BLASTED) && (!(mobj->momx)) && (!(mobj->momy))) ResetBlasted(mobj); */ // Handle X and Y momentums BlockingMobj = NULL; if (mobj->momx || mobj->momy || (mobj->flags & MF_SKULLFLY)) { P_XYMovement(mobj); if (mobj->thinker.function == (think_t) - 1) { // mobj was removed return; } } else if (mobj->flags2 & MF2_BLASTED) { // Reset to not blasted when momentums are gone ResetBlasted(mobj); } if (mobj->flags2 & MF2_FLOATBOB) { // Floating item bobbing motion (special1 is height) mobj->z = mobj->floorz + mobj->special1.i + FloatBobOffsets[(mobj->health++) & 63]; } else if ((mobj->z != mobj->floorz) || mobj->momz || BlockingMobj) { // Handle Z momentum and gravity if (mobj->flags2 & MF2_PASSMOBJ) { if (!(onmo = P_CheckOnmobj(mobj))) { P_ZMovement(mobj); if (mobj->player && mobj->flags & MF2_ONMOBJ) { mobj->flags2 &= ~MF2_ONMOBJ; } } else { if (mobj->player) { if (mobj->momz < -GRAVITY * 8 && !(mobj->flags2 & MF2_FLY)) { PlayerLandedOnThing(mobj, onmo); } if (onmo->z + onmo->height - mobj->z <= 24 * FRACUNIT) { mobj->player->viewheight -= onmo->z + onmo->height - mobj->z; mobj->player->deltaviewheight = (VIEWHEIGHT - mobj->player->viewheight) >> 3; mobj->z = onmo->z + onmo->height; mobj->flags2 |= MF2_ONMOBJ; mobj->momz = 0; } else { // hit the bottom of the blocking mobj mobj->momz = 0; } } /* Landing on another player, and mimicking his movements if(mobj->player && onmo->player) { mobj->momx = onmo->momx; mobj->momy = onmo->momy; if(onmo->z < onmo->floorz) { mobj->z += onmo->floorz-onmo->z; if(onmo->player) { onmo->player->viewheight -= onmo->floorz-onmo->z; onmo->player->deltaviewheight = (VIEWHEIGHT- onmo->player->viewheight)>>3; } onmo->z = onmo->floorz; } } */ } } else { P_ZMovement(mobj); } if (mobj->thinker.function == (think_t) - 1) { // mobj was removed return; } } // Cycle through states, calling action functions at transitions if (mobj->tics != -1) { mobj->tics--; // you can cycle through multiple states in a tic while (!mobj->tics) { if (!P_SetMobjState(mobj, mobj->state->nextstate)) { // mobj was removed return; } } } } //========================================================================== // // P_SpawnMobj // //========================================================================== mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { mobj_t *mobj; state_t *st; mobjinfo_t *info; fixed_t space; mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL); memset(mobj, 0, sizeof(*mobj)); info = &mobjinfo[type]; mobj->type = type; mobj->info = info; mobj->x = x; mobj->y = y; mobj->radius = info->radius; mobj->height = info->height; mobj->flags = info->flags; mobj->flags2 = info->flags2; mobj->damage = info->damage; mobj->health = info->spawnhealth; if (gameskill != sk_nightmare) { mobj->reactiontime = info->reactiontime; } mobj->lastlook = P_Random() % maxplayers; // Set the state, but do not use P_SetMobjState, because action // routines can't be called yet. If the spawnstate has an action // routine, it will not be called. st = &states[info->spawnstate]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // Set subsector and/or block links. P_SetThingPosition(mobj); mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; if (z == ONFLOORZ) { mobj->z = mobj->floorz; } else if (z == ONCEILINGZ) { mobj->z = mobj->ceilingz - mobj->info->height; } else if (z == FLOATRANDZ) { space = ((mobj->ceilingz) - (mobj->info->height)) - mobj->floorz; if (space > 48 * FRACUNIT) { space -= 40 * FRACUNIT; mobj->z = ((space * P_Random()) >> 8) + mobj->floorz + 40 * FRACUNIT; } else { mobj->z = mobj->floorz; } } else if (mobj->flags2 & MF2_FLOATBOB) { mobj->z = mobj->floorz + z; // artifact z passed in as height } else { mobj->z = z; } if (mobj->flags2 & MF2_FLOORCLIP && P_GetThingFloorType(mobj) >= FLOOR_LIQUID && mobj->z == mobj->subsector->sector->floorheight) { mobj->floorclip = 10 * FRACUNIT; } else { mobj->floorclip = 0; } mobj->thinker.function = P_MobjThinker; P_AddThinker(&mobj->thinker); return (mobj); } //========================================================================== // // P_RemoveMobj // //========================================================================== void P_RemoveMobj(mobj_t * mobj) { // Remove from creature queue if (mobj->flags & MF_COUNTKILL && mobj->flags & MF_CORPSE) { A_DeQueueCorpse(mobj); } if (mobj->tid) { // Remove from TID list P_RemoveMobjFromTIDList(mobj); } // Unlink from sector and block lists P_UnsetThingPosition(mobj); // Stop any playing sound S_StopSound(mobj); // Free block P_RemoveThinker((thinker_t *) mobj); } //========================================================================== // // P_SpawnPlayer // // Called when a player is spawned on the level. Most of the player // structure stays unchanged between levels. // //========================================================================== void P_SpawnPlayer(mapthing_t * mthing) { player_t *p; fixed_t x, y, z; mobj_t *mobj; if (mthing->type - 1 >= maxplayers || !playeringame[mthing->type - 1]) { // Not playing return; } p = &players[mthing->type - 1]; if (p->playerstate == PST_REBORN) { G_PlayerReborn(mthing->type - 1); } x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; z = ONFLOORZ; if (randomclass && deathmatch) { p->class = P_Random() % 3; if (p->class == PlayerClass[mthing->type - 1]) { p->class = (p->class + 1) % 3; } PlayerClass[mthing->type - 1] = p->class; SB_SetClassData(); } else { p->class = PlayerClass[mthing->type - 1]; } switch (p->class) { case PCLASS_FIGHTER: mobj = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER); break; case PCLASS_CLERIC: mobj = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC); break; case PCLASS_MAGE: mobj = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE); break; default: I_Error("P_SpawnPlayer: Unknown class type"); return; } // Set translation table data if (p->class == PCLASS_FIGHTER && (mthing->type == 1 || mthing->type == 3)) { // The first type should be blue, and the third should be the // Fighter's original gold color if (mthing->type == 1) { mobj->flags |= 2 << MF_TRANSSHIFT; } } else if (mthing->type > 1) { // Set color translation bits for player sprites mobj->flags |= (mthing->type - 1) << MF_TRANSSHIFT; } mobj->angle = ANG45 * (mthing->angle / 45); mobj->player = p; mobj->health = p->health; p->mo = mobj; p->playerstate = PST_LIVE; p->refire = 0; P_ClearMessage(p); p->damagecount = 0; p->bonuscount = 0; p->poisoncount = 0; p->morphTics = 0; p->extralight = 0; p->fixedcolormap = 0; p->viewheight = VIEWHEIGHT; P_SetupPsprites(p); if (deathmatch) { // Give all keys in death match mode p->keys = 2047; } } //========================================================================== // // P_SpawnMapThing // // The fields of the mapthing should already be in host byte order. // //========================================================================== void P_SpawnMapThing(mapthing_t * mthing) { int i; unsigned int spawnMask; mobj_t *mobj; fixed_t x, y, z; static unsigned int classFlags[] = { MTF_FIGHTER, MTF_CLERIC, MTF_MAGE }; // Count deathmatch start positions if (mthing->type == 11) { if (deathmatch_p < &deathmatchstarts[MAXDEATHMATCHSTARTS]) { memcpy(deathmatch_p, mthing, sizeof(*mthing)); deathmatch_p++; } return; } if (mthing->type == PO_ANCHOR_TYPE) { // Polyobj Anchor Pt. return; } else if (mthing->type == PO_SPAWN_TYPE || mthing->type == PO_SPAWNCRUSH_TYPE) { // Polyobj Anchor Pt. po_NumPolyobjs++; return; } // Check for player starts 1 to 4 if (mthing->type <= 4) { playerstarts[mthing->arg1][mthing->type - 1] = *mthing; if (!deathmatch && !mthing->arg1) { P_SpawnPlayer(mthing); } return; } // Check for player starts 5 to 8 if (mthing->type >= 9100 && mthing->type <= 9103) { mapthing_t *player_start; int player; player = 4 + mthing->type - 9100; player_start = &playerstarts[mthing->arg1][player]; memcpy(player_start, mthing, sizeof(mapthing_t)); player_start->type = player + 1; if (!deathmatch && !player_start->arg1) { P_SpawnPlayer(player_start); } return; } if (mthing->type >= 1400 && mthing->type < 1410) { R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->seqType = mthing->type - 1400; return; } // Check current game type with spawn flags if (netgame == false) { spawnMask = MTF_GSINGLE; } else if (deathmatch) { spawnMask = MTF_GDEATHMATCH; } else { spawnMask = MTF_GCOOP; } if (!(mthing->options & spawnMask)) { return; } // Check current skill with spawn flags if (gameskill == sk_baby || gameskill == sk_easy) { spawnMask = MTF_EASY; } else if (gameskill == sk_hard || gameskill == sk_nightmare) { spawnMask = MTF_HARD; } else { spawnMask = MTF_NORMAL; } if (!(mthing->options & spawnMask)) { return; } // Check current character classes with spawn flags if (netgame == false) { // Single player if ((mthing->options & classFlags[PlayerClass[0]]) == 0) { // Not for current class return; } } else if (deathmatch == false) { // Cooperative spawnMask = 0; for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { spawnMask |= classFlags[PlayerClass[i]]; } } if ((mthing->options & spawnMask) == 0) { return; } } // Find which type to spawn for (i = 0; i < NUMMOBJTYPES; i++) { if (mthing->type == mobjinfo[i].doomednum) { break; } } if (i == NUMMOBJTYPES) { // Can't find thing type I_Error("P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type, mthing->x, mthing->y); } // Don't spawn keys and players in deathmatch if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) { return; } // Don't spawn monsters if -nomonsters if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL)) { return; } x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (mobjinfo[i].flags & MF_SPAWNCEILING) { z = ONCEILINGZ; } else if (mobjinfo[i].flags2 & MF2_SPAWNFLOAT) { z = FLOATRANDZ; } else if (mobjinfo[i].flags2 & MF2_FLOATBOB) { z = mthing->height << FRACBITS; } else { z = ONFLOORZ; } switch (i) { // Special stuff case MT_ZLYNCHED_NOHEART: P_SpawnMobj(x, y, ONFLOORZ, MT_BLOODPOOL); break; default: break; } mobj = P_SpawnMobj(x, y, z, i); if (z == ONFLOORZ) { mobj->z += mthing->height << FRACBITS; } else if (z == ONCEILINGZ) { mobj->z -= mthing->height << FRACBITS; } mobj->tid = mthing->tid; mobj->special = mthing->special; mobj->args[0] = mthing->arg1; mobj->args[1] = mthing->arg2; mobj->args[2] = mthing->arg3; mobj->args[3] = mthing->arg4; mobj->args[4] = mthing->arg5; if (mobj->flags2 & MF2_FLOATBOB) { // Seed random starting index for bobbing motion mobj->health = P_Random(); mobj->special1.i = mthing->height << FRACBITS; } if (mobj->tics > 0) { mobj->tics = 1 + (P_Random() % mobj->tics); } // if(mobj->flags&MF_COUNTITEM) // { // totalitems++; // } if (mobj->flags & MF_COUNTKILL) { // Quantize angle to 45 degree increments mobj->angle = ANG45 * (mthing->angle / 45); } else { // Scale angle correctly (source is 0..359) mobj->angle = ((mthing->angle << 8) / 360) << 24; } if (mthing->options & MTF_AMBUSH) { mobj->flags |= MF_AMBUSH; } if (mthing->options & MTF_DORMANT) { mobj->flags2 |= MF2_DORMANT; if (mobj->type == MT_ICEGUY) { P_SetMobjState(mobj, S_ICEGUY_DORMANT); } mobj->tics = -1; } } //========================================================================== // // P_CreateTIDList // //========================================================================== void P_CreateTIDList(void) { int i; mobj_t *mobj; thinker_t *t; i = 0; for (t = thinkercap.next; t != &thinkercap; t = t->next) { // Search all current thinkers if (t->function != P_MobjThinker) { // Not a mobj thinker continue; } mobj = (mobj_t *) t; if (mobj->tid != 0) { // Add to list if (i == MAX_TID_COUNT) { I_Error("P_CreateTIDList: MAX_TID_COUNT (%d) exceeded.", MAX_TID_COUNT); } TIDList[i] = mobj->tid; TIDMobj[i++] = mobj; } } // Add termination marker TIDList[i] = 0; } //========================================================================== // // P_InsertMobjIntoTIDList // //========================================================================== void P_InsertMobjIntoTIDList(mobj_t * mobj, int tid) { int i; int index; index = -1; for (i = 0; TIDList[i] != 0; i++) { if (TIDList[i] == -1) { // Found empty slot index = i; break; } } if (index == -1) { // Append required if (i == MAX_TID_COUNT) { I_Error("P_InsertMobjIntoTIDList: MAX_TID_COUNT (%d)" "exceeded.", MAX_TID_COUNT); } index = i; TIDList[index + 1] = 0; } mobj->tid = tid; TIDList[index] = tid; TIDMobj[index] = mobj; } //========================================================================== // // P_RemoveMobjFromTIDList // //========================================================================== void P_RemoveMobjFromTIDList(mobj_t * mobj) { int i; for (i = 0; TIDList[i] != 0; i++) { if (TIDMobj[i] == mobj) { TIDList[i] = -1; TIDMobj[i] = NULL; mobj->tid = 0; return; } } mobj->tid = 0; } //========================================================================== // // P_FindMobjFromTID // //========================================================================== mobj_t *P_FindMobjFromTID(int tid, int *searchPosition) { int i; for (i = *searchPosition + 1; TIDList[i] != 0; i++) { if (TIDList[i] == tid) { *searchPosition = i; return TIDMobj[i]; } } *searchPosition = -1; return NULL; } /* =============================================================================== GAME SPAWN FUNCTIONS =============================================================================== */ //--------------------------------------------------------------------------- // // PROC P_SpawnPuff // //--------------------------------------------------------------------------- extern fixed_t attackrange; void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z) { mobj_t *puff; z += ((P_Random() - P_Random()) << 10); puff = P_SpawnMobj(x, y, z, PuffType); if (linetarget && puff->info->seesound) { // Hit thing sound S_StartSound(puff, puff->info->seesound); } else if (puff->info->attacksound) { S_StartSound(puff, puff->info->attacksound); } switch (PuffType) { case MT_PUNCHPUFF: puff->momz = FRACUNIT; break; case MT_HAMMERPUFF: puff->momz = .8 * FRACUNIT; break; default: break; } PuffSpawned = puff; } /* ================ = = P_SpawnBlood = ================ */ /* void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage) { mobj_t *th; z += ((P_Random()-P_Random())<<10); th = P_SpawnMobj (x,y,z, MT_BLOOD); th->momz = FRACUNIT*2; th->tics -= P_Random()&3; if (damage <= 12 && damage >= 9) P_SetMobjState (th,S_BLOOD2); else if (damage < 9) P_SetMobjState (th,S_BLOOD3); } */ //--------------------------------------------------------------------------- // // PROC P_BloodSplatter // //--------------------------------------------------------------------------- void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator) { mobj_t *mo; mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER); mo->target = originator; mo->momx = (P_Random() - P_Random()) << 10; mo->momy = (P_Random() - P_Random()) << 10; mo->momz = 3 * FRACUNIT; } //=========================================================================== // // P_BloodSplatter2 // //=========================================================================== void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator) { mobj_t *mo; mo = P_SpawnMobj(x + ((P_Random() - 128) << 11), y + ((P_Random() - 128) << 11), z, MT_AXEBLOOD); mo->target = originator; } //--------------------------------------------------------------------------- // // PROC P_RipperBlood // //--------------------------------------------------------------------------- void P_RipperBlood(mobj_t * mo) { mobj_t *th; fixed_t x, y, z; x = mo->x + ((P_Random() - P_Random()) << 12); y = mo->y + ((P_Random() - P_Random()) << 12); z = mo->z + ((P_Random() - P_Random()) << 12); th = P_SpawnMobj(x, y, z, MT_BLOOD); // th->flags |= MF_NOGRAVITY; th->momx = mo->momx >> 1; th->momy = mo->momy >> 1; th->tics += P_Random() & 3; } //--------------------------------------------------------------------------- // // FUNC P_GetThingFloorType // //--------------------------------------------------------------------------- int P_GetThingFloorType(mobj_t * thing) { if (thing->floorpic) { return (TerrainTypes[thing->floorpic]); } else { return (TerrainTypes[thing->subsector->sector->floorpic]); } /* if(thing->subsector->sector->floorpic == W_GetNumForName("FLTWAWA1")-firstflat) { return(FLOOR_WATER); } else { return(FLOOR_SOLID); } */ } //--------------------------------------------------------------------------- // // FUNC P_HitFloor // //--------------------------------------------------------------------------- #define SMALLSPLASHCLIP 12<floorz != thing->subsector->sector->floorheight) { // don't splash if landing on the edge above water/lava/etc.... return (FLOOR_SOLID); } // Things that don't splash go here switch (thing->type) { case MT_LEAF1: case MT_LEAF2: // case MT_BLOOD: // I set these to low mass -- pm // case MT_BLOODSPLATTER: case MT_SPLASH: case MT_SLUDGECHUNK: return (FLOOR_SOLID); default: break; } // Small splash for small masses if (thing->info->mass < 10) smallsplash = true; switch (P_GetThingFloorType(thing)) { case FLOOR_WATER: if (smallsplash) { mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE); if (mo) mo->floorclip += SMALLSPLASHCLIP; S_StartSound(mo, SFX_AMBIENT10); // small drip } else { mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH); mo->target = thing; mo->momx = (P_Random() - P_Random()) << 8; mo->momy = (P_Random() - P_Random()) << 8; mo->momz = 2 * FRACUNIT + (P_Random() << 8); mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE); if (thing->player) P_NoiseAlert(thing, thing); S_StartSound(mo, SFX_WATER_SPLASH); } return (FLOOR_WATER); case FLOOR_LAVA: if (smallsplash) { mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH); if (mo) mo->floorclip += SMALLSPLASHCLIP; } else { mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE); mo->momz = FRACUNIT + (P_Random() << 7); mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH); if (thing->player) P_NoiseAlert(thing, thing); } S_StartSound(mo, SFX_LAVA_SIZZLE); if (thing->player && leveltime & 31) { P_DamageMobj(thing, &LavaInflictor, NULL, 5); } return (FLOOR_LAVA); case FLOOR_SLUDGE: if (smallsplash) { mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH); if (mo) mo->floorclip += SMALLSPLASHCLIP; } else { mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK); mo->target = thing; mo->momx = (P_Random() - P_Random()) << 8; mo->momy = (P_Random() - P_Random()) << 8; mo->momz = FRACUNIT + (P_Random() << 8); mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH); if (thing->player) P_NoiseAlert(thing, thing); } S_StartSound(mo, SFX_SLUDGE_GLOOP); return (FLOOR_SLUDGE); } return (FLOOR_SOLID); } //--------------------------------------------------------------------------- // // FUNC P_CheckMissileSpawn // // Returns true if the missile is at a valid spawn point, otherwise // explodes it and returns false. // //--------------------------------------------------------------------------- boolean P_CheckMissileSpawn(mobj_t * missile) { //missile->tics -= P_Random()&3; // move a little forward so an angle can be computed if it // immediately explodes missile->x += (missile->momx >> 1); missile->y += (missile->momy >> 1); missile->z += (missile->momz >> 1); if (!P_TryMove(missile, missile->x, missile->y)) { P_ExplodeMissile(missile); return (false); } return (true); } //--------------------------------------------------------------------------- // // FUNC P_SpawnMissile // // Returns NULL if the missile exploded immediately, otherwise returns // a mobj_t pointer to the missile. // //--------------------------------------------------------------------------- mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type) { fixed_t z; mobj_t *th; angle_t an; int dist; switch (type) { case MT_MNTRFX1: // Minotaur swing attack missile z = source->z + 40 * FRACUNIT; break; case MT_MNTRFX2: // Minotaur floor fire missile z = ONFLOORZ + source->floorclip; break; case MT_CENTAUR_FX: z = source->z + 45 * FRACUNIT; break; case MT_ICEGUY_FX: z = source->z + 40 * FRACUNIT; break; case MT_HOLY_MISSILE: z = source->z + 40 * FRACUNIT; break; default: z = source->z + 32 * FRACUNIT; break; } z -= source->floorclip; th = P_SpawnMobj(source->x, source->y, z, type); if (th->info->seesound) { S_StartSound(th, th->info->seesound); } th->target = source; // Originator an = R_PointToAngle2(source->x, source->y, dest->x, dest->y); if (dest->flags & MF_SHADOW) { // Invisible target an += (P_Random() - P_Random()) << 21; } th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(th->info->speed, finecosine[an]); th->momy = FixedMul(th->info->speed, finesine[an]); dist = P_AproxDistance(dest->x - source->x, dest->y - source->y); dist = dist / th->info->speed; if (dist < 1) { dist = 1; } th->momz = (dest->z - source->z) / dist; return (P_CheckMissileSpawn(th) ? th : NULL); } //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileXYZ // // Returns NULL if the missile exploded immediately, otherwise returns // a mobj_t pointer to the missile. // //--------------------------------------------------------------------------- mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z, mobj_t * source, mobj_t * dest, mobjtype_t type) { mobj_t *th; angle_t an; int dist; z -= source->floorclip; th = P_SpawnMobj(x, y, z, type); if (th->info->seesound) { S_StartSound(th, th->info->seesound); } th->target = source; // Originator an = R_PointToAngle2(source->x, source->y, dest->x, dest->y); if (dest->flags & MF_SHADOW) { // Invisible target an += (P_Random() - P_Random()) << 21; } th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(th->info->speed, finecosine[an]); th->momy = FixedMul(th->info->speed, finesine[an]); dist = P_AproxDistance(dest->x - source->x, dest->y - source->y); dist = dist / th->info->speed; if (dist < 1) { dist = 1; } th->momz = (dest->z - source->z) / dist; return (P_CheckMissileSpawn(th) ? th : NULL); } //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileAngle // // Returns NULL if the missile exploded immediately, otherwise returns // a mobj_t pointer to the missile. // //--------------------------------------------------------------------------- mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type, angle_t angle, fixed_t momz) { fixed_t z; mobj_t *mo; switch (type) { case MT_MNTRFX1: // Minotaur swing attack missile z = source->z + 40 * FRACUNIT; break; case MT_MNTRFX2: // Minotaur floor fire missile z = ONFLOORZ + source->floorclip; break; case MT_ICEGUY_FX2: // Secondary Projectiles of the Ice Guy z = source->z + 3 * FRACUNIT; break; case MT_MSTAFF_FX2: z = source->z + 40 * FRACUNIT; break; default: z = source->z + 32 * FRACUNIT; break; } z -= source->floorclip; mo = P_SpawnMobj(source->x, source->y, z, type); if (mo->info->seesound) { S_StartSound(mo, mo->info->seesound); } mo->target = source; // Originator mo->angle = angle; angle >>= ANGLETOFINESHIFT; mo->momx = FixedMul(mo->info->speed, finecosine[angle]); mo->momy = FixedMul(mo->info->speed, finesine[angle]); mo->momz = momz; return (P_CheckMissileSpawn(mo) ? mo : NULL); } //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileAngleSpeed // // Returns NULL if the missile exploded immediately, otherwise returns // a mobj_t pointer to the missile. // //--------------------------------------------------------------------------- mobj_t *P_SpawnMissileAngleSpeed(mobj_t * source, mobjtype_t type, angle_t angle, fixed_t momz, fixed_t speed) { fixed_t z; mobj_t *mo; z = source->z; z -= source->floorclip; mo = P_SpawnMobj(source->x, source->y, z, type); if (mo->info->seesound) { //S_StartSound(mo, mo->info->seesound); } mo->target = source; // Originator mo->angle = angle; angle >>= ANGLETOFINESHIFT; mo->momx = FixedMul(speed, finecosine[angle]); mo->momy = FixedMul(speed, finesine[angle]); mo->momz = momz; return (P_CheckMissileSpawn(mo) ? mo : NULL); } /* ================ = = P_SpawnPlayerMissile = = Tries to aim at a nearby monster ================ */ mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type) { angle_t an; fixed_t x, y, z, slope; // Try to find a target an = source->angle; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an += 1 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an -= 2 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); } if (!linetarget) { an = source->angle; slope = ((source->player->lookdir) << FRACBITS) / 173; } } x = source->x; y = source->y; if (type == MT_LIGHTNING_FLOOR) { z = ONFLOORZ; slope = 0; } else if (type == MT_LIGHTNING_CEILING) { z = ONCEILINGZ; slope = 0; } else { z = source->z + 4 * 8 * FRACUNIT + ((source->player->lookdir) << FRACBITS) / 173; z -= source->floorclip; } MissileMobj = P_SpawnMobj(x, y, z, type); if (MissileMobj->info->seesound) { //S_StartSound(MissileMobj, MissileMobj->info->seesound); } MissileMobj->target = source; MissileMobj->angle = an; MissileMobj->momx = FixedMul(MissileMobj->info->speed, finecosine[an >> ANGLETOFINESHIFT]); MissileMobj->momy = FixedMul(MissileMobj->info->speed, finesine[an >> ANGLETOFINESHIFT]); MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope); if (MissileMobj->type == MT_MWAND_MISSILE || MissileMobj->type == MT_CFLAME_MISSILE) { // Ultra-fast ripper spawning missile MissileMobj->x += (MissileMobj->momx >> 3); MissileMobj->y += (MissileMobj->momy >> 3); MissileMobj->z += (MissileMobj->momz >> 3); } else { // Normal missile MissileMobj->x += (MissileMobj->momx >> 1); MissileMobj->y += (MissileMobj->momy >> 1); MissileMobj->z += (MissileMobj->momz >> 1); } if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y)) { // Exploded immediately P_ExplodeMissile(MissileMobj); return (NULL); } return (MissileMobj); } //---------------------------------------------------------------------------- // // P_SpawnPlayerMinotaur - // // Special missile that has larger blocking than player //---------------------------------------------------------------------------- /* mobj_t *P_SpawnPlayerMinotaur(mobj_t *source, mobjtype_t type) { angle_t an; fixed_t x, y, z; fixed_t dist=0 *FRACUNIT; an = source->angle; x = source->x + FixedMul(dist, finecosine[an>>ANGLETOFINESHIFT]); y = source->y + FixedMul(dist, finesine[an>>ANGLETOFINESHIFT]); z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<floorclip; MissileMobj = P_SpawnMobj(x, y, z, type); if(MissileMobj->info->seesound) { //S_StartSound(MissileMobj, MissileMobj->info->seesound); } MissileMobj->target = source; MissileMobj->angle = an; MissileMobj->momx = FixedMul(MissileMobj->info->speed, finecosine[an>>ANGLETOFINESHIFT]); MissileMobj->momy = FixedMul(MissileMobj->info->speed, finesine[an>>ANGLETOFINESHIFT]); MissileMobj->momz = 0; // MissileMobj->x += (MissileMobj->momx>>3); // MissileMobj->y += (MissileMobj->momy>>3); // MissileMobj->z += (MissileMobj->momz>>3); if(!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y)) { // Wouln't fit return(NULL); } return(MissileMobj); } */ //--------------------------------------------------------------------------- // // PROC P_SPMAngle // //--------------------------------------------------------------------------- mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle) { mobj_t *th; angle_t an; fixed_t x, y, z, slope; // // see which target is to be aimed at // an = angle; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an += 1 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an -= 2 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); } if (!linetarget) { an = angle; slope = ((source->player->lookdir) << FRACBITS) / 173; } } x = source->x; y = source->y; z = source->z + 4 * 8 * FRACUNIT + ((source->player->lookdir) << FRACBITS) / 173; z -= source->floorclip; th = P_SpawnMobj(x, y, z, type); // if(th->info->seesound) // { // S_StartSound(th, th->info->seesound); // } th->target = source; th->angle = an; th->momx = FixedMul(th->info->speed, finecosine[an >> ANGLETOFINESHIFT]); th->momy = FixedMul(th->info->speed, finesine[an >> ANGLETOFINESHIFT]); th->momz = FixedMul(th->info->speed, slope); return (P_CheckMissileSpawn(th) ? th : NULL); } //=========================================================================== // // P_SPMAngleXYZ // //=========================================================================== mobj_t *P_SPMAngleXYZ(mobj_t * source, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, angle_t angle) { mobj_t *th; angle_t an; fixed_t slope; // // see which target is to be aimed at // an = angle; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an += 1 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); if (!linetarget) { an -= 2 << 26; slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT); } if (!linetarget) { an = angle; slope = ((source->player->lookdir) << FRACBITS) / 173; } } z += 4 * 8 * FRACUNIT + ((source->player->lookdir) << FRACBITS) / 173; z -= source->floorclip; th = P_SpawnMobj(x, y, z, type); // if(th->info->seesound) // { // S_StartSound(th, th->info->seesound); // } th->target = source; th->angle = an; th->momx = FixedMul(th->info->speed, finecosine[an >> ANGLETOFINESHIFT]); th->momy = FixedMul(th->info->speed, finesine[an >> ANGLETOFINESHIFT]); th->momz = FixedMul(th->info->speed, slope); return (P_CheckMissileSpawn(th) ? th : NULL); } mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z, mobj_t * source, mobj_t * dest, mobjtype_t type) { mobj_t *th; angle_t an; int dist; z -= source->floorclip; th = P_SpawnMobj(x, y, z, type); if (th->info->seesound) { S_StartSound(th, th->info->seesound); } th->target = source; // Originator an = R_PointToAngle2(x, y, dest->x, dest->y); if (dest->flags & MF_SHADOW) { // Invisible target an += (P_Random() - P_Random()) << 21; } th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(th->info->speed, finecosine[an]); th->momy = FixedMul(th->info->speed, finesine[an]); dist = P_AproxDistance(dest->x - x, dest->y - y); dist = dist / th->info->speed; if (dist < 1) { dist = 1; } th->momz = (dest->z - z + (30 * FRACUNIT)) / dist; return (P_CheckMissileSpawn(th) ? th : NULL); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_plats.c000066400000000000000000000202701257432200600230120ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "m_random.h" #include "i_system.h" #include "p_local.h" plat_t *activeplats[MAXPLATS]; //================================================================== // // Move a plat up and down // //================================================================== void T_PlatRaise(plat_t * plat) { result_e res; switch (plat->status) { case PLAT_UP: res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush, 0, 1); if (res == RES_CRUSHED && (!plat->crush)) { plat->count = plat->wait; plat->status = PLAT_DOWN; SN_StartSequence((mobj_t *) & plat->sector->soundorg, SEQ_PLATFORM + plat->sector->seqType); } else if (res == RES_PASTDEST) { plat->count = plat->wait; plat->status = PLAT_WAITING; SN_StopSequence((mobj_t *) & plat->sector->soundorg); switch (plat->type) { case PLAT_DOWNWAITUPSTAY: case PLAT_DOWNBYVALUEWAITUPSTAY: P_RemoveActivePlat(plat); break; default: break; } } break; case PLAT_DOWN: res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1); if (res == RES_PASTDEST) { plat->count = plat->wait; plat->status = PLAT_WAITING; switch (plat->type) { case PLAT_UPWAITDOWNSTAY: case PLAT_UPBYVALUEWAITDOWNSTAY: P_RemoveActivePlat(plat); break; default: break; } SN_StopSequence((mobj_t *) & plat->sector->soundorg); } break; case PLAT_WAITING: if (!--plat->count) { if (plat->sector->floorheight == plat->low) plat->status = PLAT_UP; else plat->status = PLAT_DOWN; SN_StartSequence((mobj_t *) & plat->sector->soundorg, SEQ_PLATFORM + plat->sector->seqType); } // case PLAT_IN_STASIS: // break; } } //================================================================== // // Do Platforms // "amount" is only used for SOME platforms. // //================================================================== int EV_DoPlat(line_t * line, byte * args, plattype_e type, int amount) { plat_t *plat; int secnum; int rtn; sector_t *sec; secnum = -1; rtn = 0; /* // // Activate all plats that are in_stasis // switch(type) { case PLAT_PERPETUALRAISE: P_ActivateInStasis(args[0]); break; default: break; } */ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // // Find lowest & highest floors around sector // rtn = 1; plat = Z_Malloc(sizeof(*plat), PU_LEVSPEC, 0); P_AddThinker(&plat->thinker); plat->type = type; plat->sector = sec; plat->sector->specialdata = plat; plat->thinker.function = T_PlatRaise; plat->crush = false; plat->tag = args[0]; plat->speed = args[1] * (FRACUNIT / 8); switch (type) { case PLAT_DOWNWAITUPSTAY: plat->low = P_FindLowestFloorSurrounding(sec) + 8 * FRACUNIT; if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = args[2]; plat->status = PLAT_DOWN; break; case PLAT_DOWNBYVALUEWAITUPSTAY: plat->low = sec->floorheight - args[3] * 8 * FRACUNIT; if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = args[2]; plat->status = PLAT_DOWN; break; case PLAT_UPWAITDOWNSTAY: plat->high = P_FindHighestFloorSurrounding(sec); if (plat->high < sec->floorheight) plat->high = sec->floorheight; plat->low = sec->floorheight; plat->wait = args[2]; plat->status = PLAT_UP; break; case PLAT_UPBYVALUEWAITDOWNSTAY: plat->high = sec->floorheight + args[3] * 8 * FRACUNIT; if (plat->high < sec->floorheight) plat->high = sec->floorheight; plat->low = sec->floorheight; plat->wait = args[2]; plat->status = PLAT_UP; break; case PLAT_PERPETUALRAISE: plat->low = P_FindLowestFloorSurrounding(sec) + 8 * FRACUNIT; if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = P_FindHighestFloorSurrounding(sec); if (plat->high < sec->floorheight) plat->high = sec->floorheight; plat->wait = args[2]; plat->status = P_Random() & 1; break; } P_AddActivePlat(plat); SN_StartSequence((mobj_t *) & sec->soundorg, SEQ_PLATFORM + sec->seqType); } return rtn; } #if 0 void P_ActivateInStasis(int tag) { int i; for (i = 0; i < MAXPLATS; i++) if (activeplats[i] && (activeplats[i])->tag == tag && (activeplats[i])->status == PLAT_IN_STASIS) { (activeplats[i])->status = (activeplats[i])->oldstatus; (activeplats[i])->thinker.function = T_PlatRaise; } } #endif void EV_StopPlat(line_t * line, byte * args) { int i; for (i = 0; i < MAXPLATS; i++) { activeplats[i]->tag = args[0]; if (activeplats[i]->tag != 0) { activeplats[i]->sector->specialdata = NULL; P_TagFinished(activeplats[i]->sector->tag); P_RemoveThinker(&activeplats[i]->thinker); activeplats[i] = NULL; return; } } /* int j; for (j = 0;j < MAXPLATS;j++) { if (activeplats[j] && ((activeplats[j])->status != PLAT_IN_STASIS) && ((activeplats[j])->tag == args[0])) { (activeplats[j])->oldstatus = (activeplats[j])->status; (activeplats[j])->status = PLAT_IN_STASIS; (activeplats[j])->thinker.function = NULL; SN_StopSequence((mobj_t *)&(activeplats[j])->sector->soundorg); } } */ } void P_AddActivePlat(plat_t * plat) { int i; for (i = 0; i < MAXPLATS; i++) if (activeplats[i] == NULL) { activeplats[i] = plat; return; } I_Error("P_AddActivePlat: no more plats!"); } void P_RemoveActivePlat(plat_t * plat) { int i; for (i = 0; i < MAXPLATS; i++) if (plat == activeplats[i]) { (activeplats[i])->sector->specialdata = NULL; P_TagFinished(plat->sector->tag); P_RemoveThinker(&(activeplats[i])->thinker); activeplats[i] = NULL; return; } I_Error("P_RemoveActivePlat: can't find plat!"); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_pspr.c000066400000000000000000002136301257432200600226570ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" // MACROS ------------------------------------------------------------------ #define LOWERSPEED FRACUNIT*6 #define RAISESPEED FRACUNIT*6 #define WEAPONBOTTOM 128*FRACUNIT #define WEAPONTOP 32*FRACUNIT // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- extern void P_ExplodeMissile(mobj_t * mo); extern void A_UnHideThing(mobj_t * actor); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern fixed_t FloatBobOffsets[64]; // PUBLIC DATA DEFINITIONS ------------------------------------------------- fixed_t bulletslope; weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES] = { { // First Weapons { // Fighter First Weapon - Punch MANA_NONE, // mana S_PUNCHUP, // upstate S_PUNCHDOWN, // downstate S_PUNCHREADY, // readystate S_PUNCHATK1_1, // atkstate S_PUNCHATK1_1, // holdatkstate S_NULL // flashstate }, { // Cleric First Weapon - Mace MANA_NONE, // mana S_CMACEUP, // upstate S_CMACEDOWN, // downstate S_CMACEREADY, // readystate S_CMACEATK_1, // atkstate S_CMACEATK_1, // holdatkstate S_NULL // flashstate }, { // Mage First Weapon - Wand MANA_NONE, S_MWANDUP, S_MWANDDOWN, S_MWANDREADY, S_MWANDATK_1, S_MWANDATK_1, S_NULL}, { // Pig - Snout MANA_NONE, // mana S_SNOUTUP, // upstate S_SNOUTDOWN, // downstate S_SNOUTREADY, // readystate S_SNOUTATK1, // atkstate S_SNOUTATK1, // holdatkstate S_NULL // flashstate } }, { // Second Weapons { // Fighter - Axe MANA_NONE, // mana S_FAXEUP, // upstate S_FAXEDOWN, // downstate S_FAXEREADY, // readystate S_FAXEATK_1, // atkstate S_FAXEATK_1, // holdatkstate S_NULL // flashstate }, { // Cleric - Serpent Staff MANA_1, // mana S_CSTAFFUP, // upstate S_CSTAFFDOWN, // downstate S_CSTAFFREADY, // readystate S_CSTAFFATK_1, // atkstate S_CSTAFFATK_1, // holdatkstate S_NULL // flashstate }, { // Mage - Cone of shards MANA_1, // mana S_CONEUP, // upstate S_CONEDOWN, // downstate S_CONEREADY, // readystate S_CONEATK1_1, // atkstate S_CONEATK1_3, // holdatkstate S_NULL // flashstate }, { // Pig - Snout MANA_NONE, // mana S_SNOUTUP, // upstate S_SNOUTDOWN, // downstate S_SNOUTREADY, // readystate S_SNOUTATK1, // atkstate S_SNOUTATK1, // holdatkstate S_NULL // flashstate } }, { // Third Weapons { // Fighter - Hammer MANA_NONE, // mana S_FHAMMERUP, // upstate S_FHAMMERDOWN, // downstate S_FHAMMERREADY, // readystate S_FHAMMERATK_1, // atkstate S_FHAMMERATK_1, // holdatkstate S_NULL // flashstate }, { // Cleric - Flame Strike MANA_2, // mana S_CFLAMEUP, // upstate S_CFLAMEDOWN, // downstate S_CFLAMEREADY1, // readystate S_CFLAMEATK_1, // atkstate S_CFLAMEATK_1, // holdatkstate S_NULL // flashstate }, { // Mage - Lightning MANA_2, // mana S_MLIGHTNINGUP, // upstate S_MLIGHTNINGDOWN, // downstate S_MLIGHTNINGREADY, // readystate S_MLIGHTNINGATK_1, // atkstate S_MLIGHTNINGATK_1, // holdatkstate S_NULL // flashstate }, { // Pig - Snout MANA_NONE, // mana S_SNOUTUP, // upstate S_SNOUTDOWN, // downstate S_SNOUTREADY, // readystate S_SNOUTATK1, // atkstate S_SNOUTATK1, // holdatkstate S_NULL // flashstate } }, { // Fourth Weapons { // Fighter - Rune Sword MANA_BOTH, // mana S_FSWORDUP, // upstate S_FSWORDDOWN, // downstate S_FSWORDREADY, // readystate S_FSWORDATK_1, // atkstate S_FSWORDATK_1, // holdatkstate S_NULL // flashstate }, { // Cleric - Holy Symbol MANA_BOTH, // mana S_CHOLYUP, // upstate S_CHOLYDOWN, // downstate S_CHOLYREADY, // readystate S_CHOLYATK_1, // atkstate S_CHOLYATK_1, // holdatkstate S_NULL // flashstate }, { // Mage - Staff MANA_BOTH, // mana S_MSTAFFUP, // upstate S_MSTAFFDOWN, // downstate S_MSTAFFREADY, // readystate S_MSTAFFATK_1, // atkstate S_MSTAFFATK_1, // holdatkstate S_NULL // flashstate }, { // Pig - Snout MANA_NONE, // mana S_SNOUTUP, // upstate S_SNOUTDOWN, // downstate S_SNOUTREADY, // readystate S_SNOUTATK1, // atkstate S_SNOUTATK1, // holdatkstate S_NULL // flashstate } } }; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] = { {0, 2, 3, 14}, {0, 1, 4, 18}, {0, 3, 5, 15}, {0, 0, 0, 0} }; // CODE -------------------------------------------------------------------- //--------------------------------------------------------------------------- // // PROC P_SetPsprite // //--------------------------------------------------------------------------- void P_SetPsprite(player_t * player, int position, statenum_t stnum) { pspdef_t *psp; state_t *state; psp = &player->psprites[position]; do { if (!stnum) { // Object removed itself. psp->state = NULL; break; } state = &states[stnum]; psp->state = state; psp->tics = state->tics; // could be 0 if (state->misc1) { // Set coordinates. psp->sx = state->misc1 << FRACBITS; } if (state->misc2) { psp->sy = state->misc2 << FRACBITS; } if (state->action) { // Call action routine. state->action(player, psp); if (!psp->state) { break; } } stnum = psp->state->nextstate; } while (!psp->tics); // An initial state of 0 could cycle through. } //--------------------------------------------------------------------------- // // PROC P_SetPspriteNF // // Identical to P_SetPsprite, without calling the action function //--------------------------------------------------------------------------- void P_SetPspriteNF(player_t * player, int position, statenum_t stnum) { pspdef_t *psp; state_t *state; psp = &player->psprites[position]; do { if (!stnum) { // Object removed itself. psp->state = NULL; break; } state = &states[stnum]; psp->state = state; psp->tics = state->tics; // could be 0 if (state->misc1) { // Set coordinates. psp->sx = state->misc1 << FRACBITS; } if (state->misc2) { psp->sy = state->misc2 << FRACBITS; } stnum = psp->state->nextstate; } while (!psp->tics); // An initial state of 0 could cycle through. } /* ================= = = P_CalcSwing = ================= */ /* fixed_t swingx, swingy; void P_CalcSwing (player_t *player) { fixed_t swing; int angle; // OPTIMIZE: tablify this swing = player->bob; angle = (FINEANGLES/70*leveltime)&FINEMASK; swingx = FixedMul ( swing, finesine[angle]); angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK; swingy = -FixedMul ( swingx, finesine[angle]); } */ //--------------------------------------------------------------------------- // // PROC P_ActivateMorphWeapon // //--------------------------------------------------------------------------- void P_ActivateMorphWeapon(player_t * player) { player->pendingweapon = WP_NOCHANGE; player->psprites[ps_weapon].sy = WEAPONTOP; player->readyweapon = WP_FIRST; // Snout is the first weapon P_SetPsprite(player, ps_weapon, S_SNOUTREADY); } //--------------------------------------------------------------------------- // // PROC P_PostMorphWeapon // //--------------------------------------------------------------------------- void P_PostMorphWeapon(player_t * player, weapontype_t weapon) { player->pendingweapon = WP_NOCHANGE; player->readyweapon = weapon; player->psprites[ps_weapon].sy = WEAPONBOTTOM; P_SetPsprite(player, ps_weapon, WeaponInfo[weapon][player->class].upstate); } //--------------------------------------------------------------------------- // // PROC P_BringUpWeapon // // Starts bringing the pending weapon up from the bottom of the screen. // //--------------------------------------------------------------------------- void P_BringUpWeapon(player_t * player) { statenum_t new; if (player->pendingweapon == WP_NOCHANGE) { player->pendingweapon = player->readyweapon; } if (player->class == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND && player->mana[MANA_1]) { new = S_FAXEUP_G; } else { new = WeaponInfo[player->pendingweapon][player->class].upstate; } player->pendingweapon = WP_NOCHANGE; player->psprites[ps_weapon].sy = WEAPONBOTTOM; P_SetPsprite(player, ps_weapon, new); } //--------------------------------------------------------------------------- // // FUNC P_CheckMana // // Returns true if there is enough mana to shoot. If not, selects the // next weapon to use. // //--------------------------------------------------------------------------- boolean P_CheckMana(player_t * player) { manatype_t mana; int count; mana = WeaponInfo[player->readyweapon][player->class].mana; count = WeaponManaUse[player->class][player->readyweapon]; if (mana == MANA_BOTH) { if (player->mana[MANA_1] >= count && player->mana[MANA_2] >= count) { return true; } } else if (mana == MANA_NONE || player->mana[mana] >= count) { return (true); } // out of mana, pick a weapon to change to do { if (player->weaponowned[WP_THIRD] && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_THIRD]) { player->pendingweapon = WP_THIRD; } else if (player->weaponowned[WP_SECOND] && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_SECOND]) { player->pendingweapon = WP_SECOND; } else if (player->weaponowned[WP_FOURTH] && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_FOURTH] && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_FOURTH]) { player->pendingweapon = WP_FOURTH; } else { player->pendingweapon = WP_FIRST; } } while (player->pendingweapon == WP_NOCHANGE); P_SetPsprite(player, ps_weapon, WeaponInfo[player->readyweapon][player->class].downstate); return (false); } //--------------------------------------------------------------------------- // // PROC P_FireWeapon // //--------------------------------------------------------------------------- void P_FireWeapon(player_t * player) { statenum_t attackState; if (!P_CheckMana(player)) { return; } P_SetMobjState(player->mo, PStateAttack[player->class]); // S_PLAY_ATK1); if (player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND && player->mana[MANA_1] > 0) { // Glowing axe attackState = S_FAXEATK_G1; } else { attackState = player->refire ? WeaponInfo[player->readyweapon][player->class].holdatkstate : WeaponInfo[player->readyweapon][player->class].atkstate; } P_SetPsprite(player, ps_weapon, attackState); P_NoiseAlert(player->mo, player->mo); } //--------------------------------------------------------------------------- // // PROC P_DropWeapon // // The player died, so put the weapon away. // //--------------------------------------------------------------------------- void P_DropWeapon(player_t * player) { P_SetPsprite(player, ps_weapon, WeaponInfo[player->readyweapon][player->class].downstate); } //--------------------------------------------------------------------------- // // PROC A_WeaponReady // // The player can fire the weapon or change to another weapon at this time. // //--------------------------------------------------------------------------- void A_WeaponReady(player_t * player, pspdef_t * psp) { int angle; // Change player from attack state if (player->mo->state >= &states[PStateAttack[player->class]] && player->mo->state <= &states[PStateAttackEnd[player->class]]) { P_SetMobjState(player->mo, PStateNormal[player->class]); } // Put the weapon away if the player has a pending weapon or has // died. if (player->pendingweapon != WP_NOCHANGE || !player->health) { P_SetPsprite(player, ps_weapon, WeaponInfo[player->readyweapon][player->class]. downstate); return; } // Check for fire. if (player->cmd.buttons & BT_ATTACK) { player->attackdown = true; P_FireWeapon(player); return; } else { player->attackdown = false; } if (!player->morphTics) { // Bob the weapon based on movement speed. angle = (128 * leveltime) & FINEMASK; psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]); angle &= FINEANGLES / 2 - 1; psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); } } //--------------------------------------------------------------------------- // // PROC A_ReFire // // The player can re fire the weapon without lowering it entirely. // //--------------------------------------------------------------------------- void A_ReFire(player_t * player, pspdef_t * psp) { if ((player->cmd.buttons & BT_ATTACK) && player->pendingweapon == WP_NOCHANGE && player->health) { player->refire++; P_FireWeapon(player); } else { player->refire = 0; P_CheckMana(player); } } //--------------------------------------------------------------------------- // // PROC A_Lower // //--------------------------------------------------------------------------- void A_Lower(player_t * player, pspdef_t * psp) { if (player->morphTics) { psp->sy = WEAPONBOTTOM; } else { psp->sy += LOWERSPEED; } if (psp->sy < WEAPONBOTTOM) { // Not lowered all the way yet return; } if (player->playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon psp->sy = WEAPONBOTTOM; return; } if (!player->health) { // Player is dead, so keep the weapon off screen P_SetPsprite(player, ps_weapon, S_NULL); return; } player->readyweapon = player->pendingweapon; P_BringUpWeapon(player); } //--------------------------------------------------------------------------- // // PROC A_Raise // //--------------------------------------------------------------------------- void A_Raise(player_t * player, pspdef_t * psp) { psp->sy -= RAISESPEED; if (psp->sy > WEAPONTOP) { // Not raised all the way yet return; } psp->sy = WEAPONTOP; if (player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND && player->mana[MANA_1]) { P_SetPsprite(player, ps_weapon, S_FAXEREADY_G); } else { P_SetPsprite(player, ps_weapon, WeaponInfo[player->readyweapon][player->class]. readystate); } } /* =============== = = P_BulletSlope = = Sets a slope so a near miss is at aproximately the height of the = intended target = =============== */ /* void P_BulletSlope (mobj_t *mo) { angle_t an; // // see which target is to be aimed at // an = mo->angle; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); if (!linetarget) { an += 1<<26; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); if (!linetarget) { an -= 2<<26; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); } if (!linetarget) { an += 1<<26; bulletslope = (mo->player->lookdir<x, pmo->y, linetarget->x, linetarget->y); difference = (int) angle - (int) pmo->angle; if (abs(difference) > MAX_ANGADJUST) { pmo->angle += difference > 0 ? MAX_ANGADJUST : -MAX_ANGADJUST; } else { pmo->angle = angle; } } //============================================================================ // // A_SnoutAttack // //============================================================================ void A_SnoutAttack(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; damage = 3 + (P_Random() & 3); angle = player->mo->angle; slope = P_AimLineAttack(player->mo, angle, MELEERANGE); PuffType = MT_SNOUTPUFF; PuffSpawned = NULL; P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); S_StartSound(player->mo, SFX_PIG_ACTIVE1 + (P_Random() & 1)); if (linetarget) { AdjustPlayerAngle(player->mo); // player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->y, linetarget->x, linetarget->y); if (PuffSpawned) { // Bit something S_StartSound(player->mo, SFX_PIG_ATTACK); } } } //============================================================================ // // A_FHammerAttack // //============================================================================ #define HAMMER_RANGE (MELEERANGE+MELEERANGE/2) void A_FHammerAttack(player_t * player, pspdef_t * psp) { angle_t angle; mobj_t *pmo = player->mo; int damage; fixed_t power; int slope; int i; damage = 60 + (P_Random() & 63); power = 10 * FRACUNIT; PuffType = MT_HAMMERPUFF; for (i = 0; i < 16; i++) { angle = pmo->angle + i * (ANG45 / 32); slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE); if (linetarget) { P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage); AdjustPlayerAngle(pmo); if (linetarget->flags & MF_COUNTKILL || linetarget->player) { P_ThrustMobj(linetarget, angle, power); } pmo->special1.i = false; // Don't throw a hammer goto hammerdone; } angle = pmo->angle - i * (ANG45 / 32); slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE); if (linetarget) { P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage); AdjustPlayerAngle(pmo); if (linetarget->flags & MF_COUNTKILL || linetarget->player) { P_ThrustMobj(linetarget, angle, power); } pmo->special1.i = false; // Don't throw a hammer goto hammerdone; } } // didn't find any targets in meleerange, so set to throw out a hammer PuffSpawned = NULL; angle = pmo->angle; slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE); P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage); if (PuffSpawned) { pmo->special1.i = false; } else { pmo->special1.i = true; } hammerdone: if (player->mana[MANA_2] < WeaponManaUse[player->class][player->readyweapon]) { // Don't spawn a hammer if the player doesn't have enough mana pmo->special1.i = false; } return; } //============================================================================ // // A_FHammerThrow // //============================================================================ void A_FHammerThrow(player_t * player, pspdef_t * psp) { mobj_t *mo; if (!player->mo->special1.i) { return; } player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon]; mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE); if (mo) { mo->special1.i = 0; } } //============================================================================ // // A_FSwordAttack // //============================================================================ void A_FSwordAttack(player_t * player, pspdef_t * psp) { mobj_t *pmo; player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon]; pmo = player->mo; P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 10 * FRACUNIT, MT_FSWORD_MISSILE, pmo->angle + ANG45 / 4); P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 5 * FRACUNIT, MT_FSWORD_MISSILE, pmo->angle + ANG45 / 8); P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z, MT_FSWORD_MISSILE, pmo->angle); P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 5 * FRACUNIT, MT_FSWORD_MISSILE, pmo->angle - ANG45 / 8); P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 10 * FRACUNIT, MT_FSWORD_MISSILE, pmo->angle - ANG45 / 4); S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE); } //============================================================================ // // A_FSwordAttack2 // //============================================================================ void A_FSwordAttack2(mobj_t * actor) { angle_t angle = actor->angle; P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle + ANG45 / 4, 0); P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle + ANG45 / 8, 0); P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle, 0); P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle - ANG45 / 8, 0); P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle - ANG45 / 4, 0); S_StartSound(actor, SFX_FIGHTER_SWORD_FIRE); } //============================================================================ // // A_FSwordFlames // //============================================================================ void A_FSwordFlames(mobj_t * actor) { int i; for (i = 1 + (P_Random() & 3); i; i--) { P_SpawnMobj(actor->x + ((P_Random() - 128) << 12), actor->y + ((P_Random() - 128) << 12), actor->z + ((P_Random() - 128) << 11), MT_FSWORD_FLAME); } } //============================================================================ // // A_MWandAttack // //============================================================================ void A_MWandAttack(player_t * player, pspdef_t * psp) { mobj_t *mo; mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE); if (mo) { mo->thinker.function = P_BlasterMobjThinker; } S_StartSound(player->mo, SFX_MAGE_WAND_FIRE); } // ===== Mage Lightning Weapon ===== //============================================================================ // // A_LightningReady // //============================================================================ void A_LightningReady(player_t * player, pspdef_t * psp) { A_WeaponReady(player, psp); if (P_Random() < 160) { S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY); } } //============================================================================ // // A_LightningClip // //============================================================================ #define ZAGSPEED FRACUNIT void A_LightningClip(mobj_t * actor) { mobj_t *cMo; mobj_t *target = NULL; int zigZag; if (actor->type == MT_LIGHTNING_FLOOR) { actor->z = actor->floorz; target = actor->special2.m->special1.m; } else if (actor->type == MT_LIGHTNING_CEILING) { actor->z = actor->ceilingz - actor->height; target = actor->special1.m; } if (actor->type == MT_LIGHTNING_FLOOR) { // floor lightning zig-zags, and forces the ceiling lightning to mimic cMo = actor->special2.m; zigZag = P_Random(); if ((zigZag > 128 && actor->special1.i < 2) || actor->special1.i < -2) { P_ThrustMobj(actor, actor->angle + ANG90, ZAGSPEED); if (cMo) { P_ThrustMobj(cMo, actor->angle + ANG90, ZAGSPEED); } actor->special1.i++; } else { P_ThrustMobj(actor, actor->angle - ANG90, ZAGSPEED); if (cMo) { P_ThrustMobj(cMo, cMo->angle - ANG90, ZAGSPEED); } actor->special1.i--; } } if (target) { if (target->health <= 0) { P_ExplodeMissile(actor); } else { actor->angle = R_PointToAngle2(actor->x, actor->y, target->x, target->y); actor->momx = 0; actor->momy = 0; P_ThrustMobj(actor, actor->angle, actor->info->speed >> 1); } } } //============================================================================ // // A_LightningZap // //============================================================================ void A_LightningZap(mobj_t * actor) { mobj_t *mo; fixed_t deltaZ; A_LightningClip(actor); actor->health -= 8; if (actor->health <= 0) { P_SetMobjState(actor, actor->info->deathstate); return; } if (actor->type == MT_LIGHTNING_FLOOR) { deltaZ = 10 * FRACUNIT; } else { deltaZ = -10 * FRACUNIT; } mo = P_SpawnMobj(actor->x + ((P_Random() - 128) * actor->radius / 256), actor->y + ((P_Random() - 128) * actor->radius / 256), actor->z + deltaZ, MT_LIGHTNING_ZAP); if (mo) { mo->special2.m = actor; mo->momx = actor->momx; mo->momy = actor->momy; mo->target = actor->target; if (actor->type == MT_LIGHTNING_FLOOR) { mo->momz = 20 * FRACUNIT; } else { mo->momz = -20 * FRACUNIT; } } /* mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256), actor->y+((P_Random()-128)*actor->radius/256), actor->z+deltaZ, MT_LIGHTNING_ZAP); if(mo) { mo->special2.m = actor; mo->momx = actor->momx; mo->momy = actor->momy; mo->target = actor->target; if(actor->type == MT_LIGHTNING_FLOOR) { mo->momz = 16*FRACUNIT; } else { mo->momz = -16*FRACUNIT; } } */ if (actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160) { S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS); } } //============================================================================ // // A_MLightningAttack2 // //============================================================================ void A_MLightningAttack2(mobj_t * actor) { mobj_t *fmo, *cmo; fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR); cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING); if (fmo) { fmo->special1.m = NULL; fmo->special2.m = cmo; A_LightningZap(fmo); } if (cmo) { cmo->special1.m = NULL; // mobj that it will track cmo->special2.m = fmo; A_LightningZap(cmo); } S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE); } //============================================================================ // // A_MLightningAttack // //============================================================================ void A_MLightningAttack(player_t * player, pspdef_t * psp) { A_MLightningAttack2(player->mo); player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon]; } //============================================================================ // // A_ZapMimic // //============================================================================ void A_ZapMimic(mobj_t * actor) { mobj_t *mo; mo = actor->special2.m; if (mo) { if (mo->state >= &states[mo->info->deathstate] || mo->state == &states[S_FREETARGMOBJ]) { P_ExplodeMissile(actor); } else { actor->momx = mo->momx; actor->momy = mo->momy; } } } //============================================================================ // // A_LastZap // //============================================================================ void A_LastZap(mobj_t * actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP); if (mo) { P_SetMobjState(mo, S_LIGHTNING_ZAP_X1); mo->momz = 40 * FRACUNIT; } } //============================================================================ // // A_LightningRemove // //============================================================================ void A_LightningRemove(mobj_t * actor) { mobj_t *mo; mo = actor->special2.m; if (mo) { mo->special2.m = NULL; P_ExplodeMissile(mo); } } //============================================================================ // // MStaffSpawn // //============================================================================ void MStaffSpawn(mobj_t * pmo, angle_t angle) { mobj_t *mo; mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle); if (mo) { mo->target = pmo; mo->special1.m = P_RoughMonsterSearch(mo, 10); } } //============================================================================ // // A_MStaffAttack // //============================================================================ void A_MStaffAttack(player_t * player, pspdef_t * psp) { angle_t angle; mobj_t *pmo; player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon]; pmo = player->mo; angle = pmo->angle; MStaffSpawn(pmo, angle); MStaffSpawn(pmo, angle - ANG1 * 5); MStaffSpawn(pmo, angle + ANG1 * 5); S_StartSound(player->mo, SFX_MAGE_STAFF_FIRE); if (player == &players[consoleplayer]) { player->damagecount = 0; player->bonuscount = 0; I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + STARTSCOURGEPAL * 768); } } //============================================================================ // // A_MStaffPalette // //============================================================================ void A_MStaffPalette(player_t * player, pspdef_t * psp) { int pal; if (player == &players[consoleplayer]) { pal = STARTSCOURGEPAL + psp->state - (&states[S_MSTAFFATK_2]); if (pal == STARTSCOURGEPAL + 3) { // reset back to original playpal pal = 0; } I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + pal * 768); } } //============================================================================ // // A_MStaffWeave // //============================================================================ void A_MStaffWeave(mobj_t * actor) { fixed_t newX, newY; int weaveXY, weaveZ; int angle; weaveXY = actor->special2.i >> 16; weaveZ = actor->special2.i & 0xFFFF; angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT; newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2); newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2); weaveXY = (weaveXY + 6) & 63; newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2); newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2); P_TryMove(actor, newX, newY); actor->z -= FloatBobOffsets[weaveZ] << 1; weaveZ = (weaveZ + 3) & 63; actor->z += FloatBobOffsets[weaveZ] << 1; if (actor->z <= actor->floorz) { actor->z = actor->floorz + FRACUNIT; } actor->special2.i = weaveZ + (weaveXY << 16); } //============================================================================ // // A_MStaffTrack // //============================================================================ void A_MStaffTrack(mobj_t * actor) { if ((actor->special1.m == NULL) && (P_Random() < 50)) { actor->special1.m = P_RoughMonsterSearch(actor, 10); } P_SeekerMissile(actor, ANG1 * 2, ANG1 * 10); } //============================================================================ // // MStaffSpawn2 - for use by mage class boss // //============================================================================ void MStaffSpawn2(mobj_t * actor, angle_t angle) { mobj_t *mo; mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0); if (mo) { mo->target = actor; mo->special1.m = P_RoughMonsterSearch(mo, 10); } } //============================================================================ // // A_MStaffAttack2 - for use by mage class boss // //============================================================================ void A_MStaffAttack2(mobj_t * actor) { angle_t angle; angle = actor->angle; MStaffSpawn2(actor, angle); MStaffSpawn2(actor, angle - ANG1 * 5); MStaffSpawn2(actor, angle + ANG1 * 5); S_StartSound(actor, SFX_MAGE_STAFF_FIRE); } //============================================================================ // // A_FPunchAttack // //============================================================================ void A_FPunchAttack(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; mobj_t *pmo = player->mo; fixed_t power; int i; damage = 40 + (P_Random() & 15); power = 2 * FRACUNIT; PuffType = MT_PUNCHPUFF; for (i = 0; i < 16; i++) { angle = pmo->angle + i * (ANG45 / 16); slope = P_AimLineAttack(pmo, angle, 2 * MELEERANGE); if (linetarget) { player->mo->special1.i++; if (pmo->special1.i == 3) { damage <<= 1; power = 6 * FRACUNIT; PuffType = MT_HAMMERPUFF; } P_LineAttack(pmo, angle, 2 * MELEERANGE, slope, damage); if (linetarget->flags & MF_COUNTKILL || linetarget->player) { P_ThrustMobj(linetarget, angle, power); } AdjustPlayerAngle(pmo); goto punchdone; } angle = pmo->angle - i * (ANG45 / 16); slope = P_AimLineAttack(pmo, angle, 2 * MELEERANGE); if (linetarget) { pmo->special1.i++; if (pmo->special1.i == 3) { damage <<= 1; power = 6 * FRACUNIT; PuffType = MT_HAMMERPUFF; } P_LineAttack(pmo, angle, 2 * MELEERANGE, slope, damage); if (linetarget->flags & MF_COUNTKILL || linetarget->player) { P_ThrustMobj(linetarget, angle, power); } AdjustPlayerAngle(pmo); goto punchdone; } } // didn't find any creatures, so try to strike any walls pmo->special1.i = 0; angle = pmo->angle; slope = P_AimLineAttack(pmo, angle, MELEERANGE); P_LineAttack(pmo, angle, MELEERANGE, slope, damage); punchdone: if (pmo->special1.i == 3) { pmo->special1.i = 0; P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1); S_StartSound(pmo, SFX_FIGHTER_GRUNT); } return; } //============================================================================ // // A_FAxeAttack // //============================================================================ #define AXERANGE 2.25*MELEERANGE void A_FAxeAttack(player_t * player, pspdef_t * psp) { angle_t angle; mobj_t *pmo = player->mo; fixed_t power; int damage; int slope; int i; int useMana; damage = 40 + (P_Random() & 15) + (P_Random() & 7); power = 0; if (player->mana[MANA_1] > 0) { damage <<= 1; power = 6 * FRACUNIT; PuffType = MT_AXEPUFF_GLOW; useMana = 1; } else { PuffType = MT_AXEPUFF; useMana = 0; } for (i = 0; i < 16; i++) { angle = pmo->angle + i * (ANG45 / 16); slope = P_AimLineAttack(pmo, angle, AXERANGE); if (linetarget) { P_LineAttack(pmo, angle, AXERANGE, slope, damage); if (linetarget->flags & MF_COUNTKILL || linetarget->player) { P_ThrustMobj(linetarget, angle, power); } AdjustPlayerAngle(pmo); useMana++; goto axedone; } angle = pmo->angle - i * (ANG45 / 16); slope = P_AimLineAttack(pmo, angle, AXERANGE); if (linetarget) { P_LineAttack(pmo, angle, AXERANGE, slope, damage); if (linetarget->flags & MF_COUNTKILL) { P_ThrustMobj(linetarget, angle, power); } AdjustPlayerAngle(pmo); useMana++; goto axedone; } } // didn't find any creatures, so try to strike any walls pmo->special1.m = NULL; angle = pmo->angle; slope = P_AimLineAttack(pmo, angle, MELEERANGE); P_LineAttack(pmo, angle, MELEERANGE, slope, damage); axedone: if (useMana == 2) { player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; if (player->mana[MANA_1] <= 0) { P_SetPsprite(player, ps_weapon, S_FAXEATK_5); } } return; } //=========================================================================== // // A_CMaceAttack // //=========================================================================== void A_CMaceAttack(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int slope; int i; damage = 25 + (P_Random() & 15); PuffType = MT_HAMMERPUFF; for (i = 0; i < 16; i++) { angle = player->mo->angle + i * (ANG45 / 16); slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE); if (linetarget) { P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage); AdjustPlayerAngle(player->mo); // player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->y, linetarget->x, linetarget->y); goto macedone; } angle = player->mo->angle - i * (ANG45 / 16); slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE); if (linetarget) { P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage); AdjustPlayerAngle(player->mo); // player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->y, linetarget->x, linetarget->y); goto macedone; } } // didn't find any creatures, so try to strike any walls player->mo->special1.m = NULL; angle = player->mo->angle; slope = P_AimLineAttack(player->mo, angle, MELEERANGE); P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); macedone: return; } //============================================================================ // // A_CStaffCheck // //============================================================================ void A_CStaffCheck(player_t * player, pspdef_t * psp) { mobj_t *pmo; int damage; int newLife; angle_t angle; int slope; int i; pmo = player->mo; damage = 20 + (P_Random() & 15); PuffType = MT_CSTAFFPUFF; for (i = 0; i < 3; i++) { angle = pmo->angle + i * (ANG45 / 16); slope = P_AimLineAttack(pmo, angle, 1.5 * MELEERANGE); if (linetarget) { P_LineAttack(pmo, angle, 1.5 * MELEERANGE, slope, damage); pmo->angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y); if ((linetarget->player || linetarget->flags & MF_COUNTKILL) && (!(linetarget->flags2 & (MF2_DORMANT + MF2_INVULNERABLE)))) { newLife = player->health + (damage >> 3); newLife = newLife > 100 ? 100 : newLife; pmo->health = player->health = newLife; P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1); } player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; break; } angle = pmo->angle - i * (ANG45 / 16); slope = P_AimLineAttack(player->mo, angle, 1.5 * MELEERANGE); if (linetarget) { P_LineAttack(pmo, angle, 1.5 * MELEERANGE, slope, damage); pmo->angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y); if (linetarget->player || linetarget->flags & MF_COUNTKILL) { newLife = player->health + (damage >> 4); newLife = newLife > 100 ? 100 : newLife; pmo->health = player->health = newLife; P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1); } player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; break; } } } //============================================================================ // // A_CStaffAttack // //============================================================================ void A_CStaffAttack(player_t * player, pspdef_t * psp) { mobj_t *mo; mobj_t *pmo; player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; pmo = player->mo; mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle - (ANG45 / 15)); if (mo) { mo->special2.i = 32; } mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle + (ANG45 / 15)); if (mo) { mo->special2.i = 0; } S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE); } //============================================================================ // // A_CStaffMissileSlither // //============================================================================ void A_CStaffMissileSlither(mobj_t * actor) { fixed_t newX, newY; int weaveXY; int angle; weaveXY = actor->special2.i; angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT; newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]); newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]); weaveXY = (weaveXY + 3) & 63; newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]); newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]); P_TryMove(actor, newX, newY); actor->special2.i = weaveXY; } //============================================================================ // // A_CStaffInitBlink // //============================================================================ void A_CStaffInitBlink(player_t * player, pspdef_t * psp) { player->mo->special1.i = (P_Random() >> 1) + 20; } //============================================================================ // // A_CStaffCheckBlink // //============================================================================ void A_CStaffCheckBlink(player_t * player, pspdef_t * psp) { if (!--player->mo->special1.i) { P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1); player->mo->special1.i = (P_Random() + 50) >> 2; } } //============================================================================ // // A_CFlameAttack // //============================================================================ #define FLAMESPEED (0.45*FRACUNIT) #define CFLAMERANGE (12*64*FRACUNIT) void A_CFlameAttack(player_t * player, pspdef_t * psp) { mobj_t *mo; mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE); if (mo) { mo->thinker.function = P_BlasterMobjThinker; mo->special1.i = 2; } player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon]; S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE); } //============================================================================ // // A_CFlamePuff // //============================================================================ void A_CFlamePuff(mobj_t * actor) { A_UnHideThing(actor); actor->momx = 0; actor->momy = 0; actor->momz = 0; S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE); } //============================================================================ // // A_CFlameMissile // //============================================================================ void A_CFlameMissile(mobj_t * actor) { int i; int an; fixed_t dist; mobj_t *mo; A_UnHideThing(actor); S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE); if (BlockingMobj && BlockingMobj->flags & MF_SHOOTABLE) { // Hit something, so spawn the flame circle around the thing dist = BlockingMobj->radius + 18 * FRACUNIT; for (i = 0; i < 4; i++) { an = (i * ANG45) >> ANGLETOFINESHIFT; mo = P_SpawnMobj(BlockingMobj->x + FixedMul(dist, finecosine[an]), BlockingMobj->y + FixedMul(dist, finesine[an]), BlockingMobj->z + 5 * FRACUNIT, MT_CIRCLEFLAME); if (mo) { mo->angle = an << ANGLETOFINESHIFT; mo->target = actor->target; mo->momx = mo->special1.i = FixedMul(FLAMESPEED, finecosine[an]); mo->momy = mo->special2.i = FixedMul(FLAMESPEED, finesine[an]); mo->tics -= P_Random() & 3; } mo = P_SpawnMobj(BlockingMobj->x - FixedMul(dist, finecosine[an]), BlockingMobj->y - FixedMul(dist, finesine[an]), BlockingMobj->z + 5 * FRACUNIT, MT_CIRCLEFLAME); if (mo) { mo->angle = ANG180 + (an << ANGLETOFINESHIFT); mo->target = actor->target; mo->momx = mo->special1.i = FixedMul(-FLAMESPEED, finecosine[an]); mo->momy = mo->special2.i = FixedMul(-FLAMESPEED, finesine[an]); mo->tics -= P_Random() & 3; } } P_SetMobjState(actor, S_FLAMEPUFF2_1); } } /* void A_CFlameAttack(player_t *player, pspdef_t *psp) { mobj_t *pmo; angle_t angle; int damage; int i; int an, an90; fixed_t dist; mobj_t *mo; pmo = player->mo; P_BulletSlope(pmo); damage = 25+HITDICE(3); angle = pmo->angle; if(player->refire) { angle += (P_Random()-P_Random())<<17; } P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget if(!linetarget) { angle += ANG1*2; P_AimLineAttack(pmo, angle, CFLAMERANGE); if(!linetarget) { angle -= ANG1*4; P_AimLineAttack(pmo, angle, CFLAMERANGE); if(!linetarget) { angle += ANG1*2; } } } if(linetarget) { PuffType = MT_FLAMEPUFF2; } else { PuffType = MT_FLAMEPUFF; } P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage); if(linetarget) { // Hit something, so spawn the flame circle around the thing dist = linetarget->radius+18*FRACUNIT; for(i = 0; i < 4; i++) { an = (i*ANG45)>>ANGLETOFINESHIFT; an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT; mo = P_SpawnMobj(linetarget->x+FixedMul(dist, finecosine[an]), linetarget->y+FixedMul(dist, finesine[an]), linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME); if(mo) { mo->angle = an<target = pmo; mo->momx = mo->special1.i = FixedMul(FLAMESPEED, finecosine[an]); mo->momy = mo->special2.i = FixedMul(FLAMESPEED, finesine[an]); mo->tics -= P_Random()&3; } mo = P_SpawnMobj(linetarget->x-FixedMul(dist, finecosine[an]), linetarget->y-FixedMul(dist, finesine[an]), linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME); if(mo) { mo->angle = ANG180+(an<target = pmo; mo->momx = mo->special1.i = FixedMul(-FLAMESPEED, finecosine[an]); mo->momy = mo->special2.i = FixedMul(-FLAMESPEED, finesine[an]); mo->tics -= P_Random()&3; } } } // Create a line of flames from the player to the flame puff CFlameCreateFlames(player->mo); player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon]; S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE); } */ //============================================================================ // // A_CFlameRotate // //============================================================================ #define FLAMEROTSPEED 2*FRACUNIT void A_CFlameRotate(mobj_t * actor) { int an; an = (actor->angle + ANG90) >> ANGLETOFINESHIFT; actor->momx = actor->special1.i + FixedMul(FLAMEROTSPEED, finecosine[an]); actor->momy = actor->special2.i + FixedMul(FLAMEROTSPEED, finesine[an]); actor->angle += ANG90 / 15; } //============================================================================ // // A_CHolyAttack3 // // Spawns the spirits //============================================================================ void A_CHolyAttack3(mobj_t * actor) { P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE); S_StartSound(actor, SFX_CHOLY_FIRE); } //============================================================================ // // A_CHolyAttack2 // // Spawns the spirits //============================================================================ void A_CHolyAttack2(mobj_t * actor) { int j; int i; mobj_t *mo; mobj_t *tail, *next; for (j = 0; j < 4; j++) { mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX); if (!mo) { continue; } switch (j) { // float bob index case 0: mo->special2.i = P_Random() & 7; // upper-left break; case 1: mo->special2.i = 32 + (P_Random() & 7); // upper-right break; case 2: mo->special2.i = (32 + (P_Random() & 7)) << 16; // lower-left break; case 3: mo->special2.i = ((32 + (P_Random() & 7)) << 16) + 32 + (P_Random() & 7); break; } mo->z = actor->z; mo->angle = actor->angle + (ANG45 + ANG45 / 2) - ANG45 * j; P_ThrustMobj(mo, mo->angle, mo->info->speed); mo->target = actor->target; mo->args[0] = 10; // initial turn value mo->args[1] = 0; // initial look angle if (deathmatch) { // Ghosts last slightly less longer in DeathMatch mo->health = 85; } if (linetarget) { mo->special1.m = linetarget; mo->flags |= MF_NOCLIP | MF_SKULLFLY; mo->flags &= ~MF_MISSILE; } tail = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL); tail->special2.m = mo; // parent for (i = 1; i < 3; i++) { next = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL); P_SetMobjState(next, next->info->spawnstate + 1); tail->special1.m = next; tail = next; } tail->special1.m = NULL; // last tail bit } } //============================================================================ // // A_CHolyAttack // //============================================================================ void A_CHolyAttack(player_t * player, pspdef_t * psp) { player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon]; P_SpawnPlayerMissile(player->mo, MT_HOLY_MISSILE); if (player == &players[consoleplayer]) { player->damagecount = 0; player->bonuscount = 0; I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + STARTHOLYPAL * 768); } S_StartSound(player->mo, SFX_CHOLY_FIRE); } //============================================================================ // // A_CHolyPalette // //============================================================================ void A_CHolyPalette(player_t * player, pspdef_t * psp) { int pal; if (player == &players[consoleplayer]) { pal = STARTHOLYPAL + psp->state - (&states[S_CHOLYATK_6]); if (pal == STARTHOLYPAL + 3) { // reset back to original playpal pal = 0; } I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + pal * 768); } } //============================================================================ // // CHolyFindTarget // //============================================================================ static void CHolyFindTarget(mobj_t * actor) { mobj_t *target; target = P_RoughMonsterSearch(actor, 6); if (target != NULL) { actor->special1.m = target; actor->flags |= MF_NOCLIP | MF_SKULLFLY; actor->flags &= ~MF_MISSILE; } } //============================================================================ // // CHolySeekerMissile // // Similar to P_SeekerMissile, but seeks to a random Z on the target //============================================================================ static void CHolySeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax) { int dir; int dist; angle_t delta; angle_t angle; mobj_t *target; fixed_t newZ; fixed_t deltaZ; target = actor->special1.m; if (target == NULL) { return; } if (!(target->flags & MF_SHOOTABLE) || (!(target->flags & MF_COUNTKILL) && !target->player)) { // Target died/target isn't a player or creature actor->special1.m = NULL; actor->flags &= ~(MF_NOCLIP | MF_SKULLFLY); actor->flags |= MF_MISSILE; CHolyFindTarget(actor); return; } dir = P_FaceMobj(actor, target, &delta); if (delta > thresh) { delta >>= 1; if (delta > turnMax) { delta = turnMax; } } if (dir) { // Turn clockwise actor->angle += delta; } else { // Turn counter clockwise actor->angle -= delta; } angle = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(actor->info->speed, finecosine[angle]); actor->momy = FixedMul(actor->info->speed, finesine[angle]); if (!(leveltime & 15) || actor->z > target->z + (target->height) || actor->z + actor->height < target->z) { newZ = target->z + ((P_Random() * target->height) >> 8); deltaZ = newZ - actor->z; if (abs(deltaZ) > 15 * FRACUNIT) { if (deltaZ > 0) { deltaZ = 15 * FRACUNIT; } else { deltaZ = -15 * FRACUNIT; } } dist = P_AproxDistance(target->x - actor->x, target->y - actor->y); dist = dist / actor->info->speed; if (dist < 1) { dist = 1; } actor->momz = deltaZ / dist; } return; } //============================================================================ // // A_CHolyWeave // //============================================================================ static void CHolyWeave(mobj_t * actor) { fixed_t newX, newY; int weaveXY, weaveZ; int angle; weaveXY = actor->special2.i >> 16; weaveZ = actor->special2.i & 0xFFFF; angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT; newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2); newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2); weaveXY = (weaveXY + (P_Random() % 5)) & 63; newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2); newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2); P_TryMove(actor, newX, newY); actor->z -= FloatBobOffsets[weaveZ] << 1; weaveZ = (weaveZ + (P_Random() % 5)) & 63; actor->z += FloatBobOffsets[weaveZ] << 1; actor->special2.i = weaveZ + (weaveXY << 16); } //============================================================================ // // A_CHolySeek // //============================================================================ void A_CHolySeek(mobj_t * actor) { actor->health--; if (actor->health <= 0) { actor->momx >>= 2; actor->momy >>= 2; actor->momz = 0; P_SetMobjState(actor, actor->info->deathstate); actor->tics -= P_Random() & 3; return; } if (actor->special1.m) { CHolySeekerMissile(actor, actor->args[0] * ANG1, actor->args[0] * ANG1 * 2); if (!((leveltime + 7) & 15)) { actor->args[0] = 5 + (P_Random() / 20); } } CHolyWeave(actor); } //============================================================================ // // CHolyTailFollow // //============================================================================ static void CHolyTailFollow(mobj_t * actor, fixed_t dist) { mobj_t *child; int an; fixed_t oldDistance, newDistance; child = actor->special1.m; if (child) { an = R_PointToAngle2(actor->x, actor->y, child->x, child->y) >> ANGLETOFINESHIFT; oldDistance = P_AproxDistance(child->x - actor->x, child->y - actor->y); if (P_TryMove (child, actor->x + FixedMul(dist, finecosine[an]), actor->y + FixedMul(dist, finesine[an]))) { newDistance = P_AproxDistance(child->x - actor->x, child->y - actor->y) - FRACUNIT; if (oldDistance < FRACUNIT) { if (child->z < actor->z) { child->z = actor->z - dist; } else { child->z = actor->z + dist; } } else { child->z = actor->z + FixedMul(FixedDiv(newDistance, oldDistance), child->z - actor->z); } } CHolyTailFollow(child, dist - FRACUNIT); } } //============================================================================ // // CHolyTailRemove // //============================================================================ static void CHolyTailRemove(mobj_t * actor) { mobj_t *child; child = actor->special1.m; if (child) { CHolyTailRemove(child); } P_RemoveMobj(actor); } //============================================================================ // // A_CHolyTail // //============================================================================ void A_CHolyTail(mobj_t * actor) { mobj_t *parent; parent = actor->special2.m; if (parent) { if (parent->state >= &states[parent->info->deathstate]) { // Ghost removed, so remove all tail parts CHolyTailRemove(actor); return; } else if (P_TryMove(actor, parent->x - FixedMul(14 * FRACUNIT, finecosine[parent-> angle >> ANGLETOFINESHIFT]), parent->y - FixedMul(14 * FRACUNIT, finesine[parent-> angle >> ANGLETOFINESHIFT]))) { actor->z = parent->z - 5 * FRACUNIT; } CHolyTailFollow(actor, 10 * FRACUNIT); } } //============================================================================ // // A_CHolyCheckScream // //============================================================================ void A_CHolyCheckScream(mobj_t * actor) { A_CHolySeek(actor); if (P_Random() < 20) { S_StartSound(actor, SFX_SPIRIT_ACTIVE); } if (!actor->special1.m) { CHolyFindTarget(actor); } } //============================================================================ // // A_CHolySpawnPuff // //============================================================================ void A_CHolySpawnPuff(mobj_t * actor) { P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF); } //---------------------------------------------------------------------------- // // PROC A_FireConePL1 // //---------------------------------------------------------------------------- #define SHARDSPAWN_LEFT 1 #define SHARDSPAWN_RIGHT 2 #define SHARDSPAWN_UP 4 #define SHARDSPAWN_DOWN 8 void A_FireConePL1(player_t * player, pspdef_t * psp) { angle_t angle; int damage; int i; mobj_t *pmo, *mo; int conedone = false; pmo = player->mo; player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon]; S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE); damage = 90 + (P_Random() & 15); for (i = 0; i < 16; i++) { angle = pmo->angle + i * (ANG45 / 16); P_AimLineAttack(pmo, angle, MELEERANGE); if (linetarget) { pmo->flags2 |= MF2_ICEDAMAGE; P_DamageMobj(linetarget, pmo, pmo, damage); pmo->flags2 &= ~MF2_ICEDAMAGE; conedone = true; break; } } // didn't find any creatures, so fire projectiles if (!conedone) { mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1); if (mo) { mo->special1.i = SHARDSPAWN_LEFT | SHARDSPAWN_DOWN | SHARDSPAWN_UP | SHARDSPAWN_RIGHT; mo->special2.i = 3; // Set sperm count (levels of reproductivity) mo->target = pmo; mo->args[0] = 3; // Mark Initial shard as super damage } } } void A_ShedShard(mobj_t * actor) { mobj_t *mo; int spawndir = actor->special1.i; int spermcount = actor->special2.i; if (spermcount <= 0) return; // No sperm left actor->special2.i = 0; spermcount--; // every so many calls, spawn a new missile in it's set directions if (spawndir & SHARDSPAWN_LEFT) { mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle + (ANG45 / 9), 0, (20 + 2 * spermcount) << FRACBITS); if (mo) { mo->special1.i = SHARDSPAWN_LEFT; mo->special2.i = spermcount; mo->momz = actor->momz; mo->target = actor->target; mo->args[0] = (spermcount == 3) ? 2 : 0; } } if (spawndir & SHARDSPAWN_RIGHT) { mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle - (ANG45 / 9), 0, (20 + 2 * spermcount) << FRACBITS); if (mo) { mo->special1.i = SHARDSPAWN_RIGHT; mo->special2.i = spermcount; mo->momz = actor->momz; mo->target = actor->target; mo->args[0] = (spermcount == 3) ? 2 : 0; } } if (spawndir & SHARDSPAWN_UP) { mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle, 0, (15 + 2 * spermcount) << FRACBITS); if (mo) { mo->momz = actor->momz; mo->z += 8 * FRACUNIT; if (spermcount & 1) // Every other reproduction mo->special1.i = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT; else mo->special1.i = SHARDSPAWN_UP; mo->special2.i = spermcount; mo->target = actor->target; mo->args[0] = (spermcount == 3) ? 2 : 0; } } if (spawndir & SHARDSPAWN_DOWN) { mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle, 0, (15 + 2 * spermcount) << FRACBITS); if (mo) { mo->momz = actor->momz; mo->z -= 4 * FRACUNIT; if (spermcount & 1) // Every other reproduction mo->special1.i = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT; else mo->special1.i = SHARDSPAWN_DOWN; mo->special2.i = spermcount; mo->target = actor->target; mo->args[0] = (spermcount == 3) ? 2 : 0; } } } //---------------------------------------------------------------------------- // // PROC A_HideInCeiling // //---------------------------------------------------------------------------- /* void A_HideInCeiling(mobj_t *actor) { actor->z = actor->ceilingz+4*FRACUNIT; } */ //---------------------------------------------------------------------------- // // PROC A_FloatPuff // //---------------------------------------------------------------------------- /* void A_FloatPuff(mobj_t *puff) { puff->momz += 1.8*FRACUNIT; } */ void A_Light0(player_t * player, pspdef_t * psp) { player->extralight = 0; } /* void A_Light1(player_t *player, pspdef_t *psp) { player->extralight = 1; } */ /* void A_Light2(player_t *player, pspdef_t *psp) { player->extralight = 2; } */ //------------------------------------------------------------------------ // // PROC P_SetupPsprites // // Called at start of level for each player // //------------------------------------------------------------------------ void P_SetupPsprites(player_t * player) { int i; // Remove all psprites for (i = 0; i < NUMPSPRITES; i++) { player->psprites[i].state = NULL; } // Spawn the ready weapon player->pendingweapon = player->readyweapon; P_BringUpWeapon(player); } //------------------------------------------------------------------------ // // PROC P_MovePsprites // // Called every tic by player thinking routine // //------------------------------------------------------------------------ void P_MovePsprites(player_t * player) { int i; pspdef_t *psp; state_t *state; psp = &player->psprites[0]; for (i = 0; i < NUMPSPRITES; i++, psp++) { if ((state = psp->state) != 0) // a null state means not active { // drop tic count and possibly change state if (psp->tics != -1) // a -1 tic count never changes { psp->tics--; if (!psp->tics) { P_SetPsprite(player, i, psp->state->nextstate); } } } } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_setup.c000066400000000000000000000752441257432200600230420ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include #include #include "h2def.h" #include "i_system.h" #include "m_argv.h" #include "m_bbox.h" #include "m_misc.h" #include "i_swap.h" #include "s_sound.h" #include "p_local.h" // MACROS ------------------------------------------------------------------ #define MAPINFO_SCRIPT_NAME "MAPINFO" #define MCMD_SKY1 1 #define MCMD_SKY2 2 #define MCMD_LIGHTNING 3 #define MCMD_FADETABLE 4 #define MCMD_DOUBLESKY 5 #define MCMD_CLUSTER 6 #define MCMD_WARPTRANS 7 #define MCMD_NEXT 8 #define MCMD_CDTRACK 9 #define MCMD_CD_STARTTRACK 10 #define MCMD_CD_END1TRACK 11 #define MCMD_CD_END2TRACK 12 #define MCMD_CD_END3TRACK 13 #define MCMD_CD_INTERTRACK 14 #define MCMD_CD_TITLETRACK 15 #define UNKNOWN_MAP_NAME "DEVELOPMENT MAP" #define DEFAULT_SKY_NAME "SKY1" #define DEFAULT_SONG_LUMP "DEFSONG" #define DEFAULT_FADE_TABLE "COLORMAP" // TYPES ------------------------------------------------------------------- typedef struct mapInfo_s mapInfo_t; struct mapInfo_s { short cluster; short warpTrans; short nextMap; short cdTrack; char name[32]; short sky1Texture; short sky2Texture; fixed_t sky1ScrollDelta; fixed_t sky2ScrollDelta; boolean doubleSky; boolean lightning; int fadetable; char songLump[10]; }; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void P_SpawnMapThing(mapthing_t * mthing); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static int QualifyMap(int map); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- int MapCount; mapthing_t deathmatchstarts[MAXDEATHMATCHSTARTS], *deathmatch_p; mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS]; int numvertexes; vertex_t *vertexes; int numsegs; seg_t *segs; int numsectors; sector_t *sectors; int numsubsectors; subsector_t *subsectors; int numnodes; node_t *nodes; int numlines; line_t *lines; int numsides; side_t *sides; short *blockmaplump; // offsets in blockmap are from here short *blockmap; int bmapwidth, bmapheight; // in mapblocks fixed_t bmaporgx, bmaporgy; // origin of block map mobj_t **blocklinks; // for thing chains byte *rejectmatrix; // for fast sight rejection // PRIVATE DATA DEFINITIONS ------------------------------------------------ static mapInfo_t MapInfo[99]; static char *MapCmdNames[] = { "SKY1", "SKY2", "DOUBLESKY", "LIGHTNING", "FADETABLE", "CLUSTER", "WARPTRANS", "NEXT", "CDTRACK", "CD_START_TRACK", "CD_END1_TRACK", "CD_END2_TRACK", "CD_END3_TRACK", "CD_INTERMISSION_TRACK", "CD_TITLE_TRACK", NULL }; static int MapCmdIDs[] = { MCMD_SKY1, MCMD_SKY2, MCMD_DOUBLESKY, MCMD_LIGHTNING, MCMD_FADETABLE, MCMD_CLUSTER, MCMD_WARPTRANS, MCMD_NEXT, MCMD_CDTRACK, MCMD_CD_STARTTRACK, MCMD_CD_END1TRACK, MCMD_CD_END2TRACK, MCMD_CD_END3TRACK, MCMD_CD_INTERTRACK, MCMD_CD_TITLETRACK }; static int cd_NonLevelTracks[6]; // Non-level specific song cd track numbers // CODE -------------------------------------------------------------------- /* ================= = = P_LoadVertexes = ================= */ void P_LoadVertexes(int lump) { byte *data; int i; mapvertex_t *ml; vertex_t *li; numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t); vertexes = Z_Malloc(numvertexes * sizeof(vertex_t), PU_LEVEL, 0); data = W_CacheLumpNum(lump, PU_STATIC); ml = (mapvertex_t *) data; li = vertexes; for (i = 0; i < numvertexes; i++, li++, ml++) { li->x = SHORT(ml->x) << FRACBITS; li->y = SHORT(ml->y) << FRACBITS; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSegs = ================= */ void P_LoadSegs(int lump) { byte *data; int i; mapseg_t *ml; seg_t *li; line_t *ldef; int linedef, side; numsegs = W_LumpLength(lump) / sizeof(mapseg_t); segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0); memset(segs, 0, numsegs * sizeof(seg_t)); data = W_CacheLumpNum(lump, PU_STATIC); ml = (mapseg_t *) data; li = segs; for (i = 0; i < numsegs; i++, li++, ml++) { li->v1 = &vertexes[SHORT(ml->v1)]; li->v2 = &vertexes[SHORT(ml->v2)]; li->angle = (SHORT(ml->angle)) << 16; li->offset = (SHORT(ml->offset)) << 16; linedef = SHORT(ml->linedef); ldef = &lines[linedef]; li->linedef = ldef; side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; if (ldef->flags & ML_TWOSIDED) li->backsector = sides[ldef->sidenum[side ^ 1]].sector; else li->backsector = 0; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSubsectors = ================= */ void P_LoadSubsectors(int lump) { byte *data; int i; mapsubsector_t *ms; subsector_t *ss; numsubsectors = W_LumpLength(lump) / sizeof(mapsubsector_t); subsectors = Z_Malloc(numsubsectors * sizeof(subsector_t), PU_LEVEL, 0); data = W_CacheLumpNum(lump, PU_STATIC); ms = (mapsubsector_t *) data; memset(subsectors, 0, numsubsectors * sizeof(subsector_t)); ss = subsectors; for (i = 0; i < numsubsectors; i++, ss++, ms++) { ss->numlines = SHORT(ms->numsegs); ss->firstline = SHORT(ms->firstseg); } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSectors = ================= */ void P_LoadSectors(int lump) { byte *data; int i; mapsector_t *ms; sector_t *ss; numsectors = W_LumpLength(lump) / sizeof(mapsector_t); sectors = Z_Malloc(numsectors * sizeof(sector_t), PU_LEVEL, 0); memset(sectors, 0, numsectors * sizeof(sector_t)); data = W_CacheLumpNum(lump, PU_STATIC); ms = (mapsector_t *) data; ss = sectors; for (i = 0; i < numsectors; i++, ss++, ms++) { ss->floorheight = SHORT(ms->floorheight) << FRACBITS; ss->ceilingheight = SHORT(ms->ceilingheight) << FRACBITS; ss->floorpic = R_FlatNumForName(ms->floorpic); ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); ss->lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); ss->tag = SHORT(ms->tag); ss->thinglist = NULL; ss->seqType = SEQTYPE_STONE; // default seqType } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadNodes = ================= */ void P_LoadNodes(int lump) { byte *data; int i, j, k; mapnode_t *mn; node_t *no; numnodes = W_LumpLength(lump) / sizeof(mapnode_t); nodes = Z_Malloc(numnodes * sizeof(node_t), PU_LEVEL, 0); data = W_CacheLumpNum(lump, PU_STATIC); mn = (mapnode_t *) data; no = nodes; for (i = 0; i < numnodes; i++, no++, mn++) { no->x = SHORT(mn->x) << FRACBITS; no->y = SHORT(mn->y) << FRACBITS; no->dx = SHORT(mn->dx) << FRACBITS; no->dy = SHORT(mn->dy) << FRACBITS; for (j = 0; j < 2; j++) { no->children[j] = SHORT(mn->children[j]); for (k = 0; k < 4; k++) no->bbox[j][k] = SHORT(mn->bbox[j][k]) << FRACBITS; } } W_ReleaseLumpNum(lump); } //========================================================================== // // P_LoadThings // //========================================================================== void P_LoadThings(int lump) { byte *data; int i; mapthing_t spawnthing; mapthing_t *mt; int numthings; int playerCount; int deathSpotsCount; data = W_CacheLumpNum(lump, PU_STATIC); numthings = W_LumpLength(lump) / sizeof(mapthing_t); mt = (mapthing_t *) data; for (i = 0; i < numthings; i++, mt++) { spawnthing.tid = SHORT(mt->tid); spawnthing.x = SHORT(mt->x); spawnthing.y = SHORT(mt->y); spawnthing.height = SHORT(mt->height); spawnthing.angle = SHORT(mt->angle); spawnthing.type = SHORT(mt->type); spawnthing.options = SHORT(mt->options); spawnthing.special = mt->special; spawnthing.arg1 = mt->arg1; spawnthing.arg2 = mt->arg2; spawnthing.arg3 = mt->arg3; spawnthing.arg4 = mt->arg4; spawnthing.arg5 = mt->arg5; P_SpawnMapThing(&spawnthing); } P_CreateTIDList(); P_InitCreatureCorpseQueue(false); // false = do NOT scan for corpses W_ReleaseLumpNum(lump); if (!deathmatch) { // Don't need to check deathmatch spots return; } playerCount = 0; for (i = 0; i < maxplayers; i++) { playerCount += playeringame[i]; } deathSpotsCount = deathmatch_p - deathmatchstarts; if (deathSpotsCount < playerCount) { I_Error("P_LoadThings: Player count (%d) exceeds deathmatch " "spots (%d)", playerCount, deathSpotsCount); } } /* ================= = = P_LoadLineDefs = ================= */ void P_LoadLineDefs(int lump) { byte *data; int i; maplinedef_t *mld; line_t *ld; vertex_t *v1, *v2; numlines = W_LumpLength(lump) / sizeof(maplinedef_t); lines = Z_Malloc(numlines * sizeof(line_t), PU_LEVEL, 0); memset(lines, 0, numlines * sizeof(line_t)); data = W_CacheLumpNum(lump, PU_STATIC); mld = (maplinedef_t *) data; ld = lines; for (i = 0; i < numlines; i++, mld++, ld++) { ld->flags = SHORT(mld->flags); // Old line special info ... //ld->special = SHORT(mld->special); //ld->tag = SHORT(mld->tag); // New line special info ... ld->special = mld->special; ld->arg1 = mld->arg1; ld->arg2 = mld->arg2; ld->arg3 = mld->arg3; ld->arg4 = mld->arg4; ld->arg5 = mld->arg5; v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) ld->slopetype = ST_HORIZONTAL; else { if (FixedDiv(ld->dy, ld->dx) > 0) ld->slopetype = ST_POSITIVE; else ld->slopetype = ST_NEGATIVE; } if (v1->x < v2->x) { ld->bbox[BOXLEFT] = v1->x; ld->bbox[BOXRIGHT] = v2->x; } else { ld->bbox[BOXLEFT] = v2->x; ld->bbox[BOXRIGHT] = v1->x; } if (v1->y < v2->y) { ld->bbox[BOXBOTTOM] = v1->y; ld->bbox[BOXTOP] = v2->y; } else { ld->bbox[BOXBOTTOM] = v2->y; ld->bbox[BOXTOP] = v1->y; } ld->sidenum[0] = SHORT(mld->sidenum[0]); ld->sidenum[1] = SHORT(mld->sidenum[1]); if (ld->sidenum[0] != -1) ld->frontsector = sides[ld->sidenum[0]].sector; else ld->frontsector = 0; if (ld->sidenum[1] != -1) ld->backsector = sides[ld->sidenum[1]].sector; else ld->backsector = 0; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadSideDefs = ================= */ void P_LoadSideDefs(int lump) { byte *data; int i; mapsidedef_t *msd; side_t *sd; numsides = W_LumpLength(lump) / sizeof(mapsidedef_t); sides = Z_Malloc(numsides * sizeof(side_t), PU_LEVEL, 0); memset(sides, 0, numsides * sizeof(side_t)); data = W_CacheLumpNum(lump, PU_STATIC); msd = (mapsidedef_t *) data; sd = sides; for (i = 0; i < numsides; i++, msd++, sd++) { sd->textureoffset = SHORT(msd->textureoffset) << FRACBITS; sd->rowoffset = SHORT(msd->rowoffset) << FRACBITS; sd->toptexture = R_TextureNumForName(msd->toptexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->sector = §ors[SHORT(msd->sector)]; } W_ReleaseLumpNum(lump); } /* ================= = = P_LoadBlockMap = ================= */ void P_LoadBlockMap(int lump) { int i, count; int lumplen; lumplen = W_LumpLength(lump); blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL); W_ReadLump(lump, blockmaplump); blockmap = blockmaplump + 4; // Swap all short integers to native byte ordering: count = lumplen / 2; for (i = 0; i < count; i++) blockmaplump[i] = SHORT(blockmaplump[i]); bmaporgx = blockmaplump[0] << FRACBITS; bmaporgy = blockmaplump[1] << FRACBITS; bmapwidth = blockmaplump[2]; bmapheight = blockmaplump[3]; // clear out mobj chains count = sizeof(*blocklinks) * bmapwidth * bmapheight; blocklinks = Z_Malloc(count, PU_LEVEL, 0); memset(blocklinks, 0, count); } /* ================= = = P_GroupLines = = Builds sector line lists and subsector sector numbers = Finds block bounding boxes for sectors ================= */ void P_GroupLines(void) { line_t **linebuffer; int i, j, total; line_t *li; sector_t *sector; subsector_t *ss; seg_t *seg; fixed_t bbox[4]; int block; // look up sector number for each subsector ss = subsectors; for (i = 0; i < numsubsectors; i++, ss++) { seg = &segs[ss->firstline]; ss->sector = seg->sidedef->sector; } // count number of lines in each sector li = lines; total = 0; for (i = 0; i < numlines; i++, li++) { total++; li->frontsector->linecount++; if (li->backsector && li->backsector != li->frontsector) { li->backsector->linecount++; total++; } } // build line tables for each sector linebuffer = Z_Malloc(total * sizeof(line_t *), PU_LEVEL, 0); sector = sectors; for (i = 0; i < numsectors; i++, sector++) { M_ClearBox(bbox); sector->lines = linebuffer; li = lines; for (j = 0; j < numlines; j++, li++) { if (li->frontsector == sector || li->backsector == sector) { *linebuffer++ = li; M_AddToBox(bbox, li->v1->x, li->v1->y); M_AddToBox(bbox, li->v2->x, li->v2->y); } } if (linebuffer - sector->lines != sector->linecount) I_Error("P_GroupLines: miscounted"); // set the degenmobj_t to the middle of the bounding box sector->soundorg.x = (bbox[BOXRIGHT] + bbox[BOXLEFT]) / 2; sector->soundorg.y = (bbox[BOXTOP] + bbox[BOXBOTTOM]) / 2; // adjust bounding box to map blocks block = (bbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; block = block >= bmapheight ? bmapheight - 1 : block; sector->blockbox[BOXTOP] = block; block = (bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXBOTTOM] = block; block = (bbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; block = block >= bmapwidth ? bmapwidth - 1 : block; sector->blockbox[BOXRIGHT] = block; block = (bbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXLEFT] = block; } } //============================================================================= /* ================= = = P_SetupLevel = ================= */ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) { int i; int parm; char lumpname[9]; int lumpnum; mobj_t *mobj; for (i = 0; i < maxplayers; i++) { players[i].killcount = players[i].secretcount = players[i].itemcount = 0; } players[consoleplayer].viewz = 1; // will be set by player think // Waiting-for-level-load song; not played if playing music from CD // (the seek time will be so long it will just make loading take // longer) if (!cdmusic) { S_StartSongName("chess", true); } Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1); P_InitThinkers(); leveltime = 0; M_snprintf(lumpname, sizeof(lumpname), "MAP%02d", map); lumpnum = W_GetNumForName(lumpname); // // Begin processing map lumps // Note: most of this ordering is important // P_LoadBlockMap(lumpnum + ML_BLOCKMAP); P_LoadVertexes(lumpnum + ML_VERTEXES); P_LoadSectors(lumpnum + ML_SECTORS); P_LoadSideDefs(lumpnum + ML_SIDEDEFS); P_LoadLineDefs(lumpnum + ML_LINEDEFS); P_LoadSubsectors(lumpnum + ML_SSECTORS); P_LoadNodes(lumpnum + ML_NODES); P_LoadSegs(lumpnum + ML_SEGS); rejectmatrix = W_CacheLumpNum(lumpnum + ML_REJECT, PU_LEVEL); P_GroupLines(); bodyqueslot = 0; po_NumPolyobjs = 0; deathmatch_p = deathmatchstarts; P_LoadThings(lumpnum + ML_THINGS); PO_Init(lumpnum + ML_THINGS); // Initialize the polyobjs P_LoadACScripts(lumpnum + ML_BEHAVIOR); // ACS object code // // End of map lump processing // // If deathmatch, randomly spawn the active players TimerGame = 0; if (deathmatch) { for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { // must give a player spot before deathmatchspawn mobj = P_SpawnMobj(playerstarts[0][i].x << 16, playerstarts[0][i].y << 16, 0, MT_PLAYER_FIGHTER); players[i].mo = mobj; G_DeathMatchSpawnPlayer(i); P_RemoveMobj(mobj); } } //! // @arg // @category net // @vanilla // // For multiplayer games: exit each level after n minutes. // parm = M_CheckParmWithArgs("-timer", 1); if (parm) { TimerGame = atoi(myargv[parm + 1]) * 35 * 60; } } // set up world state P_SpawnSpecials(); // build subsector connect matrix // P_ConnectSubsectors (); // Load colormap and set the fullbright flag i = P_GetMapFadeTable(gamemap); W_ReadLump(i, colormaps); if (i == W_GetNumForName("COLORMAP")) { LevelUseFullBright = true; } else { // Probably fog ... don't use fullbright sprites LevelUseFullBright = false; } // preload graphics if (precache) R_PrecacheLevel(); // Check if the level is a lightning level P_InitLightning(); S_StopAllSound(); SN_StopAllSequences(); S_StartSong(gamemap, true); //printf ("free memory: 0x%x\n", Z_FreeMemory()); } //========================================================================== // // InitMapInfo // //========================================================================== static void InitMapInfo(void) { int map; int mapMax; int mcmdValue; mapInfo_t *info; char songMulch[10]; char *default_sky_name = DEFAULT_SKY_NAME; mapMax = 1; if (gamemode == shareware) { default_sky_name = "SKY2"; } // Put defaults into MapInfo[0] info = MapInfo; info->cluster = 0; info->warpTrans = 0; info->nextMap = 1; // Always go to map 1 if not specified info->cdTrack = 1; info->sky1Texture = R_TextureNumForName(default_sky_name); info->sky2Texture = info->sky1Texture; info->sky1ScrollDelta = 0; info->sky2ScrollDelta = 0; info->doubleSky = false; info->lightning = false; info->fadetable = W_GetNumForName(DEFAULT_FADE_TABLE); M_StringCopy(info->name, UNKNOWN_MAP_NAME, sizeof(info->name)); // M_StringCopy(info->songLump, DEFAULT_SONG_LUMP, sizeof(info->songLump)); SC_Open(MAPINFO_SCRIPT_NAME); while (SC_GetString()) { if (SC_Compare("MAP") == false) { SC_ScriptError(NULL); } SC_MustGetNumber(); if (sc_Number < 1 || sc_Number > 99) { // SC_ScriptError(NULL); } map = sc_Number; info = &MapInfo[map]; // Save song lump name M_StringCopy(songMulch, info->songLump, sizeof(songMulch)); // Copy defaults to current map definition memcpy(info, &MapInfo[0], sizeof(*info)); // Restore song lump name M_StringCopy(info->songLump, songMulch, sizeof(info->songLump)); // The warp translation defaults to the map number info->warpTrans = map; // Map name must follow the number SC_MustGetString(); M_StringCopy(info->name, sc_String, sizeof(info->name)); // Process optional tokens while (SC_GetString()) { if (SC_Compare("MAP")) { // Start next map definition SC_UnGet(); break; } mcmdValue = MapCmdIDs[SC_MustMatchString(MapCmdNames)]; switch (mcmdValue) { case MCMD_CLUSTER: SC_MustGetNumber(); info->cluster = sc_Number; break; case MCMD_WARPTRANS: SC_MustGetNumber(); info->warpTrans = sc_Number; break; case MCMD_NEXT: SC_MustGetNumber(); info->nextMap = sc_Number; break; case MCMD_CDTRACK: SC_MustGetNumber(); info->cdTrack = sc_Number; break; case MCMD_SKY1: SC_MustGetString(); info->sky1Texture = R_TextureNumForName(sc_String); SC_MustGetNumber(); info->sky1ScrollDelta = sc_Number << 8; break; case MCMD_SKY2: SC_MustGetString(); info->sky2Texture = R_TextureNumForName(sc_String); SC_MustGetNumber(); info->sky2ScrollDelta = sc_Number << 8; break; case MCMD_DOUBLESKY: info->doubleSky = true; break; case MCMD_LIGHTNING: info->lightning = true; break; case MCMD_FADETABLE: SC_MustGetString(); info->fadetable = W_GetNumForName(sc_String); break; case MCMD_CD_STARTTRACK: case MCMD_CD_END1TRACK: case MCMD_CD_END2TRACK: case MCMD_CD_END3TRACK: case MCMD_CD_INTERTRACK: case MCMD_CD_TITLETRACK: SC_MustGetNumber(); cd_NonLevelTracks[mcmdValue - MCMD_CD_STARTTRACK] = sc_Number; break; } } mapMax = map > mapMax ? map : mapMax; } SC_Close(); MapCount = mapMax; } //========================================================================== // // P_GetMapCluster // //========================================================================== int P_GetMapCluster(int map) { return MapInfo[QualifyMap(map)].cluster; } //========================================================================== // // P_GetMapCDTrack // //========================================================================== int P_GetMapCDTrack(int map) { return MapInfo[QualifyMap(map)].cdTrack; } //========================================================================== // // P_GetMapWarpTrans // //========================================================================== int P_GetMapWarpTrans(int map) { return MapInfo[QualifyMap(map)].warpTrans; } //========================================================================== // // P_GetMapNextMap // //========================================================================== int P_GetMapNextMap(int map) { return MapInfo[QualifyMap(map)].nextMap; } //========================================================================== // // P_TranslateMap // // Returns the actual map number given a warp map number. // //========================================================================== int P_TranslateMap(int map) { int i; for (i = 1; i < 99; i++) // Make this a macro { if (MapInfo[i].warpTrans == map) { return i; } } // Not found return -1; } //========================================================================== // // P_GetMapSky1Texture // //========================================================================== int P_GetMapSky1Texture(int map) { return MapInfo[QualifyMap(map)].sky1Texture; } //========================================================================== // // P_GetMapSky2Texture // //========================================================================== int P_GetMapSky2Texture(int map) { return MapInfo[QualifyMap(map)].sky2Texture; } //========================================================================== // // P_GetMapName // //========================================================================== char *P_GetMapName(int map) { return MapInfo[QualifyMap(map)].name; } //========================================================================== // // P_GetMapSky1ScrollDelta // //========================================================================== fixed_t P_GetMapSky1ScrollDelta(int map) { return MapInfo[QualifyMap(map)].sky1ScrollDelta; } //========================================================================== // // P_GetMapSky2ScrollDelta // //========================================================================== fixed_t P_GetMapSky2ScrollDelta(int map) { return MapInfo[QualifyMap(map)].sky2ScrollDelta; } //========================================================================== // // P_GetMapDoubleSky // //========================================================================== boolean P_GetMapDoubleSky(int map) { return MapInfo[QualifyMap(map)].doubleSky; } //========================================================================== // // P_GetMapLightning // //========================================================================== boolean P_GetMapLightning(int map) { return MapInfo[QualifyMap(map)].lightning; } //========================================================================== // // P_GetMapFadeTable // //========================================================================== boolean P_GetMapFadeTable(int map) { return MapInfo[QualifyMap(map)].fadetable; } //========================================================================== // // P_GetMapSongLump // //========================================================================== char *P_GetMapSongLump(int map) { if (!strcasecmp(MapInfo[QualifyMap(map)].songLump, DEFAULT_SONG_LUMP)) { return NULL; } else { return MapInfo[QualifyMap(map)].songLump; } } //========================================================================== // // P_PutMapSongLump // //========================================================================== void P_PutMapSongLump(int map, char *lumpName) { if (map < 1 || map > MapCount) { return; } M_StringCopy(MapInfo[map].songLump, lumpName, sizeof(MapInfo[map].songLump)); } //========================================================================== // // P_GetCDStartTrack // //========================================================================== int P_GetCDStartTrack(void) { return cd_NonLevelTracks[MCMD_CD_STARTTRACK - MCMD_CD_STARTTRACK]; } //========================================================================== // // P_GetCDEnd1Track // //========================================================================== int P_GetCDEnd1Track(void) { return cd_NonLevelTracks[MCMD_CD_END1TRACK - MCMD_CD_STARTTRACK]; } //========================================================================== // // P_GetCDEnd2Track // //========================================================================== int P_GetCDEnd2Track(void) { return cd_NonLevelTracks[MCMD_CD_END2TRACK - MCMD_CD_STARTTRACK]; } //========================================================================== // // P_GetCDEnd3Track // //========================================================================== int P_GetCDEnd3Track(void) { return cd_NonLevelTracks[MCMD_CD_END3TRACK - MCMD_CD_STARTTRACK]; } //========================================================================== // // P_GetCDIntermissionTrack // //========================================================================== int P_GetCDIntermissionTrack(void) { return cd_NonLevelTracks[MCMD_CD_INTERTRACK - MCMD_CD_STARTTRACK]; } //========================================================================== // // P_GetCDTitleTrack // //========================================================================== int P_GetCDTitleTrack(void) { return cd_NonLevelTracks[MCMD_CD_TITLETRACK - MCMD_CD_STARTTRACK]; } //========================================================================== // // QualifyMap // //========================================================================== static int QualifyMap(int map) { return (map < 1 || map > MapCount) ? 0 : map; } //========================================================================== // // P_Init // //========================================================================== void P_Init(void) { InitMapInfo(); P_InitSwitchList(); P_InitFTAnims(); // Init flat and texture animations P_InitTerrainTypes(); P_InitLava(); R_InitSprites(sprnames); } // Special early initializer needed to start sound before R_Init() void InitMapMusicInfo(void) { int i; for (i = 0; i < 99; i++) { M_StringCopy(MapInfo[i].songLump, DEFAULT_SONG_LUMP, sizeof(MapInfo[i].songLump)); } MapCount = 98; } /* void My_Debug(void) { int i; printf("My debug stuff ----------------------\n"); printf("gamemap=%d\n",gamemap); for (i=0; i<10; i++) { printf("i=%d songlump=%s\n",i,MapInfo[i].songLump); } } */ chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_sight.c000066400000000000000000000234171257432200600230130ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "p_local.h" /* ============================================================================== P_CheckSight This uses specialized forms of the maputils routines for optimized performance ============================================================================== */ fixed_t sightzstart; // eye z of looker fixed_t topslope, bottomslope; // slopes to top and bottom of target int sightcounts[3]; /* ============== = = PTR_SightTraverse = ============== */ boolean PTR_SightTraverse(intercept_t * in) { line_t *li; fixed_t slope; li = in->d.line; // // crosses a two sided line // P_LineOpening(li); if (openbottom >= opentop) // quick test for totally closed doors return false; // stop if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv(openbottom - sightzstart, in->frac); if (slope > bottomslope) bottomslope = slope; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv(opentop - sightzstart, in->frac); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop return true; // keep going } /* ================== = = P_SightBlockLinesIterator = =================== */ boolean P_SightBlockLinesIterator(int x, int y) { int offset; short *list; line_t *ld; int s1, s2; divline_t dl; polyblock_t *polyLink; seg_t **segList; int i; extern polyblock_t **PolyBlockMap; offset = y * bmapwidth + x; polyLink = PolyBlockMap[offset]; while (polyLink) { if (polyLink->polyobj) { // only check non-empty links if (polyLink->polyobj->validcount != validcount) { segList = polyLink->polyobj->segs; for (i = 0; i < polyLink->polyobj->numsegs; i++, segList++) { ld = (*segList)->linedef; if (ld->validcount == validcount) { continue; } ld->validcount = validcount; s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace); if (s1 == s2) continue; // line isn't crossed P_MakeDivline(ld, &dl); s1 = P_PointOnDivlineSide(trace.x, trace.y, &dl); s2 = P_PointOnDivlineSide(trace.x + trace.dx, trace.y + trace.dy, &dl); if (s1 == s2) continue; // line isn't crossed // try to early out the check if (!ld->backsector) return false; // stop checking // store the line for later intersection testing intercept_p->d.line = ld; intercept_p++; } polyLink->polyobj->validcount = validcount; } } polyLink = polyLink->next; } offset = *(blockmap + offset); for (list = blockmaplump + offset; *list != -1; list++) { ld = &lines[*list]; if (ld->validcount == validcount) continue; // line has already been checked ld->validcount = validcount; s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace); if (s1 == s2) continue; // line isn't crossed P_MakeDivline(ld, &dl); s1 = P_PointOnDivlineSide(trace.x, trace.y, &dl); s2 = P_PointOnDivlineSide(trace.x + trace.dx, trace.y + trace.dy, &dl); if (s1 == s2) continue; // line isn't crossed // try to early out the check if (!ld->backsector) return false; // stop checking // store the line for later intersection testing intercept_p->d.line = ld; intercept_p++; } return true; // everything was checked } /* ==================== = = P_SightTraverseIntercepts = = Returns true if the traverser function returns true for all lines ==================== */ boolean P_SightTraverseIntercepts(void) { int count; fixed_t dist; intercept_t *scan, *in; divline_t dl; count = intercept_p - intercepts; // // calculate intercept distance // for (scan = intercepts; scan < intercept_p; scan++) { P_MakeDivline(scan->d.line, &dl); scan->frac = P_InterceptVector(&trace, &dl); } // // go through in order // in = 0; // shut up compiler warning while (count--) { dist = INT_MAX; for (scan = intercepts; scan < intercept_p; scan++) if (scan->frac < dist) { dist = scan->frac; in = scan; } if (!PTR_SightTraverse(in)) return false; // don't bother going farther in->frac = INT_MAX; } return true; // everything was traversed } /* ================== = = P_SightPathTraverse = = Traces a line from x1,y1 to x2,y2, calling the traverser function for each = Returns true if the traverser function returns true for all lines ================== */ boolean P_SightPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) { fixed_t xt1, yt1, xt2, yt2; fixed_t xstep, ystep; fixed_t partial; fixed_t xintercept, yintercept; int mapx, mapy, mapxstep, mapystep; int count; validcount++; intercept_p = intercepts; if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0) x1 += FRACUNIT; // don't side exactly on a line if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0) y1 += FRACUNIT; // don't side exactly on a line trace.x = x1; trace.y = y1; trace.dx = x2 - x1; trace.dy = y2 - y1; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = x1 >> MAPBLOCKSHIFT; yt1 = y1 >> MAPBLOCKSHIFT; x2 -= bmaporgx; y2 -= bmaporgy; xt2 = x2 >> MAPBLOCKSHIFT; yt2 = y2 >> MAPBLOCKSHIFT; // points should never be out of bounds, but check once instead of // each block if (xt1 < 0 || yt1 < 0 || xt1 >= bmapwidth || yt1 >= bmapheight || xt2 < 0 || yt2 < 0 || xt2 >= bmapwidth || yt2 >= bmapheight) return false; if (xt2 > xt1) { mapxstep = 1; partial = FRACUNIT - ((x1 >> MAPBTOFRAC) & (FRACUNIT - 1)); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else if (xt2 < xt1) { mapxstep = -1; partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1); ystep = FixedDiv(y2 - y1, abs(x2 - x1)); } else { mapxstep = 0; partial = FRACUNIT; ystep = 256 * FRACUNIT; } yintercept = (y1 >> MAPBTOFRAC) + FixedMul(partial, ystep); if (yt2 > yt1) { mapystep = 1; partial = FRACUNIT - ((y1 >> MAPBTOFRAC) & (FRACUNIT - 1)); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else if (yt2 < yt1) { mapystep = -1; partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1); xstep = FixedDiv(x2 - x1, abs(y2 - y1)); } else { mapystep = 0; partial = FRACUNIT; xstep = 256 * FRACUNIT; } xintercept = (x1 >> MAPBTOFRAC) + FixedMul(partial, xstep); // // step through map blocks // Count is present to prevent a round off error from skipping the break mapx = xt1; mapy = yt1; for (count = 0; count < 64; count++) { if (!P_SightBlockLinesIterator(mapx, mapy)) { sightcounts[1]++; return false; // early out } if (mapx == xt2 && mapy == yt2) break; if ((yintercept >> FRACBITS) == mapy) { yintercept += ystep; mapx += mapxstep; } else if ((xintercept >> FRACBITS) == mapx) { xintercept += xstep; mapy += mapystep; } } // // couldn't early out, so go through the sorted list // sightcounts[2]++; return P_SightTraverseIntercepts(); } /* ===================== = = P_CheckSight = = Returns true if a straight line between t1 and t2 is unobstructed = look from eyes of t1 to any part of t2 = ===================== */ boolean P_CheckSight(mobj_t * t1, mobj_t * t2) { int s1, s2; int pnum, bytenum, bitnum; // // check for trivial rejection // s1 = (t1->subsector->sector - sectors); s2 = (t2->subsector->sector - sectors); pnum = s1 * numsectors + s2; bytenum = pnum >> 3; bitnum = 1 << (pnum & 7); if (rejectmatrix[bytenum] & bitnum) { sightcounts[0]++; return false; // can't possibly be connected } // // check precisely // sightzstart = t1->z + t1->height - (t1->height >> 2); topslope = (t2->z + t2->height) - sightzstart; bottomslope = (t2->z) - sightzstart; return P_SightPathTraverse(t1->x, t1->y, t2->x, t2->y); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_spec.c000066400000000000000000001121071257432200600226220ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "i_system.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" // MACROS ------------------------------------------------------------------ #define MAX_TAGGED_LINES 64 // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static boolean CheckedLockedDoor(mobj_t * mo, byte lock); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- int *TerrainTypes; struct { char *name; int type; } TerrainTypeDefs[] = { { "X_005", FLOOR_WATER}, { "X_001", FLOOR_LAVA}, { "X_009", FLOOR_SLUDGE}, { "F_033", FLOOR_ICE}, { "END", -1} }; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static struct { line_t *line; int lineTag; } TaggedLines[MAX_TAGGED_LINES]; static int TaggedLineCount; mobj_t LavaInflictor; // CODE -------------------------------------------------------------------- //========================================================================== // // P_InitLava // //========================================================================== void P_InitLava(void) { memset(&LavaInflictor, 0, sizeof(mobj_t)); LavaInflictor.type = MT_CIRCLEFLAME; LavaInflictor.flags2 = MF2_FIREDAMAGE | MF2_NODMGTHRUST; } //========================================================================== // // P_InitTerrainTypes // //========================================================================== void P_InitTerrainTypes(void) { int i; int lump; int size; size = (numflats + 1) * sizeof(int); TerrainTypes = Z_Malloc(size, PU_STATIC, 0); memset(TerrainTypes, 0, size); for (i = 0; TerrainTypeDefs[i].type != -1; i++) { lump = W_CheckNumForName(TerrainTypeDefs[i].name); if (lump != -1) { TerrainTypes[lump - firstflat] = TerrainTypeDefs[i].type; } } } //========================================================================== // // getSide // // Will return a side_t* given the number of the current sector, the // line number, and the side (0/1) that you want. // //========================================================================== /* side_t *getSide(int currentSector, int line, int side) { return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; } */ //========================================================================== // // getSector // // Will return a sector_t* given the number of the current sector, the // line number, and the side (0/1) that you want. // //========================================================================== /* sector_t *getSector(int currentSector, int line, int side) { return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; } */ //========================================================================== // // twoSided // // Given the sector number and the line number, will tell you whether // the line is two-sided or not. // //========================================================================== /* int twoSided(int sector, int line) { return (sectors[sector].lines[line])->flags & ML_TWOSIDED; } */ //================================================================== // // Return sector_t * of sector next to current. NULL if not two-sided line // //================================================================== sector_t *getNextSector(line_t * line, sector_t * sec) { if (!(line->flags & ML_TWOSIDED)) return NULL; if (line->frontsector == sec) return line->backsector; return line->frontsector; } //================================================================== // // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS // //================================================================== fixed_t P_FindLowestFloorSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t floor = sec->floorheight; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->floorheight < floor) floor = other->floorheight; } return floor; } //================================================================== // // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS // //================================================================== fixed_t P_FindHighestFloorSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t floor = -500 * FRACUNIT; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->floorheight > floor) floor = other->floorheight; } return floor; } //================================================================== // // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS // //================================================================== fixed_t P_FindNextHighestFloor(sector_t * sec, int currentheight) { int i; int h; int min; line_t *check; sector_t *other; fixed_t height = currentheight; fixed_t heightlist[20]; // 20 adjoining sectors max! heightlist[0] = 0; for (i = 0, h = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->floorheight > height) heightlist[h++] = other->floorheight; } // // Find lowest height in list // min = heightlist[0]; for (i = 1; i < h; i++) if (heightlist[i] < min) min = heightlist[i]; return min; } //================================================================== // // FIND LOWEST CEILING IN THE SURROUNDING SECTORS // //================================================================== fixed_t P_FindLowestCeilingSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t height = INT_MAX; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->ceilingheight < height) height = other->ceilingheight; } return height; } //================================================================== // // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS // //================================================================== fixed_t P_FindHighestCeilingSurrounding(sector_t * sec) { int i; line_t *check; sector_t *other; fixed_t height = 0; for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check, sec); if (!other) continue; if (other->ceilingheight > height) height = other->ceilingheight; } return height; } //================================================================== // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO // //================================================================== /* int P_FindSectorFromLineTag(line_t *line,int start) { int i; for (i=start+1;iarg1) return i; return -1; } */ //========================================================================= // // P_FindSectorFromTag // //========================================================================= int P_FindSectorFromTag(int tag, int start) { int i; for (i = start + 1; i < numsectors; i++) { if (sectors[i].tag == tag) { return i; } } return -1; } //================================================================== // // Find minimum light from an adjacent sector // //================================================================== /* int P_FindMinSurroundingLight(sector_t *sector,int max) { int i; int min; line_t *line; sector_t *check; min = max; for (i=0 ; i < sector->linecount ; i++) { line = sector->lines[i]; check = getNextSector(line,sector); if (!check) continue; if (check->lightlevel < min) min = check->lightlevel; } return min; } */ //========================================================================= // // EV_SectorSoundChange // //========================================================================= boolean EV_SectorSoundChange(byte * args) { int secNum; boolean rtn; if (!args[0]) { return false; } secNum = -1; rtn = false; while ((secNum = P_FindSectorFromTag(args[0], secNum)) >= 0) { sectors[secNum].seqType = args[1]; rtn = true; } return rtn; } //============================================================================ // // CheckedLockedDoor // //============================================================================ static boolean CheckedLockedDoor(mobj_t * mo, byte lock) { extern char *TextKeyMessages[11]; char LockedBuffer[80]; if (!mo->player) { return false; } if (!lock) { return true; } if (!(mo->player->keys & (1 << (lock - 1)))) { M_snprintf(LockedBuffer, sizeof(LockedBuffer), "YOU NEED THE %s\n", TextKeyMessages[lock - 1]); P_SetMessage(mo->player, LockedBuffer, true); S_StartSound(mo, SFX_DOOR_LOCKED); return false; } return true; } //========================================================================== // // EV_LineSearchForPuzzleItem // //========================================================================== boolean EV_LineSearchForPuzzleItem(line_t * line, byte * args, mobj_t * mo) { player_t *player; int i; int type; artitype_t arti; if (!mo) return false; player = mo->player; if (!player) return false; // Search player's inventory for puzzle items for (i = 0; i < player->artifactCount; i++) { arti = player->inventory[i].type; type = arti - arti_firstpuzzitem; if (type < 0) continue; if (type == line->arg1) { // A puzzle item was found for the line if (P_UseArtifact(player, arti)) { // A puzzle item was found for the line P_PlayerRemoveArtifact(player, i); if (player == &players[consoleplayer]) { if (arti < arti_firstpuzzitem) { S_StartSound(NULL, SFX_ARTIFACT_USE); } else { S_StartSound(NULL, SFX_PUZZLE_SUCCESS); } ArtifactFlash = 4; } return true; } } } return false; } /* ============================================================================== EVENTS Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers ============================================================================== */ //============================================================================ // // P_ExecuteLineSpecial // // Invoked when crossing a linedef. The args[] array should be at least // 5 elements in length. // //============================================================================ boolean P_ExecuteLineSpecial(int special, byte * args, line_t * line, int side, mobj_t * mo) { boolean buttonSuccess; buttonSuccess = false; switch (special) { case 1: // Poly Start Line break; case 2: // Poly Rotate Left buttonSuccess = EV_RotatePoly(line, args, 1, false); break; case 3: // Poly Rotate Right buttonSuccess = EV_RotatePoly(line, args, -1, false); break; case 4: // Poly Move buttonSuccess = EV_MovePoly(line, args, false, false); break; case 5: // Poly Explicit Line: Only used in initialization break; case 6: // Poly Move Times 8 buttonSuccess = EV_MovePoly(line, args, true, false); break; case 7: // Poly Door Swing buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SWING); break; case 8: // Poly Door Slide buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SLIDE); break; case 10: // Door Close buttonSuccess = EV_DoDoor(line, args, DREV_CLOSE); break; case 11: // Door Open if (!args[0]) { buttonSuccess = EV_VerticalDoor(line, mo); } else { buttonSuccess = EV_DoDoor(line, args, DREV_OPEN); } break; case 12: // Door Raise if (!args[0]) { buttonSuccess = EV_VerticalDoor(line, mo); } else { buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL); } break; case 13: // Door Locked_Raise if (CheckedLockedDoor(mo, args[3])) { if (!args[0]) { buttonSuccess = EV_VerticalDoor(line, mo); } else { buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL); } } break; case 20: // Floor Lower by Value buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE); break; case 21: // Floor Lower to Lowest buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORTOLOWEST); break; case 22: // Floor Lower to Nearest buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOOR); break; case 23: // Floor Raise by Value buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE); break; case 24: // Floor Raise to Highest buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOOR); break; case 25: // Floor Raise to Nearest buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORTONEAREST); break; case 26: // Stairs Build Down Normal buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_NORMAL); break; case 27: // Build Stairs Up Normal buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_NORMAL); break; case 28: // Floor Raise and Crush buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORCRUSH); break; case 29: // Build Pillar (no crushing) buttonSuccess = EV_BuildPillar(line, args, false); break; case 30: // Open Pillar buttonSuccess = EV_OpenPillar(line, args); break; case 31: // Stairs Build Down Sync buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_SYNC); break; case 32: // Build Stairs Up Sync buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_SYNC); break; case 35: // Raise Floor by Value Times 8 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEBYVALUETIMES8); break; case 36: // Lower Floor by Value Times 8 buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERBYVALUETIMES8); break; case 40: // Ceiling Lower by Value buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE); break; case 41: // Ceiling Raise by Value buttonSuccess = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE); break; case 42: // Ceiling Crush and Raise buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHANDRAISE); break; case 43: // Ceiling Lower and Crush buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERANDCRUSH); break; case 44: // Ceiling Crush Stop buttonSuccess = EV_CeilingCrushStop(line, args); break; case 45: // Ceiling Crush Raise and Stay buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHRAISEANDSTAY); break; case 46: // Floor Crush Stop buttonSuccess = EV_FloorCrushStop(line, args); break; case 60: // Plat Perpetual Raise buttonSuccess = EV_DoPlat(line, args, PLAT_PERPETUALRAISE, 0); break; case 61: // Plat Stop EV_StopPlat(line, args); break; case 62: // Plat Down-Wait-Up-Stay buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNWAITUPSTAY, 0); break; case 63: // Plat Down-by-Value*8-Wait-Up-Stay buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNBYVALUEWAITUPSTAY, 0); break; case 64: // Plat Up-Wait-Down-Stay buttonSuccess = EV_DoPlat(line, args, PLAT_UPWAITDOWNSTAY, 0); break; case 65: // Plat Up-by-Value*8-Wait-Down-Stay buttonSuccess = EV_DoPlat(line, args, PLAT_UPBYVALUEWAITDOWNSTAY, 0); break; case 66: // Floor Lower Instant * 8 buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERTIMES8INSTANT); break; case 67: // Floor Raise Instant * 8 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISETIMES8INSTANT); break; case 68: // Floor Move to Value * 8 buttonSuccess = EV_DoFloor(line, args, FLEV_MOVETOVALUETIMES8); break; case 69: // Ceiling Move to Value * 8 buttonSuccess = EV_DoCeiling(line, args, CLEV_MOVETOVALUETIMES8); break; case 70: // Teleport if (side == 0) { // Only teleport when crossing the front side of a line buttonSuccess = EV_Teleport(args[0], mo, true); } break; case 71: // Teleport, no fog if (side == 0) { // Only teleport when crossing the front side of a line buttonSuccess = EV_Teleport(args[0], mo, false); } break; case 72: // Thrust Mobj if (!side) // Only thrust on side 0 { P_ThrustMobj(mo, args[0] * (ANG90 / 64), args[1] << FRACBITS); buttonSuccess = 1; } break; case 73: // Damage Mobj if (args[0]) { P_DamageMobj(mo, NULL, NULL, args[0]); } else { // If arg1 is zero, then guarantee a kill P_DamageMobj(mo, NULL, NULL, 10000); } buttonSuccess = 1; break; case 74: // Teleport_NewMap if (side == 0) { // Only teleport when crossing the front side of a line if (!(mo && mo->player && mo->player->playerstate == PST_DEAD)) // Players must be alive to teleport { G_Completed(args[0], args[1]); buttonSuccess = true; } } break; case 75: // Teleport_EndGame if (side == 0) { // Only teleport when crossing the front side of a line if (!(mo && mo->player && mo->player->playerstate == PST_DEAD)) // Players must be alive to teleport { buttonSuccess = true; if (deathmatch) { // Winning in deathmatch just goes back to map 1 G_Completed(1, 0); } else { // Passing -1, -1 to G_Completed() starts the Finale G_Completed(-1, -1); } } } break; case 80: // ACS_Execute buttonSuccess = P_StartACS(args[0], args[1], &args[2], mo, line, side); break; case 81: // ACS_Suspend buttonSuccess = P_SuspendACS(args[0], args[1]); break; case 82: // ACS_Terminate buttonSuccess = P_TerminateACS(args[0], args[1]); break; case 83: // ACS_LockedExecute buttonSuccess = P_StartLockedACS(line, args, mo, side); break; case 90: // Poly Rotate Left Override buttonSuccess = EV_RotatePoly(line, args, 1, true); break; case 91: // Poly Rotate Right Override buttonSuccess = EV_RotatePoly(line, args, -1, true); break; case 92: // Poly Move Override buttonSuccess = EV_MovePoly(line, args, false, true); break; case 93: // Poly Move Times 8 Override buttonSuccess = EV_MovePoly(line, args, true, true); break; case 94: // Build Pillar Crush buttonSuccess = EV_BuildPillar(line, args, true); break; case 95: // Lower Floor and Ceiling buttonSuccess = EV_DoFloorAndCeiling(line, args, false); break; case 96: // Raise Floor and Ceiling buttonSuccess = EV_DoFloorAndCeiling(line, args, true); break; case 109: // Force Lightning buttonSuccess = true; P_ForceLightning(); break; case 110: // Light Raise by Value buttonSuccess = EV_SpawnLight(line, args, LITE_RAISEBYVALUE); break; case 111: // Light Lower by Value buttonSuccess = EV_SpawnLight(line, args, LITE_LOWERBYVALUE); break; case 112: // Light Change to Value buttonSuccess = EV_SpawnLight(line, args, LITE_CHANGETOVALUE); break; case 113: // Light Fade buttonSuccess = EV_SpawnLight(line, args, LITE_FADE); break; case 114: // Light Glow buttonSuccess = EV_SpawnLight(line, args, LITE_GLOW); break; case 115: // Light Flicker buttonSuccess = EV_SpawnLight(line, args, LITE_FLICKER); break; case 116: // Light Strobe buttonSuccess = EV_SpawnLight(line, args, LITE_STROBE); break; case 120: // Quake Tremor buttonSuccess = A_LocalQuake(args, mo); break; case 129: // UsePuzzleItem buttonSuccess = EV_LineSearchForPuzzleItem(line, args, mo); break; case 130: // Thing_Activate buttonSuccess = EV_ThingActivate(args[0]); break; case 131: // Thing_Deactivate buttonSuccess = EV_ThingDeactivate(args[0]); break; case 132: // Thing_Remove buttonSuccess = EV_ThingRemove(args[0]); break; case 133: // Thing_Destroy buttonSuccess = EV_ThingDestroy(args[0]); break; case 134: // Thing_Projectile buttonSuccess = EV_ThingProjectile(args, 0); break; case 135: // Thing_Spawn buttonSuccess = EV_ThingSpawn(args, 1); break; case 136: // Thing_ProjectileGravity buttonSuccess = EV_ThingProjectile(args, 1); break; case 137: // Thing_SpawnNoFog buttonSuccess = EV_ThingSpawn(args, 0); break; case 138: // Floor_Waggle buttonSuccess = EV_StartFloorWaggle(args[0], args[1], args[2], args[3], args[4]); break; case 140: // Sector_SoundChange buttonSuccess = EV_SectorSoundChange(args); break; // Line specials only processed during level initialization // 100: Scroll_Texture_Left // 101: Scroll_Texture_Right // 102: Scroll_Texture_Up // 103: Scroll_Texture_Down // 121: Line_SetIdentification // Inert Line specials default: break; } return buttonSuccess; } //============================================================================ // // P_ActivateLine // //============================================================================ boolean P_ActivateLine(line_t * line, mobj_t * mo, int side, int activationType) { byte args[5]; int lineActivation; boolean repeat; boolean buttonSuccess; lineActivation = GET_SPAC(line->flags); if (lineActivation != activationType) { return false; } if (!mo->player && !(mo->flags & MF_MISSILE)) { if (lineActivation != SPAC_MCROSS) { // currently, monsters can only activate the MCROSS activation type return false; } if (line->flags & ML_SECRET) return false; // never open secret doors } repeat = (line->flags & ML_REPEAT_SPECIAL) != 0; buttonSuccess = false; // Construct args[] array to contain the arguments from the line, as we // cannot rely on struct field ordering and layout. args[0] = line->arg1; args[1] = line->arg2; args[2] = line->arg3; args[3] = line->arg4; args[4] = line->arg5; buttonSuccess = P_ExecuteLineSpecial(line->special, args, line, side, mo); if (!repeat && buttonSuccess) { // clear the special on non-retriggerable lines line->special = 0; } if ((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT) && buttonSuccess) { P_ChangeSwitchTexture(line, repeat); } return true; } //---------------------------------------------------------------------------- // // PROC P_PlayerInSpecialSector // // Called every tic frame that the player origin is in a special sector. // //---------------------------------------------------------------------------- void P_PlayerInSpecialSector(player_t * player) { sector_t *sector; static int pushTab[3] = { 2048 * 5, 2048 * 10, 2048 * 25 }; sector = player->mo->subsector->sector; if (player->mo->z != sector->floorheight) { // Player is not touching the floor return; } switch (sector->special) { case 9: // SecretArea player->secretcount++; sector->special = 0; break; case 201: case 202: case 203: // Scroll_North_xxx P_Thrust(player, ANG90, pushTab[sector->special - 201]); break; case 204: case 205: case 206: // Scroll_East_xxx P_Thrust(player, 0, pushTab[sector->special - 204]); break; case 207: case 208: case 209: // Scroll_South_xxx P_Thrust(player, ANG270, pushTab[sector->special - 207]); break; case 210: case 211: case 212: // Scroll_West_xxx P_Thrust(player, ANG180, pushTab[sector->special - 210]); break; case 213: case 214: case 215: // Scroll_NorthWest_xxx P_Thrust(player, ANG90 + ANG45, pushTab[sector->special - 213]); break; case 216: case 217: case 218: // Scroll_NorthEast_xxx P_Thrust(player, ANG45, pushTab[sector->special - 216]); break; case 219: case 220: case 221: // Scroll_SouthEast_xxx P_Thrust(player, ANG270 + ANG45, pushTab[sector->special - 219]); break; case 222: case 223: case 224: // Scroll_SouthWest_xxx P_Thrust(player, ANG180 + ANG45, pushTab[sector->special - 222]); break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: // Wind specials are handled in (P_mobj):P_XYMovement break; case 26: // Stairs_Special1 case 27: // Stairs_Special2 // Used in (P_floor):ProcessStairSector break; case 198: // Lightning Special case 199: // Lightning Flash special case 200: // Sky2 // Used in (R_plane):R_Drawplanes break; default: I_Error("P_PlayerInSpecialSector: " "unknown special %i", sector->special); } } //============================================================================ // // P_PlayerOnSpecialFlat // //============================================================================ void P_PlayerOnSpecialFlat(player_t * player, int floorType) { if (player->mo->z != player->mo->floorz) { // Player is not touching the floor return; } switch (floorType) { case FLOOR_LAVA: if (!(leveltime & 31)) { P_DamageMobj(player->mo, &LavaInflictor, NULL, 10); S_StartSound(player->mo, SFX_LAVA_SIZZLE); } break; default: break; } } //---------------------------------------------------------------------------- // // PROC P_UpdateSpecials // //---------------------------------------------------------------------------- void P_UpdateSpecials(void) { int i; // Handle buttons for (i = 0; i < MAXBUTTONS; i++) { if (buttonlist[i].btimer) { buttonlist[i].btimer--; if (!buttonlist[i].btimer) { switch (buttonlist[i].where) { case SWTCH_TOP: sides[buttonlist[i].line->sidenum[0]].toptexture = buttonlist[i].btexture; break; case SWTCH_MIDDLE: sides[buttonlist[i].line->sidenum[0]].midtexture = buttonlist[i].btexture; break; case SWTCH_BOTTOM: sides[buttonlist[i].line->sidenum[0]].bottomtexture = buttonlist[i].btexture; break; } //S_StartSound((mobj_t *)&buttonlist[i].soundorg, sfx_switch); memset(&buttonlist[i], 0, sizeof(button_t)); } } } } /* ============================================================================== SPECIAL SPAWNING ============================================================================== */ /* ================================================================================ = P_SpawnSpecials = = After the map has been loaded, scan for specials that = spawn thinkers = =============================================================================== */ short numlinespecials; line_t *linespeciallist[MAXLINEANIMS]; void P_SpawnSpecials(void) { sector_t *sector; int i; // // Init special SECTORs // sector = sectors; for (i = 0; i < numsectors; i++, sector++) { if (!sector->special) continue; switch (sector->special) { case 1: // Phased light // Hardcoded base, use sector->lightlevel as the index P_SpawnPhasedLight(sector, 80, -1); break; case 2: // Phased light sequence start P_SpawnLightSequence(sector, 1); break; // Specials 3 & 4 are used by the phased light sequences /* case 1: // FLICKERING LIGHTS P_SpawnLightFlash (sector); break; case 2: // STROBE FAST P_SpawnStrobeFlash(sector,FASTDARK,0); break; case 3: // STROBE SLOW P_SpawnStrobeFlash(sector,SLOWDARK,0); break; case 4: // STROBE FAST/DEATH SLIME P_SpawnStrobeFlash(sector,FASTDARK,0); sector->special = 4; break; case 8: // GLOWING LIGHT P_SpawnGlowingLight(sector); break; case 9: // SECRET SECTOR totalsecret++; break; case 10: // DOOR CLOSE IN 30 SECONDS P_SpawnDoorCloseIn30 (sector); break; case 12: // SYNC STROBE SLOW P_SpawnStrobeFlash (sector, SLOWDARK, 1); break; case 13: // SYNC STROBE FAST P_SpawnStrobeFlash (sector, FASTDARK, 1); break; case 14: // DOOR RAISE IN 5 MINUTES P_SpawnDoorRaiseIn5Mins (sector, i); break; */ } } // // Init line EFFECTs // numlinespecials = 0; TaggedLineCount = 0; for (i = 0; i < numlines; i++) { switch (lines[i].special) { case 100: // Scroll_Texture_Left case 101: // Scroll_Texture_Right case 102: // Scroll_Texture_Up case 103: // Scroll_Texture_Down linespeciallist[numlinespecials] = &lines[i]; numlinespecials++; break; case 121: // Line_SetIdentification if (lines[i].arg1) { if (TaggedLineCount == MAX_TAGGED_LINES) { I_Error("P_SpawnSpecials: MAX_TAGGED_LINES " "(%d) exceeded.", MAX_TAGGED_LINES); } TaggedLines[TaggedLineCount].line = &lines[i]; TaggedLines[TaggedLineCount++].lineTag = lines[i].arg1; } lines[i].special = 0; break; } } // // Init other misc stuff // for (i = 0; i < MAXCEILINGS; i++) activeceilings[i] = NULL; for (i = 0; i < MAXPLATS; i++) activeplats[i] = NULL; for (i = 0; i < MAXBUTTONS; i++) memset(&buttonlist[i], 0, sizeof(button_t)); // Initialize flat and texture animations P_InitFTAnims(); } //========================================================================== // // P_FindLine // //========================================================================== line_t *P_FindLine(int lineTag, int *searchPosition) { int i; for (i = *searchPosition + 1; i < TaggedLineCount; i++) { if (TaggedLines[i].lineTag == lineTag) { *searchPosition = i; return TaggedLines[i].line; } } *searchPosition = -1; return NULL; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_spec.h000066400000000000000000000333271257432200600226350ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // extern int *TerrainTypes; // // scrolling line specials // #define MAXLINEANIMS 64 extern short numlinespecials; extern line_t *linespeciallist[MAXLINEANIMS]; // Define values for map objects #define MO_TELEPORTMAN 14 // at game start void P_InitTerrainTypes(void); void P_InitLava(void); // at map load void P_SpawnSpecials(void); // every tic void P_UpdateSpecials(void); // when needed boolean P_ExecuteLineSpecial(int special, byte * args, line_t * line, int side, mobj_t * mo); boolean P_ActivateLine(line_t * ld, mobj_t * mo, int side, int activationType); //boolean P_UseSpecialLine ( mobj_t *thing, line_t *line); //void P_ShootSpecialLine ( mobj_t *thing, line_t *line); //void P_CrossSpecialLine (int linenum, int side, mobj_t *thing); void P_PlayerInSpecialSector(player_t * player); void P_PlayerOnSpecialFlat(player_t * player, int floorType); //int twoSided(int sector,int line); //sector_t *getSector(int currentSector,int line,int side); //side_t *getSide(int currentSector,int line, int side); fixed_t P_FindLowestFloorSurrounding(sector_t * sec); fixed_t P_FindHighestFloorSurrounding(sector_t * sec); fixed_t P_FindNextHighestFloor(sector_t * sec, int currentheight); fixed_t P_FindLowestCeilingSurrounding(sector_t * sec); fixed_t P_FindHighestCeilingSurrounding(sector_t * sec); //int P_FindSectorFromLineTag(line_t *line,int start); int P_FindSectorFromTag(int tag, int start); //int P_FindMinSurroundingLight(sector_t *sector,int max); sector_t *getNextSector(line_t * line, sector_t * sec); line_t *P_FindLine(int lineTag, int *searchPosition); // // SPECIAL // //int EV_DoDonut(line_t *line); //------------------------------- // P_anim.c //------------------------------- void P_AnimateSurfaces(void); void P_InitFTAnims(void); void P_InitLightning(void); void P_ForceLightning(void); /* =============================================================================== P_LIGHTS =============================================================================== */ typedef enum { LITE_RAISEBYVALUE, LITE_LOWERBYVALUE, LITE_CHANGETOVALUE, LITE_FADE, LITE_GLOW, LITE_FLICKER, LITE_STROBE } lighttype_t; typedef struct { thinker_t thinker; sector_t *sector; lighttype_t type; int value1; int value2; int tics1; int tics2; int count; } light_t; typedef struct { thinker_t thinker; sector_t *sector; int index; int base; } phase_t; #define LIGHT_SEQUENCE_START 2 #define LIGHT_SEQUENCE 3 #define LIGHT_SEQUENCE_ALT 4 void T_Phase(phase_t * phase); void T_Light(light_t * light); void P_SpawnPhasedLight(sector_t * sector, int base, int index); void P_SpawnLightSequence(sector_t * sector, int indexStep); boolean EV_SpawnLight(line_t * line, byte * arg, lighttype_t type); #if 0 typedef struct { thinker_t thinker; sector_t *sector; int count; int maxlight; int minlight; int maxtime; int mintime; } lightflash_t; typedef struct { thinker_t thinker; sector_t *sector; int count; int minlight; int maxlight; int darktime; int brighttime; } strobe_t; typedef struct { thinker_t thinker; sector_t *sector; int minlight; int maxlight; int direction; } glow_t; typedef struct { thinker_t thinker; sector_t *sector; int index; int base; } phase_t; #define GLOWSPEED 8 #define STROBEBRIGHT 5 #define FASTDARK 15 #define SLOWDARK 35 #define LIGHT_SEQUENCE_START 2 #define LIGHT_SEQUENCE 3 #define LIGHT_SEQUENCE_ALT 4 void T_LightFlash(lightflash_t * flash); void P_SpawnLightFlash(sector_t * sector); void T_StrobeFlash(strobe_t * flash); void P_SpawnStrobeFlash(sector_t * sector, int fastOrSlow, int inSync); void EV_StartLightStrobing(line_t * line); void EV_TurnTagLightsOff(line_t * line); void EV_LightTurnOn(line_t * line, int bright); void T_Glow(glow_t * g); void P_SpawnGlowingLight(sector_t * sector); void T_Phase(phase_t * phase); void P_SpawnPhasedLight(sector_t * sector, int base, int index); void P_SpawnLightSequence(sector_t * sector, int indexStep); #endif /* =============================================================================== P_SWITCH =============================================================================== */ typedef struct { char name1[9]; char name2[9]; int soundID; } switchlist_t; typedef enum { SWTCH_TOP, SWTCH_MIDDLE, SWTCH_BOTTOM } bwhere_e; typedef struct { line_t *line; bwhere_e where; int btexture; int btimer; mobj_t *soundorg; } button_t; #define MAXSWITCHES 50 // max # of wall switches in a level #define MAXBUTTONS 16 // 4 players, 4 buttons each at once, max. #define BUTTONTIME 35 // 1 second extern button_t buttonlist[MAXBUTTONS]; void P_ChangeSwitchTexture(line_t * line, int useAgain); void P_InitSwitchList(void); /* =============================================================================== P_PLATS =============================================================================== */ typedef enum { PLAT_UP, PLAT_DOWN, PLAT_WAITING, // PLAT_IN_STASIS } plat_e; typedef enum { PLAT_PERPETUALRAISE, PLAT_DOWNWAITUPSTAY, PLAT_DOWNBYVALUEWAITUPSTAY, PLAT_UPWAITDOWNSTAY, PLAT_UPBYVALUEWAITDOWNSTAY, //PLAT_RAISEANDCHANGE, //PLAT_RAISETONEARESTANDCHANGE } plattype_e; typedef struct { thinker_t thinker; sector_t *sector; fixed_t speed; fixed_t low; fixed_t high; int wait; int count; plat_e status; plat_e oldstatus; int crush; int tag; plattype_e type; } plat_t; #define PLATWAIT 3 #define PLATSPEED FRACUNIT #define MAXPLATS 30 extern plat_t *activeplats[MAXPLATS]; void T_PlatRaise(plat_t * plat); int EV_DoPlat(line_t * line, byte * args, plattype_e type, int amount); void P_AddActivePlat(plat_t * plat); void P_RemoveActivePlat(plat_t * plat); void EV_StopPlat(line_t * line, byte * args); /* =============================================================================== P_DOORS =============================================================================== */ typedef enum { DREV_NORMAL, DREV_CLOSE30THENOPEN, DREV_CLOSE, DREV_OPEN, DREV_RAISEIN5MINS, } vldoor_e; typedef struct { thinker_t thinker; sector_t *sector; vldoor_e type; fixed_t topheight; fixed_t speed; int direction; // 1 = up, 0 = waiting at top, -1 = down int topwait; // tics to wait at the top (keep in case a door going down is reset) int topcountdown; // when it reaches 0, start going down } vldoor_t; #define VDOORSPEED FRACUNIT*2 #define VDOORWAIT 150 boolean EV_VerticalDoor(line_t * line, mobj_t * thing); int EV_DoDoor(line_t * line, byte * args, vldoor_e type); void T_VerticalDoor(vldoor_t * door); //void P_SpawnDoorCloseIn30(sector_t *sec); //void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum); /* =============================================================================== P_CEILNG =============================================================================== */ typedef enum { CLEV_LOWERTOFLOOR, CLEV_RAISETOHIGHEST, CLEV_LOWERANDCRUSH, CLEV_CRUSHANDRAISE, CLEV_LOWERBYVALUE, CLEV_RAISEBYVALUE, CLEV_CRUSHRAISEANDSTAY, CLEV_MOVETOVALUETIMES8 } ceiling_e; typedef struct { thinker_t thinker; sector_t *sector; ceiling_e type; fixed_t bottomheight, topheight; fixed_t speed; int crush; int direction; // 1 = up, 0 = waiting, -1 = down int tag; // ID int olddirection; } ceiling_t; #define CEILSPEED FRACUNIT #define CEILWAIT 150 #define MAXCEILINGS 30 extern ceiling_t *activeceilings[MAXCEILINGS]; int EV_DoCeiling(line_t * line, byte * args, ceiling_e type); void T_MoveCeiling(ceiling_t * ceiling); void P_AddActiveCeiling(ceiling_t * c); void P_RemoveActiveCeiling(ceiling_t * c); int EV_CeilingCrushStop(line_t * line, byte * args); /* =============================================================================== P_FLOOR =============================================================================== */ typedef enum { FLEV_LOWERFLOOR, // lower floor to highest surrounding floor FLEV_LOWERFLOORTOLOWEST, // lower floor to lowest surrounding floor FLEV_LOWERFLOORBYVALUE, FLEV_RAISEFLOOR, // raise floor to lowest surrounding CEILING FLEV_RAISEFLOORTONEAREST, // raise floor to next highest surrounding floor FLEV_RAISEFLOORBYVALUE, FLEV_RAISEFLOORCRUSH, FLEV_RAISEBUILDSTEP, // One step of a staircase FLEV_RAISEBYVALUETIMES8, FLEV_LOWERBYVALUETIMES8, FLEV_LOWERTIMES8INSTANT, FLEV_RAISETIMES8INSTANT, FLEV_MOVETOVALUETIMES8 } floor_e; typedef struct { thinker_t thinker; sector_t *sector; floor_e type; int crush; int direction; int newspecial; short texture; fixed_t floordestheight; fixed_t speed; int delayCount; int delayTotal; fixed_t stairsDelayHeight; fixed_t stairsDelayHeightDelta; fixed_t resetHeight; short resetDelay; short resetDelayCount; byte textureChange; } floormove_t; typedef struct { thinker_t thinker; sector_t *sector; int ceilingSpeed; int floorSpeed; int floordest; int ceilingdest; int direction; int crush; } pillar_t; typedef struct { thinker_t thinker; sector_t *sector; fixed_t originalHeight; fixed_t accumulator; fixed_t accDelta; fixed_t targetScale; fixed_t scale; fixed_t scaleDelta; int ticker; int state; } floorWaggle_t; #define FLOORSPEED FRACUNIT typedef enum { RES_OK, RES_CRUSHED, RES_PASTDEST } result_e; typedef enum { STAIRS_NORMAL, STAIRS_SYNC, STAIRS_PHASED } stairs_e; result_e T_MovePlane(sector_t * sector, fixed_t speed, fixed_t dest, int crush, int floorOrCeiling, int direction); int EV_BuildStairs(line_t * line, byte * args, int direction, stairs_e type); int EV_DoFloor(line_t * line, byte * args, floor_e floortype); void T_MoveFloor(floormove_t * floor); void T_BuildPillar(pillar_t * pillar); void T_FloorWaggle(floorWaggle_t * waggle); int EV_BuildPillar(line_t * line, byte * args, boolean crush); int EV_OpenPillar(line_t * line, byte * args); int EV_DoFloorAndCeiling(line_t * line, byte * args, boolean raise); int EV_FloorCrushStop(line_t * line, byte * args); boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset, int timer); //-------------------------------------------------------------------------- // // p_telept // //-------------------------------------------------------------------------- boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle, boolean useFog); boolean EV_Teleport(int tid, mobj_t * thing, boolean fog); //-------------------------------------------------------------------------- // // p_acs // //-------------------------------------------------------------------------- #define MAX_ACS_SCRIPT_VARS 10 #define MAX_ACS_MAP_VARS 32 #define MAX_ACS_WORLD_VARS 64 #define ACS_STACK_DEPTH 32 #define MAX_ACS_STORE 20 typedef enum { ASTE_INACTIVE, ASTE_RUNNING, ASTE_SUSPENDED, ASTE_WAITINGFORTAG, ASTE_WAITINGFORPOLY, ASTE_WAITINGFORSCRIPT, ASTE_TERMINATING } aste_t; typedef struct acs_s acs_t; typedef struct acsInfo_s acsInfo_t; struct acsInfo_s { int number; int *address; int argCount; aste_t state; int waitValue; }; struct acs_s { thinker_t thinker; mobj_t *activator; line_t *line; int side; int number; int infoIndex; int delayCount; int stack[ACS_STACK_DEPTH]; int stackPtr; int vars[MAX_ACS_SCRIPT_VARS]; int *ip; }; typedef struct { int map; // Target map int script; // Script number on target map byte args[4]; // Padded to 4 for alignment } acsstore_t; void P_LoadACScripts(int lump); boolean P_StartACS(int number, int map, byte * args, mobj_t * activator, line_t * line, int side); boolean P_StartLockedACS(line_t * line, byte * args, mobj_t * mo, int side); boolean P_TerminateACS(int number, int map); boolean P_SuspendACS(int number, int map); void T_InterpretACS(acs_t * script); void P_TagFinished(int tag); void P_PolyobjFinished(int po); void P_ACSInitNewGame(void); void P_CheckACSStore(void); extern int ACScriptCount; extern byte *ActionCodeBase; extern acsInfo_t *ACSInfo; extern int MapVars[MAX_ACS_MAP_VARS]; extern int WorldVars[MAX_ACS_WORLD_VARS]; extern acsstore_t ACSStore[MAX_ACS_STORE + 1]; // +1 for termination marker //-------------------------------------------------------------------------- // // p_things // //-------------------------------------------------------------------------- extern mobjtype_t TranslateThingType[]; boolean EV_ThingProjectile(byte * args, boolean gravity); boolean EV_ThingSpawn(byte * args, boolean fog); boolean EV_ThingActivate(int tid); boolean EV_ThingDeactivate(int tid); boolean EV_ThingRemove(int tid); boolean EV_ThingDestroy(int tid); chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_switch.c000066400000000000000000000115421257432200600231720ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" //================================================================== // // CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE // //================================================================== switchlist_t alphSwitchListDemo[] = { {"SW_1_UP", "SW_1_DN", SFX_SWITCH1}, {"SW_2_UP", "SW_2_DN", SFX_SWITCH1}, {"SW52_OFF", "SW52_ON", SFX_SWITCH2}, {"\0", "\0", 0} }; switchlist_t alphSwitchListFull[] = { {"SW_1_UP", "SW_1_DN", SFX_SWITCH1}, {"SW_2_UP", "SW_2_DN", SFX_SWITCH1}, {"VALVE1", "VALVE2", SFX_VALVE_TURN}, {"SW51_OFF", "SW51_ON", SFX_SWITCH2}, {"SW52_OFF", "SW52_ON", SFX_SWITCH2}, {"SW53_UP", "SW53_DN", SFX_ROPE_PULL}, {"PUZZLE5", "PUZZLE9", SFX_SWITCH1}, {"PUZZLE6", "PUZZLE10", SFX_SWITCH1}, {"PUZZLE7", "PUZZLE11", SFX_SWITCH1}, {"PUZZLE8", "PUZZLE12", SFX_SWITCH1}, {"\0", "\0", 0} }; switchlist_t *alphSwitchList = NULL; int switchlist[MAXSWITCHES * 2]; int numswitches; button_t buttonlist[MAXBUTTONS]; /* =============== = = P_InitSwitchList = = Only called at game initialization = =============== */ void P_InitSwitchList(void) { int i; int index; if (!alphSwitchList) { if (gamemode == shareware) { alphSwitchList = alphSwitchListDemo; } else { alphSwitchList = alphSwitchListFull; } } for (index = 0, i = 0; i < MAXSWITCHES; i++) { if (!alphSwitchList[i].soundID) { numswitches = index / 2; switchlist[index] = -1; break; } switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name1); switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name2); } } //================================================================== // // Start a button counting down till it turns off. // //================================================================== void P_StartButton(line_t * line, bwhere_e w, int texture, int time) { int i; for (i = 0; i < MAXBUTTONS; i++) { if (!buttonlist[i].btimer) { buttonlist[i].line = line; buttonlist[i].where = w; buttonlist[i].btexture = texture; buttonlist[i].btimer = time; buttonlist[i].soundorg = (mobj_t *) & line->frontsector->soundorg; return; } } I_Error("P_StartButton: no button slots left!"); } //================================================================== // // Function that changes wall texture. // Tell it if switch is ok to use again (1=yes, it's a button). // //================================================================== void P_ChangeSwitchTexture(line_t * line, int useAgain) { int texTop; int texMid; int texBot; int i; texTop = sides[line->sidenum[0]].toptexture; texMid = sides[line->sidenum[0]].midtexture; texBot = sides[line->sidenum[0]].bottomtexture; for (i = 0; i < numswitches * 2; i++) { if (switchlist[i] == texTop) { S_StartSound((mobj_t *) & line->frontsector->soundorg, alphSwitchList[i / 2].soundID); sides[line->sidenum[0]].toptexture = switchlist[i ^ 1]; if (useAgain) { P_StartButton(line, SWTCH_TOP, switchlist[i], BUTTONTIME); } return; } else if (switchlist[i] == texMid) { S_StartSound((mobj_t *) & line->frontsector->soundorg, alphSwitchList[i / 2].soundID); sides[line->sidenum[0]].midtexture = switchlist[i ^ 1]; if (useAgain) { P_StartButton(line, SWTCH_MIDDLE, switchlist[i], BUTTONTIME); } return; } else if (switchlist[i] == texBot) { S_StartSound((mobj_t *) & line->frontsector->soundorg, alphSwitchList[i / 2].soundID); sides[line->sidenum[0]].bottomtexture = switchlist[i ^ 1]; if (useAgain) { P_StartButton(line, SWTCH_BOTTOM, switchlist[i], BUTTONTIME); } return; } } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_telept.c000066400000000000000000000124371257432200600231720ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "m_random.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- //========================================================================== // // P_Teleport // //========================================================================== boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle, boolean useFog) { fixed_t oldx; fixed_t oldy; fixed_t oldz; fixed_t aboveFloor; fixed_t fogDelta; player_t *player; unsigned an; mobj_t *fog; oldx = thing->x; oldy = thing->y; oldz = thing->z; aboveFloor = thing->z - thing->floorz; if (!P_TeleportMove(thing, x, y)) { return false; } if (thing->player) { player = thing->player; if (player->powers[pw_flight] && aboveFloor) { thing->z = thing->floorz + aboveFloor; if (thing->z + thing->height > thing->ceilingz) { thing->z = thing->ceilingz - thing->height; } player->viewz = thing->z + player->viewheight; } else { thing->z = thing->floorz; player->viewz = thing->z + player->viewheight; if (useFog) { player->lookdir = 0; } } } else if (thing->flags & MF_MISSILE) { thing->z = thing->floorz + aboveFloor; if (thing->z + thing->height > thing->ceilingz) { thing->z = thing->ceilingz - thing->height; } } else { thing->z = thing->floorz; } // Spawn teleport fog at source and destination if (useFog) { fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; fog = P_SpawnMobj(oldx, oldy, oldz + fogDelta, MT_TFOG); S_StartSound(fog, SFX_TELEPORT); an = angle >> ANGLETOFINESHIFT; fog = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an], thing->z + fogDelta, MT_TFOG); S_StartSound(fog, SFX_TELEPORT); if (thing->player && !thing->player->powers[pw_speed]) { // Freeze player for about .5 sec thing->reactiontime = 18; } thing->angle = angle; } if (thing->flags2 & MF2_FLOORCLIP) { if (thing->z == thing->subsector->sector->floorheight && P_GetThingFloorType(thing) > FLOOR_SOLID) { thing->floorclip = 10 * FRACUNIT; } else { thing->floorclip = 0; } } if (thing->flags & MF_MISSILE) { angle >>= ANGLETOFINESHIFT; thing->momx = FixedMul(thing->info->speed, finecosine[angle]); thing->momy = FixedMul(thing->info->speed, finesine[angle]); } else if (useFog) // no fog doesn't alter the player's momentums { thing->momx = thing->momy = thing->momz = 0; } return true; } //========================================================================== // // EV_Teleport // //========================================================================== boolean EV_Teleport(int tid, mobj_t * thing, boolean fog) { int i; int count; mobj_t *mo; int searcher; if (!thing) { // Teleport function called with an invalid mobj return false; } if (thing->flags2 & MF2_NOTELEPORT) { return false; } count = 0; searcher = -1; while (P_FindMobjFromTID(tid, &searcher) != NULL) { count++; } if (count == 0) { return false; } count = 1 + (P_Random() % count); searcher = -1; mo = NULL; for (i = 0; i < count; i++) { mo = P_FindMobjFromTID(tid, &searcher); } if (mo == NULL) { I_Error("Can't find teleport mapspot\n"); } return P_Teleport(thing, mo->x, mo->y, mo->angle, fog); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_things.c000066400000000000000000000411721257432200600231670ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "p_local.h" #include "s_sound.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static boolean ActivateThing(mobj_t * mobj); static boolean DeactivateThing(mobj_t * mobj); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- mobjtype_t TranslateThingType[] = { MT_MAPSPOT, // T_NONE MT_CENTAUR, // T_CENTAUR MT_CENTAURLEADER, // T_CENTAURLEADER MT_DEMON, // T_DEMON MT_ETTIN, // T_ETTIN MT_FIREDEMON, // T_FIREGARGOYLE MT_SERPENT, // T_WATERLURKER MT_SERPENTLEADER, // T_WATERLURKERLEADER MT_WRAITH, // T_WRAITH MT_WRAITHB, // T_WRAITHBURIED MT_FIREBALL1, // T_FIREBALL1 MT_MANA1, // T_MANA1 MT_MANA2, // T_MANA2 MT_SPEEDBOOTS, // T_ITEMBOOTS MT_ARTIEGG, // T_ITEMEGG MT_ARTIFLY, // T_ITEMFLIGHT MT_SUMMONMAULATOR, // T_ITEMSUMMON MT_TELEPORTOTHER, // T_ITEMTPORTOTHER MT_ARTITELEPORT, // T_ITEMTELEPORT MT_BISHOP, // T_BISHOP MT_ICEGUY, // T_ICEGOLEM MT_BRIDGE, // T_BRIDGE MT_BOOSTARMOR, // T_DRAGONSKINBRACERS MT_HEALINGBOTTLE, // T_ITEMHEALTHPOTION MT_HEALTHFLASK, // T_ITEMHEALTHFLASK MT_ARTISUPERHEAL, // T_ITEMHEALTHFULL MT_BOOSTMANA, // T_ITEMBOOSTMANA MT_FW_AXE, // T_FIGHTERAXE MT_FW_HAMMER, // T_FIGHTERHAMMER MT_FW_SWORD1, // T_FIGHTERSWORD1 MT_FW_SWORD2, // T_FIGHTERSWORD2 MT_FW_SWORD3, // T_FIGHTERSWORD3 MT_CW_SERPSTAFF, // T_CLERICSTAFF MT_CW_HOLY1, // T_CLERICHOLY1 MT_CW_HOLY2, // T_CLERICHOLY2 MT_CW_HOLY3, // T_CLERICHOLY3 MT_MW_CONE, // T_MAGESHARDS MT_MW_STAFF1, // T_MAGESTAFF1 MT_MW_STAFF2, // T_MAGESTAFF2 MT_MW_STAFF3, // T_MAGESTAFF3 MT_EGGFX, // T_MORPHBLAST MT_ROCK1, // T_ROCK1 MT_ROCK2, // T_ROCK2 MT_ROCK3, // T_ROCK3 MT_DIRT1, // T_DIRT1 MT_DIRT2, // T_DIRT2 MT_DIRT3, // T_DIRT3 MT_DIRT4, // T_DIRT4 MT_DIRT5, // T_DIRT5 MT_DIRT6, // T_DIRT6 MT_ARROW, // T_ARROW MT_DART, // T_DART MT_POISONDART, // T_POISONDART MT_RIPPERBALL, // T_RIPPERBALL MT_SGSHARD1, // T_STAINEDGLASS1 MT_SGSHARD2, // T_STAINEDGLASS2 MT_SGSHARD3, // T_STAINEDGLASS3 MT_SGSHARD4, // T_STAINEDGLASS4 MT_SGSHARD5, // T_STAINEDGLASS5 MT_SGSHARD6, // T_STAINEDGLASS6 MT_SGSHARD7, // T_STAINEDGLASS7 MT_SGSHARD8, // T_STAINEDGLASS8 MT_SGSHARD9, // T_STAINEDGLASS9 MT_SGSHARD0, // T_STAINEDGLASS0 MT_PROJECTILE_BLADE, // T_BLADE MT_ICESHARD, // T_ICESHARD MT_FLAME_SMALL, // T_FLAME_SMALL MT_FLAME_LARGE, // T_FLAME_LARGE MT_ARMOR_1, // T_MESHARMOR MT_ARMOR_2, // T_FALCONSHIELD MT_ARMOR_3, // T_PLATINUMHELM MT_ARMOR_4, // T_AMULETOFWARDING MT_ARTIPOISONBAG, // T_ITEMFLECHETTE MT_ARTITORCH, // T_ITEMTORCH MT_BLASTRADIUS, // T_ITEMREPULSION MT_MANA3, // T_MANA3 MT_ARTIPUZZSKULL, // T_PUZZSKULL MT_ARTIPUZZGEMBIG, // T_PUZZGEMBIG MT_ARTIPUZZGEMRED, // T_PUZZGEMRED MT_ARTIPUZZGEMGREEN1, // T_PUZZGEMGREEN1 MT_ARTIPUZZGEMGREEN2, // T_PUZZGEMGREEN2 MT_ARTIPUZZGEMBLUE1, // T_PUZZGEMBLUE1 MT_ARTIPUZZGEMBLUE2, // T_PUZZGEMBLUE2 MT_ARTIPUZZBOOK1, // T_PUZZBOOK1 MT_ARTIPUZZBOOK2, // T_PUZZBOOK2 MT_KEY1, // T_METALKEY MT_KEY2, // T_SMALLMETALKEY MT_KEY3, // T_AXEKEY MT_KEY4, // T_FIREKEY MT_KEY5, // T_GREENKEY MT_KEY6, // T_MACEKEY MT_KEY7, // T_SILVERKEY MT_KEY8, // T_RUSTYKEY MT_KEY9, // T_HORNKEY MT_KEYA, // T_SERPENTKEY MT_WATER_DRIP, // T_WATERDRIP MT_FLAME_SMALL_TEMP, // T_TEMPSMALLFLAME MT_FLAME_SMALL, // T_PERMSMALLFLAME MT_FLAME_LARGE_TEMP, // T_TEMPLARGEFLAME MT_FLAME_LARGE, // T_PERMLARGEFLAME MT_DEMON_MASH, // T_DEMON_MASH MT_DEMON2_MASH, // T_DEMON2_MASH MT_ETTIN_MASH, // T_ETTIN_MASH MT_CENTAUR_MASH, // T_CENTAUR_MASH MT_THRUSTFLOOR_UP, // T_THRUSTSPIKEUP MT_THRUSTFLOOR_DOWN, // T_THRUSTSPIKEDOWN MT_WRAITHFX4, // T_FLESH_DRIP1 MT_WRAITHFX5, // T_FLESH_DRIP2 MT_WRAITHFX2 // T_SPARK_DRIP }; // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- //========================================================================== // // EV_ThingProjectile // //========================================================================== boolean EV_ThingProjectile(byte * args, boolean gravity) { int tid; angle_t angle; int fineAngle; fixed_t speed; fixed_t vspeed; mobjtype_t moType; mobj_t *mobj; mobj_t *newMobj; int searcher; boolean success; success = false; searcher = -1; tid = args[0]; moType = TranslateThingType[args[1]]; if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL)) { // Don't spawn monsters if -nomonsters return false; } angle = (int) args[2] << 24; fineAngle = angle >> ANGLETOFINESHIFT; speed = (int) args[3] << 13; vspeed = (int) args[4] << 13; while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { newMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, moType); if (newMobj->info->seesound) { S_StartSound(newMobj, newMobj->info->seesound); } newMobj->target = mobj; // Originator newMobj->angle = angle; newMobj->momx = FixedMul(speed, finecosine[fineAngle]); newMobj->momy = FixedMul(speed, finesine[fineAngle]); newMobj->momz = vspeed; newMobj->flags2 |= MF2_DROPPED; // Don't respawn if (gravity == true) { newMobj->flags &= ~MF_NOGRAVITY; newMobj->flags2 |= MF2_LOGRAV; } if (P_CheckMissileSpawn(newMobj) == true) { success = true; } } return success; } //========================================================================== // // EV_ThingSpawn // //========================================================================== boolean EV_ThingSpawn(byte * args, boolean fog) { int tid; angle_t angle; mobj_t *mobj; mobj_t *newMobj; mobj_t *fogMobj; mobjtype_t moType; int searcher; boolean success; fixed_t z; success = false; searcher = -1; tid = args[0]; moType = TranslateThingType[args[1]]; if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL)) { // Don't spawn monsters if -nomonsters return false; } angle = (int) args[2] << 24; while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { if (mobjinfo[moType].flags2 & MF2_FLOATBOB) { z = mobj->z - mobj->floorz; } else { z = mobj->z; } newMobj = P_SpawnMobj(mobj->x, mobj->y, z, moType); if (P_TestMobjLocation(newMobj) == false) { // Didn't fit P_RemoveMobj(newMobj); } else { newMobj->angle = angle; if (fog == true) { fogMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fogMobj, SFX_TELEPORT); } newMobj->flags2 |= MF2_DROPPED; // Don't respawn if (newMobj->flags2 & MF2_FLOATBOB) { newMobj->special1.i = newMobj->z - newMobj->floorz; } success = true; } } return success; } //========================================================================== // // EV_ThingActivate // //========================================================================== boolean EV_ThingActivate(int tid) { mobj_t *mobj; int searcher; boolean success; success = false; searcher = -1; while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { if (ActivateThing(mobj) == true) { success = true; } } return success; } //========================================================================== // // EV_ThingDeactivate // //========================================================================== boolean EV_ThingDeactivate(int tid) { mobj_t *mobj; int searcher; boolean success; success = false; searcher = -1; while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { if (DeactivateThing(mobj) == true) { success = true; } } return success; } //========================================================================== // // EV_ThingRemove // //========================================================================== boolean EV_ThingRemove(int tid) { mobj_t *mobj; int searcher; boolean success; success = false; searcher = -1; while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { if (mobj->type == MT_BRIDGE) { A_BridgeRemove(mobj); return true; } P_RemoveMobj(mobj); success = true; } return success; } //========================================================================== // // EV_ThingDestroy // //========================================================================== boolean EV_ThingDestroy(int tid) { mobj_t *mobj; int searcher; boolean success; success = false; searcher = -1; while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL) { if (mobj->flags & MF_SHOOTABLE) { P_DamageMobj(mobj, NULL, NULL, 10000); success = true; } } return success; } //========================================================================== // // EV_ThingMove // // arg[0] = tid // arg[1] = speed // arg[2] = angle (255 = use mobj angle) // arg[3] = distance (pixels>>2) // //========================================================================== /* boolean EV_ThingMove(byte *args) { return false; } */ //========================================================================== // // ActivateThing // //========================================================================== static boolean ActivateThing(mobj_t * mobj) { if (mobj->flags & MF_COUNTKILL) { // Monster if (mobj->flags2 & MF2_DORMANT) { mobj->flags2 &= ~MF2_DORMANT; mobj->tics = 1; return true; } return false; } switch (mobj->type) { case MT_ZTWINEDTORCH: case MT_ZTWINEDTORCH_UNLIT: P_SetMobjState(mobj, S_ZTWINEDTORCH_1); S_StartSound(mobj, SFX_IGNITE); break; case MT_ZWALLTORCH: case MT_ZWALLTORCH_UNLIT: P_SetMobjState(mobj, S_ZWALLTORCH1); S_StartSound(mobj, SFX_IGNITE); break; case MT_ZGEMPEDESTAL: P_SetMobjState(mobj, S_ZGEMPEDESTAL2); break; case MT_ZWINGEDSTATUENOSKULL: P_SetMobjState(mobj, S_ZWINGEDSTATUENOSKULL2); break; case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: if (mobj->args[0] == 0) { S_StartSound(mobj, SFX_THRUSTSPIKE_LOWER); mobj->flags2 &= ~MF2_DONTDRAW; if (mobj->args[1]) P_SetMobjState(mobj, S_BTHRUSTRAISE1); else P_SetMobjState(mobj, S_THRUSTRAISE1); } break; case MT_ZFIREBULL: case MT_ZFIREBULL_UNLIT: P_SetMobjState(mobj, S_ZFIREBULL_BIRTH); S_StartSound(mobj, SFX_IGNITE); break; case MT_ZBELL: if (mobj->health > 0) { P_DamageMobj(mobj, NULL, NULL, 10); // 'ring' the bell } break; case MT_ZCAULDRON: case MT_ZCAULDRON_UNLIT: P_SetMobjState(mobj, S_ZCAULDRON1); S_StartSound(mobj, SFX_IGNITE); break; case MT_FLAME_SMALL: S_StartSound(mobj, SFX_IGNITE); P_SetMobjState(mobj, S_FLAME_SMALL1); break; case MT_FLAME_LARGE: S_StartSound(mobj, SFX_IGNITE); P_SetMobjState(mobj, S_FLAME_LARGE1); break; case MT_BAT_SPAWNER: P_SetMobjState(mobj, S_SPAWNBATS1); break; default: return false; break; } return true; } //========================================================================== // // DeactivateThing // //========================================================================== static boolean DeactivateThing(mobj_t * mobj) { if (mobj->flags & MF_COUNTKILL) { // Monster if (!(mobj->flags2 & MF2_DORMANT)) { mobj->flags2 |= MF2_DORMANT; mobj->tics = -1; return true; } return false; } switch (mobj->type) { case MT_ZTWINEDTORCH: case MT_ZTWINEDTORCH_UNLIT: P_SetMobjState(mobj, S_ZTWINEDTORCH_UNLIT); break; case MT_ZWALLTORCH: case MT_ZWALLTORCH_UNLIT: P_SetMobjState(mobj, S_ZWALLTORCH_U); break; case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: if (mobj->args[0] == 1) { S_StartSound(mobj, SFX_THRUSTSPIKE_RAISE); if (mobj->args[1]) P_SetMobjState(mobj, S_BTHRUSTLOWER); else P_SetMobjState(mobj, S_THRUSTLOWER); } break; case MT_ZFIREBULL: case MT_ZFIREBULL_UNLIT: P_SetMobjState(mobj, S_ZFIREBULL_DEATH); break; case MT_ZCAULDRON: case MT_ZCAULDRON_UNLIT: P_SetMobjState(mobj, S_ZCAULDRON_U); break; case MT_FLAME_SMALL: P_SetMobjState(mobj, S_FLAME_SDORM1); break; case MT_FLAME_LARGE: P_SetMobjState(mobj, S_FLAME_LDORM1); break; case MT_BAT_SPAWNER: P_SetMobjState(mobj, S_SPAWNBATS_OFF); break; default: return false; break; } return true; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_tick.c000066400000000000000000000100631257432200600226200ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "p_local.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void RunThinkers(void); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- int leveltime; int TimerGame; thinker_t thinkercap; // The head and tail of the thinker list // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- //========================================================================== // // P_Ticker // //========================================================================== void P_Ticker(void) { int i; if (paused) { return; } for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { P_PlayerThink(&players[i]); } } if (TimerGame) { if (!--TimerGame) { G_Completed(P_TranslateMap(P_GetMapNextMap(gamemap)), 0); } } RunThinkers(); P_UpdateSpecials(); P_AnimateSurfaces(); leveltime++; } //========================================================================== // // RunThinkers // //========================================================================== static void RunThinkers(void) { thinker_t *currentthinker, *nextthinker; currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { if (currentthinker->function == (think_t) - 1) { // Time to remove it nextthinker = currentthinker->next; currentthinker->next->prev = currentthinker->prev; currentthinker->prev->next = currentthinker->next; Z_Free(currentthinker); } else { if (currentthinker->function) currentthinker->function(currentthinker); nextthinker = currentthinker->next; } currentthinker = nextthinker; } } //========================================================================== // // P_InitThinkers // //========================================================================== void P_InitThinkers(void) { thinkercap.prev = thinkercap.next = &thinkercap; } //========================================================================== // // P_AddThinker // // Adds a new thinker at the end of the list. // //========================================================================== void P_AddThinker(thinker_t * thinker) { thinkercap.prev->next = thinker; thinker->next = &thinkercap; thinker->prev = thinkercap.prev; thinkercap.prev = thinker; } //========================================================================== // // P_RemoveThinker // // Deallocation is lazy -- it will not actually be freed until its // thinking turn comes up. // //========================================================================== void P_RemoveThinker(thinker_t * thinker) { thinker->function = (think_t) - 1; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/p_user.c000066400000000000000000001323451257432200600226540ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "m_random.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" void P_PlayerNextArtifact(player_t * player); // Macros #define MAXBOB 0x100000 // 16 pixels of bob // Data boolean onground; int newtorch; // used in the torch flicker effect. int newtorchdelta; int PStateNormal[NUMCLASSES] = { S_FPLAY, S_CPLAY, S_MPLAY, S_PIGPLAY }; int PStateRun[NUMCLASSES] = { S_FPLAY_RUN1, S_CPLAY_RUN1, S_MPLAY_RUN1, S_PIGPLAY_RUN1 }; int PStateAttack[NUMCLASSES] = { S_FPLAY_ATK1, S_CPLAY_ATK1, S_MPLAY_ATK1, S_PIGPLAY_ATK1 }; int PStateAttackEnd[NUMCLASSES] = { S_FPLAY_ATK2, S_CPLAY_ATK3, S_MPLAY_ATK2, S_PIGPLAY_ATK1 }; int ArmorMax[NUMCLASSES] = { 20, 18, 16, 1 }; /* ================== = = P_Thrust = = moves the given origin along a given angle = ================== */ void P_Thrust(player_t * player, angle_t angle, fixed_t move) { angle >>= ANGLETOFINESHIFT; if (player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz)) { player->mo->momx += FixedMul(move, finecosine[angle]); player->mo->momy += FixedMul(move, finesine[angle]); } else if (P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low { player->mo->momx += FixedMul(move >> 1, finecosine[angle]); player->mo->momy += FixedMul(move >> 1, finesine[angle]); } else { player->mo->momx += FixedMul(move, finecosine[angle]); player->mo->momy += FixedMul(move, finesine[angle]); } } /* ================== = = P_CalcHeight = =Calculate the walking / running height adjustment = ================== */ void P_CalcHeight(player_t * player) { int angle; fixed_t bob; // // regular movement bobbing (needs to be calculated for gun swing even // if not on ground) // OPTIMIZE: tablify angle player->bob = FixedMul(player->mo->momx, player->mo->momx) + FixedMul(player->mo->momy, player->mo->momy); player->bob >>= 2; if (player->bob > MAXBOB) player->bob = MAXBOB; if (player->mo->flags2 & MF2_FLY && !onground) { player->bob = FRACUNIT / 2; } if ((player->cheats & CF_NOMOMENTUM)) { player->viewz = player->mo->z + VIEWHEIGHT; if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT) player->viewz = player->mo->ceilingz - 4 * FRACUNIT; player->viewz = player->mo->z + player->viewheight; return; } angle = (FINEANGLES / 20 * leveltime) & FINEMASK; bob = FixedMul(player->bob / 2, finesine[angle]); // // move viewheight // if (player->playerstate == PST_LIVE) { player->viewheight += player->deltaviewheight; if (player->viewheight > VIEWHEIGHT) { player->viewheight = VIEWHEIGHT; player->deltaviewheight = 0; } if (player->viewheight < VIEWHEIGHT / 2) { player->viewheight = VIEWHEIGHT / 2; if (player->deltaviewheight <= 0) player->deltaviewheight = 1; } if (player->deltaviewheight) { player->deltaviewheight += FRACUNIT / 4; if (!player->deltaviewheight) player->deltaviewheight = 1; } } if (player->morphTics) { player->viewz = player->mo->z + player->viewheight - (20 * FRACUNIT); } else { player->viewz = player->mo->z + player->viewheight + bob; } if (player->mo->floorclip && player->playerstate != PST_DEAD && player->mo->z <= player->mo->floorz) { player->viewz -= player->mo->floorclip; } if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT) { player->viewz = player->mo->ceilingz - 4 * FRACUNIT; } if (player->viewz < player->mo->floorz + 4 * FRACUNIT) { player->viewz = player->mo->floorz + 4 * FRACUNIT; } } /* ================= = = P_MovePlayer = ================= */ void P_MovePlayer(player_t * player) { int look; int fly; ticcmd_t *cmd; cmd = &player->cmd; player->mo->angle += (cmd->angleturn << 16); onground = (player->mo->z <= player->mo->floorz || (player->mo->flags2 & MF2_ONMOBJ)); if (cmd->forwardmove) { if (onground || player->mo->flags2 & MF2_FLY) { P_Thrust(player, player->mo->angle, cmd->forwardmove * 2048); } else { P_Thrust(player, player->mo->angle, FRACUNIT >> 8); } } if (cmd->sidemove) { if (onground || player->mo->flags2 & MF2_FLY) { P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2048); } else { P_Thrust(player, player->mo->angle, FRACUNIT >> 8); } } if (cmd->forwardmove || cmd->sidemove) { if (player->mo->state == &states[PStateNormal[player->class]]) { P_SetMobjState(player->mo, PStateRun[player->class]); } } look = cmd->lookfly & 15; if (look > 7) { look -= 16; } if (look) { if (look == TOCENTER) { player->centering = true; } else { player->lookdir += 5 * look; if (player->lookdir > 90 || player->lookdir < -110) { player->lookdir -= 5 * look; } } } if (player->centering) { if (player->lookdir > 0) { player->lookdir -= 8; } else if (player->lookdir < 0) { player->lookdir += 8; } if (abs(player->lookdir) < 8) { player->lookdir = 0; player->centering = false; } } fly = cmd->lookfly >> 4; if (fly > 7) { fly -= 16; } if (fly && player->powers[pw_flight]) { if (fly != TOCENTER) { player->flyheight = fly * 2; if (!(player->mo->flags2 & MF2_FLY)) { player->mo->flags2 |= MF2_FLY; player->mo->flags |= MF_NOGRAVITY; if (player->mo->momz <= -39 * FRACUNIT) { // stop falling scream S_StopSound(player->mo); } } } else { player->mo->flags2 &= ~MF2_FLY; player->mo->flags &= ~MF_NOGRAVITY; } } else if (fly > 0) { P_PlayerUseArtifact(player, arti_fly); } if (player->mo->flags2 & MF2_FLY) { player->mo->momz = player->flyheight * FRACUNIT; if (player->flyheight) { player->flyheight /= 2; } } } //========================================================================== // // P_DeathThink // //========================================================================== void P_DeathThink(player_t * player) { int dir; angle_t delta; int lookDelta; P_MovePsprites(player); onground = (player->mo->z <= player->mo->floorz); if (player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK) { // Flying bloody skull or flying ice chunk player->viewheight = 6 * FRACUNIT; player->deltaviewheight = 0; //player->damagecount = 20; if (onground) { if (player->lookdir < 60) { lookDelta = (60 - player->lookdir) / 8; if (lookDelta < 1 && (leveltime & 1)) { lookDelta = 1; } else if (lookDelta > 6) { lookDelta = 6; } player->lookdir += lookDelta; } } } else if (!(player->mo->flags2 & MF2_ICEDAMAGE)) { // Fall to ground (if not frozen) player->deltaviewheight = 0; if (player->viewheight > 6 * FRACUNIT) { player->viewheight -= FRACUNIT; } if (player->viewheight < 6 * FRACUNIT) { player->viewheight = 6 * FRACUNIT; } if (player->lookdir > 0) { player->lookdir -= 6; } else if (player->lookdir < 0) { player->lookdir += 6; } if (abs(player->lookdir) < 6) { player->lookdir = 0; } } P_CalcHeight(player); if (player->attacker && player->attacker != player->mo) { // Watch killer dir = P_FaceMobj(player->mo, player->attacker, &delta); if (delta < ANG1 * 10) { // Looking at killer, so fade damage and poison counters if (player->damagecount) { player->damagecount--; } if (player->poisoncount) { player->poisoncount--; } } delta = delta / 8; if (delta > ANG1 * 5) { delta = ANG1 * 5; } if (dir) { // Turn clockwise player->mo->angle += delta; } else { // Turn counter clockwise player->mo->angle -= delta; } } else if (player->damagecount || player->poisoncount) { if (player->damagecount) { player->damagecount--; } else { player->poisoncount--; } } if (player->cmd.buttons & BT_USE) { if (player == &players[consoleplayer]) { I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE)); inv_ptr = 0; curpos = 0; newtorch = 0; newtorchdelta = 0; } player->playerstate = PST_REBORN; player->mo->special1.i = player->class; if (player->mo->special1.i > 2) { player->mo->special1.i = 0; } // Let the mobj know the player has entered the reborn state. Some // mobjs need to know when it's ok to remove themselves. player->mo->special2.i = 666; } } //---------------------------------------------------------------------------- // // PROC P_MorphPlayerThink // //---------------------------------------------------------------------------- void P_MorphPlayerThink(player_t * player) { mobj_t *pmo; if (player->morphTics & 15) { return; } pmo = player->mo; if (!(pmo->momx + pmo->momy) && P_Random() < 64) { // Snout sniff P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2); S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort return; } if (P_Random() < 48) { if (P_Random() < 128) { S_StartSound(pmo, SFX_PIG_ACTIVE1); } else { S_StartSound(pmo, SFX_PIG_ACTIVE2); } } } //---------------------------------------------------------------------------- // // FUNC P_GetPlayerNum // //---------------------------------------------------------------------------- int P_GetPlayerNum(player_t * player) { int i; for (i = 0; i < maxplayers; i++) { if (player == &players[i]) { return (i); } } return (0); } //---------------------------------------------------------------------------- // // FUNC P_UndoPlayerMorph // //---------------------------------------------------------------------------- boolean P_UndoPlayerMorph(player_t * player) { mobj_t *fog; mobj_t *mo; mobj_t *pmo; fixed_t x; fixed_t y; fixed_t z; angle_t angle; int playerNum; weapontype_t weapon; int oldFlags; int oldFlags2; int oldBeast; pmo = player->mo; x = pmo->x; y = pmo->y; z = pmo->z; angle = pmo->angle; weapon = pmo->special1.i; oldFlags = pmo->flags; oldFlags2 = pmo->flags2; oldBeast = pmo->type; P_SetMobjState(pmo, S_FREETARGMOBJ); playerNum = P_GetPlayerNum(player); switch (PlayerClass[playerNum]) { case PCLASS_FIGHTER: mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER); break; case PCLASS_CLERIC: mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC); break; case PCLASS_MAGE: mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE); break; default: I_Error("P_UndoPlayerMorph: Unknown player class %d\n", player->class); return false; } if (P_TestMobjLocation(mo) == false) { // Didn't fit P_RemoveMobj(mo); mo = P_SpawnMobj(x, y, z, oldBeast); mo->angle = angle; mo->health = player->health; mo->special1.i = weapon; mo->player = player; mo->flags = oldFlags; mo->flags2 = oldFlags2; player->mo = mo; player->morphTics = 2 * 35; return (false); } if (player->class == PCLASS_FIGHTER) { // The first type should be blue, and the third should be the // Fighter's original gold color if (playerNum == 0) { mo->flags |= 2 << MF_TRANSSHIFT; } else if (playerNum != 2) { mo->flags |= playerNum << MF_TRANSSHIFT; } } else if (playerNum) { // Set color translation bits for player sprites mo->flags |= playerNum << MF_TRANSSHIFT; } mo->angle = angle; mo->player = player; mo->reactiontime = 18; if (oldFlags2 & MF2_FLY) { mo->flags2 |= MF2_FLY; mo->flags |= MF_NOGRAVITY; } player->morphTics = 0; player->health = mo->health = MAXHEALTH; player->mo = mo; player->class = PlayerClass[playerNum]; angle >>= ANGLETOFINESHIFT; fog = P_SpawnMobj(x + 20 * finecosine[angle], y + 20 * finesine[angle], z + TELEFOGHEIGHT, MT_TFOG); S_StartSound(fog, SFX_TELEPORT); P_PostMorphWeapon(player, weapon); return (true); } //---------------------------------------------------------------------------- // // PROC P_PlayerThink // //---------------------------------------------------------------------------- void P_PlayerThink(player_t * player) { ticcmd_t *cmd; weapontype_t newweapon; int floorType; mobj_t *pmo; // No-clip cheat if (player->cheats & CF_NOCLIP) { player->mo->flags |= MF_NOCLIP; } else { player->mo->flags &= ~MF_NOCLIP; } cmd = &player->cmd; if (player->mo->flags & MF_JUSTATTACKED) { // Gauntlets attack auto forward motion cmd->angleturn = 0; cmd->forwardmove = 0xc800 / 512; cmd->sidemove = 0; player->mo->flags &= ~MF_JUSTATTACKED; } // messageTics is above the rest of the counters so that messages will // go away, even in death. player->messageTics--; // Can go negative if (!player->messageTics || player->messageTics == -1) { // Refresh the screen when a message goes away player->ultimateMessage = false; // clear out any chat messages. player->yellowMessage = false; if (player == &players[consoleplayer]) { BorderTopRefresh = true; } } player->worldTimer++; if (player->playerstate == PST_DEAD) { P_DeathThink(player); return; } if (player->jumpTics) { player->jumpTics--; } if (player->morphTics) { P_MorphPlayerThink(player); } // Handle movement if (player->mo->reactiontime) { // Player is frozen player->mo->reactiontime--; } else { P_MovePlayer(player); pmo = player->mo; if (player->powers[pw_speed] && !(leveltime & 1) && P_AproxDistance(pmo->momx, pmo->momy) > 12 * FRACUNIT) { mobj_t *speedMo; int playerNum; speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED); if (speedMo) { speedMo->angle = pmo->angle; playerNum = P_GetPlayerNum(player); if (player->class == PCLASS_FIGHTER) { // The first type should be blue, and the // third should be the Fighter's original gold color if (playerNum == 0) { speedMo->flags |= 2 << MF_TRANSSHIFT; } else if (playerNum != 2) { speedMo->flags |= playerNum << MF_TRANSSHIFT; } } else if (playerNum) { // Set color translation bits for player sprites speedMo->flags |= playerNum << MF_TRANSSHIFT; } speedMo->target = pmo; speedMo->special1.i = player->class; if (speedMo->special1.i > 2) { speedMo->special1.i = 0; } speedMo->sprite = pmo->sprite; speedMo->floorclip = pmo->floorclip; if (player == &players[consoleplayer]) { speedMo->flags2 |= MF2_DONTDRAW; } } } } P_CalcHeight(player); if (player->mo->subsector->sector->special) { P_PlayerInSpecialSector(player); } if ((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID) { P_PlayerOnSpecialFlat(player, floorType); } switch (player->class) { case PCLASS_FIGHTER: if (player->mo->momz <= -35 * FRACUNIT && player->mo->momz >= -40 * FRACUNIT && !player->morphTics && !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_FIGHTER_FALLING_SCREAM)) { S_StartSound(player->mo, SFX_PLAYER_FIGHTER_FALLING_SCREAM); } break; case PCLASS_CLERIC: if (player->mo->momz <= -35 * FRACUNIT && player->mo->momz >= -40 * FRACUNIT && !player->morphTics && !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_CLERIC_FALLING_SCREAM)) { S_StartSound(player->mo, SFX_PLAYER_CLERIC_FALLING_SCREAM); } break; case PCLASS_MAGE: if (player->mo->momz <= -35 * FRACUNIT && player->mo->momz >= -40 * FRACUNIT && !player->morphTics && !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM)) { S_StartSound(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM); } break; default: break; } if (cmd->arti) { // Use an artifact if ((cmd->arti & AFLAG_JUMP) && onground && !player->jumpTics) { if (player->morphTics) { player->mo->momz = 6 * FRACUNIT; } else { player->mo->momz = 9 * FRACUNIT; } player->mo->flags2 &= ~MF2_ONMOBJ; player->jumpTics = 18; } else if (cmd->arti & AFLAG_SUICIDE) { P_DamageMobj(player->mo, NULL, NULL, 10000); } if (cmd->arti == NUMARTIFACTS) { // use one of each artifact (except puzzle artifacts) int i; for (i = 1; i < arti_firstpuzzitem; i++) { P_PlayerUseArtifact(player, i); } } else { P_PlayerUseArtifact(player, cmd->arti & AFLAG_MASK); } } // Check for weapon change if (cmd->buttons & BT_SPECIAL) { // A special event has no other buttons cmd->buttons = 0; } if (cmd->buttons & BT_CHANGE && !player->morphTics) { // The actual changing of the weapon is done when the weapon // psprite can do it (A_WeaponReady), so it doesn't happen in // the middle of an attack. newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT; if (player->weaponowned[newweapon] && newweapon != player->readyweapon) { player->pendingweapon = newweapon; } } // Check for use if (cmd->buttons & BT_USE) { if (!player->usedown) { P_UseLines(player); player->usedown = true; } } else { player->usedown = false; } // Morph counter if (player->morphTics) { if (!--player->morphTics) { // Attempt to undo the pig P_UndoPlayerMorph(player); } } // Cycle psprites P_MovePsprites(player); // Other Counters if (player->powers[pw_invulnerability]) { if (player->class == PCLASS_CLERIC) { if (!(leveltime & 7) && player->mo->flags & MF_SHADOW && !(player->mo->flags2 & MF2_DONTDRAW)) { player->mo->flags &= ~MF_SHADOW; if (!(player->mo->flags & MF_ALTSHADOW)) { player->mo->flags2 |= MF2_DONTDRAW | MF2_NONSHOOTABLE; } } if (!(leveltime & 31)) { if (player->mo->flags2 & MF2_DONTDRAW) { if (!(player->mo->flags & MF_SHADOW)) { player->mo->flags |= MF_SHADOW | MF_ALTSHADOW; } else { player->mo->flags2 &= ~(MF2_DONTDRAW | MF2_NONSHOOTABLE); } } else { player->mo->flags |= MF_SHADOW; player->mo->flags &= ~MF_ALTSHADOW; } } } if (!(--player->powers[pw_invulnerability])) { player->mo->flags2 &= ~(MF2_INVULNERABLE | MF2_REFLECTIVE); if (player->class == PCLASS_CLERIC) { player->mo->flags2 &= ~(MF2_DONTDRAW | MF2_NONSHOOTABLE); player->mo->flags &= ~(MF_SHADOW | MF_ALTSHADOW); } } } if (player->powers[pw_minotaur]) { player->powers[pw_minotaur]--; } if (player->powers[pw_infrared]) { player->powers[pw_infrared]--; } if (player->powers[pw_flight] && netgame) { if (!--player->powers[pw_flight]) { if (player->mo->z != player->mo->floorz) { // haleyjd: removed externdriver crap player->centering = true; } player->mo->flags2 &= ~MF2_FLY; player->mo->flags &= ~MF_NOGRAVITY; BorderTopRefresh = true; //make sure the sprite's cleared out } } if (player->powers[pw_speed]) { player->powers[pw_speed]--; } if (player->damagecount) { player->damagecount--; } if (player->bonuscount) { player->bonuscount--; } if (player->poisoncount && !(leveltime & 15)) { player->poisoncount -= 5; if (player->poisoncount < 0) { player->poisoncount = 0; } P_PoisonDamage(player, player->poisoner, 1, true); } // Colormaps // if(player->powers[pw_invulnerability]) // { // if(player->powers[pw_invulnerability] > BLINKTHRESHOLD // || (player->powers[pw_invulnerability]&8)) // { // player->fixedcolormap = INVERSECOLORMAP; // } // else // { // player->fixedcolormap = 0; // } // } // else if (player->powers[pw_infrared]) { if (player->powers[pw_infrared] <= BLINKTHRESHOLD) { if (player->powers[pw_infrared] & 8) { player->fixedcolormap = 0; } else { player->fixedcolormap = 1; } } else if (!(leveltime & 16) && player == &players[consoleplayer]) { if (newtorch) { if (player->fixedcolormap + newtorchdelta > 7 || player->fixedcolormap + newtorchdelta < 1 || newtorch == player->fixedcolormap) { newtorch = 0; } else { player->fixedcolormap += newtorchdelta; } } else { newtorch = (M_Random() & 7) + 1; newtorchdelta = (newtorch == player->fixedcolormap) ? 0 : ((newtorch > player->fixedcolormap) ? 1 : -1); } } } else { player->fixedcolormap = 0; } } //---------------------------------------------------------------------------- // // PROC P_ArtiTele // //---------------------------------------------------------------------------- void P_ArtiTele(player_t * player) { int i; int selections; fixed_t destX; fixed_t destY; angle_t destAngle; if (deathmatch) { selections = deathmatch_p - deathmatchstarts; i = P_Random() % selections; destX = deathmatchstarts[i].x << FRACBITS; destY = deathmatchstarts[i].y << FRACBITS; destAngle = ANG45 * (deathmatchstarts[i].angle / 45); } else { destX = playerstarts[0][0].x << FRACBITS; destY = playerstarts[0][0].y << FRACBITS; destAngle = ANG45 * (playerstarts[0][0].angle / 45); } P_Teleport(player->mo, destX, destY, destAngle, true); if (player->morphTics) { // Teleporting away will undo any morph effects (pig) P_UndoPlayerMorph(player); } //S_StartSound(NULL, sfx_wpnup); // Full volume laugh } //---------------------------------------------------------------------------- // // PROC P_ArtiTeleportOther // //---------------------------------------------------------------------------- void P_ArtiTeleportOther(player_t * player) { mobj_t *mo; mo = P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1); if (mo) { mo->target = player->mo; } } void P_TeleportToPlayerStarts(mobj_t * victim) { int i, selections = 0; fixed_t destX, destY; angle_t destAngle; for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) continue; selections++; } i = P_Random() % selections; destX = playerstarts[0][i].x << FRACBITS; destY = playerstarts[0][i].y << FRACBITS; destAngle = ANG45 * (playerstarts[0][i].angle / 45); P_Teleport(victim, destX, destY, destAngle, true); //S_StartSound(NULL, sfx_wpnup); // Full volume laugh } void P_TeleportToDeathmatchStarts(mobj_t * victim) { int i, selections; fixed_t destX, destY; angle_t destAngle; selections = deathmatch_p - deathmatchstarts; if (selections) { i = P_Random() % selections; destX = deathmatchstarts[i].x << FRACBITS; destY = deathmatchstarts[i].y << FRACBITS; destAngle = ANG45 * (deathmatchstarts[i].angle / 45); P_Teleport(victim, destX, destY, destAngle, true); //S_StartSound(NULL, sfx_wpnup); // Full volume laugh } else { P_TeleportToPlayerStarts(victim); } } //---------------------------------------------------------------------------- // // PROC P_TeleportOther // //---------------------------------------------------------------------------- void P_TeleportOther(mobj_t * victim) { if (victim->player) { if (deathmatch) P_TeleportToDeathmatchStarts(victim); else P_TeleportToPlayerStarts(victim); } else { // If death action, run it upon teleport if (victim->flags & MF_COUNTKILL && victim->special) { P_RemoveMobjFromTIDList(victim); P_ExecuteLineSpecial(victim->special, victim->args, NULL, 0, victim); victim->special = 0; } // Send all monsters to deathmatch spots P_TeleportToDeathmatchStarts(victim); } } #define BLAST_RADIUS_DIST 255*FRACUNIT #define BLAST_SPEED 20*FRACUNIT #define BLAST_FULLSTRENGTH 255 void ResetBlasted(mobj_t * mo) { mo->flags2 &= ~MF2_BLASTED; if (!(mo->flags & MF_ICECORPSE)) { mo->flags2 &= ~MF2_SLIDE; } } void P_BlastMobj(mobj_t * source, mobj_t * victim, fixed_t strength) { angle_t angle, ang; mobj_t *mo; fixed_t x, y, z; angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y); angle >>= ANGLETOFINESHIFT; if (strength < BLAST_FULLSTRENGTH) { victim->momx = FixedMul(strength, finecosine[angle]); victim->momy = FixedMul(strength, finesine[angle]); if (victim->player) { // Players handled automatically } else { victim->flags2 |= MF2_SLIDE; victim->flags2 |= MF2_BLASTED; } } else // full strength blast from artifact { if (victim->flags & MF_MISSILE) { switch (victim->type) { case MT_SORCBALL1: // don't blast sorcerer balls case MT_SORCBALL2: case MT_SORCBALL3: return; break; case MT_MSTAFF_FX2: // Reflect to originator victim->special1.m = victim->target; victim->target = source; break; default: break; } } if (victim->type == MT_HOLY_FX) { if (victim->special1.m == source) { victim->special1.m = victim->target; victim->target = source; } } victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]); victim->momy = FixedMul(BLAST_SPEED, finesine[angle]); // Spawn blast puff ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y); ang >>= ANGLETOFINESHIFT; x = victim->x + FixedMul(victim->radius + FRACUNIT, finecosine[ang]); y = victim->y + FixedMul(victim->radius + FRACUNIT, finesine[ang]); z = victim->z - victim->floorclip + (victim->height >> 1); mo = P_SpawnMobj(x, y, z, MT_BLASTEFFECT); if (mo) { mo->momx = victim->momx; mo->momy = victim->momy; } if (victim->flags & MF_MISSILE) { victim->momz = 8 * FRACUNIT; mo->momz = victim->momz; } else { victim->momz = (1000 / victim->info->mass) << FRACBITS; } if (victim->player) { // Players handled automatically } else { victim->flags2 |= MF2_SLIDE; victim->flags2 |= MF2_BLASTED; } } } // Blast all mobj things away void P_BlastRadius(player_t * player) { mobj_t *mo; mobj_t *pmo = player->mo; thinker_t *think; fixed_t dist; S_StartSound(pmo, SFX_ARTIFACT_BLAST); P_NoiseAlert(player->mo, player->mo); for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *) think; if ((mo == pmo) || (mo->flags2 & MF2_BOSS)) { // Not a valid monster continue; } if ((mo->type == MT_POISONCLOUD) || // poison cloud (mo->type == MT_HOLY_FX) || // holy fx (mo->flags & MF_ICECORPSE)) // frozen corpse { // Let these special cases go } else if ((mo->flags & MF_COUNTKILL) && (mo->health <= 0)) { continue; } else if (!(mo->flags & MF_COUNTKILL) && !(mo->player) && !(mo->flags & MF_MISSILE)) { // Must be monster, player, or missile continue; } if (mo->flags2 & MF2_DORMANT) { continue; // no dormant creatures } if ((mo->type == MT_WRAITHB) && (mo->flags2 & MF2_DONTDRAW)) { continue; // no underground wraiths } if ((mo->type == MT_SPLASHBASE) || (mo->type == MT_SPLASH)) { continue; } if (mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER) { continue; } dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y); if (dist > BLAST_RADIUS_DIST) { // Out of range continue; } P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH); } } #define HEAL_RADIUS_DIST 255*FRACUNIT // Do class specific effect for everyone in radius boolean P_HealRadius(player_t * player) { mobj_t *mo; mobj_t *pmo = player->mo; thinker_t *think; fixed_t dist; int effective = false; int amount; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *) think; if (!mo->player) continue; if (mo->health <= 0) continue; dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y); if (dist > HEAL_RADIUS_DIST) { // Out of range continue; } switch (player->class) { case PCLASS_FIGHTER: // Radius armor boost if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) || (P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) || (P_GiveArmor(mo->player, ARMOR_HELMET, 1)) || (P_GiveArmor(mo->player, ARMOR_AMULET, 1))) { effective = true; S_StartSound(mo, SFX_MYSTICINCANT); } break; case PCLASS_CLERIC: // Radius heal amount = 50 + (P_Random() % 50); if (P_GiveBody(mo->player, amount)) { effective = true; S_StartSound(mo, SFX_MYSTICINCANT); } break; case PCLASS_MAGE: // Radius mana boost amount = 50 + (P_Random() % 50); if ((P_GiveMana(mo->player, MANA_1, amount)) || (P_GiveMana(mo->player, MANA_2, amount))) { effective = true; S_StartSound(mo, SFX_MYSTICINCANT); } break; case PCLASS_PIG: default: break; } } return (effective); } //---------------------------------------------------------------------------- // // PROC P_PlayerNextArtifact // //---------------------------------------------------------------------------- void P_PlayerNextArtifact(player_t * player) { if (player == &players[consoleplayer]) { inv_ptr--; if (inv_ptr < 6) { curpos--; if (curpos < 0) { curpos = 0; } } if (inv_ptr < 0) { inv_ptr = player->inventorySlotNum - 1; if (inv_ptr < 6) { curpos = inv_ptr; } else { curpos = 6; } } player->readyArtifact = player->inventory[inv_ptr].type; } } //---------------------------------------------------------------------------- // // PROC P_PlayerRemoveArtifact // //---------------------------------------------------------------------------- void P_PlayerRemoveArtifact(player_t * player, int slot) { int i; player->artifactCount--; if (!(--player->inventory[slot].count)) { // Used last of a type - compact the artifact list player->readyArtifact = arti_none; player->inventory[slot].type = arti_none; for (i = slot + 1; i < player->inventorySlotNum; i++) { player->inventory[i - 1] = player->inventory[i]; } player->inventorySlotNum--; if (player == &players[consoleplayer]) { // Set position markers and get next readyArtifact inv_ptr--; if (inv_ptr < 6) { curpos--; if (curpos < 0) { curpos = 0; } } if (inv_ptr >= player->inventorySlotNum) { inv_ptr = player->inventorySlotNum - 1; } if (inv_ptr < 0) { inv_ptr = 0; } player->readyArtifact = player->inventory[inv_ptr].type; } } } //---------------------------------------------------------------------------- // // PROC P_PlayerUseArtifact // //---------------------------------------------------------------------------- void P_PlayerUseArtifact(player_t * player, artitype_t arti) { int i; for (i = 0; i < player->inventorySlotNum; i++) { if (player->inventory[i].type == arti) { // Found match - try to use if (P_UseArtifact(player, arti)) { // Artifact was used - remove it from inventory P_PlayerRemoveArtifact(player, i); if (player == &players[consoleplayer]) { if (arti < arti_firstpuzzitem) { S_StartSound(NULL, SFX_ARTIFACT_USE); } else { S_StartSound(NULL, SFX_PUZZLE_SUCCESS); } ArtifactFlash = 4; } } else if (arti < arti_firstpuzzitem) { // Unable to use artifact, advance pointer P_PlayerNextArtifact(player); } break; } } } //========================================================================== // // P_UseArtifact // // Returns true if the artifact was used. // //========================================================================== boolean P_UseArtifact(player_t * player, artitype_t arti) { mobj_t *mo; angle_t angle; int i; int count; switch (arti) { case arti_invulnerability: if (!P_GivePower(player, pw_invulnerability)) { return (false); } break; case arti_health: if (!P_GiveBody(player, 25)) { return (false); } break; case arti_superhealth: if (!P_GiveBody(player, 100)) { return (false); } break; case arti_healingradius: if (!P_HealRadius(player)) { return (false); } break; case arti_torch: if (!P_GivePower(player, pw_infrared)) { return (false); } break; case arti_egg: mo = player->mo; P_SpawnPlayerMissile(mo, MT_EGGFX); P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 6)); P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 6)); P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 3)); P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 3)); break; case arti_fly: if (!P_GivePower(player, pw_flight)) { return (false); } if (player->mo->momz <= -35 * FRACUNIT) { // stop falling scream S_StopSound(player->mo); } break; case arti_summon: mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX); if (mo) { mo->target = player->mo; mo->special1.m = (player->mo); mo->momz = 5 * FRACUNIT; } break; case arti_teleport: P_ArtiTele(player); break; case arti_teleportother: P_ArtiTeleportOther(player); break; case arti_poisonbag: angle = player->mo->angle >> ANGLETOFINESHIFT; if (player->class == PCLASS_CLERIC) { mo = P_SpawnMobj(player->mo->x + 16 * finecosine[angle], player->mo->y + 24 * finesine[angle], player->mo->z - player->mo->floorclip + 8 * FRACUNIT, MT_POISONBAG); if (mo) { mo->target = player->mo; } } else if (player->class == PCLASS_MAGE) { mo = P_SpawnMobj(player->mo->x + 16 * finecosine[angle], player->mo->y + 24 * finesine[angle], player->mo->z - player->mo->floorclip + 8 * FRACUNIT, MT_FIREBOMB); if (mo) { mo->target = player->mo; } } else // PCLASS_FIGHTER, obviously (also pig, not so obviously) { mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z - player->mo->floorclip + 35 * FRACUNIT, MT_THROWINGBOMB); if (mo) { mo->angle = player->mo->angle + (((P_Random() & 7) - 4) << 24); mo->momz = 4 * FRACUNIT + ((player->lookdir) << (FRACBITS - 4)); mo->z += player->lookdir << (FRACBITS - 4); P_ThrustMobj(mo, mo->angle, mo->info->speed); mo->momx += player->mo->momx >> 1; mo->momy += player->mo->momy >> 1; mo->target = player->mo; mo->tics -= P_Random() & 3; P_CheckMissileSpawn(mo); } } break; case arti_speed: if (!P_GivePower(player, pw_speed)) { return (false); } break; case arti_boostmana: if (!P_GiveMana(player, MANA_1, MAX_MANA)) { if (!P_GiveMana(player, MANA_2, MAX_MANA)) { return false; } } else { P_GiveMana(player, MANA_2, MAX_MANA); } break; case arti_boostarmor: count = 0; for (i = 0; i < NUMARMOR; i++) { count += P_GiveArmor(player, i, 1); // 1 point per armor type } if (!count) { return false; } break; case arti_blastradius: P_BlastRadius(player); break; case arti_puzzskull: case arti_puzzgembig: case arti_puzzgemred: case arti_puzzgemgreen1: case arti_puzzgemgreen2: case arti_puzzgemblue1: case arti_puzzgemblue2: case arti_puzzbook1: case arti_puzzbook2: case arti_puzzskull2: case arti_puzzfweapon: case arti_puzzcweapon: case arti_puzzmweapon: case arti_puzzgear1: case arti_puzzgear2: case arti_puzzgear3: case arti_puzzgear4: if (P_UsePuzzleItem(player, arti - arti_firstpuzzitem)) { return true; } else { P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false); return false; } break; default: return false; } return true; } //============================================================================ // // A_SpeedFade // //============================================================================ void A_SpeedFade(mobj_t * actor) { actor->flags |= MF_SHADOW; actor->flags &= ~MF_ALTSHADOW; actor->sprite = actor->target->sprite; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/po_man.c000066400000000000000000001300761257432200600226270ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "i_system.h" #include "m_bbox.h" #include "i_swap.h" #include "p_local.h" #include "r_local.h" // MACROS ------------------------------------------------------------------ #define PO_MAXPOLYSEGS 64 // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static polyobj_t *GetPolyobj(int polyNum); static int GetPolyobjMirror(int poly); static void ThrustMobj(mobj_t * mobj, seg_t * seg, polyobj_t * po); static void UpdateSegBBox(seg_t * seg); static void RotatePt(int an, fixed_t * x, fixed_t * y, fixed_t startSpotX, fixed_t startSpotY); static void UnLinkPolyobj(polyobj_t * po); static void LinkPolyobj(polyobj_t * po); static boolean CheckMobjBlocking(seg_t * seg, polyobj_t * po); static void InitBlockMap(void); static void IterFindPolySegs(int x, int y, seg_t ** segList); static void SpawnPolyobj(int index, int tag, boolean crush); static void TranslateToStartSpot(int tag, int originX, int originY); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- polyblock_t **PolyBlockMap; polyobj_t *polyobjs; // list of all poly-objects on the level int po_NumPolyobjs; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int PolySegCount; static fixed_t PolyStartX; static fixed_t PolyStartY; // CODE -------------------------------------------------------------------- // ===== Polyobj Event Code ===== //========================================================================== // // T_RotatePoly // //========================================================================== void T_RotatePoly(polyevent_t * pe) { int absSpeed; polyobj_t *poly; if (PO_RotatePolyobj(pe->polyobj, pe->speed)) { absSpeed = abs(pe->speed); if (pe->dist == -1) { // perpetual polyobj return; } pe->dist -= absSpeed; if (pe->dist <= 0) { poly = GetPolyobj(pe->polyobj); if (poly->specialdata == pe) { poly->specialdata = NULL; } SN_StopSequence((mobj_t *) & poly->startSpot); P_PolyobjFinished(poly->tag); P_RemoveThinker(&pe->thinker); } if (pe->dist < absSpeed) { pe->speed = pe->dist * (pe->speed < 0 ? -1 : 1); } } } //========================================================================== // // EV_RotatePoly // //========================================================================== boolean EV_RotatePoly(line_t * line, byte * args, int direction, boolean overRide) { int mirror; int polyNum; polyevent_t *pe; polyobj_t *poly; polyNum = args[0]; poly = GetPolyobj(polyNum); if (poly != NULL) { if (poly->specialdata && !overRide) { // poly is already moving return false; } } else { I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); } pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); P_AddThinker(&pe->thinker); pe->thinker.function = T_RotatePoly; pe->polyobj = polyNum; if (args[2]) { if (args[2] == 255) { pe->dist = -1; } else { pe->dist = args[2] * (ANG90 / 64); // Angle } } else { pe->dist = ANG_MAX - 1; } pe->speed = (args[1] * direction * (ANG90 / 64)) >> 3; poly->specialdata = pe; SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); while ((mirror = GetPolyobjMirror(polyNum)) != 0) { poly = GetPolyobj(mirror); if (poly && poly->specialdata && !overRide) { // mirroring poly is already in motion break; } pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); P_AddThinker(&pe->thinker); pe->thinker.function = T_RotatePoly; poly->specialdata = pe; pe->polyobj = mirror; if (args[2]) { if (args[2] == 255) { pe->dist = -1; } else { pe->dist = args[2] * (ANG90 / 64); // Angle } } else { pe->dist = ANG_MAX - 1; } poly = GetPolyobj(polyNum); if (poly != NULL) { poly->specialdata = pe; } else { I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); } direction = -direction; pe->speed = (args[1] * direction * (ANG90 / 64)) >> 3; polyNum = mirror; SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } return true; } //========================================================================== // // T_MovePoly // //========================================================================== void T_MovePoly(polyevent_t * pe) { int absSpeed; polyobj_t *poly; if (PO_MovePolyobj(pe->polyobj, pe->xSpeed, pe->ySpeed)) { absSpeed = abs(pe->speed); pe->dist -= absSpeed; if (pe->dist <= 0) { poly = GetPolyobj(pe->polyobj); if (poly->specialdata == pe) { poly->specialdata = NULL; } SN_StopSequence((mobj_t *) & poly->startSpot); P_PolyobjFinished(poly->tag); P_RemoveThinker(&pe->thinker); } if (pe->dist < absSpeed) { pe->speed = pe->dist * (pe->speed < 0 ? -1 : 1); pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]); pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]); } } } //========================================================================== // // EV_MovePoly // //========================================================================== boolean EV_MovePoly(line_t * line, byte * args, boolean timesEight, boolean overRide) { int mirror; int polyNum; polyevent_t *pe; polyobj_t *poly; angle_t an; polyNum = args[0]; poly = GetPolyobj(polyNum); if (poly != NULL) { if (poly->specialdata && !overRide) { // poly is already moving return false; } } else { I_Error("EV_MovePoly: Invalid polyobj num: %d\n", polyNum); } pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); P_AddThinker(&pe->thinker); pe->thinker.function = T_MovePoly; pe->polyobj = polyNum; if (timesEight) { pe->dist = args[3] * 8 * FRACUNIT; } else { pe->dist = args[3] * FRACUNIT; // Distance } pe->speed = args[1] * (FRACUNIT / 8); poly->specialdata = pe; an = args[2] * (ANG90 / 64); pe->angle = an >> ANGLETOFINESHIFT; pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]); pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]); SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); while ((mirror = GetPolyobjMirror(polyNum)) != 0) { poly = GetPolyobj(mirror); if (poly && poly->specialdata && !overRide) { // mirroring poly is already in motion break; } pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); P_AddThinker(&pe->thinker); pe->thinker.function = T_MovePoly; pe->polyobj = mirror; poly->specialdata = pe; if (timesEight) { pe->dist = args[3] * 8 * FRACUNIT; } else { pe->dist = args[3] * FRACUNIT; // Distance } pe->speed = args[1] * (FRACUNIT / 8); an = an + ANG180; // reverse the angle pe->angle = an >> ANGLETOFINESHIFT; pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]); pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]); polyNum = mirror; SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } return true; } //========================================================================== // // T_PolyDoor // //========================================================================== void T_PolyDoor(polydoor_t * pd) { int absSpeed; polyobj_t *poly; if (pd->tics) { if (!--pd->tics) { poly = GetPolyobj(pd->polyobj); SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } return; } switch (pd->type) { case PODOOR_SLIDE: if (PO_MovePolyobj(pd->polyobj, pd->xSpeed, pd->ySpeed)) { absSpeed = abs(pd->speed); pd->dist -= absSpeed; if (pd->dist <= 0) { poly = GetPolyobj(pd->polyobj); SN_StopSequence((mobj_t *) & poly->startSpot); if (!pd->close) { pd->dist = pd->totalDist; pd->close = true; pd->tics = pd->waitTics; pd->direction = (ANG_MAX >> ANGLETOFINESHIFT) - pd->direction; pd->xSpeed = -pd->xSpeed; pd->ySpeed = -pd->ySpeed; } else { if (poly->specialdata == pd) { poly->specialdata = NULL; } P_PolyobjFinished(poly->tag); P_RemoveThinker(&pd->thinker); } } } else { poly = GetPolyobj(pd->polyobj); if (poly->crush || !pd->close) { // continue moving if the poly is a crusher, or is opening return; } else { // open back up pd->dist = pd->totalDist - pd->dist; pd->direction = (ANG_MAX >> ANGLETOFINESHIFT) - pd->direction; pd->xSpeed = -pd->xSpeed; pd->ySpeed = -pd->ySpeed; pd->close = false; SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } } break; case PODOOR_SWING: if (PO_RotatePolyobj(pd->polyobj, pd->speed)) { absSpeed = abs(pd->speed); if (pd->dist == -1) { // perpetual polyobj return; } pd->dist -= absSpeed; if (pd->dist <= 0) { poly = GetPolyobj(pd->polyobj); SN_StopSequence((mobj_t *) & poly->startSpot); if (!pd->close) { pd->dist = pd->totalDist; pd->close = true; pd->tics = pd->waitTics; pd->speed = -pd->speed; } else { if (poly->specialdata == pd) { poly->specialdata = NULL; } P_PolyobjFinished(poly->tag); P_RemoveThinker(&pd->thinker); } } } else { poly = GetPolyobj(pd->polyobj); if (poly->crush || !pd->close) { // continue moving if the poly is a crusher, or is opening return; } else { // open back up and rewait pd->dist = pd->totalDist - pd->dist; pd->speed = -pd->speed; pd->close = false; SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } } break; default: break; } } //========================================================================== // // EV_OpenPolyDoor // //========================================================================== boolean EV_OpenPolyDoor(line_t * line, byte * args, podoortype_t type) { int mirror; int polyNum; polydoor_t *pd; polyobj_t *poly; angle_t an = 0; polyNum = args[0]; poly = GetPolyobj(polyNum); if (poly != NULL) { if (poly->specialdata) { // poly is already moving return false; } } else { I_Error("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum); } pd = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0); memset(pd, 0, sizeof(polydoor_t)); P_AddThinker(&pd->thinker); pd->thinker.function = T_PolyDoor; pd->type = type; pd->polyobj = polyNum; if (type == PODOOR_SLIDE) { pd->waitTics = args[4]; pd->speed = args[1] * (FRACUNIT / 8); pd->totalDist = args[3] * FRACUNIT; // Distance pd->dist = pd->totalDist; an = args[2] * (ANG90 / 64); pd->direction = an >> ANGLETOFINESHIFT; pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]); pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]); SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } else if (type == PODOOR_SWING) { pd->waitTics = args[3]; pd->direction = 1; // ADD: PODOOR_SWINGL, PODOOR_SWINGR pd->speed = (args[1] * pd->direction * (ANG90 / 64)) >> 3; pd->totalDist = args[2] * (ANG90 / 64); pd->dist = pd->totalDist; SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } poly->specialdata = pd; while ((mirror = GetPolyobjMirror(polyNum)) != 0) { poly = GetPolyobj(mirror); if (poly && poly->specialdata) { // mirroring poly is already in motion break; } pd = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0); memset(pd, 0, sizeof(polydoor_t)); P_AddThinker(&pd->thinker); pd->thinker.function = T_PolyDoor; pd->polyobj = mirror; pd->type = type; poly->specialdata = pd; if (type == PODOOR_SLIDE) { pd->waitTics = args[4]; pd->speed = args[1] * (FRACUNIT / 8); pd->totalDist = args[3] * FRACUNIT; // Distance pd->dist = pd->totalDist; an = an + ANG180; // reverse the angle pd->direction = an >> ANGLETOFINESHIFT; pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]); pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]); SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } else if (type == PODOOR_SWING) { pd->waitTics = args[3]; pd->direction = -1; // ADD: same as above pd->speed = (args[1] * pd->direction * (ANG90 / 64)) >> 3; pd->totalDist = args[2] * (ANG90 / 64); pd->dist = pd->totalDist; SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } polyNum = mirror; } return true; } // ===== Higher Level Poly Interface code ===== //========================================================================== // // GetPolyobj // //========================================================================== static polyobj_t *GetPolyobj(int polyNum) { int i; for (i = 0; i < po_NumPolyobjs; i++) { if (polyobjs[i].tag == polyNum) { return &polyobjs[i]; } } return NULL; } //========================================================================== // // GetPolyobjMirror // //========================================================================== static int GetPolyobjMirror(int poly) { int i; for (i = 0; i < po_NumPolyobjs; i++) { if (polyobjs[i].tag == poly) { return ((*polyobjs[i].segs)->linedef->arg2); } } return 0; } //========================================================================== // // ThrustMobj // //========================================================================== static void ThrustMobj(mobj_t * mobj, seg_t * seg, polyobj_t * po) { int thrustAngle; int thrustX; int thrustY; polyevent_t *pe; int force; if (!(mobj->flags & MF_SHOOTABLE) && !mobj->player) { return; } thrustAngle = (seg->angle - ANG90) >> ANGLETOFINESHIFT; pe = po->specialdata; if (pe) { if (pe->thinker.function == T_RotatePoly) { force = pe->speed >> 8; } else { force = pe->speed >> 3; } if (force < FRACUNIT) { force = FRACUNIT; } else if (force > 4 * FRACUNIT) { force = 4 * FRACUNIT; } } else { force = FRACUNIT; } thrustX = FixedMul(force, finecosine[thrustAngle]); thrustY = FixedMul(force, finesine[thrustAngle]); mobj->momx += thrustX; mobj->momy += thrustY; if (po->crush) { if (!P_CheckPosition(mobj, mobj->x + thrustX, mobj->y + thrustY)) { P_DamageMobj(mobj, NULL, NULL, 3); } } } //========================================================================== // // UpdateSegBBox // //========================================================================== static void UpdateSegBBox(seg_t * seg) { line_t *line; line = seg->linedef; if (seg->v1->x < seg->v2->x) { line->bbox[BOXLEFT] = seg->v1->x; line->bbox[BOXRIGHT] = seg->v2->x; } else { line->bbox[BOXLEFT] = seg->v2->x; line->bbox[BOXRIGHT] = seg->v1->x; } if (seg->v1->y < seg->v2->y) { line->bbox[BOXBOTTOM] = seg->v1->y; line->bbox[BOXTOP] = seg->v2->y; } else { line->bbox[BOXBOTTOM] = seg->v2->y; line->bbox[BOXTOP] = seg->v1->y; } // Update the line's slopetype line->dx = line->v2->x - line->v1->x; line->dy = line->v2->y - line->v1->y; if (!line->dx) { line->slopetype = ST_VERTICAL; } else if (!line->dy) { line->slopetype = ST_HORIZONTAL; } else { if (FixedDiv(line->dy, line->dx) > 0) { line->slopetype = ST_POSITIVE; } else { line->slopetype = ST_NEGATIVE; } } } //========================================================================== // // PO_MovePolyobj // //========================================================================== boolean PO_MovePolyobj(int num, int x, int y) { int count; seg_t **segList; seg_t **veryTempSeg; polyobj_t *po; vertex_t *prevPts; boolean blocked; if (!(po = GetPolyobj(num))) { I_Error("PO_MovePolyobj: Invalid polyobj number: %d\n", num); } UnLinkPolyobj(po); segList = po->segs; prevPts = po->prevPts; blocked = false; validcount++; for (count = po->numsegs; count; count--, segList++, prevPts++) { if ((*segList)->linedef->validcount != validcount) { (*segList)->linedef->bbox[BOXTOP] += y; (*segList)->linedef->bbox[BOXBOTTOM] += y; (*segList)->linedef->bbox[BOXLEFT] += x; (*segList)->linedef->bbox[BOXRIGHT] += x; (*segList)->linedef->validcount = validcount; } for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++) { if ((*veryTempSeg)->v1 == (*segList)->v1) { break; } } if (veryTempSeg == segList) { (*segList)->v1->x += x; (*segList)->v1->y += y; } (*prevPts).x += x; // previous points are unique for each seg (*prevPts).y += y; } segList = po->segs; for (count = po->numsegs; count; count--, segList++) { if (CheckMobjBlocking(*segList, po)) { blocked = true; } } if (blocked) { count = po->numsegs; segList = po->segs; prevPts = po->prevPts; validcount++; while (count--) { if ((*segList)->linedef->validcount != validcount) { (*segList)->linedef->bbox[BOXTOP] -= y; (*segList)->linedef->bbox[BOXBOTTOM] -= y; (*segList)->linedef->bbox[BOXLEFT] -= x; (*segList)->linedef->bbox[BOXRIGHT] -= x; (*segList)->linedef->validcount = validcount; } for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++) { if ((*veryTempSeg)->v1 == (*segList)->v1) { break; } } if (veryTempSeg == segList) { (*segList)->v1->x -= x; (*segList)->v1->y -= y; } (*prevPts).x -= x; (*prevPts).y -= y; segList++; prevPts++; } LinkPolyobj(po); return false; } po->startSpot.x += x; po->startSpot.y += y; LinkPolyobj(po); return true; } //========================================================================== // // RotatePt // //========================================================================== static void RotatePt(int an, fixed_t * x, fixed_t * y, fixed_t startSpotX, fixed_t startSpotY) { fixed_t trx, try; fixed_t gxt, gyt; trx = *x; try = *y; gxt = FixedMul(trx, finecosine[an]); gyt = FixedMul(try, finesine[an]); *x = (gxt - gyt) + startSpotX; gxt = FixedMul(trx, finesine[an]); gyt = FixedMul(try, finecosine[an]); *y = (gyt + gxt) + startSpotY; } //========================================================================== // // PO_RotatePolyobj // //========================================================================== boolean PO_RotatePolyobj(int num, angle_t angle) { int count; seg_t **segList; vertex_t *originalPts; vertex_t *prevPts; int an; polyobj_t *po; boolean blocked; if (!(po = GetPolyobj(num))) { I_Error("PO_RotatePolyobj: Invalid polyobj number: %d\n", num); } an = (po->angle + angle) >> ANGLETOFINESHIFT; UnLinkPolyobj(po); segList = po->segs; originalPts = po->originalPts; prevPts = po->prevPts; for (count = po->numsegs; count; count--, segList++, originalPts++, prevPts++) { prevPts->x = (*segList)->v1->x; prevPts->y = (*segList)->v1->y; (*segList)->v1->x = originalPts->x; (*segList)->v1->y = originalPts->y; RotatePt(an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot.x, po->startSpot.y); } segList = po->segs; blocked = false; validcount++; for (count = po->numsegs; count; count--, segList++) { if (CheckMobjBlocking(*segList, po)) { blocked = true; } if ((*segList)->linedef->validcount != validcount) { UpdateSegBBox(*segList); (*segList)->linedef->validcount = validcount; } (*segList)->angle += angle; } if (blocked) { segList = po->segs; prevPts = po->prevPts; for (count = po->numsegs; count; count--, segList++, prevPts++) { (*segList)->v1->x = prevPts->x; (*segList)->v1->y = prevPts->y; } segList = po->segs; validcount++; for (count = po->numsegs; count; count--, segList++, prevPts++) { if ((*segList)->linedef->validcount != validcount) { UpdateSegBBox(*segList); (*segList)->linedef->validcount = validcount; } (*segList)->angle -= angle; } LinkPolyobj(po); return false; } po->angle += angle; LinkPolyobj(po); return true; } //========================================================================== // // UnLinkPolyobj // //========================================================================== static void UnLinkPolyobj(polyobj_t * po) { polyblock_t *link; int i, j; int index; // remove the polyobj from each blockmap section for (j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++) { index = j * bmapwidth; for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++) { if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight) { link = PolyBlockMap[index + i]; while (link != NULL && link->polyobj != po) { link = link->next; } if (link == NULL) { // polyobj not located in the link cell continue; } link->polyobj = NULL; } } } } //========================================================================== // // LinkPolyobj // //========================================================================== static void LinkPolyobj(polyobj_t * po) { int leftX, rightX; int topY, bottomY; seg_t **tempSeg; polyblock_t **link; polyblock_t *tempLink; int i, j; // calculate the polyobj bbox tempSeg = po->segs; rightX = leftX = (*tempSeg)->v1->x; topY = bottomY = (*tempSeg)->v1->y; for (i = 0; i < po->numsegs; i++, tempSeg++) { if ((*tempSeg)->v1->x > rightX) { rightX = (*tempSeg)->v1->x; } if ((*tempSeg)->v1->x < leftX) { leftX = (*tempSeg)->v1->x; } if ((*tempSeg)->v1->y > topY) { topY = (*tempSeg)->v1->y; } if ((*tempSeg)->v1->y < bottomY) { bottomY = (*tempSeg)->v1->y; } } po->bbox[BOXRIGHT] = (rightX - bmaporgx) >> MAPBLOCKSHIFT; po->bbox[BOXLEFT] = (leftX - bmaporgx) >> MAPBLOCKSHIFT; po->bbox[BOXTOP] = (topY - bmaporgy) >> MAPBLOCKSHIFT; po->bbox[BOXBOTTOM] = (bottomY - bmaporgy) >> MAPBLOCKSHIFT; // add the polyobj to each blockmap section for (j = po->bbox[BOXBOTTOM] * bmapwidth; j <= po->bbox[BOXTOP] * bmapwidth; j += bmapwidth) { for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++) { if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight * bmapwidth) { link = &PolyBlockMap[j + i]; if (!(*link)) { // Create a new link at the current block cell *link = Z_Malloc(sizeof(polyblock_t), PU_LEVEL, 0); (*link)->next = NULL; (*link)->prev = NULL; (*link)->polyobj = po; continue; } else { tempLink = *link; while (tempLink->next != NULL && tempLink->polyobj != NULL) { tempLink = tempLink->next; } } if (tempLink->polyobj == NULL) { tempLink->polyobj = po; continue; } else { tempLink->next = Z_Malloc(sizeof(polyblock_t), PU_LEVEL, 0); tempLink->next->next = NULL; tempLink->next->prev = tempLink; tempLink->next->polyobj = po; } } // else, don't link the polyobj, since it's off the map } } } //========================================================================== // // CheckMobjBlocking // //========================================================================== static boolean CheckMobjBlocking(seg_t * seg, polyobj_t * po) { mobj_t *mobj; int i, j; int left, right, top, bottom; int tmbbox[4]; line_t *ld; boolean blocked; ld = seg->linedef; top = (ld->bbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT; bottom = (ld->bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT; left = (ld->bbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT; right = (ld->bbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT; blocked = false; bottom = bottom < 0 ? 0 : bottom; bottom = bottom >= bmapheight ? bmapheight - 1 : bottom; top = top < 0 ? 0 : top; top = top >= bmapheight ? bmapheight - 1 : top; left = left < 0 ? 0 : left; left = left >= bmapwidth ? bmapwidth - 1 : left; right = right < 0 ? 0 : right; right = right >= bmapwidth ? bmapwidth - 1 : right; for (j = bottom * bmapwidth; j <= top * bmapwidth; j += bmapwidth) { for (i = left; i <= right; i++) { for (mobj = blocklinks[j + i]; mobj; mobj = mobj->bnext) { if (mobj->flags & MF_SOLID || mobj->player) { tmbbox[BOXTOP] = mobj->y + mobj->radius; tmbbox[BOXBOTTOM] = mobj->y - mobj->radius; tmbbox[BOXLEFT] = mobj->x - mobj->radius; tmbbox[BOXRIGHT] = mobj->x + mobj->radius; if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { continue; } if (P_BoxOnLineSide(tmbbox, ld) != -1) { continue; } ThrustMobj(mobj, seg, po); blocked = true; } } } } return blocked; } //========================================================================== // // InitBlockMap // //========================================================================== static void InitBlockMap(void) { int i; int j; seg_t **segList; int leftX, rightX; int topY, bottomY; PolyBlockMap = Z_Malloc(bmapwidth * bmapheight * sizeof(polyblock_t *), PU_LEVEL, 0); memset(PolyBlockMap, 0, bmapwidth * bmapheight * sizeof(polyblock_t *)); for (i = 0; i < po_NumPolyobjs; i++) { LinkPolyobj(&polyobjs[i]); // calculate a rough area // right now, working like shit...gotta fix this... segList = polyobjs[i].segs; leftX = rightX = (*segList)->v1->x; topY = bottomY = (*segList)->v1->y; for (j = 0; j < polyobjs[i].numsegs; j++, segList++) { if ((*segList)->v1->x < leftX) { leftX = (*segList)->v1->x; } if ((*segList)->v1->x > rightX) { rightX = (*segList)->v1->x; } if ((*segList)->v1->y < bottomY) { bottomY = (*segList)->v1->y; } if ((*segList)->v1->y > topY) { topY = (*segList)->v1->y; } } // area = ((rightX >> FRACBITS) - (leftX >> FRACBITS)) * // ((topY >> FRACBITS) - (bottomY >> FRACBITS)); // fprintf(stdaux, "Area of Polyobj[%d]: %d\n", polyobjs[i].tag, area); // fprintf(stdaux, "\t[%d]\n[%d]\t\t[%d]\n\t[%d]\n", topY>>FRACBITS, // leftX>>FRACBITS, // rightX>>FRACBITS, bottomY>>FRACBITS); } } //========================================================================== // // IterFindPolySegs // // Passing NULL for segList will cause IterFindPolySegs to // count the number of segs in the polyobj //========================================================================== static void IterFindPolySegs(int x, int y, seg_t ** segList) { int i; if (x == PolyStartX && y == PolyStartY) { return; } for (i = 0; i < numsegs; i++) { if (segs[i].v1->x == x && segs[i].v1->y == y) { if (!segList) { PolySegCount++; } else { *segList++ = &segs[i]; } IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, segList); return; } } I_Error("IterFindPolySegs: Non-closed Polyobj located.\n"); } //========================================================================== // // SpawnPolyobj // //========================================================================== static void SpawnPolyobj(int index, int tag, boolean crush) { int i; int j; int psIndex; int psIndexOld; seg_t *polySegList[PO_MAXPOLYSEGS]; for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_START && segs[i].linedef->arg1 == tag) { if (polyobjs[index].segs) { I_Error("SpawnPolyobj: Polyobj %d already spawned.\n", tag); } segs[i].linedef->special = 0; segs[i].linedef->arg1 = 0; PolySegCount = 1; PolyStartX = segs[i].v1->x; PolyStartY = segs[i].v1->y; IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL); polyobjs[index].numsegs = PolySegCount; polyobjs[index].segs = Z_Malloc(PolySegCount * sizeof(seg_t *), PU_LEVEL, 0); *(polyobjs[index].segs) = &segs[i]; // insert the first seg IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, polyobjs[index].segs + 1); polyobjs[index].crush = crush; polyobjs[index].tag = tag; polyobjs[index].seqType = segs[i].linedef->arg3; if (polyobjs[index].seqType < 0 || polyobjs[index].seqType >= SEQTYPE_NUMSEQ) { polyobjs[index].seqType = 0; } break; } } if (!polyobjs[index].segs) { // didn't find a polyobj through PO_LINE_START psIndex = 0; polyobjs[index].numsegs = 0; for (j = 1; j < PO_MAXPOLYSEGS; j++) { psIndexOld = psIndex; for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->arg1 == tag) { if (!segs[i].linedef->arg2) { I_Error ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n", j + 1, tag); } if (segs[i].linedef->arg2 == j) { polySegList[psIndex] = &segs[i]; polyobjs[index].numsegs++; psIndex++; if (psIndex > PO_MAXPOLYSEGS) { I_Error ("SpawnPolyobj: psIndex > PO_MAXPOLYSEGS\n"); } } } } // Clear out any specials for these segs...we cannot clear them out // in the above loop, since we aren't guaranteed one seg per // linedef. for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->arg1 == tag && segs[i].linedef->arg2 == j) { segs[i].linedef->special = 0; segs[i].linedef->arg1 = 0; } } if (psIndex == psIndexOld) { // Check if an explicit line order has been skipped // A line has been skipped if there are any more explicit // lines with the current tag value for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->arg1 == tag) { I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n", j, tag); } } } } if (polyobjs[index].numsegs) { PolySegCount = polyobjs[index].numsegs; // PolySegCount used globally polyobjs[index].crush = crush; polyobjs[index].tag = tag; polyobjs[index].segs = Z_Malloc(polyobjs[index].numsegs * sizeof(seg_t *), PU_LEVEL, 0); for (i = 0; i < polyobjs[index].numsegs; i++) { polyobjs[index].segs[i] = polySegList[i]; } polyobjs[index].seqType = (*polyobjs[index].segs)->linedef->arg4; } // Next, change the polyobjs first line to point to a mirror // if it exists (*polyobjs[index].segs)->linedef->arg2 = (*polyobjs[index].segs)->linedef->arg3; } } //========================================================================== // // TranslateToStartSpot // //========================================================================== static void TranslateToStartSpot(int tag, int originX, int originY) { seg_t **tempSeg; seg_t **veryTempSeg; vertex_t *tempPt; subsector_t *sub; polyobj_t *po; int deltaX; int deltaY; vertex_t avg; // used to find a polyobj's center, and hence subsector int i; po = NULL; for (i = 0; i < po_NumPolyobjs; i++) { if (polyobjs[i].tag == tag) { po = &polyobjs[i]; break; } } if (!po) { // didn't match the tag with a polyobj tag I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n", tag); } if (po->segs == NULL) { I_Error ("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag); } po->originalPts = Z_Malloc(po->numsegs * sizeof(vertex_t), PU_LEVEL, 0); po->prevPts = Z_Malloc(po->numsegs * sizeof(vertex_t), PU_LEVEL, 0); deltaX = originX - po->startSpot.x; deltaY = originY - po->startSpot.y; tempSeg = po->segs; tempPt = po->originalPts; avg.x = 0; avg.y = 0; validcount++; for (i = 0; i < po->numsegs; i++, tempSeg++, tempPt++) { if ((*tempSeg)->linedef->validcount != validcount) { (*tempSeg)->linedef->bbox[BOXTOP] -= deltaY; (*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY; (*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX; (*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX; (*tempSeg)->linedef->validcount = validcount; } for (veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++) { if ((*veryTempSeg)->v1 == (*tempSeg)->v1) { break; } } if (veryTempSeg == tempSeg) { // the point hasn't been translated, yet (*tempSeg)->v1->x -= deltaX; (*tempSeg)->v1->y -= deltaY; } avg.x += (*tempSeg)->v1->x >> FRACBITS; avg.y += (*tempSeg)->v1->y >> FRACBITS; // the original Pts are based off the startSpot Pt, and are // unique to each seg, not each linedef tempPt->x = (*tempSeg)->v1->x - po->startSpot.x; tempPt->y = (*tempSeg)->v1->y - po->startSpot.y; } avg.x /= po->numsegs; avg.y /= po->numsegs; sub = R_PointInSubsector(avg.x << FRACBITS, avg.y << FRACBITS); if (sub->poly != NULL) { I_Error ("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n"); } sub->poly = po; } //========================================================================== // // PO_Init // //========================================================================== void PO_Init(int lump) { byte *data; int i; mapthing_t spawnthing; mapthing_t *mt; int numthings; int polyIndex; polyobjs = Z_Malloc(po_NumPolyobjs * sizeof(polyobj_t), PU_LEVEL, 0); memset(polyobjs, 0, po_NumPolyobjs * sizeof(polyobj_t)); data = W_CacheLumpNum(lump, PU_STATIC); numthings = W_LumpLength(lump) / sizeof(mapthing_t); mt = (mapthing_t *) data; polyIndex = 0; // index polyobj number // Find the startSpot points, and spawn each polyobj for (i = 0; i < numthings; i++, mt++) { spawnthing.x = SHORT(mt->x); spawnthing.y = SHORT(mt->y); spawnthing.angle = SHORT(mt->angle); spawnthing.type = SHORT(mt->type); // 3001 = no crush, 3002 = crushing if (spawnthing.type == PO_SPAWN_TYPE || spawnthing.type == PO_SPAWNCRUSH_TYPE) { // Polyobj StartSpot Pt. polyobjs[polyIndex].startSpot.x = spawnthing.x << FRACBITS; polyobjs[polyIndex].startSpot.y = spawnthing.y << FRACBITS; SpawnPolyobj(polyIndex, spawnthing.angle, (spawnthing.type == PO_SPAWNCRUSH_TYPE)); polyIndex++; } } mt = (mapthing_t *) data; for (i = 0; i < numthings; i++, mt++) { spawnthing.x = SHORT(mt->x); spawnthing.y = SHORT(mt->y); spawnthing.angle = SHORT(mt->angle); spawnthing.type = SHORT(mt->type); if (spawnthing.type == PO_ANCHOR_TYPE) { // Polyobj Anchor Pt. TranslateToStartSpot(spawnthing.angle, spawnthing.x << FRACBITS, spawnthing.y << FRACBITS); } } W_ReleaseLumpNum(lump); // check for a startspot without an anchor point for (i = 0; i < po_NumPolyobjs; i++) { if (!polyobjs[i].originalPts) { I_Error ("PO_Init: StartSpot located without an Anchor point: %d\n", polyobjs[i].tag); } } InitBlockMap(); } //========================================================================== // // PO_Busy // //========================================================================== boolean PO_Busy(int polyobj) { polyobj_t *poly; poly = GetPolyobj(polyobj); if (!poly->specialdata) { return false; } else { return true; } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_bsp.c000066400000000000000000000276421257432200600224670ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_system.h" #include "m_bbox.h" #include "r_local.h" seg_t *curline; side_t *sidedef; line_t *linedef; sector_t *frontsector, *backsector; drawseg_t drawsegs[MAXDRAWSEGS], *ds_p; void R_StoreWallRange(int start, int stop); /* ==================== = = R_ClearDrawSegs = ==================== */ void R_ClearDrawSegs(void) { ds_p = drawsegs; } //============================================================================= /* =============================================================================== = = ClipWallSegment = = Clips the given range of columns and includes it in the new clip list =============================================================================== */ typedef struct { int first, last; } cliprange_t; #define MAXSEGS 32 cliprange_t solidsegs[MAXSEGS], *newend; // newend is one past the last valid seg void R_ClipSolidWallSegment(int first, int last) { cliprange_t *next, *start; // find the first range that touches the range (adjacent pixels are touching) start = solidsegs; while (start->last < first - 1) start++; if (first < start->first) { if (last < start->first - 1) { // post is entirely visible (above start), so insert a new clippost R_StoreWallRange(first, last); next = newend; newend++; while (next != start) { *next = *(next - 1); next--; } next->first = first; next->last = last; return; } // there is a fragment above *start R_StoreWallRange(first, start->first - 1); start->first = first; // adjust the clip size } if (last <= start->last) return; // bottom contained in start next = start; while (last >= (next + 1)->first - 1) { // there is a fragment between two posts R_StoreWallRange(next->last + 1, (next + 1)->first - 1); next++; if (last <= next->last) { // bottom is contained in next start->last = next->last; // adjust the clip size goto crunch; } } // there is a fragment after *next R_StoreWallRange(next->last + 1, last); start->last = last; // adjust the clip size // remove start+1 to next from the clip list, // because start now covers their area crunch: if (next == start) return; // post just extended past the bottom of one post while (next++ != newend) // remove a post *++start = *next; newend = start + 1; } /* =============================================================================== = = R_ClipPassWallSegment = = Clips the given range of columns, but does not includes it in the clip list =============================================================================== */ void R_ClipPassWallSegment(int first, int last) { cliprange_t *start; // find the first range that touches the range (adjacent pixels are touching) start = solidsegs; while (start->last < first - 1) start++; if (first < start->first) { if (last < start->first - 1) { // post is entirely visible (above start) R_StoreWallRange(first, last); return; } // there is a fragment above *start R_StoreWallRange(first, start->first - 1); } if (last <= start->last) return; // bottom contained in start while (last >= (start + 1)->first - 1) { // there is a fragment between two posts R_StoreWallRange(start->last + 1, (start + 1)->first - 1); start++; if (last <= start->last) return; } // there is a fragment after *next R_StoreWallRange(start->last + 1, last); } /* ==================== = = R_ClearClipSegs = ==================== */ void R_ClearClipSegs(void) { solidsegs[0].first = -0x7fffffff; solidsegs[0].last = -1; solidsegs[1].first = viewwidth; solidsegs[1].last = 0x7fffffff; newend = solidsegs + 2; } //============================================================================= /* ====================== = = R_AddLine = = Clips the given segment and adds any visible pieces to the line list = ====================== */ void R_AddLine(seg_t * line) { int x1, x2; angle_t angle1, angle2, span, tspan; curline = line; // OPTIMIZE: quickly reject orthogonal back sides angle1 = R_PointToAngle(line->v1->x, line->v1->y); angle2 = R_PointToAngle(line->v2->x, line->v2->y); // // clip to view edges // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW) span = angle1 - angle2; if (span >= ANG180) return; // back side rw_angle1 = angle1; // global angle needed by segcalc angle1 -= viewangle; angle2 -= viewangle; tspan = angle1 + clipangle; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return; // totally off the left edge angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return; // totally off the left edge angle2 = -clipangle; } // // the seg is in the view range, but not necessarily visible // angle1 = (angle1 + ANG90) >> ANGLETOFINESHIFT; angle2 = (angle2 + ANG90) >> ANGLETOFINESHIFT; x1 = viewangletox[angle1]; x2 = viewangletox[angle2]; if (x1 == x2) return; // does not cross a pixel backsector = line->backsector; if (!backsector) goto clipsolid; // single sided line if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) goto clipsolid; // closed door if (backsector->ceilingheight != frontsector->ceilingheight || backsector->floorheight != frontsector->floorheight) goto clippass; // window // reject empty lines used for triggers and special events if (backsector->ceilingpic == frontsector->ceilingpic && backsector->floorpic == frontsector->floorpic && backsector->lightlevel == frontsector->lightlevel && backsector->special == frontsector->special && curline->sidedef->midtexture == 0) return; clippass: R_ClipPassWallSegment(x1, x2 - 1); return; clipsolid: R_ClipSolidWallSegment(x1, x2 - 1); } //============================================================================ /* =============================================================================== = = R_CheckBBox = = Returns true if some part of the bbox might be visible = =============================================================================== */ int checkcoord[12][4] = { {3, 0, 2, 1}, {3, 0, 2, 0}, {3, 1, 2, 0}, {0}, {2, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 3, 0}, {0}, {2, 0, 3, 1}, {2, 1, 3, 1}, {2, 1, 3, 0} }; boolean R_CheckBBox(fixed_t * bspcoord) { int boxx, boxy, boxpos; fixed_t x1, y1, x2, y2; angle_t angle1, angle2, span, tspan; cliprange_t *start; int sx1, sx2; // find the corners of the box that define the edges from current viewpoint if (viewx <= bspcoord[BOXLEFT]) boxx = 0; else if (viewx < bspcoord[BOXRIGHT]) boxx = 1; else boxx = 2; if (viewy >= bspcoord[BOXTOP]) boxy = 0; else if (viewy > bspcoord[BOXBOTTOM]) boxy = 1; else boxy = 2; boxpos = (boxy << 2) + boxx; if (boxpos == 5) return true; x1 = bspcoord[checkcoord[boxpos][0]]; y1 = bspcoord[checkcoord[boxpos][1]]; x2 = bspcoord[checkcoord[boxpos][2]]; y2 = bspcoord[checkcoord[boxpos][3]]; // // check clip list for an open space // angle1 = R_PointToAngle(x1, y1) - viewangle; angle2 = R_PointToAngle(x2, y2) - viewangle; span = angle1 - angle2; if (span >= ANG180) return true; // sitting on a line tspan = angle1 + clipangle; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return false; // totally off the left edge angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2 * clipangle) { tspan -= 2 * clipangle; if (tspan >= span) return false; // totally off the left edge angle2 = -clipangle; } // find the first clippost that touches the source post (adjacent pixels are touching) angle1 = (angle1 + ANG90) >> ANGLETOFINESHIFT; angle2 = (angle2 + ANG90) >> ANGLETOFINESHIFT; sx1 = viewangletox[angle1]; sx2 = viewangletox[angle2]; if (sx1 == sx2) return false; // does not cross a pixel sx2--; start = solidsegs; while (start->last < sx2) start++; if (sx1 >= start->first && sx2 <= start->last) return false; // the clippost contains the new span return true; } /* ================ = = R_Subsector = = Draw one or more segments ================ */ void R_Subsector(int num) { int count; seg_t *line; subsector_t *sub; int polyCount; seg_t **polySeg; #ifdef RANGECHECK if (num >= numsubsectors) I_Error("R_Subsector: ss %i with numss = %i", num, numsubsectors); #endif sscount++; sub = &subsectors[num]; frontsector = sub->sector; count = sub->numlines; line = &segs[sub->firstline]; if (frontsector->floorheight < viewz) { floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, frontsector->lightlevel, frontsector->special); } else { floorplane = NULL; } if (frontsector->ceilingheight > viewz || frontsector->ceilingpic == skyflatnum) { ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, frontsector->lightlevel, 0); } else { ceilingplane = NULL; } R_AddSprites(frontsector); if (sub->poly) { // Render the polyobj in the subsector first polyCount = sub->poly->numsegs; polySeg = sub->poly->segs; while (polyCount--) { R_AddLine(*polySeg++); } } while (count--) { R_AddLine(line); line++; } } /* =============================================================================== = = RenderBSPNode = =============================================================================== */ void R_RenderBSPNode(int bspnum) { node_t *bsp; int side; if (bspnum & NF_SUBSECTOR) { if (bspnum == -1) R_Subsector(0); else R_Subsector(bspnum & (~NF_SUBSECTOR)); return; } bsp = &nodes[bspnum]; // // decide which side the view point is on // side = R_PointOnSide(viewx, viewy, bsp); R_RenderBSPNode(bsp->children[side]); // recursively divide front space if (R_CheckBBox(bsp->bbox[side ^ 1])) // possibly divide back space R_RenderBSPNode(bsp->children[side ^ 1]); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_data.c000066400000000000000000000416551257432200600226140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_system.h" #include "i_swap.h" #include "m_misc.h" #include "r_local.h" #include "p_local.h" typedef struct { int originx; // block origin (allways UL), which has allready int originy; // accounted for the patch's internal origin int patch; } texpatch_t; // a maptexturedef_t describes a rectangular texture, which is composed of one // or more mappatch_t structures that arrange graphic patches typedef struct { char name[8]; // for switch changing, etc short width; short height; short patchcount; texpatch_t patches[1]; // [patchcount] drawn back to front // into the cached texture } texture_t; int firstflat, lastflat, numflats; int firstpatch, lastpatch, numpatches; int firstspritelump, lastspritelump, numspritelumps; int numtextures; texture_t **textures; int *texturewidthmask; fixed_t *textureheight; // needed for texture pegging int *texturecompositesize; short **texturecolumnlump; unsigned short **texturecolumnofs; byte **texturecomposite; int *flattranslation; // for global animation int *texturetranslation; // for global animation fixed_t *spritewidth; // needed for pre rendering fixed_t *spriteoffset; fixed_t *spritetopoffset; lighttable_t *colormaps; /* ============================================================================== MAPTEXTURE_T CACHING when a texture is first needed, it counts the number of composite columns required in the texture and allocates space for a column directory and any new columns. The directory will simply point inside other patches if there is only one patch in a given column, but any columns with multiple patches will have new column_ts generated. ============================================================================== */ /* =================== = = R_DrawColumnInCache = = Clip and draw a column from a patch into a cached post = =================== */ void R_DrawColumnInCache(column_t * patch, byte * cache, int originy, int cacheheight) { int count, position; byte *source; while (patch->topdelta != 0xff) { source = (byte *) patch + 3; count = patch->length; position = originy + patch->topdelta; if (position < 0) { count += position; position = 0; } if (position + count > cacheheight) count = cacheheight - position; if (count > 0) memcpy(cache + position, source, count); patch = (column_t *) ((byte *) patch + patch->length + 4); } } /* =================== = = R_GenerateComposite = =================== */ void R_GenerateComposite(int texnum) { byte *block; texture_t *texture; texpatch_t *patch; patch_t *realpatch; int x, x1, x2; int i; column_t *patchcol; short *collump; unsigned short *colofs; texture = textures[texnum]; block = Z_Malloc(texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]); collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // // composite the columns together // patch = texture->patches; for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1 < 0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for (; x < x2; x++) { if (collump[x] >= 0) continue; // column does not have multiple patches patchcol = (column_t *) ((byte *) realpatch + LONG(realpatch->columnofs[x - x1])); R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy, texture->height); } } // now that the texture has been built, it is purgable Z_ChangeTag(block, PU_CACHE); } /* =================== = = R_GenerateLookup = =================== */ void R_GenerateLookup(int texnum) { texture_t *texture; byte *patchcount; // [texture->width] texpatch_t *patch; patch_t *realpatch; int x, x1, x2; int i; short *collump; unsigned short *colofs; texture = textures[texnum]; texturecomposite[texnum] = 0; // composited not created yet texturecompositesize[texnum] = 0; collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // // count the number of columns that are covered by more than one patch // fill in the lump / offset, so columns with only a single patch are // all done // patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); memset(patchcount, 0, texture->width); patch = texture->patches; for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1 < 0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for (; x < x2; x++) { patchcount[x]++; collump[x] = patch->patch; colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3; } } for (x = 0; x < texture->width; x++) { if (!patchcount[x]) { ST_Message("R_GenerateLookup: column without a patch (%s)\n", texture->name); return; } // I_Error ("R_GenerateLookup: column without a patch"); if (patchcount[x] > 1) { collump[x] = -1; // use the cached block colofs[x] = texturecompositesize[texnum]; if (texturecompositesize[texnum] > 0x10000 - texture->height) I_Error("R_GenerateLookup: texture %i is >64k", texnum); texturecompositesize[texnum] += texture->height; } } Z_Free(patchcount); } /* ================ = = R_GetColumn = ================ */ byte *R_GetColumn(int tex, int col) { int lump, ofs; col &= texturewidthmask[tex]; lump = texturecolumnlump[tex][col]; ofs = texturecolumnofs[tex][col]; if (lump > 0) return (byte *) W_CacheLumpNum(lump, PU_CACHE) + ofs; if (!texturecomposite[tex]) R_GenerateComposite(tex); return texturecomposite[tex] + ofs; } /* ================== = = R_InitTextures = = Initializes the texture list with the textures from the world map = ================== */ void R_InitTextures(void) { maptexture_t *mtexture; texture_t *texture; mappatch_t *mpatch; texpatch_t *patch; int i, j; int *maptex, *maptex2, *maptex1; char name[9], *names, *name_p; int *patchlookup; int totalwidth; int nummappatches; int offset, maxoff, maxoff2; int numtextures1, numtextures2; int *directory; // // load the patch names from pnames.lmp // names = W_CacheLumpName("PNAMES", PU_STATIC); nummappatches = LONG(*((int *) names)); name_p = names + 4; patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL); for (i = 0; i < nummappatches; i++) { M_StringCopy(name, name_p + i * 8, sizeof(name)); patchlookup[i] = W_CheckNumForName(name); } W_ReleaseLumpName("PNAMES"); // // load the map texture definitions from textures.lmp // maptex = maptex1 = W_CacheLumpName("TEXTURE1", PU_STATIC); numtextures1 = LONG(*maptex); maxoff = W_LumpLength(W_GetNumForName("TEXTURE1")); directory = maptex + 1; if (W_CheckNumForName("TEXTURE2") != -1) { maptex2 = W_CacheLumpName("TEXTURE2", PU_STATIC); numtextures2 = LONG(*maptex2); maxoff2 = W_LumpLength(W_GetNumForName("TEXTURE2")); } else { maptex2 = NULL; numtextures2 = 0; maxoff2 = 0; } numtextures = numtextures1 + numtextures2; textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0); texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); texturecolumnofs = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0); texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); textureheight = Z_Malloc(numtextures * sizeof(fixed_t), PU_STATIC, 0); totalwidth = 0; for (i = 0; i < numtextures; i++, directory++) { if (i == numtextures1) { // start looking in second texture file maptex = maptex2; maxoff = maxoff2; directory = maptex + 1; } offset = LONG(*directory); if (offset > maxoff) I_Error("R_InitTextures: bad texture directory"); mtexture = (maptexture_t *) ((byte *) maptex + offset); texture = textures[i] = Z_Malloc(sizeof(texture_t) + sizeof(texpatch_t) * (SHORT(mtexture->patchcount) - 1), PU_STATIC, 0); texture->width = SHORT(mtexture->width); texture->height = SHORT(mtexture->height); texture->patchcount = SHORT(mtexture->patchcount); memcpy(texture->name, mtexture->name, sizeof(texture->name)); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; for (j = 0; j < texture->patchcount; j++, mpatch++, patch++) { patch->originx = SHORT(mpatch->originx); patch->originy = SHORT(mpatch->originy); patch->patch = patchlookup[SHORT(mpatch->patch)]; if (patch->patch == -1) I_Error("R_InitTextures: Missing patch in texture %s", texture->name); } texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); j = 1; while (j * 2 <= texture->width) j <<= 1; texturewidthmask[i] = j - 1; textureheight[i] = texture->height << FRACBITS; totalwidth += texture->width; } Z_Free(patchlookup); W_ReleaseLumpName("TEXTURE1"); if (maptex2) W_ReleaseLumpName("TEXTURE2"); // // precalculate whatever possible // for (i = 0; i < numtextures; i++) { R_GenerateLookup(i); if (!(i & 31)) ST_Progress(); } // // translation table for global animation // texturetranslation = Z_Malloc((numtextures + 1) * sizeof(int), PU_STATIC, 0); for (i = 0; i < numtextures; i++) texturetranslation[i] = i; } /* ================ = = R_InitFlats = ================= */ void R_InitFlats(void) { int i; firstflat = W_GetNumForName("F_START") + 1; lastflat = W_GetNumForName("F_END") - 1; numflats = lastflat - firstflat + 1; // translation table for global animation flattranslation = Z_Malloc((numflats + 1) * sizeof(int), PU_STATIC, 0); for (i = 0; i < numflats; i++) flattranslation[i] = i; } /* ================ = = R_InitSpriteLumps = = Finds the width and hoffset of all sprites in the wad, so the sprite doesn't = need to be cached just for the header during rendering ================= */ void R_InitSpriteLumps(void) { int i; patch_t *patch; firstspritelump = W_GetNumForName("S_START") + 1; lastspritelump = W_GetNumForName("S_END") - 1; numspritelumps = lastspritelump - firstspritelump + 1; spritewidth = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); spritetopoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); for (i = 0; i < numspritelumps; i++) { if (!(i & 127)) ST_Progress(); patch = W_CacheLumpNum(firstspritelump + i, PU_CACHE); spritewidth[i] = SHORT(patch->width) << FRACBITS; spriteoffset[i] = SHORT(patch->leftoffset) << FRACBITS; spritetopoffset[i] = SHORT(patch->topoffset) << FRACBITS; } } /* ================ = = R_InitColormaps = ================= */ void R_InitColormaps(void) { int lump, length; // // load in the light tables // 256 byte align tables // lump = W_GetNumForName("COLORMAP"); length = W_LumpLength(lump); colormaps = Z_Malloc(length, PU_STATIC, 0); W_ReadLump(lump, colormaps); } /* ================ = = R_InitData = = Locates all the lumps that will be used by all views = Must be called after W_Init ================= */ void R_InitData(void) { R_InitTextures(); R_InitFlats(); R_InitSpriteLumps(); R_InitColormaps(); } //============================================================================= /* ================ = = R_FlatNumForName = ================ */ int R_FlatNumForName(char *name) { int i; char namet[9]; i = W_CheckNumForName(name); if (i == -1) { namet[8] = 0; memcpy(namet, name, 8); I_Error("R_FlatNumForName: %s not found", namet); } return i - firstflat; } /* ================ = = R_CheckTextureNumForName = ================ */ int R_CheckTextureNumForName(char *name) { int i; if (name[0] == '-') // no texture marker return 0; for (i = 0; i < numtextures; i++) if (!strncasecmp(textures[i]->name, name, 8)) return i; return -1; } /* ================ = = R_TextureNumForName = ================ */ int R_TextureNumForName(char *name) { int i; //char namet[9]; i = R_CheckTextureNumForName(name); if (i == -1) I_Error("R_TextureNumForName: %s not found", name); return i; } /* ================= = = R_PrecacheLevel = = Preloads all relevent graphics for the level ================= */ int flatmemory, texturememory, spritememory; void R_PrecacheLevel(void) { char *flatpresent; char *texturepresent; char *spritepresent; int i, j, k, lump; texture_t *texture; thinker_t *th; spriteframe_t *sf; if (demoplayback) return; // // precache flats // flatpresent = Z_Malloc(numflats, PU_STATIC, NULL); memset(flatpresent, 0, numflats); for (i = 0; i < numsectors; i++) { flatpresent[sectors[i].floorpic] = 1; flatpresent[sectors[i].ceilingpic] = 1; } flatmemory = 0; for (i = 0; i < numflats; i++) if (flatpresent[i]) { lump = firstflat + i; flatmemory += lumpinfo[lump].size; W_CacheLumpNum(lump, PU_CACHE); } Z_Free(flatpresent); // // precache textures // texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL); memset(texturepresent, 0, numtextures); for (i = 0; i < numsides; i++) { texturepresent[sides[i].toptexture] = 1; texturepresent[sides[i].midtexture] = 1; texturepresent[sides[i].bottomtexture] = 1; } texturepresent[Sky1Texture] = 1; texturepresent[Sky2Texture] = 1; texturememory = 0; for (i = 0; i < numtextures; i++) { if (!texturepresent[i]) continue; texture = textures[i]; for (j = 0; j < texture->patchcount; j++) { lump = texture->patches[j].patch; texturememory += lumpinfo[lump].size; W_CacheLumpNum(lump, PU_CACHE); } } Z_Free(texturepresent); // // precache sprites // spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL); memset(spritepresent, 0, numsprites); for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == P_MobjThinker) spritepresent[((mobj_t *) th)->sprite] = 1; } spritememory = 0; for (i = 0; i < numsprites; i++) { if (!spritepresent[i]) continue; for (j = 0; j < sprites[i].numframes; j++) { sf = &sprites[i].spriteframes[j]; for (k = 0; k < 8; k++) { lump = firstspritelump + sf->lump[k]; spritememory += lumpinfo[lump].size; W_CacheLumpNum(lump, PU_CACHE); } } } Z_Free(spritepresent); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_draw.c000066400000000000000000000320741257432200600226330ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_system.h" #include "i_video.h" #include "r_local.h" #include "v_video.h" /* All drawing to the view buffer is accomplished in this file. The other refresh files only know about ccordinates, not the architecture of the frame buffer. */ byte *viewimage; int viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy; byte *ylookup[MAXHEIGHT]; int columnofs[MAXWIDTH]; //byte translations[3][256]; // color tables for different players /* ================== = = R_DrawColumn = = Source is the top of the column to scale = ================== */ lighttable_t *dc_colormap; int dc_x; int dc_yl; int dc_yh; fixed_t dc_iscale; fixed_t dc_texturemid; byte *dc_source; // first pixel in a column (possibly virtual) int dccount; // just for profiling void R_DrawColumn(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } void R_DrawColumnLow(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); // dccount++; #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } void R_DrawTLColumn(void) { int count; byte *dest; fixed_t frac, fracstep; if (!dc_yl) dc_yl = 1; if (dc_yh == viewheight - 1) dc_yh = viewheight - 2; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = tinttable[*dest + (dc_colormap[dc_source[(frac >> FRACBITS) & 127]] << 8)]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } //============================================================================ // // R_DrawAltTLColumn // //============================================================================ void R_DrawAltTLColumn(void) { int count; byte *dest; fixed_t frac, fracstep; if (!dc_yl) dc_yl = 1; if (dc_yh == viewheight - 1) dc_yh = viewheight - 2; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawAltTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = tinttable[((*dest) << 8) + dc_colormap[dc_source[(frac >> FRACBITS) & 127]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } /* ======================== = = R_DrawTranslatedColumn = ======================== */ byte *dc_translation; byte *translationtables; void R_DrawTranslatedColumn(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = dc_colormap[dc_translation[dc_source[frac >> FRACBITS]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } //============================================================================ // // R_DrawTranslatedTLColumn // //============================================================================ void R_DrawTranslatedTLColumn(void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl - centery) * fracstep; do { *dest = tinttable[((*dest) << 8) + dc_colormap[dc_translation [dc_source[frac >> FRACBITS]]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } //============================================================================ // // R_DrawTranslatedAltTLColumn // //============================================================================ /* void R_DrawTranslatedAltTLColumn (void) { int count; byte *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; do { *dest = tinttable[*dest +(dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8)]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } */ //-------------------------------------------------------------------------- // // PROC R_InitTranslationTables // //-------------------------------------------------------------------------- void R_InitTranslationTables(void) { int i; byte *transLump; int lumpnum; V_LoadTintTable(); // Allocate translation tables translationtables = Z_Malloc(256 * 3 * (maxplayers - 1), PU_STATIC, 0); for (i = 0; i < 3 * (maxplayers - 1); i++) { lumpnum = W_GetNumForName("trantbl0") + i; transLump = W_CacheLumpNum(lumpnum, PU_STATIC); memcpy(translationtables + i * 256, transLump, 256); W_ReleaseLumpNum(lumpnum); } } /* ================ = = R_DrawSpan = ================ */ int ds_y; int ds_x1; int ds_x2; lighttable_t *ds_colormap; fixed_t ds_xfrac; fixed_t ds_yfrac; fixed_t ds_xstep; fixed_t ds_ystep; byte *ds_source; // start of a 64*64 tile image int dscount; // just for profiling void R_DrawSpan(void) { fixed_t xfrac, yfrac; byte *dest; int count, spot; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned) ds_y > SCREENHEIGHT) I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y); // dscount++; #endif xfrac = ds_xfrac; yfrac = ds_yfrac; dest = ylookup[ds_y] + columnofs[ds_x1]; count = ds_x2 - ds_x1; do { spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63); *dest++ = ds_colormap[ds_source[spot]]; xfrac += ds_xstep; yfrac += ds_ystep; } while (count--); } void R_DrawSpanLow(void) { fixed_t xfrac, yfrac; byte *dest; int count, spot; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned) ds_y > SCREENHEIGHT) I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y); // dscount++; #endif xfrac = ds_xfrac; yfrac = ds_yfrac; dest = ylookup[ds_y] + columnofs[ds_x1]; count = ds_x2 - ds_x1; do { spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63); *dest++ = ds_colormap[ds_source[spot]]; xfrac += ds_xstep; yfrac += ds_ystep; } while (count--); } /* ================ = = R_InitBuffer = ================= */ void R_InitBuffer(int width, int height) { int i; viewwindowx = (SCREENWIDTH - width) >> 1; for (i = 0; i < width; i++) columnofs[i] = viewwindowx + i; if (width == SCREENWIDTH) viewwindowy = 0; else viewwindowy = (SCREENHEIGHT - SBARHEIGHT - height) >> 1; for (i = 0; i < height; i++) ylookup[i] = I_VideoBuffer + (i + viewwindowy) * SCREENWIDTH; } /* ================== = = R_DrawViewBorder = = Draws the border around the view for different size windows ================== */ boolean BorderNeedRefresh; void R_DrawViewBorder(void) { byte *src, *dest; int x, y; if (scaledviewwidth == SCREENWIDTH) return; src = W_CacheLumpName("F_022", PU_CACHE); dest = I_VideoBuffer; for (y = 0; y < SCREENHEIGHT - SBARHEIGHT; y++) { for (x = 0; x < SCREENWIDTH / 64; x++) { memcpy(dest, src + ((y & 63) << 6), 64); dest += 64; } if (SCREENWIDTH & 63) { memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63); dest += (SCREENWIDTH & 63); } } for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16) { V_DrawPatch(x, viewwindowy - 4, W_CacheLumpName("bordt", PU_CACHE)); V_DrawPatch(x, viewwindowy + viewheight, W_CacheLumpName("bordb", PU_CACHE)); } for (y = viewwindowy; y < viewwindowy + viewheight; y += 16) { V_DrawPatch(viewwindowx - 4, y, W_CacheLumpName("bordl", PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, y, W_CacheLumpName("bordr", PU_CACHE)); } V_DrawPatch(viewwindowx - 4, viewwindowy - 4, W_CacheLumpName("bordtl", PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, W_CacheLumpName("bordtr", PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight, W_CacheLumpName("bordbr", PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight, W_CacheLumpName("bordbl", PU_CACHE)); } /* ================== = = R_DrawTopBorder = = Draws the top border around the view for different size windows ================== */ boolean BorderTopRefresh; void R_DrawTopBorder(void) { byte *src, *dest; int x, y; if (scaledviewwidth == SCREENWIDTH) return; /* if(gamemode == shareware) { src = W_CacheLumpName ("FLOOR04", PU_CACHE); } else { src = W_CacheLumpName ("FLAT513", PU_CACHE); } */ src = W_CacheLumpName("F_022", PU_CACHE); dest = I_VideoBuffer; for (y = 0; y < 34; y++) { for (x = 0; x < SCREENWIDTH / 64; x++) { memcpy(dest, src + ((y & 63) << 6), 64); dest += 64; } if (SCREENWIDTH & 63) { memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63); dest += (SCREENWIDTH & 63); } } if (viewwindowy < 35) { for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16) { V_DrawPatch(x, viewwindowy - 4, W_CacheLumpName("bordt", PU_CACHE)); } V_DrawPatch(viewwindowx - 4, viewwindowy, W_CacheLumpName("bordl", PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy, W_CacheLumpName("bordr", PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy + 16, W_CacheLumpName("bordl", PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16, W_CacheLumpName("bordr", PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy - 4, W_CacheLumpName("bordtl", PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, W_CacheLumpName("bordtr", PU_CACHE)); } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_local.h000066400000000000000000000341411257432200600227720ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __R_LOCAL__ #define __R_LOCAL__ #include "i_video.h" #define ANGLETOSKYSHIFT 22 // sky map is 256*128*4 maps #define BASEYCENTER 100 #define MAXWIDTH 1120 #define MAXHEIGHT 832 #define PI 3.141592657 #define CENTERY (SCREENHEIGHT/2) #define MINZ (FRACUNIT*4) #define FIELDOFVIEW 2048 // fineangles in the SCREENWIDTH wide window // // lighting constants // #define LIGHTLEVELS 16 #define LIGHTSEGSHIFT 4 #define MAXLIGHTSCALE 48 #define LIGHTSCALESHIFT 12 #define MAXLIGHTZ 128 #define LIGHTZSHIFT 20 #define NUMCOLORMAPS 32 // number of diminishing #define INVERSECOLORMAP 32 /* ============================================================================== INTERNAL MAP TYPES ============================================================================== */ //================ used by play and refresh typedef struct { fixed_t x, y; } vertex_t; struct line_s; typedef struct { fixed_t floorheight, ceilingheight; short floorpic, ceilingpic; short lightlevel; short special, tag; int soundtraversed; // 0 = untraversed, 1,2 = sndlines -1 mobj_t *soundtarget; // thing that made a sound (or null) seqtype_t seqType; // stone, metal, heavy, etc... int blockbox[4]; // mapblock bounding box for height changes degenmobj_t soundorg; // for any sounds played by the sector int validcount; // if == validcount, already checked mobj_t *thinglist; // list of mobjs in sector void *specialdata; // thinker_t for reversable actions int linecount; struct line_s **lines; // [linecount] size } sector_t; typedef struct { fixed_t textureoffset; // add this to the calculated texture col fixed_t rowoffset; // add this to the calculated texture top short toptexture, bottomtexture, midtexture; sector_t *sector; } side_t; typedef enum { ST_HORIZONTAL, ST_VERTICAL, ST_POSITIVE, ST_NEGATIVE } slopetype_t; /* typedef struct line_s { vertex_t *v1, *v2; fixed_t dx,dy; // v2 - v1 for side checking short flags; short special, tag; short sidenum[2]; // sidenum[1] will be -1 if one sided fixed_t bbox[4]; slopetype_t slopetype; // to aid move clipping sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked void *specialdata; // thinker_t for reversable actions } line_t; */ typedef struct line_s { vertex_t *v1; vertex_t *v2; fixed_t dx; fixed_t dy; short flags; byte special; byte arg1; byte arg2; byte arg3; byte arg4; byte arg5; short sidenum[2]; fixed_t bbox[4]; slopetype_t slopetype; sector_t *frontsector; sector_t *backsector; int validcount; void *specialdata; } line_t; typedef struct { vertex_t *v1, *v2; fixed_t offset; angle_t angle; side_t *sidedef; line_t *linedef; sector_t *frontsector; sector_t *backsector; // NULL for one sided lines } seg_t; // ===== Polyobj data ===== typedef struct { int numsegs; seg_t **segs; degenmobj_t startSpot; vertex_t *originalPts; // used as the base for the rotations vertex_t *prevPts; // use to restore the old point values angle_t angle; int tag; // reference tag assigned in HereticEd int bbox[4]; int validcount; boolean crush; // should the polyobj attempt to crush mobjs? int seqType; fixed_t size; // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) void *specialdata; // pointer a thinker, if the poly is moving } polyobj_t; typedef struct polyblock_s { polyobj_t *polyobj; struct polyblock_s *prev; struct polyblock_s *next; } polyblock_t; typedef struct subsector_s { sector_t *sector; short numlines; short firstline; polyobj_t *poly; } subsector_t; typedef struct { fixed_t x, y, dx, dy; // partition line fixed_t bbox[2][4]; // bounding box for each child unsigned short children[2]; // if NF_SUBSECTOR its a subsector } node_t; /* ============================================================================== OTHER TYPES ============================================================================== */ typedef byte lighttable_t; // this could be wider for >8 bit display #define MAXVISPLANES 160 #define MAXOPENINGS SCREENWIDTH*64 typedef struct { fixed_t height; int picnum; int lightlevel; int special; int minx, maxx; byte pad1; // leave pads for [minx-1]/[maxx+1] byte top[SCREENWIDTH]; byte pad2; byte pad3; byte bottom[SCREENWIDTH]; byte pad4; } visplane_t; typedef struct drawseg_s { seg_t *curline; int x1, x2; fixed_t scale1, scale2, scalestep; int silhouette; // 0=none, 1=bottom, 2=top, 3=both fixed_t bsilheight; // don't clip sprites above this fixed_t tsilheight; // don't clip sprites below this // pointers to lists for sprite clipping short *sprtopclip; // adjusted so [x1] is first value short *sprbottomclip; // adjusted so [x1] is first value short *maskedtexturecol; // adjusted so [x1] is first value } drawseg_t; #define SIL_NONE 0 #define SIL_BOTTOM 1 #define SIL_TOP 2 #define SIL_BOTH 3 #define MAXDRAWSEGS 256 // A vissprite_t is a thing that will be drawn during a refresh typedef struct vissprite_s { struct vissprite_s *prev, *next; int x1, x2; fixed_t gx, gy; // for line side calculation fixed_t gz, gzt; // global bottom / top for silhouette clipping fixed_t startfrac; // horizontal position of x1 fixed_t scale; fixed_t xiscale; // negative if flipped fixed_t texturemid; int patch; lighttable_t *colormap; int mobjflags; // for color translation and shadow draw boolean psprite; // true if psprite int class; // player class (used in translation) fixed_t floorclip; } vissprite_t; extern visplane_t *floorplane, *ceilingplane; // Sprites are patches with a special naming convention so they can be // recognized by R_InitSprites. The sprite and frame specified by a // thing_t is range checked at run time. // a sprite is a patch_t that is assumed to represent a three dimensional // object and may have multiple rotations pre drawn. Horizontal flipping // is used to save space. Some sprites will only have one picture used // for all views. typedef struct { boolean rotate; // if false use 0 for any position short lump[8]; // lump to use for view angles 0-7 byte flip[8]; // flip (1 = flip) to use for view angles 0-7 } spriteframe_t; typedef struct { int numframes; spriteframe_t *spriteframes; } spritedef_t; extern spritedef_t *sprites; extern int numsprites; //============================================================================= extern int numvertexes; extern vertex_t *vertexes; extern int numsegs; extern seg_t *segs; extern int numsectors; extern sector_t *sectors; extern int numsubsectors; extern subsector_t *subsectors; extern int numnodes; extern node_t *nodes; extern int numlines; extern line_t *lines; extern int numsides; extern side_t *sides; extern fixed_t viewx, viewy, viewz; extern angle_t viewangle; extern player_t *viewplayer; extern angle_t clipangle; extern int viewangletox[FINEANGLES / 2]; extern angle_t xtoviewangle[SCREENWIDTH + 1]; extern fixed_t rw_distance; extern angle_t rw_normalangle; // // R_main.c // extern int screenblocks; extern int viewwidth, viewheight, viewwindowx, viewwindowy; extern int scaledviewwidth; extern int centerx, centery; extern int flyheight; extern fixed_t centerxfrac; extern fixed_t centeryfrac; extern fixed_t projection; extern int validcount; extern int sscount, linecount, loopcount; extern lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; extern lighttable_t *scalelightfixed[MAXLIGHTSCALE]; extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; extern int extralight; extern lighttable_t *fixedcolormap; extern fixed_t viewcos, viewsin; extern int detailshift; // 0 = high, 1 = low extern void (*colfunc) (void); extern void (*basecolfunc) (void); extern void (*tlcolfunc) (void); extern void (*spanfunc) (void); int R_PointOnSide(fixed_t x, fixed_t y, node_t * node); int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line); angle_t R_PointToAngle(fixed_t x, fixed_t y); angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); fixed_t R_PointToDist(fixed_t x, fixed_t y); fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); //void R_AddPointToBox (int x, int y, fixed_t *box); // // R_bsp.c // extern seg_t *curline; extern side_t *sidedef; extern line_t *linedef; extern sector_t *frontsector, *backsector; extern int rw_x; extern int rw_stopx; extern boolean segtextured; extern boolean markfloor; // false if the back side is the same plane extern boolean markceiling; extern boolean skymap; extern drawseg_t drawsegs[MAXDRAWSEGS], *ds_p; extern lighttable_t **hscalelight, **vscalelight, **dscalelight; typedef void (*drawfunc_t) (int start, int stop); void R_ClearClipSegs(void); void R_ClearDrawSegs(void); void R_InitSkyMap(void); void R_RenderBSPNode(int bspnum); // // R_segs.c // extern int rw_angle1; // angle to line origin extern int TransTextureStart; extern int TransTextureEnd; void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2); // // R_plane.c // typedef void (*planefunction_t) (int top, int bottom); extern planefunction_t floorfunc, ceilingfunc; extern int skyflatnum; extern short openings[MAXOPENINGS], *lastopening; extern short floorclip[SCREENWIDTH]; extern short ceilingclip[SCREENWIDTH]; extern fixed_t yslope[SCREENHEIGHT]; extern fixed_t distscale[SCREENWIDTH]; void R_InitPlanes(void); void R_ClearPlanes(void); void R_MapPlane(int y, int x1, int x2); void R_MakeSpans(int x, int t1, int b1, int t2, int b2); void R_DrawPlanes(void); visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, int special); visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop); // // R_debug.m // extern int drawbsp; void RD_OpenMapWindow(void); void RD_ClearMapWindow(void); void RD_DisplayLine(int x1, int y1, int x2, int y2, float gray); void RD_DrawNodeLine(node_t * node); void RD_DrawLineCheck(seg_t * line); void RD_DrawLine(seg_t * line); void RD_DrawBBox(fixed_t * bbox); // // R_data.c // extern fixed_t *textureheight; // needed for texture pegging extern fixed_t *spritewidth; // needed for pre rendering (fracs) extern fixed_t *spriteoffset; extern fixed_t *spritetopoffset; extern lighttable_t *colormaps; extern int firstflat; extern int numflats; extern int *flattranslation; // for global animation extern int *texturetranslation; // for global animation extern int firstspritelump, lastspritelump, numspritelumps; extern boolean LevelUseFullBright; byte *R_GetColumn(int tex, int col); void R_InitData(void); void R_PrecacheLevel(void); // // R_things.c // #define MAXVISSPRITES 192 extern vissprite_t vissprites[MAXVISSPRITES], *vissprite_p; extern vissprite_t vsprsortedhead; // constant arrays used for psprite clipping and initializing clipping extern short negonearray[SCREENWIDTH]; extern short screenheightarray[SCREENWIDTH]; // vars for R_DrawMaskedColumn extern short *mfloorclip; extern short *mceilingclip; extern fixed_t spryscale; extern fixed_t sprtopscreen; extern fixed_t sprbotscreen; extern fixed_t pspritescale, pspriteiscale; void R_DrawMaskedColumn(column_t * column, signed int baseclip); void R_SortVisSprites(void); void R_AddSprites(sector_t * sec); void R_AddPSprites(void); void R_DrawSprites(void); void R_InitSprites(char **namelist); void R_ClearSprites(void); void R_DrawMasked(void); void R_ClipVisSprite(vissprite_t * vis, int xl, int xh); //============================================================================= // // R_draw.c // //============================================================================= extern lighttable_t *dc_colormap; extern int dc_x; extern int dc_yl; extern int dc_yh; extern fixed_t dc_iscale; extern fixed_t dc_texturemid; extern byte *dc_source; // first pixel in a column void R_DrawColumn(void); void R_DrawColumnLow(void); void R_DrawTLColumn(void); void R_DrawTLColumnLow(void); void R_DrawTranslatedColumn(void); void R_DrawTranslatedTLColumn(void); void R_DrawTranslatedColumnLow(void); void R_DrawAltTLColumn(void); //void R_DrawTranslatedAltTLColumn(void); extern int ds_y; extern int ds_x1; extern int ds_x2; extern lighttable_t *ds_colormap; extern fixed_t ds_xfrac; extern fixed_t ds_yfrac; extern fixed_t ds_xstep; extern fixed_t ds_ystep; extern byte *ds_source; // start of a 64*64 tile image extern byte *translationtables; extern byte *dc_translation; void R_DrawSpan(void); void R_DrawSpanLow(void); void R_InitBuffer(int width, int height); void R_InitTranslationTables(void); #endif // __R_LOCAL__ chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_main.c000066400000000000000000000441171257432200600226230ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "m_random.h" #include "h2def.h" #include "m_bbox.h" #include "r_local.h" int viewangleoffset; // haleyjd: removed WATCOMC int validcount = 1; // increment every time a check is made lighttable_t *fixedcolormap; extern lighttable_t **walllights; int centerx, centery; fixed_t centerxfrac, centeryfrac; fixed_t projection; int framecount; // just for profiling purposes int sscount, linecount, loopcount; fixed_t viewx, viewy, viewz; angle_t viewangle; fixed_t viewcos, viewsin; player_t *viewplayer; int detailshift; // 0 = high, 1 = low // // precalculated math tables // angle_t clipangle; // The viewangletox[viewangle + FINEANGLES/4] lookup maps the visible view // angles to screen X coordinates, flattening the arc to a flat projection // plane. There will be many angles mapped to the same X. int viewangletox[FINEANGLES / 2]; // The xtoviewangleangle[] table maps a screen pixel to the lowest viewangle // that maps back to x ranges from clipangle to -clipangle angle_t xtoviewangle[SCREENWIDTH + 1]; lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; lighttable_t *scalelightfixed[MAXLIGHTSCALE]; lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; int extralight; // bumped light from gun blasts void (*colfunc) (void); void (*basecolfunc) (void); void (*tlcolfunc) (void); void (*transcolfunc) (void); void (*spanfunc) (void); /* =================== = = R_AddPointToBox = =================== */ /* void R_AddPointToBox (int x, int y, fixed_t *box) { if (x< box[BOXLEFT]) box[BOXLEFT] = x; if (x> box[BOXRIGHT]) box[BOXRIGHT] = x; if (y< box[BOXBOTTOM]) box[BOXBOTTOM] = y; if (y> box[BOXTOP]) box[BOXTOP] = y; } */ /* =============================================================================== = = R_PointOnSide = = Returns side 0 (front) or 1 (back) =============================================================================== */ int R_PointOnSide(fixed_t x, fixed_t y, node_t * node) { fixed_t dx, dy; fixed_t left, right; if (!node->dx) { if (x <= node->x) return node->dy > 0; return node->dy < 0; } if (!node->dy) { if (y <= node->y) return node->dx < 0; return node->dx > 0; } dx = (x - node->x); dy = (y - node->y); // try to quickly decide by looking at sign bits if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000) { if ((node->dy ^ dx) & 0x80000000) return 1; // (left is negative) return 0; } left = FixedMul(node->dy >> FRACBITS, dx); right = FixedMul(dy, node->dx >> FRACBITS); if (right < left) return 0; // front side return 1; // back side } int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line) { fixed_t lx, ly; fixed_t ldx, ldy; fixed_t dx, dy; fixed_t left, right; lx = line->v1->x; ly = line->v1->y; ldx = line->v2->x - lx; ldy = line->v2->y - ly; if (!ldx) { if (x <= lx) return ldy > 0; return ldy < 0; } if (!ldy) { if (y <= ly) return ldx < 0; return ldx > 0; } dx = (x - lx); dy = (y - ly); // try to quickly decide by looking at sign bits if ((ldy ^ ldx ^ dx ^ dy) & 0x80000000) { if ((ldy ^ dx) & 0x80000000) return 1; // (left is negative) return 0; } left = FixedMul(ldy >> FRACBITS, dx); right = FixedMul(dy, ldx >> FRACBITS); if (right < left) return 0; // front side return 1; // back side } /* =============================================================================== = = R_PointToAngle = =============================================================================== */ #define DBITS (FRACBITS-SLOPEBITS) angle_t R_PointToAngle(fixed_t x, fixed_t y) { x -= viewx; y -= viewy; if ((!x) && (!y)) return 0; if (x >= 0) { // x >=0 if (y >= 0) { // y>= 0 if (x > y) return tantoangle[SlopeDiv(y, x)]; // octant 0 else return ANG90 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 1 } else { // y<0 y = -y; if (x > y) return -tantoangle[SlopeDiv(y, x)]; // octant 8 else return ANG270 + tantoangle[SlopeDiv(x, y)]; // octant 7 } } else { // x<0 x = -x; if (y >= 0) { // y>= 0 if (x > y) return ANG180 - 1 - tantoangle[SlopeDiv(y, x)]; // octant 3 else return ANG90 + tantoangle[SlopeDiv(x, y)]; // octant 2 } else { // y<0 y = -y; if (x > y) return ANG180 + tantoangle[SlopeDiv(y, x)]; // octant 4 else return ANG270 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 5 } } return 0; } angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) { viewx = x1; viewy = y1; return R_PointToAngle(x2, y2); } fixed_t R_PointToDist(fixed_t x, fixed_t y) { int angle; fixed_t dx, dy, temp; fixed_t dist; dx = abs(x - viewx); dy = abs(y - viewy); if (dy > dx) { temp = dx; dx = dy; dy = temp; } angle = (tantoangle[FixedDiv(dy, dx) >> DBITS] + ANG90) >> ANGLETOFINESHIFT; dist = FixedDiv(dx, finesine[angle]); // use as cosine return dist; } /* ================= = = R_InitPointToAngle = ================= */ void R_InitPointToAngle(void) { // now getting from tables.c #if 0 int i; long t; float f; // // slope (tangent) to angle lookup // for (i = 0; i <= SLOPERANGE; i++) { f = atan((float) i / SLOPERANGE) / (3.141592657 * 2); t = 0xffffffff * f; tantoangle[i] = t; } #endif } //============================================================================= /* ================ = = R_ScaleFromGlobalAngle = = Returns the texture mapping scale for the current line at the given angle = rw_distance must be calculated first ================ */ fixed_t R_ScaleFromGlobalAngle(angle_t visangle) { fixed_t scale; int anglea, angleb; int sinea, sineb; fixed_t num, den; #if 0 { fixed_t dist, z; fixed_t sinv, cosv; sinv = finesine[(visangle - rw_normalangle) >> ANGLETOFINESHIFT]; dist = FixedDiv(rw_distance, sinv); cosv = finecosine[(viewangle - visangle) >> ANGLETOFINESHIFT]; z = abs(FixedMul(dist, cosv)); scale = FixedDiv(projection, z); return scale; } #endif anglea = ANG90 + (visangle - viewangle); angleb = ANG90 + (visangle - rw_normalangle); // bothe sines are allways positive sinea = finesine[anglea >> ANGLETOFINESHIFT]; sineb = finesine[angleb >> ANGLETOFINESHIFT]; num = FixedMul(projection, sineb) << detailshift; den = FixedMul(rw_distance, sinea); if (den > num >> 16) { scale = FixedDiv(num, den); if (scale > 64 * FRACUNIT) scale = 64 * FRACUNIT; else if (scale < 256) scale = 256; } else scale = 64 * FRACUNIT; return scale; } /* ================= = = R_InitTables = ================= */ void R_InitTables(void) { // now getting from tables.c #if 0 int i; float a, fv; int t; // // viewangle tangent table // for (i = 0; i < FINEANGLES / 2; i++) { a = (i - FINEANGLES / 4 + 0.5) * PI * 2 / FINEANGLES; fv = FRACUNIT * tan(a); t = fv; finetangent[i] = t; } // // finesine table // for (i = 0; i < 5 * FINEANGLES / 4; i++) { // OPTIMIZE: mirror... a = (i + 0.5) * PI * 2 / FINEANGLES; t = FRACUNIT * sin(a); finesine[i] = t; } #endif } /* ================= = = R_InitTextureMapping = ================= */ void R_InitTextureMapping(void) { int i; int x; int t; fixed_t focallength; // // use tangent table to generate viewangletox // viewangletox will give the next greatest x after the view angle // // calc focallength so FIELDOFVIEW angles covers SCREENWIDTH focallength = FixedDiv(centerxfrac, finetangent[FINEANGLES / 4 + FIELDOFVIEW / 2]); for (i = 0; i < FINEANGLES / 2; i++) { if (finetangent[i] > FRACUNIT * 2) t = -1; else if (finetangent[i] < -FRACUNIT * 2) t = viewwidth + 1; else { t = FixedMul(finetangent[i], focallength); t = (centerxfrac - t + FRACUNIT - 1) >> FRACBITS; if (t < -1) t = -1; else if (t > viewwidth + 1) t = viewwidth + 1; } viewangletox[i] = t; } // // scan viewangletox[] to generate xtoviewangleangle[] // // xtoviewangle will give the smallest view angle that maps to x for (x = 0; x <= viewwidth; x++) { i = 0; while (viewangletox[i] > x) i++; xtoviewangle[x] = (i << ANGLETOFINESHIFT) - ANG90; } // // take out the fencepost cases from viewangletox // for (i = 0; i < FINEANGLES / 2; i++) { t = FixedMul(finetangent[i], focallength); t = centerx - t; if (viewangletox[i] == -1) viewangletox[i] = 0; else if (viewangletox[i] == viewwidth + 1) viewangletox[i] = viewwidth; } clipangle = xtoviewangle[0]; } //============================================================================= /* ==================== = = R_InitLightTables = = Only inits the zlight table, because the scalelight table changes = with view size = ==================== */ #define DISTMAP 2 void R_InitLightTables(void) { int i, j, level, startmap; int scale; // // Calculate the light levels to use for each level / distance combination // for (i = 0; i < LIGHTLEVELS; i++) { startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS; for (j = 0; j < MAXLIGHTZ; j++) { scale = FixedDiv((SCREENWIDTH / 2 * FRACUNIT), (j + 1) << LIGHTZSHIFT); scale >>= LIGHTSCALESHIFT; level = startmap - scale / DISTMAP; if (level < 0) level = 0; if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS - 1; zlight[i][j] = colormaps + level * 256; } } } /* ============== = = R_SetViewSize = = Don't really change anything here, because i might be in the middle of = a refresh. The change will take effect next refresh. = ============== */ boolean setsizeneeded; int setblocks, setdetail; void R_SetViewSize(int blocks, int detail) { setsizeneeded = true; setblocks = blocks; setdetail = detail; } /* ============== = = R_ExecuteSetViewSize = ============== */ void R_ExecuteSetViewSize(void) { fixed_t cosadj, dy; int i, j, level, startmap; setsizeneeded = false; if (setblocks == 11) { scaledviewwidth = SCREENWIDTH; viewheight = SCREENHEIGHT; } else { scaledviewwidth = setblocks * 32; viewheight = (setblocks * 161 / 10); } detailshift = setdetail; viewwidth = scaledviewwidth >> detailshift; centery = viewheight / 2; centerx = viewwidth / 2; centerxfrac = centerx << FRACBITS; centeryfrac = centery << FRACBITS; projection = centerxfrac; if (!detailshift) { colfunc = basecolfunc = R_DrawColumn; tlcolfunc = R_DrawTLColumn; transcolfunc = R_DrawTranslatedColumn; spanfunc = R_DrawSpan; } else { colfunc = basecolfunc = R_DrawColumnLow; tlcolfunc = R_DrawTLColumn; transcolfunc = R_DrawTranslatedColumn; spanfunc = R_DrawSpanLow; } R_InitBuffer(scaledviewwidth, viewheight); R_InitTextureMapping(); // // psprite scales // pspritescale = FRACUNIT * viewwidth / SCREENWIDTH; pspriteiscale = FRACUNIT * SCREENWIDTH / viewwidth; // // thing clipping // for (i = 0; i < viewwidth; i++) screenheightarray[i] = viewheight; // // planes // for (i = 0; i < viewheight; i++) { dy = ((i - viewheight / 2) << FRACBITS) + FRACUNIT / 2; dy = abs(dy); yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT, dy); } for (i = 0; i < viewwidth; i++) { cosadj = abs(finecosine[xtoviewangle[i] >> ANGLETOFINESHIFT]); distscale[i] = FixedDiv(FRACUNIT, cosadj); } // // Calculate the light levels to use for each level / scale combination // for (i = 0; i < LIGHTLEVELS; i++) { startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS; for (j = 0; j < MAXLIGHTSCALE; j++) { level = startmap - j * SCREENWIDTH / (viewwidth << detailshift) / DISTMAP; if (level < 0) level = 0; if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS - 1; scalelight[i][j] = colormaps + level * 256; } } // // draw the border // R_DrawViewBorder(); // erase old menu stuff } /* ============== = = R_Init = ============== */ int detailLevel; int screenblocks = 10; void R_Init(void) { R_InitData(); R_InitPointToAngle(); R_InitTables(); // viewwidth / viewheight / detailLevel are set by the defaults R_SetViewSize(screenblocks, detailLevel); R_InitPlanes(); R_InitLightTables(); R_InitSkyMap(); R_InitTranslationTables(); framecount = 0; } /* ============== = = R_PointInSubsector = ============== */ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y) { node_t *node; int side, nodenum; if (!numnodes) // single subsector is a special case return subsectors; nodenum = numnodes - 1; while (!(nodenum & NF_SUBSECTOR)) { node = &nodes[nodenum]; side = R_PointOnSide(x, y, node); nodenum = node->children[side]; } return &subsectors[nodenum & ~NF_SUBSECTOR]; } //---------------------------------------------------------------------------- // // PROC R_SetupFrame // //---------------------------------------------------------------------------- void R_SetupFrame(player_t * player) { int i; int tableAngle; int tempCentery; int intensity; //drawbsp = 1; viewplayer = player; // haleyjd: removed WATCOMC // haleyjd FIXME: viewangleoffset handling? viewangle = player->mo->angle + viewangleoffset; tableAngle = viewangle >> ANGLETOFINESHIFT; viewx = player->mo->x; viewy = player->mo->y; if (localQuakeHappening[displayplayer] && !paused) { intensity = localQuakeHappening[displayplayer]; viewx += ((M_Random() % (intensity << 2)) - (intensity << 1)) << FRACBITS; viewy += ((M_Random() % (intensity << 2)) - (intensity << 1)) << FRACBITS; } extralight = player->extralight; viewz = player->viewz; tempCentery = viewheight / 2 + (player->lookdir) * screenblocks / 10; if (centery != tempCentery) { centery = tempCentery; centeryfrac = centery << FRACBITS; for (i = 0; i < viewheight; i++) { yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT, abs(((i - centery) << FRACBITS) + FRACUNIT / 2)); } } viewsin = finesine[tableAngle]; viewcos = finecosine[tableAngle]; sscount = 0; if (player->fixedcolormap) { fixedcolormap = colormaps + player->fixedcolormap * 256 * sizeof(lighttable_t); walllights = scalelightfixed; for (i = 0; i < MAXLIGHTSCALE; i++) { scalelightfixed[i] = fixedcolormap; } } else { fixedcolormap = 0; } framecount++; validcount++; if (BorderNeedRefresh) { if (setblocks < 10) { R_DrawViewBorder(); } BorderNeedRefresh = false; BorderTopRefresh = false; UpdateState |= I_FULLSCRN; } if (BorderTopRefresh) { if (setblocks < 10) { R_DrawTopBorder(); } BorderTopRefresh = false; UpdateState |= I_MESSAGES; } #if 0 { static int frame; memset(screen, frame, SCREENWIDTH * SCREENHEIGHT); frame++; } #endif } /* ============== = = R_RenderView = ============== */ void R_RenderPlayerView(player_t * player) { R_SetupFrame(player); R_ClearClipSegs(); R_ClearDrawSegs(); R_ClearPlanes(); R_ClearSprites(); NetUpdate(); // check for new console commands // Make displayed player invisible locally if (localQuakeHappening[displayplayer] && gamestate == GS_LEVEL) { players[displayplayer].mo->flags2 |= MF2_DONTDRAW; R_RenderBSPNode(numnodes - 1); // head node is the last node output players[displayplayer].mo->flags2 &= ~MF2_DONTDRAW; } else { R_RenderBSPNode(numnodes - 1); // head node is the last node output } NetUpdate(); // check for new console commands R_DrawPlanes(); NetUpdate(); // check for new console commands R_DrawMasked(); NetUpdate(); // check for new console commands } chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_plane.c000066400000000000000000000412351257432200600227740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "i_system.h" #include "r_local.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern fixed_t Sky1ScrollDelta; extern fixed_t Sky2ScrollDelta; // PUBLIC DATA DEFINITIONS ------------------------------------------------- int Sky1Texture; int Sky2Texture; fixed_t Sky1ColumnOffset; fixed_t Sky2ColumnOffset; int skyflatnum; int skytexturemid; fixed_t skyiscale; boolean DoubleSky; planefunction_t floorfunc, ceilingfunc; // Opening visplane_t visplanes[MAXVISPLANES], *lastvisplane; visplane_t *floorplane, *ceilingplane; short openings[MAXOPENINGS], *lastopening; // Clip values are the solid pixel bounding the range. // floorclip start out SCREENHEIGHT // ceilingclip starts out -1 short floorclip[SCREENWIDTH]; short ceilingclip[SCREENWIDTH]; // spanstart holds the start of a plane span, initialized to 0 int spanstart[SCREENHEIGHT]; int spanstop[SCREENHEIGHT]; // Texture mapping lighttable_t **planezlight; fixed_t planeheight; fixed_t yslope[SCREENHEIGHT]; fixed_t distscale[SCREENWIDTH]; fixed_t basexscale, baseyscale; fixed_t cachedheight[SCREENHEIGHT]; fixed_t cacheddistance[SCREENHEIGHT]; fixed_t cachedxstep[SCREENHEIGHT]; fixed_t cachedystep[SCREENHEIGHT]; // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- //========================================================================== // // R_InitSky // // Called at level load. // //========================================================================== void R_InitSky(int map) { Sky1Texture = P_GetMapSky1Texture(map); Sky2Texture = P_GetMapSky2Texture(map); Sky1ScrollDelta = P_GetMapSky1ScrollDelta(map); Sky2ScrollDelta = P_GetMapSky2ScrollDelta(map); Sky1ColumnOffset = 0; Sky2ColumnOffset = 0; DoubleSky = P_GetMapDoubleSky(map); } //========================================================================== // // R_InitSkyMap // // Called whenever the view size changes. // //========================================================================== void R_InitSkyMap(void) { skyflatnum = R_FlatNumForName("F_SKY"); skytexturemid = 200 * FRACUNIT; skyiscale = FRACUNIT; } //========================================================================== // // R_InitPlanes // // Called at game startup. // //========================================================================== void R_InitPlanes(void) { } //========================================================================== // // R_MapPlane // // Globals used: planeheight, ds_source, basexscale, baseyscale, // viewx, viewy. // //========================================================================== void R_MapPlane(int y, int x1, int x2) { angle_t angle; fixed_t distance, length; unsigned index; #ifdef RANGECHECK if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned) y > viewheight) { I_Error("R_MapPlane: %i, %i at %i", x1, x2, y); } #endif if (planeheight != cachedheight[y]) { cachedheight[y] = planeheight; distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale); ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale); } else { distance = cacheddistance[y]; ds_xstep = cachedxstep[y]; ds_ystep = cachedystep[y]; } length = FixedMul(distance, distscale[x1]); angle = (viewangle + xtoviewangle[x1]) >> ANGLETOFINESHIFT; ds_xfrac = viewx + FixedMul(finecosine[angle], length); ds_yfrac = -viewy - FixedMul(finesine[angle], length); if (fixedcolormap) { ds_colormap = fixedcolormap; } else { index = distance >> LIGHTZSHIFT; if (index >= MAXLIGHTZ) { index = MAXLIGHTZ - 1; } ds_colormap = planezlight[index]; } ds_y = y; ds_x1 = x1; ds_x2 = x2; spanfunc(); // High or low detail } //========================================================================== // // R_ClearPlanes // // Called at the beginning of each frame. // //========================================================================== void R_ClearPlanes(void) { int i; angle_t angle; // Opening / clipping determination for (i = 0; i < viewwidth; i++) { floorclip[i] = viewheight; ceilingclip[i] = -1; } lastvisplane = visplanes; lastopening = openings; // Texture calculation memset(cachedheight, 0, sizeof(cachedheight)); angle = (viewangle - ANG90) >> ANGLETOFINESHIFT; // left to right mapping // Scale will be unit scale at SCREENWIDTH/2 distance basexscale = FixedDiv(finecosine[angle], centerxfrac); baseyscale = -FixedDiv(finesine[angle], centerxfrac); } //========================================================================== // // R_FindPlane // //========================================================================== visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, int special) { visplane_t *check; if (special < 150) { // Don't let low specials affect search special = 0; } if (picnum == skyflatnum) { // All skies map together height = 0; lightlevel = 0; } for (check = visplanes; check < lastvisplane; check++) { if (height == check->height && picnum == check->picnum && lightlevel == check->lightlevel && special == check->special) break; } if (check < lastvisplane) { return (check); } if (lastvisplane - visplanes == MAXVISPLANES) { I_Error("R_FindPlane: no more visplanes"); } lastvisplane++; check->height = height; check->picnum = picnum; check->lightlevel = lightlevel; check->special = special; check->minx = SCREENWIDTH; check->maxx = -1; memset(check->top, 0xff, sizeof(check->top)); return (check); } //========================================================================== // // R_CheckPlane // //========================================================================== visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop) { int intrl, intrh; int unionl, unionh; int x; if (start < pl->minx) { intrl = pl->minx; unionl = start; } else { unionl = pl->minx; intrl = start; } if (stop > pl->maxx) { intrh = pl->maxx; unionh = stop; } else { unionh = pl->maxx; intrh = stop; } for (x = intrl; x <= intrh; x++) { if (pl->top[x] != 0xff) { break; } } if (x > intrh) { pl->minx = unionl; pl->maxx = unionh; return pl; // use the same visplane } // Make a new visplane lastvisplane->height = pl->height; lastvisplane->picnum = pl->picnum; lastvisplane->lightlevel = pl->lightlevel; lastvisplane->special = pl->special; pl = lastvisplane++; pl->minx = start; pl->maxx = stop; memset(pl->top, 0xff, sizeof(pl->top)); return pl; } //========================================================================== // // R_MakeSpans // //========================================================================== void R_MakeSpans(int x, int t1, int b1, int t2, int b2) { while (t1 < t2 && t1 <= b1) { R_MapPlane(t1, spanstart[t1], x - 1); t1++; } while (b1 > b2 && b1 >= t1) { R_MapPlane(b1, spanstart[b1], x - 1); b1--; } while (t2 < t1 && t2 <= b2) { spanstart[t2] = x; t2++; } while (b2 > b1 && b2 >= t2) { spanstart[b2] = x; b2--; } } //========================================================================== // // R_DrawPlanes // //========================================================================== #define SKYTEXTUREMIDSHIFTED 200 void R_DrawPlanes(void) { visplane_t *pl; int light; int x, stop; int angle; byte *tempSource; byte *source; byte *source2; byte *dest; int count; int offset; int skyTexture; int offset2; int skyTexture2; int scrollOffset; extern byte *ylookup[MAXHEIGHT]; extern int columnofs[MAXWIDTH]; #ifdef RANGECHECK if (ds_p - drawsegs > MAXDRAWSEGS) { I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs); } if (lastvisplane - visplanes > MAXVISPLANES) { I_Error("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes); } if (lastopening - openings > MAXOPENINGS) { I_Error("R_DrawPlanes: opening overflow (%i)", lastopening - openings); } #endif for (pl = visplanes; pl < lastvisplane; pl++) { if (pl->minx > pl->maxx) { continue; } if (pl->picnum == skyflatnum) { // Sky flat if (DoubleSky) { // Render 2 layers, sky 1 in front offset = Sky1ColumnOffset >> 16; skyTexture = texturetranslation[Sky1Texture]; offset2 = Sky2ColumnOffset >> 16; skyTexture2 = texturetranslation[Sky2Texture]; for (x = pl->minx; x <= pl->maxx; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; if (dc_yl <= dc_yh) { count = dc_yh - dc_yl; if (count < 0) { return; } angle = (viewangle + xtoviewangle[x]) >> ANGLETOSKYSHIFT; source = R_GetColumn(skyTexture, angle + offset) + SKYTEXTUREMIDSHIFTED + (dc_yl - centery); source2 = R_GetColumn(skyTexture2, angle + offset2) + SKYTEXTUREMIDSHIFTED + (dc_yl - centery); dest = ylookup[dc_yl] + columnofs[x]; do { if (*source) { *dest = *source++; source2++; } else { *dest = *source2++; source++; } dest += SCREENWIDTH; } while (count--); } } continue; // Next visplane } else { // Render single layer if (pl->special == 200) { // Use sky 2 offset = Sky2ColumnOffset >> 16; skyTexture = texturetranslation[Sky2Texture]; } else { // Use sky 1 offset = Sky1ColumnOffset >> 16; skyTexture = texturetranslation[Sky1Texture]; } for (x = pl->minx; x <= pl->maxx; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; if (dc_yl <= dc_yh) { count = dc_yh - dc_yl; if (count < 0) { return; } angle = (viewangle + xtoviewangle[x]) >> ANGLETOSKYSHIFT; source = R_GetColumn(skyTexture, angle + offset) + SKYTEXTUREMIDSHIFTED + (dc_yl - centery); dest = ylookup[dc_yl] + columnofs[x]; do { *dest = *source++; dest += SCREENWIDTH; } while (count--); } } continue; // Next visplane } } // Regular flat tempSource = W_CacheLumpNum(firstflat + flattranslation[pl->picnum], PU_STATIC); scrollOffset = leveltime >> 1 & 63; switch (pl->special) { // Handle scrolling flats case 201: case 202: case 203: // Scroll_North_xxx ds_source = tempSource + ((scrollOffset << (pl->special - 201) & 63) << 6); break; case 204: case 205: case 206: // Scroll_East_xxx ds_source = tempSource + ((63 - scrollOffset) << (pl->special - 204) & 63); break; case 207: case 208: case 209: // Scroll_South_xxx ds_source = tempSource + (((63 - scrollOffset) << (pl->special - 207) & 63) << 6); break; case 210: case 211: case 212: // Scroll_West_xxx ds_source = tempSource + (scrollOffset << (pl->special - 210) & 63); break; case 213: case 214: case 215: // Scroll_NorthWest_xxx ds_source = tempSource + (scrollOffset << (pl->special - 213) & 63) + ((scrollOffset << (pl->special - 213) & 63) << 6); break; case 216: case 217: case 218: // Scroll_NorthEast_xxx ds_source = tempSource + ((63 - scrollOffset) << (pl->special - 216) & 63) + ((scrollOffset << (pl->special - 216) & 63) << 6); break; case 219: case 220: case 221: // Scroll_SouthEast_xxx ds_source = tempSource + ((63 - scrollOffset) << (pl->special - 219) & 63) + (((63 - scrollOffset) << (pl->special - 219) & 63) << 6); break; case 222: case 223: case 224: // Scroll_SouthWest_xxx ds_source = tempSource + (scrollOffset << (pl->special - 222) & 63) + (((63 - scrollOffset) << (pl->special - 222) & 63) << 6); break; default: ds_source = tempSource; break; } planeheight = abs(pl->height - viewz); light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; if (light >= LIGHTLEVELS) { light = LIGHTLEVELS - 1; } if (light < 0) { light = 0; } planezlight = zlight[light]; pl->top[pl->maxx + 1] = 0xff; pl->top[pl->minx - 1] = 0xff; stop = pl->maxx + 1; for (x = pl->minx; x <= stop; x++) { R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1], pl->top[x], pl->bottom[x]); } W_ReleaseLumpNum(firstflat + flattranslation[pl->picnum]); } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_segs.c000066400000000000000000000462311257432200600226370ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "i_system.h" #include "r_local.h" // OPTIMIZE: closed two sided lines as single sided boolean segtextured; // true if any of the segs textures might be vis boolean markfloor; // false if the back side is the same plane boolean markceiling; boolean maskedtexture; int toptexture, bottomtexture, midtexture; angle_t rw_normalangle; int rw_angle1; // angle to line origin // // wall // int rw_x; int rw_stopx; angle_t rw_centerangle; fixed_t rw_offset; fixed_t rw_distance; fixed_t rw_scale; fixed_t rw_scalestep; fixed_t rw_midtexturemid; fixed_t rw_toptexturemid; fixed_t rw_bottomtexturemid; int worldtop, worldbottom, worldhigh, worldlow; fixed_t pixhigh, pixlow; fixed_t pixhighstep, pixlowstep; fixed_t topfrac, topstep; fixed_t bottomfrac, bottomstep; lighttable_t **walllights; short *maskedtexturecol; /* ================ = = R_RenderMaskedSegRange = ================ */ void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2) { unsigned index; column_t *col; int lightnum; int texnum; // // calculate light table // use different light tables for horizontal / vertical / diagonal // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; frontsector = curline->frontsector; backsector = curline->backsector; texnum = texturetranslation[curline->sidedef->midtexture]; lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight; //if (curline->v1->y == curline->v2->y) // lightnum--; //else if (curline->v1->x == curline->v2->x) // lightnum++; //if (lightnum < 0) // walllights = scalelight[0]; if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS - 1]; else walllights = scalelight[lightnum]; maskedtexturecol = ds->maskedtexturecol; rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1) * rw_scalestep; mfloorclip = ds->sprbottomclip; mceilingclip = ds->sprtopclip; // // find positioning // if (curline->linedef->flags & ML_DONTPEGBOTTOM) { dc_texturemid = frontsector->floorheight > backsector->floorheight ? frontsector->floorheight : backsector->floorheight; dc_texturemid = dc_texturemid + textureheight[texnum] - viewz; } else { dc_texturemid = frontsector->ceilingheight < backsector->ceilingheight ? frontsector->ceilingheight : backsector->ceilingheight; dc_texturemid = dc_texturemid - viewz; } dc_texturemid += curline->sidedef->rowoffset; if (fixedcolormap) dc_colormap = fixedcolormap; // // draw the columns // for (dc_x = x1; dc_x <= x2; dc_x++) { // calculate lighting if (maskedtexturecol[dc_x] != SHRT_MAX) { if (!fixedcolormap) { index = spryscale >> LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1; dc_colormap = walllights[index]; } sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); dc_iscale = 0xffffffffu / (unsigned) spryscale; // // draw the texture // col = (column_t *) ((byte *) R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); R_DrawMaskedColumn(col, -1); maskedtexturecol[dc_x] = SHRT_MAX; } spryscale += rw_scalestep; } } /* ================ = = R_RenderSegLoop = = Draws zero, one, or two textures (and possibly a masked texture) for walls = Can draw or mark the starting pixel of floor and ceiling textures = = CALLED: CORE LOOPING ROUTINE ================ */ #define HEIGHTBITS 12 #define HEIGHTUNIT (1<> HEIGHTBITS; if (yl < ceilingclip[rw_x] + 1) yl = ceilingclip[rw_x] + 1; // no space above wall if (markceiling) { top = ceilingclip[rw_x] + 1; bottom = yl - 1; if (bottom >= floorclip[rw_x]) bottom = floorclip[rw_x] - 1; if (top <= bottom) { ceilingplane->top[rw_x] = top; ceilingplane->bottom[rw_x] = bottom; } } yh = bottomfrac >> HEIGHTBITS; if (yh >= floorclip[rw_x]) yh = floorclip[rw_x] - 1; if (markfloor) { top = yh + 1; bottom = floorclip[rw_x] - 1; if (top <= ceilingclip[rw_x]) top = ceilingclip[rw_x] + 1; if (top <= bottom) { floorplane->top[rw_x] = top; floorplane->bottom[rw_x] = bottom; } } // // texturecolumn and lighting are independent of wall tiers // if (segtextured) { // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x]) >> ANGLETOFINESHIFT; texturecolumn = rw_offset - FixedMul(finetangent[angle], rw_distance); texturecolumn >>= FRACBITS; // calculate lighting index = rw_scale >> LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1; dc_colormap = walllights[index]; dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned) rw_scale; } // // draw the wall tiers // if (midtexture) { // single sided line dc_yl = yl; dc_yh = yh; dc_texturemid = rw_midtexturemid; dc_source = R_GetColumn(midtexture, texturecolumn); colfunc(); ceilingclip[rw_x] = viewheight; floorclip[rw_x] = -1; } else { // two sided line if (toptexture) { // top wall mid = pixhigh >> HEIGHTBITS; pixhigh += pixhighstep; if (mid >= floorclip[rw_x]) mid = floorclip[rw_x] - 1; if (mid >= yl) { dc_yl = yl; dc_yh = mid; dc_texturemid = rw_toptexturemid; dc_source = R_GetColumn(toptexture, texturecolumn); colfunc(); ceilingclip[rw_x] = mid; } else ceilingclip[rw_x] = yl - 1; } else { // no top wall if (markceiling) ceilingclip[rw_x] = yl - 1; } if (bottomtexture) { // bottom wall mid = (pixlow + HEIGHTUNIT - 1) >> HEIGHTBITS; pixlow += pixlowstep; if (mid <= ceilingclip[rw_x]) mid = ceilingclip[rw_x] + 1; // no space above wall if (mid <= yh) { dc_yl = mid; dc_yh = yh; dc_texturemid = rw_bottomtexturemid; dc_source = R_GetColumn(bottomtexture, texturecolumn); colfunc(); floorclip[rw_x] = mid; } else floorclip[rw_x] = yh + 1; } else { // no bottom wall if (markfloor) floorclip[rw_x] = yh + 1; } if (maskedtexture) { // save texturecol for backdrawing of masked mid texture maskedtexturecol[rw_x] = texturecolumn; } } rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; } } /* ===================== = = R_StoreWallRange = = A wall segment will be drawn between start and stop pixels (inclusive) = ====================== */ void R_StoreWallRange(int start, int stop) { fixed_t hyp; fixed_t sineval; angle_t distangle, offsetangle; fixed_t vtop; int lightnum; if (ds_p == &drawsegs[MAXDRAWSEGS]) return; // don't overflow and crash #ifdef RANGECHECK if (start >= viewwidth || start > stop) I_Error("Bad R_RenderWallRange: %i to %i", start, stop); #endif sidedef = curline->sidedef; linedef = curline->linedef; // mark the segment as visible for auto map linedef->flags |= ML_MAPPED; // // calculate rw_distance for scale calculation // rw_normalangle = curline->angle + ANG90; offsetangle = abs(rw_normalangle - rw_angle1); if (offsetangle > ANG90) offsetangle = ANG90; distangle = ANG90 - offsetangle; hyp = R_PointToDist(curline->v1->x, curline->v1->y); sineval = finesine[distangle >> ANGLETOFINESHIFT]; rw_distance = FixedMul(hyp, sineval); ds_p->x1 = rw_x = start; ds_p->x2 = stop; ds_p->curline = curline; rw_stopx = stop + 1; // // calculate scale at both ends and step // ds_p->scale1 = rw_scale = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[start]); if (stop > start) { ds_p->scale2 = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[stop]); ds_p->scalestep = rw_scalestep = (ds_p->scale2 - rw_scale) / (stop - start); } else { // // try to fix the stretched line bug // #if 0 if (rw_distance < FRACUNIT / 2) { fixed_t trx, try; fixed_t gxt, gyt; trx = curline->v1->x - viewx; try = curline->v1->y - viewy; gxt = FixedMul(trx, viewcos); gyt = -FixedMul(try, viewsin); ds_p->scale1 = FixedDiv(projection, gxt - gyt); } #endif ds_p->scale2 = ds_p->scale1; } // // calculate texture boundaries and decide if floor / ceiling marks // are needed // worldtop = frontsector->ceilingheight - viewz; worldbottom = frontsector->floorheight - viewz; midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; if (!backsector) { // // single sided line // midtexture = texturetranslation[sidedef->midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; if (linedef->flags & ML_DONTPEGBOTTOM) { vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; rw_midtexturemid = vtop - viewz; // bottom of texture at bottom } else rw_midtexturemid = worldtop; // top of texture at top rw_midtexturemid += sidedef->rowoffset; ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->tsilheight = INT_MIN; } else { // // two sided line // ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; if (frontsector->floorheight > backsector->floorheight) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = frontsector->floorheight; } else if (backsector->floorheight > viewz) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT_MAX; // ds_p->sprbottomclip = negonearray; } if (frontsector->ceilingheight < backsector->ceilingheight) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = frontsector->ceilingheight; } else if (backsector->ceilingheight < viewz) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; // ds_p->sprtopclip = screenheightarray; } if (backsector->ceilingheight <= frontsector->floorheight) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (backsector->floorheight >= frontsector->ceilingheight) { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT_MIN; ds_p->silhouette |= SIL_TOP; } worldhigh = backsector->ceilingheight - viewz; worldlow = backsector->floorheight - viewz; // hack to allow height changes in outdoor areas if (frontsector->ceilingpic == skyflatnum && backsector->ceilingpic == skyflatnum) worldtop = worldhigh; if (worldlow != worldbottom || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel || backsector->special != frontsector->special) markfloor = true; else markfloor = false; // same plane on both sides if (worldhigh != worldtop || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel) markceiling = true; else markceiling = false; // same plane on both sides if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) markceiling = markfloor = true; // closed door if (worldhigh < worldtop) { // top texture toptexture = texturetranslation[sidedef->toptexture]; if (linedef->flags & ML_DONTPEGTOP) rw_toptexturemid = worldtop; // top of texture at top else { vtop = backsector->ceilingheight + textureheight[sidedef->toptexture]; rw_toptexturemid = vtop - viewz; // bottom of texture } } if (worldlow > worldbottom) { // bottom texture bottomtexture = texturetranslation[sidedef->bottomtexture]; if (linedef->flags & ML_DONTPEGBOTTOM) { // bottom of texture at bottom rw_bottomtexturemid = worldtop; // top of texture at top } else // top of texture at top rw_bottomtexturemid = worldlow; } rw_toptexturemid += sidedef->rowoffset; rw_bottomtexturemid += sidedef->rowoffset; // // allocate space for masked texture tables // if (sidedef->midtexture) { // masked midtexture maskedtexture = true; ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; lastopening += rw_stopx - rw_x; } } // // calculate rw_offset (only needed for textured lines) // segtextured = midtexture | toptexture | bottomtexture | maskedtexture; if (segtextured) { offsetangle = rw_normalangle - rw_angle1; if (offsetangle > ANG180) offsetangle = -offsetangle; if (offsetangle > ANG90) offsetangle = ANG90; sineval = finesine[offsetangle >> ANGLETOFINESHIFT]; rw_offset = FixedMul(hyp, sineval); if (rw_normalangle - rw_angle1 < ANG180) rw_offset = -rw_offset; rw_offset += sidedef->textureoffset + curline->offset; rw_centerangle = ANG90 + viewangle - rw_normalangle; // // calculate light table // use different light tables for horizontal / vertical / diagonal // OPTIMIZE: get rid of LIGHTSEGSHIFT globally if (!fixedcolormap) { lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight; //if (curline->v1->y == curline->v2->y) // lightnum--; //else if (curline->v1->x == curline->v2->x) // lightnum++; //if (lightnum < 0) // walllights = scalelight[0]; if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS - 1]; else walllights = scalelight[lightnum]; } } // // if a floor / ceiling plane is on the wrong side of the view plane // it is definately invisible and doesn't need to be marked // if (frontsector->floorheight >= viewz) markfloor = false; // above view plane if (frontsector->ceilingheight <= viewz && frontsector->ceilingpic != skyflatnum) markceiling = false; // below view plane // // calculate incremental stepping values for texture edges // worldtop >>= 4; worldbottom >>= 4; topstep = -FixedMul(rw_scalestep, worldtop); topfrac = (centeryfrac >> 4) - FixedMul(worldtop, rw_scale); bottomstep = -FixedMul(rw_scalestep, worldbottom); bottomfrac = (centeryfrac >> 4) - FixedMul(worldbottom, rw_scale); if (backsector) { worldhigh >>= 4; worldlow >>= 4; if (worldhigh < worldtop) { pixhigh = (centeryfrac >> 4) - FixedMul(worldhigh, rw_scale); pixhighstep = -FixedMul(rw_scalestep, worldhigh); } if (worldlow > worldbottom) { pixlow = (centeryfrac >> 4) - FixedMul(worldlow, rw_scale); pixlowstep = -FixedMul(rw_scalestep, worldlow); } } // // render it // if (markceiling) ceilingplane = R_CheckPlane(ceilingplane, rw_x, rw_stopx - 1); if (markfloor) floorplane = R_CheckPlane(floorplane, rw_x, rw_stopx - 1); R_RenderSegLoop(); // // save sprite clipping info // if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) { memcpy(lastopening, ceilingclip + start, 2 * (rw_stopx - start)); ds_p->sprtopclip = lastopening - start; lastopening += rw_stopx - start; } if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) { memcpy(lastopening, floorclip + start, 2 * (rw_stopx - start)); ds_p->sprbottomclip = lastopening - start; lastopening += rw_stopx - start; } if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; } if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; ds_p->bsilheight = INT_MAX; } ds_p++; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/r_things.c000066400000000000000000000635521257432200600231770ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "h2def.h" #include "i_system.h" #include "i_swap.h" #include "r_local.h" //void R_DrawTranslatedAltTLColumn(void); typedef struct { int x1, x2; int column; int topclip; int bottomclip; } maskdraw_t; /* Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn CLOCKWISE around the axis. This is not the same as the angle, which increases counter clockwise (protractor). There was a lot of stuff grabbed wrong, so I changed it... */ fixed_t pspritescale, pspriteiscale; lighttable_t **spritelights; // constant arrays used for psprite clipping and initializing clipping short negonearray[SCREENWIDTH]; short screenheightarray[SCREENWIDTH]; boolean LevelUseFullBright; /* =============================================================================== INITIALIZATION FUNCTIONS =============================================================================== */ // variables used to look up and range check thing_t sprites patches spritedef_t *sprites; int numsprites; spriteframe_t sprtemp[30]; int maxframe; char *spritename; /* ================= = = R_InstallSpriteLump = = Local function for R_InitSprites ================= */ void R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation, boolean flipped) { int r; if (frame >= 30 || rotation > 8) I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump); if ((int) frame > maxframe) maxframe = frame; if (rotation == 0) { // the lump should be used for all rotations if (sprtemp[frame].rotate == false) I_Error("R_InitSprites: Sprite %s frame %c has multip rot=0 lump", spritename, 'A' + frame); if (sprtemp[frame].rotate == true) I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump", spritename, 'A' + frame); sprtemp[frame].rotate = false; for (r = 0; r < 8; r++) { sprtemp[frame].lump[r] = lump - firstspritelump; sprtemp[frame].flip[r] = (byte) flipped; } return; } // the lump is only used for one rotation if (sprtemp[frame].rotate == false) I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump", spritename, 'A' + frame); sprtemp[frame].rotate = true; rotation--; // make 0 based if (sprtemp[frame].lump[rotation] != -1) I_Error ("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it", spritename, 'A' + frame, '1' + rotation); sprtemp[frame].lump[rotation] = lump - firstspritelump; sprtemp[frame].flip[rotation] = (byte) flipped; } /* ================= = = R_InitSpriteDefs = = Pass a null terminated list of sprite names (4 chars exactly) to be used = Builds the sprite rotation matrixes to account for horizontally flipped = sprites. Will report an error if the lumps are inconsistant =Only called at startup = = Sprite lump names are 4 characters for the actor, a letter for the frame, = and a number for the rotation, A sprite that is flippable will have an = additional letter/number appended. The rotation character can be 0 to = signify no rotations ================= */ void R_InitSpriteDefs(char **namelist) { char **check; int i, l, frame, rotation; int start, end; // count the number of sprite names check = namelist; while (*check != NULL) check++; numsprites = check - namelist; if (!numsprites) return; sprites = Z_Malloc(numsprites * sizeof(*sprites), PU_STATIC, NULL); start = firstspritelump - 1; end = lastspritelump + 1; // scan all the lump names for each of the names, noting the highest // frame letter // Just compare 4 characters as ints for (i = 0; i < numsprites; i++) { spritename = namelist[i]; memset(sprtemp, -1, sizeof(sprtemp)); maxframe = -1; // // scan the lumps, filling in the frames for whatever is found // for (l = start + 1; l < end; l++) if (!strncmp(lumpinfo[l].name, namelist[i], 4)) { frame = lumpinfo[l].name[4] - 'A'; rotation = lumpinfo[l].name[5] - '0'; R_InstallSpriteLump(l, frame, rotation, false); if (lumpinfo[l].name[6]) { frame = lumpinfo[l].name[6] - 'A'; rotation = lumpinfo[l].name[7] - '0'; R_InstallSpriteLump(l, frame, rotation, true); } } // // check the frames that were found for completeness // if (maxframe == -1) { //continue; sprites[i].numframes = 0; if (gamemode == shareware) continue; I_Error("R_InitSprites: No lumps found for sprite %s", namelist[i]); } maxframe++; for (frame = 0; frame < maxframe; frame++) { switch ((int) sprtemp[frame].rotate) { case -1: // no rotations were found for that frame at all I_Error("R_InitSprites: No patches found for %s frame %c", namelist[i], frame + 'A'); case 0: // only the first rotation is needed break; case 1: // must have all 8 frames for (rotation = 0; rotation < 8; rotation++) if (sprtemp[frame].lump[rotation] == -1) I_Error ("R_InitSprites: Sprite %s frame %c is missing rotations", namelist[i], frame + 'A'); } } // // allocate space for the frames present and copy sprtemp to it // sprites[i].numframes = maxframe; sprites[i].spriteframes = Z_Malloc(maxframe * sizeof(spriteframe_t), PU_STATIC, NULL); memcpy(sprites[i].spriteframes, sprtemp, maxframe * sizeof(spriteframe_t)); } } /* =============================================================================== GAME FUNCTIONS =============================================================================== */ vissprite_t vissprites[MAXVISSPRITES], *vissprite_p; int newvissprite; /* =================== = = R_InitSprites = = Called at program start =================== */ void R_InitSprites(char **namelist) { int i; for (i = 0; i < SCREENWIDTH; i++) { negonearray[i] = -1; } R_InitSpriteDefs(namelist); } /* =================== = = R_ClearSprites = = Called at frame start =================== */ void R_ClearSprites(void) { vissprite_p = vissprites; } /* =================== = = R_NewVisSprite = =================== */ vissprite_t overflowsprite; vissprite_t *R_NewVisSprite(void) { if (vissprite_p == &vissprites[MAXVISSPRITES]) return &overflowsprite; vissprite_p++; return vissprite_p - 1; } /* ================ = = R_DrawMaskedColumn = = Used for sprites and masked mid textures ================ */ short *mfloorclip; short *mceilingclip; fixed_t spryscale; fixed_t sprtopscreen; fixed_t sprbotscreen; void R_DrawMaskedColumn(column_t * column, signed int baseclip) { int topscreen, bottomscreen; fixed_t basetexturemid; basetexturemid = dc_texturemid; for (; column->topdelta != 0xff;) { // calculate unclipped screen coordinates for post topscreen = sprtopscreen + spryscale * column->topdelta; bottomscreen = topscreen + spryscale * column->length; dc_yl = (topscreen + FRACUNIT - 1) >> FRACBITS; dc_yh = (bottomscreen - 1) >> FRACBITS; if (dc_yh >= mfloorclip[dc_x]) dc_yh = mfloorclip[dc_x] - 1; if (dc_yl <= mceilingclip[dc_x]) dc_yl = mceilingclip[dc_x] + 1; if (dc_yh >= baseclip && baseclip != -1) dc_yh = baseclip; if (dc_yl <= dc_yh) { dc_source = (byte *) column + 3; dc_texturemid = basetexturemid - (column->topdelta << FRACBITS); // dc_source = (byte *)column + 3 - column->topdelta; colfunc(); // either R_DrawColumn or R_DrawTLColumn } column = (column_t *) ((byte *) column + column->length + 4); } dc_texturemid = basetexturemid; } /* ================ = = R_DrawVisSprite = = mfloorclip and mceilingclip should also be set ================ */ void R_DrawVisSprite(vissprite_t * vis, int x1, int x2) { column_t *column; int texturecolumn; fixed_t frac; patch_t *patch; fixed_t baseclip; patch = W_CacheLumpNum(vis->patch + firstspritelump, PU_CACHE); dc_colormap = vis->colormap; // if(!dc_colormap) // colfunc = tlcolfunc; // NULL colormap = shadow draw if (vis->mobjflags & (MF_SHADOW | MF_ALTSHADOW)) { if (vis->mobjflags & MF_TRANSLATION) { colfunc = R_DrawTranslatedTLColumn; dc_translation = translationtables - 256 + vis->class * ((maxplayers - 1) * 256) + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8)); } else if (vis->mobjflags & MF_SHADOW) { // Draw using shadow column function colfunc = tlcolfunc; } else { colfunc = R_DrawAltTLColumn; } } else if (vis->mobjflags & MF_TRANSLATION) { // Draw using translated column function colfunc = R_DrawTranslatedColumn; dc_translation = translationtables - 256 + vis->class * ((maxplayers - 1) * 256) + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8)); } dc_iscale = abs(vis->xiscale) >> detailshift; dc_texturemid = vis->texturemid; frac = vis->startfrac; spryscale = vis->scale; sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); // check to see if vissprite is a weapon if (vis->psprite) { dc_texturemid += FixedMul(((centery - viewheight / 2) << FRACBITS), vis->xiscale); sprtopscreen += (viewheight / 2 - centery) << FRACBITS; } if (vis->floorclip && !vis->psprite) { sprbotscreen = sprtopscreen + FixedMul(SHORT(patch->height) << FRACBITS, spryscale); baseclip = (sprbotscreen - FixedMul(vis->floorclip, spryscale)) >> FRACBITS; } else { baseclip = -1; } for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) { texturecolumn = frac >> FRACBITS; #ifdef RANGECHECK if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) I_Error("R_DrawSpriteRange: bad texturecolumn"); #endif column = (column_t *) ((byte *) patch + LONG(patch->columnofs[texturecolumn])); R_DrawMaskedColumn(column, baseclip); } colfunc = basecolfunc; } /* =================== = = R_ProjectSprite = = Generates a vissprite for a thing if it might be visible = =================== */ void R_ProjectSprite(mobj_t * thing) { fixed_t trx, try; fixed_t gxt, gyt; fixed_t tx, tz; fixed_t xscale; int x1, x2; spritedef_t *sprdef; spriteframe_t *sprframe; int lump; unsigned rot; boolean flip; int index; vissprite_t *vis; angle_t ang; fixed_t iscale; if (thing->flags2 & MF2_DONTDRAW) { // Never make a vissprite when MF2_DONTDRAW is flagged. return; } // // transform the origin point // trx = thing->x - viewx; try = thing->y - viewy; gxt = FixedMul(trx, viewcos); gyt = -FixedMul(try, viewsin); tz = gxt - gyt; if (tz < MINZ) return; // thing is behind view plane xscale = FixedDiv(projection, tz); gxt = -FixedMul(trx, viewsin); gyt = FixedMul(try, viewcos); tx = -(gyt + gxt); if (abs(tx) > (tz << 2)) return; // too far off the side // // decide which patch to use for sprite reletive to player // #ifdef RANGECHECK if ((unsigned) thing->sprite >= numsprites) I_Error("R_ProjectSprite: invalid sprite number %i ", thing->sprite); #endif sprdef = &sprites[thing->sprite]; #ifdef RANGECHECK if ((thing->frame & FF_FRAMEMASK) >= sprdef->numframes) I_Error("R_ProjectSprite: invalid sprite frame %i : %i ", thing->sprite, thing->frame); #endif sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; if (sprframe->rotate) { // choose a different rotation based on player view ang = R_PointToAngle(thing->x, thing->y); rot = (ang - thing->angle + (unsigned) (ANG45 / 2) * 9) >> 29; lump = sprframe->lump[rot]; flip = (boolean) sprframe->flip[rot]; } else { // use single rotation for all views lump = sprframe->lump[0]; flip = (boolean) sprframe->flip[0]; } // // calculate edges of the shape // tx -= spriteoffset[lump]; x1 = (centerxfrac + FixedMul(tx, xscale)) >> FRACBITS; if (x1 > viewwidth) return; // off the right side tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul(tx, xscale)) >> FRACBITS) - 1; if (x2 < 0) return; // off the left side // // store information in a vissprite // vis = R_NewVisSprite(); vis->mobjflags = thing->flags; vis->psprite = false; vis->scale = xscale << detailshift; vis->gx = thing->x; vis->gy = thing->y; vis->gz = thing->z; vis->gzt = thing->z + spritetopoffset[lump]; if (thing->flags & MF_TRANSLATION) { if (thing->player) { vis->class = thing->player->class; } else { vis->class = thing->special1.i; } if (vis->class > 2) { vis->class = 0; } } // foot clipping vis->floorclip = thing->floorclip; vis->texturemid = vis->gzt - viewz - vis->floorclip; vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2; iscale = FixedDiv(FRACUNIT, xscale); if (flip) { vis->startfrac = spritewidth[lump] - 1; vis->xiscale = -iscale; } else { vis->startfrac = 0; vis->xiscale = iscale; } if (vis->x1 > x1) vis->startfrac += vis->xiscale * (vis->x1 - x1); vis->patch = lump; // // get light level // // if (thing->flags & MF_SHADOW) // vis->colormap = NULL; // shadow draw // else ... if (fixedcolormap) vis->colormap = fixedcolormap; // fixed map else if (LevelUseFullBright && thing->frame & FF_FULLBRIGHT) vis->colormap = colormaps; // full bright else { // diminished light index = xscale >> (LIGHTSCALESHIFT - detailshift); if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1; vis->colormap = spritelights[index]; } } /* ======================== = = R_AddSprites = ======================== */ void R_AddSprites(sector_t * sec) { mobj_t *thing; int lightnum; if (sec->validcount == validcount) return; // already added sec->validcount = validcount; lightnum = (sec->lightlevel >> LIGHTSEGSHIFT) + extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS - 1]; else spritelights = scalelight[lightnum]; for (thing = sec->thinglist; thing; thing = thing->snext) R_ProjectSprite(thing); } /* ======================== = = R_DrawPSprite = ======================== */ // Y-adjustment values for full screen (4 weapons) int PSpriteSY[NUMCLASSES][NUMWEAPONS] = { {0, -12 * FRACUNIT, -10 * FRACUNIT, 10 * FRACUNIT}, // Fighter {-8 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT, 0}, // Cleric {9 * FRACUNIT, 20 * FRACUNIT, 20 * FRACUNIT, 20 * FRACUNIT}, // Mage {10 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT} // Pig }; void R_DrawPSprite(pspdef_t * psp) { fixed_t tx; int x1, x2; spritedef_t *sprdef; spriteframe_t *sprframe; int lump; boolean flip; vissprite_t *vis, avis; int tempangle; // // decide which patch to use // #ifdef RANGECHECK if ((unsigned) psp->state->sprite >= numsprites) I_Error("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite); #endif sprdef = &sprites[psp->state->sprite]; #ifdef RANGECHECK if ((psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) I_Error("R_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame); #endif sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK]; lump = sprframe->lump[0]; flip = (boolean) sprframe->flip[0]; // // calculate edges of the shape // tx = psp->sx - 160 * FRACUNIT; tx -= spriteoffset[lump]; if (viewangleoffset) { tempangle = ((centerxfrac / 1024) * (viewangleoffset >> ANGLETOFINESHIFT)); } else { tempangle = 0; } x1 = (centerxfrac + FixedMul(tx, pspritescale) + tempangle) >> FRACBITS; if (x1 > viewwidth) return; // off the right side tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul(tx, pspritescale) + tempangle) >> FRACBITS) - 1; if (x2 < 0) return; // off the left side // // store information in a vissprite // vis = &avis; vis->mobjflags = 0; vis->class = 0; vis->psprite = true; vis->texturemid = (BASEYCENTER << FRACBITS) + FRACUNIT / 2 - (psp->sy - spritetopoffset[lump]); if (viewheight == SCREENHEIGHT) { vis->texturemid -= PSpriteSY[viewplayer->class] [players[consoleplayer].readyweapon]; } vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2; vis->scale = pspritescale << detailshift; if (flip) { vis->xiscale = -pspriteiscale; vis->startfrac = spritewidth[lump] - 1; } else { vis->xiscale = pspriteiscale; vis->startfrac = 0; } if (vis->x1 > x1) vis->startfrac += vis->xiscale * (vis->x1 - x1); vis->patch = lump; if (viewplayer->powers[pw_invulnerability] && viewplayer->class == PCLASS_CLERIC) { vis->colormap = spritelights[MAXLIGHTSCALE - 1]; if (viewplayer->powers[pw_invulnerability] > 4 * 32) { if (viewplayer->mo->flags2 & MF2_DONTDRAW) { // don't draw the psprite vis->mobjflags |= MF_SHADOW; } else if (viewplayer->mo->flags & MF_SHADOW) { vis->mobjflags |= MF_ALTSHADOW; } } else if (viewplayer->powers[pw_invulnerability] & 8) { vis->mobjflags |= MF_SHADOW; } } else if (fixedcolormap) { // Fixed color vis->colormap = fixedcolormap; } else if (psp->state->frame & FF_FULLBRIGHT) { // Full bright vis->colormap = colormaps; } else { // local light vis->colormap = spritelights[MAXLIGHTSCALE - 1]; } R_DrawVisSprite(vis, vis->x1, vis->x2); } /* ======================== = = R_DrawPlayerSprites = ======================== */ void R_DrawPlayerSprites(void) { int i, lightnum; pspdef_t *psp; // // get light level // lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) + extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS - 1]; else spritelights = scalelight[lightnum]; // // clip to screen bounds // mfloorclip = screenheightarray; mceilingclip = negonearray; // // add all active psprites // for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; i++, psp++) if (psp->state) R_DrawPSprite(psp); } /* ======================== = = R_SortVisSprites = ======================== */ vissprite_t vsprsortedhead; void R_SortVisSprites(void) { int i, count; vissprite_t *ds, *best; vissprite_t unsorted; fixed_t bestscale; count = vissprite_p - vissprites; unsorted.next = unsorted.prev = &unsorted; if (!count) return; for (ds = vissprites; ds < vissprite_p; ds++) { ds->next = ds + 1; ds->prev = ds - 1; } vissprites[0].prev = &unsorted; unsorted.next = &vissprites[0]; (vissprite_p - 1)->next = &unsorted; unsorted.prev = vissprite_p - 1; // // pull the vissprites out by scale // best = 0; // shut up the compiler warning vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; for (i = 0; i < count; i++) { bestscale = INT_MAX; for (ds = unsorted.next; ds != &unsorted; ds = ds->next) { if (ds->scale < bestscale) { bestscale = ds->scale; best = ds; } } best->next->prev = best->prev; best->prev->next = best->next; best->next = &vsprsortedhead; best->prev = vsprsortedhead.prev; vsprsortedhead.prev->next = best; vsprsortedhead.prev = best; } } /* ======================== = = R_DrawSprite = ======================== */ void R_DrawSprite(vissprite_t * spr) { drawseg_t *ds; short clipbot[SCREENWIDTH], cliptop[SCREENWIDTH]; int x, r1, r2; fixed_t scale, lowscale; int silhouette; for (x = spr->x1; x <= spr->x2; x++) clipbot[x] = cliptop[x] = -2; // // scan drawsegs from end to start for obscuring segs // the first drawseg that has a greater scale is the clip seg // for (ds = ds_p - 1; ds >= drawsegs; ds--) { // // determine if the drawseg obscures the sprite // if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || (!ds->silhouette && !ds->maskedtexturecol)) continue; // doesn't cover sprite r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; if (ds->scale1 > ds->scale2) { lowscale = ds->scale2; scale = ds->scale1; } else { lowscale = ds->scale1; scale = ds->scale2; } if (scale < spr->scale || (lowscale < spr->scale && !R_PointOnSegSide(spr->gx, spr->gy, ds->curline))) { if (ds->maskedtexturecol) // masked mid texture R_RenderMaskedSegRange(ds, r1, r2); continue; // seg is behind sprite } // // clip this piece of the sprite // silhouette = ds->silhouette; if (spr->gz >= ds->bsilheight) silhouette &= ~SIL_BOTTOM; if (spr->gzt <= ds->tsilheight) silhouette &= ~SIL_TOP; if (silhouette == 1) { // bottom sil for (x = r1; x <= r2; x++) if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; } else if (silhouette == 2) { // top sil for (x = r1; x <= r2; x++) if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } else if (silhouette == 3) { // both for (x = r1; x <= r2; x++) { if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } } } // // all clipping has been performed, so draw the sprite // // check for unclipped columns for (x = spr->x1; x <= spr->x2; x++) { if (clipbot[x] == -2) clipbot[x] = viewheight; if (cliptop[x] == -2) cliptop[x] = -1; } mfloorclip = clipbot; mceilingclip = cliptop; R_DrawVisSprite(spr, spr->x1, spr->x2); } /* ======================== = = R_DrawMasked = ======================== */ void R_DrawMasked(void) { vissprite_t *spr; drawseg_t *ds; R_SortVisSprites(); if (vissprite_p > vissprites) { // draw all vissprites back to front for (spr = vsprsortedhead.next; spr != &vsprsortedhead; spr = spr->next) R_DrawSprite(spr); } // // render any remaining masked mid textures // for (ds = ds_p - 1; ds >= drawsegs; ds--) if (ds->maskedtexturecol) R_RenderMaskedSegRange(ds, ds->x1, ds->x2); // // draw the psprites on top of everything // // Added for the sideviewing with an external device if (viewangleoffset <= 1024 << ANGLETOFINESHIFT || viewangleoffset >= -1024 << ANGLETOFINESHIFT) { // don't draw on side views R_DrawPlayerSprites(); } // if (!viewangleoffset) // don't draw on side views // R_DrawPlayerSprites (); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/s_sound.c000066400000000000000000000575171257432200600230400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "m_random.h" #include "i_cdmus.h" #include "i_sound.h" #include "i_system.h" #include "i_timer.h" #include "m_argv.h" #include "m_misc.h" #include "r_local.h" #include "p_local.h" // for P_AproxDistance #include "sounds.h" #include "s_sound.h" #define PRIORITY_MAX_ADJUST 10 #define DIST_ADJUST (MAX_SND_DIST/PRIORITY_MAX_ADJUST) #define DEFAULT_ARCHIVEPATH "o:\\sound\\archive\\" void S_ShutDown(void); // If true, CD music playback is enabled (snd_musicdevice == SNDDEVICE_CD // and CD initialization succeeded). boolean cdmusic; // Track number of a track to play explicitly chosen by the // player using cheats. A value of zero means no track chosen: static int cd_custom_track = 0; // Currently playing track: static int cd_current_track = 0; // Time (MS) at which the currently-playing CD track will finish playing // and should be looped. Zero if we are not currently playing a track: static int cd_track_end_time = 0; /* =============================================================================== MUSIC & SFX API =============================================================================== */ //static channel_t channel[MAX_CHANNELS]; //static int rs; //the current registered song. //int mus_song = -1; //int mus_lumpnum; //void *mus_sndptr; //byte *soundCurve; extern sfxinfo_t S_sfx[]; extern musicinfo_t S_music[]; static channel_t Channel[MAX_CHANNELS]; static void *RegisteredSong; //the current registered song. static boolean MusicPaused; static int Mus_Song = -1; static byte *Mus_SndPtr; static byte *SoundCurve; int snd_MaxVolume = 10; // maximum volume for sound int snd_MusicVolume = 10; // maximum volume for music int snd_Channels = 16; // int AmbChan; //========================================================================== // // S_Start // //========================================================================== void S_Start(void) { S_StopAllSound(); S_StartSong(gamemap, true); } //========================================================================== // // Returns true if we are playing a looping CD track and it is time to // restart it. // //========================================================================== static boolean ShouldRestartCDTrack(void) { return cd_track_end_time != 0 && I_GetTimeMS() > cd_track_end_time; } //========================================================================== // // Start playing a CD track. Returns true for success. // //========================================================================== static boolean StartCDTrack(int track, boolean loop) { // Already playing? If so, don't bother. if (track == cd_current_track && !ShouldRestartCDTrack()) { return true; } if (I_CDMusPlay(track)) { return false; } cd_current_track = track; if (loop) { cd_track_end_time = I_GetTimeMS() + 1000 * I_CDMusTrackLength(track); } else { cd_track_end_time = 0; } return true; } //========================================================================== // // S_StartSong // //========================================================================== void S_StartSong(int song, boolean loop) { char *songLump; int lumpnum; int length; int track; // If we're in CD music mode, play a CD track, instead: if (cdmusic) { // Default to the player-chosen track if (cd_custom_track != 0) { track = cd_custom_track; } else { track = P_GetMapCDTrack(gamemap); } StartCDTrack(track, loop); } else { if (song == Mus_Song) { // don't replay an old song return; } if (RegisteredSong) { I_StopSong(); I_UnRegisterSong(RegisteredSong); RegisteredSong = 0; } songLump = P_GetMapSongLump(song); if (!songLump) { return; } lumpnum = W_GetNumForName(songLump); Mus_SndPtr = W_CacheLumpNum(lumpnum, PU_STATIC); length = W_LumpLength(lumpnum); RegisteredSong = I_RegisterSong(Mus_SndPtr, length); I_PlaySong(RegisteredSong, loop); Mus_Song = song; W_ReleaseLumpNum(lumpnum); } } //========================================================================== // // Play a custom-chosen music track selected by the player. // // Returns true for success. // //========================================================================== boolean S_StartCustomCDTrack(int tracknum) { boolean result; result = StartCDTrack(tracknum, true); if (result) { cd_custom_track = tracknum; } return result; } //========================================================================== // // Get the currently-playing CD track; returns -1 if not playing. // //========================================================================== int S_GetCurrentCDTrack(void) { if (!cdmusic || cd_current_track == 0) { return -1; } return cd_current_track; } //========================================================================== // // S_StartSongName // //========================================================================== void S_StartSongName(char *songLump, boolean loop) { int lumpnum; int cdTrack; int length; if (!songLump) { return; } if (cdmusic) { cdTrack = 0; if (!strcmp(songLump, "hexen")) { cdTrack = P_GetCDTitleTrack(); } else if (!strcmp(songLump, "hub")) { cdTrack = P_GetCDIntermissionTrack(); } else if (!strcmp(songLump, "hall")) { cdTrack = P_GetCDEnd1Track(); } else if (!strcmp(songLump, "orb")) { cdTrack = P_GetCDEnd2Track(); } else if (!strcmp(songLump, "chess") && cd_custom_track == 0) { cdTrack = P_GetCDEnd3Track(); } /* Uncomment this, if Kevin writes a specific song for startup else if(!strcmp(songLump, "start")) { cdTrack = P_GetCDStartTrack(); } */ if (cdTrack != 0) { cd_custom_track = 0; StartCDTrack(cdTrack, loop); } } else { if (RegisteredSong) { I_StopSong(); I_UnRegisterSong(RegisteredSong); RegisteredSong = NULL; } lumpnum = W_GetNumForName(songLump); Mus_SndPtr = W_CacheLumpNum(lumpnum, PU_MUSIC); length = W_LumpLength(lumpnum); RegisteredSong = I_RegisterSong(Mus_SndPtr, length); I_PlaySong(RegisteredSong, loop); W_ReleaseLumpNum(lumpnum); Mus_Song = -1; } } //========================================================================== // // S_GetSoundID // //========================================================================== int S_GetSoundID(char *name) { int i; for (i = 0; i < NUMSFX; i++) { if (!strcmp(S_sfx[i].tagname, name)) { return i; } } return 0; } //========================================================================== // // S_StartSound // //========================================================================== void S_StartSound(mobj_t * origin, int sound_id) { S_StartSoundAtVolume(origin, sound_id, 127); } static mobj_t *GetSoundListener(void) { static degenmobj_t dummy_listener; // If we are at the title screen, the console player doesn't have an // object yet, so return a pointer to a static dummy listener instead. if (players[displayplayer].mo != NULL) { return players[displayplayer].mo; } else { dummy_listener.x = 0; dummy_listener.y = 0; dummy_listener.z = 0; return (mobj_t *) &dummy_listener; } } //========================================================================== // // S_StartSoundAtVolume // //========================================================================== void S_StartSoundAtVolume(mobj_t * origin, int sound_id, int volume) { mobj_t *listener; int dist, vol; int i; int priority; int sep; int angle; int absx; int absy; static int sndcount = 0; int chan; if (sound_id == 0 || snd_MaxVolume == 0) return; listener = GetSoundListener(); if (origin == NULL) { origin = listener; } if (volume == 0) { return; } // calculate the distance before other stuff so that we can throw out // sounds that are beyond the hearing range. absx = abs(origin->x - listener->x); absy = abs(origin->y - listener->y); dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1); dist >>= FRACBITS; if (dist >= MAX_SND_DIST) { return; // sound is beyond the hearing range... } if (dist < 0) { dist = 0; } priority = S_sfx[sound_id].priority; priority *= (PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST)); #if 0 // TODO if (!S_StopSoundID(sound_id, priority)) { return; // other sounds have greater priority } #endif for (i = 0; i < snd_Channels; i++) { if (origin->player) { i = snd_Channels; break; // let the player have more than one sound. } if (origin == Channel[i].mo) { // only allow other mobjs one sound S_StopSound(Channel[i].mo); break; } } if (i >= snd_Channels) { for (i = 0; i < snd_Channels; i++) { if (Channel[i].mo == NULL) { break; } } if (i >= snd_Channels) { // look for a lower priority sound to replace. sndcount++; if (sndcount >= snd_Channels) { sndcount = 0; } for (chan = 0; chan < snd_Channels; chan++) { i = (sndcount + chan) % snd_Channels; if (priority >= Channel[i].priority) { chan = -1; //denote that sound should be replaced. break; } } if (chan != -1) { return; //no free channels. } else //replace the lower priority sound. { if (Channel[i].handle) { if (I_SoundIsPlaying(Channel[i].handle)) { I_StopSound(Channel[i].handle); } if (S_sfx[Channel[i].sound_id].usefulness > 0) { S_sfx[Channel[i].sound_id].usefulness--; } } } } } Channel[i].mo = origin; vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * volume) >> 14; if (origin == listener) { sep = 128; // vol = (volume*(snd_MaxVolume+1)*8)>>7; } else { angle = R_PointToAngle2(listener->x, listener->y, Channel[i].mo->x, Channel[i].mo->y); angle = (angle - viewangle) >> 24; sep = angle * 2 - 128; if (sep < 64) sep = -sep; if (sep > 192) sep = 512 - sep; // vol = SoundCurve[dist]; } #if 0 // TODO if (S_sfx[sound_id].changePitch) { Channel[i].pitch = (byte) (127 + (M_Random() & 7) - (M_Random() & 7)); } else { Channel[i].pitch = 127; } #endif if (S_sfx[sound_id].lumpnum == 0) { S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]); } Channel[i].handle = I_StartSound(&S_sfx[sound_id], i, vol, sep /* , Channel[i].pitch] */); Channel[i].sound_id = sound_id; Channel[i].priority = priority; Channel[i].volume = volume; if (S_sfx[sound_id].usefulness < 0) { S_sfx[sound_id].usefulness = 1; } else { S_sfx[sound_id].usefulness++; } } //========================================================================== // // S_StopSoundID // //========================================================================== boolean S_StopSoundID(int sound_id, int priority) { int i; int lp; //least priority int found; if (S_sfx[sound_id].numchannels == -1) { return (true); } lp = -1; //denote the argument sound_id found = 0; for (i = 0; i < snd_Channels; i++) { if (Channel[i].sound_id == sound_id && Channel[i].mo) { found++; //found one. Now, should we replace it?? if (priority >= Channel[i].priority) { // if we're gonna kill one, then this'll be it lp = i; priority = Channel[i].priority; } } } if (found < S_sfx[sound_id].numchannels) { return (true); } else if (lp == -1) { return (false); // don't replace any sounds } if (Channel[lp].handle) { if (I_SoundIsPlaying(Channel[lp].handle)) { I_StopSound(Channel[lp].handle); } if (S_sfx[Channel[lp].sound_id].usefulness > 0) { S_sfx[Channel[lp].sound_id].usefulness--; } Channel[lp].mo = NULL; } return (true); } //========================================================================== // // S_StopSound // //========================================================================== void S_StopSound(mobj_t * origin) { int i; for (i = 0; i < snd_Channels; i++) { if (Channel[i].mo == origin) { I_StopSound(Channel[i].handle); if (S_sfx[Channel[i].sound_id].usefulness > 0) { S_sfx[Channel[i].sound_id].usefulness--; } Channel[i].handle = 0; Channel[i].mo = NULL; } } } //========================================================================== // // S_StopAllSound // //========================================================================== void S_StopAllSound(void) { int i; //stop all sounds for (i = 0; i < snd_Channels; i++) { if (Channel[i].handle) { S_StopSound(Channel[i].mo); } } memset(Channel, 0, 8 * sizeof(channel_t)); } //========================================================================== // // S_SoundLink // //========================================================================== void S_SoundLink(mobj_t * oldactor, mobj_t * newactor) { int i; for (i = 0; i < snd_Channels; i++) { if (Channel[i].mo == oldactor) Channel[i].mo = newactor; } } //========================================================================== // // S_PauseSound // //========================================================================== void S_PauseSound(void) { if (cdmusic) { I_CDMusStop(); } else { I_PauseSong(); } } //========================================================================== // // S_ResumeSound // //========================================================================== void S_ResumeSound(void) { if (cdmusic) { I_CDMusResume(); } else { I_ResumeSong(); } } //========================================================================== // // S_UpdateSounds // //========================================================================== void S_UpdateSounds(mobj_t * listener) { int i, dist, vol; int angle; int sep; int priority; int absx; int absy; I_UpdateSound(); // If we are looping a CD track, we need to check if it has // finished playing and needs to restart. if (cdmusic && ShouldRestartCDTrack()) { StartCDTrack(cd_current_track, true); } if (snd_MaxVolume == 0) { return; } // Update any Sequences SN_UpdateActiveSequences(); for (i = 0; i < snd_Channels; i++) { if (!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1) { continue; } if (!I_SoundIsPlaying(Channel[i].handle)) { if (S_sfx[Channel[i].sound_id].usefulness > 0) { S_sfx[Channel[i].sound_id].usefulness--; } Channel[i].handle = 0; Channel[i].mo = NULL; Channel[i].sound_id = 0; } if (Channel[i].mo == NULL || Channel[i].sound_id == 0 || Channel[i].mo == listener || listener == NULL) { continue; } else { absx = abs(Channel[i].mo->x - listener->x); absy = abs(Channel[i].mo->y - listener->y); dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1); dist >>= FRACBITS; if (dist >= MAX_SND_DIST) { S_StopSound(Channel[i].mo); continue; } if (dist < 0) { dist = 0; } //vol = SoundCurve[dist]; vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * Channel[i].volume) >> 14; if (Channel[i].mo == listener) { sep = 128; } else { angle = R_PointToAngle2(listener->x, listener->y, Channel[i].mo->x, Channel[i].mo->y); angle = (angle - viewangle) >> 24; sep = angle * 2 - 128; if (sep < 64) sep = -sep; if (sep > 192) sep = 512 - sep; } I_UpdateSoundParams(i, vol, sep /*, Channel[i].pitch */); priority = S_sfx[Channel[i].sound_id].priority; priority *= PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST); Channel[i].priority = priority; } } } //========================================================================== // // S_Init // //========================================================================== void S_Init(void) { I_SetOPLDriverVer(opl_v_old); SoundCurve = W_CacheLumpName("SNDCURVE", PU_STATIC); // SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL); if (snd_Channels > 8) { snd_Channels = 8; } I_SetMusicVolume(snd_MusicVolume * 8); I_AtExit(S_ShutDown, true); I_PrecacheSounds(S_sfx, NUMSFX); // Attempt to setup CD music if (snd_musicdevice == SNDDEVICE_CD) { ST_Message(" Attempting to initialize CD Music: "); if (!cdrom) { cdmusic = (I_CDMusInit() != -1); } else { // The user is trying to use the cdrom for both game and music cdmusic = false; } if (cdmusic) { ST_Message("initialized.\n"); } else { ST_Message("failed.\n"); } I_CDMusPrintStartup(); } } //========================================================================== // // S_GetChannelInfo // //========================================================================== void S_GetChannelInfo(SoundInfo_t * s) { int i; ChanInfo_t *c; s->channelCount = snd_Channels; s->musicVolume = snd_MusicVolume; s->soundVolume = snd_MaxVolume; for (i = 0; i < snd_Channels; i++) { c = &s->chan[i]; c->id = Channel[i].sound_id; c->priority = Channel[i].priority; c->name = S_sfx[c->id].name; c->mo = Channel[i].mo; if (c->mo != NULL) { c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy) >> FRACBITS; } else { c->distance = 0; } } } //========================================================================== // // S_GetSoundPlayingInfo // //========================================================================== boolean S_GetSoundPlayingInfo(mobj_t * mobj, int sound_id) { int i; for (i = 0; i < snd_Channels; i++) { if (Channel[i].sound_id == sound_id && Channel[i].mo == mobj) { if (I_SoundIsPlaying(Channel[i].handle)) { return true; } } } return false; } //========================================================================== // // S_SetMusicVolume // //========================================================================== void S_SetMusicVolume(void) { if (cdmusic) { I_CDMusSetVolume(snd_MusicVolume * 16); // 0-255 } else { I_SetMusicVolume(snd_MusicVolume * 8); } if (snd_MusicVolume == 0) { if (!cdmusic) { I_PauseSong(); } MusicPaused = true; } else if (MusicPaused) { if (!cdmusic) { I_ResumeSong(); } MusicPaused = false; } } //========================================================================== // // S_ShutDown // //========================================================================== void S_ShutDown(void) { I_StopSong(); I_UnRegisterSong(RegisteredSong); I_ShutdownSound(); if (cdmusic) { I_CDMusStop(); } } //========================================================================== // // S_InitScript // //========================================================================== void S_InitScript(void) { int i; SC_OpenLump("sndinfo"); while (SC_GetString()) { if (*sc_String == '$') { if (!strcasecmp(sc_String, "$ARCHIVEPATH")) { SC_MustGetString(); } else if (!strcasecmp(sc_String, "$MAP")) { SC_MustGetNumber(); SC_MustGetString(); if (sc_Number) { P_PutMapSongLump(sc_Number, sc_String); } } continue; } else { for (i = 0; i < NUMSFX; i++) { if (!strcmp(S_sfx[i].tagname, sc_String)) { SC_MustGetString(); if (*sc_String != '?') { M_StringCopy(S_sfx[i].name, sc_String, sizeof(S_sfx[i].name)); } else { M_StringCopy(S_sfx[i].name, "default", sizeof(S_sfx[i].name)); } break; } } if (i == NUMSFX) { SC_MustGetString(); } } } SC_Close(); for (i = 0; i < NUMSFX; i++) { if (!strcmp(S_sfx[i].name, "")) { M_StringCopy(S_sfx[i].name, "default", sizeof(S_sfx[i].name)); } } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/s_sound.h000066400000000000000000000045221257432200600230310ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __S_SOUND__ #define __S_SOUND__ /* typedef struct { char name[8]; int p1; } musicinfo_t; */ /* typedef struct sfxinfo_s { char tagName[32]; char lumpname[12]; // Only need 9 bytes, but padded out to be dword aligned //struct sfxinfo_s *link; // Make alias for another sound int priority; // Higher priority takes precendence int usefulness; // Determines when a sound should be cached out void *snd_ptr; int lumpnum; int numchannels; // total number of channels a sound type may occupy boolean changePitch; } sfxinfo_t; */ typedef struct { mobj_t *mo; int sound_id; int handle; int volume; int pitch; int priority; } channel_t; typedef struct { int id; unsigned short priority; char *name; mobj_t *mo; int distance; } ChanInfo_t; typedef struct { int channelCount; int musicVolume; int soundVolume; ChanInfo_t chan[8]; } SoundInfo_t; extern int snd_MaxVolume; extern int snd_MusicVolume; extern int snd_Channels; extern boolean cdmusic; void S_Start(void); void S_StartSound(mobj_t * origin, int sound_id); int S_GetSoundID(char *name); void S_StartSoundAtVolume(mobj_t * origin, int sound_id, int volume); void S_StopSound(mobj_t * origin); void S_StopAllSound(void); void S_PauseSound(void); void S_ResumeSound(void); void S_UpdateSounds(mobj_t * listener); void S_StartSong(int song, boolean loop); void S_StartSongName(char *songLump, boolean loop); void S_Init(void); void S_GetChannelInfo(SoundInfo_t * s); void S_SetMusicVolume(void); boolean S_GetSoundPlayingInfo(mobj_t * mobj, int sound_id); boolean S_StartCustomCDTrack(int tracknum); int S_GetCurrentCDTrack(void); #endif chocolate-doom-chocolate-doom-2.2.1/src/hexen/sb_bar.c000066400000000000000000001563741257432200600226170ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "i_cdmus.h" #include "i_video.h" #include "m_bbox.h" #include "m_cheat.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" #include "i_swap.h" // TYPES ------------------------------------------------------------------- typedef struct Cheat_s { void (*func) (player_t * player, struct Cheat_s * cheat); cheatseq_t *seq; } Cheat_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void DrawSoundInfo(void); static void DrINumber(signed int val, int x, int y); static void DrRedINumber(signed int val, int x, int y); static void DrBNumber(signed int val, int x, int y); static void DrawCommonBar(void); static void DrawMainBar(void); static void DrawInventoryBar(void); static void DrawKeyBar(void); static void DrawWeaponPieces(void); static void DrawFullScreenStuff(void); static void DrawAnimatedIcons(void); static boolean HandleCheats(byte key); static boolean CheatAddKey(Cheat_t * cheat, byte key, boolean * eat); static void CheatGodFunc(player_t * player, Cheat_t * cheat); static void CheatNoClipFunc(player_t * player, Cheat_t * cheat); static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat); static void CheatHealthFunc(player_t * player, Cheat_t * cheat); static void CheatKeysFunc(player_t * player, Cheat_t * cheat); static void CheatSoundFunc(player_t * player, Cheat_t * cheat); static void CheatTickerFunc(player_t * player, Cheat_t * cheat); static void CheatArtifactAllFunc(player_t * player, Cheat_t * cheat); static void CheatPuzzleFunc(player_t * player, Cheat_t * cheat); static void CheatWarpFunc(player_t * player, Cheat_t * cheat); static void CheatPigFunc(player_t * player, Cheat_t * cheat); static void CheatMassacreFunc(player_t * player, Cheat_t * cheat); static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat); static void CheatQuickenFunc1(player_t * player, Cheat_t * cheat); static void CheatQuickenFunc2(player_t * player, Cheat_t * cheat); static void CheatQuickenFunc3(player_t * player, Cheat_t * cheat); static void CheatClassFunc1(player_t * player, Cheat_t * cheat); static void CheatClassFunc2(player_t * player, Cheat_t * cheat); static void CheatInitFunc(player_t * player, Cheat_t * cheat); static void CheatVersionFunc(player_t * player, Cheat_t * cheat); static void CheatDebugFunc(player_t * player, Cheat_t * cheat); static void CheatScriptFunc1(player_t * player, Cheat_t * cheat); static void CheatScriptFunc2(player_t * player, Cheat_t * cheat); static void CheatScriptFunc3(player_t * player, Cheat_t * cheat); static void CheatRevealFunc(player_t * player, Cheat_t * cheat); static void CheatTrackFunc1(player_t * player, Cheat_t * cheat); static void CheatTrackFunc2(player_t * player, Cheat_t * cheat); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern int ArmorIncrement[NUMCLASSES][NUMARMOR]; extern int AutoArmorSave[NUMCLASSES]; // PUBLIC DATA DECLARATIONS ------------------------------------------------ boolean DebugSound; // Debug flag for displaying sound info boolean inventory; int curpos; int inv_ptr; int ArtifactFlash; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int DisplayTicker = 0; static int HealthMarker; //static int ChainWiggle; static player_t *CPlayer; static int SpinFlylump; static int SpinMinotaurLump; static int SpinSpeedLump; static int SpinDefenseLump; static int FontBNumBase; static int PlayPalette; static patch_t *PatchH2BAR; static patch_t *PatchH2TOP; static patch_t *PatchLFEDGE; static patch_t *PatchRTEDGE; static patch_t *PatchARMCLEAR; static patch_t *PatchARTICLEAR; static patch_t *PatchMANACLEAR; static patch_t *PatchKILLS; static patch_t *PatchMANAVIAL1; static patch_t *PatchMANAVIAL2; static patch_t *PatchMANAVIALDIM1; static patch_t *PatchMANAVIALDIM2; static patch_t *PatchMANADIM1; static patch_t *PatchMANADIM2; static patch_t *PatchMANABRIGHT1; static patch_t *PatchMANABRIGHT2; static patch_t *PatchCHAIN; static patch_t *PatchSTATBAR; static patch_t *PatchKEYBAR; static patch_t *PatchLIFEGEM; static patch_t *PatchSELECTBOX; static patch_t *PatchINumbers[10]; static patch_t *PatchNEGATIVE; static patch_t *PatchSmNumbers[10]; static patch_t *PatchINVBAR; static patch_t *PatchWEAPONSLOT; static patch_t *PatchWEAPONFULL; static patch_t *PatchPIECE1; static patch_t *PatchPIECE2; static patch_t *PatchPIECE3; static patch_t *PatchINVLFGEM1; static patch_t *PatchINVLFGEM2; static patch_t *PatchINVRTGEM1; static patch_t *PatchINVRTGEM2; // Toggle god mode cheatseq_t CheatGodSeq = CHEAT("satan", 0); // Toggle no clipping mode cheatseq_t CheatNoClipSeq = CHEAT("casper", 0); // Get all weapons and mana cheatseq_t CheatWeaponsSeq = CHEAT("nra", 0); // Get full health cheatseq_t CheatHealthSeq = CHEAT("clubmed", 0); // Get all keys cheatseq_t CheatKeysSeq = CHEAT("locksmith", 0); // Toggle sound debug info cheatseq_t CheatSoundSeq = CHEAT("noise", 0); // Toggle ticker cheatseq_t CheatTickerSeq = CHEAT("ticker", 0); // Get all artifacts cheatseq_t CheatArtifactAllSeq = CHEAT("indiana", 0); // Get all puzzle pieces cheatseq_t CheatPuzzleSeq = CHEAT("sherlock", 0); // Warp to new level cheatseq_t CheatWarpSeq = CHEAT("visit", 2); // Become a pig cheatseq_t CheatPigSeq = CHEAT("deliverance", 0); // Kill all monsters cheatseq_t CheatMassacreSeq = CHEAT("butcher", 0); cheatseq_t CheatIDKFASeq = CHEAT("conan", 0); cheatseq_t CheatQuickenSeq1 = CHEAT("martek", 0); cheatseq_t CheatQuickenSeq2 = CHEAT("martekmartek", 0); cheatseq_t CheatQuickenSeq3 = CHEAT("martekmartekmartek", 0); // New class cheatseq_t CheatClass1Seq = CHEAT("shadowcaster", 0); cheatseq_t CheatClass2Seq = CHEAT("shadowcaster", 1); cheatseq_t CheatInitSeq = CHEAT("init", 0); cheatseq_t CheatVersionSeq = CHEAT("mrjones", 0); cheatseq_t CheatDebugSeq = CHEAT("where", 0); cheatseq_t CheatScriptSeq1 = CHEAT("puke", 0); cheatseq_t CheatScriptSeq2 = CHEAT("puke", 1); cheatseq_t CheatScriptSeq3 = CHEAT("puke", 2); cheatseq_t CheatRevealSeq = CHEAT("mapsco", 0); cheatseq_t CheatTrackSeq1 = CHEAT("`", 0); cheatseq_t CheatTrackSeq2 = CHEAT("`", 2); static Cheat_t Cheats[] = { {CheatTrackFunc1, &CheatTrackSeq1}, {CheatTrackFunc2, &CheatTrackSeq2}, {CheatGodFunc, &CheatGodSeq}, {CheatNoClipFunc, &CheatNoClipSeq}, {CheatWeaponsFunc, &CheatWeaponsSeq}, {CheatHealthFunc, &CheatHealthSeq}, {CheatKeysFunc, &CheatKeysSeq}, {CheatSoundFunc, &CheatSoundSeq}, {CheatTickerFunc, &CheatTickerSeq}, {CheatArtifactAllFunc, &CheatArtifactAllSeq}, {CheatPuzzleFunc, &CheatPuzzleSeq}, {CheatWarpFunc, &CheatWarpSeq}, {CheatPigFunc, &CheatPigSeq}, {CheatMassacreFunc, &CheatMassacreSeq}, {CheatIDKFAFunc, &CheatIDKFASeq}, {CheatQuickenFunc1, &CheatQuickenSeq1}, {CheatQuickenFunc2, &CheatQuickenSeq2}, {CheatQuickenFunc3, &CheatQuickenSeq3}, {CheatClassFunc1, &CheatClass1Seq}, {CheatClassFunc2, &CheatClass2Seq}, {CheatInitFunc, &CheatInitSeq}, {CheatVersionFunc, &CheatVersionSeq}, {CheatDebugFunc, &CheatDebugSeq}, {CheatScriptFunc1, &CheatScriptSeq1}, {CheatScriptFunc2, &CheatScriptSeq2}, {CheatScriptFunc3, &CheatScriptSeq3}, {CheatRevealFunc, &CheatRevealSeq}, }; #define SET_CHEAT(cheat, seq) \ { memcpy(cheat.sequence, seq, sizeof(seq)); \ cheat.sequence_len = sizeof(seq) - 1; } // CODE -------------------------------------------------------------------- //========================================================================== // // SB_Init // //========================================================================== void SB_Init(void) { int i; int startLump; PatchH2BAR = W_CacheLumpName("H2BAR", PU_STATIC); PatchH2TOP = W_CacheLumpName("H2TOP", PU_STATIC); PatchINVBAR = W_CacheLumpName("INVBAR", PU_STATIC); PatchLFEDGE = W_CacheLumpName("LFEDGE", PU_STATIC); PatchRTEDGE = W_CacheLumpName("RTEDGE", PU_STATIC); PatchSTATBAR = W_CacheLumpName("STATBAR", PU_STATIC); PatchKEYBAR = W_CacheLumpName("KEYBAR", PU_STATIC); PatchSELECTBOX = W_CacheLumpName("SELECTBOX", PU_STATIC); PatchARTICLEAR = W_CacheLumpName("ARTICLS", PU_STATIC); PatchARMCLEAR = W_CacheLumpName("ARMCLS", PU_STATIC); PatchMANACLEAR = W_CacheLumpName("MANACLS", PU_STATIC); PatchMANAVIAL1 = W_CacheLumpName("MANAVL1", PU_STATIC); PatchMANAVIAL2 = W_CacheLumpName("MANAVL2", PU_STATIC); PatchMANAVIALDIM1 = W_CacheLumpName("MANAVL1D", PU_STATIC); PatchMANAVIALDIM2 = W_CacheLumpName("MANAVL2D", PU_STATIC); PatchMANADIM1 = W_CacheLumpName("MANADIM1", PU_STATIC); PatchMANADIM2 = W_CacheLumpName("MANADIM2", PU_STATIC); PatchMANABRIGHT1 = W_CacheLumpName("MANABRT1", PU_STATIC); PatchMANABRIGHT2 = W_CacheLumpName("MANABRT2", PU_STATIC); PatchINVLFGEM1 = W_CacheLumpName("invgeml1", PU_STATIC); PatchINVLFGEM2 = W_CacheLumpName("invgeml2", PU_STATIC); PatchINVRTGEM1 = W_CacheLumpName("invgemr1", PU_STATIC); PatchINVRTGEM2 = W_CacheLumpName("invgemr2", PU_STATIC); // PatchCHAINBACK = W_CacheLumpName("CHAINBACK", PU_STATIC); startLump = W_GetNumForName("IN0"); for (i = 0; i < 10; i++) { PatchINumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC); } PatchNEGATIVE = W_CacheLumpName("NEGNUM", PU_STATIC); FontBNumBase = W_GetNumForName("FONTB16"); startLump = W_GetNumForName("SMALLIN0"); for (i = 0; i < 10; i++) { PatchSmNumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC); } PlayPalette = W_GetNumForName("PLAYPAL"); SpinFlylump = W_GetNumForName("SPFLY0"); SpinMinotaurLump = W_GetNumForName("SPMINO0"); SpinSpeedLump = W_GetNumForName("SPBOOT0"); SpinDefenseLump = W_GetNumForName("SPSHLD0"); if (deathmatch) { PatchKILLS = W_CacheLumpName("KILLS", PU_STATIC); } SB_SetClassData(); if (gamemode == shareware) { SET_CHEAT(CheatGodSeq, "bgokey"); SET_CHEAT(CheatNoClipSeq, "rjohnson"); SET_CHEAT(CheatWeaponsSeq, "crhinehart"); SET_CHEAT(CheatHealthSeq,"sgurno"); SET_CHEAT(CheatKeysSeq, "mraymondjudy"); SET_CHEAT(CheatSoundSeq, "kschilder"); SET_CHEAT(CheatTickerSeq, "rrettenmund"); SET_CHEAT(CheatArtifactAllSeq, "braffel"); SET_CHEAT(CheatPuzzleSeq, "tmoore"); SET_CHEAT(CheatWarpSeq, "bpelletier"); SET_CHEAT(CheatPigSeq, "ebiessman"); SET_CHEAT(CheatMassacreSeq, "cstika"); SET_CHEAT(CheatIDKFASeq, "rambo"); SET_CHEAT(CheatQuickenSeq1, "quicken"); SET_CHEAT(CheatQuickenSeq2, "quickenquicken"); SET_CHEAT(CheatQuickenSeq3, "quickenquickenquicken"); SET_CHEAT(CheatClass1Seq, "plipo"); SET_CHEAT(CheatClass2Seq, "plipo"); SET_CHEAT(CheatVersionSeq, "pmacarther"); SET_CHEAT(CheatDebugSeq, "jsumwalt"); SET_CHEAT(CheatScriptSeq1, "mwagabaza"); SET_CHEAT(CheatScriptSeq2, "mwagabaza"); SET_CHEAT(CheatScriptSeq3, "mwagabaza"); SET_CHEAT(CheatRevealSeq, "reveal"); } } //========================================================================== // // SB_SetClassData // //========================================================================== void SB_SetClassData(void) { int class; class = PlayerClass[consoleplayer]; // original player class (not pig) PatchWEAPONSLOT = W_CacheLumpNum(W_GetNumForName("wpslot0") + class, PU_STATIC); PatchWEAPONFULL = W_CacheLumpNum(W_GetNumForName("wpfull0") + class, PU_STATIC); PatchPIECE1 = W_CacheLumpNum(W_GetNumForName("wpiecef1") + class, PU_STATIC); PatchPIECE2 = W_CacheLumpNum(W_GetNumForName("wpiecef2") + class, PU_STATIC); PatchPIECE3 = W_CacheLumpNum(W_GetNumForName("wpiecef3") + class, PU_STATIC); PatchCHAIN = W_CacheLumpNum(W_GetNumForName("chain") + class, PU_STATIC); if (!netgame) { // single player game uses red life gem (the second gem) PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("lifegem") + maxplayers * class + 1, PU_STATIC); } else { PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("lifegem") + maxplayers * class + consoleplayer, PU_STATIC); } SB_state = -1; UpdateState |= I_FULLSCRN; } //========================================================================== // // SB_Ticker // //========================================================================== void SB_Ticker(void) { int delta; int curHealth; curHealth = players[consoleplayer].mo->health; if (curHealth < 0) { curHealth = 0; } if (curHealth < HealthMarker) { delta = (HealthMarker - curHealth) >> 2; if (delta < 1) { delta = 1; } else if (delta > 6) { delta = 6; } HealthMarker -= delta; } else if (curHealth > HealthMarker) { delta = (curHealth - HealthMarker) >> 2; if (delta < 1) { delta = 1; } else if (delta > 6) { delta = 6; } HealthMarker += delta; } } //========================================================================== // // DrINumber // // Draws a three digit number. // //========================================================================== static void DrINumber(signed int val, int x, int y) { patch_t *patch; int oldval; oldval = val; if (val < 0) { val = -val; if (val > 99) { val = 99; } if (val > 9) { patch = PatchINumbers[val / 10]; V_DrawPatch(x + 8, y, patch); V_DrawPatch(x, y, PatchNEGATIVE); } else { V_DrawPatch(x + 8, y, PatchNEGATIVE); } val = val % 10; patch = PatchINumbers[val]; V_DrawPatch(x + 16, y, patch); return; } if (val > 99) { patch = PatchINumbers[val / 100]; V_DrawPatch(x, y, patch); } val = val % 100; if (val > 9 || oldval > 99) { patch = PatchINumbers[val / 10]; V_DrawPatch(x + 8, y, patch); } val = val % 10; patch = PatchINumbers[val]; V_DrawPatch(x + 16, y, patch); } //========================================================================== // // DrRedINumber // // Draws a three digit number using the red font // //========================================================================== static void DrRedINumber(signed int val, int x, int y) { patch_t *patch; int oldval; oldval = val; if (val < 0) { val = 0; } if (val > 99) { patch = W_CacheLumpNum(W_GetNumForName("inred0") + val / 100, PU_CACHE); V_DrawPatch(x, y, patch); } val = val % 100; if (val > 9 || oldval > 99) { patch = W_CacheLumpNum(W_GetNumForName("inred0") + val / 10, PU_CACHE); V_DrawPatch(x + 8, y, patch); } val = val % 10; patch = W_CacheLumpNum(W_GetNumForName("inred0") + val, PU_CACHE); V_DrawPatch(x + 16, y, patch); } //========================================================================== // // DrBNumber // // Draws a three digit number using FontB // //========================================================================== static void DrBNumber(signed int val, int x, int y) { patch_t *patch; int xpos; int oldval; oldval = val; xpos = x; if (val < 0) { val = 0; } if (val > 99) { patch = W_CacheLumpNum(FontBNumBase + val / 100, PU_CACHE); V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } val = val % 100; xpos += 12; if (val > 9 || oldval > 99) { patch = W_CacheLumpNum(FontBNumBase + val / 10, PU_CACHE); V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } val = val % 10; xpos += 12; patch = W_CacheLumpNum(FontBNumBase + val, PU_CACHE); V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch); } //========================================================================== // // DrSmallNumber // // Draws a small two digit number. // //========================================================================== static void DrSmallNumber(int val, int x, int y) { patch_t *patch; if (val <= 0) { return; } if (val > 999) { val %= 1000; } if (val > 99) { patch = PatchSmNumbers[val / 100]; V_DrawPatch(x, y, patch); patch = PatchSmNumbers[(val % 100) / 10]; V_DrawPatch(x + 4, y, patch); } else if (val > 9) { patch = PatchSmNumbers[val / 10]; V_DrawPatch(x + 4, y, patch); } val %= 10; patch = PatchSmNumbers[val]; V_DrawPatch(x + 8, y, patch); } /* //========================================================================== // // ShadeLine // //========================================================================== static void ShadeLine(int x, int y, int height, int shade) { byte *dest; byte *shades; shades = colormaps+9*256+shade*2*256; dest = I_VideoBuffer+y*SCREENWIDTH+x; while(height--) { *(dest) = *(shades+*dest); dest += SCREENWIDTH; } } //========================================================================== // // ShadeChain // //========================================================================== static void ShadeChain(void) { int i; for(i = 0; i < 16; i++) { ShadeLine(277+i, 190, 10, i/2); ShadeLine(19+i, 190, 10, 7-(i/2)); } } */ //========================================================================== // // DrawSoundInfo // // Displays sound debugging information. // //========================================================================== static void DrawSoundInfo(void) { int i; SoundInfo_t s; ChanInfo_t *c; char text[32]; int x; int y; int xPos[7] = { 1, 75, 112, 156, 200, 230, 260 }; if (leveltime & 16) { MN_DrTextA("*** SOUND DEBUG INFO ***", xPos[0], 20); } S_GetChannelInfo(&s); if (s.channelCount == 0) { return; } x = 0; MN_DrTextA("NAME", xPos[x++], 30); MN_DrTextA("MO.T", xPos[x++], 30); MN_DrTextA("MO.X", xPos[x++], 30); MN_DrTextA("MO.Y", xPos[x++], 30); MN_DrTextA("ID", xPos[x++], 30); MN_DrTextA("PRI", xPos[x++], 30); MN_DrTextA("DIST", xPos[x++], 30); for (i = 0; i < s.channelCount; i++) { c = &s.chan[i]; x = 0; y = 40 + i * 10; if (c->mo == NULL) { // Channel is unused MN_DrTextA("------", xPos[0], y); continue; } M_snprintf(text, sizeof(text), "%s", c->name); M_ForceUppercase(text); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->mo->type); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->mo->x >> FRACBITS); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->mo->y >> FRACBITS); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", (int) c->id); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->priority); MN_DrTextA(text, xPos[x++], y); M_snprintf(text, sizeof(text), "%d", c->distance); MN_DrTextA(text, xPos[x++], y); } UpdateState |= I_FULLSCRN; BorderNeedRefresh = true; } //========================================================================== // // SB_Drawer // //========================================================================== char patcharti[][10] = { {"ARTIBOX"}, // none {"ARTIINVU"}, // invulnerability {"ARTIPTN2"}, // health {"ARTISPHL"}, // superhealth {"ARTIHRAD"}, // healing radius {"ARTISUMN"}, // summon maulator {"ARTITRCH"}, // torch {"ARTIPORK"}, // egg {"ARTISOAR"}, // fly {"ARTIBLST"}, // blast radius {"ARTIPSBG"}, // poison bag {"ARTITELO"}, // teleport other {"ARTISPED"}, // speed {"ARTIBMAN"}, // boost mana {"ARTIBRAC"}, // boost armor {"ARTIATLP"}, // teleport {"ARTISKLL"}, // arti_puzzskull {"ARTIBGEM"}, // arti_puzzgembig {"ARTIGEMR"}, // arti_puzzgemred {"ARTIGEMG"}, // arti_puzzgemgreen1 {"ARTIGMG2"}, // arti_puzzgemgreen2 {"ARTIGEMB"}, // arti_puzzgemblue1 {"ARTIGMB2"}, // arti_puzzgemblue2 {"ARTIBOK1"}, // arti_puzzbook1 {"ARTIBOK2"}, // arti_puzzbook2 {"ARTISKL2"}, // arti_puzzskull2 {"ARTIFWEP"}, // arti_puzzfweapon {"ARTICWEP"}, // arti_puzzcweapon {"ARTIMWEP"}, // arti_puzzmweapon {"ARTIGEAR"}, // arti_puzzgear1 {"ARTIGER2"}, // arti_puzzgear2 {"ARTIGER3"}, // arti_puzzgear3 {"ARTIGER4"}, // arti_puzzgear4 }; int SB_state = -1; static int oldarti = 0; static int oldartiCount = 0; static int oldfrags = -9999; static int oldmana1 = -1; static int oldmana2 = -1; static int oldarmor = -1; static int oldhealth = -1; static int oldlife = -1; static int oldpieces = -1; static int oldweapon = -1; static int oldkeys = -1; extern boolean automapactive; void SB_Drawer(void) { // Sound info debug stuff if (DebugSound == true) { DrawSoundInfo(); } CPlayer = &players[consoleplayer]; if (viewheight == SCREENHEIGHT && !automapactive) { DrawFullScreenStuff(); SB_state = -1; } else { if (SB_state == -1) { V_DrawPatch(0, 134, PatchH2BAR); oldhealth = -1; } DrawCommonBar(); if (!inventory) { if (SB_state != 0) { // Main interface if (!automapactive) { V_DrawPatch(38, 162, PatchSTATBAR); } else { V_DrawPatch(38, 162, PatchKEYBAR); } oldarti = 0; oldmana1 = -1; oldmana2 = -1; oldarmor = -1; oldpieces = -1; oldfrags = -9999; //can't use -1, 'cuz of negative frags oldlife = -1; oldweapon = -1; oldkeys = -1; } if (!automapactive) { DrawMainBar(); } else { DrawKeyBar(); } SB_state = 0; } else { DrawInventoryBar(); SB_state = 1; } } SB_PaletteFlash(false); DrawAnimatedIcons(); } //========================================================================== // // DrawAnimatedIcons // //========================================================================== static void DrawAnimatedIcons(void) { int frame; static boolean hitCenterFrame; // Wings of wrath if (CPlayer->powers[pw_flight]) { if (CPlayer->powers[pw_flight] > BLINKTHRESHOLD || !(CPlayer->powers[pw_flight] & 16)) { frame = (leveltime / 3) & 15; if (CPlayer->mo->flags2 & MF2_FLY) { if (hitCenterFrame && (frame != 15 && frame != 0)) { V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + 15, PU_CACHE)); } else { V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + frame, PU_CACHE)); hitCenterFrame = false; } } else { if (!hitCenterFrame && (frame != 15 && frame != 0)) { V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + frame, PU_CACHE)); hitCenterFrame = false; } else { V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + 15, PU_CACHE)); hitCenterFrame = true; } } } BorderTopRefresh = true; UpdateState |= I_MESSAGES; } // Speed Boots if (CPlayer->powers[pw_speed]) { if (CPlayer->powers[pw_speed] > BLINKTHRESHOLD || !(CPlayer->powers[pw_speed] & 16)) { frame = (leveltime / 3) & 15; V_DrawPatch(60, 19, W_CacheLumpNum(SpinSpeedLump + frame, PU_CACHE)); } BorderTopRefresh = true; UpdateState |= I_MESSAGES; } // Defensive power if (CPlayer->powers[pw_invulnerability]) { if (CPlayer->powers[pw_invulnerability] > BLINKTHRESHOLD || !(CPlayer->powers[pw_invulnerability] & 16)) { frame = (leveltime / 3) & 15; V_DrawPatch(260, 19, W_CacheLumpNum(SpinDefenseLump + frame, PU_CACHE)); } BorderTopRefresh = true; UpdateState |= I_MESSAGES; } // Minotaur Active if (CPlayer->powers[pw_minotaur]) { if (CPlayer->powers[pw_minotaur] > BLINKTHRESHOLD || !(CPlayer->powers[pw_minotaur] & 16)) { frame = (leveltime / 3) & 15; V_DrawPatch(300, 19, W_CacheLumpNum(SpinMinotaurLump + frame, PU_CACHE)); } BorderTopRefresh = true; UpdateState |= I_MESSAGES; } } //========================================================================== // // SB_PaletteFlash // // Sets the new palette based upon the current values of // consoleplayer->damagecount and consoleplayer->bonuscount. // //========================================================================== void SB_PaletteFlash(boolean forceChange) { static int sb_palette = 0; int palette; byte *pal; if (forceChange) { sb_palette = -1; } if (gamestate == GS_LEVEL) { CPlayer = &players[consoleplayer]; if (CPlayer->poisoncount) { palette = 0; palette = (CPlayer->poisoncount + 7) >> 3; if (palette >= NUMPOISONPALS) { palette = NUMPOISONPALS - 1; } palette += STARTPOISONPALS; } else if (CPlayer->damagecount) { palette = (CPlayer->damagecount + 7) >> 3; if (palette >= NUMREDPALS) { palette = NUMREDPALS - 1; } palette += STARTREDPALS; } else if (CPlayer->bonuscount) { palette = (CPlayer->bonuscount + 7) >> 3; if (palette >= NUMBONUSPALS) { palette = NUMBONUSPALS - 1; } palette += STARTBONUSPALS; } else if (CPlayer->mo->flags2 & MF2_ICEDAMAGE) { // Frozen player palette = STARTICEPAL; } else { palette = 0; } } else { palette = 0; } if (palette != sb_palette) { sb_palette = palette; pal = (byte *) W_CacheLumpNum(PlayPalette, PU_CACHE) + palette * 768; I_SetPalette(pal); } } //========================================================================== // // DrawCommonBar // //========================================================================== void DrawCommonBar(void) { int healthPos; V_DrawPatch(0, 134, PatchH2TOP); if (oldhealth != HealthMarker) { oldhealth = HealthMarker; healthPos = HealthMarker; if (healthPos < 0) { healthPos = 0; } if (healthPos > 100) { healthPos = 100; } V_DrawPatch(28 + (((healthPos * 196) / 100) % 9), 193, PatchCHAIN); V_DrawPatch(7 + ((healthPos * 11) / 5), 193, PatchLIFEGEM); V_DrawPatch(0, 193, PatchLFEDGE); V_DrawPatch(277, 193, PatchRTEDGE); // ShadeChain(); UpdateState |= I_STATBAR; } } //========================================================================== // // DrawMainBar // //========================================================================== void DrawMainBar(void) { int i; int temp; patch_t *manaPatch1, *manaPatch2; patch_t *manaVialPatch1, *manaVialPatch2; manaPatch1 = NULL; manaPatch2 = NULL; manaVialPatch1 = NULL; manaVialPatch2 = NULL; // Ready artifact if (ArtifactFlash) { V_DrawPatch(144, 160, PatchARTICLEAR); V_DrawPatch(148, 164, W_CacheLumpNum(W_GetNumForName("useartia") + ArtifactFlash - 1, PU_CACHE)); ArtifactFlash--; oldarti = -1; // so that the correct artifact fills in after the flash UpdateState |= I_STATBAR; } else if (oldarti != CPlayer->readyArtifact || oldartiCount != CPlayer->inventory[inv_ptr].count) { V_DrawPatch(144, 160, PatchARTICLEAR); if (CPlayer->readyArtifact > 0) { V_DrawPatch(143, 163, W_CacheLumpName(patcharti[CPlayer->readyArtifact], PU_CACHE)); if (CPlayer->inventory[inv_ptr].count > 1) { DrSmallNumber(CPlayer->inventory[inv_ptr].count, 162, 184); } } oldarti = CPlayer->readyArtifact; oldartiCount = CPlayer->inventory[inv_ptr].count; UpdateState |= I_STATBAR; } // Frags if (deathmatch) { temp = 0; for (i = 0; i < maxplayers; i++) { temp += CPlayer->frags[i]; } if (temp != oldfrags) { V_DrawPatch(38, 162, PatchKILLS); DrINumber(temp, 40, 176); oldfrags = temp; UpdateState |= I_STATBAR; } } else { temp = HealthMarker; if (temp < 0) { temp = 0; } else if (temp > 100) { temp = 100; } if (oldlife != temp) { oldlife = temp; V_DrawPatch(41, 178, PatchARMCLEAR); if (temp >= 25) { DrINumber(temp, 40, 176); } else { DrRedINumber(temp, 40, 176); } UpdateState |= I_STATBAR; } } // Mana temp = CPlayer->mana[0]; if (oldmana1 != temp) { V_DrawPatch(77, 178, PatchMANACLEAR); DrSmallNumber(temp, 79, 181); manaVialPatch1 = (patch_t *) 1; // force a vial update if (temp == 0) { // Draw Dim Mana icon manaPatch1 = PatchMANADIM1; } else if (oldmana1 == 0) { manaPatch1 = PatchMANABRIGHT1; } oldmana1 = temp; UpdateState |= I_STATBAR; } temp = CPlayer->mana[1]; if (oldmana2 != temp) { V_DrawPatch(109, 178, PatchMANACLEAR); DrSmallNumber(temp, 111, 181); manaVialPatch1 = (patch_t *) 1; // force a vial update if (temp == 0) { // Draw Dim Mana icon manaPatch2 = PatchMANADIM2; } else if (oldmana2 == 0) { manaPatch2 = PatchMANABRIGHT2; } oldmana2 = temp; UpdateState |= I_STATBAR; } if (oldweapon != CPlayer->readyweapon || manaPatch1 || manaPatch2 || manaVialPatch1) { // Update mana graphics based upon mana count/weapon type if (CPlayer->readyweapon == WP_FIRST) { manaPatch1 = PatchMANADIM1; manaPatch2 = PatchMANADIM2; manaVialPatch1 = PatchMANAVIALDIM1; manaVialPatch2 = PatchMANAVIALDIM2; } else if (CPlayer->readyweapon == WP_SECOND) { if (!manaPatch1) { manaPatch1 = PatchMANABRIGHT1; } manaVialPatch1 = PatchMANAVIAL1; manaPatch2 = PatchMANADIM2; manaVialPatch2 = PatchMANAVIALDIM2; } else if (CPlayer->readyweapon == WP_THIRD) { manaPatch1 = PatchMANADIM1; manaVialPatch1 = PatchMANAVIALDIM1; if (!manaPatch2) { manaPatch2 = PatchMANABRIGHT2; } manaVialPatch2 = PatchMANAVIAL2; } else { manaVialPatch1 = PatchMANAVIAL1; manaVialPatch2 = PatchMANAVIAL2; if (!manaPatch1) { manaPatch1 = PatchMANABRIGHT1; } if (!manaPatch2) { manaPatch2 = PatchMANABRIGHT2; } } V_DrawPatch(77, 164, manaPatch1); V_DrawPatch(110, 164, manaPatch2); V_DrawPatch(94, 164, manaVialPatch1); for (i = 165; i < 187 - (22 * CPlayer->mana[0]) / MAX_MANA; i++) { I_VideoBuffer[i * SCREENWIDTH + 95] = 0; I_VideoBuffer[i * SCREENWIDTH + 96] = 0; I_VideoBuffer[i * SCREENWIDTH + 97] = 0; } V_DrawPatch(102, 164, manaVialPatch2); for (i = 165; i < 187 - (22 * CPlayer->mana[1]) / MAX_MANA; i++) { I_VideoBuffer[i * SCREENWIDTH + 103] = 0; I_VideoBuffer[i * SCREENWIDTH + 104] = 0; I_VideoBuffer[i * SCREENWIDTH + 105] = 0; } oldweapon = CPlayer->readyweapon; UpdateState |= I_STATBAR; } // Armor temp = AutoArmorSave[CPlayer->class] + CPlayer->armorpoints[ARMOR_ARMOR] + CPlayer->armorpoints[ARMOR_SHIELD] + CPlayer->armorpoints[ARMOR_HELMET] + CPlayer->armorpoints[ARMOR_AMULET]; if (oldarmor != temp) { oldarmor = temp; V_DrawPatch(255, 178, PatchARMCLEAR); DrINumber(FixedDiv(temp, 5 * FRACUNIT) >> FRACBITS, 250, 176); UpdateState |= I_STATBAR; } // Weapon Pieces if (oldpieces != CPlayer->pieces) { DrawWeaponPieces(); oldpieces = CPlayer->pieces; UpdateState |= I_STATBAR; } } //========================================================================== // // DrawInventoryBar // //========================================================================== void DrawInventoryBar(void) { int i; int x; x = inv_ptr - curpos; UpdateState |= I_STATBAR; V_DrawPatch(38, 162, PatchINVBAR); for (i = 0; i < 7; i++) { //V_DrawPatch(50+i*31, 160, W_CacheLumpName("ARTIBOX", PU_CACHE)); if (CPlayer->inventorySlotNum > x + i && CPlayer->inventory[x + i].type != arti_none) { V_DrawPatch(50 + i * 31, 163, W_CacheLumpName(patcharti [CPlayer->inventory[x + i].type], PU_CACHE)); if (CPlayer->inventory[x + i].count > 1) { DrSmallNumber(CPlayer->inventory[x + i].count, 68 + i * 31, 185); } } } V_DrawPatch(50 + curpos * 31, 163, PatchSELECTBOX); if (x != 0) { V_DrawPatch(42, 163, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2); } if (CPlayer->inventorySlotNum - x > 7) { V_DrawPatch(269, 163, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2); } } //========================================================================== // // DrawKeyBar // //========================================================================== void DrawKeyBar(void) { int i; int xPosition; int temp; if (oldkeys != CPlayer->keys) { xPosition = 46; for (i = 0; i < NUMKEYS && xPosition <= 126; i++) { if (CPlayer->keys & (1 << i)) { V_DrawPatch(xPosition, 164, W_CacheLumpNum(W_GetNumForName("keyslot1") + i, PU_CACHE)); xPosition += 20; } } oldkeys = CPlayer->keys; UpdateState |= I_STATBAR; } temp = AutoArmorSave[CPlayer->class] + CPlayer->armorpoints[ARMOR_ARMOR] + CPlayer->armorpoints[ARMOR_SHIELD] + CPlayer->armorpoints[ARMOR_HELMET] + CPlayer->armorpoints[ARMOR_AMULET]; if (oldarmor != temp) { for (i = 0; i < NUMARMOR; i++) { if (!CPlayer->armorpoints[i]) { continue; } if (CPlayer->armorpoints[i] <= (ArmorIncrement[CPlayer->class][i] >> 2)) { V_DrawTLPatch(150 + 31 * i, 164, W_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE)); } else if (CPlayer->armorpoints[i] <= (ArmorIncrement[CPlayer->class][i] >> 1)) { V_DrawAltTLPatch(150 + 31 * i, 164, W_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE)); } else { V_DrawPatch(150 + 31 * i, 164, W_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE)); } } oldarmor = temp; UpdateState |= I_STATBAR; } } //========================================================================== // // DrawWeaponPieces // //========================================================================== static int PieceX[NUMCLASSES][3] = { {190, 225, 234}, {190, 212, 225}, {190, 205, 224}, {0, 0, 0} // Pig is never used }; static void DrawWeaponPieces(void) { if (CPlayer->pieces == 7) { V_DrawPatch(190, 162, PatchWEAPONFULL); return; } V_DrawPatch(190, 162, PatchWEAPONSLOT); if (CPlayer->pieces & WPIECE1) { V_DrawPatch(PieceX[PlayerClass[consoleplayer]][0], 162, PatchPIECE1); } if (CPlayer->pieces & WPIECE2) { V_DrawPatch(PieceX[PlayerClass[consoleplayer]][1], 162, PatchPIECE2); } if (CPlayer->pieces & WPIECE3) { V_DrawPatch(PieceX[PlayerClass[consoleplayer]][2], 162, PatchPIECE3); } } //========================================================================== // // DrawFullScreenStuff // //========================================================================== void DrawFullScreenStuff(void) { int i; int x; int temp; UpdateState |= I_FULLSCRN; if (CPlayer->mo->health > 0) { DrBNumber(CPlayer->mo->health, 5, 180); } else { DrBNumber(0, 5, 180); } if (deathmatch) { temp = 0; for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { temp += CPlayer->frags[i]; } } DrINumber(temp, 45, 185); } if (!inventory) { if (CPlayer->readyArtifact > 0) { V_DrawTLPatch(286, 170, W_CacheLumpName("ARTIBOX", PU_CACHE)); V_DrawPatch(284, 169, W_CacheLumpName(patcharti[CPlayer->readyArtifact], PU_CACHE)); if (CPlayer->inventory[inv_ptr].count > 1) { DrSmallNumber(CPlayer->inventory[inv_ptr].count, 302, 192); } } } else { x = inv_ptr - curpos; for (i = 0; i < 7; i++) { V_DrawTLPatch(50 + i * 31, 168, W_CacheLumpName("ARTIBOX", PU_CACHE)); if (CPlayer->inventorySlotNum > x + i && CPlayer->inventory[x + i].type != arti_none) { V_DrawPatch(49 + i * 31, 167, W_CacheLumpName(patcharti [CPlayer->inventory[x + i].type], PU_CACHE)); if (CPlayer->inventory[x + i].count > 1) { DrSmallNumber(CPlayer->inventory[x + i].count, 66 + i * 31, 188); } } } V_DrawPatch(50 + curpos * 31, 167, PatchSELECTBOX); if (x != 0) { V_DrawPatch(40, 167, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2); } if (CPlayer->inventorySlotNum - x > 7) { V_DrawPatch(268, 167, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2); } } } //========================================================================== // // Draw_TeleportIcon // //========================================================================== void Draw_TeleportIcon(void) { patch_t *patch; patch = W_CacheLumpNum(W_GetNumForName("teleicon"), PU_CACHE); V_DrawPatch(100, 68, patch); UpdateState |= I_FULLSCRN; I_FinishUpdate(); UpdateState |= I_FULLSCRN; } //========================================================================== // // Draw_SaveIcon // //========================================================================== void Draw_SaveIcon(void) { patch_t *patch; patch = W_CacheLumpNum(W_GetNumForName("saveicon"), PU_CACHE); V_DrawPatch(100, 68, patch); UpdateState |= I_FULLSCRN; I_FinishUpdate(); UpdateState |= I_FULLSCRN; } //========================================================================== // // Draw_LoadIcon // //========================================================================== void Draw_LoadIcon(void) { patch_t *patch; patch = W_CacheLumpNum(W_GetNumForName("loadicon"), PU_CACHE); V_DrawPatch(100, 68, patch); UpdateState |= I_FULLSCRN; I_FinishUpdate(); UpdateState |= I_FULLSCRN; } //========================================================================== // // SB_Responder // //========================================================================== boolean SB_Responder(event_t * event) { if (event->type == ev_keydown) { if (HandleCheats(event->data1)) { // Need to eat the key return (true); } } return (false); } //========================================================================== // // HandleCheats // // Returns true if the caller should eat the key. // //========================================================================== static boolean HandleCheats(byte key) { int i; boolean eat; if (gameskill == sk_nightmare) { // Can't cheat in nightmare mode return (false); } else if (netgame) { // change CD track is the only cheat available in deathmatch eat = false; if (cdmusic) { if (CheatAddKey(&Cheats[0], key, &eat)) { Cheats[0].func(&players[consoleplayer], &Cheats[0]); S_StartSound(NULL, SFX_PLATFORM_STOP); } if (CheatAddKey(&Cheats[1], key, &eat)) { Cheats[1].func(&players[consoleplayer], &Cheats[1]); S_StartSound(NULL, SFX_PLATFORM_STOP); } } return eat; } if (players[consoleplayer].health <= 0) { // Dead players can't cheat return (false); } eat = false; for (i = 0; ipos) { cheat->pos = cheat->sequence; cheat->currentArg = 0; } if (*cheat->pos == 0) { *eat = true; cheat->args[cheat->currentArg++] = key; cheat->pos++; } else if (CheatLookup[key] == *cheat->pos) { cheat->pos++; } else { cheat->pos = cheat->sequence; cheat->currentArg = 0; } if (*cheat->pos == 0xff) { cheat->pos = cheat->sequence; cheat->currentArg = 0; return (true); } return (false); */ *eat = cht_CheckCheat(cheat->seq, key); return *eat; } //========================================================================== // // CHEAT FUNCTIONS // //========================================================================== static void CheatGodFunc(player_t * player, Cheat_t * cheat) { player->cheats ^= CF_GODMODE; if (player->cheats & CF_GODMODE) { P_SetMessage(player, TXT_CHEATGODON, true); } else { P_SetMessage(player, TXT_CHEATGODOFF, true); } SB_state = -1; } static void CheatNoClipFunc(player_t * player, Cheat_t * cheat) { player->cheats ^= CF_NOCLIP; if (player->cheats & CF_NOCLIP) { P_SetMessage(player, TXT_CHEATNOCLIPON, true); } else { P_SetMessage(player, TXT_CHEATNOCLIPOFF, true); } } static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat) { int i; //extern boolean *WeaponInShareware; for (i = 0; i < NUMARMOR; i++) { player->armorpoints[i] = ArmorIncrement[player->class][i]; } for (i = 0; i < NUMWEAPONS; i++) { player->weaponowned[i] = true; } for (i = 0; i < NUMMANA; i++) { player->mana[i] = MAX_MANA; } P_SetMessage(player, TXT_CHEATWEAPONS, true); } static void CheatHealthFunc(player_t * player, Cheat_t * cheat) { if (player->morphTics) { player->health = player->mo->health = MAXMORPHHEALTH; } else { player->health = player->mo->health = MAXHEALTH; } P_SetMessage(player, TXT_CHEATHEALTH, true); } static void CheatKeysFunc(player_t * player, Cheat_t * cheat) { player->keys = 2047; P_SetMessage(player, TXT_CHEATKEYS, true); } static void CheatSoundFunc(player_t * player, Cheat_t * cheat) { DebugSound = !DebugSound; if (DebugSound) { P_SetMessage(player, TXT_CHEATSOUNDON, true); } else { P_SetMessage(player, TXT_CHEATSOUNDOFF, true); } } static void CheatTickerFunc(player_t * player, Cheat_t * cheat) { DisplayTicker = !DisplayTicker; if (DisplayTicker) { P_SetMessage(player, TXT_CHEATTICKERON, true); } else { P_SetMessage(player, TXT_CHEATTICKEROFF, true); } I_DisplayFPSDots(DisplayTicker); } static void CheatArtifactAllFunc(player_t * player, Cheat_t * cheat) { int i; int j; for (i = arti_none + 1; i < arti_firstpuzzitem; i++) { for (j = 0; j < 25; j++) { P_GiveArtifact(player, i, NULL); } } P_SetMessage(player, TXT_CHEATARTIFACTS3, true); } static void CheatPuzzleFunc(player_t * player, Cheat_t * cheat) { int i; for (i = arti_firstpuzzitem; i < NUMARTIFACTS; i++) { P_GiveArtifact(player, i, NULL); } P_SetMessage(player, TXT_CHEATARTIFACTS3, true); } static void CheatInitFunc(player_t * player, Cheat_t * cheat) { G_DeferedInitNew(gameskill, gameepisode, gamemap); P_SetMessage(player, TXT_CHEATWARP, true); } static void CheatWarpFunc(player_t * player, Cheat_t * cheat) { int tens; int ones; int map; char mapName[9]; char args[2]; cht_GetParam(cheat->seq, args); tens = args[0] - '0'; ones = args[1] - '0'; if (tens < 0 || tens > 9 || ones < 0 || ones > 9) { // Bad map P_SetMessage(player, TXT_CHEATBADINPUT, true); return; } map = P_TranslateMap((args[0] - '0') * 10 + args[1] - '0'); if (map == -1) { // Not found P_SetMessage(player, TXT_CHEATNOMAP, true); return; } if (map == gamemap) { // Don't try to teleport to current map P_SetMessage(player, TXT_CHEATBADINPUT, true); return; } M_snprintf(mapName, sizeof(mapName), "MAP%02d", map); if (W_CheckNumForName(mapName) == -1) { // Can't find P_SetMessage(player, TXT_CHEATNOMAP, true); return; } P_SetMessage(player, TXT_CHEATWARP, true); G_TeleportNewMap(map, 0); } static void CheatPigFunc(player_t * player, Cheat_t * cheat) { extern boolean P_UndoPlayerMorph(player_t * player); if (player->morphTics) { P_UndoPlayerMorph(player); } else { P_MorphPlayer(player); } P_SetMessage(player, "SQUEAL!!", true); } static void CheatMassacreFunc(player_t * player, Cheat_t * cheat) { int count; char buffer[80]; count = P_Massacre(); M_snprintf(buffer, sizeof(buffer), "%d MONSTERS KILLED\n", count); P_SetMessage(player, buffer, true); } static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat) { int i; if (player->morphTics) { return; } for (i = 1; i < NUMWEAPONS; i++) { player->weaponowned[i] = false; } // In the original code, NUMWEAPONS was 8. So the writes to weaponowned // overflowed the array. We must set the following fields to zero as // well: player->mana[0] = 0; player->mana[1] = 0; player->attackdown = 0; player->usedown = 0; player->pendingweapon = WP_FIRST; P_SetMessage(player, TXT_CHEATIDKFA, true); } static void CheatQuickenFunc1(player_t * player, Cheat_t * cheat) { P_SetMessage(player, "TRYING TO CHEAT? THAT'S ONE....", true); } static void CheatQuickenFunc2(player_t * player, Cheat_t * cheat) { P_SetMessage(player, "THAT'S TWO....", true); } static void CheatQuickenFunc3(player_t * player, Cheat_t * cheat) { P_DamageMobj(player->mo, NULL, player->mo, 10000); P_SetMessage(player, "THAT'S THREE! TIME TO DIE.", true); } static void CheatClassFunc1(player_t * player, Cheat_t * cheat) { P_SetMessage(player, "ENTER NEW PLAYER CLASS (0 - 2)", true); } static void CheatClassFunc2(player_t * player, Cheat_t * cheat) { int i; int class; char args[2]; cht_GetParam(cheat->seq, args); if (player->morphTics) { // don't change class if the player is morphed return; } class = args[0] - '0'; if (class > 2 || class < 0) { P_SetMessage(player, "INVALID PLAYER CLASS", true); return; } player->class = class; for (i = 0; i < NUMARMOR; i++) { player->armorpoints[i] = 0; } PlayerClass[consoleplayer] = class; P_PostMorphWeapon(player, WP_FIRST); SB_SetClassData(); SB_state = -1; UpdateState |= I_FULLSCRN; } static void CheatVersionFunc(player_t * player, Cheat_t * cheat) { P_SetMessage(player, HEXEN_VERSIONTEXT, true); } static void CheatDebugFunc(player_t * player, Cheat_t * cheat) { char textBuffer[50]; M_snprintf(textBuffer, sizeof(textBuffer), "MAP %d (%d) X:%5d Y:%5d Z:%5d", P_GetMapWarpTrans(gamemap), gamemap, player->mo->x >> FRACBITS, player->mo->y >> FRACBITS, player->mo->z >> FRACBITS); P_SetMessage(player, textBuffer, true); } static void CheatScriptFunc1(player_t * player, Cheat_t * cheat) { P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true); } static void CheatScriptFunc2(player_t * player, Cheat_t * cheat) { P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true); } static void CheatScriptFunc3(player_t * player, Cheat_t * cheat) { int script; byte script_args[3]; int tens, ones; char textBuffer[40]; char args[2]; cht_GetParam(cheat->seq, args); tens = args[0] - '0'; ones = args[1] - '0'; script = tens * 10 + ones; if (script < 1) return; if (script > 99) return; script_args[0] = script_args[1] = script_args[2] = 0; if (P_StartACS(script, 0, script_args, player->mo, NULL, 0)) { M_snprintf(textBuffer, sizeof(textBuffer), "RUNNING SCRIPT %.2d", script); P_SetMessage(player, textBuffer, true); } } extern int cheating; static void CheatRevealFunc(player_t * player, Cheat_t * cheat) { cheating = (cheating + 1) % 3; } //=========================================================================== // // CheatTrackFunc1 // //=========================================================================== static void CheatTrackFunc1(player_t * player, Cheat_t * cheat) { char buffer[80]; if (!cdmusic) { return; } if (I_CDMusInit() == -1) { P_SetMessage(player, "ERROR INITIALIZING CD", true); } M_snprintf(buffer, sizeof(buffer), "ENTER DESIRED CD TRACK (%.2d - %.2d):\n", I_CDMusFirstTrack(), I_CDMusLastTrack()); P_SetMessage(player, buffer, true); } //=========================================================================== // // CheatTrackFunc2 // //=========================================================================== static void CheatTrackFunc2(player_t * player, Cheat_t * cheat) { char buffer[80]; int track; char args[2]; cht_GetParam(cheat->seq, args); if (!cdmusic) { return; } track = (args[0] - '0') * 10 + (args[1] - '0'); if (track < I_CDMusFirstTrack() || track > I_CDMusLastTrack()) { P_SetMessage(player, "INVALID TRACK NUMBER\n", true); return; } if (track == S_GetCurrentCDTrack()) { return; } if (!S_StartCustomCDTrack(track)) { M_snprintf(buffer, sizeof(buffer), "ERROR WHILE TRYING TO PLAY CD TRACK: %.2d\n", track); P_SetMessage(player, buffer, true); } else { // No error encountered while attempting to play the track M_snprintf(buffer, sizeof(buffer), "PLAYING TRACK: %.2d\n", track); P_SetMessage(player, buffer, true); } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/sc_man.c000066400000000000000000000254311257432200600226140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include #include #include "h2def.h" #include "i_system.h" #include "m_misc.h" // MACROS ------------------------------------------------------------------ #define MAX_STRING_SIZE 64 #define ASCII_COMMENT (';') #define ASCII_QUOTE (34) #define LUMP_SCRIPT 1 #define FILE_ZONE_SCRIPT 2 // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void CheckOpen(void); static void OpenScript(char *name, int type); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- char *sc_String; int sc_Number; int sc_Line; boolean sc_End; boolean sc_Crossed; boolean sc_FileScripts = false; char *sc_ScriptsDir = ""; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static char ScriptName[16]; static char *ScriptBuffer; static char *ScriptPtr; static char *ScriptEndPtr; static char StringBuffer[MAX_STRING_SIZE]; static int ScriptLumpNum; static boolean ScriptOpen = false; static int ScriptSize; static boolean AlreadyGot = false; // CODE -------------------------------------------------------------------- //========================================================================== // // SC_Open // //========================================================================== void SC_Open(char *name) { char fileName[128]; if (sc_FileScripts == true) { M_snprintf(fileName, sizeof(fileName), "%s%s.txt", sc_ScriptsDir, name); SC_OpenFile(fileName); } else { SC_OpenLump(name); } } //========================================================================== // // SC_OpenLump // // Loads a script (from the WAD files) and prepares it for parsing. // //========================================================================== void SC_OpenLump(char *name) { OpenScript(name, LUMP_SCRIPT); } //========================================================================== // // SC_OpenFile // // Loads a script (from a file) and prepares it for parsing. Uses the // zone memory allocator for memory allocation and de-allocation. // //========================================================================== void SC_OpenFile(char *name) { OpenScript(name, FILE_ZONE_SCRIPT); } //========================================================================== // // OpenScript // //========================================================================== static void OpenScript(char *name, int type) { SC_Close(); if (type == LUMP_SCRIPT) { // Lump script ScriptLumpNum = W_GetNumForName(name); ScriptBuffer = (char *) W_CacheLumpNum(ScriptLumpNum, PU_STATIC); ScriptSize = W_LumpLength(ScriptLumpNum); M_StringCopy(ScriptName, name, sizeof(ScriptName)); } else if (type == FILE_ZONE_SCRIPT) { // File script - zone ScriptLumpNum = -1; ScriptSize = M_ReadFile(name, (byte **) & ScriptBuffer); M_ExtractFileBase(name, ScriptName); } ScriptPtr = ScriptBuffer; ScriptEndPtr = ScriptPtr + ScriptSize; sc_Line = 1; sc_End = false; ScriptOpen = true; sc_String = StringBuffer; AlreadyGot = false; } //========================================================================== // // SC_Close // //========================================================================== void SC_Close(void) { if (ScriptOpen) { if (ScriptLumpNum >= 0) { W_ReleaseLumpNum(ScriptLumpNum); } else { Z_Free(ScriptBuffer); } ScriptOpen = false; } } //========================================================================== // // SC_GetString // //========================================================================== boolean SC_GetString(void) { char *text; boolean foundToken; CheckOpen(); if (AlreadyGot) { AlreadyGot = false; return true; } foundToken = false; sc_Crossed = false; if (ScriptPtr >= ScriptEndPtr) { sc_End = true; return false; } while (foundToken == false) { while (*ScriptPtr <= 32) { if (ScriptPtr >= ScriptEndPtr) { sc_End = true; return false; } if (*ScriptPtr++ == '\n') { sc_Line++; sc_Crossed = true; } } if (ScriptPtr >= ScriptEndPtr) { sc_End = true; return false; } if (*ScriptPtr != ASCII_COMMENT) { // Found a token foundToken = true; } else { // Skip comment while (*ScriptPtr++ != '\n') { if (ScriptPtr >= ScriptEndPtr) { sc_End = true; return false; } } sc_Line++; sc_Crossed = true; } } text = sc_String; if (*ScriptPtr == ASCII_QUOTE) { // Quoted string ScriptPtr++; while (*ScriptPtr != ASCII_QUOTE) { *text++ = *ScriptPtr++; if (ScriptPtr == ScriptEndPtr || text == &sc_String[MAX_STRING_SIZE - 1]) { break; } } ScriptPtr++; } else { // Normal string while ((*ScriptPtr > 32) && (*ScriptPtr != ASCII_COMMENT)) { *text++ = *ScriptPtr++; if (ScriptPtr == ScriptEndPtr || text == &sc_String[MAX_STRING_SIZE - 1]) { break; } } } *text = 0; return true; } //========================================================================== // // SC_MustGetString // //========================================================================== void SC_MustGetString(void) { if (SC_GetString() == false) { SC_ScriptError("Missing string."); } } //========================================================================== // // SC_MustGetStringName // //========================================================================== void SC_MustGetStringName(char *name) { SC_MustGetString(); if (SC_Compare(name) == false) { SC_ScriptError(NULL); } } //========================================================================== // // SC_GetNumber // //========================================================================== boolean SC_GetNumber(void) { char *stopper; CheckOpen(); if (SC_GetString()) { sc_Number = strtol(sc_String, &stopper, 0); if (*stopper != 0) { I_Error("SC_GetNumber: Bad numeric constant \"%s\".\n" "Script %s, Line %d", sc_String, ScriptName, sc_Line); } return true; } else { return false; } } //========================================================================== // // SC_MustGetNumber // //========================================================================== void SC_MustGetNumber(void) { if (SC_GetNumber() == false) { SC_ScriptError("Missing integer."); } } //========================================================================== // // SC_UnGet // // Assumes there is a valid string in sc_String. // //========================================================================== void SC_UnGet(void) { AlreadyGot = true; } //========================================================================== // // SC_Check // // Returns true if another token is on the current line. // //========================================================================== /* boolean SC_Check(void) { char *text; CheckOpen(); text = ScriptPtr; if(text >= ScriptEndPtr) { return false; } while(*text <= 32) { if(*text == '\n') { return false; } text++; if(text == ScriptEndPtr) { return false; } } if(*text == ASCII_COMMENT) { return false; } return true; } */ //========================================================================== // // SC_MatchString // // Returns the index of the first match to sc_String from the passed // array of strings, or -1 if not found. // //========================================================================== int SC_MatchString(char **strings) { int i; for (i = 0; *strings != NULL; i++) { if (SC_Compare(*strings++)) { return i; } } return -1; } //========================================================================== // // SC_MustMatchString // //========================================================================== int SC_MustMatchString(char **strings) { int i; i = SC_MatchString(strings); if (i == -1) { SC_ScriptError(NULL); } return i; } //========================================================================== // // SC_Compare // //========================================================================== boolean SC_Compare(char *text) { if (strcasecmp(text, sc_String) == 0) { return true; } return false; } //========================================================================== // // SC_ScriptError // //========================================================================== void SC_ScriptError(char *message) { if (message == NULL) { message = "Bad syntax."; } I_Error("Script error, \"%s\" line %d: %s", ScriptName, sc_Line, message); } //========================================================================== // // CheckOpen // //========================================================================== static void CheckOpen(void) { if (ScriptOpen == false) { I_Error("SC_ call before SC_Open()."); } } chocolate-doom-chocolate-doom-2.2.1/src/hexen/sn_sonix.c000066400000000000000000000354321257432200600232160ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include #include "m_random.h" #include "h2def.h" #include "i_system.h" #include "i_sound.h" #include "s_sound.h" // MACROS ------------------------------------------------------------------ #define SS_MAX_SCRIPTS 64 #define SS_TEMPBUFFER_SIZE 1024 #define SS_SEQUENCE_NAME_LENGTH 32 #define SS_SCRIPT_NAME "SNDSEQ" #define SS_STRING_PLAY "play" #define SS_STRING_PLAYUNTILDONE "playuntildone" #define SS_STRING_PLAYTIME "playtime" #define SS_STRING_PLAYREPEAT "playrepeat" #define SS_STRING_DELAY "delay" #define SS_STRING_DELAYRAND "delayrand" #define SS_STRING_VOLUME "volume" #define SS_STRING_END "end" #define SS_STRING_STOPSOUND "stopsound" // TYPES ------------------------------------------------------------------- typedef enum { SS_CMD_NONE, SS_CMD_PLAY, SS_CMD_WAITUNTILDONE, // used by PLAYUNTILDONE SS_CMD_PLAYTIME, SS_CMD_PLAYREPEAT, SS_CMD_DELAY, SS_CMD_DELAYRAND, SS_CMD_VOLUME, SS_CMD_STOPSOUND, SS_CMD_END } sscmds_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void VerifySequencePtr(int *base, int *ptr); static int GetSoundOffset(char *name); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern sfxinfo_t S_sfx[]; // PUBLIC DATA DEFINITIONS ------------------------------------------------- // PRIVATE DATA DEFINITIONS ------------------------------------------------ static struct { char name[SS_SEQUENCE_NAME_LENGTH]; int scriptNum; int stopSound; } SequenceTranslate[SEQ_NUMSEQ] = { { "Platform", 0, 0}, { "Platform", 0, 0}, // a 'heavy' platform is just a platform { "PlatformMetal", 0, 0}, { "Platform", 0, 0}, // same with a 'creak' platform { "Silence", 0, 0}, { "Lava", 0, 0}, { "Water", 0, 0}, { "Ice", 0, 0}, { "Earth", 0, 0}, { "PlatformMetal2", 0, 0}, { "DoorNormal", 0, 0}, { "DoorHeavy", 0, 0}, { "DoorMetal", 0, 0}, { "DoorCreak", 0, 0}, { "Silence", 0, 0}, { "Lava", 0, 0}, { "Water", 0, 0}, { "Ice", 0, 0}, { "Earth", 0, 0}, { "DoorMetal2", 0, 0}, { "Wind", 0, 0} }; static int *SequenceData[SS_MAX_SCRIPTS]; int ActiveSequences; seqnode_t *SequenceListHead; // CODE -------------------------------------------------------------------- //========================================================================== // // VerifySequencePtr // // Verifies the integrity of the temporary ptr, and ensures that the ptr // isn't exceeding the size of the temporary buffer //========================================================================== static void VerifySequencePtr(int *base, int *ptr) { if (ptr - base > SS_TEMPBUFFER_SIZE) { I_Error("VerifySequencePtr: tempPtr >= %d\n", SS_TEMPBUFFER_SIZE); } } //========================================================================== // // GetSoundOffset // //========================================================================== static int GetSoundOffset(char *name) { int i; for (i = 0; i < NUMSFX; i++) { if (!strcasecmp(name, S_sfx[i].tagname)) { return i; } } SC_ScriptError("GetSoundOffset: Unknown sound name\n"); return 0; } //========================================================================== // // SN_InitSequenceScript // //========================================================================== void SN_InitSequenceScript(void) { int i, j; int inSequence; int *tempDataStart = NULL; int *tempDataPtr = NULL; inSequence = -1; ActiveSequences = 0; for (i = 0; i < SS_MAX_SCRIPTS; i++) { SequenceData[i] = NULL; } SC_Open(SS_SCRIPT_NAME); while (SC_GetString()) { if (*sc_String == ':') { if (inSequence != -1) { SC_ScriptError("SN_InitSequenceScript: Nested Script Error"); } tempDataStart = (int *) Z_Malloc(SS_TEMPBUFFER_SIZE, PU_STATIC, NULL); memset(tempDataStart, 0, SS_TEMPBUFFER_SIZE); tempDataPtr = tempDataStart; for (i = 0; i < SS_MAX_SCRIPTS; i++) { if (SequenceData[i] == NULL) { break; } } if (i == SS_MAX_SCRIPTS) { I_Error("Number of SS Scripts >= SS_MAX_SCRIPTS"); } for (j = 0; j < SEQ_NUMSEQ; j++) { if (!strcasecmp(SequenceTranslate[j].name, sc_String + 1)) { SequenceTranslate[j].scriptNum = i; inSequence = j; break; } } continue; // parse the next command } if (inSequence == -1) { continue; } if (SC_Compare(SS_STRING_PLAYUNTILDONE)) { VerifySequencePtr(tempDataStart, tempDataPtr); SC_MustGetString(); *tempDataPtr++ = SS_CMD_PLAY; *tempDataPtr++ = GetSoundOffset(sc_String); *tempDataPtr++ = SS_CMD_WAITUNTILDONE; } else if (SC_Compare(SS_STRING_PLAY)) { VerifySequencePtr(tempDataStart, tempDataPtr); SC_MustGetString(); *tempDataPtr++ = SS_CMD_PLAY; *tempDataPtr++ = GetSoundOffset(sc_String); } else if (SC_Compare(SS_STRING_PLAYTIME)) { VerifySequencePtr(tempDataStart, tempDataPtr); SC_MustGetString(); *tempDataPtr++ = SS_CMD_PLAY; *tempDataPtr++ = GetSoundOffset(sc_String); SC_MustGetNumber(); *tempDataPtr++ = SS_CMD_DELAY; *tempDataPtr++ = sc_Number; } else if (SC_Compare(SS_STRING_PLAYREPEAT)) { VerifySequencePtr(tempDataStart, tempDataPtr); SC_MustGetString(); *tempDataPtr++ = SS_CMD_PLAYREPEAT; *tempDataPtr++ = GetSoundOffset(sc_String); } else if (SC_Compare(SS_STRING_DELAY)) { VerifySequencePtr(tempDataStart, tempDataPtr); *tempDataPtr++ = SS_CMD_DELAY; SC_MustGetNumber(); *tempDataPtr++ = sc_Number; } else if (SC_Compare(SS_STRING_DELAYRAND)) { VerifySequencePtr(tempDataStart, tempDataPtr); *tempDataPtr++ = SS_CMD_DELAYRAND; SC_MustGetNumber(); *tempDataPtr++ = sc_Number; SC_MustGetNumber(); *tempDataPtr++ = sc_Number; } else if (SC_Compare(SS_STRING_VOLUME)) { VerifySequencePtr(tempDataStart, tempDataPtr); *tempDataPtr++ = SS_CMD_VOLUME; SC_MustGetNumber(); *tempDataPtr++ = sc_Number; } else if (SC_Compare(SS_STRING_END)) { int dataSize; *tempDataPtr++ = SS_CMD_END; dataSize = (tempDataPtr - tempDataStart) * sizeof(int); SequenceData[i] = (int *) Z_Malloc(dataSize, PU_STATIC, NULL); memcpy(SequenceData[i], tempDataStart, dataSize); Z_Free(tempDataStart); inSequence = -1; } else if (SC_Compare(SS_STRING_STOPSOUND)) { SC_MustGetString(); SequenceTranslate[inSequence].stopSound = GetSoundOffset(sc_String); *tempDataPtr++ = SS_CMD_STOPSOUND; } else { SC_ScriptError("SN_InitSequenceScript: Unknown commmand.\n"); } } } //========================================================================== // // SN_StartSequence // //========================================================================== void SN_StartSequence(mobj_t * mobj, int sequence) { seqnode_t *node; SN_StopSequence(mobj); // Stop any previous sequence node = (seqnode_t *) Z_Malloc(sizeof(seqnode_t), PU_STATIC, NULL); node->sequencePtr = SequenceData[SequenceTranslate[sequence].scriptNum]; node->sequence = sequence; node->mobj = mobj; node->delayTics = 0; node->stopSound = SequenceTranslate[sequence].stopSound; node->volume = 127; // Start at max volume if (!SequenceListHead) { SequenceListHead = node; node->next = node->prev = NULL; } else { SequenceListHead->prev = node; node->next = SequenceListHead; node->prev = NULL; SequenceListHead = node; } ActiveSequences++; return; } //========================================================================== // // SN_StartSequenceName // //========================================================================== void SN_StartSequenceName(mobj_t * mobj, char *name) { int i; for (i = 0; i < SEQ_NUMSEQ; i++) { if (!strcmp(name, SequenceTranslate[i].name)) { SN_StartSequence(mobj, i); return; } } } //========================================================================== // // SN_StopSequence // //========================================================================== void SN_StopSequence(mobj_t * mobj) { seqnode_t *node; for (node = SequenceListHead; node; node = node->next) { if (node->mobj == mobj) { S_StopSound(mobj); if (node->stopSound) { S_StartSoundAtVolume(mobj, node->stopSound, node->volume); } if (SequenceListHead == node) { SequenceListHead = node->next; } if (node->prev) { node->prev->next = node->next; } if (node->next) { node->next->prev = node->prev; } Z_Free(node); ActiveSequences--; } } } //========================================================================== // // SN_UpdateActiveSequences // //========================================================================== void SN_UpdateActiveSequences(void) { seqnode_t *node; boolean sndPlaying; if (!ActiveSequences || paused) { // No sequences currently playing/game is paused return; } for (node = SequenceListHead; node; node = node->next) { if (node->delayTics) { node->delayTics--; continue; } sndPlaying = S_GetSoundPlayingInfo(node->mobj, node->currentSoundID); switch (*node->sequencePtr) { case SS_CMD_PLAY: if (!sndPlaying) { node->currentSoundID = *(node->sequencePtr + 1); S_StartSoundAtVolume(node->mobj, node->currentSoundID, node->volume); } node->sequencePtr += 2; break; case SS_CMD_WAITUNTILDONE: if (!sndPlaying) { node->sequencePtr++; node->currentSoundID = 0; } break; case SS_CMD_PLAYREPEAT: if (!sndPlaying) { node->currentSoundID = *(node->sequencePtr + 1); S_StartSoundAtVolume(node->mobj, node->currentSoundID, node->volume); } break; case SS_CMD_DELAY: node->delayTics = *(node->sequencePtr + 1); node->sequencePtr += 2; node->currentSoundID = 0; break; case SS_CMD_DELAYRAND: node->delayTics = *(node->sequencePtr + 1) + M_Random() % (*(node->sequencePtr + 2) - *(node->sequencePtr + 1)); node->sequencePtr += 2; node->currentSoundID = 0; break; case SS_CMD_VOLUME: node->volume = (127 * (*(node->sequencePtr + 1))) / 100; node->sequencePtr += 2; break; case SS_CMD_STOPSOUND: // Wait until something else stops the sequence break; case SS_CMD_END: SN_StopSequence(node->mobj); break; default: break; } } } //========================================================================== // // SN_StopAllSequences // //========================================================================== void SN_StopAllSequences(void) { seqnode_t *node; for (node = SequenceListHead; node; node = node->next) { node->stopSound = 0; // don't play any stop sounds SN_StopSequence(node->mobj); } } //========================================================================== // // SN_GetSequenceOffset // //========================================================================== int SN_GetSequenceOffset(int sequence, int *sequencePtr) { return (sequencePtr - SequenceData[SequenceTranslate[sequence].scriptNum]); } //========================================================================== // // SN_ChangeNodeData // // nodeNum zero is the first node //========================================================================== void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume, int currentSoundID) { int i; seqnode_t *node; i = 0; node = SequenceListHead; while (node && i < nodeNum) { node = node->next; i++; } if (!node) { // reach the end of the list before finding the nodeNum-th node return; } node->delayTics = delayTics; node->volume = volume; node->sequencePtr += seqOffset; node->currentSoundID = currentSoundID; } chocolate-doom-chocolate-doom-2.2.1/src/hexen/sounds.c000066400000000000000000000257341257432200600226750ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "h2def.h" #include "sounds.h" // Music info /* musicinfo_t S_music[] = { { "MUS_E1M1", 0 }, // 1-1 { "MUS_E1M2", 0 }, { "MUS_E1M3", 0 }, { "MUS_E1M4", 0 }, { "MUS_E1M5", 0 }, { "MUS_E1M6", 0 }, { "MUS_E1M7", 0 }, { "MUS_E1M8", 0 }, { "MUS_E1M9", 0 }, { "MUS_E2M1", 0 }, // 2-1 { "MUS_E2M2", 0 }, { "MUS_E2M3", 0 }, { "MUS_E2M4", 0 }, { "MUS_E1M4", 0 }, { "MUS_E2M6", 0 }, { "MUS_E2M7", 0 }, { "MUS_E2M8", 0 }, { "MUS_E2M9", 0 }, { "MUS_E1M1", 0 }, // 3-1 { "MUS_E3M2", 0 }, { "MUS_E3M3", 0 }, { "MUS_E1M6", 0 }, { "MUS_E1M3", 0 }, { "MUS_E1M2", 0 }, { "MUS_E1M5", 0 }, { "MUS_E1M9", 0 }, { "MUS_E2M6", 0 }, { "MUS_E1M6", 0 }, // 4-1 { "MUS_TITL", 0 }, { "MUS_INTR", 0 }, { "MUS_CPTD", 0 } }; */ // Sound info #define SOUND(name, priority, numchannels, pitchshift) \ { name, "", priority, NULL, pitchshift, 0, -1, 0, numchannels, NULL } sfxinfo_t S_sfx[] = { // tagname, lumpname, priority, usefulness, snd_ptr, lumpnum, numchannels, // pitchshift SOUND("", 0, 0, 0), SOUND("PlayerFighterNormalDeath", 256, 2, 1), SOUND("PlayerFighterCrazyDeath", 256, 2, 1), SOUND("PlayerFighterExtreme1Death", 256, 2, 1), SOUND("PlayerFighterExtreme2Death", 256, 2, 1), SOUND("PlayerFighterExtreme3Death", 256, 2, 1), SOUND("PlayerFighterBurnDeath", 256, 2, 1), SOUND("PlayerClericNormalDeath", 256, 2, 1), SOUND("PlayerClericCrazyDeath", 256, 2, 1), SOUND("PlayerClericExtreme1Death", 256, 2, 1), SOUND("PlayerClericExtreme2Death", 256, 2, 1), SOUND("PlayerClericExtreme3Death", 256, 2, 1), SOUND("PlayerClericBurnDeath", 256, 2, 1), SOUND("PlayerMageNormalDeath", 256, 2, 0), SOUND("PlayerMageCrazyDeath", 256, 2, 0), SOUND("PlayerMageExtreme1Death", 256, 2, 0), SOUND("PlayerMageExtreme2Death", 256, 2, 0), SOUND("PlayerMageExtreme3Death", 256, 2, 0), SOUND("PlayerMageBurnDeath", 256, 2, 0), SOUND("PlayerFighterPain", 256, 2, 1), SOUND("PlayerClericPain", 256, 2, 1), SOUND("PlayerMagePain", 256, 2, 0), SOUND("PlayerFighterGrunt", 256, 2, 1), SOUND("PlayerClericGrunt", 256, 2, 1), SOUND("PlayerMageGrunt", 256, 2, 0), SOUND("PlayerLand", 32, 2, 1), SOUND("PlayerPoisonCough", 256, 2, 1), SOUND("PlayerFighterFallingScream", 256, 2, 1), SOUND("PlayerClericFallingScream", 256, 2, 1), SOUND("PlayerMageFallingScream", 256, 2, 0), SOUND("PlayerFallingSplat", 256, 2, 1), SOUND("PlayerFighterFailedUse", 256, 1, 1), SOUND("PlayerClericFailedUse", 256, 1, 1), SOUND("PlayerMageFailedUse", 256, 1, 0), SOUND("PlatformStart", 36, 2, 1), SOUND("PlatformStartMetal", 36, 2, 1), SOUND("PlatformStop", 40, 2, 1), SOUND("StoneMove", 32, 2, 1), SOUND("MetalMove", 32, 2, 1), SOUND("DoorOpen", 36, 2, 1), SOUND("DoorLocked", 36, 2, 1), SOUND("DoorOpenMetal", 36, 2, 1), SOUND("DoorCloseMetal", 36, 2, 1), SOUND("DoorCloseLight", 36, 2, 1), SOUND("DoorCloseHeavy", 36, 2, 1), SOUND("DoorCreak", 36, 2, 1), SOUND("PickupWeapon", 36, 2, 0), SOUND("PickupArtifact", 36, 2, 1), SOUND("PickupKey", 36, 2, 1), SOUND("PickupItem", 36, 2, 1), SOUND("PickupPiece", 36, 2, 0), SOUND("WeaponBuild", 36, 2, 0), SOUND("UseArtifact", 36, 2, 1), SOUND("BlastRadius", 36, 2, 1), SOUND("Teleport", 256, 2, 1), SOUND("ThunderCrash", 30, 2, 1), SOUND("FighterPunchMiss", 80, 2, 1), SOUND("FighterPunchHitThing", 80, 2, 1), SOUND("FighterPunchHitWall", 80, 2, 1), SOUND("FighterGrunt", 80, 2, 1), SOUND("FighterAxeHitThing", 80, 2, 1), SOUND("FighterHammerMiss", 80, 2, 1), SOUND("FighterHammerHitThing", 80, 2, 1), SOUND("FighterHammerHitWall", 80, 2, 1), SOUND("FighterHammerContinuous", 32, 2, 1), SOUND("FighterHammerExplode", 80, 2, 1), SOUND("FighterSwordFire", 80, 2, 1), SOUND("FighterSwordExplode", 80, 2, 1), SOUND("ClericCStaffFire", 80, 2, 1), SOUND("ClericCStaffExplode", 40, 2, 1), SOUND("ClericCStaffHitThing", 80, 2, 1), SOUND("ClericFlameFire", 80, 2, 1), SOUND("ClericFlameExplode", 80, 2, 1), SOUND("ClericFlameCircle", 80, 2, 1), SOUND("MageWandFire", 80, 2, 1), SOUND("MageLightningFire", 80, 2, 1), SOUND("MageLightningZap", 32, 2, 1), SOUND("MageLightningContinuous", 32, 2, 1), SOUND("MageLightningReady", 30, 2, 1), SOUND("MageShardsFire", 80, 2, 1), SOUND("MageShardsExplode", 36, 2, 1), SOUND("MageStaffFire", 80, 2, 1), SOUND("MageStaffExplode", 40, 2, 1), SOUND("Switch1", 32, 2, 1), SOUND("Switch2", 32, 2, 1), SOUND("SerpentSight", 32, 2, 1), SOUND("SerpentActive", 32, 2, 1), SOUND("SerpentPain", 32, 2, 1), SOUND("SerpentAttack", 32, 2, 1), SOUND("SerpentMeleeHit", 32, 2, 1), SOUND("SerpentDeath", 40, 2, 1), SOUND("SerpentBirth", 32, 2, 1), SOUND("SerpentFXContinuous", 32, 2, 1), SOUND("SerpentFXHit", 32, 2, 1), SOUND("PotteryExplode", 32, 2, 1), SOUND("Drip", 32, 2, 1), SOUND("CentaurSight", 32, 2, 1), SOUND("CentaurActive", 32, 2, 1), SOUND("CentaurPain", 32, 2, 1), SOUND("CentaurAttack", 32, 2, 1), SOUND("CentaurDeath", 40, 2, 1), SOUND("CentaurLeaderAttack", 32, 2, 1), SOUND("CentaurMissileExplode", 32, 2, 1), SOUND("Wind", 1, 2, 1), SOUND("BishopSight", 32, 2, 1), SOUND("BishopActive", 32, 2, 1), SOUND("BishopPain", 32, 2, 1), SOUND("BishopAttack", 32, 2, 1), SOUND("BishopDeath", 40, 2, 1), SOUND("BishopMissileExplode", 32, 2, 1), SOUND("BishopBlur", 32, 2, 1), SOUND("DemonSight", 32, 2, 1), SOUND("DemonActive", 32, 2, 1), SOUND("DemonPain", 32, 2, 1), SOUND("DemonAttack", 32, 2, 1), SOUND("DemonMissileFire", 32, 2, 1), SOUND("DemonMissileExplode", 32, 2, 1), SOUND("DemonDeath", 40, 2, 1), SOUND("WraithSight", 32, 2, 1), SOUND("WraithActive", 32, 2, 1), SOUND("WraithPain", 32, 2, 1), SOUND("WraithAttack", 32, 2, 1), SOUND("WraithMissileFire", 32, 2, 1), SOUND("WraithMissileExplode", 32, 2, 1), SOUND("WraithDeath", 40, 2, 1), SOUND("PigActive1", 32, 2, 1), SOUND("PigActive2", 32, 2, 1), SOUND("PigPain", 32, 2, 1), SOUND("PigAttack", 32, 2, 1), SOUND("PigDeath", 40, 2, 1), SOUND("MaulatorSight", 32, 2, 1), SOUND("MaulatorActive", 32, 2, 1), SOUND("MaulatorPain", 32, 2, 1), SOUND("MaulatorHamSwing", 32, 2, 1), SOUND("MaulatorHamHit", 32, 2, 1), SOUND("MaulatorMissileHit", 32, 2, 1), SOUND("MaulatorDeath", 40, 2, 1), SOUND("FreezeDeath", 40, 2, 1), SOUND("FreezeShatter", 40, 2, 1), SOUND("EttinSight", 32, 2, 1), SOUND("EttinActive", 32, 2, 1), SOUND("EttinPain", 32, 2, 1), SOUND("EttinAttack", 32, 2, 1), SOUND("EttinDeath", 40, 2, 1), SOUND("FireDemonSpawn", 32, 2, 1), SOUND("FireDemonActive", 32, 2, 1), SOUND("FireDemonPain", 32, 2, 1), SOUND("FireDemonAttack", 32, 2, 1), SOUND("FireDemonMissileHit", 32, 2, 1), SOUND("FireDemonDeath", 40, 2, 1), SOUND("IceGuySight", 32, 2, 1), SOUND("IceGuyActive", 32, 2, 1), SOUND("IceGuyAttack", 32, 2, 1), SOUND("IceGuyMissileExplode", 32, 2, 1), SOUND("SorcererSight", 256, 2, 1), SOUND("SorcererActive", 256, 2, 1), SOUND("SorcererPain", 256, 2, 1), SOUND("SorcererSpellCast", 256, 2, 1), SOUND("SorcererBallWoosh", 256, 4, 1), SOUND("SorcererDeathScream", 256, 2, 1), SOUND("SorcererBishopSpawn", 80, 2, 1), SOUND("SorcererBallPop", 80, 2, 1), SOUND("SorcererBallBounce", 80, 3, 1), SOUND("SorcererBallExplode", 80, 3, 1), SOUND("SorcererBigBallExplode", 80, 3, 1), SOUND("SorcererHeadScream", 256, 2, 1), SOUND("DragonSight", 64, 2, 1), SOUND("DragonActive", 64, 2, 1), SOUND("DragonWingflap", 64, 2, 1), SOUND("DragonAttack", 64, 2, 1), SOUND("DragonPain", 64, 2, 1), SOUND("DragonDeath", 64, 2, 1), SOUND("DragonFireballExplode", 32, 2, 1), SOUND("KoraxSight", 256, 2, 1), SOUND("KoraxActive", 256, 2, 1), SOUND("KoraxPain", 256, 2, 1), SOUND("KoraxAttack", 256, 2, 1), SOUND("KoraxCommand", 256, 2, 1), SOUND("KoraxDeath", 256, 2, 1), SOUND("KoraxStep", 128, 2, 1), SOUND("ThrustSpikeRaise", 32, 2, 1), SOUND("ThrustSpikeLower", 32, 2, 1), SOUND("GlassShatter", 32, 2, 1), SOUND("FlechetteBounce", 32, 2, 1), SOUND("FlechetteExplode", 32, 2, 1), SOUND("LavaMove", 36, 2, 1), SOUND("WaterMove", 36, 2, 1), SOUND("IceStartMove", 36, 2, 1), SOUND("EarthStartMove", 36, 2, 1), SOUND("WaterSplash", 32, 2, 1), SOUND("LavaSizzle", 32, 2, 1), SOUND("SludgeGloop", 32, 2, 1), SOUND("HolySymbolFire", 64, 2, 1), SOUND("SpiritActive", 32, 2, 1), SOUND("SpiritAttack", 32, 2, 1), SOUND("SpiritDie", 32, 2, 1), SOUND("ValveTurn", 36, 2, 1), SOUND("RopePull", 36, 2, 1), SOUND("FlyBuzz", 20, 2, 1), SOUND("Ignite", 32, 2, 1), SOUND("PuzzleSuccess", 256, 2, 1), SOUND("PuzzleFailFighter", 256, 2, 1), SOUND("PuzzleFailCleric", 256, 2, 1), SOUND("PuzzleFailMage", 256, 2, 1), SOUND("Earthquake", 32, 2, 1), SOUND("BellRing", 32, 2, 0), SOUND("TreeBreak", 32, 2, 1), SOUND("TreeExplode", 32, 2, 1), SOUND("SuitofArmorBreak", 32, 2, 1), SOUND("PoisonShroomPain", 20, 2, 1), SOUND("PoisonShroomDeath", 32, 2, 1), SOUND("Ambient1", 1, 1, 1), SOUND("Ambient2", 1, 1, 1), SOUND("Ambient3", 1, 1, 1), SOUND("Ambient4", 1, 1, 1), SOUND("Ambient5", 1, 1, 1), SOUND("Ambient6", 1, 1, 1), SOUND("Ambient7", 1, 1, 1), SOUND("Ambient8", 1, 1, 1), SOUND("Ambient9", 1, 1, 1), SOUND("Ambient10", 1, 1, 1), SOUND("Ambient11", 1, 1, 1), SOUND("Ambient12", 1, 1, 1), SOUND("Ambient13", 1, 1, 1), SOUND("Ambient14", 1, 1, 1), SOUND("Ambient15", 1, 1, 1), SOUND("StartupTick", 32, 2, 1), SOUND("SwitchOtherLevel", 32, 2, 1), SOUND("Respawn", 32, 2, 1), SOUND("KoraxVoiceGreetings", 512, 2, 1), SOUND("KoraxVoiceReady", 512, 2, 1), SOUND("KoraxVoiceBlood", 512, 2, 1), SOUND("KoraxVoiceGame", 512, 2, 1), SOUND("KoraxVoiceBoard", 512, 2, 1), SOUND("KoraxVoiceWorship", 512, 2, 1), SOUND("KoraxVoiceMaybe", 512, 2, 1), SOUND("KoraxVoiceStrong", 512, 2, 1), SOUND("KoraxVoiceFace", 512, 2, 1), SOUND("BatScream", 32, 2, 1), SOUND("Chat", 512, 2, 1), SOUND("MenuMove", 32, 2, 1), SOUND("ClockTick", 32, 2, 1), SOUND("Fireball", 32, 2, 1), SOUND("PuppyBeat", 30, 2, 1), SOUND("MysticIncant", 32, 4, 1), }; chocolate-doom-chocolate-doom-2.2.1/src/hexen/sounds.h000066400000000000000000000165351257432200600227010ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __SOUNDSH__ #define __SOUNDSH__ #include "i_sound.h" #define MAX_SND_DIST 2025 #define MAX_CHANNELS 16 // Music identifiers typedef enum { mus_e1m1, mus_e1m2, mus_e1m3, mus_e1m4, mus_e1m5, mus_e1m6, mus_e1m7, mus_e1m8, mus_e1m9, mus_e2m1, mus_e2m2, mus_e2m3, mus_e2m4, mus_e2m5, mus_e2m6, mus_e2m7, mus_e2m8, mus_e2m9, mus_e3m1, mus_e3m2, mus_e3m3, mus_e3m4, mus_e3m5, mus_e3m6, mus_e3m7, mus_e3m8, mus_e3m9, mus_e4m1, mus_titl, mus_intr, mus_cptd, NUMMUSIC } musicenum_t; // Sound identifiers typedef enum { SFX_NONE, SFX_PLAYER_FIGHTER_NORMAL_DEATH, // class specific death screams SFX_PLAYER_FIGHTER_CRAZY_DEATH, SFX_PLAYER_FIGHTER_EXTREME1_DEATH, SFX_PLAYER_FIGHTER_EXTREME2_DEATH, SFX_PLAYER_FIGHTER_EXTREME3_DEATH, SFX_PLAYER_FIGHTER_BURN_DEATH, SFX_PLAYER_CLERIC_NORMAL_DEATH, SFX_PLAYER_CLERIC_CRAZY_DEATH, SFX_PLAYER_CLERIC_EXTREME1_DEATH, SFX_PLAYER_CLERIC_EXTREME2_DEATH, SFX_PLAYER_CLERIC_EXTREME3_DEATH, SFX_PLAYER_CLERIC_BURN_DEATH, SFX_PLAYER_MAGE_NORMAL_DEATH, SFX_PLAYER_MAGE_CRAZY_DEATH, SFX_PLAYER_MAGE_EXTREME1_DEATH, SFX_PLAYER_MAGE_EXTREME2_DEATH, SFX_PLAYER_MAGE_EXTREME3_DEATH, SFX_PLAYER_MAGE_BURN_DEATH, SFX_PLAYER_FIGHTER_PAIN, SFX_PLAYER_CLERIC_PAIN, SFX_PLAYER_MAGE_PAIN, SFX_PLAYER_FIGHTER_GRUNT, SFX_PLAYER_CLERIC_GRUNT, SFX_PLAYER_MAGE_GRUNT, SFX_PLAYER_LAND, SFX_PLAYER_POISONCOUGH, SFX_PLAYER_FIGHTER_FALLING_SCREAM, // class specific falling screams SFX_PLAYER_CLERIC_FALLING_SCREAM, SFX_PLAYER_MAGE_FALLING_SCREAM, SFX_PLAYER_FALLING_SPLAT, SFX_PLAYER_FIGHTER_FAILED_USE, SFX_PLAYER_CLERIC_FAILED_USE, SFX_PLAYER_MAGE_FAILED_USE, SFX_PLATFORM_START, SFX_PLATFORM_STARTMETAL, SFX_PLATFORM_STOP, SFX_STONE_MOVE, SFX_METAL_MOVE, SFX_DOOR_OPEN, SFX_DOOR_LOCKED, SFX_DOOR_METAL_OPEN, SFX_DOOR_METAL_CLOSE, SFX_DOOR_LIGHT_CLOSE, SFX_DOOR_HEAVY_CLOSE, SFX_DOOR_CREAK, SFX_PICKUP_WEAPON, SFX_PICKUP_ARTIFACT, SFX_PICKUP_KEY, SFX_PICKUP_ITEM, SFX_PICKUP_PIECE, SFX_WEAPON_BUILD, SFX_ARTIFACT_USE, SFX_ARTIFACT_BLAST, SFX_TELEPORT, SFX_THUNDER_CRASH, SFX_FIGHTER_PUNCH_MISS, SFX_FIGHTER_PUNCH_HITTHING, SFX_FIGHTER_PUNCH_HITWALL, SFX_FIGHTER_GRUNT, SFX_FIGHTER_AXE_HITTHING, SFX_FIGHTER_HAMMER_MISS, SFX_FIGHTER_HAMMER_HITTHING, SFX_FIGHTER_HAMMER_HITWALL, SFX_FIGHTER_HAMMER_CONTINUOUS, SFX_FIGHTER_HAMMER_EXPLODE, SFX_FIGHTER_SWORD_FIRE, SFX_FIGHTER_SWORD_EXPLODE, SFX_CLERIC_CSTAFF_FIRE, SFX_CLERIC_CSTAFF_EXPLODE, SFX_CLERIC_CSTAFF_HITTHING, SFX_CLERIC_FLAME_FIRE, SFX_CLERIC_FLAME_EXPLODE, SFX_CLERIC_FLAME_CIRCLE, SFX_MAGE_WAND_FIRE, SFX_MAGE_LIGHTNING_FIRE, SFX_MAGE_LIGHTNING_ZAP, SFX_MAGE_LIGHTNING_CONTINUOUS, SFX_MAGE_LIGHTNING_READY, SFX_MAGE_SHARDS_FIRE, SFX_MAGE_SHARDS_EXPLODE, SFX_MAGE_STAFF_FIRE, SFX_MAGE_STAFF_EXPLODE, SFX_SWITCH1, SFX_SWITCH2, SFX_SERPENT_SIGHT, SFX_SERPENT_ACTIVE, SFX_SERPENT_PAIN, SFX_SERPENT_ATTACK, SFX_SERPENT_MELEEHIT, SFX_SERPENT_DEATH, SFX_SERPENT_BIRTH, SFX_SERPENTFX_CONTINUOUS, SFX_SERPENTFX_HIT, SFX_POTTERY_EXPLODE, SFX_DRIP, SFX_CENTAUR_SIGHT, SFX_CENTAUR_ACTIVE, SFX_CENTAUR_PAIN, SFX_CENTAUR_ATTACK, SFX_CENTAUR_DEATH, SFX_CENTAURLEADER_ATTACK, SFX_CENTAUR_MISSILE_EXPLODE, SFX_WIND, SFX_BISHOP_SIGHT, SFX_BISHOP_ACTIVE, SFX_BISHOP_PAIN, SFX_BISHOP_ATTACK, SFX_BISHOP_DEATH, SFX_BISHOP_MISSILE_EXPLODE, SFX_BISHOP_BLUR, SFX_DEMON_SIGHT, SFX_DEMON_ACTIVE, SFX_DEMON_PAIN, SFX_DEMON_ATTACK, SFX_DEMON_MISSILE_FIRE, SFX_DEMON_MISSILE_EXPLODE, SFX_DEMON_DEATH, SFX_WRAITH_SIGHT, SFX_WRAITH_ACTIVE, SFX_WRAITH_PAIN, SFX_WRAITH_ATTACK, SFX_WRAITH_MISSILE_FIRE, SFX_WRAITH_MISSILE_EXPLODE, SFX_WRAITH_DEATH, SFX_PIG_ACTIVE1, SFX_PIG_ACTIVE2, SFX_PIG_PAIN, SFX_PIG_ATTACK, SFX_PIG_DEATH, SFX_MAULATOR_SIGHT, SFX_MAULATOR_ACTIVE, SFX_MAULATOR_PAIN, SFX_MAULATOR_HAMMER_SWING, SFX_MAULATOR_HAMMER_HIT, SFX_MAULATOR_MISSILE_HIT, SFX_MAULATOR_DEATH, SFX_FREEZE_DEATH, SFX_FREEZE_SHATTER, SFX_ETTIN_SIGHT, SFX_ETTIN_ACTIVE, SFX_ETTIN_PAIN, SFX_ETTIN_ATTACK, SFX_ETTIN_DEATH, SFX_FIRED_SPAWN, SFX_FIRED_ACTIVE, SFX_FIRED_PAIN, SFX_FIRED_ATTACK, SFX_FIRED_MISSILE_HIT, SFX_FIRED_DEATH, SFX_ICEGUY_SIGHT, SFX_ICEGUY_ACTIVE, SFX_ICEGUY_ATTACK, SFX_ICEGUY_FX_EXPLODE, SFX_SORCERER_SIGHT, SFX_SORCERER_ACTIVE, SFX_SORCERER_PAIN, SFX_SORCERER_SPELLCAST, SFX_SORCERER_BALLWOOSH, SFX_SORCERER_DEATHSCREAM, SFX_SORCERER_BISHOPSPAWN, SFX_SORCERER_BALLPOP, SFX_SORCERER_BALLBOUNCE, SFX_SORCERER_BALLEXPLODE, SFX_SORCERER_BIGBALLEXPLODE, SFX_SORCERER_HEADSCREAM, SFX_DRAGON_SIGHT, SFX_DRAGON_ACTIVE, SFX_DRAGON_WINGFLAP, SFX_DRAGON_ATTACK, SFX_DRAGON_PAIN, SFX_DRAGON_DEATH, SFX_DRAGON_FIREBALL_EXPLODE, SFX_KORAX_SIGHT, SFX_KORAX_ACTIVE, SFX_KORAX_PAIN, SFX_KORAX_ATTACK, SFX_KORAX_COMMAND, SFX_KORAX_DEATH, SFX_KORAX_STEP, SFX_THRUSTSPIKE_RAISE, SFX_THRUSTSPIKE_LOWER, SFX_STAINEDGLASS_SHATTER, SFX_FLECHETTE_BOUNCE, SFX_FLECHETTE_EXPLODE, SFX_LAVA_MOVE, SFX_WATER_MOVE, SFX_ICE_STARTMOVE, SFX_EARTH_STARTMOVE, SFX_WATER_SPLASH, SFX_LAVA_SIZZLE, SFX_SLUDGE_GLOOP, SFX_CHOLY_FIRE, SFX_SPIRIT_ACTIVE, SFX_SPIRIT_ATTACK, SFX_SPIRIT_DIE, SFX_VALVE_TURN, SFX_ROPE_PULL, SFX_FLY_BUZZ, SFX_IGNITE, SFX_PUZZLE_SUCCESS, SFX_PUZZLE_FAIL_FIGHTER, SFX_PUZZLE_FAIL_CLERIC, SFX_PUZZLE_FAIL_MAGE, SFX_EARTHQUAKE, SFX_BELLRING, SFX_TREE_BREAK, SFX_TREE_EXPLODE, SFX_SUITOFARMOR_BREAK, SFX_POISONSHROOM_PAIN, SFX_POISONSHROOM_DEATH, SFX_AMBIENT1, SFX_AMBIENT2, SFX_AMBIENT3, SFX_AMBIENT4, SFX_AMBIENT5, SFX_AMBIENT6, SFX_AMBIENT7, SFX_AMBIENT8, SFX_AMBIENT9, SFX_AMBIENT10, SFX_AMBIENT11, SFX_AMBIENT12, SFX_AMBIENT13, SFX_AMBIENT14, SFX_AMBIENT15, SFX_STARTUP_TICK, SFX_SWITCH_OTHERLEVEL, SFX_RESPAWN, SFX_KORAX_VOICE_1, SFX_KORAX_VOICE_2, SFX_KORAX_VOICE_3, SFX_KORAX_VOICE_4, SFX_KORAX_VOICE_5, SFX_KORAX_VOICE_6, SFX_KORAX_VOICE_7, SFX_KORAX_VOICE_8, SFX_KORAX_VOICE_9, SFX_BAT_SCREAM, SFX_CHAT, SFX_MENU_MOVE, SFX_CLOCK_TICK, SFX_FIREBALL, SFX_PUPPYBEAT, SFX_MYSTICINCANT, NUMSFX } sfxenum_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/hexen/st_start.c000066400000000000000000000201511257432200600232110ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include #include "config.h" #include "h2def.h" #include "i_system.h" #include "i_video.h" #include "i_videohr.h" #include "s_sound.h" #include "st_start.h" // MACROS ------------------------------------------------------------------ #define ST_MAX_NOTCHES 32 #define ST_NOTCH_WIDTH 16 #define ST_NOTCH_HEIGHT 23 #define ST_PROGRESS_X 64 // Start of notches x screen pos. #define ST_PROGRESS_Y 441 // Start of notches y screen pos. #define ST_NETPROGRESS_X 288 #define ST_NETPROGRESS_Y 32 #define ST_NETNOTCH_WIDTH 8 #define ST_NETNOTCH_HEIGHT 16 #define ST_MAX_NETNOTCHES 8 byte *ST_LoadScreen(void); void ST_UpdateNotches(int notchPosition); void ST_UpdateNetNotches(int notchPosition); // PRIVATE DATA DEFINITIONS ------------------------------------------------ static const byte *bitmap = NULL; int graphical_startup = 1; static boolean using_graphical_startup; static const byte notchTable[] = { // plane 0 0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xC0, 0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xBC, 0x3F, 0xFC, 0x20, 0x08, 0x20, 0x08, 0x2F, 0xD8, 0x37, 0xD8, 0x37, 0xF8, 0x1F, 0xF8, 0x1C, 0x50, // plane 1 0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xA0, 0x30, 0x6C, 0x24, 0x94, 0x42, 0x4A, 0x60, 0x0E, 0x60, 0x06, 0x7F, 0xF6, 0x7F, 0xF6, 0x7F, 0xF6, 0x5E, 0xF6, 0x38, 0x16, 0x23, 0xAC, // plane 2 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xE0, 0x30, 0x6C, 0x24, 0x94, 0x52, 0x6A, 0x7F, 0xFE, 0x60, 0x0E, 0x60, 0x0E, 0x6F, 0xD6, 0x77, 0xD6, 0x56, 0xF6, 0x38, 0x36, 0x23, 0xAC, // plane 3 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x02, 0x40, 0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xB4, 0x1F, 0xF0, 0x1F, 0xF8, 0x1F, 0xF8, 0x10, 0x28, 0x08, 0x28, 0x29, 0x08, 0x07, 0xE8, 0x1C, 0x50 }; // Red Network Progress notches static const byte netnotchTable[] = { // plane 0 0x80, 0x50, 0xD0, 0xf0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xD0, 0xF0, 0xC0, 0x70, 0x50, 0x80, 0x60, // plane 1 0x60, 0xE0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, 0xE0, 0x60, 0x00, // plane 2 0x80, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x80, 0x60, // plane 3 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // CODE -------------------------------------------------------------------- //-------------------------------------------------------------------------- // // Startup Screen Functions // //-------------------------------------------------------------------------- //========================================================================== // // ST_Init - Do the startup screen // //========================================================================== void ST_Init(void) { byte *pal; byte *buffer; using_graphical_startup = false; if (graphical_startup && !debugmode && !testcontrols) { I_SetWindowTitleHR("Hexen startup - " PACKAGE_STRING); // Set 640x480x16 mode if (I_SetVideoModeHR()) { using_graphical_startup = true; I_InitWindowIcon(); S_StartSongName("orb", true); I_ClearScreenHR(); I_InitPaletteHR(); I_BlackPaletteHR(); // Load graphic buffer = ST_LoadScreen(); pal = buffer; bitmap = buffer + 16 * 3; I_SlamHR(bitmap); I_FadeToPaletteHR(pal); Z_Free(buffer); } } } void ST_Done(void) { if (using_graphical_startup) { I_ClearScreenHR(); I_UnsetVideoModeHR(); } } //========================================================================== // // ST_UpdateNotches // //========================================================================== void ST_UpdateNotches(int notchPosition) { int x = ST_PROGRESS_X + notchPosition * ST_NOTCH_WIDTH; int y = ST_PROGRESS_Y; I_SlamBlockHR(x, y, ST_NOTCH_WIDTH, ST_NOTCH_HEIGHT, notchTable); } //========================================================================== // // ST_UpdateNetNotches - indicates network progress // //========================================================================== void ST_UpdateNetNotches(int notchPosition) { int x = ST_NETPROGRESS_X + notchPosition * ST_NETNOTCH_WIDTH; int y = ST_NETPROGRESS_Y; I_SlamBlockHR(x, y, ST_NETNOTCH_WIDTH, ST_NETNOTCH_HEIGHT, netnotchTable); } //========================================================================== // // ST_Progress - increments progress indicator // //========================================================================== void ST_Progress(void) { // Check for ESC press -- during startup all events eaten here if (I_CheckAbortHR()) { I_Quit(); } if (using_graphical_startup) { static int notchPosition = 0; if (notchPosition < ST_MAX_NOTCHES) { ST_UpdateNotches(notchPosition); S_StartSound(NULL, SFX_STARTUP_TICK); //I_Sleep(1000); notchPosition++; } } printf("."); } //========================================================================== // // ST_NetProgress - indicates network progress // //========================================================================== void ST_NetProgress(void) { printf("*"); if (using_graphical_startup) { static int netnotchPosition = 0; if (netnotchPosition < ST_MAX_NETNOTCHES) { ST_UpdateNetNotches(netnotchPosition); S_StartSound(NULL, SFX_DRIP); netnotchPosition++; } } } //========================================================================== // // ST_NetDone - net progress complete // //========================================================================== void ST_NetDone(void) { if (using_graphical_startup) { S_StartSound(NULL, SFX_PICKUP_WEAPON); } } //========================================================================== // // ST_Message - gives debug message // //========================================================================== void ST_Message(char *message, ...) { va_list argptr; va_start(argptr, message); vprintf(message, argptr); va_end(argptr); } //========================================================================== // // ST_RealMessage - gives user message // //========================================================================== void ST_RealMessage(char *message, ...) { va_list argptr; va_start(argptr, message); vprintf(message, argptr); va_end(argptr); } //========================================================================== // // ST_LoadScreen - loads startup graphic // //========================================================================== byte *ST_LoadScreen(void) { int length, lump; byte *buffer; lump = W_GetNumForName("STARTUP"); length = W_LumpLength(lump); buffer = (byte *) Z_Malloc(length, PU_STATIC, NULL); W_ReadLump(lump, buffer); return (buffer); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/st_start.h000066400000000000000000000024761257432200600232300ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef STSTART_H #define STSTART_H // HEADER FILES ------------------------------------------------------------ // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- extern void ST_Init(void); extern void ST_Done(void); extern void ST_Message(char *message, ...); extern void ST_RealMessage(char *message, ...); extern void ST_Progress(void); extern void ST_NetProgress(void); extern void ST_NetDone(void); // PUBLIC DATA DECLARATIONS ------------------------------------------------ extern int graphical_startup; #endif chocolate-doom-chocolate-doom-2.2.1/src/hexen/sv_save.c000066400000000000000000002171021257432200600230200ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "i_system.h" #include "m_misc.h" #include "i_swap.h" #include "p_local.h" // MACROS ------------------------------------------------------------------ #define MAX_TARGET_PLAYERS 512 #define MOBJ_NULL -1 #define MOBJ_XX_PLAYER -2 #define GET_BYTE (*SavePtr.b++) #define GET_WORD SHORT(*SavePtr.w++) #define GET_LONG LONG(*SavePtr.l++) #define MAX_MAPS 99 #define BASE_SLOT 6 #define REBORN_SLOT 7 #define REBORN_DESCRIPTION "TEMP GAME" #define MAX_THINKER_SIZE 256 // TYPES ------------------------------------------------------------------- typedef enum { ASEG_GAME_HEADER = 101, ASEG_MAP_HEADER, ASEG_WORLD, ASEG_POLYOBJS, ASEG_MOBJS, ASEG_THINKERS, ASEG_SCRIPTS, ASEG_PLAYERS, ASEG_SOUNDS, ASEG_MISC, ASEG_END } gameArchiveSegment_t; typedef enum { TC_NULL, TC_MOVE_CEILING, TC_VERTICAL_DOOR, TC_MOVE_FLOOR, TC_PLAT_RAISE, TC_INTERPRET_ACS, TC_FLOOR_WAGGLE, TC_LIGHT, TC_PHASE, TC_BUILD_PILLAR, TC_ROTATE_POLY, TC_MOVE_POLY, TC_POLY_DOOR } thinkClass_t; typedef struct { thinkClass_t tClass; think_t thinkerFunc; void (*writeFunc)(); void (*readFunc)(); void (*restoreFunc) (); size_t size; } thinkInfo_t; typedef struct { thinker_t thinker; sector_t *sector; } ssthinker_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void P_SpawnPlayer(mapthing_t * mthing); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void ArchiveWorld(void); static void UnarchiveWorld(void); static void ArchivePolyobjs(void); static void UnarchivePolyobjs(void); static void ArchiveMobjs(void); static void UnarchiveMobjs(void); static void ArchiveThinkers(void); static void UnarchiveThinkers(void); static void ArchiveScripts(void); static void UnarchiveScripts(void); static void ArchivePlayers(void); static void UnarchivePlayers(void); static void ArchiveSounds(void); static void UnarchiveSounds(void); static void ArchiveMisc(void); static void UnarchiveMisc(void); static void SetMobjArchiveNums(void); static void RemoveAllThinkers(void); static int GetMobjNum(mobj_t * mobj); static void SetMobjPtr(mobj_t **ptr, unsigned int archiveNum); static void RestoreSSThinker(ssthinker_t * sst); static void RestorePlatRaise(plat_t * plat); static void RestoreMoveCeiling(ceiling_t * ceiling); static void AssertSegment(gameArchiveSegment_t segType); static void ClearSaveSlot(int slot); static void CopySaveSlot(int sourceSlot, int destSlot); static void CopyFile(char *sourceName, char *destName); static boolean ExistingFile(char *name); static void OpenStreamOut(char *fileName); static void CloseStreamOut(void); static void StreamOutBuffer(void *buffer, int size); static void StreamOutByte(byte val); static void StreamOutWord(unsigned short val); static void StreamOutLong(unsigned int val); static void StreamOutPtr(void *ptr); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- #define DEFAULT_SAVEPATH "hexndata/" char *SavePath = DEFAULT_SAVEPATH; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int MobjCount; static mobj_t **MobjList; static mobj_t ***TargetPlayerAddrs; static int TargetPlayerCount; static byte *SaveBuffer; static boolean SavingPlayers; static union { byte *b; short *w; int *l; } SavePtr; static FILE *SavingFP; // CODE -------------------------------------------------------------------- // Autogenerated functions for reading/writing structs: // // acsstore_t // static void StreamIn_acsstore_t(acsstore_t *str) { int i; // int map; str->map = GET_LONG; // int script; str->script = GET_LONG; // byte args[4]; for (i=0; i<4; ++i) { str->args[i] = GET_BYTE; } } static void StreamOut_acsstore_t(acsstore_t *str) { int i; // int map; StreamOutLong(str->map); // int script; StreamOutLong(str->script); // byte args[4]; for (i=0; i<4; ++i) { StreamOutByte(str->args[i]); } } // // ticcmd_t // (this is based on the Vanilla definition of the struct) // static void StreamIn_ticcmd_t(ticcmd_t *str) { // char forwardmove; str->forwardmove = GET_BYTE; // char sidemove; str->sidemove = GET_BYTE; // short angleturn; str->angleturn = GET_WORD; // short consistancy; str->consistancy = GET_WORD; // byte chatchar; str->chatchar = GET_BYTE; // byte buttons; str->buttons = GET_BYTE; // byte lookfly; str->lookfly = GET_BYTE; // byte arti; str->arti = GET_BYTE; } static void StreamOut_ticcmd_t(ticcmd_t *str) { // char forwardmove; StreamOutByte(str->forwardmove); // char sidemove; StreamOutByte(str->sidemove); // short angleturn; StreamOutWord(str->angleturn); // short consistancy; StreamOutWord(str->consistancy); // byte chatchar; StreamOutByte(str->chatchar); // byte buttons; StreamOutByte(str->buttons); // byte lookfly; StreamOutByte(str->lookfly); // byte arti; StreamOutByte(str->arti); } // // inventory_t // static void StreamIn_inventory_t(inventory_t *str) { // int type; str->type = GET_LONG; // int count; str->count = GET_LONG; } static void StreamOut_inventory_t(inventory_t *str) { // int type; StreamOutLong(str->type); // int count; StreamOutLong(str->count); } // // pspdef_t // static void StreamIn_pspdef_t(pspdef_t *str) { int state_num; // state_t *state; // This is a pointer; it is stored as an index into the states table. state_num = GET_LONG; if (state_num != 0) { str->state = states + state_num; } else { str->state = NULL; } // int tics; str->tics = GET_LONG; // fixed_t sx, sy; str->sx = GET_LONG; str->sy = GET_LONG; } static void StreamOut_pspdef_t(pspdef_t *str) { // state_t *state; // This is a pointer; store the index in the states table, // rather than the pointer itself. if (str->state != NULL) { StreamOutLong(str->state - states); } else { StreamOutLong(0); } // int tics; StreamOutLong(str->tics); // fixed_t sx, sy; StreamOutLong(str->sx); StreamOutLong(str->sy); } // // player_t // static void StreamIn_player_t(player_t *str) { int i; // mobj_t *mo; // Pointer value is reset on load. str->mo = (void *) (intptr_t) GET_LONG; str->mo = NULL; // playerstate_t playerstate; str->playerstate = GET_LONG; // ticcmd_t cmd; StreamIn_ticcmd_t(&str->cmd); // pclass_t class; str->class = GET_LONG; // fixed_t viewz; str->viewz = GET_LONG; // fixed_t viewheight; str->viewheight = GET_LONG; // fixed_t deltaviewheight; str->deltaviewheight = GET_LONG; // fixed_t bob; str->bob = GET_LONG; // int flyheight; str->flyheight = GET_LONG; // int lookdir; str->lookdir = GET_LONG; // boolean centering; str->centering = GET_LONG; // int health; str->health = GET_LONG; // int armorpoints[NUMARMOR]; for (i=0; iarmorpoints[i] = GET_LONG; } // inventory_t inventory[NUMINVENTORYSLOTS]; for (i=0; iinventory[i]); } // artitype_t readyArtifact; str->readyArtifact = GET_LONG; // int artifactCount; str->artifactCount = GET_LONG; // int inventorySlotNum; str->inventorySlotNum = GET_LONG; // int powers[NUMPOWERS]; for (i=0; ipowers[i] = GET_LONG; } // int keys; str->keys = GET_LONG; // int pieces; str->pieces = GET_LONG; // signed int frags[MAXPLAYERS]; for (i=0; ifrags[i] = GET_LONG; } // weapontype_t readyweapon; str->readyweapon = GET_LONG; // weapontype_t pendingweapon; str->pendingweapon = GET_LONG; // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i] = GET_LONG; } // int mana[NUMMANA]; for (i=0; imana[i] = GET_LONG; } // int attackdown, usedown; str->attackdown = GET_LONG; str->usedown = GET_LONG; // int cheats; str->cheats = GET_LONG; // int refire; str->refire = GET_LONG; // int killcount, itemcount, secretcount; str->killcount = GET_LONG; str->itemcount = GET_LONG; str->secretcount = GET_LONG; // char message[80]; for (i=0; i<80; ++i) { str->message[i] = GET_BYTE; } // int messageTics; str->messageTics = GET_LONG; // short ultimateMessage; str->ultimateMessage = GET_WORD; // short yellowMessage; str->yellowMessage = GET_WORD; // int damagecount, bonuscount; str->damagecount = GET_LONG; str->bonuscount = GET_LONG; // int poisoncount; str->poisoncount = GET_LONG; // mobj_t *poisoner; // Pointer value is reset. str->poisoner = (void *) (intptr_t) GET_LONG; str->poisoner = NULL; // mobj_t *attacker; // Pointer value is reset. str->attacker = (void *) (intptr_t) GET_LONG; str->attacker = NULL; // int extralight; str->extralight = GET_LONG; // int fixedcolormap; str->fixedcolormap = GET_LONG; // int colormap; str->colormap = GET_LONG; // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // int morphTics; str->morphTics = GET_LONG; // unsigned int jumpTics; str->jumpTics = GET_LONG; // unsigned int worldTimer; str->worldTimer = GET_LONG; } static void StreamOut_player_t(player_t *str) { int i; // mobj_t *mo; StreamOutPtr(str->mo); // playerstate_t playerstate; StreamOutLong(str->playerstate); // ticcmd_t cmd; StreamOut_ticcmd_t(&str->cmd); // pclass_t class; StreamOutLong(str->class); // fixed_t viewz; StreamOutLong(str->viewz); // fixed_t viewheight; StreamOutLong(str->viewheight); // fixed_t deltaviewheight; StreamOutLong(str->deltaviewheight); // fixed_t bob; StreamOutLong(str->bob); // int flyheight; StreamOutLong(str->flyheight); // int lookdir; StreamOutLong(str->lookdir); // boolean centering; StreamOutLong(str->centering); // int health; StreamOutLong(str->health); // int armorpoints[NUMARMOR]; for (i=0; iarmorpoints[i]); } // inventory_t inventory[NUMINVENTORYSLOTS]; for (i=0; iinventory[i]); } // artitype_t readyArtifact; StreamOutLong(str->readyArtifact); // int artifactCount; StreamOutLong(str->artifactCount); // int inventorySlotNum; StreamOutLong(str->inventorySlotNum); // int powers[NUMPOWERS]; for (i=0; ipowers[i]); } // int keys; StreamOutLong(str->keys); // int pieces; StreamOutLong(str->pieces); // signed int frags[MAXPLAYERS]; for (i=0; ifrags[i]); } // weapontype_t readyweapon; StreamOutLong(str->readyweapon); // weapontype_t pendingweapon; StreamOutLong(str->pendingweapon); // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i]); } // int mana[NUMMANA]; for (i=0; imana[i]); } // int attackdown, usedown; StreamOutLong(str->attackdown); StreamOutLong(str->usedown); // int cheats; StreamOutLong(str->cheats); // int refire; StreamOutLong(str->refire); // int killcount, itemcount, secretcount; StreamOutLong(str->killcount); StreamOutLong(str->itemcount); StreamOutLong(str->secretcount); // char message[80]; for (i=0; i<80; ++i) { StreamOutByte(str->message[i]); } // int messageTics; StreamOutLong(str->messageTics); // short ultimateMessage; StreamOutWord(str->ultimateMessage); // short yellowMessage; StreamOutWord(str->yellowMessage); // int damagecount, bonuscount; StreamOutLong(str->damagecount); StreamOutLong(str->bonuscount); // int poisoncount; StreamOutLong(str->poisoncount); // mobj_t *poisoner; StreamOutPtr(str->poisoner); // mobj_t *attacker; StreamOutPtr(str->attacker); // int extralight; StreamOutLong(str->extralight); // int fixedcolormap; StreamOutLong(str->fixedcolormap); // int colormap; StreamOutLong(str->colormap); // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // int morphTics; StreamOutLong(str->morphTics); // unsigned int jumpTics; StreamOutLong(str->jumpTics); // unsigned int worldTimer; StreamOutLong(str->worldTimer); } // // thinker_t // static void StreamIn_thinker_t(thinker_t *str) { // struct thinker_s *prev, *next; // Pointers are discarded: str->prev = (void *) (intptr_t) GET_LONG; str->prev = NULL; str->next = (void *) (intptr_t) GET_LONG; str->next = NULL; // think_t function; // Function pointer is discarded: str->function = (void *) (intptr_t) GET_LONG; str->function = NULL; } static void StreamOut_thinker_t(thinker_t *str) { // struct thinker_s *prev, *next; StreamOutPtr(str->prev); StreamOutPtr(str->next); // think_t function; StreamOutPtr(&str->function); } // // mobj_t // static void StreamInMobjSpecials(mobj_t *mobj) { unsigned int special1, special2; special1 = GET_LONG; special2 = GET_LONG; mobj->special1.i = special1; mobj->special2.i = special2; switch (mobj->type) { // Just special1 case MT_BISH_FX: case MT_HOLY_FX: case MT_DRAGON: case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: case MT_MINOTAUR: case MT_SORCFX1: SetMobjPtr(&mobj->special1.m, special1); break; // Just special2 case MT_LIGHTNING_FLOOR: case MT_LIGHTNING_ZAP: SetMobjPtr(&mobj->special2.m, special2); break; // Both special1 and special2 case MT_HOLY_TAIL: case MT_LIGHTNING_CEILING: SetMobjPtr(&mobj->special1.m, special1); SetMobjPtr(&mobj->special2.m, special2); break; default: break; } } static void StreamIn_mobj_t(mobj_t *str) { unsigned int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // fixed_t x, y, z; str->x = GET_LONG; str->y = GET_LONG; str->z = GET_LONG; // struct mobj_s *snext, *sprev; // Pointer values are discarded: str->snext = (void *) (intptr_t) GET_LONG; str->snext = NULL; str->sprev = (void *) (intptr_t) GET_LONG; str->sprev = NULL; // angle_t angle; str->angle = GET_LONG; // spritenum_t sprite; str->sprite = GET_LONG; // int frame; str->frame = GET_LONG; // struct mobj_s *bnext, *bprev; // Values are read but discarded; this will be restored when the thing's // position is set. str->bnext = (void *) (intptr_t) GET_LONG; str->bnext = NULL; str->bprev = (void *) (intptr_t) GET_LONG; str->bprev = NULL; // struct subsector_s *subsector; // Read but discard: pointer will be restored when thing position is set. str->subsector = (void *) (intptr_t) GET_LONG; str->subsector = NULL; // fixed_t floorz, ceilingz; str->floorz = GET_LONG; str->ceilingz = GET_LONG; // fixed_t floorpic; str->floorpic = GET_LONG; // fixed_t radius, height; str->radius = GET_LONG; str->height = GET_LONG; // fixed_t momx, momy, momz; str->momx = GET_LONG; str->momy = GET_LONG; str->momz = GET_LONG; // int validcount; str->validcount = GET_LONG; // mobjtype_t type; str->type = GET_LONG; // mobjinfo_t *info; // Pointer value is read but discarded. str->info = (void *) (intptr_t) GET_LONG; str->info = NULL; // int tics; str->tics = GET_LONG; // state_t *state; // Restore as index into states table. i = GET_LONG; str->state = &states[i]; // int damage; str->damage = GET_LONG; // int flags; str->flags = GET_LONG; // int flags2; str->flags2 = GET_LONG; // specialval_t special1; // specialval_t special2; // Read in special values: there are special cases to deal with with // mobj pointers. StreamInMobjSpecials(str); // int health; str->health = GET_LONG; // int movedir; str->movedir = GET_LONG; // int movecount; str->movecount = GET_LONG; // struct mobj_s *target; i = GET_LONG; SetMobjPtr(&str->target, i); // int reactiontime; str->reactiontime = GET_LONG; // int threshold; str->threshold = GET_LONG; // struct player_s *player; // Saved as player number. i = GET_LONG; if (i == 0) { str->player = NULL; } else { str->player = &players[i - 1]; str->player->mo = str; } // int lastlook; str->lastlook = GET_LONG; // fixed_t floorclip; str->floorclip = GET_LONG; // int archiveNum; str->archiveNum = GET_LONG; // short tid; str->tid = GET_WORD; // byte special; str->special = GET_BYTE; // byte args[5]; for (i=0; i<5; ++i) { str->args[i] = GET_BYTE; } } static void StreamOutMobjSpecials(mobj_t *mobj) { unsigned int special1, special2; boolean corpse; corpse = (mobj->flags & MF_CORPSE) != 0; special1 = mobj->special1.i; special2 = mobj->special2.i; switch (mobj->type) { // Just special1 case MT_BISH_FX: case MT_HOLY_FX: case MT_DRAGON: case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: case MT_MINOTAUR: case MT_SORCFX1: case MT_MSTAFF_FX2: if (corpse) { special1 = MOBJ_NULL; } else { special1 = GetMobjNum(mobj->special1.m); } break; // Just special2 case MT_LIGHTNING_FLOOR: case MT_LIGHTNING_ZAP: if (corpse) { special2 = MOBJ_NULL; } else { special2 = GetMobjNum(mobj->special2.m); } break; // Both special1 and special2 case MT_HOLY_TAIL: case MT_LIGHTNING_CEILING: if (corpse) { special1 = MOBJ_NULL; special2 = MOBJ_NULL; } else { special1 = GetMobjNum(mobj->special1.m); special2 = GetMobjNum(mobj->special2.m); } break; // Miscellaneous case MT_KORAX: special1 = 0; // Searching index break; default: break; } // Write special values to savegame file. StreamOutLong(special1); StreamOutLong(special2); } static void StreamOut_mobj_t(mobj_t *str) { int i; // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // fixed_t x, y, z; StreamOutLong(str->x); StreamOutLong(str->y); StreamOutLong(str->z); // struct mobj_s *snext, *sprev; StreamOutPtr(str->snext); StreamOutPtr(str->sprev); // angle_t angle; StreamOutLong(str->angle); // spritenum_t sprite; StreamOutLong(str->sprite); // int frame; StreamOutLong(str->frame); // struct mobj_s *bnext, *bprev; StreamOutPtr(str->bnext); StreamOutPtr(str->bprev); // struct subsector_s *subsector; StreamOutPtr(str->subsector); // fixed_t floorz, ceilingz; StreamOutLong(str->floorz); StreamOutLong(str->ceilingz); // fixed_t floorpic; StreamOutLong(str->floorpic); // fixed_t radius, height; StreamOutLong(str->radius); StreamOutLong(str->height); // fixed_t momx, momy, momz; StreamOutLong(str->momx); StreamOutLong(str->momy); StreamOutLong(str->momz); // int validcount; StreamOutLong(str->validcount); // mobjtype_t type; StreamOutLong(str->type); // mobjinfo_t *info; StreamOutPtr(str->info); // int tics; StreamOutLong(str->tics); // state_t *state; // Save as index into the states table. StreamOutLong(str->state - states); // int damage; StreamOutLong(str->damage); // int flags; StreamOutLong(str->flags); // int flags2; StreamOutLong(str->flags2); // specialval_t special1; // specialval_t special2; // There are lots of special cases for the special values: StreamOutMobjSpecials(str); // int health; StreamOutLong(str->health); // int movedir; StreamOutLong(str->movedir); // int movecount; StreamOutLong(str->movecount); // struct mobj_s *target; if ((str->flags & MF_CORPSE) != 0) { StreamOutLong(MOBJ_NULL); } else { StreamOutLong(GetMobjNum(str->target)); } // int reactiontime; StreamOutLong(str->reactiontime); // int threshold; StreamOutLong(str->threshold); // struct player_s *player; // Stored as index into players[] array, if there is a player pointer. if (str->player != NULL) { StreamOutLong(str->player - players + 1); } else { StreamOutLong(0); } // int lastlook; StreamOutLong(str->lastlook); // fixed_t floorclip; StreamOutLong(str->floorclip); // int archiveNum; StreamOutLong(str->archiveNum); // short tid; StreamOutWord(str->tid); // byte special; StreamOutByte(str->special); // byte args[5]; for (i=0; i<5; ++i) { StreamOutByte(str->args[i]); } } // // floormove_t // static void StreamIn_floormove_t(floormove_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = sectors + i; // floor_e type; str->type = GET_LONG; // int crush; str->crush = GET_LONG; // int direction; str->direction = GET_LONG; // int newspecial; str->newspecial = GET_LONG; // short texture; str->texture = GET_WORD; // fixed_t floordestheight; str->floordestheight = GET_LONG; // fixed_t speed; str->speed = GET_LONG; // int delayCount; str->delayCount = GET_LONG; // int delayTotal; str->delayTotal = GET_LONG; // fixed_t stairsDelayHeight; str->stairsDelayHeight = GET_LONG; // fixed_t stairsDelayHeightDelta; str->stairsDelayHeightDelta = GET_LONG; // fixed_t resetHeight; str->resetHeight = GET_LONG; // short resetDelay; str->resetDelay = GET_WORD; // short resetDelayCount; str->resetDelayCount = GET_WORD; // byte textureChange; str->textureChange = GET_BYTE; } static void StreamOut_floormove_t(floormove_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // floor_e type; StreamOutLong(str->type); // int crush; StreamOutLong(str->crush); // int direction; StreamOutLong(str->direction); // int newspecial; StreamOutLong(str->newspecial); // short texture; StreamOutWord(str->texture); // fixed_t floordestheight; StreamOutLong(str->floordestheight); // fixed_t speed; StreamOutLong(str->speed); // int delayCount; StreamOutLong(str->delayCount); // int delayTotal; StreamOutLong(str->delayTotal); // fixed_t stairsDelayHeight; StreamOutLong(str->stairsDelayHeight); // fixed_t stairsDelayHeightDelta; StreamOutLong(str->stairsDelayHeightDelta); // fixed_t resetHeight; StreamOutLong(str->resetHeight); // short resetDelay; StreamOutWord(str->resetDelay); // short resetDelayCount; StreamOutWord(str->resetDelayCount); // byte textureChange; StreamOutByte(str->textureChange); } // // plat_t // static void StreamIn_plat_t(plat_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = sectors + i; // fixed_t speed; str->speed = GET_LONG; // fixed_t low; str->low = GET_LONG; // fixed_t high; str->high = GET_LONG; // int wait; str->wait = GET_LONG; // int count; str->count = GET_LONG; // plat_e status; str->status = GET_LONG; // plat_e oldstatus; str->oldstatus = GET_LONG; // int crush; str->crush = GET_LONG; // int tag; str->tag = GET_LONG; // plattype_e type; str->type = GET_LONG; } static void StreamOut_plat_t(plat_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // fixed_t speed; StreamOutLong(str->speed); // fixed_t low; StreamOutLong(str->low); // fixed_t high; StreamOutLong(str->high); // int wait; StreamOutLong(str->wait); // int count; StreamOutLong(str->count); // plat_e status; StreamOutLong(str->status); // plat_e oldstatus; StreamOutLong(str->oldstatus); // int crush; StreamOutLong(str->crush); // int tag; StreamOutLong(str->tag); // plattype_e type; StreamOutLong(str->type); } // // ceiling_t // static void StreamIn_ceiling_t(ceiling_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = sectors + i; // ceiling_e type; str->type = GET_LONG; // fixed_t bottomheight, topheight; str->bottomheight = GET_LONG; str->topheight = GET_LONG; // fixed_t speed; str->speed = GET_LONG; // int crush; str->crush = GET_LONG; // int direction; str->direction = GET_LONG; // int tag; str->tag = GET_LONG; // int olddirection; str->olddirection = GET_LONG; } static void StreamOut_ceiling_t(ceiling_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // ceiling_e type; StreamOutLong(str->type); // fixed_t bottomheight, topheight; StreamOutLong(str->bottomheight); StreamOutLong(str->topheight); // fixed_t speed; StreamOutLong(str->speed); // int crush; StreamOutLong(str->crush); // int direction; StreamOutLong(str->direction); // int tag; StreamOutLong(str->tag); // int olddirection; StreamOutLong(str->olddirection); } // // light_t // static void StreamIn_light_t(light_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = sectors + i; // lighttype_t type; str->type = GET_LONG; // int value1; str->value1 = GET_LONG; // int value2; str->value2 = GET_LONG; // int tics1; str->tics1 = GET_LONG; // int tics2; str->tics2 = GET_LONG; // int count; str->count = GET_LONG; } static void StreamOut_light_t(light_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // lighttype_t type; StreamOutLong(str->type); // int value1; StreamOutLong(str->value1); // int value2; StreamOutLong(str->value2); // int tics1; StreamOutLong(str->tics1); // int tics2; StreamOutLong(str->tics2); // int count; StreamOutLong(str->count); } // // vldoor_t // static void StreamIn_vldoor_t(vldoor_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = §ors[i]; // vldoor_e type; str->type = GET_LONG; // fixed_t topheight; str->topheight = GET_LONG; // fixed_t speed; str->speed = GET_LONG; // int direction; str->direction = GET_LONG; // int topwait; str->topwait = GET_LONG; // int topcountdown; str->topcountdown = GET_LONG; } static void StreamOut_vldoor_t(vldoor_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // vldoor_e type; StreamOutLong(str->type); // fixed_t topheight; StreamOutLong(str->topheight); // fixed_t speed; StreamOutLong(str->speed); // int direction; StreamOutLong(str->direction); // int topwait; StreamOutLong(str->topwait); // int topcountdown; StreamOutLong(str->topcountdown); } // // phase_t // static void StreamIn_phase_t(phase_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = §ors[i]; // int index; str->index = GET_LONG; // int base; str->base = GET_LONG; } static void StreamOut_phase_t(phase_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // int index; StreamOutLong(str->index); // int base; StreamOutLong(str->base); } // // acs_t // static void StreamIn_acs_t(acs_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // mobj_t *activator; i = GET_LONG; SetMobjPtr(&str->activator, i); // line_t *line; i = GET_LONG; if (i != -1) { str->line = &lines[i]; } else { str->line = NULL; } // int side; str->side = GET_LONG; // int number; str->number = GET_LONG; // int infoIndex; str->infoIndex = GET_LONG; // int delayCount; str->delayCount = GET_LONG; // int stack[ACS_STACK_DEPTH]; for (i=0; istack[i] = GET_LONG; } // int stackPtr; str->stackPtr = GET_LONG; // int vars[MAX_ACS_SCRIPT_VARS]; for (i=0; ivars[i] = GET_LONG; } // int *ip; i = GET_LONG; str->ip = (int *) (ActionCodeBase + i); } static void StreamOut_acs_t(acs_t *str) { int i; // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // mobj_t *activator; StreamOutLong(GetMobjNum(str->activator)); // line_t *line; if (str->line != NULL) { StreamOutLong(str->line - lines); } else { StreamOutLong(-1); } // int side; StreamOutLong(str->side); // int number; StreamOutLong(str->number); // int infoIndex; StreamOutLong(str->infoIndex); // int delayCount; StreamOutLong(str->delayCount); // int stack[ACS_STACK_DEPTH]; for (i=0; istack[i]); } // int stackPtr; StreamOutLong(str->stackPtr); // int vars[MAX_ACS_SCRIPT_VARS]; for (i=0; ivars[i]); } // int *ip; StreamOutLong((byte *) str->ip - ActionCodeBase); } // // polyevent_t // static void StreamIn_polyevent_t(polyevent_t *str) { // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // int polyobj; str->polyobj = GET_LONG; // int speed; str->speed = GET_LONG; // unsigned int dist; str->dist = GET_LONG; // int angle; str->angle = GET_LONG; // fixed_t xSpeed; str->xSpeed = GET_LONG; // fixed_t ySpeed; str->ySpeed = GET_LONG; } static void StreamOut_polyevent_t(polyevent_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // int polyobj; StreamOutLong(str->polyobj); // int speed; StreamOutLong(str->speed); // unsigned int dist; StreamOutLong(str->dist); // int angle; StreamOutLong(str->angle); // fixed_t xSpeed; StreamOutLong(str->xSpeed); // fixed_t ySpeed; StreamOutLong(str->ySpeed); } // // pillar_t // static void StreamIn_pillar_t(pillar_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = §ors[i]; // int ceilingSpeed; str->ceilingSpeed = GET_LONG; // int floorSpeed; str->floorSpeed = GET_LONG; // int floordest; str->floordest = GET_LONG; // int ceilingdest; str->ceilingdest = GET_LONG; // int direction; str->direction = GET_LONG; // int crush; str->crush = GET_LONG; } static void StreamOut_pillar_t(pillar_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // int ceilingSpeed; StreamOutLong(str->ceilingSpeed); // int floorSpeed; StreamOutLong(str->floorSpeed); // int floordest; StreamOutLong(str->floordest); // int ceilingdest; StreamOutLong(str->ceilingdest); // int direction; StreamOutLong(str->direction); // int crush; StreamOutLong(str->crush); } // // polydoor_t // static void StreamIn_polydoor_t(polydoor_t *str) { // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // int polyobj; str->polyobj = GET_LONG; // int speed; str->speed = GET_LONG; // int dist; str->dist = GET_LONG; // int totalDist; str->totalDist = GET_LONG; // int direction; str->direction = GET_LONG; // fixed_t xSpeed, ySpeed; str->xSpeed = GET_LONG; str->ySpeed = GET_LONG; // int tics; str->tics = GET_LONG; // int waitTics; str->waitTics = GET_LONG; // podoortype_t type; str->type = GET_LONG; // boolean close; str->close = GET_LONG; } static void StreamOut_polydoor_t(polydoor_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // int polyobj; StreamOutLong(str->polyobj); // int speed; StreamOutLong(str->speed); // int dist; StreamOutLong(str->dist); // int totalDist; StreamOutLong(str->totalDist); // int direction; StreamOutLong(str->direction); // fixed_t xSpeed, ySpeed; StreamOutLong(str->xSpeed); StreamOutLong(str->ySpeed); // int tics; StreamOutLong(str->tics); // int waitTics; StreamOutLong(str->waitTics); // podoortype_t type; StreamOutLong(str->type); // boolean close; StreamOutLong(str->close); } // // floorWaggle_t // static void StreamIn_floorWaggle_t(floorWaggle_t *str) { int i; // thinker_t thinker; StreamIn_thinker_t(&str->thinker); // sector_t *sector; i = GET_LONG; str->sector = §ors[i]; // fixed_t originalHeight; str->originalHeight = GET_LONG; // fixed_t accumulator; str->accumulator = GET_LONG; // fixed_t accDelta; str->accDelta = GET_LONG; // fixed_t targetScale; str->targetScale = GET_LONG; // fixed_t scale; str->scale = GET_LONG; // fixed_t scaleDelta; str->scaleDelta = GET_LONG; // int ticker; str->ticker = GET_LONG; // int state; str->state = GET_LONG; } static void StreamOut_floorWaggle_t(floorWaggle_t *str) { // thinker_t thinker; StreamOut_thinker_t(&str->thinker); // sector_t *sector; StreamOutLong(str->sector - sectors); // fixed_t originalHeight; StreamOutLong(str->originalHeight); // fixed_t accumulator; StreamOutLong(str->accumulator); // fixed_t accDelta; StreamOutLong(str->accDelta); // fixed_t targetScale; StreamOutLong(str->targetScale); // fixed_t scale; StreamOutLong(str->scale); // fixed_t scaleDelta; StreamOutLong(str->scaleDelta); // int ticker; StreamOutLong(str->ticker); // int state; StreamOutLong(str->state); } //========================================================================== // // SV_SaveGame // //========================================================================== void SV_SaveGame(int slot, char *description) { char fileName[100]; char versionText[HXS_VERSION_TEXT_LENGTH]; unsigned int i; // Open the output file M_snprintf(fileName, sizeof(fileName), "%shex6.hxs", SavePath); OpenStreamOut(fileName); // Write game save description StreamOutBuffer(description, HXS_DESCRIPTION_LENGTH); // Write version info memset(versionText, 0, HXS_VERSION_TEXT_LENGTH); M_StringCopy(versionText, HXS_VERSION_TEXT, HXS_VERSION_TEXT_LENGTH); StreamOutBuffer(versionText, HXS_VERSION_TEXT_LENGTH); // Place a header marker StreamOutLong(ASEG_GAME_HEADER); // Write current map and difficulty StreamOutByte(gamemap); StreamOutByte(gameskill); // Write global script info for (i = 0; i < MAX_ACS_WORLD_VARS; ++i) { StreamOutLong(WorldVars[i]); } for (i = 0; i < MAX_ACS_STORE + 1; ++i) { StreamOut_acsstore_t(&ACSStore[i]); } ArchivePlayers(); // Place a termination marker StreamOutLong(ASEG_END); // Close the output file CloseStreamOut(); // Save out the current map SV_SaveMap(true); // true = save player info // Clear all save files at destination slot ClearSaveSlot(slot); // Copy base slot to destination slot CopySaveSlot(BASE_SLOT, slot); } //========================================================================== // // SV_SaveMap // //========================================================================== void SV_SaveMap(boolean savePlayers) { char fileName[100]; SavingPlayers = savePlayers; // Open the output file M_snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", SavePath, gamemap); OpenStreamOut(fileName); // Place a header marker StreamOutLong(ASEG_MAP_HEADER); // Write the level timer StreamOutLong(leveltime); // Set the mobj archive numbers SetMobjArchiveNums(); ArchiveWorld(); ArchivePolyobjs(); ArchiveMobjs(); ArchiveThinkers(); ArchiveScripts(); ArchiveSounds(); ArchiveMisc(); // Place a termination marker StreamOutLong(ASEG_END); // Close the output file CloseStreamOut(); } //========================================================================== // // SV_LoadGame // //========================================================================== void SV_LoadGame(int slot) { int i; char fileName[100]; player_t playerBackup[MAXPLAYERS]; mobj_t *mobj; // Copy all needed save files to the base slot if (slot != BASE_SLOT) { ClearSaveSlot(BASE_SLOT); CopySaveSlot(slot, BASE_SLOT); } // Create the name M_snprintf(fileName, sizeof(fileName), "%shex6.hxs", SavePath); // Load the file M_ReadFile(fileName, &SaveBuffer); // Set the save pointer and skip the description field SavePtr.b = SaveBuffer + HXS_DESCRIPTION_LENGTH; // Check the version text if (strcmp((char *) SavePtr.b, HXS_VERSION_TEXT)) { // Bad version return; } SavePtr.b += HXS_VERSION_TEXT_LENGTH; AssertSegment(ASEG_GAME_HEADER); gameepisode = 1; gamemap = GET_BYTE; gameskill = GET_BYTE; // Read global script info for (i = 0; i < MAX_ACS_WORLD_VARS; ++i) { WorldVars[i] = GET_LONG; } for (i = 0; i < MAX_ACS_STORE + 1; ++i) { StreamIn_acsstore_t(&ACSStore[i]); } // Read the player structures UnarchivePlayers(); AssertSegment(ASEG_END); Z_Free(SaveBuffer); // Save player structs for (i = 0; i < maxplayers; i++) { playerBackup[i] = players[i]; } // Load the current map SV_LoadMap(); // Don't need the player mobj relocation info for load game Z_Free(TargetPlayerAddrs); // Restore player structs inv_ptr = 0; curpos = 0; for (i = 0; i < maxplayers; i++) { mobj = players[i].mo; players[i] = playerBackup[i]; players[i].mo = mobj; if (i == consoleplayer) { players[i].readyArtifact = players[i].inventory[inv_ptr].type; } } } //========================================================================== // // SV_UpdateRebornSlot // // Copies the base slot to the reborn slot. // //========================================================================== void SV_UpdateRebornSlot(void) { ClearSaveSlot(REBORN_SLOT); CopySaveSlot(BASE_SLOT, REBORN_SLOT); } //========================================================================== // // SV_ClearRebornSlot // //========================================================================== void SV_ClearRebornSlot(void) { ClearSaveSlot(REBORN_SLOT); } //========================================================================== // // SV_MapTeleport // //========================================================================== void SV_MapTeleport(int map, int position) { int i; int j; char fileName[100]; player_t playerBackup[MAXPLAYERS]; mobj_t *targetPlayerMobj; mobj_t *mobj; int inventoryPtr; int currentInvPos; boolean rClass; boolean playerWasReborn; boolean oldWeaponowned[NUMWEAPONS]; int oldKeys = 0; int oldPieces = 0; int bestWeapon; if (!deathmatch) { if (P_GetMapCluster(gamemap) == P_GetMapCluster(map)) { // Same cluster - save map without saving player mobjs SV_SaveMap(false); } else { // Entering new cluster - clear base slot ClearSaveSlot(BASE_SLOT); } } // Store player structs for later rClass = randomclass; randomclass = false; for (i = 0; i < maxplayers; i++) { playerBackup[i] = players[i]; } // Save some globals that get trashed during the load inventoryPtr = inv_ptr; currentInvPos = curpos; // Only SV_LoadMap() uses TargetPlayerAddrs, so it's NULLed here // for the following check (player mobj redirection) TargetPlayerAddrs = NULL; gamemap = map; M_snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", SavePath, gamemap); if (!deathmatch && ExistingFile(fileName)) { // Unarchive map SV_LoadMap(); } else { // New map G_InitNew(gameskill, gameepisode, gamemap); // Destroy all freshly spawned players for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { P_RemoveMobj(players[i].mo); } } } // Restore player structs targetPlayerMobj = NULL; for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) { continue; } players[i] = playerBackup[i]; P_ClearMessage(&players[i]); players[i].attacker = NULL; players[i].poisoner = NULL; if (netgame) { if (players[i].playerstate == PST_DEAD) { // In a network game, force all players to be alive players[i].playerstate = PST_REBORN; } if (!deathmatch) { // Cooperative net-play, retain keys and weapons oldKeys = players[i].keys; oldPieces = players[i].pieces; for (j = 0; j < NUMWEAPONS; j++) { oldWeaponowned[j] = players[i].weaponowned[j]; } } } playerWasReborn = (players[i].playerstate == PST_REBORN); if (deathmatch) { memset(players[i].frags, 0, sizeof(players[i].frags)); mobj = P_SpawnMobj(playerstarts[0][i].x << 16, playerstarts[0][i].y << 16, 0, MT_PLAYER_FIGHTER); players[i].mo = mobj; G_DeathMatchSpawnPlayer(i); P_RemoveMobj(mobj); } else { P_SpawnPlayer(&playerstarts[position][i]); } if (playerWasReborn && netgame && !deathmatch) { // Restore keys and weapons when reborn in co-op players[i].keys = oldKeys; players[i].pieces = oldPieces; for (bestWeapon = 0, j = 0; j < NUMWEAPONS; j++) { if (oldWeaponowned[j]) { bestWeapon = j; players[i].weaponowned[j] = true; } } players[i].mana[MANA_1] = 25; players[i].mana[MANA_2] = 25; if (bestWeapon) { // Bring up the best weapon players[i].pendingweapon = bestWeapon; } } if (targetPlayerMobj == NULL) { // The poor sap targetPlayerMobj = players[i].mo; } } randomclass = rClass; // Redirect anything targeting a player mobj if (TargetPlayerAddrs) { for (i = 0; i < TargetPlayerCount; i++) { *TargetPlayerAddrs[i] = targetPlayerMobj; } Z_Free(TargetPlayerAddrs); } // Destroy all things touching players for (i = 0; i < maxplayers; i++) { if (playeringame[i]) { P_TeleportMove(players[i].mo, players[i].mo->x, players[i].mo->y); } } // Restore trashed globals inv_ptr = inventoryPtr; curpos = currentInvPos; // Launch waiting scripts if (!deathmatch) { P_CheckACSStore(); } // For single play, save immediately into the reborn slot if (!netgame) { SV_SaveGame(REBORN_SLOT, REBORN_DESCRIPTION); } } //========================================================================== // // SV_GetRebornSlot // //========================================================================== int SV_GetRebornSlot(void) { return (REBORN_SLOT); } //========================================================================== // // SV_RebornSlotAvailable // // Returns true if the reborn slot is available. // //========================================================================== boolean SV_RebornSlotAvailable(void) { char fileName[100]; M_snprintf(fileName, sizeof(fileName), "%shex%d.hxs", SavePath, REBORN_SLOT); return ExistingFile(fileName); } //========================================================================== // // SV_LoadMap // //========================================================================== void SV_LoadMap(void) { char fileName[100]; // Load a base level G_InitNew(gameskill, gameepisode, gamemap); // Remove all thinkers RemoveAllThinkers(); // Create the name M_snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", SavePath, gamemap); // Load the file M_ReadFile(fileName, &SaveBuffer); SavePtr.b = SaveBuffer; AssertSegment(ASEG_MAP_HEADER); // Read the level timer leveltime = GET_LONG; UnarchiveWorld(); UnarchivePolyobjs(); UnarchiveMobjs(); UnarchiveThinkers(); UnarchiveScripts(); UnarchiveSounds(); UnarchiveMisc(); AssertSegment(ASEG_END); // Free mobj list and save buffer Z_Free(MobjList); Z_Free(SaveBuffer); } //========================================================================== // // SV_InitBaseSlot // //========================================================================== void SV_InitBaseSlot(void) { ClearSaveSlot(BASE_SLOT); } //========================================================================== // // ArchivePlayers // //========================================================================== static void ArchivePlayers(void) { int i; StreamOutLong(ASEG_PLAYERS); for (i = 0; i < maxplayers; i++) { StreamOutByte(playeringame[i]); } for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) { continue; } StreamOutByte(PlayerClass[i]); StreamOut_player_t(&players[i]); } } //========================================================================== // // UnarchivePlayers // //========================================================================== static void UnarchivePlayers(void) { int i; AssertSegment(ASEG_PLAYERS); for (i = 0; i < maxplayers; i++) { playeringame[i] = GET_BYTE; } for (i = 0; i < maxplayers; i++) { if (!playeringame[i]) { continue; } PlayerClass[i] = GET_BYTE; StreamIn_player_t(&players[i]); P_ClearMessage(&players[i]); } } //========================================================================== // // ArchiveWorld // //========================================================================== static void ArchiveWorld(void) { int i; int j; sector_t *sec; line_t *li; side_t *si; StreamOutLong(ASEG_WORLD); for (i = 0, sec = sectors; i < numsectors; i++, sec++) { StreamOutWord(sec->floorheight >> FRACBITS); StreamOutWord(sec->ceilingheight >> FRACBITS); StreamOutWord(sec->floorpic); StreamOutWord(sec->ceilingpic); StreamOutWord(sec->lightlevel); StreamOutWord(sec->special); StreamOutWord(sec->tag); StreamOutWord(sec->seqType); } for (i = 0, li = lines; i < numlines; i++, li++) { StreamOutWord(li->flags); StreamOutByte(li->special); StreamOutByte(li->arg1); StreamOutByte(li->arg2); StreamOutByte(li->arg3); StreamOutByte(li->arg4); StreamOutByte(li->arg5); for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) { continue; } si = &sides[li->sidenum[j]]; StreamOutWord(si->textureoffset >> FRACBITS); StreamOutWord(si->rowoffset >> FRACBITS); StreamOutWord(si->toptexture); StreamOutWord(si->bottomtexture); StreamOutWord(si->midtexture); } } } //========================================================================== // // UnarchiveWorld // //========================================================================== static void UnarchiveWorld(void) { int i; int j; sector_t *sec; line_t *li; side_t *si; AssertSegment(ASEG_WORLD); for (i = 0, sec = sectors; i < numsectors; i++, sec++) { sec->floorheight = GET_WORD << FRACBITS; sec->ceilingheight = GET_WORD << FRACBITS; sec->floorpic = GET_WORD; sec->ceilingpic = GET_WORD; sec->lightlevel = GET_WORD; sec->special = GET_WORD; sec->tag = GET_WORD; sec->seqType = GET_WORD; sec->specialdata = 0; sec->soundtarget = 0; } for (i = 0, li = lines; i < numlines; i++, li++) { li->flags = GET_WORD; li->special = GET_BYTE; li->arg1 = GET_BYTE; li->arg2 = GET_BYTE; li->arg3 = GET_BYTE; li->arg4 = GET_BYTE; li->arg5 = GET_BYTE; for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) { continue; } si = &sides[li->sidenum[j]]; si->textureoffset = GET_WORD << FRACBITS; si->rowoffset = GET_WORD << FRACBITS; si->toptexture = GET_WORD; si->bottomtexture = GET_WORD; si->midtexture = GET_WORD; } } } //========================================================================== // // SetMobjArchiveNums // // Sets the archive numbers in all mobj structs. Also sets the MobjCount // global. Ignores player mobjs if SavingPlayers is false. // //========================================================================== static void SetMobjArchiveNums(void) { mobj_t *mobj; thinker_t *thinker; MobjCount = 0; for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { if (thinker->function == P_MobjThinker) { mobj = (mobj_t *) thinker; if (mobj->player && !SavingPlayers) { // Skipping player mobjs continue; } mobj->archiveNum = MobjCount++; } } } //========================================================================== // // ArchiveMobjs // //========================================================================== static void ArchiveMobjs(void) { int count; thinker_t *thinker; StreamOutLong(ASEG_MOBJS); StreamOutLong(MobjCount); count = 0; for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { if (thinker->function != P_MobjThinker) { // Not a mobj thinker continue; } if (((mobj_t *) thinker)->player && !SavingPlayers) { // Skipping player mobjs continue; } count++; StreamOut_mobj_t((mobj_t *) thinker); } if (count != MobjCount) { I_Error("ArchiveMobjs: bad mobj count"); } } //========================================================================== // // UnarchiveMobjs // //========================================================================== static void UnarchiveMobjs(void) { int i; mobj_t *mobj; AssertSegment(ASEG_MOBJS); TargetPlayerAddrs = Z_Malloc(MAX_TARGET_PLAYERS * sizeof(mobj_t **), PU_STATIC, NULL); TargetPlayerCount = 0; MobjCount = GET_LONG; MobjList = Z_Malloc(MobjCount * sizeof(mobj_t *), PU_STATIC, NULL); for (i = 0; i < MobjCount; i++) { MobjList[i] = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL); } for (i = 0; i < MobjCount; i++) { mobj = MobjList[i]; StreamIn_mobj_t(mobj); // Restore broken pointers. mobj->info = &mobjinfo[mobj->type]; P_SetThingPosition(mobj); mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; mobj->thinker.function = P_MobjThinker; P_AddThinker(&mobj->thinker); } P_CreateTIDList(); P_InitCreatureCorpseQueue(true); // true = scan for corpses } //========================================================================== // // GetMobjNum // //========================================================================== static int GetMobjNum(mobj_t * mobj) { if (mobj == NULL) { return MOBJ_NULL; } if (mobj->player && !SavingPlayers) { return MOBJ_XX_PLAYER; } return mobj->archiveNum; } //========================================================================== // // SetMobjPtr // //========================================================================== static void SetMobjPtr(mobj_t **ptr, unsigned int archiveNum) { if (archiveNum == MOBJ_NULL) { *ptr = NULL; } else if (archiveNum == MOBJ_XX_PLAYER) { if (TargetPlayerCount == MAX_TARGET_PLAYERS) { I_Error("RestoreMobj: exceeded MAX_TARGET_PLAYERS"); } TargetPlayerAddrs[TargetPlayerCount++] = ptr; *ptr = NULL; } else { *ptr = MobjList[archiveNum]; } } //========================================================================== // // Thinker types list. // // This is used by ArchiveThinkers and UnarchiveThinkers, below. // // Original comment: // "This list has been prioritized using frequency estimates" // //========================================================================== static thinkInfo_t ThinkerInfo[] = { { TC_MOVE_FLOOR, T_MoveFloor, StreamOut_floormove_t, StreamIn_floormove_t, RestoreSSThinker, sizeof(floormove_t) }, { TC_PLAT_RAISE, T_PlatRaise, StreamOut_plat_t, StreamIn_plat_t, RestorePlatRaise, sizeof(plat_t) }, { TC_MOVE_CEILING, T_MoveCeiling, StreamOut_ceiling_t, StreamIn_ceiling_t, RestoreMoveCeiling, sizeof(ceiling_t) }, { TC_LIGHT, T_Light, StreamOut_light_t, StreamIn_light_t, NULL, sizeof(light_t) }, { TC_VERTICAL_DOOR, T_VerticalDoor, StreamOut_vldoor_t, StreamIn_vldoor_t, RestoreSSThinker, sizeof(vldoor_t) }, { TC_PHASE, T_Phase, StreamOut_phase_t, StreamIn_phase_t, NULL, sizeof(phase_t) }, { TC_INTERPRET_ACS, T_InterpretACS, StreamOut_acs_t, StreamIn_acs_t, NULL, sizeof(acs_t) }, { TC_ROTATE_POLY, T_RotatePoly, StreamOut_polyevent_t, StreamIn_polyevent_t, NULL, sizeof(polyevent_t) }, { TC_BUILD_PILLAR, T_BuildPillar, StreamOut_pillar_t, StreamIn_pillar_t, RestoreSSThinker, sizeof(pillar_t) }, { TC_MOVE_POLY, T_MovePoly, StreamOut_polyevent_t, StreamIn_polyevent_t, NULL, sizeof(polyevent_t) }, { TC_POLY_DOOR, T_PolyDoor, StreamOut_polydoor_t, StreamIn_polydoor_t, NULL, sizeof(polydoor_t) }, { TC_FLOOR_WAGGLE, T_FloorWaggle, StreamOut_floorWaggle_t, StreamIn_floorWaggle_t, RestoreSSThinker, sizeof(floorWaggle_t) }, { TC_NULL, NULL, NULL, NULL, NULL, 0}, }; //========================================================================== // // ArchiveThinkers // //========================================================================== static void ArchiveThinkers(void) { thinker_t *thinker; thinkInfo_t *info; StreamOutLong(ASEG_THINKERS); for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { for (info = ThinkerInfo; info->tClass != TC_NULL; info++) { if (thinker->function == info->thinkerFunc) { StreamOutByte(info->tClass); info->writeFunc(thinker); break; } } } // Add a termination marker StreamOutByte(TC_NULL); } //========================================================================== // // UnarchiveThinkers // //========================================================================== static void UnarchiveThinkers(void) { int tClass; thinker_t *thinker; thinkInfo_t *info; AssertSegment(ASEG_THINKERS); while ((tClass = GET_BYTE) != TC_NULL) { for (info = ThinkerInfo; info->tClass != TC_NULL; info++) { if (tClass == info->tClass) { thinker = Z_Malloc(info->size, PU_LEVEL, NULL); info->readFunc(thinker); thinker->function = info->thinkerFunc; if (info->restoreFunc) { info->restoreFunc(thinker); } P_AddThinker(thinker); break; } } if (info->tClass == TC_NULL) { I_Error("UnarchiveThinkers: Unknown tClass %d in " "savegame", tClass); } } } //========================================================================== // // RestoreSSThinker // //========================================================================== static void RestoreSSThinker(ssthinker_t *sst) { sst->sector->specialdata = sst->thinker.function; } //========================================================================== // // RestorePlatRaise // //========================================================================== static void RestorePlatRaise(plat_t *plat) { plat->sector->specialdata = T_PlatRaise; P_AddActivePlat(plat); } //========================================================================== // // RestoreMoveCeiling // //========================================================================== static void RestoreMoveCeiling(ceiling_t *ceiling) { ceiling->sector->specialdata = T_MoveCeiling; P_AddActiveCeiling(ceiling); } //========================================================================== // // ArchiveScripts // //========================================================================== static void ArchiveScripts(void) { int i; StreamOutLong(ASEG_SCRIPTS); for (i = 0; i < ACScriptCount; i++) { StreamOutWord(ACSInfo[i].state); StreamOutWord(ACSInfo[i].waitValue); } for (i = 0; i< MAX_ACS_MAP_VARS; ++i) { StreamOutLong(MapVars[i]); } } //========================================================================== // // UnarchiveScripts // //========================================================================== static void UnarchiveScripts(void) { int i; AssertSegment(ASEG_SCRIPTS); for (i = 0; i < ACScriptCount; i++) { ACSInfo[i].state = GET_WORD; ACSInfo[i].waitValue = GET_WORD; } for (i = 0; i < MAX_ACS_MAP_VARS; ++i) { MapVars[i] = GET_LONG; } } //========================================================================== // // ArchiveMisc // //========================================================================== static void ArchiveMisc(void) { int ix; StreamOutLong(ASEG_MISC); for (ix = 0; ix < maxplayers; ix++) { StreamOutLong(localQuakeHappening[ix]); } } //========================================================================== // // UnarchiveMisc // //========================================================================== static void UnarchiveMisc(void) { int ix; AssertSegment(ASEG_MISC); for (ix = 0; ix < maxplayers; ix++) { localQuakeHappening[ix] = GET_LONG; } } //========================================================================== // // RemoveAllThinkers // //========================================================================== static void RemoveAllThinkers(void) { thinker_t *thinker; thinker_t *nextThinker; thinker = thinkercap.next; while (thinker != &thinkercap) { nextThinker = thinker->next; if (thinker->function == P_MobjThinker) { P_RemoveMobj((mobj_t *) thinker); } else { Z_Free(thinker); } thinker = nextThinker; } P_InitThinkers(); } //========================================================================== // // ArchiveSounds // //========================================================================== static void ArchiveSounds(void) { seqnode_t *node; sector_t *sec; int difference; int i; StreamOutLong(ASEG_SOUNDS); // Save the sound sequences StreamOutLong(ActiveSequences); for (node = SequenceListHead; node; node = node->next) { StreamOutLong(node->sequence); StreamOutLong(node->delayTics); StreamOutLong(node->volume); StreamOutLong(SN_GetSequenceOffset(node->sequence, node->sequencePtr)); StreamOutLong(node->currentSoundID); for (i = 0; i < po_NumPolyobjs; i++) { if (node->mobj == (mobj_t *) & polyobjs[i].startSpot) { break; } } if (i == po_NumPolyobjs) { // Sound is attached to a sector, not a polyobj sec = R_PointInSubsector(node->mobj->x, node->mobj->y)->sector; difference = (int) ((byte *) sec - (byte *) & sectors[0]) / sizeof(sector_t); StreamOutLong(0); // 0 -- sector sound origin } else { StreamOutLong(1); // 1 -- polyobj sound origin difference = i; } StreamOutLong(difference); } } //========================================================================== // // UnarchiveSounds // //========================================================================== static void UnarchiveSounds(void) { int i; int numSequences; int sequence; int delayTics; int volume; int seqOffset; int soundID; int polySnd; int secNum; mobj_t *sndMobj; AssertSegment(ASEG_SOUNDS); // Reload and restart all sound sequences numSequences = GET_LONG; i = 0; while (i < numSequences) { sequence = GET_LONG; delayTics = GET_LONG; volume = GET_LONG; seqOffset = GET_LONG; soundID = GET_LONG; polySnd = GET_LONG; secNum = GET_LONG; if (!polySnd) { sndMobj = (mobj_t *) & sectors[secNum].soundorg; } else { sndMobj = (mobj_t *) & polyobjs[secNum].startSpot; } SN_StartSequence(sndMobj, sequence); SN_ChangeNodeData(i, seqOffset, delayTics, volume, soundID); i++; } } //========================================================================== // // ArchivePolyobjs // //========================================================================== static void ArchivePolyobjs(void) { int i; StreamOutLong(ASEG_POLYOBJS); StreamOutLong(po_NumPolyobjs); for (i = 0; i < po_NumPolyobjs; i++) { StreamOutLong(polyobjs[i].tag); StreamOutLong(polyobjs[i].angle); StreamOutLong(polyobjs[i].startSpot.x); StreamOutLong(polyobjs[i].startSpot.y); } } //========================================================================== // // UnarchivePolyobjs // //========================================================================== static void UnarchivePolyobjs(void) { int i; fixed_t deltaX; fixed_t deltaY; AssertSegment(ASEG_POLYOBJS); if (GET_LONG != po_NumPolyobjs) { I_Error("UnarchivePolyobjs: Bad polyobj count"); } for (i = 0; i < po_NumPolyobjs; i++) { if (GET_LONG != polyobjs[i].tag) { I_Error("UnarchivePolyobjs: Invalid polyobj tag"); } PO_RotatePolyobj(polyobjs[i].tag, (angle_t) GET_LONG); deltaX = GET_LONG - polyobjs[i].startSpot.x; deltaY = GET_LONG - polyobjs[i].startSpot.y; PO_MovePolyobj(polyobjs[i].tag, deltaX, deltaY); } } //========================================================================== // // AssertSegment // //========================================================================== static void AssertSegment(gameArchiveSegment_t segType) { if (GET_LONG != segType) { I_Error("Corrupt save game: Segment [%d] failed alignment check", segType); } } //========================================================================== // // ClearSaveSlot // // Deletes all save game files associated with a slot number. // //========================================================================== static void ClearSaveSlot(int slot) { int i; char fileName[100]; for (i = 0; i < MAX_MAPS; i++) { M_snprintf(fileName, sizeof(fileName), "%shex%d%02d.hxs", SavePath, slot, i); remove(fileName); } M_snprintf(fileName, sizeof(fileName), "%shex%d.hxs", SavePath, slot); remove(fileName); } //========================================================================== // // CopySaveSlot // // Copies all the save game files from one slot to another. // //========================================================================== static void CopySaveSlot(int sourceSlot, int destSlot) { int i; char sourceName[100]; char destName[100]; for (i = 0; i < MAX_MAPS; i++) { M_snprintf(sourceName, sizeof(sourceName), "%shex%d%02d.hxs", SavePath, sourceSlot, i); if (ExistingFile(sourceName)) { M_snprintf(destName, sizeof(destName), "%shex%d%02d.hxs", SavePath, destSlot, i); CopyFile(sourceName, destName); } } M_snprintf(sourceName, sizeof(sourceName), "%shex%d.hxs", SavePath, sourceSlot); if (ExistingFile(sourceName)) { M_snprintf(destName, sizeof(destName), "%shex%d.hxs", SavePath, destSlot); CopyFile(sourceName, destName); } } //========================================================================== // // CopyFile // //========================================================================== static void CopyFile(char *sourceName, char *destName) { int length; byte *buffer; length = M_ReadFile(sourceName, &buffer); M_WriteFile(destName, buffer, length); Z_Free(buffer); } //========================================================================== // // ExistingFile // //========================================================================== static boolean ExistingFile(char *name) { FILE *fp; if ((fp = fopen(name, "rb")) != NULL) { fclose(fp); return true; } else { return false; } } //========================================================================== // // OpenStreamOut // //========================================================================== static void OpenStreamOut(char *fileName) { SavingFP = fopen(fileName, "wb"); } //========================================================================== // // CloseStreamOut // //========================================================================== static void CloseStreamOut(void) { if (SavingFP) { fclose(SavingFP); } } //========================================================================== // // StreamOutBuffer // //========================================================================== static void StreamOutBuffer(void *buffer, int size) { fwrite(buffer, size, 1, SavingFP); } //========================================================================== // // StreamOutByte // //========================================================================== static void StreamOutByte(byte val) { fwrite(&val, sizeof(byte), 1, SavingFP); } //========================================================================== // // StreamOutWord // //========================================================================== static void StreamOutWord(unsigned short val) { val = SHORT(val); fwrite(&val, sizeof(unsigned short), 1, SavingFP); } //========================================================================== // // StreamOutLong // //========================================================================== static void StreamOutLong(unsigned int val) { val = LONG(val); fwrite(&val, sizeof(int), 1, SavingFP); } //========================================================================== // // StreamOutPtr // //========================================================================== static void StreamOutPtr(void *val) { long ptr; // Write a pointer value. In Vanilla Hexen pointers are 32-bit but // nowadays they might be larger. Whatever value we write here isn't // going to be much use when we reload the game. ptr = (long) val; StreamOutLong((unsigned int) (ptr & 0xffffffff)); } chocolate-doom-chocolate-doom-2.2.1/src/hexen/textdefs.h000066400000000000000000000145731257432200600232140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // MN_menu.c --------------------------------------------------------------- #define PRESSKEY "press a key." #define PRESSYN "press y or n." #define TXT_PAUSED "PAUSED" #define QUITMSG "are you sure you want to\nquit this great game?" #define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY #define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY #define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY #define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY #define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN #define QLPROMPT "do you want to quickload the game named"\ "\n\n'%s'?\n\n"PRESSYN #define NEWGAME "you can't start a new game\n"\ "while in a network game.\n\n"PRESSKEY #define MSGOFF "Messages OFF" #define MSGON "Messages ON" #define NETEND "you can't end a netgame!\n\n"PRESSKEY #define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN #define DOSY "(press y to quit to dos.)" #define TXT_GAMMA_LEVEL_OFF "GAMMA CORRECTION OFF" #define TXT_GAMMA_LEVEL_1 "GAMMA CORRECTION LEVEL 1" #define TXT_GAMMA_LEVEL_2 "GAMMA CORRECTION LEVEL 2" #define TXT_GAMMA_LEVEL_3 "GAMMA CORRECTION LEVEL 3" #define TXT_GAMMA_LEVEL_4 "GAMMA CORRECTION LEVEL 4" #define EMPTYSTRING "empty slot" // P_inter.c --------------------------------------------------------------- // Mana #define TXT_MANA_1 "BLUE MANA" #define TXT_MANA_2 "GREEN MANA" #define TXT_MANA_BOTH "COMBINED MANA" // Keys #define TXT_KEY_STEEL "STEEL KEY" #define TXT_KEY_CAVE "CAVE KEY" #define TXT_KEY_AXE "AXE KEY" #define TXT_KEY_FIRE "FIRE KEY" #define TXT_KEY_EMERALD "EMERALD KEY" #define TXT_KEY_DUNGEON "DUNGEON KEY" #define TXT_KEY_SILVER "SILVER KEY" #define TXT_KEY_RUSTED "RUSTED KEY" #define TXT_KEY_HORN "HORN KEY" #define TXT_KEY_SWAMP "SWAMP KEY" #define TXT_KEY_CASTLE "CASTLE KEY" // Artifacts #define TXT_ARTIINVULNERABILITY "ICON OF THE DEFENDER" #define TXT_ARTIHEALTH "QUARTZ FLASK" #define TXT_ARTISUPERHEALTH "MYSTIC URN" #define TXT_ARTISUMMON "DARK SERVANT" #define TXT_ARTITORCH "TORCH" #define TXT_ARTIEGG "PORKALATOR" #define TXT_ARTIFLY "WINGS OF WRATH" #define TXT_ARTITELEPORT "CHAOS DEVICE" #define TXT_ARTIPOISONBAG "FLECHETTE" #define TXT_ARTITELEPORTOTHER "BANISHMENT DEVICE" #define TXT_ARTISPEED "BOOTS OF SPEED" #define TXT_ARTIBOOSTMANA "KRATER OF MIGHT" #define TXT_ARTIBOOSTARMOR "DRAGONSKIN BRACERS" #define TXT_ARTIBLASTRADIUS "DISC OF REPULSION" #define TXT_ARTIHEALINGRADIUS "MYSTIC AMBIT INCANT" // Puzzle artifacts #define TXT_ARTIPUZZSKULL "YORICK'S SKULL" #define TXT_ARTIPUZZGEMBIG "HEART OF D'SPARIL" #define TXT_ARTIPUZZGEMRED "RUBY PLANET" #define TXT_ARTIPUZZGEMGREEN1 "EMERALD PLANET" #define TXT_ARTIPUZZGEMGREEN2 "EMERALD PLANET" #define TXT_ARTIPUZZGEMBLUE1 "SAPPHIRE PLANET" #define TXT_ARTIPUZZGEMBLUE2 "SAPPHIRE PLANET" #define TXT_ARTIPUZZBOOK1 "DAEMON CODEX" #define TXT_ARTIPUZZBOOK2 "LIBER OSCURA" #define TXT_ARTIPUZZSKULL2 "FLAME MASK" #define TXT_ARTIPUZZFWEAPON "GLAIVE SEAL" #define TXT_ARTIPUZZCWEAPON "HOLY RELIC" #define TXT_ARTIPUZZMWEAPON "SIGIL OF THE MAGUS" #define TXT_ARTIPUZZGEAR "CLOCK GEAR" #define TXT_USEPUZZLEFAILED "YOU CANNOT USE THIS HERE" // Items #define TXT_ITEMHEALTH "CRYSTAL VIAL" #define TXT_ITEMBAGOFHOLDING "BAG OF HOLDING" #define TXT_ITEMSHIELD1 "SILVER SHIELD" #define TXT_ITEMSHIELD2 "ENCHANTED SHIELD" #define TXT_ITEMSUPERMAP "MAP SCROLL" #define TXT_ARMOR1 "MESH ARMOR" #define TXT_ARMOR2 "FALCON SHIELD" #define TXT_ARMOR3 "PLATINUM HELMET" #define TXT_ARMOR4 "AMULET OF WARDING" // Weapons #define TXT_WEAPON_F2 "TIMON'S AXE" #define TXT_WEAPON_F3 "HAMMER OF RETRIBUTION" #define TXT_WEAPON_F4 "QUIETUS ASSEMBLED" #define TXT_WEAPON_C2 "SERPENT STAFF" #define TXT_WEAPON_C3 "FIRESTORM" #define TXT_WEAPON_C4 "WRAITHVERGE ASSEMBLED" #define TXT_WEAPON_M2 "FROST SHARDS" #define TXT_WEAPON_M3 "ARC OF DEATH" #define TXT_WEAPON_M4 "BLOODSCOURGE ASSEMBLED" #define TXT_QUIETUS_PIECE "SEGMENT OF QUIETUS" #define TXT_WRAITHVERGE_PIECE "SEGMENT OF WRAITHVERGE" #define TXT_BLOODSCOURGE_PIECE "SEGMENT OF BLOODSCOURGE" // SB_bar.c ---------------------------------------------------------------- #define TXT_CHEATGODON "GOD MODE ON" #define TXT_CHEATGODOFF "GOD MODE OFF" #define TXT_CHEATNOCLIPON "NO CLIPPING ON" #define TXT_CHEATNOCLIPOFF "NO CLIPPING OFF" #define TXT_CHEATWEAPONS "ALL WEAPONS" #define TXT_CHEATHEALTH "FULL HEALTH" #define TXT_CHEATKEYS "ALL KEYS" #define TXT_CHEATSOUNDON "SOUND DEBUG ON" #define TXT_CHEATSOUNDOFF "SOUND DEBUG OFF" #define TXT_CHEATTICKERON "TICKER ON" #define TXT_CHEATTICKEROFF "TICKER OFF" #define TXT_CHEATARTIFACTS3 "ALL ARTIFACTS" #define TXT_CHEATARTIFACTSFAIL "BAD INPUT" #define TXT_CHEATWARP "LEVEL WARP" #define TXT_CHEATSCREENSHOT "SCREENSHOT" #define TXT_CHEATIDDQD "TRYING TO CHEAT, EH? NOW YOU DIE!" #define TXT_CHEATIDKFA "CHEATER - YOU DON'T DESERVE WEAPONS" #define TXT_CHEATBADINPUT "BAD INPUT" #define TXT_CHEATNOMAP "CAN'T FIND MAP" // G_game.c ---------------------------------------------------------------- #define TXT_GAMESAVED "GAME SAVED" // M_misc.c ---------------------------------------------------------------- #define HUSTR_CHATMACRO1 "I'm ready to kick butt!" #define HUSTR_CHATMACRO2 "I'm OK." #define HUSTR_CHATMACRO3 "I'm not looking too good!" #define HUSTR_CHATMACRO4 "Help!" #define HUSTR_CHATMACRO5 "You suck!" #define HUSTR_CHATMACRO6 "Next time, scumbag..." #define HUSTR_CHATMACRO7 "Come here!" #define HUSTR_CHATMACRO8 "I'll take care of it." #define HUSTR_CHATMACRO9 "Yes" #define HUSTR_CHATMACRO0 "No" // AM_map.c ---------------------------------------------------------------- #define AMSTR_FOLLOWON "FOLLOW MODE ON" #define AMSTR_FOLLOWOFF "FOLLOW MODE OFF" chocolate-doom-chocolate-doom-2.2.1/src/hexen/xddefs.h000066400000000000000000000104241257432200600226320ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef __XDDEFS__ #define __XDDEFS__ #include "doomtype.h" #include "v_patch.h" //-------------------------------------------------------------------------- // // Map level types // //-------------------------------------------------------------------------- // lump order in a map wad enum { ML_LABEL, ML_THINGS, ML_LINEDEFS, ML_SIDEDEFS, ML_VERTEXES, ML_SEGS, ML_SSECTORS, ML_NODES, ML_SECTORS, ML_REJECT, ML_BLOCKMAP, ML_BEHAVIOR }; typedef struct { short x; short y; } PACKEDATTR mapvertex_t; typedef struct { short textureoffset; short rowoffset; char toptexture[8]; char bottomtexture[8]; char midtexture[8]; short sector; // on viewer's side } PACKEDATTR mapsidedef_t; typedef struct { short v1; short v2; short flags; byte special; byte arg1; byte arg2; byte arg3; byte arg4; byte arg5; short sidenum[2]; // sidenum[1] will be -1 if one sided } PACKEDATTR maplinedef_t; #define ML_BLOCKING 0x0001 #define ML_BLOCKMONSTERS 0x0002 #define ML_TWOSIDED 0x0004 #define ML_DONTPEGTOP 0x0008 #define ML_DONTPEGBOTTOM 0x0010 #define ML_SECRET 0x0020 // don't map as two sided: IT'S A SECRET! #define ML_SOUNDBLOCK 0x0040 // don't let sound cross two of these #define ML_DONTDRAW 0x0080 // don't draw on the automap #define ML_MAPPED 0x0100 // set if already drawn in automap #define ML_REPEAT_SPECIAL 0x0200 // special is repeatable #define ML_SPAC_SHIFT 10 #define ML_SPAC_MASK 0x1c00 #define GET_SPAC(flags) ((flags&ML_SPAC_MASK)>>ML_SPAC_SHIFT) // Special activation types #define SPAC_CROSS 0 // when player crosses line #define SPAC_USE 1 // when player uses line #define SPAC_MCROSS 2 // when monster crosses line #define SPAC_IMPACT 3 // when projectile hits line #define SPAC_PUSH 4 // when player/monster pushes line #define SPAC_PCROSS 5 // when projectile crosses line typedef struct { short floorheight; short ceilingheight; char floorpic[8]; char ceilingpic[8]; short lightlevel; short special; short tag; } PACKEDATTR mapsector_t; typedef struct { short numsegs; short firstseg; // segs are stored sequentially } PACKEDATTR mapsubsector_t; typedef struct { short v1; short v2; short angle; short linedef; short side; short offset; } PACKEDATTR mapseg_t; #define NF_SUBSECTOR 0x8000 typedef struct { short x, y, dx, dy; // partition line short bbox[2][4]; // bounding box for each child unsigned short children[2]; // if NF_SUBSECTOR its a subsector } PACKEDATTR mapnode_t; typedef struct { short tid; short x; short y; short height; short angle; short type; short options; byte special; byte arg1; byte arg2; byte arg3; byte arg4; byte arg5; } PACKEDATTR mapthing_t; #define MTF_EASY 1 #define MTF_NORMAL 2 #define MTF_HARD 4 #define MTF_AMBUSH 8 #define MTF_DORMANT 16 #define MTF_FIGHTER 32 #define MTF_CLERIC 64 #define MTF_MAGE 128 #define MTF_GSINGLE 256 #define MTF_GCOOP 512 #define MTF_GDEATHMATCH 1024 //-------------------------------------------------------------------------- // // Texture definition // //-------------------------------------------------------------------------- typedef struct { short originx; short originy; short patch; short stepdir; short colormap; } PACKEDATTR mappatch_t; typedef struct { char name[8]; boolean masked; short width; short height; int obsolete; short patchcount; mappatch_t patches[1]; } PACKEDATTR maptexture_t; #endif // __XDDEFS__ chocolate-doom-chocolate-doom-2.2.1/src/i_cdmus.c000066400000000000000000000075451257432200600216760ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // SDL implementation of the Hexen CD interface. // #include #include "SDL.h" #include "SDL_cdrom.h" #include "doomtype.h" #include "i_cdmus.h" static SDL_CD *cd_handle = NULL; static char *startup_error = NULL; static const char *cd_name = NULL; int cd_Error; int I_CDMusInit(void) { int drive_num = 0; // The initialize function is re-invoked when the CD track play cheat // is used, so use the opportunity to call SDL_CDStatus() to update // the status of the drive. if (cd_handle == NULL) { if (SDL_Init(SDL_INIT_CDROM) < 0) { startup_error = "Failed to init CD subsystem."; cd_Error = 1; return -1; } // TODO: config variable to control CDROM to use. cd_handle = SDL_CDOpen(drive_num); if (cd_handle == NULL) { startup_error = "Failed to open CD-ROM drive."; cd_Error = 1; return -1; } cd_name = SDL_CDName(drive_num); } if (SDL_CDStatus(cd_handle) == CD_ERROR) { startup_error = "Failed to read CD status."; cd_Error = 1; return -1; } if (!CD_INDRIVE(cd_handle->status)) { startup_error = "No CD in drive."; cd_Error = 1; return -1; } cd_Error = 0; return 0; } // We cannot print status messages inline during startup, they must // be deferred until after I_CDMusInit has returned. void I_CDMusPrintStartup(void) { if (cd_name != NULL) { printf("I_CDMusInit: Using CD-ROM drive: %s\n", cd_name); } if (startup_error != NULL) { fprintf(stderr, "I_CDMusInit: %s\n", startup_error); } } int I_CDMusPlay(int track) { int result; if (cd_handle == NULL) { cd_Error = 1; return -1; } // Play one track // Track is indexed from 1. result = SDL_CDPlayTracks(cd_handle, track - 1, 0, 1, 0); cd_Error = 0; return result; } int I_CDMusStop(void) { int result; result = SDL_CDStop(cd_handle); cd_Error = 0; return result; } int I_CDMusResume(void) { int result; result = SDL_CDResume(cd_handle); cd_Error = 0; return result; } int I_CDMusSetVolume(int volume) { /* Not supported yet */ cd_Error = 0; return 0; } int I_CDMusFirstTrack(void) { int i; if (cd_handle == NULL) { cd_Error = 1; return -1; } // Find the first audio track. for (i=0; inumtracks; ++i) { if (cd_handle->track[i].type == SDL_AUDIO_TRACK) { cd_Error = 0; // Tracks are indexed from 1. return i + 1; } } // Don't know? cd_Error = 1; return -1; } int I_CDMusLastTrack(void) { if (cd_handle == NULL) { cd_Error = 1; return -1; } cd_Error = 0; return cd_handle->numtracks; } int I_CDMusTrackLength(int track_num) { SDL_CDtrack *track; if (cd_handle == NULL || track_num < 1 || track_num > cd_handle->numtracks) { cd_Error = 1; return -1; } // Track number is indexed from 1. track = &cd_handle->track[track_num - 1]; // Round up to the next second cd_Error = 0; return (track->length + CD_FPS - 1) / CD_FPS; } chocolate-doom-chocolate-doom-2.2.1/src/i_cdmus.h000066400000000000000000000025071257432200600216740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // i_cdmus.h #ifndef __ICDMUS__ #define __ICDMUS__ #define CDERR_NOTINSTALLED 10 // MSCDEX not installed #define CDERR_NOAUDIOSUPPORT 11 // CD-ROM Doesn't support audio #define CDERR_NOAUDIOTRACKS 12 // Current CD has no audio tracks #define CDERR_BADDRIVE 20 // Bad drive number #define CDERR_BADTRACK 21 // Bad track number #define CDERR_IOCTLBUFFMEM 22 // Not enough low memory for IOCTL #define CDERR_DEVREQBASE 100 // DevReq errors extern int cd_Error; int I_CDMusInit(void); void I_CDMusPrintStartup(void); int I_CDMusPlay(int track); int I_CDMusStop(void); int I_CDMusResume(void); int I_CDMusSetVolume(int volume); int I_CDMusFirstTrack(void); int I_CDMusLastTrack(void); int I_CDMusTrackLength(int track); #endif chocolate-doom-chocolate-doom-2.2.1/src/i_endoom.c000066400000000000000000000030701257432200600220310ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Exit text-mode ENDOOM screen. // #include #include #include "config.h" #include "doomtype.h" #include "i_video.h" #include "txt_main.h" #define ENDOOM_W 80 #define ENDOOM_H 25 // // Displays the text mode ending screen after the game quits // void I_Endoom(byte *endoom_data) { unsigned char *screendata; int y; int indent; // Set up text mode screen TXT_Init(); I_InitWindowTitle(); I_InitWindowIcon(); // Write the data to the screen memory screendata = TXT_GetScreenData(); indent = (ENDOOM_W - TXT_SCREEN_W) / 2; for (y=0; y 0) { break; } TXT_Sleep(0); } // Shut down text mode screen TXT_Shutdown(); } chocolate-doom-chocolate-doom-2.2.1/src/i_endoom.h000066400000000000000000000014531257432200600220410ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Exit text-mode ENDOOM screen. // #ifndef __I_ENDOOM__ #define __I_ENDOOM__ // Display the Endoom screen on shutdown. Pass a pointer to the // ENDOOM lump. void I_Endoom(byte *data); #endif chocolate-doom-chocolate-doom-2.2.1/src/i_joystick.c000066400000000000000000000173131257432200600224140ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // SDL Joystick code. // #include "SDL.h" #include "SDL_joystick.h" #include #include #include #include "doomtype.h" #include "d_event.h" #include "i_joystick.h" #include "i_system.h" #include "m_config.h" #include "m_misc.h" // When an axis is within the dead zone, it is set to zero. // This is 5% of the full range: #define DEAD_ZONE (32768 / 3) static SDL_Joystick *joystick = NULL; // Configuration variables: // Standard default.cfg Joystick enable/disable static int usejoystick = 0; // Joystick to use, as an SDL joystick index: static int joystick_index = -1; // Which joystick axis to use for horizontal movement, and whether to // invert the direction: static int joystick_x_axis = 0; static int joystick_x_invert = 0; // Which joystick axis to use for vertical movement, and whether to // invert the direction: static int joystick_y_axis = 1; static int joystick_y_invert = 0; // Which joystick axis to use for strafing? static int joystick_strafe_axis = -1; static int joystick_strafe_invert = 0; // Virtual to physical button joystick button mapping. By default this // is a straight mapping. static int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; void I_ShutdownJoystick(void) { if (joystick != NULL) { SDL_JoystickClose(joystick); joystick = NULL; SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } } static boolean IsValidAxis(int axis) { int num_axes; if (axis < 0) { return true; } if (IS_BUTTON_AXIS(axis)) { return true; } if (IS_HAT_AXIS(axis)) { return HAT_AXIS_HAT(axis) < SDL_JoystickNumHats(joystick); } num_axes = SDL_JoystickNumAxes(joystick); return axis < num_axes; } void I_InitJoystick(void) { if (!usejoystick) { return; } if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { return; } if (joystick_index < 0 || joystick_index >= SDL_NumJoysticks()) { printf("I_InitJoystick: Invalid joystick ID: %i\n", joystick_index); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); return; } // Open the joystick joystick = SDL_JoystickOpen(joystick_index); if (joystick == NULL) { printf("I_InitJoystick: Failed to open joystick #%i\n", joystick_index); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); return; } if (!IsValidAxis(joystick_x_axis) || !IsValidAxis(joystick_y_axis) || !IsValidAxis(joystick_strafe_axis)) { printf("I_InitJoystick: Invalid joystick axis for joystick #%i " "(run joystick setup again)\n", joystick_index); SDL_JoystickClose(joystick); joystick = NULL; SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } SDL_JoystickEventState(SDL_ENABLE); // Initialized okay! printf("I_InitJoystick: %s\n", SDL_JoystickName(joystick_index)); I_AtExit(I_ShutdownJoystick, true); } static boolean IsAxisButton(int physbutton) { if (IS_BUTTON_AXIS(joystick_x_axis)) { if (physbutton == BUTTON_AXIS_NEG(joystick_x_axis) || physbutton == BUTTON_AXIS_POS(joystick_x_axis)) { return true; } } if (IS_BUTTON_AXIS(joystick_y_axis)) { if (physbutton == BUTTON_AXIS_NEG(joystick_y_axis) || physbutton == BUTTON_AXIS_POS(joystick_y_axis)) { return true; } } if (IS_BUTTON_AXIS(joystick_strafe_axis)) { if (physbutton == BUTTON_AXIS_NEG(joystick_strafe_axis) || physbutton == BUTTON_AXIS_POS(joystick_strafe_axis)) { return true; } } return false; } // Get the state of the given virtual button. static int ReadButtonState(int vbutton) { int physbutton; // Map from virtual button to physical (SDL) button. if (vbutton < NUM_VIRTUAL_BUTTONS) { physbutton = joystick_physical_buttons[vbutton]; } else { physbutton = vbutton; } // Never read axis buttons as buttons. if (IsAxisButton(physbutton)) { return 0; } return SDL_JoystickGetButton(joystick, physbutton); } // Get a bitmask of all currently-pressed buttons static int GetButtonsState(void) { int i; int result; result = 0; for (i = 0; i < 20; ++i) { if (ReadButtonState(i)) { result |= 1 << i; } } return result; } // Read the state of an axis, inverting if necessary. static int GetAxisState(int axis, int invert) { int result; // Axis -1 means disabled. if (axis < 0) { return 0; } // Is this a button axis, or a hat axis? // If so, we need to handle it specially. result = 0; if (IS_BUTTON_AXIS(axis)) { if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_NEG(axis))) { result -= 32767; } if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_POS(axis))) { result += 32767; } } else if (IS_HAT_AXIS(axis)) { int direction = HAT_AXIS_DIRECTION(axis); int hatval = SDL_JoystickGetHat(joystick, HAT_AXIS_HAT(axis)); if (direction == HAT_AXIS_HORIZONTAL) { if ((hatval & SDL_HAT_LEFT) != 0) { result -= 32767; } else if ((hatval & SDL_HAT_RIGHT) != 0) { result += 32767; } } else if (direction == HAT_AXIS_VERTICAL) { if ((hatval & SDL_HAT_UP) != 0) { result -= 32767; } else if ((hatval & SDL_HAT_DOWN) != 0) { result += 32767; } } } else { result = SDL_JoystickGetAxis(joystick, axis); if (result < DEAD_ZONE && result > -DEAD_ZONE) { result = 0; } } if (invert) { result = -result; } return result; } void I_UpdateJoystick(void) { if (joystick != NULL) { event_t ev; ev.type = ev_joystick; ev.data1 = GetButtonsState(); ev.data2 = GetAxisState(joystick_x_axis, joystick_x_invert); ev.data3 = GetAxisState(joystick_y_axis, joystick_y_invert); ev.data4 = GetAxisState(joystick_strafe_axis, joystick_strafe_invert); D_PostEvent(&ev); } } void I_BindJoystickVariables(void) { int i; M_BindIntVariable("use_joystick", &usejoystick); M_BindIntVariable("joystick_index", &joystick_index); M_BindIntVariable("joystick_x_axis", &joystick_x_axis); M_BindIntVariable("joystick_y_axis", &joystick_y_axis); M_BindIntVariable("joystick_strafe_axis", &joystick_strafe_axis); M_BindIntVariable("joystick_x_invert", &joystick_x_invert); M_BindIntVariable("joystick_y_invert", &joystick_y_invert); M_BindIntVariable("joystick_strafe_invert",&joystick_strafe_invert); for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i) { char name[32]; M_snprintf(name, sizeof(name), "joystick_physical_button%i", i); M_BindIntVariable(name, &joystick_physical_buttons[i]); } } chocolate-doom-chocolate-doom-2.2.1/src/i_joystick.h000066400000000000000000000047171257432200600224250ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System-specific joystick interface. // #ifndef __I_JOYSTICK__ #define __I_JOYSTICK__ // Number of "virtual" joystick buttons defined in configuration files. // This needs to be at least as large as the number of different key // bindings supported by the higher-level game code (joyb* variables). #define NUM_VIRTUAL_BUTTONS 10 // If this bit is set in a configuration file axis value, the axis is // not actually a joystick axis, but instead is a "button axis". This // means that instead of reading an SDL joystick axis, we read the // state of two buttons to get the axis value. This is needed for eg. // the PS3 SIXAXIS controller, where the D-pad buttons register as // buttons, not as two axes. #define BUTTON_AXIS 0x10000 // Query whether a given axis value describes a button axis. #define IS_BUTTON_AXIS(axis) ((axis) >= 0 && ((axis) & BUTTON_AXIS) != 0) // Get the individual buttons from a button axis value. #define BUTTON_AXIS_NEG(axis) ((axis) & 0xff) #define BUTTON_AXIS_POS(axis) (((axis) >> 8) & 0xff) // Create a button axis value from two button values. #define CREATE_BUTTON_AXIS(neg, pos) (BUTTON_AXIS | (neg) | ((pos) << 8)) // If this bit is set in an axis value, the axis is not actually a // joystick axis, but is a "hat" axis. This means that we read (one of) // the hats on the joystick. #define HAT_AXIS 0x20000 #define IS_HAT_AXIS(axis) ((axis) >= 0 && ((axis) & HAT_AXIS) != 0) // Get the hat number from a hat axis value. #define HAT_AXIS_HAT(axis) ((axis) & 0xff) // Which axis of the hat? (horizonal or vertical) #define HAT_AXIS_DIRECTION(axis) (((axis) >> 8) & 0xff) #define CREATE_HAT_AXIS(hat, direction) \ (HAT_AXIS | (hat) | ((direction) << 8)) #define HAT_AXIS_HORIZONTAL 1 #define HAT_AXIS_VERTICAL 2 void I_InitJoystick(void); void I_ShutdownJoystick(void); void I_UpdateJoystick(void); void I_BindJoystickVariables(void); #endif /* #ifndef __I_JOYSTICK__ */ chocolate-doom-chocolate-doom-2.2.1/src/i_main.c000066400000000000000000000021761257432200600215020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Main program, simply calls D_DoomMain high level loop. // #include "config.h" #include #include "SDL.h" #include "doomtype.h" #include "i_system.h" #include "m_argv.h" // // D_DoomMain() // Not a globally visible function, just included for source reference, // calls all startup code, parses command line options. // void D_DoomMain (void); int main(int argc, char **argv) { // save arguments myargc = argc; myargv = argv; M_FindResponseFile(); // start doom D_DoomMain (); return 0; } chocolate-doom-chocolate-doom-2.2.1/src/i_oplmusic.c000066400000000000000000001302561257432200600224120ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System interface for music. // #include #include #include #include "memio.h" #include "mus2mid.h" #include "deh_main.h" #include "i_sound.h" #include "i_swap.h" #include "m_misc.h" #include "w_wad.h" #include "z_zone.h" #include "opl.h" #include "midifile.h" // #define OPL_MIDI_DEBUG #define MAXMIDLENGTH (96 * 1024) #define GENMIDI_NUM_INSTRS 128 #define GENMIDI_NUM_PERCUSSION 47 #define GENMIDI_HEADER "#OPL_II#" #define GENMIDI_FLAG_FIXED 0x0001 /* fixed pitch */ #define GENMIDI_FLAG_2VOICE 0x0004 /* double voice (OPL3) */ #define PERCUSSION_LOG_LEN 16 typedef struct { byte tremolo; byte attack; byte sustain; byte waveform; byte scale; byte level; } PACKEDATTR genmidi_op_t; typedef struct { genmidi_op_t modulator; byte feedback; genmidi_op_t carrier; byte unused; short base_note_offset; } PACKEDATTR genmidi_voice_t; typedef struct { unsigned short flags; byte fine_tuning; byte fixed_note; genmidi_voice_t voices[2]; } PACKEDATTR genmidi_instr_t; // Data associated with a channel of a track that is currently playing. typedef struct { // The instrument currently used for this track. genmidi_instr_t *instrument; // Volume level int volume; // Pan int pan; // Pitch bend value: int bend; } opl_channel_data_t; // Data associated with a track that is currently playing. typedef struct { // Data for each channel. opl_channel_data_t channels[MIDI_CHANNELS_PER_TRACK]; // Track iterator used to read new events. midi_track_iter_t *iter; } opl_track_data_t; typedef struct opl_voice_s opl_voice_t; struct opl_voice_s { // Index of this voice: int index; // The operators used by this voice: int op1, op2; // Array used by voice: int array; // Currently-loaded instrument data genmidi_instr_t *current_instr; // The voice number in the instrument to use. // This is normally set to zero; if this is a double voice // instrument, it may be one. unsigned int current_instr_voice; // The channel currently using this voice. opl_channel_data_t *channel; // The midi key that this voice is playing. unsigned int key; // The note being played. This is normally the same as // the key, but if the instrument is a fixed pitch // instrument, it is different. unsigned int note; // The frequency value being used. unsigned int freq; // The volume of the note being played on this channel. unsigned int note_volume; // The current volume (register value) that has been set for this channel. unsigned int reg_volume; // Pan. unsigned int reg_pan; // Priority. unsigned int priority; // Next in linked list; a voice is always either in the // free list or the allocated list. opl_voice_t *next; }; // Operators used by the different voices. static const int voice_operators[2][OPL_NUM_VOICES] = { { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12 }, { 0x03, 0x04, 0x05, 0x0b, 0x0c, 0x0d, 0x13, 0x14, 0x15 } }; // Frequency values to use for each note. static const unsigned short frequency_curve[] = { 0x133, 0x133, 0x134, 0x134, 0x135, 0x136, 0x136, 0x137, // -1 0x137, 0x138, 0x138, 0x139, 0x139, 0x13a, 0x13b, 0x13b, 0x13c, 0x13c, 0x13d, 0x13d, 0x13e, 0x13f, 0x13f, 0x140, 0x140, 0x141, 0x142, 0x142, 0x143, 0x143, 0x144, 0x144, 0x145, 0x146, 0x146, 0x147, 0x147, 0x148, 0x149, 0x149, // -2 0x14a, 0x14a, 0x14b, 0x14c, 0x14c, 0x14d, 0x14d, 0x14e, 0x14f, 0x14f, 0x150, 0x150, 0x151, 0x152, 0x152, 0x153, 0x153, 0x154, 0x155, 0x155, 0x156, 0x157, 0x157, 0x158, // These are used for the first seven MIDI note values: 0x158, 0x159, 0x15a, 0x15a, 0x15b, 0x15b, 0x15c, 0x15d, // 0 0x15d, 0x15e, 0x15f, 0x15f, 0x160, 0x161, 0x161, 0x162, 0x162, 0x163, 0x164, 0x164, 0x165, 0x166, 0x166, 0x167, 0x168, 0x168, 0x169, 0x16a, 0x16a, 0x16b, 0x16c, 0x16c, 0x16d, 0x16e, 0x16e, 0x16f, 0x170, 0x170, 0x171, 0x172, // 1 0x172, 0x173, 0x174, 0x174, 0x175, 0x176, 0x176, 0x177, 0x178, 0x178, 0x179, 0x17a, 0x17a, 0x17b, 0x17c, 0x17c, 0x17d, 0x17e, 0x17e, 0x17f, 0x180, 0x181, 0x181, 0x182, 0x183, 0x183, 0x184, 0x185, 0x185, 0x186, 0x187, 0x188, // 2 0x188, 0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18d, 0x18d, 0x18e, 0x18f, 0x18f, 0x190, 0x191, 0x192, 0x192, 0x193, 0x194, 0x194, 0x195, 0x196, 0x197, 0x197, 0x198, 0x199, 0x19a, 0x19a, 0x19b, 0x19c, 0x19d, 0x19d, 0x19e, 0x19f, // 3 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a3, 0x1a4, 0x1a5, 0x1a6, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab, 0x1ac, 0x1ad, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b0, 0x1b1, 0x1b2, 0x1b3, 0x1b4, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, // 4 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bc, 0x1bd, 0x1be, 0x1bf, 0x1c0, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c4, 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb, 0x1cc, 0x1cd, 0x1ce, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, // 5 0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d8, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e5, 0x1e6, 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed, // 6 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203, // First note of looped range used for all octaves: 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, // 7 0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, // 8 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, // 9 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, // 10 0x26f, 0x270, 0x271, 0x272, 0x273, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280, 0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, // 11 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ae, 0x2af, 0x2b0, 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, // 12 0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9, 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, // 13 0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ea, 0x2ec, 0x2ed, 0x2ee, 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, 0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304, 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, // 14 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b, 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, 0x328, 0x329, 0x32b, 0x32c, 0x32e, 0x32f, 0x331, 0x332, 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, // 15 0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a, 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357, 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363, 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, // 16 0x371, 0x373, 0x374, 0x376, 0x378, 0x379, 0x37b, 0x37c, 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, 0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397, 0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4, // 17 0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1, 0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf, 0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x3c8, 0x3ca, 0x3cb, 0x3cd, // The last note has an incomplete range, and loops round back to // the start. Note that the last value is actually a buffer overrun // and does not fit with the other values. 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, // 18 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8, 0x3fa, 0x3fc, 0x3fe, 0x36c, }; // Mapping from MIDI volume level to OPL level value. static const unsigned int volume_mapping_table[] = { 0, 1, 3, 5, 6, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 27, 29, 30, 32, 33, 34, 36, 37, 39, 41, 43, 45, 47, 49, 50, 52, 54, 55, 57, 59, 60, 61, 63, 64, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 84, 85, 86, 87, 88, 89, 90, 91, 92, 92, 93, 94, 95, 96, 96, 97, 98, 99, 99, 100, 101, 101, 102, 103, 103, 104, 105, 105, 106, 107, 107, 108, 109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127 }; static opl_driver_ver_t opl_drv_ver = opl_v_new; static boolean music_initialized = false; //static boolean musicpaused = false; static int current_music_volume; // GENMIDI lump instrument data: static genmidi_instr_t *main_instrs; static genmidi_instr_t *percussion_instrs; static char (*main_instr_names)[32]; static char (*percussion_names)[32]; // Voices: static opl_voice_t voices[OPL_NUM_VOICES * 2]; static opl_voice_t *voice_free_list; static opl_voice_t *voice_alloced_list; static int voice_alloced_num; static int opl_opl3mode; static int num_opl_voices; // Track data for playing tracks: static opl_track_data_t *tracks; static unsigned int num_tracks = 0; static unsigned int running_tracks = 0; static boolean song_looping; // Tempo control variables static unsigned int ticks_per_beat; static unsigned int us_per_beat; // Mini-log of recently played percussion instruments: static uint8_t last_perc[PERCUSSION_LOG_LEN]; static unsigned int last_perc_count; // Configuration file variable, containing the port number for the // adlib chip. char *snd_dmxoption = ""; int opl_io_port = 0x388; // Load instrument table from GENMIDI lump: static boolean LoadInstrumentTable(void) { byte *lump; lump = W_CacheLumpName("GENMIDI", PU_STATIC); // Check header if (strncmp((char *) lump, GENMIDI_HEADER, strlen(GENMIDI_HEADER)) != 0) { W_ReleaseLumpName("GENMIDI"); return false; } main_instrs = (genmidi_instr_t *) (lump + strlen(GENMIDI_HEADER)); percussion_instrs = main_instrs + GENMIDI_NUM_INSTRS; main_instr_names = (char (*)[32]) (percussion_instrs + GENMIDI_NUM_PERCUSSION); percussion_names = main_instr_names + GENMIDI_NUM_INSTRS; return true; } // Get the next available voice from the freelist. static opl_voice_t *GetFreeVoice(void) { opl_voice_t *result; opl_voice_t **rover; // None available? if (voice_free_list == NULL) { return NULL; } // Remove from free list result = voice_free_list; voice_free_list = voice_free_list->next; // Add to allocated list rover = &voice_alloced_list; while (*rover != NULL) { rover = &(*rover)->next; } *rover = result; result->next = NULL; voice_alloced_num++; return result; } // Remove a voice from the allocated voices list. static void RemoveVoiceFromAllocedList(opl_voice_t *voice) { opl_voice_t **rover; rover = &voice_alloced_list; // Search the list until we find the voice, then remove it. while (*rover != NULL) { if (*rover == voice) { *rover = voice->next; voice->next = NULL; voice_alloced_num--; break; } rover = &(*rover)->next; } } // Release a voice back to the freelist. static void VoiceKeyOff(opl_voice_t *voice); static void ReleaseVoice(opl_voice_t *voice) { opl_voice_t **rover; opl_voice_t *next; boolean double_voice; voice->channel = NULL; voice->note = 0; double_voice = voice->current_instr_voice != 0; next = voice->next; // Remove from alloced list. RemoveVoiceFromAllocedList(voice); // Search to the end of the freelist (This is how Doom behaves!) rover = &voice_free_list; while (*rover != NULL) { rover = &(*rover)->next; } *rover = voice; voice->next = NULL; if (next != NULL && double_voice && opl_drv_ver == opl_v_old) { VoiceKeyOff(next); ReleaseVoice(next); } } // Load data to the specified operator static void LoadOperatorData(int operator, genmidi_op_t *data, boolean max_level) { int level; // The scale and level fields must be combined for the level register. // For the carrier wave we always set the maximum level. level = (data->scale & 0xc0) | (data->level & 0x3f); if (max_level) { level |= 0x3f; } OPL_WriteRegister(OPL_REGS_LEVEL + operator, level); OPL_WriteRegister(OPL_REGS_TREMOLO + operator, data->tremolo); OPL_WriteRegister(OPL_REGS_ATTACK + operator, data->attack); OPL_WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain); OPL_WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform); } // Set the instrument for a particular voice. static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr, unsigned int instr_voice) { genmidi_voice_t *data; unsigned int modulating; // Instrument already set for this channel? if (voice->current_instr == instr && voice->current_instr_voice == instr_voice) { return; } voice->current_instr = instr; voice->current_instr_voice = instr_voice; data = &instr->voices[instr_voice]; // Are we usind modulated feedback mode? modulating = (data->feedback & 0x01) == 0; // Doom loads the second operator first, then the first. // The carrier is set to minimum volume until the voice volume // is set in SetVoiceVolume (below). If we are not using // modulating mode, we must set both to minimum volume. LoadOperatorData(voice->op2 | voice->array, &data->carrier, true); LoadOperatorData(voice->op1 | voice->array, &data->modulator, !modulating); // Set feedback register that control the connection between the // two operators. Turn on bits in the upper nybble; I think this // is for OPL3, where it turns on channel A/B. OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array, data->feedback | voice->reg_pan); // Hack to force a volume update. voice->reg_volume = 999; // Calculate voice priority. voice->priority = 0x0f - (data->carrier.attack >> 4) + 0x0f - (data->carrier.sustain & 0x0f); } static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) { genmidi_voice_t *opl_voice; unsigned int midi_volume; unsigned int full_volume; unsigned int car_volume; unsigned int mod_volume; voice->note_volume = volume; opl_voice = &voice->current_instr->voices[voice->current_instr_voice]; // Multiply note volume and channel volume to get the actual volume. midi_volume = 2 * (volume_mapping_table[(voice->channel->volume * current_music_volume) / 127] + 1); full_volume = (volume_mapping_table[voice->note_volume] * midi_volume) >> 9; // The volume value to use in the register: car_volume = 0x3f - full_volume; // Update the volume register(s) if necessary. if (car_volume != voice->reg_volume) { voice->reg_volume = car_volume | (opl_voice->carrier.scale & 0xc0); OPL_WriteRegister((OPL_REGS_LEVEL + voice->op2) | voice->array, voice->reg_volume); // If we are using non-modulated feedback mode, we must set the // volume for both voices. if ((opl_voice->feedback & 0x01) != 0 && opl_voice->modulator.level != 0x3f) { mod_volume = 0x3f - opl_voice->modulator.level; if (mod_volume >= car_volume) { mod_volume = car_volume; } OPL_WriteRegister((OPL_REGS_LEVEL + voice->op1) | voice->array, mod_volume | (opl_voice->modulator.scale & 0xc0)); } } } static void SetVoicePan(opl_voice_t *voice, unsigned int pan) { genmidi_voice_t *opl_voice; voice->reg_pan = pan; opl_voice = &voice->current_instr->voices[voice->current_instr_voice];; OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array, opl_voice->feedback | pan); } // Initialize the voice table and freelist static void InitVoices(void) { int i; // Start with an empty free list. voice_free_list = NULL; // Initialize each voice. for (i = 0; i < num_opl_voices; ++i) { voices[i].index = i % OPL_NUM_VOICES; voices[i].op1 = voice_operators[0][i % OPL_NUM_VOICES]; voices[i].op2 = voice_operators[1][i % OPL_NUM_VOICES]; voices[i].array = (i / OPL_NUM_VOICES) << 8; voices[i].current_instr = NULL; // Add this voice to the freelist. ReleaseVoice(&voices[i]); } } // Set music volume (0 - 127) static void I_OPL_SetMusicVolume(int volume) { unsigned int i; // Internal state variable. current_music_volume = volume; // Update the volume of all voices. for (i = 0; i < num_opl_voices; ++i) { if (voices[i].channel != NULL) { SetVoiceVolume(&voices[i], voices[i].note_volume); } } } static void VoiceKeyOff(opl_voice_t *voice) { OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array, voice->freq >> 8); } static opl_channel_data_t *TrackChannelForEvent(opl_track_data_t *track, midi_event_t *event) { unsigned int channel_num = event->data.channel.channel; // MIDI uses track #9 for percussion, but for MUS it's track #15 // instead. Because DMX works on MUS data internally, we need to // swap back to the MUS version of the channel number. if (channel_num == 9) { channel_num = 15; } else if (channel_num == 15) { channel_num = 9; } return &track->channels[channel_num]; } // Get the frequency that we should be using for a voice. static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event) { opl_channel_data_t *channel; opl_voice_t *rover; opl_voice_t *prev; unsigned int key; /* printf("note off: channel %i, %i, %i\n", event->data.channel.channel, event->data.channel.param1, event->data.channel.param2); */ channel = TrackChannelForEvent(track, event); key = event->data.channel.param1; // Turn off voices being used to play this key. // If it is a double voice instrument there will be two. rover = voice_alloced_list; prev = NULL; while (rover != NULL) { if (rover->channel == channel && rover->key == key) { VoiceKeyOff(rover); // Finished with this voice now. ReleaseVoice(rover); if (prev == NULL) { rover = voice_alloced_list; } else { rover = prev->next; } } else { prev = rover; rover = rover->next; } } } // When all voices are in use, we must discard an existing voice to // play a new note. Find and free an existing voice. The channel // passed to the function is the channel for the new note to be // played. static void ReplaceExistingVoice(void) { opl_voice_t *rover; opl_voice_t *result; // Check the allocated voices, if we find an instrument that is // of a lower priority to the new instrument, discard it. // If a voice is being used to play the second voice of an instrument, // use that, as second voices are non-essential. // Lower numbered MIDI channels implicitly have a higher priority // than higher-numbered channels, eg. MIDI channel 1 is never // discarded for MIDI channel 2. result = voice_alloced_list; for (rover = voice_alloced_list; rover != NULL; rover = rover->next) { if (rover->current_instr_voice != 0 || rover->channel >= result->channel) { result = rover; } } VoiceKeyOff(result); ReleaseVoice(result); } // Alternate version of ReplaceExistingVoice() used when emulating old // versions of the DMX library used in Heretic and Hexen. static void ReplaceExistingVoiceOld(opl_channel_data_t *channel) { opl_voice_t *rover; opl_voice_t *result; opl_voice_t *roverend; int i; int priority; result = voice_alloced_list; roverend = voice_alloced_list; for (i = 0; i < voice_alloced_num - 3; i++) { roverend = roverend->next; } priority = 0x8000; for (rover = voice_alloced_list; rover != roverend; rover = rover->next) { if (rover->priority < priority && rover->channel >= channel) { priority = rover->priority; result = rover; } } VoiceKeyOff(result); ReleaseVoice(result); } static unsigned int FrequencyForVoice(opl_voice_t *voice) { genmidi_voice_t *gm_voice; signed int freq_index; unsigned int octave; unsigned int sub_index; signed int note; note = voice->note; // Apply note offset. // Don't apply offset if the instrument is a fixed note instrument. gm_voice = &voice->current_instr->voices[voice->current_instr_voice]; if ((SHORT(voice->current_instr->flags) & GENMIDI_FLAG_FIXED) == 0) { note += (signed short) SHORT(gm_voice->base_note_offset); } // Avoid possible overflow due to base note offset: while (note < 0) { note += 12; } while (note > 95) { note -= 12; } freq_index = 64 + 32 * note + voice->channel->bend; // If this is the second voice of a double voice instrument, the // frequency index can be adjusted by the fine tuning field. if (voice->current_instr_voice != 0) { freq_index += (voice->current_instr->fine_tuning / 2) - 64; } if (freq_index < 0) { freq_index = 0; } // The first 7 notes use the start of the table, while // consecutive notes loop around the latter part. if (freq_index < 284) { return frequency_curve[freq_index]; } sub_index = (freq_index - 284) % (12 * 32); octave = (freq_index - 284) / (12 * 32); // Once the seventh octave is reached, things break down. // We can only go up to octave 7 as a maximum anyway (the OPL // register only has three bits for octave number), but for the // notes in octave 7, the first five bits have octave=7, the // following notes have octave=6. This 7/6 pattern repeats in // following octaves (which are technically impossible to // represent anyway). if (octave >= 7) { octave = 7; } // Calculate the resulting register value to use for the frequency. return frequency_curve[sub_index + 284] | (octave << 10); } // Update the frequency that a voice is programmed to use. static void UpdateVoiceFrequency(opl_voice_t *voice) { unsigned int freq; // Calculate the frequency to use for this voice and update it // if neccessary. freq = FrequencyForVoice(voice); if (voice->freq != freq) { OPL_WriteRegister((OPL_REGS_FREQ_1 + voice->index) | voice->array, freq & 0xff); OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array, (freq >> 8) | 0x20); voice->freq = freq; } } // Program a single voice for an instrument. For a double voice // instrument (GENMIDI_FLAG_2VOICE), this is called twice for each // key on event. static void VoiceKeyOn(opl_channel_data_t *channel, genmidi_instr_t *instrument, unsigned int instrument_voice, unsigned int note, unsigned int key, unsigned int volume) { opl_voice_t *voice; // Find a voice to use for this new note. voice = GetFreeVoice(); if (voice == NULL) { return; } voice->channel = channel; voice->key = key; // Work out the note to use. This is normally the same as // the key, unless it is a fixed pitch instrument. if ((SHORT(instrument->flags) & GENMIDI_FLAG_FIXED) != 0) { voice->note = instrument->fixed_note; } else { voice->note = note; } voice->reg_pan = channel->pan; // Program the voice with the instrument data: SetVoiceInstrument(voice, instrument, instrument_voice); // Set the volume level. SetVoiceVolume(voice, volume); // Write the frequency value to turn the note on. voice->freq = 0; UpdateVoiceFrequency(voice); } static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event) { genmidi_instr_t *instrument; opl_channel_data_t *channel; unsigned int note, key, volume; boolean double_voice; /* printf("note on: channel %i, %i, %i\n", event->data.channel.channel, event->data.channel.param1, event->data.channel.param2); */ note = event->data.channel.param1; key = event->data.channel.param1; volume = event->data.channel.param2; // A volume of zero means key off. Some MIDI tracks, eg. the ones // in AV.wad, use a second key on with a volume of zero to mean // key off. if (volume <= 0) { KeyOffEvent(track, event); return; } // The channel. channel = TrackChannelForEvent(track, event); // Percussion channel is treated differently. if (event->data.channel.channel == 9) { if (key < 35 || key > 81) { return; } instrument = &percussion_instrs[key - 35]; last_perc[last_perc_count] = key; last_perc_count = (last_perc_count + 1) % PERCUSSION_LOG_LEN; note = 60; } else { instrument = channel->instrument; } double_voice = (SHORT(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0; if (opl_drv_ver == opl_v_old) { if (voice_alloced_num == num_opl_voices) { ReplaceExistingVoiceOld(channel); } if (voice_alloced_num == num_opl_voices - 1 && double_voice) { ReplaceExistingVoiceOld(channel); } // Find and program a voice for this instrument. If this // is a double voice instrument, we must do this twice. if (double_voice) { VoiceKeyOn(channel, instrument, 1, note, key, volume); } VoiceKeyOn(channel, instrument, 0, note, key, volume); } else { if (voice_free_list == NULL) { ReplaceExistingVoice(); } // Find and program a voice for this instrument. If this // is a double voice instrument, we must do this twice. VoiceKeyOn(channel, instrument, 0, note, key, volume); if (double_voice) { VoiceKeyOn(channel, instrument, 1, note, key, volume); } } } static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) { opl_channel_data_t *channel; int instrument; // Set the instrument used on this channel. channel = TrackChannelForEvent(track, event); instrument = event->data.channel.param1; channel->instrument = &main_instrs[instrument]; // TODO: Look through existing voices that are turned on on this // channel, and change the instrument. } static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume) { unsigned int i; channel->volume = volume; // Update all voices that this channel is using. for (i = 0; i < num_opl_voices; ++i) { if (voices[i].channel == channel) { SetVoiceVolume(&voices[i], voices[i].note_volume); } } } static void SetChannelPan(opl_channel_data_t *channel, unsigned int pan) { unsigned int reg_pan; unsigned int i; if (opl_opl3mode) { if (pan >= 96) { reg_pan = 0x10; } else if (pan <= 48) { reg_pan = 0x20; } else { reg_pan = 0x30; } if (channel->pan != reg_pan) { channel->pan = reg_pan; for (i = 0; i < num_opl_voices; i++) { if (voices[i].channel == channel) { SetVoicePan(&voices[i], reg_pan); } } } } } // Handler for the MIDI_CONTROLLER_ALL_NOTES_OFF channel event. static void AllNotesOff(opl_channel_data_t *channel, unsigned int param) { opl_voice_t *rover; opl_voice_t *prev; rover = voice_alloced_list; prev = NULL; while (rover!=NULL) { if (rover->channel == channel) { VoiceKeyOff(rover); // Finished with this voice now. ReleaseVoice(rover); if (prev == NULL) { rover = voice_alloced_list; } else { rover = prev->next; } } else { prev = rover; rover = rover->next; } } } static void ControllerEvent(opl_track_data_t *track, midi_event_t *event) { opl_channel_data_t *channel; unsigned int controller; unsigned int param; /* printf("change controller: channel %i, %i, %i\n", event->data.channel.channel, event->data.channel.param1, event->data.channel.param2); */ channel = TrackChannelForEvent(track, event); controller = event->data.channel.param1; param = event->data.channel.param2; switch (controller) { case MIDI_CONTROLLER_MAIN_VOLUME: SetChannelVolume(channel, param); break; case MIDI_CONTROLLER_PAN: SetChannelPan(channel, param); break; case MIDI_CONTROLLER_ALL_NOTES_OFF: AllNotesOff(channel, param); break; default: #ifdef OPL_MIDI_DEBUG fprintf(stderr, "Unknown MIDI controller type: %i\n", controller); #endif break; } } // Process a pitch bend event. static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event) { opl_channel_data_t *channel; unsigned int i; // Update the channel bend value. Only the MSB of the pitch bend // value is considered: this is what Doom does. channel = TrackChannelForEvent(track, event); channel->bend = event->data.channel.param2 - 64; // Update all voices for this channel. for (i = 0; i < num_opl_voices; ++i) { if (voices[i].channel == channel) { UpdateVoiceFrequency(&voices[i]); } } } static void MetaSetTempo(unsigned int tempo) { OPL_AdjustCallbacks((float) us_per_beat / tempo); us_per_beat = tempo; } // Process a meta event. static void MetaEvent(opl_track_data_t *track, midi_event_t *event) { byte *data = event->data.meta.data; unsigned int data_len = event->data.meta.length; switch (event->data.meta.type) { // Things we can just ignore. case MIDI_META_SEQUENCE_NUMBER: case MIDI_META_TEXT: case MIDI_META_COPYRIGHT: case MIDI_META_TRACK_NAME: case MIDI_META_INSTR_NAME: case MIDI_META_LYRICS: case MIDI_META_MARKER: case MIDI_META_CUE_POINT: case MIDI_META_SEQUENCER_SPECIFIC: break; case MIDI_META_SET_TEMPO: if (data_len == 3) { MetaSetTempo((data[0] << 16) | (data[1] << 8) | data[2]); } break; // End of track - actually handled when we run out of events // in the track, see below. case MIDI_META_END_OF_TRACK: break; default: #ifdef OPL_MIDI_DEBUG fprintf(stderr, "Unknown MIDI meta event type: %i\n", event->data.meta.type); #endif break; } } // Process a MIDI event from a track. static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) { switch (event->event_type) { case MIDI_EVENT_NOTE_OFF: KeyOffEvent(track, event); break; case MIDI_EVENT_NOTE_ON: KeyOnEvent(track, event); break; case MIDI_EVENT_CONTROLLER: ControllerEvent(track, event); break; case MIDI_EVENT_PROGRAM_CHANGE: ProgramChangeEvent(track, event); break; case MIDI_EVENT_PITCH_BEND: PitchBendEvent(track, event); break; case MIDI_EVENT_META: MetaEvent(track, event); break; // SysEx events can be ignored. case MIDI_EVENT_SYSEX: case MIDI_EVENT_SYSEX_SPLIT: break; default: #ifdef OPL_MIDI_DEBUG fprintf(stderr, "Unknown MIDI event type %i\n", event->event_type); #endif break; } } static void ScheduleTrack(opl_track_data_t *track); // Restart a song from the beginning. static void RestartSong(void *unused) { unsigned int i; running_tracks = num_tracks; for (i = 0; i < num_tracks; ++i) { MIDI_RestartIterator(tracks[i].iter); ScheduleTrack(&tracks[i]); } } // Callback function invoked when another event needs to be read from // a track. static void TrackTimerCallback(void *arg) { opl_track_data_t *track = arg; midi_event_t *event; // Get the next event and process it. if (!MIDI_GetNextEvent(track->iter, &event)) { return; } ProcessEvent(track, event); // End of track? if (event->event_type == MIDI_EVENT_META && event->data.meta.type == MIDI_META_END_OF_TRACK) { --running_tracks; // When all tracks have finished, restart the song. // Don't restart the song immediately, but wait for 5ms // before triggering a restart. Otherwise it is possible // to construct an empty MIDI file that causes the game // to lock up in an infinite loop. (5ms should be short // enough not to be noticeable by the listener). if (running_tracks <= 0 && song_looping) { OPL_SetCallback(5000, RestartSong, NULL); } return; } // Reschedule the callback for the next event in the track. ScheduleTrack(track); } static void ScheduleTrack(opl_track_data_t *track) { unsigned int nticks; uint64_t us; // Get the number of microseconds until the next event. nticks = MIDI_GetDeltaTime(track->iter); us = ((uint64_t) nticks * us_per_beat) / ticks_per_beat; // Set a timer to be invoked when the next event is // ready to play. OPL_SetCallback(us, TrackTimerCallback, track); } // Initialize a channel. static void InitChannel(opl_track_data_t *track, opl_channel_data_t *channel) { // TODO: Work out sensible defaults? channel->instrument = &main_instrs[0]; channel->volume = 127; channel->pan = 0x30; channel->bend = 0; } // Start a MIDI track playing: static void StartTrack(midi_file_t *file, unsigned int track_num) { opl_track_data_t *track; unsigned int i; track = &tracks[track_num]; track->iter = MIDI_IterateTrack(file, track_num); for (i = 0; i < MIDI_CHANNELS_PER_TRACK; ++i) { InitChannel(track, &track->channels[i]); } // Schedule the first event. ScheduleTrack(track); } // Start playing a mid static void I_OPL_PlaySong(void *handle, boolean looping) { midi_file_t *file; unsigned int i; if (!music_initialized || handle == NULL) { return; } file = handle; // Allocate track data. tracks = malloc(MIDI_NumTracks(file) * sizeof(opl_track_data_t)); num_tracks = MIDI_NumTracks(file); running_tracks = num_tracks; song_looping = looping; ticks_per_beat = MIDI_GetFileTimeDivision(file); // Default is 120 bpm. // TODO: this is wrong us_per_beat = 500 * 1000; for (i = 0; i < num_tracks; ++i) { StartTrack(file, i); } } static void I_OPL_PauseSong(void) { unsigned int i; if (!music_initialized) { return; } // Pause OPL callbacks. OPL_SetPaused(1); // Turn off all main instrument voices (not percussion). // This is what Vanilla does. for (i = 0; i < num_opl_voices; ++i) { if (voices[i].channel != NULL && voices[i].current_instr < percussion_instrs) { VoiceKeyOff(&voices[i]); } } } static void I_OPL_ResumeSong(void) { if (!music_initialized) { return; } OPL_SetPaused(0); } static void I_OPL_StopSong(void) { unsigned int i; if (!music_initialized) { return; } OPL_Lock(); // Stop all playback. OPL_ClearCallbacks(); // Free all voices. for (i = 0; i < num_opl_voices; ++i) { if (voices[i].channel != NULL) { VoiceKeyOff(&voices[i]); ReleaseVoice(&voices[i]); } } // Free all track data. for (i = 0; i < num_tracks; ++i) { MIDI_FreeIterator(tracks[i].iter); } free(tracks); tracks = NULL; num_tracks = 0; OPL_Unlock(); } static void I_OPL_UnRegisterSong(void *handle) { if (!music_initialized) { return; } if (handle != NULL) { MIDI_FreeFile(handle); } } // Determine whether memory block is a .mid file static boolean IsMid(byte *mem, int len) { return len > 4 && !memcmp(mem, "MThd", 4); } static boolean ConvertMus(byte *musdata, int len, char *filename) { MEMFILE *instream; MEMFILE *outstream; void *outbuf; size_t outbuf_len; int result; instream = mem_fopen_read(musdata, len); outstream = mem_fopen_write(); result = mus2mid(instream, outstream); if (result == 0) { mem_get_buf(outstream, &outbuf, &outbuf_len); M_WriteFile(filename, outbuf, outbuf_len); } mem_fclose(instream); mem_fclose(outstream); return result; } static void *I_OPL_RegisterSong(void *data, int len) { midi_file_t *result; char *filename; if (!music_initialized) { return NULL; } // MUS files begin with "MUS" // Reject anything which doesnt have this signature filename = M_TempFile("doom.mid"); if (IsMid(data, len) && len < MAXMIDLENGTH) { M_WriteFile(filename, data, len); } else { // Assume a MUS file and try to convert ConvertMus(data, len, filename); } result = MIDI_LoadFile(filename); if (result == NULL) { fprintf(stderr, "I_OPL_RegisterSong: Failed to load MID.\n"); } // remove file now remove(filename); free(filename); return result; } // Is the song playing? static boolean I_OPL_MusicIsPlaying(void) { if (!music_initialized) { return false; } return num_tracks > 0; } // Shutdown music static void I_OPL_ShutdownMusic(void) { if (music_initialized) { // Stop currently-playing track, if there is one: I_OPL_StopSong(); OPL_Shutdown(); // Release GENMIDI lump W_ReleaseLumpName("GENMIDI"); music_initialized = false; } } // Initialize music subsystem static boolean I_OPL_InitMusic(void) { char *dmxoption; opl_init_result_t chip_type; OPL_SetSampleRate(snd_samplerate); chip_type = OPL_Init(opl_io_port); if (chip_type == OPL_INIT_NONE) { printf("Dude. The Adlib isn't responding.\n"); return false; } // The DMXOPTION variable must be set to enable OPL3 support. // As an extension, we also allow it to be set from the config file. dmxoption = getenv("DMXOPTION"); if (dmxoption == NULL) { dmxoption = snd_dmxoption != NULL ? snd_dmxoption : ""; } if (chip_type == OPL_INIT_OPL3 && strstr(dmxoption, "-opl3") != NULL) { opl_opl3mode = 1; num_opl_voices = OPL_NUM_VOICES * 2; } else { opl_opl3mode = 0; num_opl_voices = OPL_NUM_VOICES; } // Initialize all registers. OPL_InitRegisters(opl_opl3mode); // Load instruments from GENMIDI lump: if (!LoadInstrumentTable()) { OPL_Shutdown(); return false; } InitVoices(); tracks = NULL; num_tracks = 0; music_initialized = true; return true; } static snddevice_t music_opl_devices[] = { SNDDEVICE_ADLIB, SNDDEVICE_SB, }; music_module_t music_opl_module = { music_opl_devices, arrlen(music_opl_devices), I_OPL_InitMusic, I_OPL_ShutdownMusic, I_OPL_SetMusicVolume, I_OPL_PauseSong, I_OPL_ResumeSong, I_OPL_RegisterSong, I_OPL_UnRegisterSong, I_OPL_PlaySong, I_OPL_StopSong, I_OPL_MusicIsPlaying, NULL, // Poll }; void I_SetOPLDriverVer(opl_driver_ver_t ver) { opl_drv_ver = ver; } //---------------------------------------------------------------------- // // Development / debug message generation, to help developing GENMIDI // lumps. // //---------------------------------------------------------------------- static int NumActiveChannels(void) { int i; for (i = MIDI_CHANNELS_PER_TRACK - 1; i >= 0; --i) { if (tracks[0].channels[i].instrument != &main_instrs[0]) { return i + 1; } } return 0; } static int ChannelInUse(opl_channel_data_t *channel) { opl_voice_t *voice; for (voice = voice_alloced_list; voice != NULL; voice = voice->next) { if (voice->channel == channel) { return 1; } } return 0; } void I_OPL_DevMessages(char *result, size_t result_len) { char tmp[80]; int instr_num; int lines; int i; if (num_tracks == 0) { M_snprintf(result, result_len, "No OPL track!"); return; } M_snprintf(result, result_len, "Tracks:\n"); lines = 1; for (i = 0; i < NumActiveChannels(); ++i) { if (tracks[0].channels[i].instrument == NULL) { continue; } instr_num = tracks[0].channels[i].instrument - main_instrs; M_snprintf(tmp, sizeof(tmp), "chan %i: %c i#%i (%s)\n", i, ChannelInUse(&tracks[0].channels[i]) ? '\'' : ' ', instr_num + 1, main_instr_names[instr_num]); M_StringConcat(result, tmp, result_len); ++lines; } M_snprintf(tmp, sizeof(tmp), "\nLast percussion:\n"); M_StringConcat(result, tmp, result_len); lines += 2; i = (last_perc_count + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN; do { if (last_perc[i] == 0) { break; } M_snprintf(tmp, sizeof(tmp), "%cp#%i (%s)\n", i == 0 ? '\'' : ' ', last_perc[i], percussion_names[last_perc[i] - 35]); M_StringConcat(result, tmp, result_len); ++lines; i = (i + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN; } while (lines < 25 && i != last_perc_count); } chocolate-doom-chocolate-doom-2.2.1/src/i_pcsound.c000066400000000000000000000154271257432200600222340ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System interface for PC speaker sound. // #include "SDL.h" #include #include "doomtype.h" #include "deh_str.h" #include "i_sound.h" #include "m_misc.h" #include "w_wad.h" #include "z_zone.h" #include "pcsound.h" #define TIMER_FREQ 1193181 /* hz */ static boolean pcs_initialized = false; static SDL_mutex *sound_lock; static boolean use_sfx_prefix; static uint8_t *current_sound_lump = NULL; static uint8_t *current_sound_pos = NULL; static unsigned int current_sound_remaining = 0; static int current_sound_handle = 0; static int current_sound_lump_num = -1; static const uint16_t divisors[] = { 0, 6818, 6628, 6449, 6279, 6087, 5906, 5736, 5575, 5423, 5279, 5120, 4971, 4830, 4697, 4554, 4435, 4307, 4186, 4058, 3950, 3836, 3728, 3615, 3519, 3418, 3323, 3224, 3131, 3043, 2960, 2875, 2794, 2711, 2633, 2560, 2485, 2415, 2348, 2281, 2213, 2153, 2089, 2032, 1975, 1918, 1864, 1810, 1757, 1709, 1659, 1612, 1565, 1521, 1478, 1435, 1395, 1355, 1316, 1280, 1242, 1207, 1173, 1140, 1107, 1075, 1045, 1015, 986, 959, 931, 905, 879, 854, 829, 806, 783, 760, 739, 718, 697, 677, 658, 640, 621, 604, 586, 570, 553, 538, 522, 507, 493, 479, 465, 452, 439, 427, 415, 403, 391, 380, 369, 359, 348, 339, 329, 319, 310, 302, 293, 285, 276, 269, 261, 253, 246, 239, 232, 226, 219, 213, 207, 201, 195, 190, 184, 179, }; static void PCSCallbackFunc(int *duration, int *freq) { unsigned int tone; *duration = 1000 / 140; if (SDL_LockMutex(sound_lock) < 0) { *freq = 0; return; } if (current_sound_lump != NULL && current_sound_remaining > 0) { // Read the next tone tone = *current_sound_pos; // Use the tone -> frequency lookup table. See pcspkr10.zip // for a full discussion of this. // Check we don't overflow the frequency table. if (tone < arrlen(divisors) && divisors[tone] != 0) { *freq = (int) (TIMER_FREQ / divisors[tone]); } else { *freq = 0; } ++current_sound_pos; --current_sound_remaining; } else { *freq = 0; } SDL_UnlockMutex(sound_lock); } static boolean CachePCSLump(sfxinfo_t *sfxinfo) { int lumplen; int headerlen; // Free the current sound lump back to the cache if (current_sound_lump != NULL) { W_ReleaseLumpNum(current_sound_lump_num); current_sound_lump = NULL; } // Load from WAD current_sound_lump = W_CacheLumpNum(sfxinfo->lumpnum, PU_STATIC); lumplen = W_LumpLength(sfxinfo->lumpnum); // Read header if (current_sound_lump[0] != 0x00 || current_sound_lump[1] != 0x00) { return false; } headerlen = (current_sound_lump[3] << 8) | current_sound_lump[2]; if (headerlen > lumplen - 4) { return false; } // Header checks out ok current_sound_remaining = headerlen; current_sound_pos = current_sound_lump + 4; current_sound_lump_num = sfxinfo->lumpnum; return true; } // These Doom PC speaker sounds are not played - this can be seen in the // Heretic source code, where there are remnants of this left over // from Doom. static boolean IsDisabledSound(sfxinfo_t *sfxinfo) { int i; const char *disabled_sounds[] = { "posact", "bgact", "dmact", "dmpain", "popain", "sawidl", }; for (i=0; iname, disabled_sounds[i])) { return true; } } return false; } static int I_PCS_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) { int result; if (!pcs_initialized) { return -1; } if (IsDisabledSound(sfxinfo)) { return -1; } if (SDL_LockMutex(sound_lock) < 0) { return -1; } result = CachePCSLump(sfxinfo); if (result) { current_sound_handle = channel; } SDL_UnlockMutex(sound_lock); if (result) { return channel; } else { return -1; } } static void I_PCS_StopSound(int handle) { if (!pcs_initialized) { return; } if (SDL_LockMutex(sound_lock) < 0) { return; } // If this is the channel currently playing, immediately end it. if (current_sound_handle == handle) { current_sound_remaining = 0; } SDL_UnlockMutex(sound_lock); } // // Retrieve the raw data lump index // for a given SFX name. // static int I_PCS_GetSfxLumpNum(sfxinfo_t* sfx) { char namebuf[9]; if (use_sfx_prefix) { M_snprintf(namebuf, sizeof(namebuf), "dp%s", DEH_String(sfx->name)); } else { M_StringCopy(namebuf, DEH_String(sfx->name), sizeof(namebuf)); } return W_GetNumForName(namebuf); } static boolean I_PCS_SoundIsPlaying(int handle) { if (!pcs_initialized) { return false; } if (handle != current_sound_handle) { return false; } return current_sound_lump != NULL && current_sound_remaining > 0; } static boolean I_PCS_InitSound(boolean _use_sfx_prefix) { use_sfx_prefix = _use_sfx_prefix; // Use the sample rate from the configuration file PCSound_SetSampleRate(snd_samplerate); // Initialize the PC speaker subsystem. pcs_initialized = PCSound_Init(PCSCallbackFunc); if (pcs_initialized) { sound_lock = SDL_CreateMutex(); } return pcs_initialized; } static void I_PCS_ShutdownSound(void) { if (pcs_initialized) { PCSound_Shutdown(); } } static void I_PCS_UpdateSound(void) { // no-op. } void I_PCS_UpdateSoundParams(int channel, int vol, int sep) { // no-op. } static snddevice_t sound_pcsound_devices[] = { SNDDEVICE_PCSPEAKER, }; sound_module_t sound_pcsound_module = { sound_pcsound_devices, arrlen(sound_pcsound_devices), I_PCS_InitSound, I_PCS_ShutdownSound, I_PCS_GetSfxLumpNum, I_PCS_UpdateSound, I_PCS_UpdateSoundParams, I_PCS_StartSound, I_PCS_StopSound, I_PCS_SoundIsPlaying, }; chocolate-doom-chocolate-doom-2.2.1/src/i_scale.c000066400000000000000000000762501257432200600216510ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Screen scale-up code: // 1x,2x,3x,4x pixel doubling // Aspect ratio-correcting stretch functions // #include #include #include #include "doomtype.h" #include "i_video.h" #include "m_argv.h" #include "z_zone.h" // Should be I_VideoBuffer static byte *src_buffer; // Destination buffer, ie. screen->pixels. static byte *dest_buffer; // Pitch of destination buffer, ie. screen->pitch. static int dest_pitch; // Lookup tables used for aspect ratio correction stretching code. // stretch_tables[0] : 20% / 80% // stretch_tables[1] : 40% / 60% // All other combinations can be reached from these two tables. static byte *stretch_tables[2] = { NULL, NULL }; // 50%/50% stretch table, for 800x600 squash mode static byte *half_stretch_table = NULL; // Called to set the source and destination buffers before doing the // scale. void I_InitScale(byte *_src_buffer, byte *_dest_buffer, int _dest_pitch) { src_buffer = _src_buffer; dest_buffer = _dest_buffer; dest_pitch = _dest_pitch; } // // Pixel doubling scale-up functions. // // 1x scale doesn't really do any scaling: it just copies the buffer // a line at a time for when pitch != SCREENWIDTH (!native_surface) static boolean I_Scale1x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp; int y; int w = x2 - x1; // Need to byte-copy from buffer into the screen buffer bufp = src_buffer + y1 * SCREENWIDTH + x1; screenp = (byte *) dest_buffer + y1 * dest_pitch + x1; for (y=y1; y 240) for (y=0; y 480) for (y=0; y 720) for (y=0; y 960) for (y=0; y 1200) for (y=0; y 0) { screenp = (byte *) dest_buffer + 2 * dest_pitch; for (y=0; y<1198; y += 3) { memset(screenp, 0, 1600); screenp += dest_pitch * 3; } } return true; } screen_mode_t mode_stretch_5x = { SCREENWIDTH * 5, SCREENHEIGHT_4_3 * 5, I_InitStretchTables, I_Stretch5x, false, }; // // Aspect ratio correcting "squash" functions. // // These do the opposite of the "stretch" functions above: while the // stretch functions increase the vertical dimensions, the squash // functions decrease the horizontal dimensions for the same result. // // The same blend tables from the stretch functions are reused; as // a result, the dimensions are *slightly* wrong (eg. 320x200 should // squash to 266x200, but actually squashes to 256x200). // // // 1x squashed scale (256x200) // static inline void WriteSquashedLine1x(byte *dest, byte *src) { int x; for (x=0; x multiples of 320x240) extern screen_mode_t mode_stretch_1x; extern screen_mode_t mode_stretch_2x; extern screen_mode_t mode_stretch_3x; extern screen_mode_t mode_stretch_4x; extern screen_mode_t mode_stretch_5x; // Horizontally squashed modes (320x200 -> multiples of 256x200) extern screen_mode_t mode_squash_1x; extern screen_mode_t mode_squash_2x; extern screen_mode_t mode_squash_3x; extern screen_mode_t mode_squash_4x; // we don't do 5x. #endif /* #ifndef __I_SCALE__ */ chocolate-doom-chocolate-doom-2.2.1/src/i_sdlmusic.c000066400000000000000000000736431257432200600224100ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System interface for music. // #include #include #include #include #include "SDL.h" #include "SDL_mixer.h" #include "config.h" #include "doomtype.h" #include "memio.h" #include "mus2mid.h" #include "deh_str.h" #include "gusconf.h" #include "i_sound.h" #include "i_system.h" #include "i_swap.h" #include "m_argv.h" #include "m_config.h" #include "m_misc.h" #include "sha1.h" #include "w_wad.h" #include "z_zone.h" #define MAXMIDLENGTH (96 * 1024) #define MID_HEADER_MAGIC "MThd" #define MUS_HEADER_MAGIC "MUS\x1a" #define FLAC_HEADER "fLaC" #define OGG_HEADER "OggS" // Looping Vorbis metadata tag names. These have been defined by ZDoom // for specifying the start and end positions for looping music tracks // in .ogg and .flac files. // More information is here: http://zdoom.org/wiki/Audio_loop #define LOOP_START_TAG "LOOP_START" #define LOOP_END_TAG "LOOP_END" // FLAC metadata headers that we care about. #define FLAC_STREAMINFO 0 #define FLAC_VORBIS_COMMENT 4 // Ogg metadata headers that we care about. #define OGG_ID_HEADER 1 #define OGG_COMMENT_HEADER 3 // Structure for music substitution. // We store a mapping based on SHA1 checksum -> filename of substitute music // file to play, so that substitution occurs based on content rather than // lump name. This has some inherent advantages: // * Music for Plutonia (reused from Doom 1) works automatically. // * If a PWAD replaces music, the replacement music is used rather than // the substitute music for the IWAD. // * If a PWAD reuses music from an IWAD (even from a different game), we get // the high quality version of the music automatically (neat!) typedef struct { sha1_digest_t hash; char *filename; } subst_music_t; // Structure containing parsed metadata read from a digital music track: typedef struct { boolean valid; unsigned int samplerate_hz; int start_time, end_time; } file_metadata_t; static subst_music_t *subst_music = NULL; static unsigned int subst_music_len = 0; static const char *subst_config_filenames[] = { "doom1-music.cfg", "doom2-music.cfg", "tnt-music.cfg", "heretic-music.cfg", "hexen-music.cfg", "strife-music.cfg", }; static boolean music_initialized = false; // If this is true, this module initialized SDL sound and has the // responsibility to shut it down static boolean sdl_was_initialized = false; static boolean musicpaused = false; static int current_music_volume; char *timidity_cfg_path = ""; static char *temp_timidity_cfg = NULL; // If true, we are playing a substitute digital track rather than in-WAD // MIDI/MUS track, and file_metadata contains loop metadata. static boolean playing_substitute = false; static file_metadata_t file_metadata; // Position (in samples) that we have reached in the current track. // This is updated by the TrackPositionCallback function. static unsigned int current_track_pos; // Currently playing music track. static Mix_Music *current_track_music = NULL; // If true, the currently playing track is being played on loop. static boolean current_track_loop; // Given a time string (for LOOP_START/LOOP_END), parse it and return // the time (in # samples since start of track) it represents. static unsigned int ParseVorbisTime(unsigned int samplerate_hz, char *value) { char *num_start, *p; unsigned int result = 0; char c; if (strchr(value, ':') == NULL) { return atoi(value); } result = 0; num_start = value; for (p = value; *p != '\0'; ++p) { if (*p == '.' || *p == ':') { c = *p; *p = '\0'; result = result * 60 + atoi(num_start); num_start = p + 1; *p = c; } if (*p == '.') { return result * samplerate_hz + (unsigned int) (atof(p) * samplerate_hz); } } return (result * 60 + atoi(num_start)) * samplerate_hz; } // Given a vorbis comment string (eg. "LOOP_START=12345"), set fields // in the metadata structure as appropriate. static void ParseVorbisComment(file_metadata_t *metadata, char *comment) { char *eq, *key, *value; eq = strchr(comment, '='); if (eq == NULL) { return; } key = comment; *eq = '\0'; value = eq + 1; if (!strcmp(key, LOOP_START_TAG)) { metadata->start_time = ParseVorbisTime(metadata->samplerate_hz, value); } else if (!strcmp(key, LOOP_END_TAG)) { metadata->end_time = ParseVorbisTime(metadata->samplerate_hz, value); } } // Parse a vorbis comments structure, reading from the given file. static void ParseVorbisComments(file_metadata_t *metadata, FILE *fs) { uint32_t buf; unsigned int num_comments, i, comment_len; char *comment; // We must have read the sample rate already from an earlier header. if (metadata->samplerate_hz == 0) { return; } // Skip the starting part we don't care about. if (fread(&buf, 4, 1, fs) < 1) { return; } if (fseek(fs, LONG(buf), SEEK_CUR) != 0) { return; } // Read count field for number of comments. if (fread(&buf, 4, 1, fs) < 1) { return; } num_comments = LONG(buf); // Read each individual comment. for (i = 0; i < num_comments; ++i) { // Read length of comment. if (fread(&buf, 4, 1, fs) < 1) { return; } comment_len = LONG(buf); // Read actual comment data into string buffer. comment = calloc(1, comment_len + 1); if (comment == NULL || fread(comment, 1, comment_len, fs) < comment_len) { free(comment); break; } // Parse comment string. ParseVorbisComment(metadata, comment); free(comment); } } static void ParseFlacStreaminfo(file_metadata_t *metadata, FILE *fs) { byte buf[34]; // Read block data. if (fread(buf, sizeof(buf), 1, fs) < 1) { return; } // We only care about sample rate and song length. metadata->samplerate_hz = (buf[10] << 12) | (buf[11] << 4) | (buf[12] >> 4); // Song length is actually a 36 bit field, but 32 bits should be // enough for everybody. //metadata->song_length = (buf[14] << 24) | (buf[15] << 16) // | (buf[16] << 8) | buf[17]; } static void ParseFlacFile(file_metadata_t *metadata, FILE *fs) { byte header[4]; unsigned int block_type; size_t block_len; boolean last_block; for (;;) { long pos = -1; // Read METADATA_BLOCK_HEADER: if (fread(header, 4, 1, fs) < 1) { return; } block_type = header[0] & ~0x80; last_block = (header[0] & 0x80) != 0; block_len = (header[1] << 16) | (header[2] << 8) | header[3]; pos = ftell(fs); if (pos < 0) { return; } if (block_type == FLAC_STREAMINFO) { ParseFlacStreaminfo(metadata, fs); } else if (block_type == FLAC_VORBIS_COMMENT) { ParseVorbisComments(metadata, fs); } if (last_block) { break; } // Seek to start of next block. if (fseek(fs, pos + block_len, SEEK_SET) != 0) { return; } } } static void ParseOggIdHeader(file_metadata_t *metadata, FILE *fs) { byte buf[21]; if (fread(buf, sizeof(buf), 1, fs) < 1) { return; } metadata->samplerate_hz = (buf[8] << 24) | (buf[7] << 16) | (buf[6] << 8) | buf[5]; } static void ParseOggFile(file_metadata_t *metadata, FILE *fs) { byte buf[7]; unsigned int offset; // Scan through the start of the file looking for headers. They // begin '[byte]vorbis' where the byte value indicates header type. memset(buf, 0, sizeof(buf)); for (offset = 0; offset < 100 * 1024; ++offset) { // buf[] is used as a sliding window. Each iteration, we // move the buffer one byte to the left and read an extra // byte onto the end. memmove(buf, buf + 1, sizeof(buf) - 1); if (fread(&buf[6], 1, 1, fs) < 1) { return; } if (!memcmp(buf + 1, "vorbis", 6)) { switch (buf[0]) { case OGG_ID_HEADER: ParseOggIdHeader(metadata, fs); break; case OGG_COMMENT_HEADER: ParseVorbisComments(metadata, fs); break; default: break; } } } } static void ReadLoopPoints(char *filename, file_metadata_t *metadata) { FILE *fs; char header[4]; metadata->valid = false; metadata->samplerate_hz = 0; metadata->start_time = 0; metadata->end_time = -1; fs = fopen(filename, "r"); if (fs == NULL) { return; } // Check for a recognized file format; use the first four bytes // of the file. if (fread(header, 4, 1, fs) < 1) { fclose(fs); return; } if (memcmp(header, FLAC_HEADER, 4) == 0) { ParseFlacFile(metadata, fs); } else if (memcmp(header, OGG_HEADER, 4) == 0) { ParseOggFile(metadata, fs); } fclose(fs); // Only valid if at the very least we read the sample rate. metadata->valid = metadata->samplerate_hz > 0; // If start and end time are both zero, ignore the loop tags. // This is consistent with other source ports. if (metadata->start_time == 0 && metadata->end_time == 0) { metadata->valid = false; } } // Given a MUS lump, look up a substitute MUS file to play instead // (or NULL to just use normal MIDI playback). static char *GetSubstituteMusicFile(void *data, size_t data_len) { sha1_context_t context; sha1_digest_t hash; char *filename; unsigned int i; // Don't bother doing a hash if we're never going to find anything. if (subst_music_len == 0) { return NULL; } SHA1_Init(&context); SHA1_Update(&context, data, data_len); SHA1_Final(hash, &context); // Look for a hash that matches. // The substitute mapping list can (intentionally) contain multiple // filename mappings for the same hash. This allows us to try // different files and fall back if our first choice isn't found. filename = NULL; for (i = 0; i < subst_music_len; ++i) { if (memcmp(hash, subst_music[i].hash, sizeof(hash)) == 0) { filename = subst_music[i].filename; // If the file exists, then use this file in preference to // any fallbacks. But we always return a filename if it's // in the list, even if it's just so we can print an error // message to the user saying it doesn't exist. if (M_FileExists(filename)) { break; } } } return filename; } // Add a substitute music file to the lookup list. static void AddSubstituteMusic(subst_music_t *subst) { ++subst_music_len; subst_music = realloc(subst_music, sizeof(subst_music_t) * subst_music_len); memcpy(&subst_music[subst_music_len - 1], subst, sizeof(subst_music_t)); } static int ParseHexDigit(char c) { c = tolower(c); if (c >= '0' && c <= '9') { return c - '0'; } else if (c >= 'a' && c <= 'f') { return 10 + (c - 'a'); } else { return -1; } } static char *GetFullPath(char *base_filename, char *path) { char *basedir, *result; char *p; // Starting with directory separator means we have an absolute path, // so just return it. if (path[0] == DIR_SEPARATOR) { return M_StringDuplicate(path); } #ifdef _WIN32 // d:\path\... if (isalpha(path[0]) && path[1] == ':' && path[2] == DIR_SEPARATOR) { return M_StringDuplicate(path); } #endif // Paths in the substitute filenames can contain Unix-style / // path separators, but we should convert this to the separator // for the native platform. path = M_StringReplace(path, "/", DIR_SEPARATOR_S); // Copy config filename and cut off the filename to just get the // parent dir. basedir = M_StringDuplicate(base_filename); p = strrchr(basedir, DIR_SEPARATOR); if (p != NULL) { p[1] = '\0'; result = M_StringJoin(basedir, path, NULL); } else { result = M_StringDuplicate(path); } free(basedir); free(path); return result; } // Parse a line from substitute music configuration file; returns error // message or NULL for no error. static char *ParseSubstituteLine(char *filename, char *line) { subst_music_t subst; char *p; int hash_index; // Strip out comments if present. p = strchr(line, '#'); if (p != NULL) { while (p > line && isspace(*(p - 1))) { --p; } *p = '\0'; } // Skip leading spaces. for (p = line; *p != '\0' && isspace(*p); ++p); // Empty line? This includes comment lines now that comments have // been stripped. if (*p == '\0') { return NULL; } // Read hash. hash_index = 0; while (*p != '\0' && *p != '=' && !isspace(*p)) { int d1, d2; d1 = ParseHexDigit(p[0]); d2 = ParseHexDigit(p[1]); if (d1 < 0 || d2 < 0) { return "Invalid hex digit in SHA1 hash"; } else if (hash_index >= sizeof(sha1_digest_t)) { return "SHA1 hash too long"; } subst.hash[hash_index] = (d1 << 4) | d2; ++hash_index; p += 2; } if (hash_index != sizeof(sha1_digest_t)) { return "SHA1 hash too short"; } // Skip spaces. for (; *p != '\0' && isspace(*p); ++p); if (*p != '=') { return "Expected '='"; } ++p; // Skip spaces. for (; *p != '\0' && isspace(*p); ++p); // We're now at the filename. Cut off trailing space characters. while (strlen(p) > 0 && isspace(p[strlen(p) - 1])) { p[strlen(p) - 1] = '\0'; } if (strlen(p) == 0) { return "No filename specified for music substitution"; } // Expand full path and add to our database of substitutes. subst.filename = GetFullPath(filename, p); AddSubstituteMusic(&subst); return NULL; } // Read a substitute music configuration file. static boolean ReadSubstituteConfig(char *filename) { char line[128]; FILE *fs; char *error; int linenum = 1; // int old_subst_music_len; fs = fopen(filename, "r"); if (fs == NULL) { return false; } // old_subst_music_len = subst_music_len; while (!feof(fs)) { M_StringCopy(line, "", sizeof(line)); fgets(line, sizeof(line), fs); error = ParseSubstituteLine(filename, line); if (error != NULL) { fprintf(stderr, "%s:%i: Error: %s\n", filename, linenum, error); } ++linenum; } fclose(fs); return true; } // Find substitute configs and try to load them. static void LoadSubstituteConfigs(void) { char *musicdir; char *path; unsigned int i; if (!strcmp(configdir, "")) { musicdir = M_StringDuplicate(""); } else { musicdir = M_StringJoin(configdir, "music", DIR_SEPARATOR_S, NULL); } // Load all music packs. We always load all music substitution packs for // all games. Why? Suppose we have a Doom PWAD that reuses some music from // Heretic. If we have the Heretic music pack loaded, then we get an // automatic substitution. for (i = 0; i < arrlen(subst_config_filenames); ++i) { path = M_StringJoin(musicdir, subst_config_filenames[i], NULL); ReadSubstituteConfig(path); free(path); } free(musicdir); if (subst_music_len > 0) { printf("Loaded %i music substitutions from config files.\n", subst_music_len); } } // Returns true if the given lump number is a music lump that should // be included in substitute configs. // Identifying music lumps by name is not feasible; some games (eg. // Heretic, Hexen) don't have a common naming pattern for music lumps. static boolean IsMusicLump(int lumpnum) { byte *data; boolean result; if (W_LumpLength(lumpnum) < 4) { return false; } data = W_CacheLumpNum(lumpnum, PU_STATIC); result = memcmp(data, MUS_HEADER_MAGIC, 4) == 0 || memcmp(data, MID_HEADER_MAGIC, 4) == 0; W_ReleaseLumpNum(lumpnum); return result; } // Dump an example config file containing checksums for all MIDI music // found in the WAD directory. static void DumpSubstituteConfig(char *filename) { sha1_context_t context; sha1_digest_t digest; char name[9]; byte *data; FILE *fs; unsigned int lumpnum; size_t h; fs = fopen(filename, "w"); if (fs == NULL) { I_Error("Failed to open %s for writing", filename); return; } fprintf(fs, "# Example %s substitute MIDI file.\n\n", PACKAGE_NAME); fprintf(fs, "# SHA1 hash = filename\n"); for (lumpnum = 0; lumpnum < numlumps; ++lumpnum) { strncpy(name, lumpinfo[lumpnum].name, 8); name[8] = '\0'; if (!IsMusicLump(lumpnum)) { continue; } // Calculate hash. data = W_CacheLumpNum(lumpnum, PU_STATIC); SHA1_Init(&context); SHA1_Update(&context, data, W_LumpLength(lumpnum)); SHA1_Final(digest, &context); W_ReleaseLumpNum(lumpnum); // Print line. for (h = 0; h < sizeof(sha1_digest_t); ++h) { fprintf(fs, "%02x", digest[h]); } fprintf(fs, " = %s.ogg\n", name); } fprintf(fs, "\n"); fclose(fs); printf("Substitute MIDI config file written to %s.\n", filename); I_Quit(); } // If the temp_timidity_cfg config variable is set, generate a "wrapper" // config file for Timidity to point to the actual config file. This // is needed to inject a "dir" command so that the patches are read // relative to the actual config file. static boolean WriteWrapperTimidityConfig(char *write_path) { char *p, *path; FILE *fstream; if (!strcmp(timidity_cfg_path, "")) { return false; } fstream = fopen(write_path, "w"); if (fstream == NULL) { return false; } p = strrchr(timidity_cfg_path, DIR_SEPARATOR); if (p != NULL) { path = M_StringDuplicate(timidity_cfg_path); path[p - timidity_cfg_path] = '\0'; fprintf(fstream, "dir %s\n", path); free(path); } fprintf(fstream, "source %s\n", timidity_cfg_path); fclose(fstream); return true; } void I_InitTimidityConfig(void) { char *env_string; boolean success; temp_timidity_cfg = M_TempFile("timidity.cfg"); if (snd_musicdevice == SNDDEVICE_GUS) { success = GUS_WriteConfig(temp_timidity_cfg); } else { success = WriteWrapperTimidityConfig(temp_timidity_cfg); } // Set the TIMIDITY_CFG environment variable to point to the temporary // config file. if (success) { env_string = M_StringJoin("TIMIDITY_CFG=", temp_timidity_cfg, NULL); putenv(env_string); } else { free(temp_timidity_cfg); temp_timidity_cfg = NULL; } } // Remove the temporary config file generated by I_InitTimidityConfig(). static void RemoveTimidityConfig(void) { if (temp_timidity_cfg != NULL) { remove(temp_timidity_cfg); free(temp_timidity_cfg); } } // Shutdown music static void I_SDL_ShutdownMusic(void) { if (music_initialized) { Mix_HaltMusic(); music_initialized = false; if (sdl_was_initialized) { Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); sdl_was_initialized = false; } } } static boolean SDLIsInitialized(void) { int freq, channels; Uint16 format; return Mix_QuerySpec(&freq, &format, &channels) != 0; } // Callback function that is invoked to track current track position. void TrackPositionCallback(int chan, void *stream, int len, void *udata) { // Position is doubled up twice: for 16-bit samples and for stereo. current_track_pos += len / 4; } // Initialize music subsystem static boolean I_SDL_InitMusic(void) { int i; // SDL_mixer prior to v1.2.11 has a bug that causes crashes // with MIDI playback. Print a warning message if we are // using an old version. #ifdef __MACOSX__ { const SDL_version *v = Mix_Linked_Version(); if (SDL_VERSIONNUM(v->major, v->minor, v->patch) < SDL_VERSIONNUM(1, 2, 11)) { printf("\n" " *** WARNING ***\n" " You are using an old version of SDL_mixer.\n" " Music playback on this version may cause crashes\n" " under OS X and is disabled by default.\n" "\n"); } } #endif //! // @arg // // Read all MIDI files from loaded WAD files, dump an example substitution // music config file to the specified filename and quit. // i = M_CheckParmWithArgs("-dumpsubstconfig", 1); if (i > 0) { DumpSubstituteConfig(myargv[i + 1]); } // If SDL_mixer is not initialized, we have to initialize it // and have the responsibility to shut it down later on. if (SDLIsInitialized()) { music_initialized = true; } else { if (SDL_Init(SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to set up sound.\n"); } else if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0) { fprintf(stderr, "Error initializing SDL_mixer: %s\n", Mix_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); } else { SDL_PauseAudio(0); sdl_was_initialized = true; music_initialized = true; } } // Once initialization is complete, the temporary Timidity config // file can be removed. RemoveTimidityConfig(); // If snd_musiccmd is set, we need to call Mix_SetMusicCMD to // configure an external music playback program. if (strlen(snd_musiccmd) > 0) { Mix_SetMusicCMD(snd_musiccmd); } // Register an effect function to track the music position. Mix_RegisterEffect(MIX_CHANNEL_POST, TrackPositionCallback, NULL, NULL); // If we're in GENMIDI mode, try to load sound packs. if (snd_musicdevice == SNDDEVICE_GENMIDI) { LoadSubstituteConfigs(); } return music_initialized; } // // SDL_mixer's native MIDI music playing does not pause properly. // As a workaround, set the volume to 0 when paused. // static void UpdateMusicVolume(void) { int vol; if (musicpaused) { vol = 0; } else { vol = (current_music_volume * MIX_MAX_VOLUME) / 127; } Mix_VolumeMusic(vol); } // Set music volume (0 - 127) static void I_SDL_SetMusicVolume(int volume) { // Internal state variable. current_music_volume = volume; UpdateMusicVolume(); } // Start playing a mid static void I_SDL_PlaySong(void *handle, boolean looping) { int loops; if (!music_initialized) { return; } if (handle == NULL) { return; } current_track_music = (Mix_Music *) handle; current_track_loop = looping; if (looping) { loops = -1; } else { loops = 1; } // Don't loop when playing substitute music, as we do it // ourselves instead. if (playing_substitute && file_metadata.valid) { loops = 1; SDL_LockAudio(); current_track_pos = 0; // start of track SDL_UnlockAudio(); } Mix_PlayMusic(current_track_music, loops); } static void I_SDL_PauseSong(void) { if (!music_initialized) { return; } musicpaused = true; UpdateMusicVolume(); } static void I_SDL_ResumeSong(void) { if (!music_initialized) { return; } musicpaused = false; UpdateMusicVolume(); } static void I_SDL_StopSong(void) { if (!music_initialized) { return; } Mix_HaltMusic(); playing_substitute = false; current_track_music = NULL; } static void I_SDL_UnRegisterSong(void *handle) { Mix_Music *music = (Mix_Music *) handle; if (!music_initialized) { return; } if (handle == NULL) { return; } Mix_FreeMusic(music); } // Determine whether memory block is a .mid file static boolean IsMid(byte *mem, int len) { return len > 4 && !memcmp(mem, "MThd", 4); } static boolean ConvertMus(byte *musdata, int len, char *filename) { MEMFILE *instream; MEMFILE *outstream; void *outbuf; size_t outbuf_len; int result; instream = mem_fopen_read(musdata, len); outstream = mem_fopen_write(); result = mus2mid(instream, outstream); if (result == 0) { mem_get_buf(outstream, &outbuf, &outbuf_len); M_WriteFile(filename, outbuf, outbuf_len); } mem_fclose(instream); mem_fclose(outstream); return result; } static void *I_SDL_RegisterSong(void *data, int len) { char *filename; Mix_Music *music; if (!music_initialized) { return NULL; } playing_substitute = false; // See if we're substituting this MUS for a high-quality replacement. filename = GetSubstituteMusicFile(data, len); if (filename != NULL) { music = Mix_LoadMUS(filename); if (music == NULL) { // Fall through and play MIDI normally, but print an error // message. fprintf(stderr, "Failed to load substitute music file: %s: %s\n", filename, Mix_GetError()); } else { // Read loop point metadata from the file so that we know where // to loop the music. playing_substitute = true; ReadLoopPoints(filename, &file_metadata); return music; } } // MUS files begin with "MUS" // Reject anything which doesnt have this signature filename = M_TempFile("doom.mid"); if (IsMid(data, len) && len < MAXMIDLENGTH) { M_WriteFile(filename, data, len); } else { // Assume a MUS file and try to convert ConvertMus(data, len, filename); } // Load the MIDI. In an ideal world we'd be using Mix_LoadMUS_RW() // by now, but Mix_SetMusicCMD() only works with Mix_LoadMUS(), so // we have to generate a temporary file. music = Mix_LoadMUS(filename); if (music == NULL) { // Failed to load fprintf(stderr, "Error loading midi: %s\n", Mix_GetError()); } // Remove the temporary MIDI file; however, when using an external // MIDI program we can't delete the file. Otherwise, the program // won't find the file to play. This means we leave a mess on // disk :( if (strlen(snd_musiccmd) == 0) { remove(filename); } free(filename); return music; } // Is the song playing? static boolean I_SDL_MusicIsPlaying(void) { if (!music_initialized) { return false; } return Mix_PlayingMusic(); } // Get position in substitute music track, in seconds since start of track. static double GetMusicPosition(void) { unsigned int music_pos; int freq; Mix_QuerySpec(&freq, NULL, NULL); SDL_LockAudio(); music_pos = current_track_pos; SDL_UnlockAudio(); return (double) music_pos / freq; } static void RestartCurrentTrack(void) { double start = (double) file_metadata.start_time / file_metadata.samplerate_hz; // If the track finished we need to restart it. if (current_track_music != NULL) { Mix_PlayMusic(current_track_music, 1); } Mix_SetMusicPosition(start); SDL_LockAudio(); current_track_pos = file_metadata.start_time; SDL_UnlockAudio(); } // Poll music position; if we have passed the loop point end position // then we need to go back. static void I_SDL_PollMusic(void) { // When playing substitute tracks, loop tags only apply if we're playing // a looping track. Tracks like the title screen music have the loop // tags ignored. if (current_track_loop && playing_substitute && file_metadata.valid) { double end = (double) file_metadata.end_time / file_metadata.samplerate_hz; // If we have reached the loop end point then we have to take action. if (file_metadata.end_time >= 0 && GetMusicPosition() >= end) { RestartCurrentTrack(); } // Have we reached the actual end of track (not loop end)? if (!Mix_PlayingMusic()) { RestartCurrentTrack(); } } } static snddevice_t music_sdl_devices[] = { SNDDEVICE_PAS, SNDDEVICE_GUS, SNDDEVICE_WAVEBLASTER, SNDDEVICE_SOUNDCANVAS, SNDDEVICE_GENMIDI, SNDDEVICE_AWE32, }; music_module_t music_sdl_module = { music_sdl_devices, arrlen(music_sdl_devices), I_SDL_InitMusic, I_SDL_ShutdownMusic, I_SDL_SetMusicVolume, I_SDL_PauseSong, I_SDL_ResumeSong, I_SDL_RegisterSong, I_SDL_UnRegisterSong, I_SDL_PlaySong, I_SDL_StopSong, I_SDL_MusicIsPlaying, I_SDL_PollMusic, }; chocolate-doom-chocolate-doom-2.2.1/src/i_sdlsound.c000066400000000000000000000636341257432200600224170ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // Copyright(C) 2008 David Flater // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System interface for sound. // #include "config.h" #include #include #include #include #include "SDL.h" #include "SDL_mixer.h" #ifdef HAVE_LIBSAMPLERATE #include #endif #include "deh_str.h" #include "i_sound.h" #include "i_system.h" #include "i_swap.h" #include "m_argv.h" #include "m_misc.h" #include "w_wad.h" #include "z_zone.h" #include "doomtype.h" #define LOW_PASS_FILTER //#define DEBUG_DUMP_WAVS #define NUM_CHANNELS 16 typedef struct allocated_sound_s allocated_sound_t; struct allocated_sound_s { sfxinfo_t *sfxinfo; Mix_Chunk chunk; int use_count; allocated_sound_t *prev, *next; }; static boolean setpanning_workaround = false; static boolean sound_initialized = false; static sfxinfo_t *channels_playing[NUM_CHANNELS]; static int mixer_freq; static Uint16 mixer_format; static int mixer_channels; static boolean use_sfx_prefix; static boolean (*ExpandSoundData)(sfxinfo_t *sfxinfo, byte *data, int samplerate, int length) = NULL; // Doubly-linked list of allocated sounds. // When a sound is played, it is moved to the head, so that the oldest // sounds not used recently are at the tail. static allocated_sound_t *allocated_sounds_head = NULL; static allocated_sound_t *allocated_sounds_tail = NULL; static int allocated_sounds_size = 0; int use_libsamplerate = 0; // Scale factor used when converting libsamplerate floating point numbers // to integers. Too high means the sounds can clip; too low means they // will be too quiet. This is an amount that should avoid clipping most // of the time: with all the Doom IWAD sound effects, at least. If a PWAD // is used, clipping might occur. float libsamplerate_scale = 0.65f; // Hook a sound into the linked list at the head. static void AllocatedSoundLink(allocated_sound_t *snd) { snd->prev = NULL; snd->next = allocated_sounds_head; allocated_sounds_head = snd; if (allocated_sounds_tail == NULL) { allocated_sounds_tail = snd; } else { snd->next->prev = snd; } } // Unlink a sound from the linked list. static void AllocatedSoundUnlink(allocated_sound_t *snd) { if (snd->prev == NULL) { allocated_sounds_head = snd->next; } else { snd->prev->next = snd->next; } if (snd->next == NULL) { allocated_sounds_tail = snd->prev; } else { snd->next->prev = snd->prev; } } static void FreeAllocatedSound(allocated_sound_t *snd) { // Unlink from linked list. AllocatedSoundUnlink(snd); // Unlink from higher-level code. snd->sfxinfo->driver_data = NULL; // Keep track of the amount of allocated sound data: allocated_sounds_size -= snd->chunk.alen; free(snd); } // Search from the tail backwards along the allocated sounds list, find // and free a sound that is not in use, to free up memory. Return true // for success. static boolean FindAndFreeSound(void) { allocated_sound_t *snd; snd = allocated_sounds_tail; while (snd != NULL) { if (snd->use_count == 0) { FreeAllocatedSound(snd); return true; } snd = snd->prev; } // No available sounds to free... return false; } // Enforce SFX cache size limit. We are just about to allocate "len" // bytes on the heap for a new sound effect, so free up some space // so that we keep allocated_sounds_size < snd_cachesize static void ReserveCacheSpace(size_t len) { if (snd_cachesize <= 0) { return; } // Keep freeing sound effects that aren't currently being played, // until there is enough space for the new sound. while (allocated_sounds_size + len > snd_cachesize) { // Free a sound. If there is nothing more to free, stop. if (!FindAndFreeSound()) { break; } } } // Allocate a block for a new sound effect. static Mix_Chunk *AllocateSound(sfxinfo_t *sfxinfo, size_t len) { allocated_sound_t *snd; // Keep allocated sounds within the cache size. ReserveCacheSpace(len); // Allocate the sound structure and data. The data will immediately // follow the structure, which acts as a header. do { snd = malloc(sizeof(allocated_sound_t) + len); // Out of memory? Try to free an old sound, then loop round // and try again. if (snd == NULL && !FindAndFreeSound()) { return NULL; } } while (snd == NULL); // Skip past the chunk structure for the audio buffer snd->chunk.abuf = (byte *) (snd + 1); snd->chunk.alen = len; snd->chunk.allocated = 1; snd->chunk.volume = MIX_MAX_VOLUME; snd->sfxinfo = sfxinfo; snd->use_count = 0; // driver_data pointer points to the allocated_sound structure. sfxinfo->driver_data = snd; // Keep track of how much memory all these cached sounds are using... allocated_sounds_size += len; AllocatedSoundLink(snd); return &snd->chunk; } // Lock a sound, to indicate that it may not be freed. static void LockAllocatedSound(allocated_sound_t *snd) { // Increase use count, to stop the sound being freed. ++snd->use_count; //printf("++ %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count); // When we use a sound, re-link it into the list at the head, so // that the oldest sounds fall to the end of the list for freeing. AllocatedSoundUnlink(snd); AllocatedSoundLink(snd); } // Unlock a sound to indicate that it may now be freed. static void UnlockAllocatedSound(allocated_sound_t *snd) { if (snd->use_count <= 0) { I_Error("Sound effect released more times than it was locked..."); } --snd->use_count; //printf("-- %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count); } // When a sound stops, check if it is still playing. If it is not, // we can mark the sound data as CACHE to be freed back for other // means. static void ReleaseSoundOnChannel(int channel) { sfxinfo_t *sfxinfo = channels_playing[channel]; if (sfxinfo == NULL) { return; } channels_playing[channel] = NULL; UnlockAllocatedSound(sfxinfo->driver_data); } #ifdef HAVE_LIBSAMPLERATE // Returns the conversion mode for libsamplerate to use. static int SRC_ConversionMode(void) { switch (use_libsamplerate) { // 0 = disabled default: case 0: return -1; // Ascending numbers give higher quality case 1: return SRC_LINEAR; case 2: return SRC_ZERO_ORDER_HOLD; case 3: return SRC_SINC_FASTEST; case 4: return SRC_SINC_MEDIUM_QUALITY; case 5: return SRC_SINC_BEST_QUALITY; } } // libsamplerate-based generic sound expansion function for any sample rate // unsigned 8 bits --> signed 16 bits // mono --> stereo // samplerate --> mixer_freq // Returns number of clipped samples. // DWF 2008-02-10 with cleanups by Simon Howard. static boolean ExpandSoundData_SRC(sfxinfo_t *sfxinfo, byte *data, int samplerate, int length) { SRC_DATA src_data; uint32_t i, abuf_index=0, clipped=0; // uint32_t alen; int retn; int16_t *expanded; Mix_Chunk *chunk; src_data.input_frames = length; src_data.data_in = malloc(length * sizeof(float)); src_data.src_ratio = (double)mixer_freq / samplerate; // We include some extra space here in case of rounding-up. src_data.output_frames = src_data.src_ratio * length + (mixer_freq / 4); src_data.data_out = malloc(src_data.output_frames * sizeof(float)); assert(src_data.data_in != NULL && src_data.data_out != NULL); // Convert input data to floats for (i=0; iabuf; // Convert the result back into 16-bit integers. for (i=0; i INT16_MAX) { cvtval_i = INT16_MAX; ++clipped; } // Left and right channels expanded[abuf_index++] = cvtval_i; expanded[abuf_index++] = cvtval_i; } free(src_data.data_in); free(src_data.data_out); if (clipped > 0) { fprintf(stderr, "Sound '%s': clipped %u samples (%0.2f %%)\n", sfxinfo->name, clipped, 400.0 * clipped / chunk->alen); } return true; } #endif static boolean ConvertibleRatio(int freq1, int freq2) { int ratio; if (freq1 > freq2) { return ConvertibleRatio(freq2, freq1); } else if ((freq2 % freq1) != 0) { // Not in a direct ratio return false; } else { // Check the ratio is a power of 2 ratio = freq2 / freq1; while ((ratio & 1) == 0) { ratio = ratio >> 1; } return ratio == 1; } } #ifdef DEBUG_DUMP_WAVS // Debug code to dump resampled sound effects to WAV files for analysis. static void WriteWAV(char *filename, byte *data, uint32_t length, int samplerate) { FILE *wav; unsigned int i; unsigned short s; wav = fopen(filename, "wb"); // Header fwrite("RIFF", 1, 4, wav); i = LONG(36 + samplerate); fwrite(&i, 4, 1, wav); fwrite("WAVE", 1, 4, wav); // Subchunk 1 fwrite("fmt ", 1, 4, wav); i = LONG(16); fwrite(&i, 4, 1, wav); // Length s = SHORT(1); fwrite(&s, 2, 1, wav); // Format (PCM) s = SHORT(2); fwrite(&s, 2, 1, wav); // Channels (2=stereo) i = LONG(samplerate); fwrite(&i, 4, 1, wav); // Sample rate i = LONG(samplerate * 2 * 2); fwrite(&i, 4, 1, wav); // Byte rate (samplerate * stereo * 16 bit) s = SHORT(2 * 2); fwrite(&s, 2, 1, wav); // Block align (stereo * 16 bit) s = SHORT(16); fwrite(&s, 2, 1, wav); // Bits per sample (16 bit) // Data subchunk fwrite("data", 1, 4, wav); i = LONG(length); fwrite(&i, 4, 1, wav); // Data length fwrite(data, 1, length, wav); // Data fclose(wav); } #endif // Generic sound expansion function for any sample rate. // Returns number of clipped samples (always 0). static boolean ExpandSoundData_SDL(sfxinfo_t *sfxinfo, byte *data, int samplerate, int length) { SDL_AudioCVT convertor; Mix_Chunk *chunk; uint32_t expanded_length; // Calculate the length of the expanded version of the sample. expanded_length = (uint32_t) ((((uint64_t) length) * mixer_freq) / samplerate); // Double up twice: 8 -> 16 bit and mono -> stereo expanded_length *= 4; // Allocate a chunk in which to expand the sound chunk = AllocateSound(sfxinfo, expanded_length); if (chunk == NULL) { return false; } // If we can, use the standard / optimized SDL conversion routines. if (samplerate <= mixer_freq && ConvertibleRatio(samplerate, mixer_freq) && SDL_BuildAudioCVT(&convertor, AUDIO_U8, 1, samplerate, mixer_format, mixer_channels, mixer_freq)) { convertor.buf = chunk->abuf; convertor.len = length; memcpy(convertor.buf, data, length); SDL_ConvertAudio(&convertor); } else { Sint16 *expanded = (Sint16 *) chunk->abuf; int expanded_length; int expand_ratio; int i; // Generic expansion if conversion does not work: // // SDL's audio conversion only works for rate conversions that are // powers of 2; if the two formats are not in a direct power of 2 // ratio, do this naive conversion instead. // number of samples in the converted sound expanded_length = ((uint64_t) length * mixer_freq) / samplerate; expand_ratio = (length << 8) / expanded_length; for (i=0; i> 8; sample = data[src] | (data[src] << 8); sample -= 32768; // expand 8->16 bits, mono->stereo expanded[i * 2] = expanded[i * 2 + 1] = sample; } #ifdef LOW_PASS_FILTER // Perform a low-pass filter on the upscaled sound to filter // out high-frequency noise from the conversion process. { float rc, dt, alpha; // Low-pass filter for cutoff frequency f: // // For sampling rate r, dt = 1 / r // rc = 1 / 2*pi*f // alpha = dt / (rc + dt) // Filter to the half sample rate of the original sound effect // (maximum frequency, by nyquist) dt = 1.0f / mixer_freq; rc = 1.0f / (3.14f * samplerate); alpha = dt / (rc + dt); // Both channels are processed in parallel, hence [i-2]: for (i=2; ilumpnum; data = W_CacheLumpNum(lumpnum, PU_STATIC); lumplen = W_LumpLength(lumpnum); // Check the header, and ensure this is a valid sound if (lumplen < 8 || data[0] != 0x03 || data[1] != 0x00) { // Invalid sound return false; } // 16 bit sample rate field, 32 bit length field samplerate = (data[3] << 8) | data[2]; length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4]; // If the header specifies that the length of the sound is greater than // the length of the lump itself, this is an invalid sound lump // We also discard sound lumps that are less than 49 samples long, // as this is how DMX behaves - although the actual cut-off length // seems to vary slightly depending on the sample rate. This needs // further investigation to better understand the correct // behavior. if (length > lumplen - 8 || length <= 48) { return false; } // The DMX sound library seems to skip the first 16 and last 16 // bytes of the lump - reason unknown. data += 16; length -= 32; // Sample rate conversion if (!ExpandSoundData(sfxinfo, data + 8, samplerate, length)) { return false; } #ifdef DEBUG_DUMP_WAVS { char filename[16]; M_snprintf(filename, sizeof(filename), "%s.wav", DEH_String(S_sfx[sound].name)); WriteWAV(filename, sound_chunks[sound].abuf, sound_chunks[sound].alen, mixer_freq); } #endif // don't need the original lump any more W_ReleaseLumpNum(lumpnum); return true; } static void GetSfxLumpName(sfxinfo_t *sfx, char *buf, size_t buf_len) { // Linked sfx lumps? Get the lump number for the sound linked to. if (sfx->link != NULL) { sfx = sfx->link; } // Doom adds a DS* prefix to sound lumps; Heretic and Hexen don't // do this. if (use_sfx_prefix) { M_snprintf(buf, buf_len, "ds%s", DEH_String(sfx->name)); } else { M_StringCopy(buf, DEH_String(sfx->name), buf_len); } } #ifdef HAVE_LIBSAMPLERATE // Preload all the sound effects - stops nasty ingame freezes static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) { char namebuf[9]; int i; // Don't need to precache the sounds unless we are using libsamplerate. if (use_libsamplerate == 0) { return; } printf("I_SDL_PrecacheSounds: Precaching all sound effects.."); for (i=0; idriver_data == NULL) { if (!CacheSFX(sfxinfo)) { return false; } } LockAllocatedSound(sfxinfo->driver_data); return true; } // // Retrieve the raw data lump index // for a given SFX name. // static int I_SDL_GetSfxLumpNum(sfxinfo_t *sfx) { char namebuf[9]; GetSfxLumpName(sfx, namebuf, sizeof(namebuf)); return W_GetNumForName(namebuf); } static void I_SDL_UpdateSoundParams(int handle, int vol, int sep) { int left, right; if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) { return; } left = ((254 - sep) * vol) / 127; right = ((sep) * vol) / 127; if (left < 0) left = 0; else if ( left > 255) left = 255; if (right < 0) right = 0; else if (right > 255) right = 255; // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning // function. A workaround is to call Mix_UnregisterAllEffects for // the channel before calling it. This is undesirable as it may lead // to the channel volumes resetting briefly. if (setpanning_workaround) { Mix_UnregisterAllEffects(handle); } Mix_SetPanning(handle, left, right); } // // Starting a sound means adding it // to the current list of active sounds // in the internal channels. // As the SFX info struct contains // e.g. a pointer to the raw data, // it is ignored. // As our sound handling does not handle // priority, it is ignored. // Pitching (that is, increased speed of playback) // is set, but currently not used by mixing. // static int I_SDL_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) { allocated_sound_t *snd; if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS) { return -1; } // Release a sound effect if there is already one playing // on this channel ReleaseSoundOnChannel(channel); // Get the sound data if (!LockSound(sfxinfo)) { return -1; } snd = sfxinfo->driver_data; // play sound Mix_PlayChannelTimed(channel, &snd->chunk, 0, -1); channels_playing[channel] = sfxinfo; // set separation, etc. I_SDL_UpdateSoundParams(channel, vol, sep); return channel; } static void I_SDL_StopSound(int handle) { if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) { return; } Mix_HaltChannel(handle); // Sound data is no longer needed; release the // sound data being used for this channel ReleaseSoundOnChannel(handle); } static boolean I_SDL_SoundIsPlaying(int handle) { if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) { return false; } return Mix_Playing(handle); } // // Periodically called to update the sound system // static void I_SDL_UpdateSound(void) { int i; // Check all channels to see if a sound has finished for (i=0; i limit) { return (1 << n); } } // Should never happen? return 1024; } static boolean I_SDL_InitSound(boolean _use_sfx_prefix) { int i; use_sfx_prefix = _use_sfx_prefix; // No sounds yet for (i=0; imajor, mixer_version->minor, mixer_version->patch); if (v <= SDL_VERSIONNUM(1, 2, 8)) { setpanning_workaround = true; fprintf(stderr, "\n" "ATTENTION: You are using an old version of SDL_mixer!\n" " This version has a bug that may cause " "your sound to stutter.\n" " Please upgrade to a newer version!\n" "\n"); } } Mix_AllocateChannels(NUM_CHANNELS); SDL_PauseAudio(0); sound_initialized = true; return true; } static snddevice_t sound_sdl_devices[] = { SNDDEVICE_SB, SNDDEVICE_PAS, SNDDEVICE_GUS, SNDDEVICE_WAVEBLASTER, SNDDEVICE_SOUNDCANVAS, SNDDEVICE_AWE32, }; sound_module_t sound_sdl_module = { sound_sdl_devices, arrlen(sound_sdl_devices), I_SDL_InitSound, I_SDL_ShutdownSound, I_SDL_GetSfxLumpNum, I_SDL_UpdateSound, I_SDL_UpdateSoundParams, I_SDL_StartSound, I_SDL_StopSound, I_SDL_SoundIsPlaying, I_SDL_PrecacheSounds, }; chocolate-doom-chocolate-doom-2.2.1/src/i_sound.c000066400000000000000000000233011257432200600216770ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // #include #include #include "SDL_mixer.h" #include "config.h" #include "doomfeatures.h" #include "doomtype.h" #include "gusconf.h" #include "i_sound.h" #include "i_video.h" #include "m_argv.h" #include "m_config.h" // Sound sample rate to use for digital output (Hz) int snd_samplerate = 44100; // Maximum number of bytes to dedicate to allocated sound effects. // (Default: 64MB) int snd_cachesize = 64 * 1024 * 1024; // Config variable that controls the sound buffer size. // We default to 28ms (1000 / 35fps = 1 buffer per tic). int snd_maxslicetime_ms = 28; // External command to invoke to play back music. char *snd_musiccmd = ""; // Low-level sound and music modules we are using static sound_module_t *sound_module; static music_module_t *music_module; int snd_musicdevice = SNDDEVICE_SB; int snd_sfxdevice = SNDDEVICE_SB; // Sound modules extern void I_InitTimidityConfig(void); extern sound_module_t sound_sdl_module; extern sound_module_t sound_pcsound_module; extern music_module_t music_sdl_module; extern music_module_t music_opl_module; // For OPL module: extern opl_driver_ver_t opl_drv_ver; extern int opl_io_port; // For native music module: extern char *timidity_cfg_path; // DOS-specific options: These are unused but should be maintained // so that the config file can be shared between chocolate // doom and doom.exe static int snd_sbport = 0; static int snd_sbirq = 0; static int snd_sbdma = 0; static int snd_mport = 0; // Compiled-in sound modules: static sound_module_t *sound_modules[] = { #ifdef FEATURE_SOUND &sound_sdl_module, &sound_pcsound_module, #endif NULL, }; // Compiled-in music modules: static music_module_t *music_modules[] = { #ifdef FEATURE_SOUND &music_sdl_module, &music_opl_module, #endif NULL, }; // Check if a sound device is in the given list of devices static boolean SndDeviceInList(snddevice_t device, snddevice_t *list, int len) { int i; for (i=0; isound_devices, sound_modules[i]->num_sound_devices)) { // Initialize the module if (sound_modules[i]->Init(use_sfx_prefix)) { sound_module = sound_modules[i]; return; } } } } // Initialize music according to snd_musicdevice. static void InitMusicModule(void) { int i; music_module = NULL; for (i=0; music_modules[i] != NULL; ++i) { // Is the music device in the list of devices supported // by this module? if (SndDeviceInList(snd_musicdevice, music_modules[i]->sound_devices, music_modules[i]->num_sound_devices)) { // Initialize the module if (music_modules[i]->Init()) { music_module = music_modules[i]; return; } } } } // // Initializes sound stuff, including volume // Sets channels, SFX and music volume, // allocates channel buffer, sets S_sfx lookup. // void I_InitSound(boolean use_sfx_prefix) { boolean nosound, nosfx, nomusic; //! // @vanilla // // Disable all sound output. // nosound = M_CheckParm("-nosound") > 0; //! // @vanilla // // Disable sound effects. // nosfx = M_CheckParm("-nosfx") > 0; //! // @vanilla // // Disable music. // nomusic = M_CheckParm("-nomusic") > 0; // Initialize the sound and music subsystems. if (!nosound && !screensaver_mode) { // This is kind of a hack. If native MIDI is enabled, set up // the TIMIDITY_CFG environment variable here before SDL_mixer // is opened. if (!nomusic && (snd_musicdevice == SNDDEVICE_GENMIDI || snd_musicdevice == SNDDEVICE_GUS)) { I_InitTimidityConfig(); } if (!nosfx) { InitSfxModule(use_sfx_prefix); } if (!nomusic) { InitMusicModule(); } } } void I_ShutdownSound(void) { if (sound_module != NULL) { sound_module->Shutdown(); } if (music_module != NULL) { music_module->Shutdown(); } } int I_GetSfxLumpNum(sfxinfo_t *sfxinfo) { if (sound_module != NULL) { return sound_module->GetSfxLumpNum(sfxinfo); } else { return 0; } } void I_UpdateSound(void) { if (sound_module != NULL) { sound_module->Update(); } if (music_module != NULL && music_module->Poll != NULL) { music_module->Poll(); } } static void CheckVolumeSeparation(int *vol, int *sep) { if (*sep < 0) { *sep = 0; } else if (*sep > 254) { *sep = 254; } if (*vol < 0) { *vol = 0; } else if (*vol > 127) { *vol = 127; } } void I_UpdateSoundParams(int channel, int vol, int sep) { if (sound_module != NULL) { CheckVolumeSeparation(&vol, &sep); sound_module->UpdateSoundParams(channel, vol, sep); } } int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) { if (sound_module != NULL) { CheckVolumeSeparation(&vol, &sep); return sound_module->StartSound(sfxinfo, channel, vol, sep); } else { return 0; } } void I_StopSound(int channel) { if (sound_module != NULL) { sound_module->StopSound(channel); } } boolean I_SoundIsPlaying(int channel) { if (sound_module != NULL) { return sound_module->SoundIsPlaying(channel); } else { return false; } } void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) { if (sound_module != NULL && sound_module->CacheSounds != NULL) { sound_module->CacheSounds(sounds, num_sounds); } } void I_InitMusic(void) { } void I_ShutdownMusic(void) { } void I_SetMusicVolume(int volume) { if (music_module != NULL) { music_module->SetMusicVolume(volume); } } void I_PauseSong(void) { if (music_module != NULL) { music_module->PauseMusic(); } } void I_ResumeSong(void) { if (music_module != NULL) { music_module->ResumeMusic(); } } void *I_RegisterSong(void *data, int len) { if (music_module != NULL) { return music_module->RegisterSong(data, len); } else { return NULL; } } void I_UnRegisterSong(void *handle) { if (music_module != NULL) { music_module->UnRegisterSong(handle); } } void I_PlaySong(void *handle, boolean looping) { if (music_module != NULL) { music_module->PlaySong(handle, looping); } } void I_StopSong(void) { if (music_module != NULL) { music_module->StopSong(); } } boolean I_MusicIsPlaying(void) { if (music_module != NULL) { return music_module->MusicIsPlaying(); } else { return false; } } void I_BindSoundVariables(void) { extern char *snd_dmxoption; extern int use_libsamplerate; extern float libsamplerate_scale; M_BindIntVariable("snd_musicdevice", &snd_musicdevice); M_BindIntVariable("snd_sfxdevice", &snd_sfxdevice); M_BindIntVariable("snd_sbport", &snd_sbport); M_BindIntVariable("snd_sbirq", &snd_sbirq); M_BindIntVariable("snd_sbdma", &snd_sbdma); M_BindIntVariable("snd_mport", &snd_mport); M_BindIntVariable("snd_maxslicetime_ms", &snd_maxslicetime_ms); M_BindStringVariable("snd_musiccmd", &snd_musiccmd); M_BindStringVariable("snd_dmxoption", &snd_dmxoption); M_BindIntVariable("snd_samplerate", &snd_samplerate); M_BindIntVariable("snd_cachesize", &snd_cachesize); M_BindIntVariable("opl_io_port", &opl_io_port); M_BindStringVariable("timidity_cfg_path", &timidity_cfg_path); M_BindStringVariable("gus_patch_path", &gus_patch_path); M_BindIntVariable("gus_ram_kb", &gus_ram_kb); #ifdef FEATURE_SOUND M_BindIntVariable("use_libsamplerate", &use_libsamplerate); M_BindFloatVariable("libsamplerate_scale", &libsamplerate_scale); #endif // Before SDL_mixer version 1.2.11, MIDI music caused the game // to crash when it looped. If this is an old SDL_mixer version, // disable MIDI. #ifdef __MACOSX__ { const SDL_version *v = Mix_Linked_Version(); if (SDL_VERSIONNUM(v->major, v->minor, v->patch) < SDL_VERSIONNUM(1, 2, 11)) { snd_musicdevice = SNDDEVICE_NONE; } } #endif } chocolate-doom-chocolate-doom-2.2.1/src/i_sound.h000066400000000000000000000125251257432200600217120ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The not so system specific sound interface. // #ifndef __I_SOUND__ #define __I_SOUND__ #include "doomtype.h" // // SoundFX struct. // typedef struct sfxinfo_struct sfxinfo_t; struct sfxinfo_struct { // tag name, used for hexen. char *tagname; // lump name. If we are running with use_sfx_prefix=true, a // 'DS' (or 'DP' for PC speaker sounds) is prepended to this. char name[9]; // Sfx priority int priority; // referenced sound if a link sfxinfo_t *link; // pitch if a link int pitch; // volume if a link int volume; // this is checked every second to see if sound // can be thrown out (if 0, then decrement, if -1, // then throw out, if > 0, then it is in use) int usefulness; // lump number of sfx int lumpnum; // Maximum number of channels that the sound can be played on // (Heretic) int numchannels; // data used by the low level code void *driver_data; }; // // MusicInfo struct. // typedef struct { // up to 6-character name char *name; // lump number of music int lumpnum; // music data void *data; // music handle once registered void *handle; } musicinfo_t; typedef enum { SNDDEVICE_NONE = 0, SNDDEVICE_PCSPEAKER = 1, SNDDEVICE_ADLIB = 2, SNDDEVICE_SB = 3, SNDDEVICE_PAS = 4, SNDDEVICE_GUS = 5, SNDDEVICE_WAVEBLASTER = 6, SNDDEVICE_SOUNDCANVAS = 7, SNDDEVICE_GENMIDI = 8, SNDDEVICE_AWE32 = 9, SNDDEVICE_CD = 10, } snddevice_t; // Interface for sound modules typedef struct { // List of sound devices that this sound module is used for. snddevice_t *sound_devices; int num_sound_devices; // Initialise sound module // Returns true if successfully initialised boolean (*Init)(boolean use_sfx_prefix); // Shutdown sound module void (*Shutdown)(void); // Returns the lump index of the given sound. int (*GetSfxLumpNum)(sfxinfo_t *sfxinfo); // Called periodically to update the subsystem. void (*Update)(void); // Update the sound settings on the given channel. void (*UpdateSoundParams)(int channel, int vol, int sep); // Start a sound on a given channel. Returns the channel id // or -1 on failure. int (*StartSound)(sfxinfo_t *sfxinfo, int channel, int vol, int sep); // Stop the sound playing on the given channel. void (*StopSound)(int channel); // Query if a sound is playing on the given channel boolean (*SoundIsPlaying)(int channel); // Called on startup to precache sound effects (if necessary) void (*CacheSounds)(sfxinfo_t *sounds, int num_sounds); } sound_module_t; void I_InitSound(boolean use_sfx_prefix); void I_ShutdownSound(void); int I_GetSfxLumpNum(sfxinfo_t *sfxinfo); void I_UpdateSound(void); void I_UpdateSoundParams(int channel, int vol, int sep); int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep); void I_StopSound(int channel); boolean I_SoundIsPlaying(int channel); void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds); // Interface for music modules typedef struct { // List of sound devices that this music module is used for. snddevice_t *sound_devices; int num_sound_devices; // Initialise the music subsystem boolean (*Init)(void); // Shutdown the music subsystem void (*Shutdown)(void); // Set music volume - range 0-127 void (*SetMusicVolume)(int volume); // Pause music void (*PauseMusic)(void); // Un-pause music void (*ResumeMusic)(void); // Register a song handle from data // Returns a handle that can be used to play the song void *(*RegisterSong)(void *data, int len); // Un-register (free) song data void (*UnRegisterSong)(void *handle); // Play the song void (*PlaySong)(void *handle, boolean looping); // Stop playing the current song. void (*StopSong)(void); // Query if music is playing. boolean (*MusicIsPlaying)(void); // Invoked periodically to poll. void (*Poll)(void); } music_module_t; void I_InitMusic(void); void I_ShutdownMusic(void); void I_SetMusicVolume(int volume); void I_PauseSong(void); void I_ResumeSong(void); void *I_RegisterSong(void *data, int len); void I_UnRegisterSong(void *handle); void I_PlaySong(void *handle, boolean looping); void I_StopSong(void); boolean I_MusicIsPlaying(void); extern int snd_sfxdevice; extern int snd_musicdevice; extern int snd_samplerate; extern int snd_cachesize; extern int snd_maxslicetime_ms; extern char *snd_musiccmd; void I_BindSoundVariables(void); // DMX version to emulate for OPL emulation: typedef enum { opl_v_old, // Hexen, Heretic opl_v_new // Doom, Strife } opl_driver_ver_t; void I_SetOPLDriverVer(opl_driver_ver_t ver); #endif chocolate-doom-chocolate-doom-2.2.1/src/i_swap.h000066400000000000000000000023731257432200600215340ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Endianess handling, swapping 16bit and 32bit. // #ifndef __I_SWAP__ #define __I_SWAP__ #include "SDL_endian.h" // Endianess handling. // WAD files are stored little endian. // Just use SDL's endianness swapping functions. // These are deliberately cast to signed values; this is the behaviour // of the macros in the original source and some code relies on it. #define SHORT(x) ((signed short) SDL_SwapLE16(x)) #define LONG(x) ((signed int) SDL_SwapLE32(x)) // Defines for checking the endianness of the system. #if SDL_BYTEORDER == SYS_LIL_ENDIAN #define SYS_LITTLE_ENDIAN #elif SDL_BYTEORDER == SYS_BIG_ENDIAN #define SYS_BIG_ENDIAN #endif #endif chocolate-doom-chocolate-doom-2.2.1/src/i_system.c000066400000000000000000000301501257432200600220730ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // #include #include #include #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #else #include #endif #include "SDL.h" #include "config.h" #include "deh_str.h" #include "doomtype.h" #include "m_argv.h" #include "m_config.h" #include "m_misc.h" #include "i_joystick.h" #include "i_sound.h" #include "i_timer.h" #include "i_video.h" #include "i_system.h" #include "w_wad.h" #include "z_zone.h" #ifdef __MACOSX__ #include #endif #define DEFAULT_RAM 16 /* MiB */ #define MIN_RAM 4 /* MiB */ typedef struct atexit_listentry_s atexit_listentry_t; struct atexit_listentry_s { atexit_func_t func; boolean run_on_error; atexit_listentry_t *next; }; static atexit_listentry_t *exit_funcs = NULL; void I_AtExit(atexit_func_t func, boolean run_on_error) { atexit_listentry_t *entry; entry = malloc(sizeof(*entry)); entry->func = func; entry->run_on_error = run_on_error; entry->next = exit_funcs; exit_funcs = entry; } // Tactile feedback function, probably used for the Logitech Cyberman void I_Tactile(int on, int off, int total) { } // Zone memory auto-allocation function that allocates the zone size // by trying progressively smaller zone sizes until one is found that // works. static byte *AutoAllocMemory(int *size, int default_ram, int min_ram) { byte *zonemem; // Allocate the zone memory. This loop tries progressively smaller // zone sizes until a size is found that can be allocated. // If we used the -mb command line parameter, only the parameter // provided is accepted. zonemem = NULL; while (zonemem == NULL) { // We need a reasonable minimum amount of RAM to start. if (default_ram < min_ram) { I_Error("Unable to allocate %i MiB of RAM for zone", default_ram); } // Try to allocate the zone memory. *size = default_ram * 1024 * 1024; zonemem = malloc(*size); // Failed to allocate? Reduce zone size until we reach a size // that is acceptable. if (zonemem == NULL) { default_ram -= 1; } } return zonemem; } byte *I_ZoneBase (int *size) { byte *zonemem; int min_ram, default_ram; int p; //! // @arg // // Specify the heap size, in MiB (default 16). // p = M_CheckParmWithArgs("-mb", 1); if (p > 0) { default_ram = atoi(myargv[p+1]); min_ram = default_ram; } else { default_ram = DEFAULT_RAM; min_ram = MIN_RAM; } zonemem = AutoAllocMemory(size, default_ram, min_ram); printf("zone memory: %p, %x allocated for zone\n", zonemem, *size); return zonemem; } void I_PrintBanner(char *msg) { int i; int spaces = 35 - (strlen(msg) / 2); for (i=0; ifunc(); entry = entry->next; } SDL_Quit(); exit(0); } #if !defined(_WIN32) && !defined(__MACOSX__) #define ZENITY_BINARY "/usr/bin/zenity" // returns non-zero if zenity is available static int ZenityAvailable(void) { return system(ZENITY_BINARY " --help >/dev/null 2>&1") == 0; } // Escape special characters in the given string so that they can be // safely enclosed in shell quotes. static char *EscapeShellString(char *string) { char *result; char *r, *s; // In the worst case, every character might be escaped. result = malloc(strlen(string) * 2 + 3); r = result; // Enclosing quotes. *r = '"'; ++r; for (s = string; *s != '\0'; ++s) { // From the bash manual: // // "Enclosing characters in double quotes preserves the literal // value of all characters within the quotes, with the exception // of $, `, \, and, when history expansion is enabled, !." // // Therefore, escape these characters by prefixing with a backslash. if (strchr("$`\\!", *s) != NULL) { *r = '\\'; ++r; } *r = *s; ++r; } // Enclosing quotes. *r = '"'; ++r; *r = '\0'; return result; } // Open a native error box with a message using zenity static int ZenityErrorBox(char *message) { int result; char *escaped_message; char *errorboxpath; static size_t errorboxpath_size; if (!ZenityAvailable()) { return 0; } escaped_message = EscapeShellString(message); errorboxpath_size = strlen(ZENITY_BINARY) + strlen(escaped_message) + 19; errorboxpath = malloc(errorboxpath_size); M_snprintf(errorboxpath, errorboxpath_size, "%s --error --text=%s", ZENITY_BINARY, escaped_message); result = system(errorboxpath); free(errorboxpath); free(escaped_message); return result; } #endif /* !defined(_WIN32) && !defined(__MACOSX__) */ // // I_Error // static boolean already_quitting = false; void I_Error (char *error, ...) { char msgbuf[512]; va_list argptr; atexit_listentry_t *entry; boolean exit_gui_popup; if (already_quitting) { fprintf(stderr, "Warning: recursive call to I_Error detected.\n"); exit(-1); } else { already_quitting = true; } // Message first. va_start(argptr, error); //fprintf(stderr, "\nError: "); vfprintf(stderr, error, argptr); fprintf(stderr, "\n\n"); va_end(argptr); fflush(stderr); // Write a copy of the message into buffer. va_start(argptr, error); memset(msgbuf, 0, sizeof(msgbuf)); M_vsnprintf(msgbuf, sizeof(msgbuf), error, argptr); va_end(argptr); // Shutdown. Here might be other errors. entry = exit_funcs; while (entry != NULL) { if (entry->run_on_error) { entry->func(); } entry = entry->next; } exit_gui_popup = !M_ParmExists("-nogui"); // Pop up a GUI dialog box to show the error message, if the // game was not run from the console (and the user will // therefore be unable to otherwise see the message). if (exit_gui_popup && !I_ConsoleStdout()) #ifdef _WIN32 { wchar_t wmsgbuf[512]; MultiByteToWideChar(CP_ACP, 0, msgbuf, strlen(msgbuf) + 1, wmsgbuf, sizeof(wmsgbuf)); MessageBoxW(NULL, wmsgbuf, L"", MB_OK); } #elif defined(__MACOSX__) { CFStringRef message; int i; // The CoreFoundation message box wraps text lines, so replace // newline characters with spaces so that multiline messages // are continuous. for (i = 0; msgbuf[i] != '\0'; ++i) { if (msgbuf[i] == '\n') { msgbuf[i] = ' '; } } message = CFStringCreateWithCString(NULL, msgbuf, kCFStringEncodingUTF8); CFUserNotificationDisplayNotice(0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL, CFSTR(PACKAGE_STRING), message, NULL); } #else { ZenityErrorBox(msgbuf); } #endif // abort(); SDL_Quit(); exit(-1); } // // Read Access Violation emulation. // // From PrBoom+, by entryway. // // C:\>debug // -d 0:0 // // DOS 6.22: // 0000:0000 (57 92 19 00) F4 06 70 00-(16 00) // DOS 7.1: // 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00) // Win98: // 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00) // DOSBox under XP: // 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00) #define DOS_MEM_DUMP_SIZE 10 static const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = { 0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00}; static const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = { 0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00}; static const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = { 0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00}; static unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE]; static const unsigned char *dos_mem_dump = mem_dump_dos622; boolean I_GetMemoryValue(unsigned int offset, void *value, int size) { static boolean firsttime = true; if (firsttime) { int p, i, val; firsttime = false; i = 0; //! // @category compat // @arg // // Specify DOS version to emulate for NULL pointer dereference // emulation. Supported versions are: dos622, dos71, dosbox. // The default is to emulate DOS 7.1 (Windows 98). // p = M_CheckParmWithArgs("-setmem", 1); if (p > 0) { if (!strcasecmp(myargv[p + 1], "dos622")) { dos_mem_dump = mem_dump_dos622; } if (!strcasecmp(myargv[p + 1], "dos71")) { dos_mem_dump = mem_dump_win98; } else if (!strcasecmp(myargv[p + 1], "dosbox")) { dos_mem_dump = mem_dump_dosbox; } else { for (i = 0; i < DOS_MEM_DUMP_SIZE; ++i) { ++p; if (p >= myargc || myargv[p][0] == '-') { break; } M_StrToInt(myargv[p], &val); mem_dump_custom[i++] = (unsigned char) val; } dos_mem_dump = mem_dump_custom; } } } switch (size) { case 1: *((unsigned char *) value) = dos_mem_dump[offset]; return true; case 2: *((unsigned short *) value) = dos_mem_dump[offset] | (dos_mem_dump[offset + 1] << 8); return true; case 4: *((unsigned int *) value) = dos_mem_dump[offset] | (dos_mem_dump[offset + 1] << 8) | (dos_mem_dump[offset + 2] << 16) | (dos_mem_dump[offset + 3] << 24); return true; } return false; } chocolate-doom-chocolate-doom-2.2.1/src/i_system.h000066400000000000000000000041341257432200600221030ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // #ifndef __I_SYSTEM__ #define __I_SYSTEM__ #include "d_ticcmd.h" #include "d_event.h" typedef void (*atexit_func_t)(void); // Called by DoomMain. void I_Init (void); // Called by startup code // to get the ammount of memory to malloc // for the zone management. byte* I_ZoneBase (int *size); boolean I_ConsoleStdout(void); // Asynchronous interrupt functions should maintain private queues // that are read by the synchronous functions // to be converted into events. // Either returns a null ticcmd, // or calls a loadable driver to build it. // This ticcmd will then be modified by the gameloop // for normal input. ticcmd_t* I_BaseTiccmd (void); // Called by M_Responder when quit is selected. // Clean exit, displays sell blurb. void I_Quit (void); void I_Error (char *error, ...); void I_Tactile (int on, int off, int total); boolean I_GetMemoryValue(unsigned int offset, void *value, int size); // Schedule a function to be called when the program exits. // If run_if_error is true, the function is called if the exit // is due to an error (I_Error) void I_AtExit(atexit_func_t func, boolean run_if_error); // Add all system-specific config file variable bindings. void I_BindVariables(void); // Print startup banner copyright message. void I_PrintStartupBanner(char *gamedescription); // Print a centered text banner displaying the given string. void I_PrintBanner(char *text); // Print a dividing line for startup banners. void I_PrintDivider(void); #endif chocolate-doom-chocolate-doom-2.2.1/src/i_timer.c000066400000000000000000000026221257432200600216720ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Timer functions. // #include "SDL.h" #include "i_timer.h" #include "doomtype.h" // // I_GetTime // returns time in 1/35th second tics // static Uint32 basetime = 0; int I_GetTime (void) { Uint32 ticks; ticks = SDL_GetTicks(); if (basetime == 0) basetime = ticks; ticks -= basetime; return (ticks * TICRATE) / 1000; } // // Same as I_GetTime, but returns time in milliseconds // int I_GetTimeMS(void) { Uint32 ticks; ticks = SDL_GetTicks(); if (basetime == 0) basetime = ticks; return ticks - basetime; } // Sleep for a specified number of ms void I_Sleep(int ms) { SDL_Delay(ms); } void I_WaitVBL(int count) { I_Sleep((count * 1000) / 70); } void I_InitTimer(void) { // initialize timer SDL_Init(SDL_INIT_TIMER); } chocolate-doom-chocolate-doom-2.2.1/src/i_timer.h000066400000000000000000000020161257432200600216740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System-specific timer interface // #ifndef __I_TIMER__ #define __I_TIMER__ #define TICRATE 35 // Called by D_DoomLoop, // returns current time in tics. int I_GetTime (void); // returns current time in ms int I_GetTimeMS (void); // Pause for a specified number of ms void I_Sleep(int ms); // Initialize timer void I_InitTimer(void); // Wait for vertical retrace or pause a bit. void I_WaitVBL(int count); #endif chocolate-doom-chocolate-doom-2.2.1/src/i_video.c000066400000000000000000001431521257432200600216640ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM graphics stuff for SDL. // #include "SDL.h" #include #include #include #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #endif #include "icon.c" #include "config.h" #include "deh_str.h" #include "doomtype.h" #include "doomkeys.h" #include "i_joystick.h" #include "i_system.h" #include "i_swap.h" #include "i_timer.h" #include "i_video.h" #include "i_scale.h" #include "m_argv.h" #include "m_config.h" #include "m_misc.h" #include "tables.h" #include "v_video.h" #include "w_wad.h" #include "z_zone.h" // Lookup table for mapping ASCII characters to their equivalent when // shift is pressed on an American layout keyboard: static const char shiftxform[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ' ', '!', '"', '#', '$', '%', '&', '"', // shift-' '(', ')', '*', '+', '<', // shift-, '_', // shift-- '>', // shift-. '?', // shift-/ ')', // shift-0 '!', // shift-1 '@', // shift-2 '#', // shift-3 '$', // shift-4 '%', // shift-5 '^', // shift-6 '&', // shift-7 '*', // shift-8 '(', // shift-9 ':', ':', // shift-; '<', '+', // shift-= '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', // shift-[ '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK ']', // shift-] '"', '_', '\'', // shift-` 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 127 }; #define LOADING_DISK_W 16 #define LOADING_DISK_H 16 // Non aspect ratio-corrected modes (direct multiples of 320x200) static screen_mode_t *screen_modes[] = { &mode_scale_1x, &mode_scale_2x, &mode_scale_3x, &mode_scale_4x, &mode_scale_5x, }; // Aspect ratio corrected modes (4:3 ratio) static screen_mode_t *screen_modes_corrected[] = { // Vertically stretched modes (320x200 -> 320x240 and multiples) &mode_stretch_1x, &mode_stretch_2x, &mode_stretch_3x, &mode_stretch_4x, &mode_stretch_5x, // Horizontally squashed modes (320x200 -> 256x200 and multiples) &mode_squash_1x, &mode_squash_2x, &mode_squash_3x, &mode_squash_4x, }; // SDL video driver name char *video_driver = ""; // Window position: static char *window_position = ""; // SDL surface for the screen. static SDL_Surface *screen; // Window title static char *window_title = ""; // Intermediate 8-bit buffer that we draw to instead of 'screen'. // This is used when we are rendering in 32-bit screen mode. // When in a real 8-bit screen mode, screenbuffer == screen. static SDL_Surface *screenbuffer = NULL; // palette static SDL_Color palette[256]; static boolean palette_to_set; // display has been set up? static boolean initialized = false; // disable mouse? static boolean nomouse = false; int usemouse = 1; // Bit mask of mouse button state. static unsigned int mouse_button_state = 0; // Disallow mouse and joystick movement to cause forward/backward // motion. Specified with the '-novert' command line parameter. // This is an int to allow saving to config file int novert = 0; // Save screenshots in PNG format. int png_screenshots = 0; // if true, I_VideoBuffer is screen->pixels static boolean native_surface; // Screen width and height, from configuration file. int screen_width = SCREENWIDTH; int screen_height = SCREENHEIGHT; // Color depth. int screen_bpp = 0; // Automatically adjust video settings if the selected mode is // not a valid video mode. static int autoadjust_video_settings = 1; // Run in full screen mode? (int type for config code) int fullscreen = true; // Aspect ratio correction mode int aspect_ratio_correct = true; // Time to wait for the screen to settle on startup before starting the // game (ms) static int startup_delay = 1000; // Grab the mouse? (int type for config code) static int grabmouse = true; // The screen buffer; this is modified to draw things to the screen byte *I_VideoBuffer = NULL; // If true, game is running as a screensaver boolean screensaver_mode = false; // Flag indicating whether the screen is currently visible: // when the screen isnt visible, don't render the screen boolean screenvisible; // If true, we display dots at the bottom of the screen to // indicate FPS. static boolean display_fps_dots; // If this is true, the screen is rendered but not blitted to the // video buffer. static boolean noblit; // Callback function to invoke to determine whether to grab the // mouse pointer. static grabmouse_callback_t grabmouse_callback = NULL; // disk image data and background overwritten by the disk to be // restored by EndRead static byte *disk_image = NULL; static byte *saved_background; static boolean window_focused; // Empty mouse cursor static SDL_Cursor *cursors[2]; // The screen mode and scale functions being used static screen_mode_t *screen_mode; // Window resize state. static boolean need_resize = false; static unsigned int resize_w, resize_h; static unsigned int last_resize_time; // If true, keyboard mapping is ignored, like in Vanilla Doom. // The sensible thing to do is to disable this if you have a non-US // keyboard. int vanilla_keyboard_mapping = true; // Is the shift key currently down? static int shiftdown = 0; // Mouse acceleration // // This emulates some of the behavior of DOS mouse drivers by increasing // the speed when the mouse is moved fast. // // The mouse input values are input directly to the game, but when // the values exceed the value of mouse_threshold, they are multiplied // by mouse_acceleration to increase the speed. float mouse_acceleration = 2.0; int mouse_threshold = 10; // Gamma correction level to use int usegamma = 0; static void ApplyWindowResize(unsigned int w, unsigned int h); static boolean MouseShouldBeGrabbed() { // never grab the mouse when in screensaver mode if (screensaver_mode) return false; // if the window doesn't have focus, never grab it if (!window_focused) return false; // always grab the mouse when full screen (dont want to // see the mouse pointer) if (fullscreen) return true; // Don't grab the mouse if mouse input is disabled if (!usemouse || nomouse) return false; // if we specify not to grab the mouse, never grab if (!grabmouse) return false; // Invoke the grabmouse callback function to determine whether // the mouse should be grabbed if (grabmouse_callback != NULL) { return grabmouse_callback(); } else { return true; } } void I_SetGrabMouseCallback(grabmouse_callback_t func) { grabmouse_callback = func; } // Set the variable controlling FPS dots. void I_DisplayFPSDots(boolean dots_on) { display_fps_dots = dots_on; } // Update the value of window_focused when we get a focus event // // We try to make ourselves be well-behaved: the grab on the mouse // is removed if we lose focus (such as a popup window appearing), // and we dont move the mouse around if we aren't focused either. static void UpdateFocus(void) { Uint8 state; state = SDL_GetAppState(); // We should have input (keyboard) focus and be visible // (not minimized) window_focused = (state & SDL_APPINPUTFOCUS) && (state & SDL_APPACTIVE); // Should the screen be grabbed? screenvisible = (state & SDL_APPACTIVE) != 0; } // Show or hide the mouse cursor. We have to use different techniques // depending on the OS. static void SetShowCursor(boolean show) { // On Windows, using SDL_ShowCursor() adds lag to the mouse input, // so work around this by setting an invisible cursor instead. On // other systems, it isn't possible to change the cursor, so this // hack has to be Windows-only. (Thanks to entryway for this) #ifdef _WIN32 if (show) { SDL_SetCursor(cursors[1]); } else { SDL_SetCursor(cursors[0]); } #else SDL_ShowCursor(show); #endif // When the cursor is hidden, grab the input. if (!screensaver_mode) { SDL_WM_GrabInput(!show); } } void I_EnableLoadingDisk(void) { patch_t *disk; byte *tmpbuf; char *disk_name; int y; char buf[20]; SDL_VideoDriverName(buf, 15); if (!strcmp(buf, "Quartz")) { // MacOS Quartz gives us pageflipped graphics that screw up the // display when we use the loading disk. Disable it. // This is a gross hack. return; } if (M_CheckParm("-cdrom") > 0) disk_name = DEH_String("STCDROM"); else disk_name = DEH_String("STDISK"); disk = W_CacheLumpName(disk_name, PU_STATIC); // Draw the patch into a temporary buffer tmpbuf = Z_Malloc(SCREENWIDTH * (disk->height + 1), PU_STATIC, NULL); V_UseBuffer(tmpbuf); // Draw the disk to the screen: V_DrawPatch(0, 0, disk); disk_image = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL); saved_background = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL); for (y=0; ysym) { case SDLK_LEFT: return KEY_LEFTARROW; case SDLK_RIGHT: return KEY_RIGHTARROW; case SDLK_DOWN: return KEY_DOWNARROW; case SDLK_UP: return KEY_UPARROW; case SDLK_ESCAPE: return KEY_ESCAPE; case SDLK_RETURN: return KEY_ENTER; case SDLK_TAB: return KEY_TAB; case SDLK_F1: return KEY_F1; case SDLK_F2: return KEY_F2; case SDLK_F3: return KEY_F3; case SDLK_F4: return KEY_F4; case SDLK_F5: return KEY_F5; case SDLK_F6: return KEY_F6; case SDLK_F7: return KEY_F7; case SDLK_F8: return KEY_F8; case SDLK_F9: return KEY_F9; case SDLK_F10: return KEY_F10; case SDLK_F11: return KEY_F11; case SDLK_F12: return KEY_F12; case SDLK_PRINT: return KEY_PRTSCR; case SDLK_BACKSPACE: return KEY_BACKSPACE; case SDLK_DELETE: return KEY_DEL; case SDLK_PAUSE: return KEY_PAUSE; case SDLK_EQUALS: return KEY_EQUALS; case SDLK_MINUS: return KEY_MINUS; case SDLK_LSHIFT: case SDLK_RSHIFT: return KEY_RSHIFT; case SDLK_LCTRL: case SDLK_RCTRL: return KEY_RCTRL; case SDLK_LALT: case SDLK_RALT: case SDLK_LMETA: case SDLK_RMETA: return KEY_RALT; case SDLK_CAPSLOCK: return KEY_CAPSLOCK; case SDLK_SCROLLOCK: return KEY_SCRLCK; case SDLK_NUMLOCK: return KEY_NUMLOCK; case SDLK_KP0: return KEYP_0; case SDLK_KP1: return KEYP_1; case SDLK_KP2: return KEYP_2; case SDLK_KP3: return KEYP_3; case SDLK_KP4: return KEYP_4; case SDLK_KP5: return KEYP_5; case SDLK_KP6: return KEYP_6; case SDLK_KP7: return KEYP_7; case SDLK_KP8: return KEYP_8; case SDLK_KP9: return KEYP_9; case SDLK_KP_PERIOD: return KEYP_PERIOD; case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY; case SDLK_KP_PLUS: return KEYP_PLUS; case SDLK_KP_MINUS: return KEYP_MINUS; case SDLK_KP_DIVIDE: return KEYP_DIVIDE; case SDLK_KP_EQUALS: return KEYP_EQUALS; case SDLK_KP_ENTER: return KEYP_ENTER; case SDLK_HOME: return KEY_HOME; case SDLK_INSERT: return KEY_INS; case SDLK_END: return KEY_END; case SDLK_PAGEUP: return KEY_PGUP; case SDLK_PAGEDOWN: return KEY_PGDN; #ifdef SDL_HAVE_APP_KEYS case SDLK_APP1: return KEY_F1; case SDLK_APP2: return KEY_F2; case SDLK_APP3: return KEY_F3; case SDLK_APP4: return KEY_F4; case SDLK_APP5: return KEY_F5; case SDLK_APP6: return KEY_F6; #endif default: return tolower(sym->sym); } } void I_ShutdownGraphics(void) { if (initialized) { SetShowCursor(true); SDL_QuitSubSystem(SDL_INIT_VIDEO); initialized = false; } } // // I_StartFrame // void I_StartFrame (void) { // er? } static void UpdateMouseButtonState(unsigned int button, boolean on) { event_t event; if (button < SDL_BUTTON_LEFT || button > MAX_MOUSE_BUTTONS) { return; } // Note: button "0" is left, button "1" is right, // button "2" is middle for Doom. This is different // to how SDL sees things. switch (button) { case SDL_BUTTON_LEFT: button = 0; break; case SDL_BUTTON_RIGHT: button = 1; break; case SDL_BUTTON_MIDDLE: button = 2; break; default: // SDL buttons are indexed from 1. --button; break; } // Turn bit representing this button on or off. if (on) { mouse_button_state |= (1 << button); } else { mouse_button_state &= ~(1 << button); } // Post an event with the new button state. event.type = ev_mouse; event.data1 = mouse_button_state; event.data2 = event.data3 = 0; D_PostEvent(&event); } static int AccelerateMouse(int val) { if (val < 0) return -AccelerateMouse(-val); if (val > mouse_threshold) { return (int)((val - mouse_threshold) * mouse_acceleration + mouse_threshold); } else { return val; } } // Get the equivalent ASCII (Unicode?) character for a keypress. static int GetTypedChar(SDL_Event *event) { int key; // If Vanilla keyboard mapping enabled, the keyboard // scan code is used to give the character typed. // This does not change depending on keyboard layout. // If you have a German keyboard, pressing 'z' will // give 'y', for example. It is desirable to be able // to fix this so that people with non-standard // keyboard mappings can type properly. If vanilla // mode is disabled, use the properly translated // version. if (vanilla_keyboard_mapping) { key = TranslateKey(&event->key.keysym); // Is shift held down? If so, perform a translation. if (shiftdown > 0) { if (key >= 0 && key < arrlen(shiftxform)) { key = shiftxform[key]; } else { key = 0; } } return key; } else { // Unicode value, from key layout. return tolower(event->key.keysym.unicode); } } static void UpdateShiftStatus(SDL_Event *event) { int change; if (event->type == SDL_KEYDOWN) { change = 1; } else if (event->type == SDL_KEYUP) { change = -1; } else { return; } if (event->key.keysym.sym == SDLK_LSHIFT || event->key.keysym.sym == SDLK_RSHIFT) { shiftdown += change; } } void I_GetEvent(void) { SDL_Event sdlevent; event_t event; // possibly not needed SDL_PumpEvents(); // put event-grabbing stuff in here while (SDL_PollEvent(&sdlevent)) { // ignore mouse events when the window is not focused if (!window_focused && (sdlevent.type == SDL_MOUSEMOTION || sdlevent.type == SDL_MOUSEBUTTONDOWN || sdlevent.type == SDL_MOUSEBUTTONUP)) { continue; } if (screensaver_mode && sdlevent.type == SDL_QUIT) { I_Quit(); } UpdateShiftStatus(&sdlevent); // process event switch (sdlevent.type) { case SDL_KEYDOWN: // data1 has the key pressed, data2 has the character // (shift-translated, etc) event.type = ev_keydown; event.data1 = TranslateKey(&sdlevent.key.keysym); event.data2 = GetTypedChar(&sdlevent); if (event.data1 != 0) { D_PostEvent(&event); } break; case SDL_KEYUP: event.type = ev_keyup; event.data1 = TranslateKey(&sdlevent.key.keysym); // data2 is just initialized to zero for ev_keyup. // For ev_keydown it's the shifted Unicode character // that was typed, but if something wants to detect // key releases it should do so based on data1 // (key ID), not the printable char. event.data2 = 0; if (event.data1 != 0) { D_PostEvent(&event); } break; /* case SDL_MOUSEMOTION: event.type = ev_mouse; event.data1 = mouse_button_state; event.data2 = AccelerateMouse(sdlevent.motion.xrel); event.data3 = -AccelerateMouse(sdlevent.motion.yrel); D_PostEvent(&event); break; */ case SDL_MOUSEBUTTONDOWN: if (usemouse && !nomouse) { UpdateMouseButtonState(sdlevent.button.button, true); } break; case SDL_MOUSEBUTTONUP: if (usemouse && !nomouse) { UpdateMouseButtonState(sdlevent.button.button, false); } break; case SDL_QUIT: event.type = ev_quit; D_PostEvent(&event); break; case SDL_ACTIVEEVENT: // need to update our focus state UpdateFocus(); break; case SDL_VIDEOEXPOSE: palette_to_set = true; break; case SDL_RESIZABLE: need_resize = true; resize_w = sdlevent.resize.w; resize_h = sdlevent.resize.h; last_resize_time = SDL_GetTicks(); break; default: break; } } } // Warp the mouse back to the middle of the screen static void CenterMouse(void) { // Warp the the screen center SDL_WarpMouse(screen->w / 2, screen->h / 2); // Clear any relative movement caused by warping SDL_PumpEvents(); SDL_GetRelativeMouseState(NULL, NULL); } // // Read the change in mouse state to generate mouse motion events // // This is to combine all mouse movement for a tic into one mouse // motion event. static void I_ReadMouse(void) { int x, y; event_t ev; SDL_GetRelativeMouseState(&x, &y); if (x != 0 || y != 0) { ev.type = ev_mouse; ev.data1 = mouse_button_state; ev.data2 = AccelerateMouse(x); if (!novert) { ev.data3 = -AccelerateMouse(y); } else { ev.data3 = 0; } D_PostEvent(&ev); } if (MouseShouldBeGrabbed()) { CenterMouse(); } } // // I_StartTic // void I_StartTic (void) { if (!initialized) { return; } I_GetEvent(); if (usemouse && !nomouse) { I_ReadMouse(); } I_UpdateJoystick(); } // // I_UpdateNoBlit // void I_UpdateNoBlit (void) { // what is this? } static void UpdateGrab(void) { static boolean currently_grabbed = false; boolean grab; grab = MouseShouldBeGrabbed(); if (screensaver_mode) { // Hide the cursor in screensaver mode SetShowCursor(false); } else if (grab && !currently_grabbed) { SetShowCursor(false); CenterMouse(); } else if (!grab && currently_grabbed) { SetShowCursor(true); // When releasing the mouse from grab, warp the mouse cursor to // the bottom-right of the screen. This is a minimally distracting // place for it to appear - we may only have released the grab // because we're at an end of level intermission screen, for // example. SDL_WarpMouse(screen->w - 16, screen->h - 16); SDL_PumpEvents(); SDL_GetRelativeMouseState(NULL, NULL); } currently_grabbed = grab; } // Update a small portion of the screen // // Does stretching and buffer blitting if neccessary // // Return true if blit was successful. static boolean BlitArea(int x1, int y1, int x2, int y2) { int x_offset, y_offset; boolean result; // No blit needed on native surface if (native_surface) { return true; } x_offset = (screenbuffer->w - screen_mode->width) / 2; y_offset = (screenbuffer->h - screen_mode->height) / 2; if (SDL_LockSurface(screenbuffer) >= 0) { I_InitScale(I_VideoBuffer, (byte *) screenbuffer->pixels + (y_offset * screenbuffer->pitch) + x_offset, screenbuffer->pitch); result = screen_mode->DrawScreen(x1, y1, x2, y2); SDL_UnlockSurface(screenbuffer); } else { result = false; } return result; } static void UpdateRect(int x1, int y1, int x2, int y2) { int x1_scaled, x2_scaled, y1_scaled, y2_scaled; // Do stretching and blitting if (BlitArea(x1, y1, x2, y2)) { // Update the area x1_scaled = (x1 * screen_mode->width) / SCREENWIDTH; y1_scaled = (y1 * screen_mode->height) / SCREENHEIGHT; x2_scaled = (x2 * screen_mode->width) / SCREENWIDTH; y2_scaled = (y2 * screen_mode->height) / SCREENHEIGHT; SDL_UpdateRect(screen, x1_scaled, y1_scaled, x2_scaled - x1_scaled, y2_scaled - y1_scaled); } } void I_BeginRead(void) { byte *screenloc = I_VideoBuffer + (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH + (SCREENWIDTH - LOADING_DISK_W); int y; if (!initialized || disk_image == NULL) return; // save background and copy the disk image in for (y=0; y last_resize_time + 500) { ApplyWindowResize(resize_w, resize_h); need_resize = false; palette_to_set = true; } UpdateGrab(); // Don't update the screen if the window isn't visible. // Not doing this breaks under Windows when we alt-tab away // while fullscreen. if (!(SDL_GetAppState() & SDL_APPACTIVE)) return; // draws little dots on the bottom of the screen if (display_fps_dots) { i = I_GetTime(); tics = i - lasttic; lasttic = i; if (tics > 20) tics = 20; for (i=0 ; iw - screenbuffer->w) / 2; dst_rect.y = (screen->h - screenbuffer->h) / 2; SDL_BlitSurface(screenbuffer, NULL, screen, &dst_rect); } SDL_Flip(screen); } // // I_ReadScreen // void I_ReadScreen (byte* scr) { memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT); } // // I_SetPalette // void I_SetPalette (byte *doompalette) { int i; for (i=0; i<256; ++i) { // Zero out the bottom two bits of each channel - the PC VGA // controller only supports 6 bits of accuracy. palette[i].r = gammatable[usegamma][*doompalette++] & ~3; palette[i].g = gammatable[usegamma][*doompalette++] & ~3; palette[i].b = gammatable[usegamma][*doompalette++] & ~3; } palette_to_set = true; } // Given an RGB value, find the closest matching palette index. int I_GetPaletteIndex(int r, int g, int b) { int best, best_diff, diff; int i; best = 0; best_diff = INT_MAX; for (i = 0; i < 256; ++i) { diff = (r - palette[i].r) * (r - palette[i].r) + (g - palette[i].g) * (g - palette[i].g) + (b - palette[i].b) * (b - palette[i].b); if (diff < best_diff) { best = i; best_diff = diff; } if (diff == 0) { break; } } return best; } // // Set the window title // void I_SetWindowTitle(char *title) { window_title = title; } // // Call the SDL function to set the window title, based on // the title set with I_SetWindowTitle. // void I_InitWindowTitle(void) { char *buf; buf = M_StringJoin(window_title, " - ", PACKAGE_STRING, NULL); SDL_WM_SetCaption(buf, NULL); free(buf); } // Set the application icon void I_InitWindowIcon(void) { SDL_Surface *surface; Uint8 *mask; int i; // Generate the mask mask = malloc(icon_w * icon_h / 8); memset(mask, 0, icon_w * icon_h / 8); for (i=0; iwidth > w || modes_list[i]->height > h) { continue; } num_pixels = modes_list[i]->width * modes_list[i]->height; if (num_pixels > best_num_pixels) { // This is a better mode than the current one best_mode = modes_list[i]; best_num_pixels = num_pixels; } } return best_mode; } // Adjust to an appropriate fullscreen mode. // Returns true if successful. static boolean AutoAdjustFullscreen(void) { SDL_Rect **modes; SDL_Rect *best_mode; screen_mode_t *screen_mode; int diff, best_diff; int i; modes = SDL_ListModes(NULL, SDL_FULLSCREEN); // No fullscreen modes available at all? if (modes == NULL || modes == (SDL_Rect **) -1 || *modes == NULL) { return false; } // Find the best mode that matches the mode specified in the // configuration file best_mode = NULL; best_diff = INT_MAX; for (i=0; modes[i] != NULL; ++i) { //printf("%ix%i?\n", modes[i]->w, modes[i]->h); // What screen_mode_t would be used for this video mode? screen_mode = I_FindScreenMode(modes[i]->w, modes[i]->h); // Never choose a screen mode that we cannot run in, or // is poor quality for fullscreen if (screen_mode == NULL || screen_mode->poor_quality) { // printf("\tUnsupported / poor quality\n"); continue; } // Do we have the exact mode? // If so, no autoadjust needed if (screen_width == modes[i]->w && screen_height == modes[i]->h) { // printf("\tExact mode!\n"); return true; } // Is this mode better than the current mode? diff = (screen_width - modes[i]->w) * (screen_width - modes[i]->w) + (screen_height - modes[i]->h) * (screen_height - modes[i]->h); if (diff < best_diff) { // printf("\tA valid mode\n"); best_mode = modes[i]; best_diff = diff; } } if (best_mode == NULL) { // Unable to find a valid mode! return false; } printf("I_InitGraphics: %ix%i mode not supported on this machine.\n", screen_width, screen_height); screen_width = best_mode->w; screen_height = best_mode->h; return true; } // Auto-adjust to a valid windowed mode. static void AutoAdjustWindowed(void) { screen_mode_t *best_mode; // Find a screen_mode_t to fit within the current settings best_mode = I_FindScreenMode(screen_width, screen_height); if (best_mode == NULL) { // Nothing fits within the current settings. // Pick the closest to 320x200 possible. best_mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT_4_3); } // Switch to the best mode if necessary. if (best_mode->width != screen_width || best_mode->height != screen_height) { printf("I_InitGraphics: Cannot run at specified mode: %ix%i\n", screen_width, screen_height); screen_width = best_mode->width; screen_height = best_mode->height; } } // Auto-adjust to a valid color depth. static void AutoAdjustColorDepth(void) { SDL_Rect **modes; SDL_PixelFormat format; const SDL_VideoInfo *info; int flags; // If screen_bpp=0, we should use the current (default) pixel depth. // Fetch it from SDL. if (screen_bpp == 0) { info = SDL_GetVideoInfo(); if (info != NULL && info->vfmt != NULL) { screen_bpp = info->vfmt->BitsPerPixel; } } if (fullscreen) { flags = SDL_FULLSCREEN; } else { flags = 0; } format.BitsPerPixel = screen_bpp; format.BytesPerPixel = (screen_bpp + 7) / 8; // Are any screen modes supported at the configured color depth? modes = SDL_ListModes(&format, flags); // If not, we must autoadjust to something sensible. if (modes == NULL) { printf("I_InitGraphics: %ibpp color depth not supported.\n", screen_bpp); info = SDL_GetVideoInfo(); if (info != NULL && info->vfmt != NULL) { screen_bpp = info->vfmt->BitsPerPixel; } } } // If the video mode set in the configuration file is not available, // try to choose a different mode. static void I_AutoAdjustSettings(void) { int old_screen_w, old_screen_h, old_screen_bpp; old_screen_w = screen_width; old_screen_h = screen_height; old_screen_bpp = screen_bpp; // Possibly adjust color depth. AutoAdjustColorDepth(); // If we are running fullscreen, try to autoadjust to a valid fullscreen // mode. If this is impossible, switch to windowed. if (fullscreen && !AutoAdjustFullscreen()) { fullscreen = 0; } // If we are running windowed, pick a valid window size. if (!fullscreen) { AutoAdjustWindowed(); } // Have the settings changed? Show a message. if (screen_width != old_screen_w || screen_height != old_screen_h || screen_bpp != old_screen_bpp) { printf("I_InitGraphics: Auto-adjusted to %ix%ix%ibpp.\n", screen_width, screen_height, screen_bpp); printf("NOTE: Your video settings have been adjusted. " "To disable this behavior,\n" "set autoadjust_video_settings to 0 in your " "configuration file.\n"); } } // Set video size to a particular scale factor (1x, 2x, 3x, etc.) static void SetScaleFactor(int factor) { int w, h; // Pick 320x200 or 320x240, depending on aspect ratio correct if (aspect_ratio_correct) { w = SCREENWIDTH; h = SCREENHEIGHT_4_3; } else { w = SCREENWIDTH; h = SCREENHEIGHT; } screen_width = w * factor; screen_height = h * factor; } void I_GraphicsCheckCommandLine(void) { int i; //! // @vanilla // // Disable blitting the screen. // noblit = M_CheckParm ("-noblit"); //! // @category video // // Grab the mouse when running in windowed mode. // if (M_CheckParm("-grabmouse")) { grabmouse = true; } //! // @category video // // Don't grab the mouse when running in windowed mode. // if (M_CheckParm("-nograbmouse")) { grabmouse = false; } // default to fullscreen mode, allow override with command line // nofullscreen because we love prboom //! // @category video // // Run in a window. // if (M_CheckParm("-window") || M_CheckParm("-nofullscreen")) { fullscreen = false; } //! // @category video // // Run in fullscreen mode. // if (M_CheckParm("-fullscreen")) { fullscreen = true; } //! // @category video // // Disable the mouse. // nomouse = M_CheckParm("-nomouse") > 0; //! // @category video // @arg // // Specify the screen width, in pixels. // i = M_CheckParmWithArgs("-width", 1); if (i > 0) { screen_width = atoi(myargv[i + 1]); } //! // @category video // @arg // // Specify the screen height, in pixels. // i = M_CheckParmWithArgs("-height", 1); if (i > 0) { screen_height = atoi(myargv[i + 1]); } //! // @category video // @arg // // Specify the color depth of the screen, in bits per pixel. // i = M_CheckParmWithArgs("-bpp", 1); if (i > 0) { screen_bpp = atoi(myargv[i + 1]); } // Because we love Eternity: //! // @category video // // Set the color depth of the screen to 32 bits per pixel. // if (M_CheckParm("-8in32")) { screen_bpp = 32; } //! // @category video // @arg [wf] // // Specify the dimensions of the window or fullscreen mode. An // optional letter of w or f appended to the dimensions selects // windowed or fullscreen mode. i = M_CheckParmWithArgs("-geometry", 1); if (i > 0) { int w, h, s; char f; s = sscanf(myargv[i + 1], "%ix%i%1c", &w, &h, &f); if (s == 2 || s == 3) { screen_width = w; screen_height = h; if (s == 3 && f == 'f') { fullscreen = true; } else if (s == 3 && f == 'w') { fullscreen = false; } } } //! // @category video // // Don't scale up the screen. // if (M_CheckParm("-1")) { SetScaleFactor(1); } //! // @category video // // Double up the screen to 2x its normal size. // if (M_CheckParm("-2")) { SetScaleFactor(2); } //! // @category video // // Double up the screen to 3x its normal size. // if (M_CheckParm("-3")) { SetScaleFactor(3); } //! // @category video // // Disable vertical mouse movement. // if (M_CheckParm("-novert")) { novert = true; } //! // @category video // // Enable vertical mouse movement. // if (M_CheckParm("-nonovert")) { novert = false; } } // Check if we have been invoked as a screensaver by xscreensaver. void I_CheckIsScreensaver(void) { char *env; env = getenv("XSCREENSAVER_WINDOW"); if (env != NULL) { screensaver_mode = true; } } static void CreateCursors(void) { static Uint8 empty_cursor_data = 0; // Save the default cursor so it can be recalled later cursors[1] = SDL_GetCursor(); // Create an empty cursor cursors[0] = SDL_CreateCursor(&empty_cursor_data, &empty_cursor_data, 1, 1, 0, 0); } static void SetSDLVideoDriver(void) { // Allow a default value for the SDL video driver to be specified // in the configuration file. if (strcmp(video_driver, "") != 0) { char *env_string; env_string = M_StringJoin("SDL_VIDEODRIVER=", video_driver, NULL); putenv(env_string); free(env_string); } } static void SetWindowPositionVars(void) { char buf[64]; int x, y; if (window_position == NULL || !strcmp(window_position, "")) { return; } if (!strcmp(window_position, "center")) { putenv("SDL_VIDEO_CENTERED=1"); } else if (sscanf(window_position, "%i,%i", &x, &y) == 2) { M_snprintf(buf, sizeof(buf), "SDL_VIDEO_WINDOW_POS=%i,%i", x, y); putenv(buf); } } static char *WindowBoxType(screen_mode_t *mode, int w, int h) { if (mode->width != w && mode->height != h) { return "Windowboxed"; } else if (mode->width == w) { return "Letterboxed"; } else if (mode->height == h) { return "Pillarboxed"; } else { return "..."; } } static void SetVideoMode(screen_mode_t *mode, int w, int h) { byte *doompal; int flags = 0; doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); // If we are already running and in a true color mode, we need // to free the screenbuffer surface before setting the new mode. if (screenbuffer != NULL && screen != screenbuffer) { SDL_FreeSurface(screenbuffer); } // Generate lookup tables before setting the video mode. if (mode != NULL && mode->InitMode != NULL) { mode->InitMode(doompal); } // Set the video mode. flags |= SDL_SWSURFACE | SDL_DOUBLEBUF; if (screen_bpp == 8) { flags |= SDL_HWPALETTE; } if (fullscreen) { flags |= SDL_FULLSCREEN; } else { // In windowed mode, the window can be resized while the game is // running. This feature is disabled on OS X, as it adds an ugly // scroll handle to the corner of the screen. #ifndef __MACOSX__ flags |= SDL_RESIZABLE; #endif } screen = SDL_SetVideoMode(w, h, screen_bpp, flags); if (screen == NULL) { I_Error("Error setting video mode %ix%ix%ibpp: %s\n", w, h, screen_bpp, SDL_GetError()); } // Blank out the full screen area in case there is any junk in // the borders that won't otherwise be overwritten. SDL_FillRect(screen, NULL, 0); // If mode was not set, it must be set now that we know the // screen size. if (mode == NULL) { mode = I_FindScreenMode(screen->w, screen->h); if (mode == NULL) { I_Error("I_InitGraphics: Unable to find a screen mode small " "enough for %ix%i", screen->w, screen->h); } // Generate lookup tables before setting the video mode. if (mode->InitMode != NULL) { mode->InitMode(doompal); } } // Create the screenbuffer surface; if we have a real 8-bit palettized // screen, then we can use the screen as the screenbuffer. if (screen->format->BitsPerPixel == 8) { screenbuffer = screen; } else { screenbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, mode->width, mode->height, 8, 0, 0, 0, 0); SDL_FillRect(screenbuffer, NULL, 0); } // Save screen mode. screen_mode = mode; } static void ApplyWindowResize(unsigned int w, unsigned int h) { screen_mode_t *mode; // Find the biggest screen mode that will fall within these // dimensions, falling back to the smallest mode possible if // none is found. mode = I_FindScreenMode(w, h); if (mode == NULL) { mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT); } // Reset mode to resize window. printf("Resize to %ix%i\n", mode->width, mode->height); SetVideoMode(mode, mode->width, mode->height); // Save settings. screen_width = mode->width; screen_height = mode->height; } void I_InitGraphics(void) { SDL_Event dummy; byte *doompal; char *env; // Pass through the XSCREENSAVER_WINDOW environment variable to // SDL_WINDOWID, to embed the SDL window into the Xscreensaver // window. env = getenv("XSCREENSAVER_WINDOW"); if (env != NULL) { char winenv[30]; int winid; sscanf(env, "0x%x", &winid); M_snprintf(winenv, sizeof(winenv), "SDL_WINDOWID=%i", winid); putenv(winenv); } SetSDLVideoDriver(); SetWindowPositionVars(); if (SDL_Init(SDL_INIT_VIDEO) < 0) { I_Error("Failed to initialize video: %s", SDL_GetError()); } // Set up title and icon. Windows cares about the ordering; this // has to be done before the call to SDL_SetVideoMode. I_InitWindowTitle(); I_InitWindowIcon(); // Warning to OS X users... though they might never see it :( #ifdef __MACOSX__ if (fullscreen) { printf("Some old versions of OS X might crash in fullscreen mode.\n" "If this happens to you, switch back to windowed mode.\n"); } #endif // // Enter into graphics mode. // // When in screensaver mode, run full screen and auto detect // screen dimensions (don't change video mode) // if (screensaver_mode) { SetVideoMode(NULL, 0, 0); } else { int w, h; if (autoadjust_video_settings) { I_AutoAdjustSettings(); } w = screen_width; h = screen_height; screen_mode = I_FindScreenMode(w, h); if (screen_mode == NULL) { I_Error("I_InitGraphics: Unable to find a screen mode small " "enough for %ix%i", w, h); } if (w != screen_mode->width || h != screen_mode->height) { printf("I_InitGraphics: %s (%ix%i within %ix%i)\n", WindowBoxType(screen_mode, w, h), screen_mode->width, screen_mode->height, w, h); } SetVideoMode(screen_mode, w, h); } // Start with a clear black screen // (screen will be flipped after we set the palette) SDL_FillRect(screenbuffer, NULL, 0); // Set the palette doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); I_SetPalette(doompal); SDL_SetColors(screenbuffer, palette, 0, 256); CreateCursors(); UpdateFocus(); UpdateGrab(); // On some systems, it takes a second or so for the screen to settle // after changing modes. We include the option to add a delay when // setting the screen mode, so that the game doesn't start immediately // with the player unable to see anything. if (fullscreen && !screensaver_mode) { SDL_Delay(startup_delay); } // Check if we have a native surface we can use // If we have to lock the screen, draw to a buffer and copy // Likewise if the screen pitch is not the same as the width // If we have to multiply, drawing is done to a separate 320x200 buf native_surface = screen == screenbuffer && !SDL_MUSTLOCK(screen) && screen_mode == &mode_scale_1x && screen->pitch == SCREENWIDTH && aspect_ratio_correct; // If not, allocate a buffer and copy from that buffer to the // screen when we do an update if (native_surface) { I_VideoBuffer = (unsigned char *) screen->pixels; I_VideoBuffer += (screen->h - SCREENHEIGHT) / 2; } else { I_VideoBuffer = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); } V_RestoreBuffer(); // Clear the screen to black. memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT); // We need SDL to give us translated versions of keys as well SDL_EnableUNICODE(1); // Repeat key presses - this is what Vanilla Doom does // Not sure about repeat rate - probably dependent on which DOS // driver is used. This is good enough though. SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); // clear out any events waiting at the start and center the mouse while (SDL_PollEvent(&dummy)); initialized = true; // Call I_ShutdownGraphics on quit I_AtExit(I_ShutdownGraphics, true); } // Bind all variables controlling video options into the configuration // file system. void I_BindVideoVariables(void) { M_BindIntVariable("use_mouse", &usemouse); M_BindIntVariable("autoadjust_video_settings", &autoadjust_video_settings); M_BindIntVariable("fullscreen", &fullscreen); M_BindIntVariable("aspect_ratio_correct", &aspect_ratio_correct); M_BindIntVariable("startup_delay", &startup_delay); M_BindIntVariable("screen_width", &screen_width); M_BindIntVariable("screen_height", &screen_height); M_BindIntVariable("screen_bpp", &screen_bpp); M_BindIntVariable("grabmouse", &grabmouse); M_BindFloatVariable("mouse_acceleration", &mouse_acceleration); M_BindIntVariable("mouse_threshold", &mouse_threshold); M_BindStringVariable("video_driver", &video_driver); M_BindStringVariable("window_position", &window_position); M_BindIntVariable("usegamma", &usegamma); M_BindIntVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping); M_BindIntVariable("novert", &novert); M_BindIntVariable("png_screenshots", &png_screenshots); // Windows Vista or later? Set screen color depth to // 32 bits per pixel, as 8-bit palettized screen modes // don't work properly in recent versions. #if defined(_WIN32) && !defined(_WIN32_WCE) { OSVERSIONINFOEX version_info; ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO *) &version_info); if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 6) { screen_bpp = 32; } } #endif // Disable fullscreen by default on OS X, as there is an SDL bug // where some old versions of OS X (<= Snow Leopard) crash. #ifdef __MACOSX__ fullscreen = 0; screen_width = 800; screen_height = 600; #endif } chocolate-doom-chocolate-doom-2.2.1/src/i_video.h000066400000000000000000000107061257432200600216670ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // #ifndef __I_VIDEO__ #define __I_VIDEO__ #include "doomtype.h" // Screen width and height. #define SCREENWIDTH 320 #define SCREENHEIGHT 200 // Screen width used for "squash" scale functions #define SCREENWIDTH_4_3 256 // Screen height used for "stretch" scale functions. #define SCREENHEIGHT_4_3 240 #define MAX_MOUSE_BUTTONS 8 typedef struct { // Screen width and height int width; int height; // Initialisation function to call when using this mode. // Called with a pointer to the Doom palette. // // If NULL, no init function is called. void (*InitMode)(byte *palette); // Function to call to draw the screen from the source buffer. // Return true if draw was successful. boolean (*DrawScreen)(int x1, int y1, int x2, int y2); // If true, this is a "poor quality" mode. The autoadjust // code should always attempt to use a different mode to this // mode in fullscreen. // // Some notes about what "poor quality" means in this context: // // The aspect ratio correction works by scaling up to the larger // screen size and then drawing pixels on the edges between the // "virtual" pixels so that an authentic blocky look-and-feel is // achieved. // // For a mode like 640x480, you can imagine the grid of the // "original" pixels spaced out, with extra "blurry" pixels added // in the space between them to fill it out. However, when you're // running at a resolution like 320x240, this is not the case. In // the small screen case, every single pixel has to be a blurry // interpolation of two pixels from the original image. // // If you run in 320x240 and put your face up close to the screen // you can see this: it's particularly visible in the small yellow // status bar numbers for example. Overall it still looks "okay" // but there's an obvious - albeit small - deterioration in // quality. // // Once you get to 640x480, all the original pixels are there at // least once and it's okay (the higher the resolution, the more // accurate it is). When I first wrote the code I was expecting // that even higher resolutions would be needed before it would // look acceptable, but it turned out to be okay even at 640x480. boolean poor_quality; } screen_mode_t; typedef boolean (*grabmouse_callback_t)(void); // Called by D_DoomMain, // determines the hardware configuration // and sets up the video mode void I_InitGraphics (void); void I_GraphicsCheckCommandLine(void); void I_ShutdownGraphics(void); // Takes full 8 bit values. void I_SetPalette (byte* palette); int I_GetPaletteIndex(int r, int g, int b); void I_UpdateNoBlit (void); void I_FinishUpdate (void); void I_ReadScreen (byte* scr); void I_BeginRead (void); void I_EndRead (void); void I_SetWindowTitle(char *title); void I_CheckIsScreensaver(void); void I_SetGrabMouseCallback(grabmouse_callback_t func); void I_DisplayFPSDots(boolean dots_on); void I_BindVideoVariables(void); void I_InitWindowTitle(void); void I_InitWindowIcon(void); // Called before processing any tics in a frame (just after displaying a frame). // Time consuming syncronous operations are performed here (joystick reading). void I_StartFrame (void); // Called before processing each tic in a frame. // Quick syncronous operations are performed here. void I_StartTic (void); // Enable the loading disk image displayed when reading from disk. void I_EnableLoadingDisk(void); extern char *video_driver; extern boolean screenvisible; extern float mouse_acceleration; extern int mouse_threshold; extern int vanilla_keyboard_mapping; extern boolean screensaver_mode; extern int usegamma; extern byte *I_VideoBuffer; extern int screen_width; extern int screen_height; extern int screen_bpp; extern int fullscreen; extern int aspect_ratio_correct; #endif chocolate-doom-chocolate-doom-2.2.1/src/i_videohr.c000066400000000000000000000125061257432200600222140ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // SDL emulation of VGA 640x480x4 planar video mode, // for Hexen startup loading screen. // #include "SDL.h" #include "string.h" #include "doomtype.h" #include "i_timer.h" // Palette fade-in takes two seconds #define FADE_TIME 2000 #define HR_SCREENWIDTH 640 #define HR_SCREENHEIGHT 480 static SDL_Surface *hr_screen = NULL; static SDL_Surface *hr_surface = NULL; static char *window_title = ""; boolean I_SetVideoModeHR(void) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { return false; } SDL_WM_SetCaption(window_title, NULL); // Create screen surface at the native desktop pixel depth (bpp=0), // as we cannot trust true 8-bit to reliably work nowadays. hr_screen = SDL_SetVideoMode(HR_SCREENWIDTH, HR_SCREENHEIGHT, 0, 0); if (hr_screen == NULL) { SDL_QuitSubSystem(SDL_INIT_VIDEO); return false; } // We do all actual drawing into an intermediate surface. hr_surface = SDL_CreateRGBSurface(0, HR_SCREENWIDTH, HR_SCREENHEIGHT, 8, 0, 0, 0, 0); return true; } void I_SetWindowTitleHR(char *title) { window_title = title; } void I_UnsetVideoModeHR(void) { if (hr_screen != NULL) { SDL_QuitSubSystem(SDL_INIT_VIDEO); hr_screen = NULL; SDL_FreeSurface(hr_surface); hr_surface = NULL; } } void I_ClearScreenHR(void) { SDL_Rect area = { 0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT }; SDL_FillRect(hr_surface, &area, 0); } void I_SlamBlockHR(int x, int y, int w, int h, const byte *src) { SDL_Rect blit_rect; const byte *srcptrs[4]; byte srcbits[4]; byte *dest; int x1, y1; int i; int bit; // Set up source pointers to read from source buffer - each 4-bit // pixel has its bits split into four sub-buffers for (i=0; i<4; ++i) { srcptrs[i] = src + (i * w * h / 8); } if (SDL_LockSurface(hr_surface) < 0) { return; } // Draw each pixel bit = 0; for (y1=y; y1pixels) + y1 * hr_surface->pitch + x; for (x1=x; x1> (7 - (bit % 8))) & 0x1; } // Reassemble the pixel value *dest = (srcbits[0] << 0) | (srcbits[1] << 1) | (srcbits[2] << 2) | (srcbits[3] << 3); // Next pixel! ++dest; ++bit; } } SDL_UnlockSurface(hr_surface); // Update the region we drew. blit_rect.x = x; blit_rect.y = y; blit_rect.w = w; blit_rect.h = h; SDL_BlitSurface(hr_surface, &blit_rect, hr_screen, &blit_rect); SDL_UpdateRects(hr_screen, 1, &blit_rect); } void I_SlamHR(const byte *buffer) { I_SlamBlockHR(0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT, buffer); } void I_InitPaletteHR(void) { // ... } void I_SetPaletteHR(const byte *palette) { SDL_Rect screen_rect = {0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT}; SDL_Color sdlpal[16]; int i; for (i=0; i<16; ++i) { sdlpal[i].r = palette[i * 3 + 0] * 4; sdlpal[i].g = palette[i * 3 + 1] * 4; sdlpal[i].b = palette[i * 3 + 2] * 4; } // After setting colors, update the screen. SDL_SetColors(hr_surface, sdlpal, 0, 16); SDL_BlitSurface(hr_surface, &screen_rect, hr_screen, &screen_rect); SDL_UpdateRects(hr_screen, 1, &screen_rect); } void I_FadeToPaletteHR(const byte *palette) { byte tmppal[16 * 3]; int starttime; int elapsed; int i; starttime = I_GetTimeMS(); for (;;) { elapsed = I_GetTimeMS() - starttime; if (elapsed >= FADE_TIME) { break; } // Generate the fake palette for (i=0; i<16 * 3; ++i) { tmppal[i] = (palette[i] * elapsed) / FADE_TIME; } I_SetPaletteHR(tmppal); SDL_Flip(hr_surface); // Sleep a bit I_Sleep(10); } // Set the final palette I_SetPaletteHR(palette); } void I_BlackPaletteHR(void) { byte blackpal[16 * 3]; memset(blackpal, 0, sizeof(blackpal)); I_SetPaletteHR(blackpal); } // Check if the user has hit the escape key to abort startup. boolean I_CheckAbortHR(void) { SDL_Event ev; boolean result = false; // Not initialized? if (hr_surface == NULL) { return false; } while (SDL_PollEvent(&ev)) { if (ev.type == SDL_KEYDOWN && ev.key.keysym.sym == SDLK_ESCAPE) { result = true; } } return result; } chocolate-doom-chocolate-doom-2.2.1/src/i_videohr.h000066400000000000000000000021721257432200600222170ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // SDL emulation of VGA 640x480x4 planar video mode, // for Hexen startup loading screen. // #ifndef I_VIDEOHR_H #define I_VIDEOHR_H boolean I_SetVideoModeHR(void); void I_UnsetVideoModeHR(void); void I_SetWindowTitleHR(char *title); void I_ClearScreenHR(void); void I_SlamBlockHR(int x, int y, int w, int h, const byte *src); void I_SlamHR(const byte *buffer); void I_InitPaletteHR(void); void I_SetPaletteHR(const byte *palette); void I_FadeToPaletteHR(const byte *palette); void I_BlackPaletteHR(void); boolean I_CheckAbortHR(void); #endif /* #ifndef I_VIDEOHR_H */ chocolate-doom-chocolate-doom-2.2.1/src/icon.c000066400000000000000000000445361257432200600212040ustar00rootroot00000000000000static int icon_w = 32; static int icon_h = 32; static unsigned char icon_data[] = { 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa2,0x86,0x73, 0xa9,0x8d,0x7a, 0xbd,0xa0,0x8c, 0xda,0xba,0xa0, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xbd,0x8d,0x67, 0xd7,0xb9,0xa5, 0xeb,0xd8,0xcd, 0xd3,0xbf,0xae, 0xbd,0xa0,0x8c, 0xeb,0xd8,0xcd, 0xc2,0x9d,0x86, 0x95,0x5d,0x38, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9b,0x7e,0x66, 0xc5,0x9e,0x81, 0xd3,0xb3,0x99, 0xd4,0xac,0x8e, 0xee,0xdc,0xd1, 0xb9,0x93,0x76, 0xad,0x71,0x45, 0xd4,0xac,0x8e, 0xb9,0x93,0x76, 0xa3,0x77,0x58, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x39,0x1d,0x2d, 0x55,0x20,0x22, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xda,0xb4,0x9c, 0xd3,0xa3,0x83, 0xaf,0x91,0x78, 0xa7,0x83,0x6d, 0xc4,0xa7,0x93, 0xee,0xe2,0xd5, 0xeb,0xd8,0xcd, 0x8c,0x60,0x3d, 0x9b,0x7e,0x66, 0xce,0x9f,0x7e, 0x84,0x54,0x33, 0xba,0x83,0x5b, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x24,0x1c,0x35, 0x00,0x0f,0x32, 0x29,0x18,0x2e, 0x55,0x20,0x22, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xd3,0xb3,0x99, 0xca,0x93,0x6f, 0xc4,0x94,0x6e, 0x98,0x66,0x45, 0x78,0x50,0x2d, 0xd7,0xb9,0xa5, 0xee,0xdc,0xd1, 0xc4,0x9b,0x79, 0xa1,0x6d,0x45, 0x66,0x40,0x24, 0xb8,0x7a,0x4f, 0xcf,0xa6,0x83, 0x98,0x6d,0x4e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x30,0x1c,0x2f, 0x08,0x13,0x30, 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x39,0x1d,0x2d, 0x52,0x1c,0x1a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9e,0x7b,0x65, 0xb9,0x89,0x64, 0xaa,0x7d,0x5e, 0x9e,0x72,0x53, 0x88,0x5e,0x40, 0xc4,0xa7,0x93, 0xb9,0x89,0x64, 0x90,0x6c,0x51, 0x7f,0x50,0x2f, 0x90,0x5e,0x37, 0x75,0x4d,0x30, 0x7f,0x50,0x2f, 0xd3,0xa3,0x83, 0xd4,0xac,0x8e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x29,0x18,0x2e, 0x08,0x13,0x30, 0x08,0x13,0x30, 0x08,0x13,0x30, 0x00,0x0f,0x32, 0x08,0x13,0x30, 0x49,0x1e,0x2b, 0x49,0x1a,0x16, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xda,0xba,0xa0, 0xd4,0xac,0x8e, 0xc4,0x9b,0x79, 0xaa,0x7d,0x5e, 0xaa,0x7d,0x5e, 0xbd,0xa0,0x8c, 0x8c,0x60,0x3d, 0x70,0x49,0x2c, 0x89,0x60,0x42, 0x57,0x38,0x20, 0x6c,0x45,0x29, 0x66,0x40,0x24, 0x51,0x35,0x21, 0x7e,0x55,0x38, 0xce,0x9f,0x7e, 0xc2,0x8a,0x61, 0x00,0x00,0x00, 0x30,0x1c,0x2f, 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x08,0x13,0x30, 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x08,0x13,0x30, 0x08,0x13,0x30, 0x59,0x25,0x2b, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xcb,0x9a,0x74, 0xb7,0x81,0x58, 0x8c,0x60,0x3d, 0x79,0x4b,0x2b, 0x89,0x58,0x31, 0x89,0x58,0x31, 0x7f,0x50,0x2f, 0x9e,0x64,0x39, 0x75,0x4c,0x2a, 0x51,0x35,0x21, 0x84,0x54,0x33, 0x54,0x36,0x1d, 0x98,0x6d,0x4e, 0xb4,0x7f,0x5c, 0xba,0x83,0x5b, 0xb8,0x7a,0x4f, 0x00,0x00,0x00, 0x3e,0x28,0x36, 0x08,0x13,0x30, 0x00,0x0f,0x32, 0x08,0x13,0x30, 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x08,0x13,0x30, 0x20,0x1f,0x36, 0x35,0x19,0x12, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xc2,0x8a,0x61, 0x89,0x60,0x42, 0x84,0x54,0x33, 0x7f,0x50,0x2f, 0x86,0x56,0x35, 0x8d,0x5b,0x35, 0x75,0x4c,0x2a, 0x8d,0x5b,0x35, 0x5c,0x38,0x22, 0x5e,0x3f,0x27, 0x75,0x4d,0x30, 0x9d,0x64,0x3f, 0x75,0x4c,0x2a, 0x78,0x50,0x2d, 0x7f,0x50,0x2f, 0xb7,0x81,0x58, 0x00,0x00,0x00, 0x46,0x35,0x42, 0x04,0x18,0x3a, 0x08,0x13,0x30, 0x5d,0x30,0x28, 0x20,0x1f,0x36, 0x08,0x13,0x30, 0x08,0x13,0x30, 0x04,0x18,0x3a, 0x19,0x1c,0x37, 0x3a,0x1d,0x16, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x91,0x5f,0x3e, 0x84,0x54,0x33, 0x89,0x58,0x31, 0x7e,0x6e,0x64, 0xc4,0x94,0x6e, 0x78,0x50,0x2d, 0x92,0x6f,0x59, 0xa1,0x7c,0x60, 0x9c,0x6f,0x4b, 0x8d,0x5b,0x35, 0xbc,0x7f,0x53, 0xad,0x71,0x45, 0x75,0x4d,0x30, 0x51,0x35,0x21, 0x4b,0x2f,0x1c, 0x70,0x49,0x2c, 0x00,0x00,0x00, 0x59,0x44,0x4d, 0x1e,0x28,0x42, 0x1e,0x28,0x42, 0x48,0x19,0x10, 0x42,0x19,0x12, 0x53,0x2b,0x30, 0x0c,0x26,0x48, 0x1e,0x28,0x42, 0x24,0x2d,0x48, 0x5f,0x2c,0x1d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x89,0x58,0x31, 0xa1,0x84,0x6c, 0xc4,0x94,0x6e, 0x88,0x64,0x44, 0xb5,0x8f,0x73, 0x9e,0x72,0x53, 0xa1,0x6d,0x45, 0x93,0x60,0x3a, 0xad,0x71,0x45, 0xb4,0x7f,0x5c, 0xbd,0x8d,0x67, 0xc2,0x8a,0x61, 0xb3,0x76,0x4b, 0xb8,0x7a,0x4f, 0x88,0x64,0x44, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x61,0x50,0x52, 0x1c,0x34,0x52, 0x1c,0x34,0x52, 0x54,0x27,0x16, 0x29,0x17,0x09, 0x5d,0x30,0x28, 0x1c,0x34,0x52, 0x1c,0x34,0x52, 0x24,0x35,0x4f, 0x69,0x34,0x24, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa7,0x83,0x6d, 0xac,0x86,0x6a, 0x74,0x47,0x2d, 0x84,0x54,0x33, 0x5c,0x38,0x22, 0x54,0x36,0x1d, 0x6c,0x45,0x29, 0x96,0x63,0x3c, 0xa3,0x6e,0x41, 0xb3,0x76,0x4b, 0xb3,0x76,0x4b, 0xa2,0x68,0x3d, 0x7c,0x4e,0x2d, 0x63,0x3e,0x27, 0x96,0x63,0x3c, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x6b,0x5d,0x59, 0x22,0x42,0x5f, 0x22,0x42,0x5f, 0x5d,0x34,0x1a, 0x38,0x23,0x0f, 0x5c,0x38,0x22, 0x22,0x42,0x5f, 0x22,0x42,0x5f, 0x2c,0x45,0x5e, 0x6f,0x3e,0x2b, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb7,0x81,0x58, 0x98,0x74,0x59, 0x6c,0x45,0x29, 0x4b,0x35,0x25, 0x78,0x50,0x2d, 0x78,0x50,0x2d, 0x78,0x50,0x2d, 0x7f,0x50,0x2f, 0x84,0x54,0x33, 0x8d,0x5b,0x35, 0x96,0x63,0x3c, 0x74,0x47,0x2d, 0x65,0x45,0x26, 0x65,0x45,0x26, 0x7c,0x4e,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x69,0x64, 0x30,0x4e,0x6d, 0x32,0x52,0x6b, 0x69,0x42,0x26, 0x49,0x31,0x11, 0x6c,0x47,0x2f, 0x27,0x4f,0x6d, 0x27,0x4f,0x6d, 0x32,0x52,0x6b, 0x70,0x49,0x2c, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb7,0x81,0x58, 0x8a,0x5a,0x39, 0x8a,0x5a,0x39, 0x91,0x5f,0x3e, 0x5e,0x3f,0x27, 0x5c,0x38,0x22, 0x89,0x58,0x31, 0x89,0x58,0x31, 0x95,0x5d,0x38, 0x9d,0x64,0x3f, 0x65,0x45,0x26, 0x4b,0x2f,0x1c, 0x7f,0x50,0x2f, 0x78,0x50,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x69,0x64, 0x36,0x5c,0x7a, 0x3e,0x5e,0x78, 0x76,0x52,0x2e, 0x5d,0x42,0x22, 0x75,0x4d,0x30, 0x36,0x5c,0x7a, 0x36,0x5c,0x7a, 0x3e,0x5e,0x78, 0x74,0x47,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x89,0x58,0x31, 0x63,0x3e,0x27, 0xa8,0x6d,0x42, 0x4b,0x2f,0x1c, 0x65,0x45,0x26, 0x70,0x49,0x2c, 0x51,0x35,0x21, 0x78,0x50,0x2d, 0x42,0x30,0x14, 0x49,0x31,0x11, 0x59,0x44,0x22, 0x7c,0x5c,0x2a, 0x8a,0x71,0x27, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x71,0x67,0x5c, 0x37,0x52,0x66, 0x3f,0x55,0x64, 0x80,0x55,0x27, 0x64,0x4c,0x1f, 0x7e,0x59,0x2e, 0x37,0x52,0x66, 0x37,0x52,0x66, 0x3f,0x55,0x64, 0x6c,0x47,0x2f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x70,0x49,0x2c, 0x65,0x45,0x26, 0x65,0x45,0x26, 0x63,0x3e,0x27, 0x76,0x4d,0x25, 0x5d,0x42,0x22, 0x5e,0x3f,0x27, 0x4e,0x43,0x18, 0x4e,0x43,0x18, 0x6a,0x5b,0x1c, 0x4e,0x43,0x18, 0x5f,0x51,0x19, 0x8a,0x76,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x63,0x38,0x19, 0x34,0x11,0x04, 0x32,0x0f,0x00, 0x86,0x58,0x1e, 0x74,0x59,0x25, 0x86,0x58,0x1e, 0x34,0x15,0x00, 0x32,0x0f,0x00, 0x34,0x15,0x00, 0x4e,0x31,0x18, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x7e,0x6c,0x27, 0x5a,0x4d,0x1c, 0x4d,0x3e,0x15, 0x67,0x58,0x21, 0x5a,0x4d,0x1c, 0x57,0x4b,0x1a, 0x5f,0x51,0x19, 0x64,0x55,0x1e, 0x5a,0x4d,0x1c, 0x8a,0x71,0x27, 0x8e,0x79,0x26, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x63,0x38,0x19, 0x34,0x11,0x04, 0x32,0x0f,0x00, 0x8d,0x63,0x1f, 0x83,0x66,0x2c, 0x8d,0x63,0x1f, 0x32,0x0f,0x00, 0x35,0x19,0x12, 0x34,0x11,0x04, 0x53,0x3a,0x20, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x76,0x65,0x20, 0x6a,0x5b,0x1c, 0x6a,0x5b,0x1c, 0x67,0x58,0x21, 0x4e,0x43,0x18, 0x4e,0x43,0x18, 0x9b,0x85,0x32, 0xb8,0x9e,0x3c, 0xb1,0x8d,0x36, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x63,0x38,0x19, 0x34,0x15,0x00, 0x32,0x0f,0x00, 0x8d,0x63,0x1f, 0x83,0x66,0x2c, 0x8d,0x63,0x1f, 0x32,0x0f,0x00, 0x32,0x0f,0x00, 0x34,0x15,0x00, 0x53,0x3a,0x20, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb0,0x96,0x34, 0x76,0x65,0x20, 0x7e,0x66,0x23, 0x8e,0x79,0x26, 0x8a,0x71,0x27, 0x7e,0x6c,0x27, 0x8a,0x71,0x27, 0x8a,0x71,0x27, 0xb0,0x96,0x34, 0x98,0x82,0x2f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x75,0x4c,0x2a, 0x38,0x19,0x05, 0x38,0x19,0x05, 0x99,0x6d,0x22, 0x96,0x70,0x2a, 0x99,0x6d,0x22, 0x38,0x19,0x05, 0x38,0x19,0x05, 0x38,0x19,0x05, 0x59,0x3f,0x25, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x8a,0x76,0x2a, 0x7e,0x66,0x23, 0x76,0x65,0x20, 0x93,0x7d,0x2a, 0x82,0x6f,0x23, 0x9f,0x88,0x35, 0xb8,0xa0,0x4c, 0xb8,0xa0,0x4c, 0xc4,0xa8,0x3f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x7c,0x5c,0x2a, 0x52,0x2e,0x0d, 0x52,0x2e,0x0d, 0xa4,0x7b,0x27, 0xa1,0x80,0x37, 0x9f,0x77,0x1a, 0x52,0x2e,0x0d, 0x52,0x2e,0x0d, 0x52,0x2e,0x0d, 0x5f,0x4e,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x86,0x72,0x26, 0xac,0x93,0x39, 0x97,0x82,0x36, 0xb1,0x8d,0x36, 0xac,0x93,0x39, 0x97,0x82,0x36, 0xa4,0x8c,0x32, 0xbd,0xa2,0x41, 0x8a,0x71,0x27, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x8b,0x6d,0x32, 0x66,0x44,0x14, 0x6d,0x4a,0x20, 0xab,0x86,0x29, 0xb1,0x8d,0x36, 0xa4,0x7b,0x27, 0x66,0x44,0x14, 0x66,0x44,0x14, 0x66,0x44,0x14, 0x69,0x56,0x2c, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x31, 0x7e,0x6c,0x27, 0x9f,0x88,0x35, 0x97,0x82,0x36, 0x7e,0x66,0x23, 0x7e,0x66,0x23, 0xb2,0x99,0x3f, 0xbd,0xa2,0x41, 0x8a,0x76,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x99,0x7a,0x38, 0x86,0x58,0x1e, 0x7f,0x59,0x22, 0xb2,0x8b,0x1c, 0x94,0x6e,0x21, 0x7f,0x59,0x22, 0x7f,0x59,0x22, 0x7f,0x59,0x22, 0x7f,0x59,0x22, 0x69,0x56,0x2c, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x8a,0x71,0x27, 0xb4,0x9c,0x48, 0x7e,0x66,0x23, 0xac,0x93,0x39, 0x9c,0x87,0x3a, 0x9c,0x87,0x3a, 0xbd,0xa2,0x41, 0x8e,0x79,0x26, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa8,0x86,0x3d, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0xa1,0x80,0x37, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb4,0x9c,0x48, 0xac,0x93,0x31, 0x93,0x7d,0x2a, 0xbd,0xa3,0x48, 0x93,0x7d,0x2a, 0xb8,0xa0,0x4c, 0xb4,0x9c,0x48, 0xcc,0xa5,0x4e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa8,0x86,0x3d, 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x97,0x82,0x36, 0xb4,0x9c,0x48, 0xb2,0x99,0x3f, 0xb4,0x9c,0x48, 0xb0,0x96,0x34, 0xc1,0xa7,0x4c, 0x9b,0x84,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xbd,0x9e,0x4c, 0xc7,0x9a,0x3f, 0xc7,0x9a,0x3f, 0xc7,0x9a,0x3f, 0xc7,0x9a,0x3f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9b,0x85,0x32, 0xa7,0x8e,0x2c, 0xac,0x93,0x39, 0xb5,0x91,0x41, 0x76,0x65,0x20, 0xa7,0x8e,0x2c, 0xb4,0x9a,0x38, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xcc,0xa5,0x4e, 0xe0,0xaf,0x45, 0xe0,0xaf,0x45, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa4,0x8c,0x32, 0xb8,0x9e,0x44, 0x86,0x72,0x26, 0x9f,0x88,0x35, 0xbd,0xa3,0x48, 0x9b,0x85,0x32, 0xa3,0x81,0x32, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xd1,0xae,0x4e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb0,0x97,0x3c, 0xb4,0x9a,0x38, 0xac,0x94,0x41, 0xb2,0x99,0x3f, 0xb4,0x9a,0x38, 0xb8,0x9e,0x3c, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xcc,0xa5,0x4e, 0xa6,0x8f,0x3c, 0xb2,0x99,0x3f, 0xb4,0x9c,0x48, 0xa8,0x90,0x36, 0x9f,0x88,0x35, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, }; chocolate-doom-chocolate-doom-2.2.1/src/m_argv.c000066400000000000000000000120651257432200600215170ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // #include #include #include #include #include "doomtype.h" #include "i_system.h" #include "m_misc.h" #include "m_argv.h" // haleyjd 20110212: warning fix int myargc; char** myargv; // // M_CheckParm // Checks for the given parameter // in the program's command line arguments. // Returns the argument number (1 to argc-1) // or 0 if not present // int M_CheckParmWithArgs(char *check, int num_args) { int i; for (i = 1; i < myargc - num_args; i++) { if (!strcasecmp(check, myargv[i])) return i; } return 0; } // // M_ParmExists // // Returns true if the given parameter exists in the program's command // line arguments, false if not. // boolean M_ParmExists(char *check) { return M_CheckParm(check) != 0; } int M_CheckParm(char *check) { return M_CheckParmWithArgs(check, 0); } #define MAXARGVS 100 static void LoadResponseFile(int argv_index) { FILE *handle; int size; char *infile; char *file; char *response_filename; char **newargv; int newargc; int i, k; response_filename = myargv[argv_index] + 1; // Read the response file into memory handle = fopen(response_filename, "rb"); if (handle == NULL) { printf ("\nNo such response file!"); exit(1); } printf("Found response file %s!\n", response_filename); size = M_FileLength(handle); // Read in the entire file // Allocate one byte extra - this is in case there is an argument // at the end of the response file, in which case a '\0' will be // needed. file = malloc(size + 1); i = 0; while (i < size) { k = fread(file + i, 1, size - i, handle); if (k < 0) { I_Error("Failed to read full contents of '%s'", response_filename); } i += k; } fclose(handle); // Create new arguments list array newargv = malloc(sizeof(char *) * MAXARGVS); newargc = 0; memset(newargv, 0, sizeof(char *) * MAXARGVS); // Copy all the arguments in the list up to the response file for (i=0; i= size) { break; } // If the next argument is enclosed in quote marks, treat // the contents as a single argument. This allows long filenames // to be specified. if (infile[k] == '\"') { // Skip the first character(") ++k; newargv[newargc++] = &infile[k]; // Read all characters between quotes while (k < size && infile[k] != '\"' && infile[k] != '\n') { ++k; } if (k >= size || infile[k] == '\n') { I_Error("Quotes unclosed in response file '%s'", response_filename); } // Cut off the string at the closing quote infile[k] = '\0'; ++k; } else { // Read in the next argument until a space is reached newargv[newargc++] = &infile[k]; while(k < size && !isspace(infile[k])) { ++k; } // Cut off the end of the argument at the first space infile[k] = '\0'; ++k; } } // Add arguments following the response file argument for (i=argv_index + 1; ibox[BOXRIGHT]) box[BOXRIGHT] = x; if (ybox[BOXTOP]) box[BOXTOP] = y; } chocolate-doom-chocolate-doom-2.2.1/src/m_bbox.h000066400000000000000000000017011257432200600215120ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Nil. // #ifndef __M_BBOX__ #define __M_BBOX__ #include #include "m_fixed.h" // Bounding box coordinate storage. enum { BOXTOP, BOXBOTTOM, BOXLEFT, BOXRIGHT }; // bbox coordinates // Bounding box functions. void M_ClearBox (fixed_t* box); void M_AddToBox ( fixed_t* box, fixed_t x, fixed_t y ); #endif chocolate-doom-chocolate-doom-2.2.1/src/m_cheat.c000066400000000000000000000041731257432200600216450ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Cheat sequence checking. // #include #include "doomtype.h" #include "m_cheat.h" // // CHEAT SEQUENCE PACKAGE // // // Called in st_stuff module, which handles the input. // Returns a 1 if the cheat was successful, 0 if failed. // int cht_CheckCheat ( cheatseq_t* cht, char key ) { // if we make a short sequence on a cheat with parameters, this // will not work in vanilla doom. behave the same. if (cht->parameter_chars > 0 && strlen(cht->sequence) < cht->sequence_len) return false; if (cht->chars_read < strlen(cht->sequence)) { // still reading characters from the cheat code // and verifying. reset back to the beginning // if a key is wrong if (key == cht->sequence[cht->chars_read]) ++cht->chars_read; else cht->chars_read = 0; cht->param_chars_read = 0; } else if (cht->param_chars_read < cht->parameter_chars) { // we have passed the end of the cheat sequence and are // entering parameters now cht->parameter_buf[cht->param_chars_read] = key; ++cht->param_chars_read; } if (cht->chars_read >= strlen(cht->sequence) && cht->param_chars_read >= cht->parameter_chars) { cht->chars_read = cht->param_chars_read = 0; return true; } // cheat not matched yet return false; } void cht_GetParam ( cheatseq_t* cht, char* buffer ) { memcpy(buffer, cht->parameter_buf, cht->parameter_chars); } chocolate-doom-chocolate-doom-2.2.1/src/m_cheat.h000066400000000000000000000023751257432200600216540ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Cheat code checking. // #ifndef __M_CHEAT__ #define __M_CHEAT__ // // CHEAT SEQUENCE PACKAGE // // declaring a cheat #define CHEAT(value, parameters) \ { value, sizeof(value) - 1, parameters, 0, 0, "" } #define MAX_CHEAT_LEN 25 #define MAX_CHEAT_PARAMS 5 typedef struct { // settings for this cheat char sequence[MAX_CHEAT_LEN]; size_t sequence_len; int parameter_chars; // state used during the game size_t chars_read; int param_chars_read; char parameter_buf[MAX_CHEAT_PARAMS]; } cheatseq_t; int cht_CheckCheat ( cheatseq_t* cht, char key ); void cht_GetParam ( cheatseq_t* cht, char* buffer ); #endif chocolate-doom-chocolate-doom-2.2.1/src/m_config.c000066400000000000000000001354561257432200600220370ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Configuration file interface. // #include #include #include #include #include #include #include "config.h" #include "doomtype.h" #include "doomkeys.h" #include "doomfeatures.h" #include "i_system.h" #include "m_argv.h" #include "m_misc.h" #include "z_zone.h" // // DEFAULTS // // Location where all configuration data is stored - // default.cfg, savegames, etc. char *configdir; // Default filenames for configuration files. static char *default_main_config; static char *default_extra_config; typedef enum { DEFAULT_INT, DEFAULT_INT_HEX, DEFAULT_STRING, DEFAULT_FLOAT, DEFAULT_KEY, } default_type_t; typedef struct { // Name of the variable char *name; // Pointer to the location in memory of the variable union { int *i; char **s; float *f; } location; // Type of the variable default_type_t type; // If this is a key value, the original integer scancode we read from // the config file before translating it to the internal key value. // If zero, we didn't read this value from a config file. int untranslated; // The value we translated the scancode into when we read the // config file on startup. If the variable value is different from // this, it has been changed and needs to be converted; otherwise, // use the 'untranslated' value. int original_translated; // If true, this config variable has been bound to a variable // and is being used. boolean bound; } default_t; typedef struct { default_t *defaults; int numdefaults; char *filename; } default_collection_t; #define CONFIG_VARIABLE_GENERIC(name, type) \ { #name, {NULL}, type, 0, 0, false } #define CONFIG_VARIABLE_KEY(name) \ CONFIG_VARIABLE_GENERIC(name, DEFAULT_KEY) #define CONFIG_VARIABLE_INT(name) \ CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT) #define CONFIG_VARIABLE_INT_HEX(name) \ CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT_HEX) #define CONFIG_VARIABLE_FLOAT(name) \ CONFIG_VARIABLE_GENERIC(name, DEFAULT_FLOAT) #define CONFIG_VARIABLE_STRING(name) \ CONFIG_VARIABLE_GENERIC(name, DEFAULT_STRING) //! @begin_config_file default static default_t doom_defaults_list[] = { //! // Mouse sensitivity. This value is used to multiply input mouse // movement to control the effect of moving the mouse. // // The "normal" maximum value available for this through the // in-game options menu is 9. A value of 31 or greater will cause // the game to crash when entering the options menu. // CONFIG_VARIABLE_INT(mouse_sensitivity), //! // Volume of sound effects, range 0-15. // CONFIG_VARIABLE_INT(sfx_volume), //! // Volume of in-game music, range 0-15. // CONFIG_VARIABLE_INT(music_volume), //! // @game strife // // If non-zero, dialogue text is displayed over characters' pictures // when engaging actors who have voices. // CONFIG_VARIABLE_INT(show_talk), //! // @game strife // // Volume of voice sound effects, range 0-15. // CONFIG_VARIABLE_INT(voice_volume), //! // @game doom // // If non-zero, messages are displayed on the heads-up display // in the game ("picked up a clip", etc). If zero, these messages // are not displayed. // CONFIG_VARIABLE_INT(show_messages), //! // Keyboard key to turn right. // CONFIG_VARIABLE_KEY(key_right), //! // Keyboard key to turn left. // CONFIG_VARIABLE_KEY(key_left), //! // Keyboard key to move forward. // CONFIG_VARIABLE_KEY(key_up), //! // Keyboard key to move backward. // CONFIG_VARIABLE_KEY(key_down), //! // Keyboard key to strafe left. // CONFIG_VARIABLE_KEY(key_strafeleft), //! // Keyboard key to strafe right. // CONFIG_VARIABLE_KEY(key_straferight), //! // @game strife // // Keyboard key to use health. // CONFIG_VARIABLE_KEY(key_useHealth), //! // @game hexen // // Keyboard key to jump. // CONFIG_VARIABLE_KEY(key_jump), //! // @game heretic hexen // // Keyboard key to fly upward. // CONFIG_VARIABLE_KEY(key_flyup), //! // @game heretic hexen // // Keyboard key to fly downwards. // CONFIG_VARIABLE_KEY(key_flydown), //! // @game heretic hexen // // Keyboard key to center flying. // CONFIG_VARIABLE_KEY(key_flycenter), //! // @game heretic hexen // // Keyboard key to look up. // CONFIG_VARIABLE_KEY(key_lookup), //! // @game heretic hexen // // Keyboard key to look down. // CONFIG_VARIABLE_KEY(key_lookdown), //! // @game heretic hexen // // Keyboard key to center the view. // CONFIG_VARIABLE_KEY(key_lookcenter), //! // @game strife // // Keyboard key to query inventory. // CONFIG_VARIABLE_KEY(key_invquery), //! // @game strife // // Keyboard key to display mission objective. // CONFIG_VARIABLE_KEY(key_mission), //! // @game strife // // Keyboard key to display inventory popup. // CONFIG_VARIABLE_KEY(key_invPop), //! // @game strife // // Keyboard key to display keys popup. // CONFIG_VARIABLE_KEY(key_invKey), //! // @game strife // // Keyboard key to jump to start of inventory. // CONFIG_VARIABLE_KEY(key_invHome), //! // @game strife // // Keyboard key to jump to end of inventory. // CONFIG_VARIABLE_KEY(key_invEnd), //! // @game heretic hexen // // Keyboard key to scroll left in the inventory. // CONFIG_VARIABLE_KEY(key_invleft), //! // @game heretic hexen // // Keyboard key to scroll right in the inventory. // CONFIG_VARIABLE_KEY(key_invright), //! // @game strife // // Keyboard key to scroll left in the inventory. // CONFIG_VARIABLE_KEY(key_invLeft), //! // @game strife // // Keyboard key to scroll right in the inventory. // CONFIG_VARIABLE_KEY(key_invRight), //! // @game heretic hexen // // Keyboard key to use the current item in the inventory. // CONFIG_VARIABLE_KEY(key_useartifact), //! // @game strife // // Keyboard key to use inventory item. // CONFIG_VARIABLE_KEY(key_invUse), //! // @game strife // // Keyboard key to drop an inventory item. // CONFIG_VARIABLE_KEY(key_invDrop), //! // @game strife // // Keyboard key to look up. // CONFIG_VARIABLE_KEY(key_lookUp), //! // @game strife // // Keyboard key to look down. // CONFIG_VARIABLE_KEY(key_lookDown), //! // Keyboard key to fire the currently selected weapon. // CONFIG_VARIABLE_KEY(key_fire), //! // Keyboard key to "use" an object, eg. a door or switch. // CONFIG_VARIABLE_KEY(key_use), //! // Keyboard key to turn on strafing. When held down, pressing the // key to turn left or right causes the player to strafe left or // right instead. // CONFIG_VARIABLE_KEY(key_strafe), //! // Keyboard key to make the player run. // CONFIG_VARIABLE_KEY(key_speed), //! // If non-zero, mouse input is enabled. If zero, mouse input is // disabled. // CONFIG_VARIABLE_INT(use_mouse), //! // Mouse button to fire the currently selected weapon. // CONFIG_VARIABLE_INT(mouseb_fire), //! // Mouse button to turn on strafing. When held down, the player // will strafe left and right instead of turning left and right. // CONFIG_VARIABLE_INT(mouseb_strafe), //! // Mouse button to move forward. // CONFIG_VARIABLE_INT(mouseb_forward), //! // @game hexen strife // // Mouse button to jump. // CONFIG_VARIABLE_INT(mouseb_jump), //! // If non-zero, joystick input is enabled. // CONFIG_VARIABLE_INT(use_joystick), //! // Joystick virtual button that fires the current weapon. // CONFIG_VARIABLE_INT(joyb_fire), //! // Joystick virtual button that makes the player strafe while // held down. // CONFIG_VARIABLE_INT(joyb_strafe), //! // Joystick virtual button to "use" an object, eg. a door or switch. // CONFIG_VARIABLE_INT(joyb_use), //! // Joystick virtual button that makes the player run while held // down. // // If this has a value of 20 or greater, the player will always run, // even if use_joystick is 0. // CONFIG_VARIABLE_INT(joyb_speed), //! // @game hexen strife // // Joystick virtual button that makes the player jump. // CONFIG_VARIABLE_INT(joyb_jump), //! // @game doom heretic hexen // // Screen size, range 3-11. // // A value of 11 gives a full-screen view with the status bar not // displayed. A value of 10 gives a full-screen view with the // status bar displayed. // CONFIG_VARIABLE_INT(screenblocks), //! // @game strife // // Screen size, range 3-11. // // A value of 11 gives a full-screen view with the status bar not // displayed. A value of 10 gives a full-screen view with the // status bar displayed. // CONFIG_VARIABLE_INT(screensize), //! // @game doom // // Screen detail. Zero gives normal "high detail" mode, while // a non-zero value gives "low detail" mode. // CONFIG_VARIABLE_INT(detaillevel), //! // Number of sounds that will be played simultaneously. // CONFIG_VARIABLE_INT(snd_channels), //! // Music output device. A non-zero value gives MIDI sound output, // while a value of zero disables music. // CONFIG_VARIABLE_INT(snd_musicdevice), //! // Sound effects device. A value of zero disables in-game sound // effects, a value of 1 enables PC speaker sound effects, while // a value in the range 2-9 enables the "normal" digital sound // effects. // CONFIG_VARIABLE_INT(snd_sfxdevice), //! // SoundBlaster I/O port. Unused. // CONFIG_VARIABLE_INT(snd_sbport), //! // SoundBlaster IRQ. Unused. // CONFIG_VARIABLE_INT(snd_sbirq), //! // SoundBlaster DMA channel. Unused. // CONFIG_VARIABLE_INT(snd_sbdma), //! // Output port to use for OPL MIDI playback. Unused. // CONFIG_VARIABLE_INT(snd_mport), //! // Gamma correction level. A value of zero disables gamma // correction, while a value in the range 1-4 gives increasing // levels of gamma correction. // CONFIG_VARIABLE_INT(usegamma), //! // @game hexen // // Directory in which to store savegames. // CONFIG_VARIABLE_STRING(savedir), //! // @game hexen // // Controls whether messages are displayed in the heads-up display. // If this has a non-zero value, messages are displayed. // CONFIG_VARIABLE_INT(messageson), //! // @game strife // // Name of background flat used by view border. // CONFIG_VARIABLE_STRING(back_flat), //! // @game strife // // Multiplayer nickname (?). // CONFIG_VARIABLE_STRING(nickname), //! // Multiplayer chat macro: message to send when alt+0 is pressed. // CONFIG_VARIABLE_STRING(chatmacro0), //! // Multiplayer chat macro: message to send when alt+1 is pressed. // CONFIG_VARIABLE_STRING(chatmacro1), //! // Multiplayer chat macro: message to send when alt+2 is pressed. // CONFIG_VARIABLE_STRING(chatmacro2), //! // Multiplayer chat macro: message to send when alt+3 is pressed. // CONFIG_VARIABLE_STRING(chatmacro3), //! // Multiplayer chat macro: message to send when alt+4 is pressed. // CONFIG_VARIABLE_STRING(chatmacro4), //! // Multiplayer chat macro: message to send when alt+5 is pressed. // CONFIG_VARIABLE_STRING(chatmacro5), //! // Multiplayer chat macro: message to send when alt+6 is pressed. // CONFIG_VARIABLE_STRING(chatmacro6), //! // Multiplayer chat macro: message to send when alt+7 is pressed. // CONFIG_VARIABLE_STRING(chatmacro7), //! // Multiplayer chat macro: message to send when alt+8 is pressed. // CONFIG_VARIABLE_STRING(chatmacro8), //! // Multiplayer chat macro: message to send when alt+9 is pressed. // CONFIG_VARIABLE_STRING(chatmacro9), //! // @game strife // // Serial port number to use for SERSETUP.EXE (unused). // CONFIG_VARIABLE_INT(comport), }; static default_collection_t doom_defaults = { doom_defaults_list, arrlen(doom_defaults_list), NULL, }; //! @begin_config_file extended static default_t extra_defaults_list[] = { //! // @game heretic hexen strife // // If non-zero, display the graphical startup screen. // CONFIG_VARIABLE_INT(graphical_startup), //! // If non-zero, video settings will be autoadjusted to a valid // configuration when the screen_width and screen_height variables // do not match any valid configuration. // CONFIG_VARIABLE_INT(autoadjust_video_settings), //! // If non-zero, the game will run in full screen mode. If zero, // the game will run in a window. // CONFIG_VARIABLE_INT(fullscreen), //! // If non-zero, the screen will be stretched vertically to display // correctly on a square pixel video mode. // CONFIG_VARIABLE_INT(aspect_ratio_correct), //! // Number of milliseconds to wait on startup after the video mode // has been set, before the game will start. This allows the // screen to settle on some monitors that do not display an image // for a brief interval after changing video modes. // CONFIG_VARIABLE_INT(startup_delay), //! // Screen width in pixels. If running in full screen mode, this is // the X dimension of the video mode to use. If running in // windowed mode, this is the width of the window in which the game // will run. // CONFIG_VARIABLE_INT(screen_width), //! // Screen height in pixels. If running in full screen mode, this is // the Y dimension of the video mode to use. If running in // windowed mode, this is the height of the window in which the game // will run. // CONFIG_VARIABLE_INT(screen_height), //! // Color depth of the screen, in bits. // If this is set to zero, the color depth will be automatically set // on startup to the machine's default/native color depth. // CONFIG_VARIABLE_INT(screen_bpp), //! // If this is non-zero, the mouse will be "grabbed" when running // in windowed mode so that it can be used as an input device. // When running full screen, this has no effect. // CONFIG_VARIABLE_INT(grabmouse), //! // If non-zero, all vertical mouse movement is ignored. This // emulates the behavior of the "novert" tool available under DOS // that performs the same function. // CONFIG_VARIABLE_INT(novert), //! // Mouse acceleration factor. When the speed of mouse movement // exceeds the threshold value (mouse_threshold), the speed is // multiplied by this value. // CONFIG_VARIABLE_FLOAT(mouse_acceleration), //! // Mouse acceleration threshold. When the speed of mouse movement // exceeds this threshold value, the speed is multiplied by an // acceleration factor (mouse_acceleration). // CONFIG_VARIABLE_INT(mouse_threshold), //! // Sound output sample rate, in Hz. Typical values to use are // 11025, 22050, 44100 and 48000. // CONFIG_VARIABLE_INT(snd_samplerate), //! // Maximum number of bytes to allocate for caching converted sound // effects in memory. If set to zero, there is no limit applied. // CONFIG_VARIABLE_INT(snd_cachesize), //! // Maximum size of the output sound buffer size in milliseconds. // Sound output is generated periodically in slices. Higher values // might be more efficient but will introduce latency to the // sound output. The default is 28ms (one slice per tic with the // 35fps timer). CONFIG_VARIABLE_INT(snd_maxslicetime_ms), //! // External command to invoke to perform MIDI playback. If set to // the empty string, SDL_mixer's internal MIDI playback is used. // This only has any effect when snd_musicdevice is set to General // MIDI output. CONFIG_VARIABLE_STRING(snd_musiccmd), //! // Value to set for the DMXOPTION environment variable. If this contains // "-opl3", output for an OPL3 chip is generated when in OPL MIDI // playback mode. // CONFIG_VARIABLE_STRING(snd_dmxoption), //! // The I/O port to use to access the OPL chip. Only relevant when // using native OPL music playback. // CONFIG_VARIABLE_INT_HEX(opl_io_port), //! // @game doom heretic strife // // If non-zero, the ENDOOM text screen is displayed when exiting the // game. If zero, the ENDOOM screen is not displayed. // CONFIG_VARIABLE_INT(show_endoom), //! // If non-zero, save screenshots in PNG format. // CONFIG_VARIABLE_INT(png_screenshots), //! // @game doom strife // // If non-zero, the Vanilla savegame limit is enforced; if the // savegame exceeds 180224 bytes in size, the game will exit with // an error. If this has a value of zero, there is no limit to // the size of savegames. // CONFIG_VARIABLE_INT(vanilla_savegame_limit), //! // @game doom strife // // If non-zero, the Vanilla demo size limit is enforced; the game // exits with an error when a demo exceeds the demo size limit // (128KiB by default). If this has a value of zero, there is no // limit to the size of demos. // CONFIG_VARIABLE_INT(vanilla_demo_limit), //! // If non-zero, the game behaves like Vanilla Doom, always assuming // an American keyboard mapping. If this has a value of zero, the // native keyboard mapping of the keyboard is used. // CONFIG_VARIABLE_INT(vanilla_keyboard_mapping), //! // Name of the SDL video driver to use. If this is an empty string, // the default video driver is used. // CONFIG_VARIABLE_STRING(video_driver), //! // Position of the window on the screen when running in windowed // mode. Accepted values are: "" (empty string) - don't care, // "center" - place window at center of screen, "x,y" - place // window at the specified coordinates. CONFIG_VARIABLE_STRING(window_position), #ifdef FEATURE_MULTIPLAYER //! // Name to use in network games for identification. This is only // used on the "waiting" screen while waiting for the game to start. // CONFIG_VARIABLE_STRING(player_name), #endif //! // Joystick number to use; '0' is the first joystick. A negative // value ('-1') indicates that no joystick is configured. // CONFIG_VARIABLE_INT(joystick_index), //! // Joystick axis to use to for horizontal (X) movement. // CONFIG_VARIABLE_INT(joystick_x_axis), //! // If non-zero, movement on the horizontal joystick axis is inverted. // CONFIG_VARIABLE_INT(joystick_x_invert), //! // Joystick axis to use to for vertical (Y) movement. // CONFIG_VARIABLE_INT(joystick_y_axis), //! // If non-zero, movement on the vertical joystick axis is inverted. // CONFIG_VARIABLE_INT(joystick_y_invert), //! // Joystick axis to use to for strafing movement. // CONFIG_VARIABLE_INT(joystick_strafe_axis), //! // If non-zero, movement on the joystick axis used for strafing // is inverted. // CONFIG_VARIABLE_INT(joystick_strafe_invert), //! // The physical joystick button that corresponds to joystick // virtual button #0. // CONFIG_VARIABLE_INT(joystick_physical_button0), //! // The physical joystick button that corresponds to joystick // virtual button #1. // CONFIG_VARIABLE_INT(joystick_physical_button1), //! // The physical joystick button that corresponds to joystick // virtual button #2. // CONFIG_VARIABLE_INT(joystick_physical_button2), //! // The physical joystick button that corresponds to joystick // virtual button #3. // CONFIG_VARIABLE_INT(joystick_physical_button3), //! // The physical joystick button that corresponds to joystick // virtual button #4. // CONFIG_VARIABLE_INT(joystick_physical_button4), //! // The physical joystick button that corresponds to joystick // virtual button #5. // CONFIG_VARIABLE_INT(joystick_physical_button5), //! // The physical joystick button that corresponds to joystick // virtual button #6. // CONFIG_VARIABLE_INT(joystick_physical_button6), //! // The physical joystick button that corresponds to joystick // virtual button #7. // CONFIG_VARIABLE_INT(joystick_physical_button7), //! // The physical joystick button that corresponds to joystick // virtual button #8. // CONFIG_VARIABLE_INT(joystick_physical_button8), //! // The physical joystick button that corresponds to joystick // virtual button #9. // CONFIG_VARIABLE_INT(joystick_physical_button9), //! // Joystick virtual button to make the player strafe left. // CONFIG_VARIABLE_INT(joyb_strafeleft), //! // Joystick virtual button to make the player strafe right. // CONFIG_VARIABLE_INT(joyb_straferight), //! // Joystick virtual button to activate the menu. // CONFIG_VARIABLE_INT(joyb_menu_activate), //! // Joystick virtual button that cycles to the previous weapon. // CONFIG_VARIABLE_INT(joyb_prevweapon), //! // Joystick virtual button that cycles to the next weapon. // CONFIG_VARIABLE_INT(joyb_nextweapon), //! // Mouse button to strafe left. // CONFIG_VARIABLE_INT(mouseb_strafeleft), //! // Mouse button to strafe right. // CONFIG_VARIABLE_INT(mouseb_straferight), //! // Mouse button to "use" an object, eg. a door or switch. // CONFIG_VARIABLE_INT(mouseb_use), //! // Mouse button to move backwards. // CONFIG_VARIABLE_INT(mouseb_backward), //! // Mouse button to cycle to the previous weapon. // CONFIG_VARIABLE_INT(mouseb_prevweapon), //! // Mouse button to cycle to the next weapon. // CONFIG_VARIABLE_INT(mouseb_nextweapon), //! // If non-zero, double-clicking a mouse button acts like pressing // the "use" key to use an object in-game, eg. a door or switch. // CONFIG_VARIABLE_INT(dclick_use), #ifdef FEATURE_SOUND //! // Controls whether libsamplerate support is used for performing // sample rate conversions of sound effects. Support for this // must be compiled into the program. // // If zero, libsamplerate support is disabled. If non-zero, // libsamplerate is enabled. Increasing values roughly correspond // to higher quality conversion; the higher the quality, the // slower the conversion process. Linear conversion = 1; // Zero order hold = 2; Fast Sinc filter = 3; Medium quality // Sinc filter = 4; High quality Sinc filter = 5. // CONFIG_VARIABLE_INT(use_libsamplerate), //! // Scaling factor used by libsamplerate. This is used when converting // sounds internally back into integer form; normally it should not // be necessary to change it from the default value. The only time // it might be needed is if a PWAD file is loaded that contains very // loud sounds, in which case the conversion may cause sound clipping // and the scale factor should be reduced. The lower the value, the // quieter the sound effects become, so it should be set as high as is // possible without clipping occurring. CONFIG_VARIABLE_FLOAT(libsamplerate_scale), //! // Full path to a Timidity configuration file to use for MIDI // playback. The file will be evaluated from the directory where // it is evaluated, so there is no need to add "dir" commands // into it. // CONFIG_VARIABLE_STRING(timidity_cfg_path), //! // Path to GUS patch files to use when operating in GUS emulation // mode. // CONFIG_VARIABLE_STRING(gus_patch_path), //! // Number of kilobytes of RAM to use in GUS emulation mode. Valid // values are 256, 512, 768 or 1024. // CONFIG_VARIABLE_INT(gus_ram_kb), #endif //! // Key to pause or unpause the game. // CONFIG_VARIABLE_KEY(key_pause), //! // Key that activates the menu when pressed. // CONFIG_VARIABLE_KEY(key_menu_activate), //! // Key that moves the cursor up on the menu. // CONFIG_VARIABLE_KEY(key_menu_up), //! // Key that moves the cursor down on the menu. // CONFIG_VARIABLE_KEY(key_menu_down), //! // Key that moves the currently selected slider on the menu left. // CONFIG_VARIABLE_KEY(key_menu_left), //! // Key that moves the currently selected slider on the menu right. // CONFIG_VARIABLE_KEY(key_menu_right), //! // Key to go back to the previous menu. // CONFIG_VARIABLE_KEY(key_menu_back), //! // Key to activate the currently selected menu item. // CONFIG_VARIABLE_KEY(key_menu_forward), //! // Key to answer 'yes' to a question in the menu. // CONFIG_VARIABLE_KEY(key_menu_confirm), //! // Key to answer 'no' to a question in the menu. // CONFIG_VARIABLE_KEY(key_menu_abort), //! // Keyboard shortcut to bring up the help screen. // CONFIG_VARIABLE_KEY(key_menu_help), //! // Keyboard shortcut to bring up the save game menu. // CONFIG_VARIABLE_KEY(key_menu_save), //! // Keyboard shortcut to bring up the load game menu. // CONFIG_VARIABLE_KEY(key_menu_load), //! // Keyboard shortcut to bring up the sound volume menu. // CONFIG_VARIABLE_KEY(key_menu_volume), //! // Keyboard shortcut to toggle the detail level. // CONFIG_VARIABLE_KEY(key_menu_detail), //! // Keyboard shortcut to quicksave the current game. // CONFIG_VARIABLE_KEY(key_menu_qsave), //! // Keyboard shortcut to end the game. // CONFIG_VARIABLE_KEY(key_menu_endgame), //! // Keyboard shortcut to toggle heads-up messages. // CONFIG_VARIABLE_KEY(key_menu_messages), //! // Keyboard shortcut to load the last quicksave. // CONFIG_VARIABLE_KEY(key_menu_qload), //! // Keyboard shortcut to quit the game. // CONFIG_VARIABLE_KEY(key_menu_quit), //! // Keyboard shortcut to toggle the gamma correction level. // CONFIG_VARIABLE_KEY(key_menu_gamma), //! // Keyboard shortcut to switch view in multiplayer. // CONFIG_VARIABLE_KEY(key_spy), //! // Keyboard shortcut to increase the screen size. // CONFIG_VARIABLE_KEY(key_menu_incscreen), //! // Keyboard shortcut to decrease the screen size. // CONFIG_VARIABLE_KEY(key_menu_decscreen), //! // Keyboard shortcut to save a screenshot. // CONFIG_VARIABLE_KEY(key_menu_screenshot), //! // Key to toggle the map view. // CONFIG_VARIABLE_KEY(key_map_toggle), //! // Key to pan north when in the map view. // CONFIG_VARIABLE_KEY(key_map_north), //! // Key to pan south when in the map view. // CONFIG_VARIABLE_KEY(key_map_south), //! // Key to pan east when in the map view. // CONFIG_VARIABLE_KEY(key_map_east), //! // Key to pan west when in the map view. // CONFIG_VARIABLE_KEY(key_map_west), //! // Key to zoom in when in the map view. // CONFIG_VARIABLE_KEY(key_map_zoomin), //! // Key to zoom out when in the map view. // CONFIG_VARIABLE_KEY(key_map_zoomout), //! // Key to zoom out the maximum amount when in the map view. // CONFIG_VARIABLE_KEY(key_map_maxzoom), //! // Key to toggle follow mode when in the map view. // CONFIG_VARIABLE_KEY(key_map_follow), //! // Key to toggle the grid display when in the map view. // CONFIG_VARIABLE_KEY(key_map_grid), //! // Key to set a mark when in the map view. // CONFIG_VARIABLE_KEY(key_map_mark), //! // Key to clear all marks when in the map view. // CONFIG_VARIABLE_KEY(key_map_clearmark), //! // Key to select weapon 1. // CONFIG_VARIABLE_KEY(key_weapon1), //! // Key to select weapon 2. // CONFIG_VARIABLE_KEY(key_weapon2), //! // Key to select weapon 3. // CONFIG_VARIABLE_KEY(key_weapon3), //! // Key to select weapon 4. // CONFIG_VARIABLE_KEY(key_weapon4), //! // Key to select weapon 5. // CONFIG_VARIABLE_KEY(key_weapon5), //! // Key to select weapon 6. // CONFIG_VARIABLE_KEY(key_weapon6), //! // Key to select weapon 7. // CONFIG_VARIABLE_KEY(key_weapon7), //! // Key to select weapon 8. // CONFIG_VARIABLE_KEY(key_weapon8), //! // Key to cycle to the previous weapon. // CONFIG_VARIABLE_KEY(key_prevweapon), //! // Key to cycle to the next weapon. // CONFIG_VARIABLE_KEY(key_nextweapon), //! // @game hexen // // Key to use one of each artifact. // CONFIG_VARIABLE_KEY(key_arti_all), //! // @game hexen // // Key to use "quartz flask" artifact. // CONFIG_VARIABLE_KEY(key_arti_health), //! // @game hexen // // Key to use "flechette" artifact. // CONFIG_VARIABLE_KEY(key_arti_poisonbag), //! // @game hexen // // Key to use "disc of repulsion" artifact. // CONFIG_VARIABLE_KEY(key_arti_blastradius), //! // @game hexen // // Key to use "chaos device" artifact. // CONFIG_VARIABLE_KEY(key_arti_teleport), //! // @game hexen // // Key to use "banishment device" artifact. // CONFIG_VARIABLE_KEY(key_arti_teleportother), //! // @game hexen // // Key to use "porkalator" artifact. // CONFIG_VARIABLE_KEY(key_arti_egg), //! // @game hexen // // Key to use "icon of the defender" artifact. // CONFIG_VARIABLE_KEY(key_arti_invulnerability), //! // Key to re-display last message. // CONFIG_VARIABLE_KEY(key_message_refresh), //! // Key to quit the game when recording a demo. // CONFIG_VARIABLE_KEY(key_demo_quit), //! // Key to send a message during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msg), //! // Key to send a message to player 1 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer1), //! // Key to send a message to player 2 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer2), //! // Key to send a message to player 3 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer3), //! // Key to send a message to player 4 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer4), //! // @game hexen strife // // Key to send a message to player 5 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer5), //! // @game hexen strife // // Key to send a message to player 6 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer6), //! // @game hexen strife // // Key to send a message to player 7 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer7), //! // @game hexen strife // // Key to send a message to player 8 during multiplayer games. // CONFIG_VARIABLE_KEY(key_multi_msgplayer8), }; static default_collection_t extra_defaults = { extra_defaults_list, arrlen(extra_defaults_list), NULL, }; // Search a collection for a variable static default_t *SearchCollection(default_collection_t *collection, char *name) { int i; for (i=0; inumdefaults; ++i) { if (!strcmp(name, collection->defaults[i].name)) { return &collection->defaults[i]; } } return NULL; } // Mapping from DOS keyboard scan code to internal key code (as defined // in doomkey.h). I think I (fraggle) reused this from somewhere else // but I can't find where. Anyway, notes: // * KEY_PAUSE is wrong - it's in the KEY_NUMLOCK spot. This shouldn't // matter in terms of Vanilla compatibility because neither of // those were valid for key bindings. // * There is no proper scan code for PrintScreen (on DOS machines it // sends an interrupt). So I added a fake scan code of 126 for it. // The presence of this is important so we can bind PrintScreen as // a screenshot key. static const int scantokey[128] = { 0 , 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', KEY_BACKSPACE, 9, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13, KEY_RCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', KEY_RSHIFT,'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT,KEYP_MULTIPLY, KEY_RALT, ' ', KEY_CAPSLOCK,KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, /*KEY_NUMLOCK?*/KEY_PAUSE,KEY_SCRLCK,KEY_HOME, KEY_UPARROW,KEY_PGUP,KEY_MINUS,KEY_LEFTARROW,KEYP_5,KEY_RIGHTARROW,KEYP_PLUS,KEY_END, KEY_DOWNARROW,KEY_PGDN,KEY_INS,KEY_DEL,0, 0, 0, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PRTSCR, 0 }; static void SaveDefaultCollection(default_collection_t *collection) { default_t *defaults; int i, v; FILE *f; f = fopen (collection->filename, "w"); if (!f) return; // can't write the file, but don't complain defaults = collection->defaults; for (i=0 ; inumdefaults ; i++) { int chars_written; // Ignore unbound variables if (!defaults[i].bound) { continue; } // Print the name and line up all values at 30 characters chars_written = fprintf(f, "%s ", defaults[i].name); for (; chars_written < 30; ++chars_written) fprintf(f, " "); // Print the value switch (defaults[i].type) { case DEFAULT_KEY: // use the untranslated version if we can, to reduce // the possibility of screwing up the user's config // file v = *defaults[i].location.i; if (v == KEY_RSHIFT) { // Special case: for shift, force scan code for // right shift, as this is what Vanilla uses. // This overrides the change check below, to fix // configuration files made by old versions that // mistakenly used the scan code for left shift. v = 54; } else if (defaults[i].untranslated && v == defaults[i].original_translated) { // Has not been changed since the last time we // read the config file. v = defaults[i].untranslated; } else { // search for a reverse mapping back to a scancode // in the scantokey table int s; for (s=0; s<128; ++s) { if (scantokey[s] == v) { v = s; break; } } } fprintf(f, "%i", v); break; case DEFAULT_INT: fprintf(f, "%i", *defaults[i].location.i); break; case DEFAULT_INT_HEX: fprintf(f, "0x%x", *defaults[i].location.i); break; case DEFAULT_FLOAT: fprintf(f, "%f", *defaults[i].location.f); break; case DEFAULT_STRING: fprintf(f,"\"%s\"", *defaults[i].location.s); break; } fprintf(f, "\n"); } fclose (f); } // Parses integer values in the configuration file static int ParseIntParameter(char *strparm) { int parm; if (strparm[0] == '0' && strparm[1] == 'x') sscanf(strparm+2, "%x", &parm); else sscanf(strparm, "%i", &parm); return parm; } static void SetVariable(default_t *def, char *value) { int intparm; // parameter found switch (def->type) { case DEFAULT_STRING: *def->location.s = M_StringDuplicate(value); break; case DEFAULT_INT: case DEFAULT_INT_HEX: *def->location.i = ParseIntParameter(value); break; case DEFAULT_KEY: // translate scancodes read from config // file (save the old value in untranslated) intparm = ParseIntParameter(value); def->untranslated = intparm; if (intparm >= 0 && intparm < 128) { intparm = scantokey[intparm]; } else { intparm = 0; } def->original_translated = intparm; *def->location.i = intparm; break; case DEFAULT_FLOAT: *def->location.f = (float) atof(value); break; } } static void LoadDefaultCollection(default_collection_t *collection) { FILE *f; default_t *def; char defname[80]; char strparm[100]; // read the file in, overriding any set defaults f = fopen(collection->filename, "r"); if (f == NULL) { // File not opened, but don't complain. // It's probably just the first time they ran the game. return; } while (!feof(f)) { if (fscanf(f, "%79s %99[^\n]\n", defname, strparm) != 2) { // This line doesn't match continue; } // Find the setting in the list def = SearchCollection(collection, defname); if (def == NULL || !def->bound) { // Unknown variable? Unbound variables are also treated // as unknown. continue; } // Strip off trailing non-printable characters (\r characters // from DOS text files) while (strlen(strparm) > 0 && !isprint(strparm[strlen(strparm)-1])) { strparm[strlen(strparm)-1] = '\0'; } // Surrounded by quotes? If so, remove them. if (strlen(strparm) >= 2 && strparm[0] == '"' && strparm[strlen(strparm) - 1] == '"') { strparm[strlen(strparm) - 1] = '\0'; memmove(strparm, strparm + 1, sizeof(strparm) - 1); } SetVariable(def, strparm); } fclose (f); } // Set the default filenames to use for configuration files. void M_SetConfigFilenames(char *main_config, char *extra_config) { default_main_config = main_config; default_extra_config = extra_config; } // // M_SaveDefaults // void M_SaveDefaults (void) { SaveDefaultCollection(&doom_defaults); SaveDefaultCollection(&extra_defaults); } // // Save defaults to alternate filenames // void M_SaveDefaultsAlternate(char *main, char *extra) { char *orig_main; char *orig_extra; // Temporarily change the filenames orig_main = doom_defaults.filename; orig_extra = extra_defaults.filename; doom_defaults.filename = main; extra_defaults.filename = extra; M_SaveDefaults(); // Restore normal filenames doom_defaults.filename = orig_main; extra_defaults.filename = orig_extra; } // // M_LoadDefaults // void M_LoadDefaults (void) { int i; // check for a custom default file //! // @arg // @vanilla // // Load main configuration from the specified file, instead of the // default. // i = M_CheckParmWithArgs("-config", 1); if (i) { doom_defaults.filename = myargv[i+1]; printf (" default file: %s\n",doom_defaults.filename); } else { doom_defaults.filename = M_StringJoin(configdir, default_main_config, NULL); } printf("saving config in %s\n", doom_defaults.filename); //! // @arg // // Load additional configuration from the specified file, instead of // the default. // i = M_CheckParmWithArgs("-extraconfig", 1); if (i) { extra_defaults.filename = myargv[i+1]; printf(" extra configuration file: %s\n", extra_defaults.filename); } else { extra_defaults.filename = M_StringJoin(configdir, default_extra_config, NULL); } LoadDefaultCollection(&doom_defaults); LoadDefaultCollection(&extra_defaults); } // Get a configuration file variable by its name static default_t *GetDefaultForName(char *name) { default_t *result; // Try the main list and the extras result = SearchCollection(&doom_defaults, name); if (result == NULL) { result = SearchCollection(&extra_defaults, name); } // Not found? Internal error. if (result == NULL) { I_Error("Unknown configuration variable: '%s'", name); } return result; } // // Bind a variable to a given configuration file variable, by name. // void M_BindIntVariable(char *name, int *location) { default_t *variable; variable = GetDefaultForName(name); assert(variable->type == DEFAULT_INT || variable->type == DEFAULT_INT_HEX || variable->type == DEFAULT_KEY); variable->location.i = location; variable->bound = true; } void M_BindFloatVariable(char *name, float *location) { default_t *variable; variable = GetDefaultForName(name); assert(variable->type == DEFAULT_FLOAT); variable->location.f = location; variable->bound = true; } void M_BindStringVariable(char *name, char **location) { default_t *variable; variable = GetDefaultForName(name); assert(variable->type == DEFAULT_STRING); variable->location.s = location; variable->bound = true; } // Set the value of a particular variable; an API function for other // parts of the program to assign values to config variables by name. boolean M_SetVariable(char *name, char *value) { default_t *variable; variable = GetDefaultForName(name); if (variable == NULL || !variable->bound) { return false; } SetVariable(variable, value); return true; } // Get the value of a variable. int M_GetIntVariable(char *name) { default_t *variable; variable = GetDefaultForName(name); if (variable == NULL || !variable->bound || (variable->type != DEFAULT_INT && variable->type != DEFAULT_INT_HEX)) { return 0; } return *variable->location.i; } const char *M_GetStringVariable(char *name) { default_t *variable; variable = GetDefaultForName(name); if (variable == NULL || !variable->bound || variable->type != DEFAULT_STRING) { return NULL; } return *variable->location.s; } float M_GetFloatVariable(char *name) { default_t *variable; variable = GetDefaultForName(name); if (variable == NULL || !variable->bound || variable->type != DEFAULT_FLOAT) { return 0; } return *variable->location.f; } // Get the path to the default configuration dir to use, if NULL // is passed to M_SetConfigDir. static char *GetDefaultConfigDir(void) { #if !defined(_WIN32) || defined(_WIN32_WCE) // Configuration settings are stored in ~/.chocolate-doom/, // except on Windows, where we behave like Vanilla Doom and // save in the current directory. char *homedir; char *result; homedir = getenv("HOME"); if (homedir != NULL) { // put all configuration in a config directory off the // homedir result = M_StringJoin(homedir, DIR_SEPARATOR_S, "." PACKAGE_TARNAME, DIR_SEPARATOR_S, NULL); return result; } else #endif /* #ifndef _WIN32 */ { return M_StringDuplicate(""); } } // // SetConfigDir: // // Sets the location of the configuration directory, where configuration // files are stored - default.cfg, chocolate-doom.cfg, savegames, etc. // void M_SetConfigDir(char *dir) { // Use the directory that was passed, or find the default. if (dir != NULL) { configdir = dir; } else { configdir = GetDefaultConfigDir(); } if (strcmp(configdir, "") != 0) { printf("Using %s for configuration and saves\n", configdir); } // Make the directory if it doesn't already exist: M_MakeDirectory(configdir); } // // Calculate the path to the directory to use to store save games. // Creates the directory as necessary. // char *M_GetSaveGameDir(char *iwadname) { char *savegamedir; char *topdir; // If not "doing" a configuration directory (Windows), don't "do" // a savegame directory, either. if (!strcmp(configdir, "")) { savegamedir = M_StringDuplicate(""); } else { // ~/.chocolate-doom/savegames topdir = M_StringJoin(configdir, "savegames", NULL); M_MakeDirectory(topdir); // eg. ~/.chocolate-doom/savegames/doom2.wad/ savegamedir = M_StringJoin(topdir, DIR_SEPARATOR_S, iwadname, DIR_SEPARATOR_S, NULL); M_MakeDirectory(savegamedir); free(topdir); } return savegamedir; } chocolate-doom-chocolate-doom-2.2.1/src/m_config.h000066400000000000000000000024611257432200600220310ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Configuration file interface. // #ifndef __M_CONFIG__ #define __M_CONFIG__ #include "doomtype.h" void M_LoadDefaults(void); void M_SaveDefaults(void); void M_SaveDefaultsAlternate(char *main, char *extra); void M_SetConfigDir(char *dir); void M_BindIntVariable(char *name, int *variable); void M_BindFloatVariable(char *name, float *variable); void M_BindStringVariable(char *name, char **variable); boolean M_SetVariable(char *name, char *value); int M_GetIntVariable(char *name); const char *M_GetStringVariable(char *name); float M_GetFloatVariable(char *name); void M_SetConfigFilenames(char *main_config, char *extra_config); char *M_GetSaveGameDir(char *iwadname); extern char *configdir; #endif chocolate-doom-chocolate-doom-2.2.1/src/m_controls.c000066400000000000000000000311161257432200600224210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "doomtype.h" #include "doomkeys.h" #include "m_config.h" #include "m_misc.h" // // Keyboard controls // int key_right = KEY_RIGHTARROW; int key_left = KEY_LEFTARROW; int key_up = KEY_UPARROW; int key_down = KEY_DOWNARROW; int key_strafeleft = ','; int key_straferight = '.'; int key_fire = KEY_RCTRL; int key_use = ' '; int key_strafe = KEY_RALT; int key_speed = KEY_RSHIFT; // // Heretic keyboard controls // int key_flyup = KEY_PGUP; int key_flydown = KEY_INS; int key_flycenter = KEY_HOME; int key_lookup = KEY_PGDN; int key_lookdown = KEY_DEL; int key_lookcenter = KEY_END; int key_invleft = '['; int key_invright = ']'; int key_useartifact = KEY_ENTER; // // Hexen key controls // int key_jump = '/'; int key_arti_all = KEY_BACKSPACE; int key_arti_health = '\\'; int key_arti_poisonbag = '0'; int key_arti_blastradius = '9'; int key_arti_teleport = '8'; int key_arti_teleportother = '7'; int key_arti_egg = '6'; int key_arti_invulnerability = '5'; // // Strife key controls // // haleyjd 09/01/10 // // Note: Strife also uses key_invleft, key_invright, key_jump, key_lookup, and // key_lookdown, but with different default values. int key_usehealth = 'h'; int key_invquery = 'q'; int key_mission = 'w'; int key_invpop = 'z'; int key_invkey = 'k'; int key_invhome = KEY_HOME; int key_invend = KEY_END; int key_invuse = KEY_ENTER; int key_invdrop = KEY_BACKSPACE; // // Mouse controls // int mousebfire = 0; int mousebstrafe = 1; int mousebforward = 2; int mousebjump = -1; int mousebstrafeleft = -1; int mousebstraferight = -1; int mousebbackward = -1; int mousebuse = -1; int mousebprevweapon = -1; int mousebnextweapon = -1; int key_message_refresh = KEY_ENTER; int key_pause = KEY_PAUSE; int key_demo_quit = 'q'; int key_spy = KEY_F12; // Multiplayer chat keys: int key_multi_msg = 't'; int key_multi_msgplayer[8]; // Weapon selection keys: int key_weapon1 = '1'; int key_weapon2 = '2'; int key_weapon3 = '3'; int key_weapon4 = '4'; int key_weapon5 = '5'; int key_weapon6 = '6'; int key_weapon7 = '7'; int key_weapon8 = '8'; int key_prevweapon = 0; int key_nextweapon = 0; // Map control keys: int key_map_north = KEY_UPARROW; int key_map_south = KEY_DOWNARROW; int key_map_east = KEY_RIGHTARROW; int key_map_west = KEY_LEFTARROW; int key_map_zoomin = '='; int key_map_zoomout = '-'; int key_map_toggle = KEY_TAB; int key_map_maxzoom = '0'; int key_map_follow = 'f'; int key_map_grid = 'g'; int key_map_mark = 'm'; int key_map_clearmark = 'c'; // menu keys: int key_menu_activate = KEY_ESCAPE; int key_menu_up = KEY_UPARROW; int key_menu_down = KEY_DOWNARROW; int key_menu_left = KEY_LEFTARROW; int key_menu_right = KEY_RIGHTARROW; int key_menu_back = KEY_BACKSPACE; int key_menu_forward = KEY_ENTER; int key_menu_confirm = 'y'; int key_menu_abort = 'n'; int key_menu_help = KEY_F1; int key_menu_save = KEY_F2; int key_menu_load = KEY_F3; int key_menu_volume = KEY_F4; int key_menu_detail = KEY_F5; int key_menu_qsave = KEY_F6; int key_menu_endgame = KEY_F7; int key_menu_messages = KEY_F8; int key_menu_qload = KEY_F9; int key_menu_quit = KEY_F10; int key_menu_gamma = KEY_F11; int key_menu_incscreen = KEY_EQUALS; int key_menu_decscreen = KEY_MINUS; int key_menu_screenshot = 0; // // Joystick controls // int joybfire = 0; int joybstrafe = 1; int joybuse = 3; int joybspeed = 2; int joybstrafeleft = -1; int joybstraferight = -1; int joybjump = -1; int joybprevweapon = -1; int joybnextweapon = -1; int joybmenu = -1; // Control whether if a mouse button is double clicked, it acts like // "use" has been pressed int dclick_use = 1; // // Bind all of the common controls used by Doom and all other games. // void M_BindBaseControls(void) { M_BindIntVariable("key_right", &key_right); M_BindIntVariable("key_left", &key_left); M_BindIntVariable("key_up", &key_up); M_BindIntVariable("key_down", &key_down); M_BindIntVariable("key_strafeleft", &key_strafeleft); M_BindIntVariable("key_straferight", &key_straferight); M_BindIntVariable("key_fire", &key_fire); M_BindIntVariable("key_use", &key_use); M_BindIntVariable("key_strafe", &key_strafe); M_BindIntVariable("key_speed", &key_speed); M_BindIntVariable("mouseb_fire", &mousebfire); M_BindIntVariable("mouseb_strafe", &mousebstrafe); M_BindIntVariable("mouseb_forward", &mousebforward); M_BindIntVariable("joyb_fire", &joybfire); M_BindIntVariable("joyb_strafe", &joybstrafe); M_BindIntVariable("joyb_use", &joybuse); M_BindIntVariable("joyb_speed", &joybspeed); M_BindIntVariable("joyb_menu_activate", &joybmenu); // Extra controls that are not in the Vanilla versions: M_BindIntVariable("joyb_strafeleft", &joybstrafeleft); M_BindIntVariable("joyb_straferight", &joybstraferight); M_BindIntVariable("mouseb_strafeleft", &mousebstrafeleft); M_BindIntVariable("mouseb_straferight", &mousebstraferight); M_BindIntVariable("mouseb_use", &mousebuse); M_BindIntVariable("mouseb_backward", &mousebbackward); M_BindIntVariable("dclick_use", &dclick_use); M_BindIntVariable("key_pause", &key_pause); M_BindIntVariable("key_message_refresh", &key_message_refresh); } void M_BindHereticControls(void) { M_BindIntVariable("key_flyup", &key_flyup); M_BindIntVariable("key_flydown", &key_flydown); M_BindIntVariable("key_flycenter", &key_flycenter); M_BindIntVariable("key_lookup", &key_lookup); M_BindIntVariable("key_lookdown", &key_lookdown); M_BindIntVariable("key_lookcenter", &key_lookcenter); M_BindIntVariable("key_invleft", &key_invleft); M_BindIntVariable("key_invright", &key_invright); M_BindIntVariable("key_useartifact", &key_useartifact); } void M_BindHexenControls(void) { M_BindIntVariable("key_jump", &key_jump); M_BindIntVariable("mouseb_jump", &mousebjump); M_BindIntVariable("joyb_jump", &joybjump); M_BindIntVariable("key_arti_all", &key_arti_all); M_BindIntVariable("key_arti_health", &key_arti_health); M_BindIntVariable("key_arti_poisonbag", &key_arti_poisonbag); M_BindIntVariable("key_arti_blastradius", &key_arti_blastradius); M_BindIntVariable("key_arti_teleport", &key_arti_teleport); M_BindIntVariable("key_arti_teleportother", &key_arti_teleportother); M_BindIntVariable("key_arti_egg", &key_arti_egg); M_BindIntVariable("key_arti_invulnerability", &key_arti_invulnerability); } void M_BindStrifeControls(void) { // These are shared with all games, but have different defaults: key_message_refresh = '/'; // These keys are shared with Heretic/Hexen but have different defaults: key_jump = 'a'; key_lookup = KEY_PGUP; key_lookdown = KEY_PGDN; key_invleft = KEY_INS; key_invright = KEY_DEL; M_BindIntVariable("key_jump", &key_jump); M_BindIntVariable("key_lookUp", &key_lookup); M_BindIntVariable("key_lookDown", &key_lookdown); M_BindIntVariable("key_invLeft", &key_invleft); M_BindIntVariable("key_invRight", &key_invright); // Custom Strife-only Keys: M_BindIntVariable("key_useHealth", &key_usehealth); M_BindIntVariable("key_invquery", &key_invquery); M_BindIntVariable("key_mission", &key_mission); M_BindIntVariable("key_invPop", &key_invpop); M_BindIntVariable("key_invKey", &key_invkey); M_BindIntVariable("key_invHome", &key_invhome); M_BindIntVariable("key_invEnd", &key_invend); M_BindIntVariable("key_invUse", &key_invuse); M_BindIntVariable("key_invDrop", &key_invdrop); // Strife also supports jump on mouse and joystick, and in the exact same // manner as Hexen! M_BindIntVariable("mouseb_jump", &mousebjump); M_BindIntVariable("joyb_jump", &joybjump); } void M_BindWeaponControls(void) { M_BindIntVariable("key_weapon1", &key_weapon1); M_BindIntVariable("key_weapon2", &key_weapon2); M_BindIntVariable("key_weapon3", &key_weapon3); M_BindIntVariable("key_weapon4", &key_weapon4); M_BindIntVariable("key_weapon5", &key_weapon5); M_BindIntVariable("key_weapon6", &key_weapon6); M_BindIntVariable("key_weapon7", &key_weapon7); M_BindIntVariable("key_weapon8", &key_weapon8); M_BindIntVariable("key_prevweapon", &key_prevweapon); M_BindIntVariable("key_nextweapon", &key_nextweapon); M_BindIntVariable("joyb_prevweapon", &joybprevweapon); M_BindIntVariable("joyb_nextweapon", &joybnextweapon); M_BindIntVariable("mouseb_prevweapon", &mousebprevweapon); M_BindIntVariable("mouseb_nextweapon", &mousebnextweapon); } void M_BindMapControls(void) { M_BindIntVariable("key_map_north", &key_map_north); M_BindIntVariable("key_map_south", &key_map_south); M_BindIntVariable("key_map_east", &key_map_east); M_BindIntVariable("key_map_west", &key_map_west); M_BindIntVariable("key_map_zoomin", &key_map_zoomin); M_BindIntVariable("key_map_zoomout", &key_map_zoomout); M_BindIntVariable("key_map_toggle", &key_map_toggle); M_BindIntVariable("key_map_maxzoom", &key_map_maxzoom); M_BindIntVariable("key_map_follow", &key_map_follow); M_BindIntVariable("key_map_grid", &key_map_grid); M_BindIntVariable("key_map_mark", &key_map_mark); M_BindIntVariable("key_map_clearmark", &key_map_clearmark); } void M_BindMenuControls(void) { M_BindIntVariable("key_menu_activate", &key_menu_activate); M_BindIntVariable("key_menu_up", &key_menu_up); M_BindIntVariable("key_menu_down", &key_menu_down); M_BindIntVariable("key_menu_left", &key_menu_left); M_BindIntVariable("key_menu_right", &key_menu_right); M_BindIntVariable("key_menu_back", &key_menu_back); M_BindIntVariable("key_menu_forward", &key_menu_forward); M_BindIntVariable("key_menu_confirm", &key_menu_confirm); M_BindIntVariable("key_menu_abort", &key_menu_abort); M_BindIntVariable("key_menu_help", &key_menu_help); M_BindIntVariable("key_menu_save", &key_menu_save); M_BindIntVariable("key_menu_load", &key_menu_load); M_BindIntVariable("key_menu_volume", &key_menu_volume); M_BindIntVariable("key_menu_detail", &key_menu_detail); M_BindIntVariable("key_menu_qsave", &key_menu_qsave); M_BindIntVariable("key_menu_endgame", &key_menu_endgame); M_BindIntVariable("key_menu_messages", &key_menu_messages); M_BindIntVariable("key_menu_qload", &key_menu_qload); M_BindIntVariable("key_menu_quit", &key_menu_quit); M_BindIntVariable("key_menu_gamma", &key_menu_gamma); M_BindIntVariable("key_menu_incscreen", &key_menu_incscreen); M_BindIntVariable("key_menu_decscreen", &key_menu_decscreen); M_BindIntVariable("key_menu_screenshot",&key_menu_screenshot); M_BindIntVariable("key_demo_quit", &key_demo_quit); M_BindIntVariable("key_spy", &key_spy); } void M_BindChatControls(unsigned int num_players) { char name[32]; // haleyjd: 20 not large enough - Thank you, come again! unsigned int i; // haleyjd: signedness conflict M_BindIntVariable("key_multi_msg", &key_multi_msg); for (i=0; i> FRACBITS; } // // FixedDiv, C version. // fixed_t FixedDiv(fixed_t a, fixed_t b) { if ((abs(a) >> 14) >= abs(b)) { return (a^b) < 0 ? INT_MIN : INT_MAX; } else { int64_t result; result = ((int64_t) a << 16) / b; return (fixed_t) result; } } chocolate-doom-chocolate-doom-2.2.1/src/m_fixed.h000066400000000000000000000016141257432200600216620ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Fixed point arithemtics, implementation. // #ifndef __M_FIXED__ #define __M_FIXED__ // // Fixed point, 32bit as 16.16. // #define FRACBITS 16 #define FRACUNIT (1< #include #include #include #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #ifdef _MSC_VER #include #endif #else #include #include #endif #include "doomtype.h" #include "deh_str.h" #include "i_swap.h" #include "i_system.h" #include "i_video.h" #include "m_misc.h" #include "v_video.h" #include "w_wad.h" #include "z_zone.h" // // Create a directory // void M_MakeDirectory(char *path) { #ifdef _WIN32 mkdir(path); #else mkdir(path, 0755); #endif } // Check if a file exists boolean M_FileExists(char *filename) { FILE *fstream; fstream = fopen(filename, "r"); if (fstream != NULL) { fclose(fstream); return true; } else { // If we can't open because the file is a directory, the // "file" exists at least! return errno == EISDIR; } } // // Determine the length of an open file. // long M_FileLength(FILE *handle) { long savedpos; long length; // save the current position in the file savedpos = ftell(handle); // jump to the end and find the length fseek(handle, 0, SEEK_END); length = ftell(handle); // go back to the old location fseek(handle, savedpos, SEEK_SET); return length; } // // M_WriteFile // boolean M_WriteFile(char *name, void *source, int length) { FILE *handle; int count; handle = fopen(name, "wb"); if (handle == NULL) return false; count = fwrite(source, 1, length, handle); fclose(handle); if (count < length) return false; return true; } // // M_ReadFile // int M_ReadFile(char *name, byte **buffer) { FILE *handle; int count, length; byte *buf; handle = fopen(name, "rb"); if (handle == NULL) I_Error ("Couldn't read file %s", name); // find the size of the file by seeking to the end and // reading the current position length = M_FileLength(handle); buf = Z_Malloc (length, PU_STATIC, NULL); count = fread(buf, 1, length, handle); fclose (handle); if (count < length) I_Error ("Couldn't read file %s", name); *buffer = buf; return length; } // Returns the path to a temporary file of the given name, stored // inside the system temporary directory. // // The returned value must be freed with Z_Free after use. char *M_TempFile(char *s) { char *tempdir; #ifdef _WIN32 // Check the TEMP environment variable to find the location. tempdir = getenv("TEMP"); if (tempdir == NULL) { tempdir = "."; } #else // In Unix, just use /tmp. tempdir = "/tmp"; #endif return M_StringJoin(tempdir, DIR_SEPARATOR_S, s, NULL); } boolean M_StrToInt(const char *str, int *result) { return sscanf(str, " 0x%x", result) == 1 || sscanf(str, " 0X%x", result) == 1 || sscanf(str, " 0%o", result) == 1 || sscanf(str, " %d", result) == 1; } void M_ExtractFileBase(char *path, char *dest) { char *src; char *filename; int length; src = path + strlen(path) - 1; // back up until a \ or the start while (src != path && *(src - 1) != DIR_SEPARATOR) { src--; } filename = src; // Copy up to eight characters // Note: Vanilla Doom exits with an error if a filename is specified // with a base of more than eight characters. To remove the 8.3 // filename limit, instead we simply truncate the name. length = 0; memset(dest, 0, 8); while (*src != '\0' && *src != '.') { if (length >= 8) { printf("Warning: Truncated '%s' lump name to '%.8s'.\n", filename, dest); break; } dest[length++] = toupper((int)*src++); } } //--------------------------------------------------------------------------- // // PROC M_ForceUppercase // // Change string to uppercase. // //--------------------------------------------------------------------------- void M_ForceUppercase(char *text) { char *p; for (p = text; *p != '\0'; ++p) { *p = toupper(*p); } } // // M_StrCaseStr // // Case-insensitive version of strstr() // char *M_StrCaseStr(char *haystack, char *needle) { unsigned int haystack_len; unsigned int needle_len; unsigned int len; unsigned int i; haystack_len = strlen(haystack); needle_len = strlen(needle); if (haystack_len < needle_len) { return NULL; } len = haystack_len - needle_len; for (i = 0; i <= len; ++i) { if (!strncasecmp(haystack + i, needle, needle_len)) { return haystack + i; } } return NULL; } // // Safe version of strdup() that checks the string was successfully // allocated. // char *M_StringDuplicate(const char *orig) { char *result; result = strdup(orig); if (result == NULL) { I_Error("Failed to duplicate string (length %i)\n", strlen(orig)); } return result; } // // String replace function. // char *M_StringReplace(const char *haystack, const char *needle, const char *replacement) { char *result, *dst; const char *p; size_t needle_len = strlen(needle); size_t result_len, dst_len; // Iterate through occurrences of 'needle' and calculate the size of // the new string. result_len = strlen(haystack) + 1; p = haystack; for (;;) { p = strstr(p, needle); if (p == NULL) { break; } p += needle_len; result_len += strlen(replacement) - needle_len; } // Construct new string. result = malloc(result_len); if (result == NULL) { I_Error("M_StringReplace: Failed to allocate new string"); return NULL; } dst = result; dst_len = result_len; p = haystack; while (*p != '\0') { if (!strncmp(p, needle, needle_len)) { M_StringCopy(dst, replacement, dst_len); p += needle_len; dst += strlen(replacement); dst_len -= strlen(replacement); } else { *dst = *p; ++dst; --dst_len; ++p; } } *dst = '\0'; return result; } // Safe string copy function that works like OpenBSD's strlcpy(). // Returns true if the string was not truncated. boolean M_StringCopy(char *dest, const char *src, size_t dest_size) { size_t len; if (dest_size >= 1) { dest[dest_size - 1] = '\0'; strncpy(dest, src, dest_size - 1); } else { return false; } len = strlen(dest); return src[len] == '\0'; } // Safe string concat function that works like OpenBSD's strlcat(). // Returns true if string not truncated. boolean M_StringConcat(char *dest, const char *src, size_t dest_size) { size_t offset; offset = strlen(dest); if (offset > dest_size) { offset = dest_size; } return M_StringCopy(dest + offset, src, dest_size - offset); } // Returns true if 's' begins with the specified prefix. boolean M_StringStartsWith(const char *s, const char *prefix) { return strlen(s) > strlen(prefix) && strncmp(s, prefix, strlen(prefix)) == 0; } // Returns true if 's' ends with the specified suffix. boolean M_StringEndsWith(const char *s, const char *suffix) { return strlen(s) >= strlen(suffix) && strcmp(s + strlen(s) - strlen(suffix), suffix) == 0; } // Return a newly-malloced string with all the strings given as arguments // concatenated together. char *M_StringJoin(const char *s, ...) { char *result; const char *v; va_list args; size_t result_len; result_len = strlen(s) + 1; va_start(args, s); for (;;) { v = va_arg(args, const char *); if (v == NULL) { break; } result_len += strlen(v); } va_end(args); result = malloc(result_len); if (result == NULL) { I_Error("M_StringJoin: Failed to allocate new string."); return NULL; } M_StringCopy(result, s, result_len); va_start(args, s); for (;;) { v = va_arg(args, const char *); if (v == NULL) { break; } M_StringConcat(result, v, result_len); } va_end(args); return result; } // On Windows, vsnprintf() is _vsnprintf(). #ifdef _WIN32 #if _MSC_VER < 1400 /* not needed for Visual Studio 2008 */ #define vsnprintf _vsnprintf #endif #endif // Safe, portable vsnprintf(). int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args) { int result; if (buf_len < 1) { return 0; } // Windows (and other OSes?) has a vsnprintf() that doesn't always // append a trailing \0. So we must do it, and write into a buffer // that is one byte shorter; otherwise this function is unsafe. result = vsnprintf(buf, buf_len, s, args); // If truncated, change the final char in the buffer to a \0. // A negative result indicates a truncated buffer on Windows. if (result < 0 || result >= buf_len) { buf[buf_len - 1] = '\0'; result = buf_len - 1; } return result; } // Safe, portable snprintf(). int M_snprintf(char *buf, size_t buf_len, const char *s, ...) { va_list args; int result; va_start(args, s); result = M_vsnprintf(buf, buf_len, s, args); va_end(args); return result; } #ifdef _WIN32 char *M_OEMToUTF8(const char *oem) { unsigned int len = strlen(oem) + 1; wchar_t *tmp; char *result; tmp = malloc(len * sizeof(wchar_t)); MultiByteToWideChar(CP_OEMCP, 0, oem, len, tmp, len); result = malloc(len * 4); WideCharToMultiByte(CP_UTF8, 0, tmp, len, result, len * 4, NULL, NULL); free(tmp); return result; } #endif chocolate-doom-chocolate-doom-2.2.1/src/m_misc.h000066400000000000000000000034041257432200600215150ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Miscellaneous. // #ifndef __M_MISC__ #define __M_MISC__ #include #include #include "doomtype.h" boolean M_WriteFile(char *name, void *source, int length); int M_ReadFile(char *name, byte **buffer); void M_MakeDirectory(char *dir); char *M_TempFile(char *s); boolean M_FileExists(char *file); long M_FileLength(FILE *handle); boolean M_StrToInt(const char *str, int *result); void M_ExtractFileBase(char *path, char *dest); void M_ForceUppercase(char *text); char *M_StrCaseStr(char *haystack, char *needle); char *M_StringDuplicate(const char *orig); boolean M_StringCopy(char *dest, const char *src, size_t dest_size); boolean M_StringConcat(char *dest, const char *src, size_t dest_size); char *M_StringReplace(const char *haystack, const char *needle, const char *replacement); char *M_StringJoin(const char *s, ...); boolean M_StringStartsWith(const char *s, const char *prefix); boolean M_StringEndsWith(const char *s, const char *suffix); int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args); int M_snprintf(char *buf, size_t buf_len, const char *s, ...); char *M_OEMToUTF8(const char *ansi); #endif chocolate-doom-chocolate-doom-2.2.1/src/manifest.xml000066400000000000000000000006741257432200600224330ustar00rootroot00000000000000 true chocolate-doom-chocolate-doom-2.2.1/src/memio.c000066400000000000000000000070411257432200600213500ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Emulates the IO functions in C stdio.h reading and writing to // memory. // #include #include #include #include "memio.h" #include "z_zone.h" typedef enum { MODE_READ, MODE_WRITE, } memfile_mode_t; struct _MEMFILE { unsigned char *buf; size_t buflen; size_t alloced; unsigned int position; memfile_mode_t mode; }; // Open a memory area for reading MEMFILE *mem_fopen_read(void *buf, size_t buflen) { MEMFILE *file; file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0); file->buf = (unsigned char *) buf; file->buflen = buflen; file->position = 0; file->mode = MODE_READ; return file; } // Read bytes size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream) { size_t items; if (stream->mode != MODE_READ) { printf("not a read stream\n"); return -1; } // Trying to read more bytes than we have left? items = nmemb; if (items * size > stream->buflen - stream->position) { items = (stream->buflen - stream->position) / size; } // Copy bytes to buffer memcpy(buf, stream->buf + stream->position, items * size); // Update position stream->position += items * size; return items; } // Open a memory area for writing MEMFILE *mem_fopen_write(void) { MEMFILE *file; file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0); file->alloced = 1024; file->buf = Z_Malloc(file->alloced, PU_STATIC, 0); file->buflen = 0; file->position = 0; file->mode = MODE_WRITE; return file; } // Write bytes to stream size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream) { size_t bytes; if (stream->mode != MODE_WRITE) { return -1; } // More bytes than can fit in the buffer? // If so, reallocate bigger. bytes = size * nmemb; while (bytes > stream->alloced - stream->position) { unsigned char *newbuf; newbuf = Z_Malloc(stream->alloced * 2, PU_STATIC, 0); memcpy(newbuf, stream->buf, stream->alloced); Z_Free(stream->buf); stream->buf = newbuf; stream->alloced *= 2; } // Copy into buffer memcpy(stream->buf + stream->position, ptr, bytes); stream->position += bytes; if (stream->position > stream->buflen) stream->buflen = stream->position; return nmemb; } void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen) { *buf = stream->buf; *buflen = stream->buflen; } void mem_fclose(MEMFILE *stream) { if (stream->mode == MODE_WRITE) { Z_Free(stream->buf); } Z_Free(stream); } long mem_ftell(MEMFILE *stream) { return stream->position; } int mem_fseek(MEMFILE *stream, signed long position, mem_rel_t whence) { unsigned int newpos; switch (whence) { case MEM_SEEK_SET: newpos = (int) position; break; case MEM_SEEK_CUR: newpos = (int) (stream->position + position); break; case MEM_SEEK_END: newpos = (int) (stream->buflen + position); break; default: return -1; } if (newpos < stream->buflen) { stream->position = newpos; return 0; } else { printf("Error seeking to %i\n", newpos); return -1; } } chocolate-doom-chocolate-doom-2.2.1/src/memio.h000066400000000000000000000022661257432200600213610ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef MEMIO_H #define MEMIO_H typedef struct _MEMFILE MEMFILE; typedef enum { MEM_SEEK_SET, MEM_SEEK_CUR, MEM_SEEK_END, } mem_rel_t; MEMFILE *mem_fopen_read(void *buf, size_t buflen); size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream); MEMFILE *mem_fopen_write(void); size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream); void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen); void mem_fclose(MEMFILE *stream); long mem_ftell(MEMFILE *stream); int mem_fseek(MEMFILE *stream, signed long offset, mem_rel_t whence); #endif /* #ifndef MEMIO_H */ chocolate-doom-chocolate-doom-2.2.1/src/midifile.c000066400000000000000000000434461257432200600220350ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Reading of MIDI files. // #include #include #include #include #include "doomtype.h" #include "i_swap.h" #include "midifile.h" #define HEADER_CHUNK_ID "MThd" #define TRACK_CHUNK_ID "MTrk" #define MAX_BUFFER_SIZE 0x10000 // haleyjd 09/09/10: packing required #ifdef _MSC_VER #pragma pack(push, 1) #endif typedef struct { byte chunk_id[4]; unsigned int chunk_size; } PACKEDATTR chunk_header_t; typedef struct { chunk_header_t chunk_header; unsigned short format_type; unsigned short num_tracks; unsigned short time_division; } PACKEDATTR midi_header_t; // haleyjd 09/09/10: packing off. #ifdef _MSC_VER #pragma pack(pop) #endif typedef struct { // Length in bytes: unsigned int data_len; // Events in this track: midi_event_t *events; int num_events; } midi_track_t; struct midi_track_iter_s { midi_track_t *track; unsigned int position; }; struct midi_file_s { midi_header_t header; // All tracks in this file: midi_track_t *tracks; unsigned int num_tracks; // Data buffer used to store data read for SysEx or meta events: byte *buffer; unsigned int buffer_size; }; // Check the header of a chunk: static boolean CheckChunkHeader(chunk_header_t *chunk, char *expected_id) { boolean result; result = (memcmp((char *) chunk->chunk_id, expected_id, 4) == 0); if (!result) { fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header, " "got '%c%c%c%c'\n", expected_id, chunk->chunk_id[0], chunk->chunk_id[1], chunk->chunk_id[2], chunk->chunk_id[3]); } return result; } // Read a single byte. Returns false on error. static boolean ReadByte(byte *result, FILE *stream) { int c; c = fgetc(stream); if (c == EOF) { fprintf(stderr, "ReadByte: Unexpected end of file\n"); return false; } else { *result = (byte) c; return true; } } // Read a variable-length value. static boolean ReadVariableLength(unsigned int *result, FILE *stream) { int i; byte b = 0; *result = 0; for (i=0; i<4; ++i) { if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadVariableLength: Error while reading " "variable-length value\n"); return false; } // Insert the bottom seven bits from this byte. *result <<= 7; *result |= b & 0x7f; // If the top bit is not set, this is the end. if ((b & 0x80) == 0) { return true; } } fprintf(stderr, "ReadVariableLength: Variable-length value too " "long: maximum of four bytes\n"); return false; } // Read a byte sequence into the data buffer. static void *ReadByteSequence(unsigned int num_bytes, FILE *stream) { unsigned int i; byte *result; // Allocate a buffer. Allocate one extra byte, as malloc(0) is // non-portable. result = malloc(num_bytes + 1); if (result == NULL) { fprintf(stderr, "ReadByteSequence: Failed to allocate buffer\n"); return NULL; } // Read the data: for (i=0; ievent_type = event_type & 0xf0; event->data.channel.channel = event_type & 0x0f; // Read parameters: if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadChannelEvent: Error while reading channel " "event parameters\n"); return false; } event->data.channel.param1 = b; // Second parameter: if (two_param) { if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadChannelEvent: Error while reading channel " "event parameters\n"); return false; } event->data.channel.param2 = b; } return true; } // Read sysex event: static boolean ReadSysExEvent(midi_event_t *event, int event_type, FILE *stream) { event->event_type = event_type; if (!ReadVariableLength(&event->data.sysex.length, stream)) { fprintf(stderr, "ReadSysExEvent: Failed to read length of " "SysEx block\n"); return false; } // Read the byte sequence: event->data.sysex.data = ReadByteSequence(event->data.sysex.length, stream); if (event->data.sysex.data == NULL) { fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n"); return false; } return true; } // Read meta event: static boolean ReadMetaEvent(midi_event_t *event, FILE *stream) { byte b = 0; event->event_type = MIDI_EVENT_META; // Read meta event type: if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadMetaEvent: Failed to read meta event type\n"); return false; } event->data.meta.type = b; // Read length of meta event data: if (!ReadVariableLength(&event->data.meta.length, stream)) { fprintf(stderr, "ReadSysExEvent: Failed to read length of " "SysEx block\n"); return false; } // Read the byte sequence: event->data.meta.data = ReadByteSequence(event->data.meta.length, stream); if (event->data.meta.data == NULL) { fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n"); return false; } return true; } static boolean ReadEvent(midi_event_t *event, unsigned int *last_event_type, FILE *stream) { byte event_type = 0; if (!ReadVariableLength(&event->delta_time, stream)) { fprintf(stderr, "ReadEvent: Failed to read event timestamp\n"); return false; } if (!ReadByte(&event_type, stream)) { fprintf(stderr, "ReadEvent: Failed to read event type\n"); return false; } // All event types have their top bit set. Therefore, if // the top bit is not set, it is because we are using the "same // as previous event type" shortcut to save a byte. Skip back // a byte so that we read this byte again. if ((event_type & 0x80) == 0) { event_type = *last_event_type; if (fseek(stream, -1, SEEK_CUR) < 0) { fprintf(stderr, "ReadEvent: Unable to seek in stream\n"); return false; } } else { *last_event_type = event_type; } // Check event type: switch (event_type & 0xf0) { // Two parameter channel events: case MIDI_EVENT_NOTE_OFF: case MIDI_EVENT_NOTE_ON: case MIDI_EVENT_AFTERTOUCH: case MIDI_EVENT_CONTROLLER: case MIDI_EVENT_PITCH_BEND: return ReadChannelEvent(event, event_type, true, stream); // Single parameter channel events: case MIDI_EVENT_PROGRAM_CHANGE: case MIDI_EVENT_CHAN_AFTERTOUCH: return ReadChannelEvent(event, event_type, false, stream); default: break; } // Specific value? switch (event_type) { case MIDI_EVENT_SYSEX: case MIDI_EVENT_SYSEX_SPLIT: return ReadSysExEvent(event, event_type, stream); case MIDI_EVENT_META: return ReadMetaEvent(event, stream); default: break; } fprintf(stderr, "ReadEvent: Unknown MIDI event type: 0x%x\n", event_type); return false; } // Free an event: static void FreeEvent(midi_event_t *event) { // Some event types have dynamically allocated buffers assigned // to them that must be freed. switch (event->event_type) { case MIDI_EVENT_SYSEX: case MIDI_EVENT_SYSEX_SPLIT: free(event->data.sysex.data); break; case MIDI_EVENT_META: free(event->data.meta.data); break; default: // Nothing to do. break; } } // Read and check the track chunk header static boolean ReadTrackHeader(midi_track_t *track, FILE *stream) { size_t records_read; chunk_header_t chunk_header; records_read = fread(&chunk_header, sizeof(chunk_header_t), 1, stream); if (records_read < 1) { return false; } if (!CheckChunkHeader(&chunk_header, TRACK_CHUNK_ID)) { return false; } track->data_len = SDL_SwapBE32(chunk_header.chunk_size); return true; } static boolean ReadTrack(midi_track_t *track, FILE *stream) { midi_event_t *new_events; midi_event_t *event; unsigned int last_event_type; track->num_events = 0; track->events = NULL; // Read the header: if (!ReadTrackHeader(track, stream)) { return false; } // Then the events: last_event_type = 0; for (;;) { // Resize the track slightly larger to hold another event: new_events = realloc(track->events, sizeof(midi_event_t) * (track->num_events + 1)); if (new_events == NULL) { return false; } track->events = new_events; // Read the next event: event = &track->events[track->num_events]; if (!ReadEvent(event, &last_event_type, stream)) { return false; } ++track->num_events; // End of track? if (event->event_type == MIDI_EVENT_META && event->data.meta.type == MIDI_META_END_OF_TRACK) { break; } } return true; } // Free a track: static void FreeTrack(midi_track_t *track) { unsigned int i; for (i=0; inum_events; ++i) { FreeEvent(&track->events[i]); } free(track->events); } static boolean ReadAllTracks(midi_file_t *file, FILE *stream) { unsigned int i; // Allocate list of tracks and read each track: file->tracks = malloc(sizeof(midi_track_t) * file->num_tracks); if (file->tracks == NULL) { return false; } memset(file->tracks, 0, sizeof(midi_track_t) * file->num_tracks); // Read each track: for (i=0; inum_tracks; ++i) { if (!ReadTrack(&file->tracks[i], stream)) { return false; } } return true; } // Read and check the header chunk. static boolean ReadFileHeader(midi_file_t *file, FILE *stream) { size_t records_read; unsigned int format_type; records_read = fread(&file->header, sizeof(midi_header_t), 1, stream); if (records_read < 1) { return false; } if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID) || SDL_SwapBE32(file->header.chunk_header.chunk_size) != 6) { fprintf(stderr, "ReadFileHeader: Invalid MIDI chunk header! " "chunk_size=%i\n", SDL_SwapBE32(file->header.chunk_header.chunk_size)); return false; } format_type = SDL_SwapBE16(file->header.format_type); file->num_tracks = SDL_SwapBE16(file->header.num_tracks); if ((format_type != 0 && format_type != 1) || file->num_tracks < 1) { fprintf(stderr, "ReadFileHeader: Only type 0/1 " "MIDI files supported!\n"); return false; } return true; } void MIDI_FreeFile(midi_file_t *file) { int i; if (file->tracks != NULL) { for (i=0; inum_tracks; ++i) { FreeTrack(&file->tracks[i]); } free(file->tracks); } free(file); } midi_file_t *MIDI_LoadFile(char *filename) { midi_file_t *file; FILE *stream; file = malloc(sizeof(midi_file_t)); if (file == NULL) { return NULL; } file->tracks = NULL; file->num_tracks = 0; file->buffer = NULL; file->buffer_size = 0; // Open file stream = fopen(filename, "rb"); if (stream == NULL) { fprintf(stderr, "MIDI_LoadFile: Failed to open '%s'\n", filename); MIDI_FreeFile(file); return NULL; } // Read MIDI file header if (!ReadFileHeader(file, stream)) { fclose(stream); MIDI_FreeFile(file); return NULL; } // Read all tracks: if (!ReadAllTracks(file, stream)) { fclose(stream); MIDI_FreeFile(file); return NULL; } fclose(stream); return file; } // Get the number of tracks in a MIDI file. unsigned int MIDI_NumTracks(midi_file_t *file) { return file->num_tracks; } // Start iterating over the events in a track. midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track) { midi_track_iter_t *iter; assert(track < file->num_tracks); iter = malloc(sizeof(*iter)); iter->track = &file->tracks[track]; iter->position = 0; return iter; } void MIDI_FreeIterator(midi_track_iter_t *iter) { free(iter); } // Get the time until the next MIDI event in a track. unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter) { if (iter->position < iter->track->num_events) { midi_event_t *next_event; next_event = &iter->track->events[iter->position]; return next_event->delta_time; } else { return 0; } } // Get a pointer to the next MIDI event. int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event) { if (iter->position < iter->track->num_events) { *event = &iter->track->events[iter->position]; ++iter->position; return 1; } else { return 0; } } unsigned int MIDI_GetFileTimeDivision(midi_file_t *file) { short result = SDL_SwapBE16(file->header.time_division); // Negative time division indicates SMPTE time and must be handled // differently. if (result < 0) { return (signed int)(-(result/256)) * (signed int)(result & 0xFF); } else { return result; } } void MIDI_RestartIterator(midi_track_iter_t *iter) { iter->position = 0; } #ifdef TEST static char *MIDI_EventTypeToString(midi_event_type_t event_type) { switch (event_type) { case MIDI_EVENT_NOTE_OFF: return "MIDI_EVENT_NOTE_OFF"; case MIDI_EVENT_NOTE_ON: return "MIDI_EVENT_NOTE_ON"; case MIDI_EVENT_AFTERTOUCH: return "MIDI_EVENT_AFTERTOUCH"; case MIDI_EVENT_CONTROLLER: return "MIDI_EVENT_CONTROLLER"; case MIDI_EVENT_PROGRAM_CHANGE: return "MIDI_EVENT_PROGRAM_CHANGE"; case MIDI_EVENT_CHAN_AFTERTOUCH: return "MIDI_EVENT_CHAN_AFTERTOUCH"; case MIDI_EVENT_PITCH_BEND: return "MIDI_EVENT_PITCH_BEND"; case MIDI_EVENT_SYSEX: return "MIDI_EVENT_SYSEX"; case MIDI_EVENT_SYSEX_SPLIT: return "MIDI_EVENT_SYSEX_SPLIT"; case MIDI_EVENT_META: return "MIDI_EVENT_META"; default: return "(unknown)"; } } void PrintTrack(midi_track_t *track) { midi_event_t *event; unsigned int i; for (i=0; inum_events; ++i) { event = &track->events[i]; if (event->delta_time > 0) { printf("Delay: %i ticks\n", event->delta_time); } printf("Event type: %s (%i)\n", MIDI_EventTypeToString(event->event_type), event->event_type); switch(event->event_type) { case MIDI_EVENT_NOTE_OFF: case MIDI_EVENT_NOTE_ON: case MIDI_EVENT_AFTERTOUCH: case MIDI_EVENT_CONTROLLER: case MIDI_EVENT_PROGRAM_CHANGE: case MIDI_EVENT_CHAN_AFTERTOUCH: case MIDI_EVENT_PITCH_BEND: printf("\tChannel: %i\n", event->data.channel.channel); printf("\tParameter 1: %i\n", event->data.channel.param1); printf("\tParameter 2: %i\n", event->data.channel.param2); break; case MIDI_EVENT_SYSEX: case MIDI_EVENT_SYSEX_SPLIT: printf("\tLength: %i\n", event->data.sysex.length); break; case MIDI_EVENT_META: printf("\tMeta type: %i\n", event->data.meta.type); printf("\tLength: %i\n", event->data.meta.length); break; } } } int main(int argc, char *argv[]) { midi_file_t *file; unsigned int i; if (argc < 2) { printf("Usage: %s \n", argv[0]); exit(1); } file = MIDI_LoadFile(argv[1]); if (file == NULL) { fprintf(stderr, "Failed to open %s\n", argv[1]); exit(1); } for (i=0; inum_tracks; ++i) { printf("\n== Track %i ==\n\n", i); PrintTrack(&file->tracks[i]); } return 0; } #endif chocolate-doom-chocolate-doom-2.2.1/src/midifile.h000066400000000000000000000077061257432200600220410ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // MIDI file parsing. // #ifndef MIDIFILE_H #define MIDIFILE_H typedef struct midi_file_s midi_file_t; typedef struct midi_track_iter_s midi_track_iter_t; #define MIDI_CHANNELS_PER_TRACK 16 typedef enum { MIDI_EVENT_NOTE_OFF = 0x80, MIDI_EVENT_NOTE_ON = 0x90, MIDI_EVENT_AFTERTOUCH = 0xa0, MIDI_EVENT_CONTROLLER = 0xb0, MIDI_EVENT_PROGRAM_CHANGE = 0xc0, MIDI_EVENT_CHAN_AFTERTOUCH = 0xd0, MIDI_EVENT_PITCH_BEND = 0xe0, MIDI_EVENT_SYSEX = 0xf0, MIDI_EVENT_SYSEX_SPLIT = 0xf7, MIDI_EVENT_META = 0xff, } midi_event_type_t; typedef enum { MIDI_CONTROLLER_BANK_SELECT = 0x0, MIDI_CONTROLLER_MODULATION = 0x1, MIDI_CONTROLLER_BREATH_CONTROL = 0x2, MIDI_CONTROLLER_FOOT_CONTROL = 0x3, MIDI_CONTROLLER_PORTAMENTO = 0x4, MIDI_CONTROLLER_DATA_ENTRY = 0x5, MIDI_CONTROLLER_MAIN_VOLUME = 0x7, MIDI_CONTROLLER_PAN = 0xa, MIDI_CONTROLLER_ALL_NOTES_OFF = 0x7b, } midi_controller_t; typedef enum { MIDI_META_SEQUENCE_NUMBER = 0x0, MIDI_META_TEXT = 0x1, MIDI_META_COPYRIGHT = 0x2, MIDI_META_TRACK_NAME = 0x3, MIDI_META_INSTR_NAME = 0x4, MIDI_META_LYRICS = 0x5, MIDI_META_MARKER = 0x6, MIDI_META_CUE_POINT = 0x7, MIDI_META_CHANNEL_PREFIX = 0x20, MIDI_META_END_OF_TRACK = 0x2f, MIDI_META_SET_TEMPO = 0x51, MIDI_META_SMPTE_OFFSET = 0x54, MIDI_META_TIME_SIGNATURE = 0x58, MIDI_META_KEY_SIGNATURE = 0x59, MIDI_META_SEQUENCER_SPECIFIC = 0x7f, } midi_meta_event_type_t; typedef struct { // Meta event type: unsigned int type; // Length: unsigned int length; // Meta event data: byte *data; } midi_meta_event_data_t; typedef struct { // Length: unsigned int length; // Event data: byte *data; } midi_sysex_event_data_t; typedef struct { // The channel number to which this applies: unsigned int channel; // Extra parameters: unsigned int param1; unsigned int param2; } midi_channel_event_data_t; typedef struct { // Time between the previous event and this event. unsigned int delta_time; // Type of event: midi_event_type_t event_type; union { midi_channel_event_data_t channel; midi_meta_event_data_t meta; midi_sysex_event_data_t sysex; } data; } midi_event_t; // Load a MIDI file. midi_file_t *MIDI_LoadFile(char *filename); // Free a MIDI file. void MIDI_FreeFile(midi_file_t *file); // Get the time division value from the MIDI header. unsigned int MIDI_GetFileTimeDivision(midi_file_t *file); // Get the number of tracks in a MIDI file. unsigned int MIDI_NumTracks(midi_file_t *file); // Start iterating over the events in a track. midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track_num); // Free an iterator. void MIDI_FreeIterator(midi_track_iter_t *iter); // Get the time until the next MIDI event in a track. unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter); // Get a pointer to the next MIDI event. int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event); // Reset an iterator to the beginning of a track. void MIDI_RestartIterator(midi_track_iter_t *iter); #endif /* #ifndef MIDIFILE_H */ chocolate-doom-chocolate-doom-2.2.1/src/mus2mid.c000066400000000000000000000422551257432200600216300ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // Copyright(C) 2006 Ben Ryves 2006 // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // mus2mid.c - Ben Ryves 2006 - http://benryves.com - benryves@benryves.com // Use to convert a MUS file into a single track, type 0 MIDI file. #include #include "doomtype.h" #include "i_swap.h" #include "memio.h" #include "mus2mid.h" #define NUM_CHANNELS 16 #define MIDI_PERCUSSION_CHAN 9 #define MUS_PERCUSSION_CHAN 15 // MUS event codes typedef enum { mus_releasekey = 0x00, mus_presskey = 0x10, mus_pitchwheel = 0x20, mus_systemevent = 0x30, mus_changecontroller = 0x40, mus_scoreend = 0x60 } musevent; // MIDI event codes typedef enum { midi_releasekey = 0x80, midi_presskey = 0x90, midi_aftertouchkey = 0xA0, midi_changecontroller = 0xB0, midi_changepatch = 0xC0, midi_aftertouchchannel = 0xD0, midi_pitchwheel = 0xE0 } midievent; // Structure to hold MUS file header typedef struct { byte id[4]; unsigned short scorelength; unsigned short scorestart; unsigned short primarychannels; unsigned short secondarychannels; unsigned short instrumentcount; } PACKEDATTR musheader; // Standard MIDI type 0 header + track header static const byte midiheader[] = { 'M', 'T', 'h', 'd', // Main header 0x00, 0x00, 0x00, 0x06, // Header size 0x00, 0x00, // MIDI type (0) 0x00, 0x01, // Number of tracks 0x00, 0x46, // Resolution 'M', 'T', 'r', 'k', // Start of track 0x00, 0x00, 0x00, 0x00 // Placeholder for track length }; // Cached channel velocities static byte channelvelocities[] = { 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 }; // Timestamps between sequences of MUS events static unsigned int queuedtime = 0; // Counter for the length of the track static unsigned int tracksize; static const byte controller_map[] = { 0x00, 0x20, 0x01, 0x07, 0x0A, 0x0B, 0x5B, 0x5D, 0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79 }; static int channel_map[NUM_CHANNELS]; // Write timestamp to a MIDI file. static boolean WriteTime(unsigned int time, MEMFILE *midioutput) { unsigned int buffer = time & 0x7F; byte writeval; while ((time >>= 7) != 0) { buffer <<= 8; buffer |= ((time & 0x7F) | 0x80); } for (;;) { writeval = (byte)(buffer & 0xFF); if (mem_fwrite(&writeval, 1, 1, midioutput) != 1) { return true; } ++tracksize; if ((buffer & 0x80) != 0) { buffer >>= 8; } else { queuedtime = 0; return false; } } } // Write the end of track marker static boolean WriteEndTrack(MEMFILE *midioutput) { byte endtrack[] = {0xFF, 0x2F, 0x00}; if (WriteTime(queuedtime, midioutput)) { return true; } if (mem_fwrite(endtrack, 1, 3, midioutput) != 3) { return true; } tracksize += 3; return false; } // Write a key press event static boolean WritePressKey(byte channel, byte key, byte velocity, MEMFILE *midioutput) { byte working = midi_presskey | channel; if (WriteTime(queuedtime, midioutput)) { return true; } if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = key & 0x7F; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = velocity & 0x7F; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } tracksize += 3; return false; } // Write a key release event static boolean WriteReleaseKey(byte channel, byte key, MEMFILE *midioutput) { byte working = midi_releasekey | channel; if (WriteTime(queuedtime, midioutput)) { return true; } if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = key & 0x7F; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = 0; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } tracksize += 3; return false; } // Write a pitch wheel/bend event static boolean WritePitchWheel(byte channel, short wheel, MEMFILE *midioutput) { byte working = midi_pitchwheel | channel; if (WriteTime(queuedtime, midioutput)) { return true; } if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = wheel & 0x7F; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = (wheel >> 7) & 0x7F; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } tracksize += 3; return false; } // Write a patch change event static boolean WriteChangePatch(byte channel, byte patch, MEMFILE *midioutput) { byte working = midi_changepatch | channel; if (WriteTime(queuedtime, midioutput)) { return true; } if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = patch & 0x7F; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } tracksize += 2; return false; } // Write a valued controller change event static boolean WriteChangeController_Valued(byte channel, byte control, byte value, MEMFILE *midioutput) { byte working = midi_changecontroller | channel; if (WriteTime(queuedtime, midioutput)) { return true; } if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } working = control & 0x7F; if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } // Quirk in vanilla DOOM? MUS controller values should be // 7-bit, not 8-bit. working = value;// & 0x7F; // Fix on said quirk to stop MIDI players from complaining that // the value is out of range: if (working & 0x80) { working = 0x7F; } if (mem_fwrite(&working, 1, 1, midioutput) != 1) { return true; } tracksize += 3; return false; } // Write a valueless controller change event static boolean WriteChangeController_Valueless(byte channel, byte control, MEMFILE *midioutput) { return WriteChangeController_Valued(channel, control, 0, midioutput); } // Allocate a free MIDI channel. static int AllocateMIDIChannel(void) { int result; int max; int i; // Find the current highest-allocated channel. max = -1; for (i=0; i max) { max = channel_map[i]; } } // max is now equal to the highest-allocated MIDI channel. We can // now allocate the next available channel. This also works if // no channels are currently allocated (max=-1) result = max + 1; // Don't allocate the MIDI percussion channel! if (result == MIDI_PERCUSSION_CHAN) { ++result; } return result; } // Given a MUS channel number, get the MIDI channel number to use // in the outputted file. static int GetMIDIChannel(int mus_channel, MEMFILE *midioutput) { // Find the MIDI channel to use for this MUS channel. // MUS channel 15 is the percusssion channel. if (mus_channel == MUS_PERCUSSION_CHAN) { return MIDI_PERCUSSION_CHAN; } else { // If a MIDI channel hasn't been allocated for this MUS channel // yet, allocate the next free MIDI channel. if (channel_map[mus_channel] == -1) { channel_map[mus_channel] = AllocateMIDIChannel(); // First time using the channel, send an "all notes off" // event. This fixes "The D_DDTBLU disease" described here: // http://www.doomworld.com/vb/source-ports/66802-the WriteChangeController_Valueless(channel_map[mus_channel], 0x7b, midioutput); } return channel_map[mus_channel]; } } static boolean ReadMusHeader(MEMFILE *file, musheader *header) { boolean result; result = mem_fread(&header->id, sizeof(byte), 4, file) == 4 && mem_fread(&header->scorelength, sizeof(short), 1, file) == 1 && mem_fread(&header->scorestart, sizeof(short), 1, file) == 1 && mem_fread(&header->primarychannels, sizeof(short), 1, file) == 1 && mem_fread(&header->secondarychannels, sizeof(short), 1, file) == 1 && mem_fread(&header->instrumentcount, sizeof(short), 1, file) == 1; if (result) { header->scorelength = SHORT(header->scorelength); header->scorestart = SHORT(header->scorestart); header->primarychannels = SHORT(header->primarychannels); header->secondarychannels = SHORT(header->secondarychannels); header->instrumentcount = SHORT(header->instrumentcount); } return result; } // Read a MUS file from a stream (musinput) and output a MIDI file to // a stream (midioutput). // // Returns 0 on success or 1 on failure. boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput) { // Header for the MUS file musheader musfileheader; // Descriptor for the current MUS event byte eventdescriptor; int channel; // Channel number musevent event; // Bunch of vars read from MUS lump byte key; byte controllernumber; byte controllervalue; // Buffer used for MIDI track size record byte tracksizebuffer[4]; // Flag for when the score end marker is hit. int hitscoreend = 0; // Temp working byte byte working; // Used in building up time delays unsigned int timedelay; // Initialise channel map to mark all channels as unused. for (channel=0; channel 14) { return true; } if (WriteChangeController_Valueless(channel, controller_map[controllernumber], midioutput)) { return true; } break; case mus_changecontroller: if (mem_fread(&controllernumber, 1, 1, musinput) != 1) { return true; } if (mem_fread(&controllervalue, 1, 1, musinput) != 1) { return true; } if (controllernumber == 0) { if (WriteChangePatch(channel, controllervalue, midioutput)) { return true; } } else { if (controllernumber < 1 || controllernumber > 9) { return true; } if (WriteChangeController_Valued(channel, controller_map[controllernumber], controllervalue, midioutput)) { return true; } } break; case mus_scoreend: hitscoreend = 1; break; default: return true; break; } if (eventdescriptor & 0x80) { break; } } // Now we need to read the time code: if (!hitscoreend) { timedelay = 0; for (;;) { if (mem_fread(&working, 1, 1, musinput) != 1) { return true; } timedelay = timedelay * 128 + (working & 0x7F); if ((working & 0x80) == 0) { break; } } queuedtime += timedelay; } } // End of track if (WriteEndTrack(midioutput)) { return true; } // Write the track size into the stream if (mem_fseek(midioutput, 18, MEM_SEEK_SET)) { return true; } tracksizebuffer[0] = (tracksize >> 24) & 0xff; tracksizebuffer[1] = (tracksize >> 16) & 0xff; tracksizebuffer[2] = (tracksize >> 8) & 0xff; tracksizebuffer[3] = tracksize & 0xff; if (mem_fwrite(tracksizebuffer, 1, 4, midioutput) != 4) { return true; } return false; } #ifdef STANDALONE #include "m_misc.h" #include "z_zone.h" int main(int argc, char *argv[]) { MEMFILE *src, *dst; byte *infile; long infile_len; void *outfile; size_t outfile_len; if (argc != 3) { printf("Usage: %s \n", argv[0]); exit(-1); } Z_Init(); infile_len = M_ReadFile(argv[1], &infile); src = mem_fopen_read(infile, infile_len); dst = mem_fopen_write(); if (mus2mid(src, dst)) { fprintf(stderr, "mus2mid() failed\n"); exit(-1); } // Write result to output file: mem_get_buf(dst, &outfile, &outfile_len); M_WriteFile(argv[2], outfile, outfile_len); return 0; } #endif chocolate-doom-chocolate-doom-2.2.1/src/mus2mid.h000066400000000000000000000016621257432200600216320ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // Copyright(C) 2006 Ben Ryves 2006 // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // mus2mid.h - Ben Ryves 2006 - http://benryves.com - benryves@benryves.com // Use to convert a MUS file into a single track, type 0 MIDI file. #ifndef MUS2MID_H #define MUS2MID_H #include "doomtype.h" #include "memio.h" boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput); #endif /* #ifndef MUS2MID_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_client.c000066400000000000000000000602211257432200600223650ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Network client code // #include #include #include #include #include "config.h" #include "doomtype.h" #include "deh_main.h" #include "deh_str.h" #include "i_system.h" #include "i_timer.h" #include "m_argv.h" #include "m_fixed.h" #include "m_config.h" #include "m_misc.h" #include "net_client.h" #include "net_common.h" #include "net_defs.h" #include "net_gui.h" #include "net_io.h" #include "net_packet.h" #include "net_server.h" #include "net_structrw.h" #include "w_checksum.h" #include "w_wad.h" extern void D_ReceiveTic(ticcmd_t *ticcmds, boolean *playeringame); typedef enum { // waiting for the game to launch CLIENT_STATE_WAITING_LAUNCH, // waiting for the game to start CLIENT_STATE_WAITING_START, // in game CLIENT_STATE_IN_GAME, } net_clientstate_t; // Type of structure used in the receive window typedef struct { // Whether this tic has been received yet boolean active; // Last time we sent a resend request for this tic unsigned int resend_time; // Tic data from server net_full_ticcmd_t cmd; } net_server_recv_t; // Type of structure used in the send window typedef struct { // Whether this slot is active yet boolean active; // The tic number unsigned int seq; // Time the command was generated unsigned int time; // Ticcmd diff net_ticdiff_t cmd; } net_server_send_t; extern fixed_t offsetms; static net_connection_t client_connection; static net_clientstate_t client_state; static net_addr_t *server_addr; static net_context_t *client_context; // game settings, as received from the server when the game started static net_gamesettings_t settings; // true if the client code is in use boolean net_client_connected; // true if we have received waiting data from the server, // and the wait data that was received. boolean net_client_received_wait_data; net_waitdata_t net_client_wait_data; // Waiting at the initial wait screen for the game to be launched? boolean net_waiting_for_launch = false; // Name that we send to the server char *net_player_name = NULL; // Connected but not participating in the game (observer) boolean drone = false; // The last ticcmd constructed static ticcmd_t last_ticcmd; // Buffer of ticcmd diffs being sent to the server static net_server_send_t send_queue[BACKUPTICS]; // Receive window static ticcmd_t recvwindow_cmd_base[NET_MAXPLAYERS]; static int recvwindow_start; static net_server_recv_t recvwindow[BACKUPTICS]; // Whether we need to send an acknowledgement and // when gamedata was last received. static boolean need_to_acknowledge; static unsigned int gamedata_recv_time; // Hash checksums of our wad directory and dehacked data. sha1_digest_t net_local_wad_sha1sum; sha1_digest_t net_local_deh_sha1sum; // Are we playing with the freedoom IWAD? unsigned int net_local_is_freedoom; // Average time between sending our ticcmd and receiving from the server static fixed_t average_latency; #define NET_CL_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b)) // Called when we become disconnected from the server static void NET_CL_Disconnected(void) { D_ReceiveTic(NULL, NULL); } // Expand a net_full_ticcmd_t, applying the diffs in cmd->cmds as // patches against recvwindow_cmd_base. Place the results into // the d_net.c structures (netcmds/nettics) and save the new ticcmd // back into recvwindow_cmd_base. static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq, ticcmd_t *ticcmds) { int latency; fixed_t adjustment; int i; // Update average_latency if (seq == send_queue[seq % BACKUPTICS].seq) { latency = I_GetTimeMS() - send_queue[seq % BACKUPTICS].time; } else if (seq > send_queue[seq % BACKUPTICS].seq) { // We have received the ticcmd from the server before we have // even sent ours latency = 0; } else { latency = -1; } if (latency >= 0) { if (seq <= 20) { average_latency = latency * FRACUNIT; } else { // Low level filter average_latency = (fixed_t)((average_latency * 0.9) + (latency * FRACUNIT * 0.1)); } } //printf("latency: %i\tremote:%i\n", average_latency / FRACUNIT, // cmd->latency); // Possibly adjust offsetms in d_net.c, try to make players all have // the same lag. Don't adjust in the first few tics of play, as // we don't have an accurate value for average_latency yet. if (seq > TICRATE) { adjustment = (cmd->latency * FRACUNIT) - average_latency; // Only adjust very slightly; the cumulative effect over // multiple tics will sort it out. adjustment = adjustment / 100; offsetms += adjustment; } // Expand tic diffs for all players for (i=0; iplayeringame[i]) { net_ticdiff_t *diff; diff = &cmd->cmds[i]; // Use the ticcmd diff to patch the previous ticcmd to // the new ticcmd NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmds[i]); // Store a copy for next time recvwindow_cmd_base[i] = ticcmds[i]; } } } // Advance the receive window static void NET_CL_AdvanceWindow(void) { ticcmd_t ticcmds[NET_MAXPLAYERS]; while (recvwindow[0].active) { // Expand tic diff data into d_net.c structures NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start, ticcmds); D_ReceiveTic(ticcmds, recvwindow[0].cmd.playeringame); // Advance the window memmove(recvwindow, recvwindow + 1, sizeof(net_server_recv_t) * (BACKUPTICS - 1)); memset(&recvwindow[BACKUPTICS-1], 0, sizeof(net_server_recv_t)); ++recvwindow_start; //printf("CL: advanced to %i\n", recvwindow_start); } } // Shut down the client code, etc. Invoked after a disconnect. static void NET_CL_Shutdown(void) { if (net_client_connected) { net_client_connected = false; NET_FreeAddress(server_addr); // Shut down network module, etc. To do. } } void NET_CL_LaunchGame(void) { NET_Conn_NewReliable(&client_connection, NET_PACKET_TYPE_LAUNCH); } void NET_CL_StartGame(net_gamesettings_t *settings) { net_packet_t *packet; // Start from a ticcmd of all zeros memset(&last_ticcmd, 0, sizeof(ticcmd_t)); // Send packet packet = NET_Conn_NewReliable(&client_connection, NET_PACKET_TYPE_GAMESTART); NET_WriteSettings(packet, settings); } static void NET_CL_SendGameDataACK(void) { net_packet_t *packet; packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_ACK); NET_WriteInt8(packet, recvwindow_start & 0xff); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); need_to_acknowledge = false; } static void NET_CL_SendTics(int start, int end) { net_packet_t *packet; int i; if (!net_client_connected) { // Disconnected from server return; } if (start < 0) start = 0; // Build a new packet to send to the server packet = NET_NewPacket(512); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA); // Write the start tic and number of tics. Send only the low byte // of start - it can be inferred by the server. NET_WriteInt8(packet, recvwindow_start & 0xff); NET_WriteInt8(packet, start & 0xff); NET_WriteInt8(packet, end - start + 1); // Add the tics. for (i=start; i<=end; ++i) { net_server_send_t *sendobj; sendobj = &send_queue[i % BACKUPTICS]; NET_WriteInt16(packet, average_latency / FRACUNIT); NET_WriteTiccmdDiff(packet, &sendobj->cmd, settings.lowres_turn); } // Send the packet NET_Conn_SendPacket(&client_connection, packet); // All done! NET_FreePacket(packet); // Acknowledgement has been sent as part of the packet need_to_acknowledge = false; } // Add a new ticcmd to the send queue void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic) { net_ticdiff_t diff; net_server_send_t *sendobj; int starttic, endtic; // Calculate the difference to the last ticcmd NET_TiccmdDiff(&last_ticcmd, ticcmd, &diff); // Store in the send queue sendobj = &send_queue[maketic % BACKUPTICS]; sendobj->active = true; sendobj->seq = maketic; sendobj->time = I_GetTimeMS(); sendobj->cmd = diff; last_ticcmd = *ticcmd; // Send to server. starttic = maketic - settings.extratics; endtic = maketic; if (starttic < 0) starttic = 0; NET_CL_SendTics(starttic, endtic); } // data received while we are waiting for the game to start static void NET_CL_ParseWaitingData(net_packet_t *packet) { net_waitdata_t wait_data; if (!NET_ReadWaitData(packet, &wait_data)) { // Invalid packet? return; } if (wait_data.num_players > wait_data.max_players || wait_data.ready_players > wait_data.num_players || wait_data.max_players > NET_MAXPLAYERS) { // insane data return; } if ((wait_data.consoleplayer >= 0 && drone) || (wait_data.consoleplayer < 0 && !drone) || (wait_data.consoleplayer >= wait_data.num_players)) { // Invalid player number return; } memcpy(&net_client_wait_data, &wait_data, sizeof(net_waitdata_t)); net_client_received_wait_data = true; } static void NET_CL_ParseLaunch(net_packet_t *packet) { unsigned int num_players; if (client_state != CLIENT_STATE_WAITING_LAUNCH) { return; } // The launch packet contains the number of players that will be // in the game when it starts, so that we can do the startup // progress indicator (the wait data is unreliable). if (!NET_ReadInt8(packet, &num_players)) { return; } net_client_wait_data.num_players = num_players; client_state = CLIENT_STATE_WAITING_START; } static void NET_CL_ParseGameStart(net_packet_t *packet) { if (!NET_ReadSettings(packet, &settings)) { return; } if (client_state != CLIENT_STATE_WAITING_START) { return; } if (settings.num_players > NET_MAXPLAYERS || settings.consoleplayer >= (signed int) settings.num_players) { // insane values return; } if ((drone && settings.consoleplayer >= 0) || (!drone && settings.consoleplayer < 0)) { // Invalid player number: must be positive for real players, // negative for drones return; } client_state = CLIENT_STATE_IN_GAME; // Clear the receive window memset(recvwindow, 0, sizeof(recvwindow)); recvwindow_start = 0; memset(&recvwindow_cmd_base, 0, sizeof(recvwindow_cmd_base)); // Clear the send queue memset(&send_queue, 0x00, sizeof(send_queue)); } static void NET_CL_SendResendRequest(int start, int end) { net_packet_t *packet; unsigned int nowtime; int i; //printf("CL: Send resend %i-%i\n", start, end); packet = NET_NewPacket(64); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND); NET_WriteInt32(packet, start); NET_WriteInt8(packet, end - start + 1); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); nowtime = I_GetTimeMS(); // Save the time we sent the resend request for (i=start; i<=end; ++i) { int index; index = i - recvwindow_start; if (index < 0 || index >= BACKUPTICS) continue; recvwindow[index].resend_time = nowtime; } } // Check for expired resend requests static void NET_CL_CheckResends(void) { int i; int resend_start, resend_end; unsigned int nowtime; nowtime = I_GetTimeMS(); resend_start = -1; resend_end = -1; for (i=0; iactive && recvobj->resend_time != 0 && nowtime > recvobj->resend_time + 300; if (need_resend) { // Start a new run of resend tics? if (resend_start < 0) { resend_start = i; } resend_end = i; } else { if (resend_start >= 0) { // End of a run of resend tics //printf("CL: resend request timed out: %i-%i\n", resend_start, resend_end); NET_CL_SendResendRequest(recvwindow_start + resend_start, recvwindow_start + resend_end); resend_start = -1; } } } if (resend_start >= 0) { //printf("CL: resend request timed out: %i-%i\n", resend_start, resend_end); NET_CL_SendResendRequest(recvwindow_start + resend_start, recvwindow_start + resend_end); } // We have received some data from the server and not acknowledged // it yet. Normally this gets acknowledged when we send our game // data, but if the client is a drone we need to do this. if (need_to_acknowledge && nowtime - gamedata_recv_time > 200) { NET_CL_SendGameDataACK(); } } // Parsing of NET_PACKET_TYPE_GAMEDATA packets // (packets containing the actual ticcmd data) static void NET_CL_ParseGameData(net_packet_t *packet) { net_server_recv_t *recvobj; unsigned int seq, num_tics; unsigned int nowtime; int resend_start, resend_end; size_t i; int index; // Read header if (!NET_ReadInt8(packet, &seq) || !NET_ReadInt8(packet, &num_tics)) { return; } nowtime = I_GetTimeMS(); // Whatever happens, we now need to send an acknowledgement of our // current receive point. if (!need_to_acknowledge) { need_to_acknowledge = true; gamedata_recv_time = nowtime; } // Expand byte value into the full tic number seq = NET_CL_ExpandTicNum(seq); for (i=0; i= BACKUPTICS) { // Out of range of the recv window continue; } // Store in the receive window recvobj = &recvwindow[index]; recvobj->active = true; recvobj->cmd = cmd; } // Has this been received out of sequence, ie. have we not received // all tics before the first tic in this packet? If so, send a // resend request. //printf("CL: %p: %i\n", client, seq); resend_end = seq - recvwindow_start; if (resend_end <= 0) return; if (resend_end >= BACKUPTICS) resend_end = BACKUPTICS - 1; index = resend_end - 1; resend_start = resend_end; while (index >= 0) { recvobj = &recvwindow[index]; if (recvobj->active) { // ended our run of unreceived tics break; } if (recvobj->resend_time != 0) { // Already sent a resend request for this tic break; } resend_start = index; --index; } // Possibly send a resend request if (resend_start < resend_end) { NET_CL_SendResendRequest(recvwindow_start + resend_start, recvwindow_start + resend_end - 1); } } // Parse a resend request from the server due to a dropped packet static void NET_CL_ParseResendRequest(net_packet_t *packet) { static unsigned int start; static unsigned int end; static unsigned int num_tics; if (drone) { // Drones don't send gamedata. return; } if (!NET_ReadInt32(packet, &start) || !NET_ReadInt8(packet, &num_tics)) { return; } end = start + num_tics - 1; //printf("requested resend %i-%i .. ", start, end); // Check we have the tics being requested. If not, reduce the // window of tics to only what we have. while (start <= end && (!send_queue[start % BACKUPTICS].active || send_queue[start % BACKUPTICS].seq != start)) { ++start; } while (start <= end && (!send_queue[end % BACKUPTICS].active || send_queue[end % BACKUPTICS].seq != end)) { --end; } //printf("%i-%i\n", start, end); // Resend those tics if (start <= end) { //printf("CL: resend %i-%i\n", start, start+num_tics-1); NET_CL_SendTics(start, end); } } // Console message that the server wants the client to print static void NET_CL_ParseConsoleMessage(net_packet_t *packet) { char *msg; msg = NET_ReadString(packet); if (msg == NULL) { return; } printf("Message from server: "); NET_SafePuts(msg); } // parse a received packet static void NET_CL_ParsePacket(net_packet_t *packet) { unsigned int packet_type; if (!NET_ReadInt16(packet, &packet_type)) { return; } if (NET_Conn_Packet(&client_connection, packet, &packet_type)) { // Packet eaten by the common connection code } else { switch (packet_type) { case NET_PACKET_TYPE_WAITING_DATA: NET_CL_ParseWaitingData(packet); break; case NET_PACKET_TYPE_LAUNCH: NET_CL_ParseLaunch(packet); break; case NET_PACKET_TYPE_GAMESTART: NET_CL_ParseGameStart(packet); break; case NET_PACKET_TYPE_GAMEDATA: NET_CL_ParseGameData(packet); break; case NET_PACKET_TYPE_GAMEDATA_RESEND: NET_CL_ParseResendRequest(packet); break; case NET_PACKET_TYPE_CONSOLE_MESSAGE: NET_CL_ParseConsoleMessage(packet); break; default: break; } } } // "Run" the client code: check for new packets, send packets as // needed void NET_CL_Run(void) { net_addr_t *addr; net_packet_t *packet; if (!net_client_connected) { return; } while (NET_RecvPacket(client_context, &addr, &packet)) { // only accept packets from the server if (addr == server_addr) { NET_CL_ParsePacket(packet); } else { NET_FreeAddress(addr); } NET_FreePacket(packet); } // Run the common connection code to send any packets as needed NET_Conn_Run(&client_connection); if (client_connection.state == NET_CONN_STATE_DISCONNECTED || client_connection.state == NET_CONN_STATE_DISCONNECTED_SLEEP) { NET_CL_Disconnected(); NET_CL_Shutdown(); } net_waiting_for_launch = client_connection.state == NET_CONN_STATE_CONNECTED && client_state == CLIENT_STATE_WAITING_LAUNCH; if (client_state == CLIENT_STATE_IN_GAME) { // Possibly advance the receive window NET_CL_AdvanceWindow(); // Check if our resend requests have timed out NET_CL_CheckResends(); } } static void NET_CL_SendSYN(net_connect_data_t *data) { net_packet_t *packet; packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_SYN); NET_WriteInt32(packet, NET_MAGIC_NUMBER); NET_WriteString(packet, PACKAGE_STRING); NET_WriteConnectData(packet, data); NET_WriteString(packet, net_player_name); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); } // connect to a server boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data) { int start_time; int last_send_time; server_addr = addr; memcpy(net_local_wad_sha1sum, data->wad_sha1sum, sizeof(sha1_digest_t)); memcpy(net_local_deh_sha1sum, data->deh_sha1sum, sizeof(sha1_digest_t)); net_local_is_freedoom = data->is_freedoom; // create a new network I/O context and add just the // necessary module client_context = NET_NewContext(); // initialize module for client mode if (!addr->module->InitClient()) { return false; } NET_AddModule(client_context, addr->module); net_client_connected = true; net_client_received_wait_data = false; // Initialize connection NET_Conn_InitClient(&client_connection, addr); // try to connect start_time = I_GetTimeMS(); last_send_time = -1; while (client_connection.state == NET_CONN_STATE_CONNECTING) { int nowtime = I_GetTimeMS(); // Send a SYN packet every second. if (nowtime - last_send_time > 1000 || last_send_time < 0) { NET_CL_SendSYN(data); last_send_time = nowtime; } // time out after 5 seconds if (nowtime - start_time > 5000) { break; } // run client code NET_CL_Run(); // run the server, just incase we are doing a loopback // connect NET_SV_Run(); // Don't hog the CPU I_Sleep(1); } if (client_connection.state == NET_CONN_STATE_CONNECTED) { // connected ok! client_state = CLIENT_STATE_WAITING_LAUNCH; drone = data->drone; return true; } else { // failed to connect NET_CL_Shutdown(); return false; } } // read game settings received from server boolean NET_CL_GetSettings(net_gamesettings_t *_settings) { if (client_state != CLIENT_STATE_IN_GAME) { return false; } memcpy(_settings, &settings, sizeof(net_gamesettings_t)); return true; } // disconnect from the server void NET_CL_Disconnect(void) { int start_time; if (!net_client_connected) { return; } NET_Conn_Disconnect(&client_connection); start_time = I_GetTimeMS(); while (client_connection.state != NET_CONN_STATE_DISCONNECTED && client_connection.state != NET_CONN_STATE_DISCONNECTED_SLEEP) { if (I_GetTimeMS() - start_time > 5000) { // time out after 5 seconds client_state = CLIENT_STATE_WAITING_START; fprintf(stderr, "NET_CL_Disconnect: Timeout while disconnecting from server\n"); break; } NET_CL_Run(); NET_SV_Run(); I_Sleep(1); } // Finished sending disconnect packets, etc. NET_CL_Shutdown(); } void NET_CL_Init(void) { // Try to set from the USER and USERNAME environment variables // Otherwise, fallback to "Player" if (net_player_name == NULL) net_player_name = getenv("USER"); if (net_player_name == NULL) net_player_name = getenv("USERNAME"); // On Windows, environment variables are in OEM codepage // encoding, so convert to UTF8: #ifdef _WIN32 if (net_player_name != NULL) { net_player_name = M_OEMToUTF8(net_player_name); } #endif if (net_player_name == NULL) net_player_name = "Player"; } void NET_Init(void) { NET_CL_Init(); } void NET_BindVariables(void) { M_BindStringVariable("player_name", &net_player_name); } chocolate-doom-chocolate-doom-2.2.1/src/net_client.h000066400000000000000000000031231257432200600223700ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Network client code // #ifndef NET_CLIENT_H #define NET_CLIENT_H #include "doomtype.h" #include "d_ticcmd.h" #include "sha1.h" #include "net_defs.h" boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data); void NET_CL_Disconnect(void); void NET_CL_Run(void); void NET_CL_Init(void); void NET_CL_LaunchGame(void); void NET_CL_StartGame(net_gamesettings_t *settings); void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic); boolean NET_CL_GetSettings(net_gamesettings_t *_settings); void NET_Init(void); void NET_BindVariables(void); extern boolean net_client_connected; extern boolean net_client_received_wait_data; extern net_waitdata_t net_client_wait_data; extern boolean net_waiting_for_launch; extern char *net_player_name; extern sha1_digest_t net_server_wad_sha1sum; extern sha1_digest_t net_server_deh_sha1sum; extern unsigned int net_server_is_freedoom; extern sha1_digest_t net_local_wad_sha1sum; extern sha1_digest_t net_local_deh_sha1sum; extern unsigned int net_local_is_freedoom; extern boolean drone; #endif /* #ifndef NET_CLIENT_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_common.c000066400000000000000000000333141257432200600224020ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Common code shared between the client and server // #include #include #include "doomtype.h" #include "d_mode.h" #include "i_timer.h" #include "net_common.h" #include "net_io.h" #include "net_packet.h" #include "net_structrw.h" // connections time out after 30 seconds #define CONNECTION_TIMEOUT_LEN 30 // maximum time between sending packets #define KEEPALIVE_PERIOD 1 // reliable packet that is guaranteed to reach its destination struct net_reliable_packet_s { net_packet_t *packet; int last_send_time; int seq; net_reliable_packet_t *next; }; static void NET_Conn_Init(net_connection_t *conn, net_addr_t *addr) { conn->last_send_time = -1; conn->num_retries = 0; conn->addr = addr; conn->reliable_packets = NULL; conn->reliable_send_seq = 0; conn->reliable_recv_seq = 0; } // Initialize as a client connection void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr) { NET_Conn_Init(conn, addr); conn->state = NET_CONN_STATE_CONNECTING; } // Initialize as a server connection void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr) { NET_Conn_Init(conn, addr); conn->state = NET_CONN_STATE_WAITING_ACK; } // Send a packet to a connection // All packets should be sent through this interface, as it maintains the // keepalive_send_time counter. void NET_Conn_SendPacket(net_connection_t *conn, net_packet_t *packet) { conn->keepalive_send_time = I_GetTimeMS(); NET_SendPacket(conn->addr, packet); } // parse an ACK packet from a client static void NET_Conn_ParseACK(net_connection_t *conn, net_packet_t *packet) { net_packet_t *reply; if (conn->state == NET_CONN_STATE_CONNECTING) { // We are a client // received a response from the server to our SYN conn->state = NET_CONN_STATE_CONNECTED; // We must send an ACK reply to the server's ACK reply = NET_NewPacket(10); NET_WriteInt16(reply, NET_PACKET_TYPE_ACK); NET_Conn_SendPacket(conn, reply); NET_FreePacket(reply); } if (conn->state == NET_CONN_STATE_WAITING_ACK) { // We are a server // Client is connected conn->state = NET_CONN_STATE_CONNECTED; } } static void NET_Conn_ParseDisconnect(net_connection_t *conn, net_packet_t *packet) { net_packet_t *reply; // Other end wants to disconnect // Send a DISCONNECT_ACK reply. reply = NET_NewPacket(10); NET_WriteInt16(reply, NET_PACKET_TYPE_DISCONNECT_ACK); NET_Conn_SendPacket(conn, reply); NET_FreePacket(reply); conn->last_send_time = I_GetTimeMS(); conn->state = NET_CONN_STATE_DISCONNECTED_SLEEP; conn->disconnect_reason = NET_DISCONNECT_REMOTE; } // Parse a DISCONNECT_ACK packet static void NET_Conn_ParseDisconnectACK(net_connection_t *conn, net_packet_t *packet) { if (conn->state == NET_CONN_STATE_DISCONNECTING) { // We have received an acknowledgement to our disconnect // request. We have been disconnected successfully. conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_LOCAL; conn->last_send_time = -1; } } static void NET_Conn_ParseReject(net_connection_t *conn, net_packet_t *packet) { char *msg; msg = NET_ReadString(packet); if (msg == NULL) { return; } if (conn->state == NET_CONN_STATE_CONNECTING) { // rejected by server conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_REMOTE; printf("Rejected by server: "); NET_SafePuts(msg); } } static void NET_Conn_ParseReliableACK(net_connection_t *conn, net_packet_t *packet) { unsigned int seq; if (!NET_ReadInt8(packet, &seq)) { return; } if (conn->reliable_packets == NULL) { return; } // Is this an acknowledgement for the first packet in the list? if (seq == (unsigned int)((conn->reliable_packets->seq + 1) & 0xff)) { net_reliable_packet_t *rp; // Discard it, then. // Unlink from the list. rp = conn->reliable_packets; conn->reliable_packets = rp->next; NET_FreePacket(rp->packet); free(rp); } } // Process the header of a reliable packet // // Returns true if the packet should be discarded (incorrect sequence) static boolean NET_Conn_ReliablePacket(net_connection_t *conn, net_packet_t *packet) { unsigned int seq; net_packet_t *reply; boolean result; // Read the sequence number if (!NET_ReadInt8(packet, &seq)) { return true; } if (seq != (unsigned int)(conn->reliable_recv_seq & 0xff)) { // This is not the next expected packet in the sequence! // // Discard the packet. If we were smart, we would use a proper // sliding window protocol to do this, but I'm lazy. result = true; } else { // Now we can receive the next packet in the sequence. conn->reliable_recv_seq = (conn->reliable_recv_seq + 1) & 0xff; result = false; } // Send an acknowledgement // Note: this is braindead. It would be much more sensible to // include this in the next packet, rather than the overhead of // sending a complete packet just for one byte of information. reply = NET_NewPacket(10); NET_WriteInt16(reply, NET_PACKET_TYPE_RELIABLE_ACK); NET_WriteInt8(reply, conn->reliable_recv_seq & 0xff); NET_Conn_SendPacket(conn, reply); NET_FreePacket(reply); return result; } // Process a packet received by the server // // Returns true if eaten by common code boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet, unsigned int *packet_type) { conn->keepalive_recv_time = I_GetTimeMS(); // Is this a reliable packet? if (*packet_type & NET_RELIABLE_PACKET) { if (NET_Conn_ReliablePacket(conn, packet)) { // Invalid packet: eat it. return true; } // Remove the reliable bit *packet_type &= ~NET_RELIABLE_PACKET; } switch (*packet_type) { case NET_PACKET_TYPE_ACK: NET_Conn_ParseACK(conn, packet); break; case NET_PACKET_TYPE_DISCONNECT: NET_Conn_ParseDisconnect(conn, packet); break; case NET_PACKET_TYPE_DISCONNECT_ACK: NET_Conn_ParseDisconnectACK(conn, packet); break; case NET_PACKET_TYPE_KEEPALIVE: // No special action needed. break; case NET_PACKET_TYPE_REJECTED: NET_Conn_ParseReject(conn, packet); break; case NET_PACKET_TYPE_RELIABLE_ACK: NET_Conn_ParseReliableACK(conn, packet); break; default: // Not a common packet return false; } // We found a packet that we found interesting, and ate it. return true; } void NET_Conn_Disconnect(net_connection_t *conn) { if (conn->state != NET_CONN_STATE_DISCONNECTED && conn->state != NET_CONN_STATE_DISCONNECTING && conn->state != NET_CONN_STATE_DISCONNECTED_SLEEP) { conn->state = NET_CONN_STATE_DISCONNECTING; conn->disconnect_reason = NET_DISCONNECT_LOCAL; conn->last_send_time = -1; conn->num_retries = 0; } } void NET_Conn_Run(net_connection_t *conn) { net_packet_t *packet; unsigned int nowtime; nowtime = I_GetTimeMS(); if (conn->state == NET_CONN_STATE_CONNECTED) { // Check the keepalive counters if (nowtime - conn->keepalive_recv_time > CONNECTION_TIMEOUT_LEN * 1000) { // Haven't received any packets from the other end in a long // time. Assume disconnected. conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_TIMEOUT; } if (nowtime - conn->keepalive_send_time > KEEPALIVE_PERIOD * 1000) { // We have not sent anything in a long time. // Send a keepalive. packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_KEEPALIVE); NET_Conn_SendPacket(conn, packet); NET_FreePacket(packet); } // Check the reliable packet list. Has the first packet in the // list timed out? // // NB. This is braindead, we have a fixed time of one second. if (conn->reliable_packets != NULL && (conn->reliable_packets->last_send_time < 0 || nowtime - conn->reliable_packets->last_send_time > 1000)) { // Packet timed out, time to resend NET_Conn_SendPacket(conn, conn->reliable_packets->packet); conn->reliable_packets->last_send_time = nowtime; } } else if (conn->state == NET_CONN_STATE_WAITING_ACK) { if (conn->last_send_time < 0 || nowtime - conn->last_send_time > 1000) { // it has been a second since the last ACK was sent, and // still no reply. if (conn->num_retries < MAX_RETRIES) { // send another ACK packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_ACK); NET_Conn_SendPacket(conn, packet); NET_FreePacket(packet); conn->last_send_time = nowtime; ++conn->num_retries; } else { // no more retries allowed. conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_TIMEOUT; } } } else if (conn->state == NET_CONN_STATE_DISCONNECTING) { // Waiting for a reply to our DISCONNECT request. if (conn->last_send_time < 0 || nowtime - conn->last_send_time > 1000) { // it has been a second since the last disconnect packet // was sent, and still no reply. if (conn->num_retries < MAX_RETRIES) { // send another disconnect packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_DISCONNECT); NET_Conn_SendPacket(conn, packet); NET_FreePacket(packet); conn->last_send_time = nowtime; ++conn->num_retries; } else { // No more retries allowed. // Force disconnect. conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_LOCAL; } } } else if (conn->state == NET_CONN_STATE_DISCONNECTED_SLEEP) { // We are disconnected, waiting in case we need to send // a DISCONNECT_ACK to the server again. if (nowtime - conn->last_send_time > 5000) { // Idle for 5 seconds, switch state conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_REMOTE; } } } net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type) { net_packet_t *packet; net_reliable_packet_t *rp; net_reliable_packet_t **listend; // Generate a packet with the right header packet = NET_NewPacket(100); NET_WriteInt16(packet, packet_type | NET_RELIABLE_PACKET); // write the low byte of the send sequence number NET_WriteInt8(packet, conn->reliable_send_seq & 0xff); // Add to the list of reliable packets rp = malloc(sizeof(net_reliable_packet_t)); rp->packet = packet; rp->next = NULL; rp->seq = conn->reliable_send_seq; rp->last_send_time = -1; for (listend = &conn->reliable_packets; *listend != NULL; listend = &((*listend)->next)); *listend = rp; // Count along the sequence conn->reliable_send_seq = (conn->reliable_send_seq + 1) & 0xff; // Finished return packet; } // Used to expand the least significant byte of a tic number into // the full tic number, from the current tic number unsigned int NET_ExpandTicNum(unsigned int relative, unsigned int b) { unsigned int l, h; unsigned int result; h = relative & ~0xff; l = relative & 0xff; result = h | b; if (l < 0x40 && b > 0xb0) result -= 0x100; if (l > 0xb0 && b < 0x40) result += 0x100; return result; } // Check that game settings are valid boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission, net_gamesettings_t *settings) { if (settings->ticdup <= 0) return false; if (settings->extratics < 0) return false; if (settings->deathmatch < 0 || settings->deathmatch > 2) return false; if (settings->skill < sk_noitems || settings->skill > sk_nightmare) return false; if (!D_ValidGameVersion(mission, settings->gameversion)) return false; if (!D_ValidEpisodeMap(mission, mode, settings->episode, settings->map)) return false; return true; } chocolate-doom-chocolate-doom-2.2.1/src/net_common.h000066400000000000000000000060541257432200600224100ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Common code shared between the client and server // #ifndef NET_COMMON_H #define NET_COMMON_H #include "d_mode.h" #include "net_defs.h" #include "net_packet.h" typedef enum { // sending syn packets, waiting for an ACK reply // (client side) NET_CONN_STATE_CONNECTING, // received a syn, sent an ack, waiting for an ack reply // (server side) NET_CONN_STATE_WAITING_ACK, // successfully connected NET_CONN_STATE_CONNECTED, // sent a DISCONNECT packet, waiting for a DISCONNECT_ACK reply NET_CONN_STATE_DISCONNECTING, // client successfully disconnected NET_CONN_STATE_DISCONNECTED, // We are disconnected, but in a sleep state, waiting for several // seconds. This is in case the DISCONNECT_ACK we sent failed // to arrive, and we need to send another one. We keep this as // a valid connection for a few seconds until we are sure that // the other end has successfully disconnected as well. NET_CONN_STATE_DISCONNECTED_SLEEP, } net_connstate_t; // Reason a connection was terminated typedef enum { // As the result of a local disconnect request NET_DISCONNECT_LOCAL, // As the result of a remote disconnect request NET_DISCONNECT_REMOTE, // Timeout (no data received in a long time) NET_DISCONNECT_TIMEOUT, } net_disconnect_reason_t; #define MAX_RETRIES 5 typedef struct net_reliable_packet_s net_reliable_packet_t; typedef struct { net_connstate_t state; net_disconnect_reason_t disconnect_reason; net_addr_t *addr; int last_send_time; int num_retries; int keepalive_send_time; int keepalive_recv_time; net_reliable_packet_t *reliable_packets; int reliable_send_seq; int reliable_recv_seq; } net_connection_t; void NET_Conn_SendPacket(net_connection_t *conn, net_packet_t *packet); void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr); void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr); boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet, unsigned int *packet_type); void NET_Conn_Disconnect(net_connection_t *conn); void NET_Conn_Run(net_connection_t *conn); net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type); // Other miscellaneous common functions unsigned int NET_ExpandTicNum(unsigned int relative, unsigned int b); boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission, net_gamesettings_t *settings); #endif /* #ifndef NET_COMMON_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_dedicated.c000066400000000000000000000040661257432200600230220ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Dedicated server code. // #include #include #include "doomtype.h" #include "i_system.h" #include "i_timer.h" #include "m_argv.h" #include "net_defs.h" #include "net_sdl.h" #include "net_server.h" // // People can become confused about how dedicated servers work. Game // options are specified to the controlling player who is the first to // join a game. Bomb out with an error message if game options are // specified to a dedicated server. // static char *not_dedicated_options[] = { "-deh", "-iwad", "-cdrom", "-gameversion", "-nomonsters", "-respawn", "-fast", "-altdeath", "-deathmatch", "-turbo", "-merge", "-af", "-as", "-aa", "-file", "-wart", "-skill", "-episode", "-timer", "-avg", "-warp", "-loadgame", "-longtics", "-extratics", "-dup", NULL, }; static void CheckForClientOptions(void) { int i; for (i=0; not_dedicated_options[i] != NULL; ++i) { if (M_CheckParm(not_dedicated_options[i]) > 0) { I_Error("The command line parameter '%s' was specified to a " "dedicated server.\nGame parameters should be specified " "to the first player to join a server, \nnot to the " "server itself. ", not_dedicated_options[i]); } } } void NET_DedicatedServer(void) { CheckForClientOptions(); NET_SV_Init(); NET_SV_AddModule(&net_sdl_module); NET_SV_RegisterWithMaster(); while (true) { NET_SV_Run(); I_Sleep(10); } } chocolate-doom-chocolate-doom-2.2.1/src/net_dedicated.h000066400000000000000000000013001257432200600230130ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Dedicated server code. // #ifndef NET_DEDICATED_H #define NET_DEDICATED_H void NET_DedicatedServer(void); #endif /* #ifndef NET_DEDICATED_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_defs.h000066400000000000000000000134341257432200600220410ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Definitions for use in networking code. // #ifndef NET_DEFS_H #define NET_DEFS_H #include #include "doomtype.h" #include "d_ticcmd.h" #include "sha1.h" // Absolute maximum number of "nodes" in the game. This is different to // NET_MAXPLAYERS, as there may be observers that are not participating // (eg. left/right monitors) #define MAXNETNODES 16 // The maximum number of players, multiplayer/networking. // This is the maximum supported by the networking code; individual games // have their own values for MAXPLAYERS that can be smaller. #define NET_MAXPLAYERS 8 // Maximum length of a player's name. #define MAXPLAYERNAME 30 // Networking and tick handling related. #define BACKUPTICS 128 typedef struct _net_module_s net_module_t; typedef struct _net_packet_s net_packet_t; typedef struct _net_addr_s net_addr_t; typedef struct _net_context_s net_context_t; struct _net_packet_s { byte *data; size_t len; size_t alloced; unsigned int pos; }; struct _net_module_s { // Initialize this module for use as a client boolean (*InitClient)(void); // Initialize this module for use as a server boolean (*InitServer)(void); // Send a packet void (*SendPacket)(net_addr_t *addr, net_packet_t *packet); // Check for new packets to receive // // Returns true if packet received boolean (*RecvPacket)(net_addr_t **addr, net_packet_t **packet); // Converts an address to a string void (*AddrToString)(net_addr_t *addr, char *buffer, int buffer_len); // Free back an address when no longer in use void (*FreeAddress)(net_addr_t *addr); // Try to resolve a name to an address net_addr_t *(*ResolveAddress)(char *addr); }; // net_addr_t struct _net_addr_s { net_module_t *module; void *handle; }; // magic number sent when connecting to check this is a valid client #define NET_MAGIC_NUMBER 3436803284U // header field value indicating that the packet is a reliable packet #define NET_RELIABLE_PACKET (1 << 15) // packet types typedef enum { NET_PACKET_TYPE_SYN, NET_PACKET_TYPE_ACK, NET_PACKET_TYPE_REJECTED, NET_PACKET_TYPE_KEEPALIVE, NET_PACKET_TYPE_WAITING_DATA, NET_PACKET_TYPE_GAMESTART, NET_PACKET_TYPE_GAMEDATA, NET_PACKET_TYPE_GAMEDATA_ACK, NET_PACKET_TYPE_DISCONNECT, NET_PACKET_TYPE_DISCONNECT_ACK, NET_PACKET_TYPE_RELIABLE_ACK, NET_PACKET_TYPE_GAMEDATA_RESEND, NET_PACKET_TYPE_CONSOLE_MESSAGE, NET_PACKET_TYPE_QUERY, NET_PACKET_TYPE_QUERY_RESPONSE, NET_PACKET_TYPE_LAUNCH, } net_packet_type_t; typedef enum { NET_MASTER_PACKET_TYPE_ADD, NET_MASTER_PACKET_TYPE_ADD_RESPONSE, NET_MASTER_PACKET_TYPE_QUERY, NET_MASTER_PACKET_TYPE_QUERY_RESPONSE, NET_MASTER_PACKET_TYPE_GET_METADATA, NET_MASTER_PACKET_TYPE_GET_METADATA_RESPONSE, NET_MASTER_PACKET_TYPE_SIGN_START, NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE, NET_MASTER_PACKET_TYPE_SIGN_END, NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE, } net_master_packet_type_t; // Settings specified when the client connects to the server. typedef struct { int gamemode; int gamemission; int lowres_turn; int drone; int max_players; int is_freedoom; sha1_digest_t wad_sha1sum; sha1_digest_t deh_sha1sum; int player_class; } net_connect_data_t; // Game settings sent by client to server when initiating game start, // and received from the server by clients when the game starts. typedef struct { int ticdup; int extratics; int deathmatch; int episode; int nomonsters; int fast_monsters; int respawn_monsters; int map; int skill; int gameversion; int lowres_turn; int new_sync; int timelimit; int loadgame; int random; // [Strife only] // These fields are only used by the server when sending a game // start message: int num_players; int consoleplayer; // Hexen player classes: int player_classes[NET_MAXPLAYERS]; } net_gamesettings_t; #define NET_TICDIFF_FORWARD (1 << 0) #define NET_TICDIFF_SIDE (1 << 1) #define NET_TICDIFF_TURN (1 << 2) #define NET_TICDIFF_BUTTONS (1 << 3) #define NET_TICDIFF_CONSISTANCY (1 << 4) #define NET_TICDIFF_CHATCHAR (1 << 5) #define NET_TICDIFF_RAVEN (1 << 6) #define NET_TICDIFF_STRIFE (1 << 7) typedef struct { unsigned int diff; ticcmd_t cmd; } net_ticdiff_t; // Complete set of ticcmds from all players typedef struct { signed int latency; unsigned int seq; boolean playeringame[NET_MAXPLAYERS]; net_ticdiff_t cmds[NET_MAXPLAYERS]; } net_full_ticcmd_t; // Data sent in response to server queries typedef struct { char *version; int server_state; int num_players; int max_players; int gamemode; int gamemission; char *description; } net_querydata_t; // Data sent by the server while waiting for the game to start. typedef struct { int num_players; int num_drones; int ready_players; int max_players; int is_controller; int consoleplayer; char player_names[NET_MAXPLAYERS][MAXPLAYERNAME]; char player_addrs[NET_MAXPLAYERS][MAXPLAYERNAME]; sha1_digest_t wad_sha1sum; sha1_digest_t deh_sha1sum; int is_freedoom; } net_waitdata_t; #endif /* #ifndef NET_DEFS_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_gui.c000066400000000000000000000257561257432200600217110ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Graphical stuff related to the networking code: // // * The client waiting screen when we are waiting for the server to // start the game. // #include #include #include #include "config.h" #include "doomkeys.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "m_argv.h" #include "m_misc.h" #include "net_client.h" #include "net_gui.h" #include "net_query.h" #include "net_server.h" #include "textscreen.h" static txt_window_t *window; static int old_max_players; static txt_label_t *player_labels[NET_MAXPLAYERS]; static txt_label_t *ip_labels[NET_MAXPLAYERS]; static txt_label_t *drone_label; static txt_label_t *master_msg_label; static boolean had_warning; // Number of players we expect to be in the game. When the number is // reached, we auto-start the game (if we're the controller). If // zero, do not autostart. static int expected_nodes; static void EscapePressed(TXT_UNCAST_ARG(widget), void *unused) { TXT_Shutdown(); I_Quit(); } static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { NET_CL_LaunchGame(); } static void OpenWaitDialog(void) { txt_window_action_t *cancel; TXT_SetDesktopTitle(PACKAGE_STRING); window = TXT_NewWindow("Waiting for game start..."); TXT_AddWidget(window, TXT_NewLabel("\nPlease wait...\n\n")); cancel = TXT_NewWindowAction(KEY_ESCAPE, "Cancel"); TXT_SignalConnect(cancel, "pressed", EscapePressed, NULL); TXT_SetWindowAction(window, TXT_HORIZ_LEFT, cancel); TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_BOTTOM, TXT_SCREEN_W / 2, TXT_SCREEN_H - 9); old_max_players = 0; } static void BuildWindow(void) { char buf[50]; txt_table_t *table; int i; TXT_ClearTable(window); table = TXT_NewTable(3); TXT_AddWidget(window, table); // Add spacers TXT_AddWidget(table, NULL); TXT_AddWidget(table, TXT_NewStrut(25, 1)); TXT_AddWidget(table, TXT_NewStrut(17, 1)); // Player labels for (i = 0; i < net_client_wait_data.max_players; ++i) { M_snprintf(buf, sizeof(buf), " %i. ", i + 1); TXT_AddWidget(table, TXT_NewLabel(buf)); player_labels[i] = TXT_NewLabel(""); ip_labels[i] = TXT_NewLabel(""); TXT_AddWidget(table, player_labels[i]); TXT_AddWidget(table, ip_labels[i]); } drone_label = TXT_NewLabel(""); TXT_AddWidget(window, drone_label); } static void UpdateGUI(void) { txt_window_action_t *startgame; char buf[50]; unsigned int i; // If the value of max_players changes, we must rebuild the // contents of the window. This includes when the first // waiting data packet is received. if (net_client_received_wait_data) { if (net_client_wait_data.max_players != old_max_players) { BuildWindow(); } } else { return; } for (i = 0; i < net_client_wait_data.max_players; ++i) { txt_color_t color = TXT_COLOR_BRIGHT_WHITE; if ((signed) i == net_client_wait_data.consoleplayer) { color = TXT_COLOR_YELLOW; } TXT_SetFGColor(player_labels[i], color); TXT_SetFGColor(ip_labels[i], color); if (i < net_client_wait_data.num_players) { TXT_SetLabel(player_labels[i], net_client_wait_data.player_names[i]); TXT_SetLabel(ip_labels[i], net_client_wait_data.player_addrs[i]); } else { TXT_SetLabel(player_labels[i], ""); TXT_SetLabel(ip_labels[i], ""); } } if (net_client_wait_data.num_drones > 0) { M_snprintf(buf, sizeof(buf), " (+%i observer clients)", net_client_wait_data.num_drones); TXT_SetLabel(drone_label, buf); } else { TXT_SetLabel(drone_label, ""); } if (net_client_wait_data.is_controller) { startgame = TXT_NewWindowAction(' ', "Start game"); TXT_SignalConnect(startgame, "pressed", StartGame, NULL); } else { startgame = NULL; } TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, startgame); } static void BuildMasterStatusWindow(void) { txt_window_t *master_window; master_window = TXT_NewWindow(NULL); master_msg_label = TXT_NewLabel(""); TXT_AddWidget(master_window, master_msg_label); // This window is here purely for information, so it should be // in the background. TXT_LowerWindow(master_window); TXT_SetWindowPosition(master_window, TXT_HORIZ_CENTER, TXT_VERT_CENTER, TXT_SCREEN_W / 2, TXT_SCREEN_H - 4); TXT_SetWindowAction(master_window, TXT_HORIZ_LEFT, NULL); TXT_SetWindowAction(master_window, TXT_HORIZ_CENTER, NULL); TXT_SetWindowAction(master_window, TXT_HORIZ_RIGHT, NULL); } static void CheckMasterStatus(void) { boolean added; if (!NET_Query_CheckAddedToMaster(&added)) { return; } if (master_msg_label == NULL) { BuildMasterStatusWindow(); } if (added) { TXT_SetLabel(master_msg_label, "Your server is now registered with the global master server.\n" "Other players can find your server online."); } else { TXT_SetLabel(master_msg_label, "Failed to register with the master server. Your server is not\n" "publicly accessible. You may need to reconfigure your Internet\n" "router to add a port forward for UDP port 2342. Look up\n" "information on port forwarding online."); } } static void PrintSHA1Digest(char *s, byte *digest) { unsigned int i; printf("%s: ", s); for (i=0; i // @category net // // Autostart the netgame when n nodes (clients) have joined the server. // i = M_CheckParmWithArgs("-nodes", 1); if (i > 0) { expected_nodes = atoi(myargv[i + 1]); } } static void CheckAutoLaunch(void) { int nodes; if (net_client_received_wait_data && net_client_wait_data.is_controller && expected_nodes > 0) { nodes = net_client_wait_data.num_players + net_client_wait_data.num_drones; if (nodes >= expected_nodes) { StartGame(NULL, NULL); expected_nodes = 0; } } } void NET_WaitForLaunch(void) { if (!TXT_Init()) { fprintf(stderr, "Failed to initialize GUI\n"); exit(-1); } I_InitWindowIcon(); ParseCommandLineArgs(); OpenWaitDialog(); had_warning = false; while (net_waiting_for_launch) { UpdateGUI(); CheckAutoLaunch(); CheckSHA1Sums(); CheckMasterStatus(); TXT_DispatchEvents(); TXT_DrawDesktop(); NET_CL_Run(); NET_SV_Run(); if (!net_client_connected) { I_Error("Lost connection to server"); } TXT_Sleep(100); } TXT_Shutdown(); } chocolate-doom-chocolate-doom-2.2.1/src/net_gui.h000066400000000000000000000014761257432200600217070ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Graphical stuff related to the networking code: // // * The client waiting screen when we are waiting for the server to // start the game. // #ifndef NET_GUI_H #define NET_GUI_H #include "doomtype.h" extern void NET_WaitForLaunch(void); #endif /* #ifndef NET_GUI_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_io.c000066400000000000000000000052661257432200600215260ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Network packet I/O. Base layer for sending/receiving packets, // through the network module system // #include #include "i_system.h" #include "net_defs.h" #include "net_io.h" #include "z_zone.h" #define MAX_MODULES 16 struct _net_context_s { net_module_t *modules[MAX_MODULES]; int num_modules; }; net_addr_t net_broadcast_addr; net_context_t *NET_NewContext(void) { net_context_t *context; context = Z_Malloc(sizeof(net_context_t), PU_STATIC, 0); context->num_modules = 0; return context; } void NET_AddModule(net_context_t *context, net_module_t *module) { if (context->num_modules >= MAX_MODULES) { I_Error("NET_AddModule: No more modules for context"); } context->modules[context->num_modules] = module; ++context->num_modules; } net_addr_t *NET_ResolveAddress(net_context_t *context, char *addr) { int i; net_addr_t *result; result = NULL; for (i=0; inum_modules; ++i) { result = context->modules[i]->ResolveAddress(addr); if (result != NULL) { break; } } return result; } void NET_SendPacket(net_addr_t *addr, net_packet_t *packet) { addr->module->SendPacket(addr, packet); } void NET_SendBroadcast(net_context_t *context, net_packet_t *packet) { int i; for (i=0; inum_modules; ++i) { context->modules[i]->SendPacket(&net_broadcast_addr, packet); } } boolean NET_RecvPacket(net_context_t *context, net_addr_t **addr, net_packet_t **packet) { int i; // check all modules for new packets for (i=0; inum_modules; ++i) { if (context->modules[i]->RecvPacket(addr, packet)) { return true; } } return false; } // Note: this prints into a static buffer, calling again overwrites // the first result char *NET_AddrToString(net_addr_t *addr) { static char buf[128]; addr->module->AddrToString(addr, buf, sizeof(buf) - 1); return buf; } void NET_FreeAddress(net_addr_t *addr) { addr->module->FreeAddress(addr); } chocolate-doom-chocolate-doom-2.2.1/src/net_io.h000066400000000000000000000023431257432200600215240ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Network packet manipulation (net_packet_t) // #ifndef NET_IO_H #define NET_IO_H #include "net_defs.h" extern net_addr_t net_broadcast_addr; net_context_t *NET_NewContext(void); void NET_AddModule(net_context_t *context, net_module_t *module); void NET_SendPacket(net_addr_t *addr, net_packet_t *packet); void NET_SendBroadcast(net_context_t *context, net_packet_t *packet); boolean NET_RecvPacket(net_context_t *context, net_addr_t **addr, net_packet_t **packet); char *NET_AddrToString(net_addr_t *addr); void NET_FreeAddress(net_addr_t *addr); net_addr_t *NET_ResolveAddress(net_context_t *context, char *address); #endif /* #ifndef NET_IO_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_loop.c000066400000000000000000000113141257432200600220570ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Loopback network module for server compiled into the client // #include #include #include "doomtype.h" #include "i_system.h" #include "m_misc.h" #include "net_defs.h" #include "net_loop.h" #include "net_packet.h" #define MAX_QUEUE_SIZE 16 typedef struct { net_packet_t *packets[MAX_QUEUE_SIZE]; int head, tail; } packet_queue_t; static packet_queue_t client_queue; static packet_queue_t server_queue; static net_addr_t client_addr; static net_addr_t server_addr; static void QueueInit(packet_queue_t *queue) { queue->head = queue->tail = 0; } static void QueuePush(packet_queue_t *queue, net_packet_t *packet) { int new_tail; new_tail = (queue->tail + 1) % MAX_QUEUE_SIZE; if (new_tail == queue->head) { // queue is full return; } queue->packets[queue->tail] = packet; queue->tail = new_tail; } static net_packet_t *QueuePop(packet_queue_t *queue) { net_packet_t *packet; if (queue->tail == queue->head) { // queue empty return NULL; } packet = queue->packets[queue->head]; queue->head = (queue->head + 1) % MAX_QUEUE_SIZE; return packet; } //----------------------------------------------------------------------------- // // Client end code // //----------------------------------------------------------------------------- static boolean NET_CL_InitClient(void) { QueueInit(&client_queue); return true; } static boolean NET_CL_InitServer(void) { I_Error("NET_CL_InitServer: attempted to initialize client pipe end as a server!"); return false; } static void NET_CL_SendPacket(net_addr_t *addr, net_packet_t *packet) { QueuePush(&server_queue, NET_PacketDup(packet)); } static boolean NET_CL_RecvPacket(net_addr_t **addr, net_packet_t **packet) { net_packet_t *popped; popped = QueuePop(&client_queue); if (popped != NULL) { *packet = popped; *addr = &client_addr; client_addr.module = &net_loop_client_module; return true; } return false; } static void NET_CL_AddrToString(net_addr_t *addr, char *buffer, int buffer_len) { M_snprintf(buffer, buffer_len, "local server"); } static void NET_CL_FreeAddress(net_addr_t *addr) { } static net_addr_t *NET_CL_ResolveAddress(char *address) { if (address == NULL) { client_addr.module = &net_loop_client_module; return &client_addr; } else { return NULL; } } net_module_t net_loop_client_module = { NET_CL_InitClient, NET_CL_InitServer, NET_CL_SendPacket, NET_CL_RecvPacket, NET_CL_AddrToString, NET_CL_FreeAddress, NET_CL_ResolveAddress, }; //----------------------------------------------------------------------------- // // Server end code // //----------------------------------------------------------------------------- static boolean NET_SV_InitClient(void) { I_Error("NET_SV_InitClient: attempted to initialize server pipe end as a client!"); return false; } static boolean NET_SV_InitServer(void) { QueueInit(&server_queue); return true; } static void NET_SV_SendPacket(net_addr_t *addr, net_packet_t *packet) { QueuePush(&client_queue, NET_PacketDup(packet)); } static boolean NET_SV_RecvPacket(net_addr_t **addr, net_packet_t **packet) { net_packet_t *popped; popped = QueuePop(&server_queue); if (popped != NULL) { *packet = popped; *addr = &server_addr; server_addr.module = &net_loop_server_module; return true; } return false; } static void NET_SV_AddrToString(net_addr_t *addr, char *buffer, int buffer_len) { M_snprintf(buffer, buffer_len, "local client"); } static void NET_SV_FreeAddress(net_addr_t *addr) { } static net_addr_t *NET_SV_ResolveAddress(char *address) { if (address == NULL) { server_addr.module = &net_loop_server_module; return &server_addr; } else { return NULL; } } net_module_t net_loop_server_module = { NET_SV_InitClient, NET_SV_InitServer, NET_SV_SendPacket, NET_SV_RecvPacket, NET_SV_AddrToString, NET_SV_FreeAddress, NET_SV_ResolveAddress, }; chocolate-doom-chocolate-doom-2.2.1/src/net_loop.h000066400000000000000000000014651257432200600220720ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Loopback network module for server compiled into the client // #ifndef NET_LOOP_H #define NET_LOOP_H #include "net_defs.h" extern net_module_t net_loop_client_module; extern net_module_t net_loop_server_module; #endif /* #ifndef NET_LOOP_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_packet.c000066400000000000000000000140511257432200600223560ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Network packet manipulation (net_packet_t) // #include #include "m_misc.h" #include "net_packet.h" #include "z_zone.h" static int total_packet_memory = 0; net_packet_t *NET_NewPacket(int initial_size) { net_packet_t *packet; packet = (net_packet_t *) Z_Malloc(sizeof(net_packet_t), PU_STATIC, 0); if (initial_size == 0) initial_size = 256; packet->alloced = initial_size; packet->data = Z_Malloc(initial_size, PU_STATIC, 0); packet->len = 0; packet->pos = 0; total_packet_memory += sizeof(net_packet_t) + initial_size; //printf("total packet memory: %i bytes\n", total_packet_memory); //printf("%p: allocated\n", packet); return packet; } // duplicates an existing packet net_packet_t *NET_PacketDup(net_packet_t *packet) { net_packet_t *newpacket; newpacket = NET_NewPacket(packet->len); memcpy(newpacket->data, packet->data, packet->len); newpacket->len = packet->len; return newpacket; } void NET_FreePacket(net_packet_t *packet) { //printf("%p: destroyed\n", packet); total_packet_memory -= sizeof(net_packet_t) + packet->alloced; Z_Free(packet->data); Z_Free(packet); } // Read a byte from the packet, returning true if read // successfully boolean NET_ReadInt8(net_packet_t *packet, unsigned int *data) { if (packet->pos + 1 > packet->len) return false; *data = packet->data[packet->pos]; packet->pos += 1; return true; } // Read a 16-bit integer from the packet, returning true if read // successfully boolean NET_ReadInt16(net_packet_t *packet, unsigned int *data) { byte *p; if (packet->pos + 2 > packet->len) return false; p = packet->data + packet->pos; *data = (p[0] << 8) | p[1]; packet->pos += 2; return true; } // Read a 32-bit integer from the packet, returning true if read // successfully boolean NET_ReadInt32(net_packet_t *packet, unsigned int *data) { byte *p; if (packet->pos + 4 > packet->len) return false; p = packet->data + packet->pos; *data = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; packet->pos += 4; return true; } // Signed read functions boolean NET_ReadSInt8(net_packet_t *packet, signed int *data) { if (NET_ReadInt8(packet,(unsigned int *) data)) { if (*data & (1 << 7)) { *data &= ~(1 << 7); *data -= (1 << 7); } return true; } else { return false; } } boolean NET_ReadSInt16(net_packet_t *packet, signed int *data) { if (NET_ReadInt16(packet, (unsigned int *) data)) { if (*data & (1 << 15)) { *data &= ~(1 << 15); *data -= (1 << 15); } return true; } else { return false; } } boolean NET_ReadSInt32(net_packet_t *packet, signed int *data) { if (NET_ReadInt32(packet, (unsigned int *) data)) { if (*data & (1 << 31)) { *data &= ~(1 << 31); *data -= (1 << 31); } return true; } else { return false; } } // Read a string from the packet. Returns NULL if a terminating // NUL character was not found before the end of the packet. char *NET_ReadString(net_packet_t *packet) { char *start; start = (char *) packet->data + packet->pos; // Search forward for a NUL character while (packet->pos < packet->len && packet->data[packet->pos] != '\0') { ++packet->pos; } if (packet->pos >= packet->len) { // Reached the end of the packet return NULL; } // packet->data[packet->pos] == '\0': We have reached a terminating // NULL. Skip past this NULL and continue reading immediately // after it. ++packet->pos; return start; } // Dynamically increases the size of a packet static void NET_IncreasePacket(net_packet_t *packet) { byte *newdata; total_packet_memory -= packet->alloced; packet->alloced *= 2; newdata = Z_Malloc(packet->alloced, PU_STATIC, 0); memcpy(newdata, packet->data, packet->len); Z_Free(packet->data); packet->data = newdata; total_packet_memory += packet->alloced; } // Write a single byte to the packet void NET_WriteInt8(net_packet_t *packet, unsigned int i) { if (packet->len + 1 > packet->alloced) NET_IncreasePacket(packet); packet->data[packet->len] = i; packet->len += 1; } // Write a 16-bit integer to the packet void NET_WriteInt16(net_packet_t *packet, unsigned int i) { byte *p; if (packet->len + 2 > packet->alloced) NET_IncreasePacket(packet); p = packet->data + packet->len; p[0] = (i >> 8) & 0xff; p[1] = i & 0xff; packet->len += 2; } // Write a single byte to the packet void NET_WriteInt32(net_packet_t *packet, unsigned int i) { byte *p; if (packet->len + 4 > packet->alloced) NET_IncreasePacket(packet); p = packet->data + packet->len; p[0] = (i >> 24) & 0xff; p[1] = (i >> 16) & 0xff; p[2] = (i >> 8) & 0xff; p[3] = i & 0xff; packet->len += 4; } void NET_WriteString(net_packet_t *packet, char *string) { byte *p; size_t string_size; string_size = strlen(string) + 1; // Increase the packet size until large enough to hold the string while (packet->len + string_size > packet->alloced) { NET_IncreasePacket(packet); } p = packet->data + packet->len; M_StringCopy((char *) p, string, string_size); packet->len += string_size; } chocolate-doom-chocolate-doom-2.2.1/src/net_packet.h000066400000000000000000000027671257432200600223760ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Definitions for use in networking code. // #ifndef NET_PACKET_H #define NET_PACKET_H #include "net_defs.h" net_packet_t *NET_NewPacket(int initial_size); net_packet_t *NET_PacketDup(net_packet_t *packet); void NET_FreePacket(net_packet_t *packet); boolean NET_ReadInt8(net_packet_t *packet, unsigned int *data); boolean NET_ReadInt16(net_packet_t *packet, unsigned int *data); boolean NET_ReadInt32(net_packet_t *packet, unsigned int *data); boolean NET_ReadSInt8(net_packet_t *packet, signed int *data); boolean NET_ReadSInt16(net_packet_t *packet, signed int *data); boolean NET_ReadSInt32(net_packet_t *packet, signed int *data); char *NET_ReadString(net_packet_t *packet); void NET_WriteInt8(net_packet_t *packet, unsigned int i); void NET_WriteInt16(net_packet_t *packet, unsigned int i); void NET_WriteInt32(net_packet_t *packet, unsigned int i); void NET_WriteString(net_packet_t *packet, char *string); #endif /* #ifndef NET_PACKET_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_query.c000066400000000000000000000532731257432200600222650ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Querying servers to find their current status. // #include #include #include #include #include "i_system.h" #include "i_timer.h" #include "m_misc.h" #include "net_common.h" #include "net_defs.h" #include "net_io.h" #include "net_packet.h" #include "net_query.h" #include "net_structrw.h" #include "net_sdl.h" // DNS address of the Internet master server. #define MASTER_SERVER_ADDRESS "master.chocolate-doom.org:2342" // Time to wait for a response before declaring a timeout. #define QUERY_TIMEOUT_SECS 2 // Time to wait for secure demo signatures before declaring a timeout. #define SIGNATURE_TIMEOUT_SECS 5 // Number of query attempts to make before giving up on a server. #define QUERY_MAX_ATTEMPTS 3 typedef enum { QUERY_TARGET_SERVER, // Normal server target. QUERY_TARGET_MASTER, // The master server. QUERY_TARGET_BROADCAST // Send a broadcast query } query_target_type_t; typedef enum { QUERY_TARGET_QUEUED, // Query not yet sent QUERY_TARGET_QUERIED, // Query sent, waiting response QUERY_TARGET_RESPONDED, // Response received QUERY_TARGET_NO_RESPONSE } query_target_state_t; typedef struct { query_target_type_t type; query_target_state_t state; net_addr_t *addr; net_querydata_t data; unsigned int ping_time; unsigned int query_time; unsigned int query_attempts; boolean printed; } query_target_t; static boolean registered_with_master = false; static boolean got_master_response = false; static net_context_t *query_context; static query_target_t *targets; static int num_targets; static boolean query_loop_running = false; static boolean printed_header = false; static int last_query_time = 0; static char *securedemo_start_message = NULL; // Resolve the master server address. net_addr_t *NET_Query_ResolveMaster(net_context_t *context) { net_addr_t *addr; addr = NET_ResolveAddress(context, MASTER_SERVER_ADDRESS); if (addr == NULL) { fprintf(stderr, "Warning: Failed to resolve address " "for master server: %s\n", MASTER_SERVER_ADDRESS); } return addr; } // Send a registration packet to the master server to register // ourselves with the global list. void NET_Query_AddToMaster(net_addr_t *master_addr) { net_packet_t *packet; packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_ADD); NET_SendPacket(master_addr, packet); NET_FreePacket(packet); } // Process a packet received from the master server. void NET_Query_MasterResponse(net_packet_t *packet) { unsigned int packet_type; unsigned int result; if (!NET_ReadInt16(packet, &packet_type) || !NET_ReadInt16(packet, &result)) { return; } if (packet_type == NET_MASTER_PACKET_TYPE_ADD_RESPONSE) { if (result != 0) { // Only show the message once. if (!registered_with_master) { printf("Registered with master server at %s\n", MASTER_SERVER_ADDRESS); registered_with_master = true; } } else { // Always show rejections. printf("Failed to register with master server at %s\n", MASTER_SERVER_ADDRESS); } got_master_response = true; } } boolean NET_Query_CheckAddedToMaster(boolean *result) { // Got response from master yet? if (!got_master_response) { return false; } *result = registered_with_master; return true; } // Send a query to the master server. static void NET_Query_SendMasterQuery(net_addr_t *addr) { net_packet_t *packet; packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_QUERY); NET_SendPacket(addr, packet); NET_FreePacket(packet); } // Given the specified address, find the target associated. If no // target is found, and 'create' is true, a new target is created. static query_target_t *GetTargetForAddr(net_addr_t *addr, boolean create) { query_target_t *target; int i; for (i=0; itype = QUERY_TARGET_SERVER; target->state = QUERY_TARGET_QUEUED; target->printed = false; target->query_attempts = 0; target->addr = addr; ++num_targets; return target; } // Transmit a query packet static void NET_Query_SendQuery(net_addr_t *addr) { net_packet_t *request; request = NET_NewPacket(10); NET_WriteInt16(request, NET_PACKET_TYPE_QUERY); if (addr == NULL) { NET_SendBroadcast(query_context, request); } else { NET_SendPacket(addr, request); } NET_FreePacket(request); } static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, net_query_callback_t callback, void *user_data) { unsigned int packet_type; net_querydata_t querydata; query_target_t *target; // Read the header if (!NET_ReadInt16(packet, &packet_type) || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) { return; } // Read query data if (!NET_ReadQueryData(packet, &querydata)) { return; } // Find the target that responded. target = GetTargetForAddr(addr, false); // If the target is not found, it may be because we are doing // a LAN broadcast search, in which case we need to create a // target for the new responder. if (target == NULL) { query_target_t *broadcast_target; broadcast_target = GetTargetForAddr(NULL, false); // Not in broadcast mode, unexpected response that came out // of nowhere. Ignore. if (broadcast_target == NULL || broadcast_target->state != QUERY_TARGET_QUERIED) { return; } // Create new target. target = GetTargetForAddr(addr, true); target->state = QUERY_TARGET_QUERIED; target->query_time = broadcast_target->query_time; } if (target->state != QUERY_TARGET_RESPONDED) { target->state = QUERY_TARGET_RESPONDED; memcpy(&target->data, &querydata, sizeof(net_querydata_t)); // Calculate RTT. target->ping_time = I_GetTimeMS() - target->query_time; // Invoke callback to signal that we have a new address. callback(addr, &target->data, target->ping_time, user_data); } } // Parse a response packet from the master server. static void NET_Query_ParseMasterResponse(net_addr_t *master_addr, net_packet_t *packet) { unsigned int packet_type; query_target_t *target; char *addr_str; net_addr_t *addr; // Read the header. We are only interested in query responses. if (!NET_ReadInt16(packet, &packet_type) || packet_type != NET_MASTER_PACKET_TYPE_QUERY_RESPONSE) { return; } // Read a list of strings containing the addresses of servers // that the master knows about. for (;;) { addr_str = NET_ReadString(packet); if (addr_str == NULL) { break; } // Resolve address and add to targets list if it is not already // there. addr = NET_ResolveAddress(query_context, addr_str); if (addr != NULL) { GetTargetForAddr(addr, true); } } // Mark the master as having responded. target = GetTargetForAddr(master_addr, true); target->state = QUERY_TARGET_RESPONDED; } static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet, net_query_callback_t callback, void *user_data) { query_target_t *target; // This might be the master server responding. target = GetTargetForAddr(addr, false); if (target != NULL && target->type == QUERY_TARGET_MASTER) { NET_Query_ParseMasterResponse(addr, packet); } else { NET_Query_ParseResponse(addr, packet, callback, user_data); } } static void NET_Query_GetResponse(net_query_callback_t callback, void *user_data) { net_addr_t *addr; net_packet_t *packet; if (NET_RecvPacket(query_context, &addr, &packet)) { NET_Query_ParsePacket(addr, packet, callback, user_data); NET_FreePacket(packet); } } // Find a target we have not yet queried and send a query. static void SendOneQuery(void) { unsigned int now; unsigned int i; now = I_GetTimeMS(); // Rate limit - only send one query every 50ms. if (now - last_query_time < 50) { return; } for (i = 0; i < num_targets; ++i) { // Not queried yet? // Or last query timed out without a response? if (targets[i].state == QUERY_TARGET_QUEUED || (targets[i].state == QUERY_TARGET_QUERIED && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000)) { break; } } if (i >= num_targets) { return; } // Found a target to query. Send a query; how to do this depends on // the target type. switch (targets[i].type) { case QUERY_TARGET_SERVER: NET_Query_SendQuery(targets[i].addr); break; case QUERY_TARGET_BROADCAST: NET_Query_SendQuery(NULL); break; case QUERY_TARGET_MASTER: NET_Query_SendMasterQuery(targets[i].addr); break; } //printf("Queried %s\n", NET_AddrToString(targets[i].addr)); targets[i].state = QUERY_TARGET_QUERIED; targets[i].query_time = now; ++targets[i].query_attempts; last_query_time = now; } // Time out servers that have been queried and not responded. static void CheckTargetTimeouts(void) { unsigned int i; unsigned int now; now = I_GetTimeMS(); for (i = 0; i < num_targets; ++i) { /* printf("target %i: state %i, queries %i, query time %i\n", i, targets[i].state, targets[i].query_attempts, now - targets[i].query_time); */ // We declare a target to be "no response" when we've sent // multiple query packets to it (QUERY_MAX_ATTEMPTS) and // received no response to any of them. if (targets[i].state == QUERY_TARGET_QUERIED && targets[i].query_attempts >= QUERY_MAX_ATTEMPTS && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000) { targets[i].state = QUERY_TARGET_NO_RESPONSE; if (targets[i].type == QUERY_TARGET_MASTER) { fprintf(stderr, "NET_MasterQuery: no response " "from master server.\n"); } } } } // If all targets have responded or timed out, returns true. static boolean AllTargetsDone(void) { unsigned int i; for (i = 0; i < num_targets; ++i) { if (targets[i].state != QUERY_TARGET_RESPONDED && targets[i].state != QUERY_TARGET_NO_RESPONSE) { return false; } } return true; } // Polling function, invoked periodically to send queries and // interpret new responses received from remote servers. // Returns zero when the query sequence has completed and all targets // have returned responses or timed out. int NET_Query_Poll(net_query_callback_t callback, void *user_data) { CheckTargetTimeouts(); // Send a query. This will only send a single query at once. SendOneQuery(); // Check for a response NET_Query_GetResponse(callback, user_data); return !AllTargetsDone(); } // Stop the query loop static void NET_Query_ExitLoop(void) { query_loop_running = false; } // Loop waiting for responses. // The specified callback is invoked when a new server responds. static void NET_Query_QueryLoop(net_query_callback_t callback, void *user_data) { query_loop_running = true; while (query_loop_running && NET_Query_Poll(callback, user_data)) { // Don't thrash the CPU I_Sleep(1); } } void NET_Query_Init(void) { if (query_context == NULL) { query_context = NET_NewContext(); NET_AddModule(query_context, &net_sdl_module); net_sdl_module.InitClient(); } free(targets); targets = NULL; num_targets = 0; printed_header = false; } // Callback that exits the query loop when the first server is found. static void NET_Query_ExitCallback(net_addr_t *addr, net_querydata_t *data, unsigned int ping_time, void *user_data) { NET_Query_ExitLoop(); } // Search the targets list and find a target that has responded. // If none have responded, returns NULL. static query_target_t *FindFirstResponder(void) { unsigned int i; for (i = 0; i < num_targets; ++i) { if (targets[i].type == QUERY_TARGET_SERVER && targets[i].state == QUERY_TARGET_RESPONDED) { return &targets[i]; } } return NULL; } // Return a count of the number of responses. static int GetNumResponses(void) { unsigned int i; int result; result = 0; for (i = 0; i < num_targets; ++i) { if (targets[i].type == QUERY_TARGET_SERVER && targets[i].state == QUERY_TARGET_RESPONDED) { ++result; } } return result; } int NET_StartLANQuery(void) { query_target_t *target; NET_Query_Init(); // Add a broadcast target to the list. target = GetTargetForAddr(NULL, true); target->type = QUERY_TARGET_BROADCAST; return 1; } int NET_StartMasterQuery(void) { net_addr_t *master; query_target_t *target; NET_Query_Init(); // Resolve master address and add to targets list. master = NET_Query_ResolveMaster(query_context); if (master == NULL) { return 0; } target = GetTargetForAddr(master, true); target->type = QUERY_TARGET_MASTER; return 1; } // ----------------------------------------------------------------------- static void formatted_printf(int wide, char *s, ...) { va_list args; int i; va_start(args, s); i = vprintf(s, args); va_end(args); while (i < wide) { putchar(' '); ++i; } } static char *GameDescription(GameMode_t mode, GameMission_t mission) { switch (mission) { case doom: if (mode == shareware) return "swdoom"; else if (mode == registered) return "regdoom"; else if (mode == retail) return "ultdoom"; else return "doom"; case doom2: return "doom2"; case pack_tnt: return "tnt"; case pack_plut: return "plutonia"; case pack_chex: return "chex"; case pack_hacx: return "hacx"; case heretic: return "heretic"; case hexen: return "hexen"; case strife: return "strife"; default: return "?"; } } static void PrintHeader(void) { int i; putchar('\n'); formatted_printf(5, "Ping"); formatted_printf(18, "Address"); formatted_printf(8, "Players"); puts("Description"); for (i=0; i<70; ++i) putchar('='); putchar('\n'); } // Callback function that just prints information in a table. static void NET_QueryPrintCallback(net_addr_t *addr, net_querydata_t *data, unsigned int ping_time, void *user_data) { // If this is the first server, print the header. if (!printed_header) { PrintHeader(); printed_header = true; } formatted_printf(5, "%4i", ping_time); formatted_printf(18, "%s: ", NET_AddrToString(addr)); formatted_printf(8, "%i/%i", data->num_players, data->max_players); if (data->gamemode != indetermined) { printf("(%s) ", GameDescription(data->gamemode, data->gamemission)); } if (data->server_state) { printf("(game running) "); } NET_SafePuts(data->description); } void NET_LANQuery(void) { if (NET_StartLANQuery()) { printf("\nSearching for servers on local LAN ...\n"); NET_Query_QueryLoop(NET_QueryPrintCallback, NULL); printf("\n%i server(s) found.\n", GetNumResponses()); } } void NET_MasterQuery(void) { if (NET_StartMasterQuery()) { printf("\nSearching for servers on Internet ...\n"); NET_Query_QueryLoop(NET_QueryPrintCallback, NULL); printf("\n%i server(s) found.\n", GetNumResponses()); } } void NET_QueryAddress(char *addr_str) { net_addr_t *addr; query_target_t *target; NET_Query_Init(); addr = NET_ResolveAddress(query_context, addr_str); if (addr == NULL) { I_Error("NET_QueryAddress: Host '%s' not found!", addr_str); } // Add the address to the list of targets. target = GetTargetForAddr(addr, true); printf("\nQuerying '%s'...\n", addr_str); // Run query loop. NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); // Check if the target responded. if (target->state == QUERY_TARGET_RESPONDED) { NET_QueryPrintCallback(addr, &target->data, target->ping_time, NULL); } else { I_Error("No response from '%s'", addr_str); } } net_addr_t *NET_FindLANServer(void) { query_target_t *target; query_target_t *responder; NET_Query_Init(); // Add a broadcast target to the list. target = GetTargetForAddr(NULL, true); target->type = QUERY_TARGET_BROADCAST; // Run the query loop, and stop at the first target found. NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); responder = FindFirstResponder(); if (responder != NULL) { return responder->addr; } else { return NULL; } } // Block until a packet of the given type is received from the given // address. static net_packet_t *BlockForPacket(net_addr_t *addr, unsigned int packet_type, unsigned int timeout_ms) { net_packet_t *packet; net_addr_t *packet_src; unsigned int read_packet_type; unsigned int start_time; start_time = I_GetTimeMS(); while (I_GetTimeMS() < start_time + timeout_ms) { if (!NET_RecvPacket(query_context, &packet_src, &packet)) { I_Sleep(20); continue; } if (packet_src == addr && NET_ReadInt16(packet, &read_packet_type) && packet_type == read_packet_type) { return packet; } NET_FreePacket(packet); } // Timeout - no response. return NULL; } // Query master server for secure demo start seed value. boolean NET_StartSecureDemo(prng_seed_t seed) { net_packet_t *request, *response; net_addr_t *master_addr; char *signature; boolean result; NET_Query_Init(); master_addr = NET_Query_ResolveMaster(query_context); // Send request packet to master server. request = NET_NewPacket(10); NET_WriteInt16(request, NET_MASTER_PACKET_TYPE_SIGN_START); NET_SendPacket(master_addr, request); NET_FreePacket(request); // Block for response and read contents. // The signed start message will be saved for later. response = BlockForPacket(master_addr, NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE, SIGNATURE_TIMEOUT_SECS * 1000); result = false; if (response != NULL) { if (NET_ReadPRNGSeed(response, seed)) { signature = NET_ReadString(response); if (signature != NULL) { securedemo_start_message = M_StringDuplicate(signature); result = true; } } NET_FreePacket(response); } return result; } // Query master server for secure demo end signature. char *NET_EndSecureDemo(sha1_digest_t demo_hash) { net_packet_t *request, *response; net_addr_t *master_addr; char *signature; master_addr = NET_Query_ResolveMaster(query_context); // Construct end request and send to master server. request = NET_NewPacket(10); NET_WriteInt16(request, NET_MASTER_PACKET_TYPE_SIGN_END); NET_WriteSHA1Sum(request, demo_hash); NET_WriteString(request, securedemo_start_message); NET_SendPacket(master_addr, request); NET_FreePacket(request); // Block for response. The response packet simply contains a string // with the ASCII signature. response = BlockForPacket(master_addr, NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE, SIGNATURE_TIMEOUT_SECS * 1000); if (response == NULL) { return NULL; } signature = NET_ReadString(response); NET_FreePacket(response); return signature; } chocolate-doom-chocolate-doom-2.2.1/src/net_query.h000066400000000000000000000027531257432200600222670ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Querying servers to find their current status. // #ifndef NET_QUERY_H #define NET_QUERY_H #include "net_defs.h" typedef void (*net_query_callback_t)(net_addr_t *addr, net_querydata_t *querydata, unsigned int ping_time, void *user_data); extern int NET_StartLANQuery(void); extern int NET_StartMasterQuery(void); extern void NET_LANQuery(void); extern void NET_MasterQuery(void); extern void NET_QueryAddress(char *addr); extern net_addr_t *NET_FindLANServer(void); extern int NET_Query_Poll(net_query_callback_t callback, void *user_data); extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context); extern void NET_Query_AddToMaster(net_addr_t *master_addr); extern boolean NET_Query_CheckAddedToMaster(boolean *result); extern void NET_Query_MasterResponse(net_packet_t *packet); #endif /* #ifndef NET_QUERY_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_sdl.c000066400000000000000000000203551257432200600216750ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Networking module which uses SDL_net // #include #include #include #include "doomtype.h" #include "i_system.h" #include "m_argv.h" #include "m_misc.h" #include "net_defs.h" #include "net_io.h" #include "net_packet.h" #include "net_sdl.h" #include "z_zone.h" // // NETWORKING // #include #define DEFAULT_PORT 2342 static boolean initted = false; static int port = DEFAULT_PORT; static UDPsocket udpsocket; static UDPpacket *recvpacket; typedef struct { net_addr_t net_addr; IPaddress sdl_addr; } addrpair_t; static addrpair_t **addr_table; static int addr_table_size = -1; // Initializes the address table static void NET_SDL_InitAddrTable(void) { addr_table_size = 16; addr_table = Z_Malloc(sizeof(addrpair_t *) * addr_table_size, PU_STATIC, 0); memset(addr_table, 0, sizeof(addrpair_t *) * addr_table_size); } static boolean AddressesEqual(IPaddress *a, IPaddress *b) { return a->host == b->host && a->port == b->port; } // Finds an address by searching the table. If the address is not found, // it is added to the table. static net_addr_t *NET_SDL_FindAddress(IPaddress *addr) { addrpair_t *new_entry; int empty_entry = -1; int i; if (addr_table_size < 0) { NET_SDL_InitAddrTable(); } for (i=0; isdl_addr)) { return &addr_table[i]->net_addr; } if (empty_entry < 0 && addr_table[i] == NULL) empty_entry = i; } // Was not found in list. We need to add it. // Is there any space in the table? If not, increase the table size if (empty_entry < 0) { addrpair_t **new_addr_table; int new_addr_table_size; // after reallocing, we will add this in as the first entry // in the new block of memory empty_entry = addr_table_size; // allocate a new array twice the size, init to 0 and copy // the existing table in. replace the old table. new_addr_table_size = addr_table_size * 2; new_addr_table = Z_Malloc(sizeof(addrpair_t *) * new_addr_table_size, PU_STATIC, 0); memset(new_addr_table, 0, sizeof(addrpair_t *) * new_addr_table_size); memcpy(new_addr_table, addr_table, sizeof(addrpair_t *) * addr_table_size); Z_Free(addr_table); addr_table = new_addr_table; addr_table_size = new_addr_table_size; } // Add a new entry new_entry = Z_Malloc(sizeof(addrpair_t), PU_STATIC, 0); new_entry->sdl_addr = *addr; new_entry->net_addr.handle = &new_entry->sdl_addr; new_entry->net_addr.module = &net_sdl_module; addr_table[empty_entry] = new_entry; return &new_entry->net_addr; } static void NET_SDL_FreeAddress(net_addr_t *addr) { int i; for (i=0; inet_addr) { Z_Free(addr_table[i]); addr_table[i] = NULL; return; } } I_Error("NET_SDL_FreeAddress: Attempted to remove an unused address!"); } static boolean NET_SDL_InitClient(void) { int p; if (initted) return true; //! // @category net // @arg // // Use the specified UDP port for communications, instead of // the default (2342). // p = M_CheckParmWithArgs("-port", 1); if (p > 0) port = atoi(myargv[p+1]); SDLNet_Init(); udpsocket = SDLNet_UDP_Open(0); if (udpsocket == NULL) { I_Error("NET_SDL_InitClient: Unable to open a socket!"); } recvpacket = SDLNet_AllocPacket(1500); #ifdef DROP_PACKETS srand(time(NULL)); #endif initted = true; return true; } static boolean NET_SDL_InitServer(void) { int p; if (initted) return true; p = M_CheckParmWithArgs("-port", 1); if (p > 0) port = atoi(myargv[p+1]); SDLNet_Init(); udpsocket = SDLNet_UDP_Open(port); if (udpsocket == NULL) { I_Error("NET_SDL_InitServer: Unable to bind to port %i", port); } recvpacket = SDLNet_AllocPacket(1500); #ifdef DROP_PACKETS srand(time(NULL)); #endif initted = true; return true; } static void NET_SDL_SendPacket(net_addr_t *addr, net_packet_t *packet) { UDPpacket sdl_packet; IPaddress ip; if (addr == &net_broadcast_addr) { SDLNet_ResolveHost(&ip, NULL, port); ip.host = INADDR_BROADCAST; } else { ip = *((IPaddress *) addr->handle); } #if 0 { static int this_second_sent = 0; static int lasttime; this_second_sent += packet->len + 64; if (I_GetTime() - lasttime > TICRATE) { printf("%i bytes sent in the last second\n", this_second_sent); lasttime = I_GetTime(); this_second_sent = 0; } } #endif #ifdef DROP_PACKETS if ((rand() % 4) == 0) return; #endif sdl_packet.channel = 0; sdl_packet.data = packet->data; sdl_packet.len = packet->len; sdl_packet.address = ip; if (!SDLNet_UDP_Send(udpsocket, -1, &sdl_packet)) { I_Error("NET_SDL_SendPacket: Error transmitting packet: %s", SDLNet_GetError()); } } static boolean NET_SDL_RecvPacket(net_addr_t **addr, net_packet_t **packet) { int result; result = SDLNet_UDP_Recv(udpsocket, recvpacket); if (result < 0) { I_Error("NET_SDL_RecvPacket: Error receiving packet: %s", SDLNet_GetError()); } // no packets received if (result == 0) return false; // Put the data into a new packet structure *packet = NET_NewPacket(recvpacket->len); memcpy((*packet)->data, recvpacket->data, recvpacket->len); (*packet)->len = recvpacket->len; // Address *addr = NET_SDL_FindAddress(&recvpacket->address); return true; } void NET_SDL_AddrToString(net_addr_t *addr, char *buffer, int buffer_len) { IPaddress *ip; uint32_t host; uint16_t port; ip = (IPaddress *) addr->handle; host = SDLNet_Read32(&ip->host); port = SDLNet_Read16(&ip->port); M_snprintf(buffer, buffer_len, "%i.%i.%i.%i", (host >> 24) & 0xff, (host >> 16) & 0xff, (host >> 8) & 0xff, host & 0xff); // If we are using the default port we just need to show the IP address, // but otherwise we need to include the port. This is important because // we use the string representation in the setup tool to provided an // address to connect to. if (port != DEFAULT_PORT) { char portbuf[10]; M_snprintf(portbuf, sizeof(portbuf), ":%i", port); M_StringConcat(buffer, portbuf, buffer_len); } } net_addr_t *NET_SDL_ResolveAddress(char *address) { IPaddress ip; char *addr_hostname; int addr_port; int result; char *colon; colon = strchr(address, ':'); if (colon != NULL) { addr_hostname = M_StringDuplicate(address); addr_hostname[colon - address] = '\0'; addr_port = atoi(colon + 1); } else { addr_hostname = address; addr_port = port; } result = SDLNet_ResolveHost(&ip, addr_hostname, addr_port); if (addr_hostname != address) { free(addr_hostname); } if (result) { // unable to resolve return NULL; } else { return NET_SDL_FindAddress(&ip); } } // Complete module net_module_t net_sdl_module = { NET_SDL_InitClient, NET_SDL_InitServer, NET_SDL_SendPacket, NET_SDL_RecvPacket, NET_SDL_AddrToString, NET_SDL_FreeAddress, NET_SDL_ResolveAddress, }; chocolate-doom-chocolate-doom-2.2.1/src/net_sdl.h000066400000000000000000000013461257432200600217010ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Networking module which uses SDL_net // #ifndef NET_SDL_H #define NET_SDL_H #include "net_defs.h" extern net_module_t net_sdl_module; #endif /* #ifndef NET_SDL_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_server.c000066400000000000000000001251401257432200600224170ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Network server code // #include #include #include #include #include "config.h" #include "doomtype.h" #include "d_mode.h" #include "i_system.h" #include "i_timer.h" #include "m_argv.h" #include "m_misc.h" #include "net_client.h" #include "net_common.h" #include "net_defs.h" #include "net_io.h" #include "net_loop.h" #include "net_packet.h" #include "net_query.h" #include "net_server.h" #include "net_sdl.h" #include "net_structrw.h" // How often to refresh our registration with the master server. #define MASTER_REFRESH_PERIOD 20 * 60 /* 20 minutes */ // How often to re-resolve the address of the master server? #define MASTER_RESOLVE_PERIOD 8 * 60 * 60 /* 8 hours */ typedef enum { // waiting for the game to be "launched" (key player to press the start // button) SERVER_WAITING_LAUNCH, // game has been launched, we are waiting for all players to be ready // so the game can start. SERVER_WAITING_START, // in a game SERVER_IN_GAME, } net_server_state_t; typedef struct { boolean active; int player_number; net_addr_t *addr; net_connection_t connection; int last_send_time; char *name; // If true, the client has sent the NET_PACKET_TYPE_GAMESTART // message indicating that it is ready for the game to start. boolean ready; // Time that this client connected to the server. // This is used to determine the controller (oldest client). unsigned int connect_time; // Last time new gamedata was received from this client int last_gamedata_time; // recording a demo without -longtics boolean recording_lowres; // send queue: items to send to the client // this is a circular buffer int sendseq; net_full_ticcmd_t sendqueue[BACKUPTICS]; // Latest acknowledged by the client unsigned int acknowledged; // Value of max_players specified by the client on connect. int max_players; // Observer: receives data but does not participate in the game. boolean drone; // SHA1 hash sums of the client's WAD directory and dehacked data sha1_digest_t wad_sha1sum; sha1_digest_t deh_sha1sum; // Is this client is playing with the Freedoom IWAD? unsigned int is_freedoom; // Player class (for Hexen) int player_class; } net_client_t; // structure used for the recv window typedef struct { // Whether this tic has been received yet boolean active; // Latency value received from the client signed int latency; // Last time we sent a resend request for this tic unsigned int resend_time; // Tic data itself net_ticdiff_t diff; } net_client_recv_t; static net_server_state_t server_state; static boolean server_initialized = false; static net_client_t clients[MAXNETNODES]; static net_client_t *sv_players[NET_MAXPLAYERS]; static net_context_t *server_context; static unsigned int sv_gamemode; static unsigned int sv_gamemission; static net_gamesettings_t sv_settings; // For registration with master server: static net_addr_t *master_server = NULL; static unsigned int master_refresh_time; static unsigned int master_resolve_time; // receive window static unsigned int recvwindow_start; static net_client_recv_t recvwindow[BACKUPTICS][NET_MAXPLAYERS]; #define NET_SV_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b)) static void NET_SV_DisconnectClient(net_client_t *client) { if (client->active) { NET_Conn_Disconnect(&client->connection); } } static boolean ClientConnected(net_client_t *client) { // Check that the client is properly connected: ie. not in the // process of connecting or disconnecting return client->active && client->connection.state == NET_CONN_STATE_CONNECTED; } // Send a message to be displayed on a client's console static void NET_SV_SendConsoleMessage(net_client_t *client, char *s, ...) { char buf[1024]; va_list args; net_packet_t *packet; va_start(args, s); M_vsnprintf(buf, sizeof(buf), s, args); va_end(args); packet = NET_Conn_NewReliable(&client->connection, NET_PACKET_TYPE_CONSOLE_MESSAGE); NET_WriteString(packet, buf); } // Send a message to all clients static void NET_SV_BroadcastMessage(char *s, ...) { char buf[1024]; va_list args; int i; va_start(args, s); M_vsnprintf(buf, sizeof(buf), s, args); va_end(args); for (i=0; iplayer_number = pl; ++pl; } else { clients[i].player_number = -1; } } } for (; plconnect_time) { best = &clients[i]; } } return best; } static void NET_SV_SendWaitingData(net_client_t *client) { net_waitdata_t wait_data; net_packet_t *packet; net_client_t *controller; int i; NET_SV_AssignPlayers(); controller = NET_SV_Controller(); wait_data.num_players = NET_SV_NumPlayers(); wait_data.num_drones = NET_SV_NumDrones(); wait_data.ready_players = NET_SV_NumReadyPlayers(); wait_data.max_players = NET_SV_MaxPlayers(); wait_data.is_controller = (client == controller); wait_data.consoleplayer = client->player_number; // Send the WAD and dehacked checksums of the controlling client. // If no controller found (?), send the details that the client // is expecting anyway. if (controller == NULL) { controller = client; } memcpy(&wait_data.wad_sha1sum, &controller->wad_sha1sum, sizeof(sha1_digest_t)); memcpy(&wait_data.deh_sha1sum, &controller->deh_sha1sum, sizeof(sha1_digest_t)); wait_data.is_freedoom = controller->is_freedoom; // set name and address of each player: for (i = 0; i < wait_data.num_players; ++i) { M_StringCopy(wait_data.player_names[i], sv_players[i]->name, MAXPLAYERNAME); M_StringCopy(wait_data.player_addrs[i], NET_AddrToString(sv_players[i]->addr), MAXPLAYERNAME); } // Construct packet: packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA); NET_WriteWaitData(packet, &wait_data); // Send packet to client and free NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); } // Find the latest tic which has been acknowledged as received by // all clients. static unsigned int NET_SV_LatestAcknowledged(void) { unsigned int lowtic = UINT_MAX; int i; for (i=0; iactive = true; client->connect_time = I_GetTimeMS(); NET_Conn_InitServer(&client->connection, addr); client->addr = addr; client->last_send_time = -1; client->name = M_StringDuplicate(player_name); // init the ticcmd send queue client->sendseq = 0; client->acknowledged = 0; client->drone = false; client->ready = false; client->last_gamedata_time = 0; memset(client->sendqueue, 0xff, sizeof(client->sendqueue)); } // parse a SYN from a client(initiating a connection) static void NET_SV_ParseSYN(net_packet_t *packet, net_client_t *client, net_addr_t *addr) { unsigned int magic; net_connect_data_t data; char *player_name; char *client_version; int i; // read the magic number if (!NET_ReadInt32(packet, &magic)) { return; } if (magic != NET_MAGIC_NUMBER) { // invalid magic number return; } // Check the client version is the same as the server client_version = NET_ReadString(packet); if (client_version == NULL) { return; } if (strcmp(client_version, PACKAGE_STRING) != 0) { //! // @category net // // When running a netgame server, ignore version mismatches between // the server and the client. Using this option may cause game // desyncs to occur, or differences in protocol may mean the netgame // will simply not function at all. // if (M_CheckParm("-ignoreversion") == 0) { NET_SV_SendReject(addr, "Different " PACKAGE_NAME " versions cannot play a net game!\n" "Version mismatch: server version is: " PACKAGE_STRING); return; } } // read the game mode and mission if (!NET_ReadConnectData(packet, &data)) { return; } if (!D_ValidGameMode(data.gamemission, data.gamemode)) { return; } // Check max_players value. This must be in a sensible range. if (data.max_players > NET_MAXPLAYERS) { return; } // read the player's name player_name = NET_ReadString(packet); if (player_name == NULL) { return; } // received a valid SYN // not accepting new connections? if (server_state != SERVER_WAITING_LAUNCH) { NET_SV_SendReject(addr, "Server is not currently accepting connections"); return; } // allocate a client slot if there isn't one already if (client == NULL) { // find a slot, or return if none found for (i=0; iconnection.state == NET_CONN_STATE_DISCONNECTED) { client->active = false; } } // New client? if (!client->active) { int num_players; // Before accepting a new client, check that there is a slot // free NET_SV_AssignPlayers(); num_players = NET_SV_NumPlayers(); if ((!data.drone && num_players >= NET_SV_MaxPlayers()) || NET_SV_NumClients() >= MAXNETNODES) { NET_SV_SendReject(addr, "Server is full!"); return; } // TODO: Add server option to allow rejecting clients which // set lowres_turn. This is potentially desirable as the // presence of such clients affects turning resolution. // Adopt the game mode and mission of the first connecting client if (num_players == 0 && !data.drone) { sv_gamemode = data.gamemode; sv_gamemission = data.gamemission; } // Save the SHA1 checksums memcpy(client->wad_sha1sum, data.wad_sha1sum, sizeof(sha1_digest_t)); memcpy(client->deh_sha1sum, data.deh_sha1sum, sizeof(sha1_digest_t)); client->is_freedoom = data.is_freedoom; client->max_players = data.max_players; // Check the connecting client is playing the same game as all // the other clients if (data.gamemode != sv_gamemode || data.gamemission != sv_gamemission) { NET_SV_SendReject(addr, "You are playing the wrong game!"); return; } // Activate, initialize connection NET_SV_InitNewClient(client, addr, player_name); client->recording_lowres = data.lowres_turn; client->drone = data.drone; client->player_class = data.player_class; } if (client->connection.state == NET_CONN_STATE_WAITING_ACK) { // force an acknowledgement client->connection.last_send_time = -1; } } // Parse a launch packet. This is sent by the key player when the "start" // button is pressed, and causes the startup process to continue. static void NET_SV_ParseLaunch(net_packet_t *packet, net_client_t *client) { net_packet_t *launchpacket; int num_players; unsigned int i; // Only the controller can launch the game. if (client != NET_SV_Controller()) { return; } // Can only launch when we are in the waiting state. if (server_state != SERVER_WAITING_LAUNCH) { return; } // Forward launch on to all clients. NET_SV_AssignPlayers(); num_players = NET_SV_NumPlayers(); for (i=0; irecording_lowres) { sv_settings.lowres_turn = true; } } sv_settings.num_players = NET_SV_NumPlayers(); // Copy player classes: for (i = 0; i < NET_MAXPLAYERS; ++i) { if (sv_players[i] != NULL) { sv_settings.player_classes[i] = sv_players[i]->player_class; } else { sv_settings.player_classes[i] = 0; } } nowtime = I_GetTimeMS(); // Send start packets to each connected node for (i = 0; i < MAXNETNODES; ++i) { if (!ClientConnected(&clients[i])) continue; clients[i].last_gamedata_time = nowtime; startpacket = NET_Conn_NewReliable(&clients[i].connection, NET_PACKET_TYPE_GAMESTART); sv_settings.consoleplayer = clients[i].player_number; NET_WriteSettings(startpacket, &sv_settings); } // Change server state server_state = SERVER_IN_GAME; memset(recvwindow, 0, sizeof(recvwindow)); recvwindow_start = 0; } // Returns true when all nodes have indicated readiness to start the game. static boolean AllNodesReady(void) { unsigned int i; for (i = 0; i < MAXNETNODES; ++i) { if (ClientConnected(&clients[i]) && !clients[i].ready) { return false; } } return true; } // Check if the game should start, and if so, start it. static void CheckStartGame(void) { if (AllNodesReady()) { StartGame(); } } // Send waiting data with current status to all nodes that are ready to // start the game. static void SendAllWaitingData(void) { unsigned int i; for (i = 0; i < MAXNETNODES; ++i) { if (ClientConnected(&clients[i]) && clients[i].ready) { NET_SV_SendWaitingData(&clients[i]); } } } // Parse a game start packet static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) { net_gamesettings_t settings; // Can only start a game if we are in the waiting start state. if (server_state != SERVER_WAITING_START) { return; } if (client == NET_SV_Controller()) { if (!NET_ReadSettings(packet, &settings)) { // Malformed packet return; } // Check the game settings are valid if (!NET_ValidGameSettings(sv_gamemode, sv_gamemission, &settings)) { return; } sv_settings = settings; } client->ready = true; CheckStartGame(); // Update all ready clients with the current state (number of players // ready, etc.). This is used by games that show startup progress // (eg. Hexen's spinal loading) SendAllWaitingData(); } // Send a resend request to a client static void NET_SV_SendResendRequest(net_client_t *client, int start, int end) { net_packet_t *packet; net_client_recv_t *recvobj; int i; unsigned int nowtime; int index; //printf("SV: send resend for %i-%i\n", start, end); packet = NET_NewPacket(20); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND); NET_WriteInt32(packet, start); NET_WriteInt8(packet, end - start + 1); NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); // Store the time we send the resend request nowtime = I_GetTimeMS(); for (i=start; i<=end; ++i) { index = i - recvwindow_start; if (index >= BACKUPTICS) { // Outside the range continue; } recvobj = &recvwindow[index][client->player_number]; recvobj->resend_time = nowtime; } } // Check for expired resend requests static void NET_SV_CheckResends(net_client_t *client) { int i; int player; int resend_start, resend_end; unsigned int nowtime; nowtime = I_GetTimeMS(); player = client->player_number; resend_start = -1; resend_end = -1; for (i=0; iactive && recvobj->resend_time != 0 && nowtime > recvobj->resend_time + 300; if (need_resend) { // Start a new run of resend tics? if (resend_start < 0) { resend_start = i; } resend_end = i; } else { if (resend_start >= 0) { // End of a run of resend tics //printf("SV: resend request timed out: %i-%i\n", resend_start, resend_end); NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end); resend_start = -1; } } } if (resend_start >= 0) { NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end); } } // Process game data from a client static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) { net_client_recv_t *recvobj; unsigned int seq; unsigned int ackseq; unsigned int num_tics; unsigned int nowtime; size_t i; int player; int resend_start, resend_end; int index; if (server_state != SERVER_IN_GAME) { return; } if (client->drone) { // Drones do not contribute any game data. return; } player = client->player_number; // Read header if (!NET_ReadInt8(packet, &ackseq) || !NET_ReadInt8(packet, &seq) || !NET_ReadInt8(packet, &num_tics)) { return; } // Get the current time nowtime = I_GetTimeMS(); // Expand 8-bit values to the full sequence number ackseq = NET_SV_ExpandTicNum(ackseq); seq = NET_SV_ExpandTicNum(seq); // Sanity checks for (i=0; i= BACKUPTICS) { // Not in range of the recv window continue; } recvobj = &recvwindow[index][player]; recvobj->active = true; recvobj->diff = diff; recvobj->latency = latency; client->last_gamedata_time = nowtime; } // Higher acknowledgement point? if (ackseq > client->acknowledged) { client->acknowledged = ackseq; } // Has this been received out of sequence, ie. have we not received // all tics before the first tic in this packet? If so, send a // resend request. //printf("SV: %p: %i\n", client, seq); resend_end = seq - recvwindow_start; if (resend_end <= 0) return; if (resend_end >= BACKUPTICS) resend_end = BACKUPTICS - 1; index = resend_end - 1; resend_start = resend_end; while (index >= 0) { recvobj = &recvwindow[index][player]; if (recvobj->active) { // ended our run of unreceived tics break; } if (recvobj->resend_time != 0) { // Already sent a resend request for this tic break; } resend_start = index; --index; } // Possibly send a resend request if (resend_start < resend_end) { /* printf("missed %i-%i before %i, send resend\n", recvwindow_start + resend_start, recvwindow_start + resend_end - 1, seq); */ NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end - 1); } } static void NET_SV_ParseGameDataACK(net_packet_t *packet, net_client_t *client) { unsigned int ackseq; if (server_state != SERVER_IN_GAME) { return; } // Read header if (!NET_ReadInt8(packet, &ackseq)) { return; } // Expand 8-bit values to the full sequence number ackseq = NET_SV_ExpandTicNum(ackseq); // Higher acknowledgement point than we already have? if (ackseq > client->acknowledged) { client->acknowledged = ackseq; } } static void NET_SV_SendTics(net_client_t *client, unsigned int start, unsigned int end) { net_packet_t *packet; unsigned int i; packet = NET_NewPacket(500); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA); // Send the start tic and number of tics NET_WriteInt8(packet, start & 0xff); NET_WriteInt8(packet, end-start + 1); // Write the tics for (i=start; i<=end; ++i) { net_full_ticcmd_t *cmd; cmd = &client->sendqueue[i % BACKUPTICS]; if (i != cmd->seq) { I_Error("Wanted to send %i, but %i is in its place", i, cmd->seq); } // Add command NET_WriteFullTiccmd(packet, cmd, sv_settings.lowres_turn); } // Send packet NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); } // Parse a retransmission request from a client static void NET_SV_ParseResendRequest(net_packet_t *packet, net_client_t *client) { unsigned int start, last; unsigned int num_tics; unsigned int i; // Read the starting tic and number of tics if (!NET_ReadInt32(packet, &start) || !NET_ReadInt8(packet, &num_tics)) { return; } //printf("SV: %p: resend %i-%i\n", client, start, start+num_tics-1); // Check we have all the requested tics last = start + num_tics - 1; for (i=start; i<=last; ++i) { net_full_ticcmd_t *cmd; cmd = &client->sendqueue[i % BACKUPTICS]; if (i != cmd->seq) { // We do not have the requested tic (any more) // This is pretty fatal. We could disconnect the client, // but then again this could be a spoofed packet. Just // ignore it. return; } } // Resend those tics NET_SV_SendTics(client, start, last); } // Send a response back to the client void NET_SV_SendQueryResponse(net_addr_t *addr) { net_packet_t *reply; net_querydata_t querydata; int p; // Version querydata.version = PACKAGE_STRING; // Server state querydata.server_state = server_state; // Number of players/maximum players querydata.num_players = NET_SV_NumPlayers(); querydata.max_players = NET_SV_MaxPlayers(); // Game mode/mission querydata.gamemode = sv_gamemode; querydata.gamemission = sv_gamemission; //! // @arg // // When starting a network server, specify a name for the server. // p = M_CheckParmWithArgs("-servername", 1); if (p > 0) { querydata.description = myargv[p + 1]; } else { querydata.description = "Unnamed server"; } // Send it and we're done. reply = NET_NewPacket(64); NET_WriteInt16(reply, NET_PACKET_TYPE_QUERY_RESPONSE); NET_WriteQueryData(reply, &querydata); NET_SendPacket(addr, reply); NET_FreePacket(reply); } // Process a packet received by the server static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) { net_client_t *client; unsigned int packet_type; // Response from master server? if (addr != NULL && addr == master_server) { NET_Query_MasterResponse(packet); return; } // Find which client this packet came from client = NET_SV_FindClient(addr); // Read the packet type if (!NET_ReadInt16(packet, &packet_type)) { // no packet type return; } if (packet_type == NET_PACKET_TYPE_SYN) { NET_SV_ParseSYN(packet, client, addr); } else if (packet_type == NET_PACKET_TYPE_QUERY) { NET_SV_SendQueryResponse(addr); } else if (client == NULL) { // Must come from a valid client; ignore otherwise } else if (NET_Conn_Packet(&client->connection, packet, &packet_type)) { // Packet was eaten by the common connection code } else { //printf("SV: %s: %i\n", NET_AddrToString(addr), packet_type); switch (packet_type) { case NET_PACKET_TYPE_GAMESTART: NET_SV_ParseGameStart(packet, client); break; case NET_PACKET_TYPE_LAUNCH: NET_SV_ParseLaunch(packet, client); break; case NET_PACKET_TYPE_GAMEDATA: NET_SV_ParseGameData(packet, client); break; case NET_PACKET_TYPE_GAMEDATA_ACK: NET_SV_ParseGameDataACK(packet, client); break; case NET_PACKET_TYPE_GAMEDATA_RESEND: NET_SV_ParseResendRequest(packet, client); break; default: // unknown packet type break; } } // If this address is not in the list of clients, be sure to // free it back. if (NET_SV_FindClient(addr) == NULL) { NET_FreeAddress(addr); } } static void NET_SV_PumpSendQueue(net_client_t *client) { net_full_ticcmd_t cmd; int recv_index; int num_players; int i; int starttic, endtic; // If a client has not sent any acknowledgments for a while, // wait until they catch up. if (client->sendseq - NET_SV_LatestAcknowledged() > 40) { return; } // Work out the index into the receive window recv_index = client->sendseq - recvwindow_start; if (recv_index < 0 || recv_index >= BACKUPTICS) { return; } // Check if we can generate a new entry for the send queue // using the data in recvwindow. num_players = 0; for (i=0; isendseq > recvwindow_start + 10) { return; } //printf("SV: have complete ticcmd for %i\n", client->sendseq); // We have all data we need to generate a command for this tic. cmd.seq = client->sendseq; // Add ticcmds from all players cmd.latency = 0; for (i=0; idiff; if (recvobj->latency > cmd.latency) cmd.latency = recvobj->latency; } //printf("SV: %i: latency %i\n", client->player_number, cmd.latency); // Add into the queue client->sendqueue[client->sendseq % BACKUPTICS] = cmd; // Transmit the new tic to the client starttic = client->sendseq - sv_settings.extratics; endtic = client->sendseq; if (starttic < 0) starttic = 0; NET_SV_SendTics(client, starttic, endtic); ++client->sendseq; } // Prevent against deadlock: resend requests are usually only // triggered if we miss a packet and receive the next one. // If we miss a whole load of packets, we can end up in a // deadlock situation where the client will not send any more. // If we don't receive any game data in a while, trigger a resend // request for the next tic we're expecting. void NET_SV_CheckDeadlock(net_client_t *client) { int nowtime; int i; // Don't expect game data from clients. if (client->drone) { return; } nowtime = I_GetTimeMS(); // If we haven't received anything for a long time, it may be a deadlock. if (nowtime - client->last_gamedata_time > 1000) { // Search the receive window for the first tic we are expecting // from this player. for (i=0; iplayer_number][i].active) { //printf("Possible deadlock: Sending resend request\n"); // Found a tic we haven't received. Send a resend request. NET_SV_SendResendRequest(client, recvwindow_start + i, recvwindow_start + i + 5); client->last_gamedata_time = nowtime; break; } } } } // Called when all players have disconnected. Return to listening for // players to start a new game, and disconnect any drones still connected. static void NET_SV_GameEnded(void) { int i; server_state = SERVER_WAITING_LAUNCH; sv_gamemode = indetermined; for (i=0; iconnection); if (client->connection.state == NET_CONN_STATE_DISCONNECTED && client->connection.disconnect_reason == NET_DISCONNECT_TIMEOUT) { NET_SV_BroadcastMessage("Client '%s' timed out and disconnected", client->name); } // Is this client disconnected? if (client->connection.state == NET_CONN_STATE_DISCONNECTED) { client->active = false; // If we were about to start a game, any player disconnecting // should cause an abort. if (server_state == SERVER_WAITING_START && !client->drone) { NET_SV_BroadcastMessage("Game startup aborted because " "player '%s' disconnected.", client->name); NET_SV_GameEnded(); } free(client->name); NET_FreeAddress(client->addr); // Are there any clients left connected? If not, return the // server to the waiting-for-players state. // // Disconnect any drones still connected. if (NET_SV_NumPlayers() <= 0) { NET_SV_GameEnded(); } } if (!ClientConnected(client)) { // client has not yet finished connecting return; } if (server_state == SERVER_WAITING_LAUNCH) { // Waiting for the game to start // Send information once every second if (client->last_send_time < 0 || I_GetTimeMS() - client->last_send_time > 1000) { NET_SV_SendWaitingData(client); client->last_send_time = I_GetTimeMS(); } } if (server_state == SERVER_IN_GAME) { NET_SV_PumpSendQueue(client); NET_SV_CheckDeadlock(client); } } // Add a network module to the server context void NET_SV_AddModule(net_module_t *module) { module->InitServer(); NET_AddModule(server_context, module); } // Initialize server and wait for connections void NET_SV_Init(void) { int i; // initialize send/receive context server_context = NET_NewContext(); // no clients yet for (i=0; i MASTER_RESOLVE_PERIOD * 1000) { net_addr_t *new_addr; new_addr = NET_Query_ResolveMaster(server_context); // Has the master server changed address? if (new_addr != NULL && new_addr != master_server) { NET_FreeAddress(master_server); master_server = new_addr; } master_resolve_time = now; } // Possibly refresh our registration with the master server. if (now - master_refresh_time > MASTER_REFRESH_PERIOD * 1000) { NET_Query_AddToMaster(master_server); master_refresh_time = now; } } void NET_SV_RegisterWithMaster(void) { //! // When running a server, don't register with the global master server. // Implies -server. // // @category net // if (!M_CheckParm("-privateserver")) { master_server = NET_Query_ResolveMaster(server_context); } else { master_server = NULL; } // Send request. if (master_server != NULL) { NET_Query_AddToMaster(master_server); master_refresh_time = I_GetTimeMS(); master_resolve_time = master_refresh_time; } } // Run server code to check for new packets/send packets as the server // requires void NET_SV_Run(void) { net_addr_t *addr; net_packet_t *packet; int i; if (!server_initialized) { return; } while (NET_RecvPacket(server_context, &addr, &packet)) { NET_SV_Packet(packet, addr); NET_FreePacket(packet); } if (master_server != NULL) { UpdateMasterServer(); } // "Run" any clients that may have things to do, independent of responses // to received packets for (i=0; i 5000) { running = false; fprintf(stderr, "SV: Timed out waiting for clients to disconnect.\n"); } // Run the client code in case this is a loopback client. NET_CL_Run(); NET_SV_Run(); // Don't hog the CPU I_Sleep(1); } } chocolate-doom-chocolate-doom-2.2.1/src/net_server.h000066400000000000000000000021241257432200600224200ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Network server code // #ifndef NET_SERVER_H #define NET_SERVER_H // initialize server and wait for connections void NET_SV_Init(void); // run server: check for new packets received etc. void NET_SV_Run(void); // Shut down the server // Blocks until all clients disconnect, or until a 5 second timeout void NET_SV_Shutdown(void); // Add a network module to the context used by the server void NET_SV_AddModule(net_module_t *module); // Register server with master server. void NET_SV_RegisterWithMaster(void); #endif /* #ifndef NET_SERVER_H */ chocolate-doom-chocolate-doom-2.2.1/src/net_structrw.c000066400000000000000000000365611257432200600230160ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Reading and writing various structures into packets // #include #include #include #include #include "doomtype.h" #include "m_misc.h" #include "net_packet.h" #include "net_structrw.h" void NET_WriteConnectData(net_packet_t *packet, net_connect_data_t *data) { NET_WriteInt8(packet, data->gamemode); NET_WriteInt8(packet, data->gamemission); NET_WriteInt8(packet, data->lowres_turn); NET_WriteInt8(packet, data->drone); NET_WriteInt8(packet, data->max_players); NET_WriteInt8(packet, data->is_freedoom); NET_WriteSHA1Sum(packet, data->wad_sha1sum); NET_WriteSHA1Sum(packet, data->deh_sha1sum); NET_WriteInt8(packet, data->player_class); } boolean NET_ReadConnectData(net_packet_t *packet, net_connect_data_t *data) { return NET_ReadInt8(packet, (unsigned int *) &data->gamemode) && NET_ReadInt8(packet, (unsigned int *) &data->gamemission) && NET_ReadInt8(packet, (unsigned int *) &data->lowres_turn) && NET_ReadInt8(packet, (unsigned int *) &data->drone) && NET_ReadInt8(packet, (unsigned int *) &data->max_players) && NET_ReadInt8(packet, (unsigned int *) &data->is_freedoom) && NET_ReadSHA1Sum(packet, data->wad_sha1sum) && NET_ReadSHA1Sum(packet, data->deh_sha1sum) && NET_ReadInt8(packet, (unsigned int *) &data->player_class); } void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings) { int i; NET_WriteInt8(packet, settings->ticdup); NET_WriteInt8(packet, settings->extratics); NET_WriteInt8(packet, settings->deathmatch); NET_WriteInt8(packet, settings->nomonsters); NET_WriteInt8(packet, settings->fast_monsters); NET_WriteInt8(packet, settings->respawn_monsters); NET_WriteInt8(packet, settings->episode); NET_WriteInt8(packet, settings->map); NET_WriteInt8(packet, settings->skill); NET_WriteInt8(packet, settings->gameversion); NET_WriteInt8(packet, settings->lowres_turn); NET_WriteInt8(packet, settings->new_sync); NET_WriteInt32(packet, settings->timelimit); NET_WriteInt8(packet, settings->loadgame); NET_WriteInt8(packet, settings->random); NET_WriteInt8(packet, settings->num_players); NET_WriteInt8(packet, settings->consoleplayer); for (i = 0; i < settings->num_players; ++i) { NET_WriteInt8(packet, settings->player_classes[i]); } } boolean NET_ReadSettings(net_packet_t *packet, net_gamesettings_t *settings) { boolean success; int i; success = NET_ReadInt8(packet, (unsigned int *) &settings->ticdup) && NET_ReadInt8(packet, (unsigned int *) &settings->extratics) && NET_ReadInt8(packet, (unsigned int *) &settings->deathmatch) && NET_ReadInt8(packet, (unsigned int *) &settings->nomonsters) && NET_ReadInt8(packet, (unsigned int *) &settings->fast_monsters) && NET_ReadInt8(packet, (unsigned int *) &settings->respawn_monsters) && NET_ReadInt8(packet, (unsigned int *) &settings->episode) && NET_ReadInt8(packet, (unsigned int *) &settings->map) && NET_ReadSInt8(packet, &settings->skill) && NET_ReadInt8(packet, (unsigned int *) &settings->gameversion) && NET_ReadInt8(packet, (unsigned int *) &settings->lowres_turn) && NET_ReadInt8(packet, (unsigned int *) &settings->new_sync) && NET_ReadInt32(packet, (unsigned int *) &settings->timelimit) && NET_ReadSInt8(packet, (signed int *) &settings->loadgame) && NET_ReadInt8(packet, (unsigned int *) &settings->random) && NET_ReadInt8(packet, (unsigned int *) &settings->num_players) && NET_ReadSInt8(packet, (signed int *) &settings->consoleplayer); if (!success) { return false; } for (i = 0; i < settings->num_players; ++i) { if (!NET_ReadInt8(packet, (unsigned int *) &settings->player_classes[i])) { return false; } } return true; } boolean NET_ReadQueryData(net_packet_t *packet, net_querydata_t *query) { boolean result; query->version = NET_ReadString(packet); result = query->version != NULL && NET_ReadInt8(packet, (unsigned int *) &query->server_state) && NET_ReadInt8(packet, (unsigned int *) &query->num_players) && NET_ReadInt8(packet, (unsigned int *) &query->max_players) && NET_ReadInt8(packet, (unsigned int *) &query->gamemode) && NET_ReadInt8(packet, (unsigned int *) &query->gamemission); if (result) { query->description = NET_ReadString(packet); return query->description != NULL; } else { return false; } } void NET_WriteQueryData(net_packet_t *packet, net_querydata_t *query) { NET_WriteString(packet, query->version); NET_WriteInt8(packet, query->server_state); NET_WriteInt8(packet, query->num_players); NET_WriteInt8(packet, query->max_players); NET_WriteInt8(packet, query->gamemode); NET_WriteInt8(packet, query->gamemission); NET_WriteString(packet, query->description); } void NET_WriteTiccmdDiff(net_packet_t *packet, net_ticdiff_t *diff, boolean lowres_turn) { // Header NET_WriteInt8(packet, diff->diff); // Write the fields which are enabled: if (diff->diff & NET_TICDIFF_FORWARD) NET_WriteInt8(packet, diff->cmd.forwardmove); if (diff->diff & NET_TICDIFF_SIDE) NET_WriteInt8(packet, diff->cmd.sidemove); if (diff->diff & NET_TICDIFF_TURN) { if (lowres_turn) { NET_WriteInt8(packet, diff->cmd.angleturn / 256); } else { NET_WriteInt16(packet, diff->cmd.angleturn); } } if (diff->diff & NET_TICDIFF_BUTTONS) NET_WriteInt8(packet, diff->cmd.buttons); if (diff->diff & NET_TICDIFF_CONSISTANCY) NET_WriteInt8(packet, diff->cmd.consistancy); if (diff->diff & NET_TICDIFF_CHATCHAR) NET_WriteInt8(packet, diff->cmd.chatchar); if (diff->diff & NET_TICDIFF_RAVEN) { NET_WriteInt8(packet, diff->cmd.lookfly); NET_WriteInt8(packet, diff->cmd.arti); } if (diff->diff & NET_TICDIFF_STRIFE) { NET_WriteInt8(packet, diff->cmd.buttons2); NET_WriteInt16(packet, diff->cmd.inventory); } } boolean NET_ReadTiccmdDiff(net_packet_t *packet, net_ticdiff_t *diff, boolean lowres_turn) { unsigned int val; signed int sval; // Read header if (!NET_ReadInt8(packet, &diff->diff)) return false; // Read fields if (diff->diff & NET_TICDIFF_FORWARD) { if (!NET_ReadSInt8(packet, &sval)) return false; diff->cmd.forwardmove = sval; } if (diff->diff & NET_TICDIFF_SIDE) { if (!NET_ReadSInt8(packet, &sval)) return false; diff->cmd.sidemove = sval; } if (diff->diff & NET_TICDIFF_TURN) { if (lowres_turn) { if (!NET_ReadSInt8(packet, &sval)) return false; diff->cmd.angleturn = sval * 256; } else { if (!NET_ReadSInt16(packet, &sval)) return false; diff->cmd.angleturn = sval; } } if (diff->diff & NET_TICDIFF_BUTTONS) { if (!NET_ReadInt8(packet, &val)) return false; diff->cmd.buttons = val; } if (diff->diff & NET_TICDIFF_CONSISTANCY) { if (!NET_ReadInt8(packet, &val)) return false; diff->cmd.consistancy = val; } if (diff->diff & NET_TICDIFF_CHATCHAR) { if (!NET_ReadInt8(packet, &val)) return false; diff->cmd.chatchar = val; } if (diff->diff & NET_TICDIFF_RAVEN) { if (!NET_ReadInt8(packet, &val)) return false; diff->cmd.lookfly = val; if (!NET_ReadInt8(packet, &val)) return false; diff->cmd.arti = val; } if (diff->diff & NET_TICDIFF_STRIFE) { if (!NET_ReadInt8(packet, &val)) return false; diff->cmd.buttons2 = val; if (!NET_ReadInt16(packet, &val)) return false; diff->cmd.inventory = val; } return true; } void NET_TiccmdDiff(ticcmd_t *tic1, ticcmd_t *tic2, net_ticdiff_t *diff) { diff->diff = 0; diff->cmd = *tic2; if (tic1->forwardmove != tic2->forwardmove) diff->diff |= NET_TICDIFF_FORWARD; if (tic1->sidemove != tic2->sidemove) diff->diff |= NET_TICDIFF_SIDE; if (tic1->angleturn != tic2->angleturn) diff->diff |= NET_TICDIFF_TURN; if (tic1->buttons != tic2->buttons) diff->diff |= NET_TICDIFF_BUTTONS; if (tic1->consistancy != tic2->consistancy) diff->diff |= NET_TICDIFF_CONSISTANCY; if (tic2->chatchar != 0) diff->diff |= NET_TICDIFF_CHATCHAR; // Heretic/Hexen-specific if (tic1->lookfly != tic2->lookfly || tic2->arti != 0) diff->diff |= NET_TICDIFF_RAVEN; // Strife-specific if (tic1->buttons2 != tic2->buttons2 || tic2->inventory != 0) diff->diff |= NET_TICDIFF_STRIFE; } void NET_TiccmdPatch(ticcmd_t *src, net_ticdiff_t *diff, ticcmd_t *dest) { memmove(dest, src, sizeof(ticcmd_t)); // Apply the diff if (diff->diff & NET_TICDIFF_FORWARD) dest->forwardmove = diff->cmd.forwardmove; if (diff->diff & NET_TICDIFF_SIDE) dest->sidemove = diff->cmd.sidemove; if (diff->diff & NET_TICDIFF_TURN) dest->angleturn = diff->cmd.angleturn; if (diff->diff & NET_TICDIFF_BUTTONS) dest->buttons = diff->cmd.buttons; if (diff->diff & NET_TICDIFF_CONSISTANCY) dest->consistancy = diff->cmd.consistancy; if (diff->diff & NET_TICDIFF_CHATCHAR) dest->chatchar = diff->cmd.chatchar; else dest->chatchar = 0; // Heretic/Hexen specific: if (diff->diff & NET_TICDIFF_RAVEN) { dest->lookfly = diff->cmd.lookfly; dest->arti = diff->cmd.arti; } else { dest->arti = 0; } // Strife-specific: if (diff->diff & NET_TICDIFF_STRIFE) { dest->buttons2 = diff->cmd.buttons2; dest->inventory = diff->cmd.inventory; } else { dest->inventory = 0; } } // // net_full_ticcmd_t // boolean NET_ReadFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean lowres_turn) { unsigned int bitfield; int i; // Latency if (!NET_ReadSInt16(packet, &cmd->latency)) { return false; } // Regenerate playeringame from the "header" bitfield if (!NET_ReadInt8(packet, &bitfield)) { return false; } for (i=0; iplayeringame[i] = (bitfield & (1 << i)) != 0; } // Read cmds for (i=0; iplayeringame[i]) { if (!NET_ReadTiccmdDiff(packet, &cmd->cmds[i], lowres_turn)) { return false; } } } return true; } void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean lowres_turn) { unsigned int bitfield; int i; // Write the latency NET_WriteInt16(packet, cmd->latency); // Write "header" byte indicating which players are active // in this ticcmd bitfield = 0; for (i=0; iplayeringame[i]) { bitfield |= 1 << i; } } NET_WriteInt8(packet, bitfield); // Write player ticcmds for (i=0; iplayeringame[i]) { NET_WriteTiccmdDiff(packet, &cmd->cmds[i], lowres_turn); } } } void NET_WriteWaitData(net_packet_t *packet, net_waitdata_t *data) { int i; NET_WriteInt8(packet, data->num_players); NET_WriteInt8(packet, data->num_drones); NET_WriteInt8(packet, data->ready_players); NET_WriteInt8(packet, data->max_players); NET_WriteInt8(packet, data->is_controller); NET_WriteInt8(packet, data->consoleplayer); for (i = 0; i < data->num_players && i < NET_MAXPLAYERS; ++i) { NET_WriteString(packet, data->player_names[i]); NET_WriteString(packet, data->player_addrs[i]); } NET_WriteSHA1Sum(packet, data->wad_sha1sum); NET_WriteSHA1Sum(packet, data->deh_sha1sum); NET_WriteInt8(packet, data->is_freedoom); } boolean NET_ReadWaitData(net_packet_t *packet, net_waitdata_t *data) { int i; char *s; if (!NET_ReadInt8(packet, (unsigned int *) &data->num_players) || !NET_ReadInt8(packet, (unsigned int *) &data->num_drones) || !NET_ReadInt8(packet, (unsigned int *) &data->ready_players) || !NET_ReadInt8(packet, (unsigned int *) &data->max_players) || !NET_ReadInt8(packet, (unsigned int *) &data->is_controller) || !NET_ReadSInt8(packet, &data->consoleplayer)) { return false; } for (i = 0; i < data->num_players && i < NET_MAXPLAYERS; ++i) { s = NET_ReadString(packet); if (s == NULL || strlen(s) >= MAXPLAYERNAME) { return false; } M_StringCopy(data->player_names[i], s, MAXPLAYERNAME); s = NET_ReadString(packet); if (s == NULL || strlen(s) >= MAXPLAYERNAME) { return false; } M_StringCopy(data->player_addrs[i], s, MAXPLAYERNAME); } return NET_ReadSHA1Sum(packet, data->wad_sha1sum) && NET_ReadSHA1Sum(packet, data->deh_sha1sum) && NET_ReadInt8(packet, (unsigned int *) &data->is_freedoom); } static boolean NET_ReadBlob(net_packet_t *packet, uint8_t *buf, size_t len) { unsigned int b; int i; for (i=0; i #include "m_config.h" #include "textscreen.h" #include "mode.h" #include "compatibility.h" #define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-compat" int vanilla_savegame_limit = 1; int vanilla_demo_limit = 1; void CompatibilitySettings(void) { txt_window_t *window; window = TXT_NewWindow("Compatibility"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); TXT_AddWidgets(window, TXT_NewCheckBox("Vanilla savegame limit", &vanilla_savegame_limit), TXT_NewCheckBox("Vanilla demo limit", &vanilla_demo_limit), NULL); } void BindCompatibilityVariables(void) { if (gamemission == doom || gamemission == strife) { M_BindIntVariable("vanilla_savegame_limit", &vanilla_savegame_limit); M_BindIntVariable("vanilla_demo_limit", &vanilla_demo_limit); } } chocolate-doom-chocolate-doom-2.2.1/src/setup/compatibility.h000066400000000000000000000014331257432200600242570ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef SETUP_COMPATIBILITY_H #define SETUP_COMPATIBILITY_H void CompatibilitySettings(void); void BindCompatibilityVariables(void); extern int vanilla_savegame_limit; extern int vanilla_demo_limit; #endif /* #ifndef SETUP_COMPATIBILITY_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/display.c000066400000000000000000000447071257432200600230610ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #endif #include "textscreen.h" #include "m_config.h" #include "m_misc.h" #include "mode.h" #include "display.h" #include "config.h" #define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-display" extern void RestartTextscreen(void); typedef struct { char *description; int bpp; } pixel_depth_t; // List of supported pixel depths. static pixel_depth_t pixel_depths[] = { { "8-bit", 8 }, { "16-bit", 16 }, { "24-bit", 24 }, { "32-bit", 32 }, }; // List of strings containing supported pixel depths. static char **supported_bpps; static int num_supported_bpps; typedef struct { int w, h; } screen_mode_t; // List of aspect ratio-uncorrected modes static screen_mode_t screen_modes_unscaled[] = { { 320, 200 }, { 640, 400 }, { 960, 600 }, { 1280, 800 }, { 1600, 1000 }, { 0, 0}, }; // List of aspect ratio-corrected modes static screen_mode_t screen_modes_scaled[] = { { 256, 200 }, { 320, 240 }, { 512, 400 }, { 640, 480 }, { 800, 600 }, { 960, 720 }, { 1024, 800 }, { 1280, 960 }, { 1600, 1200 }, { 0, 0}, }; // List of fullscreen modes generated at runtime static screen_mode_t *screen_modes_fullscreen = NULL; static int num_screen_modes_fullscreen; static int vidmode = 0; static char *video_driver = ""; static char *window_position = ""; static int autoadjust_video_settings = 1; static int aspect_ratio_correct = 1; static int fullscreen = 1; static int screen_width = 320; static int screen_height = 200; static int screen_bpp = 0; static int startup_delay = 1000; static int usegamma = 0; int graphical_startup = 1; int show_endoom = 1; int png_screenshots = 0; // These are the last screen width/height values that were chosen by the // user. These are used when finding the "nearest" mode, so when // changing the fullscreen / aspect ratio options, the setting does not // jump around. static int selected_screen_width = 0, selected_screen_height; // Index into the supported_bpps of the selected pixel depth. static int selected_bpp = 0; static int system_video_env_set; // Set the SDL_VIDEODRIVER environment variable void SetDisplayDriver(void) { static int first_time = 1; if (first_time) { system_video_env_set = getenv("SDL_VIDEODRIVER") != NULL; first_time = 0; } // Don't override the command line environment, if it has been set. if (system_video_env_set) { return; } // Use the value from the configuration file, if it has been set. if (strcmp(video_driver, "") != 0) { char *env_string; env_string = M_StringJoin("SDL_VIDEODRIVER=", video_driver, NULL); putenv(env_string); free(env_string); } } // Query SDL as to whether any fullscreen modes are available for the // specified pixel depth. static int PixelDepthSupported(int bpp) { SDL_PixelFormat format; SDL_Rect **modes; format.BitsPerPixel = bpp; format.BytesPerPixel = (bpp + 7) / 8; modes = SDL_ListModes(&format, SDL_FULLSCREEN); return modes != NULL; } // Query SDL and populate the supported_bpps array. static void IdentifyPixelDepths(void) { unsigned int i; unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); if (supported_bpps != NULL) { free(supported_bpps); } supported_bpps = malloc(sizeof(char *) * num_depths); num_supported_bpps = 0; // Check each bit depth to determine if modes are available. for (i = 0; i < num_depths; ++i) { // If modes are available, add this bit depth to the list. if (PixelDepthSupported(pixel_depths[i].bpp)) { supported_bpps[num_supported_bpps] = pixel_depths[i].description; ++num_supported_bpps; } } // No supported pixel depths? That's kind of a problem. Add 8bpp // as a fallback. if (num_supported_bpps == 0) { supported_bpps[0] = pixel_depths[0].description; ++num_supported_bpps; } } // Get the screen pixel depth corresponding to what selected_bpp is set to. static int GetSelectedBPP(void) { unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); unsigned int i; // Find which pixel depth is selected, and set screen_bpp. for (i = 0; i < num_depths; ++i) { if (pixel_depths[i].description == supported_bpps[selected_bpp]) { return pixel_depths[i].bpp; } } // Default fallback value. return 8; } // Get the index into supported_bpps of the specified pixel depth string. static int GetSupportedBPPIndex(char *description) { unsigned int i; for (i = 0; i < num_supported_bpps; ++i) { if (supported_bpps[i] == description) { return i; } } return -1; } // Set selected_bpp to match screen_bpp. static int TrySetSelectedBPP(void) { unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); unsigned int i; // Search pixel_depths, find the bpp that corresponds to screen_bpp, // then set selected_bpp to match. for (i = 0; i < num_depths; ++i) { if (pixel_depths[i].bpp == screen_bpp) { selected_bpp = GetSupportedBPPIndex(pixel_depths[i].description); if (selected_bpp >= 0) { return 1; } } } return 0; } static void SetSelectedBPP(void) { const SDL_VideoInfo *info; if (TrySetSelectedBPP()) { return; } // screen_bpp does not match any supported pixel depth. Query SDL // to find out what it recommends using. info = SDL_GetVideoInfo(); if (info != NULL && info->vfmt != NULL) { screen_bpp = info->vfmt->BitsPerPixel; } // Try again. if (!TrySetSelectedBPP()) { // Give up and just use the first in the list. selected_bpp = 0; screen_bpp = GetSelectedBPP(); } } static void ModeSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(mode)) { TXT_CAST_ARG(screen_mode_t, mode); screen_width = mode->w; screen_height = mode->h; // This is now the most recently selected screen width selected_screen_width = screen_width; selected_screen_height = screen_height; } static int GoodFullscreenMode(screen_mode_t *mode) { int w, h; w = mode->w; h = mode->h; // 320x200 and 640x400 are always good (special case) if ((w == 320 && h == 200) || (w == 640 && h == 400)) { return 1; } // Special case: 320x240 letterboxed mode is okay (but not aspect // ratio corrected 320x240) if (w == 320 && h == 240 && !aspect_ratio_correct) { return 1; } // Ignore all modes less than 640x480 return w >= 640 && h >= 480; } // Build screen_modes_fullscreen static void BuildFullscreenModesList(void) { SDL_PixelFormat format; SDL_Rect **modes; screen_mode_t *m1; screen_mode_t *m2; screen_mode_t m; int num_modes; int i; // Free the existing modes list, if one exists if (screen_modes_fullscreen != NULL) { free(screen_modes_fullscreen); } // Get a list of fullscreen modes and find out how many // modes are in the list. format.BitsPerPixel = screen_bpp; format.BytesPerPixel = (screen_bpp + 7) / 8; modes = SDL_ListModes(&format, SDL_FULLSCREEN); if (modes == NULL || modes == (SDL_Rect **) -1) { num_modes = 0; } else { for (num_modes=0; modes[num_modes] != NULL; ++num_modes); } // Build the screen_modes_fullscreen array screen_modes_fullscreen = malloc(sizeof(screen_mode_t) * (num_modes + 1)); for (i=0; iw; screen_modes_fullscreen[i].h = modes[i]->h; } screen_modes_fullscreen[i].w = 0; screen_modes_fullscreen[i].h = 0; // Reverse the order of the modes list (smallest modes first) for (i=0; i 0) { screen_width = modes[vidmode].w; screen_height = modes[vidmode].h; } } // Callback invoked when the BPP selector is changed. static void UpdateBPP(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(modes_table)) { TXT_CAST_ARG(txt_table_t, modes_table); screen_bpp = GetSelectedBPP(); // Rebuild list of fullscreen modes. BuildFullscreenModesList(); GenerateModesTable(NULL, modes_table); } static void UpdateModeSeparator(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(separator)) { TXT_CAST_ARG(txt_separator_t, separator); if (fullscreen) { TXT_SetSeparatorLabel(separator, "Screen mode"); } else { TXT_SetSeparatorLabel(separator, "Window size"); } } static void AdvancedDisplayConfig(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(modes_table)) { TXT_CAST_ARG(txt_table_t, modes_table); txt_window_t *window; txt_checkbox_t *ar_checkbox; window = TXT_NewWindow("Advanced display options"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); TXT_SetColumnWidths(window, 35); TXT_AddWidgets(window, ar_checkbox = TXT_NewCheckBox("Fix aspect ratio", &aspect_ratio_correct), NULL); if (gamemission == heretic || gamemission == hexen || gamemission == strife) { TXT_AddWidget(window, TXT_NewCheckBox("Graphical startup", &graphical_startup)); } if (gamemission == doom || gamemission == heretic || gamemission == strife) { TXT_AddWidget(window, TXT_NewCheckBox("Show ENDOOM screen on exit", &show_endoom)); } #ifdef HAVE_LIBPNG TXT_AddWidget(window, TXT_NewCheckBox("Save screenshots in PNG format", &png_screenshots)); #endif TXT_SignalConnect(ar_checkbox, "changed", GenerateModesTable, modes_table); } void ConfigDisplay(void) { txt_window_t *window; txt_table_t *modes_table; txt_separator_t *modes_separator; txt_table_t *bpp_table; txt_window_action_t *advanced_button; txt_checkbox_t *fs_checkbox; int i; int num_columns; int num_rows; int window_y; // What color depths are supported? Generate supported_bpps array // and set selected_bpp to match the current value of screen_bpp. IdentifyPixelDepths(); SetSelectedBPP(); // First time in? Initialise selected_screen_{width,height} if (selected_screen_width == 0) { selected_screen_width = screen_width; selected_screen_height = screen_height; } // Open the window window = TXT_NewWindow("Display Configuration"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); // Some machines can have lots of video modes. This tries to // keep a limit of six lines by increasing the number of // columns. In extreme cases, the window is moved up slightly. BuildFullscreenModesList(); if (num_screen_modes_fullscreen <= 24) { num_columns = 3; } else if (num_screen_modes_fullscreen <= 40) { num_columns = 4; } else { num_columns = 5; } modes_table = TXT_NewTable(num_columns); // Build window: TXT_AddWidget(window, fs_checkbox = TXT_NewCheckBox("Full screen", &fullscreen)); if (num_supported_bpps > 1) { TXT_AddWidgets(window, TXT_NewSeparator("Color depth"), bpp_table = TXT_NewTable(4), NULL); for (i = 0; i < num_supported_bpps; ++i) { txt_radiobutton_t *button; button = TXT_NewRadioButton(supported_bpps[i], &selected_bpp, i); TXT_AddWidget(bpp_table, button); TXT_SignalConnect(button, "selected", UpdateBPP, modes_table); } } TXT_AddWidgets(window, modes_separator = TXT_NewSeparator(""), modes_table, NULL); TXT_SignalConnect(fs_checkbox, "changed", GenerateModesTable, modes_table); TXT_SignalConnect(fs_checkbox, "changed", UpdateModeSeparator, modes_separator); // How many rows high will the configuration window be? // Need to take into account number of fullscreen modes, and also // number of supported pixel depths. // The windowed modes list is four rows, so take the maximum of // windowed and fullscreen. num_rows = (num_screen_modes_fullscreen + num_columns - 1) / num_columns; if (num_rows < 4) { num_rows = 4; } if (num_supported_bpps > 1) { num_rows += 2; } if (num_rows < 14) { window_y = 8 - ((num_rows + 1) / 2); } else { window_y = 1; } // The window is set at a fixed vertical position. This keeps // the top of the window stationary when switching between // fullscreen and windowed mode (which causes the window's // height to change). TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP, TXT_SCREEN_W / 2, window_y); GenerateModesTable(NULL, modes_table); UpdateModeSeparator(NULL, modes_separator); // Button to open "advanced" window. // Need to pass a pointer to the modes table, as some of the options // in there trigger a rebuild of it. advanced_button = TXT_NewWindowAction('a', "Advanced"); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, advanced_button); TXT_SignalConnect(advanced_button, "pressed", AdvancedDisplayConfig, modes_table); } void BindDisplayVariables(void) { M_BindIntVariable("autoadjust_video_settings", &autoadjust_video_settings); M_BindIntVariable("aspect_ratio_correct", &aspect_ratio_correct); M_BindIntVariable("fullscreen", &fullscreen); M_BindIntVariable("screen_width", &screen_width); M_BindIntVariable("screen_height", &screen_height); M_BindIntVariable("screen_bpp", &screen_bpp); M_BindIntVariable("startup_delay", &startup_delay); M_BindStringVariable("video_driver", &video_driver); M_BindStringVariable("window_position", &window_position); M_BindIntVariable("usegamma", &usegamma); M_BindIntVariable("png_screenshots", &png_screenshots); if (gamemission == doom || gamemission == heretic || gamemission == strife) { M_BindIntVariable("show_endoom", &show_endoom); } if (gamemission == heretic || gamemission == hexen || gamemission == strife) { M_BindIntVariable("graphical_startup", &graphical_startup); } // Windows Vista or later? Set screen color depth to // 32 bits per pixel, as 8-bit palettized screen modes // don't work properly in recent versions. #if defined(_WIN32) && !defined(_WIN32_WCE) { OSVERSIONINFOEX version_info; ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO *) &version_info); if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 6) { screen_bpp = 32; } } #endif // Disable fullscreen by default on OS X, as there is an SDL bug // where some old versions of OS X (<= Snow Leopard) crash. #ifdef __MACOSX__ fullscreen = 0; screen_width = 800; screen_height = 600; #endif } chocolate-doom-chocolate-doom-2.2.1/src/setup/display.h000066400000000000000000000014151257432200600230530ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef SETUP_DISPLAY_H #define SETUP_DISPLAY_H void ConfigDisplay(void); void SetDisplayDriver(void); void BindDisplayVariables(void); extern int show_endoom; extern int graphical_startup; #endif /* #ifndef SETUP_DISPLAY_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/execute.c000066400000000000000000000205421257432200600230450ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Code for invoking Doom #include #include #include #include #include #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #else #include #include #endif #include "textscreen.h" #include "config.h" #include "execute.h" #include "mode.h" #include "m_argv.h" #include "m_config.h" #include "m_misc.h" struct execute_context_s { char *response_file; FILE *stream; }; // Returns the path to a temporary file of the given name, stored // inside the system temporary directory. static char *TempFile(char *s) { char *tempdir; #ifdef _WIN32 // Check the TEMP environment variable to find the location. tempdir = getenv("TEMP"); if (tempdir == NULL) { tempdir = "."; } #else // In Unix, just use /tmp. tempdir = "/tmp"; #endif return M_StringJoin(tempdir, DIR_SEPARATOR_S, s, NULL); } static int ArgumentNeedsEscape(char *arg) { char *p; for (p = arg; *p != '\0'; ++p) { if (isspace(*p)) { return 1; } } return 0; } // Arguments passed to the setup tool should be passed through to the // game when launching a game. Calling this adds all arguments from // myargv to the output context. void PassThroughArguments(execute_context_t *context) { int i; for (i = 1; i < myargc; ++i) { if (ArgumentNeedsEscape(myargv[i])) { AddCmdLineParameter(context, "\"%s\"", myargv[i]); } else { AddCmdLineParameter(context, "%s", myargv[i]); } } } execute_context_t *NewExecuteContext(void) { execute_context_t *result; result = malloc(sizeof(execute_context_t)); result->response_file = TempFile("chocolat.rsp"); result->stream = fopen(result->response_file, "w"); if (result->stream == NULL) { fprintf(stderr, "Error opening response file\n"); exit(-1); } return result; } void AddCmdLineParameter(execute_context_t *context, char *s, ...) { va_list args; va_start(args, s); vfprintf(context->stream, s, args); fprintf(context->stream, "\n"); } #if defined(_WIN32) // Wait for the specified process to exit. Returns the exit code. static unsigned int WaitForProcessExit(HANDLE subprocess) { DWORD exit_code; for (;;) { WaitForSingleObject(subprocess, INFINITE); if (!GetExitCodeProcess(subprocess, &exit_code)) { return -1; } if (exit_code != STILL_ACTIVE) { return exit_code; } } } static void ConcatWCString(wchar_t *buf, const char *value) { MultiByteToWideChar(CP_OEMCP, 0, value, strlen(value) + 1, buf + wcslen(buf), strlen(value) + 1); } // Build the command line string, a wide character string of the form: // // "program" "arg" static wchar_t *BuildCommandLine(const char *program, const char *arg) { wchar_t exe_path[MAX_PATH]; wchar_t *result; wchar_t *sep; // Get the path to this .exe file. GetModuleFileNameW(NULL, exe_path, MAX_PATH); // Allocate buffer to contain result string. result = calloc(wcslen(exe_path) + strlen(program) + strlen(arg) + 6, sizeof(wchar_t)); wcscpy(result, L"\""); // Copy the path part of the filename (including ending \) // into the result buffer: sep = wcsrchr(exe_path, DIR_SEPARATOR); if (sep != NULL) { wcsncpy(result + 1, exe_path, sep - exe_path + 1); result[sep - exe_path + 2] = '\0'; } // Concatenate the name of the program: ConcatWCString(result, program); // End of program name, start of argument: wcscat(result, L"\" \""); ConcatWCString(result, arg); wcscat(result, L"\""); return result; } static int ExecuteCommand(const char *program, const char *arg) { STARTUPINFOW startup_info; PROCESS_INFORMATION proc_info; wchar_t *command; int result = 0; command = BuildCommandLine(program, arg); // Invoke the program: memset(&proc_info, 0, sizeof(proc_info)); memset(&startup_info, 0, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &proc_info)) { result = -1; } else { // Wait for the process to finish, and save the exit code. result = WaitForProcessExit(proc_info.hProcess); CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); } free(command); return result; } #else // Given the specified program name, get the full path to the program, // assuming that it is in the same directory as this program is. static char *GetFullExePath(const char *program) { char *result; char *sep; size_t result_len; unsigned int path_len; sep = strrchr(myargv[0], DIR_SEPARATOR); if (sep == NULL) { result = M_StringDuplicate(program); } else { path_len = sep - myargv[0] + 1; result_len = strlen(program) + path_len + 1; result = malloc(result_len); M_StringCopy(result, myargv[0], result_len); result[path_len] = '\0'; M_StringConcat(result, program, result_len); } return result; } static int ExecuteCommand(const char *program, const char *arg) { pid_t childpid; int result; const char *argv[3]; childpid = fork(); if (childpid == 0) { // This is the child. Execute the command. argv[0] = GetFullExePath(program); argv[1] = arg; argv[2] = NULL; execvp(argv[0], (char **) argv); exit(0x80); } else { // This is the parent. Wait for the child to finish, and return // the status code. waitpid(childpid, &result, 0); if (WIFEXITED(result) && WEXITSTATUS(result) != 0x80) { return WEXITSTATUS(result); } else { return -1; } } } #endif int ExecuteDoom(execute_context_t *context) { char *response_file_arg; int result; fclose(context->stream); // Build the command line response_file_arg = M_StringJoin("@", context->response_file, NULL); // Run Doom result = ExecuteCommand(GetExecutableName(), response_file_arg); free(response_file_arg); // Destroy context remove(context->response_file); free(context->response_file); free(context); return result; } static void TestCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data)) { execute_context_t *exec; char *main_cfg; char *extra_cfg; txt_window_t *testwindow; testwindow = TXT_MessageBox("Starting Doom", "Starting Doom to test the\n" "settings. Please wait."); TXT_DrawDesktop(); // Save temporary configuration files with the current configuration main_cfg = TempFile("tmp.cfg"); extra_cfg = TempFile("extratmp.cfg"); M_SaveDefaultsAlternate(main_cfg, extra_cfg); // Run with the -testcontrols parameter exec = NewExecuteContext(); AddCmdLineParameter(exec, "-testcontrols"); AddCmdLineParameter(exec, "-config \"%s\"", main_cfg); AddCmdLineParameter(exec, "-extraconfig \"%s\"", extra_cfg); ExecuteDoom(exec); TXT_CloseWindow(testwindow); // Delete the temporary config files remove(main_cfg); remove(extra_cfg); free(main_cfg); free(extra_cfg); } txt_window_action_t *TestConfigAction(void) { txt_window_action_t *test_action; test_action = TXT_NewWindowAction('t', "Test"); TXT_SignalConnect(test_action, "pressed", TestCallback, NULL); return test_action; } chocolate-doom-chocolate-doom-2.2.1/src/setup/execute.h000066400000000000000000000024411257432200600230500ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TESTCONFIG_H #define TESTCONFIG_H #include "textscreen.h" typedef struct execute_context_s execute_context_t; #define IWAD_DOOM2 (1 << 0) /* doom2.wad */ #define IWAD_PLUTONIA (1 << 1) /* plutonia.wad */ #define IWAD_TNT (1 << 2) /* tnt.wad */ #define IWAD_DOOM (1 << 3) /* doom.wad */ #define IWAD_DOOM1 (1 << 4) /* doom1.wad */ #define IWAD_CHEX (1 << 5) /* chex.wad */ execute_context_t *NewExecuteContext(void); void AddCmdLineParameter(execute_context_t *context, char *s, ...); void PassThroughArguments(execute_context_t *context); int ExecuteDoom(execute_context_t *context); int FindInstalledIWADs(void); txt_window_action_t *TestConfigAction(void); #endif /* #ifndef TESTCONFIG_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/joystick.c000066400000000000000000000575211257432200600232510ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "doomtype.h" #include "i_joystick.h" #include "m_config.h" #include "m_controls.h" #include "m_misc.h" #include "textscreen.h" #include "execute.h" #include "joystick.h" #include "mode.h" #include "txt_joyaxis.h" #include "txt_joybinput.h" #define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-gamepad" typedef struct { char *name; // Config file name int value; } joystick_config_t; typedef struct { char *name; int axes, buttons, hats; const joystick_config_t *configs; } known_joystick_t; // SDL joystick successfully initialized? static int joystick_initted = 0; // Joystick enable/disable static int usejoystick = 0; // Joystick to use, as an SDL joystick index: int joystick_index = -1; // Calibration button. This is the button the user pressed at the // start of the calibration sequence. They *must* press this button // for each subsequent sequence. static int calibrate_button = -1; // Which joystick axis to use for horizontal movement, and whether to // invert the direction: static int joystick_x_axis = 0; static int joystick_x_invert = 0; // Which joystick axis to use for vertical movement, and whether to // invert the direction: static int joystick_y_axis = 1; static int joystick_y_invert = 0; // Strafe axis. static int joystick_strafe_axis = -1; static int joystick_strafe_invert = 0; // Virtual to physical mapping. int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; static txt_button_t *joystick_button; static txt_joystick_axis_t *x_axis_widget; static txt_joystick_axis_t *y_axis_widget; // // Calibration // static txt_window_t *calibration_window; static SDL_Joystick **all_joysticks = NULL; // Known controllers. // There are lots of game controllers on the market. Try to configure // them in a consistent way: // // * Use the D-pad rather than an analog stick. left/right turns the // player, up/down moves forward/backward - ie. a "traditional" // layout like Vanilla Doom rather than something more elaborate. // * No strafe axis. // * Fire and run keys together, on the main right-side buttons, // ideally arranged so both can be controlled/covered simultaneously // with the thumb. // * Jump/use keys in the same cluster if possible. // * Strafe left/right configured to map to shoulder buttons if they // are present. No "strafe on" key unless shoulder buttons not present. // * If a second set of shoulder buttons are also present, these map // to prev weapon/next weapon. // * Menu button mapped to start button. // // With the common right-side button arrangement that looks like this, // which is similar to the Vanilla default configuration when using // a Gravis Gamepad: // // B A = Fire // A D B = Jump // C C = Speed // D = Use // Always loaded before others, to get a known starting configuration. static const joystick_config_t empty_defaults[] = { {"joystick_x_axis", -1}, {"joystick_x_invert", 0}, {"joystick_y_axis", -1}, {"joystick_y_invert", 0}, {"joystick_strafe_axis", -1}, {"joystick_strafe_invert", 0}, {"joyb_fire", -1}, {"joyb_use", -1}, {"joyb_strafe", -1}, {"joyb_speed", -1}, {"joyb_strafeleft", -1}, {"joyb_straferight", -1}, {"joyb_prevweapon", -1}, {"joyb_nextweapon", -1}, {"joyb_jump", -1}, {"joyb_menu_activate", -1}, {NULL, 0}, }; static const joystick_config_t ps3_controller[] = { {"joystick_x_axis", CREATE_BUTTON_AXIS(7, 5)}, {"joystick_y_axis", CREATE_BUTTON_AXIS(4, 6)}, {"joyb_fire", 15}, // Square {"joyb_speed", 14}, // X {"joyb_use", 13}, // Circle {"joyb_jump", 12}, // Triangle {"joyb_strafeleft", 8}, // Bottom shoulder buttons {"joyb_straferight", 9}, {"joyb_prevweapon", 10}, // Top shoulder buttons {"joyb_nextweapon", 11}, {"joyb_menu_activate", 3}, // Start {NULL, 0}, }; // Playstation 4 Dual Shock 4 (DS4) static const joystick_config_t ps4_ds4_controller[] = { {"joystick_x_axis", CREATE_HAT_AXIS(0, HAT_AXIS_HORIZONTAL)}, {"joystick_y_axis", CREATE_HAT_AXIS(0, HAT_AXIS_VERTICAL)}, {"joyb_fire", 0}, // Square {"joyb_speed", 1}, // X {"joyb_use", 2}, // Circle {"joyb_jump", 3}, // Triangle {"joyb_strafeleft", 6}, // Bottom shoulder buttons {"joyb_straferight", 7}, {"joyb_prevweapon", 4}, // Top shoulder buttons {"joyb_nextweapon", 5}, {"joyb_menu_activate", 12}, // Playstation logo button }; static const joystick_config_t airflo_controller[] = { {"joystick_x_axis", CREATE_HAT_AXIS(0, HAT_AXIS_HORIZONTAL)}, {"joystick_y_axis", CREATE_HAT_AXIS(0, HAT_AXIS_VERTICAL)}, {"joyb_fire", 2}, // "3" {"joyb_speed", 0}, // "1" {"joyb_jump", 3}, // "4" {"joyb_use", 1}, // "2" {"joyb_strafeleft", 6}, // Bottom shoulder buttons {"joyb_straferight", 7}, {"joyb_prevweapon", 4}, // Top shoulder buttons {"joyb_nextweapon", 5}, {"joyb_menu_activate", 9}, // "10", where "Start" usually is. {NULL, 0}, }; // Wii controller is weird, so we have to take some liberties. // Also it's not a HID device, so it won't appear the same everywhere. // Assume there is no nunchuk or classic controller attached. // When using WJoy on OS X. static const joystick_config_t wii_controller_wjoy[] = { {"joystick_x_axis", CREATE_BUTTON_AXIS(2, 3)}, {"joystick_y_axis", CREATE_BUTTON_AXIS(1, 0)}, {"joyb_fire", 9}, // Button 1 {"joyb_speed", 10}, // Button 2 {"joyb_use", 5}, // Button B (trigger) {"joyb_prevweapon", 7}, // - {"joyb_nextweapon", 6}, // + {"joyb_menu_activate", 9}, // Button A {NULL, 0}, }; // Xbox 360 controller. Thanks to Brad Harding for the details. static const joystick_config_t xbox360_controller[] = { {"joystick_x_axis", CREATE_HAT_AXIS(0, HAT_AXIS_HORIZONTAL)}, {"joystick_y_axis", CREATE_HAT_AXIS(0, HAT_AXIS_VERTICAL)}, {"joystick_strafe_axis", 2}, // Trigger buttons form an axis(???) {"joyb_fire", 2}, // X {"joyb_speed", 0}, // A {"joyb_jump", 3}, // Y {"joyb_use", 1}, // B {"joyb_prevweapon", 4}, // LB {"joyb_nextweapon", 5}, // RB {"joyb_menu_activate", 9}, // Start {NULL, 0}, }; // Xbox 360 controller under Linux. static const joystick_config_t xbox360_controller_linux[] = { {"joystick_x_axis", CREATE_HAT_AXIS(0, HAT_AXIS_HORIZONTAL)}, {"joystick_y_axis", CREATE_HAT_AXIS(0, HAT_AXIS_VERTICAL)}, // Ideally we'd like the trigger buttons to be strafe left/right // But Linux presents each trigger button as its own axis, which // we can't really work with. So we have to settle for a // suboptimal setup. {"joyb_fire", 2}, // X {"joyb_speed", 0}, // A {"joyb_jump", 3}, // Y {"joyb_use", 1}, // B {"joyb_strafeleft", 4}, // LB {"joyb_straferight", 5}, // RB {"joyb_menu_activate", 7}, // Start {"joyb_prevweapon", 6}, // Back {NULL, 0}, }; // Logitech Dual Action (F310, F710). Thanks to Brad Harding for details. static const joystick_config_t logitech_f310_controller[] = { {"joystick_x_axis", CREATE_HAT_AXIS(0, HAT_AXIS_HORIZONTAL)}, {"joystick_y_axis", CREATE_HAT_AXIS(0, HAT_AXIS_VERTICAL)}, {"joyb_fire", 0}, // X {"joyb_speed", 1}, // A {"joyb_jump", 3}, // Y {"joyb_use", 2}, // B {"joyb_strafeleft", 6}, // LT {"joyb_straferight", 7}, // RT {"joyb_prevweapon", 4}, // LB {"joyb_nextweapon", 5}, // RB {"joyb_menu_activate", 11}, // Start {NULL, 0}, }; // Multilaser JS030 gamepad, similar to a PS2 controller. static const joystick_config_t multilaser_js030_controller[] = { {"joystick_x_axis", 0}, // Left stick / D-pad {"joystick_y_axis", 1}, {"joyb_fire", 3}, // Square {"joyb_speed", 2}, // X {"joyb_use", 1}, // Circle {"joyb_jump", 0}, // Triangle {"joyb_strafeleft", 6}, // Bottom shoulder buttons {"joyb_straferight", 7}, {"joyb_prevweapon", 4}, // Top shoulder buttons {"joyb_nextweapon", 5}, {"joyb_menu_activate", 9}, // Start {NULL, 0}, }; // Buffalo Classic USB Gamepad (thanks Fabian Greffrath). static const joystick_config_t buffalo_classic_controller[] = { {"joystick_x_axis", 0}, {"joystick_y_axis", 1}, {"joyb_use", 0}, // A {"joyb_speed", 1}, // B {"joyb_jump", 2}, // X {"joyb_fire", 3}, // Y {"joyb_strafeleft", 4}, // Left shoulder {"joyb_straferight", 5}, // Right shoulder {"joyb_prevweapon", 6}, // Select {"joyb_menu_activate", 7}, // Start {NULL, 0}, }; // Config for if the user is actually using an old PC joystick or gamepad, // probably via a USB-Gameport adapter. static const joystick_config_t pc_gameport_controller[] = { {"joystick_x_axis", 0}, {"joystick_y_axis", 1}, // Button configuration is the default as used for Vanilla Doom, // Heretic and Hexen. When playing with a Gravis Gamepad, this // layout should also be vaguely similar to the standard layout // described above. {"joyb_fire", 0}, {"joyb_strafe", 1}, {"joyb_use", 3}, {"joyb_speed", 2}, {NULL, 0}, }; static const known_joystick_t known_joysticks[] = { { "PLAYSTATION(R)3 Controller", 4, 19, 0, ps3_controller, }, { "AIRFLO ", 4, 13, 1, airflo_controller, }, { "Wiimote (*", // WJoy includes the Wiimote MAC address. 6, 26, 0, wii_controller_wjoy, }, { "Controller (XBOX 360 For Windows)", 5, 10, 1, xbox360_controller, }, { "Controller (XBOX One For Windows)", 5, 10, 1, xbox360_controller, }, // Xbox 360 controller as it appears on Linux. { "Microsoft X-Box 360 pad", 6, 11, 1, xbox360_controller_linux, }, // Xbox One controller as it appears on Linux. { "Microsoft X-Box One pad", 6, 11, 1, xbox360_controller_linux, }, { "Logitech Dual Action", 4, 12, 1, logitech_f310_controller, }, { "USB Vibration Joystick", 4, 12, 1, multilaser_js030_controller, }, { "USB,2-axis 8-button gamepad ", 2, 8, 0, buffalo_classic_controller, }, // PS4 controller just appears as the generic-sounding "Wireless // Controller". Hopefully the number of buttons/axes/hats should be // enough to distinguish it from other gamepads. { "Wireless Controller", 6, 14, 1, ps4_ds4_controller, }, // This is the configuration for the USB-Gameport adapter listed on // this page as the "Mayflash USB to Gameport Adapter" (though the // device is labeled as "Super Joy Box 7"): // https://sites.google.com/site/joystickrehab/itemcatal // TODO: Add extra configurations here for other USB-Gameport adapters, // which should just be the same configuration. { "WiseGroup.,Ltd Gameport to USB Controller", 4, 8, 1, pc_gameport_controller, }, // How the Super Joy Box 7 appears on Mac OS X. { "Gameport to USB Controller", 2, 8, 1, pc_gameport_controller, }, }; static const known_joystick_t *GetJoystickType(int index) { SDL_Joystick *joystick; const char *name; int axes, buttons, hats; int i; joystick = all_joysticks[index]; name = SDL_JoystickName(index); axes = SDL_JoystickNumAxes(joystick); buttons = SDL_JoystickNumButtons(joystick); hats = SDL_JoystickNumHats(joystick); for (i = 0; i < arrlen(known_joysticks); ++i) { // Check for a name match. If the name ends in '*', this means // ignore the rest. if (M_StringEndsWith(known_joysticks[i].name, "*")) { if (strncmp(known_joysticks[i].name, name, strlen(known_joysticks[i].name) - 1) != 0) { continue; } } else { if (strcmp(known_joysticks[i].name, name) != 0) { continue; } } if (known_joysticks[i].axes == axes && known_joysticks[i].buttons == buttons && known_joysticks[i].hats == hats) { return &known_joysticks[i]; } } printf("Unknown joystick '%s' with %i axes, %i buttons, %i hats\n", name, axes, buttons, hats); printf("Please consider sending in details about your gamepad!\n"); return NULL; } // Query if the joystick at the given index is a known joystick type. static boolean IsKnownJoystick(int index) { return GetJoystickType(index) != NULL; } // Load a configuration set. static void LoadConfigurationSet(const joystick_config_t *configs) { const joystick_config_t *config; char buf[10]; int button; int i; button = 0; for (i = 0; configs[i].name != NULL; ++i) { config = &configs[i]; // Don't overwrite autorun if it is set. if (!strcmp(config->name, "joyb_speed") && joybspeed >= 20) { continue; } // For buttons, set the virtual button mapping as well. if (M_StringStartsWith(config->name, "joyb_") && config->value >= 0) { joystick_physical_buttons[button] = config->value; M_snprintf(buf, sizeof(buf), "%i", button); M_SetVariable(config->name, buf); ++button; } else { M_snprintf(buf, sizeof(buf), "%i", config->value); M_SetVariable(config->name, buf); } } } // Load configuration for joystick_index based on known types. static void LoadKnownConfiguration(void) { const known_joystick_t *jstype; jstype = GetJoystickType(joystick_index); if (jstype == NULL) { return; } LoadConfigurationSet(empty_defaults); LoadConfigurationSet(jstype->configs); } static void InitJoystick(void) { if (!joystick_initted) { joystick_initted = SDL_Init(SDL_INIT_JOYSTICK) >= 0; } } static void UnInitJoystick(void) { if (joystick_initted) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); joystick_initted = 0; } } // Set the label showing the name of the currently selected joystick static void SetJoystickButtonLabel(void) { char *name; InitJoystick(); name = "None set"; if (joystick_initted && joystick_index >= 0 && joystick_index < SDL_NumJoysticks()) { name = (char *) SDL_JoystickName(joystick_index); } TXT_SetButtonLabel(joystick_button, name); UnInitJoystick(); } // Try to open all joysticks visible to SDL. static int OpenAllJoysticks(void) { int i; int num_joysticks; int result; InitJoystick(); // SDL_JoystickOpen() all joysticks. num_joysticks = SDL_NumJoysticks(); all_joysticks = malloc(sizeof(SDL_Joystick *) * num_joysticks); result = 0; for (i = 0; i < num_joysticks; ++i) { all_joysticks[i] = SDL_JoystickOpen(i); // If any joystick is successfully opened, return true. if (all_joysticks[i] != NULL) { result = 1; } } // Success? Turn on joystick events. if (result) { SDL_JoystickEventState(SDL_ENABLE); } else { free(all_joysticks); all_joysticks = NULL; } return result; } // Close all the joysticks opened with OpenAllJoysticks() static void CloseAllJoysticks(void) { int i; int num_joysticks; num_joysticks = SDL_NumJoysticks(); for (i = 0; i < num_joysticks; ++i) { if (all_joysticks[i] != NULL) { SDL_JoystickClose(all_joysticks[i]); } } SDL_JoystickEventState(SDL_DISABLE); free(all_joysticks); all_joysticks = NULL; UnInitJoystick(); } static void CalibrateXAxis(void) { TXT_ConfigureJoystickAxis(x_axis_widget, calibrate_button, NULL); } static int CalibrationEventCallback(SDL_Event *event, void *user_data) { if (event->type != SDL_JOYBUTTONDOWN) { return 0; } // At this point, we have a button press. // In the first "center" stage, we're just trying to work out which // joystick is being configured and which button the user is pressing. usejoystick = 1; joystick_index = event->jbutton.which; calibrate_button = event->jbutton.button; // If the joystick is a known one, auto-load default // config for it. Otherwise, proceed with calibration. if (IsKnownJoystick(joystick_index)) { LoadKnownConfiguration(); TXT_CloseWindow(calibration_window); } else { TXT_CloseWindow(calibration_window); // Calibrate joystick axes: Y axis first, then X axis once // completed. TXT_ConfigureJoystickAxis(y_axis_widget, calibrate_button, CalibrateXAxis); } return 1; } static void NoJoystick(void) { TXT_MessageBox(NULL, "No gamepads or joysticks could be found.\n\n" "Try configuring your controller from within\n" "your OS first. Maybe you need to install\n" "some drivers or otherwise configure it."); usejoystick = 0; joystick_index = -1; SetJoystickButtonLabel(); } static void CalibrateWindowClosed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { CloseAllJoysticks(); TXT_SDL_SetEventCallback(NULL, NULL); SetJoystickButtonLabel(); } static void CalibrateJoystick(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { // Try to open all available joysticks. If none are opened successfully, // bomb out with an error. if (!OpenAllJoysticks()) { NoJoystick(); return; } calibration_window = TXT_NewWindow("Gamepad/Joystick calibration"); TXT_AddWidgets(calibration_window, TXT_NewStrut(0, 1), TXT_NewLabel("Center the D-pad or joystick,\n" "and press a button."), TXT_NewStrut(0, 1), NULL); TXT_SetWindowAction(calibration_window, TXT_HORIZ_LEFT, NULL); TXT_SetWindowAction(calibration_window, TXT_HORIZ_CENTER, TXT_NewWindowAbortAction(calibration_window)); TXT_SetWindowAction(calibration_window, TXT_HORIZ_RIGHT, NULL); TXT_SDL_SetEventCallback(CalibrationEventCallback, NULL); TXT_SignalConnect(calibration_window, "closed", CalibrateWindowClosed, NULL); // Start calibration usejoystick = 0; joystick_index = -1; } // // GUI // static void AddJoystickControl(txt_table_t *table, char *label, int *var) { txt_joystick_input_t *joy_input; joy_input = TXT_NewJoystickInput(var); TXT_AddWidget(table, TXT_NewLabel(label)); TXT_AddWidget(table, joy_input); } void ConfigJoystick(void) { txt_window_t *window; txt_table_t *button_table, *axis_table; txt_table_t *joystick_table; window = TXT_NewWindow("Gamepad/Joystick configuration"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); TXT_AddWidgets(window, joystick_table = TXT_NewTable(2), TXT_NewSeparator("Axes"), axis_table = TXT_NewTable(2), TXT_NewSeparator("Buttons"), button_table = TXT_NewTable(4), NULL); TXT_SetColumnWidths(joystick_table, 13, 40); TXT_AddWidgets(joystick_table, TXT_NewLabel("Controller"), joystick_button = TXT_NewButton("zzzz"), NULL); TXT_SetColumnWidths(axis_table, 20, 15); TXT_AddWidgets(axis_table, TXT_NewLabel("Forward/backward"), y_axis_widget = TXT_NewJoystickAxis(&joystick_y_axis, &joystick_y_invert, JOYSTICK_AXIS_VERTICAL), TXT_NewLabel("Turn left/right"), x_axis_widget = TXT_NewJoystickAxis(&joystick_x_axis, &joystick_x_invert, JOYSTICK_AXIS_HORIZONTAL), TXT_NewLabel("Strafe left/right"), TXT_NewJoystickAxis(&joystick_strafe_axis, &joystick_strafe_invert, JOYSTICK_AXIS_HORIZONTAL), NULL); TXT_SetColumnWidths(button_table, 16, 12, 14, 11); AddJoystickControl(button_table, "Fire/Attack", &joybfire); AddJoystickControl(button_table, "Strafe Left", &joybstrafeleft); AddJoystickControl(button_table, "Use", &joybuse); AddJoystickControl(button_table, "Strafe Right", &joybstraferight); AddJoystickControl(button_table, "Previous weapon", &joybprevweapon); AddJoystickControl(button_table, "Strafe", &joybstrafe); AddJoystickControl(button_table, "Next weapon", &joybnextweapon); // High values of joybspeed are used to activate the "always run mode" // trick in Vanilla Doom. If this has been enabled, not only is the // joybspeed value meaningless, but the control itself is useless. if (joybspeed < 20) { AddJoystickControl(button_table, "Speed", &joybspeed); } if (gamemission == hexen || gamemission == strife) { AddJoystickControl(button_table, "Jump", &joybjump); } AddJoystickControl(button_table, "Activate menu", &joybmenu); TXT_SignalConnect(joystick_button, "pressed", CalibrateJoystick, NULL); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction()); SetJoystickButtonLabel(); } void BindJoystickVariables(void) { int i; M_BindIntVariable("use_joystick", &usejoystick); M_BindIntVariable("joystick_index", &joystick_index); M_BindIntVariable("joystick_x_axis", &joystick_x_axis); M_BindIntVariable("joystick_y_axis", &joystick_y_axis); M_BindIntVariable("joystick_strafe_axis", &joystick_strafe_axis); M_BindIntVariable("joystick_x_invert", &joystick_x_invert); M_BindIntVariable("joystick_y_invert", &joystick_y_invert); M_BindIntVariable("joystick_strafe_invert", &joystick_strafe_invert); for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i) { char name[32]; M_snprintf(name, sizeof(name), "joystick_physical_button%i", i); M_BindIntVariable(name, &joystick_physical_buttons[i]); } } chocolate-doom-chocolate-doom-2.2.1/src/setup/joystick.h000066400000000000000000000013321257432200600232430ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef SETUP_JOYSTICK_H #define SETUP_JOYSTICK_H extern int joystick_index; void ConfigJoystick(void); void BindJoystickVariables(void); #endif /* #ifndef SETUP_JOYSTICK_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/keyboard.c000066400000000000000000000362571257432200600232150ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include "textscreen.h" #include "doomtype.h" #include "m_config.h" #include "m_controls.h" #include "m_misc.h" #include "execute.h" #include "txt_keyinput.h" #include "mode.h" #include "joystick.h" #include "keyboard.h" #define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-keyboard" int vanilla_keyboard_mapping = 1; static int always_run = 0; // Keys within these groups cannot have the same value. static int *controls[] = { &key_left, &key_right, &key_up, &key_down, &key_strafeleft, &key_straferight, &key_fire, &key_use, &key_strafe, &key_speed, &key_jump, &key_flyup, &key_flydown, &key_flycenter, &key_lookup, &key_lookdown, &key_lookcenter, &key_invleft, &key_invright, &key_invquery, &key_invuse, &key_invpop, &key_mission, &key_invkey, &key_invhome, &key_invend, &key_invdrop, &key_useartifact, &key_pause, &key_usehealth, &key_weapon1, &key_weapon2, &key_weapon3, &key_weapon4, &key_weapon5, &key_weapon6, &key_weapon7, &key_weapon8, &key_arti_all, &key_arti_health, &key_arti_poisonbag, &key_arti_blastradius, &key_arti_teleport, &key_arti_teleportother, &key_arti_egg, &key_arti_invulnerability, &key_prevweapon, &key_nextweapon, NULL }; static int *menu_nav[] = { &key_menu_activate, &key_menu_up, &key_menu_down, &key_menu_left, &key_menu_right, &key_menu_back, &key_menu_forward, NULL }; static int *shortcuts[] = { &key_menu_help, &key_menu_save, &key_menu_load, &key_menu_volume, &key_menu_detail, &key_menu_qsave, &key_menu_endgame, &key_menu_messages, &key_spy, &key_menu_qload, &key_menu_quit, &key_menu_gamma, &key_menu_incscreen, &key_menu_decscreen, &key_menu_screenshot, &key_message_refresh, &key_multi_msg, &key_multi_msgplayer[0], &key_multi_msgplayer[1], &key_multi_msgplayer[2], &key_multi_msgplayer[3] }; static int *map_keys[] = { &key_map_north, &key_map_south, &key_map_east, &key_map_west, &key_map_zoomin, &key_map_zoomout, &key_map_toggle, &key_map_maxzoom, &key_map_follow, &key_map_grid, &key_map_mark, &key_map_clearmark, NULL }; static void UpdateJoybSpeed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(var)) { if (always_run) { /* if you want to pick one for chocolate doom to use, pick 29, since that is the most universal one that also works with heretic, hexen and strife =P NB. This choice also works with original, ultimate and final exes. */ joybspeed = 29; } else { joybspeed = 0; } } static int VarInGroup(int *variable, int **group) { unsigned int i; for (i=0; group[i] != NULL; ++i) { if (group[i] == variable) { return 1; } } return 0; } static void CheckKeyGroup(int *variable, int **group) { unsigned int i; // Don't check unless the variable is in this group. if (!VarInGroup(variable, group)) { return; } // If another variable has the same value as the new value, reset it. for (i=0; group[i] != NULL; ++i) { if (*variable == *group[i] && group[i] != variable) { // A different key has the same value. Clear the existing // value. This ensures that no two keys can have the same // value. *group[i] = 0; } } } // Callback invoked when a key control is set static void KeySetCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(variable)) { TXT_CAST_ARG(int, variable); CheckKeyGroup(variable, controls); CheckKeyGroup(variable, menu_nav); CheckKeyGroup(variable, shortcuts); CheckKeyGroup(variable, map_keys); } // Add a label and keyboard input to the specified table. static void AddKeyControl(txt_table_t *table, char *name, int *var) { txt_key_input_t *key_input; TXT_AddWidget(table, TXT_NewLabel(name)); key_input = TXT_NewKeyInput(var); TXT_AddWidget(table, key_input); TXT_SignalConnect(key_input, "set", KeySetCallback, var); } static void AddSectionLabel(txt_table_t *table, char *title, boolean add_space) { char buf[64]; if (add_space) { TXT_AddWidgets(table, TXT_NewStrut(0, 1), TXT_NewStrut(0, 1), NULL); } M_snprintf(buf, sizeof(buf), " - %s - ", title); TXT_AddWidgets(table, TXT_NewLabel(buf), TXT_NewStrut(0, 0), NULL); } static void ConfigExtraKeys(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { txt_window_t *window; txt_scrollpane_t *scrollpane; txt_table_t *table; boolean extra_keys = gamemission == heretic || gamemission == hexen || gamemission == strife; window = TXT_NewWindow("Extra keyboard controls"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); table = TXT_NewTable(2); TXT_SetColumnWidths(table, 21, 9); if (extra_keys) { // When we have extra controls, a scrollable pane must be used. scrollpane = TXT_NewScrollPane(0, 13, table); TXT_AddWidget(window, scrollpane); AddSectionLabel(table, "View", false); AddKeyControl(table, "Look up", &key_lookup); AddKeyControl(table, "Look down", &key_lookdown); AddKeyControl(table, "Center view", &key_lookcenter); if (gamemission == heretic || gamemission == hexen) { AddSectionLabel(table, "Flying", true); AddKeyControl(table, "Fly up", &key_flyup); AddKeyControl(table, "Fly down", &key_flydown); AddKeyControl(table, "Fly center", &key_flycenter); } AddSectionLabel(table, "Inventory", true); AddKeyControl(table, "Inventory left", &key_invleft); AddKeyControl(table, "Inventory right", &key_invright); if (gamemission == strife) { AddKeyControl(table, "Home", &key_invhome); AddKeyControl(table, "End", &key_invend); AddKeyControl(table, "Query", &key_invquery); AddKeyControl(table, "Drop", &key_invdrop); AddKeyControl(table, "Show weapons", &key_invpop); AddKeyControl(table, "Show mission", &key_mission); AddKeyControl(table, "Show keys", &key_invkey); AddKeyControl(table, "Use", &key_invuse); AddKeyControl(table, "Use health", &key_usehealth); } else { AddKeyControl(table, "Use artifact", &key_useartifact); } if (gamemission == hexen) { AddSectionLabel(table, "Artifacts", true); AddKeyControl(table, "One of each", &key_arti_all); AddKeyControl(table, "Quartz Flask", &key_arti_health); AddKeyControl(table, "Flechette", &key_arti_poisonbag); AddKeyControl(table, "Disc of Repulsion", &key_arti_blastradius); AddKeyControl(table, "Chaos Device", &key_arti_teleport); AddKeyControl(table, "Banishment Device", &key_arti_teleportother); AddKeyControl(table, "Porkalator", &key_arti_egg); AddKeyControl(table, "Icon of the Defender", &key_arti_invulnerability); } } else { TXT_AddWidget(window, table); } AddSectionLabel(table, "Weapons", extra_keys); AddKeyControl(table, "Weapon 1", &key_weapon1); AddKeyControl(table, "Weapon 2", &key_weapon2); AddKeyControl(table, "Weapon 3", &key_weapon3); AddKeyControl(table, "Weapon 4", &key_weapon4); AddKeyControl(table, "Weapon 5", &key_weapon5); AddKeyControl(table, "Weapon 6", &key_weapon6); AddKeyControl(table, "Weapon 7", &key_weapon7); AddKeyControl(table, "Weapon 8", &key_weapon8); AddKeyControl(table, "Previous weapon", &key_prevweapon); AddKeyControl(table, "Next weapon", &key_nextweapon); } static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { txt_window_t *window; txt_table_t *table; txt_scrollpane_t *scrollpane; window = TXT_NewWindow("Other keys"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); table = TXT_NewTable(2); TXT_SetColumnWidths(table, 25, 9); AddSectionLabel(table, "Menu navigation", false); AddKeyControl(table, "Activate menu", &key_menu_activate); AddKeyControl(table, "Move cursor up", &key_menu_up); AddKeyControl(table, "Move cursor down", &key_menu_down); AddKeyControl(table, "Move slider left", &key_menu_left); AddKeyControl(table, "Move slider right", &key_menu_right); AddKeyControl(table, "Go to previous menu", &key_menu_back); AddKeyControl(table, "Activate menu item", &key_menu_forward); AddKeyControl(table, "Confirm action", &key_menu_confirm); AddKeyControl(table, "Cancel action", &key_menu_abort); AddSectionLabel(table, "Shortcut keys", true); AddKeyControl(table, "Pause game", &key_pause); AddKeyControl(table, "Help screen", &key_menu_help); AddKeyControl(table, "Save game", &key_menu_save); AddKeyControl(table, "Load game", &key_menu_load); AddKeyControl(table, "Sound volume", &key_menu_volume); AddKeyControl(table, "Toggle detail", &key_menu_detail); AddKeyControl(table, "Quick save", &key_menu_qsave); AddKeyControl(table, "End game", &key_menu_endgame); AddKeyControl(table, "Toggle messages", &key_menu_messages); AddKeyControl(table, "Quick load", &key_menu_qload); AddKeyControl(table, "Quit game", &key_menu_quit); AddKeyControl(table, "Toggle gamma", &key_menu_gamma); AddKeyControl(table, "Multiplayer spy", &key_spy); AddKeyControl(table, "Increase screen size", &key_menu_incscreen); AddKeyControl(table, "Decrease screen size", &key_menu_decscreen); AddKeyControl(table, "Save a screenshot", &key_menu_screenshot); AddKeyControl(table, "Display last message", &key_message_refresh); AddKeyControl(table, "Finish recording demo", &key_demo_quit); AddSectionLabel(table, "Map", true); AddKeyControl(table, "Toggle map", &key_map_toggle); AddKeyControl(table, "Zoom in", &key_map_zoomin); AddKeyControl(table, "Zoom out", &key_map_zoomout); AddKeyControl(table, "Maximum zoom out", &key_map_maxzoom); AddKeyControl(table, "Follow mode", &key_map_follow); AddKeyControl(table, "Pan north", &key_map_north); AddKeyControl(table, "Pan south", &key_map_south); AddKeyControl(table, "Pan east", &key_map_east); AddKeyControl(table, "Pan west", &key_map_west); AddKeyControl(table, "Toggle grid", &key_map_grid); AddKeyControl(table, "Mark location", &key_map_mark); AddKeyControl(table, "Clear all marks", &key_map_clearmark); AddSectionLabel(table, "Multiplayer", true); AddKeyControl(table, "Send message", &key_multi_msg); AddKeyControl(table, "- to player 1", &key_multi_msgplayer[0]); AddKeyControl(table, "- to player 2", &key_multi_msgplayer[1]); AddKeyControl(table, "- to player 3", &key_multi_msgplayer[2]); AddKeyControl(table, "- to player 4", &key_multi_msgplayer[3]); if (gamemission == hexen || gamemission == strife) { AddKeyControl(table, "- to player 5", &key_multi_msgplayer[4]); AddKeyControl(table, "- to player 6", &key_multi_msgplayer[5]); AddKeyControl(table, "- to player 7", &key_multi_msgplayer[6]); AddKeyControl(table, "- to player 8", &key_multi_msgplayer[7]); } scrollpane = TXT_NewScrollPane(0, 13, table); TXT_AddWidget(window, scrollpane); } void ConfigKeyboard(void) { txt_window_t *window; txt_table_t *movement_table; txt_table_t *action_table; txt_table_t *dialogs_table; txt_checkbox_t *run_control; always_run = joybspeed >= 20; window = TXT_NewWindow("Keyboard configuration"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); TXT_AddWidgets(window, TXT_NewSeparator("Movement"), movement_table = TXT_NewTable(4), TXT_NewSeparator("Action"), action_table = TXT_NewTable(4), dialogs_table = TXT_NewTable(2), TXT_NewSeparator("Misc."), run_control = TXT_NewCheckBox("Always run", &always_run), TXT_NewInvertedCheckBox("Use native keyboard mapping", &vanilla_keyboard_mapping), NULL); TXT_SetColumnWidths(movement_table, 15, 8, 15, 8); TXT_SignalConnect(run_control, "changed", UpdateJoybSpeed, NULL); AddKeyControl(movement_table, "Move Forward", &key_up); AddKeyControl(movement_table, " Strafe Left", &key_strafeleft); AddKeyControl(movement_table, "Move Backward", &key_down); AddKeyControl(movement_table, " Strafe Right", &key_straferight); AddKeyControl(movement_table, "Turn Left", &key_left); AddKeyControl(movement_table, " Speed On", &key_speed); AddKeyControl(movement_table, "Turn Right", &key_right); AddKeyControl(movement_table, " Strafe On", &key_strafe); if (gamemission == hexen || gamemission == strife) { AddKeyControl(movement_table, "Jump", &key_jump); } TXT_SetColumnWidths(action_table, 15, 8, 15, 8); AddKeyControl(action_table, "Fire/Attack", &key_fire); AddKeyControl(action_table, " Use", &key_use); // Other key bindings are stored in separate sub-dialogs: TXT_SetColumnWidths(dialogs_table, 24, 24); TXT_AddWidgets(dialogs_table, TXT_NewButton2("More controls...", ConfigExtraKeys, NULL), TXT_NewButton2("Other keys...", OtherKeysDialog, NULL), NULL); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction()); } void BindKeyboardVariables(void) { M_BindIntVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping); } chocolate-doom-chocolate-doom-2.2.1/src/setup/keyboard.h000066400000000000000000000013451257432200600232100ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef SETUP_KEYBOARD_H #define SETUP_KEYBOARD_H void ConfigKeyboard(void); void BindKeyboardVariables(void); extern int vanilla_keyboard_mapping; #endif /* #ifndef SETUP_KEYBOARD_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/mainmenu.c000066400000000000000000000223241257432200600232140ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "config.h" #include "textscreen.h" #include "execute.h" #include "m_argv.h" #include "m_config.h" #include "m_controls.h" #include "m_misc.h" #include "z_zone.h" #include "setup_icon.c" #include "mode.h" #include "compatibility.h" #include "display.h" #include "joystick.h" #include "keyboard.h" #include "mouse.h" #include "multiplayer.h" #include "sound.h" #define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup" static const int cheat_sequence[] = { KEY_UPARROW, KEY_UPARROW, KEY_DOWNARROW, KEY_DOWNARROW, KEY_LEFTARROW, KEY_RIGHTARROW, KEY_LEFTARROW, KEY_RIGHTARROW, 'b', 'a', KEY_ENTER, 0 }; static unsigned int cheat_sequence_index = 0; // I think these are good "sensible" defaults: static void SensibleDefaults(void) { key_up = 'w'; key_down = 's'; key_strafeleft = 'a'; key_straferight = 'd'; key_jump = '/'; key_lookup = KEY_PGUP; key_lookdown = KEY_PGDN; key_lookcenter = KEY_HOME; key_flyup = KEY_INS; key_flydown = KEY_DEL; key_flycenter = KEY_END; key_prevweapon = ','; key_nextweapon = '.'; key_invleft = '['; key_invright = ']'; key_message_refresh = '\''; key_mission = 'i'; // Strife keys key_invpop = 'o'; key_invkey = 'p'; key_multi_msgplayer[0] = 'g'; key_multi_msgplayer[1] = 'h'; key_multi_msgplayer[2] = 'j'; key_multi_msgplayer[3] = 'k'; key_multi_msgplayer[4] = 'v'; key_multi_msgplayer[5] = 'b'; key_multi_msgplayer[6] = 'n'; key_multi_msgplayer[7] = 'm'; mousebprevweapon = 4; // Scroll wheel = weapon cycle mousebnextweapon = 3; snd_musicdevice = 3; joybspeed = 29; // Always run vanilla_savegame_limit = 0; vanilla_keyboard_mapping = 0; vanilla_demo_limit = 0; graphical_startup = 0; show_endoom = 0; dclick_use = 0; novert = 1; } static int MainMenuKeyPress(txt_window_t *window, int key, void *user_data) { if (key == cheat_sequence[cheat_sequence_index]) { ++cheat_sequence_index; if (cheat_sequence[cheat_sequence_index] == 0) { SensibleDefaults(); cheat_sequence_index = 0; window = TXT_MessageBox(NULL, " \x01 "); return 1; } } else { cheat_sequence_index = 0; } return 0; } static void DoQuit(void *widget, void *dosave) { if (dosave != NULL) { M_SaveDefaults(); } TXT_Shutdown(); exit(0); } static void QuitConfirm(void *unused1, void *unused2) { txt_window_t *window; txt_label_t *label; txt_button_t *yes_button; txt_button_t *no_button; window = TXT_NewWindow(NULL); TXT_AddWidgets(window, label = TXT_NewLabel("Exiting setup.\nSave settings?"), TXT_NewStrut(24, 0), yes_button = TXT_NewButton2(" Yes ", DoQuit, DoQuit), no_button = TXT_NewButton2(" No ", DoQuit, NULL), NULL); TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER); TXT_SetWidgetAlign(yes_button, TXT_HORIZ_CENTER); TXT_SetWidgetAlign(no_button, TXT_HORIZ_CENTER); // Only an "abort" button in the middle. TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TXT_NewWindowAbortAction(window)); TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); } static void LaunchDoom(void *unused1, void *unused2) { execute_context_t *exec; // Save configuration first M_SaveDefaults(); // Shut down textscreen GUI TXT_Shutdown(); // Launch Doom exec = NewExecuteContext(); PassThroughArguments(exec); ExecuteDoom(exec); exit(0); } static txt_button_t *GetLaunchButton(void) { char *label; switch (gamemission) { case doom: label = "Save parameters and launch DOOM"; break; case heretic: label = "Save parameters and launch Heretic"; break; case hexen: label = "Save parameters and launch Hexen"; break; case strife: label = "Save parameters and launch STRIFE!"; break; default: label = "Save parameters and launch game"; break; } return TXT_NewButton2(label, LaunchDoom, NULL); } void MainMenu(void) { txt_window_t *window; txt_window_action_t *quit_action; txt_window_action_t *warp_action; window = TXT_NewWindow("Main Menu"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); TXT_AddWidgets(window, TXT_NewButton2("Configure Display", (TxtWidgetSignalFunc) ConfigDisplay, NULL), TXT_NewButton2("Configure Sound", (TxtWidgetSignalFunc) ConfigSound, NULL), TXT_NewButton2("Configure Keyboard", (TxtWidgetSignalFunc) ConfigKeyboard, NULL), TXT_NewButton2("Configure Mouse", (TxtWidgetSignalFunc) ConfigMouse, NULL), TXT_NewButton2("Configure Gamepad/Joystick", (TxtWidgetSignalFunc) ConfigJoystick, NULL), NULL); // The compatibility window is only appropriate for Doom/Strife. if (gamemission == doom || gamemission == strife) { txt_button_t *button; button = TXT_NewButton2("Compatibility", (TxtWidgetSignalFunc) CompatibilitySettings, NULL); TXT_AddWidget(window, button); } TXT_AddWidgets(window, GetLaunchButton(), TXT_NewStrut(0, 1), TXT_NewButton2("Start a Network Game", (TxtWidgetSignalFunc) StartMultiGame, NULL), TXT_NewButton2("Join a Network Game", (TxtWidgetSignalFunc) JoinMultiGame, NULL), TXT_NewButton2("Multiplayer Configuration", (TxtWidgetSignalFunc) MultiplayerConfig, NULL), NULL); quit_action = TXT_NewWindowAction(KEY_ESCAPE, "Quit"); warp_action = TXT_NewWindowAction(KEY_F2, "Warp"); TXT_SignalConnect(quit_action, "pressed", QuitConfirm, NULL); TXT_SignalConnect(warp_action, "pressed", (TxtWidgetSignalFunc) WarpMenu, NULL); TXT_SetWindowAction(window, TXT_HORIZ_LEFT, quit_action); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, warp_action); TXT_SetKeyListener(window, MainMenuKeyPress, NULL); } // // Initialize all configuration variables, load config file, etc // static void InitConfig(void) { M_SetConfigDir(NULL); InitBindings(); SetChatMacroDefaults(); SetPlayerNameDefault(); M_LoadDefaults(); } // // Application icon // static void SetIcon(void) { SDL_Surface *surface; Uint8 *mask; int i; // Generate the mask mask = malloc(setup_icon_w * setup_icon_h / 8); memset(mask, 0, setup_icon_w * setup_icon_h / 8); for (i=0; i #include #include "doomtype.h" #include "config.h" #include "textscreen.h" #include "doomtype.h" #include "d_mode.h" #include "d_iwad.h" #include "i_system.h" #include "m_argv.h" #include "m_config.h" #include "m_controls.h" #include "m_misc.h" #include "compatibility.h" #include "display.h" #include "joystick.h" #include "keyboard.h" #include "mouse.h" #include "multiplayer.h" #include "sound.h" #include "mode.h" GameMission_t gamemission; static const iwad_t **iwads; typedef struct { char *label; GameMission_t mission; int mask; char *name; char *config_file; char *extra_config_file; char *executable; } mission_config_t; // Default mission to fall back on, if no IWADs are found at all: #define DEFAULT_MISSION (&mission_configs[0]) static mission_config_t mission_configs[] = { { "Doom", doom, IWAD_MASK_DOOM, "doom", "default.cfg", PROGRAM_PREFIX "doom.cfg", PROGRAM_PREFIX "doom" }, { "Heretic", heretic, IWAD_MASK_HERETIC, "heretic", "heretic.cfg", PROGRAM_PREFIX "heretic.cfg", PROGRAM_PREFIX "heretic" }, { "Hexen", hexen, IWAD_MASK_HEXEN, "hexen", "hexen.cfg", PROGRAM_PREFIX "hexen.cfg", PROGRAM_PREFIX "hexen" }, { "Strife", strife, IWAD_MASK_STRIFE, "strife", "strife.cfg", PROGRAM_PREFIX "strife.cfg", PROGRAM_PREFIX "strife" } }; static GameSelectCallback game_selected_callback; // Miscellaneous variables that aren't used in setup. static int showMessages = 1; static int screenblocks = 9; static int detailLevel = 0; static char *savedir = NULL; static char *executable = NULL; static char *game_title = "Doom"; static char *back_flat = "F_PAVE01"; static int comport = 0; static char *nickname = NULL; static void BindMiscVariables(void) { if (gamemission == doom) { M_BindIntVariable("detaillevel", &detailLevel); M_BindIntVariable("show_messages", &showMessages); } if (gamemission == hexen) { M_BindStringVariable("savedir", &savedir); M_BindIntVariable("messageson", &showMessages); // Hexen has a variable to control the savegame directory // that is used. savedir = M_GetSaveGameDir("hexen.wad"); // On Windows, hexndata\ is the default. if (!strcmp(savedir, "")) { free(savedir); savedir = "hexndata" DIR_SEPARATOR_S; } } if (gamemission == strife) { M_BindStringVariable("back_flat", &back_flat); M_BindStringVariable("nickname", &nickname); M_BindIntVariable("screensize", &screenblocks); M_BindIntVariable("comport", &comport); } else { M_BindIntVariable("screenblocks", &screenblocks); } } // // Initialise all configuration file bindings. // void InitBindings(void) { M_ApplyPlatformDefaults(); // Keyboard, mouse, joystick controls M_BindBaseControls(); M_BindWeaponControls(); M_BindMapControls(); M_BindMenuControls(); if (gamemission == heretic || gamemission == hexen) { M_BindHereticControls(); } if (gamemission == hexen) { M_BindHexenControls(); } if (gamemission == strife) { M_BindStrifeControls(); } // All other variables BindCompatibilityVariables(); BindDisplayVariables(); BindJoystickVariables(); BindKeyboardVariables(); BindMouseVariables(); BindSoundVariables(); BindMiscVariables(); BindMultiplayerVariables(); } // Set the name of the executable program to run the game: static void SetExecutable(mission_config_t *config) { char *extension; free(executable); #ifdef _WIN32 extension = ".exe"; #else extension = ""; #endif executable = M_StringJoin(config->executable, extension, NULL); } static void SetMission(mission_config_t *config) { iwads = D_FindAllIWADs(config->mask); gamemission = config->mission; SetExecutable(config); game_title = config->label; M_SetConfigFilenames(config->config_file, config->extra_config_file); } static mission_config_t *GetMissionForName(char *name) { int i; for (i=0; iname) != NULL) { SetMission(config); callback(); return true; } } return false; } static void GameSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(config)) { TXT_CAST_ARG(mission_config_t, config); SetMission(config); game_selected_callback(); } static void OpenGameSelectDialog(GameSelectCallback callback) { mission_config_t *mission = NULL; txt_window_t *window; const iwad_t **iwads; int num_games; int i; window = TXT_NewWindow("Select game"); TXT_AddWidget(window, TXT_NewLabel("Select a game to configure:\n")); num_games = 0; // Add a button for each game. for (i=0; i // // Specify the game to configure the settings for. Valid // values are 'doom', 'heretic', 'hexen' and 'strife'. // p = M_CheckParm("-game"); if (p > 0) { mission_name = myargv[p + 1]; config = GetMissionForName(mission_name); if (config == NULL) { I_Error("Invalid parameter - '%s'", mission_name); } SetMission(config); callback(); } else if (!CheckExecutableName(callback)) { OpenGameSelectDialog(callback); } } char *GetExecutableName(void) { return executable; } char *GetGameTitle(void) { return game_title; } const iwad_t **GetIwads(void) { return iwads; } chocolate-doom-chocolate-doom-2.2.1/src/setup/mode.h000066400000000000000000000016141257432200600223330ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef SETUP_MODE_H #define SETUP_MODE_H #include "d_mode.h" #include "d_iwad.h" typedef void (*GameSelectCallback)(void); extern GameMission_t gamemission; void SetupMission(GameSelectCallback callback); void InitBindings(void); char *GetExecutableName(void); char *GetGameTitle(void); const iwad_t **GetIwads(void); #endif /* #ifndef SETUP_MODE_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/mouse.c000066400000000000000000000121271257432200600225330ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include "textscreen.h" #include "doomtype.h" #include "m_config.h" #include "m_controls.h" #include "execute.h" #include "txt_mouseinput.h" #include "mode.h" #include "mouse.h" #define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-mouse" static int usemouse = 1; static int mouseSensitivity = 5; static float mouse_acceleration = 2.0; static int mouse_threshold = 10; static int grabmouse = 1; int novert = 0; static int *all_mouse_buttons[] = { &mousebfire, &mousebstrafe, &mousebforward, &mousebstrafeleft, &mousebstraferight, &mousebbackward, &mousebuse, &mousebjump, &mousebprevweapon, &mousebnextweapon }; static void MouseSetCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(variable)) { TXT_CAST_ARG(int, variable); unsigned int i; // Check if the same mouse button is used for a different action // If so, set the other action(s) to -1 (unset) for (i=0; i #include #include #include "doomtype.h" #include "doomfeatures.h" #include "textscreen.h" #include "d_iwad.h" #include "m_config.h" #include "m_misc.h" #include "doom/d_englsh.h" #include "m_controls.h" #include "multiplayer.h" #include "mode.h" #include "execute.h" #include "net_io.h" #include "net_query.h" #define MULTI_START_HELP_URL "http://www.chocolate-doom.org/setup-multi-start" #define MULTI_JOIN_HELP_URL "http://www.chocolate-doom.org/setup-multi-join" #define MULTI_CONFIG_HELP_URL "http://www.chocolate-doom.org/setup-multi-config" #define LEVEL_WARP_HELP_URL "http://www.chocolate-doom.org/setup-level-warp" #define NUM_WADS 10 #define NUM_EXTRA_PARAMS 10 typedef enum { WARP_ExMy, WARP_MAPxy, } warptype_t; // Fallback IWADs to use if no IWADs are detected. static const iwad_t fallback_iwads[] = { { "doom.wad", doom, registered, "Doom" }, { "heretic.wad", heretic, retail, "Heretic" }, { "hexen.wad", hexen, commercial, "Hexen" }, { "strife1.wad", strife, commercial, "Strife" }, }; // Array of IWADs found to be installed static const iwad_t **found_iwads; static char **iwad_labels; // Index of the currently selected IWAD static int found_iwad_selected = -1; // Filename to pass to '-iwad'. static char *iwadfile; static char *wad_extensions[] = { "wad", "lmp", "deh", NULL }; static char *doom_skills[] = { "I'm too young to die.", "Hey, not too rough.", "Hurt me plenty.", "Ultra-Violence.", "NIGHTMARE!", }; static char *chex_skills[] = { "Easy does it", "Not so sticky", "Gobs of goo", "Extreme ooze", "SUPER SLIMEY!" }; static char *heretic_skills[] = { "Thou needeth a wet-nurse", "Yellowbellies-R-us", "Bringest them oneth", "Thou art a smite-meister", "Black plague possesses thee" }; static char *hexen_fighter_skills[] = { "Squire", "Knight", "Warrior", "Berserker", "Titan" }; static char *hexen_cleric_skills[] = { "Altar boy", "Acolyte", "Priest", "Cardinal", "Pope" }; static char *hexen_mage_skills[] = { "Apprentice", "Enchanter", "Sorceror", "Warlock", "Archimage" }; static char *strife_skills[] = { "Training", "Rookie", "Veteran", "Elite", "Bloodbath" }; static char *character_classes[] = { "Fighter", "Cleric", "Mage" }; static char *gamemodes[] = { "Co-operative", "Deathmatch", "Deathmatch 2.0" }; static char *strife_gamemodes[] = { "Normal deathmatch", "Items respawn", // (altdeath) }; static char *net_player_name; static char *chat_macros[10]; static char *wads[NUM_WADS]; static char *extra_params[NUM_EXTRA_PARAMS]; static int character_class = 0; static int skill = 2; static int nomonsters = 0; static int deathmatch = 0; static int strife_altdeath = 0; static int fast = 0; static int respawn = 0; static int udpport = 2342; static int timer = 0; static int privateserver = 0; static txt_dropdown_list_t *skillbutton; static txt_button_t *warpbutton; static warptype_t warptype = WARP_MAPxy; static int warpepisode = 1; static int warpmap = 1; // Address to connect to when joining a game static char *connect_address = NULL; static txt_window_t *query_window; static int query_servers_found; // Find an IWAD from its description static const iwad_t *GetCurrentIWAD(void) { return found_iwads[found_iwad_selected]; } // Is the currently selected IWAD the Chex Quest chex.wad? static boolean IsChexQuest(const iwad_t *iwad) { return !strcmp(iwad->name, "chex.wad"); } static void AddWADs(execute_context_t *exec) { int have_wads = 0; int i; for (i=0; i 0) { if (!have_wads) { AddCmdLineParameter(exec, "-file"); } AddCmdLineParameter(exec, "\"%s\"", wads[i]); } } } static void AddExtraParameters(execute_context_t *exec) { int i; for (i=0; i 0) { AddCmdLineParameter(exec, extra_params[i]); } } } static void AddIWADParameter(execute_context_t *exec) { if (iwadfile != NULL) { AddCmdLineParameter(exec, "-iwad %s", iwadfile); } } // Callback function invoked to launch the game. // This is used when starting a server and also when starting a // single player game via the "warp" menu. static void StartGame(int multiplayer) { execute_context_t *exec; exec = NewExecuteContext(); // Extra parameters come first, before all others; this way, // they can override any of the options set in the dialog. AddExtraParameters(exec); AddIWADParameter(exec); AddCmdLineParameter(exec, "-skill %i", skill + 1); if (gamemission == hexen) { AddCmdLineParameter(exec, "-class %i", character_class); } if (nomonsters) { AddCmdLineParameter(exec, "-nomonsters"); } if (fast) { AddCmdLineParameter(exec, "-fast"); } if (respawn) { AddCmdLineParameter(exec, "-respawn"); } if (warptype == WARP_ExMy) { // TODO: select IWAD based on warp type AddCmdLineParameter(exec, "-warp %i %i", warpepisode, warpmap); } else if (warptype == WARP_MAPxy) { AddCmdLineParameter(exec, "-warp %i", warpmap); } // Multiplayer-specific options: if (multiplayer) { AddCmdLineParameter(exec, "-server"); AddCmdLineParameter(exec, "-port %i", udpport); if (deathmatch == 1) { AddCmdLineParameter(exec, "-deathmatch"); } else if (deathmatch == 2 || strife_altdeath != 0) { AddCmdLineParameter(exec, "-altdeath"); } if (timer > 0) { AddCmdLineParameter(exec, "-timer %i", timer); } if (privateserver) { AddCmdLineParameter(exec, "-privateserver"); } } AddWADs(exec); TXT_Shutdown(); M_SaveDefaults(); PassThroughArguments(exec); ExecuteDoom(exec); exit(0); } static void StartServerGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { StartGame(1); } static void StartSinglePlayerGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { StartGame(0); } static void UpdateWarpButton(void) { char buf[10]; if (warptype == WARP_ExMy) { M_snprintf(buf, sizeof(buf), "E%iM%i", warpepisode, warpmap); } else if (warptype == WARP_MAPxy) { M_snprintf(buf, sizeof(buf), "MAP%02i", warpmap); } TXT_SetButtonLabel(warpbutton, buf); } static void UpdateSkillButton(void) { const iwad_t *iwad = GetCurrentIWAD(); if (IsChexQuest(iwad)) { skillbutton->values = chex_skills; } else switch(gamemission) { default: case doom: skillbutton->values = doom_skills; break; case heretic: skillbutton->values = heretic_skills; break; case hexen: if (character_class == 0) { skillbutton->values = hexen_fighter_skills; } else if (character_class == 2) { skillbutton->values = hexen_cleric_skills; } else { skillbutton->values = hexen_mage_skills; } break; case strife: skillbutton->values = strife_skills; break; } } static void SetExMyWarp(TXT_UNCAST_ARG(widget), void *val) { int l; l = (intptr_t) val; warpepisode = l / 10; warpmap = l % 10; UpdateWarpButton(); } static void SetMAPxyWarp(TXT_UNCAST_ARG(widget), void *val) { int l; l = (intptr_t) val; warpmap = l; UpdateWarpButton(); } static void CloseLevelSelectDialog(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(window)) { TXT_CAST_ARG(txt_window_t, window); TXT_CloseWindow(window); } static void LevelSelectDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) { txt_window_t *window; txt_table_t *table; txt_button_t *button; const iwad_t *iwad; char buf[10]; int episodes; intptr_t x, y; intptr_t l; int i; window = TXT_NewWindow("Select level"); iwad = GetCurrentIWAD(); if (warptype == WARP_ExMy) { episodes = D_GetNumEpisodes(iwad->mission, iwad->mode); table = TXT_NewTable(episodes); // ExMy levels for (y=1; y<10; ++y) { for (x=1; x<=episodes; ++x) { if (IsChexQuest(iwad) && (x > 1 || y > 5)) { continue; } if (!D_ValidEpisodeMap(iwad->mission, iwad->mode, x, y)) { TXT_AddWidget(table, NULL); continue; } M_snprintf(buf, sizeof(buf), " E%iM%i ", x, y); button = TXT_NewButton(buf); TXT_SignalConnect(button, "pressed", SetExMyWarp, (void *) (x * 10 + y)); TXT_SignalConnect(button, "pressed", CloseLevelSelectDialog, window); TXT_AddWidget(table, button); if (warpepisode == x && warpmap == y) { TXT_SelectWidget(table, button); } } } } else { table = TXT_NewTable(6); for (i=0; i<60; ++i) { x = i % 6; y = i / 6; l = x * 10 + y + 1; if (!D_ValidEpisodeMap(iwad->mission, iwad->mode, 1, l)) { TXT_AddWidget(table, NULL); continue; } M_snprintf(buf, sizeof(buf), " MAP%02i ", l); button = TXT_NewButton(buf); TXT_SignalConnect(button, "pressed", SetMAPxyWarp, (void *) l); TXT_SignalConnect(button, "pressed", CloseLevelSelectDialog, window); TXT_AddWidget(table, button); if (warpmap == l) { TXT_SelectWidget(table, button); } } } TXT_AddWidget(window, table); } static void IWADSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { const iwad_t *iwad; // Find the iwad_t selected iwad = GetCurrentIWAD(); // Update iwadfile iwadfile = iwad->name; } // Called when the IWAD button is changed, to update warptype. static void UpdateWarpType(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) { warptype_t new_warptype; const iwad_t *iwad; // Get the selected IWAD iwad = GetCurrentIWAD(); // Find the new warp type if (D_IsEpisodeMap(iwad->mission)) { new_warptype = WARP_ExMy; } else { new_warptype = WARP_MAPxy; } // Reset to E1M1 / MAP01 when the warp type is changed. if (new_warptype != warptype) { warpepisode = 1; warpmap = 1; } warptype = new_warptype; UpdateWarpButton(); UpdateSkillButton(); } // Get an IWAD list with a default fallback IWAD that is appropriate // for the game we are configuring (matches gamemission global variable). static const iwad_t **GetFallbackIwadList(void) { static const iwad_t *fallback_iwad_list[2]; unsigned int i; // Default to use if we don't find something better. fallback_iwad_list[0] = &fallback_iwads[0]; fallback_iwad_list[1] = NULL; for (i = 0; i < arrlen(fallback_iwads); ++i) { if (gamemission == fallback_iwads[i].mission) { fallback_iwad_list[0] = &fallback_iwads[i]; break; } } return fallback_iwad_list; } static txt_widget_t *IWADSelector(void) { txt_dropdown_list_t *dropdown; txt_widget_t *result; int num_iwads; unsigned int i; // Find out what WADs are installed found_iwads = GetIwads(); // Build a list of the descriptions for all installed IWADs num_iwads = 0; for (i=0; found_iwads[i] != NULL; ++i) { ++num_iwads; } iwad_labels = malloc(sizeof(*iwad_labels) * num_iwads); for (i=0; i < num_iwads; ++i) { iwad_labels[i] = found_iwads[i]->description; } // If no IWADs are found, provide Doom 2 as an option, but // we're probably screwed. if (num_iwads == 0) { found_iwads = GetFallbackIwadList(); num_iwads = 1; } // Build a dropdown list of IWADs if (num_iwads < 2) { // We have only one IWAD. Show as a label. result = (txt_widget_t *) TXT_NewLabel(found_iwads[0]->description); } else { // Dropdown list allowing IWAD to be selected. dropdown = TXT_NewDropdownList(&found_iwad_selected, iwad_labels, num_iwads); TXT_SignalConnect(dropdown, "changed", IWADSelected, NULL); result = (txt_widget_t *) dropdown; } // The first time the dialog is opened, found_iwad_selected=-1, // so select the first IWAD in the list. Don't lose the setting // if we close and reopen the dialog. if (found_iwad_selected < 0 || found_iwad_selected >= num_iwads) { found_iwad_selected = 0; } IWADSelected(NULL, NULL); return result; } // Create the window action button to start the game. This invokes // a different callback depending on whether to start a multiplayer // or single player game. static txt_window_action_t *StartGameAction(int multiplayer) { txt_window_action_t *action; TxtWidgetSignalFunc callback; action = TXT_NewWindowAction(KEY_F10, "Start"); if (multiplayer) { callback = StartServerGame; } else { callback = StartSinglePlayerGame; } TXT_SignalConnect(action, "pressed", callback, NULL); return action; } static void OpenWadsWindow(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) { txt_window_t *window; int i; window = TXT_NewWindow("Add WADs"); for (i=0; iserver_state != 0) { TXT_MessageBox("Cannot connect to server", "Gameplay is already in progress\n" "on this server."); return; } // Set address to connect to: free(connect_address); connect_address = M_StringDuplicate(button->label); // Auto-choose IWAD if there is already a player connected. if (querydata->num_players > 0) { for (i = 0; found_iwads[i] != NULL; ++i) { if (found_iwads[i]->mode == querydata->gamemode && found_iwads[i]->mission == querydata->gamemission) { found_iwad_selected = i; iwadfile = found_iwads[i]->name; break; } } if (found_iwads[i] == NULL) { TXT_MessageBox(NULL, "The game on this server seems to be:\n" "\n" " %s\n" "\n" "but the IWAD file %s is not found!\n" "Without the required IWAD file, it may not be\n" "possible to join this game.", D_SuggestGameName(querydata->gamemission, querydata->gamemode), D_SuggestIWADName(querydata->gamemission, querydata->gamemode)); } } // Finished with search. TXT_CloseWindow(query_window); } static void QueryResponseCallback(net_addr_t *addr, net_querydata_t *querydata, unsigned int ping_time, TXT_UNCAST_ARG(results_table)) { TXT_CAST_ARG(txt_table_t, results_table); char ping_time_str[16]; char description[47]; M_snprintf(ping_time_str, sizeof(ping_time_str), "%ims", ping_time); M_StringCopy(description, querydata->description, sizeof(description)); TXT_AddWidgets(results_table, TXT_NewLabel(ping_time_str), TXT_NewButton2(NET_AddrToString(addr), SelectQueryAddress, querydata), TXT_NewLabel(description), NULL); ++query_servers_found; } static void QueryPeriodicCallback(TXT_UNCAST_ARG(results_table)) { TXT_CAST_ARG(txt_table_t, results_table); if (!NET_Query_Poll(QueryResponseCallback, results_table)) { TXT_SetPeriodicCallback(NULL, NULL, 0); if (query_servers_found == 0) { TXT_AddWidget(results_table, NULL); TXT_AddWidget(results_table, TXT_NewLabel("No servers found.")); } } } static void QueryWindowClosed(TXT_UNCAST_ARG(window), void *unused) { TXT_SetPeriodicCallback(NULL, NULL, 0); } static void ServerQueryWindow(char *title) { txt_table_t *results_table; query_servers_found = 0; query_window = TXT_NewWindow(title); TXT_AddWidget(query_window, TXT_NewScrollPane(70, 10, results_table = TXT_NewTable(3))); TXT_SetColumnWidths(results_table, 7, 22, 40); TXT_SetPeriodicCallback(QueryPeriodicCallback, results_table, 1); TXT_SignalConnect(query_window, "closed", QueryWindowClosed, NULL); } static void FindInternetServer(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) { NET_StartMasterQuery(); ServerQueryWindow("Find internet server"); } static void FindLANServer(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) { NET_StartLANQuery(); ServerQueryWindow("Find LAN server"); } void JoinMultiGame(void) { txt_window_t *window; txt_table_t *gameopt_table; txt_table_t *serveropt_table; txt_inputbox_t *address_box; window = TXT_NewWindow("Join multiplayer game"); TXT_SetWindowHelpURL(window, MULTI_JOIN_HELP_URL); TXT_AddWidgets(window, gameopt_table = TXT_NewTable(2), TXT_NewSeparator("Server"), serveropt_table = TXT_NewTable(1), TXT_NewStrut(0, 1), TXT_NewButton2("Add extra parameters...", OpenExtraParamsWindow, NULL), NULL); TXT_SetColumnWidths(gameopt_table, 12, 12); TXT_AddWidgets(gameopt_table, TXT_NewLabel("Game"), IWADSelector(), NULL); if (gamemission == hexen) { TXT_AddWidgets(gameopt_table, TXT_NewLabel("Character class "), TXT_NewDropdownList(&character_class, character_classes, 3), NULL); } TXT_AddWidgets(serveropt_table, TXT_NewHorizBox( TXT_NewLabel("Connect to address: "), address_box = TXT_NewInputBox(&connect_address, 30), NULL), TXT_NewButton2("Find server on Internet...", FindInternetServer, NULL), TXT_NewButton2("Find server on local network...", FindLANServer, NULL), NULL); TXT_SelectWidget(window, address_box); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, WadWindowAction()); TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, JoinGameAction()); } void SetChatMacroDefaults(void) { int i; char *defaults[] = { HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, HUSTR_CHATMACRO2, HUSTR_CHATMACRO3, HUSTR_CHATMACRO4, HUSTR_CHATMACRO5, HUSTR_CHATMACRO6, HUSTR_CHATMACRO7, HUSTR_CHATMACRO8, HUSTR_CHATMACRO9, }; // If the chat macros have not been set, initialize with defaults. for (i=0; i<10; ++i) { if (chat_macros[i] == NULL) { chat_macros[i] = M_StringDuplicate(defaults[i]); } } } void SetPlayerNameDefault(void) { if (net_player_name == NULL) { net_player_name = getenv("USER"); } if (net_player_name == NULL) { net_player_name = getenv("USERNAME"); } if (net_player_name == NULL) { net_player_name = "player"; } // Now strdup() the string so that it's in a mutable form // that can be freed when the value changes. #ifdef _WIN32 // On Windows, environment variables are in OEM codepage // encoding, so convert to UTF8: net_player_name = M_OEMToUTF8(net_player_name); #else net_player_name = M_StringDuplicate(net_player_name); #endif } void MultiplayerConfig(void) { txt_window_t *window; txt_label_t *label; txt_table_t *table; char buf[10]; int i; window = TXT_NewWindow("Multiplayer Configuration"); TXT_SetWindowHelpURL(window, MULTI_CONFIG_HELP_URL); TXT_AddWidgets(window, TXT_NewStrut(0, 1), TXT_NewHorizBox(TXT_NewLabel("Player name: "), TXT_NewInputBox(&net_player_name, 25), NULL), TXT_NewStrut(0, 1), TXT_NewSeparator("Chat macros"), NULL); table = TXT_NewTable(2); for (i=0; i<10; ++i) { M_snprintf(buf, sizeof(buf), "#%i ", i + 1); label = TXT_NewLabel(buf); TXT_SetFGColor(label, TXT_COLOR_BRIGHT_CYAN); TXT_AddWidgets(table, label, TXT_NewInputBox(&chat_macros[(i + 1) % 10], 40), NULL); } TXT_AddWidget(window, table); } void BindMultiplayerVariables(void) { char buf[15]; int i; #ifdef FEATURE_MULTIPLAYER M_BindStringVariable("player_name", &net_player_name); #endif for (i=0; i<10; ++i) { M_snprintf(buf, sizeof(buf), "chatmacro%i", i); M_BindStringVariable(buf, &chat_macros[i]); } switch (gamemission) { case doom: M_BindChatControls(4); key_multi_msgplayer[0] = 'g'; key_multi_msgplayer[1] = 'i'; key_multi_msgplayer[2] = 'b'; key_multi_msgplayer[3] = 'r'; break; case heretic: M_BindChatControls(4); key_multi_msgplayer[0] = 'g'; key_multi_msgplayer[1] = 'y'; key_multi_msgplayer[2] = 'r'; key_multi_msgplayer[3] = 'b'; break; case hexen: M_BindChatControls(8); key_multi_msgplayer[0] = 'b'; key_multi_msgplayer[1] = 'r'; key_multi_msgplayer[2] = 'y'; key_multi_msgplayer[3] = 'g'; key_multi_msgplayer[4] = 'j'; key_multi_msgplayer[5] = 'w'; key_multi_msgplayer[6] = 'h'; key_multi_msgplayer[7] = 'p'; break; default: break; } } chocolate-doom-chocolate-doom-2.2.1/src/setup/multiplayer.h000066400000000000000000000015331257432200600237560ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef SETUP_MULTIPLAYER_H #define SETUP_MULTIPLAYER_H void StartMultiGame(void); void WarpMenu(void); void JoinMultiGame(void); void MultiplayerConfig(void); void SetChatMacroDefaults(void); void SetPlayerNameDefault(void); void BindMultiplayerVariables(void); #endif /* #ifndef SETUP_MULTIPLAYER_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/setup-manifest.xml.in000066400000000000000000000033511257432200600253310ustar00rootroot00000000000000 true chocolate-doom-chocolate-doom-2.2.1/src/setup/setup.desktop.in000066400000000000000000000003671257432200600244020ustar00rootroot00000000000000[Desktop Entry] Name=@PACKAGE_SHORTNAME@ Setup Exec=@PROGRAM_PREFIX@setup Icon=@PROGRAM_PREFIX@setup Type=Application Comment=Setup tool for @PACKAGE_SHORTNAME@ Categories=Settings; Keywords=first;person;shooter;doom;heretic;hexen;strife;vanilla; chocolate-doom-chocolate-doom-2.2.1/src/setup/setup_icon.c000066400000000000000000000445601257432200600235610ustar00rootroot00000000000000static int setup_icon_w = 32; static int setup_icon_h = 32; static unsigned char setup_icon_data[] = { 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa2,0x86,0x73, 0xa9,0x8d,0x7a, 0xbc,0x9f,0x8c, 0xda,0xba,0xa0, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xbe,0x8e,0x68, 0xd7,0xb9,0xa5, 0xeb,0xd8,0xcd, 0xd3,0xbf,0xae, 0xbe,0xa1,0x8d, 0xeb,0xd8,0xcd, 0xc2,0x9d,0x86, 0x95,0x5d,0x38, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x78,0x7a,0x77, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x78,0x7a,0x77, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9f,0x82,0x6a, 0xc5,0x9e,0x81, 0xd1,0xb2,0x98, 0xd4,0xac,0x8e, 0xeb,0xd8,0xcd, 0xc4,0x9b,0x79, 0xad,0x71,0x45, 0xd4,0xac,0x8e, 0xb9,0x93,0x76, 0xa1,0x75,0x56, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x78,0x7a,0x77, 0x6d,0x6f,0x6c, 0xcb,0xce,0xca, 0x51,0x52,0x50, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x5b,0x5d,0x5a, 0xca,0xcc,0xc9, 0x77,0x79,0x76, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xda,0xb4,0x9c, 0xd3,0xa3,0x83, 0xaf,0x91,0x78, 0xa7,0x83,0x6d, 0xc4,0xa7,0x93, 0xee,0xe2,0xd5, 0xeb,0xd8,0xcd, 0x8c,0x60,0x3d, 0x92,0x6f,0x59, 0xd0,0xa7,0x84, 0x84,0x54,0x33, 0xba,0x83,0x5b, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x78,0x7a,0x77, 0xa0,0xa2,0x9f, 0xdf,0xe1,0xde, 0x58,0x5a,0x58, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, 0xdd,0xdf,0xdc, 0xa8,0xaa,0xa7, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xd4,0xb5,0x9b, 0xc3,0x8c,0x63, 0xc4,0x94,0x6e, 0x98,0x66,0x45, 0x78,0x50,0x2d, 0xd7,0xb9,0xa5, 0xee,0xdc,0xd1, 0xc4,0x9b,0x79, 0xb6,0x80,0x58, 0x65,0x45,0x26, 0xb6,0x79,0x4d, 0xcf,0xa5,0x83, 0x9a,0x6e,0x50, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x82,0x83,0x81, 0xbb,0xbd,0xba, 0xde,0xe0,0xdd, 0x58,0x5a,0x58, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, 0xdc,0xde,0xdb, 0xc4,0xc6,0xc3, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9e,0x7b,0x65, 0xbc,0x8c,0x67, 0xaa,0x7d,0x5e, 0xa1,0x75,0x56, 0x89,0x5f,0x41, 0xc4,0xa7,0x93, 0xb7,0x88,0x63, 0x90,0x6c,0x51, 0x79,0x4b,0x2b, 0x8c,0x5b,0x34, 0x76,0x4e,0x31, 0x7f,0x50,0x30, 0xcf,0xa5,0x83, 0xd4,0xac,0x8e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x79,0x76, 0xd2,0xd4,0xd1, 0xde,0xe0,0xdd, 0x64,0x65,0x63, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x68,0x69,0x67, 0xdb,0xdd,0xda, 0xda,0xdc,0xd9, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xd8,0xb8,0x9e, 0xd4,0xac,0x8e, 0xc5,0x9e,0x81, 0xab,0x7e,0x5f, 0x9c,0x6f,0x4b, 0xbe,0xa1,0x8d, 0x8c,0x60,0x3d, 0x6e,0x47,0x2b, 0x87,0x5e,0x40, 0x5a,0x3b,0x23, 0x68,0x42,0x26, 0x65,0x40,0x23, 0x53,0x36,0x22, 0x7e,0x55,0x38, 0xce,0x9f,0x7e, 0xc3,0x8c,0x63, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x79,0x76, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0xc4,0xc6,0xc3, 0x83,0x85,0x82, 0x8c,0x8d,0x8a, 0xd2,0xd4,0xd1, 0xee,0xdc,0xd1, 0xe1,0xe4,0xe0, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xcb,0x9a,0x74, 0xb6,0x80,0x58, 0x8c,0x60,0x3d, 0x76,0x4e,0x31, 0x88,0x57,0x31, 0x83,0x53,0x33, 0x84,0x54,0x33, 0x95,0x5d,0x38, 0x79,0x4b,0x2b, 0x5c,0x38,0x22, 0x84,0x54,0x33, 0x55,0x37,0x1e, 0x96,0x6b,0x4d, 0xb4,0x7f,0x5c, 0xba,0x83,0x5b, 0xb8,0x7b,0x4f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9a,0x9b,0x98, 0xd9,0xdb,0xd7, 0xe1,0xe4,0xe0, 0xde,0xe0,0xdd, 0xdd,0xdf,0xdc, 0xe0,0xe2,0xdf, 0xda,0xdc,0xd9, 0xa3,0xa5,0xa1, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xc0,0x89,0x60, 0x89,0x5f,0x41, 0x84,0x54,0x33, 0x84,0x54,0x33, 0x8a,0x5a,0x39, 0x8f,0x5d,0x37, 0x78,0x50,0x2d, 0x8c,0x5b,0x34, 0x5a,0x3b,0x23, 0x5e,0x3f,0x27, 0x76,0x4e,0x31, 0x97,0x64,0x3d, 0x74,0x4b,0x29, 0x78,0x50,0x2d, 0x7b,0x4d,0x2c, 0xb6,0x80,0x58, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, 0xbe,0xc1,0xbd, 0xee,0xdc,0xd1, 0xe1,0xe4,0xe0, 0xc2,0xc4,0xc1, 0x68,0x69,0x67, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x95,0x62,0x3b, 0x84,0x54,0x33, 0x88,0x57,0x31, 0x7e,0x6e,0x64, 0xc4,0x94,0x6e, 0x76,0x4e,0x31, 0x90,0x6c,0x51, 0xa1,0x7c,0x60, 0x9a,0x6e,0x50, 0x95,0x5d,0x38, 0xbc,0x7f,0x53, 0xad,0x71,0x45, 0x76,0x4e,0x31, 0x53,0x36,0x22, 0x4b,0x2f,0x1c, 0x70,0x49,0x2c, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x51,0x52,0x50, 0xd2,0xd4,0xd1, 0xe0,0xe2,0xdf, 0x77,0x79,0x76, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x84,0x54,0x33, 0xa3,0x86,0x6e, 0xc4,0x94,0x6e, 0x88,0x64,0x44, 0xbc,0x8c,0x67, 0x9c,0x6f,0x4b, 0xa1,0x6d,0x45, 0x93,0x60,0x3a, 0xad,0x71,0x3f, 0xb4,0x7f,0x5c, 0xbc,0x8c,0x67, 0xc0,0x89,0x60, 0xb3,0x76,0x4b, 0xb8,0x7b,0x4f, 0x88,0x64,0x44, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x4a,0x4b,0x49, 0xdc,0xde,0xdb, 0xe1,0xe4,0xe0, 0x79,0x7b,0x78, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa7,0x83,0x6d, 0xac,0x86,0x6a, 0x76,0x4e,0x31, 0x84,0x54,0x33, 0x5c,0x38,0x22, 0x57,0x38,0x20, 0x6c,0x46,0x29, 0x95,0x62,0x3b, 0xa3,0x6e,0x41, 0xb3,0x76,0x4b, 0xb8,0x7b,0x4f, 0x9d,0x64,0x3f, 0x7e,0x4f,0x2f, 0x63,0x3e,0x27, 0x95,0x62,0x3b, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x51,0x52,0x50, 0xdd,0xdf,0xdc, 0xe0,0xe2,0xdf, 0x82,0x83,0x81, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb6,0x80,0x58, 0x98,0x74,0x59, 0x67,0x41,0x25, 0x4b,0x35,0x25, 0x81,0x52,0x31, 0x76,0x4e,0x31, 0x7b,0x4d,0x2c, 0x7e,0x4f,0x2f, 0x84,0x54,0x33, 0x8f,0x5d,0x37, 0x95,0x5d,0x38, 0x78,0x50,0x2d, 0x65,0x45,0x26, 0x65,0x40,0x23, 0x7e,0x4f,0x2f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x55,0x56,0x54, 0xee,0xdc,0xd1, 0xde,0xe0,0xdd, 0x8c,0x8d,0x8a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb4,0x7f,0x5c, 0x86,0x56,0x35, 0x8c,0x60,0x3d, 0x89,0x5f,0x41, 0x63,0x44,0x2b, 0x57,0x38,0x20, 0x86,0x56,0x35, 0x88,0x57,0x31, 0x95,0x5d,0x38, 0x97,0x64,0x3d, 0x63,0x3e,0x27, 0x50,0x33,0x20, 0x78,0x50,0x2d, 0x78,0x50,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x58,0x5a,0x58, 0xe0,0xe2,0xdf, 0xde,0xe0,0xdd, 0x8c,0x8d,0x8a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x86,0x56,0x35, 0x63,0x3e,0x27, 0xa8,0x6d,0x42, 0x50,0x33,0x20, 0x63,0x3e,0x27, 0x74,0x4b,0x29, 0x53,0x36,0x22, 0x78,0x50,0x2d, 0x42,0x30,0x14, 0x4d,0x3e,0x15, 0x4d,0x3e,0x15, 0x7c,0x5b,0x29, 0x8a,0x71,0x27, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0x91,0x93,0x90, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x6e,0x47,0x2b, 0x65,0x45,0x26, 0x5d,0x42,0x22, 0x65,0x45,0x26, 0x78,0x50,0x2d, 0x5d,0x42,0x22, 0x5e,0x3f,0x27, 0x4d,0x3e,0x15, 0x4d,0x3e,0x15, 0x67,0x58,0x21, 0x4f,0x44,0x19, 0x5f,0x51,0x19, 0x8a,0x76,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x68,0x69,0x67, 0xdf,0xe1,0xde, 0xe0,0xe2,0xdf, 0x9a,0x9b,0x98, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x8a,0x71,0x27, 0x53,0x46,0x15, 0x53,0x46,0x15, 0x67,0x58,0x21, 0x58,0x4c,0x1b, 0x5b,0x4f,0x1d, 0x5b,0x4f,0x1d, 0x67,0x58,0x21, 0x5b,0x4f,0x1d, 0x8a,0x71,0x27, 0x8c,0x77,0x24, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x70,0x72,0x6f, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0x9a,0x9b,0x98, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x7e,0x66,0x23, 0x69,0x5a,0x1b, 0x6b,0x5b,0x1d, 0x67,0x58,0x21, 0x53,0x46,0x15, 0x4d,0x3e,0x15, 0x9f,0x88,0x35, 0xb7,0x9c,0x3b, 0xac,0x93,0x39, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x79,0x76, 0xdf,0xe1,0xde, 0xe0,0xe2,0xdf, 0xa3,0xa5,0xa1, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb1,0x97,0x36, 0x6f,0x5f,0x21, 0x7e,0x66,0x23, 0x8c,0x77,0x24, 0x84,0x70,0x24, 0x78,0x67,0x22, 0x8e,0x79,0x26, 0x8a,0x71,0x27, 0xb7,0x9c,0x3b, 0x9b,0x84,0x29, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x82,0x83,0x81, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0xa8,0xaa,0xa7, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x89,0x75,0x29, 0x7e,0x66,0x23, 0x75,0x64,0x1f, 0x94,0x7e,0x2b, 0x7e,0x66,0x23, 0x9f,0x88,0x35, 0xb6,0x9d,0x4a, 0xb6,0x9d,0x4a, 0xc4,0xa8,0x3f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x82,0x83,0x81, 0xe0,0xe2,0xdf, 0xde,0xe0,0xdd, 0xab,0xad,0xaa, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x80,0x6d,0x28, 0xac,0x93,0x39, 0x97,0x82,0x36, 0xac,0x94,0x41, 0xac,0x93,0x39, 0x97,0x82,0x36, 0xa2,0x8a,0x30, 0xbd,0xa3,0x48, 0x8a,0x71,0x27, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x79,0x76, 0xe0,0xe2,0xdf, 0xd8,0xda,0xd6, 0xab,0xad,0xaa, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xae,0x95,0x33, 0x7e,0x66,0x23, 0x9f,0x88,0x35, 0x9f,0x88,0x35, 0x7e,0x66,0x23, 0x8a,0x71,0x27, 0xaf,0x96,0x3c, 0xbd,0xa2,0x41, 0x8a,0x76,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x68,0x69,0x67, 0xc2,0xc4,0xc1, 0xe0,0xe2,0xdf, 0xdf,0xe1,0xde, 0xbe,0xc1,0xbd, 0x5f,0x61,0x5e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xaf,0x96,0x3c, 0x87,0x73,0x27, 0xb2,0x99,0x3f, 0x6f,0x5f,0x21, 0xa8,0x90,0x36, 0x97,0x82,0x36, 0x9f,0x88,0x35, 0xb7,0x9c,0x3b, 0x8c,0x77,0x24, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa3,0xa5,0xa1, 0xeb,0xd8,0xcd, 0xe0,0xe2,0xdf, 0xee,0xdc,0xd1, 0xdf,0xe1,0xde, 0xe1,0xe4,0xe0, 0xda,0xdc,0xd9, 0x9a,0x9b,0x98, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb2,0x99,0x3f, 0xaf,0x96,0x3c, 0x96,0x80,0x2d, 0xbd,0xa3,0x48, 0x97,0x82,0x36, 0xb6,0x9d,0x4a, 0xb8,0xa0,0x4c, 0xc1,0xa7,0x4c, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x78,0x7a,0x77, 0xdf,0xe1,0xde, 0xe0,0xe2,0xdf, 0xd2,0xd4,0xd1, 0x8c,0x8d,0x8a, 0x82,0x83,0x81, 0xc7,0xc9,0xc6, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x96,0x80,0x2d, 0xb5,0x9c,0x49, 0xb2,0x99,0x3f, 0xb2,0x9a,0x47, 0xb0,0x97,0x3d, 0xc1,0xa7,0x4c, 0x96,0x80,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x78,0x7a,0x77, 0xd9,0xdb,0xd7, 0xda,0xdc,0xd9, 0x68,0x69,0x67, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, 0xdd,0xdf,0xdc, 0xd2,0xd4,0xd1, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9c,0x85,0x2b, 0xaa,0x91,0x2f, 0xb1,0x97,0x36, 0xa2,0x8a,0x30, 0x7e,0x66,0x23, 0xb1,0x97,0x36, 0xb4,0x99,0x30, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x79,0x7b,0x78, 0xc4,0xc6,0xc3, 0xd9,0xdb,0xd7, 0x64,0x65,0x63, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x55,0x56,0x54, 0xdf,0xe1,0xde, 0xbb,0xbd,0xba, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9f,0x88,0x35, 0xb8,0x9e,0x44, 0x8a,0x71,0x27, 0xa6,0x8f,0x3c, 0xbd,0xa3,0x48, 0x96,0x80,0x2d, 0x9f,0x88,0x35, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x82,0x83,0x81, 0xa8,0xaa,0xa7, 0xdf,0xe1,0xde, 0x64,0x65,0x63, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x58,0x5a,0x58, 0xee,0xdc,0xd1, 0xa0,0xa2,0x9f, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb0,0x97,0x3d, 0xb7,0x9c,0x3b, 0xac,0x94,0x41, 0xb2,0x99,0x3f, 0xb6,0x9b,0x32, 0xb7,0x9c,0x3b, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x79,0x76, 0x77,0x79,0x76, 0xca,0xcc,0xc9, 0x5b,0x5d,0x5a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x51,0x52,0x50, 0xcb,0xce,0xca, 0x68,0x69,0x67, 0x79,0x7b,0x78, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xbd,0xa2,0x41, 0xa6,0x8f,0x3c, 0xb0,0x97,0x3d, 0xb2,0x9a,0x47, 0xac,0x93,0x39, 0x9f,0x88,0x35, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x79,0x76, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x82,0x83,0x81, 0x79,0x7b,0x78, 0x00,0x00,0x00, 0x00,0x00,0x00, }; chocolate-doom-chocolate-doom-2.2.1/src/setup/sound.c000066400000000000000000000266321257432200600225410ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Sound control menu #include #include "SDL_mixer.h" #include "textscreen.h" #include "m_config.h" #include "m_misc.h" #include "mode.h" #include "sound.h" #define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-sound" typedef enum { SFXMODE_DISABLED, SFXMODE_DIGITAL, SFXMODE_PCSPEAKER, NUM_SFXMODES } sfxmode_t; static char *sfxmode_strings[] = { "Disabled", "Digital", "PC speaker" }; typedef enum { MUSICMODE_DISABLED, MUSICMODE_OPL, MUSICMODE_GUS, MUSICMODE_NATIVE, MUSICMODE_CD, NUM_MUSICMODES } musicmode_t; static char *musicmode_strings[] = { "Disabled", "OPL (Adlib/SB)", "GUS (emulated)", "Native MIDI", "CD audio" }; typedef enum { OPLMODE_OPL2, OPLMODE_OPL3, NUM_OPLMODES, } oplmode_t; static char *opltype_strings[] = { "OPL2", "OPL3" }; static char *cfg_extension[] = { "cfg", NULL }; // Config file variables: int snd_sfxdevice = SNDDEVICE_SB; int snd_musicdevice = SNDDEVICE_SB; int snd_samplerate = 44100; int opl_io_port = 0x388; int snd_cachesize = 64 * 1024 * 1024; int snd_maxslicetime_ms = 28; char *snd_musiccmd = ""; static int numChannels = 8; static int sfxVolume = 8; static int musicVolume = 8; static int voiceVolume = 15; static int show_talk = 0; static int use_libsamplerate = 0; static float libsamplerate_scale = 0.65; static char *snd_dmxoption = ""; static char *timidity_cfg_path = NULL; static char *gus_patch_path = NULL; static int gus_ram_kb = 1024; // DOS specific variables: these are unused but should be maintained // so that the config file can be shared between chocolate // doom and doom.exe static int snd_sbport = 0; static int snd_sbirq = 0; static int snd_sbdma = 0; static int snd_mport = 0; // GUI variables: static int snd_sfxmode; static int snd_musicmode; static int snd_oplmode; static void UpdateSndDevices(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data)) { switch (snd_sfxmode) { case SFXMODE_DISABLED: snd_sfxdevice = SNDDEVICE_NONE; break; case SFXMODE_PCSPEAKER: snd_sfxdevice = SNDDEVICE_PCSPEAKER; break; case SFXMODE_DIGITAL: snd_sfxdevice = SNDDEVICE_SB; break; } switch (snd_musicmode) { case MUSICMODE_DISABLED: snd_musicdevice = SNDDEVICE_NONE; break; case MUSICMODE_NATIVE: snd_musicdevice = SNDDEVICE_GENMIDI; break; case MUSICMODE_OPL: snd_musicdevice = SNDDEVICE_SB; break; case MUSICMODE_GUS: snd_musicdevice = SNDDEVICE_GUS; break; case MUSICMODE_CD: snd_musicdevice = SNDDEVICE_CD; break; } switch (snd_oplmode) { default: case OPLMODE_OPL2: snd_dmxoption = ""; break; case OPLMODE_OPL3: snd_dmxoption = "-opl3"; break; } } static txt_dropdown_list_t *OPLTypeSelector(void) { txt_dropdown_list_t *result; if (snd_dmxoption != NULL && strstr(snd_dmxoption, "-opl3") != NULL) { snd_oplmode = OPLMODE_OPL3; } else { snd_oplmode = OPLMODE_OPL2; } result = TXT_NewDropdownList(&snd_oplmode, opltype_strings, 2); TXT_SignalConnect(result, "changed", UpdateSndDevices, NULL); return result; } static void UpdateExtraTable(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(extra_table)) { TXT_CAST_ARG(txt_table_t, extra_table); switch (snd_musicmode) { case MUSICMODE_OPL: TXT_InitTable(extra_table, 2); TXT_SetColumnWidths(extra_table, 19, 4); TXT_AddWidgets(extra_table, TXT_NewLabel("OPL type"), OPLTypeSelector(), NULL); break; case MUSICMODE_GUS: TXT_InitTable(extra_table, 1); TXT_AddWidgets(extra_table, TXT_NewLabel("GUS patch path:"), TXT_NewFileSelector(&gus_patch_path, 30, "Select path to GUS patches", TXT_DIRECTORY), NULL); break; case MUSICMODE_NATIVE: TXT_InitTable(extra_table, 1); TXT_AddWidgets(extra_table, TXT_NewLabel("Timidity configuration file:"), TXT_NewFileSelector(&timidity_cfg_path, 30, "Select Timidity config file", cfg_extension), NULL); break; } } void ConfigSound(void) { txt_window_t *window; txt_table_t *sfx_table; txt_table_t *music_table; txt_table_t *extra_table; txt_dropdown_list_t *sfx_mode_control; txt_dropdown_list_t *music_mode_control; int num_sfx_modes, num_music_modes; // Work out what sfx mode we are currently using: if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) { snd_sfxmode = SFXMODE_PCSPEAKER; } else if (snd_sfxdevice >= SNDDEVICE_SB) { snd_sfxmode = SFXMODE_DIGITAL; } else { snd_sfxmode = SFXMODE_DISABLED; } // Is music enabled? switch (snd_musicdevice) { case SNDDEVICE_GENMIDI: snd_musicmode = MUSICMODE_NATIVE; break; case SNDDEVICE_CD: snd_musicmode = MUSICMODE_CD; break; case SNDDEVICE_SB: case SNDDEVICE_ADLIB: case SNDDEVICE_AWE32: snd_musicmode = MUSICMODE_OPL; break; case SNDDEVICE_GUS: snd_musicmode = MUSICMODE_GUS; break; default: snd_musicmode = MUSICMODE_DISABLED; break; } // Doom has PC speaker sound effects, but others do not: if (gamemission == doom) { num_sfx_modes = NUM_SFXMODES; } else { num_sfx_modes = NUM_SFXMODES - 1; } // Hexen has CD audio; others do not. if (gamemission == hexen) { num_music_modes = NUM_MUSICMODES; } else { num_music_modes = NUM_MUSICMODES - 1; } // Build the window window = TXT_NewWindow("Sound configuration"); TXT_SetWindowHelpURL(window, WINDOW_HELP_URL); TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP, TXT_SCREEN_W / 2, 5); TXT_AddWidgets(window, TXT_NewSeparator("Sound effects"), sfx_table = TXT_NewTable(2), NULL); TXT_SetColumnWidths(sfx_table, 19, 15); TXT_AddWidgets(sfx_table, TXT_NewLabel("Sound effects"), sfx_mode_control = TXT_NewDropdownList(&snd_sfxmode, sfxmode_strings, num_sfx_modes), TXT_NewLabel("Sound channels"), TXT_NewSpinControl(&numChannels, 1, 8), TXT_NewLabel("SFX volume"), TXT_NewSpinControl(&sfxVolume, 0, 15), NULL); if (gamemission == strife) { TXT_AddWidgets(sfx_table, TXT_NewLabel("Voice volume"), TXT_NewSpinControl(&voiceVolume, 0, 15), NULL); TXT_AddWidget(window, TXT_NewCheckBox("Show text with voices", &show_talk)); } TXT_AddWidgets(window, TXT_NewSeparator("Music"), music_table = TXT_NewTable(2), extra_table = TXT_NewTable(1), NULL); TXT_SetColumnWidths(music_table, 19, 15); TXT_AddWidgets(music_table, TXT_NewLabel("Music"), music_mode_control = TXT_NewDropdownList(&snd_musicmode, musicmode_strings, num_music_modes), TXT_NewLabel("Music volume"), TXT_NewSpinControl(&musicVolume, 0, 15), NULL); TXT_SignalConnect(sfx_mode_control, "changed", UpdateSndDevices, NULL); TXT_SignalConnect(music_mode_control, "changed", UpdateSndDevices, NULL); // Update extra_table when the music mode is changed, and build it now. TXT_SignalConnect(music_mode_control, "changed", UpdateExtraTable, extra_table); UpdateExtraTable(music_mode_control, extra_table); } void BindSoundVariables(void) { M_BindIntVariable("snd_sfxdevice", &snd_sfxdevice); M_BindIntVariable("snd_musicdevice", &snd_musicdevice); M_BindIntVariable("snd_channels", &numChannels); M_BindIntVariable("snd_samplerate", &snd_samplerate); M_BindIntVariable("sfx_volume", &sfxVolume); M_BindIntVariable("music_volume", &musicVolume); M_BindIntVariable("use_libsamplerate", &use_libsamplerate); M_BindFloatVariable("libsamplerate_scale", &libsamplerate_scale); M_BindIntVariable("gus_ram_kb", &gus_ram_kb); M_BindStringVariable("gus_patch_path", &gus_patch_path); M_BindStringVariable("timidity_cfg_path", &timidity_cfg_path); M_BindIntVariable("snd_sbport", &snd_sbport); M_BindIntVariable("snd_sbirq", &snd_sbirq); M_BindIntVariable("snd_sbdma", &snd_sbdma); M_BindIntVariable("snd_mport", &snd_mport); M_BindIntVariable("snd_maxslicetime_ms", &snd_maxslicetime_ms); M_BindStringVariable("snd_musiccmd", &snd_musiccmd); M_BindStringVariable("snd_dmxoption", &snd_dmxoption); M_BindIntVariable("snd_cachesize", &snd_cachesize); M_BindIntVariable("opl_io_port", &opl_io_port); if (gamemission == strife) { M_BindIntVariable("voice_volume", &voiceVolume); M_BindIntVariable("show_talk", &show_talk); } timidity_cfg_path = M_StringDuplicate(""); gus_patch_path = M_StringDuplicate(""); // Default sound volumes - different games use different values. switch (gamemission) { case doom: default: sfxVolume = 8; musicVolume = 8; break; case heretic: case hexen: sfxVolume = 10; musicVolume = 10; break; case strife: sfxVolume = 8; musicVolume = 13; break; } // Before SDL_mixer version 1.2.11, MIDI music caused the game // to crash when it looped. If this is an old SDL_mixer version, // disable MIDI. #ifdef __MACOSX__ { const SDL_version *v = Mix_Linked_Version(); if (SDL_VERSIONNUM(v->major, v->minor, v->patch) < SDL_VERSIONNUM(1, 2, 11)) { snd_musicdevice = SNDDEVICE_NONE; } } #endif } chocolate-doom-chocolate-doom-2.2.1/src/setup/sound.h000066400000000000000000000013041257432200600225330ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef SETUP_SOUND_H #define SETUP_SOUND_H #include "i_sound.h" void ConfigSound(void); void BindSoundVariables(void); #endif /* #ifndef SETUP_SOUND_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_joyaxis.c000066400000000000000000000337601257432200600237760ustar00rootroot00000000000000// // Copyright(C) 2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "SDL.h" #include "joystick.h" #include "i_joystick.h" #include "i_system.h" #include "m_controls.h" #include "m_misc.h" #include "textscreen.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_joyaxis.h" #define JOYSTICK_AXIS_WIDTH 20 static char *CalibrationLabel(txt_joystick_axis_t *joystick_axis) { switch (joystick_axis->config_stage) { case CONFIG_CENTER: return "Center the D-pad or joystick,\n" "and press a button."; case CONFIG_STAGE1: if (joystick_axis->dir == JOYSTICK_AXIS_VERTICAL) { return "Push the D-pad or joystick up,\n" "and press the button."; } else { return "Push the D-pad or joystick to the\n" "left, and press the button."; } case CONFIG_STAGE2: if (joystick_axis->dir == JOYSTICK_AXIS_VERTICAL) { return "Push the D-pad or joystick down,\n" "and press the button."; } else { return "Push the D-pad or joystick to the\n" "right, and press the button."; } } return NULL; } static void SetCalibrationLabel(txt_joystick_axis_t *joystick_axis) { TXT_SetLabel(joystick_axis->config_label, CalibrationLabel(joystick_axis)); } // Search all axes on joystick being configured; find a button that is // pressed (other than the calibrate button). Returns the button number. static int FindPressedAxisButton(txt_joystick_axis_t *joystick_axis) { int i; for (i = 0; i < SDL_JoystickNumButtons(joystick_axis->joystick); ++i) { if (i == joystick_axis->config_button) { continue; } if (SDL_JoystickGetButton(joystick_axis->joystick, i)) { return i; } } return -1; } // Look for a hat that isn't centered. Returns the encoded hat axis. static int FindUncenteredHat(SDL_Joystick *joystick, int *axis_invert) { int i, hatval; for (i = 0; i < SDL_JoystickNumHats(joystick); ++i) { hatval = SDL_JoystickGetHat(joystick, i); switch (hatval) { case SDL_HAT_LEFT: case SDL_HAT_RIGHT: *axis_invert = hatval != SDL_HAT_LEFT; return CREATE_HAT_AXIS(i, HAT_AXIS_HORIZONTAL); case SDL_HAT_UP: case SDL_HAT_DOWN: *axis_invert = hatval != SDL_HAT_UP; return CREATE_HAT_AXIS(i, HAT_AXIS_VERTICAL); // If the hat is centered, or is not pointing in a // definite direction, then ignore it. We don't accept // the hat being pointed to the upper-left for example, // because it's ambiguous. case SDL_HAT_CENTERED: default: break; } } // None found. return -1; } static boolean CalibrateAxis(txt_joystick_axis_t *joystick_axis) { int best_axis; int best_value; int best_invert; Sint16 axis_value; int i; // Check all axes to find which axis has the largest value. We test // for one axis at a time, so eg. when we prompt to push the joystick // left, whichever axis has the largest value is the left axis. best_axis = 0; best_value = 0; best_invert = 0; for (i = 0; i < SDL_JoystickNumAxes(joystick_axis->joystick); ++i) { //if (bad_axis[i]) //{ // continue; //} axis_value = SDL_JoystickGetAxis(joystick_axis->joystick, i); if (abs(axis_value) > best_value) { best_value = abs(axis_value); best_invert = axis_value > 0; best_axis = i; } } // Did we find one axis that had a significant value? if (best_value > 32768 / 4) { // Save the best values we have found *joystick_axis->axis = best_axis; *joystick_axis->invert = best_invert; return true; } // Otherwise, maybe this is a "button axis", like the PS3 SIXAXIS // controller that exposes the D-pad as four individual buttons. // Search for a button. i = FindPressedAxisButton(joystick_axis); if (i >= 0) { *joystick_axis->axis = CREATE_BUTTON_AXIS(i, 0); *joystick_axis->invert = 0; return true; } // Maybe it's a D-pad that is presented as a hat. This sounds weird // but gamepads like this really do exist; an example is the // Nyko AIRFLO Ex. i = FindUncenteredHat(joystick_axis->joystick, joystick_axis->invert); if (i >= 0) { *joystick_axis->axis = i; return true; } // User pressed the button without pushing the joystick anywhere. return false; } static boolean SetButtonAxisPositive(txt_joystick_axis_t *joystick_axis) { int button; button = FindPressedAxisButton(joystick_axis); if (button >= 0) { *joystick_axis->axis |= CREATE_BUTTON_AXIS(0, button); return true; } return false; } static void IdentifyBadAxes(txt_joystick_axis_t *joystick_axis) { int i, val; free(joystick_axis->bad_axis); joystick_axis->bad_axis = calloc(SDL_JoystickNumAxes(joystick_axis->joystick), sizeof(boolean)); // Look for uncentered axes. for (i = 0; i < SDL_JoystickNumAxes(joystick_axis->joystick); ++i) { val = SDL_JoystickGetAxis(joystick_axis->joystick, i); joystick_axis->bad_axis[i] = abs(val) > (32768 / 5); if (joystick_axis->bad_axis[i]) { printf("Ignoring uncentered joystick axis #%i: %i\n", i, val); } } } static int NextCalibrateStage(txt_joystick_axis_t *joystick_axis) { switch (joystick_axis->config_stage) { case CONFIG_CENTER: return CONFIG_STAGE1; // After pushing to the left, there are two possibilities: // either it is a button axis, in which case we need to find // the other button, or we can just move on to the next axis. case CONFIG_STAGE1: if (IS_BUTTON_AXIS(*joystick_axis->axis)) { return CONFIG_STAGE2; } else { return CONFIG_CENTER; } case CONFIG_STAGE2: return CONFIG_CENTER; } return -1; } static int EventCallback(SDL_Event *event, TXT_UNCAST_ARG(joystick_axis)) { TXT_CAST_ARG(txt_joystick_axis_t, joystick_axis); boolean advance; if (event->type != SDL_JOYBUTTONDOWN) { return 0; } // At this point, we have a button press. // In the first "center" stage, we're just trying to work out which // joystick is being configured and which button the user is pressing. if (joystick_axis->config_stage == CONFIG_CENTER) { joystick_index = event->jbutton.which; joystick_axis->config_button = event->jbutton.button; IdentifyBadAxes(joystick_axis); // Advance to next stage. joystick_axis->config_stage = CONFIG_STAGE1; SetCalibrationLabel(joystick_axis); return 1; } // In subsequent stages, the user is asked to push in a specific // direction and press the button. They must push the same button // as they did before; this is necessary to support button axes. if (event->jbutton.which == joystick_index && event->jbutton.button == joystick_axis->config_button) { switch (joystick_axis->config_stage) { default: case CONFIG_STAGE1: advance = CalibrateAxis(joystick_axis); break; case CONFIG_STAGE2: advance = SetButtonAxisPositive(joystick_axis); break; } // Advance to the next calibration stage? if (advance) { joystick_axis->config_stage = NextCalibrateStage(joystick_axis); SetCalibrationLabel(joystick_axis); // Finished? if (joystick_axis->config_stage == CONFIG_CENTER) { TXT_CloseWindow(joystick_axis->config_window); if (joystick_axis->callback != NULL) { joystick_axis->callback(); } } return 1; } } return 0; } static void CalibrateWindowClosed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(joystick_axis)) { TXT_CAST_ARG(txt_joystick_axis_t, joystick_axis); free(joystick_axis->bad_axis); joystick_axis->bad_axis = NULL; SDL_JoystickClose(joystick_axis->joystick); SDL_JoystickEventState(SDL_DISABLE); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); TXT_SDL_SetEventCallback(NULL, NULL); } void TXT_ConfigureJoystickAxis(txt_joystick_axis_t *joystick_axis, int using_button, txt_joystick_axis_callback_t callback) { // Open the joystick first. if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { return; } joystick_axis->joystick = SDL_JoystickOpen(joystick_index); if (joystick_axis->joystick == NULL) { // TODO: OpenErrorWindow(); return; } SDL_JoystickEventState(SDL_ENABLE); // Build the prompt window. joystick_axis->config_window = TXT_NewWindow("Gamepad/Joystick calibration"); TXT_AddWidgets(joystick_axis->config_window, TXT_NewStrut(0, 1), joystick_axis->config_label = TXT_NewLabel(""), TXT_NewStrut(0, 1), NULL); TXT_SetWindowAction(joystick_axis->config_window, TXT_HORIZ_LEFT, NULL); TXT_SetWindowAction(joystick_axis->config_window, TXT_HORIZ_CENTER, TXT_NewWindowAbortAction(joystick_axis->config_window)); TXT_SetWindowAction(joystick_axis->config_window, TXT_HORIZ_RIGHT, NULL); TXT_SetWidgetAlign(joystick_axis->config_window, TXT_HORIZ_CENTER); if (using_button >= 0) { joystick_axis->config_stage = CONFIG_STAGE1; joystick_axis->config_button = using_button; IdentifyBadAxes(joystick_axis); } else { joystick_axis->config_stage = CONFIG_CENTER; } SetCalibrationLabel(joystick_axis); // Close the joystick and shut down joystick subsystem when the window // is closed. TXT_SignalConnect(joystick_axis->config_window, "closed", CalibrateWindowClosed, joystick_axis); TXT_SDL_SetEventCallback(EventCallback, joystick_axis); // When successfully calibrated, invoke this callback: joystick_axis->callback = callback; } static void TXT_JoystickAxisSizeCalc(TXT_UNCAST_ARG(joystick_axis)) { TXT_CAST_ARG(txt_joystick_axis_t, joystick_axis); // All joystickinputs are the same size. joystick_axis->widget.w = JOYSTICK_AXIS_WIDTH; joystick_axis->widget.h = 1; } static void TXT_JoystickAxisDrawer(TXT_UNCAST_ARG(joystick_axis)) { TXT_CAST_ARG(txt_joystick_axis_t, joystick_axis); char buf[JOYSTICK_AXIS_WIDTH + 1]; int i; if (*joystick_axis->axis < 0) { M_StringCopy(buf, "(none)", sizeof(buf)); } else if (IS_BUTTON_AXIS(*joystick_axis->axis)) { int neg, pos; neg = BUTTON_AXIS_NEG(*joystick_axis->axis); pos = BUTTON_AXIS_POS(*joystick_axis->axis); M_snprintf(buf, sizeof(buf), "BUTTONS #%i+#%i", neg, pos); } else if (IS_HAT_AXIS(*joystick_axis->axis)) { int hat, dir; hat = HAT_AXIS_HAT(*joystick_axis->axis); dir = HAT_AXIS_DIRECTION(*joystick_axis->axis); M_snprintf(buf, sizeof(buf), "HAT #%i (%s)", hat, dir == HAT_AXIS_HORIZONTAL ? "horizontal" : "vertical"); } else { M_snprintf(buf, sizeof(buf), "AXIS #%i", *joystick_axis->axis); } TXT_SetWidgetBG(joystick_axis); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_DrawString(buf); for (i=strlen(buf); iaxis = -1; } return 0; } static void TXT_JoystickAxisMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) { TXT_CAST_ARG(txt_joystick_axis_t, widget); // Clicking is like pressing enter if (b == TXT_MOUSE_LEFT) { TXT_JoystickAxisKeyPress(widget, KEY_ENTER); } } txt_widget_class_t txt_joystick_axis_class = { TXT_AlwaysSelectable, TXT_JoystickAxisSizeCalc, TXT_JoystickAxisDrawer, TXT_JoystickAxisKeyPress, TXT_JoystickAxisDestructor, TXT_JoystickAxisMousePress, NULL, }; txt_joystick_axis_t *TXT_NewJoystickAxis(int *axis, int *invert, txt_joystick_axis_direction_t dir) { txt_joystick_axis_t *joystick_axis; joystick_axis = malloc(sizeof(txt_joystick_axis_t)); TXT_InitWidget(joystick_axis, &txt_joystick_axis_class); joystick_axis->axis = axis; joystick_axis->invert = invert; joystick_axis->dir = dir; joystick_axis->bad_axis = NULL; return joystick_axis; } chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_joyaxis.h000066400000000000000000000053321257432200600237750ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_JOY_AXIS_H #define TXT_JOY_AXIS_H typedef struct txt_joystick_axis_s txt_joystick_axis_t; typedef enum { JOYSTICK_AXIS_HORIZONTAL, JOYSTICK_AXIS_VERTICAL, } txt_joystick_axis_direction_t; typedef enum { CONFIG_CENTER, // "Center the joystick and press a button..." CONFIG_STAGE1, // "Top or left and press a button..." CONFIG_STAGE2, // [Optional] "Bottom or right and press a button..." } txt_joystick_axis_stage_t; // Callback invoked when calibration is completed. typedef void (*txt_joystick_axis_callback_t)(void); #include "txt_widget.h" #include "txt_window.h" #include "SDL.h" // // A joystick axis. // struct txt_joystick_axis_s { txt_widget_t widget; int *axis, *invert; txt_joystick_axis_direction_t dir; // Only used when configuring: // Configuration prompt window and label. txt_window_t *config_window; txt_label_t *config_label; // SDL joystick handle for reading joystick state. SDL_Joystick *joystick; // "Bad" joystick axes. Sometimes an axis can be stuck or "bad". An // example I found is that if you unplug the nunchuck extension from // a Wii remote, the axes from the nunchuck can be stuck at one of // the maximum values. These have to be ignored, so when we ask the // user to center the joystick, we look for bad axes that are not // close to zero. boolean *bad_axis; // Stage we have reached in configuring joystick axis. txt_joystick_axis_stage_t config_stage; // Button to press to advance to next stage. int config_button; // Callback invoked when the axis is calibrated. txt_joystick_axis_callback_t callback; }; txt_joystick_axis_t *TXT_NewJoystickAxis(int *axis, int *invert, txt_joystick_axis_direction_t dir); // Configure a joystick axis widget. // axis: The axis widget to configure. // using_button: If non-negative, use this joystick button as the button // to expect from the user. Otherwise, ask. void TXT_ConfigureJoystickAxis(txt_joystick_axis_t *axis, int using_button, txt_joystick_axis_callback_t callback); #endif /* #ifndef TXT_JOY_AXIS_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_joybinput.c000066400000000000000000000202301257432200600243170ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "SDL_joystick.h" #include "doomkeys.h" #include "joystick.h" #include "i_joystick.h" #include "i_system.h" #include "m_controls.h" #include "m_misc.h" #include "txt_joybinput.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_label.h" #include "txt_sdl.h" #include "txt_window.h" #define JOYSTICK_INPUT_WIDTH 10 extern int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS]; // Joystick button variables. // The ordering of this array is important. We will always try to map // each variable to the virtual button with the same array index. For // example: joybfire should always be 0, and then we change // joystick_physical_buttons[0] to point to the physical joystick // button that the user wants to use for firing. We do this so that // the menus work (the game code is hard coded to interpret // button #0 = select menu item, button #1 = go back to previous menu). static int *all_joystick_buttons[] = { &joybfire, &joybuse, &joybstrafe, &joybspeed, &joybstrafeleft, &joybstraferight, &joybprevweapon, &joybnextweapon, &joybjump, &joybmenu, }; static int PhysicalForVirtualButton(int vbutton) { if (vbutton < NUM_VIRTUAL_BUTTONS) { return joystick_physical_buttons[vbutton]; } else { return vbutton; } } // Get the virtual button number for the given variable, ie. the // variable's index in all_joystick_buttons[]. static int VirtualButtonForVariable(int *variable) { int i; for (i = 0; i < arrlen(all_joystick_buttons); ++i) { if (variable == all_joystick_buttons[i]) { return i; } } I_Error("Couldn't find virtual button"); return -1; } // Rearrange joystick button configuration to be in "canonical" form: // each joyb* variable should have a value equal to its index in // all_joystick_buttons[] above. static void CanonicalizeButtons(void) { int new_mapping[NUM_VIRTUAL_BUTTONS]; int vbutton; int i; for (i = 0; i < arrlen(all_joystick_buttons); ++i) { vbutton = *all_joystick_buttons[i]; // Don't remap the speed key if it's bound to "always run". // Also preserve "unbound" variables. if ((all_joystick_buttons[i] == &joybspeed && vbutton >= 20) || vbutton < 0) { new_mapping[i] = i; } else { new_mapping[i] = PhysicalForVirtualButton(vbutton); *all_joystick_buttons[i] = i; } } for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i) { joystick_physical_buttons[i] = new_mapping[i]; } } // Check all existing buttons and clear any using the specified physical // button. static void ClearVariablesUsingButton(int physbutton) { int vbutton; int i; for (i = 0; i < arrlen(all_joystick_buttons); ++i) { vbutton = *all_joystick_buttons[i]; if (vbutton >= 0 && physbutton == PhysicalForVirtualButton(vbutton)) { *all_joystick_buttons[i] = -1; } } } // Called in response to SDL events when the prompt window is open: static int EventCallback(SDL_Event *event, TXT_UNCAST_ARG(joystick_input)) { TXT_CAST_ARG(txt_joystick_input_t, joystick_input); // Got the joystick button press? if (event->type == SDL_JOYBUTTONDOWN) { int vbutton, physbutton; // Before changing anything, remap button configuration into // canonical form, to avoid conflicts. CanonicalizeButtons(); vbutton = VirtualButtonForVariable(joystick_input->variable); physbutton = event->jbutton.button; if (joystick_input->check_conflicts) { ClearVariablesUsingButton(physbutton); } // Set mapping. *joystick_input->variable = vbutton; joystick_physical_buttons[vbutton] = physbutton; TXT_CloseWindow(joystick_input->prompt_window); return 1; } return 0; } // When the prompt window is closed, disable the event callback function; // we are no longer interested in receiving notification of events. static void PromptWindowClosed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(joystick)) { TXT_CAST_ARG(SDL_Joystick, joystick); SDL_JoystickClose(joystick); TXT_SDL_SetEventCallback(NULL, NULL); SDL_JoystickEventState(SDL_DISABLE); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } static void OpenErrorWindow(void) { TXT_MessageBox(NULL, "Please configure a joystick first!"); } static void OpenPromptWindow(txt_joystick_input_t *joystick_input) { txt_window_t *window; SDL_Joystick *joystick; // Silently update when the shift button is held down. joystick_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT); if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { return; } // Check the current joystick is valid joystick = SDL_JoystickOpen(joystick_index); if (joystick == NULL) { OpenErrorWindow(); return; } // Open the prompt window window = TXT_MessageBox(NULL, "Press the new joystick button..."); TXT_SDL_SetEventCallback(EventCallback, joystick_input); TXT_SignalConnect(window, "closed", PromptWindowClosed, joystick); joystick_input->prompt_window = window; SDL_JoystickEventState(SDL_ENABLE); } static void TXT_JoystickInputSizeCalc(TXT_UNCAST_ARG(joystick_input)) { TXT_CAST_ARG(txt_joystick_input_t, joystick_input); // All joystickinputs are the same size. joystick_input->widget.w = JOYSTICK_INPUT_WIDTH; joystick_input->widget.h = 1; } static void GetJoystickButtonDescription(int vbutton, char *buf, size_t buf_len) { M_snprintf(buf, buf_len, "BUTTON #%i", PhysicalForVirtualButton(vbutton) + 1); } static void TXT_JoystickInputDrawer(TXT_UNCAST_ARG(joystick_input)) { TXT_CAST_ARG(txt_joystick_input_t, joystick_input); char buf[20]; int i; if (*joystick_input->variable < 0) { M_StringCopy(buf, "(none)", sizeof(buf)); } else { GetJoystickButtonDescription(*joystick_input->variable, buf, sizeof(buf)); } TXT_SetWidgetBG(joystick_input); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_DrawString(buf); for (i=strlen(buf); ivariable = -1; } return 0; } static void TXT_JoystickInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) { TXT_CAST_ARG(txt_joystick_input_t, widget); // Clicking is like pressing enter if (b == TXT_MOUSE_LEFT) { TXT_JoystickInputKeyPress(widget, KEY_ENTER); } } txt_widget_class_t txt_joystick_input_class = { TXT_AlwaysSelectable, TXT_JoystickInputSizeCalc, TXT_JoystickInputDrawer, TXT_JoystickInputKeyPress, TXT_JoystickInputDestructor, TXT_JoystickInputMousePress, NULL, }; txt_joystick_input_t *TXT_NewJoystickInput(int *variable) { txt_joystick_input_t *joystick_input; joystick_input = malloc(sizeof(txt_joystick_input_t)); TXT_InitWidget(joystick_input, &txt_joystick_input_class); joystick_input->variable = variable; return joystick_input; } chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_joybinput.h000066400000000000000000000020721257432200600243300ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_JOYB_INPUT_H #define TXT_JOYB_INPUT_H typedef struct txt_joystick_input_s txt_joystick_input_t; #include "txt_widget.h" #include "txt_window.h" // // A joystick input is like an input box. When selected, a box pops up // allowing a joystick button to be pressed to select it. // struct txt_joystick_input_s { txt_widget_t widget; int *variable; txt_window_t *prompt_window; int check_conflicts; }; txt_joystick_input_t *TXT_NewJoystickInput(int *variable); #endif /* #ifndef TXT_JOYB_INPUT_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_keyinput.c000066400000000000000000000100331257432200600241440ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "doomkeys.h" #include "m_misc.h" #include "txt_keyinput.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_label.h" #include "txt_window.h" #define KEY_INPUT_WIDTH 8 static int KeyPressCallback(txt_window_t *window, int key, TXT_UNCAST_ARG(key_input)) { TXT_CAST_ARG(txt_key_input_t, key_input); if (key != KEY_ESCAPE) { // Got the key press. Save to the variable and close the window. *key_input->variable = key; if (key_input->check_conflicts) { TXT_EmitSignal(key_input, "set"); } TXT_CloseWindow(window); // Re-enable key mappings now that we have the key TXT_EnableKeyMapping(1); return 1; } else { return 0; } } static void ReleaseGrab(TXT_UNCAST_ARG(window), TXT_UNCAST_ARG(unused)) { SDL_WM_GrabInput(SDL_GRAB_OFF); } static void OpenPromptWindow(txt_key_input_t *key_input) { txt_window_t *window; // Silently update when the shift button is held down. key_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT); window = TXT_MessageBox(NULL, "Press the new key..."); TXT_SetKeyListener(window, KeyPressCallback, key_input); // Disable key mappings while we prompt for the key press TXT_EnableKeyMapping(0); // Grab input while reading the key. On Windows Mobile // handheld devices, the hardware keypresses are only // detected when input is grabbed. SDL_WM_GrabInput(SDL_GRAB_ON); TXT_SignalConnect(window, "closed", ReleaseGrab, NULL); } static void TXT_KeyInputSizeCalc(TXT_UNCAST_ARG(key_input)) { TXT_CAST_ARG(txt_key_input_t, key_input); // All keyinputs are the same size. key_input->widget.w = KEY_INPUT_WIDTH; key_input->widget.h = 1; } static void TXT_KeyInputDrawer(TXT_UNCAST_ARG(key_input)) { TXT_CAST_ARG(txt_key_input_t, key_input); char buf[20]; int i; if (*key_input->variable == 0) { M_StringCopy(buf, "(none)", sizeof(buf)); } else { TXT_GetKeyDescription(*key_input->variable, buf, sizeof(buf)); } TXT_SetWidgetBG(key_input); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_DrawString(buf); for (i=strlen(buf); ivariable = 0; } return 0; } static void TXT_KeyInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) { TXT_CAST_ARG(txt_key_input_t, widget); // Clicking is like pressing enter if (b == TXT_MOUSE_LEFT) { TXT_KeyInputKeyPress(widget, KEY_ENTER); } } txt_widget_class_t txt_key_input_class = { TXT_AlwaysSelectable, TXT_KeyInputSizeCalc, TXT_KeyInputDrawer, TXT_KeyInputKeyPress, TXT_KeyInputDestructor, TXT_KeyInputMousePress, NULL, }; txt_key_input_t *TXT_NewKeyInput(int *variable) { txt_key_input_t *key_input; key_input = malloc(sizeof(txt_key_input_t)); TXT_InitWidget(key_input, &txt_key_input_class); key_input->variable = variable; return key_input; } chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_keyinput.h000066400000000000000000000017101257432200600241530ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_KEY_INPUT_H #define TXT_KEY_INPUT_H typedef struct txt_key_input_s txt_key_input_t; #include "txt_widget.h" // // A key input is like an input box. When selected, a box pops up // allowing a key to be selected. // struct txt_key_input_s { txt_widget_t widget; int *variable; int check_conflicts; }; txt_key_input_t *TXT_NewKeyInput(int *variable); #endif /* #ifndef TXT_KEY_INPUT_H */ chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_mouseinput.c000066400000000000000000000100241257432200600245040ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "doomkeys.h" #include "m_misc.h" #include "txt_mouseinput.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_label.h" #include "txt_window.h" #define MOUSE_INPUT_WIDTH 8 static int MousePressCallback(txt_window_t *window, int x, int y, int b, TXT_UNCAST_ARG(mouse_input)) { TXT_CAST_ARG(txt_mouse_input_t, mouse_input); // Got the mouse press. Save to the variable and close the window. *mouse_input->variable = b - TXT_MOUSE_BASE; if (mouse_input->check_conflicts) { TXT_EmitSignal(mouse_input, "set"); } TXT_CloseWindow(window); return 1; } static void OpenPromptWindow(txt_mouse_input_t *mouse_input) { txt_window_t *window; // Silently update when the shift key is held down. mouse_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT); window = TXT_MessageBox(NULL, "Press the new mouse button..."); TXT_SetMouseListener(window, MousePressCallback, mouse_input); } static void TXT_MouseInputSizeCalc(TXT_UNCAST_ARG(mouse_input)) { TXT_CAST_ARG(txt_mouse_input_t, mouse_input); // All mouseinputs are the same size. mouse_input->widget.w = MOUSE_INPUT_WIDTH; mouse_input->widget.h = 1; } static void GetMouseButtonDescription(int button, char *buf, size_t buf_len) { switch (button) { case 0: M_StringCopy(buf, "LEFT", buf_len); break; case 1: M_StringCopy(buf, "RIGHT", buf_len); break; case 2: M_StringCopy(buf, "MID", buf_len); break; default: M_snprintf(buf, buf_len, "BUTTON #%i", button + 1); break; } } static void TXT_MouseInputDrawer(TXT_UNCAST_ARG(mouse_input)) { TXT_CAST_ARG(txt_mouse_input_t, mouse_input); char buf[20]; int i; if (*mouse_input->variable < 0) { M_StringCopy(buf, "(none)", sizeof(buf)); } else { GetMouseButtonDescription(*mouse_input->variable, buf, sizeof(buf)); } TXT_SetWidgetBG(mouse_input); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_DrawString(buf); for (i=strlen(buf); ivariable = -1; } return 0; } static void TXT_MouseInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) { TXT_CAST_ARG(txt_mouse_input_t, widget); // Clicking is like pressing enter if (b == TXT_MOUSE_LEFT) { TXT_MouseInputKeyPress(widget, KEY_ENTER); } } txt_widget_class_t txt_mouse_input_class = { TXT_AlwaysSelectable, TXT_MouseInputSizeCalc, TXT_MouseInputDrawer, TXT_MouseInputKeyPress, TXT_MouseInputDestructor, TXT_MouseInputMousePress, NULL, }; txt_mouse_input_t *TXT_NewMouseInput(int *variable) { txt_mouse_input_t *mouse_input; mouse_input = malloc(sizeof(txt_mouse_input_t)); TXT_InitWidget(mouse_input, &txt_mouse_input_class); mouse_input->variable = variable; return mouse_input; } chocolate-doom-chocolate-doom-2.2.1/src/setup/txt_mouseinput.h000066400000000000000000000017341257432200600245210ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_MOUSE_INPUT_H #define TXT_MOUSE_INPUT_H typedef struct txt_mouse_input_s txt_mouse_input_t; #include "txt_widget.h" // // A mouse input is like an input box. When selected, a box pops up // allowing a mouse to be selected. // struct txt_mouse_input_s { txt_widget_t widget; int *variable; int check_conflicts; }; txt_mouse_input_t *TXT_NewMouseInput(int *variable); #endif /* #ifndef TXT_MOUSE_INPUT_H */ chocolate-doom-chocolate-doom-2.2.1/src/sha1.c000066400000000000000000000210151257432200600210730ustar00rootroot00000000000000/* sha1.c - SHA1 hash function * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * Please see below for more legal information! * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ /* Test vectors: * * "abc" * A999 3E36 4706 816A BA3E 2571 7850 C26C 9CD0 D89D * * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" * 8498 3E44 1C3B D26E BAAE 4AA1 F951 29E5 E546 70F1 */ #include #include #include #include #include "i_swap.h" #include "sha1.h" void SHA1_Init(sha1_context_t *hd) { hd->h0 = 0x67452301; hd->h1 = 0xefcdab89; hd->h2 = 0x98badcfe; hd->h3 = 0x10325476; hd->h4 = 0xc3d2e1f0; hd->nblocks = 0; hd->count = 0; } /**************** * Transform the message X which consists of 16 32-bit-words */ static void Transform(sha1_context_t *hd, byte *data) { uint32_t a,b,c,d,e,tm; uint32_t x[16]; /* get values from the chaining vars */ a = hd->h0; b = hd->h1; c = hd->h2; d = hd->h3; e = hd->h4; #ifdef SYS_BIG_ENDIAN memcpy(x, data, 64); #else { int i; byte *p2; for(i=0, p2=(byte*)x; i < 16; i++, p2 += 4 ) { p2[3] = *data++; p2[2] = *data++; p2[1] = *data++; p2[0] = *data++; } } #endif #define K1 0x5A827999L #define K2 0x6ED9EBA1L #define K3 0x8F1BBCDCL #define K4 0xCA62C1D6L #define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) #define F2(x,y,z) ( x ^ y ^ z ) #define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) #define F4(x,y,z) ( x ^ y ^ z ) #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) #define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] \ ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \ , (x[i&0x0f] = rol(tm,1)) ) #define R(a,b,c,d,e,f,k,m) do { e += rol( a, 5 ) \ + f( b, c, d ) \ + k \ + m; \ b = rol( b, 30 ); \ } while(0) R( a, b, c, d, e, F1, K1, x[ 0] ); R( e, a, b, c, d, F1, K1, x[ 1] ); R( d, e, a, b, c, F1, K1, x[ 2] ); R( c, d, e, a, b, F1, K1, x[ 3] ); R( b, c, d, e, a, F1, K1, x[ 4] ); R( a, b, c, d, e, F1, K1, x[ 5] ); R( e, a, b, c, d, F1, K1, x[ 6] ); R( d, e, a, b, c, F1, K1, x[ 7] ); R( c, d, e, a, b, F1, K1, x[ 8] ); R( b, c, d, e, a, F1, K1, x[ 9] ); R( a, b, c, d, e, F1, K1, x[10] ); R( e, a, b, c, d, F1, K1, x[11] ); R( d, e, a, b, c, F1, K1, x[12] ); R( c, d, e, a, b, F1, K1, x[13] ); R( b, c, d, e, a, F1, K1, x[14] ); R( a, b, c, d, e, F1, K1, x[15] ); R( e, a, b, c, d, F1, K1, M(16) ); R( d, e, a, b, c, F1, K1, M(17) ); R( c, d, e, a, b, F1, K1, M(18) ); R( b, c, d, e, a, F1, K1, M(19) ); R( a, b, c, d, e, F2, K2, M(20) ); R( e, a, b, c, d, F2, K2, M(21) ); R( d, e, a, b, c, F2, K2, M(22) ); R( c, d, e, a, b, F2, K2, M(23) ); R( b, c, d, e, a, F2, K2, M(24) ); R( a, b, c, d, e, F2, K2, M(25) ); R( e, a, b, c, d, F2, K2, M(26) ); R( d, e, a, b, c, F2, K2, M(27) ); R( c, d, e, a, b, F2, K2, M(28) ); R( b, c, d, e, a, F2, K2, M(29) ); R( a, b, c, d, e, F2, K2, M(30) ); R( e, a, b, c, d, F2, K2, M(31) ); R( d, e, a, b, c, F2, K2, M(32) ); R( c, d, e, a, b, F2, K2, M(33) ); R( b, c, d, e, a, F2, K2, M(34) ); R( a, b, c, d, e, F2, K2, M(35) ); R( e, a, b, c, d, F2, K2, M(36) ); R( d, e, a, b, c, F2, K2, M(37) ); R( c, d, e, a, b, F2, K2, M(38) ); R( b, c, d, e, a, F2, K2, M(39) ); R( a, b, c, d, e, F3, K3, M(40) ); R( e, a, b, c, d, F3, K3, M(41) ); R( d, e, a, b, c, F3, K3, M(42) ); R( c, d, e, a, b, F3, K3, M(43) ); R( b, c, d, e, a, F3, K3, M(44) ); R( a, b, c, d, e, F3, K3, M(45) ); R( e, a, b, c, d, F3, K3, M(46) ); R( d, e, a, b, c, F3, K3, M(47) ); R( c, d, e, a, b, F3, K3, M(48) ); R( b, c, d, e, a, F3, K3, M(49) ); R( a, b, c, d, e, F3, K3, M(50) ); R( e, a, b, c, d, F3, K3, M(51) ); R( d, e, a, b, c, F3, K3, M(52) ); R( c, d, e, a, b, F3, K3, M(53) ); R( b, c, d, e, a, F3, K3, M(54) ); R( a, b, c, d, e, F3, K3, M(55) ); R( e, a, b, c, d, F3, K3, M(56) ); R( d, e, a, b, c, F3, K3, M(57) ); R( c, d, e, a, b, F3, K3, M(58) ); R( b, c, d, e, a, F3, K3, M(59) ); R( a, b, c, d, e, F4, K4, M(60) ); R( e, a, b, c, d, F4, K4, M(61) ); R( d, e, a, b, c, F4, K4, M(62) ); R( c, d, e, a, b, F4, K4, M(63) ); R( b, c, d, e, a, F4, K4, M(64) ); R( a, b, c, d, e, F4, K4, M(65) ); R( e, a, b, c, d, F4, K4, M(66) ); R( d, e, a, b, c, F4, K4, M(67) ); R( c, d, e, a, b, F4, K4, M(68) ); R( b, c, d, e, a, F4, K4, M(69) ); R( a, b, c, d, e, F4, K4, M(70) ); R( e, a, b, c, d, F4, K4, M(71) ); R( d, e, a, b, c, F4, K4, M(72) ); R( c, d, e, a, b, F4, K4, M(73) ); R( b, c, d, e, a, F4, K4, M(74) ); R( a, b, c, d, e, F4, K4, M(75) ); R( e, a, b, c, d, F4, K4, M(76) ); R( d, e, a, b, c, F4, K4, M(77) ); R( c, d, e, a, b, F4, K4, M(78) ); R( b, c, d, e, a, F4, K4, M(79) ); /* update chainig vars */ hd->h0 += a; hd->h1 += b; hd->h2 += c; hd->h3 += d; hd->h4 += e; } /* Update the message digest with the contents * of INBUF with length INLEN. */ void SHA1_Update(sha1_context_t *hd, byte *inbuf, size_t inlen) { if (hd->count == 64) { /* flush the buffer */ Transform(hd, hd->buf); hd->count = 0; hd->nblocks++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; SHA1_Update(hd, NULL, 0); if (!inlen) return; } while (inlen >= 64) { Transform(hd, inbuf); hd->count = 0; hd->nblocks++; inlen -= 64; inbuf += 64; } for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; } /* The routine final terminates the computation and * returns the digest. * The handle is prepared for a new cycle, but adding bytes to the * handle will the destroy the returned buffer. * Returns: 20 bytes representing the digest. */ void SHA1_Final(sha1_digest_t digest, sha1_context_t *hd) { uint32_t t, msb, lsb; byte *p; SHA1_Update(hd, NULL, 0); /* flush */; t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; if ((lsb += hd->count) < t) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; if (hd->count < 56) { /* enough room */ hd->buf[hd->count++] = 0x80; /* pad */ while (hd->count < 56) hd->buf[hd->count++] = 0; /* pad */ } else { /* need one extra block */ hd->buf[hd->count++] = 0x80; /* pad character */ while (hd->count < 64) hd->buf[hd->count++] = 0; SHA1_Update(hd, NULL, 0); /* flush */; memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ hd->buf[56] = msb >> 24; hd->buf[57] = msb >> 16; hd->buf[58] = msb >> 8; hd->buf[59] = msb ; hd->buf[60] = lsb >> 24; hd->buf[61] = lsb >> 16; hd->buf[62] = lsb >> 8; hd->buf[63] = lsb ; Transform(hd, hd->buf); p = hd->buf; #ifdef SYS_BIG_ENDIAN #define X(a) do { *(uint32_t*)p = hd->h##a ; p += 4; } while(0) #else /* little endian */ #define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) #endif X(0); X(1); X(2); X(3); X(4); #undef X memcpy(digest, hd->buf, sizeof(sha1_digest_t)); } void SHA1_UpdateInt32(sha1_context_t *context, unsigned int val) { byte buf[4]; buf[0] = (val >> 24) & 0xff; buf[1] = (val >> 16) & 0xff; buf[2] = (val >> 8) & 0xff; buf[3] = val & 0xff; SHA1_Update(context, buf, 4); } void SHA1_UpdateString(sha1_context_t *context, char *str) { SHA1_Update(context, (byte *) str, strlen(str) + 1); } chocolate-doom-chocolate-doom-2.2.1/src/sha1.h000066400000000000000000000022261257432200600211030ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // SHA-1 digest. // #ifndef __SHA1_H__ #define __SHA1_H__ #include "doomtype.h" typedef struct sha1_context_s sha1_context_t; typedef byte sha1_digest_t[20]; struct sha1_context_s { uint32_t h0,h1,h2,h3,h4; uint32_t nblocks; byte buf[64]; int count; }; void SHA1_Init(sha1_context_t *context); void SHA1_Update(sha1_context_t *context, byte *buf, size_t len); void SHA1_Final(sha1_digest_t digest, sha1_context_t *context); void SHA1_UpdateInt32(sha1_context_t *context, unsigned int val); void SHA1_UpdateString(sha1_context_t *context, char *str); #endif /* #ifndef __SHA1_H__ */ chocolate-doom-chocolate-doom-2.2.1/src/strife.appdata.xml.in000066400000000000000000000033521257432200600241330ustar00rootroot00000000000000 @PROGRAM_PREFIX@strife.desktop CC0-1.0 GPL-2.0+ @PACKAGE_MAINTAINER@ @PACKAGE_URL@ @PACKAGE_ISSUES@

@PACKAGE_SHORTNAME@ Strife is a conservative, historically-accurate recreation of the Strife engine. It is completely compatible with the original game and mods created with the original engine in mind. Made with a great reverse engineering effort, it has the goal of preserving the original look, feel, limitations, and bugs of the original DOS executable.

Full support for single- and multi-player games is provided. Unlike the original executable, network play is implemented on the IP network stack, allowing it to function on modern LANs and the Internet.

http://www.chocolate-doom.org/wiki/images/b/b2/GNOME_Strife_Rowan.png Talking to Rowan http://www.chocolate-doom.org/wiki/images/1/1f/GNOME_Strife_Town.png The Town http://www.chocolate-doom.org/wiki/images/8/8a/GNOME_Strife_Opening.png Opening Cinematic http://www.chocolate-doom.org/wiki/images/c/c4/GNOME_Strife_Sewage.png In the sewage
chocolate-doom-chocolate-doom-2.2.1/src/strife.desktop.in000066400000000000000000000003331257432200600233670ustar00rootroot00000000000000[Desktop Entry] Name=@PACKAGE_SHORTNAME@ Strife Exec=@PROGRAM_PREFIX@strife Icon=@PROGRAM_PREFIX@doom Type=Application Comment=@PACKAGE_SHORTDESC@ Categories=Game;ActionGame; Keywords=first;person;shooter;doom;vanilla; chocolate-doom-chocolate-doom-2.2.1/src/strife/000077500000000000000000000000001257432200600213705ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/src/strife/.gitignore000066400000000000000000000000451257432200600233570ustar00rootroot00000000000000Makefile Makefile.in .deps tags TAGS chocolate-doom-chocolate-doom-2.2.1/src/strife/Makefile.am000066400000000000000000000051261257432200600234300ustar00rootroot00000000000000AM_CFLAGS = -I$(top_srcdir)/src @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@ noinst_LIBRARIES=libstrife.a SOURCE_FILES= \ am_map.c am_map.h \ d_englsh.h \ d_items.c d_items.h \ d_main.c d_main.h \ d_net.c \ doomdata.h \ doomdef.c doomdef.h \ doomstat.c doomstat.h \ d_player.h \ dstrings.c dstrings.h \ d_textur.h \ d_think.h \ f_finale.c f_finale.h \ f_wipe.c f_wipe.h \ g_game.c g_game.h \ hu_lib.c hu_lib.h \ hu_stuff.c hu_stuff.h \ info.c info.h \ m_menu.c m_menu.h \ m_random.c m_random.h \ m_saves.c m_saves.h \ p_ceilng.c \ p_dialog.c p_dialog.h \ p_doors.c \ p_enemy.c \ p_floor.c \ p_inter.c p_inter.h \ p_lights.c \ p_local.h \ p_map.c \ p_maputl.c \ p_mobj.c p_mobj.h \ p_plats.c \ p_pspr.c p_pspr.h \ p_saveg.c p_saveg.h \ p_setup.c p_setup.h \ p_sight.c \ p_spec.c p_spec.h \ p_switch.c \ p_telept.c \ p_tick.c p_tick.h \ p_user.c \ r_bsp.c r_bsp.h \ r_data.c r_data.h \ r_defs.h \ r_draw.c r_draw.h \ r_local.h \ r_main.c r_main.h \ r_plane.c r_plane.h \ r_segs.c r_segs.h \ r_sky.c r_sky.h \ r_state.h \ r_things.c r_things.h \ s_sound.c s_sound.h \ sounds.c sounds.h \ st_lib.c st_lib.h \ st_stuff.c st_stuff.h \ wi_stuff.c wi_stuff.h FEATURE_DEHACKED_SOURCE_FILES = \ deh_ammo.c \ deh_cheat.c \ deh_strife.c \ deh_frame.c \ deh_misc.c deh_misc.h \ deh_ptr.c \ deh_sound.c \ deh_thing.c \ deh_weapon.c libstrife_a_SOURCES = $(SOURCE_FILES) \ $(FEATURE_DEHACKED_SOURCE_FILES) chocolate-doom-chocolate-doom-2.2.1/src/strife/am_map.c000066400000000000000000000726431257432200600230020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: the automap code // #include #include "deh_main.h" #include "z_zone.h" #include "doomkeys.h" #include "doomdef.h" #include "m_misc.h" #include "st_stuff.h" #include "p_local.h" #include "w_wad.h" #include "m_cheat.h" #include "m_controls.h" #include "i_system.h" // Needs access to LFB. #include "v_video.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "dstrings.h" #include "am_map.h" // Automap colors #define BACKGROUND 240 // haleyjd [STRIFE] #define WALLCOLORS 5 // villsa [STRIFE] #define WALLRANGE 16 #define TSWALLCOLORS 16 #define FDWALLCOLORS 122 // villsa [STRIFE] #define CDWALLCOLORS 116 #define CTWALLCOLORS 19 // villsa [STRIFE] #define SPWALLCOLORS 243 // villsa [STRIFE] #define THINGCOLORS 233 // villsa [STRIFE] #define MISSILECOLORS 227 // villsa [STRIFE] #define SHOOTABLECOLORS 235 // villsa [STRIFE] // drawing stuff #define AM_NUMMARKPOINTS 10 // scale on entry #define INITSCALEMTOF (.2*FRACUNIT) // how much the automap moves window per tic in frame-buffer coordinates // moves 140 pixels in 1 second #define F_PANINC 4 // how much zoom-in per tic // goes to 2x in 1 second #define M_ZOOMIN ((int) (1.02*FRACUNIT)) // how much zoom-out per tic // pulls out to 0.5x in 1 second #define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // translates between frame-buffer and map distances #define FTOM(x) FixedMul(((x)<<16),scale_ftom) #define MTOF(x) (FixedMul((x),scale_mtof)>>16) // translates between frame-buffer and map coordinates #define CXMTOF(x) (f_x + MTOF((x)-m_x)) #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) // the following is crap #define LINE_NEVERSEE ML_DONTDRAW typedef struct { int x, y; } fpoint_t; typedef struct { fpoint_t a, b; } fline_t; typedef struct { fixed_t x,y; } mpoint_t; typedef struct { mpoint_t a, b; } mline_t; typedef struct { fixed_t slp, islp; } islope_t; // // The vector graphics for the automap. // A line drawing of the player pointing right, // starting from the middle. // #define R ((8*PLAYERRADIUS)/7) mline_t player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; #undef R #define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/6 } }, // -----> { { R, 0 }, { R-R/2, -R/6 } }, { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >-----> { { -R+R/8, 0 }, { -R-R/8, -R/6 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>-----> { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } }, { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d---> { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } }, { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } }, { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd--> { { -R/6, -R/6 }, { 0, -R/6 } }, { { 0, -R/6 }, { 0, R/4 } }, { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt-> { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } }; #undef R #define R (FRACUNIT) mline_t triangle_guy[] = { { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)(.867*R ), (fixed_t)(-.5*R) } }, { { (fixed_t)(.867*R ), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)(R ) } }, { { (fixed_t)(0 ), (fixed_t)(R ) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } }; #undef R #define R (FRACUNIT) mline_t thintriangle_guy[] = { { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } }, { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } }, { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } }; #undef R static int cheating = 0; //static int grid = 0; [STRIFE]: no such variable static int leveljuststarted = 1; // kluge until AM_LevelInit() is called boolean automapactive = false; static int finit_width = SCREENWIDTH; static int finit_height = SCREENHEIGHT - 32; // location of window on screen static int f_x; static int f_y; // size of window on screen static int f_w; static int f_h; static int lightlev; // used for funky strobing effect static byte* fb; // pseudo-frame buffer static int amclock; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords) static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords) static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords) // // width/height of window on map (map coords) // static fixed_t m_w; static fixed_t m_h; // based on level size static fixed_t min_x; static fixed_t min_y; static fixed_t max_x; static fixed_t max_y; static fixed_t max_w; // max_x-min_x, static fixed_t max_h; // max_y-min_y // based on player size static fixed_t min_w; static fixed_t min_h; static fixed_t min_scale_mtof; // used to tell when to stop zooming out static fixed_t max_scale_mtof; // used to tell when to stop zooming in // old stuff for recovery later static fixed_t old_m_w, old_m_h; static fixed_t old_m_x, old_m_y; // old location used by the Follower routine static mpoint_t f_oldloc; // used by MTOF to scale from map-to-frame-buffer coords static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow static patch_t *marknums[10]; // numbers used for marking by the automap static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are static int markpointnum = 0; // next point to be assigned static int mapmarknum = 0; // villsa [STRIFE] unused but this was meant to be used for objective based markers static int followplayer = 1; // specifies whether to follow the player around cheatseq_t cheat_amap = CHEAT("topo", 0); // villsa [STRIFE] static boolean stopped = true; // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so // that it can be used with the brain-dead drawing stuff. void AM_getIslope ( mline_t* ml, islope_t* is ) { int dx, dy; dy = ml->a.y - ml->b.y; dx = ml->b.x - ml->a.x; if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX); else is->islp = FixedDiv(dx, dy); if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX); else is->slp = FixedDiv(dy, dx); } // // // void AM_activateNewScale(void) { m_x += m_w/2; m_y += m_h/2; m_w = FTOM(f_w); m_h = FTOM(f_h); m_x -= m_w/2; m_y -= m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // // void AM_saveScaleAndLoc(void) { old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; } // // // void AM_restoreScaleAndLoc(void) { m_w = old_m_w; m_h = old_m_h; if (!followplayer) { m_x = old_m_x; m_y = old_m_y; } else { m_x = plr->mo->x - m_w/2; m_y = plr->mo->y - m_h/2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; // Change the scaling multipliers scale_mtof = FixedDiv(f_w< max_x) max_x = vertexes[i].x; if (vertexes[i].y < min_y) min_y = vertexes[i].y; else if (vertexes[i].y > max_y) max_y = vertexes[i].y; } max_w = max_x - min_x; max_h = max_y - min_y; min_w = 2*PLAYERRADIUS; // const? never changed? min_h = 2*PLAYERRADIUS; a = FixedDiv(f_w< max_x) m_x = max_x - m_w/2; else if (m_x + m_w/2 < min_x) m_x = min_x - m_w/2; if (m_y + m_h/2 > max_y) m_y = max_y - m_h/2; else if (m_y + m_h/2 < min_y) m_y = min_y - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // // void AM_initVariables(void) { int pnum; static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 }; automapactive = true; fb = I_VideoBuffer; f_oldloc.x = INT_MAX; amclock = 0; lightlev = 0; m_paninc.x = m_paninc.y = 0; ftom_zoommul = FRACUNIT; mtof_zoommul = FRACUNIT; m_w = FTOM(f_w); m_h = FTOM(f_h); // find player to center on initially if (playeringame[consoleplayer]) { plr = &players[consoleplayer]; } else { plr = &players[0]; for (pnum=0;pnummo->x - m_w/2; m_y = plr->mo->y - m_h/2; AM_changeWindowLoc(); // for saving & restoring old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; // inform the status bar of the change ST_Responder(&st_notify); } // // AM_loadPics // // haleyjd 08/27/10: [STRIFE] Changed marknums to PLMNUM%d // void AM_loadPics(void) { int i; char namebuf[9]; for (i=0;i<10;i++) { DEH_snprintf(namebuf, 9, "PLMNUM%d", i); marknums[i] = W_CacheLumpName(namebuf, PU_STATIC); } } void AM_unloadPics(void) { int i; char namebuf[9]; for (i=0;i<10;i++) { DEH_snprintf(namebuf, 9, "PLMNUM%d", i); W_ReleaseLumpName(namebuf); } } void AM_clearMarks(void) { int i; for (i=0;i max_scale_mtof) scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } // // // void AM_Stop (void) { static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; AM_unloadPics(); automapactive = false; ST_Responder(&st_notify); stopped = true; } // // // void AM_Start (void) { static int lastlevel = -1; //static int lastepisode = -1; if (!stopped) AM_Stop(); stopped = false; if (lastlevel != gamemap /*|| lastepisode != gameepisode*/) { AM_LevelInit(); lastlevel = gamemap; //lastepisode = gameepisode; } AM_initVariables(); AM_loadPics(); } // // set the window scale to the maximum size // void AM_minOutWindowScale(void) { scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // set the window scale to the minimum size // void AM_maxOutWindowScale(void) { scale_mtof = max_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // Handle events (user inputs) in automap mode // boolean AM_Responder ( event_t* ev ) { int rc; static int bigstate=0; static char buffer[20]; int key; rc = false; if (!automapactive) { if (ev->type == ev_keydown && ev->data1 == key_map_toggle) { AM_Start (); viewactive = false; rc = true; } } else if (ev->type == ev_keydown) { rc = true; key = ev->data1; if (key == key_map_east) // pan right { if (!followplayer) m_paninc.x = FTOM(F_PANINC); else rc = false; } else if (key == key_map_west) // pan left { if (!followplayer) m_paninc.x = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_north) // pan up { if (!followplayer) m_paninc.y = FTOM(F_PANINC); else rc = false; } else if (key == key_map_south) // pan down { if (!followplayer) m_paninc.y = -FTOM(F_PANINC); else rc = false; } else if (key == key_map_zoomout) // zoom out { mtof_zoommul = M_ZOOMOUT; ftom_zoommul = M_ZOOMIN; } else if (key == key_map_zoomin) // zoom in { mtof_zoommul = M_ZOOMIN; ftom_zoommul = M_ZOOMOUT; } else if (key == key_map_toggle) { bigstate = 0; viewactive = true; AM_Stop (); } else if (key == key_map_maxzoom) { bigstate = !bigstate; if (bigstate) { AM_saveScaleAndLoc(); AM_minOutWindowScale(); } else AM_restoreScaleAndLoc(); } else if (key == key_map_follow) { followplayer = !followplayer; f_oldloc.x = INT_MAX; if (followplayer) plr->message = DEH_String(AMSTR_FOLLOWON); else plr->message = DEH_String(AMSTR_FOLLOWOFF); } // haleyjd 20141101: [STRIFE] grid is not supported /* else if (key == key_map_grid) { grid = !grid; if (grid) plr->message = DEH_String(AMSTR_GRIDON); else plr->message = DEH_String(AMSTR_GRIDOFF); } */ else if (key == key_map_mark) { // haleyjd 20141101: [STRIFE] if full, mark 9 is replaced if(markpointnum == AM_NUMMARKPOINTS) --markpointnum; M_snprintf(buffer, sizeof(buffer), "%s %d", DEH_String(AMSTR_MARKEDSPOT), markpointnum + 1); // [STRIFE] plr->message = buffer; AM_addMark(); } else if (key == key_map_clearmark) { // haleyjd 20141101: [STRIFE] clears last mark only if(markpointnum > 0) { markpoints[markpointnum - 1].x = -1; --markpointnum; plr->message = DEH_String(AMSTR_MARKSCLEARED); } } else { rc = false; } if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data2)) { rc = false; cheating = (cheating+1) % 3; } } else if (ev->type == ev_keyup) { rc = false; key = ev->data1; if (key == key_map_east) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_west) { if (!followplayer) m_paninc.x = 0; } else if (key == key_map_north) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_south) { if (!followplayer) m_paninc.y = 0; } else if (key == key_map_zoomout || key == key_map_zoomin) { mtof_zoommul = FRACUNIT; ftom_zoommul = FRACUNIT; } } return rc; } // // Zooming // void AM_changeWindowScale(void) { // Change the scaling multipliers scale_mtof = FixedMul(scale_mtof, mtof_zoommul); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); if (scale_mtof < min_scale_mtof) AM_minOutWindowScale(); else if (scale_mtof > max_scale_mtof) AM_maxOutWindowScale(); else AM_activateNewScale(); } // // // void AM_doFollowPlayer(void) { if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) { m_x = FTOM(MTOF(plr->mo->x)) - m_w/2; m_y = FTOM(MTOF(plr->mo->y)) - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; f_oldloc.x = plr->mo->x; f_oldloc.y = plr->mo->y; // m_x = FTOM(MTOF(plr->mo->x - m_w/2)); // m_y = FTOM(MTOF(plr->mo->y - m_h/2)); // m_x = plr->mo->x - m_w/2; // m_y = plr->mo->y - m_h/2; } } // // // void AM_updateLightLev(void) { static int nexttic = 0; //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 }; static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 }; static int litelevelscnt = 0; // Change light level if (amclock>nexttic) { lightlev = litelevels[litelevelscnt++]; if (litelevelscnt == arrlen(litelevels)) litelevelscnt = 0; nexttic = amclock + 6 - (amclock % 6); } } // // Updates on Game Tick // void AM_Ticker (void) { if (!automapactive) return; amclock++; if (followplayer) AM_doFollowPlayer(); // Change the zoom if necessary if (ftom_zoommul != FRACUNIT) AM_changeWindowScale(); // Change x,y location if (m_paninc.x || m_paninc.y) AM_changeWindowLoc(); // Update light level // AM_updateLightLev(); } // // Clear automap frame buffer. // void AM_clearFB(int color) { memset(fb, color, f_w*f_h); } // // Automap clipping of lines. // // Based on Cohen-Sutherland clipping algorithm but with a slightly // faster reject and precalculated slopes. If the speed is needed, // use a hash algorithm to handle the common cases. // boolean AM_clipMline ( mline_t* ml, fline_t* fl ) { enum { LEFT =1, RIGHT =2, BOTTOM =4, TOP =8 }; register int outcode1 = 0; register int outcode2 = 0; register int outside; fpoint_t tmp; int dx; int dy; #define DOOUTCODE(oc, mx, my) \ (oc) = 0; \ if ((my) < 0) (oc) |= TOP; \ else if ((my) >= f_h) (oc) |= BOTTOM; \ if ((mx) < 0) (oc) |= LEFT; \ else if ((mx) >= f_w) (oc) |= RIGHT; // do trivial rejects and outcodes if (ml->a.y > m_y2) outcode1 = TOP; else if (ml->a.y < m_y) outcode1 = BOTTOM; if (ml->b.y > m_y2) outcode2 = TOP; else if (ml->b.y < m_y) outcode2 = BOTTOM; if (outcode1 & outcode2) return false; // trivially outside if (ml->a.x < m_x) outcode1 |= LEFT; else if (ml->a.x > m_x2) outcode1 |= RIGHT; if (ml->b.x < m_x) outcode2 |= LEFT; else if (ml->b.x > m_x2) outcode2 |= RIGHT; if (outcode1 & outcode2) return false; // trivially outside // transform to frame-buffer coordinates. fl->a.x = CXMTOF(ml->a.x); fl->a.y = CYMTOF(ml->a.y); fl->b.x = CXMTOF(ml->b.x); fl->b.y = CYMTOF(ml->b.y); DOOUTCODE(outcode1, fl->a.x, fl->a.y); DOOUTCODE(outcode2, fl->b.x, fl->b.y); if (outcode1 & outcode2) return false; while (outcode1 | outcode2) { // may be partially inside box // find an outside point if (outcode1) outside = outcode1; else outside = outcode2; // clip to each side if (outside & TOP) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx*(fl->a.y))/dy; tmp.y = 0; } else if (outside & BOTTOM) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy; tmp.y = f_h-1; } else if (outside & RIGHT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx; tmp.x = f_w-1; } else if (outside & LEFT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; tmp.x = 0; } else { tmp.x = 0; tmp.y = 0; } if (outside == outcode1) { fl->a = tmp; DOOUTCODE(outcode1, fl->a.x, fl->a.y); } else { fl->b = tmp; DOOUTCODE(outcode2, fl->b.x, fl->b.y); } if (outcode1 & outcode2) return false; // trivially outside } return true; } #undef DOOUTCODE // // Classic Bresenham w/ whatever optimizations needed for speed // void AM_drawFline ( fline_t* fl, int color ) { register int x; register int y; register int dx; register int dy; register int sx; register int sy; register int ax; register int ay; register int d; static int fuck = 0; // For debugging only if ( fl->a.x < 0 || fl->a.x >= f_w || fl->a.y < 0 || fl->a.y >= f_h || fl->b.x < 0 || fl->b.x >= f_w || fl->b.y < 0 || fl->b.y >= f_h) { DEH_fprintf(stderr, "fuck %d \r", fuck++); return; } #define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) dx = fl->b.x - fl->a.x; ax = 2 * (dx<0 ? -dx : dx); sx = dx<0 ? -1 : 1; dy = fl->b.y - fl->a.y; ay = 2 * (dy<0 ? -dy : dy); sy = dy<0 ? -1 : 1; x = fl->a.x; y = fl->a.y; if (ax > ay) { d = ay - ax/2; while (1) { PUTDOT(x,y,color); if (x == fl->b.x) return; if (d>=0) { y += sy; d -= ax; } x += sx; d += ay; } } else { d = ax - ay/2; while (1) { PUTDOT(x, y, color); if (y == fl->b.y) return; if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; } } } // // Clip lines, draw visible part sof lines. // void AM_drawMline ( mline_t* ml, int color ) { static fline_t fl; if (AM_clipMline(ml, &fl)) AM_drawFline(&fl, color); // draws it on frame buffer using fb coords } // // Draws flat (floor/ceiling tile) aligned grid lines. // /*void AM_drawGrid(int color) { fixed_t x, y; fixed_t start, end; mline_t ml; // Figure out start of vertical gridlines start = m_x; if ((start-bmaporgx)%(MAPBLOCKUNITS<v1->x; l.a.y = line->v1->y; l.b.x = line->v2->x; l.b.y = line->v2->y; if(cheating || (line->flags & ML_MAPPED)) { if((line->flags & LINE_NEVERSEE) && !cheating) continue; // villsa [STRIFE] if(line->special == 145 || line->special == 186) { AM_drawMline(&l, SPWALLCOLORS); } // villsa [STRIFE] lightlev is unused here else if(!line->backsector) { AM_drawMline(&l, WALLCOLORS); } else { if(line->special == 39) { // teleporters AM_drawMline(&l, WALLCOLORS+WALLRANGE/2); } else if (line->flags & ML_SECRET) // secret door { // villsa [STRIFE] just draw the wall as is! AM_drawMline(&l, WALLCOLORS); } else if(line->backsector->floorheight != line->frontsector->floorheight) { AM_drawMline(&l, FDWALLCOLORS); // floor level change } else if(line->backsector->ceilingheight != line->frontsector->ceilingheight) { AM_drawMline(&l, CDWALLCOLORS); // ceiling level change } else if (cheating) { AM_drawMline(&l, TSWALLCOLORS); } } } // villsa [STRIFE] show all of the map on map 15 else if(plr->powers[pw_allmap] || gamemap == 15) { if(!(line->flags & LINE_NEVERSEE)) AM_drawMline(&l, CTWALLCOLORS); } } } // // Rotation in 2D. // Used to rotate player arrow line character. // void AM_rotate ( fixed_t* x, fixed_t* y, angle_t a ) { fixed_t tmpx; tmpx = FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT]) - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]); *y = FixedMul(*x,finesine[a>>ANGLETOFINESHIFT]) + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]); *x = tmpx; } void AM_drawLineCharacter ( mline_t* lineguy, int lineguylines, fixed_t scale, angle_t angle, int color, fixed_t x, fixed_t y ) { int i; mline_t l; for (i=0;imo->angle, 224, plr->mo->x, plr->mo->y); return; } for(i = 0; i < MAXPLAYERS; i++) { their_color++; p = &players[i]; // villsa [STRIFE] check for gameskill?? if((gameskill && deathmatch && !singledemo) && p != plr) continue; if(!playeringame[i]) continue; // villsa [STRIFE] change to 27 if(p->powers[pw_invisibility]) color = 27; // *close* to black else color = their_colors[their_color]; AM_drawLineCharacter (player_arrow, arrlen(player_arrow), 0, p->mo->angle, color, p->mo->x, p->mo->y); } } // // AM_drawThings // // villsa [STRIFE] no arguments // void AM_drawThings(void) { int i; mobj_t* t; int colors; fixed_t radius; // villsa [STRIFE] almost re-written // specific things can have different radius, color and appearence for(i = 0; i < numsectors; i++) { t = sectors[i].thinglist; while(t) { radius = t->radius; if(t->flags & (MF_MISSILE|MF_SPECIAL)) { colors = MISSILECOLORS; } else if(t->flags & MF_COUNTKILL) { colors = SHOOTABLECOLORS; } else { colors = THINGCOLORS; radius = (16<angle, colors, t->x, t->y); t = t->snext; } } } // // AM_drawMarks // void AM_drawMarks(void) { int i, fx, fy, w, h; for(i = 0; i < AM_NUMMARKPOINTS; i++) { if(markpoints[i].x != -1) { // w = SHORT(marknums[i]->width); // h = SHORT(marknums[i]->height); w = 5; // because something's wrong with the wad, i guess h = 6; // because something's wrong with the wad, i guess fx = CXMTOF(markpoints[i].x); fy = CYMTOF(markpoints[i].y); if(fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h) { // villsa [STRIFE] if(i >= mapmarknum) V_DrawPatch(fx, fy, marknums[i]); } } } } // villsa [STRIFE] unused /*void AM_drawCrosshair(int color) { fb[(f_w*(f_h+1))/2] = color; // single point for now }*/ void AM_Drawer (void) { if (!automapactive) return; AM_clearFB(BACKGROUND); // villsa [STRIFE] not used /*if(grid) AM_drawGrid(GRIDCOLORS);*/ AM_drawWalls(); AM_drawPlayers(); // villsa [STRIFE] draw things when map powerup is enabled if(cheating == 2 || plr->powers[pw_allmap] > 1) AM_drawThings(); // villsa [STRIFE] not used //AM_drawCrosshair(XHAIRCOLORS); AM_drawMarks(); V_MarkRect(f_x, f_y, f_w, f_h); } chocolate-doom-chocolate-doom-2.2.1/src/strife/am_map.h000066400000000000000000000023331257432200600227740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // AutoMap module. // #ifndef __AMMAP_H__ #define __AMMAP_H__ #include "d_event.h" #include "m_cheat.h" // Used by ST StatusBar stuff. #define AM_MSGHEADER (('a'<<24)+('m'<<16)) #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) #define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) // Called by main loop. boolean AM_Responder (event_t* ev); // Called by main loop. void AM_Ticker (void); // Called by main loop, // called instead of view drawer if automap active. void AM_Drawer (void); // Called to force the automap to quit // if the level is completed while it is up. void AM_Stop (void); extern cheatseq_t cheat_amap; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/d_englsh.h000066400000000000000000000442621257432200600233340ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Printed strings for translation. // English language support (default). // #ifndef __D_ENGLSH__ #define __D_ENGLSH__ // // Printed strings for translation // // // D_Main.C // #define D_DEVSTR "Development mode ON.\n" #define D_CDROM "CD-ROM Version: Accessing strife.cd\n" // // M_Menu.C // #define PRESSKEY "press a key." #define PRESSYN "press y or n." #define QUITMSG "are you sure you want to\nquit this great game?" // [STRIFE] modified: #define LOADNET "you can't load while in a net game!\n\n"PRESSKEY #define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY // [STRIFE] modified: #define QSAVESPOT "you haven't picked a\nquicksave slot yet!\n\n"PRESSKEY // [STRIFE] modified: #define SAVEDEAD "you're not playing a game\n\n"PRESSKEY #define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN // [STRIFE] modified: #define QLPROMPT "do you want to quickload\n\n'%s'?\n\n"PRESSYN #define NEWGAME \ "you can't start a new game\n"\ "while in a network game.\n\n"PRESSKEY #define NIGHTMARE \ "are you sure? this skill level\n"\ "isn't even remotely fair.\n\n"PRESSYN #define SWSTRING \ "this is the shareware version of doom.\n\n"\ "you need to order the entire trilogy.\n\n"PRESSKEY #define MSGOFF "Messages OFF" #define MSGON "Messages ON" #define NETEND "you can't end a netgame!\n\n"PRESSKEY #define ENDGAME "are you sure you want\nto end the game?\n\n"PRESSYN // haleyjd 09/11/10: [STRIFE] No "to dos." on this #define DOSY "(press y to quit)" #define DETAILHI "High detail" #define DETAILLO "Low detail" #define GAMMALVL0 "Gamma correction OFF" #define GAMMALVL1 "Gamma correction level 1" #define GAMMALVL2 "Gamma correction level 2" #define GAMMALVL3 "Gamma correction level 3" #define GAMMALVL4 "Gamma correction level 4" #define EMPTYSTRING "empty slot" // // P_inter.C // #define GOTARMOR "Picked up the armor." #define GOTMEGA "Picked up the MegaArmor!" #define GOTHTHBONUS "Picked up a health bonus." #define GOTARMBONUS "Picked up an armor bonus." #define GOTSTIM "Picked up a stimpack." #define GOTMEDINEED "Picked up a medikit that you REALLY need!" #define GOTMEDIKIT "Picked up a medikit." #define GOTSUPER "Supercharge!" #define GOTBLUECARD "Picked up a blue keycard." #define GOTYELWCARD "Picked up a yellow keycard." #define GOTREDCARD "Picked up a red keycard." #define GOTBLUESKUL "Picked up a blue skull key." #define GOTYELWSKUL "Picked up a yellow skull key." #define GOTREDSKULL "Picked up a red skull key." #define GOTINVUL "Invulnerability!" #define GOTBERSERK "Berserk!" #define GOTINVIS "Partial Invisibility" #define GOTSUIT "Radiation Shielding Suit" #define GOTMAP "Computer Area Map" #define GOTVISOR "Light Amplification Visor" #define GOTMSPHERE "MegaSphere!" #define GOTCLIP "Picked up a clip." #define GOTCLIPBOX "Picked up a box of bullets." #define GOTROCKET "Picked up a rocket." #define GOTROCKBOX "Picked up a box of rockets." #define GOTCELL "Picked up an energy cell." #define GOTCELLBOX "Picked up an energy cell pack." #define GOTSHELLS "Picked up 4 shotgun shells." #define GOTSHELLBOX "Picked up a box of shotgun shells." #define GOTBACKPACK "Picked up a backpack full of ammo!" #define GOTBFG9000 "You got the BFG9000! Oh, yes." #define GOTCHAINGUN "You got the chaingun!" #define GOTCHAINSAW "A chainsaw! Find some meat!" #define GOTLAUNCHER "You got the rocket launcher!" #define GOTPLASMA "You got the plasma gun!" #define GOTSHOTGUN "You got the shotgun!" #define GOTSHOTGUN2 "You got the super shotgun!" // // P_Doors.C // #define PD_BLUEO "You need a blue key to activate this object" #define PD_REDO "You need a red key to activate this object" #define PD_YELLOWO "You need a yellow key to activate this object" #define PD_BLUEK "You need a blue key to open this door" #define PD_REDK "You need a red key to open this door" #define PD_YELLOWK "You need a yellow key to open this door" // // G_game.C // #define GGSAVED "game saved." // // HU_stuff.C // #define HUSTR_MSGU "[Message unsent]" // haleyjd 08/31/10: [STRIFE] Strife map names #define HUSTR_1 "AREA 1: sanctuary" #define HUSTR_2 "AREA 2: town" #define HUSTR_3 "AREA 3: front base" #define HUSTR_4 "AREA 4: power station" #define HUSTR_5 "AREA 5: prison" #define HUSTR_6 "AREA 6: sewers" #define HUSTR_7 "AREA 7: castle" #define HUSTR_8 "AREA 8: Audience Chamber" #define HUSTR_9 "AREA 9: Castle: Programmer's Keep" #define HUSTR_10 "AREA 10: New Front Base" #define HUSTR_11 "AREA 11: Borderlands" #define HUSTR_12 "AREA 12: the temple of the oracle" #define HUSTR_13 "AREA 13: Catacombs" #define HUSTR_14 "AREA 14: mines" #define HUSTR_15 "AREA 15: Fortress: Administration" #define HUSTR_16 "AREA 16: Fortress: Bishop's Tower" #define HUSTR_17 "AREA 17: Fortress: The Bailey" #define HUSTR_18 "AREA 18: Fortress: Stores" #define HUSTR_19 "AREA 19: Fortress: Security Complex" #define HUSTR_20 "AREA 20: Factory: Receiving" #define HUSTR_21 "AREA 21: Factory: Manufacturing" #define HUSTR_22 "AREA 22: Factory: Forge" #define HUSTR_23 "AREA 23: Order Commons" #define HUSTR_24 "AREA 24: Factory: Conversion Chapel" #define HUSTR_25 "AREA 25: Catacombs: Ruined Temple" #define HUSTR_26 "AREA 26: proving grounds" #define HUSTR_27 "AREA 27: The Lab" #define HUSTR_28 "AREA 28: Alien Ship" #define HUSTR_29 "AREA 29: Entity's Lair" #define HUSTR_30 "AREA 30: Abandoned Front Base" #define HUSTR_31 "AREA 31: Training Facility" #define HUSTR_32 "AREA 1: Sanctuary" #define HUSTR_33 "AREA 2: Town" #define HUSTR_34 "AREA 3: Movement Base" // haleyjd 20110219: [STRIFE] replaced all with Strife chat macros: #define HUSTR_CHATMACRO1 "Fucker!" #define HUSTR_CHATMACRO2 "--SPLAT-- Instant wall art." #define HUSTR_CHATMACRO3 "That had to hurt!" #define HUSTR_CHATMACRO4 "Smackings!" #define HUSTR_CHATMACRO5 "Gib-O-Matic baby." #define HUSTR_CHATMACRO6 "Burn! Yah! Yah!" #define HUSTR_CHATMACRO7 "Buh-Bye!" #define HUSTR_CHATMACRO8 "Sizzle chest!" #define HUSTR_CHATMACRO9 "That sucked!" #define HUSTR_CHATMACRO0 "Mommy?" #define HUSTR_TALKTOSELF1 "You mumble to yourself" #define HUSTR_TALKTOSELF2 "Who's there?" #define HUSTR_TALKTOSELF3 "You scare yourself" #define HUSTR_TALKTOSELF4 "You start to rave" #define HUSTR_TALKTOSELF5 "You've lost it..." #define HUSTR_MESSAGESENT "[Message Sent]" // The following should NOT be changed unless it seems // just AWFULLY necessary // [STRIFE]: Not used, as strings are local to hu_stuff.c //#define HUSTR_PLRGREEN "Green: " //#define HUSTR_PLRINDIGO "Indigo: " //#define HUSTR_PLRBROWN "Brown: " //#define HUSTR_PLRRED "Red: " #define HUSTR_KEYGREEN 'g' #define HUSTR_KEYINDIGO 'i' #define HUSTR_KEYBROWN 'b' #define HUSTR_KEYRED 'r' // // AM_map.C // #define AMSTR_FOLLOWON "Follow Mode ON" #define AMSTR_FOLLOWOFF "Follow Mode OFF" #define AMSTR_GRIDON "Grid ON" #define AMSTR_GRIDOFF "Grid OFF" #define AMSTR_MARKEDSPOT "Marked Spot" #define AMSTR_MARKSCLEARED "Last Mark Cleared" // [STRIFE] // // ST_stuff.C // #define STSTR_MUS "Music Change" #define STSTR_NOMUS "IMPOSSIBLE SELECTION" #define STSTR_DQDON "You're Invincible!" // [STRIFE] #define STSTR_DQDOFF "You're a looney!" // [STRIFE] #define STSTR_KFAADDED "Very Happy Ammo Added" #define STSTR_FAADDED "Ammo Added" // [STRIFE] #define STSTR_NCON "No Clipping Mode ON" #define STSTR_NCOFF "No Clipping Mode OFF" #define STSTR_BEHOLD "Bzrk, Inviso, Mask, Health, Pack, Stats" // [STRIFE] #define STSTR_BEHOLDX "Power-up Toggled" #define STSTR_CHOPPERS "... doesn't suck - GM" #define STSTR_CLEV "Changing Level..." // // F_Finale.C // #define E1TEXT \ "Once you beat the big badasses and\n"\ "clean out the moon base you're supposed\n"\ "to win, aren't you? Aren't you? Where's\n"\ "your fat reward and ticket home? What\n"\ "the hell is this? It's not supposed to\n"\ "end this way!\n"\ "\n" \ "It stinks like rotten meat, but looks\n"\ "like the lost Deimos base. Looks like\n"\ "you're stuck on The Shores of Hell.\n"\ "The only way out is through.\n"\ "\n"\ "To continue the DOOM experience, play\n"\ "The Shores of Hell and its amazing\n"\ "sequel, Inferno!\n" #define E2TEXT \ "You've done it! The hideous cyber-\n"\ "demon lord that ruled the lost Deimos\n"\ "moon base has been slain and you\n"\ "are triumphant! But ... where are\n"\ "you? You clamber to the edge of the\n"\ "moon and look down to see the awful\n"\ "truth.\n" \ "\n"\ "Deimos floats above Hell itself!\n"\ "You've never heard of anyone escaping\n"\ "from Hell, but you'll make the bastards\n"\ "sorry they ever heard of you! Quickly,\n"\ "you rappel down to the surface of\n"\ "Hell.\n"\ "\n" \ "Now, it's on to the final chapter of\n"\ "DOOM! -- Inferno." #define E3TEXT \ "The loathsome spiderdemon that\n"\ "masterminded the invasion of the moon\n"\ "bases and caused so much death has had\n"\ "its ass kicked for all time.\n"\ "\n"\ "A hidden doorway opens and you enter.\n"\ "You've proven too tough for Hell to\n"\ "contain, and now Hell at last plays\n"\ "fair -- for you emerge from the door\n"\ "to see the green fields of Earth!\n"\ "Home at last.\n" \ "\n"\ "You wonder what's been happening on\n"\ "Earth while you were battling evil\n"\ "unleashed. It's good that no Hell-\n"\ "spawn could have come through that\n"\ "door with you ..." #define E4TEXT \ "the spider mastermind must have sent forth\n"\ "its legions of hellspawn before your\n"\ "final confrontation with that terrible\n"\ "beast from hell. but you stepped forward\n"\ "and brought forth eternal damnation and\n"\ "suffering upon the horde as a true hero\n"\ "would in the face of something so evil.\n"\ "\n"\ "besides, someone was gonna pay for what\n"\ "happened to daisy, your pet rabbit.\n"\ "\n"\ "but now, you see spread before you more\n"\ "potential pain and gibbitude as a nation\n"\ "of demons run amok among our cities.\n"\ "\n"\ "next stop, hell on earth!" // after level 6, put this: #define C1TEXT \ "YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \ "STARPORT. BUT SOMETHING IS WRONG. THE\n" \ "MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \ "WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \ "IS BEING SUBVERTED BY THEIR PRESENCE.\n" \ "\n"\ "AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \ "FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \ "YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \ "OF THE STARBASE AND FIND THE CONTROLLING\n" \ "SWITCH WHICH HOLDS EARTH'S POPULATION\n" \ "HOSTAGE." // After level 11, put this: #define C2TEXT \ "YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \ "HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\ "THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\ "HUMAN LEFT ON THE FACE OF THE PLANET.\n"\ "CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\ "AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\ "YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\ "THAT YOU HAVE SAVED YOUR SPECIES.\n"\ "\n"\ "BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\ "MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\ "THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\ "GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\ "ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\ "YOUR OWN HOME CITY, NOT FAR FROM THE\n"\ "STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\ "UP AND RETURN TO THE FRAY." // After level 20, put this: #define C3TEXT \ "YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\ "SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\ "YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\ "ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\ "TEETH AND PLUNGE THROUGH IT.\n"\ "\n"\ "THERE MUST BE A WAY TO CLOSE IT ON THE\n"\ "OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\ "GOT TO GO THROUGH HELL TO GET TO IT?" // After level 29, put this: #define C4TEXT \ "THE HORRENDOUS VISAGE OF THE BIGGEST\n"\ "DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\ "YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\ "HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\ "UP AND DIES, ITS THRASHING LIMBS\n"\ "DEVASTATING UNTOLD MILES OF HELL'S\n"\ "SURFACE.\n"\ "\n"\ "YOU'VE DONE IT. THE INVASION IS OVER.\n"\ "EARTH IS SAVED. HELL IS A WRECK. YOU\n"\ "WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\ "DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\ "FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\ "HOME. REBUILDING EARTH OUGHT TO BE A\n"\ "LOT MORE FUN THAN RUINING IT WAS.\n" // Before level 31, put this: #define C5TEXT \ "CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\ "LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\ "HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\ "WHO THE INMATES OF THIS CORNER OF HELL\n"\ "WILL BE." // Before level 32, put this: #define C6TEXT \ "CONGRATULATIONS, YOU'VE FOUND THE\n"\ "SUPER SECRET LEVEL! YOU'D BETTER\n"\ "BLAZE THROUGH THIS ONE!\n" // after map 06 #define P1TEXT \ "You gloat over the steaming carcass of the\n"\ "Guardian. With its death, you've wrested\n"\ "the Accelerator from the stinking claws\n"\ "of Hell. You relax and glance around the\n"\ "room. Damn! There was supposed to be at\n"\ "least one working prototype, but you can't\n"\ "see it. The demons must have taken it.\n"\ "\n"\ "You must find the prototype, or all your\n"\ "struggles will have been wasted. Keep\n"\ "moving, keep fighting, keep killing.\n"\ "Oh yes, keep living, too." // after map 11 #define P2TEXT \ "Even the deadly Arch-Vile labyrinth could\n"\ "not stop you, and you've gotten to the\n"\ "prototype Accelerator which is soon\n"\ "efficiently and permanently deactivated.\n"\ "\n"\ "You're good at that kind of thing." // after map 20 #define P3TEXT \ "You've bashed and battered your way into\n"\ "the heart of the devil-hive. Time for a\n"\ "Search-and-Destroy mission, aimed at the\n"\ "Gatekeeper, whose foul offspring is\n"\ "cascading to Earth. Yeah, he's bad. But\n"\ "you know who's worse!\n"\ "\n"\ "Grinning evilly, you check your gear, and\n"\ "get ready to give the bastard a little Hell\n"\ "of your own making!" // after map 30 #define P4TEXT \ "The Gatekeeper's evil face is splattered\n"\ "all over the place. As its tattered corpse\n"\ "collapses, an inverted Gate forms and\n"\ "sucks down the shards of the last\n"\ "prototype Accelerator, not to mention the\n"\ "few remaining demons. You're done. Hell\n"\ "has gone back to pounding bad dead folks \n"\ "instead of good live ones. Remember to\n"\ "tell your grandkids to put a rocket\n"\ "launcher in your coffin. If you go to Hell\n"\ "when you die, you'll need it for some\n"\ "final cleaning-up ..." // before map 31 #define P5TEXT \ "You've found the second-hardest level we\n"\ "got. Hope you have a saved game a level or\n"\ "two previous. If not, be prepared to die\n"\ "aplenty. For master marines only." // before map 32 #define P6TEXT \ "Betcha wondered just what WAS the hardest\n"\ "level we had ready for ya? Now you know.\n"\ "No one gets out alive." #define T1TEXT \ "You've fought your way out of the infested\n"\ "experimental labs. It seems that UAC has\n"\ "once again gulped it down. With their\n"\ "high turnover, it must be hard for poor\n"\ "old UAC to buy corporate health insurance\n"\ "nowadays..\n"\ "\n"\ "Ahead lies the military complex, now\n"\ "swarming with diseased horrors hot to get\n"\ "their teeth into you. With luck, the\n"\ "complex still has some warlike ordnance\n"\ "laying around." #define T2TEXT \ "You hear the grinding of heavy machinery\n"\ "ahead. You sure hope they're not stamping\n"\ "out new hellspawn, but you're ready to\n"\ "ream out a whole herd if you have to.\n"\ "They might be planning a blood feast, but\n"\ "you feel about as mean as two thousand\n"\ "maniacs packed into one mad killer.\n"\ "\n"\ "You don't plan to go down easy." #define T3TEXT \ "The vista opening ahead looks real damn\n"\ "familiar. Smells familiar, too -- like\n"\ "fried excrement. You didn't like this\n"\ "place before, and you sure as hell ain't\n"\ "planning to like it now. The more you\n"\ "brood on it, the madder you get.\n"\ "Hefting your gun, an evil grin trickles\n"\ "onto your face. Time to take some names." #define T4TEXT \ "Suddenly, all is silent, from one horizon\n"\ "to the other. The agonizing echo of Hell\n"\ "fades away, the nightmare sky turns to\n"\ "blue, the heaps of monster corpses start \n"\ "to evaporate along with the evil stench \n"\ "that filled the air. Jeeze, maybe you've\n"\ "done it. Have you really won?\n"\ "\n"\ "Something rumbles in the distance.\n"\ "A blue light begins to glow inside the\n"\ "ruined skull of the demon-spitter." #define T5TEXT \ "What now? Looks totally different. Kind\n"\ "of like King Tut's condo. Well,\n"\ "whatever's here can't be any worse\n"\ "than usual. Can it? Or maybe it's best\n"\ "to let sleeping gods lie.." #define T6TEXT \ "Time for a vacation. You've burst the\n"\ "bowels of hell and by golly you're ready\n"\ "for a break. You mutter to yourself,\n"\ "Maybe someone else can kick Hell's ass\n"\ "next time around. Ahead lies a quiet town,\n"\ "with peaceful flowing water, quaint\n"\ "buildings, and presumably no Hellspawn.\n"\ "\n"\ "As you step off the transport, you hear\n"\ "the stomp of a cyberdemon's iron shoe." // // Character cast strings F_FINALE.C // #define CC_ZOMBIE "ZOMBIEMAN" #define CC_SHOTGUN "SHOTGUN GUY" #define CC_HEAVY "HEAVY WEAPON DUDE" #define CC_IMP "IMP" #define CC_DEMON "DEMON" #define CC_LOST "LOST SOUL" #define CC_CACO "CACODEMON" #define CC_HELL "HELL KNIGHT" #define CC_BARON "BARON OF HELL" #define CC_ARACH "ARACHNOTRON" #define CC_PAIN "PAIN ELEMENTAL" #define CC_REVEN "REVENANT" #define CC_MANCU "MANCUBUS" #define CC_ARCH "ARCH-VILE" #define CC_SPIDER "THE SPIDER MASTERMIND" #define CC_CYBER "THE CYBERDEMON" #define CC_HERO "OUR HERO" #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/d_items.c000066400000000000000000000052751257432200600231710ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // We are referring to sprite numbers. #include "info.h" #include "d_items.h" // // PSPRITE ACTIONS for waepons. // This struct controls the weapon animations. // // Each entry is: // ammo/amunition type // upstate // downstate // readystate // atkstate, i.e. attack/fire/hit frame // flashstate, muzzle flash // // villsa [STRIFE] weaponinfo_t weaponinfo[NUMWEAPONS] = { { // fist am_noammo, S_PNCH_03, S_PNCH_02, S_PNCH_01, S_PNCH_04, S_NULL, 1 }, { // electric bow am_elecbolts, S_XBOW_02, S_XBOW_01, S_XBOW_00, S_XBOW_03, S_NULL, 1 }, { // rifle am_bullets, S_RIFG_02, S_RIFG_01, S_RIFG_00, S_RIFF_00, S_NULL, 1 }, { // missile launcher am_missiles, S_MMIS_02, S_MMIS_01, S_MMIS_00, S_MMIS_03, S_NULL, 0 }, { // grenade launcher am_hegrenades, S_GREN_02, S_GREN_01, S_GREN_00, S_GREN_03, S_GREF_00, 0 }, { // flame thrower am_cell, S_FLMT_03, S_FLMT_02, S_FLMT_00, S_FLMF_00, S_NULL, 1 }, { // mauler am_cell, S_BLST_05, S_BLST_04, S_BLST_00, S_BLSF_00, S_NULL, 0 }, { // sigil am_noammo, S_SIGH_06, S_SIGH_05, S_SIGH_00, S_SIGH_07, S_SIGF_00, 0 }, { // poison bow am_poisonbolts, S_XBOW_15, S_XBOW_14, S_XBOW_13, S_XBOW_16, S_NULL, 1 }, { // wp grenade launcher am_wpgrenades, S_GREN_10, S_GREN_09, S_GREN_08, S_GREN_11, S_GREF_03, 0 }, { // torpedo am_cell, S_BLST_18, S_BLST_17, S_BLST_13, S_BLST_19, S_NULL, 0 }, }; chocolate-doom-chocolate-doom-2.2.1/src/strife/d_items.h000066400000000000000000000020221257432200600231610ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Items: key cards, artifacts, weapon, ammunition. // #ifndef __D_ITEMS__ #define __D_ITEMS__ #include "doomdef.h" // Weapon info: sprite frames, ammunition use. typedef struct { ammotype_t ammo; int upstate; int downstate; int readystate; int atkstate; int flashstate; boolean availabledemo; // villsa [STRIFE] } weaponinfo_t; extern weaponinfo_t weaponinfo[NUMWEAPONS]; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/d_main.c000066400000000000000000001441141257432200600227700ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM main program (D_DoomMain) and game loop (D_DoomLoop), // plus functions to determine game mode (shareware, registered), // parse command line parameters, configure game parameters (turbo), // and call the startup functions. // #include #include #include #include #include "config.h" #include "deh_main.h" #include "doomdef.h" #include "doomstat.h" #include "dstrings.h" #include "doomfeatures.h" #include "sounds.h" #include "d_iwad.h" #include "z_zone.h" #include "w_main.h" #include "w_wad.h" #include "s_sound.h" #include "v_video.h" #include "f_finale.h" #include "f_wipe.h" #include "m_argv.h" #include "m_config.h" #include "m_controls.h" #include "m_misc.h" #include "m_menu.h" #include "m_saves.h" // haleyjd [STRIFE] #include "p_saveg.h" #include "p_dialog.h" // haleyjd [STRIFE] #include "i_endoom.h" #include "i_joystick.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "i_swap.h" #include "g_game.h" #include "hu_stuff.h" #include "wi_stuff.h" #include "st_stuff.h" #include "am_map.h" #include "net_client.h" #include "net_dedicated.h" #include "net_query.h" #include "p_setup.h" #include "r_local.h" #include "d_main.h" // // D-DoomLoop() // Not a globally visible function, // just included for source reference, // called by D_DoomMain, never exits. // Manages timing and IO, // calls all ?_Responder, ?_Ticker, and ?_Drawer, // calls I_GetTime, I_StartFrame, and I_StartTic // void D_DoomLoop (void); static boolean D_AddFile(char *filename); // Location where savegames are stored char * savegamedir; // location of IWAD and WAD files char * iwadfile; boolean devparm; // started game with -devparm boolean nomonsters; // checkparm of -nomonsters boolean respawnparm; // checkparm of -respawn boolean fastparm; // checkparm of -fast boolean flipparm; // [STRIFE] haleyjd 20110629: checkparm of -flip boolean randomparm; // [STRIFE] haleyjd 20130915: checkparm of -random boolean showintro = true; // [STRIFE] checkparm of -nograph, disables intro //extern int soundVolume; //extern int sfxVolume; //extern int musicVolume; extern boolean inhelpscreens; skill_t startskill; int startepisode; int startmap; boolean autostart; int startloadgame; boolean advancedemo; // villsa [STRIFE] workparm variable (similar to devparm?) boolean workparm = false; // villsa [STRIFE] stonecold cheat variable boolean stonecold = false; // haleyjd 09/11/10: [STRIFE] Game type variables boolean isregistered; boolean isdemoversion; // Store demo, do not accept any inputs // haleyjd [STRIFE] Unused. //boolean storedemo; char wadfile[1024]; // primary wad file char mapdir[1024]; // directory of development maps int show_endoom = 1; int graphical_startup = 1; // If true, startup has completed and the main game loop has started. static boolean main_loop_started = false; // fraggle 06/03/11 [STRIFE]: Unused config variable, preserved // for compatibility: static int comport = 0; // fraggle 06/03/11 [STRIFE]: Multiplayer nickname? char *nickname = NULL; void D_ConnectNetGame(void); void D_CheckNetGame(void); // // D_ProcessEvents // Send all the events of the given timestamp down the responder chain // void D_ProcessEvents (void) { event_t* ev; // haleyjd 08/22/2010: [STRIFE] there is no such thing as a "store demo" // version of Strife // IF STORE DEMO, DO NOT ACCEPT INPUT //if (storedemo) // return; while ((ev = D_PopEvent()) != NULL) { if (M_Responder (ev)) continue; // menu ate the event G_Responder (ev); } } // // D_Display // draw current display, possibly wiping it from the previous // // wipegamestate can be set to -1 to force a wipe on the next draw // // haleyjd 08/23/10: [STRIFE]: // * Changes to eliminate intermission and change timing of screenwipe // * 20100901: Added ST_DrawExternal and popupactivestate static variable // * 20110206: Start wipegamestate at GS_UNKNOWN (STRIFE-TODO: rename?) // gamestate_t wipegamestate = GS_UNKNOWN; extern boolean setsizeneeded; //extern int showMessages; [STRIFE] no such variable void R_ExecuteSetViewSize (void); void D_Display (void) { static boolean viewactivestate = false; static boolean menuactivestate = false; static boolean inhelpscreensstate = false; static boolean popupactivestate = false; // [STRIFE] static boolean fullscreen = false; static gamestate_t oldgamestate = -1; static int borderdrawcount; int nowtime; int tics; int wipestart; int y; boolean done; boolean wipe; boolean redrawsbar; if (nodrawers) return; // for comparative timing / profiling redrawsbar = false; // change the view size if needed if (setsizeneeded) { R_ExecuteSetViewSize (); oldgamestate = -1; // force background redraw borderdrawcount = 3; } // save the current screen if about to wipe if (gamestate != wipegamestate) { wipe = true; wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); } else wipe = false; if (gamestate == GS_LEVEL && gametic) HU_Erase(); // do buffered drawing switch (gamestate) { case GS_LEVEL: if (!gametic) break; if (automapactive) AM_Drawer (); if (wipe || (viewheight != 200 && fullscreen) ) redrawsbar = true; // haleyjd 08/29/10: [STRIFE] Always redraw sbar if menu is/was active if (menuactivestate || (inhelpscreensstate && !inhelpscreens)) redrawsbar = true; // just put away the help screen ST_Drawer (viewheight == 200, redrawsbar ); fullscreen = viewheight == 200; break; // haleyjd 08/23/2010: [STRIFE] No intermission /* case GS_INTERMISSION: WI_Drawer (); break; */ case GS_FINALE: F_Drawer (); break; case GS_DEMOSCREEN: D_PageDrawer (); break; default: break; } // draw buffered stuff to screen I_UpdateNoBlit (); // draw the view directly if (gamestate == GS_LEVEL && !automapactive && gametic) R_RenderPlayerView (&players[displayplayer]); // clean up border stuff if (gamestate != oldgamestate && gamestate != GS_LEVEL) I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE)); // see if the border needs to be initially drawn if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL) { viewactivestate = false; // view was not active R_FillBackScreen (); // draw the pattern into the back screen } // see if the border needs to be updated to the screen if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320) { if (menuactive || menuactivestate || !viewactivestate) { borderdrawcount = 3; popupactivestate = false; } if (borderdrawcount) { R_DrawViewBorder (); // erase old menu stuff borderdrawcount--; } } if (testcontrols) { // Box showing current mouse speed V_DrawMouseSpeedBox(testcontrols_mousespeed); } menuactivestate = menuactive; viewactivestate = viewactive; inhelpscreensstate = inhelpscreens; oldgamestate = wipegamestate = gamestate; // haleyjd 20120208: [STRIFE] Rogue moved this down to below border drawing if (gamestate == GS_LEVEL && gametic) { HU_Drawer (); if(ST_DrawExternal()) popupactivestate = true; else if(popupactivestate) { popupactivestate = false; menuactivestate = 1; } } // draw pause pic if (paused) { if (automapactive) y = 4; else y = viewwindowy+4; V_DrawPatchDirect(viewwindowx + (scaledviewwidth - 68) / 2, y, W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE)); } // menus go directly to the screen M_Drawer (); // menu is drawn even on top of everything NetUpdate (); // send out any new accumulation // normal update if (!wipe) { I_FinishUpdate (); // page flip or blit buffer return; } // wipe update wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); wipestart = I_GetTime () - 1; do { do { nowtime = I_GetTime (); tics = nowtime - wipestart; I_Sleep(1); } while (tics < 3); // haleyjd 08/23/2010: [STRIFE] Changed from == 0 to < 3 // haleyjd 08/26/10: [STRIFE] Changed to use ColorXForm wipe. wipestart = nowtime; done = wipe_ScreenWipe(wipe_ColorXForm , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics); I_UpdateNoBlit (); M_Drawer (); // menu is drawn even on top of wipes I_FinishUpdate (); // page flip or blit buffer } while (!done); } // // Add configuration file variable bindings. // void D_BindVariables(void) { int i; M_ApplyPlatformDefaults(); I_BindVideoVariables(); I_BindJoystickVariables(); I_BindSoundVariables(); M_BindBaseControls(); M_BindWeaponControls(); M_BindMapControls(); M_BindMenuControls(); M_BindStrifeControls(); // haleyjd 09/01/10: [STRIFE] M_BindChatControls(MAXPLAYERS); // haleyjd 20130915: Strife chat keys key_multi_msgplayer[0] = '1'; key_multi_msgplayer[1] = '2'; key_multi_msgplayer[2] = '3'; key_multi_msgplayer[3] = '4'; key_multi_msgplayer[4] = '5'; key_multi_msgplayer[5] = '6'; key_multi_msgplayer[6] = '7'; key_multi_msgplayer[7] = '8'; #ifdef FEATURE_MULTIPLAYER NET_BindVariables(); #endif // haleyjd 08/29/10: [STRIFE] // * Added voice volume // * Added back flat // * Removed show_messages // * Added show_talk // fraggle 03/06/10: [STRIFE] // * Removed detailLevel // * screenblocks -> screensize // * Added nickname, comport M_BindIntVariable("mouse_sensitivity", &mouseSensitivity); M_BindIntVariable("sfx_volume", &sfxVolume); M_BindIntVariable("music_volume", &musicVolume); M_BindIntVariable("voice_volume", &voiceVolume); M_BindIntVariable("show_talk", &dialogshowtext); M_BindIntVariable("screensize", &screenblocks); M_BindIntVariable("snd_channels", &snd_channels); M_BindIntVariable("vanilla_savegame_limit", &vanilla_savegame_limit); M_BindIntVariable("vanilla_demo_limit", &vanilla_demo_limit); M_BindIntVariable("show_endoom", &show_endoom); M_BindIntVariable("graphical_startup", &graphical_startup); M_BindStringVariable("back_flat", &back_flat); M_BindStringVariable("nickname", &nickname); M_BindIntVariable("comport", &comport); // Multiplayer chat macros for (i=0; i<10; ++i) { char buf[12]; M_snprintf(buf, sizeof(buf), "chatmacro%i", i); M_BindStringVariable(buf, &chat_macros[i]); } } // // D_GrabMouseCallback // // Called to determine whether to grab the mouse pointer // boolean D_GrabMouseCallback(void) { // Drone players don't need mouse focus if (drone) return false; // when menu is active or game is paused, release the mouse. if (menuactive || paused) return false; // only grab mouse when playing levels (but not demos) return (gamestate == GS_LEVEL) && !demoplayback; } // During startup, never grab the mouse. static boolean D_StartupGrabCallback(void) { return false; } // // D_DoomLoop // // haleyjd 08/23/10: [STRIFE] Verified unmodified. // void D_DoomLoop (void) { if (demorecording) G_BeginRecording (); main_loop_started = true; TryRunTics(); if (!showintro) { I_SetWindowTitle(gamedescription); I_InitGraphics(); } I_EnableLoadingDisk(); I_SetGrabMouseCallback(D_GrabMouseCallback); V_RestoreBuffer(); R_ExecuteSetViewSize(); D_StartGameLoop(); if (testcontrols) { wipegamestate = gamestate; } while (1) { // frame syncronous IO operations I_StartFrame (); // process one or more tics TryRunTics (); // will run at least one tic S_UpdateSounds (players[consoleplayer].mo);// move positional sounds // Update display, next frame, with current state. if (screenvisible) D_Display (); } } // // DEMO LOOP // int demosequence; int pagetic; char *pagename; // // D_PageTicker // Handles timing for warped projection // // haleyjd 08/22/2010: [STRIFE] verified unmodified // void D_PageTicker (void) { if (--pagetic < 0) D_AdvanceDemo (); } // // D_PageDrawer // // haleyjd 08/22/2010: [STRIFE] verified unmodified // void D_PageDrawer (void) { V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE)); } // // D_AdvanceDemo // Called after each demo or intro demosequence finishes // // haleyjd 08/22/2010: [STRIFE] verified unmodified // void D_AdvanceDemo (void) { advancedemo = true; } // // This cycles through the demo sequences. // FIXME - version dependend demo numbers? // // [STRIFE] Modified for the opening slideshow and the exit screen // void D_DoAdvanceDemo (void) { players[consoleplayer].playerstate = PST_LIVE; // not reborn advancedemo = false; usergame = false; // no save / end game here paused = false; gameaction = ga_nothing; // villsa 09/12/10: [STRIFE] converted pagetics to ticrate switch (demosequence) { case -5: // exit the game I_Quit(); return; case -4: // show exit screen menuactive = false; pagetic = 3*TICRATE; gamestate = GS_DEMOSCREEN; pagename = DEH_String("PANEL7"); S_StartMusic(mus_fast); if(isdemoversion) demosequence = -3; // show Velocity logo else demosequence = -5; // exit return; case -3: // show Velocity logo for demo version pagetic = 6*TICRATE; gamestate = GS_DEMOSCREEN; pagename = DEH_String("vellogo"); demosequence = -5; // exit return; case -2: // title screen pagetic = 6*TICRATE; gamestate = GS_DEMOSCREEN; pagename = DEH_String("TITLEPIC"); S_StartMusic(mus_logo); demosequence = -1; // start intro cinematic return; case -1: // start of intro cinematic pagetic = 10; gamestate = GS_DEMOSCREEN; pagename = DEH_String("PANEL0"); S_StartSound(NULL, sfx_rb2act); wipegamestate = -1; break; case 0: // Rogue logo pagetic = 4*TICRATE; gamestate = GS_DEMOSCREEN; pagename = DEH_String("RGELOGO"); wipegamestate = -1; break; case 1: pagetic = 7*TICRATE; // The comet struck our planet without gamestate = GS_DEMOSCREEN; // warning.We lost our paradise in a pagename = DEH_String("PANEL1"); // single, violent stroke. I_StartVoice(DEH_String("pro1")); S_StartMusic(mus_intro); break; case 2: pagetic = 9*TICRATE; // The impact released a virus which gamestate = GS_DEMOSCREEN; // swept through the land and killed pagename = DEH_String("PANEL2"); // millions. They turned out to be I_StartVoice(DEH_String("pro2")); // the lucky ones... break; case 3: pagetic = 12*TICRATE; // For those that did not die became gamestate = GS_DEMOSCREEN; // mutations of humanity. Some became pagename = DEH_String("PANEL3"); // fanatics who heard the voice of a I_StartVoice(DEH_String("pro3")); // malignant God in their heads, and break; // called themselves the Order. case 4: pagetic = 11*TICRATE; // Those of us who were deaf to this pagename = DEH_String("PANEL4"); // voice suffer horribly and are gamestate = GS_DEMOSCREEN; // forced to serve these ruthless I_StartVoice(DEH_String("pro4")); // psychotics, who wield weapons more break; // powerful than anything we can muster. case 5: pagetic = 10*TICRATE; // They destroy our women and children, gamestate = GS_DEMOSCREEN; // so that we must hide them underground, pagename = DEH_String("PANEL5"); // and live like animals in constant I_StartVoice(DEH_String("pro5")); // fear for our lives. break; case 6: // But there are whispers of discontent. pagetic = 16*TICRATE; // If we organize, can we defeat our gamestate = GS_DEMOSCREEN; // masters? Weapons are being stolen, pagename = DEH_String("PANEL6"); // soldiers are being trained. A I_StartVoice(DEH_String("pro6")); // Movement is born! Born of lifelong break; // STRIFE! case 7: // titlepic again - unused... pagetic = 9*TICRATE; gamestate = GS_DEMOSCREEN; pagename = DEH_String("TITLEPIC"); wipegamestate = -1; break; case 8: // demo ClearTmp(); pagetic = 9*TICRATE; G_DeferedPlayDemo(DEH_String("demo1")); break; case 9: // velocity logo? - unused... pagetic = 6*TICRATE; gamestate = GS_DEMOSCREEN; pagename = DEH_String("vellogo"); wipegamestate = -1; break; case 10: // credits gamestate = GS_DEMOSCREEN; pagetic = 12*TICRATE; pagename = DEH_String("CREDIT"); wipegamestate = -1; break; default: break; } ++demosequence; if(demosequence > 11) demosequence = -2; if(demosequence == 7 || demosequence == 9) ++demosequence; } // // D_StartTitle // // [STRIFE] // haleyjd 09/11/10: Small modifications for new demo sequence. // void D_StartTitle (void) { gamestate = GS_DEMOSCREEN; gameaction = ga_nothing; demosequence = -2; D_AdvanceDemo (); } // // D_QuitGame // // [STRIFE] New function // haleyjd 09/11/10: Sets up the quit game snippet powered by the // demo sequence. // void D_QuitGame(void) { gameaction = ga_nothing; demosequence = -4; D_AdvanceDemo(); } // Strings for dehacked replacements of the startup banner // // These are from the original source: some of them are perhaps // not used in any dehacked patches static char *banners[] = { // strife1.wad: " " "STRIFE: Quest for the Sigil v1.2" " " }; // // Get game name: if the startup banner has been replaced, use that. // Otherwise, use the name given // static char *GetGameName(char *gamename) { size_t i; char *deh_sub; for (i=0; i 1996 || date.day > 15 && date.month > 4) I_Error("Data error! Corrupted WAD File!"); serial_year = serialnum / 10000; serial_month = serialnum / 100 - 100 * serial_year; if(date.year < serial_year || date.day < serialnum - 100 * serial_month - 10000 * serial_year && date.month < serial_month) I_Error("Bad wadfile"); } #endif // Set the gamedescription string void D_SetGameDescription(void) { gamedescription = GetGameName("Strife: Quest for the Sigil"); } // print title for every printed line char title[128]; static boolean D_AddFile(char *filename) { wad_file_t *handle; printf(" adding %s\n", filename); handle = W_AddFile(filename); return handle != NULL; } // Copyright message banners // Some dehacked mods replace these. These are only displayed if they are // replaced by dehacked. // haleyjd 08/22/2010: [STRIFE] altered to match strings from binary static char *copyright_banners[] = { "===========================================================================\n" "ATTENTION: This version of STRIFE has extra files added to it.\n" " You will not receive technical support for modified games.\n" "===========================================================================\n", "===========================================================================\n" " This version is NOT SHAREWARE, do not distribute!\n" " Please report software piracy to the SPA: 1-800-388-PIR8\n" "===========================================================================\n", "===========================================================================\n" " Shareware!\n" "===========================================================================\n" }; // Prints a message only if it has been modified by dehacked. void PrintDehackedBanners(void) { size_t i; for (i=0; i // @category compat // // Emulate a specific version of Strife. Valid values are "1.2" and "1.31". // p = M_CheckParmWithArgs("-gameversion", 1); if (p) { for (i=0; gameversions[i].description != NULL; ++i) { if (!strcmp(myargv[p+1], gameversions[i].cmdline)) { gameversion = gameversions[i].version; break; } } if (gameversions[i].description == NULL) { printf("Supported game versions:\n"); for (i=0; gameversions[i].description != NULL; ++i) { printf("\t%s (%s)\n", gameversions[i].cmdline, gameversions[i].description); } I_Error("Unknown game version '%s'", myargv[p+1]); } } else { gameversion = exe_strife_1_31; } } void PrintGameVersion(void) { int i; for (i=0; gameversions[i].description != NULL; ++i) { if (gameversions[i].version == gameversion) { printf("Emulating the behavior of the " "'%s' executable.\n", gameversions[i].description); break; } } } // Function called at exit to display the ENDOOM screen static void D_Endoom(void) { byte *endoom; // Don't show ENDOOM if we have it disabled, or we're running // in screensaver or control test mode. Only show it once the // game has actually started. if (!show_endoom || !main_loop_started || screensaver_mode || testcontrols) { return; } // haleyjd 08/27/10: [STRIFE] ENDOOM -> ENDSTRF endoom = W_CacheLumpName(DEH_String("ENDSTRF"), PU_STATIC); I_Endoom(endoom); } //============================================================================= // // haleyjd: Chocolate Strife Specifics // // None of the code in here is from the original executable, but is needed for // other reasons. // // D_PatchClipCallback // // haleyjd 08/28/10: Clip patches to the framebuffer without errors. // Returns false if V_DrawPatch should return without drawing. // boolean D_PatchClipCallback(patch_t *patch, int x, int y) { // note that offsets were already accounted for in V_DrawPatch return (x >= 0 && y >= 0 && x + SHORT(patch->width) <= SCREENWIDTH && y + SHORT(patch->height) <= SCREENHEIGHT); } // // D_InitChocoStrife // // haleyjd 08/28/10: Take care of some Strife-specific initialization // that is necessitated by Chocolate Doom issues, such as setting global // callbacks. // static void D_InitChocoStrife(void) { // set the V_DrawPatch clipping callback V_SetPatchClipCallback(D_PatchClipCallback); } // // STRIFE Graphical Intro Sequence // #define MAXINTROPROGRESS 69 static int introprogress; // track the progress of the intro static byte *rawgfx_startup0; // raw linear gfx for intro static byte *rawgfx_startp[4]; static byte *rawgfx_startlz[2]; static byte *rawgfx_startbot; // // D_IntroBackground // // [STRIFE] New function // haleyjd 20110206: Strife only drew this once, but for supporting double- // buffered or page-flipped surfaces it is best to redraw the entire screen // every frame. // static void D_IntroBackground(void) { if(!showintro) return; // Fill the background entirely (wasn't needed in vanilla) V_DrawFilledBox(0, 0, SCREENWIDTH, SCREENHEIGHT, 0); // Strife cleared the screen somewhere in the low-level code between the // intro and the titlescreen, so this is to take care of that and get // proper fade-in behavior on the titlescreen if(introprogress >= MAXINTROPROGRESS) { I_FinishUpdate(); return; } // Draw a 95-pixel rect from STARTUP0 starting at y=57 to (0,41) on the // screen (this was a memcpy directly to 0xA3340 in low DOS memory) V_DrawBlock(0, 41, 320, 95, rawgfx_startup0 + (320*57)); } // // D_InitIntroSequence // // [STRIFE] New function // haleyjd 20110206: Initialize the graphical introduction sequence // static void D_InitIntroSequence(void) { if(showintro) { // In vanilla Strife, Mode 13h was initialized directly in D_DoomMain. // We have to be a little more courteous of the low-level code here. I_SetWindowTitle(gamedescription); I_SetGrabMouseCallback(D_StartupGrabCallback); I_InitGraphics(); V_RestoreBuffer(); // make the V_ routines work // Load all graphics rawgfx_startup0 = W_CacheLumpName("STARTUP0", PU_STATIC); rawgfx_startp[0] = W_CacheLumpName("STRTPA1", PU_STATIC); rawgfx_startp[1] = W_CacheLumpName("STRTPB1", PU_STATIC); rawgfx_startp[2] = W_CacheLumpName("STRTPC1", PU_STATIC); rawgfx_startp[3] = W_CacheLumpName("STRTPD1", PU_STATIC); rawgfx_startlz[0] = W_CacheLumpName("STRTLZ1", PU_STATIC); rawgfx_startlz[1] = W_CacheLumpName("STRTLZ2", PU_STATIC); rawgfx_startbot = W_CacheLumpName("STRTBOT", PU_STATIC); // Draw the background D_IntroBackground(); } /* // STRIFE-FIXME: This was actually displayed on a special textmode // screen with ANSI color codes... would require use of textlib to // emulate properly... else { puts(DEH_String("Conversation ON")); puts(DEH_String("Rogue Entertainment")); puts(DEH_String("and")); puts(DEH_String("Velocity Games")); puts(DEH_String("present")); puts(DEH_String("S T R I F E")); puts(DEH_String("Loading...")); } */ } // // D_DrawIntroSequence // // [STRIFE] New function // haleyjd 20110206: Refresh the intro sequence // static void D_DrawIntroSequence(void) { int laserpos; int robotpos; if(!showintro) return; D_IntroBackground(); // haleyjd: refresh the background // Laser position laserpos = (200 * introprogress / MAXINTROPROGRESS) + 60; // BUG: (?) Due to this clip, the laser never even comes close to // touching the peasant; confirmed with vanilla. This MAY have been // intentional, for effect, however, since no death frames are shown // either... kind of a black-out death. if(laserpos > 200) laserpos = 200; // Draw the laser // Blitted 16 bytes for 16 rows starting at 705280 + laserpos // (705280 - 0xA0000) / 320 == 156 V_DrawBlock(laserpos, 156, 16, 16, rawgfx_startlz[laserpos % 2]); // Robot position robotpos = laserpos % 5 - 2; // Draw the robot // Blitted 48 bytes for 48 rows starting at 699534 + (320*robotpos) // 699534 - 0xA0000 == 44174, which % 320 == 14, / 320 == 138 V_DrawBlock(14, 138 + robotpos, 48, 48, rawgfx_startbot); // Draw the peasant // Blitted 32 bytes for 64 rows starting at 699142 // 699142 - 0xA0000 == 43782, which % 320 == 262, / 320 == 136 V_DrawBlock(262, 136, 32, 64, rawgfx_startp[laserpos % 4]); I_FinishUpdate(); } // // D_IntroTick // // Advance the intro sequence // void D_IntroTick(void) { static boolean didsound = false; // haleyjd 20120209 if(devparm) return; ++introprogress; if(introprogress >= MAXINTROPROGRESS) { D_IntroBackground(); // haleyjd: clear the bg anyway // haleyjd 20120209: This isn't 100% true to vanilla because vanilla // would play this sound a half-dozen times. BUT, in vanilla, for // whatever reason, under DMX, playing the same sound multiple times // doesn't add up violently like it does under SDL_mixer. This means // that without this one-time limitation, the sound is far too loud. if(!didsound) { S_StartSound(NULL, sfx_psdtha); didsound = true; } } else D_DrawIntroSequence(); } // // End Chocolate Strife Specifics // //============================================================================= static void G_CheckDemoStatusAtExit (void) { G_CheckDemoStatus(); } // // D_DoomMain // void D_DoomMain (void) { int p; char file[256]; char demolumpname[9]; I_AtExit(D_Endoom, false); // haleyjd 20110206 [STRIFE]: -nograph parameter //! // @vanilla // // Disable graphical introduction sequence // if (M_ParmExists("-nograph")) showintro = false; // Undocumented: // Invoked by setup to test the controls. if (M_ParmExists("-testcontrols")) { testcontrols = true; showintro = false; } // haleyjd 20110206: Moved up -devparm for max visibility //! // @vanilla // // Developer mode. Implies -nograph. // devparm = M_CheckParm ("-devparm"); // print banner I_PrintBanner(PACKAGE_STRING); //DEH_printf("Z_Init: Init zone memory allocation daemon. \n"); [STRIFE] removed Z_Init (); #ifdef FEATURE_MULTIPLAYER //! // @category net // // Start a dedicated server, routing packets but not participating // in the game itself. // if (M_CheckParm("-dedicated") > 0) { printf("Dedicated server mode.\n"); NET_DedicatedServer(); // Never returns } //! // @category net // // Query the Internet master server for a global list of active // servers. // if (M_CheckParm("-search")) { NET_MasterQuery(); exit(0); } //! // @arg
// @category net // // Query the status of the server running on the given IP // address. // p = M_CheckParmWithArgs("-query", 1); if (p) { NET_QueryAddress(myargv[p+1]); exit(0); } //! // @category net // // Search the local LAN for running servers. // if (M_CheckParm("-localsearch")) { NET_LANQuery(); exit(0); } #endif //! // @vanilla // // Disable monsters. // nomonsters = M_CheckParm ("-nomonsters"); //! // @vanilla // // Set Rogue playtesting mode (godmode, noclip toggled by backspace) // workparm = M_CheckParm ("-work"); //! // @vanilla // // Flip player gun sprites (broken). // flipparm = M_CheckParm ("-flip"); //! // @vanilla // // Respawn monsters after they are killed. // respawnparm = M_CheckParm ("-respawn"); //! // @vanilla // // Items respawn at random locations // randomparm = M_CheckParm ("-random"); //! // @vanilla // // Monsters move faster. // fastparm = M_CheckParm ("-fast"); I_DisplayFPSDots(devparm); // haleyjd 20110206 [STRIFE]: -devparm implies -nograph if(devparm) showintro = false; // Note: Vanilla Strife does not understand the -deathmatch command // line parameter. deathmatch=1 is the default behavior when // playing a netgame. //! // @category net // @vanilla // // Start a deathmatch game. Weapons do not stay in place and // all items respawn after 30 seconds. // if (M_CheckParm ("-altdeath")) deathmatch = 2; if (devparm) DEH_printf(D_DEVSTR); // find which dir to use for config files #ifdef _WIN32 //! // @platform windows // @vanilla // // Save configuration data and savegames in c:\strife.cd, // allowing play from CD. // if (M_CheckParm("-cdrom") > 0) { printf(D_CDROM); // haleyjd 08/22/2010: [STRIFE] Use strife.cd folder for -cdrom M_SetConfigDir("c:\\strife.cd\\"); } else #endif { // Auto-detect the configuration dir. M_SetConfigDir(NULL); } //! // @arg // @vanilla // // Turbo mode. The player's speed is multiplied by x%. If unspecified, // x defaults to 200. Values are rounded up to 10 and down to 400. // if ( (p=M_CheckParm ("-turbo")) ) { int scale = 200; extern int forwardmove[2]; extern int sidemove[2]; if (p 400) scale = 400; DEH_printf("turbo scale: %i%%\n", scale); forwardmove[0] = forwardmove[0]*scale/100; forwardmove[1] = forwardmove[1]*scale/100; sidemove[0] = sidemove[0]*scale/100; sidemove[1] = sidemove[1]*scale/100; } // init subsystems // DEH_printf("V_Init: allocate screens.\n"); [STRIFE] removed V_Init (); // Load configuration files before initialising other subsystems. // haleyjd 08/22/2010: [STRIFE] - use strife.cfg // DEH_printf("M_LoadDefaults: Load system defaults.\n"); [STRIFE] removed M_SetConfigFilenames("strife.cfg", PROGRAM_PREFIX "strife.cfg"); D_BindVariables(); M_LoadDefaults(); if (!graphical_startup) { showintro = false; } // Save configuration at exit. I_AtExit(M_SaveDefaults, false); // Find the main IWAD file and load it. iwadfile = D_FindIWAD(IWAD_MASK_STRIFE, &gamemission); // None found? if (iwadfile == NULL) { I_Error("Game mode indeterminate. No IWAD file was found. Try\n" "specifying one with the '-iwad' command line parameter.\n"); } modifiedgame = false; if(devparm) // [STRIFE] Devparm only DEH_printf("W_Init: Init WADfiles.\n"); D_AddFile(iwadfile); W_CheckCorrectIWAD(strife); #ifdef FEATURE_DEHACKED // Load dehacked patches specified on the command line. DEH_ParseCommandLine(); #endif // Load PWAD files. modifiedgame = W_ParseCommandLine(); // [STRIFE] serial number output if(devparm) { char msgbuf[80]; char *serial = W_CacheLumpName("SERIAL", PU_CACHE); int serialnum = atoi(serial); DEH_snprintf(msgbuf, sizeof(msgbuf), "Wad Serial Number: %d:", serialnum); printf("%s\n", msgbuf); } // add any files specified on the command line with -file wadfile // to the wad list // // Debug: // W_PrintDirectory(); //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp. // p = M_CheckParmWithArgs ("-playdemo", 1); if (!p) { //! // @arg // @category demo // @vanilla // // Play back the demo named demo.lmp, determining the framerate // of the screen. // p = M_CheckParmWithArgs("-timedemo", 1); } if (p) { char *uc_filename = strdup(myargv[p + 1]); M_ForceUppercase(uc_filename); // With Vanilla you have to specify the file without extension, // but make that optional. if (M_StringEndsWith(uc_filename, ".LMP")) { M_StringCopy(file, myargv[p + 1], sizeof(file)); } else { DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p+1]); } free(uc_filename); if (D_AddFile (file)) { M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name, sizeof(demolumpname)); } else { // If file failed to load, still continue trying to play // the demo in the same way as Vanilla Doom. This makes // tricks like "-playdemo demo1" possible. M_StringCopy(demolumpname, myargv[p + 1], sizeof(demolumpname)); } printf("Playing demo %s.\n", file); } I_AtExit(G_CheckDemoStatusAtExit, true); // Generate the WAD hash table. Speed things up a bit. W_GenerateHashTable(); D_IdentifyVersion(); InitGameVersion(); D_SetGameDescription(); savegamedir = M_GetSaveGameDir("strife1.wad"); // fraggle 20130405: I_InitTimer is needed here for the netgame // startup. Start low-level sound init here too. I_InitTimer(); I_InitSound(true); I_InitMusic(); #ifdef FEATURE_MULTIPLAYER if(devparm) // [STRIFE] printf ("NET_Init: Init network subsystem.\n"); NET_Init(); #endif D_ConnectNetGame(); // haleyjd 20110210: Create Strife hub save folders M_CreateSaveDirs(savegamedir); I_GraphicsCheckCommandLine(); // haleyjd 20110206 [STRIFE] Startup the introduction sequence D_InitIntroSequence(); // haleyjd 20110924: moved S_Init up to here if(devparm) // [STRIFE] DEH_printf("S_Init: Setting up sound.\n"); S_Init (sfxVolume * 8, musicVolume * 8, voiceVolume * 8); // [STRIFE]: voice D_IntroTick(); // [STRIFE] // Check for -file in shareware if (modifiedgame) { // These are the lumps that will be checked in IWAD, // if any one is not present, execution will be aborted. // haleyjd 08/22/2010: [STRIFE] Check for Strife lumps. char name[3][8]= { "map23", "map30", "ROB3E1" }; int i; // haleyjd 08/22/2010: [STRIFE] Changed string to match binary // STRIFE-FIXME: Needs to test isdemoversion variable if ( gamemode == shareware) I_Error(DEH_String("\nYou cannot -file with the demo " "version. You must buy the real game!")); // Check for fake IWAD with right name, // but w/o all the lumps of the registered version. // STRIFE-FIXME: Needs to test isregistered variable if (gamemode == registered) for (i = 0; i < 3; i++) if (W_CheckNumForName(name[i])<0) I_Error(DEH_String("\nThis is not the registered version.")); } D_IntroTick(); // [STRIFE] // get skill / episode / map from parms startskill = sk_easy; // [STRIFE]: inits to sk_easy startepisode = 1; startmap = 1; autostart = false; //! // @arg // @vanilla // // Set the game skill, 1-5 (1: easiest, 5: hardest). A skill of // 0 disables all monsters. // p = M_CheckParmWithArgs("-skill", 1); if (p) { startskill = myargv[p+1][0]-'1'; autostart = true; } // [STRIFE] no such thing in Strife // // // @arg // // @vanilla // // // // Start playing on episode n (1-4) // // // p = M_CheckParmWithArgs("-episode", 1); // if (p) // { // startepisode = myargv[p+1][0]-'0'; // startmap = 1; // autostart = true; // } timelimit = 0; //! // @arg // @category net // @vanilla // // For multiplayer games: exit each level after n minutes. // p = M_CheckParmWithArgs("-timer", 1); if (p) { timelimit = atoi(myargv[p+1]); printf("timer: %i\n", timelimit); } //! // @category net // @vanilla // // Austin Virtual Gaming: end levels after 20 minutes. // p = M_CheckParm ("-avg"); if (p) { timelimit = 20; } //! // @arg x // @vanilla // // Start a game immediately, warping to level x. // p = M_CheckParmWithArgs("-warp", 1); if (p) { if (gamemode == commercial) startmap = atoi (myargv[p+1]); else { startepisode = myargv[p+1][0]-'0'; if (p + 2 < myargc) { startmap = myargv[p+2][0]-'0'; } else { startmap = 1; } } autostart = true; } if (testcontrols) { startepisode = 1; startmap = 3; autostart = true; } // Check for load game parameter // We do this here and save the slot number, so that the network code // can override it or send the load slot to other players. //! // @arg // @vanilla // // Load the game in slot s. // p = M_CheckParmWithArgs("-loadgame", 1); if (p) { startloadgame = atoi(myargv[p+1]); } else { // Not loading a game startloadgame = -1; } if (W_CheckNumForName("SS_START") >= 0 || W_CheckNumForName("FF_END") >= 0) { I_PrintDivider(); printf(" WARNING: The loaded WAD file contains modified sprites or\n" " floor textures. You may want to use the '-merge' command\n" " line option instead of '-file'.\n"); } I_PrintStartupBanner(gamedescription); PrintDehackedBanners(); // haleyjd 08/28/10: Init Choco Strife stuff. D_InitChocoStrife(); // haleyjd 08/22/2010: [STRIFE] Modified string to match binary if(devparm) // [STRIFE] DEH_printf("R_Init: Loading Graphics - "); R_Init (); D_IntroTick(); // [STRIFE] if(devparm) // [STRIFE] DEH_printf("\nP_Init: Init Playloop state.\n"); P_Init (); D_IntroTick(); // [STRIFE] if(devparm) // [STRIFE] DEH_printf("I_Init: Setting up machine state.\n"); I_CheckIsScreensaver(); I_InitJoystick(); D_IntroTick(); // [STRIFE] D_IntroTick(); // [STRIFE] if(devparm) // [STRIFE] DEH_printf("M_Init: Init Menu.\n"); M_Init (); D_IntroTick(); // [STRIFE] // haleyjd 20110924: Moved S_Init up. D_IntroTick(); // haleyjd 20110220: This stuff was done in I_StartupSound in vanilla, but // we'll do it here instead so we don't have to modify the low-level shared // code with Strife-specific stuff. //! // @vanilla // // Disable voice dialog and show dialog as text instead, // even if voices.wad can be found. // if(disable_voices || M_CheckParm("-novoice")) { dialogshowtext = disable_voices = 1; } if(devparm) DEH_printf(" Play voices = %d\n", disable_voices == 0); if(devparm) // [STRIFE] DEH_printf("D_CheckNetGame: Checking network game status.\n"); D_CheckNetGame (); PrintGameVersion(); if(devparm) DEH_printf("HU_Init: Setting up heads up display.\n"); HU_Init (); D_IntroTick(); // [STRIFE] if(devparm) DEH_printf("ST_Init: Init status bar.\n"); ST_Init (); D_IntroTick(); // [STRIFE] // haleyjd [STRIFE] -statcopy used to be here... D_IntroTick(); // [STRIFE] // If Doom II without a MAP01 lump, this is a store demo. // Moved this here so that MAP01 isn't constantly looked up // in the main loop. // haleyjd 08/23/2010: [STRIFE] There is no storedemo version of Strife /* if (gamemode == commercial && W_CheckNumForName("map01") < 0) storedemo = true; */ //! // @arg // @category demo // @vanilla // // Record a demo named x.lmp. // p = M_CheckParmWithArgs("-record", 1); if (p) { G_RecordDemo (myargv[p+1]); autostart = true; } D_IntroTick(); // [STRIFE] p = M_CheckParmWithArgs("-playdemo", 1); if (p) { singledemo = true; // quit after one demo G_DeferedPlayDemo (demolumpname); D_DoomLoop (); // never returns } D_IntroTick(); // [STRIFE] p = M_CheckParmWithArgs("-timedemo", 1); if (p) { G_TimeDemo (demolumpname); D_DoomLoop (); // never returns } D_IntroTick(); // [STRIFE] if (startloadgame >= 0) { // [STRIFE]: different, for hubs M_LoadSelect(startloadgame); } D_IntroTick(); // [STRIFE] if (gameaction != ga_loadgame ) { if (autostart || netgame) G_InitNew (startskill, startmap); else D_StartTitle (); // start up intro loop } D_DoomLoop (); // never returns } chocolate-doom-chocolate-doom-2.2.1/src/strife/d_main.h000066400000000000000000000024531257432200600227740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // #ifndef __D_MAIN__ #define __D_MAIN__ #include "doomdef.h" // Read events from all input devices void D_ProcessEvents (void); // // BASE LEVEL // void D_PageTicker (void); void D_PageDrawer (void); void D_AdvanceDemo (void); void D_DoAdvanceDemo (void); void D_StartTitle (void); void D_QuitGame (void); // [STRIFE] void D_IntroTick(void); // [STRIFE] // // GLOBAL VARIABLES // extern gameaction_t gameaction; extern boolean isregistered; // villsa [STRIFE] extern boolean isdemoversion; // haleyjd [STRIFE] extern boolean stonecold; // villsa [STRIFE] extern boolean workparm; // villsa [STRIFE] #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/d_net.c000066400000000000000000000154031257432200600226300ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM Network game communication and protocol, // all OS independend parts. // #include #include "doomfeatures.h" #include "d_main.h" #include "m_argv.h" #include "m_menu.h" #include "m_misc.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "g_game.h" #include "doomdef.h" #include "doomstat.h" #include "w_checksum.h" #include "deh_main.h" #include "d_loop.h" ticcmd_t *netcmds; // Called when a player leaves the game static void PlayerQuitGame(player_t *player) { static char exitmsg[80]; unsigned int player_num; player_num = player - players; // Do this the same way as Vanilla Doom does, to allow dehacked // replacements of this message M_StringCopy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg)); exitmsg[7] += player_num; playeringame[player_num] = false; players[consoleplayer].message = exitmsg; // TODO: check if it is sensible to do this: if (demorecording) { G_CheckDemoStatus (); } } static void RunTic(ticcmd_t *cmds, boolean *ingame) { extern boolean advancedemo; unsigned int i; // Check for player quits. for (i = 0; i < MAXPLAYERS; ++i) { if (!demoplayback && playeringame[i] && !ingame[i]) { PlayerQuitGame(&players[i]); } } netcmds = cmds; // check that there are players in the game. if not, we cannot // run a tic. if (advancedemo) D_DoAdvanceDemo (); M_Ticker(); G_Ticker(); } static void NullMenuTicker() { // no-op. } static loop_interface_t strife_loop_interface = { D_ProcessEvents, G_BuildTiccmd, RunTic, NullMenuTicker }; // Load game settings from the specified structure and // set global variables. static void LoadGameSettings(net_gamesettings_t *settings) { unsigned int i; deathmatch = settings->deathmatch; ticdup = settings->ticdup; startepisode = settings->episode; startmap = settings->map; startskill = settings->skill; startloadgame = settings->loadgame; lowres_turn = settings->lowres_turn; nomonsters = settings->nomonsters; fastparm = settings->fast_monsters; respawnparm = settings->respawn_monsters; timelimit = settings->timelimit; consoleplayer = settings->consoleplayer; randomparm = settings->random; if (lowres_turn) { printf("NOTE: Turning resolution is reduced; this is probably " "because there is a client recording a Vanilla demo.\n"); } for (i = 0; i < MAXPLAYERS; ++i) { playeringame[i] = i < settings->num_players; } } // Save the game settings from global variables to the specified // game settings structure. static void SaveGameSettings(net_gamesettings_t *settings) { // Fill in game settings structure with appropriate parameters // for the new game settings->deathmatch = deathmatch; settings->episode = startepisode; settings->map = startmap; settings->skill = startskill; settings->loadgame = startloadgame; settings->gameversion = gameversion; settings->nomonsters = nomonsters; settings->fast_monsters = fastparm; settings->respawn_monsters = respawnparm; settings->timelimit = timelimit; settings->random = randomparm; settings->lowres_turn = M_ParmExists("-record") && !M_ParmExists("-longtics"); } static void InitConnectData(net_connect_data_t *connect_data) { connect_data->drone = false; connect_data->max_players = MAXPLAYERS; //! // @category net // // Run as the left screen in three screen mode. // if (M_CheckParm("-left") > 0) { viewangleoffset = ANG90; connect_data->drone = true; } //! // @category net // // Run as the right screen in three screen mode. // if (M_CheckParm("-right") > 0) { viewangleoffset = ANG270; connect_data->drone = true; } // // Connect data // // Game type fields: connect_data->gamemode = gamemode; connect_data->gamemission = gamemission; // Are we recording a demo? Possibly set lowres turn mode connect_data->lowres_turn = M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0; // Read checksums of our WAD directory and dehacked information W_Checksum(connect_data->wad_sha1sum); DEH_Checksum(connect_data->deh_sha1sum); connect_data->is_freedoom = 0; } void D_ConnectNetGame(void) { net_connect_data_t connect_data; InitConnectData(&connect_data); netgame = D_InitNetGame(&connect_data); //! // @category net // // Start the game playing as though in a netgame with a single // player. This can also be used to play back single player netgame // demos. // if (M_CheckParm("-solo-net") > 0) { netgame = true; } } // // D_CheckNetGame // Works out player numbers among the net participants // void D_CheckNetGame(void) { net_gamesettings_t settings; D_RegisterLoopCallbacks(&strife_loop_interface); if (netgame) { autostart = true; } SaveGameSettings(&settings); D_StartNetGame(&settings, NULL); LoadGameSettings(&settings); // Strife games are always deathmatch, though -altdeath is // supported for respawning items. if (netgame && deathmatch == 0) { deathmatch = 1; } DEH_printf("startmap: %i, skill: %i, enemies: %i, random: %i\n", startmap, startskill, !nomonsters, randomparm); DEH_printf("player %i of %i (%i nodes)\n", consoleplayer+1, settings.num_players, settings.num_players); // Show players here; the server might have specified a time limit if (timelimit > 0 && deathmatch) { // Gross hack to work like Vanilla: if (timelimit == 20 && M_CheckParm("-avg")) { DEH_printf("Austin Virtual Gaming: Levels will end " "after 20 minutes\n"); } else { DEH_printf("Levels will end after %d minute", timelimit); if (timelimit > 1) printf("s"); printf(".\n"); } } } chocolate-doom-chocolate-doom-2.2.1/src/strife/d_player.h000066400000000000000000000137411257432200600233460ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __D_PLAYER__ #define __D_PLAYER__ // The player data structure depends on a number // of other structs: items (internal inventory), // animation states (closely tied to the sprites // used to represent them, unfortunately). #include "d_items.h" #include "p_pspr.h" // In addition, the player is just a special // case of the generic moving object/actor. #include "p_mobj.h" // Finally, for odd reasons, the player input // is buffered within the player data struct, // as commands per game tick. #include "d_ticcmd.h" #include "net_defs.h" // // Player states. // typedef enum { // Playing or camping. PST_LIVE, // Dead on the ground, view follows killer. PST_DEAD, // Ready to restart/respawn??? PST_REBORN } playerstate_t; // // Player internal flags, for cheats and debug. // typedef enum { // No clipping, walk through barriers. CF_NOCLIP = 1, // No damage, no health loss. CF_GODMODE = 2, // Not really a cheat, just a debug aid. CF_NOMOMENTUM = 4, // villsa [STRIFE] new cheat // set when on fire and disable inventory CF_ONFIRE = 8, // villsa [STRIFE] new cheat // auto-use medkits CF_AUTOHEALTH = 16 } cheat_t; // haleyjd 08/30/10: [STRIFE] // Player Inventory Item Structure typedef struct inventory_s { int sprite; // a sprite number int type; // a thing type int amount; // amount being carried } inventory_t; #define NUMINVENTORY 32 // // Extended player object info: player_t // // haleyjd 08/30/10: [STRIFE] // * Transformed to match binary structure layout. // typedef struct player_s { mobj_t* mo; playerstate_t playerstate; ticcmd_t cmd; // Determine POV, // including viewpoint bobbing during movement. // Focal origin above r.z fixed_t viewz; // Base height above floor for viewz. fixed_t viewheight; // Bob/squat speed. fixed_t deltaviewheight; // bounded/scaled total momentum. fixed_t bob; // This is only used between levels, // mo->health is used during levels. int health; short armorpoints; // [STRIFE] Changed to short // Armor type is 0-2. short armortype; // [STRIFE] Changed to short // Power ups. invinc and invis are tic counters. int powers[NUMPOWERS]; // [STRIFE] Additions: int sigiltype; // Type of Sigil carried int nukagecount; // Nukage exposure counter int questflags; // Quest bit flags int pitch; // Up/down look angle boolean centerview; // True if view should be centered inventory_t inventory[NUMINVENTORY]; // Player inventory items boolean st_update; // If true, update status bar short numinventory; // Num. active inventory items short inventorycursor; // Selected inventory item short accuracy; // Accuracy stat short stamina; // Stamina stat boolean cards[NUMCARDS]; boolean backpack; // True if button down last tic. int attackdown; int usedown; int inventorydown; // [STRIFE] Use inventory item // Frags, kills of other players. int frags[MAXPLAYERS]; weapontype_t readyweapon; // Is wp_nochange if not changing. weapontype_t pendingweapon; boolean weaponowned[NUMWEAPONS]; int ammo[NUMAMMO]; int maxammo[NUMAMMO]; // Bit flags, for cheats and debug. // See cheat_t, above. int cheats; // Refired shots are less accurate. int refire; // For intermission stats. short killcount; // [STRIFE] Changed to short //int itemcount; // [STRIFE] Eliminated these. //int secretcount; // Hint messages. char* message; // For screen flashing (red or bright). int damagecount; int bonuscount; // Who did damage (NULL for floors/ceilings). mobj_t* attacker; // So gun flashes light up areas. int extralight; // Current PLAYPAL, ??? // can be set to REDCOLORMAP for pain, etc. int fixedcolormap; // Player skin colorshift, // 0-3 for which color to draw player. //int colormap; [STRIFE] no such? or did it become the below? // [STRIFE] For use of teleport beacons short allegiance; // Overlay view sprites (gun, etc). pspdef_t psprites[NUMPSPRITES]; // [STRIFE] Inefficient means of tracking automap state on all maps boolean mapstate[40]; // True if secret level has been done. //boolean didsecret; [STRIFE] Removed this. } player_t; // // INTERMISSION // Structure passed e.g. to WI_Start(wb) // typedef struct { boolean in; // whether the player is in game // Player stats, kills, collected items etc. int skills; int sitems; int ssecret; int stime; int frags[4]; int score; // current score on entry, modified on return } wbplayerstruct_t; typedef struct { int epsd; // episode # (0-2) // if true, splash the secret level boolean didsecret; // previous and next levels, origin 0 int last; int next; int maxkills; int maxitems; int maxsecret; int maxfrags; // the par time int partime; // index of this player in game int pnum; wbplayerstruct_t plyr[MAXPLAYERS]; } wbstartstruct_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/d_textur.h000066400000000000000000000016401257432200600234000ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Typedefs related to to textures etc., // isolated here to make it easier separating modules. // #ifndef __D_TEXTUR__ #define __D_TEXTUR__ #include "doomtype.h" // // Flats? // // a pic is an unmasked block of pixels typedef struct { byte width; byte height; byte data; } pic_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/d_think.h000066400000000000000000000027111257432200600231620ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // MapObj data. Map Objects or mobjs are actors, entities, // thinker, take-your-pick... anything that moves, acts, or // suffers state changes of more or less violent nature. // #ifndef __D_THINK__ #define __D_THINK__ // // Experimental stuff. // To compile this as "ANSI C with classes" // we will need to handle the various // action functions cleanly. // typedef void (*actionf_v)(); typedef void (*actionf_p1)( void* ); typedef void (*actionf_p2)( void*, void* ); typedef union { actionf_v acv; actionf_p1 acp1; actionf_p2 acp2; } actionf_t; // Historically, "think_t" is yet another // function pointer to a routine to handle // an actor. typedef actionf_t think_t; // Doubly linked list of actors. typedef struct thinker_s { struct thinker_s* prev; struct thinker_s* next; think_t function; } thinker_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/deh_ammo.c000066400000000000000000000044271257432200600233140ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Ammo" sections in dehacked files // #include #include #include #include "doomdef.h" #include "doomtype.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "p_local.h" static void *DEH_AmmoStart(deh_context_t *context, char *line) { int ammo_number = 0; if (sscanf(line, "Ammo %i", &ammo_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (ammo_number < 0 || ammo_number >= NUMAMMO) { DEH_Warning(context, "Invalid ammo number: %i", ammo_number); return NULL; } return &maxammo[ammo_number]; } static void DEH_AmmoParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; int ivalue; int ammo_number; if (tag == NULL) return; ammo_number = ((int *) tag) - maxammo; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); // maxammo if (!strcasecmp(variable_name, "Per ammo")) clipammo[ammo_number] = ivalue; else if (!strcasecmp(variable_name, "Max ammo")) maxammo[ammo_number] = ivalue; else { DEH_Warning(context, "Field named '%s' not found", variable_name); } } static void DEH_AmmoSHA1Hash(sha1_context_t *context) { int i; for (i=0; i #include #include "doomtype.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "am_map.h" #include "st_stuff.h" typedef struct { char *name; cheatseq_t *seq; } deh_cheat_t; static deh_cheat_t allcheats[] = { // haleyjd 20110224: filled in all cheats {"Change music", &cheat_mus }, {"Level Warp", &cheat_clev }, {"Stealth Boots", &cheat_stealth }, {"Sigil piece", &cheat_lego }, {"FPS", &cheat_mypos }, {"TeleportMapSpot", &cheat_scoot }, {"Gold&StatTokens", &cheat_midas }, {"God mode", &cheat_god }, {"Keys", &cheat_keys }, {"Weapons & Ammo", &cheat_ammo }, {"Massacre", &cheat_nuke }, {"No Clipping", &cheat_noclip }, {"Berserk", &cheat_powerup[0] }, {"Invisibility", &cheat_powerup[1] }, {"Enviro Suit", &cheat_powerup[2] }, {"Health", &cheat_powerup[3] }, {"Backpack", &cheat_powerup[4] }, // STRIFE-FIXME/TODO: Does SeHackEd not support PUMPUP{S,T,nil}, or "DOTS" ? }; static deh_cheat_t *FindCheatByName(char *name) { size_t i; for (i=0; i= cheat->seq->sequence_len) { DEH_Warning(context, "Cheat sequence longer than supported by " "Vanilla dehacked"); break; } if (deh_apply_cheats) { cheat->seq->sequence[i] = unsvalue[i]; } ++i; // Absolute limit - don't exceed if (i >= MAX_CHEAT_LEN - cheat->seq->parameter_chars) { DEH_Error(context, "Cheat sequence too long!"); return; } } if (deh_apply_cheats) { cheat->seq->sequence[i] = '\0'; } } deh_section_t deh_section_cheat = { "Cheat", NULL, DEH_CheatStart, DEH_CheatParseLine, NULL, NULL, }; chocolate-doom-chocolate-doom-2.2.1/src/strife/deh_frame.c000066400000000000000000000075371257432200600234620ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Frame" sections in dehacked files // #include #include #include "doomtype.h" #include "d_items.h" #include "info.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "deh_mapping.h" DEH_BEGIN_MAPPING(state_mapping, state_t) DEH_MAPPING("Sprite number", sprite) DEH_MAPPING("Sprite subnumber", frame) DEH_MAPPING("Duration", tics) DEH_MAPPING("Next frame", nextstate) DEH_UNSUPPORTED_MAPPING("Action pointer") DEH_END_MAPPING static void *DEH_FrameStart(deh_context_t *context, char *line) { int frame_number = 0; state_t *state; if (sscanf(line, "Frame %i", &frame_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (frame_number < 0 || frame_number >= NUMSTATES) { DEH_Warning(context, "Invalid frame number: %i", frame_number); return NULL; } if (frame_number >= DEH_VANILLA_NUMSTATES) { DEH_Warning(context, "Attempt to modify frame %i: this will cause " "problems in Vanilla dehacked.", frame_number); } state = &states[frame_number]; return state; } // Simulate a frame overflow: Doom has 967 frames in the states[] array, but // DOS dehacked internally only allocates memory for 966. As a result, // attempts to set frame 966 (the last frame) will overflow the dehacked // array and overwrite the weaponinfo[] array instead. // // This is noticable in Batman Doom where it is impossible to switch weapons // away from the fist once selected. static void DEH_FrameOverflow(deh_context_t *context, char *varname, int value) { if (!strcasecmp(varname, "Duration")) { weaponinfo[0].ammo = value; } else if (!strcasecmp(varname, "Codep frame")) { weaponinfo[0].upstate = value; } else if (!strcasecmp(varname, "Next frame")) { weaponinfo[0].downstate = value; } else if (!strcasecmp(varname, "Unknown 1")) { weaponinfo[0].readystate = value; } else if (!strcasecmp(varname, "Unknown 2")) { weaponinfo[0].atkstate = value; } else { DEH_Error(context, "Unable to simulate frame overflow: field '%s'", varname); } } static void DEH_FrameParseLine(deh_context_t *context, char *line, void *tag) { state_t *state; char *variable_name, *value; int ivalue; if (tag == NULL) return; state = (state_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // all values are integers ivalue = atoi(value); if (state == &states[NUMSTATES - 1]) { DEH_FrameOverflow(context, variable_name, ivalue); } else { // set the appropriate field DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue); } } static void DEH_FrameSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include "doomtype.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" #include "deh_misc.h" // Dehacked: "Initial Health" // This is the initial health a player has when starting anew. // See G_PlayerReborn in g_game.c int deh_initial_health = DEH_DEFAULT_INITIAL_HEALTH; // Dehacked: "Initial bullets" // This is the number of bullets the player has when starting anew. // See G_PlayerReborn in g_game.c int deh_initial_bullets = DEH_DEFAULT_INITIAL_BULLETS; // Dehacked: "Max Health" // This is the maximum health that can be reached using medikits // alone. See P_TouchSpecialThing in p_inter.c int deh_max_health = DEH_DEFAULT_MAX_HEALTH; // Dehacked: "Max Armor" // This is the maximum armor which can be reached by picking up // armor helmets. See P_TouchSpecialThing in p_inter.c int deh_max_armor = DEH_DEFAULT_MAX_ARMOR; // Dehacked: "Green Armor Class" // This is the armor class that is given when picking up the green // armor or an armor helmet. See P_TouchSpecialThing in p_inter.c // // DOS dehacked only modifies the behavior of the green armor shirt, // the armor class set by armor helmets is not affected. int deh_green_armor_class = DEH_DEFAULT_GREEN_ARMOR_CLASS; // Dehacked: "Blue Armor Class" // This is the armor class that is given when picking up the blue // armor or a megasphere. See P_TouchSpecialThing in p_inter.c // // DOS dehacked only modifies the MegaArmor behavior and not // the MegaSphere, which always gives armor type 2. int deh_blue_armor_class = DEH_DEFAULT_BLUE_ARMOR_CLASS; // Dehacked: "Max soulsphere" // The maximum health which can be reached by picking up the // soulsphere. See P_TouchSpecialThing in p_inter.c int deh_max_soulsphere = DEH_DEFAULT_MAX_SOULSPHERE; // Dehacked: "Soulsphere health" // The amount of health bonus that picking up a soulsphere // gives. See P_TouchSpecialThing in p_inter.c int deh_soulsphere_health = DEH_DEFAULT_SOULSPHERE_HEALTH; // Dehacked: "Megasphere health" // This is what the health is set to after picking up a // megasphere. See P_TouchSpecialThing in p_inter.c int deh_megasphere_health = DEH_DEFAULT_MEGASPHERE_HEALTH; // Dehacked: "God mode health" // This is what the health value is set to when cheating using // the IDDQD god mode cheat. See ST_Responder in st_stuff.c int deh_god_mode_health = DEH_DEFAULT_GOD_MODE_HEALTH; // Dehacked: "IDFA Armor" // This is what the armor is set to when using the IDFA cheat. // See ST_Responder in st_stuff.c int deh_idfa_armor = DEH_DEFAULT_IDFA_ARMOR; // Dehacked: "IDFA Armor Class" // This is what the armor class is set to when using the IDFA cheat. // See ST_Responder in st_stuff.c int deh_idfa_armor_class = DEH_DEFAULT_IDFA_ARMOR_CLASS; // Dehacked: "IDKFA Armor" // This is what the armor is set to when using the IDKFA cheat. // See ST_Responder in st_stuff.c int deh_idkfa_armor = DEH_DEFAULT_IDKFA_ARMOR; // Dehacked: "IDKFA Armor Class" // This is what the armor class is set to when using the IDKFA cheat. // See ST_Responder in st_stuff.c int deh_idkfa_armor_class = DEH_DEFAULT_IDKFA_ARMOR_CLASS; // Dehacked: "BFG Cells/Shot" // This is the number of CELLs firing the BFG uses up. // See P_CheckAmmo and A_FireBFG in p_pspr.c int deh_bfg_cells_per_shot = DEH_DEFAULT_BFG_CELLS_PER_SHOT; // Dehacked: "Monsters infight" // This controls whether monsters can harm other monsters of the same // species. For example, whether an imp fireball will damage other // imps. The value of this in dehacked patches is weird - '202' means // off, while '221' means on. // // See PIT_CheckThing in p_map.c int deh_species_infighting = DEH_DEFAULT_SPECIES_INFIGHTING; static struct { char *deh_name; int *value; } misc_settings[] = { {"Initial Health", &deh_initial_health}, {"Initial Bullets", &deh_initial_bullets}, {"Max Health", &deh_max_health}, {"Max Armor", &deh_max_armor}, {"LeatherArmorClass", &deh_green_armor_class}, {"Metal Armor Class", &deh_blue_armor_class}, {"Max Soulsphere", &deh_max_soulsphere}, {"Soulsphere Health", &deh_soulsphere_health}, {"Megasphere Health", &deh_megasphere_health}, {"God Mode Health", &deh_god_mode_health}, {"IDFA Armor", &deh_idfa_armor}, {"IDFA Armor Class", &deh_idfa_armor_class}, {"IDKFA Armor", &deh_idkfa_armor}, {"IDKFA Armor Class", &deh_idkfa_armor_class}, {"Mauler Cells/Shot", &deh_bfg_cells_per_shot}, }; static void *DEH_MiscStart(deh_context_t *context, char *line) { return NULL; } static void DEH_MiscParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; int ivalue; size_t i; if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); if (!strcasecmp(variable_name, "Monsters Infight")) { // See notes above. if (ivalue == 202) { deh_species_infighting = 0; } else if (ivalue == 221) { deh_species_infighting = 1; } else { DEH_Warning(context, "Invalid value for 'Monsters Infight': %i", ivalue); } return; } for (i=0; i #include #include #include "doomtype.h" #include "info.h" #include "deh_defs.h" #include "deh_io.h" #include "deh_main.h" static actionf_t codeptrs[NUMSTATES]; static int CodePointerIndex(actionf_t *ptr) { int i; for (i=0; i= NUMSTATES) { DEH_Warning(context, "Invalid frame number: %i", frame_number); return NULL; } return &states[frame_number]; } static void DEH_PointerParseLine(deh_context_t *context, char *line, void *tag) { state_t *state; char *variable_name, *value; int ivalue; if (tag == NULL) return; state = (state_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // printf("Set %s to %s for state\n", variable_name, value); // all values are integers ivalue = atoi(value); // set the appropriate field if (!strcasecmp(variable_name, "Codep frame")) { if (ivalue < 0 || ivalue >= NUMSTATES) { DEH_Warning(context, "Invalid state '%i'", ivalue); } else { state->action = codeptrs[ivalue]; } } else { DEH_Warning(context, "Unknown variable name '%s'", variable_name); } } static void DEH_PointerSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include "doomfeatures.h" #include "doomtype.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" #include "sounds.h" DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t) DEH_UNSUPPORTED_MAPPING("Offset") DEH_UNSUPPORTED_MAPPING("Zero/One") DEH_MAPPING("Value", priority) DEH_MAPPING("Zero 1", link) DEH_MAPPING("Zero 2", pitch) DEH_MAPPING("Zero 3", volume) DEH_UNSUPPORTED_MAPPING("Zero 4") DEH_MAPPING("Neg. One 1", usefulness) DEH_MAPPING("Neg. One 2", lumpnum) DEH_END_MAPPING static void *DEH_SoundStart(deh_context_t *context, char *line) { int sound_number = 0; if (sscanf(line, "Sound %i", &sound_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (sound_number < 0 || sound_number >= NUMSFX) { DEH_Warning(context, "Invalid sound number: %i", sound_number); return NULL; } if (sound_number >= DEH_VANILLA_NUMSFX) { DEH_Warning(context, "Attempt to modify SFX %i. This will cause " "problems in Vanilla dehacked.", sound_number); } return &S_sfx[sound_number]; } static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag) { sfxinfo_t *sfx; char *variable_name, *value; int ivalue; if (tag == NULL) return; sfx = (sfxinfo_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // all values are integers ivalue = atoi(value); // Set the field value DEH_SetMapping(context, &sound_mapping, sfx, variable_name, ivalue); } deh_section_t deh_section_sound = { "Sound", NULL, DEH_SoundStart, DEH_SoundParseLine, NULL, NULL, }; chocolate-doom-chocolate-doom-2.2.1/src/strife/deh_strife.c000066400000000000000000000030771257432200600236570ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Top-level dehacked definitions for Strife dehacked (sehacked) // #include #include "deh_defs.h" #include "deh_main.h" char *deh_signatures[] = { "Patch File for SeHackEd v0.4", "Patch File for SeHackEd v0.3", NULL }; // deh_ammo.c: extern deh_section_t deh_section_ammo; // deh_cheat.c: extern deh_section_t deh_section_cheat; // deh_frame.c: extern deh_section_t deh_section_frame; // deh_misc.c: extern deh_section_t deh_section_misc; // deh_ptr.c: extern deh_section_t deh_section_pointer; // deh_sound.c extern deh_section_t deh_section_sound; // deh_text.c: extern deh_section_t deh_section_text; // deh_thing.c: extern deh_section_t deh_section_thing; // deh_weapon.c: extern deh_section_t deh_section_weapon; // // List of section types: // deh_section_t *deh_section_types[] = { &deh_section_ammo, &deh_section_cheat, &deh_section_frame, &deh_section_misc, &deh_section_pointer, &deh_section_sound, &deh_section_text, &deh_section_thing, &deh_section_weapon, NULL }; chocolate-doom-chocolate-doom-2.2.1/src/strife/deh_thing.c000066400000000000000000000066631257432200600235000ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Parses "Thing" sections in dehacked files // #include #include #include "doomtype.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" #include "info.h" DEH_BEGIN_MAPPING(thing_mapping, mobjinfo_t) DEH_MAPPING("ID #", doomednum) DEH_MAPPING("Initial frame", spawnstate) DEH_MAPPING("Hit points", spawnhealth) DEH_MAPPING("First moving frame", seestate) DEH_MAPPING("Alert sound", seesound) DEH_MAPPING("Reaction time", reactiontime) DEH_MAPPING("Attack sound", attacksound) DEH_MAPPING("Injury frame", painstate) DEH_MAPPING("Pain chance", painchance) DEH_MAPPING("Pain sound", painsound) DEH_MAPPING("Close attack frame", meleestate) DEH_MAPPING("Far attack frame", missilestate) DEH_MAPPING("Crash frame", crashstate) DEH_MAPPING("Death frame", deathstate) DEH_MAPPING("Exploding frame", xdeathstate) DEH_MAPPING("Death sound", deathsound) DEH_MAPPING("Speed", speed) DEH_MAPPING("Width", radius) DEH_MAPPING("Height", height) DEH_MAPPING("Mass", mass) DEH_MAPPING("Missile damage", damage) DEH_MAPPING("Action sound", activesound) DEH_MAPPING("Bits", flags) DEH_UNSUPPORTED_MAPPING("Name pointer") DEH_END_MAPPING static void *DEH_ThingStart(deh_context_t *context, char *line) { int thing_number = 0; mobjinfo_t *mobj; if (sscanf(line, "Thing %i", &thing_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } // dehacked files are indexed from 1 --thing_number; if (thing_number < 0 || thing_number >= NUMMOBJTYPES) { DEH_Warning(context, "Invalid thing number: %i", thing_number); return NULL; } mobj = &mobjinfo[thing_number]; return mobj; } static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag) { mobjinfo_t *mobj; char *variable_name, *value; int ivalue; if (tag == NULL) return; mobj = (mobjinfo_t *) tag; // Parse the assignment if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } // printf("Set %s to %s for mobj\n", variable_name, value); // all values are integers ivalue = atoi(value); // Set the field value DEH_SetMapping(context, &thing_mapping, mobj, variable_name, ivalue); } static void DEH_ThingSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include #include "doomtype.h" #include "d_items.h" #include "deh_defs.h" #include "deh_main.h" #include "deh_mapping.h" DEH_BEGIN_MAPPING(weapon_mapping, weaponinfo_t) DEH_MAPPING("Ammo type", ammo) DEH_MAPPING("Deselect frame", upstate) DEH_MAPPING("Select frame", downstate) DEH_MAPPING("Bobbing frame", readystate) DEH_MAPPING("Shooting frame", atkstate) DEH_MAPPING("Firing frame", flashstate) DEH_UNSUPPORTED_MAPPING("? Unknown") DEH_END_MAPPING static void *DEH_WeaponStart(deh_context_t *context, char *line) { int weapon_number = 0; if (sscanf(line, "Weapon %i", &weapon_number) != 1) { DEH_Warning(context, "Parse error on section start"); return NULL; } if (weapon_number < 0 || weapon_number >= NUMWEAPONS) { DEH_Warning(context, "Invalid weapon number: %i", weapon_number); return NULL; } return &weaponinfo[weapon_number]; } static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag) { char *variable_name, *value; weaponinfo_t *weapon; int ivalue; if (tag == NULL) return; weapon = (weaponinfo_t *) tag; if (!DEH_ParseAssignment(line, &variable_name, &value)) { // Failed to parse DEH_Warning(context, "Failed to parse assignment"); return; } ivalue = atoi(value); DEH_SetMapping(context, &weapon_mapping, weapon, variable_name, ivalue); } static void DEH_WeaponSHA1Sum(sha1_context_t *context) { int i; for (i=0; i #include #include "doomtype.h" #include "i_timer.h" #include "d_mode.h" // // Global parameters/defines. // // DOOM version // // haleyjd 09/28/10: Replaced with Strife version #define STRIFE_VERSION 101 // Version code for cph's longtics hack ("v1.91") #define DOOM_191_VERSION 111 // Maximum players for Strife: #define MAXPLAYERS 8 // If rangecheck is undefined, // most parameter validation debugging code will not be compiled #define RANGECHECK // The current state of the game: whether we are // playing, gazing at the intermission screen, // the game final animation, or a demo. typedef enum { GS_LEVEL, GS_UNKNOWN, GS_FINALE, GS_DEMOSCREEN, } gamestate_t; typedef enum { ga_nothing, ga_loadlevel, ga_newgame, ga_loadgame, ga_savegame, ga_playdemo, ga_completed, ga_victory, ga_worlddone, ga_screenshot } gameaction_t; // // Difficulty/skill settings/filters. // // Skill flags. #define MTF_EASY 1 #define MTF_NORMAL 2 #define MTF_HARD 4 // villsa [STRIFE] standing monsters #define MTF_STAND 8 // villsa [STRIFE] don't spawn in single player #define MTF_NOTSINGLE 16 // Deaf monsters/do not react to sound. #define MTF_AMBUSH 32 // villsa [STRIFE] friendly to players #define MTF_FRIEND 64 // villsa [STRIFE] TODO - identify #define MTF_UNKNOWN1 128 // villsa [STRIFE] thing is translucent - STRIFE-TODO: But how much? #define MTF_TRANSLUCENT 256 // villsa [STRIFE] thing is more - or less? - translucent - STRIFE-TODO #define MTF_MVIS 512 // villsa [STRIFE] TODO - identify #define MTF_UNKNOWN2 1024 // // Key cards. // // villsa [STRIFE] typedef enum { key_BaseKey, // 0 key_GovsKey, // 1 key_Passcard, // 2 key_IDCard, // 3 key_PrisonKey, // 4 key_SeveredHand, // 5 key_Power1Key, // 6 key_Power2Key, // 7 key_Power3Key, // 8 key_GoldKey, // 9 key_IDBadge, // 10 key_SilverKey, // 11 key_OracleKey, // 12 key_MilitaryID, // 13 key_OrderKey, // 14 key_WarehouseKey, // 15 key_BrassKey, // 16 key_RedCrystalKey, // 17 key_BlueCrystalKey, // 18 key_ChapelKey, // 19 key_CatacombKey, // 20 key_SecurityKey, // 21 key_CoreKey, // 22 key_MaulerKey, // 23 key_FactoryKey, // 24 key_MineKey, // 25 key_NewKey5, // 26 NUMCARDS // 27 } card_t; // The defined weapons, // including a marker indicating // user has not changed weapon. // villsa [STRIFE] typedef enum { wp_fist, wp_elecbow, wp_rifle, wp_missile, wp_hegrenade, wp_flame, wp_mauler, wp_sigil, wp_poisonbow, wp_wpgrenade, wp_torpedo, NUMWEAPONS, // No pending weapon change. wp_nochange } weapontype_t; // Ammunition types defined. typedef enum { am_bullets, am_elecbolts, am_poisonbolts, am_cell, am_missiles, am_hegrenades, am_wpgrenades, NUMAMMO, am_noammo // unlimited ammo } ammotype_t; // Power up artifacts. // villsa [STRIFE] typedef enum { pw_strength, pw_invisibility, pw_ironfeet, pw_allmap, pw_communicator, pw_targeter, NUMPOWERS } powertype_t; // villsa [STRIFE] // quest numbers typedef enum { // Hex Watcom Name player_t offset tk_quest1, // 0x00000001 questflags & 1 0x4D tk_quest2, // 0x00000002 questflags & 2 tk_quest3, // 0x00000004 questflags & 4 tk_quest4, // 0x00000008 questflags & 8 tk_quest5, // 0x00000010 questflags & 10h tk_quest6, // 0x00000020 questflags & 20h tk_quest7, // 0x00000040 questflags & 40h tk_quest8, // 0x00000080 questflags & 80h tk_quest9, // 0x00000100 BYTE1(questflags) & 1 0x4E tk_quest10, // 0x00000200 BYTE1(questflags) & 2 tk_quest11, // 0x00000400 BYTE1(questflags) & 4 tk_quest12, // 0x00000800 BYTE1(questflags) & 8 tk_quest13, // 0x00001000 BYTE1(questflags) & 10h tk_quest14, // 0x00002000 BYTE1(questflags) & 20h tk_quest15, // 0x00004000 BYTE1(questflags) & 40h tk_quest16, // 0x00008000 BYTE1(questflags) & 80h tk_quest17, // 0x00010000 BYTE2(questflags) & 1 0x4F tk_quest18, // 0x00020000 BYTE2(questflags) & 2 tk_quest19, // 0x00040000 BYTE2(questflags) & 4 tk_quest20, // 0x00080000 BYTE2(questflags) & 8 tk_quest21, // 0x00100000 BYTE2(questflags) & 10h tk_quest22, // 0x00200000 BYTE2(questflags) & 20h tk_quest23, // 0x00400000 BYTE2(questflags) & 40h tk_quest24, // 0x00800000 BYTE2(questflags) & 80h tk_quest25, // 0x01000000 BYTE3(questflags) & 1 0x50 tk_quest26, // 0x02000000 BYTE3(questflags) & 2 tk_quest27, // 0x04000000 BYTE3(questflags) & 4 tk_quest28, // 0x08000000 BYTE3(questflags) & 8 tk_quest29, // 0x10000000 BYTE3(questflags) & 10h tk_quest30, // 0x20000000 BYTE3(questflags) & 20h tk_quest31, // 0x40000000 BYTE3(questflags) & 40h tk_quest32, // most likely unused tk_numquests } questtype_t; // haleyjd 09/12/10: [STRIFE] // flag values for each quest. enum { // Name Flag from bitnum Purpose, if known QF_QUEST1 = (1 << tk_quest1), // Obtained Beldin's ring QF_QUEST2 = (1 << tk_quest2), // Stole the Chalice QF_QUEST3 = (1 << tk_quest3), // Permission to visit Irale (visited Macil) QF_QUEST4 = (1 << tk_quest4), // Accepted Gov. Mourel's "messy" chore QF_QUEST5 = (1 << tk_quest5), // Accepted Gov. Mourel's "bloody" chore QF_QUEST6 = (1 << tk_quest6), // Destroyed the Power Coupling QF_QUEST7 = (1 << tk_quest7), // Killed Blue Acolytes ("Scanning Team") QF_QUEST8 = (1 << tk_quest8), // Unused; formerly, picked up Broken Coupling QF_QUEST9 = (1 << tk_quest9), // Obtained Derwin's ear QF_QUEST10 = (1 << tk_quest10), // Obtained Prison Pass QF_QUEST11 = (1 << tk_quest11), // Obtained Prison Key QF_QUEST12 = (1 << tk_quest12), // Obtained Judge Wolenick's hand QF_QUEST13 = (1 << tk_quest13), // Freed the Prisoners QF_QUEST14 = (1 << tk_quest14), // Destroyed the Power Crystal QF_QUEST15 = (1 << tk_quest15), // Obtained Guard Uniform QF_QUEST16 = (1 << tk_quest16), // Destroyed the Gate Mechanism QF_QUEST17 = (1 << tk_quest17), // Heard Macil's story about the Sigil (MAP10) QF_QUEST18 = (1 << tk_quest18), // Obtained Oracle Pass QF_QUEST19 = (1 << tk_quest19), QF_QUEST20 = (1 << tk_quest20), QF_QUEST21 = (1 << tk_quest21), // Killed Bishop QF_QUEST22 = (1 << tk_quest22), // Killed Oracle with QUEST21 set QF_QUEST23 = (1 << tk_quest23), // Killed Oracle (always given) QF_QUEST24 = (1 << tk_quest24), // Killed Macil QF_QUEST25 = (1 << tk_quest25), // Destroyed the Converter QF_QUEST26 = (1 << tk_quest26), // Killed Loremaster QF_QUEST27 = (1 << tk_quest27), // Destroyed the Computer (checked for good ending) QF_QUEST28 = (1 << tk_quest28), // Obtained Catacomb Key (checked by line type 228) QF_QUEST29 = (1 << tk_quest29), // Destroyed the Mines Transmitter QF_QUEST30 = (1 << tk_quest30), QF_QUEST31 = (1 << tk_quest31), QF_QUEST32 = (1 << tk_quest32), // Unused; BUG: Broken Coupling accidentally sets it. QF_ALLQUESTS = (QF_QUEST31 + (QF_QUEST31 - 1)) // does not include bit 32! }; // // Power up durations, // how many seconds till expiration, // assuming TICRATE is 35 ticks/second. // typedef enum { INVISTICS = (55*TICRATE), // villsa [STRIFE] changed from 60 to 55 IRONTICS = (80*TICRATE), // villsa [STRIFE] changed from 60 to 80 PMUPTICS = (80*TICRATE), // villsa [STRIFE] TARGTICS = (160*TICRATE),// villsa [STRIFE] } powerduration_t; #endif // __DOOMDEF__ chocolate-doom-chocolate-doom-2.2.1/src/strife/doomstat.c000066400000000000000000000017041257432200600233700ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Put all global tate variables here. // #include #include "doomstat.h" // Game Mode - identify IWAD as shareware, retail etc. GameMode_t gamemode = indetermined; GameMission_t gamemission = doom; GameVersion_t gameversion = exe_strife_1_31; char *gamedescription; // Set if homebrew PWAD stuff has been added. boolean modifiedgame; chocolate-doom-chocolate-doom-2.2.1/src/strife/doomstat.h000066400000000000000000000153641257432200600234040ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // All the global variables that store the internal state. // Theoretically speaking, the internal state of the engine // should be found by looking at the variables collected // here, and every relevant module will have to include // this header file. // In practice, things are a bit messy. // #ifndef __D_STATE__ #define __D_STATE__ // We need globally shared data structures, // for defining the global state variables. #include "doomdata.h" #include "d_loop.h" // We need the playr data structure as well. #include "d_player.h" // Game mode/mission #include "d_mode.h" #include "net_defs.h" // ------------------------ // Command line parameters. // extern boolean nomonsters; // checkparm of -nomonsters extern boolean respawnparm; // checkparm of -respawn extern boolean fastparm; // checkparm of -fast extern boolean randomparm; // [STRIFE] checkparm of -random extern boolean flipparm; // [STRIFE] checkparm of -flip extern boolean devparm; // DEBUG: launched with -devparm // ----------------------------------------------------- // Game Mode - identify IWAD as shareware, retail etc. // extern GameMode_t gamemode; extern GameMission_t gamemission; extern GameVersion_t gameversion; extern char *gamedescription; // Set if homebrew PWAD stuff has been added. extern boolean modifiedgame; // ------------------------------------------- // Selected skill type, map etc. // // Defaults for menu, methinks. extern skill_t startskill; extern int startepisode; extern int startmap; // Savegame slot to load on startup. This is the value provided to // the -loadgame option. If this has not been provided, this is -1. extern int startloadgame; extern boolean autostart; // Selected by user. extern skill_t gameskill; extern int gameepisode; extern int gamemap; // If non-zero, exit the level after this number of minutes extern int timelimit; // Nightmare mode flag, single player. extern boolean respawnmonsters; // Netgame? Only true if >1 player. extern boolean netgame; // 0=Co-op; 1=Deathmatch; 2=Altdeath extern int deathmatch; // ------------------------- // Internal parameters for sound rendering. // These have been taken from the DOS version, // but are not (yet) supported with Linux // (e.g. no sound volume adjustment with menu. // From m_menu.c: // Sound FX volume has default, 0 - 15 // Music volume has default, 0 - 15 // These are multiplied by 8. extern int sfxVolume; extern int musicVolume; extern int voiceVolume; // haleyjd 08/29/10: [STRIFE] // Current music/sfx card - index useless // w/o a reference LUT in a sound module. // Ideally, this would use indices found // in: /usr/include/linux/soundcard.h extern int snd_MusicDevice; extern int snd_SfxDevice; // Config file? Same disclaimer as above. extern int snd_DesiredMusicDevice; extern int snd_DesiredSfxDevice; // ------------------------- // Status flags for refresh. // // Depending on view size - no status bar? // Note that there is no way to disable the // status bar explicitely. extern boolean statusbaractive; extern boolean automapactive; // In AutoMap mode? extern boolean menuactive; // Menu overlayed? extern boolean menupause; // haleyjd 08/29/10: [STRIFE] extern int menupausetime; // haleyjd 09/04/10: [STRIFE] extern boolean menuindialog; // haleyjd: ditto extern boolean paused; // Game Pause? extern boolean viewactive; extern boolean nodrawers; extern boolean testcontrols; extern int testcontrols_mousespeed; // This one is related to the 3-screen display mode. // ANG90 = left side, ANG270 = right extern int viewangleoffset; // Player taking events, and displaying. extern int consoleplayer; extern int displayplayer; // ------------------------------------- // Scores, rating. // Statistics on a given map, for intermission. // extern int totalkills; //extern int totalitems; [STRIFE] unused extern int totalsecret; // Timer, for scores. extern int levelstarttic; // gametic at level start extern int leveltime; // tics in game play for par // -------------------------------------- // DEMO playback/recording related stuff. // No demo, there is a human player in charge? // Disable save/end game? extern boolean usergame; //? extern boolean demoplayback; extern boolean demorecording; extern int mouse_fire_countdown; // villsa [STRIFE] // Round angleturn in ticcmds to the nearest 256. This is used when // recording Vanilla demos in netgames. extern boolean lowres_turn; // Quit after playing a demo from cmdline. extern boolean singledemo; //? extern gamestate_t gamestate; //----------------------------- // Internal parameters, fixed. // These are set by the engine, and not changed // according to user inputs. Partly load from // WAD, partly set at startup time. // Bookkeeping on players - state. extern player_t players[MAXPLAYERS]; // Alive? Disconnected? extern boolean playeringame[MAXPLAYERS]; // Player spawn spots for deathmatch. #define MAX_DM_STARTS 10 extern mapthing_t deathmatchstarts[MAX_DM_STARTS]; extern mapthing_t* deathmatch_p; // Player spawn spots. extern mapthing_t playerstarts[MAXPLAYERS]; // haleyjd 08/24/10: [STRIFE] rift spots #define MAXRIFTSPOTS 16 extern mapthing_t riftSpots[MAXRIFTSPOTS]; // Intermission stats. // Parameters for world map / intermission. extern wbstartstruct_t wminfo; //----------------------------------------- // Internal parameters, used for engine. // // File handling stuff. extern char * savegamedir; extern char basedefault[1024]; // if true, load all graphics at level load extern boolean precache; // wipegamestate can be set to -1 // to force a wipe on the next draw extern gamestate_t wipegamestate; extern int mouseSensitivity; //extern int bodyqueslot; [STRIFE] unused // Needed to store the number of the dummy sky flat. // Used for rendering, // as well as tracking projectiles etc. extern int skyflatnum; // Netgame stuff (buffers and pointers, i.e. indices). extern int rndindex; extern ticcmd_t *netcmds; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/dstrings.c000066400000000000000000000043771257432200600234040ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Globally defined strings. // #include "dstrings.h" char *doom1_endmsg[] = { "are you sure you want to\nquit this great game?", "please don't leave, there's more\ndemons to toast!", "let's beat it -- this is turning\ninto a bloodbath!", "i wouldn't leave if i were you.\ndos is much worse.", "you're trying to say you like dos\nbetter than me, right?", "don't leave yet -- there's a\ndemon around that corner!", "ya know, next time you come in here\ni'm gonna toast ya.", "go ahead and leave. see if i care.", }; char *doom2_endmsg[] = { // QuitDOOM II messages "are you sure you want to\nquit this great game?", "you want to quit?\nthen, thou hast lost an eighth!", "don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!", "get outta here and go back\nto your boring programs.", "if i were your boss, i'd \n deathmatch ya in a minute!", "look, bud. you leave now\nand you forfeit your body count!", "just leave. when you come\nback, i'll be waiting with a bat.", "you're lucky i don't smack\nyou for thinking about leaving.", }; #if 0 // UNUSED messages included in the source release char* endmsg[] = { // DOOM1 QUITMSG, // FinalDOOM? "fuck you, pussy!\nget the fuck out!", "you quit and i'll jizz\nin your cystholes!", "if you leave, i'll make\nthe lord drink my jizz.", "hey, ron! can we say\n'fuck' in the game?", "i'd leave: this is just\nmore monsters and levels.\nwhat a load.", "suck it down, asshole!\nyou're a fucking wimp!", "don't quit now! we're \nstill spending your money!", // Internal debug. Different style, too. "THIS IS NO MESSAGE!\nPage intentionally left blank." }; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/dstrings.h000066400000000000000000000016641257432200600234050ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: // DOOM strings, by language. // #ifndef __DSTRINGS__ #define __DSTRINGS__ // All important printed strings. #include "d_englsh.h" // Misc. other strings. #define SAVEGAMENAME "doomsav" // QuitDOOM messages // 8 per each game type #define NUM_QUITMESSAGES 8 extern char *doom1_endmsg[]; extern char *doom2_endmsg[]; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/f_finale.c000066400000000000000000000655751257432200600233210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // Copyright(C) 2010 James Haley, Samuel Villarreal // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Game completion, final screen animation. // // [STRIFE] Module marked finished 2010-09-13 22:56 // #include #include // Functions. #include "deh_main.h" #include "i_system.h" #include "i_swap.h" #include "z_zone.h" #include "v_video.h" #include "w_wad.h" #include "s_sound.h" // Data. #include "d_main.h" #include "dstrings.h" #include "sounds.h" #include "doomstat.h" #include "r_state.h" #include "p_dialog.h" // [STRIFE] typedef enum { F_STAGE_TEXT, F_STAGE_ARTSCREEN, F_STAGE_CAST, } finalestage_t; // ? //#include "doomstat.h" //#include "r_local.h" //#include "f_finale.h" // Stage of animation: finalestage_t finalestage; unsigned int finalecount; // haleyjd 09/12/10: [STRIFE] Slideshow variables char *slideshow_panel; unsigned int slideshow_tics; int slideshow_state; // haleyjd 09/13/10: [STRIFE] All this is unused. /* #define TEXTSPEED 3 #define TEXTWAIT 250 typedef struct { GameMission_t mission; int episode, level; char *background; char *text; } textscreen_t; static textscreen_t textscreens[] = { { doom, 1, 8, "FLOOR4_8", E1TEXT}, { doom, 2, 8, "SFLR6_1", E2TEXT}, { doom, 3, 8, "MFLR8_4", E3TEXT}, { doom, 4, 8, "MFLR8_3", E4TEXT}, { doom2, 1, 6, "SLIME16", C1TEXT}, { doom2, 1, 11, "RROCK14", C2TEXT}, { doom2, 1, 20, "RROCK07", C3TEXT}, { doom2, 1, 30, "RROCK17", C4TEXT}, { doom2, 1, 15, "RROCK13", C5TEXT}, { doom2, 1, 31, "RROCK19", C6TEXT}, { pack_tnt, 1, 6, "SLIME16", T1TEXT}, { pack_tnt, 1, 11, "RROCK14", T2TEXT}, { pack_tnt, 1, 20, "RROCK07", T3TEXT}, { pack_tnt, 1, 30, "RROCK17", T4TEXT}, { pack_tnt, 1, 15, "RROCK13", T5TEXT}, { pack_tnt, 1, 31, "RROCK19", T6TEXT}, { pack_plut, 1, 6, "SLIME16", P1TEXT}, { pack_plut, 1, 11, "RROCK14", P2TEXT}, { pack_plut, 1, 20, "RROCK07", P3TEXT}, { pack_plut, 1, 30, "RROCK17", P4TEXT}, { pack_plut, 1, 15, "RROCK13", P5TEXT}, { pack_plut, 1, 31, "RROCK19", P6TEXT}, }; char* finaletext; char* finaleflat; */ void F_StartCast (void); void F_CastTicker (void); boolean F_CastResponder (event_t *ev); void F_CastDrawer (void); // [STRIFE] - Slideshow states enumeration enum { // Exit states SLIDE_EXITHACK = -99, // Hacky exit - start a new dialog SLIDE_HACKHACK = -9, // Bizarre unused state SLIDE_EXIT = -1, // Exit to next finale state SLIDE_CHOCO = -2, // haleyjd: This state is Choco-specific... see below. // Unknown SLIDE_UNKNOWN = 0, // Dunno what it's for, possibly unused // MAP03 - Macil's Programmer exposition SLIDE_PROGRAMMER1 = 1, SLIDE_PROGRAMMER2, SLIDE_PROGRAMMER3, SLIDE_PROGRAMMER4, // Next state = -99 // MAP10 - Macil's Sigil exposition SLIDE_SIGIL1 = 5, SLIDE_SIGIL2, SLIDE_SIGIL3, SLIDE_SIGIL4, // Next state = -99 // MAP29 - Endings // Good Ending SLIDE_GOODEND1 = 10, SLIDE_GOODEND2, SLIDE_GOODEND3, SLIDE_GOODEND4, // Next state = -1 // Bad Ending SLIDE_BADEND1 = 14, SLIDE_BADEND2, SLIDE_BADEND3, // Next state = -1 // Blah Ending SLIDE_BLAHEND1 = 17, SLIDE_BLAHEND2, SLIDE_BLAHEND3, // Next state = -1 // Demo Ending - haleyjd 20130301: v1.31 only SLIDE_DEMOEND1 = 25, SLIDE_DEMOEND2 // Next state = -1 }; // // F_StartFinale // // [STRIFE] // haleyjd 09/13/10: Modified to drive slideshow sequences. // void F_StartFinale (void) { #if 0 // haleyjd 20111006: see below... patch_t *panel; #endif gameaction = ga_nothing; gamestate = GS_FINALE; viewactive = false; automapactive = false; wipegamestate = -1; // [STRIFE] // [STRIFE] Setup the slide show slideshow_panel = DEH_String("PANEL0"); // haleyjd 20111006: These two lines of code *are* in vanilla Strife; // however, there, they were completely inconsequential due to the dirty // rects system. No intervening V_MarkRect call means PANEL0 was never // drawn to the framebuffer. In Chocolate Strife, however, with no such // system in place, this only manages to fuck up the fade-out that is // supposed to happen at the beginning of all finales. So, don't do it! #if 0 panel = (patch_t *)W_CacheLumpName(slideshow_panel, PU_CACHE); V_DrawPatch(0, 0, panel); #endif switch(gamemap) { case 3: // Macil's exposition on the Programmer slideshow_state = SLIDE_PROGRAMMER1; break; case 9: // Super hack for death of Programmer slideshow_state = SLIDE_EXITHACK; break; case 10: // Macil's exposition on the Sigil slideshow_state = SLIDE_SIGIL1; break; case 29: // Endings if(!netgame) { if(players[0].health <= 0) // Bad ending slideshow_state = SLIDE_BADEND1; // - Humanity goes extinct else { if((players[0].questflags & QF_QUEST25) && // Converter destroyed (players[0].questflags & QF_QUEST27)) // Computer destroyed (wtf?!) { // Good ending - You get the hot babe. slideshow_state = SLIDE_GOODEND1; } else { // Blah ending - You win the battle, but fail at life. slideshow_state = SLIDE_BLAHEND1; } } } break; case 34: // For the demo version ending slideshow_state = SLIDE_EXIT; // haleyjd 20130301: Somebody noticed the demo levels were missing the // ending they used to have in the demo version EXE, I guess. But the // weird thing is, this will only trigger if you run with strife0.wad, // and no released version thereof actually works with the 1.31 EXE // due to differing dialog formats... was there to be an updated demo // that never got released?! if(gameversion == exe_strife_1_31 && isdemoversion) slideshow_state = SLIDE_DEMOEND1; break; } S_ChangeMusic(mus_dark, 1); slideshow_tics = 7; finalestage = F_STAGE_TEXT; finalecount = 0; } // // F_Responder // // [STRIFE] Verified unmodified // boolean F_Responder (event_t *event) { if (finalestage == F_STAGE_CAST) return F_CastResponder (event); return false; } // // F_WaitTicker // // [STRIFE] New function // haleyjd 09/13/10: This is called from G_Ticker if gamestate is 1, but we // have no idea for what it's supposed to be. It is unused. // void F_WaitTicker(void) { if(++finalecount >= 250) { gamestate = GS_FINALE; finalestage = 0; finalecount = 0; } } // // F_DoSlideShow // // [STRIFE] New function // haleyjd 09/13/10: Handles slideshow states. Begging to be tabulated! // static void F_DoSlideShow(void) { patch_t *patch; switch(slideshow_state) { case SLIDE_UNKNOWN: // state #0, seems to be unused slideshow_tics = 700; slideshow_state = SLIDE_EXIT; // falls through into state 1, so above is pointless? ... case SLIDE_PROGRAMMER1: // state #1 slideshow_panel = DEH_String("SS2F1"); I_StartVoice(DEH_String("MAC10")); slideshow_state = SLIDE_PROGRAMMER2; slideshow_tics = 315; break; case SLIDE_PROGRAMMER2: // state #2 slideshow_panel = DEH_String("SS2F2"); I_StartVoice(DEH_String("MAC11")); slideshow_state = SLIDE_PROGRAMMER3; slideshow_tics = 350; break; case SLIDE_PROGRAMMER3: // state #3 slideshow_panel = DEH_String("SS2F3"); I_StartVoice(DEH_String("MAC12")); slideshow_state = SLIDE_PROGRAMMER4; slideshow_tics = 420; break; case SLIDE_PROGRAMMER4: // state #4 slideshow_panel = DEH_String("SS2F4"); I_StartVoice(DEH_String("MAC13")); slideshow_state = SLIDE_EXITHACK; // End of slides slideshow_tics = 595; break; case SLIDE_SIGIL1: // state #5 slideshow_panel = DEH_String("SS3F1"); I_StartVoice(DEH_String("MAC16")); slideshow_state = SLIDE_SIGIL2; slideshow_tics = 350; break; case SLIDE_SIGIL2: // state #6 slideshow_panel = DEH_String("SS3F2"); I_StartVoice(DEH_String("MAC17")); slideshow_state = SLIDE_SIGIL3; slideshow_tics = 420; break; case SLIDE_SIGIL3: // state #7 slideshow_panel = DEH_String("SS3F3"); I_StartVoice(DEH_String("MAC18")); slideshow_tics = 420; slideshow_state = SLIDE_SIGIL4; break; case SLIDE_SIGIL4: // state #8 slideshow_panel = DEH_String("SS3F4"); I_StartVoice(DEH_String("MAC19")); slideshow_tics = 385; slideshow_state = SLIDE_EXITHACK; // End of slides break; case SLIDE_GOODEND1: // state #10 slideshow_panel = DEH_String("SS4F1"); S_StartMusic(mus_happy); I_StartVoice(DEH_String("RIE01")); slideshow_state = SLIDE_GOODEND2; slideshow_tics = 455; break; case SLIDE_GOODEND2: // state #11 slideshow_panel = DEH_String("SS4F2"); I_StartVoice(DEH_String("BBX01")); slideshow_state = SLIDE_GOODEND3; slideshow_tics = 385; break; case SLIDE_GOODEND3: // state #12 slideshow_panel = DEH_String("SS4F3"); I_StartVoice(DEH_String("BBX02")); slideshow_state = SLIDE_GOODEND4; slideshow_tics = 490; break; case SLIDE_GOODEND4: // state #13 slideshow_panel = DEH_String("SS4F4"); slideshow_state = SLIDE_EXIT; // Go to end credits slideshow_tics = 980; break; case SLIDE_BADEND1: // state #14 S_StartMusic(mus_sad); slideshow_panel = DEH_String("SS5F1"); I_StartVoice(DEH_String("SS501b")); slideshow_state = SLIDE_BADEND2; slideshow_tics = 385; break; case SLIDE_BADEND2: // state #15 slideshow_panel = DEH_String("SS5F2"); I_StartVoice(DEH_String("SS502b")); slideshow_state = SLIDE_BADEND3; slideshow_tics = 350; break; case SLIDE_BADEND3: // state #16 slideshow_panel = DEH_String("SS5F3"); I_StartVoice(DEH_String("SS503b")); slideshow_state = SLIDE_EXIT; // Go to end credits slideshow_tics = 385; break; case SLIDE_BLAHEND1: // state #17 S_StartMusic(mus_end); slideshow_panel = DEH_String("SS6F1"); I_StartVoice(DEH_String("SS601A")); slideshow_state = SLIDE_BLAHEND2; slideshow_tics = 280; break; case SLIDE_BLAHEND2: // state #18 S_StartMusic(mus_end); slideshow_panel = DEH_String("SS6F2"); I_StartVoice(DEH_String("SS602A")); slideshow_state = SLIDE_BLAHEND3; slideshow_tics = 280; break; case SLIDE_BLAHEND3: // state #19 S_StartMusic(mus_end); slideshow_panel = DEH_String("SS6F3"); I_StartVoice(DEH_String("SS603A")); slideshow_state = SLIDE_EXIT; // Go to credits slideshow_tics = 315; break; case SLIDE_DEMOEND1: // state #25 - only exists in 1.31 slideshow_panel = DEH_String("PANEL7"); slideshow_tics = 175; slideshow_state = SLIDE_DEMOEND2; break; case SLIDE_DEMOEND2: // state #26 - ditto slideshow_panel = DEH_String("VELLOGO"); slideshow_tics = 175; slideshow_state = SLIDE_EXIT; // Go to end credits break; case SLIDE_EXITHACK: // state -99: super hack state gamestate = GS_LEVEL; P_DialogStartP1(); break; case SLIDE_HACKHACK: // state -9: unknown bizarre unused state S_StartSound(NULL, sfx_rifle); slideshow_tics = 3150; break; case SLIDE_EXIT: // state -1: proceed to next finale stage finalecount = 0; finalestage = F_STAGE_ARTSCREEN; wipegamestate = -1; S_StartMusic(mus_fast); // haleyjd 20130301: The ONLY glitch fixed in 1.31 of Strife // *would* be something this insignificant, of course! if(gameversion != exe_strife_1_31) slideshow_state = SLIDE_CHOCO; // haleyjd: see below... break; case SLIDE_CHOCO: // haleyjd 09/14/10: This wouldn't be necessary except that Choco // doesn't support the V_MarkRect dirty rectangles system. This // just so happens to have hidden the fact that the ending // does a screenfade every ~19 seconds due to remaining stuck in // SLIDE_EXIT state above, UNLESS the menus were active - the // V_MarkRect calls in the menu system cause it to be visible. // This means that in order to get the same behavior as the vanilla // EXE, I need different code. So, come to this state and only set // wipegamestate if menuactive is true. finalecount = 0; finalestage = F_STAGE_ARTSCREEN; if(menuactive) wipegamestate = -1; S_StartMusic(mus_fast); slideshow_state = SLIDE_CHOCO; // remain here. break; default: break; } finalecount = 0; if(gameversion != exe_strife_1_31) // See above. This was removed in 1.31. { patch = (patch_t *)W_CacheLumpName(DEH_String("PANEL0"), PU_CACHE); V_DrawPatch(0, 0, patch); } } // // F_Ticker // // [STRIFE] Modifications for new finales // haleyjd 09/13/10: Calls F_DoSlideShow // void F_Ticker (void) { size_t i; // check for skipping if (finalecount > 50) // [STRIFE] No commercial check { // go on to the next level for (i=0 ; i slideshow_tics) // [STRIFE] Advance slideshow F_DoSlideShow(); // [STRIFE]: Rest is unused /* if ( gamemode == commercial) return; if (finalestage == F_STAGE_TEXT && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT) { finalecount = 0; finalestage = F_STAGE_ARTSCREEN; wipegamestate = -1; // force a wipe if (gameepisode == 3) S_StartMusic (mus_logo); } */ } // haleyjd 09/13/10: Not present in Strife: Cast drawing functions #include "hu_stuff.h" extern patch_t *hu_font[HU_FONTSIZE]; /* // // F_TextWrite // void F_TextWrite (void) { byte* src; byte* dest; int x,y,w; signed int count; char* ch; int c; int cx; int cy; // erase the entire screen to a tiled background src = W_CacheLumpName ( finaleflat , PU_CACHE); dest = I_VideoBuffer; for (y=0 ; y HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c]->width); if (cx+w > SCREENWIDTH) break; V_DrawPatch(cx, cy, hu_font[c]); cx+=w; } } */ // // Final DOOM 2 animation // Casting by id Software. // in order of appearance // typedef struct { int isindemo; // [STRIFE] Changed from name, which is in mobjinfo mobjtype_t type; } castinfo_t; // haleyjd: [STRIFE] A new cast order was defined, however it is unused in any // of the released versions of Strife, even including the demo version :( castinfo_t castorder[] = { { 1, MT_PLAYER }, { 1, MT_BEGGAR1 }, { 1, MT_PEASANT2_A }, { 1, MT_REBEL1 }, { 1, MT_GUARD1 }, { 1, MT_CRUSADER }, { 1, MT_RLEADER2 }, { 0, MT_SENTINEL }, { 0, MT_STALKER }, { 0, MT_PROGRAMMER }, { 0, MT_REAVER }, { 0, MT_PGUARD }, { 0, MT_INQUISITOR }, { 0, MT_PRIEST }, { 0, MT_SPECTRE_A }, { 0, MT_BISHOP }, { 0, MT_ENTITY }, { 1, NUMMOBJTYPES } }; int castnum; int casttics; state_t* caststate; boolean castdeath; int castframes; int castonmelee; boolean castattacking; // // F_StartCast // // haleyjd 09/13/10: [STRIFE] Heavily modified, yet unused. // Evidence suggests this was meant to be started from a menu item. // See m_menu.c for more info. // void F_StartCast (void) { usergame = false; gameaction = ga_nothing; viewactive = false; automapactive = false; castnum = 0; gamestate = GS_FINALE; caststate = &states[mobjinfo[castorder[castnum].type].seestate]; casttics = caststate->tics; if(casttics > 50) casttics = 50; wipegamestate = -1; // force a screen wipe castdeath = false; finalestage = F_STAGE_CAST; castframes = 0; castonmelee = 0; castattacking = false; } // // F_CastTicker // // [STRIFE] Heavily modified, but unused. // haleyjd 09/13/10: Yeah, I bothered translating this even though it isn't // going to be seen, in part because I hope some Strife port or another will // pick it up and finish it, adding it as the optional menu item it was // meant to be, or just adding it as part of the ending sequence. // void F_CastTicker (void) { int st; if (--casttics > 0) return; // not time to change state yet if (caststate->tics == -1 || caststate->nextstate == S_NULL) { // switch from deathstate to next monster castnum++; castdeath = false; if (isdemoversion) { // [STRIFE] Demo version had a shorter cast if(!castorder[castnum].isindemo) castnum = 0; } // [STRIFE] Break on type == NUMMOBJTYPES rather than name == NULL if (castorder[castnum].type == NUMMOBJTYPES) castnum = 0; if (mobjinfo[castorder[castnum].type].seesound) S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound); caststate = &states[mobjinfo[castorder[castnum].type].seestate]; castframes = 0; } else { int sfx = 0; // just advance to next state in animation if (caststate == &states[S_PLAY_05]) // villsa [STRIFE] - updated goto stopattack; // Oh, gross hack! st = caststate->nextstate; caststate = &states[st]; castframes++; if (st != mobjinfo[castorder[castnum].type].meleestate && st != mobjinfo[castorder[castnum].type].missilestate) { if (st == S_PLAY_05) sfx = sfx_rifle; else sfx = 0; } else sfx = mobjinfo[castorder[castnum].type].attacksound; if (sfx) S_StartSound (NULL, sfx); } if (!castdeath && castframes == 12) { // go into attack frame castattacking = true; if (castonmelee) caststate=&states[mobjinfo[castorder[castnum].type].meleestate]; else caststate=&states[mobjinfo[castorder[castnum].type].missilestate]; castonmelee ^= 1; if (caststate == &states[S_NULL]) { if (castonmelee) caststate = &states[mobjinfo[castorder[castnum].type].meleestate]; else caststate = &states[mobjinfo[castorder[castnum].type].missilestate]; } } if (castattacking) { if (castframes == 24 || caststate == &states[mobjinfo[castorder[castnum].type].seestate] ) { stopattack: castattacking = false; castframes = 0; caststate = &states[mobjinfo[castorder[castnum].type].seestate]; } } casttics = caststate->tics; if (casttics > 50) // [STRIFE] Cap tics casttics = 50; else if (casttics == -1) casttics = 15; } // // F_CastResponder // // [STRIFE] This still exists in Strife but is never used. // It was used at some point in development, however, as they made // numerous modifications to the cast call system. // boolean F_CastResponder (event_t* ev) { if (ev->type != ev_keydown) return false; if (castdeath) return true; // already in dying frames // go into death frame castdeath = true; caststate = &states[mobjinfo[castorder[castnum].type].deathstate]; casttics = caststate->tics; if(casttics > 50) // [STRIFE] Upper bound on casttics casttics = 50; castframes = 0; castattacking = false; if (mobjinfo[castorder[castnum].type].deathsound) S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound); return true; } // // F_CastPrint // // [STRIFE] Verified unmodified, and unused. // void F_CastPrint (char* text) { char* ch; int c; int cx; int w; int width; // find width ch = text; width = 0; while (ch) { c = *ch++; if (!c) break; c = toupper(c) - HU_FONTSTART; if (c < 0 || c> HU_FONTSIZE) { width += 4; continue; } w = SHORT (hu_font[c]->width); width += w; } // draw it cx = 160-width/2; ch = text; while (ch) { c = *ch++; if (!c) break; c = toupper(c) - HU_FONTSTART; if (c < 0 || c> HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c]->width); V_DrawPatch(cx, 180, hu_font[c]); cx+=w; } } // haleyjd 09/13/10: [STRIFE] Unfortunately they removed whatever was // partway finished of this function from the binary, as there is no // trace of it. This means we cannot know for sure what the cast call // would have looked like. :( /* // // F_CastDrawer // void F_CastDrawer (void) { spritedef_t* sprdef; spriteframe_t* sprframe; int lump; boolean flip; patch_t* patch; // erase the entire screen to a background V_DrawPatch (0, 0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE)); F_CastPrint (DEH_String(castorder[castnum].name)); // draw the current frame in the middle of the screen sprdef = &sprites[caststate->sprite]; sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK]; lump = sprframe->lump[0]; flip = (boolean)sprframe->flip[0]; patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE); if (flip) V_DrawPatchFlipped(160, 170, patch); else V_DrawPatch(160, 170, patch); } */ #ifdef STRIFE_DEMO_CODE // // F_DrawPatchCol // // [STRIFE] Verified unmodified, but not present in 1.2 // It WAS present in the demo version, however... // void F_DrawPatchCol ( int x, patch_t* patch, int col ) { column_t* column; byte* source; byte* dest; byte* desttop; int count; column = (column_t *)((byte *)patch + LONG(patch->columnofs[col])); desttop = I_VideoBuffer + x; // step through the posts in a column while (column->topdelta != 0xff ) { source = (byte *)column + 3; dest = desttop + column->topdelta*SCREENWIDTH; count = column->length; while (count--) { *dest = *source++; dest += SCREENWIDTH; } column = (column_t *)( (byte *)column + column->length + 4 ); } } #endif // // F_DrawMap34End // // [STRIFE] Modified from F_BunnyScroll // * In 1.2 and up this just causes a weird black screen. // * In the demo version, it was an actual scroll between two screens. // I have implemented both code segments, though only the black screen // one will currently be used, as full demo version support isn't looking // likely right now. // void F_DrawMap34End (void) { signed int scrolled; int x; // patch_t* p1; // patch_t* p2; // p1 = W_CacheLumpName (DEH_String("credit"), PU_LEVEL); // p2 = W_CacheLumpName (DEH_String("vellogo"), PU_LEVEL); V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT); scrolled = (320 - ((signed int) finalecount-430)/2); if (scrolled > 320) scrolled = 320; if (scrolled < 0) scrolled = 0; #ifdef STRIFE_DEMO_CODE for ( x=0 ; x #include "z_zone.h" #include "i_video.h" #include "v_video.h" #include "m_random.h" #include "doomtype.h" #include "r_defs.h" // haleyjd [STRIFE] #include "r_draw.h" #include "f_wipe.h" // // SCREEN WIPE PACKAGE // // when zero, stop the wipe static boolean go = 0; static byte* wipe_scr_start; static byte* wipe_scr_end; static byte* wipe_scr; void wipe_shittyColMajorXform ( short* array, int width, int height ) { int x; int y; short* dest; dest = (short*) Z_Malloc(width*height*2, PU_STATIC, 0); for(y=0;y 0; i--) { if(*cur_screen != *end_screen) { changed = true; *cur_screen = xlatab[(*cur_screen << 8) + *end_screen]; } ++cur_screen; ++end_screen; } return !changed; } // haleyjd 08/26/10: [STRIFE] Verified unmodified. int wipe_exitColorXForm ( int width, int height, int ticks ) { return 0; } static int* y; int wipe_initMelt ( int width, int height, int ticks ) { int i, r; // copy start screen to main screen memcpy(wipe_scr, wipe_scr_start, width*height); // makes this wipe faster (in theory) // to have stuff in column-major format wipe_shittyColMajorXform((short*)wipe_scr_start, width/2, height); wipe_shittyColMajorXform((short*)wipe_scr_end, width/2, height); // setup initial column positions // (y<0 => not ready to scroll yet) y = (int *) Z_Malloc(width*sizeof(int), PU_STATIC, 0); y[0] = -(M_Random()%16); for (i=1;i 0) y[i] = 0; else if (y[i] == -16) y[i] = -15; } return 0; } int wipe_doMelt ( int width, int height, int ticks ) { int i; int j; int dy; int idx; short* s; short* d; boolean done = true; width/=2; while (ticks--) { for (i=0;i= height) dy = height - y[i]; s = &((short *)wipe_scr_end)[i*height+y[i]]; d = &((short *)wipe_scr)[y[i]*width+i]; idx = 0; for (j=dy;j;j--) { d[idx] = *(s++); idx += width; } y[i] += dy; s = &((short *)wipe_scr_start)[i*height]; d = &((short *)wipe_scr)[y[i]*width+i]; idx = 0; for (j=height-y[i];j;j--) { d[idx] = *(s++); idx += width; } done = false; } } } return done; } int wipe_exitMelt ( int width, int height, int ticks ) { Z_Free(y); Z_Free(wipe_scr_start); Z_Free(wipe_scr_end); return 0; } // haleyjd 08/26/10: [STRIFE] Verified unmodified. int wipe_StartScreen ( int x, int y, int width, int height ) { wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); I_ReadScreen(wipe_scr_start); return 0; } // haleyjd 08/26/10: [STRIFE] Verified unmodified. int wipe_EndScreen ( int x, int y, int width, int height ) { wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); I_ReadScreen(wipe_scr_end); V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr. return 0; } // haleyjd 08/26/10: [STRIFE] Verified unmodified. int wipe_ScreenWipe ( int wipeno, int x, int y, int width, int height, int ticks ) { int rc; static int (*wipes[])(int, int, int) = { wipe_initColorXForm, wipe_doColorXForm, wipe_exitColorXForm, wipe_initMelt, wipe_doMelt, wipe_exitMelt }; // initial stuff if (!go) { go = 1; // haleyjd 20110629 [STRIFE]: We *must* use a temp buffer here. wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG //wipe_scr = I_VideoBuffer; (*wipes[wipeno*3])(width, height, ticks); } // do a piece of wipe-in V_MarkRect(0, 0, width, height); rc = (*wipes[wipeno*3+1])(width, height, ticks); // haleyjd 20110629 [STRIFE]: Copy temp buffer to the real screen. V_DrawBlock(x, y, width, height, wipe_scr); // final stuff if (rc) { go = 0; (*wipes[wipeno*3+2])(width, height, ticks); } return !go; } chocolate-doom-chocolate-doom-2.2.1/src/strife/f_wipe.h000066400000000000000000000022311257432200600230100ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Mission start screen wipe/melt, special effects. // #ifndef __F_WIPE_H__ #define __F_WIPE_H__ // // SCREEN WIPE PACKAGE // enum { // [STRIFE]: ColorXForm reimplemented as a proper crossfade wipe_ColorXForm, // weird screen melt wipe_Melt, wipe_NUMWIPES }; int wipe_StartScreen ( int x, int y, int width, int height ); int wipe_EndScreen ( int x, int y, int width, int height ); int wipe_ScreenWipe ( int wipeno, int x, int y, int width, int height, int ticks ); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/g_game.c000066400000000000000000001704711257432200600227650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // #include #include #include #include "doomdef.h" #include "doomkeys.h" #include "doomstat.h" #include "deh_main.h" #include "deh_misc.h" #include "z_zone.h" #include "f_finale.h" #include "m_argv.h" #include "m_controls.h" #include "m_misc.h" #include "m_menu.h" #include "m_misc.h" #include "m_saves.h" // STRIFE #include "m_random.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "p_setup.h" #include "p_saveg.h" #include "p_tick.h" #include "d_main.h" #include "wi_stuff.h" #include "hu_stuff.h" #include "st_stuff.h" #include "am_map.h" // Needs access to LFB. #include "v_video.h" #include "w_wad.h" #include "p_local.h" #include "s_sound.h" // Data. #include "dstrings.h" #include "sounds.h" // SKY handling - still the wrong place. #include "r_data.h" #include "r_sky.h" #include "p_dialog.h" // villsa [STRIFE] #include "g_game.h" #define SAVEGAMESIZE 0x2c000 void G_ReadDemoTiccmd (ticcmd_t* cmd); void G_WriteDemoTiccmd (ticcmd_t* cmd); void G_PlayerReborn (int player); void G_DoReborn (int playernum); void G_DoLoadLevel (void); void G_DoNewGame (void); void G_DoPlayDemo (void); void G_DoCompleted (void); void G_DoVictory (void); void G_DoWorldDone (void); void G_DoSaveGame (char *path); // Gamestate the last time G_Ticker was called. gamestate_t oldgamestate; gameaction_t gameaction; gamestate_t gamestate; skill_t gameskill = 2; // [STRIFE] Default value set to 2. boolean respawnmonsters; //int gameepisode; int gamemap; // haleyjd 08/24/10: [STRIFE] New variables int destmap; // current destination map when exiting int riftdest; // destination spot for player angle_t riftangle; // player angle saved during exit // If non-zero, exit the level after this number of minutes. int timelimit; boolean paused; boolean sendpause; // send a pause event next tic boolean sendsave; // send a save event next tic boolean usergame; // ok to save / end game boolean timingdemo; // if true, exit with report on completion boolean nodrawers; // for comparative timing purposes int starttime; // for comparative timing purposes boolean viewactive; int deathmatch; // only if started as net death boolean netgame; // only true if packets are broadcast boolean playeringame[MAXPLAYERS]; player_t players[MAXPLAYERS]; boolean turbodetected[MAXPLAYERS]; int consoleplayer; // player taking events and displaying int displayplayer; // view being displayed int levelstarttic; // gametic at level start int totalkills, /*totalitems,*/ totalsecret; // for intermission char *demoname; boolean demorecording; boolean longtics; // cph's doom 1.91 longtics hack boolean lowres_turn; // low resolution turning for longtics boolean demoplayback; boolean netdemo; byte* demobuffer; byte* demo_p; byte* demoend; boolean singledemo; // quit after playing a demo from cmdline boolean precache = true; // if true, load all graphics at start boolean testcontrols = false; // Invoked by setup to test controls wbstartstruct_t wminfo; // parms for world map / intermission byte consistancy[MAXPLAYERS][BACKUPTICS]; #define MAXPLMOVE (forwardmove[1]) #define TURBOTHRESHOLD 0x32 fixed_t forwardmove[2] = {0x19, 0x32}; fixed_t sidemove[2] = {0x18, 0x28}; fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn int mouse_fire_countdown = 0; // villsa [STRIFE] static int *weapon_keys[] = { &key_weapon1, &key_weapon2, &key_weapon3, &key_weapon4, &key_weapon5, &key_weapon6, &key_weapon7, &key_weapon8 }; // Set to -1 or +1 to switch to the previous or next weapon. static int next_weapon = 0; // Used for prev/next weapon keys. // STRIFE-TODO: Check this table makes sense. static const struct { weapontype_t weapon; weapontype_t weapon_num; } weapon_order_table[] = { { wp_fist, wp_fist }, { wp_poisonbow, wp_elecbow }, { wp_elecbow, wp_elecbow }, { wp_rifle, wp_rifle }, { wp_missile, wp_missile }, { wp_wpgrenade, wp_hegrenade }, { wp_hegrenade, wp_hegrenade }, { wp_flame, wp_flame }, { wp_torpedo, wp_mauler }, { wp_mauler, wp_mauler }, { wp_sigil, wp_sigil }, }; #define SLOWTURNTICS 6 #define NUMKEYS 256 #define MAX_JOY_BUTTONS 20 static boolean gamekeydown[NUMKEYS]; static int turnheld; // for accelerative turning static boolean mousearray[MAX_MOUSE_BUTTONS + 1]; static boolean *mousebuttons = &mousearray[1]; // allow [-1] // mouse values are used once int mousex; int mousey; static int dclicktime; static boolean dclickstate; static int dclicks; static int dclicktime2; static boolean dclickstate2; static int dclicks2; // joystick values are repeated static int joyxmove; static int joyymove; static int joystrafemove; static boolean joyarray[MAX_JOY_BUTTONS + 1]; static boolean *joybuttons = &joyarray[1]; // allow [-1] static int savegameslot = 6; // [STRIFE] initialized to 6 static char savedescription[32]; int testcontrols_mousespeed; #define BODYQUESIZE 32 mobj_t* bodyque[BODYQUESIZE]; //int bodyqueslot; [STRIFE] unused int vanilla_savegame_limit = 1; int vanilla_demo_limit = 1; int G_CmdChecksum (ticcmd_t* cmd) { size_t i; int sum = 0; for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++) sum += ((int *)cmd)[i]; return sum; } static boolean WeaponSelectable(weapontype_t weapon) { player_t *player; player = &players[consoleplayer]; // Can't select a weapon if we don't own it. if (!player->weaponowned[weapon]) { return false; } // Can't use registered-only weapons in demo mode: if (isdemoversion && !weaponinfo[weapon].availabledemo) { return false; } // Special rules for switching to alternate versions of weapons. // These must match the weapon-switching rules in P_PlayerThink() // haleyjd 20141024: same fix here as in P_PlayerThink for torpedo. if (weapon == wp_torpedo && player->ammo[weaponinfo[wp_torpedo].ammo] < 30) { return false; } if (player->ammo[weaponinfo[weapon].ammo] == 0) { return false; } return true; } static int G_NextWeapon(int direction) { weapontype_t weapon; int start_i, i; // Find index in the table. if (players[consoleplayer].pendingweapon == wp_nochange) { weapon = players[consoleplayer].readyweapon; } else { weapon = players[consoleplayer].pendingweapon; } for (i=0; iconsistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; // villsa [STRIFE] look up key if(gamekeydown[key_lookup]) cmd->buttons2 |= BT2_LOOKUP; // villsa [STRIFE] look down key if(gamekeydown[key_lookdown]) cmd->buttons2 |= BT2_LOOKDOWN; // villsa [STRIFE] inventory use key if(gamekeydown[key_invuse]) { player_t* player = &players[consoleplayer]; if(player->numinventory > 0) { cmd->buttons2 |= BT2_INVUSE; cmd->inventory = player->inventory[player->inventorycursor].sprite; } } // villsa [STRIFE] inventory drop key if(gamekeydown[key_invdrop]) { player_t* player = &players[consoleplayer]; if(player->numinventory > 0) { cmd->buttons2 |= BT2_INVDROP; cmd->inventory = player->inventory[player->inventorycursor].sprite; } } // villsa [STRIFE] use medkit if(gamekeydown[key_usehealth]) cmd->buttons2 |= BT2_HEALTH; strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; // fraggle: support the old "joyb_speed = 31" hack which // allowed an autorun effect speed = key_speed >= NUMKEYS || joybspeed >= MAX_JOY_BUTTONS || gamekeydown[key_speed] || joybuttons[joybspeed]; forward = side = 0; // villsa [STRIFE] running causes centerview to occur if(speed) cmd->buttons2 |= BT2_CENTERVIEW; // villsa [STRIFE] disable running if low on health if (players[consoleplayer].health <= 15) speed = 0; // use two stage accelerative turning // on the keyboard and joystick if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left]) turnheld += ticdup; else turnheld = 0; if (turnheld < SLOWTURNTICS) tspeed = 2; // slow turn else tspeed = speed; // let movement keys cancel each other out if (strafe) { if (gamekeydown[key_right]) { // fprintf(stderr, "strafe right\n"); side += sidemove[speed]; } if (gamekeydown[key_left]) { // fprintf(stderr, "strafe left\n"); side -= sidemove[speed]; } if (joyxmove > 0) side += sidemove[speed]; if (joyxmove < 0) side -= sidemove[speed]; } else { if (gamekeydown[key_right]) cmd->angleturn -= angleturn[tspeed]; if (gamekeydown[key_left]) cmd->angleturn += angleturn[tspeed]; if (joyxmove > 0) cmd->angleturn -= angleturn[tspeed]; if (joyxmove < 0) cmd->angleturn += angleturn[tspeed]; } if (gamekeydown[key_up]) { // fprintf(stderr, "up\n"); forward += forwardmove[speed]; } if (gamekeydown[key_down]) { // fprintf(stderr, "down\n"); forward -= forwardmove[speed]; } if (joyymove < 0) forward += forwardmove[speed]; if (joyymove > 0) forward -= forwardmove[speed]; if (gamekeydown[key_strafeleft] || joybuttons[joybstrafeleft] || mousebuttons[mousebstrafeleft] || joystrafemove < 0) { side -= sidemove[speed]; } if (gamekeydown[key_straferight] || joybuttons[joybstraferight] || mousebuttons[mousebstraferight] || joystrafemove > 0) { side += sidemove[speed]; } // buttons cmd->chatchar = HU_dequeueChatChar(); // villsa [STRIFE] - add mouse button support for jump if (gamekeydown[key_jump] || mousebuttons[mousebjump] || joybuttons[joybjump]) cmd->buttons2 |= BT2_JUMP; // villsa [STRIFE]: Moved mousebuttons[mousebfire] to below if (gamekeydown[key_fire] || joybuttons[joybfire]) cmd->buttons |= BT_ATTACK; // villsa [STRIFE] if(mousebuttons[mousebfire]) { if(mouse_fire_countdown <= 0) cmd->buttons |= BT_ATTACK; else --mouse_fire_countdown; } if (gamekeydown[key_use] || joybuttons[joybuse] || mousebuttons[mousebuse]) { cmd->buttons |= BT_USE; // clear double clicks if hit use button dclicks = 0; } // If the previous or next weapon button is pressed, the // next_weapon variable is set to change weapons when // we generate a ticcmd. Choose a new weapon. if (gamestate == GS_LEVEL && next_weapon != 0) { i = G_NextWeapon(next_weapon); cmd->buttons |= BT_CHANGE; cmd->buttons |= i << BT_WEAPONSHIFT; } else { // Check weapon keys. for (i=0; ibuttons |= BT_CHANGE; cmd->buttons |= i< 1 ) { dclickstate = mousebuttons[mousebforward]; if (dclickstate) dclicks++; if (dclicks == 2) { cmd->buttons |= BT_USE; dclicks = 0; } else dclicktime = 0; } else { dclicktime += ticdup; if (dclicktime > 20) { dclicks = 0; dclickstate = 0; } } // strafe double click bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; if (bstrafe != dclickstate2 && dclicktime2 > 1 ) { dclickstate2 = bstrafe; if (dclickstate2) dclicks2++; if (dclicks2 == 2) { cmd->buttons |= BT_USE; dclicks2 = 0; } else dclicktime2 = 0; } else { dclicktime2 += ticdup; if (dclicktime2 > 20) { dclicks2 = 0; dclickstate2 = 0; } } } forward += mousey; if (strafe) side += mousex*2; else cmd->angleturn -= mousex*0x8; if (mousex == 0) { // No movement in the previous frame testcontrols_mousespeed = 0; } mousex = mousey = 0; if (forward > MAXPLMOVE) forward = MAXPLMOVE; else if (forward < -MAXPLMOVE) forward = -MAXPLMOVE; if (side > MAXPLMOVE) side = MAXPLMOVE; else if (side < -MAXPLMOVE) side = -MAXPLMOVE; cmd->forwardmove += forward; cmd->sidemove += side; // special buttons if (sendpause) { sendpause = false; cmd->buttons = BT_SPECIAL | BTS_PAUSE; } if (sendsave) { sendsave = false; cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<angleturn + carry; // round angleturn to the nearest 256 unit boundary // for recording demos with single byte values for turn cmd->angleturn = (desired_angleturn + 128) & 0xff00; // Carry forward the error from the reduced resolution to the // next tic, so that successive small movements can accumulate. carry = desired_angleturn - cmd->angleturn; } } // // G_DoLoadLevel // void G_DoLoadLevel (void) { int i; // haleyjd 10/03/10: [STRIFE] This is not done here. //skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME)); levelstarttic = gametic; // for time calculation if (wipegamestate == GS_LEVEL) wipegamestate = -1; // force a wipe gamestate = GS_LEVEL; for (i=0 ; itype == ev_keydown && ev->data1 == key_spy && (singledemo || !gameskill) ) // [STRIFE]: o_O { // spy mode do { displayplayer++; if (displayplayer == MAXPLAYERS) displayplayer = 0; } while (!playeringame[displayplayer] && displayplayer != consoleplayer); return true; } // any other key pops up menu if in demos if (gameaction == ga_nothing && !singledemo && (demoplayback || gamestate == GS_DEMOSCREEN) ) { if (ev->type == ev_keydown || (ev->type == ev_mouse && ev->data1) || (ev->type == ev_joystick && ev->data1) ) { if(devparm && ev->data1 == 'g') D_PageTicker(); // [STRIFE]: wat? o_O else M_StartControlPanel (); return true; } return false; } if (gamestate == GS_LEVEL) { #if 0 if (devparm && ev->type == ev_keydown && ev->data1 == ';') { G_DeathMatchSpawnPlayer (0); return true; } #endif if (HU_Responder (ev)) return true; // chat ate the event if (ST_Responder (ev)) return true; // status window ate it if (AM_Responder (ev)) return true; // automap ate it } if (gamestate == GS_FINALE) { if (F_Responder (ev)) return true; // finale ate the event } if (testcontrols && ev->type == ev_mouse) { // If we are invoked by setup to test the controls, save the // mouse speed so that we can display it on-screen. // Perform a low pass filter on this so that the thermometer // appears to move smoothly. testcontrols_mousespeed = abs(ev->data2); } // If the next/previous weapon keys are pressed, set the next_weapon // variable to change weapons when the next ticcmd is generated. if (ev->type == ev_keydown && ev->data1 == key_prevweapon) { next_weapon = -1; } else if (ev->type == ev_keydown && ev->data1 == key_nextweapon) { next_weapon = 1; } switch (ev->type) { case ev_keydown: if (ev->data1 == key_pause) { sendpause = true; } else if (ev->data1 data1] = true; } return true; // eat key down events case ev_keyup: if (ev->data1 data1] = false; return false; // always let key up events filter down case ev_mouse: SetMouseButtons(ev->data1); mousex = ev->data2*(mouseSensitivity+5)/10; mousey = ev->data3*(mouseSensitivity+5)/10; return true; // eat events case ev_joystick: SetJoyButtons(ev->data1); joyxmove = ev->data2; joyymove = ev->data3; joystrafemove = ev->data4; return true; // eat events default: break; } return false; } // // G_Ticker // Make ticcmd_ts for the players. // void G_Ticker (void) { int i; int buf; ticcmd_t* cmd; // do player reborns if needed for (i=0 ; iforwardmove > TURBOTHRESHOLD) { turbodetected[i] = true; } if ((gametic & 31) == 0 && ((gametic >> 5) % MAXPLAYERS) == i && turbodetected[i]) { static char turbomessage[80]; M_snprintf(turbomessage, sizeof(turbomessage), "%s is turbo!", player_names[i]); players[consoleplayer].message = turbomessage; turbodetected[i] = false; } if (netgame && !netdemo && !(gametic%ticdup) ) { if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy) { I_Error ("consistency failure (%i should be %i)", cmd->consistancy, consistancy[i][buf]); } if (players[i].mo) consistancy[i][buf] = players[i].mo->x; else consistancy[i][buf] = rndindex; } } } // check for special buttons for (i=0 ; i>BTS_SAVESHIFT; gameaction = ga_savegame; break; } } } } // Have we just finished displaying an intermission screen? // haleyjd 08/23/10: [STRIFE] No intermission. /* if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION) { WI_End(); } */ oldgamestate = gamestate; // do main actions switch (gamestate) { case GS_LEVEL: P_Ticker (); ST_Ticker (); AM_Ticker (); HU_Ticker (); break; // haleyjd 08/23/10: [STRIFE] No intermission. /* case GS_INTERMISSION: WI_Ticker (); break; */ case GS_UNKNOWN: // STRIFE-TODO: What is this? is it ever used?? F_WaitTicker(); break; case GS_FINALE: F_Ticker (); break; case GS_DEMOSCREEN: D_PageTicker (); break; } } // // PLAYER STRUCTURE FUNCTIONS // also see P_SpawnPlayer in P_Things // // // G_InitPlayer // Called at the start. // Called by the game initialization functions. // // [STRIFE] No such function. /* void G_InitPlayer (int player) { player_t* p; // set up the saved info p = &players[player]; // clear everything else to defaults G_PlayerReborn (player); } */ // // G_PlayerFinishLevel // Can when a player completes a level. // // [STRIFE] No such function. The equivalent to this logic was moved into // G_DoCompleted. /* void G_PlayerFinishLevel (int player) { player_t* p; p = &players[player]; memset (p->powers, 0, sizeof (p->powers)); memset (p->cards, 0, sizeof (p->cards)); p->mo->flags &= ~MF_SHADOW; // cancel invisibility p->extralight = 0; // cancel gun flashes p->fixedcolormap = 0; // cancel ir gogles p->damagecount = 0; // no palette changes p->bonuscount = 0; } */ // // G_PlayerReborn // Called after a player dies // almost everything is cleared and initialized // // [STRIFE] Small changes for allegiance, inventory, health auto-use, and // mission objective. // void G_PlayerReborn (int player) { player_t* p; int i; int frags[MAXPLAYERS]; int killcount; int allegiance; killcount = players[player].killcount; allegiance = players[player].allegiance; // [STRIFE] memcpy(frags,players[player].frags,sizeof(frags)); p = &players[player]; memset (p, 0, sizeof(*p)); memcpy(p->frags, frags, sizeof(p->frags)); p->usedown = true; // don't do anything immediately p->attackdown = true; p->inventorydown = true; // villsa [STRIFE] p->playerstate = PST_LIVE; p->health = deh_initial_health; // Use dehacked value p->readyweapon = wp_fist; // villsa [STRIFE] default to fists p->pendingweapon = wp_fist; // villsa [STRIFE] default to fists p->weaponowned[wp_fist] = true; // villsa [STRIFE] default to fists p->cheats |= CF_AUTOHEALTH; // villsa [STRIFE] p->killcount = killcount; p->allegiance = allegiance; // villsa [STRIFE] p->centerview = true; // villsa [STRIFE] for(i = 0; i < NUMAMMO; i++) p->maxammo[i] = maxammo[i]; // [STRIFE] clear inventory for(i = 0; i < 32; i++) p->inventory[i].type = NUMMOBJTYPES; // villsa [STRIFE]: Default objective M_StringCopy(mission_objective, DEH_String("Find help"), OBJECTIVE_LEN); } // // G_CheckSpot // Returns false if the player cannot be respawned // at the given mapthing_t spot // because something is occupying it // // [STRIFE] Changed to eliminate body queue and an odd error message was added. // void P_SpawnPlayer (mapthing_t* mthing); boolean G_CheckSpot ( int playernum, mapthing_t* mthing ) { fixed_t x; fixed_t y; subsector_t* ss; unsigned an; mobj_t* mo; int i; if (!players[playernum].mo) { // [STRIFE] weird error message added here: if(leveltime > 0) players[playernum].message = DEH_String("you didn't have a body!"); // first spawn of level, before corpses for (i=0 ; ix == mthing->x << FRACBITS && players[i].mo->y == mthing->y << FRACBITS) return false; return true; } x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (!P_CheckPosition (players[playernum].mo, x, y) ) return false; // flush an old corpse if needed // [STRIFE] player corpses remove themselves after a short time, so // evidently this wasn't needed. /* if (bodyqueslot >= BODYQUESIZE) P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]); bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo; bodyqueslot++; */ // spawn a teleport fog ss = R_PointInSubsector (x,y); an = ( ANG45 * (((unsigned int) mthing->angle)/45) ) >> ANGLETOFINESHIFT; mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an] , ss->sector->floorheight , MT_TFOG); if (players[consoleplayer].viewz != 1) S_StartSound (mo, sfx_telept); // don't start sound on first frame return true; } // // G_DeathMatchSpawnPlayer // Spawns a player at one of the random death match spots // called at level load and each death // // [STRIFE]: Modified exit message to match binary. // void G_DeathMatchSpawnPlayer (int playernum) { int i,j; int selections; selections = deathmatch_p - deathmatchstarts; if (selections < 4) I_Error ("Only %i deathmatch spots, at least 4 required!", selections); for (j=0 ; j<20 ; j++) { i = P_Random() % selections; if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) { deathmatchstarts[i].type = playernum+1; P_SpawnPlayer (&deathmatchstarts[i]); return; } } // no good spot, so the player will probably get stuck P_SpawnPlayer (&playerstarts[playernum]); } // // G_LoadPath // // haleyjd 20101003: [STRIFE] New function // Sets loadpath based on the map and "savepathtemp" // void G_LoadPath(int map) { char mapbuf[33]; memset(mapbuf, 0, sizeof(mapbuf)); M_snprintf(mapbuf, sizeof(mapbuf), "%d", map); // haleyjd: free if already set, and use M_SafeFilePath if(loadpath) Z_Free(loadpath); loadpath = M_SafeFilePath(savepathtemp, mapbuf); } // // G_DoReborn // void G_DoReborn (int playernum) { int i; if (!netgame) { // reload the level from scratch // [STRIFE] Reborn level load G_LoadPath(gamemap); gameaction = ga_loadgame; } else { // respawn at the start // first dissasociate the corpse // [STRIFE] Checks for NULL first if(players[playernum].mo) players[playernum].mo->player = NULL; // spawn at random spot if in death match if (deathmatch) { G_DeathMatchSpawnPlayer (playernum); return; } if (G_CheckSpot (playernum, &playerstarts[playernum]) ) { P_SpawnPlayer (&playerstarts[playernum]); return; } // try to spawn at one of the other players spots for (i=0 ; i Abandoned Front Base map = 30; if(map == 7) // Castle -> New Front Base map = 10; } // no rifting in deathmatch games if(deathmatch) spot = 0; riftangle = angle; riftdest = spot; destmap = map; } // // G_Exit2 // // haleyjd 20101003: [STRIFE] New function. // No xrefs to this, doesn't seem to be used. Could have gotten inlined // somewhere but I haven't seen it. // void G_Exit2(int dest, angle_t angle) { riftdest = dest; gameaction = ga_completed; riftangle = angle; destmap = gamemap; } // // G_ExitLevel // // haleyjd 20100824: [STRIFE]: // * Default to next map in numeric order; init destmap and riftdest. // void G_ExitLevel (int dest) { if(dest == 0) dest = gamemap + 1; destmap = dest; riftdest = 0; gameaction = ga_completed; } /* // haleyjd 20100823: [STRIFE] No secret exits in Strife. // Here's for the german edition. void G_SecretExitLevel (void) { // IF NO WOLF3D LEVELS, NO SECRET EXIT! if ( (gamemode == commercial) && (W_CheckNumForName("map31")<0)) secretexit = false; else secretexit = true; gameaction = ga_completed; } */ // // G_StartFinale // // haleyjd 20100921: [STRIFE] New function. // This replaced G_SecretExitLevel in Strife. I don't know that it's actually // used anywhere in the game, but it *is* usable in mods via linetype 124, // W1 Start Finale. // void G_StartFinale(void) { gameaction = ga_victory; } // // G_DoCompleted // // haleyjd 20100823: [STRIFE]: // * Removed G_PlayerFinishLevel and just sets some powerup states. // * Removed Chex, as not relevant to Strife. // * Removed DOOM level transfer logic // * Removed intermission code. // * Added setting gameaction to ga_worlddone. // void G_DoCompleted (void) { int i; // deal with powerup states for(i = 0; i < MAXPLAYERS; i++) { if(playeringame[i]) { // [STRIFE] restore pw_allmap power from mapstate cache if(destmap < 40) players[i].powers[pw_allmap] = players[i].mapstate[destmap]; // Shadowarmor doesn't persist between maps in netgames if(netgame) players[i].powers[pw_invisibility] = 0; } } stonecold = false; // villsa [STRIFE] if (automapactive) AM_Stop (); // [STRIFE] HUB SAVE if(!deathmatch) G_DoSaveGame(savepathtemp); gameaction = ga_worlddone; } // haleyjd 20100824: [STRIFE] No secret exits. /* // // G_WorldDone // void G_WorldDone (void) { gameaction = ga_worlddone; if (secretexit) players[consoleplayer].didsecret = true; if ( gamemode == commercial ) { switch (gamemap) { case 15: case 31: if (!secretexit) break; case 6: case 11: case 20: case 30: F_StartFinale (); break; } } } */ // // G_RiftPlayer // // haleyjd 20100824: [STRIFE] New function // Teleports the player to the appropriate rift spot. // void G_RiftPlayer(void) { if(riftdest) { P_TeleportMove(players[0].mo, riftSpots[riftdest - 1].x << FRACBITS, riftSpots[riftdest - 1].y << FRACBITS); players[0].mo->angle = riftangle; players[0].mo->health = players[0].health; } } // // G_RiftCheat // // haleyjd 20100824: [STRIFE] New function // Called from the cheat code to jump to a rift spot. // boolean G_RiftCheat(int riftSpotNum) { return P_TeleportMove(players[0].mo, riftSpots[riftSpotNum - 1].x << FRACBITS, riftSpots[riftSpotNum - 1].y << FRACBITS); } // // G_DoWorldDone // // haleyjd 20100824: [STRIFE] Added destmap -> gamemap set. // void G_DoWorldDone (void) { int temp_leveltime = leveltime; boolean temp_shadow = false; boolean temp_mvis = false; gamestate = GS_LEVEL; gamemap = destmap; // [STRIFE] HUB LOAD G_LoadPath(destmap); if (!deathmatch) { // Remember Shadowarmor across hub loads if(players[0].mo->flags & MF_SHADOW) temp_shadow = true; if(players[0].mo->flags & MF_MVIS) temp_mvis = true; } G_DoLoadGame(false); // [STRIFE] leveltime carries over between maps leveltime = temp_leveltime; if(!deathmatch) { // [STRIFE]: transfer saved powerups players[0].mo->flags &= ~(MF_SHADOW|MF_MVIS); if(temp_shadow) players[0].mo->flags |= MF_SHADOW; if(temp_mvis) players[0].mo->flags |= MF_MVIS; // [STRIFE] HUB SAVE G_RiftPlayer(); G_DoSaveGame(savepathtemp); M_SaveMisObj(savepathtemp); } gameaction = ga_nothing; viewactive = true; } // // G_DoWorldDone2 // // haleyjd 20101003: [STRIFE] New function. No xrefs; unused. // void G_DoWorldDone2(void) { gamestate = GS_LEVEL; gameaction = ga_nothing; viewactive = true; } // // G_ReadCurrent // // haleyjd 20101003: [STRIFE] New function. // Reads the "CURRENT" file from the given path and then sets it to // gamemap. // void G_ReadCurrent(const char *path) { char *temppath = NULL; byte *buffer = NULL; temppath = M_SafeFilePath(path, "\\current"); if(M_ReadFile(temppath, &buffer) <= 0) gameaction = ga_newgame; else { // haleyjd 20110211: do endian-correct read gamemap = (((int)buffer[0]) | ((int)buffer[1] << 8) | ((int)buffer[2] << 16) | ((int)buffer[3] << 24)); gameaction = ga_loadgame; Z_Free(buffer); } Z_Free(temppath); G_LoadPath(gamemap); } // // G_InitFromSavegame // Can be called by the startup code or the menu task. // extern boolean setsizeneeded; void R_ExecuteSetViewSize (void); char savename[256]; // [STRIFE]: No such function. /* void G_LoadGame (char* name) { M_StringCopy(savename, name, sizeof(savename)); gameaction = ga_loadgame; } */ // haleyjd 20100928: [STRIFE] VERSIONSIZE == 8 #define VERSIONSIZE 8 void G_DoLoadGame (boolean userload) { int savedleveltime; gameaction = ga_nothing; save_stream = fopen(loadpath, "rb"); // [STRIFE] If the file does not exist, G_DoLoadLevel is called. if (save_stream == NULL) { G_DoLoadLevel(); return; } savegame_error = false; if (!P_ReadSaveGameHeader()) { fclose(save_stream); return; } // haleyjd: A comment would be good here, fraggle... // Evidently this is a Choco-ism, necessitated by reading the savegame // header *before* calling G_DoLoadLevel. savedleveltime = leveltime; // load a base level // STRIFE-TODO: ???? if(userload) G_InitNew(gameskill, gamemap); else G_DoLoadLevel(); leveltime = savedleveltime; // dearchive all the modifications // [STRIFE] some portions of player_t are not overwritten when loading // between hub levels P_UnArchivePlayers (userload); P_UnArchiveWorld (); P_UnArchiveThinkers (); P_UnArchiveSpecials (); if (!P_ReadSaveGameEOF()) I_Error ("Bad savegame"); fclose(save_stream); if (setsizeneeded) R_ExecuteSetViewSize (); // draw the pattern into the back screen R_FillBackScreen (); } // // G_WriteSaveName // // haleyjd 20101003: [STRIFE] New function // // Writes the character name to the NAME file. // boolean G_WriteSaveName(int slot, const char *charname) { //char savedir[16]; char *tmpname; boolean retval; savegameslot = slot; // haleyjd: removed special -cdrom treatment, as I believe it is taken // care of automatically via using Choco's savegamedir setting. // haleyjd: free previous path, if any, and allocate new one using // M_SafeFilePath routine, which isn't limited to 128 characters. if(savepathtemp) Z_Free(savepathtemp); savepathtemp = M_SafeFilePath(savegamedir, "strfsav6.ssg"); // haleyjd: as above. if(savepath) Z_Free(savepath); savepath = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(savegameslot, "")); // haleyjd: memset full character_name for safety memset(character_name, 0, CHARACTER_NAME_LEN); M_StringCopy(character_name, charname, sizeof(character_name)); // haleyjd: use M_SafeFilePath tmpname = M_SafeFilePath(savepathtemp, "name"); // Write the "name" file under the directory retval = M_WriteFile(tmpname, character_name, 32); Z_Free(tmpname); return retval; } // // G_SaveGame // Called by the menu task. // Description is a 24 byte text string // // [STRIFE] No such function, at least in v1.2 // STRIFE-TODO: Does this make a comeback in v1.31? /* void G_SaveGame ( int slot, char* description ) { savegameslot = slot; M_StringCopy(savedescription, description, sizeof(savedescription)); sendsave = true; } */ void G_DoSaveGame (char *path) { char *current_path; char *savegame_file; char *temp_savegame_file; byte gamemapbytes[4]; char gamemapstr[33]; temp_savegame_file = P_TempSaveGameFile(); // [STRIFE] custom save file path logic memset(gamemapstr, 0, sizeof(gamemapstr)); M_snprintf(gamemapstr, sizeof(gamemapstr), "%d", gamemap); savegame_file = M_SafeFilePath(path, gamemapstr); // [STRIFE] write the "current" file, which tells which hub map // the save slot is currently on. current_path = M_SafeFilePath(path, "current"); // haleyjd: endian-agnostic IO gamemapbytes[0] = (byte)( gamemap & 0xff); gamemapbytes[1] = (byte)((gamemap >> 8) & 0xff); gamemapbytes[2] = (byte)((gamemap >> 16) & 0xff); gamemapbytes[3] = (byte)((gamemap >> 24) & 0xff); M_WriteFile(current_path, gamemapbytes, 4); Z_Free(current_path); // Open the savegame file for writing. We write to a temporary file // and then rename it at the end if it was successfully written. // This prevents an existing savegame from being overwritten by // a corrupted one, or if a savegame buffer overrun occurs. save_stream = fopen(temp_savegame_file, "wb"); if (save_stream == NULL) { return; } savegame_error = false; P_WriteSaveGameHeader(savedescription); P_ArchivePlayers (); P_ArchiveWorld (); P_ArchiveThinkers (); P_ArchiveSpecials (); P_WriteSaveGameEOF(); // Enforce the same savegame size limit as in Vanilla Doom, // except if the vanilla_savegame_limit setting is turned off. // [STRIFE]: Verified subject to same limit. if (vanilla_savegame_limit && ftell(save_stream) > SAVEGAMESIZE) { I_Error ("Savegame buffer overrun"); } // Finish up, close the savegame file. fclose(save_stream); // Now rename the temporary savegame file to the actual savegame // file, overwriting the old savegame if there was one there. remove(savegame_file); rename(temp_savegame_file, savegame_file); // haleyjd: free the savegame_file path Z_Free(savegame_file); gameaction = ga_nothing; //M_StringCopy(savedescription, "", sizeof(savedescription)); // [STRIFE]: custom message logic if(!strcmp(path, savepath)) { M_snprintf(savename, sizeof(savename), "%s saved.", character_name); players[consoleplayer].message = savename; } // draw the pattern into the back screen R_FillBackScreen (); } // skill_t d_skill; //int d_episode; [STRIFE] No such thing as episodes in Strife int d_map; // // G_DeferedInitNew // // Can be called by the startup code or the menu task, // consoleplayer, displayplayer, playeringame[] should be set. // // haleyjd 20100922: [STRIFE] Removed episode parameter // void G_DeferedInitNew(skill_t skill, int map) { d_skill = skill; d_map = map; gameaction = ga_newgame; } // // G_DoNewGame // // [STRIFE] Code added to turn off the stonecold effect. // Someone also removed the nomonsters reset... // void G_DoNewGame (void) { demoplayback = false; netdemo = false; netgame = false; deathmatch = false; playeringame[1] = playeringame[2] = playeringame[3] = 0; respawnparm = false; fastparm = false; stonecold = false; // villsa [STRIFE] //nomonsters = false; [STRIFE] not set here!?! consoleplayer = 0; G_InitNew (d_skill, d_map); gameaction = ga_nothing; } // // G_InitNew // // haleyjd 20100824: [STRIFE]: // * Added riftdest initialization // * Removed episode parameter // void G_InitNew ( skill_t skill, int map ) { char *skytexturename; int i; if (paused) { paused = false; S_ResumeSound (); } if (skill > sk_nightmare) skill = sk_nightmare; // [STRIFE] Removed episode nonsense and gamemap clipping M_ClearRandom (); if (skill == sk_nightmare || respawnparm ) respawnmonsters = true; else respawnmonsters = false; // [STRIFE] Strife skill level mobjinfo/states tweaking // BUG: None of this code runs properly when loading save games, so // basically it's impossible to play any skill level properly unless // you never quit and reload from the command line. if(!skill && gameskill) { // Setting to Baby skill... make things easier. // Acolytes walk, attack, and feel pain slower for(i = S_AGRD_13; i <= S_AGRD_23; i++) states[i].tics *= 2; // Reavers attack slower for(i = S_ROB1_10; i <= S_ROB1_15; i++) states[i].tics *= 2; // Turrets attack slower for(i = S_TURT_02; i <= S_TURT_03; i++) states[i].tics *= 2; // Crusaders attack and feel pain slower for(i = S_ROB2_09; i <= S_ROB2_19; i++) states[i].tics *= 2; // Stalkers think, walk, and attack slower for(i = S_SPID_03; i <= S_SPID_10; i++) states[i].tics *= 2; // The Bishop's homing missiles are faster (what?? BUG?) mobjinfo[MT_SEEKMISSILE].speed *= 2; } if(skill && !gameskill) { // Setting a higher skill when previously on baby... make things normal // Acolytes for(i = S_AGRD_13; i <= S_AGRD_23; i++) states[i].tics >>= 1; // Reavers for(i = S_ROB1_10; i <= S_ROB1_15; i++) states[i].tics >>= 1; // Turrets for(i = S_TURT_02; i <= S_TURT_03; i++) states[i].tics >>= 1; // Crusaders for(i = S_ROB2_09; i <= S_ROB2_19; i++) states[i].tics >>= 1; // Stalkers for(i = S_SPID_03; i <= S_SPID_10; i++) states[i].tics >>= 1; // The Bishop's homing missiles - again, seemingly backward. mobjinfo[MT_SEEKMISSILE].speed >>= 1; } if(fastparm || (skill == sk_nightmare && skill != gameskill)) { // BLOODBATH! Make some things super-aggressive. // Acolytes walk, attack, and feel pain twice as fast // (This makes just getting out of the first room almost impossible) for(i = S_AGRD_13; i <= S_AGRD_23; i++) states[i].tics >>= 1; // Bishop's homing missiles again get SLOWER and not faster o_O mobjinfo[MT_SEEKMISSILE].speed >>= 1; } else if(skill != sk_nightmare && gameskill == sk_nightmare) { // Setting back to an ordinary skill after being on Bloodbath? // Put stuff back to normal. // Acolytes for(i = S_AGRD_13; i <= S_AGRD_23; i++) states[i].tics *= 2; // Bishop's homing missiles mobjinfo[MT_SEEKMISSILE].speed *= 2; } // force players to be initialized upon first level load for (i=0 ; i= 9 && gamemap < 32) skytexturename = "skymnt01"; else skytexturename = "skymnt02"; skytexturename = DEH_String(skytexturename); skytexture = R_TextureNumForName(skytexturename); // [STRIFE] HUBS G_LoadPath(gamemap); G_DoLoadLevel(); } // // DEMO RECORDING // #define DEMOMARKER 0x80 // // G_ReadDemoTiccmd // // [STRIFE] Modified for Strife ticcmd_t // void G_ReadDemoTiccmd (ticcmd_t* cmd) { if (*demo_p == DEMOMARKER) { // end of demo data stream G_CheckDemoStatus (); return; } cmd->forwardmove = ((signed char)*demo_p++); cmd->sidemove = ((signed char)*demo_p++); cmd->angleturn = ((unsigned char) *demo_p++)<<8; cmd->buttons = (unsigned char)*demo_p++; cmd->buttons2 = (unsigned char)*demo_p++; // [STRIFE] cmd->inventory = (int)*demo_p++; // [STRIFE] } // Increase the size of the demo buffer to allow unlimited demos static void IncreaseDemoBuffer(void) { int current_length; byte *new_demobuffer; byte *new_demop; int new_length; // Find the current size current_length = demoend - demobuffer; // Generate a new buffer twice the size new_length = current_length * 2; new_demobuffer = Z_Malloc(new_length, PU_STATIC, 0); new_demop = new_demobuffer + (demo_p - demobuffer); // Copy over the old data memcpy(new_demobuffer, demobuffer, current_length); // Free the old buffer and point the demo pointers at the new buffer. Z_Free(demobuffer); demobuffer = new_demobuffer; demo_p = new_demop; demoend = demobuffer + new_length; } // // G_WriteDemoTiccmd // // [STRIFE] Modified for Strife ticcmd_t. // void G_WriteDemoTiccmd (ticcmd_t* cmd) { byte *demo_start; if (gamekeydown[key_demo_quit]) // press q to end demo recording G_CheckDemoStatus (); demo_start = demo_p; *demo_p++ = cmd->forwardmove; *demo_p++ = cmd->sidemove; *demo_p++ = cmd->angleturn >> 8; *demo_p++ = cmd->buttons; *demo_p++ = cmd->buttons2; // [STRIFE] *demo_p++ = (byte)(cmd->inventory & 0xff); // [STRIFE] // reset demo pointer back demo_p = demo_start; if (demo_p > demoend - 16) { if (vanilla_demo_limit) { // no more space G_CheckDemoStatus (); return; } else { // Vanilla demo limit disabled: unlimited // demo lengths! IncreaseDemoBuffer(); } } G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same } // // G_RecordDemo // // [STRIFE] Verified unmodified // void G_RecordDemo (char* name) { size_t demoname_size; int i; int maxsize; usergame = false; demoname_size = strlen(name) + 5; demoname = Z_Malloc(demoname_size, PU_STATIC, NULL); M_snprintf(demoname, demoname_size, "%s.lmp", name); maxsize = 0x20000; //! // @arg // @category demo // @vanilla // // Specify the demo buffer size (KiB) // i = M_CheckParmWithArgs("-maxdemo", 1); if (i) maxsize = atoi(myargv[i+1])*1024; demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL); demoend = demobuffer + maxsize; demorecording = true; } void G_BeginRecording (void) { int i; // // @category demo // // Record a high resolution "Doom 1.91" demo. // // STRIFE-TODO: if somebody makes a "Strife Plus", we could add this. /* longtics = M_CheckParm("-longtics") != 0; */ longtics = false; // If not recording a longtics demo, record in low res lowres_turn = !longtics; demo_p = demobuffer; // Save the right version code for this demo *demo_p++ = STRIFE_VERSION; *demo_p++ = gameskill; //*demo_p++ = gameepisode; [STRIFE] Doesn't have episodes. *demo_p++ = gamemap; *demo_p++ = deathmatch; *demo_p++ = respawnparm; *demo_p++ = fastparm; *demo_p++ = nomonsters; *demo_p++ = consoleplayer; for (i=0 ; i #include "doomdef.h" #include "doomkeys.h" #include "v_video.h" #include "i_swap.h" #include "hu_lib.h" #include "r_local.h" #include "r_draw.h" #include "hu_stuff.h" // [STRIFE] // boolean : whether the screen is always erased #define noterased viewwindowx extern boolean automapactive; // in AM_map.c extern boolean D_PatchClipCallback(patch_t *patch, int x, int y); // [STRIFE] // // HUlib_drawYellowText // // haleyjd 20100918: [STRIFE] New function. // void HUlib_drawYellowText(int x, int y, char *text) { int start_x = x; char *rover = text; char c; while((c = *rover++)) { if(c == '\n') { x = start_x; y += 12; continue; } // haleyjd 20110213: found MORE code ignored/misinterpreted by Hex-Rays: // Underscores are replaced by spaces. if(c == '_') c = ' '; else if (c == ' ' && x == start_x) // skip spaces at the start of a line continue; c = toupper(c) - HU_FONTSTART; if(c >= 0 && c < HU_FONTSIZE) { patch_t *patch = yfont[(int) c]; int width = SHORT(patch->width); if(x + width <= (SCREENWIDTH - 20)) { // haleyjd: STRIFE-TODO: bit different than the exe... for now if(!D_PatchClipCallback(patch, x + SHORT(patch->leftoffset), y + SHORT(patch->topoffset))) return; V_DrawPatchDirect(x, y, patch); x = x + width; } else { x = start_x; --rover; y += 12; } } else { x += 4; } } } // // HUlib_init // // [STRIFE] Verified unmodified. // void HUlib_init(void) { } // // HUlib_clearTextLine // // [STRIFE] Verified unmodified. // void HUlib_clearTextLine(hu_textline_t* t) { t->len = 0; t->l[0] = 0; t->needsupdate = true; } // // HUlib_initTextLine // // [STRIFE] Verified unmodified // void HUlib_initTextLine ( hu_textline_t* t, int x, int y, patch_t** f, int sc ) { t->x = x; t->y = y; t->f = f; t->sc = sc; HUlib_clearTextLine(t); } // // HUlib_addCharToTextLine // // [STRIFE] Verified unmodified. // boolean HUlib_addCharToTextLine ( hu_textline_t* t, char ch ) { if (t->len == HU_MAXLINELENGTH) return false; else { t->l[t->len++] = ch; t->l[t->len] = 0; t->needsupdate = 4; return true; } } // // HUlib_delCharFromTextLine // // [STRIFE] Verified unmodified. // boolean HUlib_delCharFromTextLine(hu_textline_t* t) { if (!t->len) return false; else { t->l[--t->len] = 0; t->needsupdate = 4; return true; } } // // HUlib_drawTextLine // // haleyjd 09/18/10: [STRIFE] Modified to not draw underscores in text. // void HUlib_drawTextLine ( hu_textline_t* l, boolean drawcursor ) { int i; int w; int x; unsigned char c; // draw the new stuff x = l->x; for(i = 0; i < l->len; i++) { c = toupper(l->l[i]); if (c != ' ' && c >= l->sc && c < '_') // [STRIFE]: Underscores excluded { w = SHORT(l->f[c - l->sc]->width); if (x+w > SCREENWIDTH) break; V_DrawPatchDirect(x, l->y, l->f[c - l->sc]); x += w; } else { x += 4; if (x >= SCREENWIDTH) break; } } // draw the cursor if requested if (drawcursor && x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH) { V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]); } } // // HUlib_eraseTextLine // // sorta called by HU_Erase and just better darn get things straight // // [STRIFE] Verified unmodified. // void HUlib_eraseTextLine(hu_textline_t* l) { int lh; int y; int yoffset; // Only erases when NOT in automap and the screen is reduced, // and the text must either need updating or refreshing // (because of a recent change back from the automap) if (!automapactive && viewwindowx && l->needsupdate) { lh = SHORT(l->f[0]->height) + 1; for (y=l->y,yoffset=y*SCREENWIDTH ; yy+lh ; y++,yoffset+=SCREENWIDTH) { if (y < viewwindowy || y >= viewwindowy + viewheight) R_VideoErase(yoffset, SCREENWIDTH); // erase entire line else { R_VideoErase(yoffset, viewwindowx); // erase left border R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx); // erase right border } } } if (l->needsupdate) l->needsupdate--; } // // HUlib_initSText // // [STRIFE] Verified unmodified. // void HUlib_initSText ( hu_stext_t* s, int x, int y, int h, patch_t** font, int startchar, boolean* on ) { int i; s->h = h; s->on = on; s->laston = true; s->cl = 0; for (i=0;il[i], x, y - i*(SHORT(font[0]->height)+1), font, startchar); } } // // HUlib_addLineToSText // // [STRIFE] Verified unmodified. // void HUlib_addLineToSText(hu_stext_t* s) { int i; // add a clear line if (++s->cl == s->h) s->cl = 0; HUlib_clearTextLine(&s->l[s->cl]); // everything needs updating for (i=0 ; ih ; i++) s->l[i].needsupdate = 4; } // // HUlib_addMessageToSText // // [STRIFE] Verified unmodified. // void HUlib_addMessageToSText ( hu_stext_t* s, char* prefix, char* msg ) { HUlib_addLineToSText(s); if (prefix) while (*prefix) HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++)); while (*msg) HUlib_addCharToTextLine(&s->l[s->cl], *(msg++)); } // // HUlib_drawSText // // [STRIFE] Verified unmodified. // void HUlib_drawSText(hu_stext_t* s) { int i, idx; hu_textline_t *l; if (!*s->on) return; // if not on, don't draw // draw everything for (i=0 ; ih ; i++) { idx = s->cl - i; if (idx < 0) idx += s->h; // handle queue of lines l = &s->l[idx]; // need a decision made here on whether to skip the draw HUlib_drawTextLine(l, false); // no cursor, please } } // // HUlib_eraseSText // // [STRIFE] Verified unmodified. // void HUlib_eraseSText(hu_stext_t* s) { int i; for (i=0 ; ih ; i++) { if (s->laston && !*s->on) s->l[i].needsupdate = 4; HUlib_eraseTextLine(&s->l[i]); } s->laston = *s->on; } // // HUlib_initIText // // [STRIFE] Verified unmodified. // void HUlib_initIText ( hu_itext_t* it, int x, int y, patch_t** font, int startchar, boolean* on ) { it->lm = 0; // default left margin is start of text it->on = on; it->laston = true; HUlib_initTextLine(&it->l, x, y, font, startchar); } // The following deletion routines adhere to the left margin restriction // [STRIFE] Verified unmodified. void HUlib_delCharFromIText(hu_itext_t* it) { if (it->l.len != it->lm) HUlib_delCharFromTextLine(&it->l); } // [STRIFE] Verified unmodified. void HUlib_eraseLineFromIText(hu_itext_t* it) { while (it->lm != it->l.len) HUlib_delCharFromTextLine(&it->l); } // Resets left margin as well // [STRIFE] Verified unmodified. void HUlib_resetIText(hu_itext_t* it) { it->lm = 0; HUlib_clearTextLine(&it->l); } // // HUlib_addPrefixToIText // // [STRIFE] Verified unmodified. // void HUlib_addPrefixToIText ( hu_itext_t* it, char* str ) { while (*str) HUlib_addCharToTextLine(&it->l, *(str++)); it->lm = it->l.len; } // wrapper function for handling general keyed input. // returns true if it ate the key // [STRIFE] Verified unmodified. boolean HUlib_keyInIText ( hu_itext_t* it, unsigned char ch ) { ch = toupper(ch); if (ch >= ' ' && ch <= '_') HUlib_addCharToTextLine(&it->l, (char) ch); else if (ch == KEY_BACKSPACE) HUlib_delCharFromIText(it); else if (ch != KEY_ENTER) return false; // did not eat key return true; // ate the key } // // HUlib_drawIText // // [STRIFE] Verified unmodified. // void HUlib_drawIText(hu_itext_t* it) { hu_textline_t *l = &it->l; if (!*it->on) return; HUlib_drawTextLine(l, true); // draw the line w/ cursor } // // HUlib_eraseIText // // [STRIFE] Verified unmodified. // void HUlib_eraseIText(hu_itext_t* it) { if (it->laston && !*it->on) it->l.needsupdate = 4; HUlib_eraseTextLine(&it->l); it->laston = *it->on; } chocolate-doom-chocolate-doom-2.2.1/src/strife/hu_lib.h000066400000000000000000000071661257432200600230150ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // #ifndef __HULIB__ #define __HULIB__ // We are referring to patches. #include "r_defs.h" // font stuff #define HU_CHARERASE KEY_BACKSPACE #define HU_MAXLINES 4 #define HU_MAXLINELENGTH 80 // // Typedefs of widgets // // Text Line widget // (parent of Scrolling Text and Input Text widgets) typedef struct { // left-justified position of scrolling text window int x; int y; patch_t** f; // font int sc; // start character char l[HU_MAXLINELENGTH+1]; // line of text int len; // current line length // whether this line needs to be udpated int needsupdate; } hu_textline_t; // Scrolling Text window widget // (child of Text Line widget) typedef struct { hu_textline_t l[HU_MAXLINES]; // text lines to draw int h; // height in lines int cl; // current line number // pointer to boolean stating whether to update window boolean* on; boolean laston; // last value of *->on. } hu_stext_t; // Input Text Line widget // (child of Text Line widget) typedef struct { hu_textline_t l; // text line to input on // left margin past which I am not to delete characters int lm; // pointer to boolean stating whether to update window boolean* on; boolean laston; // last value of *->on; } hu_itext_t; // // Widget creation, access, and update routines // // initializes heads-up widget library void HUlib_init(void); // // textline code // // clear a line of text void HUlib_clearTextLine(hu_textline_t *t); void HUlib_initTextLine(hu_textline_t *t, int x, int y, patch_t **f, int sc); // returns success boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch); // returns success boolean HUlib_delCharFromTextLine(hu_textline_t *t); // draws tline void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor); // erases text line void HUlib_eraseTextLine(hu_textline_t *l); // villsa [STRIFE] void HUlib_drawYellowText(int x, int y, char *text); // // Scrolling Text window widget routines // // ? void HUlib_initSText ( hu_stext_t* s, int x, int y, int h, patch_t** font, int startchar, boolean* on ); // add a new line void HUlib_addLineToSText(hu_stext_t* s); // ? void HUlib_addMessageToSText ( hu_stext_t* s, char* prefix, char* msg ); // draws stext void HUlib_drawSText(hu_stext_t* s); // erases all stext lines void HUlib_eraseSText(hu_stext_t* s); // Input Text Line widget routines void HUlib_initIText ( hu_itext_t* it, int x, int y, patch_t** font, int startchar, boolean* on ); // enforces left margin void HUlib_delCharFromIText(hu_itext_t* it); // enforces left margin void HUlib_eraseLineFromIText(hu_itext_t* it); // resets line and left margin void HUlib_resetIText(hu_itext_t* it); // left of left-margin void HUlib_addPrefixToIText ( hu_itext_t* it, char* str ); // whether eaten boolean HUlib_keyInIText ( hu_itext_t* it, unsigned char ch ); void HUlib_drawIText(hu_itext_t* it); // erases all itext lines void HUlib_eraseIText(hu_itext_t* it); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/hu_stuff.c000066400000000000000000000434431257432200600233670ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Heads-up displays // #include #include "doomdef.h" #include "doomkeys.h" #include "z_zone.h" #include "deh_main.h" #include "i_swap.h" #include "i_video.h" #include "hu_stuff.h" #include "hu_lib.h" #include "m_controls.h" #include "m_misc.h" #include "w_wad.h" #include "s_sound.h" #include "doomstat.h" // Data. #include "dstrings.h" #include "sounds.h" // // Locally used constants, shortcuts. // #define HU_TITLE (mapnames[gamemap-1]) #define HU_TITLEHEIGHT 1 #define HU_TITLEX 0 // haleyjd 09/01/10: [STRIFE] 167 -> 160 to move up level name #define HU_TITLEY (160 - SHORT(hu_font[0]->height)) #define HU_INPUTTOGGLE 't' #define HU_INPUTX HU_MSGX #define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0]->height) +1)) #define HU_INPUTWIDTH 64 #define HU_INPUTHEIGHT 1 char *chat_macros[10] = { HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, HUSTR_CHATMACRO2, HUSTR_CHATMACRO3, HUSTR_CHATMACRO4, HUSTR_CHATMACRO5, HUSTR_CHATMACRO6, HUSTR_CHATMACRO7, HUSTR_CHATMACRO8, HUSTR_CHATMACRO9 }; // villsa [STRIFE] char player_names[8][16] = { "1: ", "2: ", "3: ", "4: ", "5: ", "6: ", "7: ", "8: " }; char chat_char; // remove later. static player_t* plr; patch_t* hu_font[HU_FONTSIZE]; patch_t* yfont[HU_FONTSIZE]; // haleyjd 09/18/10: [STRIFE] static hu_textline_t w_title; boolean chat_on; static hu_itext_t w_chat; static boolean always_off = false; static char chat_dest[MAXPLAYERS]; static hu_itext_t w_inputbuffer[MAXPLAYERS]; static boolean message_on; boolean message_dontfuckwithme; static boolean message_nottobefuckedwith; static hu_stext_t w_message; static int message_counter; //extern int showMessages; [STRIFE] no such variable static boolean headsupactive = false; // haleyjd 20130915 [STRIFE]: need nickname extern char *nickname; // haleyjd 20130915 [STRIFE]: true if setting nickname static boolean hu_setting_name = false; // // Builtin map names. // The actual names can be found in DStrings.h. // // haleyjd 08/31/10: [STRIFE] Changed for Strife level names. // List of names for levels. char *mapnames[] = { // Strife map names // First "episode" - Quest to destroy the Order's Castle HUSTR_1, HUSTR_2, HUSTR_3, HUSTR_4, HUSTR_5, HUSTR_6, HUSTR_7, HUSTR_8, HUSTR_9, // Second "episode" - Kill the Bishop and Make a Choice HUSTR_10, HUSTR_11, HUSTR_12, HUSTR_13, HUSTR_14, HUSTR_15, HUSTR_16, HUSTR_17, HUSTR_18, HUSTR_19, // Third "episode" - Shut down Factory, kill Loremaster and Entity HUSTR_20, HUSTR_21, HUSTR_22, HUSTR_23, HUSTR_24, HUSTR_25, HUSTR_26, HUSTR_27, HUSTR_28, HUSTR_29, // "Secret" levels - Abandoned Base and Training Facility HUSTR_30, HUSTR_31, // Demo version maps HUSTR_32, HUSTR_33, HUSTR_34 }; // // HU_Init // // haleyjd 09/18/10: [STRIFE] // * Modified to load yfont along with hu_font. // void HU_Init(void) { int i; int j; char buffer[9]; // load the heads-up font j = HU_FONTSTART; for (i=0;i This is definitely not the best that Rogue had to offer. Markov. // // Fastcall Registers: edx ebx // Temp Registers: esi edi void HU_addMessage(char *prefix, char *message) { char c; // eax int width = 0; // edx char *rover1; // ebx (in first loop) char *rover2; // ecx (in second loop) char *bufptr; // ebx (in second loop) char buffer[HU_MAXLINELENGTH+2]; // esp+52h // Loop 1: Total up width of prefix. rover1 = prefix; if(rover1) { while((c = *rover1)) { c = toupper(c) - HU_FONTSTART; ++rover1; if(c < 0 || c >= HU_FONTSIZE) width += 4; else width += SHORT(hu_font[(int) c]->width); } } // Loop 2: Copy as much of message into buffer as will fit on screen bufptr = buffer; rover2 = message; while((c = *rover2)) { if((c == ' ' || c == '-') && width > 285) break; *bufptr = c; ++bufptr; // BUG: No check for overflow. ++rover2; c = toupper(c); if(c == ' ' || c < '!' || c >= '_') width += 4; else { c -= HU_FONTSTART; width += SHORT(hu_font[(int) c]->width); } } // Too big to fit? // BUG: doesn't consider by how much it's over. if(width > 320) { // backup a char... hell if I know why. --bufptr; --rover2; } // rover2 is not at the end? if((c = *rover2)) { // if not ON a space... if(c != ' ') { // back up both pointers til one is found. // BUG: no check against LHS of buffer. Hurr! while(*bufptr != ' ') { --bufptr; --rover2; } } } *bufptr = '\0'; // Add two message lines. HUlib_addMessageToSText(&w_message, prefix, buffer); HUlib_addMessageToSText(&w_message, NULL, rover2); } // // HU_Ticker // // haleyjd 09/18/10: [STRIFE] Changes to split up message into two lines, // and support for player names (STRIFE-TODO: unfinished!) // void HU_Ticker(void) { int i, rc; char c; //char *prefix; STRIFE-TODO // tick down message counter if message is up if (message_counter && !--message_counter) { message_on = false; message_nottobefuckedwith = false; } // haleyjd 20110219: [STRIFE] this condition was removed //if (showMessages || message_dontfuckwithme) //{ // display message if necessary if ((plr->message && !message_nottobefuckedwith) || (plr->message && message_dontfuckwithme)) { //HUlib_addMessageToSText(&w_message, 0, plr->message); HU_addMessage(NULL, plr->message); // haleyjd [STRIFE] plr->message = 0; message_on = true; message_counter = HU_MSGTIMEOUT; message_nottobefuckedwith = message_dontfuckwithme; message_dontfuckwithme = 0; } //} // else message_on = false; // check for incoming chat characters if (netgame) { for (i=0 ; idata1 == KEY_RSHIFT) { return false; } else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT) { altdown = ev->type == ev_keydown; return false; } if (ev->type != ev_keydown) return false; if (!chat_on) { if (ev->data1 == key_message_refresh) { message_on = true; message_counter = HU_MSGTIMEOUT; eatkey = true; } else if (netgame && ev->data2 == key_multi_msg) { eatkey = chat_on = true; HUlib_resetIText(&w_chat); HU_queueChatChar(HU_BROADCAST); } // [STRIFE]: You cannot go straight to chatting with a particular // player from here... you must press 't' first. See below. } else { c = ev->data2; // send a macro if (altdown) { c = c - '0'; if (c > 9) return false; // fprintf(stderr, "got here\n"); macromessage = chat_macros[c]; // kill last message with a '\n' HU_queueChatChar(KEY_ENTER); // DEBUG!!! // send the macro message while (*macromessage) HU_queueChatChar(*macromessage++); HU_queueChatChar(KEY_ENTER); // leave chat mode and notify that it was sent chat_on = false; M_StringCopy(lastmessage, chat_macros[c], sizeof(lastmessage)); plr->message = lastmessage; eatkey = true; } else { if(w_chat.l.len) // [STRIFE]: past first char of chat? { eatkey = HUlib_keyInIText(&w_chat, c); if (eatkey) HU_queueChatChar(c); } else { // [STRIFE]: check for player-specific message; // slightly different than vanilla, to allow keys to be customized for(i = 0; i < MAXPLAYERS; i++) { if(c == key_multi_msgplayer[i]) break; } if(i < MAXPLAYERS) { // talking to self? if(i == consoleplayer) { num_nobrainers++; if (num_nobrainers < 3) plr->message = DEH_String(HUSTR_TALKTOSELF1); else if (num_nobrainers < 6) plr->message = DEH_String(HUSTR_TALKTOSELF2); else if (num_nobrainers < 9) plr->message = DEH_String(HUSTR_TALKTOSELF3); else if (num_nobrainers < 32) plr->message = DEH_String(HUSTR_TALKTOSELF4); else plr->message = DEH_String(HUSTR_TALKTOSELF5); } else { eatkey = true; HU_queueChatChar(i+1); DEH_snprintf(lastmessage, sizeof(lastmessage), "Talking to: %c", '1' + i); plr->message = lastmessage; } } else if(c == '$') // [STRIFE]: name changing { eatkey = true; HU_queueChatChar(HU_CHANGENAME); M_StringCopy(lastmessage, DEH_String("Changing Name:"), sizeof(lastmessage)); plr->message = lastmessage; hu_setting_name = true; } else { eatkey = HUlib_keyInIText(&w_chat, c); if (eatkey) HU_queueChatChar(c); } } if (c == KEY_ENTER) { chat_on = false; if (w_chat.l.len) { // [STRIFE]: name setting if(hu_setting_name) { DEH_snprintf(lastmessage, sizeof(lastmessage), "%s now %.13s", player_names[consoleplayer], w_chat.l.l); // haleyjd 20141024: missing name set for local client DEH_snprintf(player_names[consoleplayer], sizeof(player_names[consoleplayer]), "%.13s: ", w_chat.l.l); hu_setting_name = false; } else { M_StringCopy(lastmessage, w_chat.l.l, sizeof(lastmessage)); } plr->message = lastmessage; } } else if (c == KEY_ESCAPE) chat_on = false; } } return eatkey; } chocolate-doom-chocolate-doom-2.2.1/src/strife/hu_stuff.h000066400000000000000000000034401257432200600233650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Head up display // #ifndef __HU_STUFF_H__ #define __HU_STUFF_H__ #include "d_event.h" #include "v_patch.h" // // Globally visible constants. // #define HU_FONTSTART '!' // the first font characters #define HU_FONTEND '_' // the last font characters // Calculate # of glyphs in font. #define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) #define HU_BROADCAST 9 // haleyjd [STRIFE] Changed 5 -> 9 #define HU_CHANGENAME 10 // haleyjd [STRIFE] Special command #define HU_MSGX 0 #define HU_MSGY (SHORT(hu_font[0]->height) + 1) // [STRIFE]: DOOM bug fix #define HU_MSGWIDTH 64 // in characters #define HU_MSGHEIGHT 2 // in lines #define HU_MSGTIMEOUT (8*TICRATE) // haleyjd [STRIFE] Doubled message timeout // // HEADS UP TEXT // void HU_Init(void); void HU_Start(void); boolean HU_Responder(event_t* ev); void HU_Ticker(void); void HU_Drawer(void); char HU_dequeueChatChar(void); void HU_Erase(void); extern char *chat_macros[10]; extern char player_names[8][16]; // villsa [STRIFE] // haleyjd [STRIFE] externalized: extern char *mapnames[]; // [STRIFE] extern patch_t* yfont[HU_FONTSIZE]; // haleyjd 09/18/10: [STRIFE] #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/info.c000066400000000000000000014615601257432200600225040ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Thing frame/state LUT, // generated by multigen utilitiy. // This one is the original DOOM version, preserved. // #include #include // Data. #include "sounds.h" #include "m_fixed.h" #include "info.h" #include "p_mobj.h" // villsa [STRIFE] char *sprnames[NUMSPRITES+1] = { "PLAY", "PNCH", "WAVE", "RBPY", "TRGT", "XBOW", "MMIS", "RIFG", "RIFF", "FLMT", "FLMF", "BLST", "BLSF", "GREN", "GREF", "SIGH", "SIGF", "POW1", "POW2", "POW3", "ZAP1", "SPRY", "BLOD", "PUFY", "SHT1", "SHT2", "GRIN", "GRAP", "UBAM", "BNG2", "BNG4", "BNG3", "FLBE", "XPRK", "OCLW", "CCLW", "TEND", "MICR", "MISS", "AROW", "ARWP", "TORP", "THIT", "TWAV", "MISL", "TFOG", "IFOG", "SHRD", "RGIB", "MRYS", "MRNO", "MRST", "MRLK", "MRBD", "MRPN", "MRGT", "BURN", "DISR", "PEAS", "GIBS", "AGRD", "ARMR", "SACR", "TNK1", "TNK2", "TNK3", "TNK4", "TNK5", "TNK6", "NEAL", "BEGR", "HMN1", "LEDR", "LEAD", "ROB1", "PGRD", "ROB2", "MLDR", "ORCL", "PRST", "PDED", "ALN1", "AL1P", "NODE", "MTHD", "MNAM", "MNAL", "MDTH", "NEST", "PODD", "ZAP6", "ZOT3", "ZAP7", "ZOT1", "ZAP5", "ZOT2", "SEWR", "SPID", "ROB3", "RBB3", "PRGR", "BASE", "FRBL", "KLAX", "TURT", "BALL", "PSTN", "SECR", "TARG", "RING", "EARS", "COMM", "BOOM", "RATT", "HOGN", "DEAD", "SBAN", "BOTR", "HATR", "TOPR", "COUP", "BUBB", "BUBF", "BUBC", "ASPR", "SPDL", "TOKN", "OTOK", "HELT", "GUNT", "FULL", "MEAT", "JUNK", "FFOT", "DIE1", "BEAC", "ARM1", "ARM2", "BARW", "BART", "LAMP", "LANT", "BARL", "BOWL", "BRAZ", "TRCH", "LTRH", "LMPC", "LOGS", "TRHO", "WATR", "MUGG", "FUSL", "CRD1", "CRD2", "TPAS", "KY1G", "KY2S", "KY3B", "HAND", "CRYS", "PRIS", "PWR1", "PWR2", "PWR3", "ORAC", "GYID", "FUBR", "WARE", "RCRY", "BCRY", "CHAP", "TUNL", "BLTK", "SECK", "MINE", "REBL", "PROC", "ANKH", "GOID", "STMP", "MDKT", "COIN", "CRED", "SACK", "CHST", "SHD1", "MASK", "UNIF", "OFIC", "PMAP", "PMUP", "BLIT", "BBOX", "MSSL", "ROKT", "BRY1", "CPAC", "PQRL", "XQRL", "GRN1", "GRN2", "BKPK", "RELC", "RIFL", "FLAM", "BFLM", "MMSL", "TRPD", "GRND", "CBOW", "SIGL", "LITE", "CNDL", "CLBR", "LITS", "LITB", "LITG", "ROK1", "ROK2", "ROK3", "ROK4", "LOGG", "RUB1", "RUB2", "RUB3", "RUB4", "RUB5", "RUB6", "RUB7", "RUB8", "CHAN", "STAT", "DSTA", "CRAB", "CAGE", "TREE", "TRE1", "BUSH", "SHRB", "STAK", "BAR1", "VASE", "STOL", "POT1", "TUB1", "ANVL", "TLMP", "TRAY", "APOW", "AFED", "DRIP", "CDRP", "SPLH", "WTFT", "HERT", "TELP", "MONI", "STEL", "STLA", "STLE", "HUGE", "STLG", NULL }; // Doesn't work with g++, needs actionf_p1 // villsa [STRIFE] void A_Look(); void A_RandomWalk(); void A_FriendLook(); void A_Listen(); void A_Chase(); void A_FaceTarget(); void A_PeasantPunch(); void A_ReaverAttack(); void A_BulletAttack(); void A_CheckTargetVisible(); void A_SentinelAttack(); void A_StalkerThink(); void A_StalkerSetLook(); void A_StalkerDrop(); void A_StalkerScratch(); void A_FloatWeave(); void A_RobotMelee(); void A_TemplarMauler(); void A_CrusaderAttack(); void A_CrusaderLeft(); void A_CrusaderRight(); void A_CheckTargetVisible2(); void A_InqFlyCheck(); void A_InqGrenade(); void A_InqTakeOff(); void A_InqFly(); void A_FireSigilWeapon(); void A_ProgrammerAttack(); void A_Sigil_A_Action(); void A_SpectreEAttack(); void A_SpectreCAttack(); void A_AlertSpectreC(); void A_Sigil_E_Action(); void A_SigilTrail(); void A_SpectreDAttack(); void A_FireSigilEOffshoot(); void A_ShadowOff(); void A_ModifyVisibility(); void A_ShadowOn(); void A_SetTLOptions(); void A_BossMeleeAtk(); void A_BishopAttack(); void A_FireHookShot(); void A_FireChainShot(); void A_MissileSmoke(); void A_SpawnSparkPuff(); void A_Tracer(); void A_ProgrammerMelee(); void A_Scream(); void A_XScream(); void A_Pain(); void A_PeasantCrash(); void A_Fall(); void A_HideZombie(); void A_MerchantPain(); void A_ProgrammerDie(); void A_InqTossArm(); void A_SpawnSpectreB(); void A_SpawnSpectreD(); void A_SpawnSpectreE(); void A_SpawnEntity(); void A_EntityDeath(); void A_SpawnZombie(); void A_ZombieInSpecialSector(); void A_CrystalExplode(); void A_QuestMsg(); void A_ExtraLightOff(); void A_CrystalRadiusAtk(); void A_DeathExplode5(); void A_DeathExplode1(); void A_DeathExplode2(); void A_DeathExplode3(); void A_RaiseAlarm(); void A_MissileTick(); void A_SpawnGrenadeFire(); void A_NodeChunk(); void A_HeadChunk(); void A_BurnSpread(); void A_AcolyteSpecial(); void A_BossDeath(); void A_InqChase(); void A_StalkerChase(); void A_PlayerScream(); void A_TeleportBeacon(); void A_BodyParts(); void A_ClaxonBlare(); void A_ActiveSound(); void A_ClearSoundTarget(); void A_DropBurnFlesh(); void A_FlameDeath(); void A_ClearForceField(); void A_WeaponReady(); void A_ReFire(); void A_CheckReload(); void A_Lower(); void A_Raise(); void A_GunFlash(); void A_Punch(); void A_FireFlameThrower(); void A_FireMissile(); void A_FireMauler2(); void A_FireGrenade(); void A_FireElectricBolt(); void A_FirePoisonBolt(); void A_FireRifle(); void A_FireMauler1(); void A_SigilSound(); void A_FireSigil(); void A_GunFlashThinker(); void A_Light0(); void A_Light1(); void A_Light2(); void A_SigilShock(); void A_TorpedoExplode(); void A_MaulerSound(); // villsa [STRIFE] state_t states[NUMSTATES] = { /*S_NULL*/ { SPR_PLAY, 0, -1, { NULL }, S_NULL }, //00 /*S_PNCH_00*/ { SPR_PNCH, 0, 0, { A_Light0 }, S_NULL }, //01 /*S_WAVE_00*/ { SPR_WAVE, 32768, 3, { NULL }, S_WAVE_01 }, //02 /*S_WAVE_01*/ { SPR_WAVE, 32769, 3, { NULL }, S_WAVE_02 }, //03 /*S_WAVE_02*/ { SPR_WAVE, 32770, 3, { NULL }, S_WAVE_03 }, //04 /*S_WAVE_03*/ { SPR_WAVE, 32771, 3, { NULL }, S_WAVE_00 }, //05 /*S_RBPY_00*/ { SPR_RBPY, 32768, 3, { NULL }, S_RBPY_01 }, //06 /*S_RBPY_01*/ { SPR_RBPY, 32769, 3, { NULL }, S_RBPY_02 }, //07 /*S_RBPY_02*/ { SPR_RBPY, 32770, 3, { NULL }, S_RBPY_03 }, //08 /*S_RBPY_03*/ { SPR_RBPY, 32771, 3, { NULL }, S_RBPY_00 }, //09 /*S_TRGT_00*/ { SPR_TRGT, 0, -1, { NULL }, S_NULL }, //10 /*S_TRGT_01*/ { SPR_TRGT, 1, -1, { NULL }, S_NULL }, //11 /*S_TRGT_02*/ { SPR_TRGT, 2, -1, { NULL }, S_NULL }, //12 /*S_PNCH_01*/ { SPR_PNCH, 0, 1, { A_WeaponReady }, S_PNCH_01 }, //13 /*S_PNCH_02*/ { SPR_PNCH, 0, 1, { A_Lower }, S_PNCH_02 }, //14 /*S_PNCH_03*/ { SPR_PNCH, 0, 1, { A_Raise }, S_PNCH_03 }, //15 /*S_PNCH_04*/ { SPR_PNCH, 1, 4, { NULL }, S_PNCH_05 }, //16 /*S_PNCH_05*/ { SPR_PNCH, 2, 4, { A_Punch }, S_PNCH_06 }, //17 /*S_PNCH_06*/ { SPR_PNCH, 3, 5, { NULL }, S_PNCH_07 }, //18 /*S_PNCH_07*/ { SPR_PNCH, 2, 4, { NULL }, S_PNCH_08 }, //19 /*S_PNCH_08*/ { SPR_PNCH, 1, 5, { A_ReFire }, S_PNCH_01 }, //20 /*S_XBOW_00*/ { SPR_XBOW, 0, 1, { A_WeaponReady }, S_XBOW_00 }, //21 /*S_XBOW_01*/ { SPR_XBOW, 0, 1, { A_Lower }, S_XBOW_01 }, //22 /*S_XBOW_02*/ { SPR_XBOW, 0, 1, { A_Raise }, S_XBOW_02 }, //23 /*S_XBOW_03*/ { SPR_XBOW, 0, 3, { A_GunFlashThinker }, S_XBOW_04 }, //24 /*S_XBOW_04*/ { SPR_XBOW, 1, 6, { A_FireElectricBolt }, S_XBOW_05 }, //25 /*S_XBOW_05*/ { SPR_XBOW, 2, 4, { NULL }, S_XBOW_06 }, //26 /*S_XBOW_06*/ { SPR_XBOW, 3, 6, { NULL }, S_XBOW_07 }, //27 /*S_XBOW_07*/ { SPR_XBOW, 4, 3, { NULL }, S_XBOW_08 }, //28 /*S_XBOW_08*/ { SPR_XBOW, 5, 5, { NULL }, S_XBOW_09 }, //29 /*S_XBOW_09*/ { SPR_XBOW, 6, 5, { A_CheckReload }, S_XBOW_00 }, //30 /*S_XBOW_10*/ { SPR_XBOW, 10, 5, { NULL }, S_XBOW_11 }, //31 /*S_XBOW_11*/ { SPR_XBOW, 11, 5, { NULL }, S_XBOW_12 }, //32 /*S_XBOW_12*/ { SPR_XBOW, 12, 5, { NULL }, S_XBOW_10 }, //33 /*S_XBOW_13*/ { SPR_XBOW, 7, 1, { A_WeaponReady }, S_XBOW_13 }, //34 /*S_XBOW_14*/ { SPR_XBOW, 7, 1, { A_Lower }, S_XBOW_14 }, //35 /*S_XBOW_15*/ { SPR_XBOW, 7, 1, { A_Raise }, S_XBOW_15 }, //36 /*S_XBOW_16*/ { SPR_XBOW, 7, 3, { NULL }, S_XBOW_17 }, //37 /*S_XBOW_17*/ { SPR_XBOW, 1, 6, { A_FirePoisonBolt }, S_XBOW_18 }, //38 /*S_XBOW_18*/ { SPR_XBOW, 2, 4, { NULL }, S_XBOW_19 }, //39 /*S_XBOW_19*/ { SPR_XBOW, 3, 6, { NULL }, S_XBOW_20 }, //40 /*S_XBOW_20*/ { SPR_XBOW, 4, 3, { NULL }, S_XBOW_21 }, //41 /*S_XBOW_21*/ { SPR_XBOW, 8, 5, { NULL }, S_XBOW_22 }, //42 /*S_XBOW_22*/ { SPR_XBOW, 9, 5, { A_CheckReload }, S_XBOW_13 }, //43 /*S_MMIS_00*/ { SPR_MMIS, 0, 1, { A_WeaponReady }, S_MMIS_00 }, //44 /*S_MMIS_01*/ { SPR_MMIS, 0, 1, { A_Lower }, S_MMIS_01 }, //45 /*S_MMIS_02*/ { SPR_MMIS, 0, 1, { A_Raise }, S_MMIS_02 }, //46 /*S_MMIS_03*/ { SPR_MMIS, 0, 4, { A_FireMissile }, S_MMIS_04 }, //47 /*S_MMIS_04*/ { SPR_MMIS, 1, 4, { A_Light1 }, S_MMIS_05 }, //48 /*S_MMIS_05*/ { SPR_MMIS, 32770, 5, { NULL }, S_MMIS_06 }, //49 /*S_MMIS_06*/ { SPR_MMIS, 32771, 2, { A_Light2 }, S_MMIS_07 }, //50 /*S_MMIS_07*/ { SPR_MMIS, 32772, 2, { NULL }, S_MMIS_08 }, //51 /*S_MMIS_08*/ { SPR_MMIS, 32773, 2, { A_Light0 }, S_MMIS_09 }, //52 /*S_MMIS_09*/ { SPR_MMIS, 5, 0, { A_ReFire }, S_MMIS_00 }, //53 /*S_RIFG_00*/ { SPR_RIFG, 0, 1, { A_WeaponReady }, S_RIFG_00 }, //54 /*S_RIFG_01*/ { SPR_RIFG, 1, 1, { A_Lower }, S_RIFG_01 }, //55 /*S_RIFG_02*/ { SPR_RIFG, 0, 1, { A_Raise }, S_RIFG_02 }, //56 /*S_RIFF_00*/ { SPR_RIFF, 0, 3, { A_FireRifle }, S_RIFF_01 }, //57 /*S_RIFF_01*/ { SPR_RIFF, 1, 3, { A_FireRifle }, S_RIFG_03 }, //58 /*S_RIFG_03*/ { SPR_RIFG, 3, 3, { A_FireRifle }, S_RIFG_04 }, //59 /*S_RIFG_04*/ { SPR_RIFG, 2, 0, { A_ReFire }, S_RIFG_05 }, //60 /*S_RIFG_05*/ { SPR_RIFG, 1, 2, { NULL }, S_RIFG_00 }, //61 /*S_FLMT_00*/ { SPR_FLMT, 0, 3, { A_WeaponReady }, S_FLMT_01 }, //62 /*S_FLMT_01*/ { SPR_FLMT, 1, 3, { A_WeaponReady }, S_FLMT_00 }, //63 /*S_FLMT_02*/ { SPR_FLMT, 0, 1, { A_Lower }, S_FLMT_02 }, //64 /*S_FLMT_03*/ { SPR_FLMT, 0, 1, { A_Raise }, S_FLMT_03 }, //65 /*S_FLMF_00*/ { SPR_FLMF, 0, 2, { A_FireFlameThrower }, S_FLMF_01 }, //66 /*S_FLMF_01*/ { SPR_FLMF, 1, 3, { A_ReFire }, S_FLMT_00 }, //67 /*S_BLST_00*/ { SPR_BLST, 5, 6, { A_WeaponReady }, S_BLST_01 }, //68 /*S_BLST_01*/ { SPR_BLST, 6, 6, { A_WeaponReady }, S_BLST_02 }, //69 /*S_BLST_02*/ { SPR_BLST, 7, 6, { A_WeaponReady }, S_BLST_03 }, //70 /*S_BLST_03*/ { SPR_BLST, 0, 6, { A_WeaponReady }, S_BLST_00 }, //71 /*S_BLST_04*/ { SPR_BLST, 0, 1, { A_Lower }, S_BLST_04 }, //72 /*S_BLST_05*/ { SPR_BLST, 0, 1, { A_Raise }, S_BLST_05 }, //73 /*S_BLSF_00*/ { SPR_BLSF, 32768, 5, { A_FireMauler1 }, S_BLST_06 }, //74 /*S_BLST_06*/ { SPR_BLST, 32769, 3, { A_Light1 }, S_BLST_07 }, //75 /*S_BLST_07*/ { SPR_BLST, 2, 2, { A_Light2 }, S_BLST_08 }, //76 /*S_BLST_08*/ { SPR_BLST, 3, 2, { NULL }, S_BLST_09 }, //77 /*S_BLST_09*/ { SPR_BLST, 4, 2, { NULL }, S_BLST_10 }, //78 /*S_BLST_10*/ { SPR_BLST, 0, 7, { A_Light0 }, S_BLST_11 }, //79 /*S_BLST_11*/ { SPR_BLST, 7, 7, { NULL }, S_BLST_12 }, //80 /*S_BLST_12*/ { SPR_BLST, 6, 7, { A_CheckReload }, S_BLST_00 }, //81 /*S_BLST_13*/ { SPR_BLST, 8, 7, { A_WeaponReady }, S_BLST_14 }, //82 /*S_BLST_14*/ { SPR_BLST, 9, 7, { A_WeaponReady }, S_BLST_15 }, //83 /*S_BLST_15*/ { SPR_BLST, 10, 7, { A_WeaponReady }, S_BLST_16 }, //84 /*S_BLST_16*/ { SPR_BLST, 11, 7, { A_WeaponReady }, S_BLST_13 }, //85 /*S_BLST_17*/ { SPR_BLST, 8, 1, { A_Lower }, S_BLST_17 }, //86 /*S_BLST_18*/ { SPR_BLST, 8, 1, { A_Raise }, S_BLST_18 }, //87 /*S_BLST_19*/ { SPR_BLST, 8, 20, { A_MaulerSound }, S_BLST_20 }, //88 /*S_BLST_20*/ { SPR_BLST, 9, 10, { A_Light1 }, S_BLSF_01 }, //89 /*S_BLSF_01*/ { SPR_BLSF, 32768, 10, { A_FireMauler2 }, S_BLST_21 }, //90 /*S_BLST_21*/ { SPR_BLST, 32769, 3, { A_Light2 }, S_BLST_22 }, //91 /*S_BLST_22*/ { SPR_BLST, 2, 2, { NULL }, S_BLST_23 }, //92 /*S_BLST_23*/ { SPR_BLST, 3, 2, { A_Light0 }, S_BLST_24 }, //93 /*S_BLST_24*/ { SPR_BLST, 4, 2, { A_ReFire }, S_BLST_13 }, //94 /*S_GREN_00*/ { SPR_GREN, 0, 1, { A_WeaponReady }, S_GREN_00 }, //95 /*S_GREN_01*/ { SPR_GREN, 0, 1, { A_Lower }, S_GREN_01 }, //96 /*S_GREN_02*/ { SPR_GREN, 0, 1, { A_Raise }, S_GREN_02 }, //97 /*S_GREN_03*/ { SPR_GREN, 0, 5, { A_FireGrenade }, S_GREN_04 }, //98 /*S_GREN_04*/ { SPR_GREN, 1, 10, { NULL }, S_GREN_05 }, //99 /*S_GREN_05*/ { SPR_GREN, 0, 5, { A_FireGrenade }, S_GREN_06 }, //100 /*S_GREN_06*/ { SPR_GREN, 2, 10, { NULL }, S_GREN_07 }, //101 /*S_GREN_07*/ { SPR_GREN, 0, 0, { A_ReFire }, S_GREN_00 }, //102 /*S_GREF_00*/ { SPR_GREF, 32768, 5, { A_Light1 }, S_PNCH_00 }, //103 /*S_GREF_01*/ { SPR_GREF, 0, 10, { A_Light0 }, S_PNCH_00 }, //104 /*S_GREF_02*/ { SPR_GREF, 32769, 5, { A_Light2 }, S_PNCH_00 }, //105 /*S_GREN_08*/ { SPR_GREN, 3, 1, { A_WeaponReady }, S_GREN_08 }, //106 /*S_GREN_09*/ { SPR_GREN, 3, 1, { A_Lower }, S_GREN_09 }, //107 /*S_GREN_10*/ { SPR_GREN, 3, 1, { A_Raise }, S_GREN_10 }, //108 /*S_GREN_11*/ { SPR_GREN, 3, 5, { A_FireGrenade }, S_GREN_12 }, //109 /*S_GREN_12*/ { SPR_GREN, 4, 10, { NULL }, S_GREN_13 }, //110 /*S_GREN_13*/ { SPR_GREN, 3, 5, { A_FireGrenade }, S_GREN_14 }, //111 /*S_GREN_14*/ { SPR_GREN, 5, 10, { NULL }, S_GREN_15 }, //112 /*S_GREN_15*/ { SPR_GREN, 0, 0, { A_ReFire }, S_GREN_08 }, //113 /*S_GREF_03*/ { SPR_GREF, 32770, 5, { A_Light1 }, S_PNCH_00 }, //114 /*S_GREF_04*/ { SPR_GREF, 2, 10, { A_Light0 }, S_PNCH_00 }, //115 /*S_GREF_05*/ { SPR_GREF, 32771, 5, { A_Light2 }, S_PNCH_00 }, //116 /*S_SIGH_00*/ { SPR_SIGH, 32768, 1, { A_WeaponReady }, S_SIGH_00 }, //117 /*S_SIGH_01*/ { SPR_SIGH, 32769, -1, { NULL }, S_NULL }, //118 /*S_SIGH_02*/ { SPR_SIGH, 32770, -1, { NULL }, S_NULL }, //119 /*S_SIGH_03*/ { SPR_SIGH, 32771, -1, { NULL }, S_NULL }, //120 /*S_SIGH_04*/ { SPR_SIGH, 32772, -1, { NULL }, S_NULL }, //121 /*S_SIGH_05*/ { SPR_SIGH, 32768, 1, { A_Lower }, S_SIGH_05 }, //122 /*S_SIGH_06*/ { SPR_SIGH, 32768, 1, { A_Raise }, S_SIGH_06 }, //123 /*S_SIGH_07*/ { SPR_SIGH, 32768, 18, { A_SigilSound }, S_SIGH_08 }, //124 /*S_SIGH_08*/ { SPR_SIGH, 32768, 3, { A_GunFlash }, S_SIGH_09 }, //125 /*S_SIGH_09*/ { SPR_SIGH, 0, 10, { A_FireSigil }, S_SIGH_10 }, //126 /*S_SIGH_10*/ { SPR_SIGH, 0, 5, { A_GunFlashThinker }, S_SIGH_00 }, //127 /*S_SIGF_00*/ { SPR_SIGF, 32768, 4, { A_Light2 }, S_SIGF_01 }, //128 /*S_SIGF_01*/ { SPR_SIGF, 32769, 6, { A_SigilShock }, S_SIGF_02 }, //129 /*S_SIGF_02*/ { SPR_SIGF, 32770, 4, { A_Light1 }, S_PNCH_00 }, //130 /*S_POW1_00*/ { SPR_POW1, 0, 4, { NULL }, S_POW1_01 }, //131 /*S_POW1_01*/ { SPR_POW1, 1, 4, { NULL }, S_POW1_02 }, //132 /*S_POW1_02*/ { SPR_POW1, 2, 4, { NULL }, S_POW1_03 }, //133 /*S_POW1_03*/ { SPR_POW1, 3, 4, { NULL }, S_POW1_04 }, //134 /*S_POW1_04*/ { SPR_POW1, 4, 4, { NULL }, S_NULL }, //135 /*S_POW1_05*/ { SPR_POW1, 5, 4, { NULL }, S_POW1_06 }, //136 /*S_POW1_06*/ { SPR_POW1, 6, 4, { NULL }, S_POW1_07 }, //137 /*S_POW1_07*/ { SPR_POW1, 7, 4, { NULL }, S_POW1_08 }, //138 /*S_POW1_08*/ { SPR_POW1, 8, 4, { NULL }, S_POW1_09 }, //139 /*S_POW1_09*/ { SPR_POW1, 9, 4, { NULL }, S_NULL }, //140 /*S_POW2_00*/ { SPR_POW2, 0, 4, { NULL }, S_POW2_01 }, //141 /*S_POW2_01*/ { SPR_POW2, 1, 4, { NULL }, S_POW2_02 }, //142 /*S_POW2_02*/ { SPR_POW2, 2, 4, { NULL }, S_POW2_03 }, //143 /*S_POW2_03*/ { SPR_POW2, 3, 4, { NULL }, S_NULL }, //144 /*S_POW3_00*/ { SPR_POW3, 0, 3, { NULL }, S_POW3_01 }, //145 /*S_POW3_01*/ { SPR_POW3, 1, 3, { NULL }, S_POW3_02 }, //146 /*S_POW3_02*/ { SPR_POW3, 2, 3, { NULL }, S_POW3_03 }, //147 /*S_POW3_03*/ { SPR_POW3, 3, 3, { NULL }, S_POW3_04 }, //148 /*S_POW3_04*/ { SPR_POW3, 4, 3, { NULL }, S_POW3_05 }, //149 /*S_POW3_05*/ { SPR_POW3, 5, 3, { NULL }, S_POW3_06 }, //150 /*S_POW3_06*/ { SPR_POW3, 6, 3, { NULL }, S_POW3_07 }, //151 /*S_POW3_07*/ { SPR_POW3, 7, 3, { NULL }, S_NULL }, //152 /*S_ZAP1_00*/ { SPR_ZAP1, 1, 3, { A_DeathExplode3 }, S_ZAP1_02 }, //153 /*S_ZAP1_01*/ { SPR_ZAP1, 0, 3, { A_RaiseAlarm }, S_ZAP1_02 }, //154 /*S_ZAP1_02*/ { SPR_ZAP1, 1, 3, { NULL }, S_ZAP1_03 }, //155 /*S_ZAP1_03*/ { SPR_ZAP1, 2, 3, { NULL }, S_ZAP1_04 }, //156 /*S_ZAP1_04*/ { SPR_ZAP1, 3, 3, { NULL }, S_ZAP1_05 }, //157 /*S_ZAP1_05*/ { SPR_ZAP1, 4, 3, { NULL }, S_ZAP1_06 }, //158 /*S_ZAP1_06*/ { SPR_ZAP1, 5, 3, { NULL }, S_ZAP1_07 }, //159 /*S_ZAP1_07*/ { SPR_ZAP1, 4, 3, { NULL }, S_ZAP1_08 }, //160 /*S_ZAP1_08*/ { SPR_ZAP1, 3, 2, { NULL }, S_ZAP1_09 }, //161 /*S_ZAP1_09*/ { SPR_ZAP1, 2, 2, { NULL }, S_ZAP1_10 }, //162 /*S_ZAP1_10*/ { SPR_ZAP1, 1, 2, { NULL }, S_ZAP1_11 }, //163 /*S_ZAP1_11*/ { SPR_ZAP1, 0, 1, { NULL }, S_NULL }, //164 /*S_SPRY_00*/ { SPR_SPRY, 0, 3, { NULL }, S_SPRY_01 }, //165 /*S_SPRY_01*/ { SPR_SPRY, 1, 3, { NULL }, S_SPRY_02 }, //166 /*S_SPRY_02*/ { SPR_SPRY, 2, 3, { NULL }, S_SPRY_03 }, //167 /*S_SPRY_03*/ { SPR_SPRY, 3, 3, { NULL }, S_SPRY_04 }, //168 /*S_SPRY_04*/ { SPR_SPRY, 4, 3, { NULL }, S_SPRY_05 }, //169 /*S_SPRY_05*/ { SPR_SPRY, 5, 3, { NULL }, S_SPRY_06 }, //170 /*S_SPRY_06*/ { SPR_SPRY, 6, 2, { NULL }, S_NULL }, //171 /*S_BLOD_00*/ { SPR_BLOD, 2, 8, { NULL }, S_BLOD_01 }, //172 /*S_BLOD_01*/ { SPR_BLOD, 1, 8, { NULL }, S_BLOD_02 }, //173 /*S_BLOD_02*/ { SPR_BLOD, 0, 8, { NULL }, S_NULL }, //174 /*S_PUFY_00*/ { SPR_PUFY, 32768, 4, { NULL }, S_PUFY_01 }, //175 /*S_PUFY_01*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_02 }, //176 /*S_PUFY_02*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_03 }, //177 /*S_PUFY_03*/ { SPR_PUFY, 3, 4, { NULL }, S_NULL }, //178 /*S_SHT1_00*/ { SPR_SHT1, 0, 4, { NULL }, S_SHT1_01 }, //179 /*S_SHT1_01*/ { SPR_SHT1, 1, 4, { NULL }, S_SHT1_00 }, //180 /*S_SHT2_00*/ { SPR_SHT2, 0, 5, { NULL }, S_SHT2_01 }, //181 /*S_SHT2_01*/ { SPR_SHT2, 1, 5, { NULL }, S_POW1_00 }, //182 /*S_GRIN_00*/ { SPR_GRIN, 0, 3, { A_MissileTick }, S_GRIN_01 }, //183 /*S_GRIN_01*/ { SPR_GRIN, 1, 3, { A_MissileTick }, S_GRIN_00 }, //184 /*S_GRAP_00*/ { SPR_GRAP, 0, 3, { A_MissileTick }, S_GRAP_01 }, //185 /*S_GRAP_01*/ { SPR_GRAP, 1, 3, { A_MissileTick }, S_GRAP_00 }, //186 /*S_UBAM_00*/ { SPR_UBAM, 0, 3, { A_MissileTick }, S_UBAM_01 }, //187 /*S_UBAM_01*/ { SPR_UBAM, 1, 3, { A_MissileTick }, S_UBAM_00 }, //188 /*S_BNG2_00*/ { SPR_BNG2, 32768, 4, { A_DeathExplode5 }, S_BNG2_01 }, //189 /*S_BNG2_01*/ { SPR_BNG2, 32769, 4, { NULL }, S_BNG2_02 }, //190 /*S_BNG2_02*/ { SPR_BNG2, 32770, 4, { NULL }, S_BNG2_03 }, //191 /*S_BNG2_03*/ { SPR_BNG2, 32771, 4, { NULL }, S_BNG2_04 }, //192 /*S_BNG2_04*/ { SPR_BNG2, 32772, 4, { NULL }, S_BNG2_05 }, //193 /*S_BNG2_05*/ { SPR_BNG2, 32773, 4, { NULL }, S_BNG2_06 }, //194 /*S_BNG2_06*/ { SPR_BNG2, 32774, 4, { NULL }, S_BNG2_07 }, //195 /*S_BNG2_07*/ { SPR_BNG2, 32775, 4, { NULL }, S_BNG2_08 }, //196 /*S_BNG2_08*/ { SPR_BNG2, 32776, 4, { NULL }, S_NULL }, //197 /*S_BNG4_00*/ { SPR_BNG4, 32768, 2, { A_DeathExplode5 }, S_BNG4_01 }, //198 /*S_BNG4_01*/ { SPR_BNG4, 32769, 3, { NULL }, S_BNG4_02 }, //199 /*S_BNG4_02*/ { SPR_BNG4, 32770, 3, { NULL }, S_BNG4_03 }, //200 /*S_BNG4_03*/ { SPR_BNG4, 32771, 3, { NULL }, S_BNG4_04 }, //201 /*S_BNG4_04*/ { SPR_BNG4, 32772, 3, { NULL }, S_BNG4_05 }, //202 /*S_BNG4_05*/ { SPR_BNG4, 32773, 3, { NULL }, S_BNG4_06 }, //203 /*S_BNG4_06*/ { SPR_BNG4, 32774, 3, { NULL }, S_BNG4_07 }, //204 /*S_BNG4_07*/ { SPR_BNG4, 32775, 3, { NULL }, S_BNG4_08 }, //205 /*S_BNG4_08*/ { SPR_BNG4, 32776, 3, { NULL }, S_BNG4_09 }, //206 /*S_BNG4_09*/ { SPR_BNG4, 32777, 3, { NULL }, S_BNG4_10 }, //207 /*S_BNG4_10*/ { SPR_BNG4, 32778, 3, { NULL }, S_BNG4_11 }, //208 /*S_BNG4_11*/ { SPR_BNG4, 32779, 3, { NULL }, S_BNG4_12 }, //209 /*S_BNG4_12*/ { SPR_BNG4, 32780, 3, { NULL }, S_BNG4_13 }, //210 /*S_BNG4_13*/ { SPR_BNG4, 32781, 3, { NULL }, S_NULL }, //211 /*S_BNG3_00*/ { SPR_BNG3, 32768, 3, { A_DeathExplode5 }, S_BNG3_01 }, //212 /*S_BNG3_01*/ { SPR_BNG3, 32769, 3, { NULL }, S_BNG3_02 }, //213 /*S_BNG3_02*/ { SPR_BNG3, 32770, 3, { NULL }, S_BNG3_03 }, //214 /*S_BNG3_03*/ { SPR_BNG3, 32771, 3, { NULL }, S_BNG3_04 }, //215 /*S_BNG3_04*/ { SPR_BNG3, 32772, 3, { NULL }, S_BNG3_05 }, //216 /*S_BNG3_05*/ { SPR_BNG3, 32773, 3, { NULL }, S_BNG3_06 }, //217 /*S_BNG3_06*/ { SPR_BNG3, 32774, 3, { NULL }, S_BNG3_07 }, //218 /*S_BNG3_07*/ { SPR_BNG3, 32775, 3, { NULL }, S_NULL }, //219 /*S_BNG3_08*/ { SPR_BNG3, 0, 1, { A_SpawnGrenadeFire }, S_NULL }, //220 /*S_BNG3_09*/ { SPR_BNG3, 32769, 2, { A_DeathExplode1 }, S_BNG3_10 }, //221 /*S_BNG3_10*/ { SPR_BNG3, 32770, 2, { A_MissileTick }, S_FLBE_00 }, //222 /*S_FLBE_00*/ { SPR_FLBE, 32768, 2, { A_BurnSpread }, S_FLBE_01 }, //223 /*S_FLBE_01*/ { SPR_FLBE, 32769, 2, { A_MissileTick }, S_FLBE_02 }, //224 /*S_FLBE_02*/ { SPR_FLBE, 32770, 2, { A_DeathExplode1 }, S_FLBE_03 }, //225 /*S_FLBE_03*/ { SPR_FLBE, 32771, 3, { A_MissileTick }, S_FLBE_04 }, //226 /*S_FLBE_04*/ { SPR_FLBE, 32772, 3, { A_DeathExplode1 }, S_FLBE_05 }, //227 /*S_FLBE_05*/ { SPR_FLBE, 32773, 3, { A_MissileTick }, S_FLBE_06 }, //228 /*S_FLBE_06*/ { SPR_FLBE, 32774, 3, { A_BurnSpread }, S_FLBE_03 }, //229 /*S_FLBE_07*/ { SPR_FLBE, 32775, 2, { NULL }, S_FLBE_08 }, //230 /*S_FLBE_08*/ { SPR_FLBE, 32776, 2, { A_BurnSpread }, S_FLBE_09 }, //231 /*S_FLBE_09*/ { SPR_FLBE, 32777, 2, { NULL }, S_FLBE_10 }, //232 /*S_FLBE_10*/ { SPR_FLBE, 32778, 2, { NULL }, S_NULL }, //233 /*S_XPRK_00*/ { SPR_XPRK, 0, 1, { A_ClearForceField }, S_NULL }, //234 /*S_OCLW_00*/ { SPR_OCLW, 0, 2, { A_FireChainShot }, S_OCLW_00 }, //235 /*S_CCLW_00*/ { SPR_CCLW, 0, 6, { NULL }, S_NULL }, //236 /*S_TEND_00*/ { SPR_TEND, 0, 20, { NULL }, S_NULL }, //237 /*S_MICR_00*/ { SPR_MICR, 32768, 6, { A_MissileSmoke }, S_MICR_00 }, //238 /*S_MISS_00*/ { SPR_MISS, 32768, 4, { A_MissileSmoke }, S_MISS_01 }, //239 /*S_MISS_01*/ { SPR_MISS, 32769, 3, { A_Tracer }, S_MISS_00 }, //240 /*S_AROW_00*/ { SPR_AROW, 0, 10, { A_ActiveSound }, S_AROW_00 }, //241 /*S_ARWP_00*/ { SPR_ARWP, 0, 10, { A_ActiveSound }, S_ARWP_00 }, //242 /*S_AROW_01*/ { SPR_AROW, 0, 1, { NULL }, S_NULL }, //243 /*S_TORP_00*/ { SPR_TORP, 32768, 4, { NULL }, S_TORP_01 }, //244 /*S_TORP_01*/ { SPR_TORP, 32769, 4, { NULL }, S_TORP_02 }, //245 /*S_TORP_02*/ { SPR_TORP, 32770, 4, { NULL }, S_TORP_03 }, //246 /*S_TORP_03*/ { SPR_TORP, 32771, 4, { NULL }, S_TORP_00 }, //247 /*S_THIT_00*/ { SPR_THIT, 32768, 8, { NULL }, S_THIT_01 }, //248 /*S_THIT_01*/ { SPR_THIT, 32769, 8, { NULL }, S_THIT_02 }, //249 /*S_THIT_02*/ { SPR_THIT, 32770, 8, { A_TorpedoExplode }, S_THIT_03 }, //250 /*S_THIT_03*/ { SPR_THIT, 32771, 8, { NULL }, S_THIT_04 }, //251 /*S_THIT_04*/ { SPR_THIT, 32772, 8, { NULL }, S_NULL }, //252 /*S_TWAV_00*/ { SPR_TWAV, 32768, 9, { NULL }, S_TWAV_01 }, //253 /*S_TWAV_01*/ { SPR_TWAV, 32769, 9, { NULL }, S_TWAV_02 }, //254 /*S_TWAV_02*/ { SPR_TWAV, 32770, 9, { NULL }, S_NULL }, //255 /*S_MISL_00*/ { SPR_MISL, 32768, 5, { NULL }, S_MISL_02 }, //256 /*S_MISL_01*/ { SPR_MISL, 32768, 5, { A_DeathExplode2 }, S_MISL_02 }, //257 /*S_MISL_02*/ { SPR_MISL, 32769, 5, { NULL }, S_MISL_03 }, //258 /*S_MISL_03*/ { SPR_MISL, 32770, 4, { NULL }, S_MISL_04 }, //259 /*S_MISL_04*/ { SPR_MISL, 32771, 2, { NULL }, S_MISL_05 }, //260 /*S_MISL_05*/ { SPR_MISL, 32772, 2, { NULL }, S_MISL_06 }, //261 /*S_MISL_06*/ { SPR_MISL, 32773, 2, { NULL }, S_MISL_07 }, //262 /*S_MISL_07*/ { SPR_MISL, 32774, 2, { NULL }, S_NULL }, //263 /*S_TFOG_00*/ { SPR_TFOG, 32768, 6, { NULL }, S_TFOG_01 }, //264 /*S_TFOG_01*/ { SPR_TFOG, 32769, 6, { NULL }, S_TFOG_02 }, //265 /*S_TFOG_02*/ { SPR_TFOG, 32770, 6, { NULL }, S_TFOG_03 }, //266 /*S_TFOG_03*/ { SPR_TFOG, 32771, 6, { NULL }, S_TFOG_04 }, //267 /*S_TFOG_04*/ { SPR_TFOG, 32772, 6, { NULL }, S_TFOG_05 }, //268 /*S_TFOG_05*/ { SPR_TFOG, 32773, 6, { NULL }, S_TFOG_06 }, //269 /*S_TFOG_06*/ { SPR_TFOG, 32772, 6, { NULL }, S_TFOG_07 }, //270 /*S_TFOG_07*/ { SPR_TFOG, 32771, 6, { NULL }, S_TFOG_08 }, //271 /*S_TFOG_08*/ { SPR_TFOG, 32770, 6, { NULL }, S_TFOG_09 }, //272 /*S_TFOG_09*/ { SPR_TFOG, 32769, 6, { NULL }, S_NULL }, //273 /*S_IFOG_00*/ { SPR_IFOG, 32768, 6, { NULL }, S_IFOG_01 }, //274 /*S_IFOG_01*/ { SPR_IFOG, 32769, 6, { NULL }, S_IFOG_02 }, //275 /*S_IFOG_02*/ { SPR_IFOG, 32768, 6, { NULL }, S_IFOG_03 }, //276 /*S_IFOG_03*/ { SPR_IFOG, 32769, 6, { NULL }, S_IFOG_04 }, //277 /*S_IFOG_04*/ { SPR_IFOG, 32770, 6, { NULL }, S_IFOG_05 }, //278 /*S_IFOG_05*/ { SPR_IFOG, 32771, 6, { NULL }, S_IFOG_06 }, //279 /*S_IFOG_06*/ { SPR_IFOG, 32772, 6, { NULL }, S_NULL }, //280 /*S_SHRD_00*/ { SPR_SHRD, 0, 128, { NULL }, S_NULL }, //281 /*S_SHRD_01*/ { SPR_SHRD, 1, 128, { NULL }, S_NULL }, //282 /*S_SHRD_02*/ { SPR_SHRD, 2, 128, { NULL }, S_NULL }, //283 /*S_SHRD_03*/ { SPR_SHRD, 3, 128, { NULL }, S_NULL }, //284 /*S_SHRD_04*/ { SPR_SHRD, 4, 128, { NULL }, S_NULL }, //285 /*S_SHRD_05*/ { SPR_SHRD, 5, 128, { NULL }, S_NULL }, //286 /*S_PLAY_00*/ { SPR_PLAY, 0, -1, { NULL }, S_NULL }, //287 /*S_PLAY_01*/ { SPR_PLAY, 0, 4, { NULL }, S_PLAY_02 }, //288 /*S_PLAY_02*/ { SPR_PLAY, 1, 4, { NULL }, S_PLAY_03 }, //289 /*S_PLAY_03*/ { SPR_PLAY, 2, 4, { NULL }, S_PLAY_04 }, //290 /*S_PLAY_04*/ { SPR_PLAY, 3, 4, { NULL }, S_PLAY_01 }, //291 /*S_PLAY_05*/ { SPR_PLAY, 4, 12, { NULL }, S_PLAY_00 }, //292 /*S_PLAY_06*/ { SPR_PLAY, 5, 6, { NULL }, S_PLAY_05 }, //293 /*S_PLAY_07*/ { SPR_PLAY, 16, 4, { A_Pain }, S_PLAY_08 }, //294 /*S_PLAY_08*/ { SPR_PLAY, 16, 4, { NULL }, S_PLAY_00 }, //295 /*S_PLAY_09*/ { SPR_PLAY, 6, 4, { NULL }, S_PLAY_10 }, //296 /*S_PLAY_10*/ { SPR_PLAY, 7, 3, { A_PlayerScream }, S_PLAY_11 }, //297 /*S_PLAY_11*/ { SPR_PLAY, 8, 3, { A_Fall }, S_PLAY_12 }, //298 /*S_PLAY_12*/ { SPR_PLAY, 9, 4, { NULL }, S_PLAY_13 }, //299 /*S_PLAY_13*/ { SPR_PLAY, 10, 4, { NULL }, S_PLAY_14 }, //300 /*S_PLAY_14*/ { SPR_PLAY, 11, 4, { NULL }, S_PLAY_15 }, //301 /*S_PLAY_15*/ { SPR_PLAY, 12, 4, { NULL }, S_PLAY_16 }, //302 /*S_PLAY_16*/ { SPR_PLAY, 13, 4, { NULL }, S_PLAY_17 }, //303 /*S_PLAY_17*/ { SPR_PLAY, 14, 4, { NULL }, S_PLAY_18 }, //304 /*S_PLAY_18*/ { SPR_PLAY, 15, 700, { NULL }, S_RGIB_07 }, //305 /*S_RGIB_00*/ { SPR_RGIB, 0, 5, { A_BodyParts }, S_RGIB_01 }, //306 /*S_RGIB_01*/ { SPR_RGIB, 1, 5, { A_XScream }, S_RGIB_02 }, //307 /*S_RGIB_02*/ { SPR_RGIB, 2, 5, { A_Fall }, S_RGIB_03 }, //308 /*S_RGIB_03*/ { SPR_RGIB, 3, 5, { A_BodyParts }, S_RGIB_04 }, //309 /*S_RGIB_04*/ { SPR_RGIB, 4, 5, { A_BodyParts }, S_RGIB_05 }, //310 /*S_RGIB_05*/ { SPR_RGIB, 5, 5, { A_BodyParts }, S_RGIB_06 }, //311 /*S_RGIB_06*/ { SPR_RGIB, 6, 5, { A_BodyParts }, S_RGIB_07 }, //312 /*S_RGIB_07*/ { SPR_RGIB, 7, 1400, { NULL }, S_NULL }, //313 /*S_MRYS_00*/ { SPR_MRYS, 0, 30, { NULL }, S_MRST_00 }, //314 /*S_MRNO_00*/ { SPR_MRNO, 0, 6, { NULL }, S_MRNO_01 }, //315 /*S_MRNO_01*/ { SPR_MRNO, 1, 6, { NULL }, S_MRNO_02 }, //316 /*S_MRNO_02*/ { SPR_MRNO, 2, 10, { NULL }, S_MRNO_03 }, //317 /*S_MRNO_03*/ { SPR_MRNO, 1, 6, { NULL }, S_MRNO_04 }, //318 /*S_MRNO_04*/ { SPR_MRNO, 0, 6, { NULL }, S_MRST_00 }, //319 /*S_MRST_00*/ { SPR_MRST, 0, 10, { A_FriendLook }, S_MRST_00 }, //320 /*S_MRLK_00*/ { SPR_MRLK, 0, 30, { A_ActiveSound }, S_MRST_00 }, //321 /*S_MRLK_01*/ { SPR_MRLK, 1, 30, { NULL }, S_MRST_00 }, //322 /*S_MRBD_00*/ { SPR_MRBD, 0, 4, { NULL }, S_MRBD_01 }, //323 /*S_MRBD_01*/ { SPR_MRBD, 1, 4, { NULL }, S_MRBD_02 }, //324 /*S_MRBD_02*/ { SPR_MRBD, 2, 4, { NULL }, S_MRBD_03 }, //325 /*S_MRBD_03*/ { SPR_MRBD, 3, 4, { NULL }, S_MRBD_04 }, //326 /*S_MRBD_04*/ { SPR_MRBD, 4, 4, { NULL }, S_MRBD_05 }, //327 /*S_MRBD_05*/ { SPR_MRBD, 3, 4, { NULL }, S_MRBD_06 }, //328 /*S_MRBD_06*/ { SPR_MRBD, 2, 4, { NULL }, S_MRBD_07 }, //329 /*S_MRBD_07*/ { SPR_MRBD, 1, 4, { NULL }, S_MRBD_08 }, //330 /*S_MRBD_08*/ { SPR_MRBD, 0, 5, { NULL }, S_MRBD_09 }, //331 /*S_MRBD_09*/ { SPR_MRBD, 5, 6, { NULL }, S_MRST_00 }, //332 /*S_MRPN_00*/ { SPR_MRPN, 0, 3, { NULL }, S_MRPN_01 }, //333 /*S_MRPN_01*/ { SPR_MRPN, 1, 3, { A_Pain }, S_MRPN_02 }, //334 /*S_MRPN_02*/ { SPR_MRPN, 2, 3, { NULL }, S_MRPN_03 }, //335 /*S_MRPN_03*/ { SPR_MRPN, 3, 9, { A_MerchantPain }, S_MRPN_04 }, //336 /*S_MRPN_04*/ { SPR_MRPN, 2, 4, { NULL }, S_MRPN_05 }, //337 /*S_MRPN_05*/ { SPR_MRPN, 1, 3, { NULL }, S_MRPN_06 }, //338 /*S_MRPN_06*/ { SPR_MRPN, 0, 3, { A_ClearSoundTarget }, S_MRST_00 }, //339 /*S_MRGT_00*/ { SPR_MRGT, 0, 5, { NULL }, S_MRGT_01 }, //340 /*S_MRGT_01*/ { SPR_MRGT, 1, 5, { NULL }, S_MRGT_02 }, //341 /*S_MRGT_02*/ { SPR_MRGT, 2, 5, { NULL }, S_MRGT_03 }, //342 /*S_MRGT_03*/ { SPR_MRGT, 3, 5, { NULL }, S_MRGT_04 }, //343 /*S_MRGT_04*/ { SPR_MRGT, 4, 5, { NULL }, S_MRGT_05 }, //344 /*S_MRGT_05*/ { SPR_MRGT, 5, 5, { NULL }, S_MRGT_06 }, //345 /*S_MRGT_06*/ { SPR_MRGT, 6, 5, { NULL }, S_MRGT_07 }, //346 /*S_MRGT_07*/ { SPR_MRGT, 7, 5, { NULL }, S_MRGT_08 }, //347 /*S_MRGT_08*/ { SPR_MRGT, 8, 5, { NULL }, S_MRST_00 }, //348 /*S_BURN_00*/ { SPR_BURN, 0, 3, { A_Scream }, S_BURN_01 }, //349 /*S_BURN_01*/ { SPR_BURN, 1, 3, { A_DropBurnFlesh }, S_BURN_02 }, //350 /*S_BURN_02*/ { SPR_BURN, 2, 3, { A_RandomWalk }, S_BURN_03 }, //351 /*S_BURN_03*/ { SPR_BURN, 3, 3, { A_Fall }, S_BURN_04 }, //352 /*S_BURN_04*/ { SPR_BURN, 4, 5, { A_DropBurnFlesh }, S_BURN_05 }, //353 /*S_BURN_05*/ { SPR_BURN, 5, 5, { A_RandomWalk }, S_BURN_06 }, //354 /*S_BURN_06*/ { SPR_BURN, 6, 5, { A_RandomWalk }, S_BURN_07 }, //355 /*S_BURN_07*/ { SPR_BURN, 7, 5, { A_RandomWalk }, S_BURN_08 }, //356 /*S_BURN_08*/ { SPR_BURN, 8, 5, { A_DropBurnFlesh }, S_BURN_09 }, //357 /*S_BURN_09*/ { SPR_BURN, 9, 5, { A_RandomWalk }, S_BURN_10 }, //358 /*S_BURN_10*/ { SPR_BURN, 10, 5, { A_RandomWalk }, S_BURN_11 }, //359 /*S_BURN_11*/ { SPR_BURN, 11, 5, { A_RandomWalk }, S_BURN_12 }, //360 /*S_BURN_12*/ { SPR_BURN, 12, 3, { A_DropBurnFlesh }, S_BURN_13 }, //361 /*S_BURN_13*/ { SPR_BURN, 13, 3, { NULL }, S_BURN_14 }, //362 /*S_BURN_14*/ { SPR_BURN, 14, 5, { NULL }, S_BURN_15 }, //363 /*S_BURN_15*/ { SPR_BURN, 15, 5, { NULL }, S_BURN_16 }, //364 /*S_BURN_16*/ { SPR_BURN, 16, 5, { NULL }, S_BURN_17 }, //365 /*S_BURN_17*/ { SPR_BURN, 15, 5, { NULL }, S_BURN_18 }, //366 /*S_BURN_18*/ { SPR_BURN, 16, 5, { NULL }, S_BURN_19 }, //367 /*S_BURN_19*/ { SPR_BURN, 17, 7, { NULL }, S_BURN_20 }, //368 /*S_BURN_20*/ { SPR_BURN, 18, 7, { NULL }, S_BURN_21 }, //369 /*S_BURN_21*/ { SPR_BURN, 19, 7, { NULL }, S_BURN_22 }, //370 /*S_BURN_22*/ { SPR_BURN, 20, 7, { NULL }, S_BURN_23 }, //371 /*S_BURN_23*/ { SPR_BURN, 21, 700, { A_PeasantCrash }, S_NULL }, //372 /*S_DISR_00*/ { SPR_DISR, 0, 5, { NULL }, S_DISR_01 }, //373 /*S_DISR_01*/ { SPR_DISR, 1, 5, { NULL }, S_DISR_02 }, //374 /*S_DISR_02*/ { SPR_DISR, 2, 5, { NULL }, S_DISR_03 }, //375 /*S_DISR_03*/ { SPR_DISR, 3, 5, { A_Fall }, S_DISR_04 }, //376 /*S_DISR_04*/ { SPR_DISR, 4, 5, { NULL }, S_DISR_05 }, //377 /*S_DISR_05*/ { SPR_DISR, 5, 5, { NULL }, S_DISR_06 }, //378 /*S_DISR_06*/ { SPR_DISR, 6, 4, { NULL }, S_DISR_07 }, //379 /*S_DISR_07*/ { SPR_DISR, 7, 4, { NULL }, S_DISR_08 }, //380 /*S_DISR_08*/ { SPR_DISR, 8, 4, { NULL }, S_DISR_09 }, //381 /*S_DISR_09*/ { SPR_DISR, 9, 4, { NULL }, S_MEAT_03 }, //382 /*S_PEAS_00*/ { SPR_PEAS, 0, 10, { A_FriendLook }, S_PEAS_00 }, //383 /*S_PEAS_01*/ { SPR_PEAS, 0, 5, { A_RandomWalk }, S_PEAS_02 }, //384 /*S_PEAS_02*/ { SPR_PEAS, 0, 5, { A_RandomWalk }, S_PEAS_03 }, //385 /*S_PEAS_03*/ { SPR_PEAS, 1, 5, { A_RandomWalk }, S_PEAS_04 }, //386 /*S_PEAS_04*/ { SPR_PEAS, 1, 5, { A_RandomWalk }, S_PEAS_05 }, //387 /*S_PEAS_05*/ { SPR_PEAS, 2, 5, { A_RandomWalk }, S_PEAS_06 }, //388 /*S_PEAS_06*/ { SPR_PEAS, 2, 5, { A_RandomWalk }, S_PEAS_07 }, //389 /*S_PEAS_07*/ { SPR_PEAS, 3, 5, { A_RandomWalk }, S_PEAS_08 }, //390 /*S_PEAS_08*/ { SPR_PEAS, 3, 5, { A_RandomWalk }, S_PEAS_00 }, //391 /*S_PEAS_09*/ { SPR_PEAS, 4, 10, { A_FaceTarget }, S_PEAS_10 }, //392 /*S_PEAS_10*/ { SPR_PEAS, 5, 8, { A_PeasantPunch }, S_PEAS_11 }, //393 /*S_PEAS_11*/ { SPR_PEAS, 4, 8, { NULL }, S_PEAS_01 }, //394 /*S_PEAS_12*/ { SPR_PEAS, 14, 3, { NULL }, S_PEAS_13 }, //395 /*S_PEAS_13*/ { SPR_PEAS, 14, 3, { A_Pain }, S_PEAS_09 }, //396 /*S_PEAS_14*/ { SPR_PEAS, 6, 5, { NULL }, S_PEAS_15 }, //397 /*S_PEAS_15*/ { SPR_PEAS, 7, 10, { A_PeasantCrash }, S_PEAS_16 }, //398 /*S_PEAS_16*/ { SPR_PEAS, 8, 6, { NULL }, S_PEAS_15 }, //399 /*S_PEAS_17*/ { SPR_PEAS, 6, 5, { NULL }, S_PEAS_18 }, //400 /*S_PEAS_18*/ { SPR_PEAS, 7, 5, { A_Scream }, S_PEAS_19 }, //401 /*S_PEAS_19*/ { SPR_PEAS, 8, 6, { NULL }, S_PEAS_20 }, //402 /*S_PEAS_20*/ { SPR_PEAS, 9, 5, { A_Fall }, S_PEAS_21 }, //403 /*S_PEAS_21*/ { SPR_PEAS, 10, 5, { NULL }, S_PEAS_22 }, //404 /*S_PEAS_22*/ { SPR_PEAS, 11, 6, { NULL }, S_PEAS_23 }, //405 /*S_PEAS_23*/ { SPR_PEAS, 12, 8, { NULL }, S_PEAS_24 }, //406 /*S_PEAS_24*/ { SPR_PEAS, 13, 1400, { NULL }, S_GIBS_08 }, //407 /*S_GIBS_00*/ { SPR_GIBS, 12, 5, { A_BodyParts }, S_GIBS_01 }, //408 /*S_GIBS_01*/ { SPR_GIBS, 13, 5, { A_XScream }, S_GIBS_02 }, //409 /*S_GIBS_02*/ { SPR_GIBS, 14, 5, { A_Fall }, S_GIBS_03 }, //410 /*S_GIBS_03*/ { SPR_GIBS, 15, 4, { A_BodyParts }, S_GIBS_04 }, //411 /*S_GIBS_04*/ { SPR_GIBS, 16, 4, { A_BodyParts }, S_GIBS_05 }, //412 /*S_GIBS_05*/ { SPR_GIBS, 17, 4, { A_BodyParts }, S_GIBS_06 }, //413 /*S_GIBS_06*/ { SPR_GIBS, 18, 4, { A_BodyParts }, S_GIBS_07 }, //414 /*S_GIBS_07*/ { SPR_GIBS, 19, 4, { NULL }, S_GIBS_08 }, //415 /*S_GIBS_08*/ { SPR_GIBS, 20, 5, { NULL }, S_GIBS_09 }, //416 /*S_GIBS_09*/ { SPR_GIBS, 21, 1400, { NULL }, S_NULL }, //417 /*S_PEAS_25*/ { SPR_PEAS, 0, 5, { A_ZombieInSpecialSector }, S_PEAS_25 }, //418 /*S_AGRD_00*/ { SPR_AGRD, 0, 5, { A_ZombieInSpecialSector }, S_AGRD_00 }, //419 /*S_ARMR_00*/ { SPR_ARMR, 0, -1, { NULL }, S_NULL }, //420 /*S_ARMR_01*/ { SPR_ARMR, 0, -1, { A_HideZombie }, S_NULL }, //421 /*S_PLAY_19*/ { SPR_PLAY, 0, 175, { A_SpawnZombie }, S_PLAY_19 }, //422 /*S_SACR_00*/ { SPR_SACR, 0, -1, { NULL }, S_NULL }, //423 /*S_TNK1_00*/ { SPR_TNK1, 0, 15, { NULL }, S_TNK1_01 }, //424 /*S_TNK1_01*/ { SPR_TNK1, 1, 11, { NULL }, S_TNK1_02 }, //425 /*S_TNK1_02*/ { SPR_TNK1, 2, 40, { NULL }, S_TNK1_00 }, //426 /*S_TNK2_00*/ { SPR_TNK2, 0, 15, { NULL }, S_TNK2_01 }, //427 /*S_TNK2_01*/ { SPR_TNK2, 1, 11, { NULL }, S_TNK2_02 }, //428 /*S_TNK2_02*/ { SPR_TNK2, 2, 40, { NULL }, S_TNK2_00 }, //429 /*S_TNK3_00*/ { SPR_TNK3, 0, 15, { NULL }, S_TNK3_01 }, //430 /*S_TNK3_01*/ { SPR_TNK3, 1, 11, { NULL }, S_TNK3_02 }, //431 /*S_TNK3_02*/ { SPR_TNK3, 2, 40, { NULL }, S_TNK3_00 }, //432 /*S_TNK4_00*/ { SPR_TNK4, 0, 15, { NULL }, S_TNK4_01 }, //433 /*S_TNK4_01*/ { SPR_TNK4, 1, 11, { NULL }, S_TNK4_02 }, //434 /*S_TNK4_02*/ { SPR_TNK4, 2, 40, { NULL }, S_TNK4_00 }, //435 /*S_TNK5_00*/ { SPR_TNK5, 0, 15, { NULL }, S_TNK5_01 }, //436 /*S_TNK5_01*/ { SPR_TNK5, 1, 11, { NULL }, S_TNK5_02 }, //437 /*S_TNK5_02*/ { SPR_TNK5, 2, 40, { NULL }, S_TNK5_00 }, //438 /*S_TNK6_00*/ { SPR_TNK6, 0, 15, { NULL }, S_TNK6_01 }, //439 /*S_TNK6_01*/ { SPR_TNK6, 1, 11, { NULL }, S_TNK6_02 }, //440 /*S_TNK6_02*/ { SPR_TNK6, 2, 40, { NULL }, S_TNK6_00 }, //441 /*S_NEAL_00*/ { SPR_NEAL, 0, 15, { A_ActiveSound }, S_NEAL_01 }, //442 /*S_NEAL_01*/ { SPR_NEAL, 1, 40, { A_ActiveSound }, S_NEAL_00 }, //443 /*S_NEAL_02*/ { SPR_NEAL, 2, 5, { A_ShadowOn }, S_NEAL_03 }, //444 /*S_NEAL_03*/ { SPR_NEAL, 1, 4, { A_Pain }, S_NEAL_04 }, //445 /*S_NEAL_04*/ { SPR_NEAL, 2, 5, { A_ShadowOff }, S_NEAL_00 }, //446 /*S_NEAL_05*/ { SPR_NEAL, 1, 6, { NULL }, S_NEAL_06 }, //447 /*S_NEAL_06*/ { SPR_NEAL, 2, 13, { A_PeasantCrash }, S_NEAL_05 }, //448 /*S_NEAL_07*/ { SPR_NEAL, 3, 5, { NULL }, S_NEAL_08 }, //449 /*S_NEAL_08*/ { SPR_NEAL, 4, 5, { A_Scream }, S_NEAL_09 }, //450 /*S_NEAL_09*/ { SPR_NEAL, 5, 6, { NULL }, S_NEAL_10 }, //451 /*S_NEAL_10*/ { SPR_NEAL, 6, 5, { A_Fall }, S_NEAL_11 }, //452 /*S_NEAL_11*/ { SPR_NEAL, 7, 5, { NULL }, S_NEAL_12 }, //453 /*S_NEAL_12*/ { SPR_NEAL, 8, 6, { NULL }, S_NEAL_13 }, //454 /*S_NEAL_13*/ { SPR_NEAL, 9, -1, { NULL }, S_NULL }, //455 /*S_BEGR_00*/ { SPR_BEGR, 0, 10, { A_Look }, S_BEGR_00 }, //456 /*S_BEGR_01*/ { SPR_BEGR, 0, 4, { A_RandomWalk }, S_BEGR_02 }, //457 /*S_BEGR_02*/ { SPR_BEGR, 0, 4, { A_RandomWalk }, S_BEGR_03 }, //458 /*S_BEGR_03*/ { SPR_BEGR, 1, 4, { A_RandomWalk }, S_BEGR_04 }, //459 /*S_BEGR_04*/ { SPR_BEGR, 1, 4, { A_RandomWalk }, S_BEGR_05 }, //460 /*S_BEGR_05*/ { SPR_BEGR, 2, 4, { A_RandomWalk }, S_BEGR_06 }, //461 /*S_BEGR_06*/ { SPR_BEGR, 2, 4, { A_RandomWalk }, S_BEGR_01 }, //462 /*S_BEGR_07*/ { SPR_BEGR, 3, 8, { NULL }, S_BEGR_08 }, //463 /*S_BEGR_08*/ { SPR_BEGR, 4, 8, { A_PeasantPunch }, S_BEGR_09 }, //464 /*S_BEGR_09*/ { SPR_BEGR, 4, 1, { A_Chase }, S_BEGR_10 }, //465 /*S_BEGR_10*/ { SPR_BEGR, 3, 8, { A_CheckTargetVisible }, S_BEGR_07 }, //466 /*S_BEGR_11*/ { SPR_BEGR, 0, 3, { A_Pain }, S_BEGR_12 }, //467 /*S_BEGR_12*/ { SPR_BEGR, 0, 3, { A_Chase }, S_BEGR_07 }, //468 /*S_BEGR_13*/ { SPR_BEGR, 5, 4, { NULL }, S_BEGR_14 }, //469 /*S_BEGR_14*/ { SPR_BEGR, 6, 4, { A_Scream }, S_BEGR_15 }, //470 /*S_BEGR_15*/ { SPR_BEGR, 7, 4, { NULL }, S_BEGR_16 }, //471 /*S_BEGR_16*/ { SPR_BEGR, 8, 4, { A_Fall }, S_BEGR_17 }, //472 /*S_BEGR_17*/ { SPR_BEGR, 9, 4, { NULL }, S_BEGR_18 }, //473 /*S_BEGR_18*/ { SPR_BEGR, 10, 4, { NULL }, S_BEGR_19 }, //474 /*S_BEGR_19*/ { SPR_BEGR, 11, 4, { NULL }, S_BEGR_20 }, //475 /*S_BEGR_20*/ { SPR_BEGR, 12, 4, { NULL }, S_BEGR_21 }, //476 /*S_BEGR_21*/ { SPR_BEGR, 13, -1, { NULL }, S_NULL }, //477 /*S_BEGR_22*/ { SPR_BEGR, 5, 5, { A_BodyParts }, S_GIBS_01 }, //478 /*S_HMN1_00*/ { SPR_HMN1, 15, 5, { A_FriendLook }, S_HMN1_00 }, //479 /*S_HMN1_01*/ { SPR_HMN1, 16, 8, { NULL }, S_HMN1_00 }, //480 /*S_HMN1_02*/ { SPR_HMN1, 17, 8, { NULL }, S_HMN1_00 }, //481 /*S_HMN1_03*/ { SPR_HMN1, 0, 6, { A_RandomWalk }, S_HMN1_04 }, //482 /*S_HMN1_04*/ { SPR_HMN1, 1, 6, { A_RandomWalk }, S_HMN1_05 }, //483 /*S_HMN1_05*/ { SPR_HMN1, 2, 6, { A_RandomWalk }, S_HMN1_06 }, //484 /*S_HMN1_06*/ { SPR_HMN1, 3, 6, { A_RandomWalk }, S_HMN1_07 }, //485 /*S_HMN1_07*/ { SPR_HMN1, 0, 6, { A_RandomWalk }, S_HMN1_08 }, //486 /*S_HMN1_08*/ { SPR_HMN1, 1, 6, { A_RandomWalk }, S_HMN1_09 }, //487 /*S_HMN1_09*/ { SPR_HMN1, 2, 6, { A_RandomWalk }, S_HMN1_10 }, //488 /*S_HMN1_10*/ { SPR_HMN1, 3, 6, { A_RandomWalk }, S_HMN1_00 }, //489 /*S_HMN1_11*/ { SPR_HMN1, 0, 3, { A_Chase }, S_HMN1_12 }, //490 /*S_HMN1_12*/ { SPR_HMN1, 0, 3, { A_Chase }, S_HMN1_13 }, //491 /*S_HMN1_13*/ { SPR_HMN1, 1, 3, { A_Chase }, S_HMN1_14 }, //492 /*S_HMN1_14*/ { SPR_HMN1, 1, 3, { A_Chase }, S_HMN1_15 }, //493 /*S_HMN1_15*/ { SPR_HMN1, 2, 3, { A_Chase }, S_HMN1_16 }, //494 /*S_HMN1_16*/ { SPR_HMN1, 2, 3, { A_Chase }, S_HMN1_17 }, //495 /*S_HMN1_17*/ { SPR_HMN1, 3, 3, { A_Chase }, S_HMN1_18 }, //496 /*S_HMN1_18*/ { SPR_HMN1, 3, 3, { A_Chase }, S_HMN1_11 }, //497 /*S_HMN1_19*/ { SPR_HMN1, 4, 10, { A_FaceTarget }, S_HMN1_20 }, //498 /*S_HMN1_20*/ { SPR_HMN1, 32773, 10, { A_BulletAttack }, S_HMN1_21 }, //499 /*S_HMN1_21*/ { SPR_HMN1, 4, 10, { A_BulletAttack }, S_HMN1_11 }, //500 /*S_HMN1_22*/ { SPR_HMN1, 14, 3, { NULL }, S_HMN1_23 }, //501 /*S_HMN1_23*/ { SPR_HMN1, 14, 3, { A_Pain }, S_HMN1_11 }, //502 /*S_HMN1_24*/ { SPR_HMN1, 6, 5, { NULL }, S_HMN1_25 }, //503 /*S_HMN1_25*/ { SPR_HMN1, 7, 5, { A_Scream }, S_HMN1_26 }, //504 /*S_HMN1_26*/ { SPR_HMN1, 8, 3, { A_Fall }, S_HMN1_27 }, //505 /*S_HMN1_27*/ { SPR_HMN1, 9, 4, { NULL }, S_HMN1_28 }, //506 /*S_HMN1_28*/ { SPR_HMN1, 10, 3, { NULL }, S_HMN1_29 }, //507 /*S_HMN1_29*/ { SPR_HMN1, 11, 3, { NULL }, S_HMN1_30 }, //508 /*S_HMN1_30*/ { SPR_HMN1, 12, 3, { NULL }, S_HMN1_31 }, //509 /*S_HMN1_31*/ { SPR_HMN1, 13, -1, { NULL }, S_NULL }, //510 /*S_RGIB_08*/ { SPR_RGIB, 0, 4, { A_BodyParts }, S_RGIB_09 }, //511 /*S_RGIB_09*/ { SPR_RGIB, 1, 4, { A_XScream }, S_RGIB_10 }, //512 /*S_RGIB_10*/ { SPR_RGIB, 2, 3, { A_Fall }, S_RGIB_11 }, //513 /*S_RGIB_11*/ { SPR_RGIB, 3, 3, { A_BodyParts }, S_RGIB_12 }, //514 /*S_RGIB_12*/ { SPR_RGIB, 4, 3, { A_BodyParts }, S_RGIB_13 }, //515 /*S_RGIB_13*/ { SPR_RGIB, 5, 3, { A_BodyParts }, S_RGIB_14 }, //516 /*S_RGIB_14*/ { SPR_RGIB, 6, 3, { NULL }, S_RGIB_15 }, //517 /*S_RGIB_15*/ { SPR_RGIB, 7, 1400, { NULL }, S_NULL }, //518 /*S_LEDR_00*/ { SPR_LEDR, 2, 5, { A_FriendLook }, S_LEDR_00 }, //519 /*S_LEDR_01*/ { SPR_LEDR, 0, 8, { NULL }, S_LEDR_00 }, //520 /*S_LEDR_02*/ { SPR_LEDR, 1, 8, { NULL }, S_LEDR_00 }, //521 /*S_LEAD_00*/ { SPR_LEAD, 0, 6, { A_RandomWalk }, S_LEAD_01 }, //522 /*S_LEAD_01*/ { SPR_LEAD, 1, 6, { A_RandomWalk }, S_LEAD_02 }, //523 /*S_LEAD_02*/ { SPR_LEAD, 2, 6, { A_RandomWalk }, S_LEAD_03 }, //524 /*S_LEAD_03*/ { SPR_LEAD, 3, 6, { A_RandomWalk }, S_LEDR_00 }, //525 /*S_LEAD_04*/ { SPR_LEAD, 0, 3, { A_Chase }, S_LEAD_05 }, //526 /*S_LEAD_05*/ { SPR_LEAD, 0, 3, { A_Chase }, S_LEAD_06 }, //527 /*S_LEAD_06*/ { SPR_LEAD, 1, 3, { A_Chase }, S_LEAD_07 }, //528 /*S_LEAD_07*/ { SPR_LEAD, 1, 3, { A_Chase }, S_LEAD_08 }, //529 /*S_LEAD_08*/ { SPR_LEAD, 2, 3, { A_Chase }, S_LEAD_09 }, //530 /*S_LEAD_09*/ { SPR_LEAD, 2, 3, { A_Chase }, S_LEAD_10 }, //531 /*S_LEAD_10*/ { SPR_LEAD, 3, 3, { A_Chase }, S_LEAD_11 }, //532 /*S_LEAD_11*/ { SPR_LEAD, 3, 3, { A_Chase }, S_LEAD_04 }, //533 /*S_LEAD_12*/ { SPR_LEAD, 4, 2, { A_FaceTarget }, S_LEAD_13 }, //534 /*S_LEAD_13*/ { SPR_LEAD, 32773, 2, { A_BulletAttack }, S_LEAD_14 }, //535 /*S_LEAD_14*/ { SPR_LEAD, 4, 1, { A_CheckTargetVisible }, S_LEAD_12 }, //536 /*S_LEAD_15*/ { SPR_LEAD, 24, 3, { NULL }, S_LEAD_16 }, //537 /*S_LEAD_16*/ { SPR_LEAD, 24, 3, { A_Pain }, S_LEAD_04 }, //538 /*S_LEAD_17*/ { SPR_LEAD, 4, 4, { A_FaceTarget }, S_LEAD_18 }, //539 /*S_LEAD_18*/ { SPR_LEAD, 32773, 4, { A_BulletAttack }, S_LEAD_19 }, //540 /*S_LEAD_19*/ { SPR_LEAD, 4, 2, { A_CheckTargetVisible }, S_LEAD_17 }, //541 /*S_LEAD_20*/ { SPR_LEAD, 6, 5, { NULL }, S_LEAD_21 }, //542 /*S_LEAD_21*/ { SPR_LEAD, 7, 5, { A_Scream }, S_LEAD_22 }, //543 /*S_LEAD_22*/ { SPR_LEAD, 8, 4, { NULL }, S_LEAD_23 }, //544 /*S_LEAD_23*/ { SPR_LEAD, 9, 4, { NULL }, S_LEAD_24 }, //545 /*S_LEAD_24*/ { SPR_LEAD, 10, 3, { NULL }, S_LEAD_25 }, //546 /*S_LEAD_25*/ { SPR_LEAD, 11, 3, { A_Fall }, S_LEAD_26 }, //547 /*S_LEAD_26*/ { SPR_LEAD, 12, 3, { NULL }, S_LEAD_27 }, //548 /*S_LEAD_27*/ { SPR_LEAD, 13, 3, { NULL }, S_LEAD_28 }, //549 /*S_LEAD_28*/ { SPR_LEAD, 14, 3, { NULL }, S_LEAD_29 }, //550 /*S_LEAD_29*/ { SPR_LEAD, 15, 3, { NULL }, S_LEAD_30 }, //551 /*S_LEAD_30*/ { SPR_LEAD, 16, 3, { NULL }, S_LEAD_31 }, //552 /*S_LEAD_31*/ { SPR_LEAD, 17, 3, { NULL }, S_LEAD_32 }, //553 /*S_LEAD_32*/ { SPR_LEAD, 18, 3, { NULL }, S_LEAD_33 }, //554 /*S_LEAD_33*/ { SPR_LEAD, 19, 3, { NULL }, S_LEAD_34 }, //555 /*S_LEAD_34*/ { SPR_LEAD, 20, 3, { NULL }, S_LEAD_35 }, //556 /*S_LEAD_35*/ { SPR_LEAD, 21, 3, { NULL }, S_LEAD_36 }, //557 /*S_LEAD_36*/ { SPR_LEAD, 22, 3, { A_SpawnSpectreD }, S_LEAD_37 }, //558 /*S_LEAD_37*/ { SPR_LEAD, 23, -1, { NULL }, S_NULL }, //559 /*S_PUFY_04*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_05 }, //560 /*S_PUFY_05*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_06 }, //561 /*S_PUFY_06*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_07 }, //562 /*S_PUFY_07*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_08 }, //563 /*S_PUFY_08*/ { SPR_PUFY, 3, 4, { NULL }, S_NULL }, //564 /*S_MICR_01*/ { SPR_MICR, 32768, 2, { A_Tracer }, S_MICR_02 }, //565 /*S_MICR_02*/ { SPR_MICR, 32768, 2, { A_Tracer }, S_MICR_01 }, //566 /*S_ROB1_00*/ { SPR_ROB1, 0, 10, { A_Look }, S_ROB1_01 }, //567 /*S_ROB1_01*/ { SPR_ROB1, 0, 10, { A_Look }, S_ROB1_00 }, //568 /*S_ROB1_02*/ { SPR_ROB1, 1, 3, { A_Chase }, S_ROB1_03 }, //569 /*S_ROB1_03*/ { SPR_ROB1, 1, 3, { A_Chase }, S_ROB1_04 }, //570 /*S_ROB1_04*/ { SPR_ROB1, 2, 3, { A_Chase }, S_ROB1_05 }, //571 /*S_ROB1_05*/ { SPR_ROB1, 2, 3, { A_Chase }, S_ROB1_06 }, //572 /*S_ROB1_06*/ { SPR_ROB1, 3, 3, { A_Chase }, S_ROB1_07 }, //573 /*S_ROB1_07*/ { SPR_ROB1, 3, 3, { A_Chase }, S_ROB1_08 }, //574 /*S_ROB1_08*/ { SPR_ROB1, 4, 3, { A_Chase }, S_ROB1_09 }, //575 /*S_ROB1_09*/ { SPR_ROB1, 4, 3, { A_Chase }, S_ROB1_02 }, //576 /*S_ROB1_10*/ { SPR_ROB1, 7, 6, { A_FaceTarget }, S_ROB1_11 }, //577 /*S_ROB1_11*/ { SPR_ROB1, 8, 8, { A_RobotMelee }, S_ROB1_12 }, //578 /*S_ROB1_12*/ { SPR_ROB1, 7, 6, { NULL }, S_ROB1_02 }, //579 /*S_ROB1_13*/ { SPR_ROB1, 5, 8, { A_FaceTarget }, S_ROB1_14 }, //580 /*S_ROB1_14*/ { SPR_ROB1, 32774, 11, { A_ReaverAttack }, S_ROB1_02 }, //581 /*S_ROB1_15*/ { SPR_ROB1, 0, 2, { NULL }, S_ROB1_16 }, //582 /*S_ROB1_16*/ { SPR_ROB1, 0, 2, { A_Pain }, S_ROB1_02 }, //583 /*S_ROB1_17*/ { SPR_ROB1, 32777, 6, { NULL }, S_ROB1_18 }, //584 /*S_ROB1_18*/ { SPR_ROB1, 32778, 6, { A_Scream }, S_ROB1_19 }, //585 /*S_ROB1_19*/ { SPR_ROB1, 32779, 5, { NULL }, S_ROB1_20 }, //586 /*S_ROB1_20*/ { SPR_ROB1, 32780, 5, { A_Fall }, S_ROB1_21 }, //587 /*S_ROB1_21*/ { SPR_ROB1, 32781, 5, { NULL }, S_ROB1_22 }, //588 /*S_ROB1_22*/ { SPR_ROB1, 32782, 5, { NULL }, S_ROB1_23 }, //589 /*S_ROB1_23*/ { SPR_ROB1, 32783, 5, { NULL }, S_ROB1_24 }, //590 /*S_ROB1_24*/ { SPR_ROB1, 32784, 6, { A_DeathExplode3 }, S_ROB1_25 }, //591 /*S_ROB1_25*/ { SPR_ROB1, 17, -1, { NULL }, S_NULL }, //592 /*S_ROB1_26*/ { SPR_ROB1, 32779, 5, { A_BodyParts }, S_ROB1_27 }, //593 /*S_ROB1_27*/ { SPR_ROB1, 32780, 5, { A_XScream }, S_ROB1_28 }, //594 /*S_ROB1_28*/ { SPR_ROB1, 32781, 5, { A_BodyParts }, S_ROB1_29 }, //595 /*S_ROB1_29*/ { SPR_ROB1, 32782, 5, { A_Fall }, S_ROB1_30 }, //596 /*S_ROB1_30*/ { SPR_ROB1, 32783, 5, { A_BodyParts }, S_ROB1_31 }, //597 /*S_ROB1_31*/ { SPR_ROB1, 32784, 5, { A_DeathExplode3 }, S_ROB1_32 }, //598 /*S_ROB1_32*/ { SPR_ROB1, 17, -1, { NULL }, S_NULL }, //599 /*S_AGRD_01*/ { SPR_AGRD, 0, 5, { A_FriendLook }, S_AGRD_01 }, //600 /*S_AGRD_02*/ { SPR_AGRD, 1, 8, { A_ShadowOff }, S_AGRD_01 }, //601 /*S_AGRD_03*/ { SPR_AGRD, 3, 8, { NULL }, S_AGRD_01 }, //602 /*S_AGRD_04*/ { SPR_AGRD, 0, 5, { A_RandomWalk }, S_AGRD_05 }, //603 /*S_AGRD_05*/ { SPR_AGRD, 1, 5, { A_RandomWalk }, S_AGRD_06 }, //604 /*S_AGRD_06*/ { SPR_AGRD, 2, 5, { A_RandomWalk }, S_AGRD_07 }, //605 /*S_AGRD_07*/ { SPR_AGRD, 3, 5, { A_RandomWalk }, S_AGRD_08 }, //606 /*S_AGRD_08*/ { SPR_AGRD, 0, 5, { A_RandomWalk }, S_AGRD_09 }, //607 /*S_AGRD_09*/ { SPR_AGRD, 1, 5, { A_RandomWalk }, S_AGRD_10 }, //608 /*S_AGRD_10*/ { SPR_AGRD, 2, 5, { A_RandomWalk }, S_AGRD_11 }, //609 /*S_AGRD_11*/ { SPR_AGRD, 3, 5, { A_RandomWalk }, S_AGRD_01 }, //610 /*S_AGRD_12*/ { SPR_AGRD, 0, 6, { A_ModifyVisibility }, S_AGRD_14 }, //611 /*S_AGRD_13*/ { SPR_AGRD, 0, 6, { A_SetTLOptions }, S_AGRD_14 }, //612 /*S_AGRD_14*/ { SPR_AGRD, 1, 6, { A_Chase }, S_AGRD_15 }, //613 /*S_AGRD_15*/ { SPR_AGRD, 2, 6, { A_Chase }, S_AGRD_16 }, //614 /*S_AGRD_16*/ { SPR_AGRD, 3, 6, { A_Chase }, S_AGRD_13 }, //615 /*S_AGRD_17*/ { SPR_AGRD, 4, 8, { A_FaceTarget }, S_AGRD_18 }, //616 /*S_AGRD_18*/ { SPR_AGRD, 5, 4, { A_BulletAttack }, S_AGRD_19 }, //617 /*S_AGRD_19*/ { SPR_AGRD, 4, 4, { A_BulletAttack }, S_AGRD_20 }, //618 /*S_AGRD_20*/ { SPR_AGRD, 5, 6, { A_BulletAttack }, S_AGRD_13 }, //619 /*S_AGRD_21*/ { SPR_AGRD, 14, 0, { A_ShadowOn }, S_AGRD_22 }, //620 /*S_AGRD_22*/ { SPR_AGRD, 14, 8, { A_Pain }, S_AGRD_12 }, //621 /*S_AGRD_23*/ { SPR_AGRD, 14, 8, { A_Pain }, S_AGRD_13 }, //622 /*S_AGRD_24*/ { SPR_AGRD, 6, 4, { NULL }, S_AGRD_25 }, //623 /*S_AGRD_25*/ { SPR_AGRD, 7, 4, { A_Scream }, S_AGRD_26 }, //624 /*S_AGRD_26*/ { SPR_AGRD, 8, 4, { NULL }, S_AGRD_27 }, //625 /*S_AGRD_27*/ { SPR_AGRD, 9, 3, { NULL }, S_AGRD_28 }, //626 /*S_AGRD_28*/ { SPR_AGRD, 10, 3, { A_Fall }, S_AGRD_29 }, //627 /*S_AGRD_29*/ { SPR_AGRD, 11, 3, { NULL }, S_AGRD_30 }, //628 /*S_AGRD_30*/ { SPR_AGRD, 12, 3, { A_AcolyteSpecial }, S_AGRD_31 }, //629 /*S_AGRD_31*/ { SPR_AGRD, 13, 1400, { NULL }, S_GIBS_20 }, //630 /*S_GIBS_10*/ { SPR_GIBS, 0, 5, { A_Fall }, S_GIBS_11 }, //631 /*S_GIBS_11*/ { SPR_GIBS, 1, 5, { A_BodyParts }, S_GIBS_12 }, //632 /*S_GIBS_12*/ { SPR_GIBS, 2, 5, { A_BodyParts }, S_GIBS_13 }, //633 /*S_GIBS_13*/ { SPR_GIBS, 3, 4, { A_BodyParts }, S_GIBS_14 }, //634 /*S_GIBS_14*/ { SPR_GIBS, 4, 4, { A_XScream }, S_GIBS_15 }, //635 /*S_GIBS_15*/ { SPR_GIBS, 5, 4, { A_BodyParts }, S_GIBS_16 }, //636 /*S_GIBS_16*/ { SPR_GIBS, 6, 4, { NULL }, S_GIBS_17 }, //637 /*S_GIBS_17*/ { SPR_GIBS, 7, 4, { NULL }, S_GIBS_18 }, //638 /*S_GIBS_18*/ { SPR_GIBS, 8, 5, { NULL }, S_GIBS_19 }, //639 /*S_GIBS_19*/ { SPR_GIBS, 9, 5, { A_AcolyteSpecial }, S_GIBS_20 }, //640 /*S_GIBS_20*/ { SPR_GIBS, 10, 5, { NULL }, S_GIBS_21 }, //641 /*S_GIBS_21*/ { SPR_GIBS, 11, 1400, { NULL }, S_NULL }, //642 /*S_PGRD_00*/ { SPR_PGRD, 0, 5, { A_FriendLook }, S_PGRD_00 }, //643 /*S_PGRD_01*/ { SPR_PGRD, 1, 10, { NULL }, S_PGRD_00 }, //644 /*S_PGRD_02*/ { SPR_PGRD, 2, 10, { NULL }, S_PGRD_00 }, //645 /*S_PGRD_03*/ { SPR_PGRD, 1, 10, { A_RandomWalk }, S_PGRD_00 }, //646 /*S_PGRD_04*/ { SPR_PGRD, 0, 3, { A_Chase }, S_PGRD_05 }, //647 /*S_PGRD_05*/ { SPR_PGRD, 0, 3, { A_Chase }, S_PGRD_06 }, //648 /*S_PGRD_06*/ { SPR_PGRD, 1, 3, { A_Chase }, S_PGRD_07 }, //649 /*S_PGRD_07*/ { SPR_PGRD, 1, 3, { A_Chase }, S_PGRD_08 }, //650 /*S_PGRD_08*/ { SPR_PGRD, 2, 3, { A_Chase }, S_PGRD_09 }, //651 /*S_PGRD_09*/ { SPR_PGRD, 2, 3, { A_Chase }, S_PGRD_10 }, //652 /*S_PGRD_10*/ { SPR_PGRD, 3, 3, { A_Chase }, S_PGRD_11 }, //653 /*S_PGRD_11*/ { SPR_PGRD, 3, 3, { A_Chase }, S_PGRD_04 }, //654 /*S_PGRD_12*/ { SPR_PGRD, 4, 8, { A_FaceTarget }, S_PGRD_13 }, //655 /*S_PGRD_13*/ { SPR_PGRD, 5, 8, { A_RobotMelee }, S_PGRD_04 }, //656 /*S_PGRD_14*/ { SPR_PGRD, 32774, 8, { A_FaceTarget }, S_PGRD_15 }, //657 /*S_PGRD_15*/ { SPR_PGRD, 32775, 8, { A_TemplarMauler }, S_PGRD_04 }, //658 /*S_PGRD_16*/ { SPR_PGRD, 0, 2, { NULL }, S_PGRD_17 }, //659 /*S_PGRD_17*/ { SPR_PGRD, 0, 2, { A_Pain }, S_PGRD_04 }, //660 /*S_PGRD_18*/ { SPR_PGRD, 32776, 4, { A_BodyParts }, S_PGRD_19 }, //661 /*S_PGRD_19*/ { SPR_PGRD, 32777, 4, { A_Scream }, S_PGRD_20 }, //662 /*S_PGRD_20*/ { SPR_PGRD, 32778, 4, { A_BodyParts }, S_PGRD_21 }, //663 /*S_PGRD_21*/ { SPR_PGRD, 32779, 4, { A_Fall }, S_PGRD_22 }, //664 /*S_PGRD_22*/ { SPR_PGRD, 32780, 4, { NULL }, S_PGRD_23 }, //665 /*S_PGRD_23*/ { SPR_PGRD, 32781, 4, { NULL }, S_PGRD_24 }, //666 /*S_PGRD_24*/ { SPR_PGRD, 14, 4, { A_BodyParts }, S_PGRD_25 }, //667 /*S_PGRD_25*/ { SPR_PGRD, 15, 4, { NULL }, S_PGRD_26 }, //668 /*S_PGRD_26*/ { SPR_PGRD, 16, 4, { NULL }, S_PGRD_27 }, //669 /*S_PGRD_27*/ { SPR_PGRD, 17, 4, { NULL }, S_PGRD_28 }, //670 /*S_PGRD_28*/ { SPR_PGRD, 18, 3, { NULL }, S_PGRD_29 }, //671 /*S_PGRD_29*/ { SPR_PGRD, 19, 3, { NULL }, S_PGRD_30 }, //672 /*S_PGRD_30*/ { SPR_PGRD, 20, 3, { NULL }, S_PGRD_31 }, //673 /*S_PGRD_31*/ { SPR_PGRD, 21, 3, { NULL }, S_PGRD_32 }, //674 /*S_PGRD_32*/ { SPR_PGRD, 22, 3, { NULL }, S_PGRD_33 }, //675 /*S_PGRD_33*/ { SPR_PGRD, 23, 3, { NULL }, S_PGRD_34 }, //676 /*S_PGRD_34*/ { SPR_PGRD, 24, 3, { NULL }, S_PGRD_35 }, //677 /*S_PGRD_35*/ { SPR_PGRD, 25, 3, { NULL }, S_PGRD_36 }, //678 /*S_PGRD_36*/ { SPR_PGRD, 26, 3, { NULL }, S_PGRD_37 }, //679 /*S_PGRD_37*/ { SPR_PGRD, 27, -1, { NULL }, S_NULL }, //680 /*S_ROB2_00*/ { SPR_ROB2, 16, 10, { A_Look }, S_ROB2_00 }, //681 /*S_ROB2_01*/ { SPR_ROB2, 0, 3, { A_Chase }, S_ROB2_02 }, //682 /*S_ROB2_02*/ { SPR_ROB2, 0, 3, { A_Chase }, S_ROB2_03 }, //683 /*S_ROB2_03*/ { SPR_ROB2, 1, 3, { A_Chase }, S_ROB2_04 }, //684 /*S_ROB2_04*/ { SPR_ROB2, 1, 3, { A_Chase }, S_ROB2_05 }, //685 /*S_ROB2_05*/ { SPR_ROB2, 2, 3, { A_Chase }, S_ROB2_06 }, //686 /*S_ROB2_06*/ { SPR_ROB2, 2, 3, { A_Chase }, S_ROB2_07 }, //687 /*S_ROB2_07*/ { SPR_ROB2, 3, 3, { A_Chase }, S_ROB2_08 }, //688 /*S_ROB2_08*/ { SPR_ROB2, 3, 3, { A_Chase }, S_ROB2_01 }, //689 /*S_ROB2_09*/ { SPR_ROB2, 4, 3, { A_FaceTarget }, S_ROB2_10 }, //690 /*S_ROB2_10*/ { SPR_ROB2, 32773, 2, { A_CrusaderAttack }, S_ROB2_11 }, //691 /*S_ROB2_11*/ { SPR_ROB2, 32772, 2, { A_CrusaderLeft }, S_ROB2_12 }, //692 /*S_ROB2_12*/ { SPR_ROB2, 32773, 3, { A_CrusaderLeft }, S_ROB2_13 }, //693 /*S_ROB2_13*/ { SPR_ROB2, 32772, 2, { A_CrusaderLeft }, S_ROB2_14 }, //694 /*S_ROB2_14*/ { SPR_ROB2, 32773, 2, { A_CrusaderLeft }, S_ROB2_15 }, //695 /*S_ROB2_15*/ { SPR_ROB2, 32772, 2, { A_CrusaderRight }, S_ROB2_16 }, //696 /*S_ROB2_16*/ { SPR_ROB2, 32773, 2, { A_CrusaderRight }, S_ROB2_17 }, //697 /*S_ROB2_17*/ { SPR_ROB2, 32772, 2, { A_CrusaderRight }, S_ROB2_18 }, //698 /*S_ROB2_18*/ { SPR_ROB2, 5, 2, { A_CheckTargetVisible2 }, S_ROB2_09 }, //699 /*S_ROB2_19*/ { SPR_ROB2, 3, 1, { A_Pain }, S_ROB2_01 }, //700 /*S_ROB2_20*/ { SPR_ROB2, 6, 3, { A_Scream }, S_ROB2_21 }, //701 /*S_ROB2_21*/ { SPR_ROB2, 7, 5, { A_BodyParts }, S_ROB2_22 }, //702 /*S_ROB2_22*/ { SPR_ROB2, 32776, 4, { A_BodyParts }, S_ROB2_23 }, //703 /*S_ROB2_23*/ { SPR_ROB2, 32777, 4, { A_DeathExplode2 }, S_ROB2_24 }, //704 /*S_ROB2_24*/ { SPR_ROB2, 32778, 4, { A_Fall }, S_ROB2_25 }, //705 /*S_ROB2_25*/ { SPR_ROB2, 11, 4, { A_DeathExplode2 }, S_ROB2_26 }, //706 /*S_ROB2_26*/ { SPR_ROB2, 12, 4, { A_BodyParts }, S_ROB2_27 }, //707 /*S_ROB2_27*/ { SPR_ROB2, 13, 4, { A_BodyParts }, S_ROB2_28 }, //708 /*S_ROB2_28*/ { SPR_ROB2, 14, 4, { A_DeathExplode2 }, S_ROB2_29 }, //709 /*S_ROB2_29*/ { SPR_ROB2, 15, -1, { A_BossDeath }, S_NULL }, //710 /*S_MLDR_00*/ { SPR_MLDR, 0, 10, { A_Look }, S_MLDR_00 }, //711 /*S_MLDR_01*/ { SPR_MLDR, 0, 3, { A_Chase }, S_MLDR_02 }, //712 /*S_MLDR_02*/ { SPR_MLDR, 0, 3, { A_Chase }, S_MLDR_03 }, //713 /*S_MLDR_03*/ { SPR_MLDR, 1, 3, { A_Chase }, S_MLDR_04 }, //714 /*S_MLDR_04*/ { SPR_MLDR, 1, 3, { A_Chase }, S_MLDR_05 }, //715 /*S_MLDR_05*/ { SPR_MLDR, 2, 3, { A_Chase }, S_MLDR_06 }, //716 /*S_MLDR_06*/ { SPR_MLDR, 2, 3, { A_Chase }, S_MLDR_07 }, //717 /*S_MLDR_07*/ { SPR_MLDR, 3, 3, { A_Chase }, S_MLDR_08 }, //718 /*S_MLDR_08*/ { SPR_MLDR, 3, 3, { A_Chase }, S_MLDR_01 }, //719 /*S_MLDR_09*/ { SPR_MLDR, 4, 3, { A_FaceTarget }, S_MLDR_10 }, //720 /*S_MLDR_10*/ { SPR_MLDR, 32773, 2, { A_BishopAttack }, S_MLDR_01 }, //721 /*S_MLDR_11*/ { SPR_MLDR, 3, 1, { A_Pain }, S_MLDR_01 }, //722 /*S_MLDR_12*/ { SPR_MLDR, 32774, 3, { NULL }, S_MLDR_13 }, //723 /*S_MLDR_13*/ { SPR_MLDR, 32775, 5, { A_Scream }, S_MLDR_14 }, //724 /*S_MLDR_14*/ { SPR_MLDR, 32776, 4, { A_BodyParts }, S_MLDR_15 }, //725 /*S_MLDR_15*/ { SPR_MLDR, 32777, 4, { A_DeathExplode2 }, S_MLDR_16 }, //726 /*S_MLDR_16*/ { SPR_MLDR, 32778, 4, { NULL }, S_MLDR_17 }, //727 /*S_MLDR_17*/ { SPR_MLDR, 32779, 4, { NULL }, S_MLDR_18 }, //728 /*S_MLDR_18*/ { SPR_MLDR, 32780, 4, { A_Fall }, S_MLDR_19 }, //729 /*S_MLDR_19*/ { SPR_MLDR, 32781, 4, { NULL }, S_MLDR_20 }, //730 /*S_MLDR_20*/ { SPR_MLDR, 32782, 4, { A_BodyParts }, S_MLDR_21 }, //731 /*S_MLDR_21*/ { SPR_MLDR, 32783, 4, { NULL }, S_MLDR_22 }, //732 /*S_MLDR_22*/ { SPR_MLDR, 32784, 4, { A_BodyParts }, S_MLDR_23 }, //733 /*S_MLDR_23*/ { SPR_MLDR, 32785, 4, { NULL }, S_MLDR_24 }, //734 /*S_MLDR_24*/ { SPR_MLDR, 32786, 4, { A_BodyParts }, S_MLDR_25 }, //735 /*S_MLDR_25*/ { SPR_MLDR, 32787, 4, { NULL }, S_MLDR_26 }, //736 /*S_MLDR_26*/ { SPR_MLDR, 32788, 4, { A_BodyParts }, S_MLDR_27 }, //737 /*S_MLDR_27*/ { SPR_MLDR, 21, 4, { A_SpawnSpectreB }, S_NULL }, //738 /*S_ORCL_00*/ { SPR_ORCL, 0, -1, { NULL }, S_NULL }, //739 /*S_ORCL_01*/ { SPR_ORCL, 1, 5, { NULL }, S_ORCL_02 }, //740 /*S_ORCL_02*/ { SPR_ORCL, 2, 5, { NULL }, S_ORCL_03 }, //741 /*S_ORCL_03*/ { SPR_ORCL, 3, 5, { NULL }, S_ORCL_04 }, //742 /*S_ORCL_04*/ { SPR_ORCL, 4, 5, { NULL }, S_ORCL_05 }, //743 /*S_ORCL_05*/ { SPR_ORCL, 5, 5, { NULL }, S_ORCL_06 }, //744 /*S_ORCL_06*/ { SPR_ORCL, 6, 5, { NULL }, S_ORCL_07 }, //745 /*S_ORCL_07*/ { SPR_ORCL, 7, 5, { NULL }, S_ORCL_08 }, //746 /*S_ORCL_08*/ { SPR_ORCL, 8, 5, { NULL }, S_ORCL_09 }, //747 /*S_ORCL_09*/ { SPR_ORCL, 9, 5, { NULL }, S_ORCL_10 }, //748 /*S_ORCL_10*/ { SPR_ORCL, 10, 5, { NULL }, S_ORCL_11 }, //749 /*S_ORCL_11*/ { SPR_ORCL, 11, 5, { A_Fall }, S_ORCL_12 }, //750 /*S_ORCL_12*/ { SPR_ORCL, 12, 5, { NULL }, S_ORCL_13 }, //751 /*S_ORCL_13*/ { SPR_ORCL, 13, 5, { A_AlertSpectreC }, S_ORCL_14 }, //752 /*S_ORCL_14*/ { SPR_ORCL, 14, 5, { NULL }, S_ORCL_15 }, //753 /*S_ORCL_15*/ { SPR_ORCL, 15, 5, { NULL }, S_ORCL_16 }, //754 /*S_ORCL_16*/ { SPR_ORCL, 16, -1, { NULL }, S_NULL }, //755 /*S_PRST_00*/ { SPR_PRST, 0, 10, { A_Look }, S_PRST_01 }, //756 /*S_PRST_01*/ { SPR_PRST, 1, 10, { A_FloatWeave }, S_PRST_00 }, //757 /*S_PRST_02*/ { SPR_PRST, 0, 4, { A_Chase }, S_PRST_03 }, //758 /*S_PRST_03*/ { SPR_PRST, 0, 4, { A_FloatWeave }, S_PRST_04 }, //759 /*S_PRST_04*/ { SPR_PRST, 1, 4, { A_Chase }, S_PRST_05 }, //760 /*S_PRST_05*/ { SPR_PRST, 1, 4, { A_FloatWeave }, S_PRST_06 }, //761 /*S_PRST_06*/ { SPR_PRST, 2, 4, { A_Chase }, S_PRST_07 }, //762 /*S_PRST_07*/ { SPR_PRST, 2, 4, { A_FloatWeave }, S_PRST_08 }, //763 /*S_PRST_08*/ { SPR_PRST, 3, 4, { A_Chase }, S_PRST_09 }, //764 /*S_PRST_09*/ { SPR_PRST, 3, 4, { A_FloatWeave }, S_PRST_02 }, //765 /*S_PRST_10*/ { SPR_PRST, 4, 4, { A_FaceTarget }, S_PRST_11 }, //766 /*S_PRST_11*/ { SPR_PRST, 5, 4, { A_BossMeleeAtk }, S_PRST_12 }, //767 /*S_PRST_12*/ { SPR_PRST, 4, 4, { A_FloatWeave }, S_PRST_02 }, //768 /*S_PRST_13*/ { SPR_PRST, 4, 4, { A_FaceTarget }, S_PRST_14 }, //769 /*S_PRST_14*/ { SPR_PRST, 5, 4, { A_FireHookShot }, S_PRST_15 }, //770 /*S_PRST_15*/ { SPR_PRST, 4, 4, { A_FloatWeave }, S_PRST_02 }, //771 /*S_PDED_00*/ { SPR_PDED, 0, 6, { NULL }, S_PDED_01 }, //772 /*S_PDED_01*/ { SPR_PDED, 1, 6, { A_Scream }, S_PDED_02 }, //773 /*S_PDED_02*/ { SPR_PDED, 2, 6, { NULL }, S_PDED_03 }, //774 /*S_PDED_03*/ { SPR_PDED, 3, 6, { A_Fall }, S_PDED_04 }, //775 /*S_PDED_04*/ { SPR_PDED, 4, 6, { NULL }, S_PDED_05 }, //776 /*S_PDED_05*/ { SPR_PDED, 5, 5, { NULL }, S_PDED_06 }, //777 /*S_PDED_06*/ { SPR_PDED, 6, 5, { NULL }, S_PDED_07 }, //778 /*S_PDED_07*/ { SPR_PDED, 7, 5, { NULL }, S_PDED_08 }, //779 /*S_PDED_08*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_09 }, //780 /*S_PDED_09*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_10 }, //781 /*S_PDED_10*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_11 }, //782 /*S_PDED_11*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_12 }, //783 /*S_PDED_12*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_14 }, //784 /*S_PDED_13*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_14 }, //785 /*S_PDED_14*/ { SPR_PDED, 10, 5, { NULL }, S_PDED_15 }, //786 /*S_PDED_15*/ { SPR_PDED, 11, 5, { NULL }, S_PDED_16 }, //787 /*S_PDED_16*/ { SPR_PDED, 12, 4, { NULL }, S_PDED_17 }, //788 /*S_PDED_17*/ { SPR_PDED, 13, 4, { NULL }, S_PDED_18 }, //789 /*S_PDED_18*/ { SPR_PDED, 14, 4, { NULL }, S_PDED_19 }, //790 /*S_PDED_19*/ { SPR_PDED, 15, 4, { NULL }, S_PDED_20 }, //791 /*S_PDED_20*/ { SPR_PDED, 16, 4, { A_SpawnSpectreE }, S_PDED_21 }, //792 /*S_PDED_21*/ { SPR_PDED, 17, 4, { NULL }, S_PDED_22 }, //793 /*S_PDED_22*/ { SPR_PDED, 18, 4, { NULL }, S_PDED_23 }, //794 /*S_PDED_23*/ { SPR_PDED, 19, -1, { NULL }, S_NULL }, //795 /*S_ALN1_00*/ { SPR_ALN1, 0, 10, { A_Look }, S_ALN1_01 }, //796 /*S_ALN1_01*/ { SPR_ALN1, 1, 10, { A_FloatWeave }, S_ALN1_00 }, //797 /*S_ALN1_02*/ { SPR_ALN1, 32768, 4, { A_Chase }, S_ALN1_03 }, //798 /*S_ALN1_03*/ { SPR_ALN1, 32769, 4, { A_Chase }, S_ALN1_04 }, //799 /*S_ALN1_04*/ { SPR_ALN1, 32770, 4, { A_FloatWeave }, S_ALN1_05 }, //800 /*S_ALN1_05*/ { SPR_ALN1, 32771, 4, { A_Chase }, S_ALN1_06 }, //801 /*S_ALN1_06*/ { SPR_ALN1, 32772, 4, { A_Chase }, S_ALN1_07 }, //802 /*S_ALN1_07*/ { SPR_ALN1, 32773, 4, { A_Chase }, S_ALN1_08 }, //803 /*S_ALN1_08*/ { SPR_ALN1, 32774, 4, { A_FloatWeave }, S_ALN1_09 }, //804 /*S_ALN1_09*/ { SPR_ALN1, 32775, 4, { A_Chase }, S_ALN1_10 }, //805 /*S_ALN1_10*/ { SPR_ALN1, 32776, 4, { A_Chase }, S_ALN1_11 }, //806 /*S_ALN1_11*/ { SPR_ALN1, 32777, 4, { A_Chase }, S_ALN1_12 }, //807 /*S_ALN1_12*/ { SPR_ALN1, 32778, 4, { A_FloatWeave }, S_ALN1_02 }, //808 /*S_ALN1_13*/ { SPR_ALN1, 32777, 4, { A_FaceTarget }, S_ALN1_14 }, //809 /*S_ALN1_14*/ { SPR_ALN1, 32776, 4, { A_BossMeleeAtk }, S_ALN1_15 }, //810 /*S_ALN1_15*/ { SPR_ALN1, 32775, 4, { NULL }, S_ALN1_04 }, //811 /*S_ALN1_16*/ { SPR_ALN1, 32777, 4, { A_FaceTarget }, S_ALN1_17 }, //812 /*S_ALN1_17*/ { SPR_ALN1, 32776, 4, { A_ProgrammerAttack }, S_ALN1_18 }, //813 /*S_ALN1_18*/ { SPR_ALN1, 32775, 4, { NULL }, S_ALN1_12 }, //814 /*S_ALN1_19*/ { SPR_ALN1, 9, 2, { A_Pain }, S_ALN1_08 }, //815 /*S_AL1P_00*/ { SPR_AL1P, 32768, 6, { A_NodeChunk }, S_AL1P_01 }, //816 /*S_AL1P_01*/ { SPR_AL1P, 32769, 6, { A_Scream }, S_AL1P_02 }, //817 /*S_AL1P_02*/ { SPR_AL1P, 32770, 6, { A_NodeChunk }, S_AL1P_03 }, //818 /*S_AL1P_03*/ { SPR_AL1P, 32771, 6, { NULL }, S_AL1P_04 }, //819 /*S_AL1P_04*/ { SPR_AL1P, 32772, 6, { NULL }, S_AL1P_05 }, //820 /*S_AL1P_05*/ { SPR_AL1P, 32773, 6, { A_NodeChunk }, S_AL1P_06 }, //821 /*S_AL1P_06*/ { SPR_AL1P, 32774, 6, { NULL }, S_AL1P_07 }, //822 /*S_AL1P_07*/ { SPR_AL1P, 32775, 6, { A_NodeChunk }, S_AL1P_08 }, //823 /*S_AL1P_08*/ { SPR_AL1P, 32776, 6, { NULL }, S_AL1P_09 }, //824 /*S_AL1P_09*/ { SPR_AL1P, 32777, 6, { NULL }, S_AL1P_10 }, //825 /*S_AL1P_10*/ { SPR_AL1P, 32778, 6, { NULL }, S_AL1P_11 }, //826 /*S_AL1P_11*/ { SPR_AL1P, 32779, 5, { NULL }, S_AL1P_12 }, //827 /*S_AL1P_12*/ { SPR_AL1P, 32780, 5, { NULL }, S_AL1P_13 }, //828 /*S_AL1P_13*/ { SPR_AL1P, 32781, 5, { A_HeadChunk }, S_AL1P_14 }, //829 /*S_AL1P_14*/ { SPR_AL1P, 32782, 5, { NULL }, S_AL1P_15 }, //830 /*S_AL1P_15*/ { SPR_AL1P, 32783, 5, { NULL }, S_AL1P_16 }, //831 /*S_AL1P_16*/ { SPR_AL1P, 32784, 5, { NULL }, S_AL1P_17 }, //832 /*S_AL1P_17*/ { SPR_AL1P, 32785, 5, { A_BossDeath }, S_NULL }, //833 /*S_NODE_00*/ { SPR_NODE, 32768, 6, { NULL }, S_NODE_01 }, //834 /*S_NODE_01*/ { SPR_NODE, 32769, 6, { NULL }, S_NODE_02 }, //835 /*S_NODE_02*/ { SPR_NODE, 32770, 6, { NULL }, S_NODE_03 }, //836 /*S_NODE_03*/ { SPR_NODE, 32771, 6, { NULL }, S_NODE_04 }, //837 /*S_NODE_04*/ { SPR_NODE, 32772, 6, { NULL }, S_NODE_05 }, //838 /*S_NODE_05*/ { SPR_NODE, 32773, 6, { NULL }, S_NODE_06 }, //839 /*S_NODE_06*/ { SPR_NODE, 32774, 6, { NULL }, S_NULL }, //840 /*S_MTHD_00*/ { SPR_MTHD, 32768, 5, { NULL }, S_MTHD_01 }, //841 /*S_MTHD_01*/ { SPR_MTHD, 32769, 5, { NULL }, S_MTHD_02 }, //842 /*S_MTHD_02*/ { SPR_MTHD, 32770, 5, { NULL }, S_MTHD_03 }, //843 /*S_MTHD_03*/ { SPR_MTHD, 32771, 5, { NULL }, S_MTHD_04 }, //844 /*S_MTHD_04*/ { SPR_MTHD, 32772, 5, { NULL }, S_MTHD_05 }, //845 /*S_MTHD_05*/ { SPR_MTHD, 32773, 5, { NULL }, S_MTHD_06 }, //846 /*S_MTHD_06*/ { SPR_MTHD, 32774, 5, { NULL }, S_MTHD_07 }, //847 /*S_MTHD_07*/ { SPR_MTHD, 32775, 5, { NULL }, S_MTHD_08 }, //848 /*S_MTHD_08*/ { SPR_MTHD, 32776, 5, { NULL }, S_MTHD_09 }, //849 /*S_MTHD_09*/ { SPR_MTHD, 32777, 5, { NULL }, S_MTHD_10 }, //850 /*S_MTHD_10*/ { SPR_MTHD, 32778, 5, { NULL }, S_NULL }, //851 /*S_ALN1_20*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_21 }, //852 /*S_ALN1_21*/ { SPR_ALN1, 8, 4, { A_FireSigilEOffshoot }, S_ALN1_22 }, //853 /*S_ALN1_22*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //854 /*S_ALN1_23*/ { SPR_ALN1, 0, 5, { A_FloatWeave }, S_ALN1_24 }, //855 /*S_ALN1_24*/ { SPR_ALN1, 1, 5, { A_FloatWeave }, S_ALN1_25 }, //856 /*S_ALN1_25*/ { SPR_ALN1, 2, 5, { A_FloatWeave }, S_ALN1_26 }, //857 /*S_ALN1_26*/ { SPR_ALN1, 3, 5, { A_FloatWeave }, S_ALN1_27 }, //858 /*S_ALN1_27*/ { SPR_ALN1, 4, 5, { A_FloatWeave }, S_ALN1_28 }, //859 /*S_ALN1_28*/ { SPR_ALN1, 5, 5, { A_FloatWeave }, S_ALN1_29 }, //860 /*S_ALN1_29*/ { SPR_ALN1, 6, 5, { A_FloatWeave }, S_ALN1_30 }, //861 /*S_ALN1_30*/ { SPR_ALN1, 7, 5, { A_FloatWeave }, S_ALN1_31 }, //862 /*S_ALN1_31*/ { SPR_ALN1, 8, 5, { A_FloatWeave }, S_ALN1_32 }, //863 /*S_ALN1_32*/ { SPR_ALN1, 9, 5, { A_FloatWeave }, S_ALN1_33 }, //864 /*S_ALN1_33*/ { SPR_ALN1, 10, 5, { A_FloatWeave }, S_ALN1_23 }, //865 /*S_ALN1_34*/ { SPR_ALN1, 0, 5, { A_Chase }, S_ALN1_35 }, //866 /*S_ALN1_35*/ { SPR_ALN1, 1, 5, { A_Chase }, S_ALN1_36 }, //867 /*S_ALN1_36*/ { SPR_ALN1, 2, 5, { A_FloatWeave }, S_ALN1_37 }, //868 /*S_ALN1_37*/ { SPR_ALN1, 3, 5, { A_Chase }, S_ALN1_38 }, //869 /*S_ALN1_38*/ { SPR_ALN1, 4, 5, { A_Chase }, S_ALN1_39 }, //870 /*S_ALN1_39*/ { SPR_ALN1, 5, 5, { A_Chase }, S_ALN1_40 }, //871 /*S_ALN1_40*/ { SPR_ALN1, 6, 5, { A_FloatWeave }, S_ALN1_41 }, //872 /*S_ALN1_41*/ { SPR_ALN1, 7, 5, { A_Chase }, S_ALN1_42 }, //873 /*S_ALN1_42*/ { SPR_ALN1, 8, 5, { A_Chase }, S_ALN1_43 }, //874 /*S_ALN1_43*/ { SPR_ALN1, 9, 5, { A_Chase }, S_ALN1_44 }, //875 /*S_ALN1_44*/ { SPR_ALN1, 10, 5, { A_FloatWeave }, S_ALN1_34 }, //876 /*S_ALN1_45*/ { SPR_ALN1, 9, 4, { A_FaceTarget }, S_ALN1_46 }, //877 /*S_ALN1_46*/ { SPR_ALN1, 8, 4, { A_BossMeleeAtk }, S_ALN1_47 }, //878 /*S_ALN1_47*/ { SPR_ALN1, 2, 4, { NULL }, S_ALN1_36 }, //879 /*S_ALN1_48*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_49 }, //880 /*S_ALN1_49*/ { SPR_ALN1, 8, 4, { A_SpectreCAttack }, S_ALN1_50 }, //881 /*S_ALN1_50*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_44 }, //882 /*S_ALN1_51*/ { SPR_ALN1, 9, 2, { A_Pain }, S_ALN1_40 }, //883 /*S_ALN1_52*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_53 }, //884 /*S_ALN1_53*/ { SPR_ALN1, 8, 4, { A_SpectreDAttack }, S_ALN1_54 }, //885 /*S_ALN1_54*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //886 /*S_ALN1_55*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_56 }, //887 /*S_ALN1_56*/ { SPR_ALN1, 8, 4, { A_SpectreEAttack }, S_ALN1_57 }, //888 /*S_ALN1_57*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //889 /*S_MNAM_00*/ { SPR_MNAM, 0, 100, { A_FloatWeave }, S_MNAM_01 }, //890 /*S_MNAM_01*/ { SPR_MNAM, 32769, 60, { A_FloatWeave }, S_MNAM_02 }, //891 /*S_MNAM_02*/ { SPR_MNAM, 32770, 4, { A_FloatWeave }, S_MNAM_03 }, //892 /*S_MNAM_03*/ { SPR_MNAM, 32771, 4, { A_FloatWeave }, S_MNAM_04 }, //893 /*S_MNAM_04*/ { SPR_MNAM, 32772, 4, { A_FloatWeave }, S_MNAM_05 }, //894 /*S_MNAM_05*/ { SPR_MNAM, 32773, 4, { A_FloatWeave }, S_MNAM_06 }, //895 /*S_MNAM_06*/ { SPR_MNAM, 32774, 4, { A_FloatWeave }, S_MNAM_07 }, //896 /*S_MNAM_07*/ { SPR_MNAM, 32775, 4, { A_FloatWeave }, S_MNAM_08 }, //897 /*S_MNAM_08*/ { SPR_MNAM, 32776, 4, { A_FloatWeave }, S_MNAM_09 }, //898 /*S_MNAM_09*/ { SPR_MNAM, 32777, 4, { A_FloatWeave }, S_MNAM_10 }, //899 /*S_MNAM_10*/ { SPR_MNAM, 32778, 4, { A_FloatWeave }, S_MNAM_11 }, //900 /*S_MNAM_11*/ { SPR_MNAM, 32779, 4, { A_FloatWeave }, S_MNAL_00 }, //901 /*S_MNAL_00*/ { SPR_MNAL, 32768, 4, { A_Look }, S_MNAL_01 }, //902 /*S_MNAL_01*/ { SPR_MNAL, 32769, 4, { A_FloatWeave }, S_MNAL_00 }, //903 /*S_MNAL_02*/ { SPR_MNAL, 32768, 4, { A_Chase }, S_MNAL_03 }, //904 /*S_MNAL_03*/ { SPR_MNAL, 32769, 4, { A_Chase }, S_MNAL_04 }, //905 /*S_MNAL_04*/ { SPR_MNAL, 32770, 4, { A_FloatWeave }, S_MNAL_05 }, //906 /*S_MNAL_05*/ { SPR_MNAL, 32771, 4, { A_Chase }, S_MNAL_06 }, //907 /*S_MNAL_06*/ { SPR_MNAL, 32772, 4, { A_Chase }, S_MNAL_07 }, //908 /*S_MNAL_07*/ { SPR_MNAL, 32773, 4, { A_Chase }, S_MNAL_08 }, //909 /*S_MNAL_08*/ { SPR_MNAL, 32774, 4, { A_FloatWeave }, S_MNAL_09 }, //910 /*S_MNAL_09*/ { SPR_MNAL, 32775, 4, { A_Chase }, S_MNAL_10 }, //911 /*S_MNAL_10*/ { SPR_MNAL, 32776, 4, { A_Chase }, S_MNAL_11 }, //912 /*S_MNAL_11*/ { SPR_MNAL, 32777, 4, { A_Chase }, S_MNAL_12 }, //913 /*S_MNAL_12*/ { SPR_MNAL, 32778, 4, { A_FloatWeave }, S_MNAL_02 }, //914 /*S_MNAL_13*/ { SPR_MNAL, 32777, 4, { A_FaceTarget }, S_MNAL_14 }, //915 /*S_MNAL_14*/ { SPR_MNAL, 32776, 4, { A_BossMeleeAtk }, S_MNAL_15 }, //916 /*S_MNAL_15*/ { SPR_MNAL, 32770, 4, { NULL }, S_MNAL_04 }, //917 /*S_MNAL_16*/ { SPR_MNAL, 32773, 4, { A_FaceTarget }, S_MNAL_17 }, //918 /*S_MNAL_17*/ { SPR_MNAL, 32776, 4, { A_FireSigilWeapon }, S_MNAL_18 }, //919 /*S_MNAL_18*/ { SPR_MNAL, 32772, 4, { NULL }, S_MNAL_12 }, //920 /*S_MNAL_19*/ { SPR_MNAL, 32777, 2, { A_Pain }, S_MNAL_08 }, //921 /*S_MNAL_20*/ { SPR_MNAL, 32779, 7, { A_NodeChunk }, S_MNAL_21 }, //922 /*S_MNAL_21*/ { SPR_MNAL, 32780, 7, { A_Scream }, S_MNAL_22 }, //923 /*S_MNAL_22*/ { SPR_MNAL, 32781, 7, { A_NodeChunk }, S_MNAL_23 }, //924 /*S_MNAL_23*/ { SPR_MNAL, 32782, 7, { A_NodeChunk }, S_MNAL_24 }, //925 /*S_MNAL_24*/ { SPR_MNAL, 32783, 7, { A_HeadChunk }, S_MNAL_25 }, //926 /*S_MNAL_25*/ { SPR_MNAL, 32784, 64, { A_NodeChunk }, S_MNAL_26 }, //927 /*S_MNAL_26*/ { SPR_MNAL, 32784, 6, { A_EntityDeath }, S_NULL }, //928 /*S_MNAL_27*/ { SPR_MNAL, 32785, 10, { A_Look }, S_MNAL_27 }, //929 /*S_MNAL_28*/ { SPR_MNAL, 32785, 5, { A_FloatWeave }, S_MNAL_29 }, //930 /*S_MNAL_29*/ { SPR_MNAL, 32786, 5, { A_Chase }, S_MNAL_30 }, //931 /*S_MNAL_30*/ { SPR_MNAL, 32787, 5, { A_Chase }, S_MNAL_31 }, //932 /*S_MNAL_31*/ { SPR_MNAL, 32788, 5, { A_FloatWeave }, S_MNAL_32 }, //933 /*S_MNAL_32*/ { SPR_MNAL, 32789, 5, { A_Chase }, S_MNAL_33 }, //934 /*S_MNAL_33*/ { SPR_MNAL, 32790, 5, { A_FloatWeave }, S_MNAL_28 }, //935 /*S_MNAL_34*/ { SPR_MNAL, 32786, 4, { A_FaceTarget }, S_MNAL_35 }, //936 /*S_MNAL_35*/ { SPR_MNAL, 32785, 4, { A_BossMeleeAtk }, S_MNAL_36 }, //937 /*S_MNAL_36*/ { SPR_MNAL, 32787, 4, { A_FloatWeave }, S_MNAL_29 }, //938 /*S_MNAL_37*/ { SPR_MNAL, 32790, 4, { A_FaceTarget }, S_MNAL_38 }, //939 /*S_MNAL_38*/ { SPR_MNAL, 32788, 4, { A_FireSigilEOffshoot }, S_MNAL_39 }, //940 /*S_MNAL_39*/ { SPR_MNAL, 32789, 4, { A_FloatWeave }, S_MNAL_32 }, //941 /*S_MNAL_40*/ { SPR_MNAL, 32785, 2, { A_Pain }, S_MNAL_28 }, //942 /*S_MDTH_00*/ { SPR_MDTH, 32768, 3, { A_Scream }, S_MDTH_01 }, //943 /*S_MDTH_01*/ { SPR_MDTH, 32769, 3, { A_BodyParts }, S_MDTH_02 }, //944 /*S_MDTH_02*/ { SPR_MDTH, 32770, 3, { A_Fall }, S_MDTH_03 }, //945 /*S_MDTH_03*/ { SPR_MDTH, 32771, 3, { A_BodyParts }, S_MDTH_04 }, //946 /*S_MDTH_04*/ { SPR_MDTH, 32772, 3, { A_BodyParts }, S_MDTH_05 }, //947 /*S_MDTH_05*/ { SPR_MDTH, 32773, 3, { A_BodyParts }, S_MDTH_06 }, //948 /*S_MDTH_06*/ { SPR_MDTH, 32774, 3, { A_BodyParts }, S_MDTH_07 }, //949 /*S_MDTH_07*/ { SPR_MDTH, 32775, 3, { A_BodyParts }, S_MDTH_08 }, //950 /*S_MDTH_08*/ { SPR_MDTH, 32776, 3, { A_BodyParts }, S_MDTH_09 }, //951 /*S_MDTH_09*/ { SPR_MDTH, 32777, 3, { A_BodyParts }, S_MDTH_10 }, //952 /*S_MDTH_10*/ { SPR_MDTH, 32778, 3, { A_BodyParts }, S_MDTH_11 }, //953 /*S_MDTH_11*/ { SPR_MDTH, 32779, 3, { A_BodyParts }, S_MDTH_12 }, //954 /*S_MDTH_12*/ { SPR_MDTH, 32780, 3, { A_BodyParts }, S_MDTH_13 }, //955 /*S_MDTH_13*/ { SPR_MDTH, 32781, 3, { A_BodyParts }, S_MDTH_14 }, //956 /*S_MDTH_14*/ { SPR_MDTH, 32782, 3, { A_BossDeath }, S_NULL }, //957 /*S_NEST_00*/ { SPR_NEST, 0, -1, { NULL }, S_NULL }, //958 /*S_PODD_00*/ { SPR_PODD, 0, 60, { A_Look }, S_PODD_00 }, //959 /*S_PODD_01*/ { SPR_PODD, 0, 360, { NULL }, S_PODD_02 }, //960 /*S_PODD_02*/ { SPR_PODD, 1, 9, { A_Fall }, S_PODD_03 }, //961 /*S_PODD_03*/ { SPR_PODD, 2, 9, { NULL }, S_PODD_04 }, //962 /*S_PODD_04*/ { SPR_PODD, 3, 9, { A_SpawnEntity }, S_PODD_05 }, //963 /*S_PODD_05*/ { SPR_PODD, 4, -1, { NULL }, S_NULL }, //964 /*S_ZAP6_00*/ { SPR_ZAP6, 32768, 4, { NULL }, S_ZAP6_01 }, //965 /*S_ZAP6_01*/ { SPR_ZAP6, 32769, 4, { A_SigilTrail }, S_ZAP6_02 }, //966 /*S_ZAP6_02*/ { SPR_ZAP6, 32770, 4, { A_SigilTrail }, S_ZAP6_00 }, //967 /*S_ZOT3_00*/ { SPR_ZOT3, 32768, 4, { NULL }, S_ZOT3_01 }, //968 /*S_ZOT3_01*/ { SPR_ZOT3, 32769, 4, { NULL }, S_ZOT3_02 }, //969 /*S_ZOT3_02*/ { SPR_ZOT3, 32770, 4, { NULL }, S_ZOT3_03 }, //970 /*S_ZOT3_03*/ { SPR_ZOT3, 32771, 4, { NULL }, S_ZOT3_04 }, //971 /*S_ZOT3_04*/ { SPR_ZOT3, 32772, 4, { NULL }, S_ZOT3_00 }, //972 /*S_ZAP6_03*/ { SPR_ZAP6, 32768, 5, { NULL }, S_ZAP6_04 }, //973 /*S_ZAP6_04*/ { SPR_ZAP6, 32769, 5, { NULL }, S_ZAP6_05 }, //974 /*S_ZAP6_05*/ { SPR_ZAP6, 32770, 5, { NULL }, S_NULL }, //975 /*S_ZAP7_00*/ { SPR_ZAP7, 32768, 4, { A_Sigil_E_Action }, S_ZAP7_01 }, //976 /*S_ZAP7_01*/ { SPR_ZAP7, 32769, 4, { A_Sigil_E_Action }, S_ZAP7_02 }, //977 /*S_ZAP7_02*/ { SPR_ZAP7, 32770, 6, { A_Sigil_E_Action }, S_ZAP7_03 }, //978 /*S_ZAP7_03*/ { SPR_ZAP7, 32771, 6, { A_Sigil_E_Action }, S_ZAP7_04 }, //979 /*S_ZAP7_04*/ { SPR_ZAP7, 32772, 6, { A_Sigil_E_Action }, S_ZAP7_00 }, //980 /*S_ZOT1_00*/ { SPR_ZOT1, 32768, 4, { NULL }, S_ZOT1_01 }, //981 /*S_ZOT1_01*/ { SPR_ZOT1, 32769, 4, { NULL }, S_ZOT1_02 }, //982 /*S_ZOT1_02*/ { SPR_ZOT1, 32770, 6, { NULL }, S_ZOT1_03 }, //983 /*S_ZOT1_03*/ { SPR_ZOT1, 32771, 6, { NULL }, S_ZOT1_04 }, //984 /*S_ZOT1_04*/ { SPR_ZOT1, 32771, 6, { NULL }, S_ZOT1_00 }, //985 /*S_ZAP5_00*/ { SPR_ZAP5, 32768, 4, { A_MissileTick }, S_ZAP5_01 }, //986 /*S_ZAP5_01*/ { SPR_ZAP5, 32769, 4, { A_Sigil_A_Action }, S_ZAP5_02 }, //987 /*S_ZAP5_02*/ { SPR_ZAP5, 32770, 4, { A_MissileTick }, S_ZAP5_03 }, //988 /*S_ZAP5_03*/ { SPR_ZAP5, 32771, 4, { A_MissileTick }, S_ZAP5_00 }, //989 /*S_ZOT2_00*/ { SPR_ZOT2, 32768, 4, { A_Tracer }, S_ZOT2_01 }, //990 /*S_ZOT2_01*/ { SPR_ZOT2, 32769, 4, { A_Tracer }, S_ZOT2_02 }, //991 /*S_ZOT2_02*/ { SPR_ZOT2, 32770, 6, { A_Tracer }, S_ZOT2_03 }, //992 /*S_ZOT2_03*/ { SPR_ZOT2, 32771, 6, { A_Tracer }, S_ZOT2_04 }, //993 /*S_ZOT2_04*/ { SPR_ZOT2, 32772, 5, { A_Tracer }, S_ZOT2_00 }, //994 /*S_SEWR_00*/ { SPR_SEWR, 0, 10, { A_Look }, S_SEWR_00 }, //995 /*S_SEWR_01*/ { SPR_SEWR, 0, 6, { A_FloatWeave }, S_SEWR_02 }, //996 /*S_SEWR_02*/ { SPR_SEWR, 0, 6, { A_Chase }, S_SEWR_01 }, //997 /*S_SEWR_03*/ { SPR_SEWR, 1, 4, { A_FaceTarget }, S_SEWR_04 }, //998 /*S_SEWR_04*/ { SPR_SEWR, 32770, 8, { A_SentinelAttack }, S_SEWR_05 }, //999 /*S_SEWR_05*/ { SPR_SEWR, 32770, 4, { A_CheckTargetVisible }, S_SEWR_04 }, //1000 /*S_SEWR_06*/ { SPR_SEWR, 3, 5, { A_Pain }, S_SEWR_05 }, //1001 /*S_SEWR_07*/ { SPR_SEWR, 3, 7, { A_Fall }, S_SEWR_08 }, //1002 /*S_SEWR_08*/ { SPR_SEWR, 32772, 8, { A_BodyParts }, S_SEWR_09 }, //1003 /*S_SEWR_09*/ { SPR_SEWR, 32773, 5, { A_Scream }, S_SEWR_10 }, //1004 /*S_SEWR_10*/ { SPR_SEWR, 32774, 4, { A_BodyParts }, S_SEWR_11 }, //1005 /*S_SEWR_11*/ { SPR_SEWR, 32775, 4, { A_BodyParts }, S_SEWR_12 }, //1006 /*S_SEWR_12*/ { SPR_SEWR, 8, 4, { NULL }, S_SEWR_13 }, //1007 /*S_SEWR_13*/ { SPR_SEWR, 9, 5, { NULL }, S_NULL }, //1008 /*S_SPID_00*/ { SPR_SPID, 0, 1, { A_StalkerSetLook }, S_SPID_00 }, //1009 /*S_SPID_01*/ { SPR_SPID, 0, 10, { A_Look }, S_SPID_01 }, //1010 /*S_SPID_02*/ { SPR_SPID, 9, 10, { A_Look }, S_SPID_02 }, //1011 /*S_SPID_03*/ { SPR_SPID, 0, 1, { A_StalkerThink }, S_SPID_04 }, //1012 /*S_SPID_04*/ { SPR_SPID, 0, 3, { A_Chase }, S_SPID_05 }, //1013 /*S_SPID_05*/ { SPR_SPID, 1, 3, { A_Chase }, S_SPID_06 }, //1014 /*S_SPID_06*/ { SPR_SPID, 1, 3, { A_Chase }, S_SPID_07 }, //1015 /*S_SPID_07*/ { SPR_SPID, 2, 3, { A_StalkerChase }, S_SPID_08 }, //1016 /*S_SPID_08*/ { SPR_SPID, 2, 3, { A_Chase }, S_SPID_03 }, //1017 /*S_SPID_09*/ { SPR_SPID, 9, 3, { A_FaceTarget }, S_SPID_10 }, //1018 /*S_SPID_10*/ { SPR_SPID, 10, 3, { A_StalkerScratch }, S_SPID_18 }, //1019 /*S_SPID_11*/ { SPR_SPID, 2, 2, { A_StalkerDrop }, S_SPID_12 }, //1020 /*S_SPID_12*/ { SPR_SPID, 8, 3, { NULL }, S_SPID_13 }, //1021 /*S_SPID_13*/ { SPR_SPID, 7, 3, { NULL }, S_SPID_14 }, //1022 /*S_SPID_14*/ { SPR_SPID, 6, 3, { NULL }, S_SPID_15 }, //1023 /*S_SPID_15*/ { SPR_SPID, 5, 3, { NULL }, S_SPID_16 }, //1024 /*S_SPID_16*/ { SPR_SPID, 4, 3, { NULL }, S_SPID_17 }, //1025 /*S_SPID_17*/ { SPR_SPID, 3, 3, { NULL }, S_SPID_09 }, //1026 /*S_SPID_18*/ { SPR_SPID, 9, 3, { A_StalkerChase }, S_SPID_19 }, //1027 /*S_SPID_19*/ { SPR_SPID, 9, 3, { A_Chase }, S_SPID_20 }, //1028 /*S_SPID_20*/ { SPR_SPID, 10, 3, { A_Chase }, S_SPID_21 }, //1029 /*S_SPID_21*/ { SPR_SPID, 10, 3, { A_Chase }, S_SPID_22 }, //1030 /*S_SPID_22*/ { SPR_SPID, 11, 3, { A_StalkerChase }, S_SPID_23 }, //1031 /*S_SPID_23*/ { SPR_SPID, 11, 3, { A_Chase }, S_SPID_18 }, //1032 /*S_SPID_24*/ { SPR_SPID, 11, 1, { A_Pain }, S_SPID_03 }, //1033 /*S_SPID_25*/ { SPR_SPID, 14, 4, { NULL }, S_SPID_26 }, //1034 /*S_SPID_26*/ { SPR_SPID, 15, 4, { A_Scream }, S_SPID_27 }, //1035 /*S_SPID_27*/ { SPR_SPID, 16, 4, { NULL }, S_SPID_28 }, //1036 /*S_SPID_28*/ { SPR_SPID, 17, 4, { NULL }, S_SPID_29 }, //1037 /*S_SPID_29*/ { SPR_SPID, 18, 4, { NULL }, S_SPID_30 }, //1038 /*S_SPID_30*/ { SPR_SPID, 19, 4, { NULL }, S_SPID_31 }, //1039 /*S_SPID_31*/ { SPR_SPID, 20, 4, { A_Fall }, S_SPID_32 }, //1040 /*S_SPID_32*/ { SPR_SPID, 21, 4, { NULL }, S_SPID_33 }, //1041 /*S_SPID_33*/ { SPR_SPID, 22, 4, { NULL }, S_SPID_34 }, //1042 /*S_SPID_34*/ { SPR_SPID, 32791, 4, { NULL }, S_SPID_35 }, //1043 /*S_SPID_35*/ { SPR_SPID, 32792, 4, { NULL }, S_SPID_36 }, //1044 /*S_SPID_36*/ { SPR_SPID, 32793, 4, { NULL }, S_SPID_37 }, //1045 /*S_SPID_37*/ { SPR_SPID, 32794, 4, { NULL }, S_NULL }, //1046 /*S_ROB3_00*/ { SPR_ROB3, 0, 10, { A_Look }, S_ROB3_01 }, //1047 /*S_ROB3_01*/ { SPR_ROB3, 1, 10, { A_Look }, S_ROB3_00 }, //1048 /*S_ROB3_02*/ { SPR_ROB3, 1, 3, { A_InqChase }, S_ROB3_03 }, //1049 /*S_ROB3_03*/ { SPR_ROB3, 1, 3, { A_Chase }, S_ROB3_04 }, //1050 /*S_ROB3_04*/ { SPR_ROB3, 2, 4, { A_Chase }, S_ROB3_05 }, //1051 /*S_ROB3_05*/ { SPR_ROB3, 2, 4, { A_Chase }, S_ROB3_06 }, //1052 /*S_ROB3_06*/ { SPR_ROB3, 3, 4, { A_Chase }, S_ROB3_07 }, //1053 /*S_ROB3_07*/ { SPR_ROB3, 3, 4, { A_Chase }, S_ROB3_08 }, //1054 /*S_ROB3_08*/ { SPR_ROB3, 4, 3, { A_InqChase }, S_ROB3_09 }, //1055 /*S_ROB3_09*/ { SPR_ROB3, 4, 3, { A_InqFlyCheck }, S_ROB3_02 }, //1056 /*S_ROB3_10*/ { SPR_ROB3, 0, 2, { A_InqFlyCheck }, S_ROB3_11 }, //1057 /*S_ROB3_11*/ { SPR_ROB3, 5, 6, { A_FaceTarget }, S_ROB3_12 }, //1058 /*S_ROB3_12*/ { SPR_ROB3, 32774, 8, { A_ReaverAttack }, S_ROB3_13 }, //1059 /*S_ROB3_13*/ { SPR_ROB3, 6, 8, { A_ReaverAttack }, S_ROB3_02 }, //1060 /*S_ROB3_14*/ { SPR_ROB3, 10, 12, { A_FaceTarget }, S_ROB3_15 }, //1061 /*S_ROB3_15*/ { SPR_ROB3, 32777, 6, { A_InqGrenade }, S_ROB3_16 }, //1062 /*S_ROB3_16*/ { SPR_ROB3, 10, 12, { NULL }, S_ROB3_02 }, //1063 /*S_ROB3_17*/ { SPR_ROB3, 32775, 8, { A_InqTakeOff }, S_ROB3_18 }, //1064 /*S_ROB3_18*/ { SPR_ROB3, 32776, 4, { A_InqFly }, S_ROB3_19 }, //1065 /*S_ROB3_19*/ { SPR_ROB3, 32775, 4, { A_InqFly }, S_ROB3_18 }, //1066 /*S_ROB3_20*/ { SPR_ROB3, 11, 4, { A_BodyParts }, S_ROB3_21 }, //1067 /*S_ROB3_21*/ { SPR_ROB3, 12, 4, { A_Scream }, S_ROB3_22 }, //1068 /*S_ROB3_22*/ { SPR_ROB3, 13, 4, { A_BodyParts }, S_ROB3_23 }, //1069 /*S_ROB3_23*/ { SPR_ROB3, 32782, 4, { A_DeathExplode1 }, S_ROB3_24 }, //1070 /*S_ROB3_24*/ { SPR_ROB3, 32783, 4, { A_BodyParts }, S_ROB3_25 }, //1071 /*S_ROB3_25*/ { SPR_ROB3, 32784, 4, { A_Fall }, S_ROB3_26 }, //1072 /*S_ROB3_26*/ { SPR_ROB3, 17, 4, { A_BodyParts }, S_ROB3_27 }, //1073 /*S_ROB3_27*/ { SPR_ROB3, 18, 4, { A_BodyParts }, S_ROB3_28 }, //1074 /*S_ROB3_28*/ { SPR_ROB3, 19, 4, { A_BodyParts }, S_ROB3_29 }, //1075 /*S_ROB3_29*/ { SPR_ROB3, 20, 4, { A_BodyParts }, S_ROB3_30 }, //1076 /*S_ROB3_30*/ { SPR_ROB3, 21, 4, { A_BodyParts }, S_ROB3_31 }, //1077 /*S_ROB3_31*/ { SPR_ROB3, 32790, 4, { A_DeathExplode1 }, S_ROB3_32 }, //1078 /*S_ROB3_32*/ { SPR_ROB3, 32791, 4, { A_BodyParts }, S_ROB3_33 }, //1079 /*S_ROB3_33*/ { SPR_ROB3, 32792, 4, { A_BodyParts }, S_ROB3_34 }, //1080 /*S_ROB3_34*/ { SPR_ROB3, 25, 4, { A_BodyParts }, S_ROB3_35 }, //1081 /*S_ROB3_35*/ { SPR_ROB3, 26, 4, { A_BodyParts }, S_ROB3_36 }, //1082 /*S_ROB3_36*/ { SPR_ROB3, 27, 3, { A_BodyParts }, S_ROB3_37 }, //1083 /*S_ROB3_37*/ { SPR_ROB3, 32796, 3, { A_DeathExplode1 }, S_RBB3_00 }, //1084 /*S_RBB3_00*/ { SPR_RBB3, 32768, 3, { A_InqTossArm }, S_RBB3_01 }, //1085 /*S_RBB3_01*/ { SPR_RBB3, 32769, 3, { A_BodyParts }, S_RBB3_02 }, //1086 /*S_RBB3_02*/ { SPR_RBB3, 2, 3, { A_BodyParts }, S_RBB3_03 }, //1087 /*S_RBB3_03*/ { SPR_RBB3, 3, 3, { A_BodyParts }, S_RBB3_04 }, //1088 /*S_RBB3_04*/ { SPR_RBB3, 4, -1, { A_BossDeath }, S_NULL }, //1089 /*S_RBB3_05*/ { SPR_RBB3, 32773, 5, { NULL }, S_RBB3_06 }, //1090 /*S_RBB3_06*/ { SPR_RBB3, 32774, 5, { NULL }, S_RBB3_07 }, //1091 /*S_RBB3_07*/ { SPR_RBB3, 7, -1, { NULL }, S_NULL }, //1092 /*S_PRGR_00*/ { SPR_PRGR, 0, 5, { A_Look }, S_PRGR_01 }, //1093 /*S_PRGR_01*/ { SPR_PRGR, 0, 1, { A_FloatWeave }, S_PRGR_00 }, //1094 /*S_PRGR_02*/ { SPR_PRGR, 0, 160, { A_FloatWeave }, S_PRGR_03 }, //1095 /*S_PRGR_03*/ { SPR_PRGR, 1, 5, { A_FloatWeave }, S_PRGR_04 }, //1096 /*S_PRGR_04*/ { SPR_PRGR, 2, 5, { A_FloatWeave }, S_PRGR_05 }, //1097 /*S_PRGR_05*/ { SPR_PRGR, 3, 5, { A_FloatWeave }, S_PRGR_06 }, //1098 /*S_PRGR_06*/ { SPR_PRGR, 4, 2, { A_FloatWeave }, S_PRGR_07 }, //1099 /*S_PRGR_07*/ { SPR_PRGR, 5, 2, { A_FloatWeave }, S_PRGR_08 }, //1100 /*S_PRGR_08*/ { SPR_PRGR, 4, 3, { A_Chase }, S_PRGR_09 }, //1101 /*S_PRGR_09*/ { SPR_PRGR, 5, 3, { A_Chase }, S_PRGR_06 }, //1102 /*S_PRGR_10*/ { SPR_PRGR, 4, 2, { A_FloatWeave }, S_PRGR_11 }, //1103 /*S_PRGR_11*/ { SPR_PRGR, 5, 3, { A_FloatWeave }, S_PRGR_12 }, //1104 /*S_PRGR_12*/ { SPR_PRGR, 4, 3, { A_FaceTarget }, S_PRGR_13 }, //1105 /*S_PRGR_13*/ { SPR_PRGR, 5, 4, { A_ProgrammerMelee }, S_PRGR_06 }, //1106 /*S_PRGR_14*/ { SPR_PRGR, 6, 5, { A_FaceTarget }, S_PRGR_15 }, //1107 /*S_PRGR_15*/ { SPR_PRGR, 7, 5, { A_FloatWeave }, S_PRGR_16 }, //1108 /*S_PRGR_16*/ { SPR_PRGR, 32776, 5, { A_FaceTarget }, S_PRGR_17 }, //1109 /*S_PRGR_17*/ { SPR_PRGR, 32777, 5, { A_ProgrammerAttack }, S_PRGR_06 }, //1110 /*S_PRGR_18*/ { SPR_PRGR, 10, 5, { A_Pain }, S_PRGR_19 }, //1111 /*S_PRGR_19*/ { SPR_PRGR, 11, 5, { A_FloatWeave }, S_PRGR_06 }, //1112 /*S_PRGR_20*/ { SPR_PRGR, 32779, 7, { A_BodyParts }, S_PRGR_21 }, //1113 /*S_PRGR_21*/ { SPR_PRGR, 32780, 7, { A_Scream }, S_PRGR_22 }, //1114 /*S_PRGR_22*/ { SPR_PRGR, 32781, 7, { A_BodyParts }, S_PRGR_23 }, //1115 /*S_PRGR_23*/ { SPR_PRGR, 32782, 7, { A_Fall }, S_PRGR_24 }, //1116 /*S_PRGR_24*/ { SPR_PRGR, 32783, 7, { A_BodyParts }, S_PRGR_25 }, //1117 /*S_PRGR_25*/ { SPR_PRGR, 32784, 7, { A_ProgrammerDie }, S_PRGR_26 }, //1118 /*S_PRGR_26*/ { SPR_PRGR, 32785, 7, { NULL }, S_PRGR_27 }, //1119 /*S_PRGR_27*/ { SPR_PRGR, 32786, 6, { NULL }, S_PRGR_28 }, //1120 /*S_PRGR_28*/ { SPR_PRGR, 32787, 5, { NULL }, S_PRGR_29 }, //1121 /*S_PRGR_29*/ { SPR_PRGR, 32788, 5, { NULL }, S_PRGR_30 }, //1122 /*S_PRGR_30*/ { SPR_PRGR, 32789, 5, { NULL }, S_PRGR_31 }, //1123 /*S_PRGR_31*/ { SPR_PRGR, 32790, 5, { NULL }, S_PRGR_32 }, //1124 /*S_PRGR_32*/ { SPR_PRGR, 32791, 32, { NULL }, S_PRGR_33 }, //1125 /*S_PRGR_33*/ { SPR_PRGR, 32791, -1, { A_BossDeath }, S_NULL }, //1126 /*S_BASE_00*/ { SPR_BASE, 32768, 5, { A_DeathExplode3 }, S_BASE_01 }, //1127 /*S_BASE_01*/ { SPR_BASE, 32769, 5, { NULL }, S_BASE_02 }, //1128 /*S_BASE_02*/ { SPR_BASE, 32770, 5, { NULL }, S_BASE_03 }, //1129 /*S_BASE_03*/ { SPR_BASE, 32771, 5, { NULL }, S_BASE_04 }, //1130 /*S_BASE_04*/ { SPR_BASE, 4, 5, { NULL }, S_BASE_05 }, //1131 /*S_BASE_05*/ { SPR_BASE, 5, 5, { NULL }, S_BASE_06 }, //1132 /*S_BASE_06*/ { SPR_BASE, 6, 5, { NULL }, S_BASE_07 }, //1133 /*S_BASE_07*/ { SPR_BASE, 7, -1, { NULL }, S_NULL }, //1134 /*S_FRBL_00*/ { SPR_FRBL, 32768, 3, { NULL }, S_FRBL_01 }, //1135 /*S_FRBL_01*/ { SPR_FRBL, 32769, 3, { NULL }, S_FRBL_02 }, //1136 /*S_FRBL_02*/ { SPR_FRBL, 32770, 3, { A_MissileTick }, S_FRBL_00 }, //1137 /*S_FRBL_03*/ { SPR_FRBL, 32771, 5, { A_FlameDeath }, S_FRBL_04 }, //1138 /*S_FRBL_04*/ { SPR_FRBL, 32772, 5, { NULL }, S_FRBL_05 }, //1139 /*S_FRBL_05*/ { SPR_FRBL, 32773, 5, { NULL }, S_FRBL_06 }, //1140 /*S_FRBL_06*/ { SPR_FRBL, 32774, 5, { NULL }, S_FRBL_07 }, //1141 /*S_FRBL_07*/ { SPR_FRBL, 32775, 5, { NULL }, S_FRBL_08 }, //1142 /*S_FRBL_08*/ { SPR_FRBL, 32776, 5, { NULL }, S_NULL }, //1143 /*S_KLAX_00*/ { SPR_KLAX, 0, 5, { A_Listen }, S_KLAX_00 }, //1144 /*S_KLAX_01*/ { SPR_KLAX, 1, 6, { A_ClaxonBlare }, S_KLAX_02 }, //1145 /*S_KLAX_02*/ { SPR_KLAX, 2, 60, { NULL }, S_KLAX_01 }, //1146 /*S_TURT_00*/ { SPR_TURT, 0, 5, { A_Listen }, S_TURT_00 }, //1147 /*S_TURT_01*/ { SPR_TURT, 0, 2, { A_Chase }, S_TURT_01 }, //1148 /*S_TURT_02*/ { SPR_TURT, 1, 4, { A_BulletAttack }, S_TURT_03 }, //1149 /*S_TURT_03*/ { SPR_TURT, 3, 3, { A_CheckTargetVisible }, S_TURT_04 }, //1150 /*S_TURT_04*/ { SPR_TURT, 0, 4, { A_CheckTargetVisible }, S_TURT_02 }, //1151 /*S_BALL_00*/ { SPR_BALL, 32768, 6, { NULL }, S_BALL_01 }, //1152 /*S_BALL_01*/ { SPR_BALL, 32769, 6, { NULL }, S_BALL_02 }, //1153 /*S_BALL_02*/ { SPR_BALL, 32770, 6, { NULL }, S_BALL_03 }, //1154 /*S_BALL_03*/ { SPR_BALL, 32771, 6, { NULL }, S_BALL_04 }, //1155 /*S_BALL_04*/ { SPR_BALL, 32772, 6, { NULL }, S_TURT_05 }, //1156 /*S_TURT_05*/ { SPR_TURT, 2, -1, { NULL }, S_NULL }, //1157 /*S_PSTN_00*/ { SPR_PSTN, 0, 8, { NULL }, S_PSTN_01 }, //1158 /*S_PSTN_01*/ { SPR_PSTN, 1, 8, { NULL }, S_PSTN_00 }, //1159 /*S_PSTN_02*/ { SPR_PSTN, 32768, 4, { A_Scream }, S_PSTN_03 }, //1160 /*S_PSTN_03*/ { SPR_PSTN, 32769, 4, { A_Fall }, S_PSTN_04 }, //1161 /*S_PSTN_04*/ { SPR_PSTN, 32770, 4, { A_QuestMsg }, S_PSTN_05 }, //1162 /*S_PSTN_05*/ { SPR_PSTN, 32771, 4, { A_SpawnSparkPuff }, S_PSTN_06 }, //1163 /*S_PSTN_06*/ { SPR_PSTN, 32772, 4, { A_BodyParts }, S_PSTN_07 }, //1164 /*S_PSTN_07*/ { SPR_PSTN, 32773, 4, { NULL }, S_PSTN_08 }, //1165 /*S_PSTN_08*/ { SPR_PSTN, 32774, 4, { A_SpawnSparkPuff }, S_PSTN_09 }, //1166 /*S_PSTN_09*/ { SPR_PSTN, 7, 4, { NULL }, S_PSTN_10 }, //1167 /*S_PSTN_10*/ { SPR_PSTN, 8, -1, { NULL }, S_NULL }, //1168 /*S_SECR_00*/ { SPR_SECR, 32768, 4, { NULL }, S_SECR_01 }, //1169 /*S_SECR_01*/ { SPR_SECR, 32769, 4, { NULL }, S_SECR_02 }, //1170 /*S_SECR_02*/ { SPR_SECR, 32770, 4, { NULL }, S_SECR_03 }, //1171 /*S_SECR_03*/ { SPR_SECR, 32771, 4, { NULL }, S_SECR_00 }, //1172 /*S_SECR_04*/ { SPR_SECR, 32772, 5, { A_SpawnSparkPuff }, S_SECR_05 }, //1173 /*S_SECR_05*/ { SPR_SECR, 32773, 5, { A_Fall }, S_SECR_06 }, //1174 /*S_SECR_06*/ { SPR_SECR, 32774, 5, { A_QuestMsg }, S_SECR_07 }, //1175 /*S_SECR_07*/ { SPR_SECR, 32775, 5, { A_BodyParts }, S_SECR_08 }, //1176 /*S_SECR_08*/ { SPR_SECR, 32776, 5, { A_SpawnSparkPuff }, S_SECR_09 }, //1177 /*S_SECR_09*/ { SPR_SECR, 9, 5, { NULL }, S_SECR_10 }, //1178 /*S_SECR_10*/ { SPR_SECR, 10, 5, { A_SpawnSparkPuff }, S_SECR_11 }, //1179 /*S_SECR_11*/ { SPR_SECR, 11, 5, { NULL }, S_SECR_12 }, //1180 /*S_SECR_12*/ { SPR_SECR, 12, 5, { A_SpawnSparkPuff }, S_SECR_13 }, //1181 /*S_SECR_13*/ { SPR_SECR, 13, 5, { NULL }, S_SECR_14 }, //1182 /*S_SECR_14*/ { SPR_SECR, 14, 5, { A_SpawnSparkPuff }, S_SECR_15 }, //1183 /*S_SECR_15*/ { SPR_SECR, 15, -1, { NULL }, S_NULL }, //1184 /*S_XPRK_01*/ { SPR_XPRK, 0, -1, { NULL }, S_NULL }, //1185 /*S_XPRK_02*/ { SPR_XPRK, 0, 1, { A_ClearForceField }, S_BNG3_00 }, //1186 /*S_TARG_00*/ { SPR_TARG, 0, -1, { NULL }, S_NULL }, //1187 /*S_RING_00*/ { SPR_RING, 0, -1, { NULL }, S_NULL }, //1188 /*S_EARS_00*/ { SPR_EARS, 0, -1, { NULL }, S_NULL }, //1189 /*S_COMM_00*/ { SPR_COMM, 0, -1, { NULL }, S_NULL }, //1190 /*S_BOOM_00*/ { SPR_BOOM, 32768, 1, { A_CrystalRadiusAtk }, S_BOOM_01 }, //1191 /*S_BOOM_01*/ { SPR_BOOM, 32769, 3, { A_QuestMsg }, S_BOOM_02 }, //1192 /*S_BOOM_02*/ { SPR_BOOM, 32770, 2, { A_CrystalExplode }, S_BOOM_03 }, //1193 /*S_BOOM_03*/ { SPR_BOOM, 32771, 3, { A_SpawnSparkPuff }, S_BOOM_04 }, //1194 /*S_BOOM_04*/ { SPR_BOOM, 32772, 3, { NULL }, S_BOOM_05 }, //1195 /*S_BOOM_05*/ { SPR_BOOM, 32773, 3, { NULL }, S_BOOM_06 }, //1196 /*S_BOOM_06*/ { SPR_BOOM, 32774, 3, { A_SpawnSparkPuff }, S_BOOM_07 }, //1197 /*S_BOOM_07*/ { SPR_BOOM, 32775, 1, { A_CrystalRadiusAtk }, S_BOOM_08 }, //1198 /*S_BOOM_08*/ { SPR_BOOM, 32776, 3, { NULL }, S_BOOM_09 }, //1199 /*S_BOOM_09*/ { SPR_BOOM, 32777, 3, { A_SpawnSparkPuff }, S_BOOM_10 }, //1200 /*S_BOOM_10*/ { SPR_BOOM, 32778, 3, { A_SpawnSparkPuff }, S_BOOM_11 }, //1201 /*S_BOOM_11*/ { SPR_BOOM, 32779, 3, { A_SpawnSparkPuff }, S_BOOM_12 }, //1202 /*S_BOOM_12*/ { SPR_BOOM, 32780, 3, { NULL }, S_BOOM_13 }, //1203 /*S_BOOM_13*/ { SPR_BOOM, 32781, 3, { NULL }, S_BOOM_14 }, //1204 /*S_BOOM_14*/ { SPR_BOOM, 32782, 3, { A_SpawnSparkPuff }, S_BOOM_15 }, //1205 /*S_BOOM_15*/ { SPR_BOOM, 32783, 3, { NULL }, S_BOOM_16 }, //1206 /*S_BOOM_16*/ { SPR_BOOM, 32784, 3, { NULL }, S_BOOM_17 }, //1207 /*S_BOOM_17*/ { SPR_BOOM, 32785, 3, { NULL }, S_BOOM_18 }, //1208 /*S_BOOM_18*/ { SPR_BOOM, 32786, 3, { NULL }, S_BOOM_19 }, //1209 /*S_BOOM_19*/ { SPR_BOOM, 32787, 3, { NULL }, S_BOOM_20 }, //1210 /*S_BOOM_20*/ { SPR_BOOM, 32788, 3, { A_ExtraLightOff }, S_BOOM_21 }, //1211 /*S_BOOM_21*/ { SPR_BOOM, 32789, 3, { NULL }, S_BOOM_22 }, //1212 /*S_BOOM_22*/ { SPR_BOOM, 32790, 3, { NULL }, S_BOOM_23 }, //1213 /*S_BOOM_23*/ { SPR_BOOM, 32791, 3, { NULL }, S_BOOM_24 }, //1214 /*S_BOOM_24*/ { SPR_BOOM, 32792, 3, { NULL }, S_NULL }, //1215 /*S_RATT_00*/ { SPR_RATT, 0, 10, { A_Look }, S_RATT_00 }, //1216 /*S_RATT_01*/ { SPR_RATT, 0, 4, { A_Chase }, S_RATT_02 }, //1217 /*S_RATT_02*/ { SPR_RATT, 0, 4, { A_Chase }, S_RATT_03 }, //1218 /*S_RATT_03*/ { SPR_RATT, 1, 4, { A_Chase }, S_RATT_04 }, //1219 /*S_RATT_04*/ { SPR_RATT, 1, 4, { A_Chase }, S_RATT_01 }, //1220 /*S_RATT_05*/ { SPR_RATT, 0, 8, { A_RandomWalk }, S_RATT_06 }, //1221 /*S_RATT_06*/ { SPR_RATT, 1, 4, { A_RandomWalk }, S_RATT_01 }, //1222 /*S_HOGN_00*/ { SPR_HOGN, 0, 2, { A_ZombieInSpecialSector }, S_HOGN_00 }, //1223 /*S_HOGN_01*/ { SPR_HOGN, 1, 1, { A_ZombieInSpecialSector }, S_HOGN_02 }, //1224 /*S_HOGN_02*/ { SPR_HOGN, 2, 1, { A_Pain }, S_HOGN_00 }, //1225 /*S_DEAD_00*/ { SPR_DEAD, 0, -1, { NULL }, S_NULL }, //1226 /*S_SBAN_00*/ { SPR_SBAN, 0, -1, { NULL }, S_NULL }, //1227 /*S_BOTR_00*/ { SPR_BOTR, 0, -1, { NULL }, S_NULL }, //1228 /*S_HATR_00*/ { SPR_HATR, 0, -1, { NULL }, S_NULL }, //1229 /*S_TOPR_00*/ { SPR_TOPR, 0, -1, { NULL }, S_NULL }, //1230 /*S_COUP_00*/ { SPR_COUP, 0, 5, { NULL }, S_COUP_01 }, //1231 /*S_COUP_01*/ { SPR_COUP, 1, 5, { NULL }, S_COUP_00 }, //1232 /*S_COUP_02*/ { SPR_COUP, 2, -1, { NULL }, S_COUP_01 }, //1233 /*S_BUBB_00*/ { SPR_BUBB, 0, 4, { A_ActiveSound }, S_BUBB_00 }, //1234 /*S_BUBF_00*/ { SPR_BUBF, 0, 4, { A_ActiveSound }, S_BUBF_00 }, //1235 /*S_BUBC_00*/ { SPR_BUBC, 0, 4, { A_ActiveSound }, S_BUBC_00 }, //1236 /*S_ASPR_00*/ { SPR_ASPR, 0, 4, { A_ActiveSound }, S_ASPR_00 }, //1237 /*S_SPDL_00*/ { SPR_SPDL, 0, 5, { A_ActiveSound }, S_SPDL_01 }, //1238 /*S_SPDL_01*/ { SPR_SPDL, 1, 5, { A_ActiveSound }, S_SPDL_02 }, //1239 /*S_SPDL_02*/ { SPR_SPDL, 2, 5, { A_ActiveSound }, S_SPDL_00 }, //1240 /*S_TOKN_00*/ { SPR_TOKN, 0, -1, { NULL }, S_NULL }, //1241 /*S_OTOK_00*/ { SPR_OTOK, 0, -1, { NULL }, S_NULL }, //1242 /*S_HELT_00*/ { SPR_HELT, 0, -1, { NULL }, S_NULL }, //1243 /*S_GUNT_00*/ { SPR_GUNT, 0, -1, { NULL }, S_NULL }, //1244 /*S_FULL_00*/ { SPR_FULL, 0, 35, { NULL }, S_FULL_01 }, //1245 /*S_FULL_01*/ { SPR_FULL, 1, 35, { NULL }, S_FULL_00 }, //1246 /*S_MEAT_00*/ { SPR_MEAT, 0, 700, { NULL }, S_NULL }, //1247 /*S_MEAT_01*/ { SPR_MEAT, 1, 700, { NULL }, S_NULL }, //1248 /*S_MEAT_02*/ { SPR_MEAT, 2, 700, { NULL }, S_NULL }, //1249 /*S_MEAT_03*/ { SPR_MEAT, 3, 700, { NULL }, S_NULL }, //1250 /*S_MEAT_04*/ { SPR_MEAT, 4, 700, { NULL }, S_NULL }, //1251 /*S_MEAT_05*/ { SPR_MEAT, 5, 700, { NULL }, S_NULL }, //1252 /*S_MEAT_06*/ { SPR_MEAT, 6, 700, { NULL }, S_NULL }, //1253 /*S_MEAT_07*/ { SPR_MEAT, 7, 700, { NULL }, S_NULL }, //1254 /*S_MEAT_08*/ { SPR_MEAT, 8, 700, { NULL }, S_NULL }, //1255 /*S_MEAT_09*/ { SPR_MEAT, 9, 700, { NULL }, S_NULL }, //1256 /*S_MEAT_10*/ { SPR_MEAT, 10, 700, { NULL }, S_NULL }, //1257 /*S_MEAT_11*/ { SPR_MEAT, 11, 700, { NULL }, S_NULL }, //1258 /*S_MEAT_12*/ { SPR_MEAT, 12, 700, { NULL }, S_NULL }, //1259 /*S_MEAT_13*/ { SPR_MEAT, 13, 700, { NULL }, S_NULL }, //1260 /*S_MEAT_14*/ { SPR_MEAT, 14, 700, { NULL }, S_NULL }, //1261 /*S_MEAT_15*/ { SPR_MEAT, 15, 700, { NULL }, S_NULL }, //1262 /*S_MEAT_16*/ { SPR_MEAT, 16, 700, { NULL }, S_NULL }, //1263 /*S_MEAT_17*/ { SPR_MEAT, 17, 700, { NULL }, S_NULL }, //1264 /*S_MEAT_18*/ { SPR_MEAT, 18, 700, { NULL }, S_NULL }, //1265 /*S_MEAT_19*/ { SPR_MEAT, 19, 700, { NULL }, S_NULL }, //1266 /*S_JUNK_00*/ { SPR_JUNK, 0, 700, { NULL }, S_NULL }, //1267 /*S_JUNK_01*/ { SPR_JUNK, 1, 700, { NULL }, S_NULL }, //1268 /*S_JUNK_02*/ { SPR_JUNK, 2, 700, { NULL }, S_NULL }, //1269 /*S_JUNK_03*/ { SPR_JUNK, 3, 700, { NULL }, S_NULL }, //1270 /*S_JUNK_04*/ { SPR_JUNK, 4, 700, { NULL }, S_NULL }, //1271 /*S_JUNK_05*/ { SPR_JUNK, 5, 700, { NULL }, S_NULL }, //1272 /*S_JUNK_06*/ { SPR_JUNK, 6, 700, { NULL }, S_NULL }, //1273 /*S_JUNK_07*/ { SPR_JUNK, 7, 700, { NULL }, S_NULL }, //1274 /*S_JUNK_08*/ { SPR_JUNK, 8, 700, { NULL }, S_NULL }, //1275 /*S_JUNK_09*/ { SPR_JUNK, 9, 700, { NULL }, S_NULL }, //1276 /*S_JUNK_10*/ { SPR_JUNK, 10, 700, { NULL }, S_NULL }, //1277 /*S_JUNK_11*/ { SPR_JUNK, 11, 700, { NULL }, S_NULL }, //1278 /*S_JUNK_12*/ { SPR_JUNK, 12, 700, { NULL }, S_NULL }, //1279 /*S_JUNK_13*/ { SPR_JUNK, 13, 700, { NULL }, S_NULL }, //1280 /*S_JUNK_14*/ { SPR_JUNK, 14, 700, { NULL }, S_NULL }, //1281 /*S_JUNK_15*/ { SPR_JUNK, 15, 700, { NULL }, S_NULL }, //1282 /*S_JUNK_16*/ { SPR_JUNK, 16, 700, { NULL }, S_NULL }, //1283 /*S_JUNK_17*/ { SPR_JUNK, 17, 700, { NULL }, S_NULL }, //1284 /*S_JUNK_18*/ { SPR_JUNK, 18, 700, { NULL }, S_NULL }, //1285 /*S_JUNK_19*/ { SPR_JUNK, 19, 700, { NULL }, S_NULL }, //1286 /*S_FFOT_00*/ { SPR_FFOT, 0, 9, { NULL }, S_FFOT_01 }, //1287 /*S_FFOT_01*/ { SPR_FFOT, 1, 9, { NULL }, S_FFOT_02 }, //1288 /*S_FFOT_02*/ { SPR_FFOT, 2, 9, { NULL }, S_FFOT_03 }, //1289 /*S_FFOT_03*/ { SPR_FFOT, 3, 9, { NULL }, S_NULL }, //1290 /*S_DIE1_00*/ { SPR_DIE1, 0, -1, { NULL }, S_NULL }, //1291 /*S_BEAC_00*/ { SPR_BEAC, 0, -1, { NULL }, S_NULL }, //1292 /*S_BEAC_01*/ { SPR_BEAC, 0, 30, { NULL }, S_BEAC_02 }, //1293 /*S_BEAC_02*/ { SPR_BEAC, 0, 160, { A_TeleportBeacon }, S_BEAC_01 }, //1294 /*S_ARM1_00*/ { SPR_ARM1, 0, -1, { NULL }, S_NULL }, //1295 /*S_ARM2_00*/ { SPR_ARM2, 0, -1, { NULL }, S_NULL }, //1296 /*S_BARW_00*/ { SPR_BARW, 0, -1, { NULL }, S_NULL }, //1297 /*S_BARW_01*/ { SPR_BARW, 1, 2, { A_Scream }, S_BARW_02 }, //1298 /*S_BARW_02*/ { SPR_BARW, 2, 2, { NULL }, S_BARW_03 }, //1299 /*S_BARW_03*/ { SPR_BARW, 3, 2, { A_Fall }, S_BARW_04 }, //1300 /*S_BARW_04*/ { SPR_BARW, 4, 2, { NULL }, S_BARW_05 }, //1301 /*S_BARW_05*/ { SPR_BARW, 5, 2, { NULL }, S_BARW_06 }, //1302 /*S_BARW_06*/ { SPR_BARW, 6, 2, { NULL }, S_BARW_07 }, //1303 /*S_BARW_07*/ { SPR_BARW, 7, -1, { NULL }, S_NULL }, //1304 /*S_BART_00*/ { SPR_BART, 0, -1, { NULL }, S_NULL }, //1305 /*S_BART_01*/ { SPR_BART, 32769, 2, { A_Scream }, S_BART_02 }, //1306 /*S_BART_02*/ { SPR_BART, 32770, 2, { NULL }, S_BART_03 }, //1307 /*S_BART_03*/ { SPR_BART, 32771, 2, { NULL }, S_BART_04 }, //1308 /*S_BART_04*/ { SPR_BART, 32772, 2, { A_Fall }, S_BART_05 }, //1309 /*S_BART_05*/ { SPR_BART, 32773, 2, { A_DeathExplode2 }, S_BART_06 }, //1310 /*S_BART_06*/ { SPR_BART, 32774, 2, { NULL }, S_BART_07 }, //1311 /*S_BART_07*/ { SPR_BART, 32775, 2, { NULL }, S_BART_08 }, //1312 /*S_BART_08*/ { SPR_BART, 32776, 2, { NULL }, S_BART_09 }, //1313 /*S_BART_09*/ { SPR_BART, 32777, 3, { NULL }, S_BART_10 }, //1314 /*S_BART_10*/ { SPR_BART, 32778, 3, { NULL }, S_BART_11 }, //1315 /*S_BART_11*/ { SPR_BART, 11, -1, { NULL }, S_NULL }, //1316 /*S_LAMP_00*/ { SPR_LAMP, 0, -1, { NULL }, S_NULL }, //1317 /*S_LANT_00*/ { SPR_LANT, 0, -1, { NULL }, S_NULL }, //1318 /*S_BARL_00*/ { SPR_BARL, 32768, 4, { NULL }, S_BARL_01 }, //1319 /*S_BARL_01*/ { SPR_BARL, 32769, 4, { NULL }, S_BARL_02 }, //1320 /*S_BARL_02*/ { SPR_BARL, 32770, 4, { NULL }, S_BARL_03 }, //1321 /*S_BARL_03*/ { SPR_BARL, 32771, 4, { NULL }, S_BARL_00 }, //1322 /*S_BOWL_00*/ { SPR_BOWL, 32768, 4, { A_ActiveSound }, S_BOWL_01 }, //1323 /*S_BOWL_01*/ { SPR_BOWL, 32769, 4, { NULL }, S_BOWL_02 }, //1324 /*S_BOWL_02*/ { SPR_BOWL, 32770, 4, { NULL }, S_BOWL_03 }, //1325 /*S_BOWL_03*/ { SPR_BOWL, 32771, 4, { NULL }, S_BOWL_00 }, //1326 /*S_BRAZ_00*/ { SPR_BRAZ, 32768, 4, { A_ActiveSound }, S_BRAZ_01 }, //1327 /*S_BRAZ_01*/ { SPR_BRAZ, 32769, 4, { NULL }, S_BRAZ_02 }, //1328 /*S_BRAZ_02*/ { SPR_BRAZ, 32770, 4, { NULL }, S_BRAZ_03 }, //1329 /*S_BRAZ_03*/ { SPR_BRAZ, 32771, 4, { NULL }, S_BRAZ_00 }, //1330 /*S_TRCH_00*/ { SPR_TRCH, 32768, 4, { A_ActiveSound }, S_TRCH_01 }, //1331 /*S_TRCH_01*/ { SPR_TRCH, 32769, 4, { NULL }, S_TRCH_02 }, //1332 /*S_TRCH_02*/ { SPR_TRCH, 32770, 4, { NULL }, S_TRCH_03 }, //1333 /*S_TRCH_03*/ { SPR_TRCH, 32771, 4, { NULL }, S_TRCH_00 }, //1334 /*S_LTRH_00*/ { SPR_LTRH, 32768, 4, { NULL }, S_LTRH_01 }, //1335 /*S_LTRH_01*/ { SPR_LTRH, 32769, 4, { NULL }, S_LTRH_02 }, //1336 /*S_LTRH_02*/ { SPR_LTRH, 32770, 4, { NULL }, S_LTRH_03 }, //1337 /*S_LTRH_03*/ { SPR_LTRH, 32771, 4, { NULL }, S_LTRH_00 }, //1338 /*S_LMPC_00*/ { SPR_LMPC, 32768, 4, { A_ActiveSound }, S_LMPC_01 }, //1339 /*S_LMPC_01*/ { SPR_LMPC, 32769, 4, { NULL }, S_LMPC_02 }, //1340 /*S_LMPC_02*/ { SPR_LMPC, 32770, 4, { NULL }, S_LMPC_03 }, //1341 /*S_LMPC_03*/ { SPR_LMPC, 32771, 4, { NULL }, S_LMPC_00 }, //1342 /*S_LOGS_00*/ { SPR_LOGS, 32768, 4, { A_ActiveSound }, S_LOGS_01 }, //1343 /*S_LOGS_01*/ { SPR_LOGS, 32769, 4, { NULL }, S_LOGS_02 }, //1344 /*S_LOGS_02*/ { SPR_LOGS, 32770, 4, { NULL }, S_LOGS_03 }, //1345 /*S_LOGS_03*/ { SPR_LOGS, 32771, 4, { NULL }, S_LOGS_00 }, //1346 /*S_TRHO_00*/ { SPR_TRHO, 0, -1, { NULL }, S_NULL }, //1347 /*S_WATR_00*/ { SPR_WATR, 0, -1, { NULL }, S_NULL }, //1348 /*S_MUGG_00*/ { SPR_MUGG, 0, -1, { NULL }, S_NULL }, //1349 /*S_FUSL_00*/ { SPR_FUSL, 0, -1, { NULL }, S_NULL }, //1350 /*S_CRD1_00*/ { SPR_CRD1, 0, -1, { NULL }, S_NULL }, //1351 /*S_CRD2_00*/ { SPR_CRD2, 0, -1, { NULL }, S_NULL }, //1352 /*S_TPAS_00*/ { SPR_TPAS, 0, -1, { NULL }, S_NULL }, //1353 /*S_KY1G_00*/ { SPR_KY1G, 0, -1, { NULL }, S_NULL }, //1354 /*S_KY2S_00*/ { SPR_KY2S, 0, -1, { NULL }, S_NULL }, //1355 /*S_KY3B_00*/ { SPR_KY3B, 0, -1, { NULL }, S_NULL }, //1356 /*S_HAND_00*/ { SPR_HAND, 0, -1, { NULL }, S_NULL }, //1357 /*S_CRYS_00*/ { SPR_CRYS, 0, 16, { A_ActiveSound }, S_CRYS_01 }, //1358 /*S_CRYS_01*/ { SPR_CRYS, 1, 5, { A_ActiveSound }, S_CRYS_02 }, //1359 /*S_CRYS_02*/ { SPR_CRYS, 2, 4, { A_ActiveSound }, S_CRYS_03 }, //1360 /*S_CRYS_03*/ { SPR_CRYS, 3, 4, { A_ActiveSound }, S_CRYS_04 }, //1361 /*S_CRYS_04*/ { SPR_CRYS, 4, 4, { A_ActiveSound }, S_CRYS_05 }, //1362 /*S_CRYS_05*/ { SPR_CRYS, 5, 4, { A_ActiveSound }, S_CRYS_00 }, //1363 /*S_PRIS_00*/ { SPR_PRIS, 0, -1, { NULL }, S_NULL }, //1364 /*S_PWR1_00*/ { SPR_PWR1, 0, -1, { NULL }, S_NULL }, //1365 /*S_PWR2_00*/ { SPR_PWR2, 0, -1, { NULL }, S_NULL }, //1366 /*S_PWR3_00*/ { SPR_PWR3, 0, -1, { NULL }, S_NULL }, //1367 /*S_ORAC_00*/ { SPR_ORAC, 0, -1, { NULL }, S_NULL }, //1368 /*S_GYID_00*/ { SPR_GYID, 0, -1, { NULL }, S_NULL }, //1369 /*S_FUBR_00*/ { SPR_FUBR, 0, -1, { NULL }, S_NULL }, //1370 /*S_WARE_00*/ { SPR_WARE, 0, -1, { NULL }, S_NULL }, //1371 /*S_RCRY_00*/ { SPR_RCRY, 32768, -1, { NULL }, S_NULL }, //1372 /*S_BCRY_00*/ { SPR_BCRY, 32768, -1, { NULL }, S_NULL }, //1373 /*S_CHAP_00*/ { SPR_CHAP, 0, -1, { NULL }, S_NULL }, //1374 /*S_TUNL_00*/ { SPR_TUNL, 0, -1, { NULL }, S_NULL }, //1375 /*S_BLTK_00*/ { SPR_BLTK, 0, -1, { NULL }, S_NULL }, //1376 /*S_SECK_00*/ { SPR_SECK, 0, -1, { NULL }, S_NULL }, //1377 /*S_MINE_00*/ { SPR_MINE, 0, -1, { NULL }, S_NULL }, //1378 /*S_REBL_00*/ { SPR_REBL, 0, -1, { NULL }, S_NULL }, //1379 /*S_PROC_00*/ { SPR_PROC, 0, -1, { NULL }, S_NULL }, //1380 /*S_ANKH_00*/ { SPR_ANKH, 0, -1, { NULL }, S_NULL }, //1381 /*S_GOID_00*/ { SPR_GOID, 0, -1, { NULL }, S_NULL }, //1382 /*S_STMP_00*/ { SPR_STMP, 0, -1, { NULL }, S_NULL }, //1383 /*S_MDKT_00*/ { SPR_MDKT, 0, -1, { NULL }, S_NULL }, //1384 /*S_COIN_00*/ { SPR_COIN, 0, -1, { NULL }, S_NULL }, //1385 /*S_CRED_00*/ { SPR_CRED, 0, -1, { NULL }, S_NULL }, //1386 /*S_SACK_00*/ { SPR_SACK, 0, -1, { NULL }, S_NULL }, //1387 /*S_CHST_00*/ { SPR_CHST, 0, -1, { NULL }, S_NULL }, //1388 /*S_SHD1_00*/ { SPR_SHD1, 0, 17, { A_ShadowOff }, S_SHD1_01 }, //1389 /*S_SHD1_01*/ { SPR_SHD1, 0, 17, { A_ModifyVisibility }, S_SHD1_02 }, //1390 /*S_SHD1_02*/ { SPR_SHD1, 0, 17, { A_ShadowOn }, S_SHD1_03 }, //1391 /*S_SHD1_03*/ { SPR_SHD1, 0, 17, { A_ModifyVisibility }, S_SHD1_00 }, //1392 /*S_MASK_00*/ { SPR_MASK, 0, -1, { NULL }, S_NULL }, //1393 /*S_UNIF_00*/ { SPR_UNIF, 0, -1, { NULL }, S_NULL }, //1394 /*S_OFIC_00*/ { SPR_OFIC, 0, -1, { NULL }, S_NULL }, //1395 /*S_PMAP_00*/ { SPR_PMAP, 32768, 6, { NULL }, S_PMAP_01 }, //1396 /*S_PMAP_01*/ { SPR_PMAP, 32769, 6, { NULL }, S_PMAP_00 }, //1397 /*S_PMUP_00*/ { SPR_PMUP, 32768, 6, { NULL }, S_PMUP_01 }, //1398 /*S_PMUP_01*/ { SPR_PMUP, 32769, 6, { NULL }, S_PMUP_00 }, //1399 /*S_BLIT_00*/ { SPR_BLIT, 0, -1, { NULL }, S_NULL }, //1400 /*S_BBOX_00*/ { SPR_BBOX, 0, -1, { NULL }, S_NULL }, //1401 /*S_MSSL_00*/ { SPR_MSSL, 0, -1, { NULL }, S_NULL }, //1402 /*S_ROKT_00*/ { SPR_ROKT, 0, -1, { NULL }, S_NULL }, //1403 /*S_BRY1_00*/ { SPR_BRY1, 0, 6, { NULL }, S_BRY1_01 }, //1404 /*S_BRY1_01*/ { SPR_BRY1, 1, 6, { NULL }, S_BRY1_00 }, //1405 /*S_CPAC_00*/ { SPR_CPAC, 0, 6, { NULL }, S_CPAC_01 }, //1406 /*S_CPAC_01*/ { SPR_CPAC, 1, 6, { NULL }, S_CPAC_00 }, //1407 /*S_PQRL_00*/ { SPR_PQRL, 0, -1, { NULL }, S_NULL }, //1408 /*S_XQRL_00*/ { SPR_XQRL, 0, -1, { NULL }, S_NULL }, //1409 /*S_GRN1_00*/ { SPR_GRN1, 0, -1, { NULL }, S_NULL }, //1410 /*S_GRN2_00*/ { SPR_GRN2, 0, -1, { NULL }, S_NULL }, //1411 /*S_BKPK_00*/ { SPR_BKPK, 0, -1, { NULL }, S_NULL }, //1412 /*S_RELC_00*/ { SPR_RELC, 32768, -1, { NULL }, S_NULL }, //1413 /*S_RIFL_00*/ { SPR_RIFL, 0, -1, { NULL }, S_NULL }, //1414 /*S_RIFL_01*/ { SPR_RIFL, 1, -1, { NULL }, S_NULL }, //1415 /*S_FLAM_00*/ { SPR_FLAM, 0, -1, { NULL }, S_NULL }, //1416 /*S_BFLM_00*/ { SPR_BFLM, 0, -1, { NULL }, S_NULL }, //1417 /*S_MMSL_00*/ { SPR_MMSL, 0, -1, { NULL }, S_NULL }, //1418 /*S_TRPD_00*/ { SPR_TRPD, 0, -1, { NULL }, S_NULL }, //1419 /*S_GRND_00*/ { SPR_GRND, 0, -1, { NULL }, S_NULL }, //1420 /*S_CBOW_00*/ { SPR_CBOW, 0, -1, { NULL }, S_NULL }, //1421 /*S_SIGL_00*/ { SPR_SIGL, 0, -1, { NULL }, S_NULL }, //1422 /*S_SIGL_01*/ { SPR_SIGL, 1, -1, { NULL }, S_NULL }, //1423 /*S_SIGL_02*/ { SPR_SIGL, 2, -1, { NULL }, S_NULL }, //1424 /*S_SIGL_03*/ { SPR_SIGL, 3, -1, { NULL }, S_NULL }, //1425 /*S_SIGL_04*/ { SPR_SIGL, 4, -1, { NULL }, S_NULL }, //1426 /*S_LITE_00*/ { SPR_LITE, 32768, -1, { NULL }, S_NULL }, //1427 /*S_CNDL_00*/ { SPR_CNDL, 32768, -1, { NULL }, S_NULL }, //1428 /*S_CLBR_00*/ { SPR_CLBR, 32768, -1, { NULL }, S_NULL }, //1429 /*S_LITS_00*/ { SPR_LITS, 32768, -1, { NULL }, S_NULL }, //1430 /*S_LITB_00*/ { SPR_LITB, 32768, -1, { NULL }, S_NULL }, //1431 /*S_LITG_00*/ { SPR_LITG, 32768, -1, { NULL }, S_NULL }, //1432 /*S_ROK1_00*/ { SPR_ROK1, 0, -1, { NULL }, S_NULL }, //1433 /*S_ROK2_00*/ { SPR_ROK2, 0, -1, { NULL }, S_NULL }, //1434 /*S_ROK3_00*/ { SPR_ROK3, 0, -1, { NULL }, S_NULL }, //1435 /*S_ROK4_00*/ { SPR_ROK4, 0, -1, { NULL }, S_NULL }, //1436 /*S_LOGG_00*/ { SPR_LOGG, 0, 5, { A_ActiveSound }, S_LOGG_01 }, //1437 /*S_LOGG_01*/ { SPR_LOGG, 1, 5, { A_ActiveSound }, S_LOGG_02 }, //1438 /*S_LOGG_02*/ { SPR_LOGG, 2, 5, { A_ActiveSound }, S_LOGG_03 }, //1439 /*S_LOGG_03*/ { SPR_LOGG, 3, 5, { A_ActiveSound }, S_LOGG_00 }, //1440 /*S_RUB1_00*/ { SPR_RUB1, 0, -1, { NULL }, S_NULL }, //1441 /*S_RUB2_00*/ { SPR_RUB2, 0, -1, { NULL }, S_NULL }, //1442 /*S_RUB3_00*/ { SPR_RUB3, 0, -1, { NULL }, S_NULL }, //1443 /*S_RUB4_00*/ { SPR_RUB4, 0, -1, { NULL }, S_NULL }, //1444 /*S_RUB5_00*/ { SPR_RUB5, 0, -1, { NULL }, S_NULL }, //1445 /*S_RUB6_00*/ { SPR_RUB6, 0, -1, { NULL }, S_NULL }, //1446 /*S_RUB7_00*/ { SPR_RUB7, 0, -1, { NULL }, S_NULL }, //1447 /*S_RUB8_00*/ { SPR_RUB8, 0, -1, { NULL }, S_NULL }, //1448 /*S_CHAN_00*/ { SPR_CHAN, 0, -1, { NULL }, S_NULL }, //1449 /*S_STAT_00*/ { SPR_STAT, 0, -1, { NULL }, S_NULL }, //1450 /*S_DSTA_00*/ { SPR_DSTA, 0, -1, { NULL }, S_NULL }, //1451 /*S_CRAB_00*/ { SPR_CRAB, 0, -1, { NULL }, S_NULL }, //1452 /*S_CAGE_00*/ { SPR_CAGE, 0, -1, { NULL }, S_NULL }, //1453 /*S_TREE_00*/ { SPR_TREE, 0, -1, { NULL }, S_NULL }, //1454 /*S_TREE_01*/ { SPR_TREE, 1, -1, { NULL }, S_NULL }, //1455 /*S_TREE_02*/ { SPR_TREE, 2, -1, { NULL }, S_NULL }, //1456 /*S_TRE1_00*/ { SPR_TRE1, 0, -1, { NULL }, S_NULL }, //1457 /*S_BUSH_00*/ { SPR_BUSH, 0, -1, { NULL }, S_NULL }, //1458 /*S_SHRB_00*/ { SPR_SHRB, 0, -1, { NULL }, S_NULL }, //1459 /*S_STAK_00*/ { SPR_STAK, 0, -1, { NULL }, S_NULL }, //1460 /*S_BAR1_00*/ { SPR_BAR1, 0, -1, { NULL }, S_NULL }, //1461 /*S_VASE_00*/ { SPR_VASE, 0, -1, { NULL }, S_NULL }, //1462 /*S_VASE_01*/ { SPR_VASE, 1, -1, { NULL }, S_NULL }, //1463 /*S_STOL_00*/ { SPR_STOL, 0, -1, { NULL }, S_NULL }, //1464 /*S_POT1_00*/ { SPR_POT1, 0, -1, { NULL }, S_NULL }, //1465 /*S_TUB1_00*/ { SPR_TUB1, 0, -1, { NULL }, S_NULL }, //1466 /*S_ANVL_00*/ { SPR_ANVL, 0, -1, { NULL }, S_NULL }, //1467 /*S_TLMP_00*/ { SPR_TLMP, 0, -1, { NULL }, S_NULL }, //1468 /*S_TLMP_01*/ { SPR_TLMP, 1, -1, { NULL }, S_NULL }, //1469 /*S_TRAY_00*/ { SPR_TRAY, 0, -1, { NULL }, S_NULL }, //1470 /*S_APOW_00*/ { SPR_APOW, 0, 4, { A_ActiveSound }, S_APOW_00 }, //1471 /*S_AFED_00*/ { SPR_AFED, 0, -1, { NULL }, S_NULL }, //1472 /*S_DRIP_00*/ { SPR_DRIP, 0, 6, { A_ActiveSound }, S_DRIP_01 }, //1473 /*S_DRIP_01*/ { SPR_DRIP, 1, 4, { NULL }, S_DRIP_02 }, //1474 /*S_DRIP_02*/ { SPR_DRIP, 2, 4, { NULL }, S_DRIP_03 }, //1475 /*S_DRIP_03*/ { SPR_DRIP, 3, 4, { A_ActiveSound }, S_DRIP_04 }, //1476 /*S_DRIP_04*/ { SPR_DRIP, 4, 4, { NULL }, S_DRIP_05 }, //1477 /*S_DRIP_05*/ { SPR_DRIP, 5, 4, { NULL }, S_DRIP_06 }, //1478 /*S_DRIP_06*/ { SPR_DRIP, 6, 4, { A_ActiveSound }, S_DRIP_07 }, //1479 /*S_DRIP_07*/ { SPR_DRIP, 7, 4, { NULL }, S_DRIP_00 }, //1480 /*S_CDRP_00*/ { SPR_CDRP, 0, 10, { NULL }, S_CDRP_01 }, //1481 /*S_CDRP_01*/ { SPR_CDRP, 1, 8, { NULL }, S_CDRP_02 }, //1482 /*S_CDRP_02*/ { SPR_CDRP, 2, 8, { NULL }, S_CDRP_03 }, //1483 /*S_CDRP_03*/ { SPR_CDRP, 3, 8, { NULL }, S_CDRP_00 }, //1484 /*S_SPLH_00*/ { SPR_SPLH, 0, 4, { NULL }, S_SPLH_01 }, //1485 /*S_SPLH_01*/ { SPR_SPLH, 1, 4, { NULL }, S_SPLH_02 }, //1486 /*S_SPLH_02*/ { SPR_SPLH, 2, 4, { NULL }, S_SPLH_03 }, //1487 /*S_SPLH_03*/ { SPR_SPLH, 3, 8, { NULL }, S_SPLH_04 }, //1488 /*S_SPLH_04*/ { SPR_SPLH, 4, 4, { NULL }, S_SPLH_05 }, //1489 /*S_SPLH_05*/ { SPR_SPLH, 5, 4, { NULL }, S_SPLH_06 }, //1490 /*S_SPLH_06*/ { SPR_SPLH, 6, 4, { NULL }, S_SPLH_07 }, //1491 /*S_SPLH_07*/ { SPR_SPLH, 7, 4, { A_ActiveSound }, S_SPLH_00 }, //1492 /*S_WTFT_00*/ { SPR_WTFT, 0, 4, { NULL }, S_WTFT_01 }, //1493 /*S_WTFT_01*/ { SPR_WTFT, 1, 4, { NULL }, S_WTFT_02 }, //1494 /*S_WTFT_02*/ { SPR_WTFT, 2, 4, { NULL }, S_WTFT_03 }, //1495 /*S_WTFT_03*/ { SPR_WTFT, 3, 4, { A_ActiveSound }, S_WTFT_00 }, //1496 /*S_HERT_00*/ { SPR_HERT, 32768, 4, { NULL }, S_HERT_01 }, //1497 /*S_HERT_01*/ { SPR_HERT, 32769, 4, { NULL }, S_HERT_02 }, //1498 /*S_HERT_02*/ { SPR_HERT, 32770, 4, { NULL }, S_HERT_00 }, //1499 /*S_TELP_00*/ { SPR_TELP, 32768, 3, { NULL }, S_TELP_01 }, //1500 /*S_TELP_01*/ { SPR_TELP, 32769, 3, { NULL }, S_TELP_02 }, //1501 /*S_TELP_02*/ { SPR_TELP, 32770, 3, { NULL }, S_TELP_03 }, //1502 /*S_TELP_03*/ { SPR_TELP, 32771, 3, { NULL }, S_TELP_00 }, //1503 /*S_MONI_00*/ { SPR_MONI, 0, -1, { NULL }, S_NULL }, //1504 /*S_STEL_00*/ { SPR_STEL, 0, -1, { NULL }, S_NULL }, //1505 /*S_STLA_00*/ { SPR_STLA, 0, -1, { NULL }, S_NULL }, //1506 /*S_STLE_00*/ { SPR_STLE, 0, -1, { NULL }, S_NULL }, //1507 /*S_HUGE_00*/ { SPR_HUGE, 0, 4, { NULL }, S_HUGE_01 }, //1508 /*S_HUGE_01*/ { SPR_HUGE, 1, 5, { NULL }, S_HUGE_02 }, //1509 /*S_HUGE_02*/ { SPR_HUGE, 2, 5, { NULL }, S_HUGE_03 }, //1510 /*S_HUGE_03*/ { SPR_HUGE, 3, 5, { NULL }, S_HUGE_00 }, //1511 /*S_STLG_00*/ { SPR_STLG, 0, -1, { NULL }, S_NULL }, //1512 /*S_STLG_01*/ { SPR_STLG, 1, -1, { NULL }, S_NULL }, //1513 /*S_STLG_02*/ { SPR_STLG, 2, -1, { NULL }, S_NULL }, //1514 /*S_STLG_03*/ { SPR_STLG, 3, -1, { NULL }, S_NULL }, //1515 /*S_STLG_04*/ { SPR_STLG, 4, -1, { NULL }, S_NULL }, //1516 /*S_STLG_05*/ { SPR_STLG, 5, -1, { NULL }, S_NULL }, //1517 }; // villsa [STRIFE] mobjinfo_t mobjinfo[NUMMOBJTYPES] = { { /*MT_FIELDGUARD*/ 25, //doomednum S_TOKN_00, //spawnstate 10, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_XPRK_00, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 2*FRACUNIT, //radius 1*FRACUNIT, //height 10000, //mass 0, //damage sfx_None, //activesound MF_SHOOTABLE|MF_NOSECTOR|MF_NODIALOG, //flags NULL, //namepointer }, { /*MT_PLAYER*/ -1, //doomednum S_PLAY_00, //spawnstate 100, //spawnhealth S_PLAY_01, //seestate sfx_None, //seesound 0, //reactiontime sfx_None, //attacksound S_PLAY_07, //painstate 255, //painchance sfx_plpain, //painsound S_NULL, //meleestate S_PLAY_05, //missilestate S_NULL, //crashstate S_PLAY_09, //deathstate S_RGIB_00, //xdeathstate sfx_pldeth, //deathsound 0, //speed 18*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOTDMATCH|MF_ALLY, //flags NULL, //namepointer }, { /*MT_SHOPKEEPER_W*/ 116, //doomednum S_MRST_00, //spawnstate 10000000, //spawnhealth S_MRPN_00, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_MRPN_00, //painstate 150, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 5000, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH, //flags "Weapon_Smith", //namepointer }, { /*MT_SHOPKEEPER_B*/ 72, //doomednum S_MRST_00, //spawnstate 10000000, //spawnhealth S_MRPN_00, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_MRPN_00, //painstate 150, //painchance sfx_ambbar, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 5000, //mass 0, //damage sfx_ambppl, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP1|MF_COLORSWAP3, //flags "Bar_Keep", //namepointer }, { /*MT_SHOPKEEPER_A*/ 73, //doomednum S_MRST_00, //spawnstate 10000000, //spawnhealth S_MRPN_00, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_MRPN_00, //painstate 150, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 5000, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP2|MF_COLORSWAP3, //flags "Armorer", //namepointer }, { /*MT_SHOPKEEPER_M*/ 74, //doomednum S_MRST_00, //spawnstate 10000000, //spawnhealth S_MRPN_00, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_MRPN_00, //painstate 150, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 50000, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP1|MF_COLORSWAP2 |MF_COLORSWAP3, //flags "Medic", //namepointer }, { /*MT_PEASANT2_A*/ 3004, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 4, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_PEASANT2_B*/ 130, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 5, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_PEASANT2_C*/ 131, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 5, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_PEASANT5_A*/ 65, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 7, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags NULL, //namepointer }, { /*MT_PEASANT5_B*/ 132, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 7, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags NULL, //namepointer }, { /*MT_PEASANT5_C*/ 133, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 7, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags NULL, //namepointer }, { /*MT_PEASANT4_A*/ 66, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1 |MF_COLORSWAP2, //flags NULL, //namepointer }, { /*MT_PEASANT4_B*/ 134, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1 |MF_COLORSWAP2, //flags NULL, //namepointer }, { /*MT_PEASANT4_C*/ 135, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1 |MF_COLORSWAP2, //flags NULL, //namepointer }, { /*MT_PEASANT6_A*/ 67, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags NULL, //namepointer }, { /*MT_PEASANT6_B*/ 136, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 7, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags NULL, //namepointer }, { /*MT_PEASANT6_C*/ 137, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags NULL, //namepointer }, { /*MT_PEASANT3_A*/ 172, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT3_B*/ 173, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT3_C*/ 174, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT8_A*/ 175, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2 |MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT8_B*/ 176, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2 |MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT8_C*/ 177, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2 |MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT7_A*/ 178, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1 |MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT7_B*/ 179, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1 |MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT7_C*/ 180, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1 |MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_PEASANT1*/ 181, //doomednum S_PEAS_00, //spawnstate 31, //spawnhealth S_PEAS_01, //seestate sfx_rebact, //seesound 8, //reactiontime sfx_meatht, //attacksound S_PEAS_12, //painstate 200, //painchance sfx_pespna, //painsound S_PEAS_09, //meleestate S_NULL, //missilestate S_PEAS_14, //crashstate S_PEAS_17, //deathstate S_GIBS_00, //xdeathstate sfx_psdtha, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1 |MF_COLORSWAP2|MF_COLORSWAP3, //flags NULL, //namepointer }, { /*MT_ZOMBIE*/ 169, //doomednum S_PEAS_25, //spawnstate 31, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_AGRD_00, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_GIBS_00, //deathstate S_NULL, //xdeathstate sfx_psdtha, //deathsound 0, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1, //flags NULL, //namepointer }, { /*MT_BECOMING*/ 201, //doomednum S_ARMR_00, //spawnstate 61, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_ARMR_01, //painstate 255, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_GIBS_10, //deathstate S_NULL, //xdeathstate sfx_psdtha, //deathsound 0, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_ZOMBIESPAWNER*/ 170, //doomednum S_PLAY_19, //spawnstate 20, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_telept, //activesound MF_SHOOTABLE|MF_NOSECTOR, //flags NULL, //namepointer }, { /*MT_HUGE_TANK_1*/ 209, //doomednum S_TNK1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 192*FRACUNIT, //height 50000, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_HUGE_TANK_2*/ 210, //doomednum S_TNK2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 192*FRACUNIT, //height 50000, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_HUGE_TANK_3*/ 211, //doomednum S_TNK3_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 192*FRACUNIT, //height 50000, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TANK_4*/ 213, //doomednum S_TNK4_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 56*FRACUNIT, //height 50000, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TANK_5*/ 214, //doomednum S_TNK5_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 56*FRACUNIT, //height 50000, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TANK_6*/ 229, //doomednum S_TNK6_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 56*FRACUNIT, //height 50000, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_KNEELING_GUY*/ 204, //doomednum S_NEAL_00, //spawnstate 51, //spawnhealth S_NEAL_00, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NEAL_02, //painstate 255, //painchance sfx_static, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NEAL_05, //crashstate S_NEAL_07, //deathstate S_NULL, //xdeathstate sfx_static, //deathsound 0, //speed 6*FRACUNIT, //radius 6*FRACUNIT, //height 50000, //mass 0, //damage sfx_chant, //activesound MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_BEGGAR1*/ 141, //doomednum S_BEGR_00, //spawnstate 20, //spawnhealth S_BEGR_01, //seestate sfx_None, //seesound 8, //reactiontime sfx_meatht, //attacksound S_BEGR_11, //painstate 250, //painchance sfx_pespna, //painsound S_BEGR_07, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BEGR_13, //deathstate S_BEGR_22, //xdeathstate sfx_psdtha, //deathsound 3, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags "Beggar", //namepointer }, { /*MT_BEGGAR2*/ 155, //doomednum S_BEGR_00, //spawnstate 20, //spawnhealth S_BEGR_01, //seestate sfx_None, //seesound 8, //reactiontime sfx_meatht, //attacksound S_BEGR_11, //painstate 250, //painchance sfx_pespna, //painsound S_BEGR_07, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BEGR_13, //deathstate S_BEGR_22, //xdeathstate sfx_psdtha, //deathsound 3, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags "Beggar", //namepointer }, { /*MT_BEGGAR3*/ 156, //doomednum S_BEGR_00, //spawnstate 20, //spawnhealth S_BEGR_01, //seestate sfx_None, //seesound 8, //reactiontime sfx_meatht, //attacksound S_BEGR_11, //painstate 250, //painchance sfx_pespna, //painsound S_BEGR_07, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BEGR_13, //deathstate S_BEGR_22, //xdeathstate sfx_psdtha, //deathsound 3, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags "Beggar", //namepointer }, { /*MT_BEGGAR4*/ 157, //doomednum S_BEGR_00, //spawnstate 20, //spawnhealth S_BEGR_01, //seestate sfx_None, //seesound 8, //reactiontime sfx_meatht, //attacksound S_BEGR_11, //painstate 250, //painchance sfx_pespna, //painsound S_BEGR_07, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BEGR_13, //deathstate S_BEGR_22, //xdeathstate sfx_psdtha, //deathsound 3, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags "Beggar", //namepointer }, { /*MT_BEGGAR5*/ 158, //doomednum S_BEGR_00, //spawnstate 20, //spawnhealth S_BEGR_01, //seestate sfx_None, //seesound 8, //reactiontime sfx_meatht, //attacksound S_BEGR_11, //painstate 250, //painchance sfx_pespna, //painsound S_BEGR_07, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BEGR_13, //deathstate S_BEGR_22, //xdeathstate sfx_psdtha, //deathsound 3, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags "Beggar", //namepointer }, { /*MT_REBEL1*/ 9, //doomednum S_HMN1_00, //spawnstate 60, //spawnhealth S_HMN1_11, //seestate sfx_wpnup, //seesound 8, //reactiontime sfx_None, //attacksound S_HMN1_22, //painstate 250, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_HMN1_19, //missilestate S_NULL, //crashstate S_HMN1_24, //deathstate S_RGIB_08, //xdeathstate sfx_rebdth, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags "Rebel", //namepointer }, { /*MT_REBEL2*/ 144, //doomednum S_HMN1_00, //spawnstate 60, //spawnhealth S_HMN1_11, //seestate sfx_wpnup, //seesound 8, //reactiontime sfx_None, //attacksound S_HMN1_22, //painstate 250, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_HMN1_19, //missilestate S_NULL, //crashstate S_HMN1_24, //deathstate S_RGIB_08, //xdeathstate sfx_rebdth, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags "Rebel", //namepointer }, { /*MT_REBEL3*/ 145, //doomednum S_HMN1_00, //spawnstate 60, //spawnhealth S_HMN1_11, //seestate sfx_wpnup, //seesound 8, //reactiontime sfx_None, //attacksound S_HMN1_22, //painstate 250, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_HMN1_19, //missilestate S_NULL, //crashstate S_HMN1_24, //deathstate S_RGIB_08, //xdeathstate sfx_rebdth, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags "Rebel", //namepointer }, { /*MT_REBEL4*/ 149, //doomednum S_HMN1_00, //spawnstate 60, //spawnhealth S_HMN1_11, //seestate sfx_wpnup, //seesound 8, //reactiontime sfx_None, //attacksound S_HMN1_22, //painstate 250, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_HMN1_19, //missilestate S_NULL, //crashstate S_HMN1_24, //deathstate S_RGIB_08, //xdeathstate sfx_rebdth, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags "Rebel", //namepointer }, { /*MT_REBEL5*/ 150, //doomednum S_HMN1_00, //spawnstate 60, //spawnhealth S_HMN1_11, //seestate sfx_wpnup, //seesound 8, //reactiontime sfx_None, //attacksound S_HMN1_22, //painstate 250, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_HMN1_19, //missilestate S_NULL, //crashstate S_HMN1_24, //deathstate S_RGIB_08, //xdeathstate sfx_rebdth, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags "Rebel", //namepointer }, { /*MT_REBEL6*/ 151, //doomednum S_HMN1_00, //spawnstate 60, //spawnhealth S_HMN1_11, //seestate sfx_wpnup, //seesound 8, //reactiontime sfx_None, //attacksound S_HMN1_22, //painstate 250, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_HMN1_19, //missilestate S_NULL, //crashstate S_HMN1_24, //deathstate S_RGIB_08, //xdeathstate sfx_rebdth, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags "Rebel", //namepointer }, { /*MT_RLEADER*/ 64, //doomednum S_LEDR_00, //spawnstate 95, //spawnhealth S_LEAD_04, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_None, //attacksound S_LEAD_15, //painstate 250, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_LEAD_12, //missilestate S_NULL, //crashstate S_LEAD_04, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOTDMATCH, //flags "MACIL", //namepointer }, { /*MT_RLEADER2*/ 200, //doomednum S_LEDR_00, //spawnstate 95, //spawnhealth S_LEAD_04, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_None, //attacksound S_LEAD_15, //painstate 200, //painchance sfx_pespna, //painsound S_NULL, //meleestate S_LEAD_17, //missilestate S_NULL, //crashstate S_LEAD_20, //deathstate S_LEAD_20, //xdeathstate sfx_slop, //deathsound 8, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_rebact, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOTDMATCH|MF_SPECTRAL, //flags "MACIL", //namepointer }, { /*MT_MISSILESMOKE*/ -1, //doomednum S_PUFY_04, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_rflite, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags NULL, //namepointer }, { /*MT_REAVER*/ 3001, //doomednum S_ROB1_00, //spawnstate 150, //spawnhealth S_ROB1_02, //seestate sfx_revsee, //seesound 8, //reactiontime sfx_None, //attacksound S_ROB1_15, //painstate 128, //painchance sfx_reavpn, //painsound S_ROB1_10, //meleestate S_ROB1_13, //missilestate S_NULL, //crashstate S_ROB1_17, //deathstate S_ROB1_26, //xdeathstate sfx_revdth, //deathsound 12, //speed 20*FRACUNIT, //radius 60*FRACUNIT, //height 500, //mass 0, //damage sfx_revact, //activesound MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_GUARD1*/ 3002, //doomednum S_AGRD_01, //spawnstate 70, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac1, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags "ACOLYTE", //namepointer }, { /*MT_GUARD2*/ 142, //doomednum S_AGRD_01, //spawnstate 70, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac2, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1, //flags "ACOLYTE", //namepointer }, { /*MT_GUARD3*/ 143, //doomednum S_AGRD_01, //spawnstate 70, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac3, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP2, //flags "ACOLYTE", //namepointer }, { /*MT_GUARD4*/ 146, //doomednum S_AGRD_01, //spawnstate 70, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac1, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP2, //flags "ACOLYTE", //namepointer }, { /*MT_GUARD5*/ 147, //doomednum S_AGRD_01, //spawnstate 70, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac2, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP3, //flags "ACOLYTE", //namepointer }, { /*MT_GUARD6*/ 148, //doomednum S_AGRD_01, //spawnstate 70, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac3, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP3, //flags "ACOLYTE", //namepointer }, { /*MT_GUARD7*/ 232, //doomednum S_AGRD_01, //spawnstate 60, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac3, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP2|MF_COLORSWAP3, //flags "ACOLYTE", //namepointer }, { /*MT_GUARD8*/ 231, //doomednum S_AGRD_01, //spawnstate 60, //spawnhealth S_AGRD_13, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_23, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac3, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP2 |MF_COLORSWAP3, //flags "ACOLYTE", //namepointer }, { /*MT_SHADOWGUARD*/ 58, //doomednum S_AGRD_01, //spawnstate 70, //spawnhealth S_AGRD_12, //seestate sfx_agrsee, //seesound 8, //reactiontime sfx_rifle, //attacksound S_AGRD_21, //painstate 150, //painchance sfx_agrdpn, //painsound S_NULL, //meleestate S_AGRD_17, //missilestate S_NULL, //crashstate S_AGRD_24, //deathstate S_GIBS_10, //xdeathstate sfx_agrdth, //deathsound 7, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 400, //mass 0, //damage sfx_agrac2, //activesound MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags "ACOLYTE", //namepointer }, { /*MT_PGUARD*/ 3003, //doomednum S_PGRD_00, //spawnstate 300, //spawnhealth S_PGRD_04, //seestate sfx_pgrsee, //seesound 8, //reactiontime sfx_None, //attacksound S_PGRD_16, //painstate 100, //painchance sfx_pgrdpn, //painsound S_PGRD_12, //meleestate S_PGRD_14, //missilestate S_NULL, //crashstate S_PGRD_18, //deathstate S_NULL, //xdeathstate sfx_pgrdth, //deathsound 8, //speed 20*FRACUNIT, //radius 60*FRACUNIT, //height 500, //mass 0, //damage sfx_pgract, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_COUNTKILL, //flags "TEMPLAR", //namepointer }, { /*MT_CRUSADER*/ 3005, //doomednum S_ROB2_00, //spawnstate 400, //spawnhealth S_ROB2_01, //seestate sfx_rb2see, //seesound 8, //reactiontime sfx_None, //attacksound S_ROB2_19, //painstate 128, //painchance sfx_rb2pn, //painsound S_NULL, //meleestate S_ROB2_09, //missilestate S_NULL, //crashstate S_ROB2_20, //deathstate S_NULL, //xdeathstate sfx_rb2dth, //deathsound 8, //speed 40*FRACUNIT, //radius 56*FRACUNIT, //height 400, //mass 0, //damage sfx_rb2act, //activesound MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_BISHOP*/ 187, //doomednum S_MLDR_00, //spawnstate 500, //spawnhealth S_MLDR_01, //seestate sfx_rb2see, //seesound 8, //reactiontime sfx_None, //attacksound S_MLDR_11, //painstate 128, //painchance sfx_rb2pn, //painsound S_NULL, //meleestate S_MLDR_09, //missilestate S_NULL, //crashstate S_MLDR_12, //deathstate S_NULL, //xdeathstate sfx_pgrdth, //deathsound 8, //speed 40*FRACUNIT, //radius 56*FRACUNIT, //height 500, //mass 0, //damage sfx_rb2act, //activesound MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL |MF_NOTDMATCH, //flags NULL, //namepointer }, { /*MT_ORACLE*/ 199, //doomednum S_ORCL_00, //spawnstate 1, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ORCL_01, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 15*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags "ORACLE", //namepointer }, { /*MT_PRIEST*/ 12, //doomednum S_PRST_00, //spawnstate 800, //spawnhealth S_PRST_02, //seestate sfx_lorsee, //seesound 8, //reactiontime sfx_revbld, //attacksound S_NULL, //painstate 0, //painchance sfx_lorpn, //painsound S_PRST_10, //meleestate S_PRST_13, //missilestate S_NULL, //crashstate S_PDED_00, //deathstate S_NULL, //xdeathstate sfx_slop, //deathsound 10, //speed 15*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_tend, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_FLOAT |MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags "PRIEST", //namepointer }, { /*MT_SPECTRE_A*/ 129, //doomednum S_ALN1_00, //spawnstate 1000, //spawnhealth S_ALN1_02, //seestate sfx_alnsee, //seesound 8, //reactiontime sfx_revbld, //attacksound S_ALN1_19, //painstate 250, //painchance sfx_alnpn, //painsound S_ALN1_13, //meleestate S_ALN1_16, //missilestate S_NULL, //crashstate S_AL1P_00, //deathstate S_NULL, //xdeathstate sfx_alndth, //deathsound 12, //speed 64*FRACUNIT, //radius 64*FRACUNIT, //height 1000, //mass 0, //damage sfx_alnact, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH |MF_MVIS|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_NODE*/ -1, //doomednum S_NODE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH, //flags NULL, //namepointer }, { /*MT_SPECTREHEAD*/ -1, //doomednum S_MTHD_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH, //flags NULL, //namepointer }, { /*MT_SPECTRE_B*/ 75, //doomednum S_ALN1_00, //spawnstate 1200, //spawnhealth S_ALN1_02, //seestate sfx_alnsee, //seesound 8, //reactiontime sfx_revbld, //attacksound S_ALN1_19, //painstate 50, //painchance sfx_alnpn, //painsound S_ALN1_13, //meleestate S_ALN1_20, //missilestate S_NULL, //crashstate S_AL1P_00, //deathstate S_NULL, //xdeathstate sfx_alndth, //deathsound 12, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 1000, //mass 0, //damage sfx_alnact, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH |MF_MVIS|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SPECTRE_C*/ 76, //doomednum S_ALN1_23, //spawnstate 1500, //spawnhealth S_ALN1_34, //seestate sfx_alnsee, //seesound 8, //reactiontime sfx_revbld, //attacksound S_ALN1_51, //painstate 50, //painchance sfx_alnpn, //painsound S_ALN1_45, //meleestate S_ALN1_48, //missilestate S_NULL, //crashstate S_AL1P_00, //deathstate S_NULL, //xdeathstate sfx_alndth, //deathsound 12, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 1000, //mass 0, //damage sfx_alnact, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH |MF_MVIS|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SPECTRE_D*/ 167, //doomednum S_ALN1_00, //spawnstate 1700, //spawnhealth S_ALN1_02, //seestate sfx_alnsee, //seesound 8, //reactiontime sfx_revbld, //attacksound S_ALN1_19, //painstate 50, //painchance sfx_alnpn, //painsound S_ALN1_13, //meleestate S_ALN1_52, //missilestate S_NULL, //crashstate S_AL1P_00, //deathstate S_NULL, //xdeathstate sfx_alndth, //deathsound 12, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 1000, //mass 0, //damage sfx_alnact, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH |MF_MVIS|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SPECTRE_E*/ 168, //doomednum S_ALN1_00, //spawnstate 2000, //spawnhealth S_ALN1_02, //seestate sfx_alnsee, //seesound 8, //reactiontime sfx_revbld, //attacksound S_ALN1_19, //painstate 50, //painchance sfx_alnpn, //painsound S_ALN1_13, //meleestate S_ALN1_55, //missilestate S_NULL, //crashstate S_AL1P_00, //deathstate S_NULL, //xdeathstate sfx_alndth, //deathsound 12, //speed 24*FRACUNIT, //radius 64*FRACUNIT, //height 1000, //mass 0, //damage sfx_alnact, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH |MF_MVIS|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_ENTITY*/ 128, //doomednum S_MNAM_00, //spawnstate 2500, //spawnhealth S_MNAL_02, //seestate sfx_mnalse, //seesound 8, //reactiontime sfx_revbld, //attacksound S_MNAL_19, //painstate 255, //painchance sfx_alnpn, //painsound S_MNAL_13, //meleestate S_MNAL_16, //missilestate S_NULL, //crashstate S_MNAL_20, //deathstate S_NULL, //xdeathstate sfx_mnaldt, //deathsound 13, //speed 130*FRACUNIT, //radius 200*FRACUNIT, //height 1000, //mass 0, //damage sfx_alnact, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH |MF_MVIS|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SUBENTITY*/ -1, //doomednum S_MNAL_27, //spawnstate 990, //spawnhealth S_MNAL_28, //seestate sfx_alnsee, //seesound 8, //reactiontime sfx_revbld, //attacksound S_MNAL_40, //painstate 255, //painchance sfx_alnpn, //painsound S_MNAL_34, //meleestate S_MNAL_37, //missilestate S_NULL, //crashstate S_MDTH_00, //deathstate S_NULL, //xdeathstate sfx_alndth, //deathsound 14, //speed 130*FRACUNIT, //radius 200*FRACUNIT, //height 1000, //mass 0, //damage sfx_alnact, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH |MF_MVIS|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_NEST*/ 26, //doomednum S_NEST_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 84*FRACUNIT, //radius 47*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_NOTDMATCH, //flags NULL, //namepointer }, { /*MT_POD*/ 198, //doomednum S_PODD_00, //spawnstate 1000, //spawnhealth S_PODD_01, //seestate sfx_slop, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 25*FRACUNIT, //radius 91*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_NOTDMATCH, //flags NULL, //namepointer }, { /*MT_SIGIL_B_SHOT*/ -1, //doomednum S_ZAP6_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_00, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 30*FRACUNIT, //speed 8*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 70, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_SB_SHOT*/ -1, //doomednum S_ZAP6_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_00, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 30*FRACUNIT, //speed 8*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 20, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_C_SHOT*/ -1, //doomednum S_ZOT3_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_00, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 30*FRACUNIT, //speed 8*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 70, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_SC_SHOT*/ -1, //doomednum S_ZOT3_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_00, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 30*FRACUNIT, //speed 8*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 20, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_E_OFFSHOOT*/ -1, //doomednum S_ZAP6_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_00, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 30*FRACUNIT, //speed 8*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 10, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_TRAIL*/ -1, //doomednum S_ZAP6_03, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF, //flags NULL, //namepointer }, { /*MT_SIGIL_E_SHOT*/ -1, //doomednum S_ZAP7_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_02, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 18*FRACUNIT, //speed 20*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 130, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_SE_SHOT*/ -1, //doomednum S_ZAP7_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_02, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 18*FRACUNIT, //speed 20*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 30, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_A_ZAP_LEFT*/ -1, //doomednum S_ZOT1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_06, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 22*FRACUNIT, //speed 8*FRACUNIT, //radius 24*FRACUNIT, //height 100, //mass 100, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_A_ZAP_RIGHT*/ -1, //doomednum S_ZOT1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_06, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 22*FRACUNIT, //speed 8*FRACUNIT, //radius 24*FRACUNIT, //height 100, //mass 50, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_A_GROUND*/ -1, //doomednum S_ZAP5_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 70, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_01, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 18*FRACUNIT, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_SHADOW, //flags NULL, //namepointer }, { /*MT_SIGIL_D_SHOT*/ -1, //doomednum S_ZOT2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_01, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 28*FRACUNIT, //speed 8*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 120, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SIGIL_SD_SHOT*/ -1, //doomednum S_ZOT2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_sigil, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_01, //deathstate S_NULL, //xdeathstate sfx_sglhit, //deathsound 28*FRACUNIT, //speed 8*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 60, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags NULL, //namepointer }, { /*MT_SENTINEL*/ 3006, //doomednum S_SEWR_00, //spawnstate 100, //spawnhealth S_SEWR_01, //seestate sfx_sntsee, //seesound 8, //reactiontime sfx_None, //attacksound S_SEWR_06, //painstate 255, //painchance sfx_None, //painsound S_NULL, //meleestate S_SEWR_03, //missilestate S_NULL, //crashstate S_SEWR_07, //deathstate S_NULL, //xdeathstate sfx_sntdth, //deathsound 7, //speed 23*FRACUNIT, //radius 53*FRACUNIT, //height 300, //mass 0, //damage sfx_sntact, //activesound MF_SOLID|MF_SHOOTABLE|MF_SPAWNCEILING|MF_NOGRAVITY|MF_GIVEQUEST |MF_FLOAT|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_STALKER*/ 186, //doomednum S_SPID_00, //spawnstate 80, //spawnhealth S_SPID_03, //seestate sfx_spisit, //seesound 8, //reactiontime sfx_spdatk, //attacksound S_SPID_24, //painstate 40, //painchance sfx_spdatk, //painsound S_SPID_09, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_SPID_25, //deathstate S_NULL, //xdeathstate sfx_spidth, //deathsound 16, //speed 31*FRACUNIT, //radius 25*FRACUNIT, //height 100, //mass 0, //damage sfx_spisit, //activesound MF_SOLID|MF_SHOOTABLE|MF_SPAWNCEILING|MF_NOGRAVITY|MF_DROPOFF |MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_INQUISITOR*/ 16, //doomednum S_ROB3_00, //spawnstate 1000, //spawnhealth S_ROB3_02, //seestate sfx_inqsee, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_ROB3_10, //missilestate S_NULL, //crashstate S_ROB3_20, //deathstate S_NULL, //xdeathstate sfx_inqdth, //deathsound 12, //speed 40*FRACUNIT, //radius 110*FRACUNIT, //height 1000, //mass 0, //damage sfx_inqact, //activesound MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOBLOOD|MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_INQARM*/ -1, //doomednum S_RBB3_05, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 25, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_PROGRAMMER*/ 71, //doomednum S_PRGR_00, //spawnstate 1100, //spawnhealth S_PRGR_02, //seestate sfx_None, //seesound 8, //reactiontime sfx_revbld, //attacksound S_PRGR_18, //painstate 50, //painchance sfx_prgpn, //painsound S_PRGR_10, //meleestate S_PRGR_14, //missilestate S_NULL, //crashstate S_PRGR_20, //deathstate S_NULL, //xdeathstate sfx_rb2dth, //deathsound 26, //speed 45*FRACUNIT, //radius 60*FRACUNIT, //height 800, //mass 4, //damage sfx_progac, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_FLOAT |MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags NULL, //namepointer }, { /*MT_PROGRAMMERBASE*/ -1, //doomednum S_BASE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_HOOKSHOT*/ -1, //doomednum S_OCLW_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_chain, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_CCLW_00, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 20*FRACUNIT, //speed 10*FRACUNIT, //radius 14*FRACUNIT, //height 100, //mass 2, //damage sfx_swish, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_CHAINSHOT*/ -1, //doomednum S_TEND_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_tend, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_MINIMISSLE*/ -1, //doomednum S_MICR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_rlaunc, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_MISL_01, //deathstate S_NULL, //xdeathstate sfx_mislht, //deathsound 20*FRACUNIT, //speed 10*FRACUNIT, //radius 14*FRACUNIT, //height 100, //mass 10, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_C_MISSILE*/ -1, //doomednum S_MICR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_rlaunc, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_MISL_00, //deathstate S_NULL, //xdeathstate sfx_mislht, //deathsound 20*FRACUNIT, //speed 10*FRACUNIT, //radius 14*FRACUNIT, //height 100, //mass 7, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_SEEKMISSILE*/ -1, //doomednum S_MISS_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_rlaunc, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_MISL_01, //deathstate S_NULL, //xdeathstate sfx_mislht, //deathsound 20*FRACUNIT, //speed 10*FRACUNIT, //radius 14*FRACUNIT, //height 100, //mass 10, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_ELECARROW*/ -1, //doomednum S_AROW_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_swish, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_ZAP1_01, //deathstate S_NULL, //xdeathstate sfx_firxpl, //deathsound 30*FRACUNIT, //speed 10*FRACUNIT, //radius 10*FRACUNIT, //height 100, //mass 10, //damage sfx_swish, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_POISARROW*/ -1, //doomednum S_ARWP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_swish, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_AROW_01, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 30*FRACUNIT, //speed 10*FRACUNIT, //radius 10*FRACUNIT, //height 100, //mass 500, //damage sfx_swish, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_R_LASER*/ -1, //doomednum S_SHT1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_POW1_09, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 40*FRACUNIT, //speed 10*FRACUNIT, //radius 8*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_L_LASER*/ -1, //doomednum S_SHT1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_plasma, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_POW1_05, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 40*FRACUNIT, //speed 10*FRACUNIT, //radius 8*FRACUNIT, //height 100, //mass 1, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_HEGRENADE*/ -1, //doomednum S_GRAP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_phoot, //seesound 30, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BNG4_00, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 15*FRACUNIT, //speed 13*FRACUNIT, //radius 13*FRACUNIT, //height 20, //mass 1, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_PGRENADE*/ -1, //doomednum S_GRIN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_phoot, //seesound 40, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BNG3_08, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 15*FRACUNIT, //speed 13*FRACUNIT, //radius 13*FRACUNIT, //height 20, //mass 1, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_INQGRENADE*/ -1, //doomednum S_UBAM_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_phoot, //seesound 15, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BNG2_00, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 25*FRACUNIT, //speed 13*FRACUNIT, //radius 13*FRACUNIT, //height 15, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_PFLAME*/ -1, //doomednum S_BNG3_09, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 120, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_FLBE_07, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_TORPEDO*/ -1, //doomednum S_TORP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_protfl, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_THIT_00, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 20*FRACUNIT, //speed 13*FRACUNIT, //radius 8*FRACUNIT, //height 100, //mass 1, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_TORPEDOSPREAD*/ -1, //doomednum S_TWAV_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_TWAV_02, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 35*FRACUNIT, //speed 13*FRACUNIT, //radius 13*FRACUNIT, //height 100, //mass 10, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_SFIREBALL*/ -1, //doomednum S_FRBL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_flburn, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_FRBL_03, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 15*FRACUNIT, //speed 8*FRACUNIT, //radius 11*FRACUNIT, //height 10, //mass 4, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_C_FLAME*/ -1, //doomednum S_FRBL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_flburn, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_FRBL_03, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 35*FRACUNIT, //speed 8*FRACUNIT, //radius 11*FRACUNIT, //height 50, //mass 1, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags NULL, //namepointer }, { /*MT_STRIFEPUFF3*/ -1, //doomednum S_SHT2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_STRIFEPUFF*/ -1, //doomednum S_PUFY_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags NULL, //namepointer }, { /*MT_SPARKPUFF*/ -1, //doomednum S_POW3_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_BLOOD_DEATH*/ -1, //doomednum S_SPRY_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_TFOG*/ -1, //doomednum S_TFOG_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags NULL, //namepointer }, { /*MT_IFOG*/ -1, //doomednum S_IFOG_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags NULL, //namepointer }, { /*MT_TELEPORTMAN*/ 14, //doomednum S_NULL, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOSECTOR|MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_01*/ 24, //doomednum S_KLAX_00, //spawnstate 1000, //spawnhealth S_KLAX_01, //seestate sfx_None, //seesound 60, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_STAND|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_TURRET*/ 27, //doomednum S_TURT_00, //spawnstate 125, //spawnhealth S_TURT_01, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_TURT_02, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_TURT_02, //missilestate S_NULL, //crashstate S_BALL_00, //deathstate S_NULL, //xdeathstate sfx_mislht, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 10000000, //mass 0, //damage sfx_None, //activesound MF_SHOOTABLE|MF_STAND|MF_SPAWNCEILING|MF_NOGRAVITY|MF_NOBLOOD |MF_COUNTKILL, //flags NULL, //namepointer }, { /*MT_GATE*/ 45, //doomednum S_PSTN_00, //spawnstate 100, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_PSTN_02, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 16, //speed 20*FRACUNIT, //radius 76*FRACUNIT, //height 10000000, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_COMPUTER*/ 182, //doomednum S_SECR_00, //spawnstate 80, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_SECR_04, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 27, //speed 26*FRACUNIT, //radius 128*FRACUNIT, //height 100000, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_INV_MED1*/ 2011, //doomednum S_STMP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 20, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Med_patch", //namepointer }, { /*MT_INV_MED2*/ 2012, //doomednum S_MDKT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 15, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Medical_kit", //namepointer }, { /*MT_INV_MED3*/ 83, //doomednum S_FULL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 5, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Surgery_Kit", //namepointer }, { /*MT_DEGNINORE*/ 59, //doomednum S_XPRK_01, //spawnstate 10, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_XPRK_02, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 0, //speed 16*FRACUNIT, //radius 16*FRACUNIT, //height 10, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags "Degnin_Ore", //namepointer }, { /*MT_INV_ARMOR2*/ 2019, //doomednum S_ARM1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 3, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Metal_Armor", //namepointer }, { /*MT_INV_ARMOR1*/ 2018, //doomednum S_ARM2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 5, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Leather_Armor", //namepointer }, { /*MT_MISC_22*/ 2014, //doomednum S_WATR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_MISC_11*/ 164, //doomednum S_MUGG_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_KEY_BASE*/ 230, //doomednum S_FUSL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Base_Key", //namepointer }, { /*MT_GOVSKEY*/ -1, //doomednum S_REBL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Govs_Key", //namepointer }, { /*MT_KEY_TRAVEL*/ 185, //doomednum S_TPAS_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Passcard", //namepointer }, { /*MT_KEY_ID_BLUE*/ 184, //doomednum S_CRD1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "ID_Badge", //namepointer }, { /*MT_PRISONKEY*/ -1, //doomednum S_PRIS_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 11, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags "Prison_Key", //namepointer }, { /*MT_KEY_HAND*/ 91, //doomednum S_HAND_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 12, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags "Severed_Hand", //namepointer }, { /*MT_POWER1KEY*/ -1, //doomednum S_PWR1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Power1_Key", //namepointer }, { /*MT_POWER2KEY*/ -1, //doomednum S_PWR2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Power2_Key", //namepointer }, { /*MT_POWER3KEY*/ -1, //doomednum S_PWR3_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Power3_Key", //namepointer }, { /*MT_KEY_GOLD*/ 40, //doomednum S_KY1G_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Gold_Key", //namepointer }, { /*MT_KEY_ID_GOLD*/ 13, //doomednum S_CRD2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "ID_Card", //namepointer }, { /*MT_KEY_SILVER*/ 38, //doomednum S_KY2S_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Silver_Key", //namepointer }, { /*MT_KEY_ORACLE*/ 61, //doomednum S_ORAC_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Oracle_Key", //namepointer }, { /*MT_MILITARYID*/ -1, //doomednum S_GYID_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Military_ID", //namepointer }, { /*MT_KEY_ORDER*/ 86, //doomednum S_FUBR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Order_Key", //namepointer }, { /*MT_KEY_WAREHOUSE*/ 166, //doomednum S_WARE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Warehouse_Key", //namepointer }, { /*MT_KEY_BRASS*/ 39, //doomednum S_KY3B_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Brass_Key", //namepointer }, { /*MT_KEY_RED_CRYSTAL*/ 192, //doomednum S_RCRY_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Red_Crystal_Key", //namepointer }, { /*MT_KEY_BLUE_CRYSTAL*/ 193, //doomednum S_BCRY_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Blue_Crystal_Key", //namepointer }, { /*MT_KEY_CHAPEL*/ 195, //doomednum S_CHAP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Chapel_Key", //namepointer }, { /*MT_CATACOMBKEY*/ -1, //doomednum S_TUNL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 28, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags "Catacomb_Key", //namepointer }, { /*MT_SECURITYKEY*/ -1, //doomednum S_SECK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Security_Key", //namepointer }, { /*MT_KEY_CORE*/ 236, //doomednum S_GOID_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Core_Key", //namepointer }, { /*MT_KEY_MAULER*/ 233, //doomednum S_BLTK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Mauler_Key", //namepointer }, { /*MT_KEY_FACTORY*/ 234, //doomednum S_PROC_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Factory_Key", //namepointer }, { /*MT_KEY_MINE*/ 235, //doomednum S_MINE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "MINE_KEY", //namepointer }, { /*MT_NEWKEY5*/ -1, //doomednum S_BLTK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "New_Key5", //namepointer }, { /*MT_INV_SHADOWARMOR*/ 2024, //doomednum S_SHD1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 2, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Shadow_armor", //namepointer }, { /*MT_INV_SUIT*/ 2025, //doomednum S_MASK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 5, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Environmental_Suit", //namepointer }, { /*MT_QUEST_UNIFORM*/ 90, //doomednum S_UNIF_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 15, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST, //flags "Guard_Uniform", //namepointer }, { /*MT_QUEST_GUARD_UNIFORM*/ 52, //doomednum S_OFIC_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Officer's_Uniform", //namepointer }, { /*MT_INV_SUPERMAP*/ 2026, //doomednum S_PMAP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "map", //namepointer }, { /*MT_INV_RADAR*/ 2027, //doomednum S_PMUP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 1, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "scanner", //namepointer }, { /*MT_BEACON*/ 10, //doomednum S_BEAC_00, //spawnstate 5, //spawnhealth S_BEAC_01, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 16*FRACUNIT, //height 3, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_DROPPED, //flags "Teleporter_Beacon", //namepointer }, { /*MT_INV_TARGETER*/ 207, //doomednum S_TARG_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 5, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Targeter", //namepointer }, { /*MT_MONY_1*/ 93, //doomednum S_COIN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 2147483647, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags "coin", //namepointer }, { /*MT_MONY_10*/ 138, //doomednum S_CRED_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags "10_gold", //namepointer }, { /*MT_MONY_25*/ 139, //doomednum S_SACK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags "25_gold", //namepointer }, { /*MT_MONY_50*/ 140, //doomednum S_CHST_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags "50_gold", //namepointer }, { /*MT_MONY_300*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 3, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags "300_gold", //namepointer }, { /*MT_TOKEN_RING*/ -1, //doomednum S_RING_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 1, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags "ring", //namepointer }, { /*MT_INV_CHALICE*/ 205, //doomednum S_RELC_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 2, //speed 10*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags "Offering_Chalice", //namepointer }, { /*MT_TOKEN_EAR*/ -1, //doomednum S_EARS_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 9, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST, //flags "ear", //namepointer }, { /*MT_INV_COMMUNICATOR*/ 206, //doomednum S_COMM_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_NOTDMATCH, //flags "Communicator", //namepointer }, { /*MT_AGREN*/ 152, //doomednum S_GRN1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "HE-Grenade_Rounds", //namepointer }, { /*MT_APGREN*/ 153, //doomednum S_GRN2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Phosphorus-Grenade_Rounds", //namepointer }, { /*MT_ACLIP*/ 2007, //doomednum S_BLIT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "clip_of_bullets", //namepointer }, { /*MT_AAMMOBOX*/ 2048, //doomednum S_BBOX_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "ammo", //namepointer }, { /*MT_AMINI*/ 2010, //doomednum S_MSSL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "mini_missiles", //namepointer }, { /*MT_AMINIBOX*/ 2046, //doomednum S_ROKT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "crate_of_missiles", //namepointer }, { /*MT_ACELL*/ 2047, //doomednum S_BRY1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "energy_pod", //namepointer }, { /*MT_APCELL*/ 17, //doomednum S_CPAC_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "energy_pack", //namepointer }, { /*MT_APAROW*/ 115, //doomednum S_PQRL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "poison_bolts", //namepointer }, { /*MT_AAROW*/ 114, //doomednum S_XQRL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "electric_bolts", //namepointer }, { /*MT_INV_SATCHEL*/ 183, //doomednum S_BKPK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "ammo_satchel", //namepointer }, { /*MT_PULSE*/ 2002, //doomednum S_RIFL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "assault_gun", //namepointer }, { /*MT_RIFLESTAND*/ 2006, //doomednum S_RIFL_01, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "assault_gun", //namepointer }, { /*MT_FLAMETHROWER*/ 2005, //doomednum S_FLAM_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "flame_thrower", //namepointer }, { /*MT_TOKEN_FLAME_THROWER_PARTS*/ -1, //doomednum S_BFLM_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "flame_thrower_parts", //namepointer }, { /*MT_MISSILELAUNCHER*/ 2003, //doomednum S_MMSL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "mini_missile_launcher", //namepointer }, { /*MT_BLASTER*/ 2004, //doomednum S_TRPD_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "mauler", //namepointer }, { /*MT_CROSSBOW*/ 2001, //doomednum S_CBOW_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "crossbow", //namepointer }, { /*MT_GRENADELAUNCHER*/ 154, //doomednum S_GRND_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Grenade_launcher", //namepointer }, { /*MT_SIGIL_A*/ 77, //doomednum S_SIGL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "SIGIL", //namepointer }, { /*MT_SIGIL_B*/ 78, //doomednum S_SIGL_01, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "SIGIL", //namepointer }, { /*MT_SIGIL_C*/ 79, //doomednum S_SIGL_02, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "SIGIL", //namepointer }, { /*MT_SIGIL_D*/ 80, //doomednum S_SIGL_03, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "SIGIL", //namepointer }, { /*MT_SIGIL_E*/ 81, //doomednum S_SIGL_04, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "SIGIL", //namepointer }, { /*MT_POWER_CRYSTAL*/ 92, //doomednum S_CRYS_00, //spawnstate 50, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BOOM_00, //deathstate S_NULL, //xdeathstate sfx_explod, //deathsound 14, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 99999999, //mass 0, //damage sfx_reactr, //activesound MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_RAT*/ 85, //doomednum S_RATT_00, //spawnstate 5, //spawnhealth S_RATT_01, //seestate sfx_ratact, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_RATT_05, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_MEAT_16, //deathstate S_NULL, //xdeathstate sfx_ratact, //deathsound 13, //speed 10*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_ratact, //activesound MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags "rat_buddy", //namepointer }, { /*MT_MISC_05*/ 82, //doomednum S_BARW_00, //spawnstate 10, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BARW_01, //deathstate S_NULL, //xdeathstate sfx_wbrldt, //deathsound 0, //speed 10*FRACUNIT, //radius 32*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_MISC_06*/ 94, //doomednum S_BART_00, //spawnstate 30, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_BART_01, //deathstate S_NULL, //xdeathstate sfx_barexp, //deathsound 0, //speed 10*FRACUNIT, //radius 32*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_MISC_15*/ 208, //doomednum S_HOGN_00, //spawnstate 99999999, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_HOGN_01, //painstate 255, //painchance sfx_mtalht, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 10*FRACUNIT, //radius 72*FRACUNIT, //height 9999999, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags NULL, //namepointer }, { /*MT_LIGHT14*/ 95, //doomednum S_LITS_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 4*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_LIGHT13*/ 96, //doomednum S_LITB_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 4*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_LIGHT12*/ 97, //doomednum S_LITG_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 4*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_LIGHT18*/ 2028, //doomednum S_LITE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR2*/ 48, //doomednum S_MONI_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 128*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR3*/ 54, //doomednum S_STEL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 128*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR4*/ 55, //doomednum S_STLA_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 80*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR5*/ 56, //doomednum S_STLE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR6*/ 57, //doomednum S_HUGE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 24*FRACUNIT, //radius 192*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR7*/ 227, //doomednum S_APOW_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 24*FRACUNIT, //radius 192*FRACUNIT, //height 100, //mass 0, //damage sfx_amaln2, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_CAVE2*/ 98, //doomednum S_STLG_02, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 54*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_CAVE3*/ 161, //doomednum S_STLG_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_CAVE4*/ 160, //doomednum S_STLG_01, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_CAVE6*/ 159, //doomednum S_STLG_03, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 128*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_CAVE7*/ 162, //doomednum S_STLG_04, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 128*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_CAVE5*/ 163, //doomednum S_STLG_05, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 25*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT2*/ 34, //doomednum S_CNDL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_LIGHT3*/ 35, //doomednum S_CLBR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_03*/ 103, //doomednum S_DRIP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_wdrip, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_13*/ 104, //doomednum S_SPLH_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_wfall, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_02*/ 53, //doomednum S_CDRP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 1*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_MISC_07*/ 112, //doomednum S_WTFT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_wsplsh, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_BIO2*/ 113, //doomednum S_HERT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TELEPORTSTAND*/ 23, //doomednum S_TELP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_SHADOW, //flags NULL, //namepointer }, { /*MT_DEADTHING1*/ 22, //doomednum S_ROB2_28, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_DEADTHING2*/ 15, //doomednum S_PLAY_18, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_DEADTHING3*/ 18, //doomednum S_PEAS_24, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_DEADTHING4*/ 21, //doomednum S_AGRD_31, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_DEADTHING5*/ 20, //doomednum S_ROB1_25, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_DEADTHING6*/ 19, //doomednum S_HMN1_31, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_BIO1*/ 212, //doomednum S_SACR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_GIBS*/ 54, //doomednum S_DEAD_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_MISC_04*/ 70, //doomednum S_BARL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 48*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT11*/ 105, //doomednum S_BOWL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_smfire, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT10*/ 106, //doomednum S_BRAZ_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 10*FRACUNIT, //radius 32*FRACUNIT, //height 100, //mass 0, //damage sfx_smfire, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT9*/ 107, //doomednum S_TRCH_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 0*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_smfire, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_LIGHT8*/ 108, //doomednum S_TRHO_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 0*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_14*/ 109, //doomednum S_CHAN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 93*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_LIGHT1*/ 28, //doomednum S_CAGE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 3*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_PILLAR8*/ 110, //doomednum S_STAT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 64*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR9*/ 44, //doomednum S_DSTA_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT15*/ 111, //doomednum S_LTRH_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 4*FRACUNIT, //radius 72*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT4*/ 43, //doomednum S_LAMP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 3*FRACUNIT, //radius 80*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT5*/ 46, //doomednum S_LANT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 3*FRACUNIT, //radius 80*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_ROCK1*/ 99, //doomednum S_ROK1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_ROCK2*/ 100, //doomednum S_ROK2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_ROCK3*/ 101, //doomednum S_ROK3_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_ROCK4*/ 102, //doomednum S_ROK4_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_TREE7*/ 215, //doomednum S_LOGG_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_wriver, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_RUBBLE1*/ 29, //doomednum S_RUB1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_RUBBLE2*/ 30, //doomednum S_RUB2_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_RUBBLE3*/ 31, //doomednum S_RUB3_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_RUBBLE4*/ 32, //doomednum S_RUB4_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_RUBBLE5*/ 36, //doomednum S_RUB5_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_RUBBLE6*/ 37, //doomednum S_RUB6_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_RUBBLE7*/ 41, //doomednum S_RUB7_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_RUBBLE8*/ 42, //doomednum S_RUB8_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_MISC_08*/ 117, //doomednum S_CRAB_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_LIGHT6*/ 47, //doomednum S_LMPC_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 10*FRACUNIT, //radius 72*FRACUNIT, //height 100, //mass 0, //damage sfx_smfire, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT7*/ 50, //doomednum S_LOGS_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 10*FRACUNIT, //radius 80*FRACUNIT, //height 100, //mass 0, //damage sfx_smfire, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TREE2*/ 51, //doomednum S_TREE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 15*FRACUNIT, //radius 109*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TREE3*/ 202, //doomednum S_TREE_01, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 15*FRACUNIT, //radius 109*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TREE4*/ 203, //doomednum S_TREE_02, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 15*FRACUNIT, //radius 64*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TREE1*/ 33, //doomednum S_TRE1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 15*FRACUNIT, //radius 80*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TREE6*/ 60, //doomednum S_BUSH_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 15*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_TREE5*/ 62, //doomednum S_SHRB_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 64*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_CAVE1*/ 63, //doomednum S_STAK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 64*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR1*/ 69, //doomednum S_BAR1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 128*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_10*/ 165, //doomednum S_VASE_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 12*FRACUNIT, //radius 24*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_09*/ 188, //doomednum S_VASE_01, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 12*FRACUNIT, //radius 32*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_17*/ 189, //doomednum S_STOL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 6*FRACUNIT, //radius 24*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_18*/ 190, //doomednum S_POT1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_19*/ 191, //doomednum S_TUB1_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_20*/ 194, //doomednum S_ANVL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 32*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT16*/ 196, //doomednum S_TLMP_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 11*FRACUNIT, //radius 64*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT17*/ 197, //doomednum S_TLMP_01, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 8*FRACUNIT, //radius 64*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_21*/ 68, //doomednum S_TRAY_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 24*FRACUNIT, //radius 40*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_12*/ 228, //doomednum S_AFED_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 12*FRACUNIT, //radius 24*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MISC_26*/ 216, //doomednum S_SBAN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 24*FRACUNIT, //radius 96*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_23*/ 217, //doomednum S_BOTR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_24*/ 218, //doomednum S_HATR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_MISC_25*/ 219, //doomednum S_TOPR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP, //flags NULL, //namepointer }, { /*MT_COUPLING*/ 220, //doomednum S_COUP_00, //spawnstate 40, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 6, //speed 17*FRACUNIT, //radius 64*FRACUNIT, //height 999999, //mass 0, //damage sfx_None, //activesound MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_DROPPED |MF_NOBLOOD|MF_NOTDMATCH, //flags NULL, //namepointer }, { /*MT_COUPLING_BROKEN*/ 226, //doomednum S_COUP_02, //spawnstate 40, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 512*FRACUNIT, //speed 16*FRACUNIT, //radius 16*FRACUNIT, //height 1, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags "BROKEN_POWER_COUPLING", //namepointer }, { /*MT_PILLAR10*/ 221, //doomednum S_BUBB_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 128*FRACUNIT, //height 100, //mass 0, //damage sfx_amaln5, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR11*/ 222, //doomednum S_BUBF_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 72*FRACUNIT, //height 100, //mass 0, //damage sfx_amaln6, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_PILLAR12*/ 223, //doomednum S_BUBF_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 72*FRACUNIT, //height 100, //mass 0, //damage sfx_amaln4, //activesound MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags NULL, //namepointer }, { /*MT_PILLAR13*/ 224, //doomednum S_ASPR_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 16*FRACUNIT, //radius 128*FRACUNIT, //height 100, //mass 0, //damage sfx_amaln3, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_LIGHT19*/ 225, //doomednum S_SPDL_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 32*FRACUNIT, //radius 56*FRACUNIT, //height 100, //mass 0, //damage sfx_amaln1, //activesound MF_SOLID, //flags NULL, //namepointer }, { /*MT_MEAT*/ -1, //doomednum S_MEAT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_JUNK*/ -1, //doomednum S_JUNK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_BURNDROP*/ -1, //doomednum S_FFOT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_NOBLOCKMAP|MF_NOCLIP, //flags NULL, //namepointer }, { /*MT_TOKEN_AMMO*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Ammo", //namepointer }, { /*MT_TOKEN_HEALTH*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Health", //namepointer }, { /*MT_TOKEN*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "info", //namepointer }, { /*MT_TOKEN_ALARM*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "alarm", //namepointer }, { /*MT_TOKEN_DOOR1*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags NULL, //namepointer }, { /*MT_TOKEN_SHOPCLOSE*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags NULL, //namepointer }, { /*MT_TOKEN_PRISON_PASS*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 10, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST, //flags "Prison_pass", //namepointer }, { /*MT_TOKEN_DOOR3*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags NULL, //namepointer }, { /*MT_TOKEN_STAMINA*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags NULL, //namepointer }, { /*MT_TOKEN_NEW_ACCURACY*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags NULL, //namepointer }, { /*MT_TOKEN_REPORT*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "report", //namepointer }, { /*MT_TOKEN_TOUGHNESS*/ -1, //doomednum S_HELT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Toughness", //namepointer }, { /*MT_TOKEN_ACCURACY*/ -1, //doomednum S_GUNT_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags "Accuracy", //namepointer }, { /*MT_TOKEN_ORACLE_PASS*/ -1, //doomednum S_OTOK_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 18, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL|MF_GIVEQUEST, //flags "Oracle_Pass", //namepointer }, { /*MT_TOKEN_QUEST1*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST2*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST3*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST4*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "quest4", //namepointer }, { /*MT_TOKEN_QUEST5*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "quest5", //namepointer }, { /*MT_TOKEN_QUEST6*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "quest6", //namepointer }, { /*MT_TOKEN_QUEST7*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST8*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST9*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST10*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST11*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST12*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST13*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_CRYSTAL*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "You've_Blown_Up_the_Crystal", //namepointer }, { /*MT_TOKEN_QUEST15*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_GATEQUEST*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "You've_Blown_Up_the_Gates", //namepointer }, { /*MT_TOKEN_QUEST17*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST18*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST19*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST20*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_BISHOP*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "You_Killed_the_Bishop!", //namepointer }, { /*MT_TOKEN_QUEST22*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_ORACLE*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "You've_Killed_The_Oracle!", //namepointer }, { /*MT_TOKEN_MACIL*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "You_Killed_Macil!", //namepointer }, { /*MT_TOKEN_QUEST25*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_LOREMASTER*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "You've_Killed_The_Loremaster!", //namepointer }, { /*MT_SECRQUEST*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags "You've_Blown_Up_the_Computer", //namepointer }, { /*MT_TOKEN_QUEST28*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST29*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST30*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_TOKEN_QUEST31*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound 0, //flags NULL, //namepointer }, { /*MT_SLIDESHOW*/ -1, //doomednum S_TOKN_00, //spawnstate 1000, //spawnhealth S_NULL, //seestate sfx_None, //seesound 8, //reactiontime sfx_None, //attacksound S_NULL, //painstate 0, //painchance sfx_None, //painsound S_NULL, //meleestate S_NULL, //missilestate S_NULL, //crashstate S_NULL, //deathstate S_NULL, //xdeathstate sfx_None, //deathsound 0, //speed 20*FRACUNIT, //radius 16*FRACUNIT, //height 100, //mass 0, //damage sfx_None, //activesound MF_SPECIAL, //flags NULL, //namepointer }, }; chocolate-doom-chocolate-doom-2.2.1/src/strife/info.h000066400000000000000000001621331257432200600225020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Thing frame/state LUT, // generated by multigen utilitiy. // This one is the original DOOM version, preserved. // #ifndef __INFO__ #define __INFO__ // Needed for action function pointer handling. #include "d_think.h" // villsa [STRIFE] typedef enum { SPR_PLAY, // 0 SPR_PNCH, // 1 SPR_WAVE, // 2 SPR_RBPY, // 3 SPR_TRGT, // 4 SPR_XBOW, // 5 SPR_MMIS, // 6 SPR_RIFG, // 7 SPR_RIFF, // 8 SPR_FLMT, // 9 SPR_FLMF, // 10 SPR_BLST, // 11 SPR_BLSF, // 12 SPR_GREN, // 13 SPR_GREF, // 14 SPR_SIGH, // 15 SPR_SIGF, // 16 SPR_POW1, // 17 SPR_POW2, // 18 SPR_POW3, // 19 SPR_ZAP1, // 20 SPR_SPRY, // 21 SPR_BLOD, // 22 SPR_PUFY, // 23 SPR_SHT1, // 24 SPR_SHT2, // 25 SPR_GRIN, // 26 SPR_GRAP, // 27 SPR_UBAM, // 28 SPR_BNG2, // 29 SPR_BNG4, // 30 SPR_BNG3, // 31 SPR_FLBE, // 32 SPR_XPRK, // 33 SPR_OCLW, // 34 SPR_CCLW, // 35 SPR_TEND, // 36 SPR_MICR, // 37 SPR_MISS, // 38 SPR_AROW, // 39 SPR_ARWP, // 40 SPR_TORP, // 41 SPR_THIT, // 42 SPR_TWAV, // 43 SPR_MISL, // 44 SPR_TFOG, // 45 SPR_IFOG, // 46 SPR_SHRD, // 47 SPR_RGIB, // 48 SPR_MRYS, // 49 SPR_MRNO, // 50 SPR_MRST, // 51 SPR_MRLK, // 52 SPR_MRBD, // 53 SPR_MRPN, // 54 SPR_MRGT, // 55 SPR_BURN, // 56 SPR_DISR, // 57 SPR_PEAS, // 58 SPR_GIBS, // 59 SPR_AGRD, // 60 SPR_ARMR, // 61 SPR_SACR, // 62 SPR_TNK1, // 63 SPR_TNK2, // 64 SPR_TNK3, // 65 SPR_TNK4, // 66 SPR_TNK5, // 67 SPR_TNK6, // 68 SPR_NEAL, // 69 SPR_BEGR, // 70 SPR_HMN1, // 71 SPR_LEDR, // 72 SPR_LEAD, // 73 SPR_ROB1, // 74 SPR_PGRD, // 75 SPR_ROB2, // 76 SPR_MLDR, // 77 SPR_ORCL, // 78 SPR_PRST, // 79 SPR_PDED, // 80 SPR_ALN1, // 81 SPR_AL1P, // 82 SPR_NODE, // 83 SPR_MTHD, // 84 SPR_MNAM, // 85 SPR_MNAL, // 86 SPR_MDTH, // 87 SPR_NEST, // 88 SPR_PODD, // 89 SPR_ZAP6, // 90 SPR_ZOT3, // 91 SPR_ZAP7, // 92 SPR_ZOT1, // 93 SPR_ZAP5, // 94 SPR_ZOT2, // 95 SPR_SEWR, // 96 SPR_SPID, // 97 SPR_ROB3, // 98 SPR_RBB3, // 99 SPR_PRGR, // 100 SPR_BASE, // SPR_FRBL, // SPR_KLAX, // SPR_TURT, // SPR_BALL, // 105 SPR_PSTN, // SPR_SECR, // SPR_TARG, // SPR_RING, // SPR_EARS, // 110 SPR_COMM, // SPR_BOOM, // SPR_RATT, // SPR_HOGN, // SPR_DEAD, // 115 SPR_SBAN, // SPR_BOTR, // SPR_HATR, // SPR_TOPR, // SPR_COUP, // 120 SPR_BUBB, // SPR_BUBF, // SPR_BUBC, // SPR_ASPR, // SPR_SPDL, // 125 SPR_TOKN, // SPR_OTOK, // SPR_HELT, // SPR_GUNT, // SPR_FULL, // 130 SPR_MEAT, // SPR_JUNK, // SPR_FFOT, // SPR_DIE1, // SPR_BEAC, // 135 SPR_ARM1, // SPR_ARM2, // SPR_BARW, // SPR_BART, // SPR_LAMP, // 140 SPR_LANT, // SPR_BARL, // SPR_BOWL, // SPR_BRAZ, // SPR_TRCH, // 145 SPR_LTRH, // SPR_LMPC, // SPR_LOGS, // SPR_TRHO, // SPR_WATR, // 150 SPR_MUGG, // SPR_FUSL, // SPR_CRD1, // SPR_CRD2, // SPR_TPAS, // 155 SPR_KY1G, // SPR_KY2S, // SPR_KY3B, // SPR_HAND, // SPR_CRYS, // 160 SPR_PRIS, // SPR_PWR1, // SPR_PWR2, // SPR_PWR3, // SPR_ORAC, // 165 SPR_GYID, // SPR_FUBR, // SPR_WARE, // SPR_RCRY, // SPR_BCRY, // 170 SPR_CHAP, // SPR_TUNL, // SPR_BLTK, // SPR_SECK, // SPR_MINE, // 175 SPR_REBL, // SPR_PROC, // SPR_ANKH, // SPR_GOID, // SPR_STMP, // 180 SPR_MDKT, // SPR_COIN, // SPR_CRED, // SPR_SACK, // SPR_CHST, // 185 SPR_SHD1, // SPR_MASK, // SPR_UNIF, // SPR_OFIC, // SPR_PMAP, // 190 SPR_PMUP, // SPR_BLIT, // SPR_BBOX, // SPR_MSSL, // SPR_ROKT, // 195 SPR_BRY1, // SPR_CPAC, // SPR_PQRL, // SPR_XQRL, // SPR_GRN1, // 200 SPR_GRN2, // SPR_BKPK, // SPR_RELC, // SPR_RIFL, // SPR_FLAM, // 205 SPR_BFLM, // SPR_MMSL, // SPR_TRPD, // SPR_GRND, // SPR_CBOW, // 210 SPR_SIGL, // SPR_LITE, // SPR_CNDL, // SPR_CLBR, // SPR_LITS, // 215 SPR_LITB, // SPR_LITG, // SPR_ROK1, // SPR_ROK2, // SPR_ROK3, // 220 SPR_ROK4, // SPR_LOGG, // SPR_RUB1, // SPR_RUB2, // SPR_RUB3, // 225 SPR_RUB4, // SPR_RUB5, // SPR_RUB6, // SPR_RUB7, // SPR_RUB8, // 230 SPR_CHAN, // SPR_STAT, // SPR_DSTA, // SPR_CRAB, // SPR_CAGE, // 235 SPR_TREE, // SPR_TRE1, // SPR_BUSH, // SPR_SHRB, // SPR_STAK, // 240 SPR_BAR1, // SPR_VASE, // SPR_STOL, // SPR_POT1, // SPR_TUB1, // 245 SPR_ANVL, // SPR_TLMP, // SPR_TRAY, // SPR_APOW, // SPR_AFED, // 250 SPR_DRIP, // SPR_CDRP, // SPR_SPLH, // SPR_WTFT, // SPR_HERT, // SPR_TELP, // SPR_MONI, // SPR_STEL, // SPR_STLA, // SPR_STLE, // 260 SPR_HUGE, // 261 SPR_STLG, // 262 NUMSPRITES } spritenum_t; // villsa [STRIFE] typedef enum { S_NULL, // 00 S_PNCH_00, // 01 S_WAVE_00, // 02 S_WAVE_01, // 03 S_WAVE_02, // 04 S_WAVE_03, // 05 S_RBPY_00, // 06 S_RBPY_01, // 07 S_RBPY_02, // 08 S_RBPY_03, // 09 S_TRGT_00, // 10 S_TRGT_01, // 11 S_TRGT_02, // 12 S_PNCH_01, // 13 S_PNCH_02, // 14 S_PNCH_03, // 15 S_PNCH_04, // 16 S_PNCH_05, // 17 S_PNCH_06, // 18 S_PNCH_07, // 19 S_PNCH_08, // 20 S_XBOW_00, // 21 S_XBOW_01, // 22 S_XBOW_02, // 23 S_XBOW_03, // 24 S_XBOW_04, // 25 S_XBOW_05, // 26 S_XBOW_06, // 27 S_XBOW_07, // 28 S_XBOW_08, // 29 S_XBOW_09, // 30 S_XBOW_10, // 31 S_XBOW_11, // 32 S_XBOW_12, // 33 S_XBOW_13, // 34 S_XBOW_14, // 35 S_XBOW_15, // 36 S_XBOW_16, // 37 S_XBOW_17, // 38 S_XBOW_18, // 39 S_XBOW_19, // 40 S_XBOW_20, // 41 S_XBOW_21, // 42 S_XBOW_22, // 43 S_MMIS_00, // 44 S_MMIS_01, // 45 S_MMIS_02, // 46 S_MMIS_03, // 47 S_MMIS_04, // 48 S_MMIS_05, // 49 S_MMIS_06, // 50 S_MMIS_07, // 51 S_MMIS_08, // 52 S_MMIS_09, // 53 S_RIFG_00, // 54 S_RIFG_01, // 55 S_RIFG_02, // 56 S_RIFF_00, // 57 S_RIFF_01, // 58 S_RIFG_03, // 59 S_RIFG_04, // 60 S_RIFG_05, // 61 S_FLMT_00, // 62 S_FLMT_01, // 63 S_FLMT_02, // 64 S_FLMT_03, // 65 S_FLMF_00, // 66 S_FLMF_01, // 67 S_BLST_00, // 68 S_BLST_01, // 69 S_BLST_02, // 70 S_BLST_03, // 71 S_BLST_04, // 72 S_BLST_05, // 73 S_BLSF_00, // 74 S_BLST_06, // 75 S_BLST_07, // 76 S_BLST_08, // 77 S_BLST_09, // 78 S_BLST_10, // 79 S_BLST_11, // 80 S_BLST_12, // 81 S_BLST_13, // 82 S_BLST_14, // 83 S_BLST_15, // 84 S_BLST_16, // 85 S_BLST_17, // 86 S_BLST_18, // 87 S_BLST_19, // 88 S_BLST_20, // 89 S_BLSF_01, // 90 S_BLST_21, // 91 S_BLST_22, // 92 S_BLST_23, // 93 S_BLST_24, // 94 S_GREN_00, // 95 S_GREN_01, // 96 S_GREN_02, // 97 S_GREN_03, // 98 S_GREN_04, // 99 S_GREN_05, // 100 S_GREN_06, // 101 S_GREN_07, // 102 S_GREF_00, // 103 S_GREF_01, // 104 S_GREF_02, // 105 S_GREN_08, // 106 S_GREN_09, // 107 S_GREN_10, // 108 S_GREN_11, // 109 S_GREN_12, // 110 S_GREN_13, // 111 S_GREN_14, // 112 S_GREN_15, // 113 S_GREF_03, // 114 S_GREF_04, // 115 S_GREF_05, // 116 S_SIGH_00, // 117 S_SIGH_01, // 118 S_SIGH_02, // 119 S_SIGH_03, // 120 S_SIGH_04, // 121 S_SIGH_05, // 122 S_SIGH_06, // 123 S_SIGH_07, // 124 S_SIGH_08, // 125 S_SIGH_09, // 126 S_SIGH_10, // 127 S_SIGF_00, // 128 S_SIGF_01, // 129 S_SIGF_02, // 130 S_POW1_00, // 131 S_POW1_01, // 132 S_POW1_02, // 133 S_POW1_03, // 134 S_POW1_04, // 135 S_POW1_05, // 136 S_POW1_06, // 137 S_POW1_07, // 138 S_POW1_08, // 139 S_POW1_09, // 140 S_POW2_00, // 141 S_POW2_01, // 142 S_POW2_02, // 143 S_POW2_03, // 144 S_POW3_00, // 145 S_POW3_01, // 146 S_POW3_02, // 147 S_POW3_03, // 148 S_POW3_04, // 149 S_POW3_05, // 150 S_POW3_06, // 151 S_POW3_07, // 152 S_ZAP1_00, // 153 S_ZAP1_01, // 154 S_ZAP1_02, // 155 S_ZAP1_03, // 156 S_ZAP1_04, // 157 S_ZAP1_05, // 158 S_ZAP1_06, // 159 S_ZAP1_07, // 160 S_ZAP1_08, // 161 S_ZAP1_09, // 162 S_ZAP1_10, // 163 S_ZAP1_11, // 164 S_SPRY_00, // 165 S_SPRY_01, // 166 S_SPRY_02, // 167 S_SPRY_03, // 168 S_SPRY_04, // 169 S_SPRY_05, // 170 S_SPRY_06, // 171 S_BLOD_00, // 172 S_BLOD_01, // 173 S_BLOD_02, // 174 S_PUFY_00, // 175 S_PUFY_01, // 176 S_PUFY_02, // 177 S_PUFY_03, // 178 S_SHT1_00, // 179 S_SHT1_01, // 180 S_SHT2_00, // 181 S_SHT2_01, // 182 S_GRIN_00, // 183 S_GRIN_01, // 184 S_GRAP_00, // 185 S_GRAP_01, // 186 S_UBAM_00, // 187 S_UBAM_01, // 188 S_BNG2_00, // 189 S_BNG2_01, // 190 S_BNG2_02, // 191 S_BNG2_03, // 192 S_BNG2_04, // 193 S_BNG2_05, // 194 S_BNG2_06, // 195 S_BNG2_07, // 196 S_BNG2_08, // 197 S_BNG4_00, // 198 S_BNG4_01, // 199 S_BNG4_02, // 200 S_BNG4_03, // 201 S_BNG4_04, // 202 S_BNG4_05, // 203 S_BNG4_06, // 204 S_BNG4_07, // 205 S_BNG4_08, // 206 S_BNG4_09, // 207 S_BNG4_10, // 208 S_BNG4_11, // 209 S_BNG4_12, // 210 S_BNG4_13, // 211 S_BNG3_00, // 212 S_BNG3_01, // 213 S_BNG3_02, // 214 S_BNG3_03, // 215 S_BNG3_04, // 216 S_BNG3_05, // 217 S_BNG3_06, // 218 S_BNG3_07, // 219 S_BNG3_08, // 220 S_BNG3_09, // 221 S_BNG3_10, // 222 S_FLBE_00, // 223 S_FLBE_01, // 224 S_FLBE_02, // 225 S_FLBE_03, // 226 S_FLBE_04, // 227 S_FLBE_05, // 228 S_FLBE_06, // 229 S_FLBE_07, // 230 S_FLBE_08, // 231 S_FLBE_09, // 232 S_FLBE_10, // 233 S_XPRK_00, // 234 S_OCLW_00, // 235 S_CCLW_00, // 236 S_TEND_00, // 237 S_MICR_00, // 238 S_MISS_00, // 239 S_MISS_01, // 240 S_AROW_00, // 241 S_ARWP_00, // 242 S_AROW_01, // 243 S_TORP_00, // 244 S_TORP_01, // 245 S_TORP_02, // 246 S_TORP_03, // 247 S_THIT_00, // 248 S_THIT_01, // 249 S_THIT_02, // 250 S_THIT_03, // 251 S_THIT_04, // 252 S_TWAV_00, // 253 S_TWAV_01, // 254 S_TWAV_02, // 255 S_MISL_00, // 256 S_MISL_01, // 257 S_MISL_02, // 258 S_MISL_03, // 259 S_MISL_04, // 260 S_MISL_05, // 261 S_MISL_06, // 262 S_MISL_07, // 263 S_TFOG_00, // 264 S_TFOG_01, // 265 S_TFOG_02, // 266 S_TFOG_03, // 267 S_TFOG_04, // 268 S_TFOG_05, // 269 S_TFOG_06, // 270 S_TFOG_07, // 271 S_TFOG_08, // 272 S_TFOG_09, // 273 S_IFOG_00, // 274 S_IFOG_01, // 275 S_IFOG_02, // 276 S_IFOG_03, // 277 S_IFOG_04, // 278 S_IFOG_05, // 279 S_IFOG_06, // 280 S_SHRD_00, // 281 S_SHRD_01, // 282 S_SHRD_02, // 283 S_SHRD_03, // 284 S_SHRD_04, // 285 S_SHRD_05, // 286 S_PLAY_00, // 287 S_PLAY_01, // 288 S_PLAY_02, // 289 S_PLAY_03, // 290 S_PLAY_04, // 291 S_PLAY_05, // 292 S_PLAY_06, // 293 S_PLAY_07, // 294 S_PLAY_08, // 295 S_PLAY_09, // 296 S_PLAY_10, // 297 S_PLAY_11, // 298 S_PLAY_12, // 299 S_PLAY_13, // 300 S_PLAY_14, // 301 S_PLAY_15, // 302 S_PLAY_16, // 303 S_PLAY_17, // 304 S_PLAY_18, // 305 S_RGIB_00, // 306 S_RGIB_01, // 307 S_RGIB_02, // 308 S_RGIB_03, // 309 S_RGIB_04, // 310 S_RGIB_05, // 311 S_RGIB_06, // 312 S_RGIB_07, // 313 S_MRYS_00, // 314 S_MRNO_00, // 315 S_MRNO_01, // 316 S_MRNO_02, // 317 S_MRNO_03, // 318 S_MRNO_04, // 319 S_MRST_00, // 320 S_MRLK_00, // 321 S_MRLK_01, // 322 S_MRBD_00, // 323 S_MRBD_01, // 324 S_MRBD_02, // 325 S_MRBD_03, // 326 S_MRBD_04, // 327 S_MRBD_05, // 328 S_MRBD_06, // 329 S_MRBD_07, // 330 S_MRBD_08, // 331 S_MRBD_09, // 332 S_MRPN_00, // 333 S_MRPN_01, // 334 S_MRPN_02, // 335 S_MRPN_03, // 336 S_MRPN_04, // 337 S_MRPN_05, // 338 S_MRPN_06, // 339 S_MRGT_00, // 340 S_MRGT_01, // 341 S_MRGT_02, // 342 S_MRGT_03, // 343 S_MRGT_04, // 344 S_MRGT_05, // 345 S_MRGT_06, // 346 S_MRGT_07, // 347 S_MRGT_08, // 348 S_BURN_00, // 349 S_BURN_01, // 350 S_BURN_02, // 351 S_BURN_03, // 352 S_BURN_04, // 353 S_BURN_05, // 354 S_BURN_06, // 355 S_BURN_07, // 356 S_BURN_08, // 357 S_BURN_09, // 358 S_BURN_10, // 359 S_BURN_11, // 360 S_BURN_12, // 361 S_BURN_13, // 362 S_BURN_14, // 363 S_BURN_15, // 364 S_BURN_16, // 365 S_BURN_17, // 366 S_BURN_18, // 367 S_BURN_19, // 368 S_BURN_20, // 369 S_BURN_21, // 370 S_BURN_22, // 371 S_BURN_23, // 372 S_DISR_00, // 373 S_DISR_01, // 374 S_DISR_02, // 375 S_DISR_03, // 376 S_DISR_04, // 377 S_DISR_05, // 378 S_DISR_06, // 379 S_DISR_07, // 380 S_DISR_08, // 381 S_DISR_09, // 382 S_PEAS_00, // 383 S_PEAS_01, // 384 S_PEAS_02, // 385 S_PEAS_03, // 386 S_PEAS_04, // 387 S_PEAS_05, // 388 S_PEAS_06, // 389 S_PEAS_07, // 390 S_PEAS_08, // 391 S_PEAS_09, // 392 S_PEAS_10, // 393 S_PEAS_11, // 394 S_PEAS_12, // 395 S_PEAS_13, // 396 S_PEAS_14, // 397 S_PEAS_15, // 398 S_PEAS_16, // 399 S_PEAS_17, // 400 S_PEAS_18, // 401 S_PEAS_19, // 402 S_PEAS_20, // 403 S_PEAS_21, // 404 S_PEAS_22, // 405 S_PEAS_23, // 406 S_PEAS_24, // 407 S_GIBS_00, // 408 S_GIBS_01, // 409 S_GIBS_02, // 410 S_GIBS_03, // 411 S_GIBS_04, // 412 S_GIBS_05, // 413 S_GIBS_06, // 414 S_GIBS_07, // 415 S_GIBS_08, // 416 S_GIBS_09, // 417 S_PEAS_25, // 418 S_AGRD_00, // 419 S_ARMR_00, // 420 S_ARMR_01, // 421 S_PLAY_19, // 422 S_SACR_00, // 423 S_TNK1_00, // 424 S_TNK1_01, // 425 S_TNK1_02, // 426 S_TNK2_00, // 427 S_TNK2_01, // 428 S_TNK2_02, // 429 S_TNK3_00, // 430 S_TNK3_01, // 431 S_TNK3_02, // 432 S_TNK4_00, // 433 S_TNK4_01, // 434 S_TNK4_02, // 435 S_TNK5_00, // 436 S_TNK5_01, // 437 S_TNK5_02, // 438 S_TNK6_00, // 439 S_TNK6_01, // 440 S_TNK6_02, // 441 S_NEAL_00, // 442 S_NEAL_01, // 443 S_NEAL_02, // 444 S_NEAL_03, // 445 S_NEAL_04, // 446 S_NEAL_05, // 447 S_NEAL_06, // 448 S_NEAL_07, // 449 S_NEAL_08, // 450 S_NEAL_09, // 451 S_NEAL_10, // 452 S_NEAL_11, // 453 S_NEAL_12, // 454 S_NEAL_13, // 455 S_BEGR_00, // 456 S_BEGR_01, // 457 S_BEGR_02, // 458 S_BEGR_03, // 459 S_BEGR_04, // 460 S_BEGR_05, // 461 S_BEGR_06, // 462 S_BEGR_07, // 463 S_BEGR_08, // 464 S_BEGR_09, // 465 S_BEGR_10, // 466 S_BEGR_11, // 467 S_BEGR_12, // 468 S_BEGR_13, // 469 S_BEGR_14, // 470 S_BEGR_15, // 471 S_BEGR_16, // 472 S_BEGR_17, // 473 S_BEGR_18, // 474 S_BEGR_19, // 475 S_BEGR_20, // 476 S_BEGR_21, // 477 S_BEGR_22, // 478 S_HMN1_00, // 479 S_HMN1_01, // 480 S_HMN1_02, // 481 S_HMN1_03, // 482 S_HMN1_04, // 483 S_HMN1_05, // 484 S_HMN1_06, // 485 S_HMN1_07, // 486 S_HMN1_08, // 487 S_HMN1_09, // 488 S_HMN1_10, // 489 S_HMN1_11, // 490 S_HMN1_12, // 491 S_HMN1_13, // 492 S_HMN1_14, // 493 S_HMN1_15, // 494 S_HMN1_16, // 495 S_HMN1_17, // 496 S_HMN1_18, // 497 S_HMN1_19, // 498 S_HMN1_20, // 499 S_HMN1_21, // 500 S_HMN1_22, // 501 S_HMN1_23, // 502 S_HMN1_24, // 503 S_HMN1_25, // 504 S_HMN1_26, // 505 S_HMN1_27, // 506 S_HMN1_28, // 507 S_HMN1_29, // 508 S_HMN1_30, // 509 S_HMN1_31, // 510 S_RGIB_08, // 511 S_RGIB_09, // 512 S_RGIB_10, // 513 S_RGIB_11, // 514 S_RGIB_12, // 515 S_RGIB_13, // 516 S_RGIB_14, // 517 S_RGIB_15, // 518 S_LEDR_00, // 519 S_LEDR_01, // 520 S_LEDR_02, // 521 S_LEAD_00, // 522 S_LEAD_01, // 523 S_LEAD_02, // 524 S_LEAD_03, // 525 S_LEAD_04, // 526 S_LEAD_05, // 527 S_LEAD_06, // 528 S_LEAD_07, // 529 S_LEAD_08, // 530 S_LEAD_09, // 531 S_LEAD_10, // 532 S_LEAD_11, // 533 S_LEAD_12, // 534 S_LEAD_13, // 535 S_LEAD_14, // 536 S_LEAD_15, // 537 S_LEAD_16, // 538 S_LEAD_17, // 539 S_LEAD_18, // 540 S_LEAD_19, // 541 S_LEAD_20, // 542 S_LEAD_21, // 543 S_LEAD_22, // 544 S_LEAD_23, // 545 S_LEAD_24, // 546 S_LEAD_25, // 547 S_LEAD_26, // 548 S_LEAD_27, // 549 S_LEAD_28, // 550 S_LEAD_29, // 551 S_LEAD_30, // 552 S_LEAD_31, // 553 S_LEAD_32, // 554 S_LEAD_33, // 555 S_LEAD_34, // 556 S_LEAD_35, // 557 S_LEAD_36, // 558 S_LEAD_37, // 559 S_PUFY_04, // 560 S_PUFY_05, // 561 S_PUFY_06, // 562 S_PUFY_07, // 563 S_PUFY_08, // 564 S_MICR_01, // 565 S_MICR_02, // 566 S_ROB1_00, // 567 S_ROB1_01, // 568 S_ROB1_02, // 569 S_ROB1_03, // 570 S_ROB1_04, // 571 S_ROB1_05, // 572 S_ROB1_06, // 573 S_ROB1_07, // 574 S_ROB1_08, // 575 S_ROB1_09, // 576 S_ROB1_10, // 577 S_ROB1_11, // 578 S_ROB1_12, // 579 S_ROB1_13, // 580 S_ROB1_14, // 581 S_ROB1_15, // 582 S_ROB1_16, // 583 S_ROB1_17, // 584 S_ROB1_18, // 585 S_ROB1_19, // 586 S_ROB1_20, // 587 S_ROB1_21, // 588 S_ROB1_22, // 589 S_ROB1_23, // 590 S_ROB1_24, // 591 S_ROB1_25, // 592 S_ROB1_26, // 593 S_ROB1_27, // 594 S_ROB1_28, // 595 S_ROB1_29, // 596 S_ROB1_30, // 597 S_ROB1_31, // 598 S_ROB1_32, // 599 S_AGRD_01, // 600 S_AGRD_02, // 601 S_AGRD_03, // 602 S_AGRD_04, // 603 S_AGRD_05, // 604 S_AGRD_06, // 605 S_AGRD_07, // 606 S_AGRD_08, // 607 S_AGRD_09, // 608 S_AGRD_10, // 609 S_AGRD_11, // 610 S_AGRD_12, // 611 S_AGRD_13, // 612 S_AGRD_14, // 613 S_AGRD_15, // 614 S_AGRD_16, // 615 S_AGRD_17, // 616 S_AGRD_18, // 617 S_AGRD_19, // 618 S_AGRD_20, // 619 S_AGRD_21, // 620 S_AGRD_22, // 621 S_AGRD_23, // 622 S_AGRD_24, // 623 S_AGRD_25, // 624 S_AGRD_26, // 625 S_AGRD_27, // 626 S_AGRD_28, // 627 S_AGRD_29, // 628 S_AGRD_30, // 629 S_AGRD_31, // 630 S_GIBS_10, // 631 S_GIBS_11, // 632 S_GIBS_12, // 633 S_GIBS_13, // 634 S_GIBS_14, // 635 S_GIBS_15, // 636 S_GIBS_16, // 637 S_GIBS_17, // 638 S_GIBS_18, // 639 S_GIBS_19, // 640 S_GIBS_20, // 641 S_GIBS_21, // 642 S_PGRD_00, // 643 S_PGRD_01, // 644 S_PGRD_02, // 645 S_PGRD_03, // 646 S_PGRD_04, // 647 S_PGRD_05, // 648 S_PGRD_06, // 649 S_PGRD_07, // 650 S_PGRD_08, // 651 S_PGRD_09, // 652 S_PGRD_10, // 653 S_PGRD_11, // 654 S_PGRD_12, // 655 S_PGRD_13, // 656 S_PGRD_14, // 657 S_PGRD_15, // 658 S_PGRD_16, // 659 S_PGRD_17, // 660 S_PGRD_18, // 661 S_PGRD_19, // 662 S_PGRD_20, // 663 S_PGRD_21, // 664 S_PGRD_22, // 665 S_PGRD_23, // 666 S_PGRD_24, // 667 S_PGRD_25, // 668 S_PGRD_26, // 669 S_PGRD_27, // 670 S_PGRD_28, // 671 S_PGRD_29, // 672 S_PGRD_30, // 673 S_PGRD_31, // 674 S_PGRD_32, // 675 S_PGRD_33, // 676 S_PGRD_34, // 677 S_PGRD_35, // 678 S_PGRD_36, // 679 S_PGRD_37, // 680 S_ROB2_00, // 681 S_ROB2_01, // 682 S_ROB2_02, // 683 S_ROB2_03, // 684 S_ROB2_04, // 685 S_ROB2_05, // 686 S_ROB2_06, // 687 S_ROB2_07, // 688 S_ROB2_08, // 689 S_ROB2_09, // 690 S_ROB2_10, // 691 S_ROB2_11, // 692 S_ROB2_12, // 693 S_ROB2_13, // 694 S_ROB2_14, // 695 S_ROB2_15, // 696 S_ROB2_16, // 697 S_ROB2_17, // 698 S_ROB2_18, // 699 S_ROB2_19, // 700 S_ROB2_20, // 701 S_ROB2_21, // 702 S_ROB2_22, // 703 S_ROB2_23, // 704 S_ROB2_24, // 705 S_ROB2_25, // 706 S_ROB2_26, // 707 S_ROB2_27, // 708 S_ROB2_28, // 709 S_ROB2_29, // 710 S_MLDR_00, // 711 S_MLDR_01, // 712 S_MLDR_02, // 713 S_MLDR_03, // 714 S_MLDR_04, // 715 S_MLDR_05, // 716 S_MLDR_06, // 717 S_MLDR_07, // 718 S_MLDR_08, // 719 S_MLDR_09, // 720 S_MLDR_10, // 721 S_MLDR_11, // 722 S_MLDR_12, // 723 S_MLDR_13, // 724 S_MLDR_14, // 725 S_MLDR_15, // 726 S_MLDR_16, // 727 S_MLDR_17, // 728 S_MLDR_18, // 729 S_MLDR_19, // 730 S_MLDR_20, // 731 S_MLDR_21, // 732 S_MLDR_22, // 733 S_MLDR_23, // 734 S_MLDR_24, // 735 S_MLDR_25, // 736 S_MLDR_26, // 737 S_MLDR_27, // 738 S_ORCL_00, // 739 S_ORCL_01, // 740 S_ORCL_02, // 741 S_ORCL_03, // 742 S_ORCL_04, // 743 S_ORCL_05, // 744 S_ORCL_06, // 745 S_ORCL_07, // 746 S_ORCL_08, // 747 S_ORCL_09, // 748 S_ORCL_10, // 749 S_ORCL_11, // 750 S_ORCL_12, // 751 S_ORCL_13, // 752 S_ORCL_14, // 753 S_ORCL_15, // 754 S_ORCL_16, // 755 S_PRST_00, // 756 S_PRST_01, // 757 S_PRST_02, // 758 S_PRST_03, // 759 S_PRST_04, // 760 S_PRST_05, // 761 S_PRST_06, // 762 S_PRST_07, // 763 S_PRST_08, // 764 S_PRST_09, // 765 S_PRST_10, // 766 S_PRST_11, // 767 S_PRST_12, // 768 S_PRST_13, // 769 S_PRST_14, // 770 S_PRST_15, // 771 S_PDED_00, // 772 S_PDED_01, // 773 S_PDED_02, // 774 S_PDED_03, // 775 S_PDED_04, // 776 S_PDED_05, // 777 S_PDED_06, // 778 S_PDED_07, // 779 S_PDED_08, // 780 S_PDED_09, // 781 S_PDED_10, // 782 S_PDED_11, // 783 S_PDED_12, // 784 S_PDED_13, // 785 S_PDED_14, // 786 S_PDED_15, // 787 S_PDED_16, // 788 S_PDED_17, // 789 S_PDED_18, // 790 S_PDED_19, // 791 S_PDED_20, // 792 S_PDED_21, // 793 S_PDED_22, // 794 S_PDED_23, // 795 S_ALN1_00, // 796 S_ALN1_01, // 797 S_ALN1_02, // 798 S_ALN1_03, // 799 S_ALN1_04, // 800 S_ALN1_05, // 801 S_ALN1_06, // 802 S_ALN1_07, // 803 S_ALN1_08, // 804 S_ALN1_09, // 805 S_ALN1_10, // 806 S_ALN1_11, // 807 S_ALN1_12, // 808 S_ALN1_13, // 809 S_ALN1_14, // 810 S_ALN1_15, // 811 S_ALN1_16, // 812 S_ALN1_17, // 813 S_ALN1_18, // 814 S_ALN1_19, // 815 S_AL1P_00, // 816 S_AL1P_01, // 817 S_AL1P_02, // 818 S_AL1P_03, // 819 S_AL1P_04, // 820 S_AL1P_05, // 821 S_AL1P_06, // 822 S_AL1P_07, // 823 S_AL1P_08, // 824 S_AL1P_09, // 825 S_AL1P_10, // 826 S_AL1P_11, // 827 S_AL1P_12, // 828 S_AL1P_13, // 829 S_AL1P_14, // 830 S_AL1P_15, // 831 S_AL1P_16, // 832 S_AL1P_17, // 833 S_NODE_00, // 834 S_NODE_01, // 835 S_NODE_02, // 836 S_NODE_03, // 837 S_NODE_04, // 838 S_NODE_05, // 839 S_NODE_06, // 840 S_MTHD_00, // 841 S_MTHD_01, // 842 S_MTHD_02, // 843 S_MTHD_03, // 844 S_MTHD_04, // 845 S_MTHD_05, // 846 S_MTHD_06, // 847 S_MTHD_07, // 848 S_MTHD_08, // 849 S_MTHD_09, // 850 S_MTHD_10, // 851 S_ALN1_20, // 852 S_ALN1_21, // 853 S_ALN1_22, // 854 S_ALN1_23, // 855 S_ALN1_24, // 856 S_ALN1_25, // 857 S_ALN1_26, // 858 S_ALN1_27, // 859 S_ALN1_28, // 860 S_ALN1_29, // 861 S_ALN1_30, // 862 S_ALN1_31, // 863 S_ALN1_32, // 864 S_ALN1_33, // 865 S_ALN1_34, // 866 S_ALN1_35, // 867 S_ALN1_36, // 868 S_ALN1_37, // 869 S_ALN1_38, // 870 S_ALN1_39, // 871 S_ALN1_40, // 872 S_ALN1_41, // 873 S_ALN1_42, // 874 S_ALN1_43, // 875 S_ALN1_44, // 876 S_ALN1_45, // 877 S_ALN1_46, // 878 S_ALN1_47, // 879 S_ALN1_48, // 880 S_ALN1_49, // 881 S_ALN1_50, // 882 S_ALN1_51, // 883 S_ALN1_52, // 884 S_ALN1_53, // 885 S_ALN1_54, // 886 S_ALN1_55, // 887 S_ALN1_56, // 888 S_ALN1_57, // 889 S_MNAM_00, // 890 S_MNAM_01, // 891 S_MNAM_02, // 892 S_MNAM_03, // 893 S_MNAM_04, // 894 S_MNAM_05, // 895 S_MNAM_06, // 896 S_MNAM_07, // 897 S_MNAM_08, // 898 S_MNAM_09, // 899 S_MNAM_10, // 900 S_MNAM_11, // 901 S_MNAL_00, // 902 S_MNAL_01, // 903 S_MNAL_02, // 904 S_MNAL_03, // 905 S_MNAL_04, // 906 S_MNAL_05, // 907 S_MNAL_06, // 908 S_MNAL_07, // 909 S_MNAL_08, // 910 S_MNAL_09, // 911 S_MNAL_10, // 912 S_MNAL_11, // 913 S_MNAL_12, // 914 S_MNAL_13, // 915 S_MNAL_14, // 916 S_MNAL_15, // 917 S_MNAL_16, // 918 S_MNAL_17, // 919 S_MNAL_18, // 920 S_MNAL_19, // 921 S_MNAL_20, // 922 S_MNAL_21, // 923 S_MNAL_22, // 924 S_MNAL_23, // 925 S_MNAL_24, // 926 S_MNAL_25, // 927 S_MNAL_26, // 928 S_MNAL_27, // 929 S_MNAL_28, // 930 S_MNAL_29, // 931 S_MNAL_30, // 932 S_MNAL_31, // 933 S_MNAL_32, // 934 S_MNAL_33, // 935 S_MNAL_34, // 936 S_MNAL_35, // 937 S_MNAL_36, // 938 S_MNAL_37, // 939 S_MNAL_38, // 940 S_MNAL_39, // 941 S_MNAL_40, // 942 S_MDTH_00, // 943 S_MDTH_01, // 944 S_MDTH_02, // 945 S_MDTH_03, // 946 S_MDTH_04, // 947 S_MDTH_05, // 948 S_MDTH_06, // 949 S_MDTH_07, // 950 S_MDTH_08, // 951 S_MDTH_09, // 952 S_MDTH_10, // 953 S_MDTH_11, // 954 S_MDTH_12, // 955 S_MDTH_13, // 956 S_MDTH_14, // 957 S_NEST_00, // 958 S_PODD_00, // 959 S_PODD_01, // 960 S_PODD_02, // 961 S_PODD_03, // 962 S_PODD_04, // 963 S_PODD_05, // 964 S_ZAP6_00, // 965 S_ZAP6_01, // 966 S_ZAP6_02, // 967 S_ZOT3_00, // 968 S_ZOT3_01, // 969 S_ZOT3_02, // 970 S_ZOT3_03, // 971 S_ZOT3_04, // 972 S_ZAP6_03, // 973 S_ZAP6_04, // 974 S_ZAP6_05, // 975 S_ZAP7_00, // 976 S_ZAP7_01, // 977 S_ZAP7_02, // 978 S_ZAP7_03, // 979 S_ZAP7_04, // 980 S_ZOT1_00, // 981 S_ZOT1_01, // 982 S_ZOT1_02, // 983 S_ZOT1_03, // 984 S_ZOT1_04, // 985 S_ZAP5_00, // 986 S_ZAP5_01, // 987 S_ZAP5_02, // 988 S_ZAP5_03, // 989 S_ZOT2_00, // 990 S_ZOT2_01, // 991 S_ZOT2_02, // 992 S_ZOT2_03, // 993 S_ZOT2_04, // 994 S_SEWR_00, // 995 S_SEWR_01, // 996 S_SEWR_02, // 997 S_SEWR_03, // 998 S_SEWR_04, // 999 S_SEWR_05, // 1000 S_SEWR_06, // 1001 S_SEWR_07, // 1002 S_SEWR_08, // 1003 S_SEWR_09, // 1004 S_SEWR_10, // 1005 S_SEWR_11, // 1006 S_SEWR_12, // 1007 S_SEWR_13, // 1008 S_SPID_00, // 1009 S_SPID_01, // 1010 S_SPID_02, // 1011 S_SPID_03, // 1012 S_SPID_04, // 1013 S_SPID_05, // 1014 S_SPID_06, // 1015 S_SPID_07, // 1016 S_SPID_08, // 1017 S_SPID_09, // 1018 S_SPID_10, // 1019 S_SPID_11, // 1020 S_SPID_12, // 1021 S_SPID_13, // 1022 S_SPID_14, // 1023 S_SPID_15, // 1024 S_SPID_16, // 1025 S_SPID_17, // 1026 S_SPID_18, // 1027 S_SPID_19, // 1028 S_SPID_20, // 1029 S_SPID_21, // 1030 S_SPID_22, // 1031 S_SPID_23, // 1032 S_SPID_24, // 1033 S_SPID_25, // 1034 S_SPID_26, // 1035 S_SPID_27, // 1036 S_SPID_28, // 1037 S_SPID_29, // 1038 S_SPID_30, // 1039 S_SPID_31, // 1040 S_SPID_32, // 1041 S_SPID_33, // 1042 S_SPID_34, // 1043 S_SPID_35, // 1044 S_SPID_36, // 1045 S_SPID_37, // 1046 S_ROB3_00, // 1047 S_ROB3_01, // 1048 S_ROB3_02, // 1049 S_ROB3_03, // 1050 S_ROB3_04, // 1051 S_ROB3_05, // 1052 S_ROB3_06, // 1053 S_ROB3_07, // 1054 S_ROB3_08, // 1055 S_ROB3_09, // 1056 S_ROB3_10, // 1057 S_ROB3_11, // 1058 S_ROB3_12, // 1059 S_ROB3_13, // 1060 S_ROB3_14, // 1061 S_ROB3_15, // 1062 S_ROB3_16, // 1063 S_ROB3_17, // 1064 S_ROB3_18, // 1065 S_ROB3_19, // 1066 S_ROB3_20, // 1067 S_ROB3_21, // 1068 S_ROB3_22, // 1069 S_ROB3_23, // 1070 S_ROB3_24, // 1071 S_ROB3_25, // 1072 S_ROB3_26, // 1073 S_ROB3_27, // 1074 S_ROB3_28, // 1075 S_ROB3_29, // 1076 S_ROB3_30, // 1077 S_ROB3_31, // 1078 S_ROB3_32, // 1079 S_ROB3_33, // 1080 S_ROB3_34, // 1081 S_ROB3_35, // 1082 S_ROB3_36, // 1083 S_ROB3_37, // 1084 S_RBB3_00, // 1085 S_RBB3_01, // 1086 S_RBB3_02, // 1087 S_RBB3_03, // 1088 S_RBB3_04, // 1089 S_RBB3_05, // 1090 S_RBB3_06, // 1091 S_RBB3_07, // 1092 S_PRGR_00, // 1093 S_PRGR_01, // 1094 S_PRGR_02, // 1095 S_PRGR_03, // 1096 S_PRGR_04, // 1097 S_PRGR_05, // 1098 S_PRGR_06, // 1099 S_PRGR_07, // 1100 S_PRGR_08, // 1101 S_PRGR_09, // 1102 S_PRGR_10, // 1103 S_PRGR_11, // 1104 S_PRGR_12, // 1105 S_PRGR_13, // 1106 S_PRGR_14, // 1107 S_PRGR_15, // 1108 S_PRGR_16, // 1109 S_PRGR_17, // 1110 S_PRGR_18, // 1111 S_PRGR_19, // 1112 S_PRGR_20, // 1113 S_PRGR_21, // 1114 S_PRGR_22, // 1115 S_PRGR_23, // 1116 S_PRGR_24, // 1117 S_PRGR_25, // 1118 S_PRGR_26, // 1119 S_PRGR_27, // 1120 S_PRGR_28, // 1121 S_PRGR_29, // 1122 S_PRGR_30, // 1123 S_PRGR_31, // 1124 S_PRGR_32, // 1125 S_PRGR_33, // 1126 S_BASE_00, // 1127 S_BASE_01, // 1128 S_BASE_02, // 1129 S_BASE_03, // 1130 S_BASE_04, // 1131 S_BASE_05, // 1132 S_BASE_06, // 1133 S_BASE_07, // 1134 S_FRBL_00, // 1135 S_FRBL_01, // 1136 S_FRBL_02, // 1137 S_FRBL_03, // 1138 S_FRBL_04, // 1139 S_FRBL_05, // 1140 S_FRBL_06, // 1141 S_FRBL_07, // 1142 S_FRBL_08, // 1143 S_KLAX_00, // 1144 S_KLAX_01, // 1145 S_KLAX_02, // 1146 S_TURT_00, // 1147 S_TURT_01, // 1148 S_TURT_02, // 1149 S_TURT_03, // 1150 S_TURT_04, // 1151 S_BALL_00, // 1152 S_BALL_01, // 1153 S_BALL_02, // 1154 S_BALL_03, // 1155 S_BALL_04, // 1156 S_TURT_05, // 1157 S_PSTN_00, // 1158 S_PSTN_01, // 1159 S_PSTN_02, // 1160 S_PSTN_03, // 1161 S_PSTN_04, // 1162 S_PSTN_05, // 1163 S_PSTN_06, // 1164 S_PSTN_07, // 1165 S_PSTN_08, // 1166 S_PSTN_09, // 1167 S_PSTN_10, // 1168 S_SECR_00, // 1169 S_SECR_01, // 1170 S_SECR_02, // 1171 S_SECR_03, // 1172 S_SECR_04, // 1173 S_SECR_05, // 1174 S_SECR_06, // 1175 S_SECR_07, // 1176 S_SECR_08, // 1177 S_SECR_09, // 1178 S_SECR_10, // 1179 S_SECR_11, // 1180 S_SECR_12, // 1181 S_SECR_13, // 1182 S_SECR_14, // 1183 S_SECR_15, // 1184 S_XPRK_01, // 1185 S_XPRK_02, // 1186 S_TARG_00, // 1187 S_RING_00, // 1188 S_EARS_00, // 1189 S_COMM_00, // 1190 S_BOOM_00, // 1191 S_BOOM_01, // 1192 S_BOOM_02, // 1193 S_BOOM_03, // 1194 S_BOOM_04, // 1195 S_BOOM_05, // 1196 S_BOOM_06, // 1197 S_BOOM_07, // 1198 S_BOOM_08, // 1199 S_BOOM_09, // 1200 S_BOOM_10, // 1201 S_BOOM_11, // 1202 S_BOOM_12, // 1203 S_BOOM_13, // 1204 S_BOOM_14, // 1205 S_BOOM_15, // 1206 S_BOOM_16, // 1207 S_BOOM_17, // 1208 S_BOOM_18, // 1209 S_BOOM_19, // 1210 S_BOOM_20, // 1211 S_BOOM_21, // 1212 S_BOOM_22, // 1213 S_BOOM_23, // 1214 S_BOOM_24, // 1215 S_RATT_00, // 1216 S_RATT_01, // 1217 S_RATT_02, // 1218 S_RATT_03, // 1219 S_RATT_04, // 1220 S_RATT_05, // 1221 S_RATT_06, // 1222 S_HOGN_00, // 1223 S_HOGN_01, // 1224 S_HOGN_02, // 1225 S_DEAD_00, // 1226 S_SBAN_00, // 1227 S_BOTR_00, // 1228 S_HATR_00, // 1229 S_TOPR_00, // 1230 S_COUP_00, // 1231 S_COUP_01, // 1232 S_COUP_02, // 1233 S_BUBB_00, // 1234 S_BUBF_00, // 1235 S_BUBC_00, // 1236 S_ASPR_00, // 1237 S_SPDL_00, // 1238 S_SPDL_01, // 1239 S_SPDL_02, // 1240 S_TOKN_00, // 1241 S_OTOK_00, // 1242 S_HELT_00, // 1243 S_GUNT_00, // 1244 S_FULL_00, // 1245 S_FULL_01, // 1246 S_MEAT_00, // 1247 S_MEAT_01, // 1248 S_MEAT_02, // 1249 S_MEAT_03, // 1250 S_MEAT_04, // 1251 S_MEAT_05, // 1252 S_MEAT_06, // 1253 S_MEAT_07, // 1254 S_MEAT_08, // 1255 S_MEAT_09, // 1256 S_MEAT_10, // 1257 S_MEAT_11, // 1258 S_MEAT_12, // 1259 S_MEAT_13, // 1260 S_MEAT_14, // 1261 S_MEAT_15, // 1262 S_MEAT_16, // 1263 S_MEAT_17, // 1264 S_MEAT_18, // 1265 S_MEAT_19, // 1266 S_JUNK_00, // 1267 S_JUNK_01, // 1268 S_JUNK_02, // 1269 S_JUNK_03, // 1270 S_JUNK_04, // 1271 S_JUNK_05, // 1272 S_JUNK_06, // 1273 S_JUNK_07, // 1274 S_JUNK_08, // 1275 S_JUNK_09, // 1276 S_JUNK_10, // 1277 S_JUNK_11, // 1278 S_JUNK_12, // 1279 S_JUNK_13, // 1280 S_JUNK_14, // 1281 S_JUNK_15, // 1282 S_JUNK_16, // 1283 S_JUNK_17, // 1284 S_JUNK_18, // 1285 S_JUNK_19, // 1286 S_FFOT_00, // 1287 S_FFOT_01, // 1288 S_FFOT_02, // 1289 S_FFOT_03, // 1290 S_DIE1_00, // 1291 S_BEAC_00, // 1292 S_BEAC_01, // 1293 S_BEAC_02, // 1294 S_ARM1_00, // 1295 S_ARM2_00, // 1296 S_BARW_00, // 1297 S_BARW_01, // 1298 S_BARW_02, // 1299 S_BARW_03, // 1300 S_BARW_04, // 1301 S_BARW_05, // 1302 S_BARW_06, // 1303 S_BARW_07, // 1304 S_BART_00, // 1305 S_BART_01, // 1306 S_BART_02, // 1307 S_BART_03, // 1308 S_BART_04, // 1309 S_BART_05, // 1310 S_BART_06, // 1311 S_BART_07, // 1312 S_BART_08, // 1313 S_BART_09, // 1314 S_BART_10, // 1315 S_BART_11, // 1316 S_LAMP_00, // 1317 S_LANT_00, // 1318 S_BARL_00, // 1319 S_BARL_01, // 1320 S_BARL_02, // 1321 S_BARL_03, // 1322 S_BOWL_00, // 1323 S_BOWL_01, // 1324 S_BOWL_02, // 1325 S_BOWL_03, // 1326 S_BRAZ_00, // 1327 S_BRAZ_01, // 1328 S_BRAZ_02, // 1329 S_BRAZ_03, // 1330 S_TRCH_00, // 1331 S_TRCH_01, // 1332 S_TRCH_02, // 1333 S_TRCH_03, // 1334 S_LTRH_00, // 1335 S_LTRH_01, // 1336 S_LTRH_02, // 1337 S_LTRH_03, // 1338 S_LMPC_00, // 1339 S_LMPC_01, // 1340 S_LMPC_02, // 1341 S_LMPC_03, // 1342 S_LOGS_00, // 1343 S_LOGS_01, // 1344 S_LOGS_02, // 1345 S_LOGS_03, // 1346 S_TRHO_00, // 1347 S_WATR_00, // 1348 S_MUGG_00, // 1349 S_FUSL_00, // 1350 S_CRD1_00, // 1351 S_CRD2_00, // 1352 S_TPAS_00, // 1353 S_KY1G_00, // 1354 S_KY2S_00, // 1355 S_KY3B_00, // 1356 S_HAND_00, // 1357 S_CRYS_00, // 1358 S_CRYS_01, // 1359 S_CRYS_02, // 1360 S_CRYS_03, // 1361 S_CRYS_04, // 1362 S_CRYS_05, // 1363 S_PRIS_00, // 1364 S_PWR1_00, // 1365 S_PWR2_00, // 1366 S_PWR3_00, // 1367 S_ORAC_00, // 1368 S_GYID_00, // 1369 S_FUBR_00, // 1370 S_WARE_00, // 1371 S_RCRY_00, // 1372 S_BCRY_00, // 1373 S_CHAP_00, // 1374 S_TUNL_00, // 1375 S_BLTK_00, // 1376 S_SECK_00, // 1377 S_MINE_00, // 1378 S_REBL_00, // 1379 S_PROC_00, // 1380 S_ANKH_00, // 1381 S_GOID_00, // 1382 S_STMP_00, // 1383 S_MDKT_00, // 1384 S_COIN_00, // 1385 S_CRED_00, // 1386 S_SACK_00, // 1387 S_CHST_00, // 1388 S_SHD1_00, // 1389 S_SHD1_01, // 1390 S_SHD1_02, // 1391 S_SHD1_03, // 1392 S_MASK_00, // 1393 S_UNIF_00, // 1394 S_OFIC_00, // 1395 S_PMAP_00, // 1396 S_PMAP_01, // 1397 S_PMUP_00, // 1398 S_PMUP_01, // 1399 S_BLIT_00, // 1400 S_BBOX_00, // 1401 S_MSSL_00, // 1402 S_ROKT_00, // 1403 S_BRY1_00, // 1404 S_BRY1_01, // 1405 S_CPAC_00, // 1406 S_CPAC_01, // 1407 S_PQRL_00, // 1408 S_XQRL_00, // 1409 S_GRN1_00, // 1410 S_GRN2_00, // 1411 S_BKPK_00, // 1412 S_RELC_00, // 1413 S_RIFL_00, // 1414 S_RIFL_01, // 1415 S_FLAM_00, // 1416 S_BFLM_00, // 1417 S_MMSL_00, // 1418 S_TRPD_00, // 1419 S_GRND_00, // 1420 S_CBOW_00, // 1421 S_SIGL_00, // 1422 S_SIGL_01, // 1423 S_SIGL_02, // 1424 S_SIGL_03, // 1425 S_SIGL_04, // 1426 S_LITE_00, // 1427 S_CNDL_00, // 1428 S_CLBR_00, // 1429 S_LITS_00, // 1430 S_LITB_00, // 1431 S_LITG_00, // 1432 S_ROK1_00, // 1433 S_ROK2_00, // 1434 S_ROK3_00, // 1435 S_ROK4_00, // 1436 S_LOGG_00, // 1437 S_LOGG_01, // 1438 S_LOGG_02, // 1439 S_LOGG_03, // 1440 S_RUB1_00, // 1441 S_RUB2_00, // 1442 S_RUB3_00, // 1443 S_RUB4_00, // 1444 S_RUB5_00, // 1445 S_RUB6_00, // 1446 S_RUB7_00, // 1447 S_RUB8_00, // 1448 S_CHAN_00, // 1449 S_STAT_00, // 1450 S_DSTA_00, // 1451 S_CRAB_00, // 1452 S_CAGE_00, // 1453 S_TREE_00, // 1454 S_TREE_01, // 1455 S_TREE_02, // 1456 S_TRE1_00, // 1457 S_BUSH_00, // 1458 S_SHRB_00, // 1459 S_STAK_00, // 1460 S_BAR1_00, // 1461 S_VASE_00, // 1462 S_VASE_01, // 1463 S_STOL_00, // 1464 S_POT1_00, // 1465 S_TUB1_00, // 1466 S_ANVL_00, // 1467 S_TLMP_00, // 1468 S_TLMP_01, // 1469 S_TRAY_00, // 1470 S_APOW_00, // 1471 S_AFED_00, // 1472 S_DRIP_00, // 1473 S_DRIP_01, // 1474 S_DRIP_02, // 1475 S_DRIP_03, // 1476 S_DRIP_04, // 1477 S_DRIP_05, // 1478 S_DRIP_06, // 1479 S_DRIP_07, // 1480 S_CDRP_00, // 1481 S_CDRP_01, // 1482 S_CDRP_02, // 1483 S_CDRP_03, // 1484 S_SPLH_00, // 1485 S_SPLH_01, // 1486 S_SPLH_02, // 1487 S_SPLH_03, // 1488 S_SPLH_04, // 1489 S_SPLH_05, // 1490 S_SPLH_06, // 1491 S_SPLH_07, // 1492 S_WTFT_00, // 1493 S_WTFT_01, // 1494 S_WTFT_02, // 1495 S_WTFT_03, // 1496 S_HERT_00, // 1497 S_HERT_01, // 1498 S_HERT_02, // 1499 S_TELP_00, // 1500 S_TELP_01, // 1501 S_TELP_02, // 1502 S_TELP_03, // 1503 S_MONI_00, // 1504 S_STEL_00, // 1505 S_STLA_00, // 1506 S_STLE_00, // 1507 S_HUGE_00, // 1508 S_HUGE_01, // 1509 S_HUGE_02, // 1510 S_HUGE_03, // 1511 S_STLG_00, // 1512 S_STLG_01, // 1513 S_STLG_02, // 1514 S_STLG_03, // 1515 S_STLG_04, // 1516 S_STLG_05, // 1517 NUMSTATES } statenum_t; typedef struct { spritenum_t sprite; int frame; int tics; // void (*action) (); actionf_t action; statenum_t nextstate; //int misc1; // villsa [STRIFE] unused //int misc2; // villsa [STRIFE] unused } state_t; extern state_t states[NUMSTATES]; extern char *sprnames[]; typedef enum { MT_FIELDGUARD, //000 MT_PLAYER, //001 MT_SHOPKEEPER_W, //002 MT_SHOPKEEPER_B, //003 MT_SHOPKEEPER_A, //004 MT_SHOPKEEPER_M, //005 MT_PEASANT2_A, //006 MT_PEASANT2_B, //007 MT_PEASANT2_C, //008 MT_PEASANT5_A, //009 MT_PEASANT5_B, //010 MT_PEASANT5_C, //011 MT_PEASANT4_A, //012 MT_PEASANT4_B, //013 MT_PEASANT4_C, //014 MT_PEASANT6_A, //015 MT_PEASANT6_B, //016 MT_PEASANT6_C, //017 MT_PEASANT3_A, //018 MT_PEASANT3_B, //019 MT_PEASANT3_C, //020 MT_PEASANT8_A, //021 MT_PEASANT8_B, //022 MT_PEASANT8_C, //023 MT_PEASANT7_A, //024 MT_PEASANT7_B, //025 MT_PEASANT7_C, //026 MT_PEASANT1, //027 MT_ZOMBIE, //028 MT_BECOMING, //029 MT_ZOMBIESPAWNER, //030 MT_HUGE_TANK_1, //031 MT_HUGE_TANK_2, //032 MT_HUGE_TANK_3, //033 MT_TANK_4, //034 MT_TANK_5, //035 MT_TANK_6, //036 MT_KNEELING_GUY, //037 MT_BEGGAR1, //038 MT_BEGGAR2, //039 MT_BEGGAR3, //040 MT_BEGGAR4, //041 MT_BEGGAR5, //042 MT_REBEL1, //043 MT_REBEL2, //044 MT_REBEL3, //045 MT_REBEL4, //046 MT_REBEL5, //047 MT_REBEL6, //048 MT_RLEADER, //049 MT_RLEADER2, //050 MT_MISSILESMOKE, //051 MT_REAVER, //052 MT_GUARD1, //053 MT_GUARD2, //054 MT_GUARD3, //055 MT_GUARD4, //056 MT_GUARD5, //057 MT_GUARD6, //058 MT_GUARD7, //059 MT_GUARD8, //060 MT_SHADOWGUARD, //061 MT_PGUARD, //062 MT_CRUSADER, //063 MT_BISHOP, //064 MT_ORACLE, //065 MT_PRIEST, //066 MT_SPECTRE_A, //067 MT_NODE, //068 MT_SPECTREHEAD, //069 MT_SPECTRE_B, //070 MT_SPECTRE_C, //071 MT_SPECTRE_D, //072 MT_SPECTRE_E, //073 MT_ENTITY, //074 MT_SUBENTITY, //075 MT_NEST, //076 MT_POD, //077 MT_SIGIL_B_SHOT, //078 MT_SIGIL_SB_SHOT, //079 MT_SIGIL_C_SHOT, //080 MT_SIGIL_SC_SHOT, //081 MT_SIGIL_E_OFFSHOOT, //082 MT_SIGIL_TRAIL, //083 MT_SIGIL_E_SHOT, //084 MT_SIGIL_SE_SHOT, //085 MT_SIGIL_A_ZAP_LEFT, //086 MT_SIGIL_A_ZAP_RIGHT, //087 MT_SIGIL_A_GROUND, //088 MT_SIGIL_D_SHOT, //089 MT_SIGIL_SD_SHOT, //090 MT_SENTINEL, //091 MT_STALKER, //092 MT_INQUISITOR, //093 MT_INQARM, //094 MT_PROGRAMMER, //095 MT_PROGRAMMERBASE, //096 MT_HOOKSHOT, //097 MT_CHAINSHOT, //098 MT_MINIMISSLE, //099 MT_C_MISSILE, //100 MT_SEEKMISSILE, //101 MT_ELECARROW, //102 MT_POISARROW, //103 MT_R_LASER, //104 MT_L_LASER, //105 MT_HEGRENADE, //106 MT_PGRENADE, //107 MT_INQGRENADE, //108 MT_PFLAME, //109 MT_TORPEDO, //110 MT_TORPEDOSPREAD, //111 MT_SFIREBALL, //112 MT_C_FLAME, //113 MT_STRIFEPUFF3, //114 MT_STRIFEPUFF, //115 MT_SPARKPUFF, //116 MT_BLOOD_DEATH, //117 MT_TFOG, //118 MT_IFOG, //119 MT_TELEPORTMAN, //120 MT_MISC_01, //121 MT_TURRET, //122 MT_GATE, //123 MT_COMPUTER, //124 MT_INV_MED1, //125 MT_INV_MED2, //126 MT_INV_MED3, //127 MT_DEGNINORE, //128 MT_INV_ARMOR2, //129 MT_INV_ARMOR1, //130 MT_MISC_22, //131 MT_MISC_11, //132 MT_KEY_BASE, //133 MT_GOVSKEY, //134 MT_KEY_TRAVEL, //135 MT_KEY_ID_BLUE, //136 MT_PRISONKEY, //137 MT_KEY_HAND, //138 MT_POWER1KEY, //139 MT_POWER2KEY, //140 MT_POWER3KEY, //141 MT_KEY_GOLD, //142 MT_KEY_ID_GOLD, //143 MT_KEY_SILVER, //144 MT_KEY_ORACLE, //145 MT_MILITARYID, //146 MT_KEY_ORDER, //147 MT_KEY_WAREHOUSE, //148 MT_KEY_BRASS, //149 MT_KEY_RED_CRYSTAL, //150 MT_KEY_BLUE_CRYSTAL, //151 MT_KEY_CHAPEL, //152 MT_CATACOMBKEY, //153 MT_SECURITYKEY, //154 MT_KEY_CORE, //155 MT_KEY_MAULER, //156 MT_KEY_FACTORY, //157 MT_KEY_MINE, //158 MT_NEWKEY5, //159 MT_INV_SHADOWARMOR, //160 MT_INV_SUIT, //161 MT_QUEST_UNIFORM, //162 MT_QUEST_GUARD_UNIFORM, //163 MT_INV_SUPERMAP, //164 MT_INV_RADAR, //165 MT_BEACON, //166 MT_INV_TARGETER, //167 MT_MONY_1, //168 MT_MONY_10, //169 MT_MONY_25, //170 MT_MONY_50, //171 MT_MONY_300, //172 MT_TOKEN_RING, //173 MT_INV_CHALICE, //174 MT_TOKEN_EAR, //175 MT_INV_COMMUNICATOR, //176 MT_AGREN, //177 MT_APGREN, //178 MT_ACLIP, //179 MT_AAMMOBOX, //180 MT_AMINI, //181 MT_AMINIBOX, //182 MT_ACELL, //183 MT_APCELL, //184 MT_APAROW, //185 MT_AAROW, //186 MT_INV_SATCHEL, //187 MT_PULSE, //188 MT_RIFLESTAND, //189 MT_FLAMETHROWER, //190 MT_TOKEN_FLAME_THROWER_PARTS, //191 MT_MISSILELAUNCHER, //192 MT_BLASTER, //193 MT_CROSSBOW, //194 MT_GRENADELAUNCHER, //195 MT_SIGIL_A, //196 MT_SIGIL_B, //197 MT_SIGIL_C, //198 MT_SIGIL_D, //199 MT_SIGIL_E, //200 MT_POWER_CRYSTAL, //201 MT_RAT, //202 MT_MISC_05, //203 MT_MISC_06, //204 MT_MISC_15, //205 MT_LIGHT14, //206 MT_LIGHT13, //207 MT_LIGHT12, //208 MT_LIGHT18, //209 MT_PILLAR2, //210 MT_PILLAR3, //211 MT_PILLAR4, //212 MT_PILLAR5, //213 MT_PILLAR6, //214 MT_PILLAR7, //215 MT_CAVE2, //216 MT_CAVE3, //217 MT_CAVE4, //218 MT_CAVE6, //219 MT_CAVE7, //220 MT_CAVE5, //221 MT_LIGHT2, //222 MT_LIGHT3, //223 MT_MISC_03, //224 MT_MISC_13, //225 MT_MISC_02, //226 MT_MISC_07, //227 MT_BIO2, //228 MT_TELEPORTSTAND, //229 MT_DEADTHING1, //230 MT_DEADTHING2, //231 MT_DEADTHING3, //232 MT_DEADTHING4, //233 MT_DEADTHING5, //234 MT_DEADTHING6, //235 MT_BIO1, //236 MT_GIBS, //237 MT_MISC_04, //238 MT_LIGHT11, //239 MT_LIGHT10, //240 MT_LIGHT9, //241 MT_LIGHT8, //242 MT_MISC_14, //243 MT_LIGHT1, //244 MT_PILLAR8, //245 MT_PILLAR9, //246 MT_LIGHT15, //247 MT_LIGHT4, //248 MT_LIGHT5, //249 MT_ROCK1, //250 MT_ROCK2, //251 MT_ROCK3, //252 MT_ROCK4, //253 MT_TREE7, //254 MT_RUBBLE1, //255 MT_RUBBLE2, //256 MT_RUBBLE3, //257 MT_RUBBLE4, //258 MT_RUBBLE5, //259 MT_RUBBLE6, //260 MT_RUBBLE7, //261 MT_RUBBLE8, //262 MT_MISC_08, //263 MT_LIGHT6, //264 MT_LIGHT7, //265 MT_TREE2, //266 MT_TREE3, //267 MT_TREE4, //268 MT_TREE1, //269 MT_TREE6, //270 MT_TREE5, //271 MT_CAVE1, //272 MT_PILLAR1, //273 MT_MISC_10, //274 MT_MISC_09, //275 MT_MISC_17, //276 MT_MISC_18, //277 MT_MISC_19, //278 MT_MISC_20, //279 MT_LIGHT16, //280 MT_LIGHT17, //281 MT_MISC_21, //282 MT_MISC_12, //283 MT_MISC_26, //284 MT_MISC_23, //285 MT_MISC_24, //286 MT_MISC_25, //287 MT_COUPLING, //288 MT_COUPLING_BROKEN, //289 MT_PILLAR10, //290 MT_PILLAR11, //291 MT_PILLAR12, //292 MT_PILLAR13, //293 MT_LIGHT19, //294 MT_MEAT, //295 MT_JUNK, //296 MT_BURNDROP, //297 MT_TOKEN_AMMO, //298 MT_TOKEN_HEALTH, //299 MT_TOKEN, //300 MT_TOKEN_ALARM, //301 MT_TOKEN_DOOR1, //302 MT_TOKEN_SHOPCLOSE, //303 MT_TOKEN_PRISON_PASS, //304 MT_TOKEN_DOOR3, //305 MT_TOKEN_STAMINA, //306 MT_TOKEN_NEW_ACCURACY, //307 MT_TOKEN_REPORT, //308 MT_TOKEN_TOUGHNESS, //309 MT_TOKEN_ACCURACY, //310 MT_TOKEN_ORACLE_PASS, //311 MT_TOKEN_QUEST1, //312 MT_TOKEN_QUEST2, //313 MT_TOKEN_QUEST3, //314 MT_TOKEN_QUEST4, //315 MT_TOKEN_QUEST5, //316 MT_TOKEN_QUEST6, //317 MT_TOKEN_QUEST7, //318 MT_TOKEN_QUEST8, //319 MT_TOKEN_QUEST9, //320 MT_TOKEN_QUEST10, //321 MT_TOKEN_QUEST11, //322 MT_TOKEN_QUEST12, //323 MT_TOKEN_QUEST13, //324 MT_TOKEN_CRYSTAL, //325 MT_TOKEN_QUEST15, //326 MT_GATEQUEST, //327 MT_TOKEN_QUEST17, //328 MT_TOKEN_QUEST18, //329 MT_TOKEN_QUEST19, //330 MT_TOKEN_QUEST20, //331 MT_TOKEN_BISHOP, //332 MT_TOKEN_QUEST22, //333 MT_TOKEN_ORACLE, //334 MT_TOKEN_MACIL, //335 MT_TOKEN_QUEST25, //336 MT_TOKEN_LOREMASTER, //337 MT_SECRQUEST, //338 MT_TOKEN_QUEST28, //339 MT_TOKEN_QUEST29, //340 MT_TOKEN_QUEST30, //341 MT_TOKEN_QUEST31, //342 MT_SLIDESHOW, //343 NUMMOBJTYPES } mobjtype_t; // villsa [STRIFE] updated mobjinfo struct typedef struct { int doomednum; int spawnstate; int spawnhealth; int seestate; int seesound; int reactiontime; int attacksound; int painstate; int painchance; int painsound; int meleestate; int missilestate; int crashstate; int deathstate; int xdeathstate; int deathsound; int speed; int radius; int height; int mass; int damage; int activesound; int flags; char* name; } mobjinfo_t; extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/m_menu.c000066400000000000000000001501201257432200600230130ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // DOOM selection menu, options, episode etc. // Sliders and icons. Kinda widget stuff. // #include #include #include "doomdef.h" #include "doomkeys.h" #include "dstrings.h" #include "d_main.h" #include "deh_main.h" #include "i_swap.h" #include "i_system.h" #include "i_timer.h" #include "i_video.h" #include "z_zone.h" #include "v_video.h" #include "w_wad.h" #include "r_local.h" #include "hu_stuff.h" #include "g_game.h" #include "m_argv.h" #include "m_controls.h" #include "m_misc.h" #include "m_saves.h" // [STRIFE] #include "p_saveg.h" #include "s_sound.h" #include "doomstat.h" // Data. #include "sounds.h" #include "m_menu.h" #include "p_dialog.h" extern void M_QuitStrife(int); extern patch_t* hu_font[HU_FONTSIZE]; extern boolean message_dontfuckwithme; extern boolean chat_on; // in heads-up code extern boolean sendsave; // [STRIFE] // // defaulted values // int mouseSensitivity = 5; // [STRIFE]: removed this entirely // Show messages has default, 0 = off, 1 = on //int showMessages = 1; // Blocky mode, has default, 0 = high, 1 = normal int detailLevel = 0; int screenblocks = 10; // [STRIFE] default 10, not 9 // temp for screenblocks (0-9) int screenSize; // -1 = no quicksave slot picked! int quickSaveSlot; // 1 = message to be printed int messageToPrint; // ...and here is the message string! char* messageString; // message x & y int messx; int messy; int messageLastMenuActive; // timed message = no input from user boolean messageNeedsInput; void (*messageRoutine)(int response); char gammamsg[5][26] = { GAMMALVL0, GAMMALVL1, GAMMALVL2, GAMMALVL3, GAMMALVL4 }; // we are going to be entering a savegame string int saveStringEnter; int saveSlot; // which slot to save in int saveCharIndex; // which char we're editing // old save description before edit char saveOldString[SAVESTRINGSIZE]; boolean inhelpscreens; boolean menuactive; boolean menupause; // haleyjd 08/29/10: [STRIFE] New global int menupausetime; // haleyjd 09/04/10: [STRIFE] New global boolean menuindialog; // haleyjd 09/04/10: ditto // haleyjd 08/27/10: [STRIFE] SKULLXOFF == -28, LINEHEIGHT == 19 #define CURSORXOFF -28 #define LINEHEIGHT 19 extern boolean sendpause; char savegamestrings[10][SAVESTRINGSIZE]; char endstring[160]; // haleyjd 09/04/10: [STRIFE] Moved menuitem / menu structures into header // because they are needed externally by the dialog engine. // haleyjd 08/27/10: [STRIFE] skull* stuff changed to cursor* stuff short itemOn; // menu item skull is on short cursorAnimCounter; // skull animation counter short whichCursor; // which skull to draw // graphic name of cursors // haleyjd 08/27/10: [STRIFE] M_SKULL* -> M_CURS* char *cursorName[8] = {"M_CURS1", "M_CURS2", "M_CURS3", "M_CURS4", "M_CURS5", "M_CURS6", "M_CURS7", "M_CURS8" }; // haleyjd 20110210 [STRIFE]: skill level for menus int menuskill; // current menudef menu_t* currentMenu; // haleyjd 03/01/13: [STRIFE] v1.31-only: // Keeps track of whether the save game menu is being used to name a new // character slot, or to just save the current game. In the v1.31 disassembly // this was the new dword_8632C variable. boolean namingCharacter; // // PROTOTYPES // void M_NewGame(int choice); void M_Episode(int choice); void M_ChooseSkill(int choice); void M_LoadGame(int choice); void M_SaveGame(int choice); void M_Options(int choice); void M_EndGame(int choice); void M_ReadThis(int choice); void M_ReadThis2(int choice); void M_ReadThis3(int choice); // [STRIFE] //void M_ChangeMessages(int choice); [STRIFE] void M_ChangeSensitivity(int choice); void M_SfxVol(int choice); void M_VoiceVol(int choice); // [STRIFE] void M_MusicVol(int choice); void M_SizeDisplay(int choice); void M_StartGame(int choice); void M_Sound(int choice); //void M_FinishReadThis(int choice); - [STRIFE] unused void M_SaveSelect(int choice); void M_ReadSaveStrings(void); void M_QuickSave(void); void M_QuickLoad(void); void M_DrawMainMenu(void); void M_DrawReadThis1(void); void M_DrawReadThis2(void); void M_DrawReadThis3(void); // [STRIFE] void M_DrawNewGame(void); void M_DrawEpisode(void); void M_DrawOptions(void); void M_DrawSound(void); void M_DrawLoad(void); void M_DrawSave(void); void M_DrawSaveLoadBorder(int x,int y); void M_SetupNextMenu(menu_t *menudef); void M_DrawThermo(int x,int y,int thermWidth,int thermDot); void M_DrawEmptyCell(menu_t *menu,int item); void M_DrawSelCell(menu_t *menu,int item); int M_StringWidth(char *string); int M_StringHeight(char *string); void M_StartMessage(char *string,void *routine,boolean input); void M_StopMessage(void); // // DOOM MENU // enum { newgame = 0, options, loadgame, savegame, readthis, quitdoom, main_end } main_e; menuitem_t MainMenu[]= { {1,"M_NGAME",M_NewGame,'n'}, {1,"M_OPTION",M_Options,'o'}, {1,"M_LOADG",M_LoadGame,'l'}, {1,"M_SAVEG",M_SaveGame,'s'}, // Another hickup with Special edition. {1,"M_RDTHIS",M_ReadThis,'h'}, // haleyjd 08/28/10: 'r' -> 'h' {1,"M_QUITG",M_QuitStrife,'q'} }; menu_t MainDef = { main_end, NULL, MainMenu, M_DrawMainMenu, 97,45, // haleyjd 08/28/10: [STRIFE] changed y coord 0 }; // // EPISODE SELECT // /* enum { ep1, ep2, ep3, ep4, ep_end } episodes_e; menuitem_t EpisodeMenu[]= { {1,"M_EPI1", M_Episode,'k'}, {1,"M_EPI2", M_Episode,'t'}, {1,"M_EPI3", M_Episode,'i'}, {1,"M_EPI4", M_Episode,'t'} }; menu_t EpiDef = { ep_end, // # of menu items &MainDef, // previous menu EpisodeMenu, // menuitem_t -> M_DrawEpisode, // drawing routine -> 48,63, // x,y ep1 // lastOn }; */ // // NEW GAME // enum { killthings, toorough, hurtme, violence, nightmare, newg_end } newgame_e; menuitem_t NewGameMenu[]= { // haleyjd 08/28/10: [STRIFE] changed all shortcut letters {1,"M_JKILL", M_ChooseSkill, 't'}, {1,"M_ROUGH", M_ChooseSkill, 'r'}, {1,"M_HURT", M_ChooseSkill, 'v'}, {1,"M_ULTRA", M_ChooseSkill, 'e'}, {1,"M_NMARE", M_ChooseSkill, 'b'} }; menu_t NewDef = { newg_end, // # of menu items &MainDef, // previous menu - haleyjd [STRIFE] changed to MainDef NewGameMenu, // menuitem_t -> M_DrawNewGame, // drawing routine -> 48,63, // x,y toorough // lastOn - haleyjd [STRIFE]: default to skill 1 }; // // OPTIONS MENU // enum { // haleyjd 08/28/10: [STRIFE] Removed messages, mouse sens., detail. endgame, scrnsize, option_empty1, soundvol, opt_end } options_e; menuitem_t OptionsMenu[]= { // haleyjd 08/28/10: [STRIFE] Removed messages, mouse sens., detail. {1,"M_ENDGAM", M_EndGame,'e'}, {2,"M_SCRNSZ", M_SizeDisplay,'s'}, {-1,"",0,'\0'}, {1,"M_SVOL", M_Sound,'s'} }; menu_t OptionsDef = { opt_end, &MainDef, OptionsMenu, M_DrawOptions, 60,37, 0 }; // // Read This! MENU 1 & 2 & [STRIFE] 3 // enum { rdthsempty1, read1_end } read_e; menuitem_t ReadMenu1[] = { {1,"",M_ReadThis2,0} }; menu_t ReadDef1 = { read1_end, &MainDef, ReadMenu1, M_DrawReadThis1, 280,185, 0 }; enum { rdthsempty2, read2_end } read_e2; menuitem_t ReadMenu2[]= { {1,"",M_ReadThis3,0} // haleyjd 08/28/10: [STRIFE] Go to ReadThis3 }; menu_t ReadDef2 = { read2_end, &ReadDef1, ReadMenu2, M_DrawReadThis2, 250,185, // haleyjd 08/28/10: [STRIFE] changed coords 0 }; // haleyjd 08/28/10: Added Read This! menu 3 enum { rdthsempty3, read3_end } read_e3; menuitem_t ReadMenu3[]= { {1,"",M_ClearMenus,0} }; menu_t ReadDef3 = { read3_end, &ReadDef2, ReadMenu3, M_DrawReadThis3, 250, 185, 0 }; // // SOUND VOLUME MENU // enum { sfx_vol, sfx_empty1, music_vol, sfx_empty2, voice_vol, sfx_empty3, sfx_mouse, sfx_empty4, sound_end } sound_e; // haleyjd 08/29/10: // [STRIFE] // * Added voice volume // * Moved mouse sensitivity here (who knows why...) menuitem_t SoundMenu[]= { {2,"M_SFXVOL",M_SfxVol,'s'}, {-1,"",0,'\0'}, {2,"M_MUSVOL",M_MusicVol,'m'}, {-1,"",0,'\0'}, {2,"M_VOIVOL",M_VoiceVol,'v'}, {-1,"",0,'\0'}, {2,"M_MSENS",M_ChangeSensitivity,'m'}, {-1,"",0,'\0'} }; menu_t SoundDef = { sound_end, &OptionsDef, SoundMenu, M_DrawSound, 80,35, // [STRIFE] changed y coord 64 -> 35 0 }; // // LOAD GAME MENU // enum { load1, load2, load3, load4, load5, load6, load_end } load_e; menuitem_t LoadMenu[]= { {1,"", M_LoadSelect,'1'}, {1,"", M_LoadSelect,'2'}, {1,"", M_LoadSelect,'3'}, {1,"", M_LoadSelect,'4'}, {1,"", M_LoadSelect,'5'}, {1,"", M_LoadSelect,'6'} }; menu_t LoadDef = { load_end, &MainDef, LoadMenu, M_DrawLoad, 80,54, 0 }; // // SAVE GAME MENU // menuitem_t SaveMenu[]= { {1,"", M_SaveSelect,'1'}, {1,"", M_SaveSelect,'2'}, {1,"", M_SaveSelect,'3'}, {1,"", M_SaveSelect,'4'}, {1,"", M_SaveSelect,'5'}, {1,"", M_SaveSelect,'6'} }; menu_t SaveDef = { load_end, &MainDef, SaveMenu, M_DrawSave, 80,54, 0 }; void M_DrawNameChar(void); // // NAME CHARACTER MENU // // [STRIFE] // haleyjd 20110210: New "Name Your Character" Menu // menu_t NameCharDef = { load_end, &NewDef, SaveMenu, M_DrawNameChar, 80,54, 0 }; // // M_ReadSaveStrings // read the strings from the savegame files // // [STRIFE] // haleyjd 20110210: Rewritten to read "name" file in each slot directory // void M_ReadSaveStrings(void) { FILE *handle; int i; char *fname = NULL; for(i = 0; i < load_end; i++) { if(fname) Z_Free(fname); fname = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(i, "\\name")); handle = fopen(fname, "rb"); if(handle == NULL) { M_StringCopy(savegamestrings[i], EMPTYSTRING, sizeof(savegamestrings[i])); LoadMenu[i].status = 0; continue; } fread(savegamestrings[i], 1, SAVESTRINGSIZE, handle); fclose(handle); LoadMenu[i].status = 1; } if(fname) Z_Free(fname); } // // M_DrawNameChar // // haleyjd 09/22/10: [STRIFE] New function // Handler for drawing the "Name Your Character" menu. // void M_DrawNameChar(void) { int i; M_WriteText(72, 28, DEH_String("Name Your Character")); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } if (saveStringEnter) { i = M_StringWidth(savegamestrings[quickSaveSlot]); M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*quickSaveSlot,"_"); } } // // M_DoNameChar // // haleyjd 09/22/10: [STRIFE] New function // Handler for items in the "Name Your Character" menu. // void M_DoNameChar(int choice) { int map; // 20130301: clear naming character flag for 1.31 save logic if(gameversion == exe_strife_1_31) namingCharacter = false; sendsave = 1; ClearTmp(); G_WriteSaveName(choice, savegamestrings[choice]); quickSaveSlot = choice; SaveDef.lastOn = choice; ClearSlot(); FromCurr(); if(isdemoversion) map = 33; else map = 2; G_DeferedInitNew(menuskill, map); M_ClearMenus(0); } // // M_LoadGame & Cie. // void M_DrawLoad(void) { int i; V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE)); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } } // // Draw border for the savegame description // void M_DrawSaveLoadBorder(int x,int y) { int i; V_DrawPatchDirect(x - 8, y + 7, W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE)); for (i = 0;i < 24;i++) { V_DrawPatchDirect(x, y + 7, W_CacheLumpName(DEH_String("M_LSCNTR"), PU_CACHE)); x += 8; } V_DrawPatchDirect(x, y + 7, W_CacheLumpName(DEH_String("M_LSRGHT"), PU_CACHE)); } // // User wants to load this game // void M_LoadSelect(int choice) { // [STRIFE]: completely rewritten char *name = NULL; G_WriteSaveName(choice, savegamestrings[choice]); ToCurr(); // use safe & portable filepath concatenation for Choco name = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(choice, "")); G_ReadCurrent(name); quickSaveSlot = choice; M_ClearMenus(0); Z_Free(name); } // // Selected from DOOM menu // // [STRIFE] Verified unmodified // void M_LoadGame (int choice) { if (netgame) { M_StartMessage(DEH_String(LOADNET), NULL, false); return; } M_SetupNextMenu(&LoadDef); M_ReadSaveStrings(); } // // M_SaveGame & Cie. // void M_DrawSave(void) { int i; V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE)); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } if (saveStringEnter) { i = M_StringWidth(savegamestrings[quickSaveSlot]); M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*quickSaveSlot,"_"); } } // // M_Responder calls this when user is finished // void M_DoSave(int slot) { // [STRIFE]: completely rewritten if(slot >= 0) { sendsave = 1; G_WriteSaveName(slot, savegamestrings[slot]); M_ClearMenus(0); quickSaveSlot = slot; // haleyjd 20130922: slight divergence. We clear the destination slot // of files here, which vanilla did not do. As a result, 1.31 had // broken save behavior to the point of unusability. fraggle agrees // this is detrimental enough to be fixed - unconditionally, for now. ClearSlot(); FromCurr(); } else M_StartMessage(DEH_String(QSAVESPOT), NULL, false); } // // User wants to save. Start string input for M_Responder // void M_SaveSelect(int choice) { // we are going to be intercepting all chars saveStringEnter = 1; // [STRIFE] quickSaveSlot = choice; //saveSlot = choice; M_StringCopy(saveOldString, savegamestrings[choice], sizeof(saveOldString)); if (!strcmp(savegamestrings[choice],EMPTYSTRING)) savegamestrings[choice][0] = 0; saveCharIndex = strlen(savegamestrings[choice]); } // // Selected from DOOM menu // void M_SaveGame (int choice) { // [STRIFE] if (netgame) { // haleyjd 20110211: Hooray for Rogue's awesome multiplayer support... M_StartMessage(DEH_String("You can't save a netgame"), NULL, false); return; } if (!usergame) { M_StartMessage(DEH_String(SAVEDEAD),NULL,false); return; } if (gamestate != GS_LEVEL) return; // [STRIFE] if(gameversion == exe_strife_1_31) { // haleyjd 20130301: in 1.31, we can choose a slot again. M_SetupNextMenu(&SaveDef); M_ReadSaveStrings(); } else { // In 1.2 and lower, you save over your character slot exclusively M_ReadSaveStrings(); M_DoSave(quickSaveSlot); } } // // M_QuickSave // char tempstring[80]; void M_QuickSaveResponse(int key) { if (key == key_menu_confirm) { M_DoSave(quickSaveSlot); S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound } } void M_QuickSave(void) { if (netgame) { // haleyjd 20110211 [STRIFE]: More fun... M_StartMessage(DEH_String("You can't save a netgame"), NULL, false); return; } if (!usergame) { S_StartSound(NULL, sfx_oof); return; } if (gamestate != GS_LEVEL) return; if (quickSaveSlot < 0) { M_StartControlPanel(); M_ReadSaveStrings(); M_SetupNextMenu(&SaveDef); quickSaveSlot = -2; // means to pick a slot now return; } DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickSaveResponse,true); } // // M_QuickLoadResponse // void M_QuickLoadResponse(int key) { if (key == key_menu_confirm) { M_LoadSelect(quickSaveSlot); S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound } } // // M_QuickLoad // // [STRIFE] Verified unmodified // void M_QuickLoad(void) { if (netgame) { M_StartMessage(DEH_String(QLOADNET),NULL,false); return; } if (quickSaveSlot < 0) { M_StartMessage(DEH_String(QSAVESPOT),NULL,false); return; } DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickLoadResponse,true); } // // Read This Menus // Had a "quick hack to fix romero bug" // haleyjd 08/28/10: [STRIFE] Draw HELP1, unconditionally. // void M_DrawReadThis1(void) { inhelpscreens = true; V_DrawPatchDirect (0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE)); } // // Read This Menus // haleyjd 08/28/10: [STRIFE] Not optional, draws HELP2 // void M_DrawReadThis2(void) { inhelpscreens = true; V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP2"), PU_CACHE)); } // // Read This Menus // haleyjd 08/28/10: [STRIFE] New function to draw HELP3. // void M_DrawReadThis3(void) { inhelpscreens = true; V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP3"), PU_CACHE)); } // // Change Sfx & Music volumes // // haleyjd 08/29/10: [STRIFE] // * Changed title graphic coordinates // * Added voice volume and sensitivity sliders // void M_DrawSound(void) { V_DrawPatchDirect (100, 10, W_CacheLumpName(DEH_String("M_SVOL"), PU_CACHE)); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1), 16,sfxVolume); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1), 16,musicVolume); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(voice_vol+1), 16,voiceVolume); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_mouse+1), 16,mouseSensitivity); } void M_Sound(int choice) { M_SetupNextMenu(&SoundDef); } void M_SfxVol(int choice) { switch(choice) { case 0: if (sfxVolume) sfxVolume--; break; case 1: if (sfxVolume < 15) sfxVolume++; break; } S_SetSfxVolume(sfxVolume * 8); } // // M_VoiceVol // // haleyjd 08/29/10: [STRIFE] New function // Sets voice volume level. // void M_VoiceVol(int choice) { switch(choice) { case 0: if (voiceVolume) voiceVolume--; break; case 1: if (voiceVolume < 15) voiceVolume++; break; } S_SetVoiceVolume(voiceVolume * 8); } void M_MusicVol(int choice) { switch(choice) { case 0: if (musicVolume) musicVolume--; break; case 1: if (musicVolume < 15) musicVolume++; break; } S_SetMusicVolume(musicVolume * 8); } // // M_DrawMainMenu // // haleyjd 08/27/10: [STRIFE] Changed x coordinate; M_DOOM -> M_STRIFE // void M_DrawMainMenu(void) { V_DrawPatchDirect(84, 2, W_CacheLumpName(DEH_String("M_STRIFE"), PU_CACHE)); } // // M_NewGame // // haleyjd 08/31/10: [STRIFE] Changed M_NEWG -> M_NGAME // void M_DrawNewGame(void) { V_DrawPatchDirect(96, 14, W_CacheLumpName(DEH_String("M_NGAME"), PU_CACHE)); V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_SKILL"), PU_CACHE)); } void M_NewGame(int choice) { if (netgame && !demoplayback) { M_StartMessage(DEH_String(NEWGAME),NULL,false); return; } // haleyjd 09/07/10: [STRIFE] Removed Chex Quest and DOOM gamemodes if(gameversion == exe_strife_1_31) namingCharacter = true; // for 1.31 save logic M_SetupNextMenu(&NewDef); } // // M_Episode // // haleyjd: [STRIFE] Unused /* int epi; void M_DrawEpisode(void) { V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE)); } void M_VerifyNightmare(int key) { if (key != key_menu_confirm) return; G_DeferedInitNew(nightmare, 1); M_ClearMenus (0); } */ void M_ChooseSkill(int choice) { // haleyjd 09/07/10: Removed nightmare confirmation // [STRIFE]: start "Name Your Character" menu menuskill = choice; currentMenu = &NameCharDef; itemOn = NameCharDef.lastOn; M_ReadSaveStrings(); } /* // haleyjd [STRIFE] Unused void M_Episode(int choice) { if ( (gamemode == shareware) && choice) { M_StartMessage(DEH_String(SWSTRING),NULL,false); M_SetupNextMenu(&ReadDef1); return; } // Yet another hack... if ( (gamemode == registered) && (choice > 2)) { fprintf( stderr, "M_Episode: 4th episode requires UltimateDOOM\n"); choice = 0; } epi = choice; M_SetupNextMenu(&NewDef); } */ // // M_Options // char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"}; char msgNames[2][9] = {"M_MSGOFF","M_MSGON"}; void M_DrawOptions(void) { // haleyjd 08/27/10: [STRIFE] M_OPTTTL -> M_OPTION V_DrawPatchDirect(108, 15, W_CacheLumpName(DEH_String("M_OPTION"), PU_CACHE)); // haleyjd 08/26/10: [STRIFE] Removed messages, sensitivity, detail. M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1), 9,screenSize); } void M_Options(int choice) { M_SetupNextMenu(&OptionsDef); } // // M_AutoUseHealth // // [STRIFE] New function // haleyjd 20110211: toggle autouse health state // void M_AutoUseHealth(void) { if(!netgame && usergame) { players[consoleplayer].cheats ^= CF_AUTOHEALTH; if(players[consoleplayer].cheats & CF_AUTOHEALTH) players[consoleplayer].message = DEH_String("Auto use health ON"); else players[consoleplayer].message = DEH_String("Auto use health OFF"); } } // // M_ChangeShowText // // [STRIFE] New function // void M_ChangeShowText(void) { dialogshowtext ^= true; if(dialogshowtext) players[consoleplayer].message = DEH_String("Conversation Text On"); else players[consoleplayer].message = DEH_String("Conversation Text Off"); } // // Toggle messages on/off // // [STRIFE] Messages cannot be disabled in Strife /* void M_ChangeMessages(int choice) { // warning: unused parameter `int choice' choice = 0; showMessages = 1 - showMessages; if (!showMessages) players[consoleplayer].message = DEH_String(MSGOFF); else players[consoleplayer].message = DEH_String(MSGON); message_dontfuckwithme = true; } */ // // M_EndGame // void M_EndGameResponse(int key) { if (key != key_menu_confirm) return; currentMenu->lastOn = itemOn; M_ClearMenus (0); D_StartTitle (); } void M_EndGame(int choice) { choice = 0; if (!usergame) { S_StartSound(NULL,sfx_oof); return; } if (netgame) { M_StartMessage(DEH_String(NETEND),NULL,false); return; } M_StartMessage(DEH_String(ENDGAME),M_EndGameResponse,true); } // // M_ReadThis // void M_ReadThis(int choice) { choice = 0; M_SetupNextMenu(&ReadDef1); } // // M_ReadThis2 // // haleyjd 08/28/10: [STRIFE] Eliminated DOOM stuff. // void M_ReadThis2(int choice) { choice = 0; M_SetupNextMenu(&ReadDef2); } // // M_ReadThis3 // // haleyjd 08/28/10: [STRIFE] New function. // void M_ReadThis3(int choice) { choice = 0; M_SetupNextMenu(&ReadDef3); } /* // haleyjd 08/28/10: [STRIFE] Not used. void M_FinishReadThis(int choice) { choice = 0; M_SetupNextMenu(&MainDef); } */ #if 0 extern void F_StartCast(void); // // M_CheckStartCast // // [STRIFE] New but unused function. Was going to start a cast // call from within the menu system... not functional even in // the earliest demo version. // void M_CheckStartCast() { if(usergame) { M_StartMessage(DEH_String("You have to end your game first."), NULL, false); return; } F_StartCast(); M_ClearMenus(0); } #endif // // M_QuitResponse // // haleyjd 09/11/10: [STRIFE] Modifications to start up endgame // demosequence. // void M_QuitResponse(int key) { char buffer[20]; if (key != key_menu_confirm) return; if(netgame) I_Quit(); else { DEH_snprintf(buffer, sizeof(buffer), "qfmrm%i", gametic % 8 + 1); I_StartVoice(buffer); D_QuitGame(); } } /* // haleyjd 09/11/10: [STRIFE] Unused static char *M_SelectEndMessage(void) { } */ // // M_QuitStrife // // [STRIFE] Renamed from M_QuitDOOM // haleyjd 09/11/10: No randomized text message; that's taken care of // by the randomized voice message after confirmation. // void M_QuitStrife(int choice) { DEH_snprintf(endstring, sizeof(endstring), "Do you really want to leave?\n\n" DOSY); M_StartMessage(endstring, M_QuitResponse, true); } void M_ChangeSensitivity(int choice) { switch(choice) { case 0: if (mouseSensitivity) mouseSensitivity--; break; case 1: if (mouseSensitivity < 9) mouseSensitivity++; break; } } /* // haleyjd [STRIFE] Unused void M_ChangeDetail(int choice) { choice = 0; detailLevel = 1 - detailLevel; R_SetViewSize (screenblocks, detailLevel); if (!detailLevel) players[consoleplayer].message = DEH_String(DETAILHI); else players[consoleplayer].message = DEH_String(DETAILLO); } */ // [STRIFE] Verified unmodified void M_SizeDisplay(int choice) { switch(choice) { case 0: if (screenSize > 0) { screenblocks--; screenSize--; } break; case 1: if (screenSize < 8) { screenblocks++; screenSize++; } break; } R_SetViewSize (screenblocks, detailLevel); } // // Menu Functions // // // M_DrawThermo // // haleyjd 08/28/10: [STRIFE] Changes to some patch coordinates. // void M_DrawThermo ( int x, int y, int thermWidth, int thermDot ) { int xx; int yy; // [STRIFE] Needs a temp y coordinate variable int i; xx = x; yy = y + 6; // [STRIFE] +6 to y coordinate V_DrawPatchDirect(xx, yy, W_CacheLumpName(DEH_String("M_THERML"), PU_CACHE)); xx += 8; for (i=0;ix - 10, menu->y + item * LINEHEIGHT - 1, W_CacheLumpName(DEH_String("M_CELL1"), PU_CACHE)); } void M_DrawSelCell ( menu_t* menu, int item ) { V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1, W_CacheLumpName(DEH_String("M_CELL2"), PU_CACHE)); } void M_StartMessage ( char* string, void* routine, boolean input ) { messageLastMenuActive = menuactive; messageToPrint = 1; messageString = string; messageRoutine = routine; messageNeedsInput = input; menuactive = true; return; } void M_StopMessage(void) { menuactive = messageLastMenuActive; messageToPrint = 0; } // // Find string width from hu_font chars // int M_StringWidth(char* string) { size_t i; int w = 0; int c; for (i = 0;i < strlen(string);i++) { c = toupper(string[i]) - HU_FONTSTART; if (c < 0 || c >= HU_FONTSIZE) w += 4; else w += SHORT (hu_font[c]->width); } return w; } // // Find string height from hu_font chars // int M_StringHeight(char* string) { size_t i; int h; int height = SHORT(hu_font[0]->height); h = height; for (i = 0;i < strlen(string);i++) if (string[i] == '\n') h += height; return h; } // // M_WriteText // // Write a string using the hu_font // haleyjd 09/04/10: [STRIFE] // * Rogue made a lot of changes to this for the dialog system. // int M_WriteText ( int x, int y, const char* string) // haleyjd: made const for safety w/dialog engine { int w; const char* ch; int c; int cx; int cy; ch = string; cx = x; cy = y; while(1) { c = *ch++; if (!c) break; // haleyjd 09/04/10: [STRIFE] Don't draw spaces at the start of lines. if(c == ' ' && cx == x) continue; if (c == '\n') { cx = x; cy += 11; // haleyjd 09/04/10: [STRIFE]: Changed 12 -> 11 continue; } c = toupper(c) - HU_FONTSTART; if (c < 0 || c>= HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c]->width); // haleyjd 09/04/10: [STRIFE] Different linebreak handling if (cx + w > SCREENWIDTH - 20) { cx = x; cy += 11; --ch; } else { V_DrawPatchDirect(cx, cy, hu_font[c]); cx += w; } } // [STRIFE] Return final y coordinate. return cy + 12; } // // M_DialogDimMsg // // [STRIFE] New function // haleyjd 09/04/10: Painstakingly transformed from the assembly code, as the // decompiler could not touch it. Redimensions a string to fit on screen, leaving // at least a 20 pixel margin on the right side. The string passed in must be // writable. // void M_DialogDimMsg(int x, int y, char *str, boolean useyfont) { int rightbound = (SCREENWIDTH - 20) - x; patch_t **fontarray; // ebp int linewidth = 0; // esi int i = 0; // edx char *message = str; // edi char bl; // bl if(useyfont) fontarray = yfont; else fontarray = hu_font; bl = toupper(*message); if(!bl) return; // outer loop - run to end of string do { if(bl != '\n') { int charwidth; // eax int tempwidth; // ecx if(bl < HU_FONTSTART || bl > HU_FONTEND) charwidth = 4; else charwidth = SHORT(fontarray[bl - HU_FONTSTART]->width); tempwidth = linewidth + charwidth; // Test if the line still fits within the boundary... if(tempwidth >= rightbound) { // Doesn't fit... char *tempptr = &message[i]; // ebx char al; // al // inner loop - run backward til a space (or the start of the // string) is found, subtracting width off the current line. // BUG: shouldn't we stop at a previous '\n' too? while(*tempptr != ' ' && i > 0) { tempptr--; // BUG: they didn't add the first char to linewidth yet... linewidth -= charwidth; i--; al = toupper(*tempptr); if(al < HU_FONTSTART || al > HU_FONTEND) charwidth = 4; else charwidth = SHORT(fontarray[al - HU_FONTSTART]->width); } // Replace the space with a linebreak. // BUG: what if i is zero? ... infinite loop time! message[i] = '\n'; linewidth = 0; } else { // The line does fit. // Spaces at the start of a line don't count though. if(!(bl == ' ' && linewidth == 0)) linewidth += charwidth; } } else linewidth = 0; // '\n' seen, so reset the line width } while((bl = toupper(message[++i])) != 0); // step to the next character } // These keys evaluate to a "null" key in Vanilla Doom that allows weird // jumping in the menus. Preserve this behavior for accuracy. static boolean IsNullKey(int key) { return key == KEY_PAUSE || key == KEY_CAPSLOCK || key == KEY_SCRLCK || key == KEY_NUMLOCK; } // // CONTROL PANEL // // // M_Responder // boolean M_Responder (event_t* ev) { int ch; int key; int i; static int joywait = 0; static int mousewait = 0; static int mousey = 0; static int lasty = 0; static int mousex = 0; static int lastx = 0; // In testcontrols mode, none of the function keys should do anything // - the only key is escape to quit. if (testcontrols) { if (ev->type == ev_quit || (ev->type == ev_keydown && (ev->data1 == key_menu_activate || ev->data1 == key_menu_quit))) { I_Quit(); return true; } return false; } // "close" button pressed on window? if (ev->type == ev_quit) { // First click on close button = bring up quit confirm message. // Second click on close button = confirm quit if (menuactive && messageToPrint && messageRoutine == M_QuitResponse) { M_QuitResponse(key_menu_confirm); } else { S_StartSound(NULL, sfx_swtchn); M_QuitStrife(0); } return true; } // key is the key pressed, ch is the actual character typed ch = 0; key = -1; if (ev->type == ev_joystick && joywait < I_GetTime()) { if (ev->data3 < 0) { key = key_menu_up; joywait = I_GetTime() + 5; } else if (ev->data3 > 0) { key = key_menu_down; joywait = I_GetTime() + 5; } if (ev->data2 < 0) { key = key_menu_left; joywait = I_GetTime() + 2; } else if (ev->data2 > 0) { key = key_menu_right; joywait = I_GetTime() + 2; } if (ev->data1&1) { key = key_menu_forward; joywait = I_GetTime() + 5; } if (ev->data1&2) { key = key_menu_back; joywait = I_GetTime() + 5; } if (joybmenu >= 0 && (ev->data1 & (1 << joybmenu)) != 0) { key = key_menu_activate; joywait = I_GetTime() + 5; } } else { if (ev->type == ev_mouse && mousewait < I_GetTime()) { mousey += ev->data3; if (mousey < lasty-30) { key = key_menu_down; mousewait = I_GetTime() + 5; mousey = lasty -= 30; } else if (mousey > lasty+30) { key = key_menu_up; mousewait = I_GetTime() + 5; mousey = lasty += 30; } mousex += ev->data2; if (mousex < lastx-30) { key = key_menu_left; mousewait = I_GetTime() + 5; mousex = lastx -= 30; } else if (mousex > lastx+30) { key = key_menu_right; mousewait = I_GetTime() + 5; mousex = lastx += 30; } if (ev->data1&1) { key = key_menu_forward; mousewait = I_GetTime() + 15; mouse_fire_countdown = 5; // villsa [STRIFE] } if (ev->data1&2) { key = key_menu_back; mousewait = I_GetTime() + 15; } } else { if (ev->type == ev_keydown) { key = ev->data1; ch = ev->data2; } } } if (key == -1) return false; // Save Game string input if (saveStringEnter) { switch(key) { case KEY_BACKSPACE: if (saveCharIndex > 0) { saveCharIndex--; savegamestrings[quickSaveSlot][saveCharIndex] = 0; } break; case KEY_ESCAPE: saveStringEnter = 0; M_StringCopy(savegamestrings[quickSaveSlot], saveOldString, sizeof(savegamestrings[quickSaveSlot])); break; case KEY_ENTER: // [STRIFE] saveStringEnter = 0; if(gameversion == exe_strife_1_31 && !namingCharacter) { // In 1.31, we can be here as a result of normal saving again, // whereas in 1.2 this only ever happens when naming your // character to begin a new game. M_DoSave(quickSaveSlot); return true; } if (savegamestrings[quickSaveSlot][0]) M_DoNameChar(quickSaveSlot); break; default: // This is complicated. // Vanilla has a bug where the shift key is ignored when entering // a savegame name. If vanilla_keyboard_mapping is on, we want // to emulate this bug by using 'data1'. But if it's turned off, // it implies the user doesn't care about Vanilla emulation: just // use the correct 'data2'. if (vanilla_keyboard_mapping) { ch = key; } ch = toupper(ch); if (ch != ' ' && (ch - HU_FONTSTART < 0 || ch - HU_FONTSTART >= HU_FONTSIZE)) { break; } if (ch >= 32 && ch <= 127 && saveCharIndex < SAVESTRINGSIZE-1 && M_StringWidth(savegamestrings[quickSaveSlot]) < (SAVESTRINGSIZE-2)*8) { savegamestrings[quickSaveSlot][saveCharIndex++] = ch; savegamestrings[quickSaveSlot][saveCharIndex] = 0; } break; } return true; } // Take care of any messages that need input if (messageToPrint) { if (messageNeedsInput) { if (key != ' ' && key != KEY_ESCAPE && key != key_menu_confirm && key != key_menu_abort) { return false; } } menuactive = messageLastMenuActive; messageToPrint = 0; if (messageRoutine) messageRoutine(key); menupause = false; // [STRIFE] unpause menuactive = false; S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound return true; } // [STRIFE]: // * In v1.2 this is moved to F9 (quickload) // * In v1.31 it is moved to F12 with DM spy, and quicksave // functionality is restored separate from normal saving /* if (devparm && key == key_menu_help) { G_ScreenShot (); return true; } */ // F-Keys if (!menuactive) { if (key == key_menu_decscreen) // Screen size down { if (automapactive || chat_on) return false; M_SizeDisplay(0); S_StartSound(NULL, sfx_stnmov); return true; } else if (key == key_menu_incscreen) // Screen size up { if (automapactive || chat_on) return false; M_SizeDisplay(1); S_StartSound(NULL, sfx_stnmov); return true; } else if (key == key_menu_help) // Help key { M_StartControlPanel (); // haleyjd 08/29/10: [STRIFE] always ReadDef1 currentMenu = &ReadDef1; itemOn = 0; S_StartSound(NULL, sfx_swtchn); return true; } else if (key == key_menu_save) // Save { // [STRIFE]: Hub saves if(gameversion == exe_strife_1_31) namingCharacter = false; // just saving normally, in 1.31 if(netgame || players[consoleplayer].health <= 0 || players[consoleplayer].cheats & CF_ONFIRE) { S_StartSound(NULL, sfx_oof); } else { M_StartControlPanel(); S_StartSound(NULL, sfx_swtchn); M_SaveGame(0); } return true; } else if (key == key_menu_load) // Load { // [STRIFE]: Hub saves if(gameversion == exe_strife_1_31) { // 1.31: normal save loading namingCharacter = false; M_StartControlPanel(); M_LoadGame(0); S_StartSound(NULL, sfx_swtchn); } else { // Pre 1.31: quickload only S_StartSound(NULL, sfx_swtchn); M_QuickLoad(); } return true; } else if (key == key_menu_volume) // Sound Volume { M_StartControlPanel (); currentMenu = &SoundDef; itemOn = sfx_vol; S_StartSound(NULL, sfx_swtchn); return true; } else if (key == key_menu_detail) // Detail toggle { //M_ChangeDetail(0); M_AutoUseHealth(); // [STRIFE] S_StartSound(NULL, sfx_swtchn); return true; } else if (key == key_menu_qsave) // Quicksave { // [STRIFE]: Hub saves if(gameversion == exe_strife_1_31) namingCharacter = false; // for 1.31 save changes if(netgame || players[consoleplayer].health <= 0 || players[consoleplayer].cheats & CF_ONFIRE) { S_StartSound(NULL, sfx_oof); } else { S_StartSound(NULL, sfx_swtchn); M_QuickSave(); } return true; } else if (key == key_menu_endgame) // End game { S_StartSound(NULL, sfx_swtchn); M_EndGame(0); return true; } else if (key == key_menu_messages) // Toggle messages { //M_ChangeMessages(0); M_ChangeShowText(); // [STRIFE] S_StartSound(NULL, sfx_swtchn); return true; } else if (key == key_menu_qload) // Quickload { // [STRIFE] // * v1.2: takes a screenshot // * v1.31: does quickload again if(gameversion == exe_strife_1_31) { namingCharacter = false; S_StartSound(NULL, sfx_swtchn); M_QuickLoad(); } else G_ScreenShot(); return true; } else if (key == key_menu_quit) // Quit DOOM { S_StartSound(NULL, sfx_swtchn); M_QuitStrife(0); return true; } else if (key == key_menu_gamma) // gamma toggle { usegamma++; if (usegamma > 4) usegamma = 0; players[consoleplayer].message = DEH_String(gammamsg[usegamma]); I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE)); return true; } else if(gameversion == exe_strife_1_31 && key == key_spy) { // haleyjd 20130301: 1.31 moved screenshots to F12. G_ScreenShot(); return true; } else if (key != 0 && key == key_menu_screenshot) { G_ScreenShot(); return true; } } // Pop-up menu? if (!menuactive) { if (key == key_menu_activate) { M_StartControlPanel (); S_StartSound(NULL, sfx_swtchn); return true; } return false; } // Keys usable within menu if (key == key_menu_down) { // Move down to next item do { if (itemOn+1 > currentMenu->numitems-1) itemOn = 0; else itemOn++; S_StartSound(NULL, sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); return true; } else if (key == key_menu_up) { // Move back up to previous item do { if (!itemOn) itemOn = currentMenu->numitems-1; else itemOn--; S_StartSound(NULL, sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); return true; } else if (key == key_menu_left) { // Slide slider left if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { S_StartSound(NULL, sfx_stnmov); currentMenu->menuitems[itemOn].routine(0); } return true; } else if (key == key_menu_right) { // Slide slider right if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { S_StartSound(NULL, sfx_stnmov); currentMenu->menuitems[itemOn].routine(1); } return true; } else if (key == key_menu_forward) { // Activate menu item if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status) { currentMenu->lastOn = itemOn; if (currentMenu->menuitems[itemOn].status == 2) { currentMenu->menuitems[itemOn].routine(1); // right arrow S_StartSound(NULL, sfx_stnmov); } else { currentMenu->menuitems[itemOn].routine(itemOn); //S_StartSound(NULL, sfx_swish); [STRIFE] No sound is played here. } } return true; } else if (key == key_menu_activate) { // Deactivate menu if(gameversion == exe_strife_1_31) // [STRIFE]: 1.31 saving namingCharacter = false; if(menuindialog) // [STRIFE] - Get out of dialog engine semi-gracefully P_DialogDoChoice(-1); currentMenu->lastOn = itemOn; M_ClearMenus (0); S_StartSound(NULL, sfx_mtalht); // villsa [STRIFE]: sounds return true; } else if (key == key_menu_back) { // Go back to previous menu currentMenu->lastOn = itemOn; if (currentMenu->prevMenu) { currentMenu = currentMenu->prevMenu; itemOn = currentMenu->lastOn; S_StartSound(NULL, sfx_swtchn); } return true; } // Keyboard shortcut? // Vanilla Strife has a weird behavior where it jumps to the scroll bars // when certain keys are pressed, so emulate this. else if (ch != 0 || IsNullKey(key)) { // Keyboard shortcut? for (i = itemOn+1;i < currentMenu->numitems;i++) { if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL, sfx_pstop); return true; } } for (i = 0;i <= itemOn;i++) { if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL, sfx_pstop); return true; } } } return false; } // // M_StartControlPanel // void M_StartControlPanel (void) { // intro might call this repeatedly if (menuactive) return; menuactive = 1; menupause = true; currentMenu = &MainDef; // JDC itemOn = currentMenu->lastOn; // JDC } // // M_Drawer // Called after the view has been rendered, // but before it has been blitted. // void M_Drawer (void) { static short x; static short y; unsigned int i; unsigned int max; char string[80]; char *name; int start; inhelpscreens = false; // Horiz. & Vertically center string and print it. if (messageToPrint) { start = 0; y = 100 - M_StringHeight(messageString) / 2; while (messageString[start] != '\0') { int foundnewline = 0; for (i = 0; i < strlen(messageString + start); i++) { if (messageString[start + i] == '\n') { M_StringCopy(string, messageString + start, sizeof(string)); if (i < sizeof(string)) { string[i] = '\0'; } foundnewline = 1; start += i + 1; break; } } if (!foundnewline) { M_StringCopy(string, messageString + start, sizeof(string)); start += strlen(string); } x = 160 - M_StringWidth(string) / 2; M_WriteText(x, y, string); y += SHORT(hu_font[0]->height); } return; } if (!menuactive) return; if (currentMenu->routine) currentMenu->routine(); // call Draw routine // DRAW MENU x = currentMenu->x; y = currentMenu->y; max = currentMenu->numitems; for (i=0;imenuitems[i].name); if (name[0]) { V_DrawPatchDirect (x, y, W_CacheLumpName(name, PU_CACHE)); } y += LINEHEIGHT; } // haleyjd 08/27/10: [STRIFE] Adjust to draw spinning Sigil // DRAW SIGIL V_DrawPatchDirect(x + CURSORXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT, W_CacheLumpName(DEH_String(cursorName[whichCursor]), PU_CACHE)); } // // M_ClearMenus // // haleyjd 08/28/10: [STRIFE] Added an int param so this can be called by menus. // 09/08/10: Added menupause. // void M_ClearMenus (int choice) { choice = 0; // haleyjd: for no warning; not from decompilation. menuactive = 0; menupause = 0; } // // M_SetupNextMenu // void M_SetupNextMenu(menu_t *menudef) { currentMenu = menudef; itemOn = currentMenu->lastOn; } // // M_Ticker // // haleyjd 08/27/10: [STRIFE] Rewritten for Sigil cursor // void M_Ticker (void) { if (--cursorAnimCounter <= 0) { whichCursor = (whichCursor + 1) % 8; cursorAnimCounter = 5; } } // // M_Init // // haleyjd 08/27/10: [STRIFE] Removed DOOM gamemode stuff // void M_Init (void) { currentMenu = &MainDef; menuactive = 0; itemOn = currentMenu->lastOn; whichCursor = 0; cursorAnimCounter = 10; screenSize = screenblocks - 3; messageToPrint = 0; messageString = NULL; messageLastMenuActive = menuactive; // STRIFE-FIXME: assigns 0 here... quickSaveSlot = -1; // [STRIFE]: Initialize savegame paths and clear temporary directory G_WriteSaveName(5, "ME"); ClearTmp(); // Here we could catch other version dependencies, // like HELP1/2, and four episodes. } chocolate-doom-chocolate-doom-2.2.1/src/strife/m_menu.h000066400000000000000000000047461257432200600230340ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Menu widget stuff, episode selection and such. // #ifndef __M_MENU__ #define __M_MENU__ #include "d_event.h" // // MENU TYPEDEFS // // haleyjd 09/04/10: [STRIFE] Made external typedef struct { // 0 = no cursor here, 1 = ok, 2 = arrows ok short status; char name[10]; // choice = menu item #. // if status = 2, // choice=0:leftarrow,1:rightarrow void (*routine)(int choice); // hotkey in menu char alphaKey; } menuitem_t; typedef struct menu_s { short numitems; // # of menu items struct menu_s* prevMenu; // previous menu menuitem_t* menuitems; // menu items void (*routine)(); // draw routine short x; short y; // x,y of menu short lastOn; // last item user was on in menu } menu_t; extern menu_t* currentMenu; // villsa [STRIFE] made external extern short itemOn; // // MENUS // // Called by main loop, // saves config file and calls I_Quit when user exits. // Even when the menu is not displayed, // this can resize the view and change game parameters. // Does all the real work of the menu interaction. boolean M_Responder (event_t *ev); // Called by main loop, // only used for menu (skull cursor) animation. void M_Ticker (void); // Called by main loop, // draws the menus directly into the screen buffer. void M_Drawer (void); // Called by D_DoomMain, // loads the config file. void M_Init (void); // Called by intro code to force menu up upon a keypress, // does nothing if menu is already up. void M_StartControlPanel (void); // haleyjd 09/04/10: Externalized. Draws menu text. int M_WriteText(int x, int y, const char *string); // haleyjd 09/04/10: [STRIFE] New function. void M_DialogDimMsg(int x, int y, char *str, boolean useyfont); // haleyjd [STRIFE] Externalized void M_ClearMenus (int choice); void M_LoadSelect(int choice); extern int detailLevel; extern int screenblocks; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/m_random.c000066400000000000000000000047571257432200600233450ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Random number LUT. // #include #include "m_random.h" // // M_Random // Returns a 0-255 number // static const unsigned char rndtable[256] = { 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 , 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 , 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 , 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 , 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 , 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 , 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 , 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 , 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 , 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 , 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 , 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 , 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 , 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 , 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 , 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 , 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 , 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 , 120, 163, 236, 249 }; int rndindex = 0; int prndindex = 0; // Which one is deterministic? int P_Random (void) { prndindex = (prndindex+1)&0xff; return rndtable[prndindex]; } int M_Random (void) { rndindex = (rndindex+1)&0xff; return rndtable[rndindex]; } // // M_ClearRandom // // haleyjd 20110204 [STRIFE]: No "seeding" of M_Random index // void M_ClearRandom (void) { prndindex = 0; rndindex = 0; } chocolate-doom-chocolate-doom-2.2.1/src/strife/m_random.h000066400000000000000000000016151257432200600233400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __M_RANDOM__ #define __M_RANDOM__ #include "doomtype.h" // Returns a number from 0 to 255, // from a lookup table. int M_Random (void); // As M_Random, but used only by the play simulation. int P_Random (void); // Fix randoms for demos. void M_ClearRandom (void); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/m_saves.c000066400000000000000000000325721257432200600232020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2010 James Haley, Samuel Villarreal // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // [STRIFE] New Module // // Strife Hub Saving Code // // For GNU C and POSIX targets, dirent.h should be available. Otherwise, for // Visual C++, we need to include the win_opendir module. #if defined(_MSC_VER) #include #elif defined(__GNUC__) || defined(POSIX) #include #else #error Need an include for dirent.h! #endif #include #include #include #include "z_zone.h" #include "i_system.h" #include "d_player.h" #include "deh_str.h" #include "doomstat.h" #include "m_misc.h" #include "m_saves.h" #include "p_dialog.h" // // File Paths // // Strife maintains multiple file paths related to savegames. // char *savepath; // The actual path of the selected saveslot char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg) char *loadpath; // Path used while loading the game char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot // // ClearTmp // // Clear the temporary save directory // void ClearTmp(void) { DIR *sp2dir = NULL; struct dirent *f = NULL; if(savepathtemp == NULL) I_Error("you fucked up savedir man!"); if(!(sp2dir = opendir(savepathtemp))) I_Error("ClearTmp: Couldn't open dir %s", savepathtemp); while((f = readdir(sp2dir))) { char *filepath = NULL; // haleyjd: skip "." and ".." without assuming they're the // first two entries like the original code did. if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, "..")) continue; // haleyjd: use M_SafeFilePath, not sprintf filepath = M_SafeFilePath(savepathtemp, f->d_name); remove(filepath); Z_Free(filepath); } closedir(sp2dir); } // // ClearSlot // // Clear a single save slot folder // void ClearSlot(void) { DIR *spdir = NULL; struct dirent *f = NULL; if(savepath == NULL) I_Error("userdir is fucked up man!"); if(!(spdir = opendir(savepath))) I_Error("ClearSlot: Couldn't open dir %s", savepath); while((f = readdir(spdir))) { char *filepath = NULL; if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, "..")) continue; // haleyjd: use M_SafeFilePath, not sprintf filepath = M_SafeFilePath(savepath, f->d_name); remove(filepath); Z_Free(filepath); } closedir(spdir); } // // FromCurr // // Copying files from savepathtemp to savepath // void FromCurr(void) { DIR *sp2dir = NULL; struct dirent *f = NULL; if(!(sp2dir = opendir(savepathtemp))) I_Error("FromCurr: Couldn't open dir %s", savepathtemp); while((f = readdir(sp2dir))) { byte *filebuffer = NULL; int filelen = 0; char *srcfilename = NULL; char *dstfilename = NULL; // haleyjd: skip "." and ".." without assuming they're the // first two entries like the original code did. if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, "..")) continue; // haleyjd: use M_SafeFilePath, NOT sprintf. srcfilename = M_SafeFilePath(savepathtemp, f->d_name); dstfilename = M_SafeFilePath(savepath, f->d_name); filelen = M_ReadFile(srcfilename, &filebuffer); M_WriteFile(dstfilename, filebuffer, filelen); Z_Free(filebuffer); Z_Free(srcfilename); Z_Free(dstfilename); } closedir(sp2dir); } // // ToCurr // // Copying files from savepath to savepathtemp // void ToCurr(void) { DIR *spdir = NULL; struct dirent *f = NULL; ClearTmp(); // BUG: Rogue copypasta'd this error message, which is why we don't know // the real original name of this function. if(!(spdir = opendir(savepath))) I_Error("ClearSlot: Couldn't open dir %s", savepath); while((f = readdir(spdir))) { byte *filebuffer = NULL; int filelen = 0; char *srcfilename = NULL; char *dstfilename = NULL; if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, "..")) continue; // haleyjd: use M_SafeFilePath, NOT sprintf. srcfilename = M_SafeFilePath(savepath, f->d_name); dstfilename = M_SafeFilePath(savepathtemp, f->d_name); filelen = M_ReadFile(srcfilename, &filebuffer); M_WriteFile(dstfilename, filebuffer, filelen); Z_Free(filebuffer); Z_Free(srcfilename); Z_Free(dstfilename); } closedir(spdir); } // // M_SaveMoveMapToHere // // Moves a map to the "HERE" save. // void M_SaveMoveMapToHere(void) { char *mapsave = NULL; char *heresave = NULL; char tmpnum[33]; // haleyjd: no itoa available... M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap); // haleyjd: use M_SafeFilePath, not sprintf mapsave = M_SafeFilePath(savepath, tmpnum); heresave = M_SafeFilePath(savepath, "here"); // haleyjd: use M_FileExists, not access if(M_FileExists(mapsave)) { remove(heresave); rename(mapsave, heresave); } Z_Free(mapsave); Z_Free(heresave); } // // M_SaveMoveHereToMap // // Moves the "HERE" save to a map. // void M_SaveMoveHereToMap(void) { char *mapsave = NULL; char *heresave = NULL; char tmpnum[33]; // haleyjd: no itoa available... M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap); mapsave = M_SafeFilePath(savepathtemp, tmpnum); heresave = M_SafeFilePath(savepathtemp, "here"); if(M_FileExists(heresave)) { remove(mapsave); rename(heresave, mapsave); } Z_Free(mapsave); Z_Free(heresave); } // // M_SaveMisObj // // Writes the mission objective into the MIS_OBJ file. // boolean M_SaveMisObj(const char *path) { boolean result; char *destpath = NULL; // haleyjd 20110210: use M_SafeFilePath, not sprintf destpath = M_SafeFilePath(path, "mis_obj"); result = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN); Z_Free(destpath); return result; } // // M_ReadMisObj // // Reads the mission objective from the MIS_OBJ file. // void M_ReadMisObj(void) { FILE *f = NULL; char *srcpath = NULL; // haleyjd: use M_SafeFilePath, not sprintf srcpath = M_SafeFilePath(savepathtemp, "mis_obj"); if((f = fopen(srcpath, "rb"))) { fread(mission_objective, 1, OBJECTIVE_LEN, f); fclose(f); } Z_Free(srcpath); } //============================================================================= // // Original Routines // // haleyjd - None of the below code is derived from Strife itself, but has been // adapted or created in order to provide secure, portable filepath handling // for the purposes of savegame support. This is partially needed to allow for // differences in Choco due to it being multiplatform. The rest exists because // I cannot stand programming in an impoverished ANSI C environment that // calls sprintf on fixed-size buffers. :P // // // M_Calloc // // haleyjd 20110210 - original routine // Because Choco doesn't have Z_Calloc O_o // void *M_Calloc(size_t n1, size_t n2) { return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL; } // // M_StringAlloc // // haleyjd: This routine takes any number of strings and a number of extra // characters, calculates their combined length, and calls Z_Alloca to create // a temporary buffer of that size. This is extremely useful for allocation of // file paths, and is used extensively in d_main.c. The pointer returned is // to a temporary Z_Alloca buffer, which lives until the next main loop // iteration, so don't cache it. Note that this idiom is not possible with the // normal non-standard alloca function, which allocates stack space. // // [STRIFE] - haleyjd 20110210 // This routine is taken from the Eternity Engine and adapted to do without // Z_Alloca. I need secure string concatenation for filepath handling. The // only difference from use in EE is that the pointer returned in *str must // be manually freed. // int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...) { va_list args; size_t len = extra; if(numstrs < 1) I_Error("M_StringAlloc: invalid input\n"); len += strlen(str1); --numstrs; if(numstrs != 0) { va_start(args, str1); while(numstrs != 0) { const char *argstr = va_arg(args, const char *); len += strlen(argstr); --numstrs; } va_end(args); } ++len; *str = (char *)(M_Calloc(1, len)); return len; } // // M_NormalizeSlashes // // Remove trailing slashes, translate backslashes to slashes // The string to normalize is passed and returned in str // // killough 11/98: rewritten // // [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect // the DIR_SEPARATOR define used by Choco Doom. This routine originated in // BOOM. // void M_NormalizeSlashes(char *str) { char *p; // Convert all slashes/backslashes to DIR_SEPARATOR for(p = str; *p; p++) { if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR) *p = DIR_SEPARATOR; } // Remove trailing slashes while(p > str && *--p == DIR_SEPARATOR) *p = 0; // Collapse multiple slashes for(p = str; (*str++ = *p); ) if(*p++ == DIR_SEPARATOR) while(*p == DIR_SEPARATOR) p++; } // // M_SafeFilePath // // haleyjd 20110210 - original routine. // This routine performs safe, portable concatenation of a base file path // with another path component or file name. The returned string is Z_Malloc'd // and should be freed when it has exhausted its usefulness. // char *M_SafeFilePath(const char *basepath, const char *newcomponent) { int newstrlen = 0; char *newstr = NULL; if (!strcmp(basepath, "")) { basepath = "."; } // Always throw in a slash. M_NormalizeSlashes will remove it in the case // that either basepath or newcomponent includes a redundant slash at the // end or beginning respectively. newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent); M_snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent); M_NormalizeSlashes(newstr); return newstr; } // // M_CreateSaveDirs // // haleyjd 20110210: Vanilla Strife went tits-up if it didn't have the full set // of save folders which were created externally by the installer. fraggle says // that's no good for Choco purposes, and I agree, so this routine will create // the full set of folders under the configured savegamedir. // void M_CreateSaveDirs(const char *savedir) { int i; for(i = 0; i < 7; i++) { char *compositedir; // compose the full path by concatenating with savedir compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, "")); M_MakeDirectory(compositedir); Z_Free(compositedir); } } // // M_MakeStrifeSaveDir // // haleyjd 20110211: Convenience routine // char *M_MakeStrifeSaveDir(int slotnum, const char *extra) { static char tmpbuffer[32]; M_snprintf(tmpbuffer, sizeof(tmpbuffer), "strfsav%d.ssg%s", slotnum, extra); return tmpbuffer; } // // M_GetFilePath // // haleyjd: STRIFE-FIXME: Temporary? // Code borrowed from Eternity, and modified to return separator char // char M_GetFilePath(const char *fn, char *dest, size_t len) { boolean found_slash = false; char *p; char sepchar = '\0'; memset(dest, 0, len); p = dest + len - 1; M_StringCopy(dest, fn, len); while(p >= dest) { if(*p == '/' || *p == '\\') { sepchar = *p; found_slash = true; // mark that the path ended with a slash *p = '\0'; break; } *p = '\0'; p--; } // haleyjd: in the case that no slash was ever found, yet the // path string is empty, we are dealing with a file local to the // working directory. The proper path to return for such a string is // not "", but ".", since the format strings add a slash now. When // the string is empty but a slash WAS found, we really do want to // return the empty string, since the path is relative to the root. if(!found_slash && *dest == '\0') *dest = '.'; // if a separator is not found, default to forward, because Windows // supports that too. if(sepchar == '\0') sepchar = '/'; return sepchar; } // EOF chocolate-doom-chocolate-doom-2.2.1/src/strife/m_saves.h000066400000000000000000000031351257432200600232000ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2010 James Haley, Samuel Villareal // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // [STRIFE] New Module // // Strife Hub Saving Code // #ifndef M_SAVES_H__ #define M_SAVES_H__ #define CHARACTER_NAME_LEN 32 extern char *savepath; extern char *savepathtemp; extern char *loadpath; extern char character_name[CHARACTER_NAME_LEN]; // Strife Savegame Functions void ClearTmp(void); void ClearSlot(void); void FromCurr(void); void ToCurr(void); void M_SaveMoveMapToHere(void); void M_SaveMoveHereToMap(void); boolean M_SaveMisObj(const char *path); void M_ReadMisObj(void); // Custom Utilities for Filepath Handling void *M_Calloc(size_t n1, size_t n2); void M_NormalizeSlashes(char *str); int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...); char *M_SafeFilePath(const char *basepath, const char *newcomponent); char M_GetFilePath(const char *fn, char *dest, size_t len); char *M_MakeStrifeSaveDir(int slotnum, const char *extra); void M_CreateSaveDirs(const char *savedir); #endif // EOF chocolate-doom-chocolate-doom-2.2.1/src/strife/p_ceilng.c000066400000000000000000000162621257432200600233230ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Ceiling aninmation (lowering, crushing, raising) // #include "z_zone.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" // // CEILINGS // ceiling_t* activeceilings[MAXCEILINGS]; // // T_MoveCeiling // void T_MoveCeiling (ceiling_t* ceiling) { result_e res; switch(ceiling->direction) { case 0: // IN STASIS break; case 1: // UP res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false,1,ceiling->direction); if (!(leveltime&7)) { switch(ceiling->type) { case silentCrushAndRaise: break; default: S_StartSound(&ceiling->sector->soundorg, sfx_stnmov); // ? break; } } if (res == pastdest) { switch(ceiling->type) { case raiseToHighest: P_RemoveActiveCeiling(ceiling); break; case silentCrushAndRaise: S_StartSound(&ceiling->sector->soundorg, sfx_pstop); case fastCrushAndRaise: case crushAndRaise: ceiling->direction = -1; break; default: break; } } break; case -1: // DOWN res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush,1,ceiling->direction); if (!(leveltime&7)) { switch(ceiling->type) { case silentCrushAndRaise: break; default: S_StartSound(&ceiling->sector->soundorg, sfx_stnmov); } } if (res == pastdest) { switch(ceiling->type) { case silentCrushAndRaise: S_StartSound(&ceiling->sector->soundorg, sfx_pstop); case crushAndRaise: ceiling->speed = CEILSPEED; case fastCrushAndRaise: ceiling->direction = 1; break; case lowerAndCrush: case lowerToFloor: P_RemoveActiveCeiling(ceiling); break; default: break; } } else // ( res != pastdest ) { if (res == crushed) { switch(ceiling->type) { case silentCrushAndRaise: case crushAndRaise: case lowerAndCrush: ceiling->speed = CEILSPEED / 8; break; default: break; } } } break; } } // // EV_DoCeiling // Move a ceiling up/down and all around! // // haleyjd 10/04/10: [STRIFE] Changes: // * Fast crushers were made 2x as fast. // * lowerAndCrush was apparently "fixed" to actually crush, and was also // altered to lower all the way to the floor rather than remain 8 above. // * silentCrushAndRaise and crushAndRaise no longer crush. int EV_DoCeiling ( line_t* line, ceiling_e type ) { int secnum; int rtn; sector_t* sec; ceiling_t* ceiling; secnum = -1; rtn = 0; // Reactivate in-stasis ceilings...for certain types. switch(type) { case fastCrushAndRaise: case silentCrushAndRaise: case crushAndRaise: P_ActivateInStasisCeiling(line); default: break; } while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // new door thinker rtn = 1; ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); P_AddThinker (&ceiling->thinker); sec->specialdata = ceiling; ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling; ceiling->sector = sec; ceiling->crush = false; switch(type) { case fastCrushAndRaise: // [STRIFE]: Speed of fast crushers increased by 2x! ceiling->crush = true; ceiling->topheight = sec->ceilingheight; ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); ceiling->direction = -1; ceiling->speed = CEILSPEED * 4; // [STRIFE] Was CEILSPEED * 2 break; case lowerAndCrush: // [STRIFE] lowerAndCrush doesn't seem to have crushed in DOOM, // but it was certainly made to do so in Strife! It is also // changed to lower all the way to the floor. ceiling->crush = 1; ceiling->direction = -1; ceiling->speed = CEILSPEED; ceiling->bottomheight = sec->floorheight; break; case silentCrushAndRaise: case crushAndRaise: // [STRIFE] haleyjd 20130209: Turns out these types do NOT crush // in Strife... yeah, that makes a lot of sense. Thanks to Gez for // having detected this difference. //ceiling->crush = true; ceiling->topheight = sec->ceilingheight; case lowerToFloor: ceiling->bottomheight = sec->floorheight; if (type != lowerToFloor) ceiling->bottomheight += 8*FRACUNIT; ceiling->direction = -1; ceiling->speed = CEILSPEED; break; case raiseToHighest: ceiling->topheight = P_FindHighestCeilingSurrounding(sec); ceiling->direction = 1; ceiling->speed = CEILSPEED; break; } ceiling->tag = sec->tag; ceiling->type = type; P_AddActiveCeiling(ceiling); } return rtn; } // // Add an active ceiling // void P_AddActiveCeiling(ceiling_t* c) { int i; for (i = 0; i < MAXCEILINGS;i++) { if (activeceilings[i] == NULL) { activeceilings[i] = c; return; } } } // // Remove a ceiling's thinker // void P_RemoveActiveCeiling(ceiling_t* c) { int i; for (i = 0;i < MAXCEILINGS;i++) { if (activeceilings[i] == c) { activeceilings[i]->sector->specialdata = NULL; P_RemoveThinker (&activeceilings[i]->thinker); activeceilings[i] = NULL; break; } } } // // Restart a ceiling that's in-stasis // void P_ActivateInStasisCeiling(line_t* line) { int i; for (i = 0;i < MAXCEILINGS;i++) { if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && (activeceilings[i]->direction == 0)) { activeceilings[i]->direction = activeceilings[i]->olddirection; activeceilings[i]->thinker.function.acp1 = (actionf_p1)T_MoveCeiling; } } } // // EV_CeilingCrushStop // Stop a ceiling from crushing! // int EV_CeilingCrushStop(line_t *line) { int i; int rtn; rtn = 0; for (i = 0;i < MAXCEILINGS;i++) { if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && (activeceilings[i]->direction != 0)) { activeceilings[i]->olddirection = activeceilings[i]->direction; activeceilings[i]->thinker.function.acv = (actionf_v)NULL; activeceilings[i]->direction = 0; // in-stasis rtn = 1; } } return rtn; } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_dialog.c000066400000000000000000001217571257432200600233270ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2010 James Haley, Samuel Villarreal // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // [STRIFE] New Module // // Dialog Engine for Strife // #include #include "z_zone.h" #include "w_wad.h" #include "deh_str.h" #include "d_main.h" #include "d_mode.h" #include "d_player.h" #include "doomstat.h" #include "m_random.h" #include "m_menu.h" #include "m_misc.h" #include "r_main.h" #include "v_video.h" #include "p_local.h" #include "sounds.h" #include "p_dialog.h" #include "s_sound.h" #include "p_local.h" #include "p_inter.h" // // Defines and Macros // // haleyjd: size of the original Strife mapdialog_t structure. #define ORIG_MAPDIALOG_SIZE 0x5EC #define DIALOG_INT(field, ptr) \ field = ((int)ptr[0] | \ ((int)ptr[1] << 8) | \ ((int)ptr[2] << 16) | \ ((int)ptr[3] << 24)); \ ptr += 4; #define DIALOG_STR(field, ptr, len) \ memcpy(field, ptr, len); \ ptr += len; // // Globals // // This can be toggled at runtime to determine if the full dialog messages // are subtitled on screen or not. Defaults to off. int dialogshowtext = false; // The global mission objective buffer. This gets written to and read from file, // and is set by dialogs and line actions. char mission_objective[OBJECTIVE_LEN]; // // Static Globals // // True if SCRIPT00 is loaded. static boolean script0loaded; // Number of dialogs defined in the current level's script. static int numleveldialogs; // The actual level dialogs. This didn't exist in Strife, but is new to account // for structure alignment/packing concerns, given that Chocolate Doom is // multiplatform. static mapdialog_t *leveldialogs; // The actual script00 dialogs. As above. static mapdialog_t *script0dialogs; // Number of dialogs defined in the SCRIPT00 lump. static int numscript0dialogs; // The player engaged in dialog. This is always player 1, though, since Rogue // never completed the ability to use dialog outside of single-player mode. static player_t *dialogplayer; // The object to which the player is speaking. static mobj_t *dialogtalker; // The talker's current angle static angle_t dialogtalkerangle; // The currently active mapdialog object. static mapdialog_t *currentdialog; // Text at the end of the choices static char dialoglastmsgbuffer[48]; // Item to display to player when picked up or recieved static char pickupstring[46]; // Health based on gameskill given by the front's medic static const int healthamounts[] = { -100 , -75, -50, -50, -100 }; //============================================================================= // // Dialog State Sets // // These are used to animate certain actors in response to what happens in // their dialog sequences. // typedef struct dialogstateset_s { mobjtype_t type; // the type of object statenum_t greet; // greeting state, for start of dialog statenum_t yes; // "yes" state, for an affirmative response statenum_t no; // "no" state, when you don't have the right items } dialogstateset_t; static dialogstateset_t dialogstatesets[] = { { MT_PLAYER, S_NULL, S_NULL, S_NULL }, { MT_SHOPKEEPER_W, S_MRGT_00, S_MRYS_00, S_MRNO_00 }, { MT_SHOPKEEPER_B, S_MRGT_00, S_MRYS_00, S_MRNO_00 }, { MT_SHOPKEEPER_A, S_MRGT_00, S_MRYS_00, S_MRNO_00 }, { MT_SHOPKEEPER_M, S_MRGT_00, S_MRYS_00, S_MRNO_00 } }; // Rogue stored this in a static global rather than making it a define... static int numdialogstatesets = arrlen(dialogstatesets); // Current dialog talker state static dialogstateset_t *dialogtalkerstates; //============================================================================= // // Random Messages // // Rogue hard-coded these so they wouldn't have to repeat them several times // in the SCRIPT00 lump, apparently. // #define MAXRNDMESSAGES 10 typedef struct rndmessage_s { const char *type_name; int nummessages; char *messages[MAXRNDMESSAGES]; } rndmessage_t; static rndmessage_t rndMessages[] = { // Peasants { "PEASANT", 10, { "PLEASE DON'T HURT ME.", "IF YOU'RE LOOKING TO HURT ME, I'M \n" "NOT REALLY WORTH THE EFFORT.", "I DON'T KNOW ANYTHING.", "GO AWAY OR I'LL CALL THE GUARDS!", "I WISH SOMETIMES THAT ALL THESE \n" "REBELS WOULD JUST LEARN THEIR \n" "PLACE AND STOP THIS NONSENSE.", "JUST LEAVE ME ALONE, OK?", "I'M NOT SURE, BUT SOMETIMES I THINK \n" "THAT I KNOW SOME OF THE ACOLYTES.", "THE ORDER'S GOT EVERYTHING AROUND HERE PRETTY WELL LOCKED UP TIGHT.", "THERE'S NO WAY THAT THIS IS JUST A \n" "SECURITY FORCE.", "I'VE HEARD THAT THE ORDER IS REALLY \n" "NERVOUS ABOUT THE FRONT'S \n" "ACTIONS AROUND HERE." } }, // Rebel { "REBEL", 10, { "THERE'S NO WAY THE ORDER WILL \n" "STAND AGAINST US.", "WE'RE ALMOST READY TO STRIKE. \n" "MACIL'S PLANS ARE FALLING IN PLACE.", "WE'RE ALL BEHIND YOU, DON'T WORRY.", "DON'T GET TOO CLOSE TO ANY OF THOSE BIG ROBOTS. THEY'LL MELT YOU DOWN \n" "FOR SCRAP!", "THE DAY OF OUR GLORY WILL SOON \n" "COME, AND THOSE WHO OPPOSE US WILL \n" "BE CRUSHED!", "DON'T GET TOO COMFORTABLE. WE'VE \n" "STILL GOT OUR WORK CUT OUT FOR US.", "MACIL SAYS THAT YOU'RE THE NEW \n" "HOPE. BEAR THAT IN MIND.", "ONCE WE'VE TAKEN THESE CHARLATANS DOWN, WE'LL BE ABLE TO REBUILD THIS " "WORLD AS IT SHOULD BE.", "REMEMBER THAT YOU AREN'T FIGHTING \n" "JUST FOR YOURSELF, BUT FOR \n" "EVERYONE HERE AND OUTSIDE.", "AS LONG AS ONE OF US STILL STANDS, \n" "WE WILL WIN." } }, // Acolyte { "AGUARD", 10, { "MOVE ALONG, PEASANT.", "FOLLOW THE TRUE FAITH, ONLY THEN \n" "WILL YOU BEGIN TO UNDERSTAND.", "ONLY THROUGH DEATH CAN ONE BE \n" "TRULY REBORN.", "I'M NOT INTERESTED IN YOUR USELESS \n" "DRIVEL.", "IF I HAD WANTED TO TALK TO YOU I \n" "WOULD HAVE TOLD YOU SO.", "GO AND ANNOY SOMEONE ELSE!", "KEEP MOVING!", "IF THE ALARM GOES OFF, JUST STAY OUT OF OUR WAY!", "THE ORDER WILL CLEANSE THE WORLD \n" "AND USHER IT INTO THE NEW ERA.", "PROBLEM? NO, I THOUGHT NOT.", } }, // Beggar { "BEGGAR", 10, { "ALMS FOR THE POOR?", "WHAT ARE YOU LOOKING AT, SURFACER?", "YOU WOULDN'T HAVE ANY EXTRA FOOD, WOULD YOU?", "YOU SURFACE PEOPLE WILL NEVER \n" " " " UNDERSTAND US.", "HA, THE GUARDS CAN'T FIND US. THOSE \n" "IDIOTS DON'T EVEN KNOW WE EXIST.", "ONE DAY EVERYONE BUT THOSE WHO SERVE THE ORDER WILL BE FORCED TO " " JOIN US.", "STARE NOW, BUT YOU KNOW THAT THIS WILL BE YOUR OWN FACE ONE DAY.", // Note: "NOTHING THING" is an authentic typo "THERE'S NOTHING THING MORE \n" "ANNOYING THAN A SURFACER WITH AN ATTITUDE!", "THE ORDER WILL MAKE SHORT WORK OF YOUR PATHETIC FRONT.", "WATCH YOURSELF SURFACER. WE KNOW OUR ENEMIES!" } }, // Templar { "PGUARD", 10, { "WE ARE THE HANDS OF FATE. TO EARN \n" "OUR WRATH IS TO FIND OBLIVION!", "THE ORDER WILL CLEANSE THE WORLD \n" "OF THE WEAK AND CORRUPT!", "OBEY THE WILL OF THE MASTERS!", "LONG LIFE TO THE BROTHERS OF THE \n" "ORDER!", "FREE WILL IS AN ILLUSION THAT BINDS \n" "THE WEAK MINDED.", "POWER IS THE PATH TO GLORY. TO \n" "FOLLOW THE ORDER IS TO WALK THAT \n" "PATH!", "TAKE YOUR PLACE AMONG THE \n" "RIGHTEOUS, JOIN US!", "THE ORDER PROTECTS ITS OWN.", "ACOLYTES? THEY HAVE YET TO SEE THE FULL GLORY OF THE ORDER.", "IF THERE IS ANY HONOR INSIDE THAT \n" "PATHETIC SHELL OF A BODY, \n" "YOU'LL ENTER INTO THE ARMS OF THE \n" "ORDER." } } }; // And again, this could have been a define, but was a variable. static int numrndmessages = arrlen(rndMessages); //============================================================================= // // Dialog Menu Structure // // The Strife dialog system is actually just a serious abuse of the DOOM menu // engine. Hence why it doesn't work in multiplayer games or during demo // recording. // #define NUMDIALOGMENUITEMS 6 static void P_DialogDrawer(void); static menuitem_t dialogmenuitems[] = { { 1, "", P_DialogDoChoice, '1' }, // These items are loaded dynamically { 1, "", P_DialogDoChoice, '2' }, { 1, "", P_DialogDoChoice, '3' }, { 1, "", P_DialogDoChoice, '4' }, { 1, "", P_DialogDoChoice, '5' }, { 1, "", P_DialogDoChoice, '6' } // Item 6 is always the dismissal item }; static menu_t dialogmenu = { NUMDIALOGMENUITEMS, NULL, dialogmenuitems, P_DialogDrawer, 42, 75, 0 }; // Lump number of the dialog background picture, if any. static int dialogbgpiclumpnum; // Name of current speaking character. static char *dialogname; // Current dialog text. static const char *dialogtext; //============================================================================= // // Routines // // // P_ParseDialogLump // // haleyjd 09/02/10: This is an original function added to parse out the // dialogs from the dialog lump rather than reading them raw from the lump // pointer. This avoids problems with structure packing. // static void P_ParseDialogLump(byte *lump, mapdialog_t **dialogs, int numdialogs, int tag) { int i; byte *rover = lump; *dialogs = Z_Malloc(numdialogs * sizeof(mapdialog_t), tag, NULL); for(i = 0; i < numdialogs; i++) { int j; mapdialog_t *curdialog = &((*dialogs)[i]); DIALOG_INT(curdialog->speakerid, rover); DIALOG_INT(curdialog->dropitem, rover); DIALOG_INT(curdialog->checkitem[0], rover); DIALOG_INT(curdialog->checkitem[1], rover); DIALOG_INT(curdialog->checkitem[2], rover); DIALOG_INT(curdialog->jumptoconv, rover); DIALOG_STR(curdialog->name, rover, MDLG_NAMELEN); DIALOG_STR(curdialog->voice, rover, MDLG_LUMPLEN); DIALOG_STR(curdialog->backpic, rover, MDLG_LUMPLEN); DIALOG_STR(curdialog->text, rover, MDLG_TEXTLEN); // copy choices for(j = 0; j < 5; j++) { mapdlgchoice_t *curchoice = &(curdialog->choices[j]); DIALOG_INT(curchoice->giveitem, rover); DIALOG_INT(curchoice->needitems[0], rover); DIALOG_INT(curchoice->needitems[1], rover); DIALOG_INT(curchoice->needitems[2], rover); DIALOG_INT(curchoice->needamounts[0], rover); DIALOG_INT(curchoice->needamounts[1], rover); DIALOG_INT(curchoice->needamounts[2], rover); DIALOG_STR(curchoice->text, rover, MDLG_CHOICELEN); DIALOG_STR(curchoice->textok, rover, MDLG_MSGLEN); DIALOG_INT(curchoice->next, rover); DIALOG_INT(curchoice->objective, rover); DIALOG_STR(curchoice->textno, rover, MDLG_MSGLEN); } } } // // P_DialogLoad // // [STRIFE] New function // haleyjd 09/02/10: Loads the dialog script for the current map. Also loads // SCRIPT00 if it has not yet been loaded. // void P_DialogLoad(void) { char lumpname[9]; int lumpnum; // load the SCRIPTxy lump corresponding to MAPxy, if it exists. DEH_snprintf(lumpname, sizeof(lumpname), "script%02d", gamemap); if((lumpnum = W_CheckNumForName(lumpname)) == -1) numleveldialogs = 0; else { byte *leveldialogptr = W_CacheLumpNum(lumpnum, PU_STATIC); numleveldialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE; P_ParseDialogLump(leveldialogptr, &leveldialogs, numleveldialogs, PU_LEVEL); Z_Free(leveldialogptr); // haleyjd: free the original lump } // also load SCRIPT00 if it has not been loaded yet if(!script0loaded) { byte *script0ptr; script0loaded = true; // BUG: Rogue should have used W_GetNumForName here... lumpnum = W_CheckNumForName(DEH_String("script00")); script0ptr = W_CacheLumpNum(lumpnum, PU_STATIC); numscript0dialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE; P_ParseDialogLump(script0ptr, &script0dialogs, numscript0dialogs, PU_STATIC); Z_Free(script0ptr); // haleyjd: free the original lump } } // // P_PlayerHasItem // // [STRIFE] New function // haleyjd 09/02/10: Checks for inventory items, quest flags, etc. for dialogs. // Returns the amount possessed, or 0 if none. // int P_PlayerHasItem(player_t *player, mobjtype_t type) { int i; if(type > 0) { // check keys if(type >= MT_KEY_BASE && type < MT_INV_SHADOWARMOR) return (player->cards[type - MT_KEY_BASE]); // check sigil pieces if(type >= MT_SIGIL_A && type <= MT_SIGIL_E) return (type - MT_SIGIL_A <= player->sigiltype); // check quest tokens if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31) return (player->questflags & (1 << (type - MT_TOKEN_QUEST1))); // check inventory for(i = 0; i < 32; i++) { if(type == player->inventory[i].type) return player->inventory[i].amount; } } return 0; } // // P_DialogFind // // [STRIFE] New function // haleyjd 09/03/10: Looks for a dialog definition matching the given // Script ID # for an mobj. // mapdialog_t *P_DialogFind(mobjtype_t type, int jumptoconv) { int i; // check the map-specific dialogs first for(i = 0; i < numleveldialogs; i++) { if(type == leveldialogs[i].speakerid) { if(jumptoconv <= 1) return &leveldialogs[i]; else --jumptoconv; } } // check SCRIPT00 dialogs next for(i = 0; i < numscript0dialogs; i++) { if(type == script0dialogs[i].speakerid) return &script0dialogs[i]; } // the default dialog is script 0 in the SCRIPT00 lump. return &script0dialogs[0]; } // // P_DialogGetStates // // [STRIFE] New function // haleyjd 09/03/10: Find the set of special dialog states (greetings, yes, no) // for a particular thing type. // static dialogstateset_t *P_DialogGetStates(mobjtype_t type) { int i; // look for a match by type for(i = 0; i < numdialogstatesets; i++) { if(type == dialogstatesets[i].type) return &dialogstatesets[i]; } // return the default 0 record if no match. return &dialogstatesets[0]; } // // P_DialogGetMsg // // [STRIFE] New function // haleyjd 09/03/10: Redirects dialog messages when the script indicates that // the actor should use a random message stored in the executable instead. // static const char *P_DialogGetMsg(const char *message) { // if the message starts with "RANDOM"... if(!strncasecmp(message, DEH_String("RANDOM"), 6)) { int i; const char *nameloc = message + 7; // look for a match in rndMessages for the string starting // 7 chars after "RANDOM_" for(i = 0; i < numrndmessages; i++) { if(!strncasecmp(nameloc, rndMessages[i].type_name, 4)) { // found a match, so return a random message int rnd = M_Random(); int nummessages = rndMessages[i].nummessages; return DEH_String(rndMessages[i].messages[rnd % nummessages]); } } } // otherwise, just return the message passed in. return message; } // // P_GiveInventoryItem // // [STRIFE] New function // haleyjd 09/03/10: Give an inventory item to the player, if possible. // villsa 09/09/10: Fleshed out routine // boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type) { int curinv = 0; int i; boolean ok = false; mobjtype_t item = 0; inventory_t* invtail; // repaint the status bar due to inventory changing player->st_update = true; while(1) { // inventory is full if(curinv > player->numinventory) return true; item = player->inventory[curinv].type; if(type < item) { if(curinv != MAXINVENTORYSLOTS) { // villsa - sort inventory item if needed invtail = &player->inventory[player->numinventory - 1]; if(player->numinventory >= (curinv + 1)) { for(i = player->numinventory; i >= (curinv + 1); --i) { invtail[1].sprite = invtail[0].sprite; invtail[1].type = invtail[0].type; invtail[1].amount = invtail[0].amount; invtail--; } } // villsa - add inventory item player->inventory[curinv].amount = 1; player->inventory[curinv].sprite = sprnum; player->inventory[curinv].type = type; // sort cursor if needed if(player->numinventory) { if(curinv <= player->inventorycursor) player->inventorycursor++; } player->numinventory++; return true; } return false; } if(type == item) break; curinv++; } // check amount of inventory item by using the mass from mobjinfo if(player->inventory[curinv].amount < mobjinfo[item].mass) { player->inventory[curinv].amount++; ok = true; } else ok = false; return ok; } // // P_GiveItemToPlayer // // [STRIFE] New function // haleyjd 09/03/10: Sorts out how to give something to the player. // Not strictly just for inventory items. // villsa 09/09/10: Fleshed out function // boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type) { int i = 0; line_t junk; int sound = sfx_itemup; // haleyjd 09/21/10: different sounds for items // set quest if mf_givequest flag is set if(mobjinfo[type].flags & MF_GIVEQUEST) player->questflags |= 1 << (mobjinfo[type].speed - 1); // check for keys if(type >= MT_KEY_BASE && type <= MT_NEWKEY5) { P_GiveCard(player, type - MT_KEY_BASE); return true; } // check for quest tokens if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31) { if(mobjinfo[type].name) { M_StringCopy(pickupstring, DEH_String(mobjinfo[type].name), 39); player->message = pickupstring; } player->questflags |= 1 << (type - MT_TOKEN_QUEST1); if(player == &players[consoleplayer]) S_StartSound(NULL, sound); return true; } // haleyjd 09/22/10: Refactored to give sprites higher priority than // mobjtypes and to implement missing logic. switch(sprnum) { case SPR_HELT: // This is given only by the "DONNYTRUMP" cheat (aka Midas) P_GiveInventoryItem(player, SPR_HELT, MT_TOKEN_TOUGHNESS); P_GiveInventoryItem(player, SPR_GUNT, MT_TOKEN_ACCURACY); // [STRIFE] Bizarre... for(i = 0; i < 5 * player->accuracy + 300; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; case SPR_ARM1: // Armor 1 if(!P_GiveArmor(player, -2)) P_GiveInventoryItem(player, sprnum, type); break; case SPR_ARM2: // Armor 2 if(!P_GiveArmor(player, -1)) P_GiveInventoryItem(player, sprnum, type); break; case SPR_COIN: // 1 Gold P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; case SPR_CRED: // 10 Gold for(i = 0; i < 10; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; case SPR_SACK: // 25 gold for(i = 0; i < 25; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; case SPR_CHST: // 50 gold for(i = 0; i < 50; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; // haleyjd 20141215: missing break, caused Rowan to not take ring from you. case SPR_BBOX: // Box of Bullets if(!P_GiveAmmo(player, am_bullets, 5)) return false; break; case SPR_BLIT: // Bullet Clip if(!P_GiveAmmo(player, am_bullets, 1)) return false; break; case SPR_PMAP: // Map powerup if(!P_GivePower(player, pw_allmap)) return false; sound = sfx_yeah; // bluh-doop! break; case SPR_COMM: // Communicator if(!P_GivePower(player, pw_communicator)) return false; sound = sfx_yeah; // bluh-doop! break; case SPR_MSSL: // Mini-missile if(!P_GiveAmmo(player, am_missiles, 1)) return false; break; case SPR_ROKT: // Crate of missiles if(!P_GiveAmmo(player, am_missiles, 5)) return false; break; case SPR_BRY1: // Battery cell if(!P_GiveAmmo(player, am_cell, 1)) return false; break; case SPR_CPAC: // Cell pack if(!P_GiveAmmo(player, am_cell, 5)) return false; break; case SPR_PQRL: // Poison bolts if(!P_GiveAmmo(player, am_poisonbolts, 5)) return false; break; case SPR_XQRL: // Electric bolts if(!P_GiveAmmo(player, am_elecbolts, 5)) return false; break; case SPR_GRN1: // HE Grenades if(!P_GiveAmmo(player, am_hegrenades, 1)) return false; break; case SPR_GRN2: // WP Grenades if(!P_GiveAmmo(player, am_wpgrenades, 1)) return false; break; case SPR_BKPK: // Backpack (aka Ammo Satchel) if(!player->backpack) { for(i = 0; i < NUMAMMO; i++) player->maxammo[i] *= 2; player->backpack = true; } for(i = 0; i < NUMAMMO; i++) P_GiveAmmo(player, i, 1); break; case SPR_RIFL: // Assault Rifle if(player->weaponowned[wp_rifle]) return false; if(!P_GiveWeapon(player, wp_rifle, false)) return false; sound = sfx_wpnup; // SHK-CHK! break; case SPR_FLAM: // Flamethrower if(player->weaponowned[wp_flame]) return false; if(!P_GiveWeapon(player, wp_flame, false)) return false; sound = sfx_wpnup; // SHK-CHK! break; case SPR_MMSL: // Mini-missile Launcher if(player->weaponowned[wp_missile]) return false; if(!P_GiveWeapon(player, wp_missile, false)) return false; sound = sfx_wpnup; // SHK-CHK! break; case SPR_TRPD: // Mauler if(player->weaponowned[wp_mauler]) return false; if(!P_GiveWeapon(player, wp_mauler, false)) return false; sound = sfx_wpnup; // SHK-CHK! break; case SPR_CBOW: // Here's a crossbow. Just aim straight, and *SPLAT!* if(player->weaponowned[wp_elecbow]) return false; if(!P_GiveWeapon(player, wp_elecbow, false)) return false; sound = sfx_wpnup; // SHK-CHK! break; case SPR_TOKN: // Miscellaneous items - These are determined by thingtype. switch(type) { case MT_KEY_HAND: // Severed hand P_GiveCard(player, key_SeveredHand); break; case MT_MONY_300: // 300 Gold (this is the only way to get it, in fact) for(i = 0; i < 300; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; case MT_TOKEN_AMMO: // Ammo token - you get this from the Weapons Trainer if(player->ammo[am_bullets] >= 50) return false; player->ammo[am_bullets] = 50; break; case MT_TOKEN_HEALTH: // Health token - from the Front's doctor if(!P_GiveBody(player, healthamounts[gameskill])) return false; break; case MT_TOKEN_ALARM: // Alarm token - particularly from the Oracle. P_NoiseAlert(player->mo, player->mo); A_AlertSpectreC(dialogtalker); // BUG: assumes in a dialog o_O break; case MT_TOKEN_DOOR1: // Door special 1 junk.tag = 222; EV_DoDoor(&junk, vld_open); break; case MT_TOKEN_PRISON_PASS: // Door special 1 - Prison pass junk.tag = 223; EV_DoDoor(&junk, vld_open); if(gamemap == 2) // If on Tarnhill, give Prison pass object P_GiveInventoryItem(player, sprnum, type); break; case MT_TOKEN_SHOPCLOSE: // Door special 3 - "Shop close" - unused? junk.tag = 222; EV_DoDoor(&junk, vld_close); break; case MT_TOKEN_DOOR3: // Door special 4 (or 3? :P ) junk.tag = 224; EV_DoDoor(&junk, vld_close); break; case MT_TOKEN_STAMINA: // Stamina upgrade if(player->stamina >= 100) return false; player->stamina += 10; P_GiveBody(player, 200); // full healing break; case MT_TOKEN_NEW_ACCURACY: // Accuracy upgrade if(player->accuracy >= 100) return false; player->accuracy += 10; break; case MT_SLIDESHOW: // Slideshow (start a finale) gameaction = ga_victory; if(gamemap == 10) P_GiveItemToPlayer(player, SPR_TOKN, MT_TOKEN_QUEST17); break; default: // The default is to just give it as an inventory item. P_GiveInventoryItem(player, sprnum, type); break; } break; default: // The ultimate default: Give it as an inventory item. if(!P_GiveInventoryItem(player, sprnum, type)) return false; break; } // Play sound. if(player == &players[consoleplayer]) S_StartSound(NULL, sound); return true; } // // P_TakeDialogItem // // [STRIFE] New function // haleyjd 09/03/10: Removes needed items from the player's inventory. // static void P_TakeDialogItem(player_t *player, int type, int amount) { int i; if(amount <= 0) return; for(i = 0; i < player->numinventory; i++) { // find a matching item if(type != player->inventory[i].type) continue; // if there is none left... if((player->inventory[i].amount -= amount) < 1) { // ...shift everything above it down int j; // BUG: They should have stopped at j < numinventory. This // seems to implicitly assume that numinventory is always at // least one less than the max # of slots, otherwise it // pulls in data from the following player_t fields: // st_update, numinventory, inventorycursor, accuracy, stamina for(j = i + 1; j <= player->numinventory; j++) { inventory_t *item1 = &(player->inventory[j - 1]); inventory_t *item2 = &(player->inventory[j]); *item1 = *item2; } // blank the topmost slot // BUG: This will overwrite the aforementioned fields if // numinventory is equal to the number of slots! // STRIFE-TODO: Overflow emulation? player->inventory[player->numinventory].type = NUMMOBJTYPES; player->inventory[player->numinventory].sprite = -1; player->numinventory--; // update cursor position if(player->inventorycursor >= player->numinventory) { if(player->inventorycursor) player->inventorycursor--; } } // end if return; // done! } // end for } // // P_DialogDrawer // // This function is set as the drawer callback for the dialog menu. // static void P_DialogDrawer(void) { angle_t angle; int y; int i; int height; int finaly; char choicetext[64]; char choicetext2[64]; // Run down bonuscount faster than usual so that flashes from being given // items are less obvious. if(dialogplayer->bonuscount) { dialogplayer->bonuscount -= 3; if(dialogplayer->bonuscount < 0) dialogplayer->bonuscount = 0; } angle = R_PointToAngle2(dialogplayer->mo->x, dialogplayer->mo->y, dialogtalker->x, dialogtalker->y); angle -= dialogplayer->mo->angle; // Dismiss the dialog if the player is out of alignment, or the thing he was // talking to is now engaged in battle. if ((angle > ANG45 && angle < (ANG270+ANG45)) || (dialogtalker->flags & MF_NODIALOG) != 0) { P_DialogDoChoice(dialogmenu.numitems - 1); } dialogtalker->reactiontime = 2; // draw background if(dialogbgpiclumpnum != -1) { patch_t *patch = W_CacheLumpNum(dialogbgpiclumpnum, PU_CACHE); V_DrawPatchDirect(0, 0, patch); } // if there's a valid background pic, delay drawing the rest of the menu // for a while; otherwise, it will appear immediately if(dialogbgpiclumpnum == -1 || menupausetime <= gametic) { if(menuindialog) { // time to pause the game? if(menupausetime + 3 < gametic) menupause = true; } // draw character name M_WriteText(12, 18, dialogname); y = 28; // show text (optional for dialogs with voices) if(dialogshowtext || currentdialog->voice[0] == '\0') y = M_WriteText(20, 28, dialogtext); height = 20 * dialogmenu.numitems; finaly = 175 - height; // preferred height if(y > finaly) finaly = 199 - height; // height it will bump down to if necessary. // draw divider M_WriteText(42, finaly - 6, DEH_String("______________________________")); dialogmenu.y = finaly + 6; y = 0; // draw the menu items for(i = 0; i < dialogmenu.numitems - 1; i++) { DEH_snprintf(choicetext, sizeof(choicetext), "%d) %s", i + 1, currentdialog->choices[i].text); // alternate text for items that need money if(currentdialog->choices[i].needamounts[0] > 0) { // haleyjd 20120401: necessary to avoid undefined behavior: M_StringCopy(choicetext2, choicetext, sizeof(choicetext2)); DEH_snprintf(choicetext, sizeof(choicetext), "%s for %d", choicetext2, currentdialog->choices[i].needamounts[0]); } M_WriteText(dialogmenu.x, dialogmenu.y + 3 + y, choicetext); y += 19; } // draw the final item for dismissing the dialog M_WriteText(dialogmenu.x, 19 * i + dialogmenu.y + 3, dialoglastmsgbuffer); } } // // P_DialogDoChoice // // [STRIFE] New function // haleyjd 09/05/10: Handles making a choice in a dialog. Installed as the // callback for all items in the dialogmenu structure. // void P_DialogDoChoice(int choice) { int i = 0, nextdialog = 0; boolean candochoice = true; char *message = NULL; mapdlgchoice_t *currentchoice; if(choice == -1) choice = dialogmenu.numitems - 1; currentchoice = &(currentdialog->choices[choice]); I_StartVoice(NULL); // STRIFE-TODO: verify (should stop previous voice I believe) // villsa 09/08/10: converted into for loop for(i = 0; i < MDLG_MAXITEMS; i++) { if(P_PlayerHasItem(dialogplayer, currentchoice->needitems[i]) < currentchoice->needamounts[i]) { candochoice = false; // nope, missing something } } if(choice != dialogmenu.numitems - 1 && candochoice) { int item; message = currentchoice->textok; if(dialogtalkerstates->yes) P_SetMobjState(dialogtalker, dialogtalkerstates->yes); item = currentchoice->giveitem; if(item < 0 || P_GiveItemToPlayer(dialogplayer, states[mobjinfo[item].spawnstate].sprite, item)) { // if successful, take needed items int count = 0; // villsa 09/08/10: converted into for loop for(count = 0; count < MDLG_MAXITEMS; count++) { P_TakeDialogItem(dialogplayer, currentchoice->needitems[count], currentchoice->needamounts[count]); } } else message = DEH_String("You seem to have enough!"); // store next dialog into the talking actor nextdialog = currentchoice->next; if(nextdialog != 0) dialogtalker->miscdata = (byte)(abs(nextdialog)); } else { // not successful message = currentchoice->textno; if(dialogtalkerstates->no) P_SetMobjState(dialogtalker, dialogtalkerstates->no); } if(choice != dialogmenu.numitems - 1) { int objective; char *objlump; if((objective = currentchoice->objective)) { DEH_snprintf(mission_objective, OBJECTIVE_LEN, "log%i", objective); objlump = W_CacheLumpName(mission_objective, PU_CACHE); M_StringCopy(mission_objective, objlump, OBJECTIVE_LEN); } // haleyjd 20130301: v1.31 hack: if first char of message is a period, // clear the player's message. Is this actually used anywhere? if(gameversion == exe_strife_1_31 && message[0] == '.') message = NULL; dialogplayer->message = message; } dialogtalker->angle = dialogtalkerangle; dialogplayer->st_update = true; M_ClearMenus(0); if(nextdialog >= 0 || gameaction == ga_victory) // Macil hack menuindialog = false; else P_DialogStart(dialogplayer); } // // P_DialogStartP1 // // [STRIFE] New function // haleyjd 09/13/10: This is a hack used by the finale system. // void P_DialogStartP1(void) { P_DialogStart(&players[0]); } // // P_DialogStart // // villsa [STRIFE] New function // void P_DialogStart(player_t *player) { int i = 0; int pic; int rnd = 0; char* byetext; int jumptoconv; if(menuactive || netgame) return; // are we facing towards our NPC? P_AimLineAttack(player->mo, player->mo->angle, (128*FRACUNIT)); if(!linetarget) { P_AimLineAttack(player->mo, player->mo->angle + (ANG90/16), (128*FRACUNIT)); if(!linetarget) P_AimLineAttack(player->mo, player->mo->angle - (ANG90/16), (128*FRACUNIT)); } if(!linetarget) return; // already in combat, can't talk to it if(linetarget->flags & MF_NODIALOG) return; // set pointer to the character talking dialogtalker = linetarget; // play a sound if(player == &players[consoleplayer]) S_StartSound(0, sfx_radio); linetarget->target = player->mo; // target the player dialogtalker->reactiontime = 2; // set reactiontime dialogtalkerangle = dialogtalker->angle; // remember original angle // face talker towards player A_FaceTarget(dialogtalker); // face towards NPC's direction player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, dialogtalker->x, dialogtalker->y); // set pointer to player talking dialogplayer = player; // haleyjd 09/08/10: get any stored dialog state from this object jumptoconv = linetarget->miscdata; // check item requirements while(1) { int i = 0; currentdialog = P_DialogFind(linetarget->type, jumptoconv); // dialog's jumptoconv equal to 0? There's nothing to jump to. if(currentdialog->jumptoconv == 0) break; // villsa 09/08/10: converted into for loop for(i = 0; i < MDLG_MAXITEMS; i++) { // if the item is non-zero, the player must have at least one in his // or her inventory if(currentdialog->checkitem[i] != 0 && P_PlayerHasItem(dialogplayer, currentdialog->checkitem[i]) < 1) break; } if(i < MDLG_MAXITEMS) // didn't find them all? this is our dialog! break; jumptoconv = currentdialog->jumptoconv; } M_DialogDimMsg(20, 28, currentdialog->text, false); dialogtext = P_DialogGetMsg(currentdialog->text); // get states dialogtalkerstates = P_DialogGetStates(linetarget->type); // have talker greet the player if(dialogtalkerstates->greet) P_SetMobjState(dialogtalker, dialogtalkerstates->greet); // get talker's name if(currentdialog->name[0]) dialogname = currentdialog->name; else { // use a fallback: if(mobjinfo[linetarget->type].name) dialogname = DEH_String(mobjinfo[linetarget->type].name); // mobjtype name else dialogname = DEH_String("Person"); // default name - like Joe in Doom 3 :P } // setup number of choices to choose from for(i = 0; i < MDLG_MAXCHOICES; i++) { if(!currentdialog->choices[i].giveitem) break; } // set number of choices to menu dialogmenu.numitems = i + 1; rnd = M_Random() % 3; // setup dialog menu M_StartControlPanel(); menupause = false; menuindialog = true; menupausetime = gametic + 17; currentMenu = &dialogmenu; if(i >= dialogmenu.lastOn) itemOn = dialogmenu.lastOn; else itemOn = 0; // get backdrop pic = W_CheckNumForName(currentdialog->backpic); dialogbgpiclumpnum = pic; if(pic != -1) V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE)); // get voice I_StartVoice(currentdialog->voice); // get bye text switch(rnd) { case 2: byetext = DEH_String("BYE!"); break; case 1: byetext = DEH_String("Thanks, Bye!"); break; default: case 0: byetext = DEH_String("See you later!"); break; } DEH_snprintf(dialoglastmsgbuffer, sizeof(dialoglastmsgbuffer), "%d) %s", i + 1, byetext); } // EOF chocolate-doom-chocolate-doom-2.2.1/src/strife/p_dialog.h000066400000000000000000000071541257432200600233260ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1996 Rogue Entertainment / Velocity, Inc. // Copyright(C) 2010 James Haley, Samuel Villareal // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // [STRIFE] New Module // // Dialog Engine for Strife // #ifndef P_DIALOG_H__ #define P_DIALOG_H__ #define OBJECTIVE_LEN 300 #define MAXINVENTORYSLOTS 30 #define MDLG_CHOICELEN 32 #define MDLG_MSGLEN 80 #define MDLG_NAMELEN 16 #define MDLG_LUMPLEN 8 #define MDLG_TEXTLEN 320 #define MDLG_MAXCHOICES 5 #define MDLG_MAXITEMS 3 extern char mission_objective[OBJECTIVE_LEN]; extern int dialogshowtext; // villsa - convenient macro for giving objective logs to player #define GiveObjective(x, minlumpnum) \ do { \ int obj_ln = W_CheckNumForName(DEH_String(x)); \ if(obj_ln > minlumpnum) \ M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \ OBJECTIVE_LEN);\ } while(0) // haleyjd - voice and objective in one #define GiveVoiceObjective(voice, log, minlumpnum) \ do { \ int obj_ln = W_CheckNumForName(DEH_String(log)); \ I_StartVoice(DEH_String(voice)); \ if(obj_ln > minlumpnum) \ M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \ OBJECTIVE_LEN);\ } while(0) typedef struct mapdlgchoice_s { int giveitem; // item given when successful int needitems[MDLG_MAXITEMS]; // item needed for success int needamounts[MDLG_MAXITEMS]; // amount of items needed char text[MDLG_CHOICELEN]; // normal text char textok[MDLG_MSGLEN]; // message given on success int next; // next dialog? int objective; // ??? char textno[MDLG_MSGLEN]; // message given on failure } mapdlgchoice_t; typedef struct mapdialog_s { int speakerid; // script ID# for mobjtype that will use this dialog int dropitem; // item to drop if that thingtype is killed int checkitem[MDLG_MAXITEMS]; // item(s) needed to see this dialog int jumptoconv; // conversation to jump to when... ? char name[MDLG_NAMELEN]; // name of speaker char voice[MDLG_LUMPLEN]; // voice file to play char backpic[MDLG_LUMPLEN]; // backdrop pic for character, if any char text[MDLG_TEXTLEN]; // main message text // options that this dialog gives the player mapdlgchoice_t choices[MDLG_MAXCHOICES]; } mapdialog_t; void P_DialogLoad(void); void P_DialogStart(player_t *player); void P_DialogDoChoice(int choice); boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type); boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type); boolean P_UseInventoryItem(player_t* player, int item); void P_DialogStartP1(void); mapdialog_t* P_DialogFind(mobjtype_t type, int jumptoconv); int P_PlayerHasItem(player_t *player, mobjtype_t type); #endif // EOF chocolate-doom-chocolate-doom-2.2.1/src/strife/p_doors.c000066400000000000000000001053411257432200600232050ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: Door animation code (opening/closing) // #include "z_zone.h" #include "doomdef.h" #include "deh_main.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "dstrings.h" #include "sounds.h" // [STRIFE] #include "p_dialog.h" #include "i_system.h" // // VERTICAL DOORS // // // T_VerticalDoor // void T_VerticalDoor(vldoor_t* door) { result_e res1; result_e res2; switch(door->direction) { case 0: // WAITING if (!--door->topcountdown) { switch(door->type) { case vld_blazeRaise: door->direction = -1; // time to go back down S_StartSound(&door->sector->soundorg, sfx_bdcls); break; case vld_normal: door->direction = -1; // time to go back down // villsa [STRIFE] closesound added S_StartSound(&door->sector->soundorg, door->closesound); break; // villsa [STRIFE] case vld_shopClose: door->direction = 1; door->speed = (2*FRACUNIT); S_StartSound(&door->sector->soundorg, door->opensound); break; case vld_close30ThenOpen: door->direction = 1; // villsa [STRIFE] opensound added S_StartSound(&door->sector->soundorg, door->opensound); break; default: break; } } break; case 2: // INITIAL WAIT if (!--door->topcountdown) { switch(door->type) { case vld_raiseIn5Mins: door->direction = 1; door->type = vld_normal; // villsa [STRIFE] opensound added S_StartSound(&door->sector->soundorg, door->opensound); break; default: break; } } break; // villsa [STRIFE] case -2: // SPLIT res1 = T_MovePlane(door->sector, door->speed, door->topheight, 0, 1, 1); res2 = T_MovePlane(door->sector, door->speed, door->topwait, 0, 0, -1); if(res1 == pastdest && res2 == pastdest) { door->sector->specialdata = NULL; P_RemoveThinker(&door->thinker); // unlink and free } break; case -1: // DOWN res1 = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction); if(res1 == pastdest) { switch(door->type) { case vld_normal: case vld_close: case vld_blazeRaise: case vld_blazeClose: door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free // villsa [STRIFE] no sounds break; case vld_close30ThenOpen: door->direction = 0; door->topcountdown = TICRATE*30; break; // villsa [STRIFE] case vld_shopClose: door->direction = 0; door->topcountdown = TICRATE*120; break; default: break; } } else if(res1 == crushed) { switch(door->type) { case vld_blazeClose: case vld_close: // DO NOT GO BACK UP! case vld_shopClose: // villsa [STRIFE] break; default: door->direction = 1; // villsa [STRIFE] opensound added S_StartSound(&door->sector->soundorg, door->opensound); break; } } break; case 1: // UP res1 = T_MovePlane(door->sector, door->speed, door->topheight, false,1,door->direction); if(res1 == pastdest) { switch(door->type) { case vld_blazeRaise: case vld_normal: door->direction = 0; // wait at top door->topcountdown = door->topwait; break; case vld_close30ThenOpen: case vld_blazeOpen: case vld_open: case vld_shopClose: // villsa [STRIFE] door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free break; default: break; } } break; } } // // EV_DoLockedDoor // Move a locked door up/down // // [STRIFE] This game has a crap load of keys. And this function doesn't even // deal with all of them... // int EV_DoLockedDoor(line_t* line, vldoor_e type, mobj_t* thing) { player_t* p; p = thing->player; if(!p) return 0; switch(line->special) { case 99: case 133: if(!p->cards[key_IDCard]) { p->message = DEH_String("You need an id card"); S_StartSound(NULL, sfx_oof); return 0; } break; case 134: case 135: if(!p->cards[key_IDBadge]) { p->message = DEH_String("You need an id badge"); S_StartSound(NULL, sfx_oof); return 0; } break; case 136: case 137: if(!p->cards[key_Passcard]) { p->message = DEH_String("You need a pass card"); S_StartSound(NULL, sfx_oof); return 0; } break; case 151: case 164: if(!p->cards[key_GoldKey]) { p->message = DEH_String("You need a gold key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 153: case 163: if(!p->cards[key_SilverKey]) { p->message = DEH_String("You need a silver key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 152: case 162: if(!p->cards[key_BrassKey]) { p->message = DEH_String("You need a brass key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 167: case 168: if(!p->cards[key_SeveredHand]) { p->message = DEH_String("Hand print not on file"); S_StartSound(NULL, sfx_oof); return 0; } break; case 171: if(!p->cards[key_PrisonKey]) { p->message = DEH_String("You don't have the key to the prison"); S_StartSound(NULL, sfx_oof); return 0; } break; case 172: if(!p->cards[key_Power1Key]) { p->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 173: if(!p->cards[key_Power2Key]) { p->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 176: if(!p->cards[key_Power3Key]) { p->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 189: if(!p->cards[key_OracleKey]) { p->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 191: if(!p->cards[key_MilitaryID]) { p->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 192: if(!p->cards[key_WarehouseKey]) { p->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return 0; } break; case 223: if(!p->cards[key_MineKey]) { p->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return 0; } break; } return EV_DoDoor(line,type); } // // EV_DoDoor // int EV_DoDoor(line_t* line, vldoor_e type) { int secnum, rtn; sector_t* sec; vldoor_t* door; secnum = -1; rtn = 0; while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if(sec->specialdata) continue; // new door thinker rtn = 1; door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->type = type; door->topwait = VDOORWAIT; door->speed = VDOORSPEED; R_SoundNumForDoor(door); // villsa [STRIFE] set door sounds switch(type) { // villsa [STRIFE] new door type case vld_splitOpen: door->direction = -2; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->speed = FRACUNIT; // yes, it using topwait to get the floor height door->topwait = P_FindLowestFloorSurrounding(sec); if(door->topheight == sec->ceilingheight) continue; S_StartSound(&sec->soundorg, door->opensound); break; // villsa [STRIFE] new door type case vld_splitRaiseNearest: door->direction = -2; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->speed = FRACUNIT; // yes, it using topwait to get the floor height door->topwait = P_FindHighestFloorSurrounding(sec); if(door->topheight == sec->ceilingheight) continue; S_StartSound(&sec->soundorg, door->opensound); break; case vld_blazeClose: case vld_shopClose: // villsa [STRIFE] door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; door->speed = VDOORSPEED * 4; S_StartSound(&door->sector->soundorg, sfx_bdcls); break; case vld_close: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; // villsa [STRIFE] set door sounds S_StartSound(&door->sector->soundorg, door->opensound); break; case vld_close30ThenOpen: door->topheight = sec->ceilingheight; door->direction = -1; // villsa [STRIFE] set door sounds S_StartSound(&door->sector->soundorg, door->closesound); break; case vld_blazeRaise: case vld_blazeOpen: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->speed = VDOORSPEED * 4; if (door->topheight != sec->ceilingheight) S_StartSound(&door->sector->soundorg, sfx_bdopn); break; case vld_normal: case vld_open: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; if(door->topheight != sec->ceilingheight) S_StartSound(&door->sector->soundorg, door->opensound); break; default: break; } } return rtn; } // // EV_ClearForceFields // // villsa [STRIFE] new function // boolean EV_ClearForceFields(line_t* line) { int secnum; sector_t* sec; int i; line_t* secline; boolean ret = false; secnum = -1; while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; line->special = 0; ret = true; // haleyjd 09/18/10: fixed to continue w/linecount == 0, not return for(i = 0; i < sec->linecount; i++) { secline = sec->lines[i]; if(!(secline->flags & ML_TWOSIDED)) continue; if(secline->special != 148) continue; secline->flags &= ~ML_BLOCKING; secline->special = 0; sides[secline->sidenum[0]].midtexture = 0; sides[secline->sidenum[1]].midtexture = 0; } } return ret; } // // EV_VerticalDoor : open a door manually, no tag value // // [STRIFE] Tons of new door types were added. // void EV_VerticalDoor(line_t* line, mobj_t* thing) { player_t* player; sector_t* sec; vldoor_t* door; int side; side = 0; // only front sides can be used // Check for locks player = thing->player; // haleyjd 09/15/10: [STRIFE] myriad checks here... switch(line->special) { case 26: // DR ID Card door case 32: // D1 ID Card door if(!player->cards[key_IDCard]) { player->message = DEH_String("You need an id card to open this door"); S_StartSound(NULL, sfx_oof); return; } break; case 27: // DR Pass Card door case 34: // D1 Pass Card door if(!player->cards[key_Passcard]) { player->message = DEH_String("You need a pass card key to open this door"); S_StartSound(NULL, sfx_oof); return; } break; case 28: // DR ID Badge door case 33: // D1 ID Badge door if(!player->cards[key_IDBadge]) { player->message = DEH_String("You need an id badge to open this door"); S_StartSound(NULL, sfx_oof); return; } break; case 156: // D1 brass key door case 161: // DR brass key door if(!player->cards[key_BrassKey]) { player->message = DEH_String("You need a brass key"); S_StartSound(NULL, sfx_oof); return; } break; case 157: // D1 silver key door case 160: // DR silver key door if(!player->cards[key_SilverKey]) { player->message = DEH_String("You need a silver key"); S_StartSound(NULL, sfx_oof); return; } break; case 158: // D1 gold key door case 159: // DR gold key door if(!player->cards[key_GoldKey]) { player->message = DEH_String("You need a gold key"); S_StartSound(NULL, sfx_oof); return; } break; // villsa [STRIFE] added 09/15/10 case 165: player->message = DEH_String("That doesn't seem to work"); S_StartSound(NULL, sfx_oof); return; case 166: // DR Hand Print door if(!player->cards[key_SeveredHand]) { player->message = DEH_String("Hand print not on file"); S_StartSound(NULL, sfx_oof); return; } break; case 169: // DR Base key door if(!player->cards[key_BaseKey]) { player->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return; } break; case 170: // DR Gov's Key door if(!player->cards[key_GovsKey]) { player->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return; } break; case 190: // DR Order Key door if(!player->cards[key_OrderKey]) { player->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return; } break; case 205: // DR "Only in retail" player->message = DEH_String("THIS AREA IS ONLY AVAILABLE IN THE " "RETAIL VERSION OF STRIFE"); S_StartSound(NULL, sfx_oof); return; case 213: // DR Chalice door if(!P_PlayerHasItem(player, MT_INV_CHALICE)) { player->message = DEH_String("You need the chalice!"); S_StartSound(NULL, sfx_oof); return; } break; case 217: // DR Core Key door if(!player->cards[key_CoreKey]) { player->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return; } break; case 221: // DR Mauler Key door if(!player->cards[key_MaulerKey]) { player->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return; } break; case 224: // DR Chapel Key door if(!player->cards[key_ChapelKey]) { player->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return; } break; case 225: // DR Catacomb Key door if(!player->cards[key_CatacombKey]) { player->message = DEH_String("You don't have the key"); S_StartSound(NULL, sfx_oof); return; } break; case 232: // DR Oracle Pass door if(!(player->questflags & QF_QUEST18)) { player->message = DEH_String("You need the Oracle Pass!"); S_StartSound(NULL, sfx_oof); return; } break; default: break; } // if the sector has an active thinker, use it sec = sides[ line->sidenum[side^1]] .sector; if (sec->specialdata) { door = sec->specialdata; // [STRIFE] Adjusted to handle linetypes handled here by Strife. // BUG: Not all door types are checked here. This means that certain // door lines are allowed to fall through and start a new thinker on the // sector! This is why some doors can become jammed in Strife - stuck in // midair, or unable to be opened at all. Multiple thinkers will fight // over how to move the door. They should have added a default return if // they weren't going to handle this unconditionally... switch(line->special) { case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s case 26: case 27: case 28: case 117: case 159: // villsa case 160: // haleyjd case 161: // villsa case 166: // villsa case 169: // villsa case 170: // villsa case 190: // villsa case 213: // villsa case 232: // villsa if(door->direction == -1) door->direction = 1; // go back up else { if (!thing->player) return; // When is a door not a door? // In Vanilla, door->direction is set, even though // "specialdata" might not actually point at a door. if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor) { door->direction = -1; // start going down immediately } else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise) { // Erm, this is a plat, not a door. // This notably causes a problem in ep1-0500.lmp where // a plat and a door are cross-referenced; the door // doesn't open on 64-bit. // The direction field in vldoor_t corresponds to the wait // field in plat_t. Let's set that to -1 instead. plat_t *plat; plat = (plat_t *) door; plat->wait = -1; } else { // This isn't a door OR a plat. Now we're in trouble. fprintf(stderr, "EV_VerticalDoor: Tried to close " "something that wasn't a door.\n"); // Try closing it anyway. At least it will work on 32-bit // machines. door->direction = -1; } } return; default: break; } } // haleyjd 09/15/10: [STRIFE] Removed DOOM door sounds // new door thinker door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor; door->sector = sec; door->direction = 1; door->speed = VDOORSPEED; door->topwait = VDOORWAIT; R_SoundNumForDoor(door); // haleyjd 09/15/10: [STRIFE] Get door sounds // for proper sound - [STRIFE] - verified complete switch(line->special) { case 117: // BLAZING DOOR RAISE case 118: // BLAZING DOOR OPEN S_StartSound(&sec->soundorg, sfx_bdopn); break; default: // NORMAL DOOR SOUND S_StartSound(&sec->soundorg, door->opensound); break; } // haleyjd: [STRIFE] - verified all. switch(line->special) { case 1: case 26: case 27: case 28: door->type = vld_normal; break; case 31: case 32: case 33: case 34: case 156: // villsa [STRIFE] case 157: // villsa [STRIFE] case 158: // villsa [STRIFE] door->type = vld_open; line->special = 0; break; case 117: // blazing door raise door->type = vld_blazeRaise; door->speed = VDOORSPEED*4; break; case 118: // blazing door open door->type = vld_blazeOpen; line->special = 0; door->speed = VDOORSPEED*4; break; default: // haleyjd: [STRIFE] pretty important to have this here! door->type = vld_normal; break; } // find the top and bottom of the movement range door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; } // // Spawn a door that closes after 30 seconds // void P_SpawnDoorCloseIn30 (sector_t* sec) { vldoor_t* door; door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 0; door->type = vld_normal; door->speed = VDOORSPEED; door->topcountdown = 30 * TICRATE; } // // Spawn a door that opens after 5 minutes // void P_SpawnDoorRaiseIn5Mins ( sector_t* sec, int secnum ) { vldoor_t* door; door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 2; door->type = vld_raiseIn5Mins; door->speed = VDOORSPEED; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->topwait = VDOORWAIT; door->topcountdown = 5 * 60 * TICRATE; } // villsa [STRIFE] resurrected sliding doors // // // villsa [STRIFE] // // Sliding door name information // static slidename_t slideFrameNames[MAXSLIDEDOORS] = { // SIGLDR { "SIGLDR01", // frame1 "SIGLDR02", // frame2 "SIGLDR03", // frame3 "SIGLDR04", // frame4 "SIGLDR05", // frame5 "SIGLDR06", // frame6 "SIGLDR07", // frame7 "SIGLDR08" // frame8 }, // DORSTN { "DORSTN01", // frame1 "DORSTN02", // frame2 "DORSTN03", // frame3 "DORSTN04", // frame4 "DORSTN05", // frame5 "DORSTN06", // frame6 "DORSTN07", // frame7 "DORSTN08" // frame8 }, // DORQTR { "DORQTR01", // frame1 "DORQTR02", // frame2 "DORQTR03", // frame3 "DORQTR04", // frame4 "DORQTR05", // frame5 "DORQTR06", // frame6 "DORQTR07", // frame7 "DORQTR08" // frame8 }, // DORCRG { "DORCRG01", // frame1 "DORCRG02", // frame2 "DORCRG03", // frame3 "DORCRG04", // frame4 "DORCRG05", // frame5 "DORCRG06", // frame6 "DORCRG07", // frame7 "DORCRG08" // frame8 }, // DORCHN { "DORCHN01", // frame1 "DORCHN02", // frame2 "DORCHN03", // frame3 "DORCHN04", // frame4 "DORCHN05", // frame5 "DORCHN06", // frame6 "DORCHN07", // frame7 "DORCHN08" // frame8 }, // DORIRS { "DORIRS01", // frame1 "DORIRS02", // frame2 "DORIRS03", // frame3 "DORIRS04", // frame4 "DORIRS05", // frame5 "DORIRS06", // frame6 "DORIRS07", // frame7 "DORIRS08" // frame8 }, // DORALN { "DORALN01", // frame1 "DORALN02", // frame2 "DORALN03", // frame3 "DORALN04", // frame4 "DORALN05", // frame5 "DORALN06", // frame6 "DORALN07", // frame7 "DORALN08" // frame8 }, {"\0","\0","\0","\0","\0","\0","\0","\0"} }; // // villsa [STRIFE] // // Sliding door open sounds // static sfxenum_t slideOpenSounds[MAXSLIDEDOORS] = { sfx_drlmto, sfx_drston, sfx_airlck, sfx_drsmto, sfx_drchno, sfx_airlck, sfx_airlck, sfx_None }; // // villsa [STRIFE] // // Sliding door close sounds // static sfxenum_t slideCloseSounds[MAXSLIDEDOORS] = { sfx_drlmtc, sfx_drston, sfx_airlck, sfx_drsmtc, sfx_drchnc, sfx_airlck, sfx_airlck, sfx_None }; slideframe_t slideFrames[MAXSLIDEDOORS]; // // P_InitSlidingDoorFrames // // villsa [STRIFE] resurrected // void P_InitSlidingDoorFrames(void) { int i; int f1; int f2; int f3; int f4; memset(slideFrames, 0, sizeof(slideframe_t) * MAXSLIDEDOORS); for(i = 0; i < MAXSLIDEDOORS; i++) { if(!slideFrameNames[i].frame1[0]) break; f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame1)); f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame2)); f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame3)); f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame4)); slideFrames[i].frames[0] = f1; slideFrames[i].frames[1] = f2; slideFrames[i].frames[2] = f3; slideFrames[i].frames[3] = f4; f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame5)); f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame6)); f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame7)); f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame8)); slideFrames[i].frames[4] = f1; slideFrames[i].frames[5] = f2; slideFrames[i].frames[6] = f3; slideFrames[i].frames[7] = f4; } } // // P_FindSlidingDoorType // // Return index into "slideFrames" array // for which door type to use // // villsa [STRIFE] resurrected // int P_FindSlidingDoorType(line_t* line) { int i; int val; for(i = 0; i < MAXSLIDEDOORS-1; i++) { val = sides[line->sidenum[0]].toptexture; if(val == slideFrames[i].frames[0]) return i; } return -1; } // // T_SlidingDoor // // villsa [STRIFE] resurrected // void T_SlidingDoor(slidedoor_t* door) { sector_t* sec; sec = door->frontsector; switch(door->status) { case sd_opening: if(!door->timer--) { if(++door->frame == SNUMFRAMES) { // IF DOOR IS DONE OPENING... door->line1->flags &= ~ML_BLOCKING; door->line2->flags &= ~ML_BLOCKING; if(door->type == sdt_openOnly) { door->frontsector->specialdata = NULL; P_RemoveThinker (&door->thinker); return; } door->timer = SDOORWAIT; door->status = sd_waiting; } else { // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME... door->timer = SWAITTICS; sides[door->line2->sidenum[0]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; sides[door->line2->sidenum[1]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; sides[door->line1->sidenum[0]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; sides[door->line1->sidenum[1]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; } } return; case sd_waiting: // IF DOOR IS DONE WAITING... if(!door->timer--) { fixed_t speed; fixed_t cheight; sec = door->frontsector; // CAN DOOR CLOSE? if(sec->thinglist != NULL) { door->timer = SDOORWAIT; return; } else { cheight = sec->ceilingheight; speed = cheight - sec->floorheight - (10*FRACUNIT); // something blocking it? if(T_MovePlane(sec, speed, sec->floorheight, 0, 1, -1) == crushed) { door->timer = SDOORWAIT; return; } else { // Instantly move plane T_MovePlane(sec, (128*FRACUNIT), cheight, 0, 1, 1); // turn line blocking back on door->line1->flags |= ML_BLOCKING; door->line2->flags |= ML_BLOCKING; // play close sound S_StartSound(&sec->soundorg, slideCloseSounds[door->whichDoorIndex]); door->status = sd_closing; door->timer = SWAITTICS; } } } return; case sd_closing: if (!door->timer--) { if(--door->frame < 0) { // IF DOOR IS DONE CLOSING... T_MovePlane(sec, (128*FRACUNIT), sec->floorheight, 0, 1, -1); door->frontsector->specialdata = NULL; P_RemoveThinker (&door->thinker); return; } else { // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME... door->timer = SWAITTICS; sides[door->line2->sidenum[0]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; sides[door->line2->sidenum[1]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; sides[door->line1->sidenum[0]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; sides[door->line1->sidenum[1]].midtexture = slideFrames[door->whichDoorIndex].frames[door->frame]; } } return; } } // // EV_RemoteSlidingDoor // // villsa [STRIFE] new function // int EV_RemoteSlidingDoor(line_t* line, mobj_t* thing) { int secnum; sector_t* sec; int i; int rtn; line_t* secline; secnum = -1; rtn = 0; while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if(sec->specialdata) continue; for(i = 0; i < 4; i++) { secline = sec->lines[i]; if(P_FindSlidingDoorType(secline) < 0) continue; EV_SlidingDoor(secline, thing); rtn = 1; } } return rtn; } // // EV_SlidingDoor // // villsa [STRIFE] // void EV_SlidingDoor(line_t* line, mobj_t* thing) { sector_t* sec; slidedoor_t* door; int i; line_t* secline; // Make sure door isn't already being animated sec = sides[line->sidenum[1]].sector; door = NULL; if(sec->specialdata) { if (!thing->player) return; door = sec->specialdata; if(door->type == sdt_openAndClose) { if(door->status == sd_waiting) { door->status = sd_closing; door->timer = SWAITTICS; // villsa [STRIFE] } } else return; } // Init sliding door vars if(!door) { door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->type = sdt_openAndClose; door->status = sd_opening; door->whichDoorIndex = P_FindSlidingDoorType(line); // villsa [STRIFE] different error message if(door->whichDoorIndex < 0) I_Error(DEH_String("EV_SlidingDoor: Textures are not defined for sliding door!")); sides[line->sidenum[0]].midtexture = sides[line->sidenum[0]].toptexture; // villsa [STRIFE] door->line1 = line; door->line2 = line; // villsa [STRIFE] this loop assumes that the sliding door is made up // of only four linedefs! for(i = 0; i < 4; i++) { secline = sec->lines[i]; if(secline != line) { side_t* side1; side_t* side2; side1 = &sides[secline->sidenum[0]]; side2 = &sides[line->sidenum[0]]; if(side1->toptexture == side2->toptexture) door->line2 = secline; } } door->thinker.function.acp1 = (actionf_p1)T_SlidingDoor; door->timer = SWAITTICS; door->frontsector = sec; door->frame = 0; // villsa [STRIFE] preset flags door->line1->flags |= ML_BLOCKING; door->line2->flags |= ML_BLOCKING; // villsa [STRIFE] set the closing sector T_MovePlane( door->frontsector, (128*FRACUNIT), P_FindLowestCeilingSurrounding(door->frontsector), 0, 1, 1); // villsa [STRIFE] play open sound S_StartSound(&door->frontsector->soundorg, slideOpenSounds[door->whichDoorIndex]); } } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_enemy.c000066400000000000000000002350451257432200600232010ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Enemy thinking, AI. // Action Pointer Functions // that are associated with states/frames. // #include #include #include "m_random.h" #include "i_system.h" #include "doomdef.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" #include "g_game.h" #include "z_zone.h" // villsa [STRIFE] // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" // [STRIFE] Dialog / Inventory #include "p_dialog.h" #include "deh_str.h" #include "w_wad.h" #include "f_finale.h" #include "p_inter.h" // Forward Declarations: void A_RandomWalk(mobj_t *); void A_ProgrammerAttack(mobj_t* actor); void A_FireSigilEOffshoot(mobj_t *actor); void A_SpectreCAttack(mobj_t *actor); void A_SpectreDAttack(mobj_t *actor); void A_SpectreEAttack(mobj_t *actor); void P_ThrustMobj(mobj_t *actor, angle_t angle, fixed_t force); typedef enum { DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_NODIR, NUMDIRS } dirtype_t; // // P_NewChaseDir related LUT. // dirtype_t opposite[] = { DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR }; dirtype_t diags[] = { DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST }; void A_Fall (mobj_t *actor); // // ENEMY THINKING // Enemies are allways spawned // with targetplayer = -1, threshold = 0 // Most monsters are spawned unaware of all players, // but some can be made preaware // // // Called by P_NoiseAlert. // Recursively traverse adjacent sectors, // sound blocking lines cut off traversal. // // haleyjd 09/05/10: [STRIFE] Verified unmodified // mobj_t* soundtarget; void P_RecursiveSound ( sector_t* sec, int soundblocks ) { int i; line_t* check; sector_t* other; // wake up all monsters in this sector if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) { return; // already flooded } sec->validcount = validcount; sec->soundtraversed = soundblocks+1; sec->soundtarget = soundtarget; for (i=0 ;ilinecount ; i++) { check = sec->lines[i]; if (! (check->flags & ML_TWOSIDED) ) continue; P_LineOpening (check); if (openrange <= 0) continue; // closed door if ( sides[ check->sidenum[0] ].sector == sec) other = sides[ check->sidenum[1] ] .sector; else other = sides[ check->sidenum[0] ].sector; if (check->flags & ML_SOUNDBLOCK) { if (!soundblocks) P_RecursiveSound (other, 1); } else P_RecursiveSound (other, soundblocks); } } // // P_NoiseAlert // If a monster yells at a player, // it will alert other monsters to the player. // // haleyjd 09/05/10: [STRIFE] Verified unmodified // void P_NoiseAlert ( mobj_t* target, mobj_t* emmiter ) { soundtarget = target; validcount++; P_RecursiveSound (emmiter->subsector->sector, 0); } // // P_WakeUpThing // // villsa [STRIFE] New function // Wakes up an mobj.nearby when somebody has been punched. // static void P_WakeUpThing(mobj_t* puncher, mobj_t* bystander) { if(!(bystander->flags & MF_NODIALOG)) { bystander->target = puncher; if(bystander->info->seesound) S_StartSound(bystander, bystander->info->seesound); P_SetMobjState(bystander, bystander->info->seestate); } } // // P_DoPunchAlert // // villsa [STRIFE] New function (by Quasar ;) // Wake up buddies nearby when the player thinks he's gotten too clever // with the punch dagger. Walks sector links. // void P_DoPunchAlert(mobj_t *puncher, mobj_t *punchee) { mobj_t *rover; // don't bother with this crap if we're already on alert if(punchee->subsector->sector->soundtarget) return; // gotta still be alive to call for help if(punchee->health <= 0) return; // has to be something you can wake up and kill too if(!(punchee->flags & MF_COUNTKILL) || punchee->flags & MF_NODIALOG) return; // make the punchee hurt - haleyjd 09/05/10: Fixed to use painstate. punchee->target = puncher; P_SetMobjState(punchee, punchee->info->painstate); // wake up everybody nearby // scan forward on sector list for(rover = punchee->snext; rover; rover = rover->snext) { // we only wake up certain thing types (Acolytes and Templars?) if(rover->health > 0 && rover->type >= MT_GUARD1 && rover->type <= MT_PGUARD && (P_CheckSight(rover, puncher) || P_CheckSight(rover, punchee))) { P_WakeUpThing(puncher, rover); rover->flags |= MF_NODIALOG; } } // scan backward on sector list for(rover = punchee->sprev; rover; rover = rover->sprev) { // we only wake up certain thing types (Acolytes and Templars?) if(rover->health > 0 && rover->type >= MT_GUARD1 && rover->type <= MT_PGUARD && (P_CheckSight(rover, puncher) || P_CheckSight(rover, punchee))) { P_WakeUpThing(puncher, rover); rover->flags |= MF_NODIALOG; } } } // // P_CheckMeleeRange // // [STRIFE] Minor change to meleerange. // boolean P_CheckMeleeRange(mobj_t* actor) { mobj_t* pl; fixed_t dist; if(!actor->target) return false; pl = actor->target; if(actor->z + 3 * actor->height / 2 < pl->z) // villsa [STRIFE] return false; dist = P_AproxDistance(pl->x - actor->x, pl->y - actor->y); if(dist >= MELEERANGE - 20*FRACUNIT + pl->info->radius) return false; if(!P_CheckSight (actor, actor->target)) return false; return true; } // // P_CheckMissileRange // // [STRIFE] // Changes to eliminate DOOM-specific code and to allow for // varying attack ranges for Strife monsters, as well as a general tweak // to considered distance for all monsters. // boolean P_CheckMissileRange(mobj_t* actor) { fixed_t dist; if(!P_CheckSight(actor, actor->target)) return false; if(actor->flags & MF_JUSTHIT) { // the target just hit the enemy, // so fight back! actor->flags &= ~MF_JUSTHIT; return true; } if(actor->reactiontime) return false; // do not attack yet // OPTIMIZE: get this from a global checksight dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT; if (!actor->info->meleestate) dist -= 128*FRACUNIT; // no melee attack, so fire more dist >>= 16; // villsa [STRIFE] checks for acolytes // haleyjd 09/05/10: Repaired to match disassembly: Was including // SHADOWGUARD in the wrong case, was missing MT_SENTINEL entirely. // Structure of ASM also indicates this was probably a switch // statement turned into a cascading if/else by the compiler. switch(actor->type) { case MT_GUARD1: case MT_GUARD2: case MT_GUARD3: case MT_GUARD4: case MT_GUARD5: case MT_GUARD6: // oddly, not all Acolytes are included here... dist >>= 4; break; case MT_SHADOWGUARD: case MT_CRUSADER: case MT_SENTINEL: dist >>= 1; break; default: break; } // villsa [STRIFE] changed to 150 if (dist > 150) dist = 150; // haleyjd 20100910: Hex-Rays was leaving this out completely: if (actor->type == MT_CRUSADER && dist > 120) dist = 120; // haleyjd 20110224 [STRIFE]: reversed predicate return (dist < P_Random()); } // // P_CheckRobotRange // // villsa [STRIFE] New function // boolean P_CheckRobotRange(mobj_t *actor) { fixed_t dist; if(!P_CheckSight(actor, actor->target)) return false; if(actor->reactiontime) return false; // do not attack yet dist = (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT) >> FRACBITS; return (dist < 200); } // // P_Move // Move in the current direction, // returns false if the move is blocked. // // [STRIFE] // villsa/haleyjd 09/05/10: Modified for terrain types and 3D object // clipping. Below constants are verified to be unmodified: // fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000}; fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000}; #define MAXSPECIALCROSS 8 extern line_t* spechit[MAXSPECIALCROSS]; extern int numspechit; boolean P_Move (mobj_t* actor) { fixed_t tryx; fixed_t tryy; line_t* ld; // warning: 'catch', 'throw', and 'try' // are all C++ reserved words boolean try_ok; boolean good; if (actor->movedir == DI_NODIR) return false; if ((unsigned)actor->movedir >= 8) I_Error ("Weird actor->movedir!"); tryx = actor->x + actor->info->speed*xspeed[actor->movedir]; tryy = actor->y + actor->info->speed*yspeed[actor->movedir]; try_ok = P_TryMove (actor, tryx, tryy); if (!try_ok) { // open any specials if (actor->flags & MF_FLOAT && floatok) { // must adjust height if (actor->z < tmfloorz) actor->z += FLOATSPEED; // [STRIFE] Note FLOATSPEED == 5*FRACUNIT else actor->z -= FLOATSPEED; actor->flags |= MF_INFLOAT; return true; } if (!numspechit) return false; actor->movedir = DI_NODIR; good = false; while (numspechit--) { ld = spechit[numspechit]; // if the special is not a door // that can be opened, // return false if (P_UseSpecialLine (actor, ld,0)) good = true; } return good; } else { actor->flags &= ~(MF_INFLOAT|MF_FEETCLIPPED); // villsa [STRIFE] // villsa [STRIFE] if(P_GetTerrainType(actor) != FLOOR_SOLID) actor->flags |= MF_FEETCLIPPED; } // villsa [STRIFE] Removed pulling non-floating actors down to the ground. // (haleyjd 09/05/10: Verified) /*if (! (actor->flags & MF_FLOAT) ) actor->z = actor->floorz;*/ return true; } // // TryWalk // Attempts to move actor on // in its current (ob->moveangle) direction. // If blocked by either a wall or an actor // returns FALSE // If move is either clear or blocked only by a door, // returns TRUE and sets... // If a door is in the way, // an OpenDoor call is made to start it opening. // // haleyjd 09/05/10: [STRIFE] Verified unmodified. // boolean P_TryWalk (mobj_t* actor) { if (!P_Move (actor)) { return false; } actor->movecount = P_Random()&15; return true; } // // P_NewChaseDir // void P_NewChaseDir(mobj_t* actor) { fixed_t deltax; fixed_t deltay; dirtype_t d[3]; int tdir; dirtype_t olddir; dirtype_t turnaround; // villsa [STRIFE] don't bomb out and instead set spawnstate if(!actor->target) { //I_Error("P_NewChaseDir: called with no target"); P_SetMobjState(actor, actor->info->spawnstate); return; } olddir = actor->movedir; turnaround=opposite[olddir]; deltax = actor->target->x - actor->x; deltay = actor->target->y - actor->y; if (deltax>10*FRACUNIT) d[1]= DI_EAST; else if (deltax<-10*FRACUNIT) d[1]= DI_WEST; else d[1]=DI_NODIR; if (deltay<-10*FRACUNIT) d[2]= DI_SOUTH; else if (deltay>10*FRACUNIT) d[2]= DI_NORTH; else d[2]=DI_NODIR; // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { actor->movedir = diags[((deltay<0)<<1)+(deltax>0)]; if (actor->movedir != (int) turnaround && P_TryWalk(actor)) return; } // try other directions if (P_Random() > 200 || abs(deltay)>abs(deltax)) { tdir=d[1]; d[1]=d[2]; d[2]=tdir; } if (d[1]==turnaround) d[1]=DI_NODIR; if (d[2]==turnaround) d[2]=DI_NODIR; if (d[1]!=DI_NODIR) { actor->movedir = d[1]; if (P_TryWalk(actor)) { // either moved forward or attacked return; } } if (d[2]!=DI_NODIR) { actor->movedir =d[2]; if (P_TryWalk(actor)) return; } // there is no direct path to the player, // so pick another direction. if (olddir!=DI_NODIR) { actor->movedir =olddir; if (P_TryWalk(actor)) return; } // randomly determine direction of search if (P_Random()&1) { for ( tdir=DI_EAST; tdir<=DI_SOUTHEAST; tdir++ ) { if (tdir != (int) turnaround) { actor->movedir =tdir; if ( P_TryWalk(actor) ) return; } } } else { for ( tdir=DI_SOUTHEAST; tdir != (DI_EAST-1); tdir-- ) { if (tdir != (int) turnaround) { actor->movedir = tdir; if ( P_TryWalk(actor) ) return; } } } if (turnaround != DI_NODIR) { actor->movedir =turnaround; if ( P_TryWalk(actor) ) return; } actor->movedir = DI_NODIR; // can not move } // // P_NewRandomDir // // villsa [STRIFE] new function // // haleyjd: Almost identical to the tail-end of P_NewChaseDir, this function // finds a purely random direction for an object to walk. Called from // A_RandomWalk. // // Shockingly similar to the RandomWalk pointer in Eternity :) // void P_NewRandomDir(mobj_t* actor) { int dir = 0; int omovedir = opposite[actor->movedir]; // haleyjd 20110223: nerfed this... // randomly determine direction of search if(P_Random() & 1) { // Try all non-reversal directions forward, first for(dir = 0; dir < DI_NODIR; dir++) { if(dir != omovedir) { actor->movedir = dir; if(P_Random() & 1) { if(P_TryWalk(actor)) break; } } } // haleyjd 20110223: logic missing entirely: // failed all non-reversal directions? try reversing if(dir > DI_SOUTHEAST) { if(omovedir == DI_NODIR) { actor->movedir = DI_NODIR; return; } actor->movedir = omovedir; if(P_TryWalk(actor)) return; else { actor->movedir = DI_NODIR; return; } } } else { // Try directions one at a time in backward order dir = DI_SOUTHEAST; while(1) { // haleyjd 09/05/10: missing random code. if(dir != omovedir) { actor->movedir = dir; // villsa 09/06/10: un-inlined code if(P_TryWalk(actor)) return; } // Ran out of non-reversal directions to try? Reverse. if(--dir == -1) { if(omovedir == DI_NODIR) { actor->movedir = DI_NODIR; return; } actor->movedir = omovedir; // villsa 09/06/10: un-inlined code if(P_TryWalk(actor)) return; else { actor->movedir = DI_NODIR; return; } } // end if(--dir == -1) } // end while(1) } // end else } // haleyjd 09/05/10: Needed below. extern void P_BulletSlope (mobj_t *mo); // // P_LookForPlayers // // If allaround is false, only look 180 degrees in front. // Returns true if a player is targeted. // // [STRIFE] // haleyjd 09/05/10: Modifications to support friendly units. // boolean P_LookForPlayers ( mobj_t* actor, boolean allaround ) { int c; int stop; player_t* player; angle_t an; fixed_t dist; mobj_t * master = players[actor->miscdata].mo; // haleyjd 09/05/10: handle Allies if(actor->flags & MF_ALLY) { // Deathmatch: support team behavior for Rebels. if(netgame) { // Rebels adopt the allied player's target if it is not of the same // allegiance. Other allies do it unconditionally. if(master && master->target && (master->target->type != MT_REBEL1 || master->target->miscdata != actor->miscdata)) { actor->target = master->target; } else { // haleyjd 09/06/10: Note that this sets actor->target in Strife! P_BulletSlope(actor); // Clear target if nothing is visible, or if the target is a // friendly Rebel or the allied player. if (linetarget == NULL || (actor->target->type == MT_REBEL1 && actor->target->miscdata == actor->miscdata) || actor->target == master) { actor->target = NULL; return false; } } } else { // Single-player: Adopt any non-allied player target. if(master && master->target && !(master->target->flags & MF_ALLY)) { actor->target = master->target; return true; } // haleyjd 09/06/10: Note that this sets actor->target in Strife! P_BulletSlope(actor); // Clear target if nothing is visible, or if the target is an ally. if(!linetarget || actor->target->flags & MF_ALLY) { actor->target = NULL; return false; } } return true; } c = 0; // NOTE: This behavior has been changed from the Vanilla behavior, where // an infinite loop can occur if players 0-3 all quit the game. Although // technically this is not what Vanilla does, fixing this is highly // desirable, and having the game simply lock up is not acceptable. // stop = (actor->lastlook - 1) & 3; // for (;; actor->lastlook = (actor->lastlook + 1) & 3) stop = (actor->lastlook + MAXPLAYERS - 1) % MAXPLAYERS; for ( ; ; actor->lastlook = (actor->lastlook + 1) % MAXPLAYERS) { if (!playeringame[actor->lastlook]) continue; if (c++ == 2 || actor->lastlook == stop) { // done looking return false; } player = &players[actor->lastlook]; if (player->health <= 0) continue; // dead if (!P_CheckSight (actor, player->mo)) continue; // out of sight if (!allaround) { an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; if (an > ANG90 && an < ANG270) { dist = P_AproxDistance (player->mo->x - actor->x, player->mo->y - actor->y); // if real close, react anyway if (dist > MELEERANGE) continue; // behind back } } actor->target = player->mo; return true; } return false; } // haleyjd 09/05/10: [STRIFE] Removed A_KeenDie // // ACTION ROUTINES // // // A_Look // Stay in state until a player is sighted. // // [STRIFE] // haleyjd 09/05/10: Adjusted for allies, Inquisitors, etc. // void A_Look (mobj_t* actor) { mobj_t* targ; actor->threshold = 0; // any shot will wake up targ = actor->subsector->sector->soundtarget; if (targ && (targ->flags & MF_SHOOTABLE) ) { // [STRIFE] Allies wander when they call this. if(actor->flags & MF_ALLY) A_RandomWalk(actor); else { actor->target = targ; if ( actor->flags & MF_AMBUSH ) { if (P_CheckSight (actor, actor->target)) goto seeyou; } else goto seeyou; } } // haleyjd 09/05/10: This is bizarre, as Rogue keeps using the GIVEQUEST flag // as a parameter to control allaround look behavior. Did they just run out of // flags, or what? // STRIFE-TODO: Needs serious verification. if (!P_LookForPlayers(actor, (actor->flags & MF_GIVEQUEST) != 0)) return; // go into chase state seeyou: if (actor->info->seesound) { int sound = actor->info->seesound; mobj_t * emitter = actor; // [STRIFE] Removed DOOM random sounds. // [STRIFE] Only Inquisitors roar loudly here. if (actor->type == MT_INQUISITOR) emitter = NULL; S_StartSound (emitter, sound); } // [STRIFE] Set threshold (kinda odd as it's still set to 0 above...) actor->threshold = 20; P_SetMobjState (actor, actor->info->seestate); } // // A_RandomWalk // // [STRIFE] New function. // haleyjd 09/05/10: Action routine used to meander about. // void A_RandomWalk(mobj_t* actor) { // Standing actors do not wander. if(actor->flags & MF_STAND) return; if(actor->reactiontime) actor->reactiontime--; // count down reaction time else { // turn to a new angle if(actor->movedir < DI_NODIR) { int delta; actor->angle &= (7 << 29); delta = actor->angle - (actor->movedir << 29); if(delta < 0) actor->angle += ANG90/2; else if(delta > 0) actor->angle -= ANG90/2; } // try moving if(--actor->movecount < 0 || !P_Move(actor)) { P_NewRandomDir(actor); actor->movecount += 5; } } } // // A_FriendLook // // [STRIFE] New function // haleyjd 09/05/10: Action function used mostly by mundane characters such as // peasants. // void A_FriendLook(mobj_t* actor) { mobj_t *soundtarget = actor->subsector->sector->soundtarget; actor->threshold = 0; if(soundtarget && soundtarget->flags & MF_SHOOTABLE) { // Handle allies, except on maps 3 and 34 (Front Base/Movement Base) if((actor->flags & MF_ALLY) == (soundtarget->flags & MF_ALLY) && gamemap != 3 && gamemap != 34) { // STRIFE-TODO: Needs serious verification. if(P_LookForPlayers(actor, (actor->flags & MF_GIVEQUEST) != 0)) { P_SetMobjState(actor, actor->info->seestate); actor->flags |= MF_NODIALOG; return; } } else { actor->target = soundtarget; if(!(actor->flags & MF_AMBUSH) || P_CheckSight(actor, actor->target)) { actor->threshold = 10; P_SetMobjState(actor, actor->info->seestate); return; } } } // do some idle animation if(P_Random() < 30) { int t = P_Random(); P_SetMobjState(actor, (t & 1) + actor->info->spawnstate + 1); } // wander around a bit if(!(actor->flags & MF_STAND) && P_Random() < 40) P_SetMobjState(actor, actor->info->spawnstate + 3); } // // A_Listen // // [STRIFE] New function // haleyjd 09/05/10: Action routine used to strictly listen for a target. // void A_Listen(mobj_t* actor) { mobj_t *soundtarget; actor->threshold = 0; soundtarget = actor->subsector->sector->soundtarget; if(soundtarget && (soundtarget->flags & MF_SHOOTABLE)) { if((actor->flags & MF_ALLY) != (soundtarget->flags & MF_ALLY)) { actor->target = soundtarget; if(!(actor->flags & MF_AMBUSH) || P_CheckSight(actor, actor->target)) { if(actor->info->seesound) S_StartSound(actor, actor->info->seesound); actor->threshold = 10; P_SetMobjState(actor, actor->info->seestate); } } } } // // A_Chase // Actor has a melee attack, // so it tries to close as fast as possible // // haleyjd 09/05/10: [STRIFE] Various minor changes // void A_Chase (mobj_t* actor) { int delta; if (actor->reactiontime) actor->reactiontime--; // modify target threshold if (actor->threshold) { // haleyjd 20110204 [STRIFE]: No health <= 0 check here! if (actor->target) actor->threshold--; else actor->threshold = 0; } // turn towards movement direction if not there yet if (actor->movedir < 8) { actor->angle &= (7<<29); delta = actor->angle - (actor->movedir << 29); if (delta > 0) actor->angle -= ANG90/2; else if (delta < 0) actor->angle += ANG90/2; } if (!actor->target || !(actor->target->flags&MF_SHOOTABLE)) { // look for a new target if (P_LookForPlayers(actor, true)) return; // got a new target P_SetMobjState (actor, actor->info->spawnstate); return; } // do not attack twice in a row if (actor->flags & MF_JUSTATTACKED) { actor->flags &= ~MF_JUSTATTACKED; // [STRIFE] Checks only against fastparm, not gameskill == 5 if (!fastparm) P_NewChaseDir (actor); return; } // check for melee attack if (actor->info->meleestate && P_CheckMeleeRange (actor)) { if (actor->info->attacksound) S_StartSound (actor, actor->info->attacksound); P_SetMobjState (actor, actor->info->meleestate); return; } // check for missile attack if (actor->info->missilestate) { // [STRIFE] Checks only fastparm. if (!fastparm && actor->movecount) { goto nomissile; } if (!P_CheckMissileRange (actor)) goto nomissile; P_SetMobjState (actor, actor->info->missilestate); // [STRIFE] Add NODIALOG flag to disable dialog actor->flags |= (MF_NODIALOG|MF_JUSTATTACKED); return; } // ? nomissile: // possibly choose another target if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) ) { if (P_LookForPlayers(actor, true)) return; // got a new target } // chase towards player if (--actor->movecount<0 || !P_Move (actor)) { P_NewChaseDir (actor); } // [STRIFE] Changes to active sound behavior: // * Significantly more frequent // * Acolytes have randomized wandering sounds // make active sound if (actor->info->activesound && P_Random () < 38) { if(actor->info->activesound >= sfx_agrac1 && actor->info->activesound <= sfx_agrac4) { S_StartSound(actor, sfx_agrac1 + P_Random() % 4); } else S_StartSound(actor, actor->info->activesound); } } // // A_FaceTarget // // [STRIFE] // haleyjd 09/05/10: Handling for visibility-modifying flags. // void A_FaceTarget (mobj_t* actor) { if (!actor->target) return; actor->flags &= ~MF_AMBUSH; actor->angle = R_PointToAngle2 (actor->x, actor->y, actor->target->x, actor->target->y); if(actor->target->flags & MF_SHADOW) { // [STRIFE] increased SHADOW inaccuracy by a power of 2 int t = P_Random(); actor->angle += (t - P_Random()) << 22; } else if(actor->target->flags & MF_MVIS) { // [STRIFE] MVIS gives even worse aiming! int t = P_Random(); actor->angle += (t - P_Random()) << 23; } } // // A_PeasantPunch // // [STRIFE] New function // haleyjd 09/05/10: Attack used by Peasants as a one-time retaliation // when the player or a monster injures them. Weak doesn't begin to // describe it :P // void A_PeasantPunch(mobj_t* actor) { if(!actor->target) return; A_FaceTarget(actor); if(P_CheckMeleeRange(actor)) P_DamageMobj(actor->target, actor, actor, 2 * (P_Random() % 5) + 2); } // // A_ReaverAttack // // [STRIFE] New function // haleyjd 09/06/10: Action routine used by Reavers to fire bullets. // Also apparently used by Inquistors, though they don't seem to use // it too often, as they're content to blow your face off with their // HE grenades instead. // void A_ReaverAttack(mobj_t* actor) { int i = 0; fixed_t slope; if(!actor->target) return; S_StartSound(actor, sfx_reavat); A_FaceTarget(actor); slope = P_AimLineAttack(actor, actor->angle, 2048*FRACUNIT); do { int t = P_Random(); angle_t shootangle = actor->angle + ((t - P_Random()) << 20); int damage = (P_Random() & 7) + 1; P_LineAttack(actor, shootangle, 2048*FRACUNIT, slope, damage); ++i; } while(i < 3); } // // A_BulletAttack // // [STRIFE] New function // haleyjd 09/06/10: Action function for generic bullet attacks. Used by // a lot of different characters, including Acolytes, Rebels, and Macil. // void A_BulletAttack(mobj_t* actor) { int t, damage; fixed_t slope; angle_t shootangle; if(!actor->target) return; S_StartSound(actor, sfx_rifle); A_FaceTarget(actor); slope = P_AimLineAttack(actor, actor->angle, 2048*FRACUNIT); t = P_Random(); shootangle = ((t - P_Random()) << 19) + actor->angle; damage = 3 * (P_Random() % 5 + 1); P_LineAttack(actor, shootangle, 2048*FRACUNIT, slope, damage); } // // A_CheckTargetVisible // // [STRIFE] New function // haleyjd 09/06/10: Action routine which sets a thing back to its // seestate at random, or if it cannot see its target, or its target // is dead. Used by diverse actors. // void A_CheckTargetVisible(mobj_t* actor) { A_FaceTarget(actor); if(P_Random() >= 30) { mobj_t *target = actor->target; if(!target || target->health <= 0 || !P_CheckSight(actor, target) || P_Random() < 40) { P_SetMobjState(actor, actor->info->seestate); } } } // // A_SentinelAttack // // [STRIFE] New function // haleyjd 09/06/10: Action function implementing the Sentinel's laser attack // villsa 09/06/10 implemented // void A_SentinelAttack(mobj_t* actor) { mobj_t* mo; mobj_t* mo2; fixed_t x; fixed_t y; fixed_t z; angle_t an; int i; mo = P_SpawnFacingMissile(actor, actor->target, MT_L_LASER); an = actor->angle >> ANGLETOFINESHIFT; if(mo->momy | mo->momx) // villsa - fixed typo (yes, they actually used '|' instead of'||') { for(i = 8; i > 1; i--) { x = mo->x + FixedMul(mobjinfo[MT_L_LASER].radius * i, finecosine[an]); y = mo->y + FixedMul(mobjinfo[MT_L_LASER].radius * i, finesine[an]); z = mo->z + i * (mo->momz >> 2); mo2 = P_SpawnMobj(x, y, z, MT_R_LASER); mo2->target = actor; mo2->momx = mo->momx; mo2->momy = mo->momy; mo2->momz = mo->momz; P_CheckMissileSpawn(mo2); } } mo->z += mo->momz >> 2; } // // A_StalkerThink // // [STRIFE] New function // haleyjd 09/06/10: Action function to drive Stalker logic. // void A_StalkerThink(mobj_t* actor) { statenum_t statenum; if(actor->flags & MF_NOGRAVITY) { if(actor->ceilingz - actor->info->height <= actor->z) return; statenum = S_SPID_11; // 1020 } else statenum = S_SPID_18; // 1027 P_SetMobjState(actor, statenum); } // // A_StalkerSetLook // // [STRIFE] New function // haleyjd 09/06/10: Action function to marshall transitions to the // Stalker's spawnstate. // void A_StalkerSetLook(mobj_t* actor) { statenum_t statenum; if(!actor) // weird; totally unnecessary. return; if(actor->flags & MF_NOGRAVITY) { if(actor->state->nextstate == S_SPID_01) // 1010 return; statenum = S_SPID_01; // 1010 } else { if(actor->state->nextstate == S_SPID_02) // 1011 return; statenum = S_SPID_02; // 1011 } P_SetMobjState(actor, statenum); } // // A_StalkerDrop // // [STRIFE] New function // haleyjd 09/06/10: Dead simple: removes NOGRAVITY status. // void A_StalkerDrop(mobj_t* actor) { actor->flags &= ~MF_NOGRAVITY; } // // A_StalkerScratch // // [STRIFE] New function // haleyjd 09/06/10: Action function for Stalker's attack. // void A_StalkerScratch(mobj_t* actor) { if(actor->flags & MF_NOGRAVITY) { // Drop him down before he can attack P_SetMobjState(actor, S_SPID_11); // 1020 return; } if(!actor->target) return; A_FaceTarget(actor); if(P_CheckMeleeRange(actor)) P_DamageMobj(actor->target, actor, actor, 2 * (P_Random() % 8) + 2); } // // A_FloatWeave // // [STRIFE] New function // haleyjd 09/06/10: Action function which is responsible for floating // actors' constant upward and downward movement. Probably a really bad // idea in retrospect given how dodgy the 3D clipping implementation is. // void A_FloatWeave(mobj_t* actor) { fixed_t height; fixed_t z; if(actor->threshold) return; if(actor->flags & MF_INFLOAT) return; height = actor->info->height; // v2 z = actor->floorz + 96*FRACUNIT; // v1 if ( z > actor->ceilingz - height - 16*FRACUNIT ) z = actor->ceilingz - height - 16*FRACUNIT; if ( z >= actor->z ) actor->momz += FRACUNIT; else actor->momz -= FRACUNIT; if ( z == actor->z ) actor->threshold = 4; else actor->threshold = 8; } // // A_RobotMelee // // [STRIFE] New function // haleyjd 09/06/10: Action function for Reaver and Templar melee attacks. // void A_RobotMelee(mobj_t* actor) { if(!actor->target) return; A_FaceTarget(actor); if(P_CheckMeleeRange(actor)) { S_StartSound(actor, sfx_revbld); P_DamageMobj(actor->target, actor, actor, 3 * (P_Random() % 8 + 1)); } } // // A_TemplarMauler // // [STRIFE] New function // haleyjd 09/06/10: Exactly what it sounds like. Kicks your ass. // void A_TemplarMauler(mobj_t* actor) { int i, t; int angle; int bangle; int damage; int slope; if(!actor->target) return; S_StartSound(actor, sfx_pgrdat); A_FaceTarget(actor); bangle = actor->angle; slope = P_AimLineAttack(actor, bangle, 2048*FRACUNIT); for(i = 0; i < 10; i++) { // haleyjd 09/06/10: Very carefully preserved order of P_Random calls damage = (P_Random() & 4) * 2; t = P_Random(); angle = bangle + ((t - P_Random()) << 19); t = P_Random(); slope = ((t - P_Random()) << 5) + slope; P_LineAttack(actor, angle, 2112*FRACUNIT, slope, damage); } } // // A_CrusaderAttack // // villsa [STRIFE] new codepointer // 09/06/10: Action function for the Crusader's Flamethrower. // Very similar to the player's flamethrower, seeing how it was ripped // off a Crusader by the Rat People ;) // void A_CrusaderAttack(mobj_t* actor) { if(!actor->target) return; actor->z += (8*FRACUNIT); if(P_CheckRobotRange(actor)) { A_FaceTarget(actor); actor->angle -= (ANG90 / 8); P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME); } else if(P_CheckMissileRange(actor)) { A_FaceTarget(actor); actor->z += (16*FRACUNIT); P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE); actor->angle -= (ANG45 / 32); actor->z -= (16*FRACUNIT); P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE); actor->angle += (ANG45 / 16); P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE); P_SetMobjState(actor, actor->info->seestate); actor->reactiontime += 15; } else P_SetMobjState(actor, actor->info->seestate); actor->z -= (8*FRACUNIT); } // // A_CrusaderLeft // // villsa [STRIFE] new codepointer // void A_CrusaderLeft(mobj_t* actor) { mobj_t* mo; actor->angle += (ANG90 / 16); mo = P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME); mo->momz = FRACUNIT; mo->z += (16*FRACUNIT); } // // A_CrusaderRight // // villsa [STRIFE] new codepointer // void A_CrusaderRight(mobj_t* actor) { mobj_t* mo; actor->angle -= (ANG90 / 16); mo = P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME); mo->momz = FRACUNIT; mo->z += (16*FRACUNIT); } // // A_CheckTargetVisible2 // // [STRIFE] New function // haleyjd 09/06/10: Mostly the same as CheckTargetVisible, except without // the randomness. // void A_CheckTargetVisible2(mobj_t* actor) { if(!actor->target || actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) { P_SetMobjState(actor, actor->info->seestate); } } // // A_InqFlyCheck // // [STRIFE] New function // haleyjd 09/06/10: Action function to check if an Inquisitor wishes // to take to flight. // void A_InqFlyCheck(mobj_t* actor) { if(!actor->target) return; A_FaceTarget(actor); // if not in "robot" range, shoot grenades. if(!P_CheckRobotRange(actor)) P_SetMobjState(actor, S_ROB3_14); // 1061 if(actor->z != actor->target->z) { // Take off all zig! if(actor->z + actor->height + 54*FRACUNIT < actor->ceilingz) P_SetMobjState(actor, S_ROB3_17); // 1064 } } // // A_InqGrenade // // villsa [STRIFE] new codepointer // 09/06/10: Inquisitor grenade attack action routine. // void A_InqGrenade(mobj_t* actor) { mobj_t* mo; if(!actor->target) return; A_FaceTarget(actor); actor->z += MAXRADIUS; // grenade 1 actor->angle -= (ANG45 / 32); mo = P_SpawnFacingMissile(actor, actor->target, MT_INQGRENADE); mo->momz += (9*FRACUNIT); // grenade 2 actor->angle += (ANG45 / 16); mo = P_SpawnFacingMissile(actor, actor->target, MT_INQGRENADE); mo->momz += (16*FRACUNIT); actor->z -= MAXRADIUS; } // // A_InqTakeOff // // [STRIFE] New function // haleyjd 09/06/10: Makes an Inquisitor start flying. // void A_InqTakeOff(mobj_t* actor) { angle_t an; fixed_t speed = actor->info->speed * (2 * FRACUNIT / 3); fixed_t dist; if(!actor->target) return; S_StartSound(actor, sfx_inqjmp); actor->z += 64 * FRACUNIT; A_FaceTarget(actor); an = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(finecosine[an], speed); actor->momy = FixedMul(finesine[an], speed); dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); dist /= speed; if(dist < 1) dist = 1; actor->momz = (actor->target->z - actor->z) / dist; actor->reactiontime = 60; actor->flags |= MF_NOGRAVITY; } // // A_InqFly // // [STRIFE] New function // haleyjd 09/06/10: Handles an Inquisitor in flight. // void A_InqFly(mobj_t* actor) { if(!(leveltime & 7)) S_StartSound(actor, sfx_inqjmp); if(--actor->reactiontime < 0 || !actor->momx || !actor->momy || actor->z <= actor->floorz) { // Come in for a landing. P_SetMobjState(actor, actor->info->seestate); actor->reactiontime = 0; actor->flags &= ~MF_NOGRAVITY; } } // // A_FireSigilWeapon // // [STRIFE] New function // haleyjd 09/06/10: Action function for the Entity's attack. // void A_FireSigilWeapon(mobj_t* actor) { int choice = P_Random() % 5; // STRIFE-TODO: Needs verification. This switch is just weird. switch(choice) { case 0: A_ProgrammerAttack(actor); break; // ain't not seen no case 1, bub... case 2: A_FireSigilEOffshoot(actor); break; case 3: A_SpectreCAttack(actor); break; case 4: A_SpectreDAttack(actor); break; case 5: // BUG: never used? wtf were they thinking? A_SpectreEAttack(actor); break; default: break; } } // // A_ProgrammerAttack // // [STRIFE] New function // haleyjd 09/06/10: Action function for the Programmer's main // attack; equivalent to the player's first Sigil. // void A_ProgrammerAttack(mobj_t* actor) { mobj_t *mo; if(!actor->target) return; mo = P_SpawnMobj(actor->target->x, actor->target->y, ONFLOORZ, MT_SIGIL_A_GROUND); mo->threshold = 25; mo->target = actor; mo->health = -2; mo->tracer = actor->target; } // // A_Sigil_A_Action // // [STRIFE] New function // haleyjd 09/06/10: Called by MT_SIGIL_A_GROUND to zot anyone nearby with // corny looking lightning bolts. // void A_Sigil_A_Action(mobj_t* actor) { int t, x, y, type; mobj_t *mo; if(actor->threshold) actor->threshold--; t = P_Random(); actor->momx += ((t & 3) - (P_Random() & 3)) << FRACBITS; t = P_Random(); actor->momy += ((t & 3) - (P_Random() & 3)) << FRACBITS; t = P_Random(); x = 50*FRACUNIT * ((t & 3) - (P_Random() & 3)) + actor->x; t = P_Random(); y = 50*FRACUNIT * ((t & 3) - (P_Random() & 3)) + actor->y; if(actor->threshold <= 25) type = MT_SIGIL_A_ZAP_LEFT; else type = MT_SIGIL_A_ZAP_RIGHT; mo = P_SpawnMobj(x, y, ONCEILINGZ, type); mo->momz = -18 * FRACUNIT; mo->target = actor->target; mo->health = actor->health; mo = P_SpawnMobj(actor->x, actor->y, ONCEILINGZ, MT_SIGIL_A_ZAP_RIGHT); mo->momz = -18 * FRACUNIT; mo->target = actor->target; mo->health = actor->health; } // // A_SpectreEAttack // // [STRIFE] New function // haleyjd 09/06/10: Action function for the Loremaster's Spectre. // Equivalent to the player's final Sigil attack. // void A_SpectreEAttack(mobj_t* actor) { mobj_t *mo; if(!actor->target) return; mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_SE_SHOT); mo->health = -2; } // // A_SpectreCAttack // // villsa [STRIFE] new codepointer // 09/06/10: Action routine for the Oracle's Spectre. Equivalent to the player's // third Sigil attack. // void A_SpectreCAttack(mobj_t* actor) { mobj_t* mo; int i; if(!actor->target) return; mo = P_SpawnMobj(actor->x, actor->y, actor->z + (32*FRACUNIT), MT_SIGIL_A_ZAP_RIGHT); mo->momz = -(18*FRACUNIT); mo->target = actor; mo->health = -2; mo->tracer = actor->target; actor->angle -= ANG90; for(i = 0; i < 20; i++) { actor->angle += (ANG90 / 10); mo = P_SpawnMortar(actor, MT_SIGIL_C_SHOT); mo->health = -2; mo->z = actor->z + (32*FRACUNIT); } actor->angle -= ANG90; } // // A_AlertSpectreC // // [STRIFE] New function // haleyjd 09/06/10: Action function called by the Oracle when it is // killed. Finds an MT_SPECTRE_C anywhere on the map and awakens it. // void A_AlertSpectreC(mobj_t* actor) { thinker_t *th; for(th = thinkercap.next; th != &thinkercap; th = th->next) { if(th->function.acp1 == (actionf_p1)P_MobjThinker) { mobj_t *mo = (mobj_t *)th; if(mo->type == MT_SPECTRE_C) { P_SetMobjState(mo, mo->info->seestate); mo->target = actor->target; return; } } } } // // A_Sigil_E_Action // // villsa [STRIFE] new codepointer // 09/06/10: Action routine for Sigil "E" shots. Spawns the room-filling // lightning bolts that seem to often do almost nothing. // void A_Sigil_E_Action(mobj_t* actor) { actor->angle += ANG90; P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT); actor->angle -= ANG180; P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT); actor->angle += ANG90; P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT); } // // A_SigilTrail // // villsa [STRIFE] new codepointer // void A_SigilTrail(mobj_t* actor) { mobj_t* mo; mo = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy, actor->z, MT_SIGIL_TRAIL); mo->angle = actor->angle; mo->health = actor->health; } // // A_SpectreDAttack // // [STRIFE] New function // haleyjd 09/06/10: Action function for Macil's Spectre. // Equivalent of the player's fourth Sigil attack. // void A_SpectreDAttack(mobj_t* actor) { mobj_t *mo; if(!actor->target) return; mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_SD_SHOT); mo->health = -2; mo->tracer = actor->target; } // // A_FireSigilEOffshoot // // [STRIFE] New function // haleyjd 09/06/10: Action function to fire part of a Sigil E // attack. Used at least by the Entity. // void A_FireSigilEOffshoot(mobj_t* actor) { mobj_t *mo; if(!actor->target) return; mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_E_OFFSHOOT); mo->health = -2; } // // A_ShadowOff // // villsa [STRIFE] new codepointer // 09/06/10: Disables SHADOW and MVIS flags. // void A_ShadowOff(mobj_t* actor) { actor->flags &= ~(MF_SHADOW|MF_MVIS); } // // A_ModifyVisibility // // villsa [STRIFE] new codepointer // 09/06/10: Turns on SHADOW, and turns off MVIS. // void A_ModifyVisibility(mobj_t* actor) { actor->flags |= MF_SHADOW; actor->flags &= ~MF_MVIS; } // // A_ShadowOn // // villsa [STRIFE] new codepointer // 09/06/10: Turns on SHADOW and MVIS. // void A_ShadowOn(mobj_t* actor) { actor->flags |= (MF_SHADOW|MF_MVIS); } // // A_SetTLOptions // // villsa [STRIFE] new codepointer // 09/06/10: Sets SHADOW and/or MVIS based on the thing's spawnpoint options. // void A_SetTLOptions(mobj_t* actor) { if(actor->spawnpoint.options & MTF_TRANSLUCENT) actor->flags |= MF_SHADOW; if(actor->spawnpoint.options & MTF_MVIS) actor->flags |= MF_MVIS; } // // A_BossMeleeAtk // // villsa [STRIFE] new codepointer // 09/06/10: Gratuitous melee attack used by multiple boss characters, // just for the sake of having one. It's not like anybody in their right // mind would get close to any of the maniacs that use this ;) // void A_BossMeleeAtk(mobj_t* actor) { if(!actor->target) return; P_DamageMobj(actor->target, actor, actor, 10 * (P_Random() & 9)); } // // A_BishopAttack // // villsa [STRIFE] new codepointer // 09/06/10: Bishop's homing missile attack. // void A_BishopAttack(mobj_t* actor) { mobj_t* mo; if(!actor->target) return; actor->z += MAXRADIUS; mo = P_SpawnMissile(actor, actor->target, MT_SEEKMISSILE); mo->tracer = actor->target; actor->z -= MAXRADIUS; } // // A_FireHookShot // // villsa [STRIFE] new codepointer // 09/06/10: Action function for the Loremaster's hookshot attack. // void A_FireHookShot(mobj_t* actor) { if(!actor->target) return; P_SpawnMissile(actor, actor->target, MT_HOOKSHOT); } // // A_FireChainShot // // villsa [STRIFE] new codepointer // 09/06/10: Action function for the hookshot projectile. Spawns echoes // to create a chain-like appearance. // void A_FireChainShot(mobj_t* actor) { S_StartSound(actor, sfx_tend); P_SpawnMobj(actor->x, actor->y, actor->z, MT_CHAINSHOT); // haleyjd: fixed type P_SpawnMobj(actor->x - (actor->momx >> 1), actor->y - (actor->momy >> 1), actor->z, MT_CHAINSHOT); P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy, actor->z, MT_CHAINSHOT); } // // A_MissileSmoke // // villsa [STRIFE] new codepointer // void A_MissileSmoke(mobj_t* actor) { mobj_t* mo; S_StartSound(actor, sfx_rflite); P_SpawnPuff(actor->x, actor->y, actor->z); mo = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy, actor->z, MT_MISSILESMOKE); mo->momz = FRACUNIT; } // // A_SpawnSparkPuff // // villsa [STRIFE] new codepointer // void A_SpawnSparkPuff(mobj_t* actor) { int r; mobj_t* mo; fixed_t x; fixed_t y; r = P_Random(); x = (10*FRACUNIT) * ((r & 3) - (P_Random() & 3)) + actor->x; r = P_Random(); y = (10*FRACUNIT) * ((r & 3) - (P_Random() & 3)) + actor->y; mo = P_SpawnMobj(x, y, actor->z, MT_SPARKPUFF); P_SetMobjState(mo, S_BNG4_01); // 199 mo->momz = FRACUNIT; } // haleyjd 09/05/10: [STRIFE] Removed: // A_PosAttack, A_SPosAttack, A_CPosAttack, A_CPosRefire, A_SpidRefire, // A_BspiAttack, A_TroopAttack, A_SargAttack, A_HeadAttack, A_CyberAttack, // A_BruisAttack, A_SkelMissile int TRACEANGLE = 0xE000000; // villsa [STRIFE] changed from 0xC000000 to 0xE000000 // // A_Tracer // void A_Tracer (mobj_t* actor) { angle_t exact; fixed_t dist; fixed_t slope; mobj_t* dest; //mobj_t* th; // villsa [STRIFE] removed all randomization and puff code // adjust direction dest = actor->tracer; if(!dest || dest->health <= 0) return; // change angle exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y); if(exact != actor->angle) { // villsa [STRIFE] slightly different algorithm if(exact - actor->angle <= 0x80000000) { actor->angle += TRACEANGLE; if(exact - actor->angle > 0x80000000) actor->angle = exact; } else { actor->angle -= TRACEANGLE; if (exact - actor->angle < 0x80000000) actor->angle = exact; } } exact = actor->angle>>ANGLETOFINESHIFT; actor->momx = FixedMul (actor->info->speed, finecosine[exact]); actor->momy = FixedMul (actor->info->speed, finesine[exact]); // change slope dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y); dist = dist / actor->info->speed; if (dist < 1) dist = 1; slope = (dest->z+40*FRACUNIT - actor->z) / dist; if (slope < actor->momz) actor->momz -= FRACUNIT/8; else actor->momz += FRACUNIT/8; } // // A_ProgrammerMelee // // villsa [STRIFE] new codepointer // 09/08/10: Melee attack for the Programmer. // haleyjd - fixed damage formula // void A_ProgrammerMelee(mobj_t* actor) { if(!actor->target) return; A_FaceTarget(actor); if(P_CheckMeleeRange(actor)) { int damage = 8 * (P_Random() % 10 + 1); S_StartSound(actor, sfx_mtalht); P_DamageMobj(actor->target, actor, actor, damage); } } // haleyjd 09/05/10: [STRIFE] Removed: // A_SkelWhoosh, A_SkelFist, PIT_VileCheck, A_VileChase, A_VileStart, // A_StartFire, A_FireCrackle, A_Fire, A_VileTarget, A_VileAttack // A_FatRaise, A_FatAttack1, A_FatAttack2, A_FatAttack3, A_SkullAttack, // A_PainShootSkull, A_PainAttack, A_PainDie // // A_Scream // // villsa [STRIFE] // * Has no random death sounds, so play deathsound directly // * Full-volume roars for the Entity and Inquisitor. // void A_Scream(mobj_t* actor) { if(!actor->info->deathsound) return; // Check for bosses. if(actor->type == MT_ENTITY || actor->type == MT_INQUISITOR) S_StartSound(NULL, actor->info->deathsound); // full volume else S_StartSound(actor, actor->info->deathsound); } // // A_XScream // // villsa [STRIFE] // * Robots will play deathsound while non-robots play the slop sfx // void A_XScream(mobj_t* actor) { int sound; if(actor->flags & MF_NOBLOOD && actor->info->deathsound) sound = actor->info->deathsound; else sound = sfx_slop; S_StartSound(actor, sound); } // // A_Pain // // villsa [STRIFE] // * Play random peasant sounds; otherwise play painsound directly // void A_Pain(mobj_t* actor) { int sound = actor->info->painsound; if(sound) { if(sound >= sfx_pespna && sound <= sfx_pespnd) sound = sfx_pespna + (P_Random() % 4); S_StartSound(actor, sound); } } // // A_PeasantCrash // // villsa [STRIFE] new codepointer // 09/08/10: Called from Peasant's "crash" state (not to be confused with // Heretic crash states), which is invoked when the Peasant has taken // critical but sub-fatal damage. It will "bleed out" the rest of its // health by calling this function repeatedly. // void A_PeasantCrash(mobj_t* actor) { // Set NODIALOG, because you probably wouldn't feel like talking either // if somebody just stabbed you in the gut with a punch dagger... actor->flags |= MF_NODIALOG; if(!(P_Random() % 5)) { A_Pain(actor); // inlined in asm actor->health--; } if(actor->health <= 0) P_KillMobj(actor->target, actor); } // // A_Fall // // [STRIFE] // * Set NODIALOG, and clear NOGRAVITY and SHADOW // void A_Fall (mobj_t *actor) { // villsa [STRIFE] set NODIALOG flag to stop dialog actor->flags |= MF_NODIALOG; // actor is on ground, it can be walked over // villsa [STRIFE] remove nogravity/shadow flags as well actor->flags &= ~(MF_SOLID|MF_NOGRAVITY|MF_SHADOW); } // // A_HideZombie // // villsa [STRIFE] new codepointer // Used by the "Becoming" Acolytes on the Loremaster's level. // void A_HideZombie(mobj_t* actor) { line_t junk; junk.tag = 999; EV_DoDoor(&junk, vld_blazeClose); if(actor->target && actor->target->player) P_NoiseAlert(actor->target, actor); // inlined in asm } // // A_MerchantPain // // villsa [STRIFE] new codepointer // 09/08/10: Pain pointer for merchant characters. They close up shop for // a while and set off the alarm. // void A_MerchantPain(mobj_t* actor) { line_t junk; junk.tag = 999; EV_DoDoor(&junk, vld_shopClose); if(actor->target && actor->target->player) P_NoiseAlert(actor->target, actor); // inlined in asm } // haleyjd 09/05/10: Removed unused CheckBossEnd Choco routine. // haleyjd 09/05/10: [STRIFE] Removed: // A_Hoof, A_Metal, A_BabyMetal, A_OpenShotgun2, A_LoadShotgun2, // A_CloseShotgun2, A_BrainAwake, A_BrainPain, A_BrainScream, A_BrainExplode, // A_BrainDie, A_BrainSpit, A_SpawnSound, A_SpawnFly // // A_ProgrammerDie // // villsa [STRIFE] new codepointer // 09/08/10: Action routine for the Programmer's grisly death. Spawns the // separate mechanical base object and sends it flying off in some random // direction. // void A_ProgrammerDie(mobj_t* actor) { int r; angle_t an; mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 24*FRACUNIT, MT_PROGRAMMERBASE); // haleyjd 20110223: fix add w/ANG180 r = P_Random(); an = ((r - P_Random()) << 22) + actor->angle + ANG180; mo->angle = an; P_ThrustMobj(mo, an, mo->info->speed); // inlined in asm mo->momz = P_Random() << 9; } // // A_InqTossArm // // villsa [STRIFE] new codepointer // 09/08/10: Inquisitor death action. Spawns an arm and tosses it. // void A_InqTossArm(mobj_t* actor) { int r; angle_t an; mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), MT_INQARM); r = P_Random(); an = ((r - P_Random()) << 22) + actor->angle - ANG90; mo->angle = an; P_ThrustMobj(mo, an, mo->info->speed); // inlined in asm mo->momz = P_Random() << 10; } // // A_SpawnSpectreA // // villsa [STRIFE] new codepointer (unused) // 09/08/10: Spawns Spectre A. Or would, if anything actually used this. // This is evidence that the Programmer's spectre, which appears in the // Catacombs in the final version, was originally meant to be spawned // after his death. // void A_SpawnSpectreA(mobj_t* actor) { mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_A); mo->momz = P_Random() << 9; } // // A_SpawnSpectreB // // villsa [STRIFE] new codepointer // 09/08/10: Action function to spawn the Bishop's spectre. // void A_SpawnSpectreB(mobj_t* actor) { mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_B); mo->momz = P_Random() << 9; } // // A_SpawnSpectreC // // villsa [STRIFE] new codepointer (unused) // 09/08/10: Action function to spawn the Oracle's spectre. Also // unused, because the Oracle's spectre is already present on the // map and is awakened on his death. Also left over from the // unreleased beta (and demo) versions. // void A_SpawnSpectreC(mobj_t* actor) { mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_C); mo->momz = P_Random() << 9; } // // A_SpawnSpectreD // // villsa [STRIFE] new codepointer // 09/08/10: Action function to spawn Macil's Spectre. // void A_SpawnSpectreD(mobj_t* actor) { mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_D); mo->momz = P_Random() << 9; } // // A_SpawnSpectreE // // villsa [STRIFE] new codepointer // 09/08/10: Action function to spawn the Loremaster's Spectre. // void A_SpawnSpectreE(mobj_t* actor) { mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_E); mo->momz = P_Random() << 9; } // [STRIFE] New statics - Remember the Entity's spawning position. static fixed_t entity_pos_x = 0; static fixed_t entity_pos_y = 0; static fixed_t entity_pos_z = 0; // // A_SpawnEntity // // villsa [STRIFE] new codepointer // 09/08/10: You will fall on your knees before the True God, the One Light. // void A_SpawnEntity(mobj_t* actor) { mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 70*FRACUNIT, MT_ENTITY); mo->momz = 5*FRACUNIT; entity_pos_x = mo->x; entity_pos_y = mo->y; entity_pos_z = mo->z; } // // P_ThrustMobj // // villsa [STRIFE] new function // Thrusts an thing in a specified force/direction // Beware! This is inlined everywhere in the asm // void P_ThrustMobj(mobj_t *actor, angle_t angle, fixed_t force) { angle_t an = angle >> ANGLETOFINESHIFT; actor->momx += FixedMul(finecosine[an], force); actor->momy += FixedMul(finesine[an], force); } // // A_EntityDeath // // [STRIFE] // haleyjd 09/08/10: The death of the Entity's spectre brings forth // three subentities, which are significantly less dangerous on their // own but threatening together. // void A_EntityDeath(mobj_t* actor) { mobj_t *subentity; angle_t an; fixed_t dist; dist = 2 * mobjinfo[MT_SUBENTITY].radius; // Subentity One an = actor->angle >> ANGLETOFINESHIFT; subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x, FixedMul(finesine[an], dist) + entity_pos_y, entity_pos_z, MT_SUBENTITY); subentity->target = actor->target; A_FaceTarget(subentity); P_ThrustMobj(subentity, subentity->angle, 625 << 13); // Subentity Two an = (actor->angle + ANG90) >> ANGLETOFINESHIFT; subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x, FixedMul(finesine[an], dist) + entity_pos_y, entity_pos_z, MT_SUBENTITY); subentity->target = actor->target; P_ThrustMobj(subentity, actor->angle + ANG90, 4); A_FaceTarget(subentity); // Subentity Three an = (actor->angle - ANG90) >> ANGLETOFINESHIFT; subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x, FixedMul(finesine[an], dist) + entity_pos_y, entity_pos_z, MT_SUBENTITY); subentity->target = actor->target; P_ThrustMobj(subentity, actor->angle - ANG90, 4); A_FaceTarget(subentity); } // // A_SpawnZombie // // villsa [STRIFE] new codepointer // void A_SpawnZombie(mobj_t* actor) { P_SpawnMobj(actor->x, actor->y, actor->z, MT_ZOMBIE); } // // A_ZombieInSpecialSector // // villsa [STRIFE] new codepointer // void A_ZombieInSpecialSector(mobj_t* actor) { sector_t* sector; fixed_t force; angle_t angle; int tagval; sector = actor->subsector->sector; if(actor->z != sector->floorheight) return; if(sector->special <= 15) P_DamageMobj(actor, NULL, NULL, 999); else if(sector->special == 18) { tagval = sector->tag - 100; force = (tagval % 10) << 12; angle = (tagval / 10) << 29; P_ThrustMobj(actor, angle, force); // inlined in asm } } // // A_CrystalExplode // // villsa [STRIFE] new codepointer // Throws out debris from the Power Crystal and sets its sector floorheight // to the lowest surrounding floor (this is maybe the only time a direct // level-changing action is done by an object in this fashion in any of // the DOOM engine games... they usually call a line special instead) // void A_CrystalExplode(mobj_t* actor) { sector_t* sector; mobj_t* rubble; int i; int r; sector = actor->subsector->sector; sector->lightlevel = 0; sector->floorheight = P_FindLowestFloorSurrounding(sector); // spawn rubble for(i = 0; i < 8; i++) { rubble = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RUBBLE1 + i); r = P_Random(); rubble->momx = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS; r = P_Random(); rubble->momy = ((r & 7) - (P_Random() & 7)) << FRACBITS; rubble->momz = ((P_Random() & 3) << FRACBITS) + (7*FRACUNIT); } } // [STRIFE] New static global - buffer used for various player messages. static char pmsgbuffer[80]; // // P_FreePrisoners // // haleyjd 09/08/10: [STRIFE] New function // * Called when the prisoners get freed, obviously. Gives a // message and awards quest token 13. // void P_FreePrisoners(void) { int i; DEH_snprintf(pmsgbuffer, sizeof(pmsgbuffer), "You've freed the prisoners!"); for(i = 0; i < MAXPLAYERS; i++) { P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST13); players[i].message = pmsgbuffer; } } // // P_DestroyConverter // // haleyjd 09/08/10: [STRIFE] New function // * Called when the converter is shut down in the factory. // Gives several items and a message. // void P_DestroyConverter(void) { int i; DEH_snprintf(pmsgbuffer, sizeof(pmsgbuffer), "You've destroyed the Converter!"); for(i = 0; i < MAXPLAYERS; i++) { P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST25); P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_STAMINA); P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_NEW_ACCURACY); players[i].message = pmsgbuffer; } } // // A_QuestMsg // // villsa [STRIFE] new codepointer // Displays text based on quest item's name // Quest item is based on actor's speed // void A_QuestMsg(mobj_t* actor) { char* name; int quest; int i; // get name name = DEH_String(mobjinfo[(MT_TOKEN_QUEST1 - 1) + actor->info->speed].name); M_StringCopy(pmsgbuffer, name, sizeof(pmsgbuffer)); // inlined in asm // give quest and display message to players for(i = 0; i < MAXPLAYERS; i++) { quest = 1 << (actor->info->speed - 1); players[i].message = pmsgbuffer; players[i].questflags |= quest; } } // // A_ExtraLightOff // // villsa [STRIFE] new codepointer // 09/08/10: Called by the Power Crystal to turn off the extended // flash of light caused by its explosion. // void A_ExtraLightOff(mobj_t* actor) { if(!actor->target) return; if(!actor->target->player) return; actor->target->player->extralight = 0; } // // A_CrystalRadiusAtk // // villsa [STRIFE] new codepointer // 09/08/10: Called by the power crystal when it dies. // void A_CrystalRadiusAtk(mobj_t* actor) { P_RadiusAttack(actor, actor->target, 512); if(!(actor->target && actor->target->player)) return; // set extralight to 5 for near full-bright actor->target->player->extralight = 5; } // // A_DeathExplode5 // // villsa [STRIFE] new codepointer // void A_DeathExplode5(mobj_t* actor) { P_RadiusAttack(actor, actor->target, 192); if(actor->target && actor->target->player) P_NoiseAlert(actor->target, actor); // inlined in asm } // // A_DeathExplode1 // // villsa [STRIFE] new codepointer // void A_DeathExplode1(mobj_t* actor) { P_RadiusAttack(actor, actor->target, 128); if(actor->target && actor->target->player) P_NoiseAlert(actor->target, actor); // inlined in asm } // // A_DeathExplode2 // // villsa [STRIFE] new codepointer // void A_DeathExplode2(mobj_t* actor) { P_RadiusAttack(actor, actor->target, 64); if(actor->target && actor->target->player) P_NoiseAlert(actor->target, actor); // inlined in asm } // // A_DeathExplode3 // // villsa [STRIFE] new codepointer // void A_DeathExplode3(mobj_t* actor) { P_RadiusAttack(actor, actor->target, 32); if(actor->target && actor->target->player) P_NoiseAlert(actor->target, actor); // inlined in asm } // // A_RaiseAlarm // // villsa [STRIFE] new codepointer // 09/08/10: Set off the infamous alarm. This is just a noise alert. // void A_RaiseAlarm(mobj_t* actor) { if(actor->target && actor->target->player) P_NoiseAlert(actor->target, actor); // inlined in asm } // // A_MissileTick // villsa [STRIFE] - new codepointer // void A_MissileTick(mobj_t* actor) { if(--actor->reactiontime <= 0) { P_ExplodeMissile(actor); actor->flags &= ~MF_MISSILE; } } // // A_SpawnGrenadeFire // villsa [STRIFE] - new codepointer // void A_SpawnGrenadeFire(mobj_t* actor) { P_SpawnMobj(actor->x, actor->y, actor->z, MT_PFLAME); } // // A_NodeChunk // // villsa [STRIFE] - new codepointer // Throw out "nodes" from a spectral entity // void A_NodeChunk(mobj_t* actor) { int r; mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 10*FRACUNIT, MT_NODE); r = P_Random(); mo->momx = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS; r = P_Random(); mo->momy = ((r & 7) - (P_Random() & 0x0f)) << FRACBITS; mo->momz = (P_Random() & 0x0f) << FRACBITS; } // // A_HeadChunk // // villsa [STRIFE] - new codepointer // Throw out the little "eye"-like object from a spectral entity when it dies. // void A_HeadChunk(mobj_t* actor) { int r; mobj_t* mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z + 10*FRACUNIT, MT_SPECTREHEAD); r = P_Random(); mo->momx = ((r & 7) - (P_Random() & 0x0f)) << FRACBITS; r = P_Random(); mo->momy = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS; mo->momz = (P_Random() & 7) << FRACBITS; } // // A_BurnSpread // villsa [STRIFE] - new codepointer // void A_BurnSpread(mobj_t* actor) { int t; mobj_t* mo; fixed_t x; fixed_t y; actor->momz -= (8*FRACUNIT); t = P_Random(); actor->momx += ((t & 3) - (P_Random() & 3)) << FRACBITS; t = P_Random(); actor->momy += ((t & 3) - (P_Random() & 3)) << FRACBITS; S_StartSound(actor, sfx_lgfire); if(actor->flags & MF_DROPPED) return; // not the parent // haleyjd 20110223: match order of calls in binary y = actor->y + (((P_Random() + 12) & 31) << FRACBITS); x = actor->x + (((P_Random() + 12) & 31) << FRACBITS); // spawn child mo = P_SpawnMobj(x, y, actor->z + (4*FRACUNIT), MT_PFLAME); t = P_Random(); mo->momx += ((t & 7) - (P_Random() & 7)) << FRACBITS; t = P_Random(); mo->momy += ((t & 7) - (P_Random() & 7)) << FRACBITS; mo->momz -= FRACUNIT; mo->flags |= MF_DROPPED; mo->reactiontime = (P_Random() & 3) + 2; } // // A_BossDeath // // Possibly trigger special effects // if on first boss level // // haleyjd 09/17/10: [STRIFE] // * Modified to handle all Strife bosses. // void A_BossDeath (mobj_t* actor) { int i; thinker_t *th; line_t junk; // only the following types can be a boss: switch(actor->type) { case MT_CRUSADER: case MT_SPECTRE_A: case MT_SPECTRE_B: case MT_SPECTRE_C: case MT_SPECTRE_D: case MT_SPECTRE_E: case MT_SUBENTITY: case MT_PROGRAMMER: break; default: return; } // check for a living player for(i = 0; i < MAXPLAYERS; i++) { if(playeringame[i] && players[i].health > 0) break; } if(i == MAXPLAYERS) return; // everybody's dead. // check for a still living boss for(th = thinkercap.next; th != &thinkercap; th = th->next) { if(th->function.acp1 == (actionf_p1) P_MobjThinker) { mobj_t *mo = (mobj_t *)th; if(mo != actor && mo->type == actor->type && mo->health > 0) return; // one is still alive. } } // Victory! switch(actor->type) { case MT_CRUSADER: junk.tag = 667; EV_DoFloor(&junk, lowerFloorToLowest); break; case MT_SPECTRE_A: GiveVoiceObjective("VOC95", "LOG95", 0); junk.tag = 999; EV_DoFloor(&junk, lowerFloorToLowest); break; case MT_SPECTRE_B: P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_BISHOP); GiveVoiceObjective("VOC74", "LOG74", 0); break; case MT_SPECTRE_C: // Look for an MT_ORACLE - this is for in case the player awakened the // Oracle's spectre without killing the Oracle, which is possible by // looking up to max and firing the Sigil at it. If this were not done, // a serious sequence break possibility would arise where one could // kill both the Oracle AND Macil, possibly throwing the game out of // sorts entirely. Too bad they thought of it ;) However this also // causes a bug sometimes! The Oracle, in its death state, sets the // Spectre C back to its seestate. If the Spectre C is already dead, // it becomes an undead ghost monster. Then it's a REAL spectre ;) for(th = thinkercap.next; th != &thinkercap; th = th->next) { if(th->function.acp1 == (actionf_p1) P_MobjThinker) { mobj_t *mo = (mobj_t *)th; // KILL ALL ORACLES! RAWWR! if(mo != actor && mo->type == MT_ORACLE && mo->health > 0) P_KillMobj(actor, mo); } } P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_ORACLE); // Bishop is dead? - verify. if(players[0].questflags & QF_QUEST21) P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_QUEST22); // Macil is dead? if(players[0].questflags & QF_QUEST24) { // Loremaster is dead? if(players[0].questflags & QF_QUEST26) { // We wield the complete sigil, blahblah GiveVoiceObjective("VOC85", "LOG85", 0); } } else { // So much for prognostication! GiveVoiceObjective("VOC87", "LOG87", 0); } junk.tag = 222; // Open the exit door again; EV_DoDoor(&junk, vld_open); // Note this is NOT the Loremaster door... break; case MT_SPECTRE_D: P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_MACIL); if(players[0].questflags & QF_QUEST25) // Destroyed converter? GiveVoiceObjective("VOC106", "LOG106", 0); else GiveVoiceObjective("VOC79", "LOG79", 0); break; case MT_SPECTRE_E: P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_LOREMASTER); if(!netgame) { P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_STAMINA); P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_NEW_ACCURACY); } if(players[0].sigiltype == 4) GiveVoiceObjective("VOC85", "LOG85", 0); else GiveVoiceObjective("VOC83", "LOG83", 0); junk.tag = 666; EV_DoFloor(&junk, lowerFloorToLowest); break; case MT_SUBENTITY: F_StartFinale(); break; case MT_PROGRAMMER: F_StartFinale(); G_ExitLevel(0); break; default: // Real classy, Rogue. if(actor->type) I_Error("Error: Unconnected BossDeath id %d", actor->type); break; } } // // A_AcolyteSpecial // // villsa [STRIFE] - new codepointer // Awards quest #7 when all the Blue Acolytes are killed in Tarnhill // void A_AcolyteSpecial(mobj_t* actor) { int i; thinker_t* th; if(actor->type != MT_GUARD8) return; // must be MT_GUARD8 for(i = 0; i < MAXPLAYERS; i++) { if(playeringame[i] && players[i].health > 0) break; } if(i == 8) return; for(th = thinkercap.next; th != &thinkercap; th = th->next) { if(th->function.acp1 == (actionf_p1) P_MobjThinker) { mobj_t *mo = (mobj_t *)th; // Found a living MT_GUARD8? if(mo != actor && mo->type == actor->type && mo->health > 0) return; } } // All MT_GUARD8 are dead, give quest token #7 to all players for(i = 0; i < MAXPLAYERS; i++) P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST7); // play voice, give objective GiveVoiceObjective("VOC14", "LOG14", 0); } // // A_InqChase // villsa [STRIFE] - new codepointer // void A_InqChase(mobj_t* actor) { S_StartSound(actor, sfx_inqact); A_Chase(actor); } // // A_StalkerChase // villsa [STRIFE] - new codepointer // void A_StalkerChase(mobj_t* actor) { S_StartSound(actor, sfx_spdwlk); A_Chase(actor); } // // A_PlayerScream // // [STRIFE] // * Modified to eliminate gamemode check and to use Strife sound. // void A_PlayerScream (mobj_t* mo) { // Default death sound. int sound = sfx_pldeth; // villsa [STRIFE] don't check for gamemode if(mo->health < -50) { // IF THE PLAYER DIES // LESS THAN -50% WITHOUT GIBBING sound = sfx_plxdth; // villsa [STRIFE] different sound } S_StartSound (mo, sound); } // // A_TeleportBeacon // // villsa [STRIFE] - new codepointer // void A_TeleportBeacon(mobj_t* actor) { mobj_t* mobj; mobj_t* fog; fixed_t fog_x; fixed_t fog_y; if(actor->target != players[actor->miscdata].mo) actor->target = players[actor->miscdata].mo; mobj = P_SpawnMobj(actor->x, actor->y, ONFLOORZ, MT_REBEL1); // haleyjd 20141024: missing code from disassembly; transfer allegiance // originally from master player to the rebel. mobj->miscdata = actor->miscdata; if(!P_TryMove(mobj, mobj->x, mobj->y)) { // Rebel is probably stuck in something.. too bad P_RemoveMobj(mobj); return; } // beacon no longer special actor->flags &= ~MF_SPECIAL; // set color and flags mobj->flags |= ((actor->miscdata << MF_TRANSSHIFT) | MF_NODIALOG); mobj->target = NULL; // double Rebel's health in deathmatch mode if(deathmatch) mobj->health <<= 1; if(actor->target) { mobj_t* targ = actor->target->target; if(targ) { if(targ->type != MT_REBEL1 || targ->miscdata != mobj->miscdata) mobj->target = targ; } } P_SetMobjState(mobj, mobj->info->seestate); mobj->angle = actor->angle; fog_x = mobj->x + FixedMul(20*FRACUNIT, finecosine[actor->angle>>ANGLETOFINESHIFT]); fog_y = mobj->y + FixedMul(20*FRACUNIT, finesine[actor->angle>>ANGLETOFINESHIFT]); fog = P_SpawnMobj(fog_x, fog_y, mobj->z, MT_TFOG); S_StartSound(fog, sfx_telept); if(--actor->health < 0) P_RemoveMobj(actor); } // // A_BodyParts // // villsa [STRIFE] new codepointer // 09/06/10: Spawns gibs when organic actors get splattered, or junk // when robots explode. // void A_BodyParts(mobj_t* actor) { mobjtype_t type; mobj_t* mo; angle_t an; if(actor->flags & MF_NOBLOOD) // Robots are flagged NOBLOOD type = MT_JUNK; else type = MT_MEAT; mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), type); P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 19)); an = (P_Random() << 13) / 255; mo->angle = an << ANGLETOFINESHIFT; mo->momx = FixedMul(finecosine[an], (P_Random() & 0x0f) << FRACBITS); mo->momy = FixedMul(finesine[an], (P_Random() & 0x0f) << FRACBITS); mo->momz = (P_Random() & 0x0f) << FRACBITS; } // // A_ClaxonBlare // // [STRIFE] New function // haleyjd 09/08/10: The ever-dreadful Strife alarm! // void A_ClaxonBlare(mobj_t* actor) { // Timer ran down? if(--actor->reactiontime < 0) { // reset to initial state actor->target = NULL; actor->reactiontime = actor->info->reactiontime; // listen for more noise A_Listen(actor); // If we heard something, stay on for a while, // otherwise return to spawnstate. if(actor->target) actor->reactiontime = 50; else P_SetMobjState(actor, actor->info->spawnstate); } // When almost ran down, clear the soundtarget so it doesn't // retrigger the alarm. // Also, play the harsh, grating claxon. if(actor->reactiontime == 2) actor->subsector->sector->soundtarget = NULL; else if(actor->reactiontime > 50) S_StartSound(actor, sfx_alarm); } // // A_ActiveSound // // villsa [STRIFE] new codepointer // 09/06/10: Plays an object's active sound periodically. // void A_ActiveSound(mobj_t* actor) { if(actor->info->activesound) { if(!(leveltime & 7)) // haleyjd: added parens S_StartSound(actor, actor->info->activesound); } } // // A_ClearSoundTarget // // villsa [STRIFE] new codepointer // 09/06/10: Clears the actor's sector soundtarget, so that the actor // will not be continually alerted/awakened ad infinitum. Used by // shopkeepers. // void A_ClearSoundTarget(mobj_t* actor) { actor->subsector->sector->soundtarget = NULL; } // // A_DropBurnFlesh // // villsa [STRIFE] new codepointer // void A_DropBurnFlesh(mobj_t* actor) { mobj_t* mo; mobjtype_t type; type = actor->type; mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), MT_BURNDROP); mo->momz = -FRACUNIT; actor->type = MT_SFIREBALL; P_RadiusAttack(actor, actor, 64); actor->type = type; } // // A_FlameDeath // // villsa [STRIFE] new codepointer // 09/06/10: Death animation for flamethrower fireballs. // void A_FlameDeath(mobj_t* actor) { actor->flags |= MF_NOGRAVITY; actor->momz = (P_Random() & 3) << FRACBITS; } // // A_ClearForceField // // villsa [STRIFE] new codepointer // check for all matching lines in the sector // and disable blocking/midtextures // void A_ClearForceField(mobj_t* actor) { int i; sector_t *sec; line_t *secline; actor->flags &= ~(MF_SOLID|MF_SPECIAL); sec = actor->subsector->sector; if(!sec->linecount) return; for(i = 0; i < sec->linecount; i++) { secline = sec->lines[i]; // BUG: will crash if 1S line has TWOSIDED flag! if(!(secline->flags & ML_TWOSIDED)) continue; if(secline->special != 148) continue; secline->flags &= ~ML_BLOCKING; secline->special = 0; sides[secline->sidenum[0]].midtexture = 0; sides[secline->sidenum[1]].midtexture = 0; } } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_floor.c000066400000000000000000000415211257432200600231770ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Floor animation: raising stairs. // #include "z_zone.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" // // FLOORS // // // Move a plane (floor or ceiling) and check for crushing // // [STRIFE] Various changes were made to remove calls to P_ChangeSector when // P_ChangeSector returns true. // result_e T_MovePlane ( sector_t* sector, fixed_t speed, fixed_t dest, boolean crush, int floorOrCeiling, int direction ) { boolean flag; fixed_t lastpos; switch(floorOrCeiling) { case 0: // FLOOR switch(direction) { case -1: // DOWN if (sector->floorheight - speed < dest) { // villsa [STRIFE] unused //lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector,crush); // villsa [STRIFE] unused /*if (flag == true) { sector->floorheight =lastpos; P_ChangeSector(sector,crush); //return crushed; }*/ return pastdest; } else { // villsa [STRIFE] unused //lastpos = sector->floorheight; sector->floorheight -= speed; flag = P_ChangeSector(sector,crush); // villsa [STRIFE] unused /*if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector,crush); return crushed; }*/ return ok; } break; case 1: // UP if (sector->floorheight + speed > dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector,crush); //return crushed; } return pastdest; } else { // COULD GET CRUSHED lastpos = sector->floorheight; sector->floorheight += speed; flag = P_ChangeSector(sector,crush); if (flag == true) { // haleyjd 20130210: Bug fix - Strife DOES do this. if (crush == true) return crushed; sector->floorheight = lastpos; P_ChangeSector(sector,crush); return crushed; } else return ok; } break; } break; case 1: // CEILING switch(direction) { case -1: // DOWN if (sector->ceilingheight - speed < dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector,crush); //return crushed; } return pastdest; } else { // COULD GET CRUSHED lastpos = sector->ceilingheight; sector->ceilingheight -= speed; flag = P_ChangeSector(sector,crush); if (flag == true) { if (crush == true) return crushed; sector->ceilingheight = lastpos; P_ChangeSector(sector,crush); return crushed; } } break; case 1: // UP if (sector->ceilingheight + speed > dest) { // villsa [STRIFE] unused //lastpos = sector->ceilingheight; sector->ceilingheight = dest; // villsa [STRIFE] unused //flag = P_ChangeSector(sector,crush); /*if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector,crush); //return crushed; }*/ return pastdest; } else { // villsa [STRIFE] unused //lastpos = sector->ceilingheight; sector->ceilingheight += speed; // villsa [STRIFE] unused //flag = P_ChangeSector(sector,crush); return ok; } break; } break; } return ok; } // // MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN) // void T_MoveFloor(floormove_t* floor) { result_e res; res = T_MovePlane(floor->sector, floor->speed, floor->floordestheight, floor->crush,0,floor->direction); if (!(leveltime&7)) S_StartSound(&floor->sector->soundorg, sfx_stnmov); if (res == pastdest) { floor->sector->specialdata = NULL; if (floor->direction == 1) { switch(floor->type) { case donutRaise: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } } else if (floor->direction == -1) { switch(floor->type) { case lowerAndChange: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } } P_RemoveThinker(&floor->thinker); S_StartSound(&floor->sector->soundorg, sfx_pstop); } } // // HANDLE FLOOR TYPES // // haleyjd 09/16/2010: [STRIFE] Modifications to floortypes: // * raiseFloor24 was changed into raiseFloor64 // * turboLower does not appear to adjust the floor height (STRIFE-TODO: verify) // * raiseFloor512AndChange type was added. // int EV_DoFloor ( line_t* line, floor_e floortype ) { int secnum; int rtn; int i; sector_t* sec; floormove_t* floor; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // new floor thinker rtn = 1; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); sec->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = floortype; floor->crush = false; switch(floortype) { case lowerFloor: // [STRIFE] verified unmodified floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindHighestFloorSurrounding(sec); break; case lowerFloorToLowest: // [STRIFE] verified unmodified floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestFloorSurrounding(sec); break; case turboLower: // [STRIFE] Modified: does not += 8 floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED * 4; floor->floordestheight = P_FindHighestFloorSurrounding(sec); //if (floor->floordestheight != sec->floorheight) // floor->floordestheight += 8*FRACUNIT; break; case raiseFloorCrush: // [STRIFE] verified unmodified floor->crush = true; case raiseFloor: floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestCeilingSurrounding(sec); if (floor->floordestheight > sec->ceilingheight) floor->floordestheight = sec->ceilingheight; floor->floordestheight -= (8*FRACUNIT)* (floortype == raiseFloorCrush); break; case raiseFloorTurbo: // [STRIFE] verified unmodified floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED*4; floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); break; case raiseFloorToNearest: // [STRIFE] verified unmodified floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); break; case raiseFloor64: // [STRIFE] modified from raiseFloor24! floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 64 * FRACUNIT; // [STRIFE] break; case raiseFloor512: // [STRIFE] verified unmodified floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT; break; case raiseFloor24AndChange: // [STRIFE] verified unmodified floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; sec->floorpic = line->frontsector->floorpic; sec->special = line->frontsector->special; break; case raiseFloor512AndChange: // [STRIFE] New floor type floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT; sec->floorpic = line->frontsector->floorpic; sec->special = line->frontsector->special; break; case raiseToTexture: // [STRIFE] verified unmodified { int minsize = INT_MAX; side_t* side; floor->direction = 1; floor->sector = sec; floor->speed = FLOORSPEED; for (i = 0; i < sec->linecount; i++) { if (twoSided (secnum, i) ) { side = getSide(secnum,i,0); if (side->bottomtexture >= 0) if (textureheight[side->bottomtexture] < minsize) minsize = textureheight[side->bottomtexture]; side = getSide(secnum,i,1); if (side->bottomtexture >= 0) if (textureheight[side->bottomtexture] < minsize) minsize = textureheight[side->bottomtexture]; } } floor->floordestheight = floor->sector->floorheight + minsize; } break; case lowerAndChange: // [STRIFE] verified unmodified floor->direction = -1; floor->sector = sec; floor->speed = FLOORSPEED; floor->floordestheight = P_FindLowestFloorSurrounding(sec); floor->texture = sec->floorpic; for (i = 0; i < sec->linecount; i++) { if ( twoSided(secnum, i) ) { if (getSide(secnum,i,0)->sector-sectors == secnum) { sec = getSector(secnum,i,1); if (sec->floorheight == floor->floordestheight) { floor->texture = sec->floorpic; floor->newspecial = sec->special; break; } } else { sec = getSector(secnum,i,0); if (sec->floorheight == floor->floordestheight) { floor->texture = sec->floorpic; floor->newspecial = sec->special; break; } } } } default: break; } } return rtn; } // // BUILD A STAIRCASE! // int EV_BuildStairs ( line_t* line, stair_e type ) { int secnum; int height; int i; int newsecnum; int texture; int ok; int rtn; sector_t* sec; sector_t* tsec; floormove_t* floor; // Either Watcom or Rogue moved the switch out of the loop below, probably // because it was a loop invariant, and put the default values in the // initializers here. I cannot be bothered to figure it out without doing // this myself :P fixed_t stairsize = 8*FRACUNIT; fixed_t speed = FLOORSPEED; int direction = 1; switch(type) { case build8: // [STRIFE] Verified unmodified. speed = FLOORSPEED/4; break; case turbo16: // [STRIFE] Verified unmodified. speed = FLOORSPEED*4; stairsize = 16*FRACUNIT; break; case buildDown16: // [STRIFE] New stair type stairsize = -16*FRACUNIT; direction = -1; break; } secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // new floor thinker rtn = 1; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); sec->tag = 0; // haleyjd 20140919: [STRIFE] clears tag of first stair sector sec->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->direction = direction; // haleyjd 20140919: bug fix: direction, not "1" floor->sector = sec; floor->speed = speed; height = sec->floorheight + stairsize; floor->floordestheight = height; texture = sec->floorpic; // Find next sector to raise // 1. Find 2-sided line with same sector side[0] // 2. Other side is the next sector to raise do { ok = 0; for (i = 0;i < sec->linecount;i++) { if ( !((sec->lines[i])->flags & ML_TWOSIDED) ) continue; tsec = (sec->lines[i])->frontsector; newsecnum = tsec-sectors; if (secnum != newsecnum) continue; tsec = (sec->lines[i])->backsector; newsecnum = tsec - sectors; if (tsec->floorpic != texture) continue; height += stairsize; if (tsec->specialdata) continue; sec = tsec; secnum = newsecnum; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); sec->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->direction = direction; // [STRIFE]: for buildDown16 floor->sector = sec; floor->speed = speed; floor->floordestheight = height; ok = 1; break; } } while(ok); } return rtn; } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_inter.c000066400000000000000000001135611257432200600232030ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Handling interactions (i.e., collisions). // // Data. #include "doomdef.h" #include "dstrings.h" #include "sounds.h" #include "deh_main.h" #include "deh_misc.h" #include "doomstat.h" #include "m_misc.h" #include "m_random.h" #include "i_system.h" #include "am_map.h" #include "p_local.h" #include "p_dialog.h" // villsa [STRIFE] #include "s_sound.h" #include "p_inter.h" #include "hu_stuff.h" // villsa [STRIFE] #include "z_zone.h" // villsa [STRIFE] // haleyjd [STRIFE] #include "w_wad.h" #include "p_pspr.h" #include "p_dialog.h" #include "f_finale.h" #define BONUSADD 6 // a weapon is found with two clip loads, // a big item has five clip loads // villsa [STRIFE] updated arrays int maxammo[NUMAMMO] = { 250, 50, 25, 400, 100, 30, 16 }; int clipammo[NUMAMMO] = { 10, 4, 2, 20, 4, 6, 4 }; // // GET STUFF // // // P_GiveAmmo // Num is the number of clip loads, // not the individual count (0= 1/2 clip). // Returns false if the ammo can't be picked up at all // // [STRIFE] Modified for Strife ammo types // boolean P_GiveAmmo(player_t* player, ammotype_t ammo, int num) { int oldammo; if(ammo == am_noammo) return false; if(ammo > NUMAMMO) I_Error ("P_GiveAmmo: bad type %i", ammo); if(player->ammo[ammo] == player->maxammo[ammo]) return false; if(num) num *= clipammo[ammo]; else num = clipammo[ammo]/2; if(gameskill == sk_baby || gameskill == sk_nightmare) { // give double ammo in trainer mode, // you'll need in nightmare num <<= 1; } oldammo = player->ammo[ammo]; player->ammo[ammo] += num; if(player->ammo[ammo] > player->maxammo[ammo]) player->ammo[ammo] = player->maxammo[ammo]; // If non zero ammo, // don't change up weapons, // player was lower on purpose. if(oldammo) return true; // We were down to zero, // so select a new weapon. // Preferences are not user selectable. // villsa [STRIFE] ammo update // where's the check for grenades? - haleyjd: verified no switch to grenades // haleyjd 10/03/10: don't change to electric bow when picking up poison // arrows. if(!player->readyweapon) { switch(ammo) { case am_bullets: if(player->weaponowned[wp_rifle]) player->pendingweapon = wp_rifle; break; case am_elecbolts: if(player->weaponowned[wp_elecbow]) player->pendingweapon = wp_elecbow; break; case am_cell: if(player->weaponowned[wp_mauler]) player->pendingweapon = wp_mauler; break; case am_missiles: if(player->weaponowned[wp_missile]) player->pendingweapon = wp_missile; break; default: break; } } return true; } // // P_GiveWeapon // The weapon name may have a MF_DROPPED flag ored in. // // villsa [STRIFE] some stuff has been changed/moved around // boolean P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped) { boolean gaveammo; boolean gaveweapon; // villsa [STRIFE] new code for giving alternate version // of the weapon to player if(player->weaponowned[weapon]) gaveweapon = false; else { gaveweapon = true; player->weaponowned[weapon] = true; // Alternate "sister" weapons that you also get as a bonus: switch(weapon) { case wp_elecbow: player->weaponowned[wp_poisonbow] = true; break; case wp_hegrenade: player->weaponowned[wp_wpgrenade] = true; break; case wp_mauler: player->weaponowned[wp_torpedo] = true; break; default: break; } // check for the standard weapons only if(weapon > player->readyweapon && weapon <= wp_sigil) player->pendingweapon = weapon; } if(netgame && (deathmatch != 2) && !dropped) { // leave placed weapons forever on net games if(!gaveweapon) return false; player->bonuscount += BONUSADD; player->weaponowned[weapon] = true; if(deathmatch) P_GiveAmmo(player, weaponinfo[weapon].ammo, 5); else P_GiveAmmo(player, weaponinfo[weapon].ammo, 2); if(player == &players[consoleplayer]) S_StartSound (NULL, sfx_wpnup); return false; } if(weaponinfo[weapon].ammo != am_noammo) { // give one clip with a dropped weapon, // two clips with a found weapon if(dropped) gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1); else gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); } else gaveammo = false; return(gaveweapon || gaveammo); } // // P_GiveBody // Returns false if the body isn't needed at all // // villsa [STRIFE] a lot of changes have been added for stamina // boolean P_GiveBody(player_t* player, int num) { int maxhealth; int healing; maxhealth = MAXHEALTH + player->stamina; if(num >= 0) // haleyjd 20100923: fixed to give proper amount of health { mobj_t *mo; // haleyjd 20110225: needed below... // any healing to do? if(player->health >= maxhealth) return false; // give, and cap to maxhealth player->health += num; if(player->health >= maxhealth) player->health = maxhealth; // Set mo->health for consistency. // haleyjd 20110225: Seems Strife can call this on a NULL player->mo // when giving items to players that are not in the game... mo = P_SubstNullMobj(player->mo); mo->health = player->health; } else { // [STRIFE] handle healing from the Front's medic // The amount the player's health will be set to scales up with stamina // increases. // Ex 1: On the wimpiest skill level, -100 is sent in. This restores // full health no matter what your stamina. // (100*100)/100 = 100 // (200*100)/100 = 200 // Ex 2: On the most stringent skill levels, -50 is sent in. This will // restore at most half of your health. // (100*50)/100 = 50 // (200*50)/100 = 100 healing = (-num * maxhealth) / MAXHEALTH; // This is also the "threshold" of healing. You need less health than // the amount that will be restored in order to get any benefit. // So on the easiest skill you will always be fully healed. // On the hardest skill you must have less than 50 health, and will // only recover to 50 (assuming base stamina stat) if(player->health >= healing) return false; // Set health. BUG: Oddly, mo->health is NOT set here... player->health = healing; } return true; } // // P_GiveArmor // Returns false if the armor is worse // than the current armor. // // [STRIFE] Modified for Strife armor items // boolean P_GiveArmor(player_t* player, int armortype) { int hits; // villsa [STRIFE] if(armortype < 0) { if(player->armorpoints) return false; armortype = -armortype; } hits = armortype * 100; if(player->armorpoints >= hits) return false; // don't pick up player->armortype = armortype; player->armorpoints = hits; return true; } // // P_GiveCard // // [STRIFE] Modified to use larger bonuscount // boolean P_GiveCard(player_t* player, card_t card) { if (player->cards[card]) return false; // villsa [STRIFE] multiply by 2 player->bonuscount = BONUSADD * 2; player->cards[card] = true; return true; } // // P_GivePower // // [STRIFE] Modifications for new powerups // boolean P_GivePower(player_t* player, powertype_t power) { // haleyjd 09/14/10: [STRIFE] moved to top, exception for Shadow Armor if(player->powers[power] && power != pw_invisibility) return false; // already got it // if giving pw_invisibility and player already has MVIS, no can do. if(power == pw_invisibility && (player->mo->flags & MF_MVIS)) return false; // villsa [STRIFE] if(power == pw_targeter) { player->powers[power] = TARGTICS; P_SetPsprite(player, ps_targcenter, S_TRGT_00); // 10 P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11 P_SetPsprite(player, ps_targright, S_TRGT_02); // 12 player->psprites[ps_targcenter].sx = (160*FRACUNIT); player->psprites[ps_targleft ].sy = (100*FRACUNIT); player->psprites[ps_targcenter].sy = (100*FRACUNIT); player->psprites[ps_targright ].sy = (100*FRACUNIT); return true; } if(power == pw_invisibility) { // if player already had this power... if(player->powers[power]) { // remove SHADOW, give MVIS. player->mo->flags &= ~MF_SHADOW; player->mo->flags |= MF_MVIS; } else // give SHADOW player->mo->flags |= MF_SHADOW; // set tics if giving shadow, or renew them if MVIS. player->powers[power] = INVISTICS; return true; } if(power == pw_ironfeet) { player->powers[power] = IRONTICS; return true; } if(power == pw_strength) { P_GiveBody(player, 100); player->powers[power] = 1; return true; } // villsa [STRIFE] if(power == pw_allmap) { // remember in mapstate if(gamemap < 40) player->mapstate[gamemap] = true; player->powers[power] = 1; return true; } // villsa [STRIFE] if(power == pw_communicator) { player->powers[power] = 1; return true; } // default behavior: player->powers[power] = 1; return true; } // villsa [STRIFE] static char pickupmsg[80]; // // P_TouchSpecialThing // // [STRIFE] Rewritten for Strife collectables. // void P_TouchSpecialThing(mobj_t* special, mobj_t* toucher) { player_t* player; int i; fixed_t delta; int sound; delta = special->z - toucher->z; if(delta > toucher->height || delta < -8*FRACUNIT) return; // out of reach sound = sfx_itemup; player = toucher->player; // Dead thing touching. // Can happen with a sliding player corpse. if(toucher->health <= 0) return; // villsa [STRIFE] damage toucher if special is spectral // haleyjd 09/21/10: corrected to test for SPECTRE thingtypes specifically switch(special->type) { case MT_SPECTRE_A: case MT_SPECTRE_B: case MT_SPECTRE_C: case MT_SPECTRE_D: case MT_SPECTRE_E: case MT_ENTITY: case MT_SUBENTITY: P_DamageMobj(toucher, NULL, NULL, 5); return; default: break; } // villsa [STRIFE] pickupmsg[0] = 0; // Identify by sprite. // villsa [STRIFE] new items switch(special->sprite) { // bullets case SPR_BLIT: // haleyjd: fixed missing MF_DROPPED check if(!P_GiveAmmo(player, am_bullets, !(special->flags & MF_DROPPED))) return; break; // box of bullets case SPR_BBOX: if(!P_GiveAmmo(player, am_bullets, 5)) return; break; // missile case SPR_ROKT: if(!P_GiveAmmo(player, am_missiles, 1)) return; break; // box of missiles case SPR_MSSL: if(!P_GiveAmmo(player, am_missiles, 5)) return; break; // battery case SPR_BRY1: if(!P_GiveAmmo(player, am_cell, 1)) return; break; // cell pack case SPR_CPAC: if(!P_GiveAmmo(player, am_cell, 5)) return; break; // poison bolts case SPR_PQRL: if(!P_GiveAmmo(player, am_poisonbolts, 5)) return; break; // electric bolts case SPR_XQRL: if(!P_GiveAmmo(player, am_elecbolts, 5)) return; break; // he grenades case SPR_GRN1: if(!P_GiveAmmo(player, am_hegrenades, 1)) return; break; // wp grenades case SPR_GRN2: if(!P_GiveAmmo(player, am_wpgrenades, 1)) return; break; // rifle case SPR_RIFL: if(!P_GiveWeapon(player, wp_rifle, (special->flags & MF_DROPPED) != 0)) return; sound = sfx_wpnup; // haleyjd: SHK-CHK! break; // flame thrower case SPR_FLAM: if(!P_GiveWeapon(player, wp_flame, false)) return; // haleyjd: gives extra ammo. P_GiveAmmo(player, am_cell, 3); sound = sfx_wpnup; // haleyjd: SHK-CHK! break; // missile launcher case SPR_MMSL: if(!P_GiveWeapon(player, wp_missile, false)) return; sound = sfx_wpnup; // haleyjd: SHK-CHK! break; // grenade launcher case SPR_GRND: if(!P_GiveWeapon(player, wp_hegrenade, (special->flags & MF_DROPPED) != 0)) return; sound = sfx_wpnup; // haleyjd: SHK-CHK! break; // mauler case SPR_TRPD: if(!P_GiveWeapon(player, wp_mauler, false)) return; sound = sfx_wpnup; // haleyjd: SHK-CHK! break; // electric bolt crossbow case SPR_CBOW: if(!P_GiveWeapon(player, wp_elecbow, (special->flags & MF_DROPPED) != 0)) return; sound = sfx_wpnup; // haleyjd: SHK-CHK! break; // haleyjd 09/21/10: missed case: THE SIGIL! case SPR_SIGL: if(!P_GiveWeapon(player, wp_sigil, (special->flags & MF_DROPPED) != 0)) { player->sigiltype = special->frame; return; } if(netgame) player->sigiltype = 4; player->pendingweapon = wp_sigil; player->st_update = true; if(deathmatch) return; sound = sfx_wpnup; break; // backpack case SPR_BKPK: if(!player->backpack) { for(i = 0; i < NUMAMMO; i++) player->maxammo[i] *= 2; player->backpack = true; } for(i = 0; i < NUMAMMO; i++) P_GiveAmmo(player, i, 1); break; // 1 Gold case SPR_COIN: P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; // 10 Gold case SPR_CRED: for(i = 0; i < 10; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; // 25 Gold case SPR_SACK: // haleyjd 09/21/10: missed code: if a SPR_SACK object has negative // health, it will give that much gold - STRIFE-TODO: verify if(special->health < 0) { for(i = special->health; i != 0; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); } else { for(i = 0; i < 25; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); } break; // 50 Gold case SPR_CHST: for(i = 0; i < 50; i++) P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); break; // Leather Armor case SPR_ARM1: if(!P_GiveArmor(player, -2)) if(!P_GiveInventoryItem(player, special->sprite, special->type)) pickupmsg[0] = '!'; break; // Metal Armor case SPR_ARM2: if(!P_GiveArmor(player, -1)) if(!P_GiveInventoryItem(player, special->sprite, special->type)) pickupmsg[0] = '!'; break; // All-map powerup case SPR_PMAP: if(!P_GivePower(player, pw_allmap)) return; sound = sfx_yeah; break; // The Comm Unit - because you need Blackbird whining in your ear the // whole time and telling you how lost she is :P case SPR_COMM: if(!P_GivePower(player, pw_communicator)) return; sound = sfx_yeah; break; // haleyjd 09/21/10: missed case - Shadow Armor; though, I do not know why // this has a case distinct from generic inventory items... Maybe it started // out as an auto-use-if-possible item much like regular armor... case SPR_SHD1: if(!P_GiveInventoryItem(player, SPR_SHD1, special->type)) pickupmsg[0] = '!'; break; // villsa [STRIFE] check default items case SPR_TOKN: default: if(special->type >= MT_KEY_BASE && special->type <= MT_NEWKEY5) { // haleyjd 09/21/10: Strife player still picks up keys that // he has already found. (break, not return) if(!P_GiveCard(player, special->type - MT_KEY_BASE)) break; } else { if(!P_GiveInventoryItem(player, special->sprite, special->type)) pickupmsg[0] = '!'; } break; } // villsa [STRIFE] set message if(!pickupmsg[0]) { if(special->info->name) { DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You picked up the %s.", DEH_String(special->info->name)); } else DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You picked up the item."); } // use the first character to indicate that the player is full on items else if(pickupmsg[0] == '!') { DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You cannot hold any more."); player->message = pickupmsg; return; } if(special->flags & MF_GIVEQUEST) { // [STRIFE]: Award quest flag based on the thing's speed. Quest 8 was // apparently at some point given by the Broken Power Coupling, which is // why they don't want to award it if you have Quest 6 (which is // acquired by destroying the Front's working power coupling). BUT, the // broken coupling object's speed is NOT 8... it is 512*FRACUNIT. For // strict portability beyond the x86, we need to AND the operand by 31. if(special->info->speed != 8 || !(player->questflags & QF_QUEST6)) player->questflags |= 1 << ((special->info->speed - 1) & 31); } // haleyjd 08/30/10: [STRIFE] No itemcount //if (special->flags & MF_COUNTITEM) // player->itemcount++; P_RemoveMobj(special); player->message = pickupmsg; player->bonuscount += BONUSADD; if(player == &players[consoleplayer]) S_StartSound(NULL, sound); } // villsa [STRIFE] static char plrkilledmsg[80]; // // KillMobj // // [STRIFE] Major modifications for drop types, no tic randomization, etc. // void P_KillMobj(mobj_t* source, mobj_t* target) { mobjtype_t item; mobj_t* mo; line_t junk; int i; // villsa [STRIFE] corpse and dropoff are removed, but why when these two flags // are set a few lines later? watcom nonsense perhaps? target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_BOUNCE|MF_CORPSE|MF_DROPOFF); // villsa [STRIFE] unused /* if (target->type != MT_SKULL) target->flags &= ~MF_NOGRAVITY; */ target->flags |= MF_CORPSE|MF_DROPOFF; target->height = FRACUNIT; // villsa [STRIFE] set to fracunit instead of >>= 2 if(source && source->player) { // count for intermission if(target->flags & MF_COUNTKILL) source->player->killcount++; if(target->player) { source->player->frags[target->player-players]++; // villsa [STRIFE] new messages when fragging players // haleyjd 20141024: corrected; uses player->allegiance, not mo->miscdata DEH_snprintf(plrkilledmsg, sizeof(plrkilledmsg), "%s killed %s", player_names[source->player->allegiance], player_names[target->player->allegiance]); if(netgame) players[consoleplayer].message = plrkilledmsg; } } else if(!netgame && (target->flags & MF_COUNTKILL)) { // count all monster deaths, // even those caused by other monsters players[0].killcount++; } if(target->player) { // count environment kills against you if(!source) target->player->frags[target->player-players]++; if(gamemap == 29 && !netgame) { // haleyjd 09/13/10: [STRIFE] Give player the bad ending. F_StartFinale(); return; } // villsa [STRIFE] spit out inventory items when killed if(netgame) { int amount = 0; mobj_t* loot; int r = 0; while(1) { if(target->player->inventory[0].amount <= 0) break; item = target->player->inventory[0].type; if(item == MT_MONY_1) { loot = P_SpawnMobj(target->x, target->y, target->z + (24*FRACUNIT), MT_MONY_25); // [STRIFE] TODO - what the hell is it doing here? loot->health = target->player->inventory[0].amount; loot->health = -target->player->inventory[0].amount; amount = target->player->inventory[0].amount; } else { loot = P_SpawnMobj(target->x, target->y, target->z + (24*FRACUNIT), item); amount = 1; } P_RemoveInventoryItem(target->player, 0, amount); r = P_Random(); loot->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS; loot->momy += ((P_Random() & 7) + 1) << FRACBITS; loot->flags |= MF_DROPPED; } } target->flags &= ~MF_SOLID; target->player->playerstate = PST_DEAD; target->player->mo->momz = 5*FRACUNIT; // [STRIFE]: small hop! P_DropWeapon(target->player); if(target->player == &players[consoleplayer] && automapactive) { // don't die in auto map, // switch view prior to dying AM_Stop (); } } // villsa [STRIFE] some modifications to setting states if(target->state != &states[S_BURN_23]) { if(target->health == -6666) P_SetMobjState(target, S_DISR_00); // 373 else { if(target->health < -target->info->spawnhealth && target->info->xdeathstate) P_SetMobjState(target, target->info->xdeathstate); else P_SetMobjState(target, target->info->deathstate); } } // villsa [STRIFE] no death tics randomization // Drop stuff. // villsa [STRIFE] get item from dialog target item = P_DialogFind(target->type, target->miscdata)->dropitem; if(!item) { // villsa [STRIFE] drop default items switch(target->type) { case MT_ORACLE: item = MT_MEAT; break; case MT_PROGRAMMER: item = MT_SIGIL_A; break; case MT_PRIEST: item = MT_JUNK; break; case MT_BISHOP: item = MT_AMINIBOX; break; case MT_PGUARD: case MT_CRUSADER: item = MT_ACELL; break; case MT_RLEADER: item = MT_AAMMOBOX; break; case MT_GUARD1: case MT_REBEL1: case MT_SHADOWGUARD: item = MT_ACLIP; break; case MT_SPECTRE_B: item = MT_SIGIL_B; break; case MT_SPECTRE_C: item = MT_SIGIL_C; break; case MT_SPECTRE_D: item = MT_SIGIL_D; break; case MT_SPECTRE_E: item = MT_SIGIL_E; break; case MT_COUPLING: junk.tag = 225; EV_DoDoor(&junk, vld_close); junk.tag = 44; EV_DoFloor(&junk, lowerFloor); GiveVoiceObjective("VOC13", "LOG13", 0); item = MT_COUPLING_BROKEN; players[0].questflags |= (1 << (mobjinfo[MT_COUPLING].speed - 1)); break; default: return; } } // handle special case for scripted target's dropped item switch(item) { case MT_TOKEN_SHOPCLOSE: junk.tag = 222; EV_DoDoor(&junk, vld_close); P_NoiseAlert(players[0].mo, players[0].mo); M_snprintf(plrkilledmsg, sizeof(plrkilledmsg), "%s", DEH_String("You're dead! You set off the alarm.")); if(!deathmatch) players[consoleplayer].message = plrkilledmsg; return; case MT_TOKEN_PRISON_PASS: junk.tag = 223; EV_DoDoor(&junk, vld_open); return; case MT_TOKEN_DOOR3: junk.tag = 224; EV_DoDoor(&junk, vld_open); return; case MT_SIGIL_A: case MT_SIGIL_B: case MT_SIGIL_C: case MT_SIGIL_D: case MT_SIGIL_E: for(i = 0; i < MAXPLAYERS; i++) { if(!P_GiveWeapon(&players[i], wp_sigil, false)) { if(players[i].sigiltype++ > 4) players[i].sigiltype = 4; } // haleyjd 20110225: fixed these two assignments which Watcom munged // up in the assembly by pre-incrementing the pointer into players[] players[i].st_update = true; players[i].pendingweapon = wp_sigil; } return; case MT_TOKEN_ALARM: P_NoiseAlert(players[0].mo, players[0].mo); M_snprintf(plrkilledmsg, sizeof(plrkilledmsg), "%s", DEH_String("You Fool! You've set off the alarm")); if(!deathmatch) players[consoleplayer].message = plrkilledmsg; return; default: break; } // villsa [STRIFE] toss out item if(!deathmatch || !(mobjinfo[item].flags & MF_NOTDMATCH)) { int r; mo = P_SpawnMobj(target->x, target->y, target->z + (24*FRACUNIT), item); r = P_Random(); mo->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS; r = P_Random(); mo->momy += ((r & 7) - (P_Random() & 7)) << FRACBITS; mo->flags |= (MF_SPECIAL|MF_DROPPED); // special versions of items } } // // P_IsMobjBoss // // villsa [STRIFE] new function // static boolean P_IsMobjBoss(mobjtype_t type) { switch(type) { case MT_PROGRAMMER: case MT_BISHOP: case MT_RLEADER: case MT_ORACLE: case MT_PRIEST: return true; default: return false; } } // // P_DamageMobj // Damages both enemies and players // "inflictor" is the thing that caused the damage // creature or missile, can be NULL (slime, etc) // "source" is the thing to target after taking damage // creature or NULL // Source and inflictor are the same for melee attacks. // Source can be NULL for slime, barrel explosions // and other environmental stuff. // // [STRIFE] Extensive changes for spectrals, fire damage, disintegration, and // a plethora of mobjtype-specific hacks. // void P_DamageMobj(mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage) { angle_t ang; int saved; player_t* player; fixed_t thrust; int temp; if(!(target->flags & MF_SHOOTABLE) ) return; // shouldn't happen... if(target->health <= 0) return; player = target->player; // villsa [STRIFE] unused - skullfly check (removed) // villsa [STRIFE] handle spectral stuff // notes on projectile health: // -2 == enemy spectral projectile // -1 == player spectral projectile // haleyjd 20110203: refactored completely if(inflictor && (inflictor->flags & MF_SPECTRAL)) { // players aren't damaged by their own (or others???) sigils // STRIFE-TODO: verify in deathmatch if(target->type == MT_PLAYER && inflictor->health == -1) return; // enemies aren't damaged by enemy sigil attacks if((target->flags & MF_SPECTRAL) && inflictor->health == -2) return; // Macil2, Oracle, and Spectre C cannot be damaged by Sigil A switch(target->type) { case MT_RLEADER2: case MT_ORACLE: case MT_SPECTRE_C: // haleyjd: added source->player validity check for safety... if(source->player && source->player->sigiltype < 1) return; default: break; } } // villsa [STRIFE] new checks for various actors if(inflictor) { // Fire damage inflictors if(inflictor->type == MT_SFIREBALL || inflictor->type == MT_C_FLAME || inflictor->type == MT_PFLAME) { temp = damage / 2; if(P_IsMobjBoss(target->type)) damage /= 2; else if(inflictor->type == MT_PFLAME) { damage /= 2; // robots take very little damage if(target->flags & MF_NOBLOOD) damage = temp / 2; } } else { switch(inflictor->type) { case MT_HOOKSHOT: // haleyjd 20110203: should use source, not inflictor ang = R_PointToAngle2( target->x, target->y, source->x, source->y) >> ANGLETOFINESHIFT; target->momx += FixedMul(finecosine[ang], (12750*FRACUNIT) / target->info->mass); target->momy += FixedMul(finesine[ang], (12750*FRACUNIT) / target->info->mass); target->reactiontime += 10; temp = P_AproxDistance(target->x - source->x, target->y - source->y); temp /= target->info->mass; if(temp < 1) temp = 1; target->momz = (source->z - target->z) / temp; break; case MT_POISARROW: // don't affect robots if(target->flags & MF_NOBLOOD) return; // instant kill damage = target->health + 10; break; default: // Spectral retaliation, though this may in fact be unreachable // since non-spectral inflictors are mostly filtered out. if(target->flags & MF_SPECTRAL && !(inflictor->flags & MF_SPECTRAL)) { P_SetMobjState(target, target->info->missilestate); return; // take no damage } break; } } } // villsa [STRIFE] special cases for shopkeepers and macil if((target->type >= MT_SHOPKEEPER_W && target->type <= MT_SHOPKEEPER_M) || target->type == MT_RLEADER) { if(source) target->target = source; P_SetMobjState(target, target->info->painstate); return; } // villsa [STRIFE] handle fieldguard damage if(target->type == MT_FIELDGUARD) { // degnin ores are only allowed to damage the fieldguard if(!inflictor || inflictor->type != MT_DEGNINORE) return; damage = target->health; } if(player && gameskill == sk_baby) damage >>= 1; // take half damage in trainer mode // Some close combat weapons should not // inflict thrust and push the victim out of reach, // thus kick away unless using the chainsaw. if (inflictor && !(target->flags & MF_NOCLIP) && (!source || !source->player || source->player->readyweapon != wp_flame)) { ang = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y); thrust = damage * (FRACUNIT>>3) * 100 / target->info->mass; // make fall forwards sometimes if(damage < 40 && damage > target->health && target->z - inflictor->z > 64*FRACUNIT && (P_Random() & 1)) { ang += ANG180; thrust *= 4; } ang >>= ANGLETOFINESHIFT; target->momx += FixedMul (thrust, finecosine[ang]); target->momy += FixedMul (thrust, finesine[ang]); } // player specific if(player) { // end of game hell hack if (target->subsector->sector->special == 11 && damage >= target->health) { damage = target->health - 1; } // Below certain threshold, // ignore damage in GOD mode. // villsa [STRIFE] removed pw_invulnerability check if(damage < 1000 && (player->cheats & CF_GODMODE)) return; // villsa [STRIFE] flame attacks don't damage player if wearing envirosuit if(player->powers[pw_ironfeet] && inflictor) { if(inflictor->type == MT_SFIREBALL || inflictor->type == MT_C_FLAME || inflictor->type == MT_PFLAME) { damage = 0; } } if(player->armortype) { if (player->armortype == 1) saved = damage/3; else saved = damage/2; if(player->armorpoints <= saved) { // armor is used up saved = player->armorpoints; player->armortype = 0; // villsa [STRIFE] P_UseInventoryItem(player, SPR_ARM1); P_UseInventoryItem(player, SPR_ARM2); } player->armorpoints -= saved; damage -= saved; } player->health -= damage; // mirror mobj health here for Dave // [STRIFE] haleyjd 20130302: bug fix - this is *not* capped here. //if(player->health < 0) // player->health = 0; player->attacker = source; player->damagecount += damage; // add damage after armor / invuln // haleyjd 20110203 [STRIFE]: target->target set here if(target != source) target->target = source; if(player->damagecount > 100) player->damagecount = 100; // teleport stomp does 10k points... temp = damage < 100 ? damage : 100; if(player == &players[consoleplayer]) I_Tactile (40,10,40+temp*2); } // do the damage target->health -= damage; // villsa [STRIFE] auto use medkits if(player && player->health < 50) { if(deathmatch || player->cheats & CF_AUTOHEALTH) { while(player->health < 50 && P_UseInventoryItem(player, SPR_MDKT)); while(player->health < 50 && P_UseInventoryItem(player, SPR_STMP)); } } if(target->health <= 0) { // villsa [STRIFE] grenades hurt... OUCH if(inflictor && inflictor->type == MT_HEGRENADE) target->health = -target->info->spawnhealth; else if(!(target->flags & MF_NOBLOOD)) { // villsa [STRIFE] disintegration death if(inflictor && (inflictor->type == MT_STRIFEPUFF3 || inflictor->type == MT_L_LASER || inflictor->type == MT_TORPEDO || inflictor->type == MT_TORPEDOSPREAD)) { S_StartSound(target, sfx_dsrptr); target->health = -6666; } } // villsa [STRIFE] flame death stuff if(!(target->flags & MF_NOBLOOD) && inflictor && (inflictor->type == MT_SFIREBALL || inflictor->type == MT_C_FLAME || inflictor->type == MT_PFLAME)) { target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SHADOW|MF_MVIS); if(target->player) { target->player->cheats |= CF_ONFIRE; target->player->powers[pw_communicator] = false; target->player->readyweapon = 0; P_SetPsprite(target->player, ps_weapon, S_WAVE_00); // 02 P_SetPsprite(target->player, ps_flash, S_NULL); } P_SetMobjState(target, S_BURN_00); // 349 S_StartSound(target, sfx_burnme); return; } P_KillMobj(source, target); return; } // villsa [STRIFE] set crash state if(target->health <= 6 && target->info->crashstate) { P_SetMobjState(target, target->info->crashstate); return; } if(damage) { // villsa [STRIFE] removed unused skullfly flag if(P_Random() < target->info->painchance) { target->flags |= MF_JUSTHIT; // fight back! P_SetMobjState (target, target->info->painstate); } } target->reactiontime = 0; // we're awake now... // villsa [STRIFE] new checks for thing types if (target->type != MT_PROGRAMMER && (!target->threshold || target->type == MT_ENTITY) && source && source != target && source->type != MT_ENTITY && ((source->flags & MF_ALLY) != (target->flags & MF_ALLY))) { // if not intent on another player, // chase after this one target->target = source; target->threshold = BASETHRESHOLD; if(target->state == &states[target->info->spawnstate] && target->info->seestate != S_NULL) P_SetMobjState (target, target->info->seestate); } } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_inter.h000066400000000000000000000021341257432200600232010ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // // #ifndef __P_INTER__ #define __P_INTER__ // haleyjd [STRIFE]: Multiple externals added boolean P_GiveCard(player_t* player, card_t card); boolean P_GiveBody(player_t* player, int num); boolean P_GiveArmor(player_t* player, int armortype); boolean P_GivePower(player_t* player, powertype_t power); boolean P_GiveAmmo(player_t* player, ammotype_t ammo, int num); boolean P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped); void P_KillMobj(mobj_t* source, mobj_t* target); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/p_lights.c000066400000000000000000000172671257432200600233620ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Handle Sector base lighting effects. // Muzzle flash? // #include "z_zone.h" #include "m_random.h" #include "doomdef.h" #include "p_local.h" // State. #include "r_state.h" // // FIRELIGHT FLICKER // // // T_FireFlicker // // [STRIFE] // haleyjd 2011023: Changes to amount and duration of flicker // void T_FireFlicker (fireflicker_t* flick) { int amount; if (--flick->count) return; amount = (P_Random() & 3) * 8; // [STRIFE] 16 -> 8 if (flick->sector->lightlevel - amount < flick->minlight) flick->sector->lightlevel = flick->minlight; else flick->sector->lightlevel = flick->maxlight - amount; // [STRIFE] flicker count made random! flick->count = (P_Random() & 3) + 1; } // // P_SpawnFireFlicker // // [STRIFE] // haleyjd 2011023: Changes to minimum light level and initial duration // void P_SpawnFireFlicker (sector_t* sector) { fireflicker_t* flick; // Note that we are resetting sector attributes. // Nothing special about it during gameplay. sector->special = 0; flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0); P_AddThinker (&flick->thinker); flick->thinker.function.acp1 = (actionf_p1) T_FireFlicker; flick->sector = sector; flick->maxlight = sector->lightlevel; flick->minlight = sector->lightlevel - 32; // [STRIFE] changed from min surrounding+16 flick->count = 2; // [STRIFE]: Initial count 4 -> 2 } // // BROKEN LIGHT FLASHING // // // T_LightFlash // Do flashing lights. // // [STRIFE] Verified unmodified // void T_LightFlash (lightflash_t* flash) { if (--flash->count) return; if (flash->sector->lightlevel == flash->maxlight) { flash->sector->lightlevel = flash->minlight; flash->count = (P_Random()&flash->mintime)+1; } else { flash->sector->lightlevel = flash->maxlight; flash->count = (P_Random()&flash->maxtime)+1; } } // // P_SpawnLightFlash // After the map has been loaded, scan each sector // for specials that spawn thinkers // // [STRIFE] Verified unmodified // void P_SpawnLightFlash (sector_t* sector) { lightflash_t* flash; // nothing special about it during gameplay sector->special = 0; flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); P_AddThinker (&flash->thinker); flash->thinker.function.acp1 = (actionf_p1) T_LightFlash; flash->sector = sector; flash->maxlight = sector->lightlevel; flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); flash->maxtime = 64; flash->mintime = 7; flash->count = (P_Random()&flash->maxtime)+1; } // // STROBE LIGHT FLASHING // // // T_StrobeFlash // // [STRIFE] Verified unmodified // void T_StrobeFlash (strobe_t* flash) { if (--flash->count) return; if (flash->sector->lightlevel == flash->minlight) { flash-> sector->lightlevel = flash->maxlight; flash->count = flash->brighttime; } else { flash-> sector->lightlevel = flash->minlight; flash->count =flash->darktime; } } // // P_SpawnStrobeFlash // After the map has been loaded, scan each sector // for specials that spawn thinkers // // [STRIFE] Verified unmodified // void P_SpawnStrobeFlash ( sector_t* sector, int fastOrSlow, int inSync ) { strobe_t* flash; flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); P_AddThinker (&flash->thinker); flash->sector = sector; flash->darktime = fastOrSlow; flash->brighttime = STROBEBRIGHT; flash->thinker.function.acp1 = (actionf_p1) T_StrobeFlash; flash->maxlight = sector->lightlevel; flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); if (flash->minlight == flash->maxlight) flash->minlight = 0; // nothing special about it during gameplay sector->special = 0; if (!inSync) flash->count = (P_Random()&7)+1; else flash->count = 1; } // // Start strobing lights (usually from a trigger) // // [STRIFE] Verified unmodified // void EV_StartLightStrobing(line_t* line) { int secnum; sector_t* sec; secnum = -1; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; P_SpawnStrobeFlash (sec, SLOWDARK, 0); } } // // TURN LINE'S TAG LIGHTS OFF // // [STRIFE] Verified unmodified // void EV_TurnTagLightsOff(line_t* line) { int i; int j; int min; sector_t* sector; sector_t* tsec; line_t* templine; sector = sectors; for (j = 0;j < numsectors; j++, sector++) { if (sector->tag == line->tag) { min = sector->lightlevel; for (i = 0;i < sector->linecount; i++) { templine = sector->lines[i]; tsec = getNextSector(templine,sector); if (!tsec) continue; if (tsec->lightlevel < min) min = tsec->lightlevel; } sector->lightlevel = min; } } } // // TURN LINE'S TAG LIGHTS ON // // [STRIFE] Verified unmodified // void EV_LightTurnOn ( line_t* line, int bright ) { int i; int j; sector_t* sector; sector_t* temp; line_t* templine; sector = sectors; for (i=0;itag == line->tag) { // bright = 0 means to search // for highest light level // surrounding sector if (!bright) { for (j = 0;j < sector->linecount; j++) { templine = sector->lines[j]; temp = getNextSector(templine,sector); if (!temp) continue; if (temp->lightlevel > bright) bright = temp->lightlevel; } } sector-> lightlevel = bright; } } } // // Spawn glowing light // // [STRIFE] Verified unmodified // void T_Glow(glow_t* g) { switch(g->direction) { case -1: // DOWN g->sector->lightlevel -= GLOWSPEED; if (g->sector->lightlevel <= g->minlight) { g->sector->lightlevel += GLOWSPEED; g->direction = 1; } break; case 1: // UP g->sector->lightlevel += GLOWSPEED; if (g->sector->lightlevel >= g->maxlight) { g->sector->lightlevel -= GLOWSPEED; g->direction = -1; } break; } } // // [STRIFE] Verified unmodified // void P_SpawnGlowingLight(sector_t* sector) { glow_t* g; g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0); P_AddThinker(&g->thinker); g->sector = sector; g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); g->maxlight = sector->lightlevel; g->thinker.function.acp1 = (actionf_p1) T_Glow; g->direction = -1; sector->special = 0; } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_local.h000066400000000000000000000155441257432200600231630ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Play functions, animation, global header. // #ifndef __P_LOCAL__ #define __P_LOCAL__ #ifndef __R_LOCAL__ #include "r_local.h" #endif #define FLOATSPEED (FRACUNIT*5) // villsa [STRIFE] change to 5 (was 4) #define MAXHEALTH 100 #define VIEWHEIGHT (41*FRACUNIT) // mapblocks are used to check movement // against lines and things #define MAPBLOCKUNITS 128 #define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) #define MAPBLOCKSHIFT (FRACBITS+7) #define MAPBMASK (MAPBLOCKSIZE-1) #define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) // player radius for movement checking #define PLAYERRADIUS 16*FRACUNIT // MAXRADIUS is for precalculated sector block boxes // the spider demon is larger, // but we do not have any moving sectors nearby #define MAXRADIUS 32*FRACUNIT #define GRAVITY FRACUNIT #define MAXMOVE (30*FRACUNIT) #define USERANGE (64*FRACUNIT) #define MELEERANGE (64*FRACUNIT) #define PLAYERMELEERANGE (80*FRACUNIT) // haleyjd [STRIFE] New constant #define MISSILERANGE (32*64*FRACUNIT) // follow a player exlusively for 3 seconds #define BASETHRESHOLD 100 // // P_TICK // // both the head and tail of the thinker list extern thinker_t thinkercap; void P_InitThinkers (void); void P_AddThinker (thinker_t* thinker); void P_RemoveThinker (thinker_t* thinker); // // P_PSPR // void P_SetupPsprites (player_t* curplayer); void P_MovePsprites (player_t* curplayer); void P_DropWeapon (player_t* player); // // P_USER // // haleyjd 09/15/10: externalized #define INVERSECOLORMAP 32 void P_PlayerThink (player_t* player); // haleyjd 08/30/10: [STRIFE] Needed externally void P_Thrust (player_t* player, angle_t angle, fixed_t move); // villsa [STRIFE] char* P_RemoveInventoryItem(player_t *player, int slot, int amount); // // P_MOBJ // #define ONFLOORZ INT_MIN #define ONCEILINGZ INT_MAX // Time interval for item respawning. #define ITEMQUESIZE 128 extern mapthing_t itemrespawnque[ITEMQUESIZE]; extern int itemrespawntime[ITEMQUESIZE]; extern int iquehead; extern int iquetail; void P_RespawnSpecials (void); mobj_t* P_SpawnMobj ( fixed_t x, fixed_t y, fixed_t z, mobjtype_t type ); void P_RemoveMobj (mobj_t* th); mobj_t* P_SubstNullMobj (mobj_t* th); boolean P_SetMobjState (mobj_t* mobj, statenum_t state); void P_MobjThinker (mobj_t* mobj); void P_SpawnPuff (fixed_t x, fixed_t y, fixed_t z); mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z); // villsa [STRIFE] void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage); mobj_t* P_SpawnMissile (mobj_t* source, mobj_t* dest, mobjtype_t type); mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type); // villsa [STRIFE] mobj_t* P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type); mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type); // villsa [STRIFE] void P_ExplodeMissile (mobj_t* mo); // villsa [STRIFE] // // P_ENEMY // void P_NoiseAlert (mobj_t* target, mobj_t* emmiter); void P_DoPunchAlert(mobj_t *puncher, mobj_t *punchee); // villsa [STRIFE] void A_BodyParts(mobj_t *actor); // haleyjd: [STRIFE] void A_AlertSpectreC(mobj_t* actor); void A_FaceTarget (mobj_t* actor); void P_FreePrisoners(void); void P_DestroyConverter(void); // // P_MAPUTL // typedef struct { fixed_t x; fixed_t y; fixed_t dx; fixed_t dy; } divline_t; typedef struct { fixed_t frac; // along trace line boolean isaline; union { mobj_t* thing; line_t* line; } d; } intercept_t; // Extended MAXINTERCEPTS, to allow for intercepts overrun emulation. #define MAXINTERCEPTS_ORIGINAL 128 #define MAXINTERCEPTS (MAXINTERCEPTS_ORIGINAL + 61) extern intercept_t intercepts[MAXINTERCEPTS]; extern intercept_t* intercept_p; typedef boolean (*traverser_t) (intercept_t *in); fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); int P_PointOnLineSide (fixed_t x, fixed_t y, line_t* line); int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t* line); void P_MakeDivline (line_t* li, divline_t* dl); fixed_t P_InterceptVector (divline_t* v2, divline_t* v1); int P_BoxOnLineSide (fixed_t* tmbox, line_t* ld); extern fixed_t opentop; extern fixed_t openbottom; extern fixed_t openrange; extern fixed_t lowfloor; void P_LineOpening (line_t* linedef); boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) ); boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) ); #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 #define PT_EARLYOUT 4 extern divline_t trace; boolean P_PathTraverse ( fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean (*trav) (intercept_t *)); void P_UnsetThingPosition (mobj_t* thing); void P_SetThingPosition (mobj_t* thing); // // P_MAP // // If "floatok" true, move would be ok // if within "tmfloorz - tmceilingz". extern boolean floatok; extern fixed_t tmfloorz; extern fixed_t tmceilingz; extern line_t *ceilingline; extern line_t *blockingline; // [STRIFE] New global boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y); boolean P_TryMove (mobj_t* thing, fixed_t x, fixed_t y); boolean P_CheckPositionZ(mobj_t* thing, fixed_t z); // villsa [STRIFE] boolean P_TeleportMove (mobj_t* thing, fixed_t x, fixed_t y); void P_SlideMove (mobj_t* mo); boolean P_CheckSight (mobj_t* t1, mobj_t* t2); void P_UseLines (player_t* player); boolean P_ChangeSector (sector_t* sector, boolean crunch); extern mobj_t* linetarget; // who got hit (or NULL) fixed_t P_AimLineAttack ( mobj_t* t1, angle_t angle, fixed_t distance ); void P_LineAttack ( mobj_t* t1, angle_t angle, fixed_t distance, fixed_t slope, int damage ); void P_RadiusAttack ( mobj_t* spot, mobj_t* source, int damage ); // // P_SETUP // extern byte* rejectmatrix; // for fast sight rejection extern short* blockmaplump; // offsets in blockmap are from here extern short* blockmap; extern int bmapwidth; extern int bmapheight; // in mapblocks extern fixed_t bmaporgx; extern fixed_t bmaporgy; // origin of block map extern mobj_t** blocklinks; // for thing chains // // P_INTER // extern int maxammo[NUMAMMO]; extern int clipammo[NUMAMMO]; void P_TouchSpecialThing ( mobj_t* special, mobj_t* toucher ); void P_DamageMobj ( mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage ); // // P_SPEC // #include "p_spec.h" #endif // __P_LOCAL__ chocolate-doom-chocolate-doom-2.2.1/src/strife/p_map.c000066400000000000000000001204601257432200600226330ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard, Andrey Budko // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Movement, collision handling. // Shooting and aiming. // #include #include #include "deh_misc.h" #include "m_bbox.h" #include "m_random.h" #include "i_system.h" #include "doomdef.h" #include "m_argv.h" #include "m_misc.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" // Spechit overrun magic value. // // This is the value used by PrBoom-plus. I think the value below is // actually better and works with more demos. However, I think // it's better for the spechits emulation to be compatible with // PrBoom-plus, at least so that the big spechits emulation list // on Doomworld can also be used with Chocolate Doom. #define DEFAULT_SPECHIT_MAGIC 0x01C09C98 // This is from a post by myk on the Doomworld forums, // outputted from entryway's spechit_magic generator for // s205n546.lmp. The _exact_ value of this isn't too // important; as long as it is in the right general // range, it will usually work. Otherwise, we can use // the generator (hacked doom2.exe) and provide it // with -spechit. //#define DEFAULT_SPECHIT_MAGIC 0x84f968e8 fixed_t tmbbox[4]; mobj_t* tmthing; int tmflags; fixed_t tmx; fixed_t tmy; // If "floatok" true, move would be ok // if within "tmfloorz - tmceilingz". boolean floatok; fixed_t tmfloorz; fixed_t tmceilingz; fixed_t tmdropoffz; // keep track of the line that lowers the ceiling, // so missiles don't explode against sky hack walls line_t* ceilingline; // haleyjd 20110203: [STRIFE] New global // "blockingline" tracks the linedef responsible for blocking motion of an mobj // for purposes of doing impact special activation by missiles. Suspiciously // similar to the solution used by Raven in Heretic and Hexen. line_t *blockingline; // keep track of special lines as they are hit, // but don't process them until the move is proven valid // fraggle: I have increased the size of this buffer. In the original Doom, // overrunning past this limit caused other bits of memory to be overwritten, // affecting demo playback. However, in doing so, the limit was still // exceeded. So we have to support more than 8 specials. // // We keep the original limit, to detect what variables in memory were // overwritten (see SpechitOverrun()) #define MAXSPECIALCROSS 20 #define MAXSPECIALCROSS_ORIGINAL 8 line_t* spechit[MAXSPECIALCROSS]; int numspechit; // // TELEPORT MOVE // // // PIT_StompThing // // [STRIFE] haleyjd 09/15/10: Modified so monsters can telestomp. // boolean PIT_StompThing (mobj_t* thing) { fixed_t blockdist; if (!(thing->flags & MF_SHOOTABLE) ) return true; blockdist = thing->radius + tmthing->radius; if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist ) { // didn't hit it return true; } // don't clip against self if (thing == tmthing) return true; // [STRIFE] monsters DO stomp things, on all levels // Basically, one thing involved must be a player. // Monsters can telefrag players, and players can telefrag monsters, but // monsters cannot telefrag other monsters. if (!(tmthing->player || thing->player)) return false; P_DamageMobj (thing, tmthing, tmthing, 10000); return true; } // // P_TeleportMove // // [STRIFE] // haleyjd 09/15/10: Modified to set thing z position. // boolean P_TeleportMove(mobj_t* thing, fixed_t x, fixed_t y) { int xl; int xh; int yl; int yh; int bx; int by; subsector_t* newsubsec; // kill anything occupying the position tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector (x,y); ceilingline = NULL; // The base floor/ceiling is from the subsector // that contains the point. // Any contacted lines the step closer together // will adjust them. tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; validcount++; numspechit = 0; // stomp on any things contacted xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockThingsIterator(bx,by,PIT_StompThing)) return false; // the move is ok, // so link the thing into its new position P_UnsetThingPosition (thing); thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; thing->z = tmfloorz; // haleyjd 09/15/10: [STRIFE] Rogue added a z-set here P_SetThingPosition (thing); return true; } // // MOVEMENT ITERATOR FUNCTIONS // static void SpechitOverrun(line_t *ld); // // PIT_CheckLine // Adjusts tmfloorz and tmceilingz as lines are contacted // boolean PIT_CheckLine (line_t* ld) { if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) return true; if (P_BoxOnLineSide (tmbbox, ld) != -1) return true; // A line has been hit // The moving thing's destination position will cross // the given line. // If this should not be allowed, return false. // If the line is special, keep track of it // to process later if the move is proven ok. // NOTE: specials are NOT sorted by order, // so two special lines that are only 8 pixels apart // could be crossed in either order. if (!ld->backsector) return false; // one sided line if (!(tmthing->flags & MF_MISSILE) ) { // villsa [STRIFE] include jumpover flag if ( ld->flags & ML_BLOCKING && (!(ld->flags & ML_JUMPOVER) || tmfloorz + (32*FRACUNIT) > tmthing->z) ) return false; // explicitly blocking everything // villsa [STRIFE] exclude floaters from blockmonster lines if ( !tmthing->player && (ld->flags & ML_BLOCKMONSTERS) && !(tmthing->flags & MF_FLOAT)) return false; // block monsters only // villsa [STRIFE] if ( ld->flags & ML_BLOCKFLOATERS && tmthing->flags & MF_FLOAT ) return false; // block floaters only } // set openrange, opentop, openbottom P_LineOpening (ld); // adjust floor / ceiling heights if (opentop < tmceilingz) { tmceilingz = opentop; ceilingline = ld; } if (openbottom > tmfloorz) tmfloorz = openbottom; if (lowfloor < tmdropoffz) tmdropoffz = lowfloor; // if contacted a special line, add it to the list if (ld->special) { spechit[numspechit] = ld; numspechit++; // fraggle: spechits overrun emulation code from prboom-plus if (numspechit > MAXSPECIALCROSS_ORIGINAL) { SpechitOverrun(ld); } } return true; } // // PIT_CheckThing // boolean PIT_CheckThing (mobj_t* thing) { fixed_t blockdist; boolean solid; int damage; if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) )) return true; // don't clip against self if (thing == tmthing) return true; blockdist = thing->radius + tmthing->radius; if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist ) { // didn't hit it return true; } // villsa [STRIFE] see if it went over / under if(thing->height + thing->z < tmthing->z) return true; // overhead // villsa [STRIFE] see if it went over / under if (tmthing->z + tmthing->height < thing->z) return true; // underneath // villsa [STRIFE] unused // check for skulls slamming into things (removed) // missiles can hit other things if (tmthing->flags & MF_MISSILE) { // villsa [STRIFE] code to check over/under clipping moved to the beginning of the // function, so that it applies to everything. // villsa [STRIFE] updated to strife version if (tmthing->target && (tmthing->target->type == thing->type)) { // Don't hit same species as originator. if (thing == tmthing->target) return true; // sdh: Add deh_species_infighting here. We can override the // "monsters of the same species cant hurt each other" behavior // through dehacked patches if (thing->type != MT_PLAYER && !deh_species_infighting) { // Explode, but do no damage. // Let players missile other players. return false; } } if (!(thing->flags & MF_SHOOTABLE)) { // didn't do any damage return !(thing->flags & MF_SOLID); } // haleyjd 09/01/10: [STRIFE] Spectral check: // Missiles cannot hit SPECTRAL entities unless the missiles are also // flagged as SPECTRAL. if (thing->flags & MF_SPECTRAL && !(tmthing->flags & MF_SPECTRAL)) return true; // keep going // damage / explode // haleyjd 09/01/10: [STRIFE] Modified missile damage formula damage = ((P_Random()&3)+1)*tmthing->info->damage; P_DamageMobj (thing, tmthing, tmthing->target, damage); // don't traverse any more return false; } // check for special pickup if (thing->flags & MF_SPECIAL) { solid = (thing->flags & MF_SOLID) != 0; if (tmthing->player) // villsa [STRIFE] no longer checks MF_PICKUP flag { // can remove thing P_TouchSpecialThing (thing, tmthing); } return !solid; } return !(thing->flags & MF_SOLID); } // // MOVEMENT CLIPPING // // // P_CheckPosition // This is purely informative, nothing is modified // (except things picked up). // // in: // a mobj_t (can be valid or invalid) // a position to be checked // (doesn't need to be related to the mobj_t->x,y) // // during: // special things are touched if MF_PICKUP // early out on solid lines? // // out: // newsubsec // floorz // ceilingz // tmdropoffz // the lowest point contacted // (monsters won't move to a dropoff) // speciallines[] // numspeciallines // // haleyjd 20110203: // [STRIFE] Modified to clear blockingline in advance of P_BlockLinesIterator // boolean P_CheckPosition ( mobj_t* thing, fixed_t x, fixed_t y ) { int xl; int xh; int yl; int yh; int bx; int by; subsector_t* newsubsec; tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector (x,y); // [STRIFE] clear blockingline (see P_XYMovement, P_BlockLinesIterator) blockingline = NULL; ceilingline = NULL; // The base floor / ceiling is from the subsector // that contains the point. // Any contacted lines the step closer together // will adjust them. tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; validcount++; numspechit = 0; if ( tmflags & MF_NOCLIP ) return true; // Check things first, possibly picking things up. // The bounding box is extended by MAXRADIUS // because mobj_ts are grouped into mapblocks // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) return false; // check lines xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) return false; return true; } // // P_TryMove // Attempt to move to a new position, // crossing special lines unless MF_TELEPORT is set. // boolean P_TryMove ( mobj_t* thing, fixed_t x, fixed_t y ) { fixed_t oldx; fixed_t oldy; int side; int oldside; line_t* ld; floatok = false; if (!P_CheckPosition (thing, x, y)) return false; // solid wall or thing if ( !(thing->flags & MF_NOCLIP) ) { if (tmceilingz - tmfloorz < thing->height) return false; // doesn't fit floatok = true; // villsa [STRIFE] Removed MF_TELEPORT if (tmceilingz - thing->z < thing->height) return false; // mobj must lower itself to fit // villsa [STRIFE] non-robots are limited to 16 unit step height if ((thing->flags & MF_NOBLOOD) == 0 && tmfloorz - thing->z > (16*FRACUNIT)) return false; if (tmfloorz - thing->z > 24*FRACUNIT) return false; // too big a step up // villsa [STRIFE] special case for missiles if((thing->flags & MF_MISSILE) && tmfloorz - thing->z > 4*FRACUNIT) return false; // haleyjd 20110204 [STRIFE]: dropoff height changed 24 -> 32 if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT)) && tmfloorz - tmdropoffz > 32*FRACUNIT ) return false; // don't stand over a dropoff } // the move is ok, // so link the thing into its new position P_UnsetThingPosition (thing); oldx = thing->x; oldy = thing->y; thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; P_SetThingPosition (thing); // if any special lines were hit, do the effect if (! (thing->flags&MF_NOCLIP) ) // villsa [STRIFE] MF_TELEPORT not used { while (numspechit--) { // see if the line was crossed ld = spechit[numspechit]; side = P_PointOnLineSide (thing->x, thing->y, ld); oldside = P_PointOnLineSide (oldx, oldy, ld); if (side != oldside) { if (ld->special) P_CrossSpecialLine (ld-lines, oldside, thing); } } } return true; } // // P_CheckPositionZ // // villsa [STRIFE] new function // Check colliding things on top of one another; ie., 3D Object Clipping // boolean P_CheckPositionZ(mobj_t* thing, fixed_t height) { fixed_t x; fixed_t y; fixed_t z; int xl; int xh; int yl; int yh; int bx; int by; subsector_t* newsubsec; x = thing->x; y = thing->y; z = thing->z; thing->z = height; tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; ceilingline = 0; newsubsec = thing->subsector; // The base floor / ceiling is from the subsector // that contains the point. // Any contacted lines the step closer together // will adjust them. tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; if(tmflags & MF_NOCLIP) return true; // Check things first, possibly picking things up. // The bounding box is extended by MAXRADIUS // because mobj_ts are grouped into mapblocks // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; for(bx = xl; bx <= xh; bx++) { for(by = yl; by <= yh; by++) { if(!P_BlockThingsIterator(bx, by, PIT_CheckThing)) { tmthing->z = z; return false; } } } return true; } // // P_ThingHeightClip // Takes a valid thing and adjusts the thing->floorz, // thing->ceilingz, and possibly thing->z. // This is called for all nearby monsters // whenever a sector changes height. // If the thing doesn't fit, // the z will be set to the lowest value // and false will be returned. // // [STRIFE] Verified unmodified // boolean P_ThingHeightClip (mobj_t* thing) { boolean onfloor; onfloor = (thing->z == thing->floorz); P_CheckPosition (thing, thing->x, thing->y); // what about stranding a monster partially off an edge? thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; if (onfloor) { // walking monsters rise and fall with the floor thing->z = thing->floorz; } else { // don't adjust a floating monster unless forced to if (thing->z+thing->height > thing->ceilingz) thing->z = thing->ceilingz - thing->height; } if (thing->ceilingz - thing->floorz < thing->height) return false; return true; } // // SLIDE MOVE // Allows the player to slide along any angled walls. // fixed_t bestslidefrac; fixed_t secondslidefrac; line_t* bestslideline; line_t* secondslideline; mobj_t* slidemo; fixed_t tmxmove; fixed_t tmymove; // // P_HitSlideLine // Adjusts the xmove / ymove // so that the next move will slide along the wall. // // [STRIFE] Verified unmodified // void P_HitSlideLine (line_t* ld) { int side; angle_t lineangle; angle_t moveangle; angle_t deltaangle; fixed_t movelen; fixed_t newlen; if (ld->slopetype == ST_HORIZONTAL) { tmymove = 0; return; } if (ld->slopetype == ST_VERTICAL) { tmxmove = 0; return; } side = P_PointOnLineSide (slidemo->x, slidemo->y, ld); lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy); if (side == 1) lineangle += ANG180; moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove); deltaangle = moveangle-lineangle; if (deltaangle > ANG180) deltaangle += ANG180; // I_Error ("SlideLine: ang>ANG180"); lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; movelen = P_AproxDistance (tmxmove, tmymove); newlen = FixedMul (movelen, finecosine[deltaangle]); tmxmove = FixedMul (newlen, finecosine[lineangle]); tmymove = FixedMul (newlen, finesine[lineangle]); } // // PTR_SlideTraverse // // [STRIFE] Modified for smaller step-up height // boolean PTR_SlideTraverse (intercept_t* in) { line_t* li; if (!in->isaline) I_Error ("PTR_SlideTraverse: not a line?"); li = in->d.line; if ( ! (li->flags & ML_TWOSIDED) ) { if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) { // don't hit the back side return true; } goto isblocking; } // set openrange, opentop, openbottom P_LineOpening (li); if (openrange < slidemo->height) goto isblocking; // doesn't fit if (opentop - slidemo->z < slidemo->height) goto isblocking; // mobj is too high // villsa [STRIFE] change from 24 to 16 if (openbottom - slidemo->z > 16*FRACUNIT ) goto isblocking; // too big a step up // this line doesn't block movement return true; // the line does block movement, // see if it is closer than best so far isblocking: if (in->frac < bestslidefrac) { secondslidefrac = bestslidefrac; secondslideline = bestslideline; bestslidefrac = in->frac; bestslideline = li; } return false; // stop } // // P_SlideMove // The momx / momy move is bad, so try to slide // along a wall. // Find the first line hit, move flush to it, // and slide along it // // This is a kludgy mess. // // [STRIFE] Verified unmodified // void P_SlideMove (mobj_t* mo) { fixed_t leadx; fixed_t leady; fixed_t trailx; fixed_t traily; fixed_t newx; fixed_t newy; int hitcount; slidemo = mo; hitcount = 0; retry: if (++hitcount == 3) goto stairstep; // don't loop forever // trace along the three leading corners if (mo->momx > 0) { leadx = mo->x + mo->radius; trailx = mo->x - mo->radius; } else { leadx = mo->x - mo->radius; trailx = mo->x + mo->radius; } if (mo->momy > 0) { leady = mo->y + mo->radius; traily = mo->y - mo->radius; } else { leady = mo->y - mo->radius; traily = mo->y + mo->radius; } bestslidefrac = FRACUNIT+1; P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy, PT_ADDLINES, PTR_SlideTraverse ); P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy, PT_ADDLINES, PTR_SlideTraverse ); P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy, PT_ADDLINES, PTR_SlideTraverse ); // move up to the wall if (bestslidefrac == FRACUNIT+1) { // the move most have hit the middle, so stairstep stairstep: if (!P_TryMove (mo, mo->x, mo->y + mo->momy)) P_TryMove (mo, mo->x + mo->momx, mo->y); return; } // fudge a bit to make sure it doesn't hit bestslidefrac -= 0x800; if (bestslidefrac > 0) { newx = FixedMul (mo->momx, bestslidefrac); newy = FixedMul (mo->momy, bestslidefrac); if (!P_TryMove (mo, mo->x+newx, mo->y+newy)) goto stairstep; } // Now continue along the wall. // First calculate remainder. bestslidefrac = FRACUNIT-(bestslidefrac+0x800); if (bestslidefrac > FRACUNIT) bestslidefrac = FRACUNIT; if (bestslidefrac <= 0) return; tmxmove = FixedMul (mo->momx, bestslidefrac); tmymove = FixedMul (mo->momy, bestslidefrac); P_HitSlideLine (bestslideline); // clip the moves mo->momx = tmxmove; mo->momy = tmymove; if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove)) { goto retry; } } // // P_LineAttack // mobj_t* linetarget; // who got hit (or NULL) mobj_t* shootthing; // Height if not aiming up or down // ???: use slope for monsters? fixed_t shootz; int la_damage; fixed_t attackrange; fixed_t aimslope; // slopes to top and bottom of target extern fixed_t topslope; extern fixed_t bottomslope; // // PTR_AimTraverse // Sets linetaget and aimslope when a target is aimed at. // // [STRIFE] Verified unmodified // boolean PTR_AimTraverse (intercept_t* in) { line_t* li; mobj_t* th; fixed_t slope; fixed_t thingtopslope; fixed_t thingbottomslope; fixed_t dist; if (in->isaline) { li = in->d.line; if ( !(li->flags & ML_TWOSIDED) ) return false; // stop // Crosses a two sided line. // A two sided line will restrict // the possible target ranges. P_LineOpening (li); if (openbottom >= opentop) return false; // stop dist = FixedMul (attackrange, in->frac); // Return false if there is no back sector. This should never // be the case if the line is two-sided; however, some WADs // (eg. ottawau.wad) use this as an "impassible glass" trick // and rely on Vanilla Doom's (unintentional) support for this. if (li->backsector == NULL) { return false; } if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv (openbottom - shootz , dist); if (slope > bottomslope) bottomslope = slope; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv (opentop - shootz , dist); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop return true; // shot continues } // shoot a thing th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags&MF_SHOOTABLE)) return true; // corpse or something // check angles to see if the thing can be aimed at dist = FixedMul (attackrange, in->frac); thingtopslope = FixedDiv (th->z+th->height - shootz , dist); if (thingtopslope < bottomslope) return true; // shot over the thing thingbottomslope = FixedDiv (th->z - shootz, dist); if (thingbottomslope > topslope) return true; // shot under the thing // this thing can be hit! if (thingtopslope > topslope) thingtopslope = topslope; if (thingbottomslope < bottomslope) thingbottomslope = bottomslope; aimslope = (thingtopslope+thingbottomslope)/2; linetarget = th; return false; // don't go any farther } // // PTR_ShootTraverse // // [STRIFE] Changes for Spectres and Mauler puff/damage inflictor // boolean PTR_ShootTraverse (intercept_t* in) { fixed_t x; fixed_t y; fixed_t z; fixed_t frac; line_t* li; mobj_t* th; mobj_t* th2; // villsa [STRIFE] fixed_t slope; fixed_t dist; fixed_t thingtopslope; fixed_t thingbottomslope; if (in->isaline) { li = in->d.line; if (li->special) P_ShootSpecialLine (shootthing, li); if ( !(li->flags & ML_TWOSIDED) ) goto hitline; // crosses a two sided line P_LineOpening (li); dist = FixedMul (attackrange, in->frac); // Check if backsector is NULL. See comment in PTR_AimTraverse. if (li->backsector == NULL) { goto hitline; } if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv (openbottom - shootz , dist); if (slope > aimslope) goto hitline; } if (li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv (opentop - shootz , dist); if (slope < aimslope) goto hitline; } // shot continues return true; // hit line hitline: // position a bit closer frac = in->frac - FixedDiv (4*FRACUNIT,attackrange); x = trace.x + FixedMul (trace.dx, frac); y = trace.y + FixedMul (trace.dy, frac); z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); if (li->frontsector->ceilingpic == skyflatnum) { // don't shoot the sky! if (z > li->frontsector->ceilingheight) return false; // it's a sky hack wall if (li->backsector && li->backsector->ceilingpic == skyflatnum) return false; } // villsa [STRIFE] if(la_damage > 0) { // villsa [STRIFE] Test against Mauler attack range if(attackrange != 2112*FRACUNIT) P_SpawnPuff(x, y, z); // Spawn bullet puffs. else P_SpawnMobj(x, y, z, MT_STRIFEPUFF3); } // don't go any farther return false; } // shoot a thing th = in->d.thing; if (th == shootthing) return true; // can't shoot self if (!(th->flags&MF_SHOOTABLE)) return true; // corpse or something // haleyjd 09/18/10: [STRIFE] Corrected - not MVIS, but SPECTRAL. if(th->flags & MF_SPECTRAL) return true; // is a spectral entity // check angles to see if the thing can be aimed at dist = FixedMul (attackrange, in->frac); thingtopslope = FixedDiv (th->z+th->height - shootz , dist); if (thingtopslope < aimslope) return true; // shot over the thing thingbottomslope = FixedDiv (th->z - shootz, dist); if (thingbottomslope > aimslope) return true; // shot under the thing // hit thing // position a bit closer frac = in->frac - FixedDiv (10*FRACUNIT,attackrange); x = trace.x + FixedMul (trace.dx, frac); y = trace.y + FixedMul (trace.dy, frac); z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); // villsa [STRIFE] Check for Mauler attack range if(attackrange == 2112*FRACUNIT) { th2 = P_SpawnMobj(x, y, z, MT_STRIFEPUFF3); th2->momz = -FRACUNIT; P_DamageMobj(th, th2, shootthing, la_damage); return false; } // villsa [STRIFE] disabled check for damage //if (la_damage) P_DamageMobj (th, shootthing, shootthing, la_damage); // Spawn bullet puffs or blod spots, // depending on target type. if (in->d.thing->flags & MF_NOBLOOD) P_SpawnSparkPuff(x, y, z); // villsa [STRIFE] call spark puff function instead else P_SpawnBlood (x,y,z, la_damage); // don't go any farther return false; } // // P_AimLineAttack // // [STRIFE] Modified to support player->pitch // fixed_t P_AimLineAttack ( mobj_t* t1, angle_t angle, fixed_t distance ) { fixed_t x2; fixed_t y2; t1 = P_SubstNullMobj(t1); angle >>= ANGLETOFINESHIFT; shootthing = t1; x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; // can't shoot outside view angles topslope = 100*FRACUNIT/160; bottomslope = -100*FRACUNIT/160; attackrange = distance; linetarget = NULL; P_PathTraverse ( t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse ); if (linetarget) return aimslope; else // villsa [STRIFE] checks for player pitch { if(t1->player) return (t1->player->pitch << FRACBITS) / 160; } return 0; } // // P_LineAttack // If damage == 0, it is just a test trace // that will leave linetarget set. // // [STRIFE] Modified to check lines only if damage <= 0 (see P_RadiusAttack) // void P_LineAttack ( mobj_t* t1, angle_t angle, fixed_t distance, fixed_t slope, int damage ) { fixed_t x2; fixed_t y2; int traverseflags; angle >>= ANGLETOFINESHIFT; shootthing = t1; la_damage = damage; x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; attackrange = distance; aimslope = slope; // villsa [STRIFE] test lines only if damage is <= 0 if(damage >= 1) traverseflags = (PT_ADDLINES|PT_ADDTHINGS); else traverseflags = PT_ADDLINES; P_PathTraverse(t1->x, t1->y, x2, y2, traverseflags, PTR_ShootTraverse); } // // USE LINES // // [STRIFE] Verified unmodified // mobj_t* usething; boolean PTR_UseTraverse (intercept_t* in) { int side; if (!in->d.line->special) { P_LineOpening (in->d.line); if (openrange <= 0) { S_StartSound (usething, sfx_noway); // can't use through a wall return false; } // not a special line, but keep checking return true ; } side = 0; if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) side = 1; // return false; // don't use back side P_UseSpecialLine (usething, in->d.line, side); // can't use for than one special line in a row return false; } // // P_UseLines // Looks for special lines in front of the player to activate. // // [STRIFE] Verified unmodified // void P_UseLines (player_t* player) { int angle; fixed_t x1; fixed_t y1; fixed_t x2; fixed_t y2; usething = player->mo; angle = player->mo->angle >> ANGLETOFINESHIFT; x1 = player->mo->x; y1 = player->mo->y; x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]; y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]; P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ); } // // RADIUS ATTACK // mobj_t* bombsource; mobj_t* bombspot; int bombdamage; // // PIT_RadiusAttack // "bombsource" is the creature // that caused the explosion at "bombspot". // // [STRIFE] Modified for Spectral and Inquisitor exclusions // boolean PIT_RadiusAttack (mobj_t* thing) { fixed_t dx; fixed_t dy; fixed_t dist; if (!(thing->flags & MF_SHOOTABLE)) return true; // haleyjd 10/04/10: Spectrals are not damaged by blast radii if(thing->flags & MF_SPECTRAL) return true; // Boss spider and cyborg // take no damage from concussion. // villsa [STRIFE] unused // - haleyjd: INQUISITOR if(thing->type == MT_INQUISITOR) return true; dx = abs(thing->x - bombspot->x); dy = abs(thing->y - bombspot->y); dist = dx>dy ? dx : dy; dist = (dist - thing->radius) >> FRACBITS; if (dist < 0) dist = 0; if (dist >= bombdamage) return true; // out of range if ( P_CheckSight (thing, bombspot) ) { // must be in direct path P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist); } return true; } // // P_RadiusAttack // Source is the creature that caused the explosion at spot. // // [STRIFE] Modified to emit "test" tracers which can shatter glass screens // and windows. // void P_RadiusAttack ( mobj_t* spot, mobj_t* source, int damage ) { int x; int y; int xl; int xh; int yl; int yh; fixed_t dist; dist = (damage+MAXRADIUS)<y + dist - bmaporgy)>>MAPBLOCKSHIFT; yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT; xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT; xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT; bombspot = spot; bombsource = source; bombdamage = damage; for (y=yl ; y<=yh ; y++) for (x=xl ; x<=xh ; x++) P_BlockThingsIterator (x, y, PIT_RadiusAttack ); // villsa [STRIFE] Send out 0 damage tracers to shatter nearby glass. spot->z += 32*FRACUNIT; P_LineAttack(spot, 0, dist, 1, 0); P_LineAttack(spot, ANG90, dist, 1, 0); P_LineAttack(spot, ANG180, dist, 1, 0); P_LineAttack(spot, ANG270, dist, 1, 0); spot->z -= 32*FRACUNIT; } // // SECTOR HEIGHT CHANGING // After modifying a sectors floor or ceiling height, // call this routine to adjust the positions // of all things that touch the sector. // // If anything doesn't fit anymore, true will be returned. // If crunch is true, they will take damage // as they are being crushed. // If Crunch is false, you should set the sector height back // the way it was and call P_ChangeSector again // to undo the changes. // boolean crushchange; boolean nofit; // // PIT_ChangeSector // // [STRIFE] Changes to crushing behavior // boolean PIT_ChangeSector (mobj_t* thing) { mobj_t* mo; if (P_ThingHeightClip (thing)) { // keep checking return true; } // crunch bodies to giblets if (thing->health <= 0) { // villsa [STRIFE] do something with the player if(thing->player && thing->subsector->sector->specialdata) { nofit = true; return false; } //P_SetMobjState (thing, S_GIBS); // villsa [STRIFE] unused A_BodyParts(thing); // villsa [STRIFE] spit out meat/junk stuff thing->flags &= ~MF_SOLID; thing->height = 0; thing->radius = 0; // keep checking return true; } // crunch dropped items if (thing->flags & MF_DROPPED) { P_RemoveMobj (thing); // keep checking return true; } if (! (thing->flags & MF_SHOOTABLE) ) { // assume it is bloody gibs or something return true; } nofit = true; if (crushchange && !(leveltime&3) ) { int t; S_StartSound(thing, sfx_pcrush); // villsa [STRIFE] P_DamageMobj(thing,NULL,NULL,10); // spray blood in a random direction mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, MT_BLOOD_DEATH); t = P_Random(); mo->momx = (t - P_Random ()) << 12; t = P_Random(); mo->momy = (t - P_Random ()) << 12; } // keep checking (crush other things) return true; } // // P_ChangeSector // // [STRIFE] Verified unmodified // boolean P_ChangeSector ( sector_t* sector, boolean crunch ) { int x; int y; nofit = false; crushchange = crunch; // re-check heights for all things near the moving sector for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++) for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++) P_BlockThingsIterator (x, y, PIT_ChangeSector); return nofit; } // Code to emulate the behavior of Vanilla Doom when encountering an overrun // of the spechit array. This is by Andrey Budko (e6y) and comes from his // PrBoom plus port. A big thanks to Andrey for this. static void SpechitOverrun(line_t *ld) { static unsigned int baseaddr = 0; unsigned int addr; if (baseaddr == 0) { int p; // This is the first time we have had an overrun. Work out // what base address we are going to use. // Allow a spechit value to be specified on the command line. //! // @category compat // @arg // // Use the specified magic value when emulating spechit overruns. // p = M_CheckParmWithArgs("-spechit", 1); if (p > 0) { M_StrToInt(myargv[p+1], (int *) &baseaddr); } else { baseaddr = DEFAULT_SPECHIT_MAGIC; } } // Calculate address used in doom2.exe addr = baseaddr + (ld - lines) * 0x3E; switch(numspechit) { case 9: case 10: case 11: case 12: tmbbox[numspechit-9] = addr; break; case 13: nofit = addr; // haleyjd 20110204: nofit/crushchange are in opposite break; // order in the Strife binary. case 14: crushchange = addr; break; default: fprintf(stderr, "SpechitOverrun: Warning: unable to emulate" "an overrun where numspechit=%i\n", numspechit); break; } } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_maputl.c000066400000000000000000000554401257432200600233650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // Copyright(C) 2005, 2006 Andrey Budko // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Movement/collision utility functions, // as used by function in p_map.c. // BLOCKMAP Iterator functions, // and some PIT_* functions to use for iteration. // #include #include "m_bbox.h" #include "doomdef.h" #include "doomstat.h" #include "p_local.h" // State. #include "r_state.h" // // P_AproxDistance // Gives an estimation of distance (not exact) // // [STRIFE] Verified unmodified // fixed_t P_AproxDistance ( fixed_t dx, fixed_t dy ) { dx = abs(dx); dy = abs(dy); if (dx < dy) return dx+dy-(dx>>1); return dx+dy-(dy>>1); } // // P_PointOnLineSide // Returns 0 or 1 // // [STRIFE] Verified unmodified // int P_PointOnLineSide ( fixed_t x, fixed_t y, line_t* line ) { fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; if (!line->dx) { if (x <= line->v1->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->v1->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->v1->x); dy = (y - line->v1->y); left = FixedMul ( line->dy>>FRACBITS , dx ); right = FixedMul ( dy , line->dx>>FRACBITS ); if (right < left) return 0; // front side return 1; // back side } // // P_BoxOnLineSide // Considers the line to be infinite // Returns side 0 or 1, -1 if box crosses the line. // // [STRIFE] Verified unmodified // int P_BoxOnLineSide ( fixed_t* tmbox, line_t* ld ) { int p1 = 0; int p2 = 0; switch (ld->slopetype) { case ST_HORIZONTAL: p1 = tmbox[BOXTOP] > ld->v1->y; p2 = tmbox[BOXBOTTOM] > ld->v1->y; if (ld->dx < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_VERTICAL: p1 = tmbox[BOXRIGHT] < ld->v1->x; p2 = tmbox[BOXLEFT] < ld->v1->x; if (ld->dy < 0) { p1 ^= 1; p2 ^= 1; } break; case ST_POSITIVE: p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld); break; case ST_NEGATIVE: p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld); p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld); break; } if (p1 == p2) return p1; return -1; } // // P_PointOnDivlineSide // Returns 0 or 1. // // [STRIFE] Verified unmodified // int P_PointOnDivlineSide ( fixed_t x, fixed_t y, divline_t* line ) { fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; if (!line->dx) { if (x <= line->x) return line->dy > 0; return line->dy < 0; } if (!line->dy) { if (y <= line->y) return line->dx < 0; return line->dx > 0; } dx = (x - line->x); dy = (y - line->y); // try to quickly decide by looking at sign bits if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 ) { if ( (line->dy ^ dx) & 0x80000000 ) return 1; // (left is negative) return 0; } left = FixedMul ( line->dy>>8, dx>>8 ); right = FixedMul ( dy>>8 , line->dx>>8 ); if (right < left) return 0; // front side return 1; // back side } // // P_MakeDivline // void P_MakeDivline ( line_t* li, divline_t* dl ) { dl->x = li->v1->x; dl->y = li->v1->y; dl->dx = li->dx; dl->dy = li->dy; } // // P_InterceptVector // Returns the fractional intercept point // along the first divline. // This is only called by the addthings // and addlines traversers. // // [STRIFE] Verified unmodified // fixed_t P_InterceptVector ( divline_t* v2, divline_t* v1 ) { #if 1 fixed_t frac; fixed_t num; fixed_t den; den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy); if (den == 0) return 0; // I_Error ("P_InterceptVector: parallel"); num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy ) +FixedMul ( (v2->y - v1->y)>>8, v1->dx ); frac = FixedDiv (num , den); return frac; #else // UNUSED, float debug. float frac; float num; float den; float v1x; float v1y; float v1dx; float v1dy; float v2x; float v2y; float v2dx; float v2dy; v1x = (float)v1->x/FRACUNIT; v1y = (float)v1->y/FRACUNIT; v1dx = (float)v1->dx/FRACUNIT; v1dy = (float)v1->dy/FRACUNIT; v2x = (float)v2->x/FRACUNIT; v2y = (float)v2->y/FRACUNIT; v2dx = (float)v2->dx/FRACUNIT; v2dy = (float)v2->dy/FRACUNIT; den = v1dy*v2dx - v1dx*v2dy; if (den == 0) return 0; // parallel num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx; frac = num / den; return frac*FRACUNIT; #endif } // // P_LineOpening // Sets opentop and openbottom to the window // through a two sided line. // OPTIMIZE: keep this precalculated // // [STRIFE] Verified unmodified // fixed_t opentop; fixed_t openbottom; fixed_t openrange; fixed_t lowfloor; void P_LineOpening (line_t* linedef) { sector_t* front; sector_t* back; if (linedef->sidenum[1] == -1) { // single sided line openrange = 0; return; } front = linedef->frontsector; back = linedef->backsector; if (front->ceilingheight < back->ceilingheight) opentop = front->ceilingheight; else opentop = back->ceilingheight; if (front->floorheight > back->floorheight) { openbottom = front->floorheight; lowfloor = back->floorheight; } else { openbottom = back->floorheight; lowfloor = front->floorheight; } openrange = opentop - openbottom; } // // THING POSITION SETTING // // // P_UnsetThingPosition // Unlinks a thing from block map and sectors. // On each position change, BLOCKMAP and other // lookups maintaining lists ot things inside // these structures need to be updated. // // [STRIFE] Verified unmodified // void P_UnsetThingPosition (mobj_t* thing) { int blockx; int blocky; if ( ! (thing->flags & MF_NOSECTOR) ) { // inert things don't need to be in blockmap? // unlink from subsector if (thing->snext) thing->snext->sprev = thing->sprev; if (thing->sprev) thing->sprev->snext = thing->snext; else thing->subsector->sector->thinglist = thing->snext; } if ( ! (thing->flags & MF_NOBLOCKMAP) ) { // inert things don't need to be in blockmap // unlink from block map if (thing->bnext) thing->bnext->bprev = thing->bprev; if (thing->bprev) thing->bprev->bnext = thing->bnext; else { blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky bnext; } } } } // // P_SetThingPosition // Links a thing into both a block and a subsector // based on it's x y. // Sets thing->subsector properly // // [STRIFE] Verified unmodified // void P_SetThingPosition (mobj_t* thing) { subsector_t* ss; sector_t* sec; int blockx; int blocky; mobj_t** link; // link into subsector ss = R_PointInSubsector (thing->x,thing->y); thing->subsector = ss; if ( ! (thing->flags & MF_NOSECTOR) ) { // invisible things don't go into the sector links sec = ss->sector; thing->sprev = NULL; thing->snext = sec->thinglist; if (sec->thinglist) sec->thinglist->sprev = thing; sec->thinglist = thing; } // link into blockmap if ( ! (thing->flags & MF_NOBLOCKMAP) ) { // inert things don't need to be in blockmap blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight) { link = &blocklinks[blocky*bmapwidth+blockx]; thing->bprev = NULL; thing->bnext = *link; if (*link) (*link)->bprev = thing; *link = thing; } else { // thing is off the map thing->bnext = thing->bprev = NULL; } } } // // BLOCK MAP ITERATORS // For each line/thing in the given mapblock, // call the passed PIT_* function. // If the function returns false, // exit with false without checking anything else. // // // P_BlockLinesIterator // The validcount flags are used to avoid checking lines // that are marked in multiple mapblocks, // so increment validcount before the first call // to P_BlockLinesIterator, then make one or more calls // to it. // // haleyjd 20110203: // [STRIFE] Modified to track blockingline // boolean P_BlockLinesIterator ( int x, int y, boolean(*func)(line_t*) ) { int offset; short* list; line_t* ld; if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight) { return true; } offset = y*bmapwidth+x; offset = *(blockmap+offset); for ( list = blockmaplump+offset ; *list != -1 ; list++) { ld = &lines[*list]; // [STRIFE]: set blockingline (see P_XYMovement @ p_mobj.c) blockingline = ld; if (ld->validcount == validcount) continue; // line has already been checked ld->validcount = validcount; if ( !func(ld) ) return false; } return true; // everything was checked } // // P_BlockThingsIterator // // [STRIFE] Verified unmodified // boolean P_BlockThingsIterator ( int x, int y, boolean(*func)(mobj_t*) ) { mobj_t* mobj; if ( x<0 || y<0 || x>=bmapwidth || y>=bmapheight) { return true; } for (mobj = blocklinks[y*bmapwidth+x] ; mobj ; mobj = mobj->bnext) { if (!func( mobj ) ) return false; } return true; } // // INTERCEPT ROUTINES // intercept_t intercepts[MAXINTERCEPTS]; intercept_t* intercept_p; divline_t trace; boolean earlyout; int ptflags; //static void InterceptsOverrun(int num_intercepts, intercept_t *intercept); // // PIT_AddLineIntercepts. // Looks for lines in the given block // that intercept the given trace // to add to the intercepts list. // // A line is crossed if its endpoints // are on opposite sides of the trace. // Returns true if earlyout and a solid line hit. // // haleyjd 20110204 [STRIFE]: Added Rogue's fix for intercepts overflows // boolean PIT_AddLineIntercepts (line_t* ld) { int s1; int s2; fixed_t frac; divline_t dl; // avoid precision problems with two routines if ( trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 || trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16) { s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace); } else { s1 = P_PointOnLineSide (trace.x, trace.y, ld); s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld); } if (s1 == s2) return true; // line isn't crossed // hit the line P_MakeDivline (ld, &dl); frac = P_InterceptVector (&trace, &dl); if (frac < 0) return true; // behind source // try to early out the check if (earlyout && frac < FRACUNIT && !ld->backsector) { return false; // stop checking } intercept_p->frac = frac; intercept_p->isaline = true; intercept_p->d.line = ld; intercept_p++; // haleyjd 20110204 [STRIFE] // Evidently Rogue had trouble with intercepts overflows during // development, as they added this check here which will stop adding // intercepts if the array would be overflown. if(intercept_p <= &intercepts[MAXINTERCEPTS_ORIGINAL-2]) return true; // continue else return false; // [STRIFE] Not needed? //InterceptsOverrun(intercept_p - intercepts, intercept_p); } // // PIT_AddThingIntercepts // boolean PIT_AddThingIntercepts (mobj_t* thing) { fixed_t x1; fixed_t y1; fixed_t x2; fixed_t y2; int s1; int s2; boolean tracepositive; divline_t dl; fixed_t frac; tracepositive = (trace.dx ^ trace.dy)>0; // check a corner to corner crossection for hit if (tracepositive) { x1 = thing->x - thing->radius; y1 = thing->y + thing->radius; x2 = thing->x + thing->radius; y2 = thing->y - thing->radius; } else { x1 = thing->x - thing->radius; y1 = thing->y - thing->radius; x2 = thing->x + thing->radius; y2 = thing->y + thing->radius; } s1 = P_PointOnDivlineSide (x1, y1, &trace); s2 = P_PointOnDivlineSide (x2, y2, &trace); if (s1 == s2) return true; // line isn't crossed dl.x = x1; dl.y = y1; dl.dx = x2-x1; dl.dy = y2-y1; frac = P_InterceptVector (&trace, &dl); if (frac < 0) return true; // behind source intercept_p->frac = frac; intercept_p->isaline = false; intercept_p->d.thing = thing; intercept_p++; // haleyjd 20110204 [STRIFE]: As above, protection against intercepts // overflows, courtesy of Rogue Software. if(intercept_p <= &intercepts[MAXINTERCEPTS_ORIGINAL-2]) return true; // keep going else return false; // haleyjd [STRIFE]: Not needed? //InterceptsOverrun(intercept_p - intercepts, intercept_p); } // // P_TraverseIntercepts // Returns true if the traverser function returns true // for all lines. // // [STRIFE] Verified unmodified. // boolean P_TraverseIntercepts ( traverser_t func, fixed_t maxfrac ) { int count; fixed_t dist; intercept_t* scan; intercept_t* in; count = intercept_p - intercepts; in = 0; // shut up compiler warning while (count--) { dist = INT_MAX; for (scan = intercepts ; scanfrac < dist) { dist = scan->frac; in = scan; } } if (dist > maxfrac) return true; // checked everything in range #if 0 // UNUSED { // don't check these yet, there may be others inserted in = scan = intercepts; for ( scan = intercepts ; scanfrac > maxfrac) *in++ = *scan; intercept_p = in; return false; } #endif if ( !func (in) ) return false; // don't bother going farther in->frac = INT_MAX; } return true; // everything was traversed } extern fixed_t bulletslope; #if 0 // Intercepts Overrun emulation, from PrBoom-plus. // Thanks to Andrey Budko (entryway) for researching this and his // implementation of Intercepts Overrun emulation in PrBoom-plus // which this is based on. typedef struct { int len; void *addr; boolean int16_array; } intercepts_overrun_t; // Intercepts memory table. This is where various variables are located // in memory in Vanilla Doom. When the intercepts table overflows, we // need to write to them. // // Almost all of the values to overwrite are 32-bit integers, except for // playerstarts, which is effectively an array of 16-bit integers and // must be treated differently. // haleyjd 20110204: NB: This array has *not* been updated for Strife, // because Strife has protection against intercepts overflows. The memory // layout of the 1.2 and 1.31 EXEs is radically different with respect // to this area of the BSS segment, so it would have to be redone entirely // if it were needed. static intercepts_overrun_t intercepts_overrun[] = { {4, NULL, false}, {4, NULL, /* &earlyout, */ false}, {4, NULL, /* &intercept_p, */ false}, {4, &lowfloor, false}, {4, &openbottom, false}, {4, &opentop, false}, {4, &openrange, false}, {4, NULL, false}, {120, NULL, /* &activeplats, */ false}, {8, NULL, false}, {4, &bulletslope, false}, {4, NULL, /* &swingx, */ false}, {4, NULL, /* &swingy, */ false}, {4, NULL, false}, {40, &playerstarts, true}, {4, NULL, /* &blocklinks, */ false}, {4, &bmapwidth, false}, {4, NULL, /* &blockmap, */ false}, {4, &bmaporgx, false}, {4, &bmaporgy, false}, {4, NULL, /* &blockmaplump, */ false}, {4, &bmapheight, false}, {0, NULL, false}, }; // Overwrite a specific memory location with a value. static void InterceptsMemoryOverrun(int location, int value) { int i, offset; int index; void *addr; i = 0; offset = 0; // Search down the array until we find the right entry while (intercepts_overrun[i].len != 0) { if (offset + intercepts_overrun[i].len > location) { addr = intercepts_overrun[i].addr; // Write the value to the memory location. // 16-bit and 32-bit values are written differently. if (addr != NULL) { if (intercepts_overrun[i].int16_array) { index = (location - offset) / 2; ((short *) addr)[index] = value & 0xffff; ((short *) addr)[index + 1] = (value >> 16) & 0xffff; } else { index = (location - offset) / 4; ((int *) addr)[index] = value; } } break; } offset += intercepts_overrun[i].len; ++i; } } // Emulate overruns of the intercepts[] array. static void InterceptsOverrun(int num_intercepts, intercept_t *intercept) { int location; if (num_intercepts <= MAXINTERCEPTS_ORIGINAL) { // No overrun return; } location = (num_intercepts - MAXINTERCEPTS_ORIGINAL - 1) * 12; // Overwrite memory that is overwritten in Vanilla Doom, using // the values from the intercept structure. // // Note: the ->d.{thing,line} member should really have its // address translated into the correct address value for // Vanilla Doom. InterceptsMemoryOverrun(location, intercept->frac); InterceptsMemoryOverrun(location + 4, intercept->isaline); InterceptsMemoryOverrun(location + 8, (int) intercept->d.thing); } #endif // // P_PathTraverse // Traces a line from x1,y1 to x2,y2, // calling the traverser function for each. // Returns true if the traverser function returns true // for all lines. // // [STRIFE] Verified unmodified // boolean P_PathTraverse ( fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean (*trav) (intercept_t *)) { fixed_t xt1; fixed_t yt1; fixed_t xt2; fixed_t yt2; fixed_t xstep; fixed_t ystep; fixed_t partial; fixed_t xintercept; fixed_t yintercept; int mapx; int mapy; int mapxstep; int mapystep; int count; earlyout = (flags & PT_EARLYOUT) != 0; validcount++; intercept_p = intercepts; if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) x1 += FRACUNIT; // don't side exactly on a line if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0) y1 += FRACUNIT; // don't side exactly on a line trace.x = x1; trace.y = y1; trace.dx = x2 - x1; trace.dy = y2 - y1; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = x1>>MAPBLOCKSHIFT; yt1 = y1>>MAPBLOCKSHIFT; x2 -= bmaporgx; y2 -= bmaporgy; xt2 = x2>>MAPBLOCKSHIFT; yt2 = y2>>MAPBLOCKSHIFT; if (xt2 > xt1) { mapxstep = 1; partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1)); ystep = FixedDiv (y2-y1,abs(x2-x1)); } else if (xt2 < xt1) { mapxstep = -1; partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1); ystep = FixedDiv (y2-y1,abs(x2-x1)); } else { mapxstep = 0; partial = FRACUNIT; ystep = 256*FRACUNIT; } yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep); if (yt2 > yt1) { mapystep = 1; partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1)); xstep = FixedDiv (x2-x1,abs(y2-y1)); } else if (yt2 < yt1) { mapystep = -1; partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1); xstep = FixedDiv (x2-x1,abs(y2-y1)); } else { mapystep = 0; partial = FRACUNIT; xstep = 256*FRACUNIT; } xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep); // Step through map blocks. // Count is present to prevent a round off error // from skipping the break. mapx = xt1; mapy = yt1; for (count = 0 ; count < 64 ; count++) { if (flags & PT_ADDLINES) { if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts)) return false; // early out } if (flags & PT_ADDTHINGS) { if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts)) return false; // early out } if (mapx == xt2 && mapy == yt2) { break; } if ( (yintercept >> FRACBITS) == mapy) { yintercept += ystep; mapx += mapxstep; } else if ( (xintercept >> FRACBITS) == mapx) { xintercept += xstep; mapy += mapystep; } } // go through the sorted list return P_TraverseIntercepts ( trav, FRACUNIT ); } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_mobj.c000066400000000000000000001020171257432200600230030ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Moving object handling. Spawn functions. // #include #include "i_system.h" #include "z_zone.h" #include "m_random.h" #include "doomdef.h" #include "p_local.h" #include "sounds.h" #include "st_stuff.h" #include "hu_stuff.h" #include "s_sound.h" #include "doomstat.h" #include "d_main.h" // villsa [STRIFE] extern line_t *spechit[]; // haleyjd: extern int numspechit; // [STRIFE] - needed in P_XYMovement void G_PlayerReborn (int player); void P_SpawnMapThing (mapthing_t* mthing); // // P_SetMobjState // Returns true if the mobj is still present. // // [STRIFE] Verified unmodified // int test; boolean P_SetMobjState ( mobj_t* mobj, statenum_t state ) { state_t* st; do { if (state == S_NULL) { mobj->state = (state_t *) S_NULL; P_RemoveMobj (mobj); return false; } st = &states[state]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // Modified handling. // Call action functions when the state is set if (st->action.acp1) st->action.acp1(mobj); state = st->nextstate; } while (!mobj->tics); return true; } // // P_ExplodeMissile // // [STRIFE] Removed randomization of deathstate tics // void P_ExplodeMissile (mobj_t* mo) { mo->momx = mo->momy = mo->momz = 0; P_SetMobjState (mo, mobjinfo[mo->type].deathstate); // villsa [STRIFE] removed tics randomization mo->flags &= ~MF_MISSILE; if (mo->info->deathsound) S_StartSound (mo, mo->info->deathsound); } // // P_XYMovement // // [STRIFE] Modifications for: // * No SKULLFLY logic (replaced by BOUNCE flag) // * Missiles can activate G1/GR line types // * Player walking logic // * Air friction for players // #define STOPSPEED 0x1000 #define FRICTION 0xe800 #define AIRFRICTION 0xfff0 // [STRIFE] void P_XYMovement (mobj_t* mo) { fixed_t ptryx; fixed_t ptryy; player_t* player; fixed_t xmove; fixed_t ymove; // villsa [STRIFE] unused /* if (!mo->momx && !mo->momy) { if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->flags &= ~MF_SKULLFLY; mo->momx = mo->momy = mo->momz = 0; P_SetMobjState (mo, mo->info->spawnstate); } return; } */ player = mo->player; if (mo->momx > MAXMOVE) mo->momx = MAXMOVE; else if (mo->momx < -MAXMOVE) mo->momx = -MAXMOVE; if (mo->momy > MAXMOVE) mo->momy = MAXMOVE; else if (mo->momy < -MAXMOVE) mo->momy = -MAXMOVE; xmove = mo->momx; ymove = mo->momy; do { if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2) { ptryx = mo->x + xmove/2; ptryy = mo->y + ymove/2; xmove >>= 1; ymove >>= 1; } else { ptryx = mo->x + xmove; ptryy = mo->y + ymove; xmove = ymove = 0; } if (!P_TryMove (mo, ptryx, ptryy)) { // blocked move if (mo->player) { // try to slide along it P_SlideMove (mo); } // villsa [STRIFE] check for bouncy missiles else if(mo->flags & MF_BOUNCE) { mo->momx >>= 3; mo->momy >>= 3; if (P_TryMove(mo, mo->x - xmove, ymove + mo->y)) mo->momy = -mo->momy; else mo->momx = -mo->momx; xmove = 0; ymove = 0; } else if (mo->flags & MF_MISSILE) { // haley 20110203: [STRIFE] // This modification allows missiles to activate shoot specials. // *** BUG: In vanilla Strife the second condition is simply // if(numspechit). However, numspechit can be negative, and // when it is, this accesses spechit[-2]. This always causes the // DOS exe to read from NULL, and the 'special' value there (in // DOS 6.22 at least) is 0x70, which does nothing. if(blockingline && blockingline->special) P_ShootSpecialLine(mo, blockingline); if(numspechit > 0) P_ShootSpecialLine(mo, spechit[numspechit-1]); // explode a missile if (ceilingline && ceilingline->backsector && ceilingline->backsector->ceilingpic == skyflatnum) { // Hack to prevent missiles exploding // against the sky. // Does not handle sky floors. P_RemoveMobj (mo); return; } P_ExplodeMissile (mo); } else mo->momx = mo->momy = 0; } } while (xmove || ymove); // slow down if (player && player->cheats & CF_NOMOMENTUM) { // debug option for no sliding at all mo->momx = mo->momy = 0; return; } // villsa [STRIFE] replace skullfly flag with MF_BOUNCE if (mo->flags & (MF_MISSILE | MF_BOUNCE) ) return; // no friction for missiles ever // haleyjd 20110224: [STRIFE] players experience friction even in the air, // although less than when on the ground. With this fix, the 1.2-and-up // IWAD demo is now in sync! if (mo->z > mo->floorz) { if(player) { mo->momx = FixedMul (mo->momx, AIRFRICTION); mo->momy = FixedMul (mo->momy, AIRFRICTION); } return; // no friction when airborne } if (mo->flags & MF_CORPSE) { // do not stop sliding // if halfway off a step with some momentum if (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 || mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) { if (mo->floorz != mo->subsector->sector->floorheight) return; } } if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && mo->momy > -STOPSPEED && mo->momy < STOPSPEED && (!player || (player->cmd.forwardmove == 0 && player->cmd.sidemove == 0 ) ) ) { // if in a walking frame, stop moving // villsa [STRIFE]: different player state (haleyjd - verified 20110202) if ( player&&(unsigned)((player->mo->state - states) - S_PLAY_01) < 4) P_SetMobjState (player->mo, S_PLAY_00); mo->momx = 0; mo->momy = 0; } else { mo->momx = FixedMul (mo->momx, FRICTION); mo->momy = FixedMul (mo->momy, FRICTION); } } // // P_ZMovement // // [STRIFE] Modifications for: // * 3D Object Clipping // * Different momz handling // * No SKULLFLY logic (replaced with BOUNCE) // * Missiles don't hit sky flats // void P_ZMovement (mobj_t* mo) { fixed_t dist; fixed_t delta; // check for smooth step up if (mo->player && mo->z < mo->floorz) { mo->player->viewheight -= mo->floorz-mo->z; mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3; } // adjust height // villsa [STRIFE] check for things standing on top of other things if(!P_CheckPositionZ(mo, mo->z + mo->momz)) { if(mo->momz >= 0) mo->ceilingz = mo->height + mo->z; else mo->floorz = mo->z; } //mo->z += mo->momz; // villsa [STRIFE] unused if ( mo->flags & MF_FLOAT && mo->target) { // float down towards target if too close if ( /*!(mo->flags & MF_SKULLFLY) // villsa [STRIFE] unused &&*/ !(mo->flags & MF_INFLOAT) ) { dist = P_AproxDistance (mo->x - mo->target->x, mo->y - mo->target->y); delta =(mo->target->z + (mo->height>>1)) - mo->z; if (delta<0 && dist < -(delta*3) ) mo->z -= FLOATSPEED; else if (delta>0 && dist < (delta*3) ) mo->z += FLOATSPEED; } } // clip movement if (mo->z <= mo->floorz) { // hit the floor if (mo->flags & MF_BOUNCE) { // the skull slammed into something // villsa [STRIFE] affect reactiontime // momz is also shifted by 1 mo->momz = -mo->momz >> 1; mo->reactiontime >>= 1; // villsa [STRIFE] get terrain type if(P_GetTerrainType(mo) != FLOOR_SOLID) mo->flags &= ~MF_BOUNCE; } if (mo->momz < 0) { if (mo->player && mo->momz < -GRAVITY*8) { // Squat down. // Decrease viewheight for a moment // after hitting the ground (hard), // and utter appropriate sound. mo->player->deltaviewheight = mo->momz>>3; // villsa [STRIFE] fall damage // haleyjd 09/18/10: Repaired calculation if(mo->momz < -20*FRACUNIT) P_DamageMobj(mo, NULL, mo, mo->momz / -25000); // haleyjd 20110224: *Any* fall centers your view, not just // damaging falls (moved outside the above if). mo->player->centerview = 1; S_StartSound (mo, sfx_oof); } mo->momz = 0; } mo->z = mo->floorz; // cph 2001/05/26 - // See lost soul bouncing comment above. We need this here for bug // compatibility with original Doom2 v1.9 - if a soul is charging and // hit by a raising floor this incorrectly reverses its Y momentum. // // villsa [STRIFE] unused /* if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) mo->momz = -mo->momz; */ // villsa [STRIFE] also check for MF_BOUNCE if ( (mo->flags & MF_MISSILE) && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) ) { P_ExplodeMissile (mo); } } else // haleyjd 20110224: else here, not else if - Strife change or what? { if (! (mo->flags & MF_NOGRAVITY) ) { if (mo->momz == 0) mo->momz = -GRAVITY*2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // villsa [STRIFE] replace skullfly flag with MF_BOUNCE if (mo->flags & MF_BOUNCE) { // villsa [STRIFE] affect reactiontime // momz is also shifted by 1 mo->momz = -mo->momz >> 1; mo->reactiontime >>= 1; } // hit the ceiling if (mo->momz > 0) mo->momz = 0; mo->z = mo->ceilingz - mo->height; // villsa [STRIFE] also check for MF_BOUNCE if ( (mo->flags & MF_MISSILE) && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) ) { // villsa [STRIFE] check against skies if(mo->subsector->sector->ceilingpic == skyflatnum) P_RemoveMobj(mo); else P_ExplodeMissile (mo); } } } } // // P_NightmareRespawn // // [STRIFE] Modifications for: // * Destination fog z coordinate // * Restoration of all Strife mapthing flags // void P_NightmareRespawn (mobj_t* mobj) { fixed_t x; fixed_t y; fixed_t z; mobj_t* mo; mapthing_t* mthing; x = mobj->spawnpoint.x << FRACBITS; y = mobj->spawnpoint.y << FRACBITS; // somthing is occupying it's position? if (!P_CheckPosition (mobj, x, y) ) return; // no respwan // spawn a teleport fog at old spot // because of removal of the body? mo = P_SpawnMobj (mobj->x, mobj->y, mobj->subsector->sector->floorheight , MT_TFOG); // initiate teleport sound S_StartSound (mo, sfx_telept); // spawn a teleport fog at the new spot //ss = R_PointInSubsector (x,y); // haleyjd [STRIFE]: Uses ONFLOORZ instead of ss->sector->floorheight mo = P_SpawnMobj (x, y, ONFLOORZ , MT_TFOG); S_StartSound (mo, sfx_telept); // spawn the new monster mthing = &mobj->spawnpoint; // spawn it if (mobj->info->flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; // inherit attributes from deceased one mo = P_SpawnMobj (x,y,z, mobj->type); mo->spawnpoint = mobj->spawnpoint; mo->angle = ANG45 * (mthing->angle/45); if (mthing->options & MTF_AMBUSH) mo->flags |= MF_AMBUSH; if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs mobj->flags |= MF_STAND; if (mthing->options & MTF_FRIEND) // [STRIFE] Allies mobj->flags |= MF_ALLY; if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object mobj->flags |= MF_SHADOW; if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency mobj->flags |= MF_MVIS; mo->reactiontime = 18; // remove the old monster, P_RemoveMobj (mobj); } // // P_MobjThinker // // [STRIFE] Modified for: // * Terrain effects // * Stonecold cheat // * Altered skill 5 respawn behavior // void P_MobjThinker (mobj_t* mobj) { // momentum movement if (mobj->momx || mobj->momy /*|| (mobj->flags&MF_SKULLFLY)*/ ) // villsa [STRIFE] unused { P_XYMovement (mobj); // FIXME: decent NOP/NULL/Nil function pointer please. if (mobj->thinker.function.acv == (actionf_v) (-1)) return; // mobj was removed // villsa [STRIFE] terrain clipping if(P_GetTerrainType(mobj) == FLOOR_SOLID) mobj->flags &= ~MF_FEETCLIPPED; else mobj->flags |= MF_FEETCLIPPED; } if ( (mobj->z != mobj->floorz && !(mobj->flags & MF_NOGRAVITY)) // villsa [STRIFE] || mobj->momz ) { P_ZMovement (mobj); // FIXME: decent NOP/NULL/Nil function pointer please. if (mobj->thinker.function.acv == (actionf_v) (-1)) return; // mobj was removed // villsa [STRIFE] terrain clipping and sounds if(P_GetTerrainType(mobj) == FLOOR_SOLID) mobj->flags &= ~MF_FEETCLIPPED; else { S_StartSound(mobj, sfx_wsplsh); mobj->flags |= MF_FEETCLIPPED; } } // cycle through states, // calling action functions at transitions if (mobj->tics != -1) { mobj->tics--; // villsa [STRIFE] stonecold cheat if(stonecold) { if(mobj->flags & MF_COUNTKILL) P_DamageMobj(mobj, mobj, mobj, 10); } // you can cycle through multiple states in a tic if (!mobj->tics) if (!P_SetMobjState (mobj, mobj->state->nextstate) ) return; // freed itself } else { // check for nightmare respawn if (! (mobj->flags & MF_COUNTKILL) ) return; if (!respawnmonsters) return; mobj->movecount++; // haleyjd [STRIFE]: respawn time increased from 12 to 16 if (mobj->movecount < 16*TICRATE) return; if ( leveltime&31 ) return; if (P_Random () > 4) return; // haleyjd [STRIFE]: NOTDMATCH things don't respawn if(mobj->flags & MF_NOTDMATCH) return; P_NightmareRespawn (mobj); } } // // P_SpawnMobj // // [STRIFE] Modifications to reactiontime and for terrain types. // mobj_t* P_SpawnMobj ( fixed_t x, fixed_t y, fixed_t z, mobjtype_t type ) { mobj_t* mobj; state_t* st; mobjinfo_t* info; mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); memset (mobj, 0, sizeof (*mobj)); info = &mobjinfo[type]; mobj->type = type; mobj->info = info; mobj->x = x; mobj->y = y; mobj->radius = info->radius; mobj->height = info->height; mobj->flags = info->flags; mobj->health = info->spawnhealth; // haleyjd 09/25/10: [STRIFE] Doesn't do this; messes up flamethrower // and a lot of other stuff using reactiontime as a counter. //if (gameskill != sk_nightmare) mobj->reactiontime = info->reactiontime; mobj->lastlook = P_Random () % MAXPLAYERS; // do not set the state with P_SetMobjState, // because action routines can not be called yet st = &states[info->spawnstate]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // set subsector and/or block links P_SetThingPosition (mobj); mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; if (z == ONFLOORZ) { mobj->z = mobj->floorz; // villsa [STRIFE] if(P_GetTerrainType(mobj) != FLOOR_SOLID) mobj->flags |= MF_FEETCLIPPED; } else if (z == ONCEILINGZ) mobj->z = mobj->ceilingz - mobj->info->height; else mobj->z = z; mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; P_AddThinker (&mobj->thinker); return mobj; } // // P_RemoveMobj // // [STRIFE] Modifications for item respawn timing // mapthing_t itemrespawnque[ITEMQUESIZE]; int itemrespawntime[ITEMQUESIZE]; int iquehead; int iquetail; void P_RemoveMobj (mobj_t* mobj) { // villsa [STRIFE] removed invuln/invis. sphere exceptions if ((mobj->flags & MF_SPECIAL) && !(mobj->flags & MF_DROPPED)) { itemrespawnque[iquehead] = mobj->spawnpoint; itemrespawntime[iquehead] = leveltime + 30*TICRATE; // [STRIFE] // [STRIFE] haleyjd 20130915 // -random parameter affects the behavior of respawning items here. if(randomparm && iquehead != iquetail) { short type = itemrespawnque[iquehead].type; short options = itemrespawnque[iquehead].options; // swap the type and options of iquehead and iquetail itemrespawnque[iquehead].type = itemrespawnque[iquetail].type; itemrespawnque[iquehead].options = itemrespawnque[iquetail].options; itemrespawnque[iquetail].type = type; itemrespawnque[iquetail].options = options; } iquehead = (iquehead+1)&(ITEMQUESIZE-1); // lose one off the end? if (iquehead == iquetail) iquetail = (iquetail+1)&(ITEMQUESIZE-1); } // unlink from sector and block lists P_UnsetThingPosition (mobj); // stop any playing sound S_StopSound (mobj); // free block P_RemoveThinker ((thinker_t*)mobj); } // // P_RespawnSpecials // // [STRIFE] modification to item respawn time handling // void P_RespawnSpecials (void) { fixed_t x; fixed_t y; fixed_t z; subsector_t* ss; mobj_t* mo; mapthing_t* mthing; int i; // only respawn items in deathmatch if (deathmatch != 2) return; // nothing left to respawn? if (iquehead == iquetail) return; // haleyjd [STRIFE]: 30 second wait is not accounted for here, see above. if (leveltime < itemrespawntime[iquetail]) return; mthing = &itemrespawnque[iquetail]; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; // spawn a teleport fog at the new spot ss = R_PointInSubsector (x,y); mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); S_StartSound (mo, sfx_itmbk); // find which type to spawn for (i=0 ; i< NUMMOBJTYPES ; i++) { if (mthing->type == mobjinfo[i].doomednum) break; } // spawn it if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mo = P_SpawnMobj (x,y,z, i); mo->spawnpoint = *mthing; mo->angle = ANG45 * (mthing->angle/45); // pull it from the que iquetail = (iquetail+1)&(ITEMQUESIZE-1); } // // P_SpawnPlayer // Called when a player is spawned on the level. // Most of the player structure stays unchanged // between levels. // // [STRIFE] Modifications for: // * stonecold cheat, -workparm // * default inventory/questflags // void P_SpawnPlayer(mapthing_t* mthing) { player_t* p; fixed_t x; fixed_t y; fixed_t z; mobj_t* mobj; if(mthing->type == 0) return; // not playing? if(!playeringame[mthing->type-1]) return; p = &players[mthing->type-1]; if (p->playerstate == PST_REBORN) G_PlayerReborn (mthing->type-1); x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; z = ONFLOORZ; mobj = P_SpawnMobj (x,y,z, MT_PLAYER); // set color translations for player sprites if(mthing->type > 1) mobj->flags |= (mthing->type-1)<angle = ANG45 * (mthing->angle/45); mobj->player = p; mobj->health = p->health; p->mo = mobj; p->playerstate = PST_LIVE; p->refire = 0; p->message = NULL; p->damagecount = 0; p->bonuscount = 0; p->extralight = 0; p->fixedcolormap = 0; p->viewheight = VIEWHEIGHT; // setup gun psprite P_SetupPsprites(p); // villsa [STRIFE] stonecold = false; // villsa [STRIFE] what a nasty hack... if(gamemap == 10) p->weaponowned[wp_sigil] = true; // villsa [STRIFE] instead of just giving cards in deathmatch mode, also // set accuracy to 50 and give all quest flags if(deathmatch) { int i; p->accuracy = 50; p->questflags = QF_ALLQUESTS; // 0x7fffffff for(i = 0; i < NUMCARDS; i++) p->cards[i] = true; } // villsa [STRIFE] set godmode? if(workparm) p->cheats |= CF_GODMODE; if(mthing->type - 1 == consoleplayer) { // wake up the status bar ST_Start (); // wake up the heads up text HU_Start (); } } // // P_SpawnMapThing // The fields of the mapthing should // already be in host byte order. // // [STRIFE] Modifications for: // * No Lost Souls, item count // * New mapthing_t flag bits // * 8-player support // void P_SpawnMapThing (mapthing_t* mthing) { int i; int bit; mobj_t* mobj; fixed_t x; fixed_t y; fixed_t z; // count deathmatch start positions if (mthing->type == 11) { if (deathmatch_p < &deathmatchstarts[10]) { memcpy (deathmatch_p, mthing, sizeof(*mthing)); deathmatch_p++; } return; } if (mthing->type <= 0) { // Thing type 0 is actually "player -1 start". // For some reason, Vanilla Doom accepts/ignores this. return; } // check for players specially // haleyjd 20120209: [STRIFE] 8 player starts if (mthing->type <= 8) { // save spots for respawning in network games playerstarts[mthing->type-1] = *mthing; if (!deathmatch) P_SpawnPlayer (mthing); return; } // check for apropriate skill level if (!netgame && (mthing->options & 16) ) return; if (gameskill == sk_baby) bit = 1; else if (gameskill == sk_nightmare) bit = 4; else bit = 1<<(gameskill-1); if (!(mthing->options & bit) ) return; // find which type to spawn for (i=0 ; i< NUMMOBJTYPES ; i++) if (mthing->type == mobjinfo[i].doomednum) break; if (i==NUMMOBJTYPES) I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type, mthing->x, mthing->y); // don't spawn keycards and players in deathmatch if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) return; // don't spawn any monsters if -nomonsters // villsa [STRIFE] Removed MT_SKULL if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL)) return; // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mobj = P_SpawnMobj (x,y,z, i); mobj->spawnpoint = *mthing; if (mobj->tics > 0) mobj->tics = 1 + (P_Random () % mobj->tics); if (mobj->flags & MF_COUNTKILL) totalkills++; // villsa [STRIFE] unused /* if (mobj->flags & MF_COUNTITEM) totalitems++; */ mobj->angle = ANG45 * (mthing->angle/45); if (mthing->options & MTF_AMBUSH) mobj->flags |= MF_AMBUSH; if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs mobj->flags |= MF_STAND; if (mthing->options & MTF_FRIEND) // [STRIFE] Allies mobj->flags |= MF_ALLY; if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object mobj->flags |= MF_SHADOW; if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency mobj->flags |= MF_MVIS; } // // GAME SPAWN FUNCTIONS // // // P_SpawnPuff // // [STRIFE] Modifications for: // * No spawn tics randomization // * Player melee behavior // extern fixed_t attackrange; void P_SpawnPuff ( fixed_t x, fixed_t y, fixed_t z ) { mobj_t* th; int t; t = P_Random(); z += ((t - P_Random()) << 10); // [STRIFE] removed momz and tics randomization th = P_SpawnMobj(x, y, z, MT_STRIFEPUFF); // [STRIFE]: new type // don't make punches spark on the wall // [STRIFE] Use a separate melee attack range for the player if(attackrange == PLAYERMELEERANGE) P_SetMobjState(th, S_POW2_00); // 141 // villsa [STRIFE] unused /* if (th->tics < 1) th->tics = 1; */ } // // P_SpawnSparkPuff // // villsa [STRIFE] new function // mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z) { int t = P_Random(); return P_SpawnMobj(x, y, ((t - P_Random()) << 10) + z, MT_SPARKPUFF); } // // P_SpawnBlood // // [STRIFE] Modifications for: // * No spawn tics randomization // * Different damage ranges for state setting // void P_SpawnBlood ( fixed_t x, fixed_t y, fixed_t z, int damage ) { mobj_t* th; int temp; temp = P_Random(); z += (temp - P_Random()) << 10; th = P_SpawnMobj(x, y, z, MT_BLOOD_DEATH); th->momz = FRACUNIT*2; // villsa [STRIFE]: removed tics randomization // villsa [STRIFE] different checks for damage range if(damage >= 10 && damage <= 13) P_SetMobjState(th, S_BLOD_00); else if(damage >= 7 && damage < 10) P_SetMobjState(th, S_BLOD_01); else if(damage < 7) P_SetMobjState(th, S_BLOD_02); } // // P_CheckMissileSpawn // Moves the missile forward a bit // and possibly explodes it right there. // // [STRIFE] Modifications for: // * No spawn tics randomization // void P_CheckMissileSpawn (mobj_t* th) { // villsa [STRIFE] removed tics randomization // move a little forward so an angle can // be computed if it immediately explodes th->x += (th->momx>>1); th->y += (th->momy>>1); th->z += (th->momz>>1); if (!P_TryMove (th, th->x, th->y)) P_ExplodeMissile (th); } // Certain functions assume that a mobj_t pointer is non-NULL, // causing a crash in some situations where it is NULL. Vanilla // Doom did not crash because of the lack of proper memory // protection. This function substitutes NULL pointers for // pointers to a dummy mobj, to avoid a crash. mobj_t *P_SubstNullMobj(mobj_t *mobj) { if (mobj == NULL) { static mobj_t dummy_mobj; dummy_mobj.x = 0; dummy_mobj.y = 0; dummy_mobj.z = 0; dummy_mobj.flags = 0; mobj = &dummy_mobj; } return mobj; } // // P_SpawnMissile // // [STRIFE] Added MVIS inaccuracy // mobj_t* P_SpawnMissile ( mobj_t* source, mobj_t* dest, mobjtype_t type ) { mobj_t* th; angle_t an; int dist; th = P_SpawnMobj (source->x, source->y, source->z + 4*8*FRACUNIT, type); if (th->info->seesound) S_StartSound (th, th->info->seesound); th->target = source; // where it came from an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); // fuzzy player if (dest->flags & MF_SHADOW) { int t = P_Random(); // haleyjd 20110223: remove order-of-evaluation dependencies an += (t - P_Random()) << 21; } // villsa [STRIFE] check for heavily transparent things else if(dest->flags & MF_MVIS) { int t = P_Random(); an += (t - P_Random()) << 22; } th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul (th->info->speed, finecosine[an]); th->momy = FixedMul (th->info->speed, finesine[an]); dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); dist = dist / th->info->speed; if (dist < 1) dist = 1; th->momz = (dest->z - source->z) / dist; P_CheckMissileSpawn (th); return th; } // // P_SpawnFacingMissile // // villsa [STRIFE] new function // Spawn a missile based on source's angle // mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type) { mobj_t* th; angle_t an; fixed_t dist; th = P_SpawnMobj(source->x, source->y, source->z + (32*FRACUNIT), type); if(th->info->seesound) S_StartSound(th, th->info->seesound); th->target = source; // where it came from th->angle = source->angle; // haleyjd 09/06/10: fix0red an = th->angle; // fuzzy player if (target->flags & MF_SHADOW) { int t = P_Random(); an += (t - P_Random()) << 21; } // villsa [STRIFE] check for heavily transparent things else if(target->flags & MF_MVIS) { int t = P_Random(); an += (t - P_Random()) << 22; } an >>= ANGLETOFINESHIFT; th->momx = FixedMul (th->info->speed, finecosine[an]); th->momy = FixedMul (th->info->speed, finesine[an]); dist = P_AproxDistance (target->x - source->x, target->y - source->y); dist = dist / th->info->speed; if(dist < 1) dist = 1; th->momz = (target->z - source->z) / dist; P_CheckMissileSpawn (th); return th; } // // P_SpawnPlayerMissile // // Tries to aim at a nearby monster // villsa [STRIFE] now returns a mobj // * Also modified to allow up/down look, and to account for foot-clipping // by liquid terrain. // mobj_t* P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type) { mobj_t* th; angle_t an; fixed_t x; fixed_t y; fixed_t z; fixed_t slope; // see which target is to be aimed at an = source->angle; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); if (!linetarget) { an += 1<<26; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); if (!linetarget) { an -= 2<<26; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); } if (!linetarget) { an = source->angle; // haleyjd 09/21/10: [STRIFE] Removed, for look up/down support. //slope = 0; } } // villsa [STRIFE] if(linetarget) source->target = linetarget; x = source->x; y = source->y; // villsa [STRIFE] if(!(source->flags & MF_FEETCLIPPED)) z = source->z + 32*FRACUNIT; else z = source->z + 22*FRACUNIT; th = P_SpawnMobj (x,y,z, type); if (th->info->seesound) S_StartSound (th, th->info->seesound); th->target = source; th->angle = an; th->momx = FixedMul( th->info->speed, finecosine[an>>ANGLETOFINESHIFT]); th->momy = FixedMul( th->info->speed, finesine[an>>ANGLETOFINESHIFT]); th->momz = FixedMul( th->info->speed, slope); P_CheckMissileSpawn (th); return th; } // // P_SpawnMortar // // villsa [STRIFE] new function // Spawn a high-arcing ballistic projectile // mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type) { mobj_t* th; angle_t an; fixed_t slope; an = source->angle; th = P_SpawnMobj(source->x, source->y, source->z, type); th->target = source; th->angle = an; an >>= ANGLETOFINESHIFT; // haleyjd 20110203: corrected order of function calls th->momx = FixedMul(th->info->speed, finecosine[an]); th->momy = FixedMul(th->info->speed, finesine[an]); P_CheckMissileSpawn(th); slope = P_AimLineAttack(source, source->angle, 1024*FRACUNIT); th->momz = FixedMul(th->info->speed, slope); return th; } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_mobj.h000066400000000000000000000241141257432200600230110ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Map Objects, MObj, definition and handling. // #ifndef __P_MOBJ__ #define __P_MOBJ__ // Basics. #include "tables.h" #include "m_fixed.h" // We need the thinker_t stuff. #include "d_think.h" // We need the WAD data structure for Map things, // from the THINGS lump. #include "doomdata.h" // States are tied to finite states are // tied to animation frames. // Needs precompiled tables/data structures. #include "info.h" // // NOTES: mobj_t // // mobj_ts are used to tell the refresh where to draw an image, // tell the world simulation when objects are contacted, // and tell the sound driver how to position a sound. // // The refresh uses the next and prev links to follow // lists of things in sectors as they are being drawn. // The sprite, frame, and angle elements determine which patch_t // is used to draw the sprite if it is visible. // The sprite and frame values are allmost allways set // from state_t structures. // The statescr.exe utility generates the states.h and states.c // files that contain the sprite/frame numbers from the // statescr.txt source file. // The xyz origin point represents a point at the bottom middle // of the sprite (between the feet of a biped). // This is the default origin position for patch_ts grabbed // with lumpy.exe. // A walking creature will have its z equal to the floor // it is standing on. // // The sound code uses the x,y, and subsector fields // to do stereo positioning of any sound effited by the mobj_t. // // The play simulation uses the blocklinks, x,y,z, radius, height // to determine when mobj_ts are touching each other, // touching lines in the map, or hit by trace lines (gunshots, // lines of sight, etc). // The mobj_t->flags element has various bit flags // used by the simulation. // // Every mobj_t is linked into a single sector // based on its origin coordinates. // The subsector_t is found with R_PointInSubsector(x,y), // and the sector_t can be found with subsector->sector. // The sector links are only used by the rendering code, // the play simulation does not care about them at all. // // Any mobj_t that needs to be acted upon by something else // in the play world (block movement, be shot, etc) will also // need to be linked into the blockmap. // If the thing has the MF_NOBLOCK flag set, it will not use // the block links. It can still interact with other things, // but only as the instigator (missiles will run into other // things, but nothing can run into a missile). // Each block in the grid is 128*128 units, and knows about // every line_t that it contains a piece of, and every // interactable mobj_t that has its origin contained. // // A valid mobj_t is a mobj_t that has the proper subsector_t // filled in for its xy coordinates and is linked into the // sector from which the subsector was made, or has the // MF_NOSECTOR flag set (the subsector_t needs to be valid // even if MF_NOSECTOR is set), and is linked into a blockmap // block or has the MF_NOBLOCKMAP flag set. // Links should only be modified by the P_[Un]SetThingPosition() // functions. // Do not change the MF_NO? flags while a thing is valid. // // Any questions? // // // Misc. mobj flags // typedef enum { // Call P_SpecialThing when touched. MF_SPECIAL = 1, // Blocks. MF_SOLID = 2, // Can be hit. MF_SHOOTABLE = 4, // Don't use the sector links (invisible but touchable). MF_NOSECTOR = 8, // Don't use the blocklinks (inert but displayable) MF_NOBLOCKMAP = 16, // villsa [STRIFE] Stand around until alerted MF_STAND = 32, // Will try to attack right back. MF_JUSTHIT = 64, // Will take at least one step before attacking. MF_JUSTATTACKED = 128, // On level spawning (initial position), // hang from ceiling instead of stand on floor. MF_SPAWNCEILING = 256, // Don't apply gravity (every tic), // that is, object will float, keeping current height // or changing it actively. MF_NOGRAVITY = 512, // Movement flags. // This allows jumps from high places. MF_DROPOFF = 0x400, // villsa [STRIFE] For players, count as quest item MF_GIVEQUEST = 0x800, // Player cheat. ??? MF_NOCLIP = 0x1000, // villsa [STRIFE] are feet clipped into water/slude floor? MF_FEETCLIPPED = 0x2000, // Allow moves to any height, no gravity. // For active floaters, e.g. cacodemons, pain elementals. MF_FLOAT = 0x4000, // villsa [STRIFE] can NPC talk? MF_NODIALOG = 0x8000, // Don't hit same species, explode on block. // Player missiles as well as fireballs of various kinds. MF_MISSILE = 0x10000, // Dropped by a demon, not level spawned. // E.g. ammo clips dropped by dying former humans. MF_DROPPED = 0x20000, // Use fuzzy draw (shadow demons or spectres), // temporary player invisibility powerup. MF_SHADOW = 0x40000, // Flag: don't bleed when shot (use puff), // barrels and shootable furniture shall not bleed. MF_NOBLOOD = 0x80000, // Don't stop moving halfway off a step, // that is, have dead bodies slide down all the way. MF_CORPSE = 0x100000, // Floating to a height for a move, ??? // don't auto float to target's height. MF_INFLOAT = 0x200000, // On kill, count this enemy object // towards intermission kill total. // Happy gathering. MF_COUNTKILL = 0x400000, // Not to be activated by sound, deaf monster. MF_AMBUSH = 0x800000, // villsa [STRIFE] flag used for bouncing projectiles MF_BOUNCE = 0x1000000, // Don't spawn this object // in death match mode (e.g. key cards). MF_NOTDMATCH = 0x2000000, // villsa [STRIFE] friendly towards player with matching flag MF_ALLY = 0x4000000, // villsa [STRIFE] 75% or 25% transparency? -- NEEDS VERIFICATION MF_MVIS = 0x8000000, // villsa [STRIFE] color translation MF_COLORSWAP1 = 0x10000000, // villsa [STRIFE] color translation MF_COLORSWAP2 = 0x20000000, // villsa [STRIFE] color translation MF_COLORSWAP3 = 0x40000000, // villsa [STRIFE] spectral entity, only damaged by spectral missiles MF_SPECTRAL = 0x80000000, // Player sprites in multiplayer modes are modified // using an internal color lookup table for re-indexing. // haleyjd 09/06/10: redid for Strife translations MF_TRANSLATION = (MF_COLORSWAP1|MF_COLORSWAP2|MF_COLORSWAP3), // Turns 0x10000000 into 0x01 to get a translation index. // villsa [STRIFE] change from 26 to 28 MF_TRANSSHIFT = 28 } mobjflag_t; // Map Object definition. // // [STRIFE]: Amazingly, only one modification was made to mobj_t over DOOM // 1.666, and that was the addition of the single-byte allegiance field for // tracking with which player friendly monsters are allied. // typedef struct mobj_s { // List: thinker links. thinker_t thinker; // Info for drawing: position. fixed_t x; fixed_t y; fixed_t z; // More list: links in sector (if needed) struct mobj_s* snext; struct mobj_s* sprev; //More drawing info: to determine current sprite. angle_t angle; // orientation spritenum_t sprite; // used to find patch_t and flip value int frame; // might be ORed with FF_FULLBRIGHT // Interaction info, by BLOCKMAP. // Links in blocks (if needed). struct mobj_s* bnext; struct mobj_s* bprev; struct subsector_s* subsector; // The closest interval over all contacted Sectors. fixed_t floorz; fixed_t ceilingz; // For movement checking. fixed_t radius; fixed_t height; // Momentums, used to update position. fixed_t momx; fixed_t momy; fixed_t momz; // If == validcount, already checked. int validcount; mobjtype_t type; mobjinfo_t* info; // &mobjinfo[mobj->type] int tics; // state tic counter state_t* state; int flags; int health; // Movement direction, movement generation (zig-zagging). int movedir; // 0-7 int movecount; // when 0, select a new dir // Thing being chased/attacked (or NULL), // also the originator for missiles. struct mobj_s* target; // Reaction time: if non 0, don't attack yet. // Used by player to freeze a bit after teleporting. int reactiontime; // If >0, the target will be chased // no matter what (even if shot) int threshold; // Additional info record for player avatars only. // Only valid if type == MT_PLAYER struct player_s* player; // Player number last looked for. int lastlook; // For nightmare respawn. mapthing_t spawnpoint; // Thing being chased/attacked for tracers. struct mobj_s* tracer; // [STRIFE] haleyjd 09/05/10: // * In multiplayer this stores allegiance, for friends and teleport beacons // * In single-player this tracks dialog state. byte miscdata; } mobj_t; // haleyjd [STRIFE] Exported void P_CheckMissileSpawn (mobj_t* th); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/p_plats.c000066400000000000000000000212621257432200600232010ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Plats (i.e. elevator platforms) code, raising/lowering. // #include #include "i_system.h" #include "z_zone.h" #include "m_random.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" #include "r_state.h" // Data. #include "sounds.h" plat_t* activeplats[MAXPLATS]; // // Move a plat up and down // void T_PlatRaise(plat_t* plat) { result_e res; switch(plat->status) { case up: res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush, 0, 1); if(plat->type == raiseAndChange || plat->type == raiseToNearestAndChange) { if(!(leveltime&7)) S_StartSound(&plat->sector->soundorg, sfx_stnmov); } // villsa [STRIFE] if(plat->type == slowDWUS) { if(!(leveltime&7)) S_StartSound(&plat->sector->soundorg, sfx_stnmov); } if(res == crushed && (!plat->crush)) { plat->count = plat->wait; plat->status = down; S_StartSound(&plat->sector->soundorg, sfx_pstart); } else { if(res == pastdest) { plat->count = plat->wait; plat->status = waiting; S_StartSound(&plat->sector->soundorg, sfx_pstop); switch(plat->type) { case blazeDWUS: case downWaitUpStay: case raiseAndChange: case slowDWUS: // villsa [STRIFE] case raiseToNearestAndChange: P_RemoveActivePlat(plat); break; default: break; } } } break; case down: res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1); // villsa [STRIFE] if(plat->type == slowDWUS) { if(!(leveltime&7)) S_StartSound(&plat->sector->soundorg, sfx_stnmov); } if(res == pastdest) { plat->count = plat->wait; plat->status = waiting; S_StartSound(&plat->sector->soundorg,sfx_pstop); // villsa [STRIFE] if(plat->type == upWaitDownStay) P_RemoveActivePlat(plat); } break; case waiting: if(!--plat->count) { if(plat->sector->floorheight == plat->low) plat->status = up; else plat->status = down; S_StartSound(&plat->sector->soundorg,sfx_pstart); } case in_stasis: break; } } // // EV_DoPlat // // Do Platforms "amount" is only used for SOME platforms. // int EV_DoPlat(line_t* line, plattype_e type, int amount) { plat_t* plat; int secnum; int rtn; sector_t* sec; secnum = -1; rtn = 0; // Activate all plats that are in_stasis switch(type) { case perpetualRaise: P_ActivateInStasis(line->tag); break; default: break; } while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // Find lowest & highest floors around sector rtn = 1; plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); P_AddThinker(&plat->thinker); plat->type = type; plat->sector = sec; plat->sector->specialdata = plat; plat->thinker.function.acp1 = (actionf_p1) T_PlatRaise; plat->crush = false; plat->tag = line->tag; switch(type) { case raiseToNearestAndChange: plat->speed = PLATSPEED/2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = P_FindNextHighestFloor(sec,sec->floorheight); plat->wait = 0; plat->status = up; // NO MORE DAMAGE, IF APPLICABLE sec->special = 0; S_StartSound(&sec->soundorg, sfx_stnmov); break; case raiseAndChange: plat->speed = PLATSPEED/2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = sec->floorheight + amount * FRACUNIT; plat->wait = 0; plat->status = up; S_StartSound(&sec->soundorg, sfx_stnmov); break; // villsa [STRIFE] case upWaitDownStay: plat->speed = PLATSPEED * 4; plat->high = P_FindNextHighestFloor(sec, sec->floorheight); plat->low = sec->floorheight; plat->wait = TICRATE * PLATWAIT; plat->status = up; S_StartSound(&sec->soundorg, sfx_pstart); break; case downWaitUpStay: plat->speed = PLATSPEED * 4; plat->low = P_FindLowestFloorSurrounding(sec); if(plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = TICRATE * PLATWAIT; plat->status = down; S_StartSound(&sec->soundorg, sfx_pstart); break; // villsa [STRIFE] case slowDWUS: plat->speed = PLATSPEED; plat->low = P_FindLowestFloorSurrounding(sec); if(plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = TICRATE * (PLATWAIT * 10); plat->status = down; S_StartSound(&sec->soundorg,sfx_pstart); break; case blazeDWUS: plat->speed = PLATSPEED * 8; plat->low = P_FindLowestFloorSurrounding(sec); if(plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = TICRATE * PLATWAIT; plat->status = down; S_StartSound(&sec->soundorg, sfx_pstart); break; case perpetualRaise: plat->speed = PLATSPEED; plat->low = P_FindLowestFloorSurrounding(sec); if(plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = P_FindHighestFloorSurrounding(sec); if(plat->high < sec->floorheight) plat->high = sec->floorheight; plat->wait = TICRATE * PLATWAIT; plat->status = P_Random() & 1; S_StartSound(&sec->soundorg, sfx_pstart); break; } P_AddActivePlat(plat); } return rtn; } // // P_ActivateInStasis // void P_ActivateInStasis(int tag) { int i; for(i = 0; i < MAXPLATS; i++) if(activeplats[i] && (activeplats[i])->tag == tag && (activeplats[i])->status == in_stasis) { (activeplats[i])->status = (activeplats[i])->oldstatus; (activeplats[i])->thinker.function.acp1 = (actionf_p1)T_PlatRaise; } } // // EV_StopPlat // void EV_StopPlat(line_t* line) { int j; for(j = 0; j < MAXPLATS; j++) if (activeplats[j] && ((activeplats[j])->status != in_stasis) && ((activeplats[j])->tag == line->tag)) { (activeplats[j])->oldstatus = (activeplats[j])->status; (activeplats[j])->status = in_stasis; (activeplats[j])->thinker.function.acv = (actionf_v)NULL; } } // // P_AddActivePlat // void P_AddActivePlat(plat_t* plat) { int i; for(i = 0; i < MAXPLATS; i++) if (activeplats[i] == NULL) { activeplats[i] = plat; return; } I_Error("P_AddActivePlat: no more plats!"); } // // P_RemoveActivePlat // void P_RemoveActivePlat(plat_t* plat) { int i; for(i = 0; i < MAXPLATS; i++) if(plat == activeplats[i]) { (activeplats[i])->sector->specialdata = NULL; P_RemoveThinker(&(activeplats[i])->thinker); activeplats[i] = NULL; return; } I_Error("P_RemoveActivePlat: can't find plat!"); } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_pspr.c000066400000000000000000000577111257432200600230520ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Weapon sprite animation, weapon objects. // Action functions for weapons. // #include "doomdef.h" #include "d_event.h" #include "deh_misc.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" // State. #include "doomstat.h" // Data. #include "sounds.h" #include "p_pspr.h" #define LOWERSPEED FRACUNIT*6 #define RAISESPEED FRACUNIT*6 #define WEAPONBOTTOM 128*FRACUNIT #define WEAPONTOP 32*FRACUNIT // // P_SetPsprite // // [STRIFE] // villsa: Removed psprite sx, sy modification via misc1/2 // void P_SetPsprite ( player_t* player, int position, statenum_t stnum ) { pspdef_t* psp; state_t* state; psp = &player->psprites[position]; do { if (!stnum) { // object removed itself psp->state = NULL; break; } state = &states[stnum]; psp->state = state; psp->tics = state->tics; // could be 0 // villsa [STRIFE] unused /*if (state->misc1) { // coordinate set psp->sx = state->misc1 << FRACBITS; psp->sy = state->misc2 << FRACBITS; }*/ // Call action routine. // Modified handling. if (state->action.acp2) { state->action.acp2(player, psp); if (!psp->state) break; } stnum = psp->state->nextstate; } while (!psp->tics); // an initial state of 0 could cycle through } // haleyjd 09/06/10: [STRIFE] Removed P_CalcSwing // // P_BringUpWeapon // Starts bringing the pending weapon up // from the bottom of the screen. // Uses player // // villsa [STRIFE] Modifications for Strife weapons // void P_BringUpWeapon (player_t* player) { statenum_t newstate; if (player->pendingweapon == wp_nochange) player->pendingweapon = player->readyweapon; if (player->pendingweapon == wp_flame) S_StartSound (player->mo, sfx_flidl); // villsa [STRIFE] flame sounds newstate = weaponinfo[player->pendingweapon].upstate; player->psprites[ps_weapon].sy = WEAPONBOTTOM; P_SetPsprite (player, ps_weapon, newstate); // villsa [STRIFE] set various flash states if(player->pendingweapon == wp_elecbow) P_SetPsprite(player, ps_flash, S_XBOW_10); // 31 else if(player->pendingweapon == wp_sigil && player->sigiltype) P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype); // 117 else P_SetPsprite(player, ps_flash, S_NULL); player->pendingweapon = wp_nochange; } // // P_CheckAmmo // Returns true if there is enough ammo to shoot. // If not, selects the next weapon to use. // // villsa [STRIFE] Changes to handle Strife weapons // boolean P_CheckAmmo (player_t* player) { ammotype_t ammo; int count; ammo = weaponinfo[player->readyweapon].ammo; // Minimal amount for one shot varies. if (player->readyweapon == wp_torpedo) count = 30; else if (player->readyweapon == wp_mauler) count = 20; else count = 1; // Regular. // Some do not need ammunition anyway. // Return if current ammunition sufficient. if (ammo == am_noammo || player->ammo[ammo] >= count) return true; // Out of ammo, pick a weapon to change to. // Preferences are set here. // villsa [STRIFE] new weapon preferences if (player->weaponowned[wp_mauler] && player->ammo[am_cell] >= 20) player->pendingweapon = wp_mauler; else if(player->weaponowned[wp_rifle] && player->ammo[am_bullets]) player->pendingweapon = wp_rifle; else if (player->weaponowned[wp_elecbow] && player->ammo[am_elecbolts]) player->pendingweapon = wp_elecbow; else if (player->weaponowned[wp_missile] && player->ammo[am_missiles]) player->pendingweapon = wp_missile; else if (player->weaponowned[wp_flame] && player->ammo[am_cell]) player->pendingweapon = wp_flame; else if (player->weaponowned[wp_hegrenade] && player->ammo[am_hegrenades]) player->pendingweapon = wp_hegrenade; else if (player->weaponowned[wp_poisonbow] && player->ammo[am_poisonbolts]) player->pendingweapon = wp_poisonbow; else if (player->weaponowned[wp_wpgrenade] && player->ammo[am_wpgrenades]) player->pendingweapon = wp_wpgrenade; // BUG: This will *never* be selected for an automatic switch because the // normal Mauler is higher priority and uses less ammo. else if (player->weaponowned[wp_torpedo] && player->ammo[am_cell] >= 30) player->pendingweapon = wp_torpedo; else player->pendingweapon = wp_fist; // Now set appropriate weapon overlay. P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate); return false; } // // P_FireWeapon. // // villsa [STRIFE] Changes for player state and weapons // void P_FireWeapon (player_t* player) { statenum_t newstate; if (!P_CheckAmmo (player)) return; P_SetMobjState (player->mo, S_PLAY_05); // 292 newstate = weaponinfo[player->readyweapon].atkstate; P_SetPsprite (player, ps_weapon, newstate); // villsa [STRIFE] exclude these weapons from causing noise if(player->readyweapon > wp_elecbow && player->readyweapon != wp_poisonbow) P_NoiseAlert (player->mo, player->mo); } // // P_DropWeapon // Player died, so put the weapon away. // void P_DropWeapon (player_t* player) { P_SetPsprite (player, ps_weapon, weaponinfo[player->readyweapon].downstate); } // // A_WeaponReady // The player can fire the weapon // or change to another weapon at this time. // Follows after getting weapon up, // or after previous attack/fire sequence. // void A_WeaponReady( player_t* player, pspdef_t* psp) { statenum_t newstate; int angle; // get out of attack state if (player->mo->state == &states[S_PLAY_05] || // 292 player->mo->state == &states[S_PLAY_06]) // 293 { P_SetMobjState (player->mo, S_PLAY_00); // 287 } // villsa [STRIFE] check for wp_flame instead of chainsaw // haleyjd 09/06/10: fixed state (00 rather than 01) if (player->readyweapon == wp_flame && psp->state == &states[S_FLMT_00]) // 62 { S_StartSound (player->mo, sfx_flidl); } // check for change // if player is dead, put the weapon away if (player->pendingweapon != wp_nochange || !player->health) { // change weapon // (pending weapon should allready be validated) newstate = weaponinfo[player->readyweapon].downstate; P_SetPsprite (player, ps_weapon, newstate); return; } // check for fire // the missile launcher and torpedo do not auto fire if (player->cmd.buttons & BT_ATTACK) { if ( !player->attackdown || (player->readyweapon != wp_missile && player->readyweapon != wp_torpedo)) // villsa [STRIFE] replace bfg with torpedo { player->attackdown = true; P_FireWeapon (player); return; } } else player->attackdown = false; // bob the weapon based on movement speed angle = (128*leveltime)&FINEMASK; psp->sx = FRACUNIT + FixedMul (player->bob, finecosine[angle]); angle &= FINEANGLES/2-1; psp->sy = WEAPONTOP + FixedMul (player->bob, finesine[angle]); } // // A_ReFire // The player can re-fire the weapon // without lowering it entirely. // void A_ReFire ( player_t* player, pspdef_t* psp ) { // check for fire // (if a weaponchange is pending, let it go through instead) if ( (player->cmd.buttons & BT_ATTACK) && player->pendingweapon == wp_nochange && player->health) { player->refire++; P_FireWeapon (player); } else { player->refire = 0; P_CheckAmmo (player); } } // // A_CheckReload // void A_CheckReload(player_t* player, pspdef_t* psp) { P_CheckAmmo(player); // villsa [STRIFE] set animating sprite for crossbow if(player->readyweapon == wp_elecbow) P_SetPsprite(player, player->readyweapon, S_XBOW_10); } // // A_Lower // Lowers current weapon, // and changes weapon at bottom. // void A_Lower ( player_t* player, pspdef_t* psp ) { psp->sy += LOWERSPEED; // Is already down. if (psp->sy < WEAPONBOTTOM ) return; // Player is dead. if (player->playerstate == PST_DEAD) { psp->sy = WEAPONBOTTOM; // don't bring weapon back up return; } // The old weapon has been lowered off the screen, // so change the weapon and start raising it if (!player->health) { // Player is dead, so keep the weapon off screen. P_SetPsprite (player, ps_weapon, S_NULL); return; } player->readyweapon = player->pendingweapon; P_BringUpWeapon (player); } // // A_Raise // void A_Raise ( player_t* player, pspdef_t* psp ) { statenum_t newstate; psp->sy -= RAISESPEED; if (psp->sy > WEAPONTOP ) return; psp->sy = WEAPONTOP; // The weapon has been raised all the way, // so change to the ready state. newstate = weaponinfo[player->readyweapon].readystate; P_SetPsprite (player, ps_weapon, newstate); } // // A_GunFlash // void A_GunFlash ( player_t* player, pspdef_t* psp ) { P_SetMobjState (player->mo, S_PLAY_06); P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate); } // // WEAPON ATTACKS // // // A_Punch // void A_Punch(player_t* player, pspdef_t* psp) { angle_t angle; int damage; int slope; int sound; int stamina; int t; // villsa [STRIFE] new damage formula // haleyjd 09/19/10: seriously corrected... stamina = player->stamina; damage = (P_Random() & ((stamina/10) + 7)) * ((stamina/10) + 2); if(player->powers[pw_strength]) damage *= 10; angle = player->mo->angle; t = P_Random(); angle += (t - P_Random()) << 18; slope = P_AimLineAttack (player->mo, angle, PLAYERMELEERANGE); P_LineAttack (player->mo, angle, PLAYERMELEERANGE, slope, damage); // turn to face target if(linetarget) { // villsa [STRIFE] check for non-flesh types if(linetarget->flags & MF_NOBLOOD) sound = sfx_mtalht; else sound = sfx_meatht; S_StartSound (player->mo, sound); player->mo->angle = R_PointToAngle2 (player->mo->x, player->mo->y, linetarget->x, linetarget->y); // villsa [STRIFE] apply flag player->mo->flags |= MF_JUSTATTACKED; // villsa [STRIFE] do punch alert routine P_DoPunchAlert(player->mo, linetarget); } else S_StartSound (player->mo, sfx_swish); } // // A_FireFlameThrower // // villsa [STRIFE] new codepointer // void A_FireFlameThrower(player_t* player, pspdef_t* psp) { mobj_t* mo; int t; P_SetMobjState(player->mo, S_PLAY_06); player->ammo[weaponinfo[player->readyweapon].ammo]--; t = P_Random(); player->mo->angle += (t - P_Random()) << 18; mo = P_SpawnPlayerMissile(player->mo, MT_SFIREBALL); mo->momz += (5*FRACUNIT); } // // A_FireMissile // // villsa [STRIFE] completly new compared to the original // void A_FireMissile(player_t* player, pspdef_t* psp) { angle_t an; int t; // haleyjd 09/19/10: I previously missed an add op that meant it should be // accuracy * 5, not 4. Checks out with other sources. an = player->mo->angle; t = P_Random(); player->mo->angle += (t - P_Random()) << (19 - (player->accuracy * 5 / 100)); P_SetMobjState(player->mo, S_PLAY_06); player->ammo[weaponinfo[player->readyweapon].ammo]--; P_SpawnPlayerMissile(player->mo, MT_MINIMISSLE); player->mo->angle = an; } // // A_FireMauler2 // // villsa [STRIFE] - new codepointer // void A_FireMauler2(player_t* player, pspdef_t* pspr) { P_SetMobjState(player->mo, S_PLAY_06); P_DamageMobj(player->mo, player->mo, NULL, 20); player->ammo[weaponinfo[player->readyweapon].ammo] -= 30; P_SpawnPlayerMissile(player->mo, MT_TORPEDO); P_Thrust(player, player->mo->angle + ANG180, 512000); } // // A_FireGrenade // // villsa [STRIFE] - new codepointer // void A_FireGrenade(player_t* player, pspdef_t* pspr) { mobjtype_t type; mobj_t* mo; state_t* st1; state_t* st2; angle_t an; fixed_t radius; // decide on what type of grenade to spawn if(player->readyweapon == wp_hegrenade) { type = MT_HEGRENADE; } else if(player->readyweapon == wp_wpgrenade) { type = MT_PGRENADE; } else { type = MT_HEGRENADE; fprintf(stderr, "Warning: A_FireGrenade used on wrong weapon!\n"); } player->ammo[weaponinfo[player->readyweapon].ammo]--; // set flash frame st1 = &states[(pspr->state - states) + weaponinfo[player->readyweapon].flashstate]; st2 = &states[weaponinfo[player->readyweapon].atkstate]; P_SetPsprite(player, ps_flash, st1 - st2); player->mo->z += 32*FRACUNIT; // ugh mo = P_SpawnMortar(player->mo, type); player->mo->z -= 32*FRACUNIT; // ugh // change momz based on player's pitch mo->momz = FixedMul((player->pitch<info->speed) + (8*FRACUNIT); S_StartSound(mo, mo->info->seesound); radius = mobjinfo[type].radius + player->mo->info->radius; an = (player->mo->angle >> ANGLETOFINESHIFT); mo->x += FixedMul(finecosine[an], radius + (4*FRACUNIT)); mo->y += FixedMul(finesine[an], radius + (4*FRACUNIT)); // shoot grenade from left or right side? if(&states[weaponinfo[player->readyweapon].atkstate] == pspr->state) an = (player->mo->angle - ANG90) >> ANGLETOFINESHIFT; else an = (player->mo->angle + ANG90) >> ANGLETOFINESHIFT; mo->x += FixedMul((15*FRACUNIT), finecosine[an]); mo->y += FixedMul((15*FRACUNIT), finesine[an]); // set bounce flag mo->flags |= MF_BOUNCE; } // // A_FireElectricBolt // villsa [STRIFE] - new codepointer // void A_FireElectricBolt(player_t* player, pspdef_t* pspr) { angle_t an = player->mo->angle; int t; // haleyjd 09/19/10: Use 5 mul on accuracy here as well t = P_Random(); player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100)); player->ammo[weaponinfo[player->readyweapon].ammo]--; P_SpawnPlayerMissile(player->mo, MT_ELECARROW); player->mo->angle = an; S_StartSound(player->mo, sfx_xbow); } // // A_FirePoisonBolt // villsa [STRIFE] - new codepointer // void A_FirePoisonBolt(player_t* player, pspdef_t* pspr) { angle_t an = player->mo->angle; int t; // haleyjd 09/19/10: Use 5 mul on accuracy here as well t = P_Random(); player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100)); player->ammo[weaponinfo[player->readyweapon].ammo]--; P_SpawnPlayerMissile(player->mo, MT_POISARROW); player->mo->angle = an; S_StartSound(player->mo, sfx_xbow); } // // P_BulletSlope // Sets a slope so a near miss is at aproximately // the height of the intended target // // haleyjd 09/06/10 [STRIFE] Modified with a little target hack... // fixed_t bulletslope; void P_BulletSlope (mobj_t *mo) { angle_t an; // see which target is to be aimed at an = mo->angle; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); if (!linetarget) { an += 1<<26; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); if (!linetarget) { an -= 2<<26; bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT); } } // haleyjd 09/06/10: [STRIFE] Somebody added this here, and without it, you // will get spurious crashing in routines such as P_LookForPlayers! if(linetarget) mo->target = linetarget; } // // P_GunShot // // [STRIFE] Modifications to support accuracy. // void P_GunShot ( mobj_t* mo, boolean accurate ) { angle_t angle; int damage; angle = mo->angle; // villsa [STRIFE] apply player accuracy // haleyjd 09/18/10: made some corrections: use 5x accuracy; // eliminated order-of-evaluation dependency if (!accurate) { int t = P_Random(); angle += (t - P_Random()) << (20 - ((mo->player->accuracy * 5) / 100)); } // haleyjd 09/18/10 [STRIFE] corrected damage formula and moved down to // preserve proper P_Random call order. damage = 4 * (P_Random() % 3 + 1); P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage); } // // A_FireRifle // // villsa [STRIFE] - new codepointer // void A_FireRifle(player_t* player, pspdef_t* pspr) { S_StartSound(player->mo, sfx_rifle); if(player->ammo[weaponinfo[player->readyweapon].ammo]) { P_SetMobjState(player->mo, S_PLAY_06); // 293 player->ammo[weaponinfo[player->readyweapon].ammo]--; P_BulletSlope(player->mo); P_GunShot(player->mo, !player->refire); } } // // A_FireMauler1 // // villsa [STRIFE] - new codepointer // void A_FireMauler1(player_t* player, pspdef_t* pspr) { int i; angle_t angle; int damage; // haleyjd 09/18/10: Corrected ammo check to use >= if(player->ammo[weaponinfo[player->readyweapon].ammo] >= 20) { player->ammo[weaponinfo[player->readyweapon].ammo] -= 20; P_BulletSlope(player->mo); S_StartSound(player->mo, sfx_pgrdat); for(i = 0; i < 20; i++) { int t; damage = 5*(P_Random ()%3+1); angle = player->mo->angle; t = P_Random(); angle += (t - P_Random()) << 19; t = P_Random(); P_LineAttack(player->mo, angle, 2112*FRACUNIT, bulletslope + ((t - P_Random())<<5), damage); } } } // // A_SigilSound // // villsa [STRIFE] - new codepointer // void A_SigilSound(player_t* player, pspdef_t* pspr) { S_StartSound(player->mo, sfx_siglup); player->extralight = 2; } // // A_FireSigil // // villsa [STRIFE] - new codepointer // void A_FireSigil(player_t* player, pspdef_t* pspr) { mobj_t* mo; angle_t an; int i; // keep info on armor because sigil does piercing damage i = player->armortype; player->armortype = 0; // BUG: setting inflictor causes firing the Sigil to always push the player // toward the east, no matter what direction he is facing. P_DamageMobj(player->mo, player->mo, NULL, 4 * (player->sigiltype + 1)); // restore armor player->armortype = i; S_StartSound(player->mo, sfx_siglup); switch(player->sigiltype) { // falling lightning bolts from the sky case 0: P_BulletSlope(player->mo); if(linetarget) { // haleyjd 09/18/10: corrected z coordinate mo = P_SpawnMobj(linetarget->x, linetarget->y, ONFLOORZ, MT_SIGIL_A_GROUND); mo->tracer = linetarget; } else { an = player->mo->angle>>ANGLETOFINESHIFT; mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SIGIL_A_GROUND); mo->momx += FixedMul((28*FRACUNIT), finecosine[an]); mo->momy += FixedMul((28*FRACUNIT), finesine[an]); } mo->health = -1; mo->target = player->mo; break; // simple projectile case 1: P_SpawnPlayerMissile(player->mo, MT_SIGIL_B_SHOT)->health = -1; break; // spread shot case 2: player->mo->angle -= ANG90; // starting at 270... for(i = 0; i < 20; i++) // increment by 1/10 of 90, 20 times. { player->mo->angle += (ANG90 / 10); mo = P_SpawnMortar(player->mo, MT_SIGIL_C_SHOT); mo->health = -1; mo->z = player->mo->z + (32*FRACUNIT); } player->mo->angle -= ANG90; // subtract off the extra 90 break; // tracer attack case 3: P_BulletSlope(player->mo); if(linetarget) { mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT); mo->tracer = linetarget; } else { an = player->mo->angle >> ANGLETOFINESHIFT; mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT); mo->momx += FixedMul(mo->info->speed, finecosine[an]); mo->momy += FixedMul(mo->info->speed, finesine[an]); } mo->health = -1; break; // mega blast case 4: mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_E_SHOT); mo->health = -1; if(!linetarget) { an = player->pitch >> ANGLETOFINESHIFT; mo->momz += FixedMul(finesine[an], mo->info->speed); } break; default: break; } } // // A_GunFlashThinker // // villsa [STRIFE] - new codepointer // void A_GunFlashThinker(player_t* player, pspdef_t* pspr) { if(player->readyweapon == wp_sigil && player->sigiltype) P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype); else P_SetPsprite(player, ps_flash, S_NULL); } // // ? // void A_Light0 (player_t *player, pspdef_t *psp) { player->extralight = 0; } void A_Light1 (player_t *player, pspdef_t *psp) { player->extralight = 1; } void A_Light2 (player_t *player, pspdef_t *psp) { player->extralight = 2; } // // A_SigilShock // // villsa [STRIFE] - new codepointer // void A_SigilShock (player_t *player, pspdef_t *psp) { player->extralight = -3; } // // A_TorpedoExplode // // villsa [STRIFE] - new codepointer // void A_TorpedoExplode(mobj_t* actor) { int i; actor->angle -= ANG180; for(i = 0; i < 80; i++) { actor->angle += (ANG90 / 20); P_SpawnMortar(actor, MT_TORPEDOSPREAD)->target = actor->target; } } // // A_MaulerSound // // villsa [STRIFE] - new codepointer // void A_MaulerSound(player_t *player, pspdef_t *psp) { int t; S_StartSound(player->mo, sfx_proton); t = P_Random(); psp->sx += (t - P_Random()) << 10; t = P_Random(); psp->sy += (t - P_Random()) << 10; } // // P_SetupPsprites // Called at start of level for each player. // void P_SetupPsprites(player_t* player) { int i; // remove all psprites for(i = 0; i < NUMPSPRITES; i++) player->psprites[i].state = NULL; // spawn the gun player->pendingweapon = player->readyweapon; P_BringUpWeapon(player); } // // P_MovePsprites // Called every tic by player thinking routine. // void P_MovePsprites (player_t* player) { int i; pspdef_t* psp; state_t* state; psp = &player->psprites[0]; for(i = 0; i < NUMPSPRITES; i++, psp++) { // a null state means not active if((state = psp->state)) { // drop tic count and possibly change state // a -1 tic count never changes if(psp->tics != -1) { psp->tics--; if(!psp->tics) P_SetPsprite (player, i, psp->state->nextstate); } } } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; // villsa [STRIFE] extra stuff for targeter player->psprites[ps_targleft].sx = (160*FRACUNIT) - ((100 - player->accuracy) << FRACBITS); player->psprites[ps_targright].sx = ((100 - player->accuracy) << FRACBITS) + (160*FRACUNIT); } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_pspr.h000066400000000000000000000034111257432200600230430ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Sprite animation. // #ifndef __P_PSPR__ #define __P_PSPR__ // Basic data types. // Needs fixed point, and BAM angles. #include "m_fixed.h" #include "tables.h" // // Needs to include the precompiled // sprite animation tables. // Header generated by multigen utility. // This includes all the data for thing animation, // i.e. the Thing Atrributes table // and the Frame Sequence table. #include "info.h" // // Frame flags: // handles maximum brightness (torches, muzzle flare, light sources) // #define FF_FULLBRIGHT 0x8000 // flag in thing->frame #define FF_FRAMEMASK 0x7fff // // Overlay psprites are scaled shapes // drawn directly on the view screen, // coordinates are given for a 320*200 view screen. // typedef enum { ps_weapon, ps_flash, ps_targcenter, // villsa [STRIFE] ps_targleft, // villsa [STRIFE] ps_targright, // villsa [STRIFE] NUMPSPRITES } psprnum_t; typedef struct { state_t* state; // a NULL state means not active int tics; fixed_t sx; fixed_t sy; } pspdef_t; typedef struct player_s *playerptr; // haleyjd [STRIFE] Exported void P_SetPsprite(playerptr player, int position, statenum_t stnum); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/p_saveg.c000066400000000000000000001346131257432200600231700ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Archiving: SaveGame I/O. // #include #include #include "dstrings.h" #include "deh_main.h" #include "i_system.h" #include "z_zone.h" #include "m_misc.h" #include "p_local.h" #include "p_saveg.h" // State. #include "doomstat.h" #include "r_state.h" #define SAVEGAME_EOF 0x1d // haleyjd 09/28/10: [STRIFE] VERSIONSIZE == 8 #define VERSIONSIZE 8 FILE *save_stream; int savegamelength; boolean savegame_error; // Get the filename of a temporary file to write the savegame to. After // the file has been successfully saved, it will be renamed to the // real file. char *P_TempSaveGameFile(void) { static char *filename = NULL; if (filename == NULL) { filename = M_StringJoin(savegamedir, "temp.dsg", NULL); } return filename; } // Get the filename of the save game file to use for the specified slot. char *P_SaveGameFile(int slot) { static char *filename = NULL; static size_t filename_size; char basename[32]; if (filename == NULL) { filename_size = strlen(savegamedir) + 32; filename = malloc(filename_size); } DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot); M_snprintf(filename, filename_size, "%s%s", savegamedir, basename); return filename; } // Endian-safe integer read/write functions static byte saveg_read8(void) { byte result; if (fread(&result, 1, 1, save_stream) < 1) { if (!savegame_error) { fprintf(stderr, "saveg_read8: Unexpected end of file while " "reading save game\n"); savegame_error = true; } } return result; } static void saveg_write8(byte value) { if (fwrite(&value, 1, 1, save_stream) < 1) { if (!savegame_error) { fprintf(stderr, "saveg_write8: Error while writing save game\n"); savegame_error = true; } } } static short saveg_read16(void) { int result; result = saveg_read8(); result |= saveg_read8() << 8; return result; } static void saveg_write16(short value) { saveg_write8(value & 0xff); saveg_write8((value >> 8) & 0xff); } static int saveg_read32(void) { int result; result = saveg_read8(); result |= saveg_read8() << 8; result |= saveg_read8() << 16; result |= saveg_read8() << 24; return result; } static void saveg_write32(int value) { saveg_write8(value & 0xff); saveg_write8((value >> 8) & 0xff); saveg_write8((value >> 16) & 0xff); saveg_write8((value >> 24) & 0xff); } // Pad to 4-byte boundaries static void saveg_read_pad(void) { unsigned long pos; int padding; int i; pos = ftell(save_stream); padding = (4 - (pos & 3)) & 3; for (i=0; ix = saveg_read16(); // short y; str->y = saveg_read16(); // short angle; str->angle = saveg_read16(); // short type; str->type = saveg_read16(); // short options; str->options = saveg_read16(); } static void saveg_write_mapthing_t(mapthing_t *str) { // short x; saveg_write16(str->x); // short y; saveg_write16(str->y); // short angle; saveg_write16(str->angle); // short type; saveg_write16(str->type); // short options; saveg_write16(str->options); } // // actionf_t // static void saveg_read_actionf_t(actionf_t *str) { // actionf_p1 acp1; str->acp1 = saveg_readp(); } static void saveg_write_actionf_t(actionf_t *str) { // actionf_p1 acp1; saveg_writep(str->acp1); } // // think_t // // This is just an actionf_t. // #define saveg_read_think_t saveg_read_actionf_t #define saveg_write_think_t saveg_write_actionf_t // // thinker_t // static void saveg_read_thinker_t(thinker_t *str) { // struct thinker_s* prev; str->prev = saveg_readp(); // struct thinker_s* next; str->next = saveg_readp(); // think_t function; saveg_read_think_t(&str->function); } static void saveg_write_thinker_t(thinker_t *str) { // struct thinker_s* prev; saveg_writep(str->prev); // struct thinker_s* next; saveg_writep(str->next); // think_t function; saveg_write_think_t(&str->function); } // // mobj_t // // haleyjd 09/28/10: [STRIFE] Changed to match Strife binary mobj_t structure. // static void saveg_read_mobj_t(mobj_t *str) { int pl; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // fixed_t x; str->x = saveg_read32(); // fixed_t y; str->y = saveg_read32(); // fixed_t z; str->z = saveg_read32(); // struct mobj_s* snext; str->snext = saveg_readp(); // struct mobj_s* sprev; str->sprev = saveg_readp(); // angle_t angle; str->angle = saveg_read32(); // spritenum_t sprite; str->sprite = saveg_read_enum(); // int frame; str->frame = saveg_read32(); // struct mobj_s* bnext; str->bnext = saveg_readp(); // struct mobj_s* bprev; str->bprev = saveg_readp(); // struct subsector_s* subsector; str->subsector = saveg_readp(); // fixed_t floorz; str->floorz = saveg_read32(); // fixed_t ceilingz; str->ceilingz = saveg_read32(); // fixed_t radius; str->radius = saveg_read32(); // fixed_t height; str->height = saveg_read32(); // fixed_t momx; str->momx = saveg_read32(); // fixed_t momy; str->momy = saveg_read32(); // fixed_t momz; str->momz = saveg_read32(); // int validcount; str->validcount = saveg_read32(); // mobjtype_t type; str->type = saveg_read_enum(); // mobjinfo_t* info; str->info = saveg_readp(); // int tics; str->tics = saveg_read32(); // state_t* state; str->state = &states[saveg_read32()]; // int flags; str->flags = saveg_read32(); // int health; str->health = saveg_read32(); // int movedir; str->movedir = saveg_read32(); // int movecount; str->movecount = saveg_read32(); // struct mobj_s* target; str->target = saveg_readp(); // int reactiontime; str->reactiontime = saveg_read32(); // int threshold; str->threshold = saveg_read32(); // struct player_s* player; pl = saveg_read32(); if (pl > 0) { str->player = &players[pl - 1]; str->player->mo = str; } else { str->player = NULL; } // int lastlook; str->lastlook = saveg_read32(); // mapthing_t spawnpoint; saveg_read_mapthing_t(&str->spawnpoint); // struct mobj_s* tracer; str->tracer = saveg_readp(); // byte miscdata; str->miscdata = saveg_read8(); // [STRIFE] Only change to mobj_t. } static void saveg_write_mobj_t(mobj_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // fixed_t x; saveg_write32(str->x); // fixed_t y; saveg_write32(str->y); // fixed_t z; saveg_write32(str->z); // struct mobj_s* snext; saveg_writep(str->snext); // struct mobj_s* sprev; saveg_writep(str->sprev); // angle_t angle; saveg_write32(str->angle); // spritenum_t sprite; saveg_write_enum(str->sprite); // int frame; saveg_write32(str->frame); // struct mobj_s* bnext; saveg_writep(str->bnext); // struct mobj_s* bprev; saveg_writep(str->bprev); // struct subsector_s* subsector; saveg_writep(str->subsector); // fixed_t floorz; saveg_write32(str->floorz); // fixed_t ceilingz; saveg_write32(str->ceilingz); // fixed_t radius; saveg_write32(str->radius); // fixed_t height; saveg_write32(str->height); // fixed_t momx; saveg_write32(str->momx); // fixed_t momy; saveg_write32(str->momy); // fixed_t momz; saveg_write32(str->momz); // int validcount; saveg_write32(str->validcount); // mobjtype_t type; saveg_write_enum(str->type); // mobjinfo_t* info; saveg_writep(str->info); // int tics; saveg_write32(str->tics); // state_t* state; saveg_write32(str->state - states); // int flags; saveg_write32(str->flags); // int health; saveg_write32(str->health); // int movedir; saveg_write32(str->movedir); // int movecount; saveg_write32(str->movecount); // struct mobj_s* target; saveg_writep(str->target); // int reactiontime; saveg_write32(str->reactiontime); // int threshold; saveg_write32(str->threshold); // struct player_s* player; if (str->player) { saveg_write32(str->player - players + 1); } else { saveg_write32(0); } // int lastlook; saveg_write32(str->lastlook); // mapthing_t spawnpoint; saveg_write_mapthing_t(&str->spawnpoint); // struct mobj_s* tracer; saveg_writep(str->tracer); // byte miscdata; saveg_write8(str->miscdata); // [STRIFE] Only change to mobj_t. } // // ticcmd_t // // haleyjd 09/28/10: [STRIFE] Modified for Strife binary ticcmd_t structure. // static void saveg_read_ticcmd_t(ticcmd_t *str) { // signed char forwardmove; str->forwardmove = saveg_read8(); // signed char sidemove; str->sidemove = saveg_read8(); // short angleturn; str->angleturn = saveg_read16(); // short consistancy; // STRIFE-FIXME: throwing away top byte of consistancy until // the true Strife ticcmd_t structure is available. str->consistancy = (byte)saveg_read16(); // byte chatchar; str->chatchar = saveg_read8(); // byte buttons; str->buttons = saveg_read8(); // byte buttons2; str->buttons2 = saveg_read8(); // [STRIFE] // int inventory; str->inventory = saveg_read32(); // [STRIFE] } static void saveg_write_ticcmd_t(ticcmd_t *str) { // signed char forwardmove; saveg_write8(str->forwardmove); // signed char sidemove; saveg_write8(str->sidemove); // short angleturn; saveg_write16(str->angleturn); // short consistancy; saveg_write16(str->consistancy); // byte chatchar; saveg_write8(str->chatchar); // byte buttons; saveg_write8(str->buttons); // byte buttons2; saveg_write8(str->buttons2); // [STRIFE] // int inventory; saveg_write32(str->inventory); // [STRIFE] } // // pspdef_t // static void saveg_read_pspdef_t(pspdef_t *str) { int state; // state_t* state; state = saveg_read32(); if (state > 0) { str->state = &states[state]; } else { str->state = NULL; } // int tics; str->tics = saveg_read32(); // fixed_t sx; str->sx = saveg_read32(); // fixed_t sy; str->sy = saveg_read32(); } static void saveg_write_pspdef_t(pspdef_t *str) { // state_t* state; if (str->state) { saveg_write32(str->state - states); } else { saveg_write32(0); } // int tics; saveg_write32(str->tics); // fixed_t sx; saveg_write32(str->sx); // fixed_t sy; saveg_write32(str->sy); } // // inventory_t // // haleyjd 09/28/10: [STRIFE] handle inventory input/output // static void saveg_read_inventory_t(inventory_t *str) { //int sprite; str->sprite = saveg_read32(); //int type; str->type = saveg_read32(); //int amount; str->amount = saveg_read32(); } static void saveg_write_inventory_t(inventory_t *str) { saveg_write32(str->sprite); saveg_write32(str->type); saveg_write32(str->amount); } // // player_t // // haleyjd 09/28/10: [STRIFE] Modified for Strife binary player_t structure. // static void saveg_read_player_t(player_t *str) { int i; // mobj_t* mo; str->mo = saveg_readp(); // playerstate_t playerstate; str->playerstate = saveg_read_enum(); // ticcmd_t cmd; saveg_read_ticcmd_t(&str->cmd); // fixed_t viewz; str->viewz = saveg_read32(); // fixed_t viewheight; str->viewheight = saveg_read32(); // fixed_t deltaviewheight; str->deltaviewheight = saveg_read32(); // fixed_t bob; str->bob = saveg_read32(); // int health; str->health = saveg_read32(); // int armorpoints; str->armorpoints = saveg_read16(); // [STRIFE] 32 -> 16 // int armortype; str->armortype = saveg_read16(); // [STRIFE] 32 -> 16 // int powers[NUMPOWERS]; for (i=0; ipowers[i] = saveg_read32(); } // int sigiltype; str->sigiltype = saveg_read32(); // [STRIFE] // int nukagecount; str->nukagecount = saveg_read32(); // [STRIFE] // int questflags; str->questflags = saveg_read32(); // [STRIFE] // int pitch; str->pitch = saveg_read32(); // [STRIFE] // int centerview; str->centerview = saveg_read32(); // [STRIFE] // inventory_t inventory[NUMINVENTORY]; for(i = 0; i < NUMINVENTORY; i++) { saveg_read_inventory_t(&(str->inventory[i])); // [STRIFE] } // int st_update; str->st_update = saveg_read32(); // [STRIFE] // short numinventory; str->numinventory = saveg_read16(); // [STRIFE] // short inventorycursor; str->inventorycursor = saveg_read16(); // [STRIFE] // short accuracy; str->accuracy = saveg_read16(); // [STRIFE] // short stamina; str->stamina = saveg_read16(); // [STRIFE] // boolean cards[NUMCARDS]; for (i=0; icards[i] = saveg_read32(); } // boolean backpack; str->backpack = saveg_read32(); // int attackdown; str->attackdown = saveg_read32(); // int usedown; str->usedown = saveg_read32(); // int inventorydown; str->inventorydown = saveg_read32(); // [STRIFE] // int frags[MAXPLAYERS]; for (i=0; ifrags[i] = saveg_read32(); } // weapontype_t readyweapon; str->readyweapon = saveg_read_enum(); // weapontype_t pendingweapon; str->pendingweapon = saveg_read_enum(); // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i] = saveg_read32(); } // int ammo[NUMAMMO]; for (i=0; iammo[i] = saveg_read32(); } // int maxammo[NUMAMMO]; for (i=0; imaxammo[i] = saveg_read32(); } // int cheats; str->cheats = saveg_read32(); // int refire; str->refire = saveg_read32(); // short killcount; str->killcount = saveg_read16(); // [STRIFE] 32 -> 16 // haleyjd 08/30/10 [STRIFE] No itemcount. // int itemcount; //str->itemcount = saveg_read32(); // haleyjd 08/30/10 [STRIFE] No secretcount. // int secretcount; //str->secretcount = saveg_read32(); // char* message; str->message = saveg_readp(); // int damagecount; str->damagecount = saveg_read32(); // int bonuscount; str->bonuscount = saveg_read32(); // mobj_t* attacker; str->attacker = saveg_readp(); // int extralight; str->extralight = saveg_read32(); // int fixedcolormap; str->fixedcolormap = saveg_read32(); // int colormap; - [STRIFE] no such field //str->colormap = saveg_read32(); // short allegiance; str->allegiance = saveg_read16(); // [STRIFE] // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // int mapstate[40]; for(i = 0; i < 40; ++i) // [STRIFE] { str->mapstate[i] = saveg_read32(); } // haleyjd 08/30/10: [STRIFE] No intermission, no didsecret. // boolean didsecret; //str->didsecret = saveg_read32(); } static void saveg_write_player_t(player_t *str) { int i; // mobj_t* mo; saveg_writep(str->mo); // playerstate_t playerstate; saveg_write_enum(str->playerstate); // ticcmd_t cmd; saveg_write_ticcmd_t(&str->cmd); // fixed_t viewz; saveg_write32(str->viewz); // fixed_t viewheight; saveg_write32(str->viewheight); // fixed_t deltaviewheight; saveg_write32(str->deltaviewheight); // fixed_t bob; saveg_write32(str->bob); // int health; saveg_write32(str->health); // int armorpoints; saveg_write16(str->armorpoints); // [STRIFE] 32 -> 16 // int armortype; saveg_write16(str->armortype); // [STRIFE] 32 -> 16 // int powers[NUMPOWERS]; for (i=0; ipowers[i]); } // int sigiltype; saveg_write32(str->sigiltype); // [STRIFE] // int nukagecount; saveg_write32(str->nukagecount); // [STRIFE] // int questflags; saveg_write32(str->questflags); // [STRIFE] // int pitch; saveg_write32(str->pitch); // [STRIFE] // int centerview; saveg_write32(str->centerview); // [STRIFE] // inventory_t inventory[NUMINVENTORY]; for(i = 0; i < NUMINVENTORY; ++i) // [STRIFE] { saveg_write_inventory_t(&str->inventory[i]); } // int st_update; saveg_write32(str->st_update); // [STRIFE] // short numinventory; saveg_write16(str->numinventory); // [STRIFE] // short inventorycursor; saveg_write16(str->inventorycursor); // [STRIFE] // short accuracy; saveg_write16(str->accuracy); // [STRIFE] // short stamina; saveg_write16(str->stamina); // [STRIFE] // boolean cards[NUMCARDS]; for (i=0; icards[i]); } // boolean backpack; saveg_write32(str->backpack); // int attackdown; saveg_write32(str->attackdown); // int usedown; saveg_write32(str->usedown); // int inventorydown; saveg_write32(str->inventorydown); // [STRIFE] // int frags[MAXPLAYERS]; for (i=0; ifrags[i]); } // weapontype_t readyweapon; saveg_write_enum(str->readyweapon); // weapontype_t pendingweapon; saveg_write_enum(str->pendingweapon); // boolean weaponowned[NUMWEAPONS]; for (i=0; iweaponowned[i]); } // int ammo[NUMAMMO]; for (i=0; iammo[i]); } // int maxammo[NUMAMMO]; for (i=0; imaxammo[i]); } // int cheats; saveg_write32(str->cheats); // int refire; saveg_write32(str->refire); // short killcount; saveg_write16(str->killcount); // [STRIFE] 32 -> 16 // haleyjd 08/30/10 [STRIFE] No itemcount // int itemcount; //saveg_write32(str->itemcount); // haleyjd 08/30/10 [STRIFE] No secretcount // int secretcount; //saveg_write32(str->secretcount); // char* message; saveg_writep(str->message); // int damagecount; saveg_write32(str->damagecount); // int bonuscount; saveg_write32(str->bonuscount); // mobj_t* attacker; saveg_writep(str->attacker); // int extralight; saveg_write32(str->extralight); // int fixedcolormap; saveg_write32(str->fixedcolormap); // int colormap; [STRIFE] no such field //saveg_write32(str->colormap); // short allegiance; saveg_write16(str->allegiance); // [STRIFE] // pspdef_t psprites[NUMPSPRITES]; for (i=0; ipsprites[i]); } // int mapstate[40]; for(i = 0; i < 40; ++i) // [STRIFE] { saveg_write32(str->mapstate[i]); } // haleyjd 08/30/10: [STRIFE] No intermission, no secret. // boolean didsecret; //saveg_write32(str->didsecret); } // // ceiling_t // static void saveg_read_ceiling_t(ceiling_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // ceiling_e type; str->type = saveg_read_enum(); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // fixed_t bottomheight; str->bottomheight = saveg_read32(); // fixed_t topheight; str->topheight = saveg_read32(); // fixed_t speed; str->speed = saveg_read32(); // boolean crush; str->crush = saveg_read32(); // int direction; str->direction = saveg_read32(); // int tag; str->tag = saveg_read32(); // int olddirection; str->olddirection = saveg_read32(); } static void saveg_write_ceiling_t(ceiling_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // ceiling_e type; saveg_write_enum(str->type); // sector_t* sector; saveg_write32(str->sector - sectors); // fixed_t bottomheight; saveg_write32(str->bottomheight); // fixed_t topheight; saveg_write32(str->topheight); // fixed_t speed; saveg_write32(str->speed); // boolean crush; saveg_write32(str->crush); // int direction; saveg_write32(str->direction); // int tag; saveg_write32(str->tag); // int olddirection; saveg_write32(str->olddirection); } // // vldoor_t // // haleyjd 09/28/10: [STRIFE] Modified for Strife binary vldoor_t structure. // static void saveg_read_vldoor_t(vldoor_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // vldoor_e type; str->type = saveg_read_enum(); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // fixed_t topheight; str->topheight = saveg_read32(); // fixed_t speed; str->speed = saveg_read32(); // int direction; str->direction = saveg_read32(); // int topwait; str->topwait = saveg_read32(); // int topcountdown; str->topcountdown = saveg_read32(); // villsa [STRIFE] new field - sound to play when opening //int opensound; str->opensound = saveg_read32(); // villsa [STRIFE] new field - sound to play when closing //int closesound; str->closesound = saveg_read32(); } static void saveg_write_vldoor_t(vldoor_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // vldoor_e type; saveg_write_enum(str->type); // sector_t* sector; saveg_write32(str->sector - sectors); // fixed_t topheight; saveg_write32(str->topheight); // fixed_t speed; saveg_write32(str->speed); // int direction; saveg_write32(str->direction); // int topwait; saveg_write32(str->topwait); // int topcountdown; saveg_write32(str->topcountdown); // villsa [STRIFE] new field - sound to play when opening //int opensound; saveg_write32(str->opensound); // villsa [STRIFE] new field - sound to play when closing //int closesound; saveg_write32(str->closesound); } // // slidedoor_t [STRIFE]: new thinker type // static void saveg_read_slidedoor_t(slidedoor_t *str) { int sector; int line; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sdt_e type; str->type = saveg_read_enum(); // line_t *line1; line = saveg_read32(); str->line1 = &lines[line]; // line_t *line2; line = saveg_read32(); str->line2 = &lines[line]; // int frame; str->frame = saveg_read32(); // int whichDoorIndex; str->whichDoorIndex = saveg_read32(); // int timer; str->timer = saveg_read32(); // sector_t *frontsector; sector = saveg_read32(); str->frontsector = §ors[sector]; // sd_e status; str->status = saveg_read_enum(); } static void saveg_write_slidedoor_t(slidedoor_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sdt_e type; saveg_write_enum(str->type); // line_t *line1; saveg_write32(str->line1 - lines); // line_t *line2; saveg_write32(str->line2 - lines); // int frame; saveg_write32(str->frame); // int whichDoorIndex; saveg_write32(str->whichDoorIndex); // int timer; saveg_write32(str->timer); // sector_t *frontsector; saveg_write32(str->frontsector - sectors); // sd_e status; saveg_write_enum(str->status); } // // floormove_t // static void saveg_read_floormove_t(floormove_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // floor_e type; str->type = saveg_read_enum(); // boolean crush; str->crush = saveg_read32(); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int direction; str->direction = saveg_read32(); // int newspecial; str->newspecial = saveg_read32(); // short texture; str->texture = saveg_read16(); // fixed_t floordestheight; str->floordestheight = saveg_read32(); // fixed_t speed; str->speed = saveg_read32(); } static void saveg_write_floormove_t(floormove_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // floor_e type; saveg_write_enum(str->type); // boolean crush; saveg_write32(str->crush); // sector_t* sector; saveg_write32(str->sector - sectors); // int direction; saveg_write32(str->direction); // int newspecial; saveg_write32(str->newspecial); // short texture; saveg_write16(str->texture); // fixed_t floordestheight; saveg_write32(str->floordestheight); // fixed_t speed; saveg_write32(str->speed); } // // plat_t // static void saveg_read_plat_t(plat_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // fixed_t speed; str->speed = saveg_read32(); // fixed_t low; str->low = saveg_read32(); // fixed_t high; str->high = saveg_read32(); // int wait; str->wait = saveg_read32(); // int count; str->count = saveg_read32(); // plat_e status; str->status = saveg_read_enum(); // plat_e oldstatus; str->oldstatus = saveg_read_enum(); // boolean crush; str->crush = saveg_read32(); // int tag; str->tag = saveg_read32(); // plattype_e type; str->type = saveg_read_enum(); } static void saveg_write_plat_t(plat_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // fixed_t speed; saveg_write32(str->speed); // fixed_t low; saveg_write32(str->low); // fixed_t high; saveg_write32(str->high); // int wait; saveg_write32(str->wait); // int count; saveg_write32(str->count); // plat_e status; saveg_write_enum(str->status); // plat_e oldstatus; saveg_write_enum(str->oldstatus); // boolean crush; saveg_write32(str->crush); // int tag; saveg_write32(str->tag); // plattype_e type; saveg_write_enum(str->type); } // // lightflash_t // static void saveg_read_lightflash_t(lightflash_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int count; str->count = saveg_read32(); // int maxlight; str->maxlight = saveg_read32(); // int minlight; str->minlight = saveg_read32(); // int maxtime; str->maxtime = saveg_read32(); // int mintime; str->mintime = saveg_read32(); } static void saveg_write_lightflash_t(lightflash_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // int count; saveg_write32(str->count); // int maxlight; saveg_write32(str->maxlight); // int minlight; saveg_write32(str->minlight); // int maxtime; saveg_write32(str->maxtime); // int mintime; saveg_write32(str->mintime); } // // strobe_t // static void saveg_read_strobe_t(strobe_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int count; str->count = saveg_read32(); // int minlight; str->minlight = saveg_read32(); // int maxlight; str->maxlight = saveg_read32(); // int darktime; str->darktime = saveg_read32(); // int brighttime; str->brighttime = saveg_read32(); } static void saveg_write_strobe_t(strobe_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // int count; saveg_write32(str->count); // int minlight; saveg_write32(str->minlight); // int maxlight; saveg_write32(str->maxlight); // int darktime; saveg_write32(str->darktime); // int brighttime; saveg_write32(str->brighttime); } // // glow_t // static void saveg_read_glow_t(glow_t *str) { int sector; // thinker_t thinker; saveg_read_thinker_t(&str->thinker); // sector_t* sector; sector = saveg_read32(); str->sector = §ors[sector]; // int minlight; str->minlight = saveg_read32(); // int maxlight; str->maxlight = saveg_read32(); // int direction; str->direction = saveg_read32(); } static void saveg_write_glow_t(glow_t *str) { // thinker_t thinker; saveg_write_thinker_t(&str->thinker); // sector_t* sector; saveg_write32(str->sector - sectors); // int minlight; saveg_write32(str->minlight); // int maxlight; saveg_write32(str->maxlight); // int direction; saveg_write32(str->direction); } // // Write the header for a savegame // // haleyjd 09/28/10: [STRIFE] numerous modifications. // void P_WriteSaveGameHeader(char *description) { char name[VERSIONSIZE]; int i; /* [STRIFE] This is in the "NAME" file in a Strife save directory. for (i=0; description[i] != '\0'; ++i) saveg_write8(description[i]); for (; i> 16) & 0xff); saveg_write8((leveltime >> 8) & 0xff); saveg_write8(leveltime & 0xff); } // // Read the header for a savegame // boolean P_ReadSaveGameHeader(void) { int i; byte a, b, c; char vcheck[VERSIONSIZE]; char read_vcheck[VERSIONSIZE]; // skip the description field /* for (i=0; ifloorheight >> FRACBITS); saveg_write16(sec->ceilingheight >> FRACBITS); saveg_write16(sec->floorpic); //saveg_write16(sec->ceilingpic); [STRIFE] not saved. saveg_write16(sec->lightlevel); saveg_write16(sec->special); // needed? //saveg_write16(sec->tag); // needed? [STRIFE] not saved. } // do lines for (i=0, li = lines ; iflags); saveg_write16(li->special); //saveg_write16(li->tag); [STRIFE] not saved. for (j=0 ; j<2 ; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; // [STRIFE] offsets not saved. //saveg_write16(si->textureoffset >> FRACBITS); //saveg_write16(si->rowoffset >> FRACBITS); saveg_write16(si->toptexture); saveg_write16(si->bottomtexture); saveg_write16(si->midtexture); } } } // // P_UnArchiveWorld // void P_UnArchiveWorld (void) { int i; int j; sector_t* sec; line_t* li; side_t* si; // do sectors for (i=0, sec = sectors ; ifloorheight = saveg_read16() << FRACBITS; sec->ceilingheight = saveg_read16() << FRACBITS; sec->floorpic = saveg_read16(); //sec->ceilingpic = saveg_read16(); [STRIFE] not saved sec->lightlevel = saveg_read16(); sec->special = saveg_read16(); // needed? //sec->tag = saveg_read16(); // needed? [STRIFE] not saved sec->specialdata = 0; sec->soundtarget = 0; } // do lines for (i=0, li = lines ; iflags = saveg_read16(); li->special = saveg_read16(); //li->tag = saveg_read16(); [STRIFE] not saved for (j=0 ; j<2 ; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; // [STRIFE] offsets not saved. //si->textureoffset = saveg_read16() << FRACBITS; //si->rowoffset = saveg_read16() << FRACBITS; si->toptexture = saveg_read16(); si->bottomtexture = saveg_read16(); si->midtexture = saveg_read16(); } } } // // Thinkers // typedef enum { tc_end, tc_mobj } thinkerclass_t; // // P_ArchiveThinkers // // [STRIFE] Verified unmodified. // void P_ArchiveThinkers (void) { thinker_t* th; // save off the current thinkers for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acp1 == (actionf_p1)P_MobjThinker) { saveg_write8(tc_mobj); saveg_write_pad(); saveg_write_mobj_t((mobj_t *) th); continue; } // haleyjd: This may seem mysterious but in the DOOM prebeta, // different types of things used different thinker functions. // Those would have all been handled here and this message is // probably a relic of that old system, not to mention the odd // name of this function, and use of an enumeration with only // two values in it. // I_Error ("P_ArchiveThinkers: Unknown thinker function"); } // add a terminating marker saveg_write8(tc_end); } // // P_UnArchiveThinkers // void P_UnArchiveThinkers (void) { byte tclass; thinker_t* currentthinker; thinker_t* next; mobj_t* mobj; // remove all the current thinkers currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { next = currentthinker->next; if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) P_RemoveMobj ((mobj_t *)currentthinker); else Z_Free (currentthinker); currentthinker = next; } P_InitThinkers (); // read in saved thinkers while (1) { tclass = saveg_read8(); switch (tclass) { case tc_end: return; // end of list case tc_mobj: saveg_read_pad(); mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); saveg_read_mobj_t(mobj); // haleyjd 09/29/10: Strife sets the targets of non-allied creatures // who had a non-NULL target at save time to players[0].mo so that // they won't fall back asleep. // // BUG: As the player may not have been spawned yet, we could be // setting monsters' targets to the mobj which was spawned by // P_SetupLevel and then removed just above. Due to a subtle glitch // in the DOOM engine whereby all things removed in this function // are leaked until the next time P_SetupLevel is called, this is a // safe operation - the call to P_InitThinkers above stops any of // the objects removed, including the player's previous body, from // being passed to Z_Free. One glitch relying on another! if(mobj->target != NULL && (mobj->flags & MF_ALLY) != MF_ALLY) mobj->target = players[0].mo; else mobj->target = NULL; // WARNING! Strife does not seem to set tracer! I am leaving it be // for now because so far no crashes have been observed, and failing // to set this here will almost certainly crash Choco. mobj->tracer = NULL; P_SetThingPosition (mobj); mobj->info = &mobjinfo[mobj->type]; // [STRIFE]: doesn't set these //mobj->floorz = mobj->subsector->sector->floorheight; //mobj->ceilingz = mobj->subsector->sector->ceilingheight; mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; P_AddThinker (&mobj->thinker); break; default: I_Error ("Unknown tclass %i in savegame",tclass); } } } // // P_ArchiveSpecials // enum { tc_ceiling, tc_door, tc_floor, tc_plat, tc_flash, tc_strobe, tc_glow, tc_slidingdoor, // [STRIFE] tc_endspecials } specials_e; // // Things to handle: // // T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list // T_VerticalDoor, (vldoor_t: sector_t * swizzle), // T_SlidingDoor, (slidedoor_t: sector_t *, line_t * x 2 swizzle) [STRIFE] // T_MoveFloor, (floormove_t: sector_t * swizzle), // T_LightFlash, (lightflash_t: sector_t * swizzle), // T_StrobeFlash, (strobe_t: sector_t *), // T_Glow, (glow_t: sector_t *), // T_PlatRaise, (plat_t: sector_t *), - active list // void P_ArchiveSpecials (void) { thinker_t* th; int i; // save off the current thinkers for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acv == (actionf_v)NULL) { for (i = 0; i < MAXCEILINGS;i++) if (activeceilings[i] == (ceiling_t *)th) break; if (ifunction.acp1 == (actionf_p1)T_MoveCeiling) { saveg_write8(tc_ceiling); saveg_write_pad(); saveg_write_ceiling_t((ceiling_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_VerticalDoor) { saveg_write8(tc_door); saveg_write_pad(); saveg_write_vldoor_t((vldoor_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_SlidingDoor) { saveg_write8(tc_slidingdoor); saveg_write_pad(); saveg_write_slidedoor_t((slidedoor_t *)th); continue; } if (th->function.acp1 == (actionf_p1)T_MoveFloor) { saveg_write8(tc_floor); saveg_write_pad(); saveg_write_floormove_t((floormove_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_PlatRaise) { saveg_write8(tc_plat); saveg_write_pad(); saveg_write_plat_t((plat_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_LightFlash) { saveg_write8(tc_flash); saveg_write_pad(); saveg_write_lightflash_t((lightflash_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_StrobeFlash) { saveg_write8(tc_strobe); saveg_write_pad(); saveg_write_strobe_t((strobe_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_Glow) { saveg_write8(tc_glow); saveg_write_pad(); saveg_write_glow_t((glow_t *) th); continue; } } // add a terminating marker saveg_write8(tc_endspecials); } // // P_UnArchiveSpecials // void P_UnArchiveSpecials (void) { byte tclass; ceiling_t* ceiling; vldoor_t* door; slidedoor_t* slidedoor; // haleyjd [STRIFE] floormove_t* floor; plat_t* plat; lightflash_t* flash; strobe_t* strobe; glow_t* glow; // read in saved thinkers while (1) { tclass = saveg_read8(); switch (tclass) { case tc_endspecials: return; // end of list case tc_ceiling: saveg_read_pad(); ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL); saveg_read_ceiling_t(ceiling); ceiling->sector->specialdata = ceiling; if (ceiling->thinker.function.acp1) ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling; P_AddThinker (&ceiling->thinker); P_AddActiveCeiling(ceiling); break; case tc_door: saveg_read_pad(); door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL); saveg_read_vldoor_t(door); door->sector->specialdata = door; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; P_AddThinker (&door->thinker); break; case tc_slidingdoor: // haleyjd 09/29/10: [STRIFE] New thinker type for sliding doors saveg_read_pad(); slidedoor = Z_Malloc(sizeof(*slidedoor), PU_LEVEL, NULL); saveg_read_slidedoor_t(slidedoor); slidedoor->frontsector->specialdata = slidedoor; slidedoor->thinker.function.acp1 = (actionf_p1)T_SlidingDoor; P_AddThinker(&slidedoor->thinker); break; case tc_floor: saveg_read_pad(); floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL); saveg_read_floormove_t(floor); floor->sector->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor; P_AddThinker (&floor->thinker); break; case tc_plat: saveg_read_pad(); plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL); saveg_read_plat_t(plat); plat->sector->specialdata = plat; if (plat->thinker.function.acp1) plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise; P_AddThinker (&plat->thinker); P_AddActivePlat(plat); break; case tc_flash: saveg_read_pad(); flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL); saveg_read_lightflash_t(flash); flash->thinker.function.acp1 = (actionf_p1)T_LightFlash; P_AddThinker (&flash->thinker); break; case tc_strobe: saveg_read_pad(); strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL); saveg_read_strobe_t(strobe); strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash; P_AddThinker (&strobe->thinker); break; case tc_glow: saveg_read_pad(); glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL); saveg_read_glow_t(glow); glow->thinker.function.acp1 = (actionf_p1)T_Glow; P_AddThinker (&glow->thinker); break; default: I_Error ("P_UnarchiveSpecials:Unknown tclass %i " "in savegame",tclass); } } } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_saveg.h000066400000000000000000000030551257432200600231700ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Savegame I/O, archiving, persistence. // #ifndef __P_SAVEG__ #define __P_SAVEG__ #include // maximum size of a savegame description #define SAVESTRINGSIZE 24 // temporary filename to use while saving. char *P_TempSaveGameFile(void); // filename to use for a savegame slot char *P_SaveGameFile(int slot); // Savegame file header read/write functions boolean P_ReadSaveGameHeader(void); void P_WriteSaveGameHeader(char *description); // Savegame end-of-file read/write functions boolean P_ReadSaveGameEOF(void); void P_WriteSaveGameEOF(void); // Persistent storage/archiving. // These are the load / save game routines. void P_ArchivePlayers (void); void P_UnArchivePlayers (boolean userload); void P_ArchiveWorld (void); void P_UnArchiveWorld (void); void P_ArchiveThinkers (void); void P_UnArchiveThinkers (void); void P_ArchiveSpecials (void); void P_UnArchiveSpecials (void); extern FILE *save_stream; extern boolean savegame_error; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/p_setup.c000066400000000000000000000464031257432200600232220ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Do all the WAD I/O, get map description, // set up initial state and misc. LUTs. // #include #include "z_zone.h" #include "deh_main.h" #include "i_swap.h" #include "m_argv.h" #include "m_bbox.h" #include "g_game.h" #include "i_system.h" #include "w_wad.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "doomstat.h" void P_SpawnMapThing (mapthing_t* mthing); // // MAP related Lookup tables. // Store VERTEXES, LINEDEFS, SIDEDEFS, etc. // int numvertexes; vertex_t* vertexes; int numsegs; seg_t* segs; int numsectors; sector_t* sectors; int numsubsectors; subsector_t* subsectors; int numnodes; node_t* nodes; int numlines; line_t* lines; int numsides; side_t* sides; static int totallines; // BLOCKMAP // Created from axis aligned bounding box // of the map, a rectangular array of // blocks of size ... // Used to speed up collision detection // by spatial subdivision in 2D. // // Blockmap size. int bmapwidth; int bmapheight; // size in mapblocks short* blockmap; // int for larger maps // offsets in blockmap are from here short* blockmaplump; // origin of block map fixed_t bmaporgx; fixed_t bmaporgy; // for thing chains mobj_t** blocklinks; // REJECT // For fast sight rejection. // Speeds up enemy AI by skipping detailed // LineOf Sight calculation. // Without special effect, this could be // used as a PVS lookup as well. // byte* rejectmatrix; // Maintain single and multi player starting spots. #define MAX_DEATHMATCH_STARTS 10 mapthing_t deathmatchstarts[MAX_DEATHMATCH_STARTS]; mapthing_t* deathmatch_p; mapthing_t playerstarts[MAXPLAYERS]; // haleyjd 08/24/10: [STRIFE] rift spots for player spawning mapthing_t riftSpots[MAXRIFTSPOTS]; // // P_LoadVertexes // void P_LoadVertexes (int lump) { byte* data; int i; mapvertex_t* ml; vertex_t* li; // Determine number of lumps: // total lump length / vertex record length. numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t); // Allocate zone memory for buffer. vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); // Load data into cache. data = W_CacheLumpNum (lump, PU_STATIC); ml = (mapvertex_t *)data; li = vertexes; // Copy and convert vertex coordinates, // internal representation as fixed. for (i=0 ; ix = SHORT(ml->x)<y = SHORT(ml->y)<v1 = &vertexes[SHORT(ml->v1)]; li->v2 = &vertexes[SHORT(ml->v2)]; li->angle = (SHORT(ml->angle))<<16; li->offset = (SHORT(ml->offset))<<16; linedef = SHORT(ml->linedef); ldef = &lines[linedef]; li->linedef = ldef; side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; if (ldef-> flags & ML_TWOSIDED) { sidenum = ldef->sidenum[side ^ 1]; // If the sidenum is out of range, this may be a "glass hack" // impassible window. Point at side #0 (this may not be // the correct Vanilla behavior; however, it seems to work for // OTTAWAU.WAD, which is the one place I've seen this trick // used). if (sidenum < 0 || sidenum >= numsides) { sidenum = 0; } li->backsector = sides[sidenum].sector; } else { li->backsector = 0; } } W_ReleaseLumpNum(lump); } // // P_LoadSubsectors // void P_LoadSubsectors (int lump) { byte* data; int i; mapsubsector_t* ms; subsector_t* ss; numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t); subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0); data = W_CacheLumpNum (lump,PU_STATIC); ms = (mapsubsector_t *)data; memset (subsectors,0, numsubsectors*sizeof(subsector_t)); ss = subsectors; for (i=0 ; inumlines = SHORT(ms->numsegs); ss->firstline = SHORT(ms->firstseg); } W_ReleaseLumpNum(lump); } // // P_LoadSectors // void P_LoadSectors (int lump) { byte* data; int i; mapsector_t* ms; sector_t* ss; numsectors = W_LumpLength (lump) / sizeof(mapsector_t); sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0); memset (sectors, 0, numsectors*sizeof(sector_t)); data = W_CacheLumpNum (lump,PU_STATIC); ms = (mapsector_t *)data; ss = sectors; for (i=0 ; ifloorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = R_FlatNumForName(ms->floorpic); ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); ss->lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); ss->tag = SHORT(ms->tag); ss->thinglist = NULL; } W_ReleaseLumpNum(lump); } // // P_LoadNodes // void P_LoadNodes (int lump) { byte* data; int i; int j; int k; mapnode_t* mn; node_t* no; numnodes = W_LumpLength (lump) / sizeof(mapnode_t); nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0); data = W_CacheLumpNum (lump,PU_STATIC); mn = (mapnode_t *)data; no = nodes; for (i=0 ; ix = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); for (k=0 ; k<4 ; k++) no->bbox[j][k] = SHORT(mn->bbox[j][k])<type)) { case 68: // Arachnotron case 64: // Archvile case 88: // Boss Brain case 89: // Boss Shooter case 69: // Hell Knight case 67: // Mancubus case 71: // Pain Elemental case 65: // Former Human Commando case 66: // Revenant case 84: // Wolf SS spawn = false; break; } } if (spawn == false) break; */ // Do spawn all other stuff. spawnthing.x = SHORT(mt->x); spawnthing.y = SHORT(mt->y); spawnthing.angle = SHORT(mt->angle); spawnthing.type = SHORT(mt->type); spawnthing.options = SHORT(mt->options); // haleyjd 08/24/2010: Special Strife checks if(spawnthing.type >= 118 && spawnthing.type < 128) { // initialize riftSpots int riftSpotNum = spawnthing.type - 118; riftSpots[riftSpotNum] = spawnthing; riftSpots[riftSpotNum].type = 1; } else if(spawnthing.type >= 9001 && spawnthing.type < 9011) { // STRIFE-TODO: mystery array of 90xx objects } else P_SpawnMapThing(&spawnthing); } W_ReleaseLumpNum(lump); } // // P_LoadLineDefs // Also counts secret lines for intermissions. // void P_LoadLineDefs (int lump) { byte* data; int i; maplinedef_t* mld; line_t* ld; vertex_t* v1; vertex_t* v2; numlines = W_LumpLength (lump) / sizeof(maplinedef_t); lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0); memset (lines, 0, numlines*sizeof(line_t)); data = W_CacheLumpNum (lump,PU_STATIC); mld = (maplinedef_t *)data; ld = lines; for (i=0 ; iflags = SHORT(mld->flags); ld->special = SHORT(mld->special); ld->tag = SHORT(mld->tag); v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) ld->slopetype = ST_HORIZONTAL; else { if (FixedDiv (ld->dy , ld->dx) > 0) ld->slopetype = ST_POSITIVE; else ld->slopetype = ST_NEGATIVE; } if (v1->x < v2->x) { ld->bbox[BOXLEFT] = v1->x; ld->bbox[BOXRIGHT] = v2->x; } else { ld->bbox[BOXLEFT] = v2->x; ld->bbox[BOXRIGHT] = v1->x; } if (v1->y < v2->y) { ld->bbox[BOXBOTTOM] = v1->y; ld->bbox[BOXTOP] = v2->y; } else { ld->bbox[BOXBOTTOM] = v2->y; ld->bbox[BOXTOP] = v1->y; } ld->sidenum[0] = SHORT(mld->sidenum[0]); ld->sidenum[1] = SHORT(mld->sidenum[1]); if (ld->sidenum[0] != -1) ld->frontsector = sides[ld->sidenum[0]].sector; else ld->frontsector = 0; if (ld->sidenum[1] != -1) ld->backsector = sides[ld->sidenum[1]].sector; else ld->backsector = 0; } W_ReleaseLumpNum(lump); } // // P_LoadSideDefs // void P_LoadSideDefs (int lump) { byte* data; int i; mapsidedef_t* msd; side_t* sd; numsides = W_LumpLength (lump) / sizeof(mapsidedef_t); sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0); memset (sides, 0, numsides*sizeof(side_t)); data = W_CacheLumpNum (lump,PU_STATIC); msd = (mapsidedef_t *)data; sd = sides; for (i=0 ; itextureoffset = SHORT(msd->textureoffset)<rowoffset = SHORT(msd->rowoffset)<toptexture = R_TextureNumForName(msd->toptexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->sector = §ors[SHORT(msd->sector)]; } W_ReleaseLumpNum(lump); } // // P_LoadBlockMap // void P_LoadBlockMap (int lump) { int i; int count; int lumplen; lumplen = W_LumpLength(lump); count = lumplen / 2; blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL); W_ReadLump(lump, blockmaplump); blockmap = blockmaplump + 4; // Swap all short integers to native byte ordering. for (i=0; ifirstline]; ss->sector = seg->sidedef->sector; } // count number of lines in each sector li = lines; totallines = 0; for (i=0 ; ifrontsector->linecount++; if (li->backsector && li->backsector != li->frontsector) { li->backsector->linecount++; totallines++; } } // build line tables for each sector linebuffer = Z_Malloc (totallines*sizeof(line_t *), PU_LEVEL, 0); for (i=0; ifrontsector != NULL) { sector = li->frontsector; sector->lines[sector->linecount] = li; ++sector->linecount; } if (li->backsector != NULL && li->frontsector != li->backsector) { sector = li->backsector; sector->lines[sector->linecount] = li; ++sector->linecount; } } // Generate bounding boxes for sectors sector = sectors; for (i=0 ; ilinecount; j++) { li = sector->lines[j]; M_AddToBox (bbox, li->v1->x, li->v1->y); M_AddToBox (bbox, li->v2->x, li->v2->y); } // set the degenmobj_t to the middle of the bounding box sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; // adjust bounding box to map blocks block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; block = block >= bmapheight ? bmapheight-1 : block; sector->blockbox[BOXTOP]=block; block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXBOTTOM]=block; block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; block = block >= bmapwidth ? bmapwidth-1 : block; sector->blockbox[BOXRIGHT]=block; block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXLEFT]=block; } } // Pad the REJECT lump with extra data when the lump is too small, // to simulate a REJECT buffer overflow in Vanilla Doom. static void PadRejectArray(byte *array, unsigned int len) { unsigned int i; unsigned int byte_num; byte *dest; unsigned int padvalue; // Values to pad the REJECT array with: unsigned int rejectpad[4] = { ((totallines * 4 + 3) & ~3) + 24, // Size 0, // Part of z_zone block header 50, // PU_LEVEL 0x1d4a11 // DOOM_CONST_ZONEID }; // Copy values from rejectpad into the destination array. dest = array; for (i=0; i> (byte_num * 8)) & 0xff; ++dest; } // We only have a limited pad size. Print a warning if the // REJECT lump is too small. if (len > sizeof(rejectpad)) { fprintf(stderr, "PadRejectArray: REJECT lump too short to pad! (%i > %i)\n", len, (int) sizeof(rejectpad)); // Pad remaining space with 0 (or 0xff, if specified on command line). if (M_CheckParm("-reject_pad_with_ff")) { padvalue = 0xff; } else { padvalue = 0xf00; } memset(array + sizeof(rejectpad), padvalue, len - sizeof(rejectpad)); } } static void P_LoadReject(int lumpnum) { int minlength; int lumplen; // Calculate the size that the REJECT lump *should* be. minlength = (numsectors * numsectors + 7) / 8; // If the lump meets the minimum length, it can be loaded directly. // Otherwise, we need to allocate a buffer of the correct size // and pad it with appropriate data. lumplen = W_LumpLength(lumpnum); if (lumplen >= minlength) { rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL); } else { rejectmatrix = Z_Malloc(minlength, PU_LEVEL, &rejectmatrix); W_ReadLump(lumpnum, rejectmatrix); PadRejectArray(rejectmatrix + lumplen, minlength - lumplen); } } // // P_SetupLevel // void P_SetupLevel ( int map, int playermask, skill_t skill) { int i; char lumpname[9]; int lumpnum; // haleyjd 20110205 [STRIFE]: removed totalitems and wminfo totalkills = totalsecret = 0; for (i=0 ; idx) { if (x==node->x) return 2; if (x <= node->x) return node->dy > 0; return node->dy < 0; } if (!node->dy) { if (x==node->y) return 2; if (y <= node->y) return node->dx < 0; return node->dx > 0; } dx = (x - node->x); dy = (y - node->y); left = (node->dy>>FRACBITS) * (dx>>FRACBITS); right = (dy>>FRACBITS) * (node->dx>>FRACBITS); if (right < left) return 0; // front side if (left == right) return 2; return 1; // back side } // // P_InterceptVector2 // Returns the fractional intercept point // along the first divline. // This is only called by the addthings and addlines traversers. // // [STRIFE] Verified unmodified // fixed_t P_InterceptVector2 ( divline_t* v2, divline_t* v1 ) { fixed_t frac; fixed_t num; fixed_t den; den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy); if (den == 0) return 0; // I_Error ("P_InterceptVector: parallel"); num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) + FixedMul ( (v2->y - v1->y)>>8 , v1->dx); frac = FixedDiv (num , den); return frac; } // // P_CrossSubsector // Returns true // if strace crosses the given subsector successfully. // // [STRIFE] Verified unmodified // boolean P_CrossSubsector (int num) { seg_t* seg; line_t* line; int s1; int s2; int count; subsector_t* sub; sector_t* front; sector_t* back; fixed_t opentop; fixed_t openbottom; divline_t divl; vertex_t* v1; vertex_t* v2; fixed_t frac; fixed_t slope; #ifdef RANGECHECK if (num>=numsubsectors) I_Error ("P_CrossSubsector: ss %i with numss = %i", num, numsubsectors); #endif sub = &subsectors[num]; // check lines count = sub->numlines; seg = &segs[sub->firstline]; for ( ; count ; seg++, count--) { line = seg->linedef; // allready checked other side? if (line->validcount == validcount) continue; line->validcount = validcount; v1 = line->v1; v2 = line->v2; s1 = P_DivlineSide (v1->x, v1->y, &strace); s2 = P_DivlineSide (v2->x, v2->y, &strace); // line isn't crossed? if (s1 == s2) continue; divl.x = v1->x; divl.y = v1->y; divl.dx = v2->x - v1->x; divl.dy = v2->y - v1->y; s1 = P_DivlineSide (strace.x, strace.y, &divl); s2 = P_DivlineSide (t2x, t2y, &divl); // line isn't crossed? if (s1 == s2) continue; // Backsector may be NULL if this is an "impassible // glass" hack line. if (line->backsector == NULL) { return false; } // stop because it is not two sided anyway // might do this after updating validcount? if ( !(line->flags & ML_TWOSIDED) ) return false; // crosses a two sided line front = seg->frontsector; back = seg->backsector; // no wall to block sight with? if (front->floorheight == back->floorheight && front->ceilingheight == back->ceilingheight) continue; // possible occluder // because of ceiling height differences if (front->ceilingheight < back->ceilingheight) opentop = front->ceilingheight; else opentop = back->ceilingheight; // because of ceiling height differences if (front->floorheight > back->floorheight) openbottom = front->floorheight; else openbottom = back->floorheight; // quick test for totally closed doors if (openbottom >= opentop) return false; // stop frac = P_InterceptVector2 (&strace, &divl); if (front->floorheight != back->floorheight) { slope = FixedDiv (openbottom - sightzstart , frac); if (slope > bottomslope) bottomslope = slope; } if (front->ceilingheight != back->ceilingheight) { slope = FixedDiv (opentop - sightzstart , frac); if (slope < topslope) topslope = slope; } if (topslope <= bottomslope) return false; // stop } // passed the subsector ok return true; } // // P_CrossBSPNode // Returns true // if strace crosses the given node successfully. // // [STRIFE] Verified unmodified // boolean P_CrossBSPNode (int bspnum) { node_t* bsp; int side; if (bspnum & NF_SUBSECTOR) { if (bspnum == -1) return P_CrossSubsector (0); else return P_CrossSubsector (bspnum&(~NF_SUBSECTOR)); } bsp = &nodes[bspnum]; // decide which side the start point is on side = P_DivlineSide (strace.x, strace.y, (divline_t *)bsp); if (side == 2) side = 0; // an "on" should cross both sides // cross the starting side if (!P_CrossBSPNode (bsp->children[side]) ) return false; // the partition plane is crossed here if (side == P_DivlineSide (t2x, t2y,(divline_t *)bsp)) { // the line doesn't touch the other side return true; } // cross the ending side return P_CrossBSPNode (bsp->children[side^1]); } // // P_CheckSight // Returns true // if a straight line between t1 and t2 is unobstructed. // Uses REJECT. // // [STRIFE] Verified unmodified // boolean P_CheckSight ( mobj_t* t1, mobj_t* t2 ) { int s1; int s2; int pnum; int bytenum; int bitnum; // First check for trivial rejection. // Determine subsector entries in REJECT table. s1 = (t1->subsector->sector - sectors); s2 = (t2->subsector->sector - sectors); pnum = s1*numsectors + s2; bytenum = pnum>>3; bitnum = 1 << (pnum&7); // Check in REJECT table. if (rejectmatrix[bytenum]&bitnum) { sightcounts[0]++; // can't possibly be connected return false; } // An unobstructed LOS is possible. // Now look from eyes of t1 to any part of t2. sightcounts[1]++; validcount++; sightzstart = t1->z + t1->height - (t1->height>>2); topslope = (t2->z+t2->height) - sightzstart; bottomslope = (t2->z) - sightzstart; strace.x = t1->x; strace.y = t1->y; t2x = t2->x; t2y = t2->y; strace.dx = t2->x - t1->x; strace.dy = t2->y - t1->y; // the head node is the last node output return P_CrossBSPNode (numnodes-1); } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_spec.c000066400000000000000000001441341257432200600230140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Implements special effects: // Texture animation, height or lighting changes // according to adjacent sectors, respective // utility functions, etc. // Line Tag handling. Line and Sector triggers. // #include #include "doomdef.h" #include "doomstat.h" #include "deh_main.h" #include "i_system.h" #include "z_zone.h" #include "m_argv.h" #include "m_misc.h" #include "m_random.h" #include "w_wad.h" #include "r_local.h" #include "p_local.h" #include "g_game.h" #include "s_sound.h" // State. #include "r_state.h" // Data. #include "sounds.h" // [STRIFE] #include "hu_stuff.h" #include "p_dialog.h" // // Animating textures and planes // There is another anim_t used in wi_stuff, unrelated. // typedef struct { boolean istexture; int picnum; int basepic; int numpics; int speed; } anim_t; // // source animation definition // typedef struct { int istexture; // if false, it is a flat char endname[9]; char startname[9]; int speed; } animdef_t; // haleyjd 08/30/10: [STRIFE] MAXANIMS raised from 32 to 40 #define MAXANIMS 40 // // P_InitPicAnims // // Floor/ceiling animation sequences, // defined by first and last frame, // i.e. the flat (64x64 tile) name to // be used. // The full animation sequence is given // using all the flats between the start // and end entry, in the order found in // the WAD file. // // haleyjd 08/29/10: [STRIFE] Changed animdefs. // animdef_t animdefs[] = { { false, "F_SCANR8", "F_SCANR5", 4}, { false, "F_WATR03", "F_WATR01", 8}, { false, "F_PWATR3", "F_PWATR1", 11}, { false, "F_SCANR4", "F_SCANR1", 4}, { true, "SCAN08", "SCAN05", 4}, { true, "SWTRMG03", "SWTRMG01", 4}, { true, "SCAN04", "SCAN01", 4}, { true, "COMP04", "COMP01", 4}, { true, "COMP08", "COMP05", 6}, { true, "COMP12", "COMP09", 11}, { true, "COMP16", "COMP13", 12}, { true, "COMP20", "COMP17", 12}, { true, "COMP24", "COMP21", 12}, { true, "COMP28", "COMP25", 12}, { true, "COMP32", "COMP29", 12}, { true, "COMP37", "COMP33", 12}, { true, "COMP41", "COMP38", 12}, { true, "COMP49", "COMP42", 10}, { true, "BRKGRY16", "BRKGRY13", 10}, { true, "BRNSCN04", "BRNSCN01", 10}, { true, "CONCRT12", "CONCRT09", 11}, { true, "CONCRT25", "CONCRT22", 11}, { true, "WALPMP02", "WALPMP01", 16}, { true, "WALTEK17", "WALTEK16", 8}, { true, "FORCE04", "FORCE01", 4}, { true, "FORCE08", "FORCE05", 4}, { true, "FAN02", "FAN01", 4}, { false, "F_VWATR3", "P_VWATR1", 4}, { false, "F_HWATR3", "F_HWATR1", 4}, { false, "F_TELE2", "F_TELE1", 4}, { false, "F_FAN2", "F_FAN1", 4}, { false, "F_CONVY2", "F_CONVY1", 4}, { false, "F_RDALN4", "F_RDALN1", 4}, { -1, "", "", 0}, }; anim_t anims[MAXANIMS]; anim_t* lastanim; // // Animating line specials // // haleyjd 08/29/10: [STRIFE] MAXLINEANIMS raised from 64 to 96 #define MAXLINEANIMS 96 extern short numlinespecials; extern line_t* linespeciallist[MAXLINEANIMS]; void P_InitPicAnims (void) { int i; // Init animation lastanim = anims; for (i=0 ; animdefs[i].istexture != -1 ; i++) { char *startname, *endname; startname = DEH_String(animdefs[i].startname); endname = DEH_String(animdefs[i].endname); if (animdefs[i].istexture) { // different episode ? if (R_CheckTextureNumForName(startname) == -1) continue; lastanim->picnum = R_TextureNumForName(endname); lastanim->basepic = R_TextureNumForName(startname); } else { if (W_CheckNumForName(startname) == -1) continue; lastanim->picnum = R_FlatNumForName(endname); lastanim->basepic = R_FlatNumForName(startname); } lastanim->istexture = animdefs[i].istexture; lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; if (lastanim->numpics < 2) I_Error ("P_InitPicAnims: bad cycle from %s to %s", startname, endname); lastanim->speed = animdefs[i].speed; lastanim++; } } // villsa [STRIFE] terrain type definitions typedef struct { char* flat; int type; int num; } terraintype_t; terraintype_t terraintypes[] = { { "F_WATR03", FLOOR_WATER, -1 }, { "F_WATR02", FLOOR_WATER, -1 }, { "F_WATR01", FLOOR_WATER, -1 }, { "F_VWATR3", FLOOR_WATER, -1 }, { "F_VWATR2", FLOOR_WATER, -1 }, { "P_VWATR1", FLOOR_WATER, -1 }, { "F_HWATR3", FLOOR_WATER, -1 }, { "F_HWATR2", FLOOR_WATER, -1 }, { "F_HWATR1", FLOOR_WATER, -1 }, { "F_PWATR3", FLOOR_SLIME, -1 }, { "F_PWATR2", FLOOR_SLIME, -1 }, { "F_PWATR1", FLOOR_SLIME, -1 }, { "END", FLOOR_END, -1 }, }; // // P_GetTerrainType // villsa [STRIFE] new function // terraintype_e P_GetTerrainType(mobj_t* mobj) { int i = 0; subsector_t* ss = mobj->subsector; if(mobj->z <= ss->sector->floorheight && terraintypes[0].type != FLOOR_END) { while(ss->sector->floorpic != terraintypes[i].num) { if(terraintypes[i+1].type == FLOOR_END) return FLOOR_SOLID; i++; } return terraintypes[i].type; } return FLOOR_SOLID; } // // P_InitTerrainTypes // villsa [STRIFE] new function // Initialize terrain types // void P_InitTerrainTypes(void) { int i = 0; if(terraintypes[0].type != FLOOR_END) { while(terraintypes[i].type != FLOOR_END) { terraintypes[i].num = R_FlatNumForName(terraintypes[i].flat); i++; } } } // // UTILITIES // // // getSide() // Will return a side_t* // given the number of the current sector, // the line number, and the side (0/1) that you want. // side_t* getSide ( int currentSector, int line, int side ) { return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; } // // getSector() // Will return a sector_t* // given the number of the current sector, // the line number and the side (0/1) that you want. // sector_t* getSector ( int currentSector, int line, int side ) { return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; } // // twoSided() // Given the sector number and the line number, // it will tell you whether the line is two-sided or not. // int twoSided ( int sector, int line ) { return (sectors[sector].lines[line])->flags & ML_TWOSIDED; } // // getNextSector() // Return sector_t * of sector next to current. // NULL if not two-sided line // sector_t* getNextSector ( line_t* line, sector_t* sec ) { if (!(line->flags & ML_TWOSIDED)) return NULL; if (line->frontsector == sec) return line->backsector; return line->frontsector; } // // P_FindLowestFloorSurrounding() // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS // fixed_t P_FindLowestFloorSurrounding(sector_t* sec) { int i; line_t* check; sector_t* other; fixed_t floor = sec->floorheight; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->floorheight < floor) floor = other->floorheight; } return floor; } // // P_FindHighestFloorSurrounding() // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS // fixed_t P_FindHighestFloorSurrounding(sector_t *sec) { int i; line_t* check; sector_t* other; fixed_t floor = -500*FRACUNIT; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->floorheight > floor) floor = other->floorheight; } return floor; } // // P_FindNextHighestFloor // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS // Note: this should be doable w/o a fixed array. // Thanks to entryway for the Vanilla overflow emulation. // 20 adjoining sectors max! #define MAX_ADJOINING_SECTORS 20 fixed_t P_FindNextHighestFloor ( sector_t* sec, int currentheight ) { int i; int h; int min; line_t* check; sector_t* other; fixed_t height = currentheight; fixed_t heightlist[MAX_ADJOINING_SECTORS + 2]; for (i=0, h=0; i < sec->linecount; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->floorheight > height) { // Emulation of memory (stack) overflow if (h == MAX_ADJOINING_SECTORS + 1) { height = other->floorheight; } else if (h == MAX_ADJOINING_SECTORS + 2) { // Fatal overflow: game crashes at 22 textures I_Error("Sector with more than 22 adjoining sectors. " "Vanilla will crash here"); } heightlist[h++] = other->floorheight; } } // Find lowest height in list if (!h) { return currentheight; } min = heightlist[0]; // Range checking? for (i = 1; i < h; i++) { if (heightlist[i] < min) { min = heightlist[i]; } } return min; } // // FIND LOWEST CEILING IN THE SURROUNDING SECTORS // fixed_t P_FindLowestCeilingSurrounding(sector_t* sec) { int i; line_t* check; sector_t* other; fixed_t height = INT_MAX; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->ceilingheight < height) height = other->ceilingheight; } return height; } // // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS // fixed_t P_FindHighestCeilingSurrounding(sector_t* sec) { int i; line_t* check; sector_t* other; fixed_t height = 0; for (i=0 ;i < sec->linecount ; i++) { check = sec->lines[i]; other = getNextSector(check,sec); if (!other) continue; if (other->ceilingheight > height) height = other->ceilingheight; } return height; } // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO // int P_FindSectorFromLineTag ( line_t* line, int start ) { int i; for (i=start+1;itag) return i; return -1; } // // Find minimum light from an adjacent sector // int P_FindMinSurroundingLight ( sector_t* sector, int max ) { int i; int min; line_t* line; sector_t* check; min = max; for (i=0 ; i < sector->linecount ; i++) { line = sector->lines[i]; check = getNextSector(line,sector); if (!check) continue; if (check->lightlevel < min) min = check->lightlevel; } return min; } // // EVENTS // Events are operations triggered by using, crossing, // or shooting special lines, or by timed thinkers. // // [STRIFE] static char crosslinestr[90]; // // P_CrossSpecialLine - TRIGGER // Called every time a thing origin is about // to cross a line with a non 0 special. // void P_CrossSpecialLine ( int linenum, int side, mobj_t* thing ) { line_t* line; side_t* sidedef; // [STRIFE] int flag; // [STRIFE] int ok; line = &lines[linenum]; // haleyjd 09/21/10: corpses and missiles cannot activate any cross-over // line types, *except* 182 (which is for the sake of missiles). if((thing->flags & (MF_MISSILE|MF_CORPSE)) && line->special != 182) return; // Triggers that other things can activate if (!thing->player) { // Things that should NOT trigger specials... // villsa [STRIFE] unused // haleyjd: removed dead switch. Strife only excludes missiles and // corpses, which is handled above. ok = 0; // [STRIFE] Added several line types. Removed none. switch(line->special) { case 97: // TELEPORT RETRIGGER case 185: // haleyjd: [STRIFE] Silent Teleport (used for Converter) case 195: // haleyjd: [STRIFE] Silent Teleport and Change Zombie case 231: // haleyjd: [STRIFE] WR Teleport (Silent at Source) case 125: // TELEPORT MONSTERONLY TRIGGER case 126: // TELEPORT MONSTERONLY RETRIGGER case 182: // haleyjd: [STRIFE] Break glass - it's a W1 type too! case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER case 39: // TELEPORT TRIGGER case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER case 4: // RAISE DOOR ok = 1; break; } if (!ok) return; } // Note: could use some const's here. switch (line->special) { // // TRIGGERS. // All from here to RETRIGGERS. // case 230: // haleyjd 09/21/10: [STRIFE] W1 Open Door if Quest sidedef = &sides[line->sidenum[0]]; flag = (sidedef->rowoffset >> FRACBITS) - 1; if(!(thing->player->questflags & (1 << flag))) break; // fall-through: case 2: // Open Door - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_open); line->special = 0; break; case 227: // haleyjd 09/21/10: [STRIFE] W1 Close Door if Quest sidedef = &sides[line->sidenum[0]]; flag = (sidedef->rowoffset >> FRACBITS) - 1; if(!(thing->player->questflags & (1 << flag))) break; // fall-through: case 3: // Close Door - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_close); line->special = 0; break; case 4: // Raise Door - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_normal); line->special = 0; break; case 5: // Raise Floor - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloor); line->special = 0; break; case 6: // Fast Ceiling Crush & Raise - [STRIFE] Verified unmodified. EV_DoCeiling(line,fastCrushAndRaise); line->special = 0; break; case 8: // Build Stairs - [STRIFE] Verified unmodified. EV_BuildStairs(line,build8); line->special = 0; break; case 10: // PlatDownWaitUp - [STRIFE] Verified unmodified. EV_DoPlat(line,downWaitUpStay,0); line->special = 0; break; case 12: // Light Turn On - brightest near - [STRIFE] Verified unmodified. EV_LightTurnOn(line,0); line->special = 0; break; case 13: // Light Turn On 255 - [STRIFE] Verified unmodified. EV_LightTurnOn(line,255); line->special = 0; break; case 16: // Close Door 30 - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_close30ThenOpen); line->special = 0; break; case 17: // Start Light Strobing - [STRIFE] Verified unmodified. EV_StartLightStrobing(line); line->special = 0; break; case 19: // Lower Floor - [STRIFE] Verified unmodified. EV_DoFloor(line,lowerFloor); line->special = 0; break; case 22: // villsa [STRIFE] Verified unmodified. // Raise floor to nearest height and change texture EV_DoPlat(line,raiseToNearestAndChange,0); line->special = 0; break; case 25: // Ceiling Crush and Raise - [STRIFE] Verified unmodified. EV_DoCeiling(line,crushAndRaise); line->special = 0; break; case 30: // Raise floor to shortest texture height - [STRIFE] Verified unmodified. // on either side of lines. EV_DoFloor(line,raiseToTexture); line->special = 0; break; case 35: // Lights Very Dark - [STRIFE] Verified unmodified. EV_LightTurnOn(line,35); line->special = 0; break; case 36: // Lower Floor (TURBO) - [STRIFE] Verified unmodified. EV_DoFloor(line,turboLower); line->special = 0; break; case 37: // LowerAndChange - [STRIFE] Verified unmodified. EV_DoFloor(line,lowerAndChange); line->special = 0; break; case 193: // haleyjd 09/21/10: [STRIFE] W1 Floor Lower to Lowest if Quest sidedef = &sides[line->sidenum[0]]; flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t // must have the questflag indicated in the line's y offset if(!(thing->player->questflags & (1 << flag))) break; // fall-through: case 38: // Lower Floor To Lowest - [STRIFE] Verified unmodified. EV_DoFloor( line, lowerFloorToLowest ); line->special = 0; break; case 39: // TELEPORT! - [STRIFE] Verified unmodified (except for 0 flags param) EV_Teleport( line, side, thing, TF_NORMAL ); line->special = 0; break; /*case 40: // RaiseCeilingLowerFloor EV_DoCeiling( line, raiseToHighest ); EV_DoFloor( line, lowerFloorToLowest ); line->special = 0; break;*/ case 44: // Ceiling Crush - [STRIFE] Verified unmodified. EV_DoCeiling( line, lowerAndCrush ); line->special = 0; break; case 52: // EXIT! - haleyjd 09/21/10: [STRIFE] Exit to level tag/100 G_ExitLevel (line->tag / 100); break; case 53: // Perpetual Platform Raise - [STRIFE] Verified unmodified. EV_DoPlat(line,perpetualRaise,0); line->special = 0; break; case 54: // Platform Stop - [STRIFE] Verified unmodified. EV_StopPlat(line); line->special = 0; break; case 56: // Raise Floor Crush - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloorCrush); line->special = 0; break; case 57: // Ceiling Crush Stop - [STRIFE] Verified unmodified. EV_CeilingCrushStop(line); line->special = 0; break; case 58: // [STRIFE] raiseFloor24 was modified into raiseFloor64 // Raise Floor 64 EV_DoFloor(line,raiseFloor64); line->special = 0; break; case 59: // Raise Floor 24 And Change - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloor24AndChange); line->special = 0; break; case 104: // Turn lights off in sector(tag) - [STRIFE] Verified unmodified. EV_TurnTagLightsOff(line); line->special = 0; break; case 108: // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified. EV_DoDoor (line,vld_blazeRaise); line->special = 0; break; case 109: // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified. EV_DoDoor (line,vld_blazeOpen); line->special = 0; break; case 100: // Build Stairs Turbo 16 - [STRIFE] Verified unmodified. EV_BuildStairs(line,turbo16); line->special = 0; break; case 197: // haleyjd 09/21/10: [STRIFE] Blazing Door Close if Has Sigil B if(thing->player->sigiltype <= 0) break; // fall-through: case 110: // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified. EV_DoDoor (line,vld_blazeClose); line->special = 0; break; case 119: // Raise floor to nearest surr. floor - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloorToNearest); line->special = 0; break; case 121: // villsa [STRIFE] Verified unmodified. // Blazing PlatDownWaitUpStay EV_DoPlat(line,blazeDWUS,0); line->special = 0; break; case 124: // haleyjd 09/21/10: [STRIFE] W1 Start Finale // Altered from G_SecretExitLevel. G_StartFinale(); break; case 125: // TELEPORT MonsterONLY - [STRIFE] Verified unmodified // (except for 0 flags parameter) if (!thing->player) { EV_Teleport( line, side, thing, TF_NORMAL ); line->special = 0; } break; case 130: // Raise Floor Turbo - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloorTurbo); line->special = 0; break; case 141: // Silent Ceiling Crush & Raise - [STRIFE] Verified unmodified. EV_DoCeiling(line,silentCrushAndRaise); line->special = 0; break; case 174: // villsa [STRIFE] Split Open EV_DoDoor(line, vld_splitOpen); line->special = 0; break; case 183: // villsa [STRIFE] Split Raise Nearest EV_DoDoor(line, vld_splitRaiseNearest); line->special = 0; break; case 178: // haleyjd 09/24/10: [STRIFE] W1 Build Stairs Down 16 EV_BuildStairs(line, buildDown16); line->special = 0; break; case 179: // haleyjd 09/25/10: [STRIFE] W1 Ceiling Lower to Floor EV_DoCeiling(line, lowerToFloor); line->special = 0; break; case 182: // haleyjd 09/21/10: [STRIFE] Break Glass // 182 is a unique linetype in that it is both a G1 and a W1 linetype, // but only missiles may activate it as a W1 type. if(thing->flags & MF_MISSILE) P_ChangeSwitchTexture(line, 1); // why 1? it will be cleared anyway. break; case 187: // haleyjd 09/21/10: [STRIFE] W1 Clear Force Fields if Quest sidedef = &sides[line->sidenum[0]]; flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t // must have the questflag indicated in the line's y offset if(!(thing->player->questflags & (1 << flag))) break; // Do it! EV_ClearForceFields(line); line->special = 0; break; case 188: // haleyjd 09/21/10: [STRIFE] W1 Open Door if Quest 16 (Gate Mechanism // Destroyed) if(!(thing->player->questflags & QF_QUEST16)) break; EV_DoDoor(line, vld_open); line->special = 0; break; case 196: // haleyjd 09/26/10: [STRIFE] W1 Floor Lower to Lowest if Sigil Type > 0 if(thing->player->sigiltype > 0) { EV_DoFloor(line, lowerFloorToLowest); line->special = 0; } break; case 200: // haleyjd 09/21/10: [STRIFE] W1 Open Door if Sigil Owned if(!(thing->player->weaponowned[wp_sigil])) break; EV_DoDoor(line, vld_open); line->special = 0; break; case 201: // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective (First Side Only) if(side == 1) break; // fall-through: case 202: // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective (Tag = VOC/LOG #) // must be consoleplayer if(thing->player != &players[consoleplayer]) break; // must have comm unit if(!(thing->player->powers[pw_communicator])) break; // load voice DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag); I_StartVoice(crosslinestr); // load objective DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag); GiveObjective(crosslinestr, 0); // Put up a message thing->player->message = DEH_String("Incoming Message..."); line->special = 0; break; case 210: // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective if Flamethrower???? // I don't think this is actually used anywhere o_O // must be player 1... if(thing->player != &players[0]) break; // must have comm unit if(!(thing->player->powers[pw_communicator])) break; // must have... the flamethrower?! if(!(thing->player->weaponowned[wp_flame])) break; // load voice DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag); I_StartVoice(crosslinestr); // load objective DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag); GiveObjective(crosslinestr, 0); // Put up a message thing->player->message = DEH_String("Incoming Message from BlackBird..."); line->special = 0; break; case 212: // haleyjd 09/25/10: [STRIFE] W1 Floor Lower to Lowest if Have Flamethrower if(thing->player->weaponowned[wp_flame]) { EV_DoFloor(line, lowerFloorToLowest); line->special = 0; } break; case 215: // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective if Quest (Tag/100, Tag%100) // must be player 1... if(thing->player != &players[0]) break; // must have comm unit if(!(thing->player->powers[pw_communicator])) break; if(line->tag != 0) { // test for questflag if(!(thing->player->questflags & (1 << (line->tag % 100 - 1)))) break; } // start voice DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag/100); I_StartVoice(crosslinestr); // give objective DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag/100); GiveObjective(crosslinestr, 0); // Put up a message thing->player->message = DEH_String("Incoming Message from BlackBird..."); line->special = 0; break; case 204: // haleyjd 09/21/10: [STRIFE] W1 Change Music (unused!) if(thing->player != &players[0]) break; S_ChangeMusic(line->tag, 1); line->special = 0; break; case 228: // haleyjd 09/21/10: [STRIFE] W1 Entity Voice? if(!(thing->player->questflags & QF_QUEST24)) // Not killed Macil??? break; // STRIFE-TODO: verify... if(!(thing->player->questflags & QF_QUEST28)) // ????? STRIFE-TODO I_StartVoice(DEH_String("voc128")); else I_StartVoice(DEH_String("voc130")); line->special = 0; break; // // RETRIGGERS. All from here till end. // case 72: // Ceiling Crush - [STRIFE] Verified unmodified. EV_DoCeiling( line, lowerAndCrush ); break; case 73: // Ceiling Crush and Raise - [STRIFE] Verified unmodified. EV_DoCeiling(line,crushAndRaise); break; case 74: // Ceiling Crush Stop - [STRIFE] Verified unmodified. EV_CeilingCrushStop(line); break; case 75: // Close Door - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_close); break; case 76: // Close Door 30 - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_close30ThenOpen); break; case 77: // Fast Ceiling Crush & Raise - [STRIFE] Verified unmodified. EV_DoCeiling(line,fastCrushAndRaise); break; case 79: // Lights Very Dark - [STRIFE] Verified unmodified. EV_LightTurnOn(line,35); break; case 80: // Light Turn On - brightest near - [STRIFE] Verified unmodified. EV_LightTurnOn(line,0); break; case 81: // Light Turn On 255 - [STRIFE] Verified unmodified. EV_LightTurnOn(line,255); break; case 82: // Lower Floor To Lowest - [STRIFE] Verified unmodified. EV_DoFloor( line, lowerFloorToLowest ); break; case 83: // Lower Floor - [STRIFE] Verified unmodified. EV_DoFloor(line,lowerFloor); break; case 84: // LowerAndChange - [STRIFE] Verified unmodified. EV_DoFloor(line,lowerAndChange); break; case 86: // Open Door - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_open); break; case 87: // Perpetual Platform Raise - [STRIFE] Verified unmodified. EV_DoPlat(line,perpetualRaise,0); break; case 88: // PlatDownWaitUp - [STRIFE] Verified unmodified. EV_DoPlat(line,downWaitUpStay,0); break; case 89: // Platform Stop - [STRIFE] Verified unmodified. EV_StopPlat(line); break; case 216: // haleyjd 09/21/10: [STRIFE] WR Raise Door if Quest sidedef = &sides[line->sidenum[0]]; flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t. if(!(thing->player->questflags & (1 << flag))) break; // fall-through: case 90: // Raise Door - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_normal); break; case 91: // Raise Floor - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloor); break; case 92: // [STRIFE] raiseFloor24 changed to raiseFloor64 // Raise Floor 64 EV_DoFloor(line,raiseFloor64); break; case 93: // Raise Floor 24 And Change - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloor24AndChange); break; case 94: // Raise Floor Crush - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloorCrush); break; case 95: // villsa [STRIFE] Verified unmodified. // Raise floor to nearest height // and change texture. EV_DoPlat(line,raiseToNearestAndChange,0); break; case 96: // Raise floor to shortest texture height - [STRIFE] Verified unmodified. // on either side of lines. EV_DoFloor(line,raiseToTexture); break; case 97: // TELEPORT! - [STRIFE] Verified unmodified (except for 0 flags param) EV_Teleport( line, side, thing, TF_NORMAL ); break; case 98: // Lower Floor (TURBO) - [STRIFE] Verified unmodified. EV_DoFloor(line,turboLower); break; case 105: // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified. EV_DoDoor (line,vld_blazeRaise); break; case 106: // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified. EV_DoDoor (line,vld_blazeOpen); break; case 107: // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified. EV_DoDoor (line,vld_blazeClose); break; case 120: // villsa [STRIFE] Verified unmodified. // Blazing PlatDownWaitUpStay. EV_DoPlat(line,blazeDWUS,0); break; case 126: // TELEPORT MonsterONLY. - [STRIFE] Verified unmodified (except for 0 flags param) if (!thing->player) EV_Teleport( line, side, thing, TF_NORMAL ); break; case 128: // Raise To Nearest Floor - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloorToNearest); break; case 129: // Raise Floor Turbo - [STRIFE] Verified unmodified. EV_DoFloor(line,raiseFloorTurbo); break; case 186: // haleyjd [STRIFE] Exit Level to Spot, First Side Only if(side == 1) break; // fall-through: case 145: // haleyjd [STRIFE] Exit Level to Spot thing->momx = thing->momy = thing->momz = 0; { int map = line->tag / 100; int spot = line->tag % 100; if(thing->player->weaponowned[wp_sigil]) { if(map == 3) map = 30; else if(map == 7) map = 10; } DEH_snprintf(crosslinestr, sizeof(crosslinestr), "Entering%s", DEH_String(mapnames[map - 1]) + 8); thing->player->message = crosslinestr; if(netgame && deathmatch) { if(levelTimer && levelTimeCount != 0) { DEH_snprintf(crosslinestr, sizeof(crosslinestr), "%d min left", (levelTimeCount/TICRATE)/60); break; } // raise switch from floor EV_DoFloor(line, raiseFloor64); } else { // normal single-player exit // BUG: Here is the opening for a flaming player to cross past // the exit line and hit a deathmatch switch ;) It's not so much // that this is incorrect, as that they forgot to add such a // check to the other kind of exit lines too ;) if(thing->player->health <= 0) break; G_RiftExitLevel(map, spot, thing->angle); } } break; case 175: // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if < 16 Above Floor if(thing->z < thing->floorz + 16 * FRACUNIT) P_NoiseAlert(thing->player->mo, thing->player->mo); break; case 198: // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if No Guard Uniform if(P_PlayerHasItem(thing->player, MT_QUEST_GUARD_UNIFORM)) break; // fall-through: case 150: // haleyjd 09/21/10: [STRIFE] WR Raise Alarm P_NoiseAlert(thing->player->mo, thing->player->mo); break; case 208: // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if Have Flamethrower // O_o - this is definitely unused. Was an entire flamethrower quest // cut out of the game before release? if(thing->player->weaponowned[wp_flame]) P_NoiseAlert(thing->player->mo, thing->player->mo); break; case 206: // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if Have Chalice // This *is* used, inside the Tavern in Tarnhill. Oddly there is also // one just randomly placed outside the entrance to the Power Station. if(P_PlayerHasItem(thing->player, MT_INV_CHALICE)) P_NoiseAlert(thing->player->mo, thing->player->mo); break; case 184: // villsa [STRIFE] plat up wait down stay if(EV_DoPlat(line, upWaitDownStay, 0)) P_ChangeSwitchTexture(line, 1); // In P_CrossSpecialLine? Copypasta error? break; case 185: // haleyjd 09/21/10: [STRIFE] Silent Teleport (used for Converter) EV_Teleport(line, side, thing, TF_FULLSILENCE); break; case 195: // haleyjd 09/21/10: [STRIFE] Silent Teleport and Change Zombie EV_Teleport(line, side, thing, TF_FULLSILENCE); P_SetMobjState(thing, S_AGRD_00); // 419 break; case 203: // haleyjd 09/21/10: [STRIFE] WR Change Music if(thing->player != &players[0]) break; S_ChangeMusic(line->tag, 1); break; case 231: // haleyjd 09/21/10: [STRIFE] WR Teleport (Silent at Source) EV_Teleport(line, side, thing, TF_SRCSILENCE); break; // haleyjd 09/21/10: Moved one-time-use lines up above with the others. } } // // P_ShootSpecialLine - IMPACT SPECIALS // Called when a thing shoots a special line. // void P_ShootSpecialLine ( mobj_t* thing, line_t* line ) { int ok; // Impacts that other things can activate. if (!thing->player) { ok = 0; switch(line->special) { case 46: // OPEN DOOR IMPACT case 182: // villsa [STRIFE] for windows ok = 1; break; } if (!ok) return; } switch(line->special) { case 24: // RAISE FLOOR - [STRIFE] Verified unmodified EV_DoFloor(line,raiseFloor); P_ChangeSwitchTexture(line,0); break; case 46: // OPEN DOOR - [STRIFE] Verified unmodified. EV_DoDoor(line,vld_open); P_ChangeSwitchTexture(line,1); break; case 47: // villsa [STRIFE] Verified unmodified. // RAISE FLOOR NEAR AND CHANGE EV_DoPlat(line,raiseToNearestAndChange,0); P_ChangeSwitchTexture(line,0); break; case 180: // haleyjd 09/22/10: [STRIFE] G1 Raise Floor 512 & Change EV_DoFloor(line, raiseFloor512AndChange); P_ChangeSwitchTexture(line, 0); break; case 182: // villsa [STRIFE] G1 Break Glass // haleyjd: note that 182 is also a W1 type in P_CrossSpecialLine, but // can only be activated in that manner by an MF_MISSILE object. P_ChangeSwitchTexture(line, 0); break; } } // // P_PlayerInSpecialSector // Called every tic frame // that the player origin is in a special sector // // [STRIFE] Modified for new sector types and changes to old ones. // void P_PlayerInSpecialSector (player_t* player) { sector_t* sector; sector = player->mo->subsector->sector; // Falling, not all the way down yet? if (player->mo->z != sector->floorheight) return; // Has hitten ground. switch (sector->special) { case 5: // HELLSLIME DAMAGE // [STRIFE] +2 to nukagecount if(!player->powers[pw_ironfeet]) player->nukagecount += 2; break; case 16: // [STRIFE] +4 to nukagecount if(!player->powers[pw_ironfeet]) player->nukagecount += 4; break; case 4: case 7: // [STRIFE] Immediate 5 damage every 31 tics if(!player->powers[pw_ironfeet]) if(!(leveltime & 0x1f)) P_DamageMobj(player->mo, NULL, NULL, 5); break; case 9: // SECRET SECTOR //player->secretcount++; [STRIFE] Don't have a secret count. sector->special = 0; if(player - players == consoleplayer) S_StartSound(NULL, sfx_yeah); break; case 11: // EXIT SUPER DAMAGE! (for E1M8 finale) player->cheats &= ~CF_GODMODE; if (!(leveltime&0x1f)) P_DamageMobj (player->mo, NULL, NULL, 20); if (player->health <= 10) G_ExitLevel(0); break; case 15: // haleyjd 08/30/10: [STRIFE] "Instant" Death sector P_DamageMobj(player->mo, NULL, NULL, 999); break; case 18: // haleyjd 08/30/10: [STRIFE] Water current { int tagval = sector->tag - 100; fixed_t force; angle_t angle; if(player->cheats & CF_NOCLIP) return; force = (tagval % 10) << 12; angle = (tagval / 10) << 29; P_Thrust(player, angle, force); } break; default: I_Error ("P_PlayerInSpecialSector: " "unknown special %i", sector->special); break; }; } // // P_UpdateSpecials // Animate planes, scroll walls, etc. // // [STRIFE] Modifications to support multiple scrolling line types. // boolean levelTimer; int levelTimeCount; void P_UpdateSpecials (void) { anim_t* anim; int pic; int i; line_t* line; // LEVEL TIMER if (levelTimer == true) { if(levelTimeCount) // [STRIFE] Does not allow to go negative levelTimeCount--; /* // [STRIFE] Not done here. Exit lines check this manually instead. if (!levelTimeCount) G_ExitLevel(0); */ } // ANIMATE FLATS AND TEXTURES GLOBALLY for (anim = anims ; anim < lastanim ; anim++) { for (i=anim->basepic ; ibasepic+anim->numpics ; i++) { pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics ); if (anim->istexture) texturetranslation[i] = pic; else flattranslation[i] = pic; } } // ANIMATE LINE SPECIALS for (i = 0; i < numlinespecials; i++) { line = linespeciallist[i]; switch(line->special) { case 48: // EFFECT FIRSTCOL SCROLL + sides[line->sidenum[0]].textureoffset += FRACUNIT; break; case 142: // haleyjd 09/25/10 [STRIFE] Scroll Up Slow sides[line->sidenum[0]].rowoffset += FRACUNIT; break; case 143: // haleyjd 09/25/10 [STRIFE] Scroll Down Fast (3 Units/Tic) sides[line->sidenum[0]].rowoffset -= 3*FRACUNIT; break; case 149: // haleyjd 09/25/10 [STRIFE] Scroll Down Slow sides[line->sidenum[0]].rowoffset -= FRACUNIT; break; } } // DO BUTTONS for (i = 0; i < MAXBUTTONS; i++) if (buttonlist[i].btimer) { buttonlist[i].btimer--; if (!buttonlist[i].btimer) { switch(buttonlist[i].where) { case top: sides[buttonlist[i].line->sidenum[0]].toptexture = buttonlist[i].btexture; break; case middle: sides[buttonlist[i].line->sidenum[0]].midtexture = buttonlist[i].btexture; break; case bottom: sides[buttonlist[i].line->sidenum[0]].bottomtexture = buttonlist[i].btexture; break; } S_StartSound(&buttonlist[i].soundorg,sfx_swtchn); memset(&buttonlist[i],0,sizeof(button_t)); } } } // // Donut overrun emulation // // Derived from the code from PrBoom+. Thanks go to Andrey Budko (entryway) // as usual :-) // #define DONUT_FLOORHEIGHT_DEFAULT 0x00000000 #define DONUT_FLOORPIC_DEFAULT 0x16 static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic, line_t *line, sector_t *pillar_sector) { static int first = 1; static int tmp_s3_floorheight; static int tmp_s3_floorpic; extern int numflats; if (first) { int p; // This is the first time we have had an overrun. first = 0; // Default values tmp_s3_floorheight = DONUT_FLOORHEIGHT_DEFAULT; tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT; //! // @category compat // @arg // // Use the specified magic values when emulating behavior caused // by memory overruns from improperly constructed donuts. // In Vanilla Strife this can differ depending on the operating // system. The default (if this option is not specified) is to // emulate the behavior when running under Windows 98. p = M_CheckParmWithArgs("-donut", 2); if (p > 0) { // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008 // // C:\>debug // -d 0:0 // // DOS 6.22: // 0000:0000 (57 92 19 00) F4 06 70 00-(16 00) // DOS 7.1: // 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00) // Win98: // 0000:0000 (00 00 00 00) 65 04 70 00-(16 00) // DOSBox under XP: // 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00) M_StrToInt(myargv[p + 1], &tmp_s3_floorheight); M_StrToInt(myargv[p + 2], &tmp_s3_floorpic); if (tmp_s3_floorpic >= numflats) { fprintf(stderr, "DonutOverrun: The second parameter for \"-donut\" " "switch should be greater than 0 and less than number " "of flats (%d). Using default value (%d) instead. \n", numflats, DONUT_FLOORPIC_DEFAULT); tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT; } } } /* fprintf(stderr, "Linedef: %d; Sector: %d; " "New floor height: %d; New floor pic: %d\n", line->iLineID, pillar_sector->iSectorID, tmp_s3_floorheight >> 16, tmp_s3_floorpic); */ *s3_floorheight = (fixed_t) tmp_s3_floorheight; *s3_floorpic = (short) tmp_s3_floorpic; } // // Special Stuff that can not be categorized // int EV_DoDonut(line_t* line) { sector_t* s1; sector_t* s2; sector_t* s3; int secnum; int rtn; int i; floormove_t* floor; fixed_t s3_floorheight; short s3_floorpic; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { s1 = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (s1->specialdata) continue; rtn = 1; s2 = getNextSector(s1->lines[0],s1); // Vanilla Doom does not check if the linedef is one sided. The // game does not crash, but reads invalid memory and causes the // sector floor to move "down" to some unknown height. // DOSbox prints a warning about an invalid memory access. // // I'm not sure exactly what invalid memory is being read. This // isn't something that should be done, anyway. // Just print a warning and return. if (s2 == NULL) { fprintf(stderr, "EV_DoDonut: linedef had no second sidedef! " "Unexpected behavior may occur in Vanilla Doom. \n"); break; } for (i = 0; i < s2->linecount; i++) { s3 = s2->lines[i]->backsector; if (s3 == s1) continue; if (s3 == NULL) { // e6y // s3 is NULL, so // s3->floorheight is an int at 0000:0000 // s3->floorpic is a short at 0000:0008 // Trying to emulate fprintf(stderr, "EV_DoDonut: WARNING: emulating buffer overrun due to " "NULL back sector. " "Unexpected behavior may occur in Vanilla Doom.\n"); DonutOverrun(&s3_floorheight, &s3_floorpic, line, s1); } else { s3_floorheight = s3->floorheight; s3_floorpic = s3->floorpic; } // Spawn rising slime floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); s2->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = donutRaise; floor->crush = false; floor->direction = 1; floor->sector = s2; floor->speed = FLOORSPEED / 2; floor->texture = s3_floorpic; floor->newspecial = 0; floor->floordestheight = s3_floorheight; // Spawn lowering donut-hole floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); s1->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = lowerFloor; floor->crush = false; floor->direction = -1; floor->sector = s1; floor->speed = FLOORSPEED / 2; floor->floordestheight = s3_floorheight; break; } } return rtn; } // // SPECIAL SPAWNING // // // P_SpawnSpecials // After the map has been loaded, scan for specials // that spawn thinkers // short numlinespecials; line_t* linespeciallist[MAXLINEANIMS]; // Parses command line parameters. // // haleyjd 09/25/10: [STRIFE] Modifications for more scrolling line types and // for initialization of sliding door resources. // void P_SpawnSpecials (void) { sector_t* sector; int i; // See if -TIMER was specified. if (timelimit > 0 && deathmatch) { levelTimer = true; levelTimeCount = timelimit * 60 * TICRATE; } else { levelTimer = false; } // Init special SECTORs - [STRIFE] Verified unmodified. sector = sectors; for (i=0 ; ispecial) continue; switch (sector->special) { case 1: // FLICKERING LIGHTS P_SpawnLightFlash (sector); break; case 2: // STROBE FAST P_SpawnStrobeFlash(sector,FASTDARK,0); break; case 3: // STROBE SLOW P_SpawnStrobeFlash(sector,SLOWDARK,0); break; case 4: // STROBE FAST/DEATH SLIME P_SpawnStrobeFlash(sector,FASTDARK,0); sector->special = 4; break; case 8: // GLOWING LIGHT P_SpawnGlowingLight(sector); break; case 9: // SECRET SECTOR totalsecret++; break; case 10: // DOOR CLOSE IN 30 SECONDS P_SpawnDoorCloseIn30 (sector); break; case 12: // SYNC STROBE SLOW P_SpawnStrobeFlash (sector, SLOWDARK, 1); break; case 13: // SYNC STROBE FAST P_SpawnStrobeFlash (sector, FASTDARK, 1); break; case 14: // DOOR RAISE IN 5 MINUTES P_SpawnDoorRaiseIn5Mins (sector, i); break; case 17: P_SpawnFireFlicker(sector); break; } } // Init line EFFECTs numlinespecials = 0; for (i = 0;i < numlines; i++) { switch(lines[i].special) { case 48: // EFFECT FIRSTCOL SCROLL+ case 142: case 143: case 149: linespeciallist[numlinespecials] = &lines[i]; numlinespecials++; break; } } // Init other misc stuff for (i = 0;i < MAXCEILINGS;i++) activeceilings[i] = NULL; for (i = 0;i < MAXPLATS;i++) activeplats[i] = NULL; for (i = 0;i < MAXBUTTONS;i++) memset(&buttonlist[i],0,sizeof(button_t)); // villsa [STRIFE] P_InitSlidingDoorFrames(); } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_spec.h000066400000000000000000000261061257432200600230170ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // Implements special effects: // Texture animation, height or lighting changes // according to adjacent sectors, respective // utility functions, etc. // #ifndef __P_SPEC__ #define __P_SPEC__ // // End-level timer (-TIMER option) // extern boolean levelTimer; extern int levelTimeCount; // Define values for map objects #define MO_TELEPORTMAN 14 // at game start void P_InitPicAnims (void); // villsa [STRIFE] typedef enum { FLOOR_WATER = 0, FLOOR_SLIME = 1, FLOOR_SOLID = 2, FLOOR_END = -1 } terraintype_e; void P_InitTerrainTypes(void); // villsa [STRIFE] terraintype_e P_GetTerrainType(mobj_t* mobj); // villsa [STRIFE] // at map load void P_SpawnSpecials (void); // every tic void P_UpdateSpecials (void); // when needed boolean P_UseSpecialLine ( mobj_t* thing, line_t* line, int side ); void P_ShootSpecialLine ( mobj_t* thing, line_t* line ); void P_CrossSpecialLine ( int linenum, int side, mobj_t* thing ); void P_PlayerInSpecialSector (player_t* player); int twoSided ( int sector, int line ); sector_t* getSector ( int currentSector, int line, int side ); side_t* getSide ( int currentSector, int line, int side ); fixed_t P_FindLowestFloorSurrounding(sector_t* sec); fixed_t P_FindHighestFloorSurrounding(sector_t* sec); fixed_t P_FindNextHighestFloor ( sector_t* sec, int currentheight ); fixed_t P_FindLowestCeilingSurrounding(sector_t* sec); fixed_t P_FindHighestCeilingSurrounding(sector_t* sec); int P_FindSectorFromLineTag ( line_t* line, int start ); int P_FindMinSurroundingLight ( sector_t* sector, int max ); sector_t* getNextSector ( line_t* line, sector_t* sec ); // // SPECIAL // int EV_DoDonut(line_t* line); boolean EV_ClearForceFields(line_t* line); // villsa [STRIFE] // // P_LIGHTS // typedef struct { thinker_t thinker; sector_t* sector; int count; int maxlight; int minlight; } fireflicker_t; typedef struct { thinker_t thinker; sector_t* sector; int count; int maxlight; int minlight; int maxtime; int mintime; } lightflash_t; typedef struct { thinker_t thinker; sector_t* sector; int count; int minlight; int maxlight; int darktime; int brighttime; } strobe_t; typedef struct { thinker_t thinker; sector_t* sector; int minlight; int maxlight; int direction; } glow_t; #define GLOWSPEED 8 #define STROBEBRIGHT 5 #define FASTDARK 15 #define SLOWDARK 35 void P_SpawnFireFlicker (sector_t* sector); void T_LightFlash (lightflash_t* flash); void P_SpawnLightFlash (sector_t* sector); void T_StrobeFlash (strobe_t* flash); void P_SpawnStrobeFlash ( sector_t* sector, int fastOrSlow, int inSync ); void EV_StartLightStrobing(line_t* line); void EV_TurnTagLightsOff(line_t* line); void EV_LightTurnOn ( line_t* line, int bright ); void T_Glow(glow_t* g); void P_SpawnGlowingLight(sector_t* sector); // // P_SWITCH // typedef struct { char name1[9]; char name2[9]; short episode; int sound; // villsa [STRIFE] } switchlist_t; typedef enum { top, middle, bottom } bwhere_e; typedef struct { line_t* line; bwhere_e where; int btexture; int btimer; degenmobj_t *soundorg; } button_t; // max # of wall switches in a level #define MAXSWITCHES 80 // villsa [STRIFE] changed from 50 to 80 // 4 players, 4 buttons each at once, max. #define MAXBUTTONS 16 // 1 second, in ticks. #define BUTTONTIME 35 extern button_t buttonlist[MAXBUTTONS]; void P_ChangeSwitchTexture ( line_t* line, int useAgain ); void P_InitSwitchList(void); // // P_PLATS // typedef enum { up, down, waiting, in_stasis } plat_e; typedef enum { perpetualRaise, downWaitUpStay, slowDWUS, // villsa [STRIFE] raiseAndChange, raiseToNearestAndChange, blazeDWUS, upWaitDownStay // villsa [STRIFE] } plattype_e; typedef struct { thinker_t thinker; sector_t* sector; fixed_t speed; fixed_t low; fixed_t high; int wait; int count; plat_e status; plat_e oldstatus; boolean crush; int tag; plattype_e type; } plat_t; #define PLATWAIT 3 #define PLATSPEED FRACUNIT #define MAXPLATS 30 extern plat_t* activeplats[MAXPLATS]; void T_PlatRaise(plat_t* plat); int EV_DoPlat ( line_t* line, plattype_e type, int amount ); void P_AddActivePlat(plat_t* plat); void P_RemoveActivePlat(plat_t* plat); void EV_StopPlat(line_t* line); void P_ActivateInStasis(int tag); // // P_DOORS // typedef enum { vld_normal, vld_close30ThenOpen, vld_close, vld_open, vld_raiseIn5Mins, vld_blazeRaise, vld_blazeOpen, vld_blazeClose, vld_shopClose, // villsa [STRIFE] vld_splitRaiseNearest, // villsa [STRIFE] vld_splitOpen // villsa [STRIFE] } vldoor_e; typedef struct { thinker_t thinker; vldoor_e type; sector_t* sector; fixed_t topheight; fixed_t speed; // 1 = up, 0 = waiting at top, -1 = down int direction; // tics to wait at the top int topwait; // (keep in case a door going down is reset) // when it reaches 0, start going down int topcountdown; // villsa [STRIFE] new field - sound to play when opening int opensound; // villsa [STRIFE] new field - sound to play when closing int closesound; } vldoor_t; #define VDOORSPEED FRACUNIT*2 #define VDOORWAIT 150 void EV_VerticalDoor ( line_t* line, mobj_t* thing ); int EV_DoDoor ( line_t* line, vldoor_e type ); int EV_DoLockedDoor ( line_t* line, vldoor_e type, mobj_t* thing ); void T_VerticalDoor (vldoor_t* door); void P_SpawnDoorCloseIn30 (sector_t* sec); void P_SpawnDoorRaiseIn5Mins ( sector_t* sec, int secnum ); // villsa [STRIFE] resurrected sliding doors // // Sliding doors... // typedef enum { sd_opening, sd_waiting, sd_closing } sd_e; typedef enum { sdt_openOnly, sdt_closeOnly, sdt_openAndClose } sdt_e; // villsa [STRIFE] Rogue added a second line_t in the struct // backsector is removed typedef struct { thinker_t thinker; sdt_e type; line_t* line1; line_t* line2; int frame; int whichDoorIndex; int timer; sector_t* frontsector; sd_e status; } slidedoor_t; // villsa [STRIFE] no front/back frames typedef struct { char frame1[9]; char frame2[9]; char frame3[9]; char frame4[9]; char frame5[9]; char frame6[9]; char frame7[9]; char frame8[9]; } slidename_t; // villsa [STRIFE] no front/back frames typedef struct { int frames[8]; } slideframe_t; // haleyjd 09/29/10: [STRIFE] Externalized for savegames void T_SlidingDoor(slidedoor_t* door); // how many frames of animation #define SNUMFRAMES 8 // villsa [STRIFE] changed from 4 to 8 #define SDOORWAIT TICRATE*3 #define SWAITTICS 4 // how many diff. types of anims #define MAXSLIDEDOORS 8 // villsa [STRIFE] changed from 5 to 8 void P_InitSlidingDoorFrames(void); void EV_SlidingDoor(line_t* line, mobj_t* thing); int EV_RemoteSlidingDoor(line_t* line, mobj_t* thing); // // P_CEILNG // typedef enum { lowerToFloor, raiseToHighest, lowerAndCrush, crushAndRaise, fastCrushAndRaise, silentCrushAndRaise } ceiling_e; typedef struct { thinker_t thinker; ceiling_e type; sector_t* sector; fixed_t bottomheight; fixed_t topheight; fixed_t speed; boolean crush; // 1 = up, 0 = waiting, -1 = down int direction; // ID int tag; int olddirection; } ceiling_t; #define CEILSPEED FRACUNIT #define CEILWAIT 150 #define MAXCEILINGS 30 extern ceiling_t* activeceilings[MAXCEILINGS]; int EV_DoCeiling ( line_t* line, ceiling_e type ); void T_MoveCeiling (ceiling_t* ceiling); void P_AddActiveCeiling(ceiling_t* c); void P_RemoveActiveCeiling(ceiling_t* c); int EV_CeilingCrushStop(line_t* line); void P_ActivateInStasisCeiling(line_t* line); // // P_FLOOR // typedef enum { // lower floor to highest surrounding floor lowerFloor, // lower floor to lowest surrounding floor lowerFloorToLowest, // lower floor to highest surrounding floor VERY FAST turboLower, // raise floor to lowest surrounding CEILING raiseFloor, // raise floor to next highest surrounding floor raiseFloorToNearest, // raise floor to shortest height texture around it raiseToTexture, // lower floor to lowest surrounding floor // and change floorpic lowerAndChange, raiseFloor64, // [STRIFE] changed from 24 to 64 raiseFloor24AndChange, raiseFloorCrush, // raise to next highest floor, turbo-speed raiseFloorTurbo, donutRaise, raiseFloor512, // [STRIFE] New floor type - used for the coolant reactor pit raiseFloor512AndChange } floor_e; typedef enum { build8, // slowly build by 8 turbo16, // quickly build by 16 buildDown16 // haleyjd 09/24/10: [STRIFE] new stair type } stair_e; typedef struct { thinker_t thinker; floor_e type; boolean crush; sector_t* sector; int direction; int newspecial; short texture; fixed_t floordestheight; fixed_t speed; } floormove_t; #define FLOORSPEED FRACUNIT typedef enum { ok, crushed, pastdest } result_e; result_e T_MovePlane ( sector_t* sector, fixed_t speed, fixed_t dest, boolean crush, int floorOrCeiling, int direction ); int EV_BuildStairs ( line_t* line, stair_e type ); int EV_DoFloor ( line_t* line, floor_e floortype ); void T_MoveFloor( floormove_t* floor); // // P_TELEPT // // [STRIFE] Teleportation flags - teleflags // Not to be conflated with telefrags, though they be tangentially related ;) typedef enum teleflags { TF_NOSRCSND = 0x01, TF_NODSTSND = 0x02, TF_NODSTFOG = 0x10, TF_NOSRCFOG = 0x20, TF_NORMAL = 0, TF_DSTSILENCE = (TF_NODSTSND|TF_NODSTFOG), // 0x12 (18) (Not used) TF_SRCSILENCE = (TF_NOSRCSND|TF_NOSRCFOG), // 0x21 (33) TF_FULLSILENCE = (TF_SRCSILENCE|TF_DSTSILENCE) // 0x33 (51) } teleflags_e; int EV_Teleport ( line_t* line, int side, mobj_t* thing, teleflags_e flags); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/p_switch.c000066400000000000000000001004311257432200600233530ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // DESCRIPTION: // Switches, buttons. Two-state animation. Exits. // #include #include "i_system.h" #include "deh_main.h" #include "doomdef.h" #include "p_local.h" #include "g_game.h" #include "d_main.h" // villsa [STRIFE] #include "z_zone.h" // villsa [STRIFE] #include "w_wad.h" // villsa [STRIFE] #include "s_sound.h" #include "m_random.h" // haleyjd [STRIFE] #include "p_dialog.h" #include "p_local.h" // haleyjd [STRIFE] #include "m_bbox.h" // villsa [STRIFE] #include "m_misc.h" // Data. #include "sounds.h" // State. #include "doomstat.h" #include "r_state.h" // // CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE // // villsa [STRIFE] new switch list switchlist_t alphSwitchList[] = { { "GLASS01", "GLASS02", 1, sfx_bglass }, { "GLASS03", "GLASS04", 1, sfx_bglass }, { "GLASS05", "GLASS06", 1, sfx_bglass }, { "GLASS07", "GLASS08", 1, sfx_bglass }, { "GLASS17", "GLASS18", 1, sfx_bglass }, { "GLASS19", "GLASS20", 1, sfx_bglass }, { "SWKNOB01", "SWKNOB02", 1, sfx_swknob }, { "SWLITE01", "SWLITE02", 1, sfx_None }, { "SWCHN01", "SWCHN02", 1, sfx_pulchn }, { "COMP01", "COMP04B", 1, sfx_bglass }, { "COMP05", "COMP12B", 1, sfx_bglass }, { "COMP09", "COMP12B", 1, sfx_bglass }, { "COMP12", "COMP04B", 1, sfx_bglass }, { "COMP13", "COMP12B", 1, sfx_bglass }, { "COMP17", "COMP20B", 1, sfx_bglass }, { "COMP21", "COMP28B", 1, sfx_bglass }, { "WALTEK09", "WALTEKB1", 1, sfx_None }, { "WALTEK10", "WALTEKB1", 1, sfx_None }, { "WALTEK15", "WALTEKB1", 1, sfx_None }, { "SWFORC01", "SWFORC02", 1, sfx_None }, { "SWEXIT01", "SWEXIT02", 1, sfx_None }, { "DORSBK01", "DORSBK02", 1, sfx_swston }, { "SWSLD01", "SWSLD02", 1, sfx_None }, { "DORWS04", "DORWS05", 1, sfx_swbolt }, { "SWIRON01", "SWIRON02", 1, sfx_None }, { "GLASS09", "GLASS10", 2, sfx_bglass }, { "GLASS11", "GLASS12", 2, sfx_bglass }, { "GLASS13", "GLASS14", 2, sfx_bglass }, { "GLASS15", "GLASS16", 2, sfx_bglass }, { "SWFORC03", "SWFORC04", 2, sfx_None }, { "SWCIT01", "SWCIT02", 2, sfx_None }, { "SWTRMG01", "SWTRMG04", 2, sfx_None }, { "SWMETL01", "SWMETL02", 2, sfx_None }, { "SWWOOD01", "SWWOOD02", 2, sfx_None }, { "SWTKBL01", "SWTKBL02", 2, sfx_None }, { "AZWAL21", "AZWAL22", 2, sfx_None }, { "SWINDT01", "SWINDT02", 2, sfx_None }, { "SWRUST01", "SWRUST02", 2, sfx_None }, { "SWCHAP01", "SWCHAP02", 2, sfx_None }, { "SWALIN01", "SWALIN02", 2, sfx_None }, { "SWWALG01", "SWWALG02", 2, sfx_None }, { "SWWALG03", "SWWALG04", 2, sfx_None }, { "SWTRAM01", "SWTRAM02", 2, sfx_None }, { "SWTRAM03", "SWTRAM04", 2, sfx_None }, { "SWORC01", "SWORC02", 2, sfx_None }, { "SWBRIK01", "SWBRIK02", 2, sfx_None }, { "SWIRON03", "SWIRON04", 2, sfx_None }, { "SWIRON05", "SWIRON06", 2, sfx_None }, { "SWIRON07", "SWIRON08", 2, sfx_None }, { "SWCARD01", "SWCARD02", 2, sfx_keycrd }, { "SWSIGN01", "SWSIGN02", 2, sfx_None }, { "SWLEV01", "SWLEV02", 2, sfx_None }, { "SWLEV03", "SWLEV04", 2, sfx_None }, { "SWLEV05", "SWLEV06", 2, sfx_None }, { "SWBRN01", "SWBRN02", 2, sfx_keycrd }, { "SWPIP01", "SWPIP02", 2, sfx_valve }, { "SWPALM01", "SWPALM02", 2, sfx_swscan }, { "SWKNOB03", "SWKNOB04", 2, sfx_swknob }, { "ALTSW01", "ALTSW02", 2, sfx_None }, { "COMP25", "COMP28B", 2, sfx_bglass }, { "COMP29", "COMP20B", 2, sfx_bglass }, { "COMP33", "COMP50", 2, sfx_bglass }, { "COMP42", "COMP51", 2, sfx_bglass }, { "GODSCRN1", "GODSCRN2", 2, sfx_difool }, { "ALIEN04", "ALIEN05", 2, sfx_None }, { "CITADL04", "CITADL05", 2, sfx_None }, { "SWITE03", "SWITE04", 2, sfx_None }, { "SWTELP01", "SWTELP02", 2, sfx_None }, { "BRNSCN01", "BRNSCN05", 2, sfx_firxpl }, { "\0", "\0", 0, sfx_None } }; int switchlist[MAXSWITCHES * 2]; int numswitches; button_t buttonlist[MAXBUTTONS]; // // P_InitSwitchList // Only called at game initialization. // void P_InitSwitchList(void) { int i; int index; int episode; episode = 1; if(isregistered) episode = 2; // villsa [STRIFE] unused /*else if ( gamemode == commercial ) episode = 3;*/ for(index = 0, i = 0; i < MAXSWITCHES; i++) { if(!alphSwitchList[i].episode) { numswitches = index/2; switchlist[index] = -1; break; } if (alphSwitchList[i].episode <= episode) { switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name1)); switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name2)); } } } // // P_StartButton // Start a button counting down till it turns off. // void P_StartButton(line_t* line, bwhere_e w, int texture, int time) { int i; // See if button is already pressed for(i = 0; i < MAXBUTTONS; i++) { if(buttonlist[i].btimer && buttonlist[i].line == line) return; } for(i = 0; i < MAXBUTTONS; i++) { if(!buttonlist[i].btimer) { buttonlist[i].line = line; buttonlist[i].where = w; buttonlist[i].btexture = texture; buttonlist[i].btimer = time; buttonlist[i].soundorg = &line->frontsector->soundorg; return; } } I_Error("P_StartButton: no button slots left!"); } // // P_SpawnBrokenGlass // villsa [STRIFE] new function // static void P_SpawnBrokenGlass(line_t* line) { fixed_t x1; fixed_t x2; fixed_t y1; fixed_t y2; int i; mobj_t* glass; angle_t an; x1 = (line->v2->x + line->v1->x) / 2; y1 = (line->v2->y + line->v1->y) / 2; x2 = ((line->frontsector->soundorg.x - x1) / 5) + x1; y2 = ((line->frontsector->soundorg.y - y1) / 5) + y1; for(i = 0; i < 7; i++) { glass = P_SpawnMobj(x2, y2, ONFLOORZ, MT_JUNK); glass->z += (24*FRACUNIT); glass->flags |= (MF_SHADOW|MF_MVIS); P_SetMobjState(glass, P_Random() % 3 + S_SHRD_03); // 284 an = ((P_Random() << 13) / 255); glass->angle = (an << ANGLETOFINESHIFT); glass->momx = FixedMul(finecosine[an], (P_Random() & 3) << FRACBITS); glass->momy = FixedMul(finesine[an], (P_Random() & 3) << FRACBITS); glass->momz = (P_Random() & 7) << FRACBITS; glass->tics += (P_Random() + 7) & 7; } } // // Function that changes wall texture. // Tell it if switch is ok to use again (1=yes, it's a button). // void P_ChangeSwitchTexture(line_t* line, int useAgain) { int texTop; int texMid; int texBot; int i; int sound; boolean breakglass; // villsa [STRIFE] switchlist_t* sl; // villsa [STRIFE] breakglass = false; // villsa [STRIFE] texTop = sides[line->sidenum[0]].toptexture; texMid = sides[line->sidenum[0]].midtexture; texBot = sides[line->sidenum[0]].bottomtexture; sound = sfx_swtchn; // villsa [STRIFE] check for linetype 182 (break glass) if(line->special == 182) { line->flags &= ~ML_BLOCKING; breakglass = true; if(useAgain) { // haleyjd 09/21/10: Corrected (>> 16 == next field) texTop = 0; texBot = 0; } if(texMid) // haleyjd 09/21/10: Corrected (>> 16 == next field) useAgain = 0; sound = sfx_bglass; } if(!useAgain) line->special = 0; for(i = 0; i < numswitches*2; i++) { sl = &alphSwitchList[i / 2]; // villsa [STRIFE] if(switchlist[i] == texTop) { // villsa [STRIFE] set sound if(sl->sound) sound = sl->sound; // haleyjd 20141026: [STRIFE]: Rogue fixed wrong sound origin S_StartSound(&line->frontsector->soundorg, sound); sides[line->sidenum[0]].toptexture = switchlist[i^1]; if(useAgain) P_StartButton(line,top,switchlist[i],BUTTONTIME); if(breakglass) P_SpawnBrokenGlass(line); return; } else { if(switchlist[i] == texMid) { // villsa [STRIFE] set sound if(sl->sound) sound = sl->sound; // haleyjd 20141026: [STRIFE]: Rogue fixed wrong sound origin S_StartSound(&line->frontsector->soundorg, sound); sides[line->sidenum[0]].midtexture = switchlist[i^1]; // villsa [STRIFE] affect second side of line // BUG: will crash if 1S line is marked with TWOSIDED flag! if(line->flags & ML_TWOSIDED) sides[line->sidenum[1]].midtexture = switchlist[i^1]; if(useAgain) P_StartButton(line, middle,switchlist[i],BUTTONTIME); // villsa [STRIFE]: Mines Transmitter hack if(sound == sfx_firxpl) { breakglass = true; // give quest flag 29 to player players[0].questflags |= QF_QUEST29; // give stamina/accuracy items if(!netgame) { P_GiveItemToPlayer(players, SPR_TOKN, MT_TOKEN_STAMINA); P_GiveItemToPlayer(players, SPR_TOKN, MT_TOKEN_NEW_ACCURACY); } } // villsa [STRIFE] if(breakglass || sound == sfx_bglass) P_SpawnBrokenGlass(line); return; } else { if(switchlist[i] == texBot) { // villsa [STRIFE] set sound if(sl->sound) sound = sl->sound; // haleyjd 20141026: [STRIFE]: Rogue fixed wrong sound origin S_StartSound(&line->frontsector->soundorg, sound); sides[line->sidenum[0]].bottomtexture = switchlist[i^1]; if(useAgain) P_StartButton(line, bottom,switchlist[i],BUTTONTIME); if(breakglass) P_SpawnBrokenGlass(line); return; } } } } } // // P_MoveWall // // villsa [STRIFE] New function. // Dynamically move a solid line. Unused in Strife // static void P_MoveWall(line_t *line, mobj_t *thing) { vertex_t *v2; vertex_t *v1; fixed_t x; fixed_t y; v1 = line->v1; v2 = line->v2; S_StartSound(thing, sfx_stnmov); if (line->dx) { if (thing->x >= v1->x) { v1->y -= (8 * FRACUNIT); v2->y -= (8 * FRACUNIT); } else { v1->y += (8 * FRACUNIT); v2->y += (8 * FRACUNIT); } } else { if (thing->y >= v1->y) { v1->x -= (8 * FRACUNIT); v2->x -= (8 * FRACUNIT); } else { v1->x += (8 * FRACUNIT); v2->x += (8 * FRACUNIT); } } if (v1->x >= v2->x) { line->bbox[BOXLEFT] = v2->x; x = v1->x; } else { line->bbox[BOXLEFT] = v1->x; x = v2->x; } line->bbox[BOXRIGHT] = x; if (v1->y >= v2->y) { line->bbox[BOXBOTTOM] = v2->y; y = v1->y; } else { line->bbox[BOXBOTTOM] = v1->y; y = v2->y; } line->bbox[BOXTOP] = y; } // villsa [STRIFE] static char usemessage[92]; // // P_UseSpecialLine // Called when a thing uses a special line. // Only the front sides of lines are usable. // boolean P_UseSpecialLine(mobj_t* thing, line_t* line, int side) { // Err... // Use the back sides of VERY SPECIAL lines... if (side) { switch(line->special) { case 148: // haleyjd [STRIFE] break; default: return false; } } // Switches that other things can activate. if (!thing->player) { // never open secret doors if (line->flags & ML_SECRET) return false; switch(line->special) { case 1: // MANUAL DOOR RAISE case 31: // haleyjd [STRIFE] case 144: // haleyjd [STRIFE] Manual sliding door break; default: return false; break; } } // do something switch(line->special) { // MANUALS case 1: // Vertical Door case 26: // DR ID Card case 27: // DR Pass Card case 28: // DR ID Badge case 31: // Manual door open case 32: // D1 ID Card case 33: // D1 ID Badge case 34: // D1 Pass Card case 117: // Blazing door raise case 118: // Blazing door open case 156: // haleyjd [STRIFE] D1 Brass Key case 157: // haleyjd [STRIFE] D1 Silver Key case 158: // haleyjd [STRIFE] D1 Gold Key case 159: // haleyjd [STRIFE] DR Gold Key case 160: // haleyjd [STRIFE] DR Silver Key case 161: // haleyjd [STRIFE] DR Brass Key case 165: // villsa [STRIFE] That doesn't seem to work case 166: // haleyjd [STRIFE] DR Hand Print case 169: // haleyjd [STRIFE] DR Base Key case 170: // haleyjd [STRIFE] DR Gov's Key case 190: // haleyjd [STRIFE] DR Order Key case 205: // villsa [STRIFE] Available in retail only case 213: // haleyjd [STRIFE] DR Chalice case 217: // haleyjd [STRIFE] DR Core Key case 221: // haleyjd [STRIFE] DR Mauler Key case 224: // haleyjd [STRIFE] DR Chapel Key case 225: // haleyjd [STRIFE] DR Catacomb Key case 232: // villsa [STRIFE] DR Oracle Pass EV_VerticalDoor (line, thing); break; // haleyjd: For the sake of our sanity, I have reordered all the line // specials from this point down so that they are strictly in numeric // order, and not divided up in a semi-arbitrary fashion. case 7: // Build Stairs - [STRIFE] Verified unmodified if (EV_BuildStairs(line,build8)) P_ChangeSwitchTexture(line,0); break; case 9: // Change Donut - [STRIFE] Verified unmodified if (EV_DoDonut(line)) P_ChangeSwitchTexture(line,0); break; case 11: // Exit level - [STRIFE] Modified to take tag, etc. P_ChangeSwitchTexture(line, 1); if(levelTimer && levelTimeCount) break; G_ExitLevel(line->tag); break; case 14: // Raise Floor 32 and change texture - [STRIFE] Verified unmodified if (EV_DoPlat(line, raiseAndChange,32)) P_ChangeSwitchTexture(line,0); break; case 15: // Raise Floor 24 and change texture if (EV_DoPlat(line, raiseAndChange,24)) P_ChangeSwitchTexture(line,0); break; case 18: // Raise Floor to next highest floor - [STRIFE] Verified unmodified if (EV_DoFloor(line, raiseFloorToNearest)) P_ChangeSwitchTexture(line,0); break; case 20: // Raise Plat next highest floor and change texture - [STRIFE] Verified unmodified if(EV_DoPlat(line, raiseToNearestAndChange, 0)) P_ChangeSwitchTexture(line,0); break; case 21: // PlatDownWaitUpStay - [STRIFE] Verified unmodified if (EV_DoPlat(line, downWaitUpStay,0)) P_ChangeSwitchTexture(line,0); break; case 23: // Lower Floor to Lowest - [STRIFE] Verified unmodified if (EV_DoFloor(line,lowerFloorToLowest)) P_ChangeSwitchTexture(line,0); break; case 29: // Raise Door - [STRIFE] Verified unmodified if (EV_DoDoor(line,vld_normal)) P_ChangeSwitchTexture(line,0); break; case 40: // villsa [STRIFE] Split Open Door if(EV_DoDoor(line, vld_splitOpen)) P_ChangeSwitchTexture(line, 0); break; // haleyjd case 41: // Lower Ceiling to Floor - [STRIFE] Verified unmodified if (EV_DoCeiling(line,lowerToFloor)) P_ChangeSwitchTexture(line,0); break; case 42: // Close Door - [STRIFE] Verified unmodified if (EV_DoDoor(line,vld_close)) P_ChangeSwitchTexture(line,1); break; case 43: // Lower Ceiling to Floor - [STRIFE] Verified unmodified if (EV_DoCeiling(line,lowerToFloor)) P_ChangeSwitchTexture(line,1); break; case 45: // Lower Floor to Surrounding floor height - [STRIFE] Verified unmodified if (EV_DoFloor(line,lowerFloor)) P_ChangeSwitchTexture(line,1); break; case 49: // Ceiling Crush And Raise - [STRIFE] Verified unmodified if (EV_DoCeiling(line,crushAndRaise)) P_ChangeSwitchTexture(line,0); break; case 50: // Close Door - [STRIFE] Verified unmodified if (EV_DoDoor(line,vld_close)) P_ChangeSwitchTexture(line,0); break; case 51: // [STRIFE] Modifed into S1 Start Finale (was Secret Exit) P_ChangeSwitchTexture(line,0); G_StartFinale(); break; case 55: // Raise Floor Crush - [STRIFE] Verified unmodified if (EV_DoFloor(line,raiseFloorCrush)) P_ChangeSwitchTexture(line,0); break; case 60: // Lower Floor to Lowest - [STRIFE] Verified unmodified if (EV_DoFloor(line,lowerFloorToLowest)) P_ChangeSwitchTexture(line,1); break; case 61: // Open Door - [STRIFE] Verified unmodified if (EV_DoDoor(line,vld_open)) P_ChangeSwitchTexture(line,1); break; case 62: // PlatDownWaitUpStay - [STRIFE] Verified unmodified if (EV_DoPlat(line, downWaitUpStay,1)) P_ChangeSwitchTexture(line,1); break; case 63: // Raise Door - [STRIFE] Verified unmodified if (EV_DoDoor(line,vld_normal)) P_ChangeSwitchTexture(line,1); break; case 64: // Raise Floor to ceiling - [STRIFE] Verified unmodified if (EV_DoFloor(line,raiseFloor)) P_ChangeSwitchTexture(line,1); break; case 65: // Raise Floor Crush - [STRIFE] Verified unmodified if (EV_DoFloor(line,raiseFloorCrush)) P_ChangeSwitchTexture(line,1); break; case 66: // Raise Floor 24 and change texture - [STRIFE] Verified unmodified if (EV_DoPlat(line, raiseAndChange, 24)) P_ChangeSwitchTexture(line,1); break; case 67: // Raise Floor 32 and change texture - [STRIFE] Verified unmodified if (EV_DoPlat(line, raiseAndChange, 32)) P_ChangeSwitchTexture(line,1); break; case 68: // Raise Plat to next highest floor and change texture - [STRIFE] Verified unmodified if (EV_DoPlat(line, raiseToNearestAndChange, 0)) P_ChangeSwitchTexture(line,1); break; case 69: // Raise Floor to next highest floor - [STRIFE] Verified unmodified if (EV_DoFloor(line, raiseFloorToNearest)) P_ChangeSwitchTexture(line,1); break; case 70: // Turbo Lower Floor - [STRIFE] Verified unmodified if (EV_DoFloor(line,turboLower)) P_ChangeSwitchTexture(line,1); break; case 71: // Turbo Lower Floor - [STRIFE] Verified unmodified if (EV_DoFloor(line,turboLower)) P_ChangeSwitchTexture(line,0); break; case 101: // Raise Floor - [STRIFE] Verified unmodified if (EV_DoFloor(line,raiseFloor)) P_ChangeSwitchTexture(line,0); break; case 102: // Lower Floor to Surrounding floor height - [STRIFE] Verified unmodified if (EV_DoFloor(line,lowerFloor)) P_ChangeSwitchTexture(line,0); break; case 103: // Open Door - [STRIFE] Verified unmodified if (EV_DoDoor(line,vld_open)) P_ChangeSwitchTexture(line,0); break; case 111: // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified if (EV_DoDoor (line,vld_blazeRaise)) P_ChangeSwitchTexture(line,0); break; case 112: // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified if (EV_DoDoor (line,vld_blazeOpen)) P_ChangeSwitchTexture(line,0); break; case 113: // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified if (EV_DoDoor (line,vld_blazeClose)) P_ChangeSwitchTexture(line,0); break; case 114: // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified if (EV_DoDoor (line,vld_blazeRaise)) P_ChangeSwitchTexture(line,1); break; case 115: // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified if (EV_DoDoor (line,vld_blazeOpen)) P_ChangeSwitchTexture(line,1); break; case 116: // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified if (EV_DoDoor (line,vld_blazeClose)) P_ChangeSwitchTexture(line,1); break; case 122: // Blazing PlatDownWaitUpStay - [STRIFE] Verified unmodified if(EV_DoPlat(line, blazeDWUS, 0)) P_ChangeSwitchTexture(line,0); break; case 123: // Blazing PlatDownWaitUpStay - [STRIFE] Verified unmodified if(EV_DoPlat(line, blazeDWUS, 0)) P_ChangeSwitchTexture(line,1); break; case 127: // Build Stairs Turbo 16 - [STRIFE] Verified unmodified if (EV_BuildStairs(line,turbo16)) P_ChangeSwitchTexture(line,0); break; case 131: // Raise Floor Turbo - [STRIFE] Verified unmodified if (EV_DoFloor(line,raiseFloorTurbo)) P_ChangeSwitchTexture(line,0); break; case 132: // Raise Floor Turbo - [STRIFE] Verified unmodified if (EV_DoFloor(line,raiseFloorTurbo)) P_ChangeSwitchTexture(line,1); break; case 133: // [STRIFE] TODO - which key is it? case 135: // [STRIFE] TODO - which key is it? case 137: // [STRIFE] TODO - which key is it? if (EV_DoLockedDoor (line,vld_blazeOpen,thing)) P_ChangeSwitchTexture(line,0); break; case 99: // [STRIFE] TODO: which key is it? case 134: // [STRIFE] TODO: which key is it? case 136: // [STRIFE] TODO: which key is it? if (EV_DoLockedDoor (line,vld_blazeOpen,thing)) P_ChangeSwitchTexture(line,1); break; case 138: // Light Turn On - [STRIFE] Verified unmodified EV_LightTurnOn(line,255); P_ChangeSwitchTexture(line,1); break; case 139: // Light Turn Off - [STRIFE] Verified unmodified EV_LightTurnOn(line,35); P_ChangeSwitchTexture(line,1); break; case 140: // Raise Floor 512 - [STRIFE] Verified unmodified if (EV_DoFloor(line,raiseFloor512)) P_ChangeSwitchTexture(line,0); break; case 144: // villsa [STRIFE] manual sliding door EV_SlidingDoor(line, thing); break; case 146: // haleyjd 09/24/10: [STRIFE] S1 Build Stairs Down 16 (new type) if(EV_BuildStairs(line, buildDown16)) P_ChangeSwitchTexture(line, 0); break; case 147: // haleyjd 09/24/10: [STRIFE] S1 Clear Force Fields if(EV_ClearForceFields(line)) P_ChangeSwitchTexture(line, 0); break; case 148: // haleyjd 09/16/10: [STRIFE] using forcefields hurts P_DamageMobj(thing, NULL, NULL, 16); P_Thrust(thing->player, thing->angle + ANG180, 125*FRACUNIT/16); break; case 151: // villsa [STRIFE] BlzOpenDoor Gold key case 152: // [STRIFE] TODO: which key is it? case 153: // [STRIFE] TODO: which key is it? if(EV_DoLockedDoor(line, vld_blazeOpen, thing)) P_ChangeSwitchTexture(line, 1); break; case 154: // villsa [STRIFE] plat lower wait rise if have gold key if(thing->player->cards[key_GoldKey]) { if(EV_DoPlat(line, downWaitUpStay, 0)) P_ChangeSwitchTexture(line, 1); } else { thing->player->message = DEH_String("You need a gold key"); S_StartSound(thing, sfx_oof); } break; case 155: // villsa [STRIFE] raise plat wait lower if(EV_DoPlat(line, upWaitDownStay, 0)) P_ChangeSwitchTexture(line, 1); break; case 162: // [STRIFE] TODO: which key is it? case 163: // [STRIFE] TODO: which key is it? case 164: // villsa [STRIFE] BlzOpenDoor Gold key case 167: // [STRIFE] TODO: which key is it? if(EV_DoLockedDoor(line, vld_blazeOpen, thing)) P_ChangeSwitchTexture(line, 0); break; case 168: // [STRIFE] TODO: which key is it? // haleyjd 09/25/10: [STRIFE] SR Blaze Open Door ???? Key if(EV_DoLockedDoor(line, vld_blazeOpen, thing)) P_ChangeSwitchTexture(line, 1); break; case 171: // [STRIFE] TODO: which key is it? // haleyjd 09/25/10: [STRIFE] S1 Open Door ???? Key if(EV_DoLockedDoor(line, vld_open, thing)) P_ChangeSwitchTexture(line, 0); break; case 172: // [STRIFE] TODO: which key is it? case 173: // [STRIFE] TODO: which key is it? case 176: // [STRIFE] TODO: which key is it? case 191: // [STRIFE] TODO: which key is it? case 192: // [STRIFE] TODO: which key is it? case 223: // [STRIFE] TODO: which key is it? if(EV_DoLockedDoor(line, vld_normal, thing)) P_ChangeSwitchTexture(line, 1); break; case 177: // villsa [STRIFE] plat lower wait rise if have power3 key if(thing->player->cards[key_Power3Key]) { if(EV_DoPlat(line, downWaitUpStay, 0)) P_ChangeSwitchTexture(line, 1); } else { thing->player->message = DEH_String("You don't have the key"); S_StartSound(thing, sfx_oof); } break; case 181: // haleyjd 09/25/10: [STRIFE] S1 Floor Raise 512 & Change if(EV_DoFloor(line, raiseFloor512AndChange)) P_ChangeSwitchTexture(line, 0); break; case 189: // [STRIFE] TODO: which key is it??? // haleyjd 09/25/10: [STRIFE] S1 Split Open Door ???? Key if(EV_DoLockedDoor(line, vld_splitOpen, thing)) P_ChangeSwitchTexture(line, 0); break; case 194: // villsa [STRIFE] S1 Free Prisoners if(EV_DoDoor(line, vld_open)) { P_ChangeSwitchTexture(line, 0); P_FreePrisoners(); } break; case 199: // haleyjd 09/25/10: [STRIFE] S1 Destroy Converter if(EV_DoCeiling(line, lowerAndCrush)) { P_ChangeSwitchTexture(line, 0); P_DestroyConverter(); } break; case 207: // villsa [STRIFE] SR Remote Sliding Door if(EV_RemoteSlidingDoor(line, thing)) P_ChangeSwitchTexture(line, 1); break; // haleyjd case 209: // haleyjd 09/24/10: [STRIFE] S1 Build Stairs Down 16 if Have Chalice if(!P_PlayerHasItem(thing->player, MT_INV_CHALICE)) { DEH_snprintf(usemessage, sizeof(usemessage), "You need the chalice!"); thing->player->message = usemessage; S_StartSound(thing, sfx_oof); break; } else if(EV_BuildStairs(line, buildDown16)) P_ChangeSwitchTexture(line, 0); break; case 211: // villsa [STRIFE] S1 Play VOC## sound if(&players[consoleplayer] == thing->player && thing->player->powers[pw_communicator]) { DEH_snprintf(usemessage, sizeof(usemessage), "voc%i", line->tag); I_StartVoice(usemessage); line->special = 0; } break; case 214: // villsa [STRIFE] S1 slow lift lower wait up stay if(EV_DoPlat(line, slowDWUS, 1)) P_ChangeSwitchTexture(line, 1); break; case 219: // haleyjd 09/25/10: S1 Lower Floor Blue Crystal if(!thing->player->cards[key_BlueCrystalKey]) { thing->player->message = DEH_String("You need the Blue Crystal"); S_StartSound(thing, sfx_oof); } else if(EV_DoFloor(line, lowerFloor)) P_ChangeSwitchTexture(line, 0); break; case 220: // haleyjd 09/25/10: S1 Lower Floor Red Crystal if(!thing->player->cards[key_RedCrystalKey]) { thing->player->message = DEH_String("You need the Red Crystal"); S_StartSound(thing, sfx_oof); } else if(EV_DoFloor(line, lowerFloor)) P_ChangeSwitchTexture(line, 0); break; case 226: // villsa [STRIFE] S1 Complete Training Area if(EV_DoFloor(line, lowerFloor)) { P_GiveItemToPlayer(thing->player, SPR_TOKN, MT_TOKEN_STAMINA); P_GiveItemToPlayer(thing->player, SPR_TOKN, MT_TOKEN_NEW_ACCURACY); P_ChangeSwitchTexture(line, 0); DEH_snprintf(usemessage, sizeof(usemessage), DEH_String("Congratulations! You have completed the training area.")); thing->player->message = usemessage; } break; case 229: // villsa [STRIFE] SR Sigil Sliding Door if(thing->player->sigiltype == 4) { if(EV_RemoteSlidingDoor(line, thing)) P_ChangeSwitchTexture(line, 1); } break; // haleyjd case 233: // villsa [STRIFE] objective given after revealing the computer if(!EV_DoDoor(line, vld_splitOpen)) return true; P_ChangeSwitchTexture(line, 1); GiveVoiceObjective("voc70", "log70", 0); // haleyjd: Strife used sprintf here, not a direct set. DEH_snprintf(usemessage, sizeof(usemessage), "Incoming Message from BlackBird..."); thing->player->message = usemessage; break; case 234: // haleyjd 09/24/10: [STRIFE] SR Raise Door if Quest 3 if(!(thing->player->questflags & QF_QUEST3)) // QUEST3 == Irale { // BUG: doesn't make sfx_oof sound like all other message- // giving door types. I highly doubt this was intentional. DEH_snprintf(usemessage, sizeof(usemessage), "That doesn't seem to work!"); thing->player->message = usemessage; } else if(EV_DoDoor(line, vld_normal)) P_ChangeSwitchTexture(line, 1); break; case 235: // haleyjd 09/25/10: [STRIFE] S1 Split Open Door if Have Sigil 4 if(thing->player->sigiltype == 4) { if(EV_DoDoor(line, vld_splitOpen)) P_ChangeSwitchTexture(line, 0); } break; case 666: // villsa [STRIFE] SR Move Wall P_MoveWall(line, thing); break; } return true; } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_telept.c000066400000000000000000000106651257432200600233600ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Teleportation. // #include "doomdef.h" #include "doomstat.h" #include "s_sound.h" #include "p_local.h" // Data. #include "sounds.h" // State. #include "r_state.h" // // TELEPORTATION // // haleyjd 09/22/10: [STRIFE] Modified to take a flags parameter to control // silent teleportation. Rogue also removed the check for missiles, and the // z-set was replaced with one in P_TeleportMove. // int EV_Teleport ( line_t* line, int side, mobj_t* thing, teleflags_e flags) { int i; int tag; mobj_t* m; mobj_t* fog = NULL; unsigned an; thinker_t* thinker; sector_t* sector; fixed_t oldx; fixed_t oldy; fixed_t oldz; // haleyjd 20110205 [STRIFE]: this is not checked here // don't teleport missiles //if (thing->flags & MF_MISSILE) // return 0; // Don't teleport if hit back of line, // so you can get out of teleporter. if (side == 1) return 0; tag = line->tag; for (i = 0; i < numsectors; i++) { if (sectors[ i ].tag == tag ) { thinker = thinkercap.next; for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { // not a mobj if (thinker->function.acp1 != (actionf_p1)P_MobjThinker) continue; m = (mobj_t *)thinker; // not a teleportman if (m->type != MT_TELEPORTMAN ) continue; sector = m->subsector->sector; // wrong sector if (sector-sectors != i ) continue; oldx = thing->x; oldy = thing->y; oldz = thing->z; if (!P_TeleportMove (thing, m->x, m->y)) return 0; // fraggle: this was changed in final doom, // problem between normal doom2 1.9 and final doom // // Note that although chex.exe is based on Final Doom, // it does not have this quirk. // // haleyjd 20110205 [STRIFE] This code is *not* present, // because of a z-set which Rogue added to P_TeleportMove. /* if (gameversion < exe_final || gameversion == exe_chex) thing->z = thing->floorz; */ if (thing->player) thing->player->viewz = thing->z+thing->player->viewheight; // spawn teleport fog at source and destination // haleyjd 09/22/10: [STRIFE] controlled by teleport flags // BUG: Behavior would be undefined if this function were passed // any combination of teleflags that has the NO*FOG but not the // corresponding NO*SND flag - fortunately this is never done // anywhere in the code. if(!(flags & TF_NOSRCFOG)) fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG); if(!(flags & TF_NOSRCSND)) S_StartSound (fog, sfx_telept); an = m->angle >> ANGLETOFINESHIFT; if(!(flags & TF_NODSTFOG)) fog = P_SpawnMobj (m->x+20*finecosine[an], m->y+20*finesine[an], thing->z, MT_TFOG); if(!(flags & TF_NODSTSND)) S_StartSound (fog, sfx_telept); // don't move for a bit if (thing->player) thing->reactiontime = 18; thing->angle = m->angle; thing->momx = thing->momy = thing->momz = 0; return 1; } } } return 0; } chocolate-doom-chocolate-doom-2.2.1/src/strife/p_tick.c000066400000000000000000000063201257432200600230060ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Archiving: SaveGame I/O. // Thinker, Ticker. // #include "z_zone.h" #include "p_local.h" #include "doomstat.h" int leveltime; // // THINKERS // All thinkers should be allocated by Z_Malloc // so they can be operated on uniformly. // The actual structures will vary in size, // but the first element must be thinker_t. // // Both the head and tail of the thinker list. thinker_t thinkercap; // // P_InitThinkers // // [STRIFE] Verified unmodified // void P_InitThinkers (void) { thinkercap.prev = thinkercap.next = &thinkercap; } // // P_AddThinker // Adds a new thinker at the end of the list. // // [STRIFE] Verified unmodified // void P_AddThinker (thinker_t* thinker) { thinkercap.prev->next = thinker; thinker->next = &thinkercap; thinker->prev = thinkercap.prev; thinkercap.prev = thinker; } // // P_RemoveThinker // Deallocation is lazy -- it will not actually be freed // until its thinking turn comes up. // // [STRIFE] Verified unmodified // void P_RemoveThinker (thinker_t* thinker) { // FIXME: NOP. thinker->function.acv = (actionf_v)(-1); } // // P_AllocateThinker // Allocates memory and adds a new thinker at the end of the list. // void P_AllocateThinker (thinker_t* thinker) { } // // P_RunThinkers // // [STRIFE] Verified unmodified // void P_RunThinkers (void) { thinker_t *currentthinker, *nextthinker; currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { if ( currentthinker->function.acv == (actionf_v)(-1) ) { // time to remove it nextthinker = currentthinker->next; currentthinker->next->prev = currentthinker->prev; currentthinker->prev->next = currentthinker->next; Z_Free (currentthinker); } else { if (currentthinker->function.acp1) currentthinker->function.acp1 (currentthinker); nextthinker = currentthinker->next; } currentthinker = nextthinker; } } // // P_Ticker // // [STRIFE] Menu pause behavior modified // void P_Ticker (void) { int i; // run the tic if (paused) return; // pause if in menu and at least one tic has been run // haleyjd 09/08/10 [STRIFE]: menuactive -> menupause if (!netgame && menupause && !demoplayback && players[consoleplayer].viewz != 1) { return; } for (i=0 ; i #include "doomdef.h" #include "d_event.h" #include "p_local.h" #include "sounds.h" // villsa [STRIFE] #include "p_dialog.h" // villsa [STRIFE] #include "d_main.h" // villsa [STRIFE] #include "doomstat.h" #include "deh_str.h" // haleyjd [STRIFE] #include "z_zone.h" #include "w_wad.h" #include "p_pspr.h" #include "m_misc.h" #include "m_random.h" #include "s_sound.h" #include "p_inter.h" // Index of the special effects (INVUL inverse) map. #define LOOKPITCHAMOUNT 6 // villsa [STRIFE] #define CENTERVIEWAMOUNT (LOOKPITCHAMOUNT + 2) // villsa [STRIFE] #define LOOKUPMAX 90 // villsa [STRIFE] #define LOOKDOWNMAX -110 // villsa [STRIFE] void P_DropInventoryItem(player_t* player, int sprite); // villsa [STRIFE] boolean P_ItemBehavior(player_t* player, int item); // villsa [STRIFE] static char useinventorymsg[44]; // villsa [STRIFE] // // Movement. // // 16 pixels of bob #define MAXBOB 0x100000 boolean onground; // // P_Thrust // Moves the given origin along a given angle. // // [STRIFE] Verified unmodified // void P_Thrust ( player_t* player, angle_t angle, fixed_t move ) { angle >>= ANGLETOFINESHIFT; player->mo->momx += FixedMul(move,finecosine[angle]); player->mo->momy += FixedMul(move,finesine[angle]); } // // P_CalcHeight // Calculate the walking / running height adjustment // // [STRIFE] Some odd adjustments, and terrain view height adjustment // void P_CalcHeight (player_t* player) { int angle; fixed_t bob; // Regular movement bobbing // (needs to be calculated for gun swing // even if not on ground) // OPTIMIZE: tablify angle // Note: a LUT allows for effects // like a ramp with low health. player->bob = FixedMul (player->mo->momx, player->mo->momx) + FixedMul (player->mo->momy,player->mo->momy); player->bob >>= 2; if (player->bob>MAXBOB) player->bob = MAXBOB; // haleyjd 20110205 [STRIFE]: No CF_NOMOMENTUM check, and Rogue also removed // the dead code inside. if (!onground) { /* player->viewz = player->mo->z + VIEWHEIGHT; if (player->viewz > player->mo->ceilingz-4*FRACUNIT) player->viewz = player->mo->ceilingz-4*FRACUNIT; */ player->viewz = player->mo->z + player->viewheight; return; } angle = (FINEANGLES/20*leveltime)&FINEMASK; bob = FixedMul ( player->bob/2, finesine[angle]); // move viewheight if (player->playerstate == PST_LIVE) { player->viewheight += player->deltaviewheight; if (player->viewheight > VIEWHEIGHT) { player->viewheight = VIEWHEIGHT; player->deltaviewheight = 0; } if (player->viewheight < VIEWHEIGHT/2) { player->viewheight = VIEWHEIGHT/2; if (player->deltaviewheight <= 0) player->deltaviewheight = 1; } if (player->deltaviewheight) { player->deltaviewheight += FRACUNIT/4; if (!player->deltaviewheight) player->deltaviewheight = 1; } } player->viewz = player->mo->z + player->viewheight + bob; // villsa [STRIFE] account for terrain lowering the view if(player->mo->flags & MF_FEETCLIPPED) player->viewz -= 13*FRACUNIT; if (player->viewz > player->mo->ceilingz-4*FRACUNIT) player->viewz = player->mo->ceilingz-4*FRACUNIT; // haleyjd [STRIFE]: added a floorz clip here if (player->viewz < player->mo->floorz) player->viewz = player->mo->floorz; } // // P_MovePlayer // // [STRIFE] Adjustments to allow air control, jumping, and up/down look. // void P_MovePlayer (player_t* player) { ticcmd_t* cmd; cmd = &player->cmd; player->mo->angle += (cmd->angleturn<<16); // Do not let the player control movement // if not onground. onground = (player->mo->z <= player->mo->floorz); // villsa [STRIFE] allows player to climb over things by jumping // haleyjd 20110205: air control thrust should be 256, not cmd->forwardmove if(!onground) { if(cmd->forwardmove) P_Thrust (player, player->mo->angle, 256); } else { // villsa [STRIFE] jump button if (cmd->buttons2 & BT2_JUMP) { if(!player->deltaviewheight) player->mo->momz += 8*FRACUNIT; } // haleyjd 20110205 [STRIFE] Either Rogue or Watcom removed the // redundant "onground" checks from these if's. if (cmd->forwardmove) P_Thrust (player, player->mo->angle, cmd->forwardmove*2048); if (cmd->sidemove) P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048); } // villsa [STRIFE] player walking state set if ( (cmd->forwardmove || cmd->sidemove) && player->mo->state == &states[S_PLAY_00] ) { P_SetMobjState (player->mo, S_PLAY_01); } // villsa [STRIFE] centerview button if (cmd->buttons2 & BT2_CENTERVIEW) player->centerview = 1; // villsa [STRIFE] adjust player's pitch when centerviewing if (player->centerview) { if (player->pitch <= 0) { if (player->pitch < 0) player->pitch = player->pitch + CENTERVIEWAMOUNT; } else { player->pitch = player->pitch - CENTERVIEWAMOUNT; } if (abs(player->pitch) < CENTERVIEWAMOUNT) { player->pitch = 0; player->centerview = 0; } } // villsa [STRIFE] look up action if (cmd->buttons2 & BT2_LOOKUP) { player->pitch += LOOKPITCHAMOUNT; if (player->pitch > LOOKUPMAX || player->pitch < LOOKDOWNMAX) player->pitch -= LOOKPITCHAMOUNT; } else { // villsa [STRIFE] look down action if (cmd->buttons2 & BT2_LOOKDOWN) { player->pitch -= LOOKPITCHAMOUNT; if (player->pitch > LOOKUPMAX || player->pitch < LOOKDOWNMAX) player->pitch += LOOKPITCHAMOUNT; } } } // // P_DeathThink // Fall on your face when dying. // Decrease POV height to floor height. // // [STRIFE] Modifications for up/down look. // #define ANG5 (ANG90/18) void P_DeathThink(player_t* player) { angle_t angle; angle_t delta; P_MovePsprites(player); // fall to the ground if (player->viewheight > 6*FRACUNIT) player->viewheight -= FRACUNIT; if (player->viewheight < 6*FRACUNIT) player->viewheight = 6*FRACUNIT; player->deltaviewheight = 0; onground = (player->mo->z <= player->mo->floorz); P_CalcHeight(player); if(player->attacker && player->attacker != player->mo) { angle = R_PointToAngle2 (player->mo->x, player->mo->y, player->attacker->x, player->attacker->y); delta = angle - player->mo->angle; if (delta < ANG5 || delta > (unsigned)-ANG5) { // Looking at killer, // so fade damage flash down. player->mo->angle = angle; if (player->damagecount) player->damagecount--; } else if (delta < ANG180) player->mo->angle += ANG5; else player->mo->angle -= ANG5; } else if (player->damagecount) player->damagecount--; // villsa [STRIFE] if(player->pitch <= 90) player->pitch = player->pitch + 3; if(player->cmd.buttons & BT_USE) player->playerstate = PST_REBORN; } // // P_PlayerThink // // [STRIFE] Massive changes/additions: // * NOCLIP hack removed // * P_DeathThink moved up // * Inventory use/dropping // * Strife weapons logic // * Dialog // * Strife powerups and nukage behavior // * Fire Death/Sigil Shock // void P_PlayerThink (player_t* player) { ticcmd_t* cmd; weapontype_t newweapon; // villsa [STRIFE] unused code (see ST_Responder) /* // fixme: do this in the cheat code if (player->cheats & CF_NOCLIP) player->mo->flags |= MF_NOCLIP; else player->mo->flags &= ~MF_NOCLIP; */ // haleyjd 20110205 [STRIFE]: P_DeathThink moved up if (player->playerstate == PST_DEAD) { P_DeathThink (player); return; } // chain saw run forward cmd = &player->cmd; if (player->mo->flags & MF_JUSTATTACKED) { cmd->angleturn = 0; cmd->forwardmove = 0xc800/512; cmd->sidemove = 0; player->mo->flags &= ~MF_JUSTATTACKED; } // Move around. // Reactiontime is used to prevent movement // for a bit after a teleport. if (player->mo->reactiontime) player->mo->reactiontime--; else P_MovePlayer (player); P_CalcHeight (player); if (player->mo->subsector->sector->special) P_PlayerInSpecialSector (player); // villsa [STRIFE] handle inventory input if(cmd->buttons2 & (BT2_HEALTH|BT2_INVUSE|BT2_INVDROP)) { if(!player->inventorydown) { if(cmd->buttons2 & BT2_HEALTH) P_UseInventoryItem(player, SPR_FULL); else if(cmd->buttons2 & BT2_INVUSE) P_UseInventoryItem(player, cmd->inventory); else if(cmd->buttons2 & BT2_INVDROP) { P_DropInventoryItem(player, cmd->inventory); // haleyjd 20110205: removed incorrect "else" here // villsa [STRIFE] if(workparm) { int cheat = player->cheats ^ 1; player->cheats ^= CF_NOCLIP; if(cheat & CF_NOCLIP) { player->message = DEH_String("No Clipping Mode ON"); player->mo->flags |= MF_NOCLIP; } else { player->mo->flags &= ~MF_NOCLIP; player->message = DEH_String("No Clipping Mode OFF"); } } } } player->inventorydown = true; } else player->inventorydown = false; // Check for weapon change. // A special event has no other buttons. if(cmd->buttons & BT_SPECIAL) cmd->buttons = 0; if(cmd->buttons & BT_CHANGE) { // The actual changing of the weapon is done // when the weapon psprite can do it // (read: not in the middle of an attack). newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT; // villsa [STRIFE] select poison bow if(newweapon == wp_elecbow) { if(player->weaponowned[wp_poisonbow] && player->readyweapon == wp_elecbow) { if(player->ammo[weaponinfo[wp_poisonbow].ammo]) newweapon = wp_poisonbow; } } // villsa [STRIFE] select wp grenade launcher if(newweapon == wp_hegrenade) { if(player->weaponowned[wp_wpgrenade] && player->readyweapon == wp_hegrenade) { if(player->ammo[weaponinfo[wp_wpgrenade].ammo]) newweapon = wp_wpgrenade; } } // villsa [STRIFE] select torpedo if(newweapon == wp_mauler) { if(player->weaponowned[wp_torpedo] && player->readyweapon == wp_mauler) { // haleyjd 20140924: bug fix - using wrong enum value am_cell // caused this to check the missile launcher for rocket ammo if(player->ammo[weaponinfo[wp_torpedo].ammo] >= 30) newweapon = wp_torpedo; } } if(player->weaponowned[newweapon] && newweapon != player->readyweapon) { // villsa [STRIFE] check weapon if in demo mode or not if(weaponinfo[newweapon].availabledemo || !isdemoversion) { if(player->ammo[weaponinfo[newweapon].ammo]) player->pendingweapon = newweapon; else { // decide between electric bow or poison arrow if(newweapon == wp_elecbow && player->ammo[am_poisonbolts] && player->readyweapon != wp_poisonbow) { player->pendingweapon = wp_poisonbow; } // decide between hp grenade launcher or wp grenade launcher else if(newweapon == wp_hegrenade && player->ammo[am_wpgrenades] && player->readyweapon != wp_wpgrenade) { player->pendingweapon = wp_wpgrenade; } // villsa [STRIFE] - no check for mauler/torpedo?? } } } } // check for use if(cmd->buttons & BT_USE) { if(!player->usedown) { P_DialogStart(player); // villsa [STRIFE] P_UseLines (player); player->usedown = true; } } else player->usedown = false; // cycle psprites P_MovePsprites (player); // Counters, time dependend power ups. // Strength counts up to diminish fade. if (player->powers[pw_strength]) player->powers[pw_strength]++; // villsa [STRIFE] targeter powerup if(player->powers[pw_targeter]) { player->powers[pw_targeter]--; if(player->powers[pw_targeter] == 1) { P_SetPsprite(player, ps_targcenter, S_NULL); P_SetPsprite(player, ps_targleft, S_NULL); P_SetPsprite(player, ps_targright, S_NULL); } else if(player->powers[pw_targeter] - 1 < 5*TICRATE) { if(player->powers[pw_targeter] & 32) { P_SetPsprite(player, ps_targright, S_NULL); P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11 } else if(player->powers[pw_targeter] & 16) // haleyjd 20110205: missing else { P_SetPsprite(player, ps_targright, S_TRGT_02); // 12 P_SetPsprite(player, ps_targleft, S_NULL); } } } if(player->powers[pw_invisibility]) { // villsa [STRIFE] remove mvis flag as well if(!--player->powers[pw_invisibility]) player->mo->flags &= ~(MF_SHADOW|MF_MVIS); } if(player->powers[pw_ironfeet]) { player->powers[pw_ironfeet]--; // villsa [STRIFE] gasmask sound if(!(leveltime & 0x3f)) S_StartSound(player->mo, sfx_mask); } if(player->powers[pw_allmap] > 1) player->powers[pw_allmap]--; // haleyjd 08/30/10: [STRIFE] // Nukage count keeps track of exposure to hazardous conditions over time. // After accumulating 16 total seconds or more of exposure, you will take // 5 damage roughly once per second until the count drops back under 560 // tics. if(player->nukagecount) { player->nukagecount--; if(!(leveltime & 0x1f) && player->nukagecount > 16*TICRATE) P_DamageMobj(player->mo, NULL, NULL, 5); } if(player->damagecount) player->damagecount--; if(player->bonuscount) player->bonuscount--; // villsa [STRIFE] checks for extralight if(player->extralight >= 0) { if(player->cheats & CF_ONFIRE) player->fixedcolormap = 1; else player->fixedcolormap = 0; } else // Sigil shock: player->fixedcolormap = INVERSECOLORMAP; } // // P_RemoveInventoryItem // villsa [STRIFE] new function // char* P_RemoveInventoryItem(player_t *player, int slot, int amount) { mobjtype_t type; player->inventory[slot].amount -= amount; player->st_update = true; type = player->inventory[slot].type; if(!player->inventory[slot].amount) { // shift everything above it down // see P_TakeDialogItem for notes on possible bugs int j; for(j = slot + 1; j <= player->numinventory; j++) { inventory_t *item1 = &(player->inventory[j - 1]); inventory_t *item2 = &(player->inventory[j]); *item1 = *item2; } player->inventory[player->numinventory].type = NUMMOBJTYPES; player->inventory[player->numinventory].sprite = -1; player->numinventory--; // update cursor position if(player->inventorycursor >= player->numinventory) { if(player->inventorycursor) player->inventorycursor--; } } return mobjinfo[type].name; } // // P_DropInventoryItem // villsa [STRIFE] new function // void P_DropInventoryItem(player_t* player, int sprite) { int invslot; inventory_t *item; mobjtype_t type; int amount; invslot = 0; amount = 1; while(invslot < player->numinventory && sprite != player->inventory[invslot].sprite) invslot++; item = &(player->inventory[invslot]); type = item->type; if(item->amount) { angle_t angle; fixed_t dist; mobj_t* mo; mobj_t* mobjitem; fixed_t x; fixed_t y; fixed_t z; int r; if(item->type == MT_MONY_1) { if(item->amount >= 50) { type = MT_MONY_50; amount = 50; } else if(item->amount >= 25) { type = MT_MONY_25; amount = 25; } else if(item->amount >= 10) { type = MT_MONY_10; amount = 10; } } if(type >= NUMMOBJTYPES) return; angle = player->mo->angle; r = P_Random(); angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT; if(angle < 7618 && angle >= 6718) angle = 7618; else if(angle < 5570 && angle >= 4670) angle = 5570; else if(angle < 3522 && angle >= 2622) angle = 3522; else if(angle < 1474 && angle >= 574) angle = 1474; mo = player->mo; dist = mobjinfo[type].radius + mo->info->radius + (4*FRACUNIT); x = mo->x + FixedMul(finecosine[angle], dist); y = mo->y + FixedMul(finesine[angle], dist); z = mo->z + (10*FRACUNIT); mobjitem = P_SpawnMobj(x, y, z, type); mobjitem->flags |= (MF_SPECIAL|MF_DROPPED); if(P_CheckPosition(mobjitem, x, y)) { mobjitem->angle = (angle << ANGLETOFINESHIFT); mobjitem->momx = FixedMul(finecosine[angle], (5*FRACUNIT)) + mo->momx; mobjitem->momy = FixedMul(finesine[angle], (5*FRACUNIT)) + mo->momy; mobjitem->momz = FRACUNIT; P_RemoveInventoryItem(player, invslot, amount); } else P_RemoveMobj(mobjitem); } } // // P_TossDegninOre // villsa [STRIFE] new function // boolean P_TossDegninOre(player_t* player) { angle_t angle; mobj_t* mo; mobj_t* ore; fixed_t x; fixed_t y; fixed_t z; fixed_t dist; angle = player->mo->angle >> ANGLETOFINESHIFT; if(angle < 7618 && angle >= 6718) angle = 7618; else if(angle < 5570 && angle >= 4670) angle = 5570; else if(angle < 3522 && angle >= 2622) angle = 3522; else if(angle < 1474 && angle >= 574) angle = 1474; mo = player->mo; dist = mobjinfo[MT_DEGNINORE].radius + mo->info->radius + (4*FRACUNIT); x = mo->x + FixedMul(finecosine[angle], dist); y = mo->y + FixedMul(finesine[angle], dist); z = mo->z + (10*FRACUNIT); ore = P_SpawnMobj(x, y, z, MT_DEGNINORE); if(P_CheckPosition(ore, x, y)) { ore->target = mo; ore->angle = (angle << ANGLETOFINESHIFT); ore->momx = FixedMul(finecosine[angle], (5*FRACUNIT)); ore->momy = FixedMul(finesine[angle], (5*FRACUNIT)); ore->momz = FRACUNIT; return true; } else P_RemoveMobj(ore); return false; } // // P_SpawnTeleportBeacon // // villsa [STRIFE] new function // haleyjd 20140918: bug fixed to propagate allegiance properly. // boolean P_SpawnTeleportBeacon(player_t* player) { angle_t angle; int r; mobj_t* mo; mobj_t* beacon; fixed_t x; fixed_t y; fixed_t z; fixed_t dist; angle = player->mo->angle; r = P_Random(); angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT; if(angle < 7618 && angle >= 6718) angle = 7618; else if(angle < 5570 && angle >= 4670) angle = 5570; else if(angle < 3522 && angle >= 2622) angle = 3522; else if(angle < 1474 && angle >= 574) angle = 1474; mo = player->mo; dist = mobjinfo[MT_BEACON].radius + mo->info->radius + (4*FRACUNIT); x = mo->x + FixedMul(finecosine[angle], dist); y = mo->y + FixedMul(finesine[angle], dist); z = mo->z + (10*FRACUNIT); beacon = P_SpawnMobj(x, y, z, MT_BEACON); if(P_CheckPosition(beacon, x, y)) { beacon->target = mo; beacon->miscdata = (byte)(player->allegiance); beacon->angle = (angle << ANGLETOFINESHIFT); beacon->momx = FixedMul(finecosine[angle], (5*FRACUNIT)); beacon->momy = FixedMul(finesine[angle], (5*FRACUNIT)); beacon->momz = FRACUNIT; P_SetMobjState(beacon, beacon->info->seestate); return true; } else P_RemoveMobj(beacon); return false; } // // P_UseInventoryItem // villsa [STRIFE] new function // boolean P_UseInventoryItem(player_t* player, int item) { int i; char* name; if(player->cheats & CF_ONFIRE) return false; for(i = 0; i < player->numinventory; i++) { if(item != player->inventory[i].sprite) continue; if(!P_ItemBehavior(player, item)) return false; name = P_RemoveInventoryItem(player, i, 1); if(name == NULL) name = "Item"; M_snprintf(useinventorymsg, sizeof(useinventorymsg), "You used the %s.", name); player->message = useinventorymsg; if(player == &players[consoleplayer]) S_StartSound(NULL, sfx_itemup); return true; } return false; } // // P_ItemBehavior // villsa [STRIFE] new function // boolean P_ItemBehavior(player_t* player, int item) { switch(item) { case SPR_ARM1: // 136 return P_GiveArmor(player, 2); case SPR_ARM2: // 137 return P_GiveArmor(player, 1); case SPR_SHD1: // 186 return P_GivePower(player, pw_invisibility); case SPR_MASK: // 187 return P_GivePower(player, pw_ironfeet); case SPR_PMUP: // 191 if(!player->powers[pw_allmap]) { player->message = "The scanner won't work without a map!"; return false; } player->powers[pw_allmap] = PMUPTICS; return true; // haleyjd 20110228: repaired case SPR_STMP: // 180 return P_GiveBody(player, 10); case SPR_MDKT: // 181 return P_GiveBody(player, 25); case SPR_FULL: // 130 return P_GiveBody(player, 200); case SPR_BEAC: // 135 return P_SpawnTeleportBeacon(player); case SPR_TARG: // 108 return P_GivePower(player, pw_targeter); } return false; } chocolate-doom-chocolate-doom-2.2.1/src/strife/r_bsp.c000066400000000000000000000254321257432200600226470ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // BSP traversal, handling of LineSegs for rendering. // #include "doomdef.h" #include "m_bbox.h" #include "i_system.h" #include "r_main.h" #include "r_plane.h" #include "r_things.h" // State. #include "doomstat.h" #include "r_state.h" //#include "r_local.h" seg_t* curline; side_t* sidedef; line_t* linedef; sector_t* frontsector; sector_t* backsector; drawseg_t drawsegs[MAXDRAWSEGS]; drawseg_t* ds_p; void R_StoreWallRange ( int start, int stop ); // // R_ClearDrawSegs // void R_ClearDrawSegs (void) { ds_p = drawsegs; } // // ClipWallSegment // Clips the given range of columns // and includes it in the new clip list. // typedef struct { int first; int last; } cliprange_t; #define MAXSEGS 32 // newend is one past the last valid seg cliprange_t* newend; cliprange_t solidsegs[MAXSEGS]; // // R_ClipSolidWallSegment // Does handle solid walls, // e.g. single sided LineDefs (middle texture) // that entirely block the view. // void R_ClipSolidWallSegment ( int first, int last ) { cliprange_t* next; cliprange_t* start; // Find the first range that touches the range // (adjacent pixels are touching). start = solidsegs; while (start->last < first-1) start++; if (first < start->first) { if (last < start->first-1) { // Post is entirely visible (above start), // so insert a new clippost. R_StoreWallRange (first, last); next = newend; newend++; while (next != start) { *next = *(next-1); next--; } next->first = first; next->last = last; return; } // There is a fragment above *start. R_StoreWallRange (first, start->first - 1); // Now adjust the clip size. start->first = first; } // Bottom contained in start? if (last <= start->last) return; next = start; while (last >= (next+1)->first-1) { // There is a fragment between two posts. R_StoreWallRange (next->last + 1, (next+1)->first - 1); next++; if (last <= next->last) { // Bottom is contained in next. // Adjust the clip size. start->last = next->last; goto crunch; } } // There is a fragment after *next. R_StoreWallRange (next->last + 1, last); // Adjust the clip size. start->last = last; // Remove start+1 to next from the clip list, // because start now covers their area. crunch: if (next == start) { // Post just extended past the bottom of one post. return; } while (next++ != newend) { // Remove a post. *++start = *next; } newend = start+1; } // // R_ClipPassWallSegment // Clips the given range of columns, // but does not includes it in the clip list. // Does handle windows, // e.g. LineDefs with upper and lower texture. // void R_ClipPassWallSegment ( int first, int last ) { cliprange_t* start; // Find the first range that touches the range // (adjacent pixels are touching). start = solidsegs; while (start->last < first-1) start++; if (first < start->first) { if (last < start->first-1) { // Post is entirely visible (above start). R_StoreWallRange (first, last); return; } // There is a fragment above *start. R_StoreWallRange (first, start->first - 1); } // Bottom contained in start? if (last <= start->last) return; while (last >= (start+1)->first-1) { // There is a fragment between two posts. R_StoreWallRange (start->last + 1, (start+1)->first - 1); start++; if (last <= start->last) return; } // There is a fragment after *next. R_StoreWallRange (start->last + 1, last); } // // R_ClearClipSegs // void R_ClearClipSegs (void) { solidsegs[0].first = -0x7fffffff; solidsegs[0].last = -1; solidsegs[1].first = viewwidth; solidsegs[1].last = 0x7fffffff; newend = solidsegs+2; } // // R_AddLine // Clips the given segment // and adds any visible pieces to the line list. // void R_AddLine (seg_t* line) { int x1; int x2; angle_t angle1; angle_t angle2; angle_t span; angle_t tspan; curline = line; // OPTIMIZE: quickly reject orthogonal back sides. angle1 = R_PointToAngle (line->v1->x, line->v1->y); angle2 = R_PointToAngle (line->v2->x, line->v2->y); // Clip to view edges. // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW). span = angle1 - angle2; // Back side? I.e. backface culling? if (span >= ANG180) return; // Global angle needed by segcalc. rw_angle1 = angle1; angle1 -= viewangle; angle2 -= viewangle; tspan = angle1 + clipangle; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return; angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return; angle2 = 0 - clipangle; } // The seg is in the view range, // but not necessarily visible. angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; x1 = viewangletox[angle1]; x2 = viewangletox[angle2]; // Does not cross a pixel? if (x1 == x2) return; backsector = line->backsector; // Single sided line? if (!backsector) goto clipsolid; // Closed door. if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) goto clipsolid; // Window. if (backsector->ceilingheight != frontsector->ceilingheight || backsector->floorheight != frontsector->floorheight) goto clippass; // Reject empty lines used for triggers // and special events. // Identical floor and ceiling on both sides, // identical light levels on both sides, // and no middle texture. if (backsector->ceilingpic == frontsector->ceilingpic && backsector->floorpic == frontsector->floorpic && backsector->lightlevel == frontsector->lightlevel && curline->sidedef->midtexture == 0) { return; } clippass: R_ClipPassWallSegment (x1, x2-1); return; clipsolid: R_ClipSolidWallSegment (x1, x2-1); } // // R_CheckBBox // Checks BSP node/subtree bounding box. // Returns true // if some part of the bbox might be visible. // int checkcoord[12][4] = { {3,0,2,1}, {3,0,2,0}, {3,1,2,0}, {0}, {2,0,2,1}, {0,0,0,0}, {3,1,3,0}, {0}, {2,0,3,1}, {2,1,3,1}, {2,1,3,0} }; boolean R_CheckBBox (fixed_t* bspcoord) { int boxx; int boxy; int boxpos; fixed_t x1; fixed_t y1; fixed_t x2; fixed_t y2; angle_t angle1; angle_t angle2; angle_t span; angle_t tspan; cliprange_t* start; int sx1; int sx2; // Find the corners of the box // that define the edges from current viewpoint. if (viewx <= bspcoord[BOXLEFT]) boxx = 0; else if (viewx < bspcoord[BOXRIGHT]) boxx = 1; else boxx = 2; if (viewy >= bspcoord[BOXTOP]) boxy = 0; else if (viewy > bspcoord[BOXBOTTOM]) boxy = 1; else boxy = 2; boxpos = (boxy<<2)+boxx; if (boxpos == 5) return true; x1 = bspcoord[checkcoord[boxpos][0]]; y1 = bspcoord[checkcoord[boxpos][1]]; x2 = bspcoord[checkcoord[boxpos][2]]; y2 = bspcoord[checkcoord[boxpos][3]]; // check clip list for an open space angle1 = R_PointToAngle (x1, y1) - viewangle; angle2 = R_PointToAngle (x2, y2) - viewangle; span = angle1 - angle2; // Sitting on a line? if (span >= ANG180) return true; tspan = angle1 + clipangle; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return false; angle1 = clipangle; } tspan = clipangle - angle2; if (tspan > 2*clipangle) { tspan -= 2*clipangle; // Totally off the left edge? if (tspan >= span) return false; angle2 = 0 - clipangle; } // Find the first clippost // that touches the source post // (adjacent pixels are touching). angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; sx1 = viewangletox[angle1]; sx2 = viewangletox[angle2]; // Does not cross a pixel. if (sx1 == sx2) return false; sx2--; start = solidsegs; while (start->last < sx2) start++; if (sx1 >= start->first && sx2 <= start->last) { // The clippost contains the new span. return false; } return true; } // // R_Subsector // Determine floor/ceiling planes. // Add sprites of things in sector. // Draw one or more line segments. // void R_Subsector (int num) { int count; seg_t* line; subsector_t* sub; #ifdef RANGECHECK if (num>=numsubsectors) I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors); #endif sscount++; sub = &subsectors[num]; frontsector = sub->sector; count = sub->numlines; line = &segs[sub->firstline]; if (frontsector->floorheight < viewz) { floorplane = R_FindPlane (frontsector->floorheight, frontsector->floorpic, frontsector->lightlevel); } else floorplane = NULL; if (frontsector->ceilingheight > viewz || frontsector->ceilingpic == skyflatnum) { ceilingplane = R_FindPlane (frontsector->ceilingheight, frontsector->ceilingpic, frontsector->lightlevel); } else ceilingplane = NULL; R_AddSprites (frontsector); while (count--) { R_AddLine (line); line++; } } // // RenderBSPNode // Renders all subsectors below a given node, // traversing subtree recursively. // Just call with BSP root. void R_RenderBSPNode (int bspnum) { node_t* bsp; int side; // Found a subsector? if (bspnum & NF_SUBSECTOR) { if (bspnum == -1) R_Subsector (0); else R_Subsector (bspnum&(~NF_SUBSECTOR)); return; } bsp = &nodes[bspnum]; // Decide which side the view point is on. side = R_PointOnSide (viewx, viewy, bsp); // Recursively divide front space. R_RenderBSPNode (bsp->children[side]); // Possibly divide back space. if (R_CheckBBox (bsp->bbox[side^1])) R_RenderBSPNode (bsp->children[side^1]); } chocolate-doom-chocolate-doom-2.2.1/src/strife/r_bsp.h000066400000000000000000000025311257432200600226470ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh module, BSP traversal and handling. // #ifndef __R_BSP__ #define __R_BSP__ extern seg_t* curline; extern side_t* sidedef; extern line_t* linedef; extern sector_t* frontsector; extern sector_t* backsector; extern int rw_x; extern int rw_stopx; extern boolean segtextured; // false if the back side is the same plane extern boolean markfloor; extern boolean markceiling; extern boolean skymap; extern drawseg_t drawsegs[MAXDRAWSEGS]; extern drawseg_t* ds_p; extern lighttable_t** hscalelight; extern lighttable_t** vscalelight; extern lighttable_t** dscalelight; typedef void (*drawfunc_t) (int start, int stop); // BSP? void R_ClearClipSegs (void); void R_ClearDrawSegs (void); void R_RenderBSPNode (int bspnum); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/r_data.c000066400000000000000000000551051257432200600227740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Preparation of data for rendering, // generation of lookups, caching, retrieval by name. // #include #include "d_main.h" #include "deh_main.h" #include "i_swap.h" #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "doomdef.h" #include "r_local.h" #include "p_local.h" #include "doomstat.h" #include "m_misc.h" #include "r_sky.h" #include "r_data.h" #include "sounds.h" // villsa [STRIFE] // // Graphics. // DOOM graphics for walls and sprites // is stored in vertical runs of opaque pixels (posts). // A column is composed of zero or more posts, // a patch or sprite is composed of zero or more columns. // // // Texture definition. // Each texture is composed of one or more patches, // with patches being lumps stored in the WAD. // The lumps are referenced by number, and patched // into the rectangular texture space using origin // and possibly other attributes. // typedef struct { short originx; short originy; short patch; //short stepdir; // villsa [STRIFE] removed //short colormap; // villsa [STRIFE] removed } PACKEDATTR mappatch_t; // // Texture definition. // A DOOM wall texture is a list of patches // which are to be combined in a predefined order. // typedef struct { char name[8]; int masked; short width; short height; //int obsolete; // villsa [STRIFE] removed short patchcount; mappatch_t patches[1]; } PACKEDATTR maptexture_t; // A single patch from a texture definition, // basically a rectangular area within // the texture rectangle. typedef struct { // Block origin (allways UL), // which has allready accounted // for the internal origin of the patch. short originx; short originy; int patch; } texpatch_t; // A maptexturedef_t describes a rectangular texture, // which is composed of one or more mappatch_t structures // that arrange graphic patches. typedef struct texture_s texture_t; struct texture_s { // Keep name for switch changing, etc. char name[8]; short width; short height; // Index in textures list int index; // Next in hash table chain texture_t *next; // All the patches[patchcount] // are drawn back to front into the cached texture. short patchcount; texpatch_t patches[1]; }; int firstflat; int lastflat; int numflats; int firstpatch; int lastpatch; int numpatches; int firstspritelump; int lastspritelump; int numspritelumps; int numtextures; texture_t** textures; texture_t** textures_hashtable; int* texturewidthmask; // needed for texture pegging fixed_t* textureheight; int* texturecompositesize; short** texturecolumnlump; unsigned short** texturecolumnofs; byte** texturecomposite; // for global animation int* flattranslation; int* texturetranslation; // needed for pre rendering fixed_t* spritewidth; fixed_t* spriteoffset; fixed_t* spritetopoffset; lighttable_t *colormaps; // // MAPTEXTURE_T CACHING // When a texture is first needed, // it counts the number of composite columns // required in the texture and allocates space // for a column directory and any new columns. // The directory will simply point inside other patches // if there is only one patch in a given column, // but any columns with multiple patches // will have new column_ts generated. // // // R_DrawColumnInCache // Clip and draw a column // from a patch into a cached post. // void R_DrawColumnInCache ( column_t* patch, byte* cache, int originy, int cacheheight ) { int count; int position; byte* source; while (patch->topdelta != 0xff) { source = (byte *)patch + 3; count = patch->length; position = originy + patch->topdelta; if (position < 0) { count += position; position = 0; } if (position + count > cacheheight) count = cacheheight - position; if (count > 0) memcpy (cache + position, source, count); patch = (column_t *)( (byte *)patch + patch->length + 4); } } // // R_GenerateComposite // Using the texture definition, // the composite texture is created from the patches, // and each column is cached. // void R_GenerateComposite (int texnum) { byte* block; texture_t* texture; texpatch_t* patch; patch_t* realpatch; int x; int x1; int x2; int i; column_t* patchcol; short* collump; unsigned short* colofs; texture = textures[texnum]; block = Z_Malloc (texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]); collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // Composite the columns together. patch = texture->patches; for (i=0 , patch = texture->patches; ipatchcount; i++, patch++) { realpatch = W_CacheLumpNum (patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1<0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for ( ; x= 0) continue; patchcol = (column_t *)((byte *)realpatch + LONG(realpatch->columnofs[x-x1])); R_DrawColumnInCache (patchcol, block + colofs[x], patch->originy, texture->height); } } // Now that the texture has been built in column cache, // it is purgable from zone memory. Z_ChangeTag (block, PU_CACHE); } // // R_GenerateLookup // void R_GenerateLookup (int texnum) { texture_t* texture; byte* patchcount; // patchcount[texture->width] texpatch_t* patch; patch_t* realpatch; int x; int x1; int x2; int i; short* collump; unsigned short* colofs; texture = textures[texnum]; // Composited texture not created yet. texturecomposite[texnum] = 0; texturecompositesize[texnum] = 0; collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // Now count the number of columns // that are covered by more than one patch. // Fill in the lump / offset, so columns // with only a single patch are all done. patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); memset (patchcount, 0, texture->width); patch = texture->patches; for (i=0 , patch = texture->patches; ipatchcount; i++, patch++) { realpatch = W_CacheLumpNum (patch->patch, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1 < 0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for ( ; xpatch; colofs[x] = LONG(realpatch->columnofs[x-x1])+3; } } for (x=0 ; xwidth ; x++) { if (!patchcount[x]) { printf ("R_GenerateLookup: column without a patch (%s)\n", texture->name); return; } // I_Error ("R_GenerateLookup: column without a patch"); if (patchcount[x] > 1) { // Use the cached block. collump[x] = -1; colofs[x] = texturecompositesize[texnum]; if (texturecompositesize[texnum] > 0x10000-texture->height) { I_Error ("R_GenerateLookup: texture %i is >64k", texnum); } texturecompositesize[texnum] += texture->height; } } Z_Free(patchcount); } // // R_GetColumn // byte* R_GetColumn ( int tex, int col ) { int lump; int ofs; col &= texturewidthmask[tex]; lump = texturecolumnlump[tex][col]; ofs = texturecolumnofs[tex][col]; if (lump > 0) return (byte *)W_CacheLumpNum(lump,PU_CACHE)+ofs; if (!texturecomposite[tex]) R_GenerateComposite (tex); return texturecomposite[tex] + ofs; } static void GenerateTextureHashTable(void) { texture_t **rover; int i; int key; textures_hashtable = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0); memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures); // Add all textures to hash table for (i=0; iindex = i; // Vanilla Doom does a linear search of the texures array // and stops at the first entry it finds. If there are two // entries with the same name, the first one in the array // wins. The new entry must therefore be added at the end // of the hash chain, so that earlier entries win. key = W_LumpNameHash(textures[i]->name) % numtextures; rover = &textures_hashtable[key]; while (*rover != NULL) { rover = &(*rover)->next; } // Hook into hash table textures[i]->next = NULL; *rover = textures[i]; } } // // R_InitTextures // Initializes the texture list // with the textures from the world map. // void R_InitTextures (void) { maptexture_t* mtexture; texture_t* texture; mappatch_t* mpatch; texpatch_t* patch; int i; int j; int* maptex; int* maptex2; int* maptex1; char name[9]; char* names; char* name_p; int* patchlookup; int totalwidth; int nummappatches; int offset; int maxoff; int maxoff2; int numtextures1; int numtextures2; int* directory; int temp1; int temp2; int temp3; // Load the patch names from pnames.lmp. names = W_CacheLumpName (DEH_String("PNAMES"), PU_STATIC); nummappatches = LONG ( *((int *)names) ); name_p = names+4; patchlookup = Z_Malloc(nummappatches*sizeof(*patchlookup), PU_STATIC, NULL); for (i = 0; i < nummappatches; i++) { M_StringCopy(name, name_p + i * 8, sizeof(name)); patchlookup[i] = W_CheckNumForName (name); } W_ReleaseLumpName(DEH_String("PNAMES")); // Load the map texture definitions from textures.lmp. // The data is contained in one or two lumps, // TEXTURE1 for shareware, plus TEXTURE2 for commercial. maptex = maptex1 = W_CacheLumpName (DEH_String("TEXTURE1"), PU_STATIC); numtextures1 = LONG(*maptex); maxoff = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE1"))); directory = maptex+1; if (W_CheckNumForName (DEH_String("TEXTURE2")) != -1) { maptex2 = W_CacheLumpName (DEH_String("TEXTURE2"), PU_STATIC); numtextures2 = LONG(*maptex2); maxoff2 = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE2"))); } else { maptex2 = NULL; numtextures2 = 0; maxoff2 = 0; } numtextures = numtextures1 + numtextures2; textures = Z_Malloc (numtextures * sizeof(*textures), PU_STATIC, 0); texturecolumnlump = Z_Malloc (numtextures * sizeof(*texturecolumnlump), PU_STATIC, 0); texturecolumnofs = Z_Malloc (numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0); texturecomposite = Z_Malloc (numtextures * sizeof(*texturecomposite), PU_STATIC, 0); texturecompositesize = Z_Malloc (numtextures * sizeof(*texturecompositesize), PU_STATIC, 0); texturewidthmask = Z_Malloc (numtextures * sizeof(*texturewidthmask), PU_STATIC, 0); textureheight = Z_Malloc (numtextures * sizeof(*textureheight), PU_STATIC, 0); totalwidth = 0; // Really complex printing shit... temp1 = W_GetNumForName (DEH_String("S_START")); // P_??????? temp2 = W_GetNumForName (DEH_String("S_END")) - 1; temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64); // If stdout is a real console, use the classic vanilla "filling // up the box" effect, which uses backspace to "step back" inside // the box. If stdout is a file, don't draw the box. // haleyjd 20110206 [STRIFE]: box is in devparm only if (devparm && I_ConsoleStdout()) { printf("["); for (i = 0; i < temp3 + 9; i++) printf(" "); printf("]"); for (i = 0; i < temp3 + 10; i++) printf("\b"); } for (i=0 ; i maxoff) I_Error ("R_InitTextures: bad texture directory"); mtexture = (maptexture_t *) ( (byte *)maptex + offset); texture = textures[i] = Z_Malloc (sizeof(texture_t) + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1), PU_STATIC, 0); texture->width = SHORT(mtexture->width); texture->height = SHORT(mtexture->height); texture->patchcount = SHORT(mtexture->patchcount); memcpy (texture->name, mtexture->name, sizeof(texture->name)); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; for (j=0 ; jpatchcount ; j++, mpatch++, patch++) { patch->originx = SHORT(mpatch->originx); patch->originy = SHORT(mpatch->originy); patch->patch = patchlookup[SHORT(mpatch->patch)]; if (patch->patch == -1) { I_Error ("R_InitTextures: Missing patch in texture %s", texture->name); } } texturecolumnlump[i] = Z_Malloc (texture->width*sizeof(**texturecolumnlump), PU_STATIC,0); texturecolumnofs[i] = Z_Malloc (texture->width*sizeof(**texturecolumnofs), PU_STATIC,0); j = 1; while (j*2 <= texture->width) j<<=1; texturewidthmask[i] = j-1; textureheight[i] = texture->height<width; } Z_Free(patchlookup); W_ReleaseLumpName(DEH_String("TEXTURE1")); if (maptex2) W_ReleaseLumpName(DEH_String("TEXTURE2")); // Precalculate whatever possible. for (i=0 ; iwidth)<leftoffset)<topoffset)<name, name, 8) ) return texture->index; texture = texture->next; } return -1; } // // R_TextureNumForName // Calls R_CheckTextureNumForName, // aborts with error message. // int R_TextureNumForName (char* name) { int i; i = R_CheckTextureNumForName (name); if (i==-1) { I_Error ("R_TextureNumForName: %s not found", name); } return i; } // // R_SoundNumForDoor // // villsa [STRIFE] - new function // Set sounds associated with door though why // on earth is this function placed here? // void R_SoundNumForDoor(vldoor_t* door) { int i; sector_t *sector; line_t *line; texture_t *texture; char name[8]; char c1; char c2; // set default sounds door->opensound = sfx_drsmto; door->closesound = sfx_drsmtc; for(sector = door->sector, i = 0; i < sector->linecount; i++) { line = sector->lines[i]; if(!(line->flags & ML_TWOSIDED)) continue; texture = textures[sides[line->sidenum[0]].toptexture]; memcpy(name, texture->name, 8); if(strncmp(name, "DOR", 3)) continue; c1 = name[3]; c2 = name[4]; // S type if(c1 == 'S') { door->opensound = sfx_drston; door->closesound = sfx_drston; return; } // M type if(c1 == 'M') { // L subtype if(c2 == 'L') { door->opensound = sfx_drlmto; door->closesound = sfx_drlmtc; } // S subtype else if(c2 == 'S') { door->opensound = sfx_drsmto; door->closesound = sfx_drsmtc; } return; } // W type else if(c1 == 'W') { // L subtype if(c2 == 'L') { door->opensound = sfx_drlwud; door->closesound = sfx_drlwud; } // S subtype else if(c2 == 'S') { door->opensound = sfx_drswud; door->closesound = sfx_drswud; } return; } } } // // R_PrecacheLevel // Preloads all relevant graphics for the level. // int flatmemory; int texturememory; int spritememory; void R_PrecacheLevel (void) { char* flatpresent; char* texturepresent; char* spritepresent; int i; int j; int k; int lump; texture_t* texture; thinker_t* th; spriteframe_t* sf; if (demoplayback) return; // Precache flats. flatpresent = Z_Malloc(numflats, PU_STATIC, NULL); memset (flatpresent,0,numflats); for (i=0 ; ipatchcount ; j++) { lump = texture->patches[j].patch; texturememory += lumpinfo[lump].size; W_CacheLumpNum(lump , PU_CACHE); } } Z_Free(texturepresent); // Precache sprites. spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL); memset (spritepresent,0, numsprites); for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acp1 == (actionf_p1)P_MobjThinker) spritepresent[((mobj_t *)th)->sprite] = 1; } spritememory = 0; for (i=0 ; ilump[k]; spritememory += lumpinfo[lump].size; W_CacheLumpNum(lump , PU_CACHE); } } } Z_Free(spritepresent); } chocolate-doom-chocolate-doom-2.2.1/src/strife/r_data.h000066400000000000000000000025211257432200600227730ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh module, data I/O, caching, retrieval of graphics // by name. // #ifndef __R_DATA__ #define __R_DATA__ #include "r_defs.h" #include "r_state.h" #include "p_spec.h" // villsa [STRIFE] // Retrieve column data for span blitting. byte* R_GetColumn ( int tex, int col ); // I/O, setting up the stuff. void R_InitData (void); void R_PrecacheLevel (void); // Retrieval. // Floor/ceiling opaque texture tiles, // lookup by name. For animation? int R_FlatNumForName (char* name); // Called by P_Ticker for switches and animations, // returns the texture number for the texture name. int R_TextureNumForName (char *name); int R_CheckTextureNumForName (char *name); void R_SoundNumForDoor(vldoor_t* door); // villsa [STRIFE] #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/r_defs.h000066400000000000000000000177131257432200600230140ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh/rendering module, shared data struct definitions. // #ifndef __R_DEFS__ #define __R_DEFS__ // Screenwidth. #include "doomdef.h" // Some more or less basic data types // we depend on. #include "m_fixed.h" // We rely on the thinker data struct // to handle sound origins in sectors. #include "d_think.h" // SECTORS do store MObjs anyway. #include "p_mobj.h" #include "i_video.h" #include "v_patch.h" // Silhouette, needed for clipping Segs (mainly) // and sprites representing things. #define SIL_NONE 0 #define SIL_BOTTOM 1 #define SIL_TOP 2 #define SIL_BOTH 3 #define MAXDRAWSEGS 256 // // INTERNAL MAP TYPES // used by play and refresh // // // Your plain vanilla vertex. // Note: transformed values not buffered locally, // like some DOOM-alikes ("wt", "WebView") did. // typedef struct { fixed_t x; fixed_t y; } vertex_t; // Forward of LineDefs, for Sectors. struct line_s; // Each sector has a degenmobj_t in its center // for sound origin purposes. // I suppose this does not handle sound from // moving objects (doppler), because // position is prolly just buffered, not // updated. typedef struct { thinker_t thinker; // not used for anything fixed_t x; fixed_t y; fixed_t z; } degenmobj_t; // // The SECTORS record, at runtime. // Stores things/mobjs. // typedef struct { fixed_t floorheight; fixed_t ceilingheight; short floorpic; short ceilingpic; short lightlevel; short special; short tag; // 0 = untraversed, 1,2 = sndlines -1 int soundtraversed; // thing that made a sound (or null) mobj_t* soundtarget; // mapblock bounding box for height changes int blockbox[4]; // origin for any sounds played by the sector degenmobj_t soundorg; // if == validcount, already checked int validcount; // list of mobjs in sector mobj_t* thinglist; // thinker_t for reversable actions void* specialdata; int linecount; struct line_s** lines; // [linecount] size } sector_t; // // The SideDef. // typedef struct { // add this to the calculated texture column fixed_t textureoffset; // add this to the calculated texture top fixed_t rowoffset; // Texture indices. // We do not maintain names here. short toptexture; short bottomtexture; short midtexture; // Sector the SideDef is facing. sector_t* sector; } side_t; // // Move clipping aid for LineDefs. // typedef enum { ST_HORIZONTAL, ST_VERTICAL, ST_POSITIVE, ST_NEGATIVE } slopetype_t; typedef struct line_s { // Vertices, from v1 to v2. vertex_t* v1; vertex_t* v2; // Precalculated v2 - v1 for side checking. fixed_t dx; fixed_t dy; // Animation related. short flags; short special; short tag; // Visual appearance: SideDefs. // sidenum[1] will be -1 if one sided short sidenum[2]; // Neat. Another bounding box, for the extent // of the LineDef. fixed_t bbox[4]; // To aid move clipping. slopetype_t slopetype; // Front and back sector. // Note: redundant? Can be retrieved from SideDefs. sector_t* frontsector; sector_t* backsector; // if == validcount, already checked int validcount; // thinker_t for reversable actions void* specialdata; } line_t; // // A SubSector. // References a Sector. // Basically, this is a list of LineSegs, // indicating the visible walls that define // (all or some) sides of a convex BSP leaf. // typedef struct subsector_s { sector_t* sector; short numlines; short firstline; } subsector_t; // // The LineSeg. // typedef struct { vertex_t* v1; vertex_t* v2; fixed_t offset; angle_t angle; side_t* sidedef; line_t* linedef; // Sector references. // Could be retrieved from linedef, too. // backsector is NULL for one sided lines sector_t* frontsector; sector_t* backsector; } seg_t; // // BSP node. // typedef struct { // Partition line. fixed_t x; fixed_t y; fixed_t dx; fixed_t dy; // Bounding box for each child. fixed_t bbox[2][4]; // If NF_SUBSECTOR its a subsector. unsigned short children[2]; } node_t; // PC direct to screen pointers //B UNUSED - keep till detailshift in r_draw.c resolved //extern byte* destview; //extern byte* destscreen; // // OTHER TYPES // // This could be wider for >8 bit display. // Indeed, true color support is posibble // precalculating 24bpp lightmap/colormap LUT. // from darkening PLAYPAL to all black. // Could even us emore than 32 levels. typedef byte lighttable_t; // // ? // typedef struct drawseg_s { seg_t* curline; int x1; int x2; fixed_t scale1; fixed_t scale2; fixed_t scalestep; // 0=none, 1=bottom, 2=top, 3=both int silhouette; // do not clip sprites above this fixed_t bsilheight; // do not clip sprites below this fixed_t tsilheight; // Pointers to lists for sprite clipping, // all three adjusted so [x1] is first value. short* sprtopclip; short* sprbottomclip; short* maskedtexturecol; } drawseg_t; // A vissprite_t is a thing // that will be drawn during a refresh. // I.e. a sprite object that is partly visible. typedef struct vissprite_s { // Doubly linked list. struct vissprite_s* prev; struct vissprite_s* next; int x1; int x2; // for line side calculation fixed_t gx; fixed_t gy; // global bottom / top for silhouette clipping fixed_t gz; fixed_t gzt; // horizontal position of x1 fixed_t startfrac; fixed_t scale; // negative if flipped fixed_t xiscale; fixed_t texturemid; int patch; // for color translation and shadow draw, // maxbright frames as well lighttable_t* colormap; int mobjflags; } vissprite_t; // // Sprites are patches with a special naming convention // so they can be recognized by R_InitSprites. // The base name is NNNNFx or NNNNFxFx, with // x indicating the rotation, x = 0, 1-7. // The sprite and frame specified by a thing_t // is range checked at run time. // A sprite is a patch_t that is assumed to represent // a three dimensional object and may have multiple // rotations pre drawn. // Horizontal flipping is used to save space, // thus NNNNF2F5 defines a mirrored patch. // Some sprites will only have one picture used // for all views: NNNNF0 // typedef struct { // If false use 0 for any position. // Note: as eight entries are available, // we might as well insert the same name eight times. boolean rotate; // Lump to use for view angles 0-7. short lump[8]; // Flip bit (1 = flip) to use for view angles 0-7. byte flip[8]; } spriteframe_t; // // A sprite definition: // a number of animation frames. // typedef struct { int numframes; spriteframe_t* spriteframes; } spritedef_t; // // Now what is a visplane, anyway? // typedef struct { fixed_t height; int picnum; int lightlevel; int minx; int maxx; // leave pads for [minx-1]/[maxx+1] byte pad1; // Here lies the rub for all // dynamic resize/change of resolution. byte top[SCREENWIDTH]; byte pad2; byte pad3; // See above. byte bottom[SCREENWIDTH]; byte pad4; } visplane_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/r_draw.c000066400000000000000000000565731257432200600230320ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The actual span/column drawing functions. // Here find the main potential for optimization, // e.g. inline assembly, different algorithms. // #include "doomdef.h" #include "deh_main.h" #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "r_local.h" // Needs access to LFB (guess what). #include "v_video.h" // State. #include "doomstat.h" // ? #define MAXWIDTH 1120 #define MAXHEIGHT 832 // status bar height at bottom of screen // haleyjd 08/31/10: Verified unmodified. #define SBARHEIGHT 32 // // All drawing to the view buffer is accomplished in this file. // The other refresh files only know about ccordinates, // not the architecture of the frame buffer. // Conveniently, the frame buffer is a linear one, // and we need only the base address, // and the total size == width*height*depth/8., // byte* viewimage; int viewwidth; int scaledviewwidth; int viewheight; int viewwindowx; int viewwindowy; byte* ylookup[MAXHEIGHT]; int columnofs[MAXWIDTH]; // Color tables for different players, // translate a limited part to another // (color ramps used for suit colors). // // [STRIFE] Unused. //byte translations[3][256]; // Backing buffer containing the bezel drawn around the screen and // surrounding background. static byte *background_buffer = NULL; // haleyjd 08/29/10: [STRIFE] Rogue added the ability to customize the view // border flat by storing it in the configuration file. char *back_flat = "F_PAVE01"; // // R_DrawColumn // Source is the top of the column to scale. // lighttable_t* dc_colormap; int dc_x; int dc_yl; int dc_yh; fixed_t dc_iscale; fixed_t dc_texturemid; // first pixel in a column (possibly virtual) byte* dc_source; // just for profiling int dccount; // // A column is a vertical slice/span from a wall texture that, // given the DOOM style restrictions on the view orientation, // will always have constant z depth. // Thus a special case loop for very fast rendering can // be used. It has also been used with Wolfenstein 3D. // void R_DrawColumn (void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; count = dc_yh - dc_yl; // Zero length, column does not exceed a pixel. if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); #endif // Framebuffer destination address. // Use ylookup LUT to avoid multiply with ScreenWidth. // Use columnofs LUT for subwindows? dest = ylookup[dc_yl] + columnofs[dc_x]; // Determine scaling, // which is the only mapping to be done. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Inner loop that does the actual texture mapping, // e.g. a DDA-lile scaling. // This is as fast as it gets. do { // Re-map color indices from wall texture column // using a lighting/special effects LUT. *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } // UNUSED. // Loop unrolled. #if 0 void R_DrawColumn (void) { int count; byte* source; byte* dest; byte* colormap; unsigned frac; unsigned fracstep; unsigned fracstep2; unsigned fracstep3; unsigned fracstep4; count = dc_yh - dc_yl + 1; source = dc_source; colormap = dc_colormap; dest = ylookup[dc_yl] + columnofs[dc_x]; fracstep = dc_iscale<<9; frac = (dc_texturemid + (dc_yl-centery)*dc_iscale)<<9; fracstep2 = fracstep+fracstep; fracstep3 = fracstep2+fracstep; fracstep4 = fracstep3+fracstep; while (count >= 8) { dest[0] = colormap[source[frac>>25]]; dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]]; dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]]; dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]]; frac += fracstep4; dest[SCREENWIDTH*4] = colormap[source[frac>>25]]; dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]]; dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]]; dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]]; frac += fracstep4; dest += SCREENWIDTH*8; count -= 8; } while (count > 0) { *dest = colormap[source[frac>>25]]; dest += SCREENWIDTH; frac += fracstep; count--; } } #endif // haleyjd 09/06/10 [STRIFE] Removed low detail // // Spectre/Invisibility. // // haleyjd 09/06/10: ]STRIFE] replaced fuzzdraw with translucency. // // R_DrawMVisTLColumn // // villsa [STRIFE] new function // Replacement for R_DrawFuzzColumn // void R_DrawMVisTLColumn(void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; // Adjust borders. Low... if (!dc_yl) dc_yl = 1; // .. and high. if (dc_yh == viewheight-1) dc_yh = viewheight - 2; count = dc_yh - dc_yl; // Zero length. if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); } #endif dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; do { byte src = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; byte col = xlatab[*dest + (src << 8)]; *dest = col; dest += SCREENWIDTH; frac += fracstep; } while(count--); } // // R_DrawTLColumn // // villsa [STRIFE] new function // Achieves a second translucency level using the same lookup table, // via inversion of the colors in the index computation. // void R_DrawTLColumn(void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; // Adjust borders. Low... if (!dc_yl) dc_yl = 1; // .. and high. if (dc_yh == viewheight-1) dc_yh = viewheight - 2; count = dc_yh - dc_yl; // Zero length. if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ("R_DrawFuzzColumn2: %i to %i at %i", dc_yl, dc_yh, dc_x); } #endif dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; do { byte src = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; byte col = xlatab[(*dest << 8) + src]; *dest = col; dest += SCREENWIDTH; frac += fracstep; } while(count--); } // // R_DrawTranslatedColumn // Used to draw player sprites // with the green colorramp mapped to others. // Could be used with different translation // tables, e.g. the lighter colored version // of the BaronOfHell, the HellKnight, uses // identical sprites, kinda brightened up. // byte* dc_translation; byte* translationtables; void R_DrawTranslatedColumn (void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ( "R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); } #endif dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Here we do an additional index re-mapping. do { // Translation tables are used // to map certain colorramps to other ones, // used with PLAY sprites. // Thus the "green" ramp of the player 0 sprite // is mapped to gray, red, black/indigo. *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; dest += SCREENWIDTH; frac += fracstep; } while (count--); } // haleyjd 09/06/10 [STRIFE] Removed low detail // // R_DrawTRTLColumn // // villsa [STRIFE] new function // Combines translucency and color translation. // void R_DrawTRTLColumn(void) { int count; byte* dest; fixed_t frac; fixed_t fracstep; count = dc_yh - dc_yl; if (count < 0) return; #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) { I_Error ( "R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); } #endif dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; // Here we do an additional index re-mapping. do { byte src = dc_colormap[dc_translation[dc_source[frac>>FRACBITS&127]]]; byte col = xlatab[(*dest << 8) + src]; *dest = col; dest += SCREENWIDTH; frac += fracstep; } while (count--); } // // R_InitTranslationTables // Creates the translation tables to map // the green color ramp to gray, brown, red. // Assumes a given structure of the PLAYPAL. // Could be read from a lump instead. // // haleyjd 08/26/10: [STRIFE] // * Added loading of XLATAB // void R_InitTranslationTables (void) { int i; byte col1, col2; // [STRIFE] Load xlatab. Here's how Rogue did it: // v7 = W_CacheLumpName("XLATAB", PU_CACHE); // note potential cache bug... // HIWORD(v8) = (Z_Malloc(131072, PU_STATIC, NULL) + 65535) >> 16; // LOWORD(v8) = 0; // aligning to a 64K boundary, as if this is Wolf3D. // xlatab = v8; // memcpy(v8, v7, 65536); // As you can see, they copypasta'd id's unnecessary 64K boundary alignment // from the colormap code. Since this doesn't accomplish anything, and isn't // strictly portable, all we need to do is this: // villsa [STRIFE] 09/26/10: load table through this function instead V_LoadXlaTable(); // villsa [STRIFE] allocate a larger size for translation tables translationtables = Z_Malloc (256*8, PU_STATIC, 0); col1 = 0xFA; col2 = 0xE0; // villsa [STRIFE] setup all translation tables for(i = 0; i < 256; i++) { if(i >= 0x80 && i <= 0x8f) { translationtables [i ] = (i & 0x0f) + 64; translationtables [i+ 256] = (i & 0x0f) - 80; translationtables [i+2*256] = (i & 0x0f) + 16; translationtables [i+3*256] = (i & 0x0f) + 48; translationtables [i+4*256] = (i & 0x0f) + 80; translationtables [i+5*256] = (i & 0x0f) + 96; translationtables [i+6*256] = (i & 0x0f) - 112; } else if(i >= 0x50 && i<= 0x5f) { translationtables [i ] = i; translationtables [i+ 256] = i; translationtables [i+2*256] = i; translationtables [i+3*256] = i; translationtables [i+4*256] = (i & 0x0f) + 0x80; translationtables [i+5*256] = (i & 0x0f) + 16; translationtables [i+6*256] = (i & 0x0f) + 64; } else if(i >= 0xd0 && i<= 0xdf) { translationtables [i ] = i; translationtables [i+ 256] = i; translationtables [i+2*256] = i; translationtables [i+3*256] = i; translationtables [i+4*256] = (i & 0x0f) - 80; translationtables [i+5*256] = (i & 0x0f) + 48; translationtables [i+6*256] = (i & 0x0f) + 16; } else if(i >= 0xc0 && i<= 0xcf) { translationtables [i ] = i; translationtables [i+ 256] = i; translationtables [i+2*256] = i; translationtables [i+3*256] = i; translationtables [i+4*256] = (i & 0x0f) - 96; translationtables [i+5*256] = (i & 0x0f) + 32; translationtables [i+6*256] = (i & 0x0f); // haleyjd 20110213: missing code: if(!(i & 0x0f)) translationtables[i+6*256] = 1; } else if(i >= 0xf7 && i<= 0xfb) { translationtables [i ] = col1; translationtables [i+ 256] = i; translationtables [i+2*256] = i; translationtables [i+3*256] = i; translationtables [i+4*256] = i; translationtables [i+5*256] = i; translationtables [i+6*256] = i; } else if(i >= 0xf1 && i<= 0xf6) { translationtables [i ] = (i & 0x0f) - 33; translationtables [i+ 256] = i; translationtables [i+2*256] = i; translationtables [i+3*256] = i; translationtables [i+4*256] = i; translationtables [i+5*256] = i; translationtables [i+6*256] = i; } else if(i >= 0x20 && i <= 0x3f) // haleyjd 20110213: fixed upper end { translationtables [i ] = col2; translationtables [i+ 256] = col2; translationtables [i+2*256] = (i & 0x0f) - 48; translationtables [i+3*256] = (i & 0x0f) - 48; translationtables [i+4*256] = col2; translationtables [i+5*256] = col2; translationtables [i+6*256] = col2; } else // Keep all other colors as is. { translationtables[i]= translationtables[i+256]= translationtables[i+2*256]= translationtables[i+3*256]= translationtables[i+4*256]= translationtables[i+5*256]= translationtables[i+6*256]=i; } ++col1; ++col2; } } // // R_DrawSpan // With DOOM style restrictions on view orientation, // the floors and ceilings consist of horizontal slices // or spans with constant z depth. // However, rotation around the world z axis is possible, // thus this mapping, while simpler and faster than // perspective correct texture mapping, has to traverse // the texture at an angle in all but a few cases. // In consequence, flats are not stored by column (like walls), // and the inner loop has to step in texture space u and v. // int ds_y; int ds_x1; int ds_x2; lighttable_t* ds_colormap; fixed_t ds_xfrac; fixed_t ds_yfrac; fixed_t ds_xstep; fixed_t ds_ystep; // start of a 64*64 tile image byte* ds_source; // just for profiling int dscount; // // Draws the actual span. void R_DrawSpan (void) { unsigned int position, step; byte *dest; int count; int spot; unsigned int xtemp, ytemp; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1<0 || ds_x2>=SCREENWIDTH || (unsigned)ds_y>SCREENHEIGHT) { I_Error( "R_DrawSpan: %i to %i at %i", ds_x1,ds_x2,ds_y); } // dscount++; #endif // Pack position and step variables into a single 32-bit integer, // with x in the top 16 bits and y in the bottom 16 bits. For // each 16-bit part, the top 6 bits are the integer part and the // bottom 10 bits are the fractional part of the pixel position. position = ((ds_xfrac << 10) & 0xffff0000) | ((ds_yfrac >> 6) & 0x0000ffff); step = ((ds_xstep << 10) & 0xffff0000) | ((ds_ystep >> 6) & 0x0000ffff); dest = ylookup[ds_y] + columnofs[ds_x1]; // We do not check for zero spans here? count = ds_x2 - ds_x1; do { // Calculate current texture index in u,v. ytemp = (position >> 4) & 0x0fc0; xtemp = (position >> 26); spot = xtemp | ytemp; // Lookup pixel from flat texture tile, // re-index using light/colormap. *dest++ = ds_colormap[ds_source[spot]]; position += step; } while (count--); } // UNUSED. // Loop unrolled by 4. #if 0 void R_DrawSpan (void) { unsigned position, step; byte* source; byte* colormap; byte* dest; unsigned count; usingned spot; unsigned value; unsigned temp; unsigned xtemp; unsigned ytemp; position = ((ds_xfrac<<10)&0xffff0000) | ((ds_yfrac>>6)&0xffff); step = ((ds_xstep<<10)&0xffff0000) | ((ds_ystep>>6)&0xffff); source = ds_source; colormap = ds_colormap; dest = ylookup[ds_y] + columnofs[ds_x1]; count = ds_x2 - ds_x1 + 1; while (count >= 4) { ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[0] = colormap[source[spot]]; ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[1] = colormap[source[spot]]; ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[2] = colormap[source[spot]]; ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; dest[3] = colormap[source[spot]]; count -= 4; dest += 4; } while (count > 0) { ytemp = position>>4; ytemp = ytemp & 4032; xtemp = position>>26; spot = xtemp | ytemp; position += step; *dest++ = colormap[source[spot]]; count--; } } #endif // // Again.. // void R_DrawSpanLow (void) { unsigned int position, step; unsigned int xtemp, ytemp; byte *dest; int count; int spot; #ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1<0 || ds_x2>=SCREENWIDTH || (unsigned)ds_y>SCREENHEIGHT) { I_Error( "R_DrawSpan: %i to %i at %i", ds_x1,ds_x2,ds_y); } // dscount++; #endif position = ((ds_xfrac << 10) & 0xffff0000) | ((ds_yfrac >> 6) & 0x0000ffff); step = ((ds_xstep << 10) & 0xffff0000) | ((ds_ystep >> 6) & 0x0000ffff); count = (ds_x2 - ds_x1); // Blocky mode, need to multiply by 2. ds_x1 <<= 1; ds_x2 <<= 1; dest = ylookup[ds_y] + columnofs[ds_x1]; do { // Calculate current texture index in u,v. ytemp = (position >> 4) & 0x0fc0; xtemp = (position >> 26); spot = xtemp | ytemp; // Lowres/blocky mode does it twice, // while scale is adjusted appropriately. *dest++ = ds_colormap[ds_source[spot]]; *dest++ = ds_colormap[ds_source[spot]]; position += step; } while (count--); } // // R_InitBuffer // Creats lookup tables that avoid // multiplies and other hazzles // for getting the framebuffer address // of a pixel to draw. // void R_InitBuffer ( int width, int height ) { int i; // Handle resize, // e.g. smaller view windows // with border and/or status bar. viewwindowx = (SCREENWIDTH-width) >> 1; // Column offset. For windows. for (i=0 ; i> 1; // Preclaculate all row offsets. for (i=0 ; i #include #include "doomdef.h" #include "doomstat.h" // villsa [STRIFE] #include "d_main.h" #include "m_bbox.h" #include "m_menu.h" #include "r_local.h" #include "r_sky.h" // Fineangles in the SCREENWIDTH wide window. #define FIELDOFVIEW 2048 int viewangleoffset; // increment every time a check is made int validcount = 1; lighttable_t* fixedcolormap; extern lighttable_t** walllights; int centerx; int centery; fixed_t centerxfrac; fixed_t centeryfrac; fixed_t projection; // just for profiling purposes int framecount; int sscount; int linecount; int loopcount; fixed_t viewx; fixed_t viewy; fixed_t viewz; int viewpitch; // villsa [STRIFE] angle_t viewangle; fixed_t viewcos; fixed_t viewsin; player_t* viewplayer; // 0 = high, 1 = low int detailshift; // // precalculated math tables // angle_t clipangle; // The viewangletox[viewangle + FINEANGLES/4] lookup // maps the visible view angles to screen X coordinates, // flattening the arc to a flat projection plane. // There will be many angles mapped to the same X. int viewangletox[FINEANGLES/2]; // The xtoviewangleangle[] table maps a screen pixel // to the lowest viewangle that maps back to x ranges // from clipangle to -clipangle. angle_t xtoviewangle[SCREENWIDTH+1]; lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; lighttable_t* scalelightfixed[MAXLIGHTSCALE]; lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ]; // bumped light from gun blasts int extralight; void (*colfunc) (void); void (*basecolfunc) (void); void (*fuzzcolfunc) (void); void (*transcolfunc) (void); void (*spanfunc) (void); // // R_AddPointToBox // Expand a given bbox // so that it encloses a given point. // void R_AddPointToBox ( int x, int y, fixed_t* box ) { if (x< box[BOXLEFT]) box[BOXLEFT] = x; if (x> box[BOXRIGHT]) box[BOXRIGHT] = x; if (y< box[BOXBOTTOM]) box[BOXBOTTOM] = y; if (y> box[BOXTOP]) box[BOXTOP] = y; } // // R_PointOnSide // Traverse BSP (sub) tree, // check point against partition plane. // Returns side 0 (front) or 1 (back). // int R_PointOnSide ( fixed_t x, fixed_t y, node_t* node ) { fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; if (!node->dx) { if (x <= node->x) return node->dy > 0; return node->dy < 0; } if (!node->dy) { if (y <= node->y) return node->dx < 0; return node->dx > 0; } dx = (x - node->x); dy = (y - node->y); // Try to quickly decide by looking at sign bits. if ( (node->dy ^ node->dx ^ dx ^ dy)&0x80000000 ) { if ( (node->dy ^ dx) & 0x80000000 ) { // (left is negative) return 1; } return 0; } left = FixedMul ( node->dy>>FRACBITS , dx ); right = FixedMul ( dy , node->dx>>FRACBITS ); if (right < left) { // front side return 0; } // back side return 1; } int R_PointOnSegSide ( fixed_t x, fixed_t y, seg_t* line ) { fixed_t lx; fixed_t ly; fixed_t ldx; fixed_t ldy; fixed_t dx; fixed_t dy; fixed_t left; fixed_t right; lx = line->v1->x; ly = line->v1->y; ldx = line->v2->x - lx; ldy = line->v2->y - ly; if (!ldx) { if (x <= lx) return ldy > 0; return ldy < 0; } if (!ldy) { if (y <= ly) return ldx < 0; return ldx > 0; } dx = (x - lx); dy = (y - ly); // Try to quickly decide by looking at sign bits. if ( (ldy ^ ldx ^ dx ^ dy)&0x80000000 ) { if ( (ldy ^ dx) & 0x80000000 ) { // (left is negative) return 1; } return 0; } left = FixedMul ( ldy>>FRACBITS , dx ); right = FixedMul ( dy , ldx>>FRACBITS ); if (right < left) { // front side return 0; } // back side return 1; } // // R_PointToAngle // To get a global angle from cartesian coordinates, // the coordinates are flipped until they are in // the first octant of the coordinate system, then // the y (<=x) is scaled and divided by x to get a // tangent (slope) value which is looked up in the // tantoangle[] table. // angle_t R_PointToAngle ( fixed_t x, fixed_t y ) { x -= viewx; y -= viewy; if ( (!x) && (!y) ) return 0; if (x>= 0) { // x >=0 if (y>= 0) { // y>= 0 if (x>y) { // octant 0 return tantoangle[ SlopeDiv(y,x)]; } else { // octant 1 return ANG90-1-tantoangle[ SlopeDiv(x,y)]; } } else { // y<0 y = -y; if (x>y) { // octant 8 return 0 - tantoangle[SlopeDiv(y,x)]; } else { // octant 7 return ANG270+tantoangle[ SlopeDiv(x,y)]; } } } else { // x<0 x = -x; if (y>= 0) { // y>= 0 if (x>y) { // octant 3 return ANG180-1-tantoangle[ SlopeDiv(y,x)]; } else { // octant 2 return ANG90+ tantoangle[ SlopeDiv(x,y)]; } } else { // y<0 y = -y; if (x>y) { // octant 4 return ANG180+tantoangle[ SlopeDiv(y,x)]; } else { // octant 5 return ANG270-1-tantoangle[ SlopeDiv(x,y)]; } } } return 0; } angle_t R_PointToAngle2 ( fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2 ) { viewx = x1; viewy = y1; return R_PointToAngle (x2, y2); } fixed_t R_PointToDist ( fixed_t x, fixed_t y ) { int angle; fixed_t dx; fixed_t dy; fixed_t temp; fixed_t dist; fixed_t frac; dx = abs(x - viewx); dy = abs(y - viewy); if (dy>dx) { temp = dx; dx = dy; dy = temp; } // Fix crashes in udm1.wad if (dx != 0) { frac = FixedDiv(dy, dx); } else { frac = 0; } angle = (tantoangle[frac>>DBITS]+ANG90) >> ANGLETOFINESHIFT; // use as cosine dist = FixedDiv (dx, finesine[angle] ); return dist; } // // R_InitPointToAngle // void R_InitPointToAngle (void) { // UNUSED - now getting from tables.c #if 0 int i; long t; float f; // // slope (tangent) to angle lookup // for (i=0 ; i<=SLOPERANGE ; i++) { f = atan( (float)i/SLOPERANGE )/(3.141592657*2); t = 0xffffffff*f; tantoangle[i] = t; } #endif } // // R_ScaleFromGlobalAngle // Returns the texture mapping scale // for the current line (horizontal span) // at the given angle. // rw_distance must be calculated first. // fixed_t R_ScaleFromGlobalAngle (angle_t visangle) { fixed_t scale; angle_t anglea; angle_t angleb; int sinea; int sineb; fixed_t num; int den; // UNUSED #if 0 { fixed_t dist; fixed_t z; fixed_t sinv; fixed_t cosv; sinv = finesine[(visangle-rw_normalangle)>>ANGLETOFINESHIFT]; dist = FixedDiv (rw_distance, sinv); cosv = finecosine[(viewangle-visangle)>>ANGLETOFINESHIFT]; z = abs(FixedMul (dist, cosv)); scale = FixedDiv(projection, z); return scale; } #endif anglea = ANG90 + (visangle-viewangle); angleb = ANG90 + (visangle-rw_normalangle); // both sines are allways positive sinea = finesine[anglea>>ANGLETOFINESHIFT]; sineb = finesine[angleb>>ANGLETOFINESHIFT]; num = FixedMul(projection,sineb)< num>>16) { scale = FixedDiv (num, den); if (scale > 64*FRACUNIT) scale = 64*FRACUNIT; else if (scale < 256) scale = 256; } else scale = 64*FRACUNIT; return scale; } // // R_InitTables // void R_InitTables (void) { // UNUSED: now getting from tables.c #if 0 int i; float a; float fv; int t; // viewangle tangent table for (i=0 ; i FRACUNIT*2) t = -1; else if (finetangent[i] < -FRACUNIT*2) t = viewwidth+1; else { t = FixedMul (finetangent[i], focallength); t = (centerxfrac - t+FRACUNIT-1)>>FRACBITS; if (t < -1) t = -1; else if (t>viewwidth+1) t = viewwidth+1; } viewangletox[i] = t; } // Scan viewangletox[] to generate xtoviewangle[]: // xtoviewangle will give the smallest view angle // that maps to x. for (x=0;x<=viewwidth;x++) { i = 0; while (viewangletox[i]>x) i++; xtoviewangle[x] = (i<>= LIGHTSCALESHIFT; level = startmap - scale/DISTMAP; if (level < 0) level = 0; if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS-1; zlight[i][j] = colormaps + level*256; } } } // // R_SetViewSize // Do not really change anything here, // because it might be in the middle of a refresh. // The change will take effect next refresh. // boolean setsizeneeded; int setblocks; int setdetail; void R_SetViewSize ( int blocks, int detail ) { setsizeneeded = true; setblocks = blocks; setdetail = detail; } // // R_ExecuteSetViewSize // void R_ExecuteSetViewSize (void) { fixed_t cosadj; fixed_t dy; int i; int j; int level; int startmap; setsizeneeded = false; if (setblocks == 11) { scaledviewwidth = SCREENWIDTH; viewheight = SCREENHEIGHT; } else { scaledviewwidth = setblocks*32; viewheight = (setblocks*168/10)&~7; } detailshift = setdetail; viewwidth = scaledviewwidth>>detailshift; // villsa [STRIFE] calculate centery from player's pitch centery = (setblocks*players[consoleplayer].pitch); centery = (unsigned int)(centery/10)+viewheight/2; centerx = viewwidth/2; centerxfrac = centerx< centery, accounts for up/down look dy = ((i - centery)<>ANGLETOFINESHIFT]); distscale[i] = FixedDiv (FRACUNIT,cosadj); } // Calculate the light levels to use // for each level / scale combination. for (i=0 ; i< LIGHTLEVELS ; i++) { startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS; for (j=0 ; j= NUMCOLORMAPS) level = NUMCOLORMAPS-1; scalelight[i][j] = colormaps + level*256; } } } // // R_Init // void R_Init (void) { R_InitData (); if(devparm) printf ("."); else D_IntroTick(); // [STRIFE] tick intro R_InitPointToAngle (); if(devparm) printf ("."); R_InitTables (); // viewwidth / viewheight / detailLevel are set by the defaults if(devparm) printf ("."); R_SetViewSize (screenblocks, detailLevel); R_InitPlanes (); if(devparm) printf ("."); R_InitLightTables (); if(devparm) printf ("."); else D_IntroTick(); R_InitSkyMap (); if(!devparm) D_IntroTick(); R_InitTranslationTables (); if(devparm) printf ("."); else D_IntroTick(); framecount = 0; } // // R_PointInSubsector // subsector_t* R_PointInSubsector ( fixed_t x, fixed_t y ) { node_t* node; int side; int nodenum; // single subsector is a special case if (!numnodes) return subsectors; nodenum = numnodes-1; while (! (nodenum & NF_SUBSECTOR) ) { node = &nodes[nodenum]; side = R_PointOnSide (x, y, node); nodenum = node->children[side]; } return &subsectors[nodenum & ~NF_SUBSECTOR]; } // // R_SetupPitch // villsa [STRIFE] new function // Calculate centery/centeryfrac for player viewpitch // void R_SetupPitch(player_t* player) { int pitchfrac; int i = 0; if(viewpitch != player->pitch) { viewpitch = player->pitch; pitchfrac = (setblocks * player->pitch) / 10; centery = pitchfrac + viewheight / 2; centeryfrac = centery << FRACBITS; for(i = 0; i < viewheight; i++) { yslope[i] = FixedDiv(viewwidth / 2 * FRACUNIT, abs(((i - centery) << FRACBITS) + (FRACUNIT/2))); } } } // // R_SetupFrame // void R_SetupFrame (player_t* player) { int i; R_SetupPitch(player); // villsa [STRIFE] viewplayer = player; viewx = player->mo->x; viewy = player->mo->y; viewangle = player->mo->angle + viewangleoffset; extralight = player->extralight; viewz = player->viewz; viewsin = finesine[viewangle>>ANGLETOFINESHIFT]; viewcos = finecosine[viewangle>>ANGLETOFINESHIFT]; sscount = 0; if (player->fixedcolormap) { fixedcolormap = colormaps + player->fixedcolormap*256*sizeof(lighttable_t); walllights = scalelightfixed; for (i=0 ; i #include #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "doomdef.h" #include "doomstat.h" #include "r_local.h" #include "r_sky.h" planefunction_t floorfunc; planefunction_t ceilingfunc; // // opening // // Here comes the obnoxious "visplane". // haleyjd 08/29/10: [STRIFE] MAXVISPLANES increased to 200 #define MAXVISPLANES 200 visplane_t visplanes[MAXVISPLANES]; visplane_t* lastvisplane; visplane_t* floorplane; visplane_t* ceilingplane; // ? #define MAXOPENINGS SCREENWIDTH*64 short openings[MAXOPENINGS]; short* lastopening; // // Clip values are the solid pixel bounding the range. // floorclip starts out SCREENHEIGHT // ceilingclip starts out -1 // short floorclip[SCREENWIDTH]; short ceilingclip[SCREENWIDTH]; // // spanstart holds the start of a plane span // initialized to 0 at start // int spanstart[SCREENHEIGHT]; int spanstop[SCREENHEIGHT]; // // texture mapping // lighttable_t** planezlight; fixed_t planeheight; fixed_t yslope[SCREENHEIGHT]; fixed_t distscale[SCREENWIDTH]; fixed_t basexscale; fixed_t baseyscale; fixed_t cachedheight[SCREENHEIGHT]; fixed_t cacheddistance[SCREENHEIGHT]; fixed_t cachedxstep[SCREENHEIGHT]; fixed_t cachedystep[SCREENHEIGHT]; // // R_InitPlanes // Only at game startup. // void R_InitPlanes (void) { // Doh! } // // R_MapPlane // // Uses global vars: // planeheight // ds_source // basexscale // baseyscale // viewx // viewy // // BASIC PRIMITIVE // void R_MapPlane ( int y, int x1, int x2 ) { angle_t angle; fixed_t distance; fixed_t length; unsigned index; #ifdef RANGECHECK if (x2 < x1 || x1 < 0 || x2 >= viewwidth || y > viewheight) { I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y); } #endif if (planeheight != cachedheight[y]) { cachedheight[y] = planeheight; distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]); ds_xstep = cachedxstep[y] = FixedMul (distance,basexscale); ds_ystep = cachedystep[y] = FixedMul (distance,baseyscale); } else { distance = cacheddistance[y]; ds_xstep = cachedxstep[y]; ds_ystep = cachedystep[y]; } length = FixedMul (distance,distscale[x1]); angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; ds_xfrac = viewx + FixedMul(finecosine[angle], length); ds_yfrac = -viewy - FixedMul(finesine[angle], length); if (fixedcolormap) ds_colormap = fixedcolormap; else { index = distance >> LIGHTZSHIFT; if (index >= MAXLIGHTZ ) index = MAXLIGHTZ-1; ds_colormap = planezlight[index]; } ds_y = y; ds_x1 = x1; ds_x2 = x2; // high or low detail spanfunc (); } // // R_ClearPlanes // At begining of frame. // void R_ClearPlanes (void) { int i; angle_t angle; // opening / clipping determination for (i=0 ; i>ANGLETOFINESHIFT; // scale will be unit scale at SCREENWIDTH/2 distance basexscale = FixedDiv (finecosine[angle],centerxfrac); baseyscale = -FixedDiv (finesine[angle],centerxfrac); } // // R_FindPlane // visplane_t* R_FindPlane ( fixed_t height, int picnum, int lightlevel ) { visplane_t* check; if (picnum == skyflatnum) { height = 0; // all skys map together lightlevel = 0; } for (check=visplanes; checkheight && picnum == check->picnum && lightlevel == check->lightlevel) { break; } } if (check < lastvisplane) return check; if (lastvisplane - visplanes == MAXVISPLANES) I_Error ("R_FindPlane: no more visplanes"); lastvisplane++; check->height = height; check->picnum = picnum; check->lightlevel = lightlevel; check->minx = SCREENWIDTH; check->maxx = -1; memset (check->top,0xff,sizeof(check->top)); return check; } // // R_CheckPlane // visplane_t* R_CheckPlane ( visplane_t* pl, int start, int stop ) { int intrl; int intrh; int unionl; int unionh; int x; if (start < pl->minx) { intrl = pl->minx; unionl = start; } else { unionl = pl->minx; intrl = start; } if (stop > pl->maxx) { intrh = pl->maxx; unionh = stop; } else { unionh = pl->maxx; intrh = stop; } for (x=intrl ; x<= intrh ; x++) if (pl->top[x] != 0xff) break; if (x > intrh) { pl->minx = unionl; pl->maxx = unionh; // use the same one return pl; } // make a new visplane lastvisplane->height = pl->height; lastvisplane->picnum = pl->picnum; lastvisplane->lightlevel = pl->lightlevel; pl = lastvisplane++; pl->minx = start; pl->maxx = stop; memset (pl->top,0xff,sizeof(pl->top)); return pl; } // // R_MakeSpans // void R_MakeSpans ( int x, int t1, int b1, int t2, int b2 ) { while (t1 < t2 && t1<=b1) { R_MapPlane (t1,spanstart[t1],x-1); t1++; } while (b1 > b2 && b1>=t1) { R_MapPlane (b1,spanstart[b1],x-1); b1--; } while (t2 < t1 && t2<=b2) { spanstart[t2] = x; t2++; } while (b2 > b1 && b2>=t2) { spanstart[b2] = x; b2--; } } // // R_DrawPlanes // At the end of each frame. // void R_DrawPlanes (void) { visplane_t* pl; int light; int x; int stop; int angle; int lumpnum; #ifdef RANGECHECK if (ds_p - drawsegs > MAXDRAWSEGS) I_Error ("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs); if (lastvisplane - visplanes > MAXVISPLANES) I_Error ("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes); if (lastopening - openings > MAXOPENINGS) I_Error ("R_DrawPlanes: opening overflow (%i)", lastopening - openings); #endif for (pl = visplanes ; pl < lastvisplane ; pl++) { if (pl->minx > pl->maxx) continue; // sky flat if (pl->picnum == skyflatnum) { dc_iscale = pspriteiscale>>detailshift; // Sky is allways drawn full bright, // i.e. colormaps[0] is used. // Because of this hack, sky is not affected // by INVUL inverse mapping. dc_colormap = colormaps; dc_texturemid = skytexturemid; for (x=pl->minx ; x <= pl->maxx ; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; if (dc_yl <= dc_yh) { angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; dc_x = x; dc_source = R_GetColumn(skytexture, angle); colfunc (); } } continue; } // regular flat lumpnum = firstflat + flattranslation[pl->picnum]; ds_source = W_CacheLumpNum(lumpnum, PU_STATIC); planeheight = abs(pl->height-viewz); light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight; if (light >= LIGHTLEVELS) light = LIGHTLEVELS-1; if (light < 0) light = 0; planezlight = zlight[light]; pl->top[pl->maxx+1] = 0xff; pl->top[pl->minx-1] = 0xff; stop = pl->maxx + 1; for (x=pl->minx ; x<= stop ; x++) { R_MakeSpans(x,pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x]); } W_ReleaseLumpNum(lumpnum); } } chocolate-doom-chocolate-doom-2.2.1/src/strife/r_plane.h000066400000000000000000000026271257432200600231700ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh, visplane stuff (floor, ceilings). // #ifndef __R_PLANE__ #define __R_PLANE__ #include "r_data.h" // Visplane related. extern short* lastopening; typedef void (*planefunction_t) (int top, int bottom); extern planefunction_t floorfunc; extern planefunction_t ceilingfunc_t; extern short floorclip[SCREENWIDTH]; extern short ceilingclip[SCREENWIDTH]; extern fixed_t yslope[SCREENHEIGHT]; extern fixed_t distscale[SCREENWIDTH]; void R_InitPlanes (void); void R_ClearPlanes (void); void R_MapPlane ( int y, int x1, int x2 ); void R_MakeSpans ( int x, int t1, int b1, int t2, int b2 ); void R_DrawPlanes (void); visplane_t* R_FindPlane ( fixed_t height, int picnum, int lightlevel ); visplane_t* R_CheckPlane ( visplane_t* pl, int start, int stop ); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/r_segs.c000066400000000000000000000416251257432200600230260ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // All the clipping: columns, horizontal spans, sky columns. // #include #include #include "i_system.h" #include "doomdef.h" #include "doomstat.h" #include "r_local.h" #include "r_sky.h" // OPTIMIZE: closed two sided lines as single sided // True if any of the segs textures might be visible. boolean segtextured; // False if the back side is the same plane. boolean markfloor; boolean markceiling; boolean maskedtexture; int toptexture; int bottomtexture; int midtexture; angle_t rw_normalangle; // angle to line origin int rw_angle1; // // regular wall // int rw_x; int rw_stopx; angle_t rw_centerangle; fixed_t rw_offset; fixed_t rw_distance; fixed_t rw_scale; fixed_t rw_scalestep; fixed_t rw_midtexturemid; fixed_t rw_toptexturemid; fixed_t rw_bottomtexturemid; int worldtop; int worldbottom; int worldhigh; int worldlow; fixed_t pixhigh; fixed_t pixlow; fixed_t pixhighstep; fixed_t pixlowstep; fixed_t topfrac; fixed_t topstep; fixed_t bottomfrac; fixed_t bottomstep; lighttable_t** walllights; short* maskedtexturecol; // // R_RenderMaskedSegRange // void R_RenderMaskedSegRange ( drawseg_t* ds, int x1, int x2 ) { unsigned index; column_t* col; int lightnum; int texnum; // Calculate light table. // Use different light tables // for horizontal / vertical / diagonal. Diagonal? // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; frontsector = curline->frontsector; backsector = curline->backsector; texnum = texturetranslation[curline->sidedef->midtexture]; lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight; if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS-1]; else walllights = scalelight[lightnum]; maskedtexturecol = ds->maskedtexturecol; rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; mfloorclip = ds->sprbottomclip; mceilingclip = ds->sprtopclip; // find positioning if (curline->linedef->flags & ML_DONTPEGBOTTOM) { dc_texturemid = frontsector->floorheight > backsector->floorheight ? frontsector->floorheight : backsector->floorheight; dc_texturemid = dc_texturemid + textureheight[texnum] - viewz; } else { dc_texturemid =frontsector->ceilingheightceilingheight ? frontsector->ceilingheight : backsector->ceilingheight; dc_texturemid = dc_texturemid - viewz; } dc_texturemid += curline->sidedef->rowoffset; if (fixedcolormap) dc_colormap = fixedcolormap; // villsa [STRIFE] render as transparent (25% or 75%?) if(curline->linedef->flags & ML_TRANSPARENT1) colfunc = fuzzcolfunc; // villsa [STRIFE] render as transparent (25% or 75%?) if(curline->linedef->flags & ML_TRANSPARENT2) colfunc = R_DrawMVisTLColumn; // draw the columns for (dc_x = x1 ; dc_x <= x2 ; dc_x++) { // calculate lighting if (maskedtexturecol[dc_x] != SHRT_MAX) { if (!fixedcolormap) { index = spryscale>>LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE ) index = MAXLIGHTSCALE-1; dc_colormap = walllights[index]; } sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); dc_iscale = 0xffffffffu / (unsigned)spryscale; // draw the texture col = (column_t *)( (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3); // villsa [STRIFE] added 0 argument R_DrawMaskedColumn (col, 0); maskedtexturecol[dc_x] = SHRT_MAX; } spryscale += rw_scalestep; } colfunc = basecolfunc; // villsa [STRIFE] reset draw routines } // // R_RenderSegLoop // Draws zero, one, or two textures (and possibly a masked // texture) for walls. // Can draw or mark the starting pixel of floor and ceiling // textures. // CALLED: CORE LOOPING ROUTINE. // #define HEIGHTBITS 12 #define HEIGHTUNIT (1<>HEIGHTBITS; // no space above wall? if (yl < ceilingclip[rw_x]+1) yl = ceilingclip[rw_x]+1; if (markceiling) { top = ceilingclip[rw_x]+1; bottom = yl-1; if (bottom >= floorclip[rw_x]) bottom = floorclip[rw_x]-1; if (top <= bottom) { ceilingplane->top[rw_x] = top; ceilingplane->bottom[rw_x] = bottom; } } yh = bottomfrac>>HEIGHTBITS; if (yh >= floorclip[rw_x]) yh = floorclip[rw_x]-1; if (markfloor) { top = yh+1; bottom = floorclip[rw_x]-1; if (top <= ceilingclip[rw_x]) top = ceilingclip[rw_x]+1; if (top <= bottom) { floorplane->top[rw_x] = top; floorplane->bottom[rw_x] = bottom; } } // texturecolumn and lighting are independent of wall tiers if (segtextured) { // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT; texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance); texturecolumn >>= FRACBITS; // calculate lighting index = rw_scale>>LIGHTSCALESHIFT; if (index >= MAXLIGHTSCALE ) index = MAXLIGHTSCALE-1; dc_colormap = walllights[index]; dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned)rw_scale; } else { // purely to shut up the compiler texturecolumn = 0; } // draw the wall tiers if (midtexture) { // single sided line dc_yl = yl; dc_yh = yh; dc_texturemid = rw_midtexturemid; dc_source = R_GetColumn(midtexture,texturecolumn); colfunc (); ceilingclip[rw_x] = viewheight; floorclip[rw_x] = -1; } else { // two sided line if (toptexture) { // top wall mid = pixhigh>>HEIGHTBITS; pixhigh += pixhighstep; if (mid >= floorclip[rw_x]) mid = floorclip[rw_x]-1; if (mid >= yl) { dc_yl = yl; dc_yh = mid; dc_texturemid = rw_toptexturemid; dc_source = R_GetColumn(toptexture,texturecolumn); colfunc (); ceilingclip[rw_x] = mid; } else ceilingclip[rw_x] = yl-1; } else { // no top wall if (markceiling) ceilingclip[rw_x] = yl-1; } if (bottomtexture) { // bottom wall mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS; pixlow += pixlowstep; // no space above wall? if (mid <= ceilingclip[rw_x]) mid = ceilingclip[rw_x]+1; if (mid <= yh) { dc_yl = mid; dc_yh = yh; dc_texturemid = rw_bottomtexturemid; dc_source = R_GetColumn(bottomtexture, texturecolumn); colfunc (); floorclip[rw_x] = mid; } else floorclip[rw_x] = yh+1; } else { // no bottom wall if (markfloor) floorclip[rw_x] = yh+1; } if (maskedtexture) { // save texturecol // for backdrawing of masked mid texture maskedtexturecol[rw_x] = texturecolumn; } } rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; } } // // R_StoreWallRange // A wall segment will be drawn // between start and stop pixels (inclusive). // void R_StoreWallRange ( int start, int stop ) { fixed_t hyp; fixed_t sineval; angle_t distangle, offsetangle; fixed_t vtop; int lightnum; // don't overflow and crash if (ds_p == &drawsegs[MAXDRAWSEGS]) return; #ifdef RANGECHECK if (start >=viewwidth || start > stop) I_Error ("Bad R_RenderWallRange: %i to %i", start , stop); #endif sidedef = curline->sidedef; linedef = curline->linedef; // mark the segment as visible for auto map linedef->flags |= ML_MAPPED; // calculate rw_distance for scale calculation rw_normalangle = curline->angle + ANG90; offsetangle = abs(rw_normalangle-rw_angle1); if (offsetangle > ANG90) offsetangle = ANG90; distangle = ANG90 - offsetangle; hyp = R_PointToDist (curline->v1->x, curline->v1->y); sineval = finesine[distangle>>ANGLETOFINESHIFT]; rw_distance = FixedMul (hyp, sineval); ds_p->x1 = rw_x = start; ds_p->x2 = stop; ds_p->curline = curline; rw_stopx = stop+1; // calculate scale at both ends and step ds_p->scale1 = rw_scale = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]); if (stop > start ) { ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]); ds_p->scalestep = rw_scalestep = (ds_p->scale2 - rw_scale) / (stop-start); } else { // UNUSED: try to fix the stretched line bug #if 0 if (rw_distance < FRACUNIT/2) { fixed_t trx,try; fixed_t gxt,gyt; trx = curline->v1->x - viewx; try = curline->v1->y - viewy; gxt = FixedMul(trx,viewcos); gyt = -FixedMul(try,viewsin); ds_p->scale1 = FixedDiv(projection, gxt-gyt)<scale2 = ds_p->scale1; } // calculate texture boundaries // and decide if floor / ceiling marks are needed worldtop = frontsector->ceilingheight - viewz; worldbottom = frontsector->floorheight - viewz; midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; if (!backsector) { // single sided line midtexture = texturetranslation[sidedef->midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; if (linedef->flags & ML_DONTPEGBOTTOM) { vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; // bottom of texture at bottom rw_midtexturemid = vtop - viewz; } else { // top of texture at top rw_midtexturemid = worldtop; } rw_midtexturemid += sidedef->rowoffset; ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->tsilheight = INT_MIN; } else { // two sided line ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; if (frontsector->floorheight > backsector->floorheight) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = frontsector->floorheight; } else if (backsector->floorheight > viewz) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT_MAX; // ds_p->sprbottomclip = negonearray; } if (frontsector->ceilingheight < backsector->ceilingheight) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = frontsector->ceilingheight; } else if (backsector->ceilingheight < viewz) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; // ds_p->sprtopclip = screenheightarray; } if (backsector->ceilingheight <= frontsector->floorheight) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (backsector->floorheight >= frontsector->ceilingheight) { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT_MIN; ds_p->silhouette |= SIL_TOP; } worldhigh = backsector->ceilingheight - viewz; worldlow = backsector->floorheight - viewz; // hack to allow height changes in outdoor areas if (frontsector->ceilingpic == skyflatnum && backsector->ceilingpic == skyflatnum) { worldtop = worldhigh; } if (worldlow != worldbottom || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel) { markfloor = true; } else { // same plane on both sides markfloor = false; } if (worldhigh != worldtop || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel) { markceiling = true; } else { // same plane on both sides markceiling = false; } if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) { // closed door markceiling = markfloor = true; } if (worldhigh < worldtop) { // top texture toptexture = texturetranslation[sidedef->toptexture]; if (linedef->flags & ML_DONTPEGTOP) { // top of texture at top rw_toptexturemid = worldtop; } else { vtop = backsector->ceilingheight + textureheight[sidedef->toptexture]; // bottom of texture rw_toptexturemid = vtop - viewz; } } if (worldlow > worldbottom) { // bottom texture bottomtexture = texturetranslation[sidedef->bottomtexture]; if (linedef->flags & ML_DONTPEGBOTTOM ) { // bottom of texture at bottom // top of texture at top rw_bottomtexturemid = worldtop; } else // top of texture at top rw_bottomtexturemid = worldlow; } rw_toptexturemid += sidedef->rowoffset; rw_bottomtexturemid += sidedef->rowoffset; // allocate space for masked texture tables if (sidedef->midtexture) { // masked midtexture maskedtexture = true; ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; lastopening += rw_stopx - rw_x; } } // calculate rw_offset (only needed for textured lines) segtextured = midtexture | toptexture | bottomtexture | maskedtexture; if (segtextured) { offsetangle = rw_normalangle-rw_angle1; if (offsetangle > ANG180) offsetangle = 0 - offsetangle; if (offsetangle > ANG90) offsetangle = ANG90; sineval = finesine[offsetangle >>ANGLETOFINESHIFT]; rw_offset = FixedMul (hyp, sineval); if (rw_normalangle-rw_angle1 < ANG180) rw_offset = -rw_offset; rw_offset += sidedef->textureoffset + curline->offset; rw_centerangle = ANG90 + viewangle - rw_normalangle; // calculate light table // use different light tables // for horizontal / vertical / diagonal // OPTIMIZE: get rid of LIGHTSEGSHIFT globally if (!fixedcolormap) { lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight; if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS-1]; else walllights = scalelight[lightnum]; } } // if a floor / ceiling plane is on the wrong side // of the view plane, it is definitely invisible // and doesn't need to be marked. if (frontsector->floorheight >= viewz) { // above view plane markfloor = false; } if (frontsector->ceilingheight <= viewz && frontsector->ceilingpic != skyflatnum) { // below view plane markceiling = false; } // calculate incremental stepping values for texture edges worldtop >>= 4; worldbottom >>= 4; topstep = -FixedMul (rw_scalestep, worldtop); topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); bottomstep = -FixedMul (rw_scalestep,worldbottom); bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); if (backsector) { worldhigh >>= 4; worldlow >>= 4; if (worldhigh < worldtop) { pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); pixhighstep = -FixedMul (rw_scalestep,worldhigh); } if (worldlow > worldbottom) { pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); pixlowstep = -FixedMul (rw_scalestep,worldlow); } } // render it if (markceiling) ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); if (markfloor) floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); R_RenderSegLoop (); // save sprite clipping info if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) { memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start)); ds_p->sprtopclip = lastopening - start; lastopening += rw_stopx - start; } if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) { memcpy (lastopening, floorclip+start, 2*(rw_stopx-start)); ds_p->sprbottomclip = lastopening - start; lastopening += rw_stopx - start; } if (maskedtexture && !(ds_p->silhouette&SIL_TOP)) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; } if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; ds_p->bsilheight = INT_MAX; } ds_p++; } chocolate-doom-chocolate-doom-2.2.1/src/strife/r_segs.h000066400000000000000000000014141257432200600230230ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh module, drawing LineSegs from BSP. // #ifndef __R_SEGS__ #define __R_SEGS__ void R_RenderMaskedSegRange ( drawseg_t* ds, int x1, int x2 ); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/r_sky.c000066400000000000000000000024511257432200600226650ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Sky rendering. The DOOM sky is a texture map like any // wall, wrapping around. A 1024 columns equal 360 degrees. // The default sky map is 256 columns and repeats 4 times // on a 320 screen? // // // Needed for FRACUNIT. #include "m_fixed.h" // Needed for Flat retrieval. #include "r_data.h" #include "r_sky.h" // // sky mapping // int skyflatnum; int skytexture; int skytexturemid; // // R_InitSkyMap // Called whenever the view size changes. // void R_InitSkyMap (void) { // haleyjd 10/03/10: [STRIFE] Sky is set here, not in G_DoLoadLevel. // Also skytexturemid changed from 100 to 199. skyflatnum = R_FlatNumForName ( SKYFLATNAME ); skytexturemid = 199*FRACUNIT; } chocolate-doom-chocolate-doom-2.2.1/src/strife/r_sky.h000066400000000000000000000016701257432200600226740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Sky rendering. // #ifndef __R_SKY__ #define __R_SKY__ // SKY, store the number for name. #define SKYFLATNAME "F_SKY001" // villsa [STRIFE] // The sky map is 256*128*4 maps. #define ANGLETOSKYSHIFT 22 extern int skytexture; extern int skytexturemid; // Called whenever the view size changes. void R_InitSkyMap (void); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/r_state.h000066400000000000000000000044541257432200600232110ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh/render internal state variables (global). // #ifndef __R_STATE__ #define __R_STATE__ // Need data structure definitions. #include "d_player.h" #include "r_data.h" // // Refresh internal data structures, // for rendering. // // needed for texture pegging extern fixed_t* textureheight; // needed for pre rendering (fracs) extern fixed_t* spritewidth; extern fixed_t* spriteoffset; extern fixed_t* spritetopoffset; extern lighttable_t* colormaps; extern int viewwidth; extern int scaledviewwidth; extern int viewheight; extern int firstflat; // for global animation extern int* flattranslation; extern int* texturetranslation; // Sprite.... extern int firstspritelump; extern int lastspritelump; extern int numspritelumps; // // Lookup tables for map data. // extern int numsprites; extern spritedef_t* sprites; extern int numvertexes; extern vertex_t* vertexes; extern int numsegs; extern seg_t* segs; extern int numsectors; extern sector_t* sectors; extern int numsubsectors; extern subsector_t* subsectors; extern int numnodes; extern node_t* nodes; extern int numlines; extern line_t* lines; extern int numsides; extern side_t* sides; // // POV data. // extern fixed_t viewx; extern fixed_t viewy; extern fixed_t viewz; extern angle_t viewangle; extern player_t* viewplayer; // ? extern angle_t clipangle; extern int viewangletox[FINEANGLES/2]; extern angle_t xtoviewangle[SCREENWIDTH+1]; //extern fixed_t finetangent[FINEANGLES/2]; extern fixed_t rw_distance; extern angle_t rw_normalangle; // angle to line origin extern int rw_angle1; // Segs count? extern int sscount; extern visplane_t* floorplane; extern visplane_t* ceilingplane; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/r_things.c000066400000000000000000000564461257432200600233700ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh of things, i.e. objects represented by sprites. // #include #include #include "deh_main.h" #include "doomdef.h" #include "i_swap.h" #include "i_system.h" #include "z_zone.h" #include "w_wad.h" #include "r_local.h" #include "doomstat.h" // haleyjd #include "p_local.h" #define MINZ (FRACUNIT*4) #define BASEYCENTER 100 //void R_DrawColumn (void); //void R_DrawFuzzColumn (void); typedef struct { int x1; int x2; int column; int topclip; int bottomclip; } maskdraw_t; // // Sprite rotation 0 is facing the viewer, // rotation 1 is one angle turn CLOCKWISE around the axis. // This is not the same as the angle, // which increases counter clockwise (protractor). // There was a lot of stuff grabbed wrong, so I changed it... // fixed_t pspritescale; fixed_t pspriteiscale; lighttable_t** spritelights; // constant arrays // used for psprite clipping and initializing clipping short negonearray[SCREENWIDTH]; short screenheightarray[SCREENWIDTH]; // // INITIALIZATION FUNCTIONS // // variables used to look up // and range check thing_t sprites patches spritedef_t* sprites; int numsprites; spriteframe_t sprtemp[29]; int maxframe; char* spritename; // // R_InstallSpriteLump // Local function for R_InitSprites. // void R_InstallSpriteLump ( int lump, unsigned frame, unsigned rotation, boolean flipped ) { int r; if (frame >= 29 || rotation > 8) I_Error("R_InstallSpriteLump: " "Bad frame characters in lump %i", lump); if ((int)frame > maxframe) maxframe = frame; if (rotation == 0) { // the lump should be used for all rotations if (sprtemp[frame].rotate == false) I_Error ("R_InitSprites: Sprite %s frame %c has " "multip rot=0 lump", spritename, 'A'+frame); if (sprtemp[frame].rotate == true) I_Error ("R_InitSprites: Sprite %s frame %c has rotations " "and a rot=0 lump", spritename, 'A'+frame); sprtemp[frame].rotate = false; for (r=0 ; r<8 ; r++) { sprtemp[frame].lump[r] = lump - firstspritelump; sprtemp[frame].flip[r] = (byte)flipped; } return; } // the lump is only used for one rotation if (sprtemp[frame].rotate == false) I_Error ("R_InitSprites: Sprite %s frame %c has rotations " "and a rot=0 lump", spritename, 'A'+frame); sprtemp[frame].rotate = true; // make 0 based rotation--; if (sprtemp[frame].lump[rotation] != -1) I_Error ("R_InitSprites: Sprite %s : %c : %c " "has two lumps mapped to it", spritename, 'A'+frame, '1'+rotation); sprtemp[frame].lump[rotation] = lump - firstspritelump; sprtemp[frame].flip[rotation] = (byte)flipped; } // // R_InitSpriteDefs // Pass a null terminated list of sprite names // (4 chars exactly) to be used. // Builds the sprite rotation matrixes to account // for horizontally flipped sprites. // Will report an error if the lumps are inconsistant. // Only called at startup. // // Sprite lump names are 4 characters for the actor, // a letter for the frame, and a number for the rotation. // A sprite that is flippable will have an additional // letter/number appended. // The rotation character can be 0 to signify no rotations. // void R_InitSpriteDefs (char** namelist) { char** check; int i; int l; int frame; int rotation; int start; int end; int patched; // count the number of sprite names check = namelist; while (*check != NULL) check++; numsprites = check-namelist; if (!numsprites) return; sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL); start = firstspritelump-1; end = lastspritelump+1; // scan all the lump names for each of the names, // noting the highest frame letter. // Just compare 4 characters as ints for (i=0 ; itopdelta != 0xff ; ) { // calculate unclipped screen coordinates // for post topscreen = sprtopscreen + spryscale*column->topdelta; bottomscreen = topscreen + spryscale*column->length; dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS; if (dc_yh >= mfloorclip[dc_x]) dc_yh = mfloorclip[dc_x]-1; if (dc_yl <= mceilingclip[dc_x]) dc_yl = mceilingclip[dc_x]+1; // villsa [STRIFE] checks for clipping if(baseclip) { if(dc_yh > baseclip) dc_yh = baseclip; } if (dc_yl <= dc_yh) { dc_source = (byte *)column + 3; dc_texturemid = basetexturemid - (column->topdelta<topdelta; // Drawn by either R_DrawColumn // or (SHADOW) R_DrawFuzzColumn. colfunc (); } column = (column_t *)( (byte *)column + column->length + 4); } dc_texturemid = basetexturemid; } // // R_DrawVisSprite // mfloorclip and mceilingclip should also be set. // void R_DrawVisSprite ( vissprite_t* vis, int x1, int x2 ) { column_t* column; int texturecolumn; fixed_t frac; patch_t* patch; int clip; // villsa [STRIFE] int translation; // villsa [STRIFE] patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE); dc_colormap = vis->colormap; // villsa [STRIFE] // haleyjd 09/06/10: updated MF_TRANSLATION for Strife translation = vis->mobjflags & MF_TRANSLATION; // villsa [STRIFE] unused /*if (!dc_colormap) { // NULL colormap = shadow draw colfunc = fuzzcolfunc; }*/ // villsa [STRIFE] Handle the two types of translucency if(vis->mobjflags & MF_SHADOW) { if(!translation) { if(vis->mobjflags & MF_MVIS) colfunc = R_DrawMVisTLColumn; else colfunc = fuzzcolfunc; } else { colfunc = R_DrawTRTLColumn; dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8)); } } else if(vis->mobjflags & MF_MVIS) { // haleyjd 20141215: [STRIFE] Objects which are *only* MF_MVIS (players // using double Shadow Armors, in particular) are totally invisible. // Upstreamed after discovered in SVE. Note this causes a // vanilla-accurate glitch with Shadow Acolytes - if they die while // MF_MVIS is set, A_Fall fails to remove it and their corpse will // completely disappear (that's also fixed in SVE, but not here). return; } else if(translation) // villsa [STRIFE] new translation tables { colfunc = transcolfunc; dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8)); } dc_iscale = abs(vis->xiscale)>>detailshift; dc_texturemid = vis->texturemid; frac = vis->startfrac; spryscale = vis->scale; sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale); // villsa [STRIFE] clip sprite's feet if needed if(vis->mobjflags & MF_FEETCLIPPED) { sprbotscreen = sprtopscreen + FixedMul(spryscale, SHORT(patch->height) << FRACBITS); clip = (sprbotscreen - FixedMul(10*FRACUNIT, spryscale)) >> FRACBITS; } else clip = 0; for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale) { texturecolumn = frac>>FRACBITS; #ifdef RANGECHECK if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) I_Error ("R_DrawSpriteRange: bad texturecolumn"); #endif column = (column_t *) ((byte *)patch + LONG(patch->columnofs[texturecolumn])); R_DrawMaskedColumn (column, clip); // villsa [STRIFE] clip argument } colfunc = basecolfunc; } // // R_ProjectSprite // Generates a vissprite for a thing // if it might be visible. // void R_ProjectSprite (mobj_t* thing) { fixed_t tr_x; fixed_t tr_y; fixed_t gxt; fixed_t gyt; fixed_t tx; fixed_t tz; fixed_t xscale; int x1; int x2; spritedef_t* sprdef; spriteframe_t* sprframe; int lump; unsigned rot; boolean flip; int index; vissprite_t* vis; angle_t ang; fixed_t iscale; // transform the origin point tr_x = thing->x - viewx; tr_y = thing->y - viewy; gxt = FixedMul(tr_x,viewcos); gyt = -FixedMul(tr_y,viewsin); tz = gxt-gyt; // thing is behind view plane? if (tz < MINZ) return; xscale = FixedDiv(projection, tz); gxt = -FixedMul(tr_x,viewsin); gyt = FixedMul(tr_y,viewcos); tx = -(gyt+gxt); // too far off the side? if (abs(tx)>(tz<<2)) return; // decide which patch to use for sprite relative to player #ifdef RANGECHECK if ((unsigned int) thing->sprite >= (unsigned int) numsprites) I_Error ("R_ProjectSprite: invalid sprite number %i ", thing->sprite); #endif sprdef = &sprites[thing->sprite]; #ifdef RANGECHECK if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes ) I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", thing->sprite, thing->frame); #endif sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK]; if (sprframe->rotate) { // choose a different rotation based on player view ang = R_PointToAngle (thing->x, thing->y); rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29; lump = sprframe->lump[rot]; flip = (boolean)sprframe->flip[rot]; } else { // use single rotation for all views lump = sprframe->lump[0]; flip = (boolean)sprframe->flip[0]; } // calculate edges of the shape tx -= spriteoffset[lump]; x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS; // off the right side? if (x1 > viewwidth) return; tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1; // off the left side if (x2 < 0) return; // store information in a vissprite vis = R_NewVisSprite (); vis->mobjflags = thing->flags; vis->scale = xscale<gx = thing->x; vis->gy = thing->y; vis->gz = thing->z; // villsa [STRIFE] if(thing->flags & MF_FEETCLIPPED) vis->gz -= (10*FRACUNIT); // villsa [STRIFE] vis->gzt = vis->gz + spritetopoffset[lump]; vis->texturemid = vis->gzt - viewz; vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; iscale = FixedDiv (FRACUNIT, xscale); if (flip) { vis->startfrac = spritewidth[lump]-1; vis->xiscale = -iscale; } else { vis->startfrac = 0; vis->xiscale = iscale; } if (vis->x1 > x1) vis->startfrac += vis->xiscale*(vis->x1-x1); vis->patch = lump; // get light level // villsa [STRIFE] unused /*if (thing->flags & MF_SHADOW) { // shadow draw vis->colormap = NULL; } else */if (fixedcolormap) { // fixed map vis->colormap = fixedcolormap; } else if (thing->frame & FF_FULLBRIGHT) { // full bright vis->colormap = colormaps; } else { // diminished light index = xscale>>(LIGHTSCALESHIFT-detailshift); if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE-1; vis->colormap = spritelights[index]; } } // // R_AddSprites // During BSP traversal, this adds sprites by sector. // void R_AddSprites (sector_t* sec) { mobj_t* thing; int lightnum; // BSP is traversed by subsector. // A sector might have been split into several // subsectors during BSP building. // Thus we check whether its already added. if (sec->validcount == validcount) return; // Well, now it will be done. sec->validcount = validcount; lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS-1]; else spritelights = scalelight[lightnum]; // Handle all things in sector. for (thing = sec->thinglist ; thing ; thing = thing->snext) R_ProjectSprite (thing); } // // R_DrawPSprite // void R_DrawPSprite (pspdef_t* psp) { fixed_t tx; int x1; int x2; spritedef_t* sprdef; spriteframe_t* sprframe; int lump; boolean flip; vissprite_t* vis; vissprite_t avis; // decide which patch to use #ifdef RANGECHECK if ( (unsigned)psp->state->sprite >= (unsigned int) numsprites) I_Error ("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite); #endif sprdef = &sprites[psp->state->sprite]; #ifdef RANGECHECK if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame); #endif sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ]; lump = sprframe->lump[0]; // [STRIFE] haleyjd 20110629: -flip replaces this. //flip = (boolean)sprframe->flip[0]; flip = flipparm; // calculate edges of the shape tx = psp->sx-160*FRACUNIT; tx -= spriteoffset[lump]; x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS; // off the right side if (x1 > viewwidth) return; tx += spritewidth[lump]; x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1; // off the left side if (x2 < 0) return; // store information in a vissprite vis = &avis; vis->mobjflags = 0; vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; vis->scale = pspritescale<xiscale = -pspriteiscale; vis->startfrac = spritewidth[lump]-1; } else { vis->xiscale = pspriteiscale; vis->startfrac = 0; } // villsa [STRIFE] calculate y offset with view pitch vis->texturemid = ((BASEYCENTER<sy-spritetopoffset[lump]) + FixedMul(vis->xiscale, (centery-viewheight/2)<x1 > x1) vis->startfrac += vis->xiscale*(vis->x1-x1); vis->patch = lump; if (viewplayer->powers[pw_invisibility] > 4*32 || (viewplayer->powers[pw_invisibility] & 8)) { // shadow draw vis->colormap = spritelights[MAXLIGHTSCALE-1]; vis->mobjflags |= MF_SHADOW; } else if(viewplayer->powers[pw_invisibility] & 4) { vis->mobjflags |= (MF_SHADOW|MF_MVIS); } // When not MVIS, or if SHADOW, behave normally: if(!(viewplayer->mo->flags & MF_MVIS) || (viewplayer->mo->flags & MF_SHADOW)) { if (fixedcolormap) { // fixed color vis->colormap = fixedcolormap; } else if (psp->state->frame & FF_FULLBRIGHT) { // full bright vis->colormap = colormaps; } else { // local light vis->colormap = spritelights[MAXLIGHTSCALE-1]; } } else { // When MVIS, use invulnerability colormap vis->colormap = colormaps + INVERSECOLORMAP * 256 * sizeof(lighttable_t); } R_DrawVisSprite (vis, vis->x1, vis->x2); } // // R_DrawPlayerSprites // void R_DrawPlayerSprites (void) { int i; int lightnum; pspdef_t* psp; // get light level lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) +extralight; if (lightnum < 0) spritelights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) spritelights = scalelight[LIGHTLEVELS-1]; else spritelights = scalelight[lightnum]; // clip to screen bounds mfloorclip = screenheightarray; mceilingclip = negonearray; // add all active psprites for (i=0, psp=viewplayer->psprites; istate) R_DrawPSprite (psp); } } // // R_SortVisSprites // vissprite_t vsprsortedhead; void R_SortVisSprites (void) { int i; int count; vissprite_t* ds; vissprite_t* best; vissprite_t unsorted; fixed_t bestscale; count = vissprite_p - vissprites; unsorted.next = unsorted.prev = &unsorted; if (!count) return; for (ds=vissprites ; dsnext = ds+1; ds->prev = ds-1; } vissprites[0].prev = &unsorted; unsorted.next = &vissprites[0]; (vissprite_p-1)->next = &unsorted; unsorted.prev = vissprite_p-1; // pull the vissprites out by scale vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; for (i=0 ; inext) { if (ds->scale < bestscale) { bestscale = ds->scale; best = ds; } } best->next->prev = best->prev; best->prev->next = best->next; best->next = &vsprsortedhead; best->prev = vsprsortedhead.prev; vsprsortedhead.prev->next = best; vsprsortedhead.prev = best; } } // // R_DrawSprite // void R_DrawSprite (vissprite_t* spr) { drawseg_t* ds; short clipbot[SCREENWIDTH]; short cliptop[SCREENWIDTH]; int x; int r1; int r2; fixed_t scale; fixed_t lowscale; int silhouette; for (x = spr->x1 ; x<=spr->x2 ; x++) clipbot[x] = cliptop[x] = -2; // Scan drawsegs from end to start for obscuring segs. // The first drawseg that has a greater scale // is the clip seg. for (ds=ds_p-1 ; ds >= drawsegs ; ds--) { // determine if the drawseg obscures the sprite if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || (!ds->silhouette && !ds->maskedtexturecol) ) { // does not cover sprite continue; } r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; if (ds->scale1 > ds->scale2) { lowscale = ds->scale2; scale = ds->scale1; } else { lowscale = ds->scale1; scale = ds->scale2; } if (scale < spr->scale || ( lowscale < spr->scale && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline) ) ) { // masked mid texture? if (ds->maskedtexturecol) R_RenderMaskedSegRange (ds, r1, r2); // seg is behind sprite continue; } // clip this piece of the sprite silhouette = ds->silhouette; if (spr->gz >= ds->bsilheight) silhouette &= ~SIL_BOTTOM; if (spr->gzt <= ds->tsilheight) silhouette &= ~SIL_TOP; if (silhouette == 1) { // bottom sil for (x=r1 ; x<=r2 ; x++) if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; } else if (silhouette == 2) { // top sil for (x=r1 ; x<=r2 ; x++) if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } else if (silhouette == 3) { // both for (x=r1 ; x<=r2 ; x++) { if (clipbot[x] == -2) clipbot[x] = ds->sprbottomclip[x]; if (cliptop[x] == -2) cliptop[x] = ds->sprtopclip[x]; } } } // all clipping has been performed, so draw the sprite // check for unclipped columns for (x = spr->x1 ; x<=spr->x2 ; x++) { if (clipbot[x] == -2) clipbot[x] = viewheight; if (cliptop[x] == -2) cliptop[x] = -1; } mfloorclip = clipbot; mceilingclip = cliptop; R_DrawVisSprite (spr, spr->x1, spr->x2); } // // R_DrawMasked // void R_DrawMasked (void) { vissprite_t* spr; drawseg_t* ds; R_SortVisSprites (); if (vissprite_p > vissprites) { // draw all vissprites back to front for (spr = vsprsortedhead.next ; spr != &vsprsortedhead ; spr=spr->next) { R_DrawSprite (spr); } } // render any remaining masked mid textures for (ds=ds_p-1 ; ds >= drawsegs ; ds--) if (ds->maskedtexturecol) R_RenderMaskedSegRange (ds, ds->x1, ds->x2); // draw the psprites on top of everything // but does not draw on side views if (!viewangleoffset) R_DrawPlayerSprites (); } chocolate-doom-chocolate-doom-2.2.1/src/strife/r_things.h000066400000000000000000000030741257432200600233620ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Rendering of moving objects, sprites. // #ifndef __R_THINGS__ #define __R_THINGS__ #define MAXVISSPRITES 128 extern vissprite_t vissprites[MAXVISSPRITES]; extern vissprite_t* vissprite_p; extern vissprite_t vsprsortedhead; // Constant arrays used for psprite clipping // and initializing clipping. extern short negonearray[SCREENWIDTH]; extern short screenheightarray[SCREENWIDTH]; // vars for R_DrawMaskedColumn extern short* mfloorclip; extern short* mceilingclip; extern fixed_t spryscale; extern fixed_t sprtopscreen; extern fixed_t pspritescale; extern fixed_t pspriteiscale; // villsa [STIFE] new argument void R_DrawMaskedColumn (column_t *column, int baseclip); void R_SortVisSprites (void); void R_AddSprites (sector_t* sec); void R_AddPSprites (void); void R_DrawSprites (void); void R_InitSprites (char** namelist); void R_ClearSprites (void); void R_DrawMasked (void); void R_ClipVisSprite ( vissprite_t* vis, int xl, int xh ); #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/s_sound.c000066400000000000000000000455001257432200600232120ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: none // #include #include #include #include "i_sound.h" #include "i_system.h" #include "doomfeatures.h" #include "deh_str.h" #include "doomstat.h" #include "doomtype.h" #include "sounds.h" #include "s_sound.h" #include "m_misc.h" #include "m_random.h" #include "m_argv.h" #include "p_local.h" #include "w_wad.h" #include "z_zone.h" // when to clip out sounds // Does not fit the large outdoor areas. #define S_CLIPPING_DIST (1200 * FRACUNIT) // Distance tp origin when sounds should be maxed out. // This should relate to movement clipping resolution // (see BLOCKMAP handling). // In the source code release: (160*FRACUNIT). Changed back to the // Vanilla value of 200 (why was this changed?) #define S_CLOSE_DIST (200 * FRACUNIT) // The range over which sound attenuates #define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS) // Stereo separation #define S_STEREO_SWING (96 * FRACUNIT) #define NORM_PITCH 128 #define NORM_PRIORITY 64 #define NORM_SEP 128 typedef struct { // sound information (if null, channel avail.) sfxinfo_t *sfxinfo; // origin of sound mobj_t *origin; // handle of the sound being played int handle; } channel_t; // The set of channels available static channel_t *channels; // Maximum volume of a sound effect. // Internal default is max out of 0-15. int sfxVolume = 8; // Maximum volume of music. int musicVolume = 13; // haleyjd 08/29/10: [STRIFE] New global variable // Volume of voice channel. int voiceVolume = 15; // Internal volume level, ranging from 0-127 static int snd_SfxVolume; // haleyjd 09/11/10: [STRIFE] Internal voice volume level static int snd_VoiceVolume; // Whether songs are mus_paused static boolean mus_paused; // Music currently being played static musicinfo_t *mus_playing = NULL; // Number of channels to use int snd_channels = 8; // haleyjd 09/11/10: [STRIFE] Handle of current voice channel. // This has been implemented at a higher level than it was implemented // in strife1.exe, as there it relied on a priority system which was // implicit in the SFX_PlayPatch API of DMX. Here we'll just ignore // the current voice channel when doing normal sound playing. static int i_voicehandle = -1; // haleyjd 09/11/10: [STRIFE] whether to play voices or not int disable_voices = 0; // // Initializes sound stuff, including volume // Sets channels, SFX and music volume, // allocates channel buffer, sets S_sfx lookup. // // haleyjd 09/11/10: [STRIFE] Added voice volume // void S_Init(int sfxVolume, int musicVolume, int voiceVolume) { int i; I_SetOPLDriverVer(opl_v_new); I_PrecacheSounds(S_sfx, NUMSFX); S_SetSfxVolume(sfxVolume); S_SetMusicVolume(musicVolume); S_SetVoiceVolume(voiceVolume); // Allocating the internal channels for mixing // (the maximum numer of sounds rendered // simultaneously) within zone memory. channels = Z_Malloc(snd_channels*sizeof(channel_t), PU_STATIC, 0); // Free all channels for use for (i=0 ; isfxinfo) { // stop the sound playing if (I_SoundIsPlaying(c->handle)) { I_StopSound(c->handle); } // check to see if other channels are playing the sound for (i=0; isfxinfo == channels[i].sfxinfo) { break; } } // degrade usefulness of sound data c->sfxinfo->usefulness--; c->sfxinfo = NULL; } } // // Per level startup code. // Kills playing sounds at start of level, // determines music if any, changes music. // // haleyjd 08/31/10: [STRIFE] // * Removed DOOM music handling and replaced with Strife code. // void S_Start(void) { int cnum; int mnum; // kill all playing sounds at start of level // (trust me - a good idea) for (cnum=0 ; cnumpriority > channels[cnum].sfxinfo->priority) return -1; S_StopChannel(cnum); break; } } // None available if (cnum == snd_channels) { // Look for lower priority for (cnum=0 ; cnumpriority >= sfxinfo->priority) { // haleyjd 09/11/10: [STRIFE] voice has absolute priority if (isvoice || cnum != i_voicehandle) break; } } if (cnum == snd_channels) { // FUCK! No lower priority. Sorry, Charlie. return -1; } else { // Otherwise, kick out lower priority. S_StopChannel(cnum); } } c = &channels[cnum]; // channel is decided to be cnum. c->sfxinfo = sfxinfo; c->origin = origin; return cnum; } // // Changes volume and stereo-separation variables // from the norm of a sound effect to be played. // If the sound is not audible, returns a 0. // Otherwise, modifies parameters and returns 1. // // [STRIFE] // haleyjd 20110220: changed to eliminate the gamemap == 8 hack that was // left over from Doom 1's original boss levels. Kind of amazing that Rogue // was able to catch the smallest things like that. // static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, int *vol, int *sep) { fixed_t approx_dist; fixed_t adx; fixed_t ady; angle_t angle; // calculate the distance to sound origin // and clip it if necessary adx = abs(listener->x - source->x); ady = abs(listener->y - source->y); // From _GG1_ p.428. Appox. eucledian distance fast. approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); // [STRIFE] removed gamemap == 8 hack if (approx_dist > S_CLIPPING_DIST) { return 0; } // angle of source to listener angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y); if (angle > listener->angle) { angle = angle - listener->angle; } else { angle = angle + (0xffffffff - listener->angle); } angle >>= ANGLETOFINESHIFT; // stereo separation *sep = 128 - (FixedMul(S_STEREO_SWING, finesine[angle]) >> FRACBITS); // volume calculation // [STRIFE] Removed gamemap == 8 hack if (approx_dist < S_CLOSE_DIST) { *vol = snd_SfxVolume; } else { // distance effect *vol = (snd_SfxVolume * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; } return (*vol > 0); } void S_StartSound(void *origin_p, int sfx_id) { sfxinfo_t *sfx; mobj_t *origin; int rc; int sep; int cnum; int volume; origin = (mobj_t *) origin_p; volume = snd_SfxVolume; // check for bogus sound # if (sfx_id < 1 || sfx_id > NUMSFX) { // [STRIFE]: BUG - Note: vanilla had some extremely buggy and dangerous // code here that tried to print the sprite name of the object playing // the bad sound. Because it invokes multiple undefined behaviors and // is of basically no consequence, it has deliberately not been ported. I_Error("Bad sfx #: %d", sfx_id); } sfx = &S_sfx[sfx_id]; // Initialize sound parameters if (sfx->link) { volume += sfx->volume; if (volume < 1) { return; } if (volume > snd_SfxVolume) { volume = snd_SfxVolume; } } // Check to see if it is audible, // and if not, modify the params if (origin && origin != players[consoleplayer].mo) { rc = S_AdjustSoundParams(players[consoleplayer].mo, origin, &volume, &sep); if (origin->x == players[consoleplayer].mo->x && origin->y == players[consoleplayer].mo->y) { sep = NORM_SEP; } if (!rc) { return; } } else { sep = NORM_SEP; } // kill old sound [STRIFE] - nope! //S_StopSound(origin); // try to find a channel cnum = S_GetChannel(origin, sfx, false); // haleyjd: not a voice. if (cnum < 0) { return; } // increase the usefulness if (sfx->usefulness++ < 0) { sfx->usefulness = 1; } if (sfx->lumpnum < 0) { sfx->lumpnum = I_GetSfxLumpNum(sfx); } channels[cnum].handle = I_StartSound(sfx, cnum, volume, sep); } // haleyjd 09/11/10: [STRIFE] // None of this was necessary in the vanilla EXE but Choco's low-level code // won't play nice with a temporary sfxinfo because it insists that the // "driver_data" member remain valid from the last time the sound was used, // even if it has already stopped playing. Thanks to this cuteness I get // to maintain a dynamic cache of sfxinfo objects! typedef struct voiceinfo_s { sfxinfo_t sfx; struct voiceinfo_s *next; // next on hash chain } voiceinfo_t; #define NUMVOICECHAINS 257 // // Ripped from Eternity. // static unsigned int S_voiceHash(const char *str) { const char *c = str; unsigned int h = 0; if(!str) I_Error("S_voiceHash: cannot hash NULL string!\n"); // note: this needs to be case insensitive for lump names while(*c) { h = 5 * h + toupper(*c); ++c; } return h; } static voiceinfo_t *voices[NUMVOICECHAINS]; // // S_getVoice // // Gets an entry from the voice table, if it exists. If it does not, one will be // created. // static voiceinfo_t *S_getVoice(const char *name, int lumpnum) { voiceinfo_t *voice; unsigned int hashkey = S_voiceHash(name) % NUMVOICECHAINS; voice = voices[hashkey]; while(voice && strcasecmp(voice->sfx.name, name)) voice = voice->next; if(!voice) { voice = calloc(1, sizeof(voiceinfo_t)); M_StringCopy(voice->sfx.name, name, sizeof(voice->sfx.name)); voice->sfx.priority = INT_MIN; // make highest possible priority voice->sfx.pitch = -1; voice->sfx.volume = -1; voice->sfx.numchannels = -1; voice->sfx.usefulness = -1; voice->sfx.lumpnum = lumpnum; // throw it onto the table. voice->next = voices[hashkey]; voices[hashkey] = voice; } return voice; } // // I_StartVoice // // haleyjd 09/11/10: [STRIFE] New function // Note this was in i_sound.c in Strife itself, but relied on DMX-specific // features to ensure voice channels had absolute priority. Here we must // populate a fake sfxinfo_t and send the sound through some of the normal // routines. But in the end, it still works the same. // void I_StartVoice(const char *lumpname) { int lumpnum; voiceinfo_t *voice; // choco-specific char lumpnamedup[9]; // no voices in deathmatch mode. if(netgame) return; // STRIFE-TODO: checks if snd_SfxDevice == 83 // This is probably turning off voice if using PC speaker... // user has disabled voices? if(disable_voices) return; // have a voice playing already? stop it. if(i_voicehandle >= 0) S_StopChannel(i_voicehandle); // Vanilla STRIFE appears to have stopped any current voice without // starting a new one if NULL was passed in here, though I cannot // find an explicit check for NULL in the assembly. Either way, it // didn't crash, so do a check now: if(lumpname == NULL) return; // Because of constness problems... M_StringCopy(lumpnamedup, lumpname, sizeof(lumpnamedup)); if((lumpnum = W_CheckNumForName(lumpnamedup)) != -1) { // haleyjd: Choco-specific: get a voice structure voice = S_getVoice(lumpnamedup, lumpnum); // get a channel for the voice i_voicehandle = S_GetChannel(NULL, &voice->sfx, true); channels[i_voicehandle].handle = I_StartSound(&voice->sfx, i_voicehandle, snd_VoiceVolume, NORM_SEP); } } // // Stop and resume music, during game PAUSE. // void S_PauseSound(void) { if (mus_playing && !mus_paused) { I_PauseSong(); mus_paused = true; } } void S_ResumeSound(void) { if (mus_playing && mus_paused) { I_ResumeSong(); mus_paused = false; } } // // Updates music & sounds // void S_UpdateSounds(mobj_t *listener) { int audible; int cnum; int volume; int sep; sfxinfo_t* sfx; channel_t* c; I_UpdateSound(); for (cnum=0; cnumsfxinfo; if (c->sfxinfo) { if (I_SoundIsPlaying(c->handle)) { // initialize parameters volume = snd_SfxVolume; sep = NORM_SEP; if (sfx->link) { volume += sfx->volume; if (volume < 1) { S_StopChannel(cnum); continue; } else if (volume > snd_SfxVolume) { volume = snd_SfxVolume; } } // check non-local sounds for distance clipping // or modify their params if (c->origin && listener != c->origin) { audible = S_AdjustSoundParams(listener, c->origin, &volume, &sep); if (!audible) { S_StopChannel(cnum); } else { I_UpdateSoundParams(c->handle, volume, sep); } } } else { // if channel is allocated but sound has stopped, // free it S_StopChannel(cnum); } } } } void S_SetMusicVolume(int volume) { if (volume < 0 || volume > 127) { I_Error("Attempt to set music volume at %d", volume); } I_SetMusicVolume(volume); } void S_SetSfxVolume(int volume) { if (volume < 0 || volume > 127) { I_Error("Attempt to set sfx volume at %d", volume); } snd_SfxVolume = volume; } // // S_SetVoiceVolume // // haleyjd 09/11/10: [STRIFE] // Set the internal voice volume level. // void S_SetVoiceVolume(int volume) { if (volume < 0 || volume > 127) { I_Error("Attempt to set voice volume at %d", volume); } snd_VoiceVolume = volume; } // // Starts some music with the music id found in sounds.h. // void S_StartMusic(int m_id) { S_ChangeMusic(m_id, false); } void S_ChangeMusic(int musicnum, int looping) { musicinfo_t *music = NULL; char namebuf[9]; void *handle; if (musicnum <= mus_None || musicnum >= NUMMUSIC) { I_Error("Bad music number %d", musicnum); } else { music = &S_music[musicnum]; } if (mus_playing == music) { return; } // shutdown old music S_StopMusic(); // get lumpnum if neccessary if (!music->lumpnum) { M_snprintf(namebuf, sizeof(namebuf), "d_%s", DEH_String(music->name)); music->lumpnum = W_GetNumForName(namebuf); } music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC); handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); music->handle = handle; I_PlaySong(handle, looping); mus_playing = music; } boolean S_MusicPlaying(void) { return I_MusicIsPlaying(); } void S_StopMusic(void) { if (mus_playing) { if (mus_paused) { I_ResumeSong(); } I_StopSong(); I_UnRegisterSong(mus_playing->handle); W_ReleaseLumpNum(mus_playing->lumpnum); mus_playing->data = NULL; mus_playing = NULL; } } chocolate-doom-chocolate-doom-2.2.1/src/strife/s_sound.h000066400000000000000000000040721257432200600232160ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The not so system specific sound interface. // #ifndef __S_SOUND__ #define __S_SOUND__ #include "p_mobj.h" #include "sounds.h" // // Initializes sound stuff, including volume // Sets channels, SFX and music volume, // allocates channel buffer, sets S_sfx lookup. // void S_Init(int sfxVolume, int musicVolume, int voiceVolume); // Shut down sound void S_Shutdown(void); // // Per level startup code. // Kills playing sounds at start of level, // determines music if any, changes music. // void S_Start(void); // // Start sound for thing at // using from sounds.h // void S_StartSound(void *origin, int sound_id); // haleyjd 09/11/10: [STRIFE] Start a voice. void I_StartVoice(const char *lumpname); // Stop sound for thing at void S_StopSound(mobj_t *origin); // Start music using from sounds.h void S_StartMusic(int music_id); // Start music using from sounds.h, // and set whether looping void S_ChangeMusic(int music_id, int looping); // query if music is playing boolean S_MusicPlaying(void); // Stops the music fer sure. void S_StopMusic(void); // Stop and resume music, during game PAUSE. void S_PauseSound(void); void S_ResumeSound(void); // // Updates music & sounds // void S_UpdateSounds(mobj_t *listener); void S_SetMusicVolume(int volume); void S_SetSfxVolume(int volume); void S_SetVoiceVolume(int volume); // haleyjd 09/11/10: [STRIFE] extern int snd_channels; extern int disable_voices; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/sounds.c000066400000000000000000000126101257432200600230470ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Created by a sound utility. // Kept as a sample, DOOM2 sounds. // #include #include "doomtype.h" #include "sounds.h" // // Information about all the music // #define MUSIC(name) \ { name, 0, NULL, NULL } // villsa [STRIFE] musicinfo_t S_music[] = { MUSIC(NULL), MUSIC("logo"), MUSIC("action"), MUSIC("tavern"), MUSIC("danger"), MUSIC("fast"), MUSIC("intro"), MUSIC("darker"), MUSIC("strike"), MUSIC("slide"), MUSIC("tribal"), MUSIC("march"), MUSIC("danger"), MUSIC("mood"), MUSIC("castle"), MUSIC("darker"), MUSIC("action"), MUSIC("fight"), MUSIC("spense"), MUSIC("slide"), MUSIC("strike"), MUSIC("dark"), MUSIC("tech"), MUSIC("slide"), MUSIC("drone"), MUSIC("panthr"), MUSIC("sad"), MUSIC("instry"), MUSIC("tech"), MUSIC("action"), MUSIC("instry"), MUSIC("drone"), MUSIC("fight"), MUSIC("happy"), MUSIC("end") }; // // Information about all the sfx // #define SOUND(name, priority) \ { NULL, name, priority, NULL, -1, -1, 0, 0, -1, NULL } #define SOUND_LINK(name, priority, link_id, pitch, volume) \ { NULL, name, priority, &S_sfx[link_id], pitch, volume, 0, 0, -1, NULL } // villsa [STRIFE] sfxinfo_t S_sfx[] = { // S_sfx[0] needs to be a dummy for odd reasons. SOUND("none", 0), SOUND("swish", 64), SOUND("meatht", 64), SOUND("mtalht", 64), SOUND("wpnup", 78), SOUND("rifle", 64), SOUND("mislht", 64), SOUND("barexp", 32), SOUND("flburn", 64), SOUND("flidl", 118), SOUND("agrsee", 98), SOUND("plpain", 96), SOUND("pcrush", 96), SOUND("pespna", 98), SOUND("pespnb", 98), SOUND("pespnc", 98), SOUND("pespnd", 98), SOUND("agrdpn", 98), SOUND("pldeth", 32), SOUND("plxdth", 32), SOUND("slop", 78), SOUND("rebdth", 98), SOUND("agrdth", 98), SOUND("lgfire", 211), SOUND("smfire", 211), SOUND("alarm", 210), SOUND("drlmto", 98), SOUND("drlmtc", 98), SOUND("drsmto", 98), SOUND("drsmtc", 98), SOUND("drlwud", 98), SOUND("drswud", 98), SOUND("drston", 98), SOUND("bdopn", 98), SOUND("bdcls", 98), SOUND("swtchn", 78), SOUND("swbolt", 98), SOUND("swscan", 98), SOUND("yeah", 10), SOUND("mask", 210), SOUND("pstart", 100), SOUND("pstop", 100), SOUND("itemup", 78), SOUND("bglass", 200), SOUND("wriver", 201), SOUND("wfall", 201), SOUND("wdrip", 201), SOUND("wsplsh", 95), SOUND("rebact", 200), SOUND("agrac1", 98), SOUND("agrac2", 98), SOUND("agrac3", 98), SOUND("agrac4", 98), SOUND("ambppl", 218), SOUND("ambbar", 218), SOUND("telept", 32), SOUND("ratact", 99), SOUND("itmbk", 100), SOUND("xbow", 99), SOUND("burnme", 95), SOUND("oof", 96), SOUND("wbrldt", 98), SOUND("psdtha", 109), SOUND("psdthb", 109), SOUND("psdthc", 109), SOUND("rb2pn", 96), SOUND("rb2dth", 32), SOUND("rb2see", 98), SOUND("rb2act", 98), SOUND("firxpl", 70), SOUND("stnmov", 100), SOUND("noway", 78), SOUND("rlaunc", 64), SOUND("rflite", 65), SOUND("radio", 60), SOUND("pulchn", 98), SOUND("swknob", 98), SOUND("keycrd", 98), SOUND("swston", 98), SOUND("sntsee", 98), SOUND("sntdth", 98), SOUND("sntact", 98), SOUND("pgrdat", 64), SOUND("pgrsee", 90), SOUND("pgrdpn", 96), SOUND("pgrdth", 32), SOUND("pgract", 120), SOUND("proton", 64), SOUND("protfl", 64), SOUND("plasma", 64), SOUND("dsrptr", 30), SOUND("reavat", 64), SOUND("revbld", 64), SOUND("revsee", 90), SOUND("reavpn", 96), SOUND("revdth", 32), SOUND("revact", 120), SOUND("spisit", 90), SOUND("spdwlk", 65), SOUND("spidth", 32), SOUND("spdatk", 32), SOUND("chant", 218), SOUND("static", 32), SOUND("chain", 70), SOUND("tend", 100), SOUND("phoot", 32), SOUND("explod", 32), SOUND("sigil", 32), SOUND("sglhit", 32), SOUND("siglup", 32), SOUND("prgpn", 96), SOUND("progac", 120), SOUND("lorpn", 96), SOUND("lorsee", 90), SOUND("difool", 32), SOUND("inqdth", 32), SOUND("inqact", 98), SOUND("inqsee", 90), SOUND("inqjmp", 65), SOUND("amaln1", 99), SOUND("amaln2", 99), SOUND("amaln3", 99), SOUND("amaln4", 99), SOUND("amaln5", 99), SOUND("amaln6", 99), SOUND("mnalse", 64), SOUND("alnsee", 64), SOUND("alnpn", 96), SOUND("alnact", 120), SOUND("alndth", 32), SOUND("mnaldt", 32), SOUND("reactr", 31), SOUND("airlck", 98), SOUND("drchno", 98), SOUND("drchnc", 98), SOUND("valve", 98) }; chocolate-doom-chocolate-doom-2.2.1/src/strife/sounds.h000066400000000000000000000073011257432200600230550ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Created by the sound utility written by Dave Taylor. // Kept as a sample, DOOM2 sounds. Frozen. // #ifndef __SOUNDS__ #define __SOUNDS__ #include "i_sound.h" // the complete set of sound effects extern sfxinfo_t S_sfx[]; // the complete set of music extern musicinfo_t S_music[]; // // Identifiers for all music in game. // // villsa [STRIFE] typedef enum { mus_None, mus_logo, mus_action, mus_tavern, mus_danger, mus_fast, mus_intro, mus_darker, mus_strike, mus_slide, mus_tribal, mus_march, mus_danger2, mus_mood, mus_castle, mus_darker2, mus_action2, mus_fight, mus_spense, mus_slide2, mus_strike2, mus_dark, mus_tech, mus_slide3, mus_drone, mus_panthr, mus_sad, mus_instry, mus_tech2, mus_action3, mus_instry2, mus_drone2, mus_fight2, mus_happy, mus_end, NUMMUSIC } musicenum_t; // // Identifiers for all sfx in game. // typedef enum { sfx_None, sfx_swish, sfx_meatht, sfx_mtalht, sfx_wpnup, sfx_rifle, sfx_mislht, sfx_barexp, sfx_flburn, sfx_flidl, sfx_agrsee, sfx_plpain, sfx_pcrush, sfx_pespna, sfx_pespnb, sfx_pespnc, sfx_pespnd, sfx_agrdpn, sfx_pldeth, sfx_plxdth, sfx_slop, sfx_rebdth, sfx_agrdth, sfx_lgfire, sfx_smfire, sfx_alarm, sfx_drlmto, sfx_drlmtc, sfx_drsmto, sfx_drsmtc, sfx_drlwud, sfx_drswud, sfx_drston, sfx_bdopn, sfx_bdcls, sfx_swtchn, sfx_swbolt, sfx_swscan, sfx_yeah, sfx_mask, sfx_pstart, sfx_pstop, sfx_itemup, sfx_bglass, sfx_wriver, sfx_wfall, sfx_wdrip, sfx_wsplsh, sfx_rebact, sfx_agrac1, sfx_agrac2, sfx_agrac3, sfx_agrac4, sfx_ambppl, sfx_ambbar, sfx_telept, sfx_ratact, sfx_itmbk, sfx_xbow, sfx_burnme, sfx_oof, sfx_wbrldt, sfx_psdtha, sfx_psdthb, sfx_psdthc, sfx_rb2pn, sfx_rb2dth, sfx_rb2see, sfx_rb2act, sfx_firxpl, sfx_stnmov, sfx_noway, sfx_rlaunc, sfx_rflite, sfx_radio, sfx_pulchn, sfx_swknob, sfx_keycrd, sfx_swston, sfx_sntsee, sfx_sntdth, sfx_sntact, sfx_pgrdat, sfx_pgrsee, sfx_pgrdpn, sfx_pgrdth, sfx_pgract, sfx_proton, sfx_protfl, sfx_plasma, sfx_dsrptr, sfx_reavat, sfx_revbld, sfx_revsee, sfx_reavpn, sfx_revdth, sfx_revact, sfx_spisit, sfx_spdwlk, sfx_spidth, sfx_spdatk, sfx_chant, sfx_static, sfx_chain, sfx_tend, sfx_phoot, sfx_explod, sfx_sigil, sfx_sglhit, sfx_siglup, sfx_prgpn, sfx_progac, sfx_lorpn, sfx_lorsee, sfx_difool, sfx_inqdth, sfx_inqact, sfx_inqsee, sfx_inqjmp, sfx_amaln1, sfx_amaln2, sfx_amaln3, sfx_amaln4, sfx_amaln5, sfx_amaln6, sfx_mnalse, sfx_alnsee, sfx_alnpn, sfx_alnact, sfx_alndth, sfx_mnaldt, sfx_reactr, sfx_airlck, sfx_drchno, sfx_drchnc, sfx_valve, NUMSFX } sfxenum_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/st_lib.c000066400000000000000000000133661257432200600230210ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The status bar widget code. // #include #include #include "deh_main.h" #include "doomdef.h" #include "z_zone.h" #include "v_video.h" #include "i_swap.h" #include "i_system.h" #include "w_wad.h" #include "st_stuff.h" #include "st_lib.h" #include "r_local.h" // in AM_map.c extern boolean automapactive; // // Hack display negative frags. // Loads and store the stminus lump. // patch_t* sttminus; void STlib_init(void) { // haleyjd 08/28/10: [STRIFE] STTMINUS -> STCFN045 sttminus = (patch_t *) W_CacheLumpName(DEH_String("STCFN045"), PU_STATIC); } // // STlib_initNum // // haleyjd 09/01/10: [STRIFE] // * Rogue removed the "on" member of st_number_t. void STlib_initNum ( st_number_t* n, int x, int y, patch_t** pl, int* num, int width ) { n->x = x; n->y = y; n->width = width; n->num = num; n->p = pl; } // // STlib_drawNum // // A fairly efficient way to draw a number // based on differences from the old number. // Note: worth the trouble? // // haleyjd 09/01/10: [STRIFE] // * Rogue removed the "refresh" parameter and caching code // void STlib_drawNum ( st_number_t* n) { int numdigits = n->width; int num = *n->num; int w = SHORT(n->p[0]->width) + 1; // [STRIFE] +1 int x = n->x; int neg; neg = num < 0; if (neg) { if (numdigits == 2 && num < -9) num = -9; else if (numdigits == 3 && num < -99) num = -99; num = -num; } /* haleyjd 09/01/10: [STRIFE] Widget caching system removed by Rogue // clear the area x = n->x - numdigits*w; if (n->y - ST_Y < 0) I_Error("drawNum: n->y - ST_Y < 0"); V_CopyRect(x, n->y - ST_Y, st_backing_screen, w*numdigits, h, x, n->y); */ // if non-number, do not draw it if (num == 1994) return; x = n->x; // in the special case of 0, you draw 0 if (!num) V_DrawPatch(x - w, n->y, n->p[ 0 ]); // draw the new number while (num && numdigits--) { x -= w; V_DrawPatch(x, n->y, n->p[ num % 10 ]); num /= 10; } // draw a minus sign if necessary if (neg) V_DrawPatch(x - 8, n->y, sttminus); } // // STlib_drawNumPositive // // haleyjd 09/01/10: [STRIFE] New function. // * Mostly the same as STlib_drawNum, except doesn't draw negatives. // void STlib_drawNumPositive ( st_number_t* n) { int numdigits = n->width; int num = *n->num; int w = SHORT(n->p[0]->width) + 1; // [STRIFE] +1 int x = n->x; // Don't draw negative values. if (num < 0) num = 0; // if non-number, do not draw it if (num == 1994) return; x = n->x; // in the special case of 0, you draw 0 if (!num) V_DrawPatch(x - w, n->y, n->p[ 0 ]); // draw the new number while (num && numdigits--) { x -= w; V_DrawPatch(x, n->y, n->p[ num % 10 ]); num /= 10; } } // haleyjd 09/01/10: [STRIFE] All other functions were removed. /* void STlib_updateNum ( st_number_t* n, boolean refresh ) { if (*n->on) STlib_drawNum(n, refresh); } // void STlib_initPercent ( st_percent_t* p, int x, int y, patch_t** pl, int* num, boolean* on, patch_t* percent ) { STlib_initNum(&p->n, x, y, pl, num, on, 3); p->p = percent; } void STlib_updatePercent ( st_percent_t* per, int refresh ) { if (refresh && *per->n.on) V_DrawPatch(per->n.x, per->n.y, per->p); STlib_updateNum(&per->n, refresh); } void STlib_initMultIcon ( st_multicon_t* i, int x, int y, patch_t** il, int* inum, boolean* on ) { i->x = x; i->y = y; i->oldinum = -1; i->inum = inum; i->on = on; i->p = il; } void STlib_updateMultIcon ( st_multicon_t* mi, boolean refresh ) { int w; int h; int x; int y; if (*mi->on && (mi->oldinum != *mi->inum || refresh) && (*mi->inum!=-1)) { if (mi->oldinum != -1) { x = mi->x - SHORT(mi->p[mi->oldinum]->leftoffset); y = mi->y - SHORT(mi->p[mi->oldinum]->topoffset); w = SHORT(mi->p[mi->oldinum]->width); h = SHORT(mi->p[mi->oldinum]->height); if (y - ST_Y < 0) I_Error("updateMultIcon: y - ST_Y < 0"); V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y); } V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]); mi->oldinum = *mi->inum; } } void STlib_initBinIcon ( st_binicon_t* b, int x, int y, patch_t* i, boolean* val, boolean* on ) { b->x = x; b->y = y; b->oldval = false; b->val = val; b->on = on; b->p = i; } void STlib_updateBinIcon ( st_binicon_t* bi, boolean refresh ) { int x; int y; int w; int h; if (*bi->on && (bi->oldval != *bi->val || refresh)) { x = bi->x - SHORT(bi->p->leftoffset); y = bi->y - SHORT(bi->p->topoffset); w = SHORT(bi->p->width); h = SHORT(bi->p->height); if (y - ST_Y < 0) I_Error("updateBinIcon: y - ST_Y < 0"); if (*bi->val) V_DrawPatch(bi->x, bi->y, bi->p); else V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y); bi->oldval = *bi->val; } } */ chocolate-doom-chocolate-doom-2.2.1/src/strife/st_lib.h000066400000000000000000000072331257432200600230220ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // The status bar widget code. // #ifndef __STLIB__ #define __STLIB__ // We are referring to patches. #include "r_defs.h" // // Typedefs of widgets // // Number widget typedef struct { // upper right-hand corner // of the number (right-justified) int x; int y; // max # of digits in number int width; // haleyjd 09/01/10: [STRIFE] Removed "oldnum" member //int oldnum; // pointer to current value int* num; // haleyjd 09/01/10: [STRIFE] Removed "on" member // boolean* on; // list of patches for 0-9 patch_t** p; // user data int data; } st_number_t; // Percent widget ("child" of number widget, // or, more precisely, contains a number widget.) typedef struct { // number information st_number_t n; // percent sign graphic patch_t* p; } st_percent_t; // Multiple Icon widget typedef struct { // center-justified location of icons int x; int y; // last icon number int oldinum; // pointer to current icon int* inum; // pointer to boolean stating // whether to update icon boolean* on; // list of icons patch_t** p; // user data int data; } st_multicon_t; // Binary Icon widget typedef struct { // center-justified location of icon int x; int y; // last icon value boolean oldval; // pointer to current icon status boolean* val; // pointer to boolean // stating whether to update icon boolean* on; patch_t* p; // icon int data; // user data } st_binicon_t; // // Widget creation, access, and update routines // // Initializes widget library. // More precisely, initialize STMINUS, // everything else is done somewhere else. // void STlib_init(void); // Number widget routines // haleyjd 09/01/10: [STRIFE] Removed "on" parameter. void STlib_initNum ( st_number_t* n, int x, int y, patch_t** pl, int* num, int width ); // haleyjd 09/01/10: [STRIFE] Made globally visible. void STlib_drawNum ( st_number_t* n); // haleyjd 09/01/10: [STRIFE] New function void STlib_drawNumPositive ( st_number_t* n); /* haleyjd 09/01/10: [STRIFE] All the below were removed void STlib_updateNum ( st_number_t* n, boolean refresh ); // Percent widget routines void STlib_initPercent ( st_percent_t* p, int x, int y, patch_t** pl, int* num, boolean* on, patch_t* percent ); void STlib_updatePercent ( st_percent_t* per, int refresh ); // Multiple Icon widget routines void STlib_initMultIcon ( st_multicon_t* mi, int x, int y, patch_t** il, int* inum, boolean* on ); void STlib_updateMultIcon ( st_multicon_t* mi, boolean refresh ); // Binary Icon widget routines void STlib_initBinIcon ( st_binicon_t* b, int x, int y, patch_t* i, boolean* val, boolean* on ); void STlib_updateBinIcon ( st_binicon_t* bi, boolean refresh ); */ #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/st_stuff.c000066400000000000000000001253261257432200600234020ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Status bar code. // Does the face/direction indicator animatin. // Does palette indicators as well (red pain/berserk, bright pickup) // #include #include "i_system.h" #include "i_video.h" #include "z_zone.h" #include "m_random.h" #include "w_wad.h" #include "deh_main.h" #include "deh_misc.h" #include "doomdef.h" #include "doomkeys.h" #include "g_game.h" #include "st_stuff.h" #include "st_lib.h" #include "r_local.h" #include "p_local.h" #include "p_inter.h" #include "p_dialog.h" // villsa [STRIFE] #include "am_map.h" #include "m_cheat.h" #include "m_menu.h" // villsa [STRIFE] #include "m_misc.h" #include "s_sound.h" // Needs access to LFB. #include "v_video.h" #include "i_swap.h" // State. #include "doomstat.h" #include "d_main.h" // [STRIFE] // Data. #include "dstrings.h" #include "sounds.h" #include "m_controls.h" #include "hu_lib.h" // [STRIFE] #include "hu_stuff.h" // // STATUS BAR DATA // // Palette indices. // For damage/bonus red-/gold-shifts #define STARTREDPALS 1 #define STARTBONUSPALS 9 #define NUMREDPALS 8 #define NUMBONUSPALS 4 // Radiation suit, green shift. #define RADIATIONPAL 13 // Location of status bar #define ST_X 0 // Location and size of statistics, // justified according to widget type. // Problem is, within which space? STbar? Screen? // Note: this could be read in by a lump. // Problem is, is the stuff rendered // into a buffer, // or into the frame buffer? // AMMO number pos. // haleyjd 20100901: [STRIFE] Adjusted. #define ST_AMMOWIDTH 3 #define ST_AMMOX 311 #define ST_AMMOY 162 // HEALTH number pos. // haleyjd 20100901: [STRIFE] Adjusted. #define ST_HEALTHWIDTH 3 #define ST_HEALTHX 79 #define ST_HEALTHY 162 // [STRIFE] // Removed: // * Weapon pos. // * Frags pos. // * ARMOR number pos. // * Key icon positions. // Ammunition counter. // haleyjd 20110213 [STRIFE]: ammo counters for the popup widget #define ST_POPUPAMMOX 206 static const int st_yforammo[NUMAMMO] = { 75, 99, 91, 139, 131, 115, 123 }; static const int st_wforammo[NUMAMMO] = { 3, 3, 2, 3, 3, 2, 3 }; // Indicate maximum ammunition. // Only needed because backpack exists. // haleyjd 20110213 [STRIFE]: maxammo counters for the popup widget #define ST_POPUPMAXAMMOX 239 // [STRIFE] // Removed: // * Doom weapon stuff // * DETH title (???) // Dimensions given in characters. #define ST_MSGWIDTH 52 // haleyjd 20100831: [STRIFE] // * Removed faces. // haleyjd 20100901: // * Removed DOOM pre-beta cruft. // * Removed deathmatch frags/arms-related stuff. // * Removed arms panel stuff. // * Removed unused widgets. // * Removed more faces, keyboxes, st_randomnumber // graphics are drawn to a backing screen and blitted to the real screen //byte *st_backing_screen; - [STRIFE]: Unused. // main player in game static player_t* plyr; // ST_Start() has just been called static boolean st_firsttime; // lump number for PLAYPAL static int lu_palette; // whether in automap or first-person static st_stateenum_t st_gamestate; // whether left-side main status bar is active static boolean st_statusbaron; // villsa [STRIFE] static boolean st_dosizedisplay = false; // haleyjd 09/01/10: [STRIFE] // Whether or not a popup is currently displayed static boolean st_displaypopup = false; // villsa [STRIFE] static int st_popupdisplaytics = 0; // villsa [STRIFE] // Whether or not show popup objective screen static boolean st_showobjective = false; // villsa [STRIFE] static boolean st_showinvpop = false; // villsa [STRIFE] static boolean st_showkeys = false; // villsa [STRIFE] TODO - identify variables static int st_keypage = -1; // [unused] static int dword_88490 = 0; // haleyjd 09/19/10: [STRIFE] Cached player data static int st_lastcursorpos; static int st_lastammo; static int st_lastarmortype; static int st_lasthealth; // haleyjd 20100901: [STRIFE] sbar -> invback // main inventory background and other bits static patch_t* invback; // main bar static patch_t* stback; // multiplayer background static patch_t* invtop; // top bit static patch_t* invpop; // popup frame with text static patch_t* invpop2; // plain popup frame static patch_t* invpbak; // popup background w/details static patch_t* invpbak2; // plain popup background static patch_t* invcursor; // cursor // ammo/weapon/armor patches static patch_t* invammo[NUMAMMO]; // ammo/weapons static patch_t* invsigil[5]; // sigil pieces static patch_t* invarmor[2]; // armor icons // names for ammo patches static char *invammonames[NUMAMMO] = { "I_BLIT", "I_XQRL", "I_PQRL", "I_BRY1", "I_ROKT", "I_GRN1", "I_GRN2" }; // haleyjd 20100901: [STRIFE] Replaced tallnum, shortnum w/inv fonts // 0-9, green numbers static patch_t* invfontg[10]; // 0-9, yellow numbers static patch_t* invfonty[10]; // [unused] 3 key-cards, 3 skulls -- [STRIFE] has a lot more keys than 3 :P //static patch_t* keys[NUMCARDS]; // ready-weapon widget static st_number_t w_ready; // haleyjd [STRIFE]: This is still used. // haleyjd: [STRIFE] This is still used but was changed to a st_number_t. // health widget static st_number_t w_health; // ammo widgets static st_number_t w_ammo[NUMAMMO]; // haleyjd [STRIFE]: Still used. // max ammo widgets static st_number_t w_maxammo[NUMAMMO]; // haleyjd [STRIFE]: Still used. // [unused] number of frags so far in deathmatch //static int st_fragscount; cheatseq_t cheat_mus = CHEAT("spin", 2); // [STRIFE]: idmus -> spin cheatseq_t cheat_god = CHEAT("omnipotent", 0); // [STRIFE]: iddqd -> omnipotent cheatseq_t cheat_ammo = CHEAT("boomstix", 0); // [STRIFE]: idfa -> boomstix cheatseq_t cheat_noclip = CHEAT("elvis", 0); // [STRIFE]: idclip -> elvis cheatseq_t cheat_clev = CHEAT("rift", 2); // [STRIFE]: idclev -> rift cheatseq_t cheat_mypos = CHEAT("gps", 0); // [STRIFE]: idmypos -> gps cheatseq_t cheat_scoot = CHEAT("scoot", 1); // [STRIFE]: new cheat scoot cheatseq_t cheat_nuke = CHEAT("stonecold", 0); // [STRIFE]: new cheat stonecold cheatseq_t cheat_keys = CHEAT("jimmy", 0); // [STRIFE]: new cheat jimmy (all keys) cheatseq_t cheat_stealth = CHEAT("gripper", 0); // [STRIFE]: new cheat gripper cheatseq_t cheat_midas = CHEAT("donnytrump", 0); // [STRIFE]: new cheat cheatseq_t cheat_lego = CHEAT("lego", 0); // [STRIFE]: new cheat cheatseq_t cheat_dev = CHEAT("dots", 0); // [STRIFE]: new cheat // haleyjd 20110224: enumeration for access to powerup cheats enum { ST_PUMPUP_B, ST_PUMPUP_I, ST_PUMPUP_M, ST_PUMPUP_H, ST_PUMPUP_P, ST_PUMPUP_S, ST_PUMPUP_T, ST_PUMPUP, NUM_ST_PUMPUP }; cheatseq_t cheat_powerup[NUM_ST_PUMPUP] = // [STRIFE] { CHEAT("pumpupb", 0), CHEAT("pumpupi", 0), CHEAT("pumpupm", 0), CHEAT("pumpuph", 0), CHEAT("pumpupp", 0), CHEAT("pumpups", 0), CHEAT("pumpupt", 0), CHEAT("pumpup", 0), }; //cheatseq_t cheat_choppers = CHEAT("idchoppers", 0); [STRIFE] no such thing void M_SizeDisplay(int choice); // villsa [STRIFE] // // STATUS BAR CODE // void ST_Stop(void); // [STRIFE] static char st_msgbuf[ST_MSGWIDTH]; // Respond to keyboard input events, // intercept cheats. boolean ST_Responder(event_t* ev) { // haleyjd 09/27/10: made static to ST_Responder static boolean st_keystate = false; int i; // Filter automap on/off. if(ev->type == ev_keyup) { if((ev->data1 & 0xffff0000) == AM_MSGHEADER) { switch(ev->data1) { case AM_MSGENTERED: st_gamestate = AutomapState; st_firsttime = true; break; case AM_MSGEXITED: st_gamestate = FirstPersonState; break; } return false; } // villsa [STRIFE] if(ev->data1 != key_invpop && ev->data1 != key_mission && ev->data1 != key_invkey) return false; // villsa [STRIFE] if(ev->data1 == key_invpop) st_showinvpop = false; else { if(ev->data1 == key_mission) st_showobjective = false; else { if(ev->data1 == key_invkey) { st_showkeys = false; st_keystate = false; } } } if(!st_showkeys && !st_showobjective && !st_showinvpop) { if(!st_popupdisplaytics) { st_displaypopup = false; if(st_dosizedisplay) M_SizeDisplay(true); st_dosizedisplay = false; } } return true; } // if a user keypress... if(ev->type != ev_keydown) return false; // haleyjd 20100927: No input allowed when the player is dead if(plyr->mo->health <= 0) return false; // keydown events if(ev->data1 == key_invquery) // inventory query { inventory_t *inv = &(plyr->inventory[plyr->inventorycursor]); if(inv->amount) { DEH_snprintf(st_msgbuf, sizeof(st_msgbuf), "%d %s", inv->amount, DEH_String(mobjinfo[inv->type].name)); plyr->message = st_msgbuf; } } // villsa [STRIFE] if(ev->data1 == key_invpop || ev->data1 == key_invkey || ev->data1 == key_mission) { if(ev->data1 == key_invkey) { st_showobjective = false; st_showinvpop = false; if(!st_keystate) { st_keystate = true; if(++st_keypage > 2) { st_popupdisplaytics = 0; st_showkeys = false; st_displaypopup = false; st_keypage = -1; return true; } } if(netgame) st_popupdisplaytics = 20; else st_popupdisplaytics = 50; st_showkeys = true; } else { if(ev->data1 != key_mission || netgame) { if(ev->data1 == key_invpop) { st_keypage = -1; st_popupdisplaytics = false; st_showkeys = false; st_showobjective = false; st_showinvpop = true; } } else { st_showkeys = netgame; st_showinvpop = netgame; st_keypage = -1; st_popupdisplaytics = ev->data2 ^ key_mission; st_showobjective = true; } } if(st_showkeys || st_showobjective || st_showinvpop) { st_displaypopup = true; if(viewheight == SCREENHEIGHT) { M_SizeDisplay(false); st_dosizedisplay = true; } } } if(ev->data1 == key_invleft) // inventory move left { if(plyr->inventorycursor > 0) plyr->inventorycursor--; return true; } else if(ev->data1 == key_invright) { if(plyr->inventorycursor < plyr->numinventory - 1) plyr->inventorycursor++; return true; } else if(ev->data1 == key_invhome) { plyr->inventorycursor = 0; return true; } else if(ev->data1 == key_invend) { if(plyr->numinventory) plyr->inventorycursor = plyr->numinventory - 1; else plyr->inventorycursor = 0; return true; } // // [STRIFE] Cheats which are allowed in netgames/demos: // // 'spin' cheat for changing music if (cht_CheckCheat(&cheat_mus, ev->data2)) { char buf[3]; int musnum; plyr->message = DEH_String(STSTR_MUS); cht_GetParam(&cheat_mus, buf); musnum = (buf[0] - '0') * 10 + buf[1] - '0'; if (((buf[0]-'0')*10 + buf[1]-'0') > 35) plyr->message = DEH_String(STSTR_NOMUS); else S_ChangeMusic(musnum, 1); } // [STRIFE]: "dev" cheat - "DOTS" else if (cht_CheckCheat(&cheat_dev, ev->data2)) { devparm = !devparm; if (devparm) plyr->message = DEH_String("devparm ON"); else plyr->message = DEH_String("devparm OFF"); } // [STRIFE] Cheats below are not allowed in netgames or demos if(netgame || !usergame) return false; if (cht_CheckCheat(&cheat_god, ev->data2)) { // 'omnipotent' cheat for toggleable god mode plyr->cheats ^= CF_GODMODE; if (plyr->cheats & CF_GODMODE) { if (plyr->mo) plyr->mo->health = 100; plyr->health = deh_god_mode_health; plyr->st_update = true; // [STRIFE] plyr->message = DEH_String(STSTR_DQDON); } else { plyr->st_update = true; plyr->message = DEH_String(STSTR_DQDOFF); } } else if (cht_CheckCheat(&cheat_ammo, ev->data2)) { // [STRIFE]: "BOOMSTIX" cheat for all normal weapons plyr->armorpoints = deh_idkfa_armor; plyr->armortype = deh_idkfa_armor_class; for (i = 0; i < NUMWEAPONS; i++) if(!isdemoversion || weaponinfo[i].availabledemo) plyr->weaponowned[i] = true; // Takes away the Sigil, even if you already had it... plyr->weaponowned[wp_sigil] = false; for (i=0;iammo[i] = plyr->maxammo[i]; plyr->message = DEH_String(STSTR_FAADDED); } else if(cht_CheckCheat(&cheat_keys, ev->data2)) { // villsa [STRIFE]: "JIMMY" cheat for all keys #define FIRSTKEYSETAMOUNT 16 if(plyr->cards[FIRSTKEYSETAMOUNT - 1]) { if(plyr->cards[NUMCARDS - 1] || isdemoversion) { for(i = 0; i < NUMCARDS; i++) plyr->cards[i] = false; plyr->message = DEH_String("Keys removed"); } else { for(i = 0; i < NUMCARDS; i++) plyr->cards[i] = true; plyr->message = DEH_String("Cheater Keys Added"); } } else { for(i = 0; i < FIRSTKEYSETAMOUNT; i++) plyr->cards[i] = true; plyr->message = DEH_String("Cheater Keys Added"); } } else if (cht_CheckCheat(&cheat_noclip, ev->data2)) { // [STRIFE] Removed idspispopd, added NOCLIP flag setting/removal // Noclip cheat - "ELVIS" (hah-hah :P ) plyr->cheats ^= CF_NOCLIP; if (plyr->cheats & CF_NOCLIP) { plyr->message = DEH_String(STSTR_NCON); plyr->mo->flags |= MF_NOCLIP; } else { plyr->message = DEH_String(STSTR_NCOFF); plyr->mo->flags &= ~MF_NOCLIP; } } else if(cht_CheckCheat(&cheat_stealth, ev->data2)) { // villsa [STRIFE]: "GRIPPER" cheat; nothing to do with stealth... plyr->cheats ^= CF_NOMOMENTUM; if(plyr->cheats & CF_NOMOMENTUM) plyr->message = DEH_String("STEALTH BOOTS ON"); else plyr->message = DEH_String("STEALTH BOOTS OFF"); } for(i = 0; i < ST_PUMPUP_B + 3; ++i) { // [STRIFE]: Handle berserk, invisibility, and envirosuit if(cht_CheckCheat(&cheat_powerup[i], ev->data2)) { if(plyr->powers[i]) plyr->powers[i] = (i != 1); else P_GivePower(plyr, i); plyr->message = DEH_String(STSTR_BEHOLDX); } } if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_H], ev->data2)) { // [STRIFE]: PUMPUPH gives medical inventory items P_GiveItemToPlayer(plyr, SPR_STMP, MT_INV_MED1); P_GiveItemToPlayer(plyr, SPR_MDKT, MT_INV_MED2); P_GiveItemToPlayer(plyr, SPR_FULL, MT_INV_MED3); plyr->message = DEH_String("you got the stuff!"); } if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_P], ev->data2)) { // [STRIFE]: PUMPUPP gives backpack if(!plyr->backpack) { for(i = 0; i < NUMAMMO; ++i) plyr->maxammo[i] = 2 * plyr->maxammo[i]; } plyr->backpack = true; for(i = 0; i < NUMAMMO; ++i) P_GiveAmmo(plyr, i, 1); plyr->message = DEH_String("you got the stuff!"); } if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_S], ev->data2)) { // [STRIFE]: PUMPUPS gives stamina and accuracy upgrades P_GiveItemToPlayer(plyr, SPR_TOKN, MT_TOKEN_STAMINA); P_GiveItemToPlayer(plyr, SPR_TOKN, MT_TOKEN_NEW_ACCURACY); plyr->message = DEH_String("you got the stuff!"); } if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_T], ev->data2)) { // [STRIFE] PUMPUPT gives targeter P_GivePower(plyr, pw_targeter); plyr->message = DEH_String("you got the stuff!"); } // [STRIFE]: PUMPUP if (cht_CheckCheat(&cheat_powerup[ST_PUMPUP], ev->data2)) { // 'behold' power-up menu plyr->message = DEH_String(STSTR_BEHOLD); return false; } if (cht_CheckCheat(&cheat_mypos, ev->data2)) { // [STRIFE] 'GPS' for player position static char buf[ST_MSGWIDTH]; M_snprintf(buf, sizeof(buf), "ang=0x%x;x,y=(0x%x,0x%x)", players[consoleplayer].mo->angle, players[consoleplayer].mo->x, players[consoleplayer].mo->y); plyr->message = buf; } // 'rift' change-level cheat if (cht_CheckCheat(&cheat_clev, ev->data2)) { char buf[3]; int map; cht_GetParam(&cheat_clev, buf); map = (buf[0] - '0') * 10 + buf[1] - '0'; // haleyjd 20100901: Removed Chex Quest stuff. // haleyjd 20100915: Removed retail/registered/shareware stuff // haleyjd 20130301: different bounds in v1.31 // Ohmygod - this is not going to work. if(gameversion == exe_strife_1_31) { if ((isdemoversion && (map < 32 || map > 34)) || (isregistered && (map <= 0 || map > 34))) return false; } else { if (map <= 0 || map > 40) return false; } // So be it. plyr->message = DEH_String(STSTR_CLEV); G_RiftExitLevel(map, 0, plyr->mo->angle); } else if(cht_CheckCheat(&cheat_scoot, ev->data2)) { char buf[3]; int spot; cht_GetParam(&cheat_scoot, buf); spot = buf[0] - '0'; // BUG: should be <= 9. Shouldn't do anything bad though... if(spot <= 10) { plyr->message = DEH_String("Spawning to spot"); G_RiftCheat(spot); return false; } } // villsa [STRIFE] if(cht_CheckCheat(&cheat_nuke, ev->data2)) { stonecold ^= 1; plyr->message = DEH_String("Kill 'em. Kill 'em All"); return false; } // villsa [STRIFE] if(cht_CheckCheat(&cheat_midas, ev->data2)) { plyr->message = DEH_String("YOU GOT THE MIDAS TOUCH, BABY"); P_GiveItemToPlayer(plyr, SPR_HELT, MT_TOKEN_TOUGHNESS); } // villsa [STRIFE] // haleyjd 20110224: No sigil in demo version if(!isdemoversion && cht_CheckCheat(&cheat_lego, ev->data2)) { plyr->st_update = true; if(plyr->weaponowned[wp_sigil]) { if(++plyr->sigiltype > 4) { plyr->sigiltype = -1; plyr->pendingweapon = wp_fist; plyr->weaponowned[wp_sigil] = false; } } else { plyr->weaponowned[wp_sigil] = true; plyr->sigiltype = 0; } // BUG: This brings up a bad version of the Sigil (sigiltype -1) which // causes some VERY interesting behavior, when you type LEGO for the // sixth time. This shouldn't be done when taking it away, and yet it // is here... verified with vanilla. plyr->pendingweapon = wp_sigil; } return false; } /* int ST_calcPainOffset(void) { // haleyjd 08/31/10: [STRIFE] Removed. } */ // // This is a not-very-pretty routine which handles // the face states and their timing. // the precedence of expressions is: // dead > evil grin > turned head > straight ahead // /* void ST_updateFaceWidget(void) { // haleyjd 08/31/10: [STRIFE] Removed. } */ /* void ST_updateWidgets(void) { // haleyjd 09/01/10: [STRIFE] Rogue merged this into ST_Ticker below. } */ // // ST_Ticker // // haleyjd 09/01/10: [STRIFE] // * Removed st_clock and st_randomnumber. // * Merged ST_updateWidgets here. Wasn't inlined, as doesn't exist separately // in the binary as inlined functions normally do. // void ST_Ticker (void) { static int largeammo = 1994; // means "n/a" // must redirect the pointer if the ready weapon has changed. if (weaponinfo[plyr->readyweapon].ammo == am_noammo) w_ready.num = &largeammo; else w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo]; w_ready.data = plyr->readyweapon; // STRIFE-TODO: Gobbledeegunk. /* v2 = dword_88490-- == 1; // no clue yet... if(v2) dword_DC7F4 = dword_DC7F0;*/ if(st_popupdisplaytics) { int tics = st_popupdisplaytics; --st_popupdisplaytics; if(tics == 1) { st_displaypopup = false; st_showkeys = false; st_keypage = -1; if(st_dosizedisplay) M_SizeDisplay(true); // mondo hack? st_dosizedisplay = false; } } // haleyjd 20100901: [STRIFE] Keys are handled on a popup // haleyjd 20100831: [STRIFE] No face widget // haleyjd 20100901: [STRIFE] Armor, weapons, frags, etc. handled elsewhere // haleyjd: This is from the PRE-BETA! Left here because it amuses me ;) // get rid of chat window if up because of message //if (!--st_msgcounter) // st_chat = st_oldchat; } static int st_palette = 0; // // ST_doPaletteStuff // // haleyjd 20100831: [STRIFE] // * Changed radsuit palette handling for Strife nukagecount. // * All other logic verified to be unmodified. // void ST_doPaletteStuff(void) { int palette; byte* pal; int cnt; int bzc; cnt = plyr->damagecount; if (plyr->powers[pw_strength]) { // slowly fade the berzerk out bzc = 12 - (plyr->powers[pw_strength]>>6); if (bzc > cnt) cnt = bzc; } if (cnt) { palette = (cnt+7)>>3; if (palette >= NUMREDPALS) palette = NUMREDPALS-1; palette += STARTREDPALS; } else if (plyr->bonuscount) { palette = (plyr->bonuscount+7)>>3; if (palette >= NUMBONUSPALS) palette = NUMBONUSPALS-1; palette += STARTBONUSPALS; } // haleyjd 20100831: [STRIFE] Flash green when in nukage, not when has // an environment suit (a breathing sound is played to indicate that // instead). else if ( plyr->nukagecount > 16*TICRATE || (plyr->nukagecount & 8)) palette = RADIATIONPAL; else palette = 0; // haleyjd 08/31/10: Removed Chex Quest if (palette != st_palette) { st_palette = palette; pal = (byte *) W_CacheLumpNum (lu_palette, PU_CACHE)+palette*768; I_SetPalette (pal); } } /* void ST_drawWidgets(boolean refresh) { haleyjd 09/01/10: [STRIFE] Removed } */ // // ST_drawNumFontY // // haleyjd 20100919: [STRIFE] New function // Draws a small yellow number for inventory etc. // void ST_drawNumFontY(int x, int y, int num) { if(!num) V_DrawPatch(x, y, invfonty[0]); while(num) { V_DrawPatch(x, y, invfonty[num % 10]); x -= SHORT(invfonty[0]->width) + 1; num /= 10; } } // // ST_drawNumFontY2 // // haleyjd 20100919: [STRIFE] New function // As above, but turns negative numbers into zero. // void ST_drawNumFontY2(int x, int y, int num) { if(!num) V_DrawPatch(x, y, invfonty[0]); if(num < 0) num = 0; while(num) { V_DrawPatchDirect(x, y, invfonty[num % 10]); x -= SHORT(invfonty[0]->width) + 1; num /= 10; } } // // ST_drawLine // // haleyjd 20100920: [STRIFE] New function // Basic horizontal line drawing routine used for the health bars. // void ST_drawLine(int x, int y, int len, int color) { byte putcolor = (byte)(color); byte *drawpos = I_VideoBuffer + y * SCREENWIDTH + x; int i = 0; while(i < len) { *drawpos++ = putcolor; ++i; } } // // ST_doRefresh // // haleyjd 20100920: Evidence more than suggests that Rogue moved all status bar // drawing down to this function. // void ST_doRefresh(void) { // draw status bar background to off-screen buff if (st_statusbaron) { int firstinventory, icon_x, num_x, i, numdrawn; // haleyjd 20100919: No backscreen caching in Strife. //V_UseBuffer(st_backing_screen); // TODO: only sometimes drawing? plyr->st_update = false; // cache data st_lastcursorpos = plyr->inventorycursor; st_lastammo = weaponinfo[plyr->readyweapon].ammo; st_lastarmortype = plyr->armortype; st_lasthealth = plyr->health; st_firsttime = false; // draw main status bar V_DrawPatch(ST_X, ST_Y, invback); // draw multiplayer armor backdrop if netgame // haleyjd 20131031: BUG - vanilla is accessing a NULL pointer here when // playing back netdemos! It doesn't appear to draw anything, and there // is no apparent ill effect on gameplay, so the best we can do is check. if(netgame && stback) V_DrawPatch(ST_X, 173, stback); if(plyr->inventorycursor >= 6) firstinventory = plyr->inventorycursor - 5; else firstinventory = 0; // Draw cursor. if(plyr->numinventory) { V_DrawPatch(35 * (plyr->inventorycursor - firstinventory) + 42, 180, invcursor); } // Draw inventory bar for(num_x = 68, icon_x = 48, i = firstinventory, numdrawn = 0; num_x < 278; num_x += 35, icon_x += 35, i++, numdrawn++) { int lumpnum; patch_t *patch; char iconname[8]; if(plyr->numinventory <= numdrawn) break; DEH_snprintf(iconname, sizeof(iconname), "I_%s", DEH_String(sprnames[plyr->inventory[i].sprite])); lumpnum = W_CheckNumForName(iconname); if(lumpnum == -1) patch = W_CacheLumpName(DEH_String("STCFN063"), PU_CACHE); else patch = W_CacheLumpNum(lumpnum, PU_STATIC); V_DrawPatch(icon_x, 182, patch); ST_drawNumFontY(num_x, 191, plyr->inventory[i].amount); } // haleyjd 20100919: Draw sigil icon if(plyr->weaponowned[wp_sigil]) V_DrawPatch(253, 175, invsigil[plyr->sigiltype]); // haleyjd 20100919: Draw ammo if(st_lastammo < NUMAMMO) V_DrawPatch(290, 180, invammo[st_lastammo]); // haleyjd 20100919: Draw armor if(plyr->armortype) { V_DrawPatch(2, 177, invarmor[plyr->armortype - 1]); ST_drawNumFontY(20, 191, plyr->armorpoints); } // haleyjd 20100920: Draw life bars. { int barlength; int lifecolor1; int lifecolor2; barlength = plyr->health; if(barlength > 100) barlength = 200 - plyr->health; barlength *= 2; if(plyr->health < 11) // Danger, Will Robinson! lifecolor1 = 64; else if(plyr->health < 21) // Caution lifecolor1 = 80; else // All is well. lifecolor1 = 96; if(plyr->cheats & CF_GODMODE) // Gold, probably a throwback to DOOM. lifecolor1 = 226; lifecolor2 = lifecolor1 + 3; // Draw the normal health bars ST_drawLine(49, 172, barlength, lifecolor1); ST_drawLine(49, 173, barlength, lifecolor2); ST_drawLine(49, 175, barlength, lifecolor1); ST_drawLine(49, 176, barlength, lifecolor2); // Draw the > 100 health lines if(plyr->health > 100) { int oldbarlength = barlength; lifecolor1 = 112; // Shades of blue lifecolor2 = lifecolor1 + 3; // take up the difference not drawn by the first (<= 100) bar barlength = 200 - barlength; ST_drawLine(49 + oldbarlength, 172, barlength, lifecolor1); ST_drawLine(49 + oldbarlength, 173, barlength, lifecolor2); ST_drawLine(49 + oldbarlength, 175, barlength, lifecolor1); ST_drawLine(49 + oldbarlength, 176, barlength, lifecolor2); } } // end local-scope block // haleyjd 20100919: nope, not in Strife. //V_RestoreBuffer(); //V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y); } } // haleyjd [STRIFE]: Removed ST_diffDraw void ST_Drawer (boolean fullscreen, boolean refresh) { st_statusbaron = (!fullscreen) || automapactive; st_firsttime = st_firsttime || refresh; // Do red-/gold-shifts from damage/items ST_doPaletteStuff(); // If just after ST_Start(), refresh all ST_doRefresh(); // Otherwise, update as little as possible //ST_diffDraw(); [STRIFE]: nope } // // ST_calcFrags // // haleyjd [STRIFE] New function. // Calculate frags for display on the frags popup. // static int ST_calcFrags(int pnum) { int i; int result = 0; for(i = 0; i < MAXPLAYERS; i++) { if(i == pnum) // self-frags result -= players[pnum].frags[i]; else result += players[pnum].frags[i]; } return result; } // // ST_drawTime // // villsa [STRIFE] New function. // Draws game time on pop up screen // static void ST_drawTime(int x, int y, int time) { int hours; int minutes; int seconds; char string[16]; // haleyjd 20110213: fixed minutes hours = time / 3600; minutes = (time / 60) % 60; seconds = time % 60; DEH_snprintf(string, 16, "%02d:%02d:%02d", hours, minutes, seconds); HUlib_drawYellowText(x, y, string); } #define ST_KEYSPERPAGE 10 #define ST_KEYS_X 20 #define ST_KEYS_Y 63 #define ST_KEYNAME_X 17 #define ST_KEYNAME_Y 4 #define ST_KEYS_YSTEP 17 #define ST_KEYS_NUMROWS 4 #define ST_KEYS_COL2X 160 // // ST_drawKeysPopup // // haleyjd 20110213: [STRIFE] New function // This has taken the longest out of almost everything to get working properly. // static boolean ST_drawKeysPopup(void) { int x, y, yt, key, keycount; mobjinfo_t *info; V_DrawXlaPatch(0, 56, invpbak2); V_DrawPatchDirect(0, 56, invpop2); if(deathmatch) { int pnum; patch_t *colpatch; char buffer[128]; int frags; // In deathmatch, the keys popup is replaced by a chart of frag counts // first column y = 64; yt = 66; for(pnum = 0; pnum < MAXPLAYERS/2; pnum++) { DEH_snprintf(buffer, sizeof(buffer), "stcolor%d", pnum+1); colpatch = W_CacheLumpName(buffer, PU_CACHE); V_DrawPatchDirect(28, y, colpatch); frags = ST_calcFrags(pnum); DEH_snprintf(buffer, sizeof(buffer), "%s%d", player_names[pnum], frags); HUlib_drawYellowText(38, yt, buffer); if(!playeringame[pnum]) HUlib_drawYellowText(28, pnum*17 + 65, "X"); y += 17; yt += 17; } // second column y = 64; yt = 66; for(pnum = MAXPLAYERS/2; pnum < MAXPLAYERS; pnum++) { DEH_snprintf(buffer, sizeof(buffer), "stcolor%d", pnum+1); colpatch = W_CacheLumpName(buffer, PU_CACHE); V_DrawPatchDirect(158, y, colpatch); frags = ST_calcFrags(pnum); DEH_snprintf(buffer, sizeof(buffer), "%s%d", player_names[pnum], frags); HUlib_drawYellowText(168, yt, buffer); if(!playeringame[pnum]) HUlib_drawYellowText(158, pnum*17 - 3, "X"); y += 17; yt += 17; } } else { // Bounds-check page number if(st_keypage < 0 || st_keypage > 2) { st_keypage = -1; st_popupdisplaytics = 0; st_displaypopup = false; return false; } // Are there any keys to display on this page? if(st_keypage > 0) { boolean haskeyinrange = false; for(key = ST_KEYSPERPAGE * st_keypage, keycount = 0; keycount < ST_KEYSPERPAGE && key < NUMCARDS; ++key, ++keycount) { if(plyr->cards[key]) haskeyinrange = true; } if(!haskeyinrange) { st_displaypopup = false; st_showkeys = false; st_keypage = -1; return false; } } // Draw the keys for the current page key = ST_KEYSPERPAGE * st_keypage; keycount = 0; x = ST_KEYS_X; y = ST_KEYS_Y; info = &mobjinfo[MT_KEY_BASE + key]; for(; keycount < ST_KEYSPERPAGE && key < NUMCARDS; ++key, ++keycount, ++info) { char sprname[8]; patch_t *patch; memset(sprname, 0, sizeof(sprname)); if(plyr->cards[key]) { // Get spawnstate sprite name and load corresponding icon DEH_snprintf(sprname, sizeof(sprname), "I_%s", sprnames[states[info->spawnstate].sprite]); patch = W_CacheLumpName(sprname, PU_CACHE); V_DrawPatchDirect(x, y, patch); HUlib_drawYellowText(x + ST_KEYNAME_X, y + ST_KEYNAME_Y, info->name); } if(keycount != ST_KEYS_NUMROWS) y += ST_KEYS_YSTEP; else { x = ST_KEYS_COL2X; y = ST_KEYS_Y; } } } return true; } // // ST_DrawExternal // // haleyjd 20100901: [STRIFE] New function. // * Draws external portions of the status bar such the top bar and popups. // boolean ST_DrawExternal(void) { int i; if(st_statusbaron) { V_DrawPatchDirect(0, 160, invtop); STlib_drawNumPositive(&w_health); STlib_drawNumPositive(&w_ready); } else { ammotype_t ammo; ST_drawNumFontY2(15, 194, plyr->health); ammo = weaponinfo[plyr->readyweapon].ammo; if (ammo != am_noammo) ST_drawNumFontY2(310, 194, plyr->ammo[ammo]); } if(!st_displaypopup) return false; // villsa [STRIFE] added 20100926 if(st_showobjective) { V_DrawXlaPatch(0, 56, invpbak2); V_DrawPatchDirect(0, 56, invpop2); M_DialogDimMsg(24, 74, mission_objective, true); HUlib_drawYellowText(24, 74, mission_objective); ST_drawTime(210, 64, leveltime / TICRATE); } else { int keys = 0; // villsa [STRIFE] keys popup if(st_showkeys || st_popupdisplaytics) return ST_drawKeysPopup(); V_DrawXlaPatch(0, 56, invpbak); V_DrawPatchDirect(0, 56, invpop); for(i = 0; i < NUMCARDS; i++) { if(plyr->cards[i]) keys++; } ST_drawNumFontY2(261, 132, keys); if(plyr->weaponowned[wp_elecbow]) { V_DrawPatchDirect(38, 86, W_CacheLumpName(DEH_String("CBOWA0"), PU_CACHE)); } if(plyr->weaponowned[wp_rifle]) { V_DrawPatchDirect(40, 107, W_CacheLumpName(DEH_String("RIFLA0"), PU_CACHE)); } if(plyr->weaponowned[wp_missile]) { V_DrawPatchDirect(39, 131, W_CacheLumpName(DEH_String("MMSLA0"), PU_CACHE)); } if(plyr->weaponowned[wp_hegrenade]) { V_DrawPatchDirect(78, 87, W_CacheLumpName(DEH_String("GRNDA0"), PU_CACHE)); } if(plyr->weaponowned[wp_flame]) { V_DrawPatchDirect(80, 117, W_CacheLumpName(DEH_String("FLAMA0"), PU_CACHE)); } if(plyr->weaponowned[wp_mauler]) { V_DrawPatchDirect(75, 142, W_CacheLumpName(DEH_String("TRPDA0"), PU_CACHE)); } // haleyjd 20110213: draw ammo for(i = 0; i < NUMAMMO; i++) { STlib_drawNumPositive(&w_ammo[i]); STlib_drawNumPositive(&w_maxammo[i]); } ST_drawNumFontY2(261, 84, plyr->accuracy); ST_drawNumFontY2(261, 108, plyr->stamina); if(plyr->powers[pw_communicator]) { V_DrawPatchDirect(280, 130, W_CacheLumpName(DEH_String("I_COMM"), PU_CACHE)); } } return true; } typedef void (*load_callback_t)(char *lumpname, patch_t **variable); // // ST_loadUnloadGraphics // // Iterates through all graphics to be loaded or unloaded, along with // the variable they use, invoking the specified callback function. // // [STRIFE] Altered to load all Strife status bar resources. // static void ST_loadUnloadGraphics(load_callback_t callback) { int i; char namebuf[9]; // haleyjd 20100901: [STRIFE] // Load the numbers, green and yellow for (i=0;i<10;i++) { DEH_snprintf(namebuf, 9, "INVFONG%d", i); callback(namebuf, &invfontg[i]); DEH_snprintf(namebuf, 9, "INVFONY%d", i); callback(namebuf, &invfonty[i]); } // haleyjd 20100919: load Sigil patches if(!isdemoversion) { for(i = 0; i < 5; i++) { DEH_snprintf(namebuf, 9, "I_SGL%d", i+1); callback(namebuf, &invsigil[i]); } } // load ammo patches for(i = 0; i < NUMAMMO; i++) callback(DEH_String(invammonames[i]), &invammo[i]); // load armor patches callback(DEH_String("I_ARM2"), &invarmor[0]); callback(DEH_String("I_ARM1"), &invarmor[1]); // haleyjd 20100919: [STRIFE] // * No face, but there is this patch, which appears behind the armor DEH_snprintf(namebuf, 9, "STBACK0%d", consoleplayer + 1); if(netgame) callback(namebuf, &stback); // 20100901: // * Removed all unused DOOM stuff (arms, numbers, %, etc). // haleyjd 20100901: [STRIFE]: stbar -> invback, added new patches // status bar background bits callback(DEH_String("INVBACK"), &invback); callback(DEH_String("INVTOP"), &invtop); callback(DEH_String("INVPOP"), &invpop); callback(DEH_String("INVPOP2"), &invpop2); callback(DEH_String("INVPBAK"), &invpbak); callback(DEH_String("INVPBAK2"), &invpbak2); callback(DEH_String("INVCURS"), &invcursor); } static void ST_loadCallback(char *lumpname, patch_t **variable) { *variable = W_CacheLumpName(lumpname, PU_STATIC); } void ST_loadGraphics(void) { ST_loadUnloadGraphics(ST_loadCallback); } void ST_loadData(void) { // static int dword_8848C = 1; // STRIFE-TODO: what is the purpose of this? // dword_8848C = 0; lu_palette = W_GetNumForName (DEH_String("PLAYPAL")); ST_loadGraphics(); } static void ST_unloadCallback(char *lumpname, patch_t **variable) { W_ReleaseLumpName(lumpname); *variable = NULL; } void ST_unloadGraphics(void) { ST_loadUnloadGraphics(ST_unloadCallback); } void ST_unloadData(void) { ST_unloadGraphics(); } // // ST_initData // // haleyjd 20100901: [STRIFE] // * Removed prebeta cruft, face stuff, keyboxes, and oldwe // void ST_initData(void) { st_firsttime = true; plyr = &players[consoleplayer]; st_gamestate = FirstPersonState; st_statusbaron = true; st_palette = -1; STlib_init(); } void ST_createWidgets(void) { int i; // ready weapon ammo STlib_initNum(&w_ready, ST_AMMOX, ST_AMMOY, invfontg, &plyr->ammo[weaponinfo[plyr->readyweapon].ammo], ST_AMMOWIDTH); // the last weapon type w_ready.data = plyr->readyweapon; // health percentage STlib_initNum(&w_health, ST_HEALTHX, ST_HEALTHY, invfontg, &plyr->health, ST_HEALTHWIDTH); // haleyjd 20100831: [STRIFE] // * No face. // 20100901: // * No arms, weaponsowned, frags, armor, keyboxes // haleyjd 20110213: Ammo Widgets!!! for(i = 0; i < NUMAMMO; i++) { STlib_initNum(&w_ammo[i], ST_POPUPAMMOX, st_yforammo[i], invfonty, &plyr->ammo[i], st_wforammo[i]); STlib_initNum(&w_maxammo[i], ST_POPUPMAXAMMOX, st_yforammo[i], invfonty, &plyr->maxammo[i], st_wforammo[i]); } } static boolean st_stopped = true; void ST_Start (void) { if (!st_stopped) ST_Stop(); ST_initData(); ST_createWidgets(); st_stopped = false; } void ST_Stop (void) { if (st_stopped) return; I_SetPalette (W_CacheLumpNum (lu_palette, PU_CACHE)); st_stopped = true; } void ST_Init (void) { ST_loadData(); // haleyjd 20100919: This is not used by Strife. More memory for voices! //st_backing_screen = (byte *) Z_Malloc(ST_WIDTH * ST_HEIGHT, PU_STATIC, 0); } chocolate-doom-chocolate-doom-2.2.1/src/strife/st_stuff.h000066400000000000000000000051231257432200600233770ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Status bar code. // Does the face/direction indicator animatin. // Does palette indicators as well (red pain/berserk, bright pickup) // #ifndef __STSTUFF_H__ #define __STSTUFF_H__ #include "doomtype.h" #include "d_event.h" #include "m_cheat.h" // Size of statusbar. // Now sensitive for scaling. #define ST_HEIGHT 32 #define ST_WIDTH SCREENWIDTH #define ST_Y (SCREENHEIGHT - ST_HEIGHT) // // STATUS BAR // // Called by main loop. boolean ST_Responder (event_t* ev); // Called by main loop. void ST_Ticker (void); // Called by main loop. void ST_Drawer (boolean fullscreen, boolean refresh); // haleyjd 09/01/10: [STRIFE] New function. // Called by main loop to draw external status bar bits. // Returns true if a popup is drawing. boolean ST_DrawExternal(void); // Called when the console player is spawned on each level. void ST_Start (void); // Called by startup code. void ST_Init (void); // States for status bar code. typedef enum { AutomapState, FirstPersonState } st_stateenum_t; // States for the chat code. typedef enum { StartChatState, WaitDestState, GetChatState } st_chatstateenum_t; extern byte *st_backing_screen; extern cheatseq_t cheat_mus; // [STRIFE]: idmus -> spin extern cheatseq_t cheat_god; // [STRIFE]: iddqd -> omnipotent extern cheatseq_t cheat_ammo; // [STRIFE]: idfa -> boomstix extern cheatseq_t cheat_noclip; // [STRIFE]: idclip -> elvis extern cheatseq_t cheat_clev; // [STRIFE]: idclev -> rift extern cheatseq_t cheat_mypos; // [STRIFE]: idmypos -> gps extern cheatseq_t cheat_scoot; // [STRIFE]: new cheat scoot extern cheatseq_t cheat_nuke; // [STRIFE]: new cheat stonecold extern cheatseq_t cheat_keys; // [STRIFE]: new cheat jimmy (all keys) extern cheatseq_t cheat_stealth; // [STRIFE]: new cheat gripper extern cheatseq_t cheat_midas; // [STRIFE]: new cheat extern cheatseq_t cheat_lego; // [STRIFE]: new cheat extern cheatseq_t cheat_dev; // [STRIFE]: new cheat extern cheatseq_t cheat_powerup[]; #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/wi_stuff.c000066400000000000000000001022471257432200600233700ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Intermission screens. // // haleyjd 08/23/2010: There is no intermission in Strife #if 0 #include #include "z_zone.h" #include "m_random.h" #include "deh_main.h" #include "i_swap.h" #include "i_system.h" #include "w_wad.h" #include "g_game.h" #include "r_local.h" #include "s_sound.h" #include "doomstat.h" // Data. #include "sounds.h" // Needs access to LFB. #include "v_video.h" #include "wi_stuff.h" // // Data needed to add patches to full screen intermission pics. // Patches are statistics messages, and animations. // Loads of by-pixel layout and placement, offsets etc. // // // Different vetween registered DOOM (1994) and // Ultimate DOOM - Final edition (retail, 1995?). // This is supposedly ignored for commercial // release (aka DOOM II), which had 34 maps // in one episode. So there. #define NUMEPISODES 4 #define NUMMAPS 9 // in tics //U #define PAUSELEN (TICRATE*2) //U #define SCORESTEP 100 //U #define ANIMPERIOD 32 // pixel distance from "(YOU)" to "PLAYER N" //U #define STARDIST 10 //U #define WK 1 // GLOBAL LOCATIONS #define WI_TITLEY 2 #define WI_SPACINGY 33 // SINGPLE-PLAYER STUFF #define SP_STATSX 50 #define SP_STATSY 50 #define SP_TIMEX 16 #define SP_TIMEY (SCREENHEIGHT-32) // NET GAME STUFF #define NG_STATSY 50 #define NG_STATSX (32 + SHORT(star->width)/2 + 32*!dofrags) #define NG_SPACINGX 64 // DEATHMATCH STUFF #define DM_MATRIXX 42 #define DM_MATRIXY 68 #define DM_SPACINGX 40 #define DM_TOTALSX 269 #define DM_KILLERSX 10 #define DM_KILLERSY 100 #define DM_VICTIMSX 5 #define DM_VICTIMSY 50 typedef enum { ANIM_ALWAYS, ANIM_RANDOM, ANIM_LEVEL } animenum_t; typedef struct { int x; int y; } point_t; // // Animation. // There is another anim_t used in p_spec. // typedef struct { animenum_t type; // period in tics between animations int period; // number of animation frames int nanims; // location of animation point_t loc; // ALWAYS: n/a, // RANDOM: period deviation (<256), // LEVEL: level int data1; // ALWAYS: n/a, // RANDOM: random base period, // LEVEL: n/a int data2; // actual graphics for frames of animations patch_t* p[3]; // following must be initialized to zero before use! // next value of bcnt (used in conjunction with period) int nexttic; // last drawn animation frame int lastdrawn; // next frame number to animate int ctr; // used by RANDOM and LEVEL when animating int state; } anim_t; static point_t lnodes[NUMEPISODES][NUMMAPS] = { // Episode 0 World Map { { 185, 164 }, // location of level 0 (CJ) { 148, 143 }, // location of level 1 (CJ) { 69, 122 }, // location of level 2 (CJ) { 209, 102 }, // location of level 3 (CJ) { 116, 89 }, // location of level 4 (CJ) { 166, 55 }, // location of level 5 (CJ) { 71, 56 }, // location of level 6 (CJ) { 135, 29 }, // location of level 7 (CJ) { 71, 24 } // location of level 8 (CJ) }, // Episode 1 World Map should go here { { 254, 25 }, // location of level 0 (CJ) { 97, 50 }, // location of level 1 (CJ) { 188, 64 }, // location of level 2 (CJ) { 128, 78 }, // location of level 3 (CJ) { 214, 92 }, // location of level 4 (CJ) { 133, 130 }, // location of level 5 (CJ) { 208, 136 }, // location of level 6 (CJ) { 148, 140 }, // location of level 7 (CJ) { 235, 158 } // location of level 8 (CJ) }, // Episode 2 World Map should go here { { 156, 168 }, // location of level 0 (CJ) { 48, 154 }, // location of level 1 (CJ) { 174, 95 }, // location of level 2 (CJ) { 265, 75 }, // location of level 3 (CJ) { 130, 48 }, // location of level 4 (CJ) { 279, 23 }, // location of level 5 (CJ) { 198, 48 }, // location of level 6 (CJ) { 140, 25 }, // location of level 7 (CJ) { 281, 136 } // location of level 8 (CJ) } }; // // Animation locations for episode 0 (1). // Using patches saves a lot of space, // as they replace 320x200 full screen frames. // #define ANIM(type, period, nanims, x, y, nexttic) \ { (type), (period), (nanims), { (x), (y) }, (nexttic), \ 0, { NULL, NULL, NULL }, 0, 0, 0, 0 } static anim_t epsd0animinfo[] = { ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0), }; static anim_t epsd1animinfo[] = { ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7), ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8), ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8), }; static anim_t epsd2animinfo[] = { ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0), ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0), ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0), }; static int NUMANIMS[NUMEPISODES] = { arrlen(epsd0animinfo), arrlen(epsd1animinfo), arrlen(epsd2animinfo), }; static anim_t *anims[NUMEPISODES] = { epsd0animinfo, epsd1animinfo, epsd2animinfo }; // // GENERAL DATA // // // Locally used stuff. // // States for single-player #define SP_KILLS 0 #define SP_ITEMS 2 #define SP_SECRET 4 #define SP_FRAGS 6 #define SP_TIME 8 #define SP_PAR ST_TIME #define SP_PAUSE 1 // in seconds #define SHOWNEXTLOCDELAY 4 //#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY // used to accelerate or skip a stage static int acceleratestage; // wbs->pnum static int me; // specifies current state static stateenum_t state; // contains information passed into intermission static wbstartstruct_t* wbs; static wbplayerstruct_t* plrs; // wbs->plyr[] // used for general timing static int cnt; // used for timing of background animation static int bcnt; // signals to refresh everything for one frame static int firstrefresh; static int cnt_kills[MAXPLAYERS]; static int cnt_items[MAXPLAYERS]; static int cnt_secret[MAXPLAYERS]; static int cnt_time; static int cnt_par; static int cnt_pause; // # of commercial levels static int NUMCMAPS; // // GRAPHICS // // You Are Here graphic static patch_t* yah[3] = { NULL, NULL, NULL }; // splat static patch_t* splat[2] = { NULL, NULL }; // %, : graphics static patch_t* percent; static patch_t* colon; // 0-9 graphic static patch_t* num[10]; // minus sign static patch_t* wiminus; // "Finished!" graphics static patch_t* finished; // "Entering" graphic static patch_t* entering; // "secret" static patch_t* sp_secret; // "Kills", "Scrt", "Items", "Frags" static patch_t* kills; static patch_t* secret; static patch_t* items; static patch_t* frags; // Time sucks. static patch_t* timepatch; static patch_t* par; static patch_t* sucks; // "killers", "victims" static patch_t* killers; static patch_t* victims; // "Total", your face, your dead face static patch_t* total; static patch_t* star; static patch_t* bstar; // "red P[1..MAXPLAYERS]" static patch_t* p[MAXPLAYERS]; // "gray P[1..MAXPLAYERS]" static patch_t* bp[MAXPLAYERS]; // Name graphics of each level (centered) static patch_t** lnames; // Buffer storing the backdrop static patch_t *background; // // CODE // // slam background void WI_slamBackground(void) { V_DrawPatch(0, 0, background); } // The ticker is used to detect keys // because of timing issues in netgames. boolean WI_Responder(event_t* ev) { return false; } // Draws " Finished!" void WI_drawLF(void) { int y = WI_TITLEY; if (gamemode != commercial || wbs->last < NUMCMAPS) { // draw V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2, y, lnames[wbs->last]); // draw "Finished!" y += (5*SHORT(lnames[wbs->last]->height))/4; V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished); } else if (wbs->last == NUMCMAPS) { // MAP33 - nothing is displayed! } else if (wbs->last > NUMCMAPS) { // > MAP33. Doom bombs out here with a Bad V_DrawPatch error. // I'm pretty sure that doom2.exe is just reading into random // bits of memory at this point, but let's try to be accurate // anyway. This deliberately triggers a V_DrawPatch error. patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1, { 0, 0, 0, 0, 0, 0, 0, 0 } }; V_DrawPatch(0, y, &tmp); } } // Draws "Entering " void WI_drawEL(void) { int y = WI_TITLEY; // draw "Entering" V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2, y, entering); // draw level y += (5*SHORT(lnames[wbs->next]->height))/4; V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2, y, lnames[wbs->next]); } void WI_drawOnLnode ( int n, patch_t* c[] ) { int i; int left; int top; int right; int bottom; boolean fits = false; i = 0; do { left = lnodes[wbs->epsd][n].x - SHORT(c[i]->leftoffset); top = lnodes[wbs->epsd][n].y - SHORT(c[i]->topoffset); right = left + SHORT(c[i]->width); bottom = top + SHORT(c[i]->height); if (left >= 0 && right < SCREENWIDTH && top >= 0 && bottom < SCREENHEIGHT) { fits = true; } else { i++; } } while (!fits && i!=2 && c[i] != NULL); if (fits && i<2) { V_DrawPatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, c[i]); } else { // DEBUG printf("Could not place patch on level %d", n+1); } } void WI_initAnimatedBack(void) { int i; anim_t* a; if (gamemode == commercial) return; if (wbs->epsd > 2) return; for (i=0;iepsd];i++) { a = &anims[wbs->epsd][i]; // init variables a->ctr = -1; // specify the next time to draw it if (a->type == ANIM_ALWAYS) a->nexttic = bcnt + 1 + (M_Random()%a->period); else if (a->type == ANIM_RANDOM) a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1); else if (a->type == ANIM_LEVEL) a->nexttic = bcnt + 1; } } void WI_updateAnimatedBack(void) { int i; anim_t* a; if (gamemode == commercial) return; if (wbs->epsd > 2) return; for (i=0;iepsd];i++) { a = &anims[wbs->epsd][i]; if (bcnt == a->nexttic) { switch (a->type) { case ANIM_ALWAYS: if (++a->ctr >= a->nanims) a->ctr = 0; a->nexttic = bcnt + a->period; break; case ANIM_RANDOM: a->ctr++; if (a->ctr == a->nanims) { a->ctr = -1; a->nexttic = bcnt+a->data2+(M_Random()%a->data1); } else a->nexttic = bcnt + a->period; break; case ANIM_LEVEL: // gawd-awful hack for level anims if (!(state == StatCount && i == 7) && wbs->next == a->data1) { a->ctr++; if (a->ctr == a->nanims) a->ctr--; a->nexttic = bcnt + a->period; } break; } } } } void WI_drawAnimatedBack(void) { int i; anim_t* a; if (gamemode == commercial) return; if (wbs->epsd > 2) return; for (i=0 ; iepsd] ; i++) { a = &anims[wbs->epsd][i]; if (a->ctr >= 0) V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]); } } // // Draws a number. // If digits > 0, then use that many digits minimum, // otherwise only use as many as necessary. // Returns new x position. // int WI_drawNum ( int x, int y, int n, int digits ) { int fontwidth = SHORT(num[0]->width); int neg; int temp; if (digits < 0) { if (!n) { // make variable-length zeros 1 digit long digits = 1; } else { // figure out # of digits in # digits = 0; temp = n; while (temp) { temp /= 10; digits++; } } } neg = n < 0; if (neg) n = -n; // if non-number, do not draw it if (n == 1994) return 0; // draw the new number while (digits--) { x -= fontwidth; V_DrawPatch(x, y, num[ n % 10 ]); n /= 10; } // draw a minus sign if necessary if (neg) V_DrawPatch(x-=8, y, wiminus); return x; } void WI_drawPercent ( int x, int y, int p ) { if (p < 0) return; V_DrawPatch(x, y, percent); WI_drawNum(x, y, p, -1); } // // Display level completion time and par, // or "sucks" message if overflow. // void WI_drawTime ( int x, int y, int t ) { int div; int n; if (t<0) return; if (t <= 61*59) { div = 1; do { n = (t / div) % 60; x = WI_drawNum(x, y, n, 2) - SHORT(colon->width); div *= 60; // draw if (div==60 || t / div) V_DrawPatch(x, y, colon); } while (t / div); } else { // "sucks" V_DrawPatch(x - SHORT(sucks->width), y, sucks); } } void WI_End(void) { void WI_unloadData(void); WI_unloadData(); } void WI_initNoState(void) { state = NoState; acceleratestage = 0; cnt = 10; } void WI_updateNoState(void) { WI_updateAnimatedBack(); if (!--cnt) { // Don't call WI_End yet. G_WorldDone doesnt immediately // change gamestate, so WI_Drawer is still going to get // run until that happens. If we do that after WI_End // (which unloads all the graphics), we're in trouble. //WI_End(); G_WorldDone(); } } static boolean snl_pointeron = false; void WI_initShowNextLoc(void) { state = ShowNextLoc; acceleratestage = 0; cnt = SHOWNEXTLOCDELAY * TICRATE; WI_initAnimatedBack(); } void WI_updateShowNextLoc(void) { WI_updateAnimatedBack(); if (!--cnt || acceleratestage) WI_initNoState(); else snl_pointeron = (cnt & 31) < 20; } void WI_drawShowNextLoc(void) { int i; int last; WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); if ( gamemode != commercial) { if (wbs->epsd > 2) { WI_drawEL(); return; } last = (wbs->last == 8) ? wbs->next - 1 : wbs->last; // draw a splat on taken cities. for (i=0 ; i<=last ; i++) WI_drawOnLnode(i, splat); // splat the secret level? if (wbs->didsecret) WI_drawOnLnode(8, splat); // draw flashing ptr if (snl_pointeron) WI_drawOnLnode(wbs->next, yah); } // draws which level you are entering.. if ( (gamemode != commercial) || wbs->next != 30) WI_drawEL(); } void WI_drawNoState(void) { snl_pointeron = true; WI_drawShowNextLoc(); } int WI_fragSum(int playernum) { int i; int frags = 0; for (i=0 ; i 99) dm_frags[i][j] = 99; if (dm_frags[i][j] < -99) dm_frags[i][j] = -99; stillticking = true; } } dm_totals[i] = WI_fragSum(i); if (dm_totals[i] > 99) dm_totals[i] = 99; if (dm_totals[i] < -99) dm_totals[i] = -99; } } if (!stillticking) { S_StartSound(0, sfx_barexp); dm_state++; } } else if (dm_state == 4) { if (acceleratestage) { S_StartSound(0, sfx_slop); if ( gamemode == commercial) WI_initNoState(); else WI_initShowNextLoc(); } } else if (dm_state & 1) { if (!--cnt_pause) { dm_state++; cnt_pause = TICRATE; } } } void WI_drawDeathmatchStats(void) { int i; int j; int x; int y; int w; int lh; // line height lh = WI_SPACINGY; WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); WI_drawLF(); // draw stat titles (top line) V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2, DM_MATRIXY-WI_SPACINGY+10, total); V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers); V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims); // draw P? x = DM_MATRIXX + DM_SPACINGX; y = DM_MATRIXY; for (i=0 ; iwidth)/2, DM_MATRIXY - WI_SPACINGY, p[i]); V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, p[i]); if (i == me) { V_DrawPatch(x-SHORT(p[i]->width)/2, DM_MATRIXY - WI_SPACINGY, bstar); V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, star); } } else { // V_DrawPatch(x-SHORT(bp[i]->width)/2, // DM_MATRIXY - WI_SPACINGY, bp[i]); // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2, // y, bp[i]); } x += DM_SPACINGX; y += WI_SPACINGY; } // draw stats y = DM_MATRIXY+10; w = SHORT(num[0]->width); for (i=0 ; imaxkills; cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret; if (dofrags) cnt_frags[i] = WI_fragSum(i); } S_StartSound(0, sfx_barexp); ng_state = 10; } if (ng_state == 2) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (plrs[i].skills * 100) / wbs->maxkills) cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_barexp); ng_state++; } } else if (ng_state == 4) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (plrs[i].sitems * 100) / wbs->maxitems) cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_barexp); ng_state++; } } else if (ng_state == 6) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (plrs[i].ssecret * 100) / wbs->maxsecret) cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_barexp); ng_state += 1 + 2*!dofrags; } } else if (ng_state == 8) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); stillticking = false; for (i=0 ; i= (fsum = WI_fragSum(i))) cnt_frags[i] = fsum; else stillticking = true; } if (!stillticking) { S_StartSound(0, sfx_pldeth); ng_state++; } } else if (ng_state == 10) { if (acceleratestage) { S_StartSound(0, sfx_sgcock); if ( gamemode == commercial ) WI_initNoState(); else WI_initShowNextLoc(); } } else if (ng_state & 1) { if (!--cnt_pause) { ng_state++; cnt_pause = TICRATE; } } } void WI_drawNetgameStats(void) { int i; int x; int y; int pwidth = SHORT(percent->width); WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); WI_drawLF(); // draw stat titles (top line) V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width), NG_STATSY, kills); V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width), NG_STATSY, items); V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width), NG_STATSY, secret); if (dofrags) V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width), NG_STATSY, frags); // draw stats y = NG_STATSY + SHORT(kills->height); for (i=0 ; iwidth), y, p[i]); if (i == me) V_DrawPatch(x-SHORT(p[i]->width), y, star); x += NG_SPACINGX; WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX; WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX; WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX; if (dofrags) WI_drawNum(x, y+10, cnt_frags[i], -1); y += WI_SPACINGY; } } static int sp_state; void WI_initStats(void) { state = StatCount; acceleratestage = 0; sp_state = 1; cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1; cnt_time = cnt_par = -1; cnt_pause = TICRATE; WI_initAnimatedBack(); } void WI_updateStats(void) { WI_updateAnimatedBack(); if (acceleratestage && sp_state != 10) { acceleratestage = 0; cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret; cnt_time = plrs[me].stime / TICRATE; cnt_par = wbs->partime / TICRATE; S_StartSound(0, sfx_barexp); sp_state = 10; } if (sp_state == 2) { cnt_kills[0] += 2; if (!(bcnt&3)) S_StartSound(0, sfx_pistol); if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) { cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; S_StartSound(0, sfx_barexp); sp_state++; } } else if (sp_state == 4) { cnt_items[0] += 2; if (!(bcnt&3)) S_StartSound(0, sfx_pistol); if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) { cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; S_StartSound(0, sfx_barexp); sp_state++; } } else if (sp_state == 6) { cnt_secret[0] += 2; if (!(bcnt&3)) S_StartSound(0, sfx_pistol); if (cnt_secret[0] >= (plrs[me].ssecret * 100) / wbs->maxsecret) { cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret; S_StartSound(0, sfx_barexp); sp_state++; } } else if (sp_state == 8) { if (!(bcnt&3)) S_StartSound(0, sfx_pistol); cnt_time += 3; if (cnt_time >= plrs[me].stime / TICRATE) cnt_time = plrs[me].stime / TICRATE; cnt_par += 3; if (cnt_par >= wbs->partime / TICRATE) { cnt_par = wbs->partime / TICRATE; if (cnt_time >= plrs[me].stime / TICRATE) { S_StartSound(0, sfx_barexp); sp_state++; } } } else if (sp_state == 10) { if (acceleratestage) { S_StartSound(0, sfx_sgcock); if (gamemode == commercial) WI_initNoState(); else WI_initShowNextLoc(); } } else if (sp_state & 1) { if (!--cnt_pause) { sp_state++; cnt_pause = TICRATE; } } } void WI_drawStats(void) { // line height int lh; lh = (3*SHORT(num[0]->height))/2; WI_slamBackground(); // draw animated background WI_drawAnimatedBack(); WI_drawLF(); V_DrawPatch(SP_STATSX, SP_STATSY, kills); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]); V_DrawPatch(SP_STATSX, SP_STATSY+lh, items); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]); V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch); WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time); if (wbs->epsd < 3) { V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par); WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par); } } void WI_checkForAccelerate(void) { int i; player_t *player; // check for button presses to skip delays for (i=0, player = players ; icmd.buttons & BT_ATTACK) { if (!player->attackdown) acceleratestage = 1; player->attackdown = true; } else player->attackdown = false; if (player->cmd.buttons & BT_USE) { if (!player->usedown) acceleratestage = 1; player->usedown = true; } else player->usedown = false; } } } // Updates stuff each tick void WI_Ticker(void) { // counter for general background animation bcnt++; if (bcnt == 1) { // intermission music if ( gamemode == commercial ) S_ChangeMusic(mus_dm2int, true); else S_ChangeMusic(mus_inter, true); } WI_checkForAccelerate(); switch (state) { case StatCount: if (deathmatch) WI_updateDeathmatchStats(); else if (netgame) WI_updateNetgameStats(); else WI_updateStats(); break; case ShowNextLoc: WI_updateShowNextLoc(); break; case NoState: WI_updateNoState(); break; } } typedef void (*load_callback_t)(char *lumpname, patch_t **variable); // Common load/unload function. Iterates over all the graphics // lumps to be loaded/unloaded into memory. static void WI_loadUnloadData(load_callback_t callback) { int i, j; char name[9]; anim_t *a; if (gamemode == commercial) { for (i=0 ; iepsd, i); callback(name, &lnames[i]); } // you are here callback(DEH_String("WIURH0"), &yah[0]); // you are here (alt.) callback(DEH_String("WIURH1"), &yah[1]); // splat callback(DEH_String("WISPLAT"), &splat[0]); if (wbs->epsd < 3) { for (j=0;jepsd];j++) { a = &anims[wbs->epsd][j]; for (i=0;inanims;i++) { // MONDO HACK! if (wbs->epsd != 1 || j != 8) { // animations DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i); callback(name, &a->p[i]); } else { // HACK ALERT! a->p[i] = anims[1][4].p[i]; } } } } } // More hacks on minus sign. callback(DEH_String("WIMINUS"), &wiminus); for (i=0;i<10;i++) { // numbers 0-9 DEH_snprintf(name, 9, "WINUM%d", i); callback(name, &num[i]); } // percent sign callback(DEH_String("WIPCNT"), &percent); // "finished" callback(DEH_String("WIF"), &finished); // "entering" callback(DEH_String("WIENTER"), &entering); // "kills" callback(DEH_String("WIOSTK"), &kills); // "scrt" callback(DEH_String("WIOSTS"), &secret); // "secret" callback(DEH_String("WISCRT2"), &sp_secret); // french wad uses WIOBJ (?) if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0) { // "items" if (netgame && !deathmatch) callback(DEH_String("WIOBJ"), &items); else callback(DEH_String("WIOSTI"), &items); } else { callback(DEH_String("WIOSTI"), &items); } // "frgs" callback(DEH_String("WIFRGS"), &frags); // ":" callback(DEH_String("WICOLON"), &colon); // "time" callback(DEH_String("WITIME"), &timepatch); // "sucks" callback(DEH_String("WISUCKS"), &sucks); // "par" callback(DEH_String("WIPAR"), &par); // "killers" (vertical) callback(DEH_String("WIKILRS"), &killers); // "victims" (horiz) callback(DEH_String("WIVCTMS"), &victims); // "total" callback(DEH_String("WIMSTT"), &total); for (i=0 ; iepsd == 3) { M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name)); name[8] = '\0'; } else { DEH_snprintf(name, 9, "WIMAP%d", wbs->epsd); } // Draw backdrop and save to a temporary buffer callback(name, &background); } static void WI_loadCallback(char *name, patch_t **variable) { *variable = W_CacheLumpName(name, PU_STATIC); } void WI_loadData(void) { if (gamemode == commercial) { NUMCMAPS = 32; lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS, PU_STATIC, NULL); } else { lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS, PU_STATIC, NULL); } WI_loadUnloadData(WI_loadCallback); // These two graphics are special cased because we're sharing // them with the status bar code // your face star = W_CacheLumpName(DEH_String("STFST01"), PU_STATIC); // dead face bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC); } static void WI_unloadCallback(char *name, patch_t **variable) { W_ReleaseLumpName(name); *variable = NULL; } void WI_unloadData(void) { WI_loadUnloadData(WI_unloadCallback); // We do not free these lumps as they are shared with the status // bar code. // W_ReleaseLumpName("STFST01"); // W_ReleaseLumpName("STFDEAD0"); } void WI_Drawer (void) { switch (state) { case StatCount: if (deathmatch) WI_drawDeathmatchStats(); else if (netgame) WI_drawNetgameStats(); else WI_drawStats(); break; case ShowNextLoc: WI_drawShowNextLoc(); break; case NoState: WI_drawNoState(); break; } } void WI_initVariables(wbstartstruct_t* wbstartstruct) { wbs = wbstartstruct; #ifdef RANGECHECKING if (gamemode != commercial) { if ( gamemode == retail ) RNGCHECK(wbs->epsd, 0, 3); else RNGCHECK(wbs->epsd, 0, 2); } else { RNGCHECK(wbs->last, 0, 8); RNGCHECK(wbs->next, 0, 8); } RNGCHECK(wbs->pnum, 0, MAXPLAYERS); RNGCHECK(wbs->pnum, 0, MAXPLAYERS); #endif acceleratestage = 0; cnt = bcnt = 0; firstrefresh = 1; me = wbs->pnum; plrs = wbs->plyr; if (!wbs->maxkills) wbs->maxkills = 1; if (!wbs->maxitems) wbs->maxitems = 1; if (!wbs->maxsecret) wbs->maxsecret = 1; if ( gamemode != retail ) if (wbs->epsd > 2) wbs->epsd -= 3; } void WI_Start(wbstartstruct_t* wbstartstruct) { WI_initVariables(wbstartstruct); WI_loadData(); if (deathmatch) WI_initDeathmatchStats(); else if (netgame) WI_initNetgameStats(); else WI_initStats(); } #endif chocolate-doom-chocolate-doom-2.2.1/src/strife/wi_stuff.h000066400000000000000000000023251257432200600233710ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Intermission. // #ifndef __WI_STUFF__ #define __WI_STUFF__ // haleyjd 08/23/2010: Strife does not have an intermission #if 0 //#include "v_video.h" #include "doomdef.h" // States for the intermission typedef enum { NoState = -1, StatCount, ShowNextLoc, } stateenum_t; // Called by main loop, animate the intermission. void WI_Ticker (void); // Called by main loop, // draws the intermission directly into the screen buffer. void WI_Drawer (void); // Setup for an intermission screen. void WI_Start(wbstartstruct_t* wbstartstruct); // Shut down the intermission screen void WI_End(void); #endif #endif chocolate-doom-chocolate-doom-2.2.1/src/tables.c000066400000000000000000003763021257432200600215250ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Lookup tables. // Do not try to look them up :-). // In the order of appearance: // // int finetangent[4096] - Tangens LUT. // Should work with BAM fairly well (12 of 16bit, // effectively, by shifting). // // int finesine[10240] - Sine lookup. // Guess what, serves as cosine, too. // Remarkable thing is, how to use BAMs with this? // // int tantoangle[2049] - ArcTan LUT, // maps tan(angle) to angle fast. Gotta search. // // #include "tables.h" // to get a global angle from cartesian coordinates, the coordinates are // flipped until they are in the first octant of the coordinate system, then // the y (<=x) is scaled and divided by x to get a tangent (slope) value // which is looked up in the tantoangle[] table. The +1 size is to handle // the case when x==y without additional checking. int SlopeDiv(unsigned int num, unsigned int den) { unsigned ans; if (den < 512) { return SLOPERANGE; } else { ans = (num << 3) / (den >> 8); if (ans <= SLOPERANGE) { return ans; } else { return SLOPERANGE; } } } const int finetangent[4096] = { -170910304,-56965752,-34178904,-24413316,-18988036,-15535599,-13145455,-11392683, -10052327,-8994149,-8137527,-7429880,-6835455,-6329090,-5892567,-5512368, -5178251,-4882318,-4618375,-4381502,-4167737,-3973855,-3797206,-3635590, -3487165,-3350381,-3223918,-3106651,-2997613,-2895966,-2800983,-2712030, -2628549,-2550052,-2476104,-2406322,-2340362,-2277919,-2218719,-2162516, -2109087,-2058233,-2009771,-1963536,-1919378,-1877161,-1836758,-1798063, -1760956,-1725348,-1691149,-1658278,-1626658,-1596220,-1566898,-1538632, -1511367,-1485049,-1459630,-1435065,-1411312,-1388330,-1366084,-1344537, -1323658,-1303416,-1283783,-1264730,-1246234,-1228269,-1210813,-1193846, -1177345,-1161294,-1145673,-1130465,-1115654,-1101225,-1087164,-1073455, -1060087,-1047046,-1034322,-1021901,-1009774,-997931,-986361,-975054, -964003,-953199,-942633,-932298,-922186,-912289,-902602,-893117, -883829,-874730,-865817,-857081,-848520,-840127,-831898,-823827, -815910,-808143,-800521,-793041,-785699,-778490,-771411,-764460, -757631,-750922,-744331,-737853,-731486,-725227,-719074,-713023, -707072,-701219,-695462,-689797,-684223,-678737,-673338,-668024, -662792,-657640,-652568,-647572,-642651,-637803,-633028,-628323, -623686,-619117,-614613,-610174,-605798,-601483,-597229,-593033, -588896,-584815,-580789,-576818,-572901,-569035,-565221,-561456, -557741,-554074,-550455,-546881,-543354,-539870,-536431,-533034, -529680,-526366,-523094,-519861,-516667,-513512,-510394,-507313, -504269,-501261,-498287,-495348,-492443,-489571,-486732,-483925, -481150,-478406,-475692,-473009,-470355,-467730,-465133,-462565, -460024,-457511,-455024,-452564,-450129,-447720,-445337,-442978, -440643,-438332,-436045,-433781,-431540,-429321,-427125,-424951, -422798,-420666,-418555,-416465,-414395,-412344,-410314,-408303, -406311,-404338,-402384,-400448,-398530,-396630,-394747,-392882, -391034,-389202,-387387,-385589,-383807,-382040,-380290,-378555, -376835,-375130,-373440,-371765,-370105,-368459,-366826,-365208, -363604,-362013,-360436,-358872,-357321,-355783,-354257,-352744, -351244,-349756,-348280,-346816,-345364,-343924,-342495,-341078, -339671,-338276,-336892,-335519,-334157,-332805,-331464,-330133, -328812,-327502,-326201,-324910,-323629,-322358,-321097,-319844, -318601,-317368,-316143,-314928,-313721,-312524,-311335,-310154, -308983,-307819,-306664,-305517,-304379,-303248,-302126,-301011, -299904,-298805,-297714,-296630,-295554,-294485,-293423,-292369, -291322,-290282,-289249,-288223,-287204,-286192,-285186,-284188, -283195,-282210,-281231,-280258,-279292,-278332,-277378,-276430, -275489,-274553,-273624,-272700,-271782,-270871,-269965,-269064, -268169,-267280,-266397,-265519,-264646,-263779,-262917,-262060, -261209,-260363,-259522,-258686,-257855,-257029,-256208,-255392, -254581,-253774,-252973,-252176,-251384,-250596,-249813,-249035, -248261,-247492,-246727,-245966,-245210,-244458,-243711,-242967, -242228,-241493,-240763,-240036,-239314,-238595,-237881,-237170, -236463,-235761,-235062,-234367,-233676,-232988,-232304,-231624, -230948,-230275,-229606,-228941,-228279,-227621,-226966,-226314, -225666,-225022,-224381,-223743,-223108,-222477,-221849,-221225, -220603,-219985,-219370,-218758,-218149,-217544,-216941,-216341, -215745,-215151,-214561,-213973,-213389,-212807,-212228,-211652, -211079,-210509,-209941,-209376,-208815,-208255,-207699,-207145, -206594,-206045,-205500,-204956,-204416,-203878,-203342,-202809, -202279,-201751,-201226,-200703,-200182,-199664,-199149,-198636, -198125,-197616,-197110,-196606,-196105,-195606,-195109,-194614, -194122,-193631,-193143,-192658,-192174,-191693,-191213,-190736, -190261,-189789,-189318,-188849,-188382,-187918,-187455,-186995, -186536,-186080,-185625,-185173,-184722,-184274,-183827,-183382, -182939,-182498,-182059,-181622,-181186,-180753,-180321,-179891, -179463,-179037,-178612,-178190,-177769,-177349,-176932,-176516, -176102,-175690,-175279,-174870,-174463,-174057,-173653,-173251, -172850,-172451,-172053,-171657,-171263,-170870,-170479,-170089, -169701,-169315,-168930,-168546,-168164,-167784,-167405,-167027, -166651,-166277,-165904,-165532,-165162,-164793,-164426,-164060, -163695,-163332,-162970,-162610,-162251,-161893,-161537,-161182, -160828,-160476,-160125,-159775,-159427,-159079,-158734,-158389, -158046,-157704,-157363,-157024,-156686,-156349,-156013,-155678, -155345,-155013,-154682,-154352,-154024,-153697,-153370,-153045, -152722,-152399,-152077,-151757,-151438,-151120,-150803,-150487, -150172,-149859,-149546,-149235,-148924,-148615,-148307,-148000, -147693,-147388,-147084,-146782,-146480,-146179,-145879,-145580, -145282,-144986,-144690,-144395,-144101,-143808,-143517,-143226, -142936,-142647,-142359,-142072,-141786,-141501,-141217,-140934, -140651,-140370,-140090,-139810,-139532,-139254,-138977,-138701, -138426,-138152,-137879,-137607,-137335,-137065,-136795,-136526, -136258,-135991,-135725,-135459,-135195,-134931,-134668,-134406, -134145,-133884,-133625,-133366,-133108,-132851,-132594,-132339, -132084,-131830,-131576,-131324,-131072,-130821,-130571,-130322, -130073,-129825,-129578,-129332,-129086,-128841,-128597,-128353, -128111,-127869,-127627,-127387,-127147,-126908,-126669,-126432, -126195,-125959,-125723,-125488,-125254,-125020,-124787,-124555, -124324,-124093,-123863,-123633,-123404,-123176,-122949,-122722, -122496,-122270,-122045,-121821,-121597,-121374,-121152,-120930, -120709,-120489,-120269,-120050,-119831,-119613,-119396,-119179, -118963,-118747,-118532,-118318,-118104,-117891,-117678,-117466, -117254,-117044,-116833,-116623,-116414,-116206,-115998,-115790, -115583,-115377,-115171,-114966,-114761,-114557,-114354,-114151, -113948,-113746,-113545,-113344,-113143,-112944,-112744,-112546, -112347,-112150,-111952,-111756,-111560,-111364,-111169,-110974, -110780,-110586,-110393,-110200,-110008,-109817,-109626,-109435, -109245,-109055,-108866,-108677,-108489,-108301,-108114,-107927, -107741,-107555,-107369,-107184,-107000,-106816,-106632,-106449, -106266,-106084,-105902,-105721,-105540,-105360,-105180,-105000, -104821,-104643,-104465,-104287,-104109,-103933,-103756,-103580, -103404,-103229,-103054,-102880,-102706,-102533,-102360,-102187, -102015,-101843,-101671,-101500,-101330,-101159,-100990,-100820, -100651,-100482,-100314,-100146,-99979,-99812,-99645,-99479, -99313,-99148,-98982,-98818,-98653,-98489,-98326,-98163, -98000,-97837,-97675,-97513,-97352,-97191,-97030,-96870, -96710,-96551,-96391,-96233,-96074,-95916,-95758,-95601, -95444,-95287,-95131,-94975,-94819,-94664,-94509,-94354, -94200,-94046,-93892,-93739,-93586,-93434,-93281,-93129, -92978,-92826,-92675,-92525,-92375,-92225,-92075,-91926, -91777,-91628,-91480,-91332,-91184,-91036,-90889,-90742, -90596,-90450,-90304,-90158,-90013,-89868,-89724,-89579, -89435,-89292,-89148,-89005,-88862,-88720,-88577,-88435, -88294,-88152,-88011,-87871,-87730,-87590,-87450,-87310, -87171,-87032,-86893,-86755,-86616,-86479,-86341,-86204, -86066,-85930,-85793,-85657,-85521,-85385,-85250,-85114, -84980,-84845,-84710,-84576,-84443,-84309,-84176,-84043, -83910,-83777,-83645,-83513,-83381,-83250,-83118,-82987, -82857,-82726,-82596,-82466,-82336,-82207,-82078,-81949, -81820,-81691,-81563,-81435,-81307,-81180,-81053,-80925, -80799,-80672,-80546,-80420,-80294,-80168,-80043,-79918, -79793,-79668,-79544,-79420,-79296,-79172,-79048,-78925, -78802,-78679,-78557,-78434,-78312,-78190,-78068,-77947, -77826,-77705,-77584,-77463,-77343,-77223,-77103,-76983, -76864,-76744,-76625,-76506,-76388,-76269,-76151,-76033, -75915,-75797,-75680,-75563,-75446,-75329,-75213,-75096, -74980,-74864,-74748,-74633,-74517,-74402,-74287,-74172, -74058,-73944,-73829,-73715,-73602,-73488,-73375,-73262, -73149,-73036,-72923,-72811,-72699,-72587,-72475,-72363, -72252,-72140,-72029,-71918,-71808,-71697,-71587,-71477, -71367,-71257,-71147,-71038,-70929,-70820,-70711,-70602, -70494,-70385,-70277,-70169,-70061,-69954,-69846,-69739, -69632,-69525,-69418,-69312,-69205,-69099,-68993,-68887, -68781,-68676,-68570,-68465,-68360,-68255,-68151,-68046, -67942,-67837,-67733,-67629,-67526,-67422,-67319,-67216, -67113,-67010,-66907,-66804,-66702,-66600,-66498,-66396, -66294,-66192,-66091,-65989,-65888,-65787,-65686,-65586, -65485,-65385,-65285,-65185,-65085,-64985,-64885,-64786, -64687,-64587,-64488,-64389,-64291,-64192,-64094,-63996, -63897,-63799,-63702,-63604,-63506,-63409,-63312,-63215, -63118,-63021,-62924,-62828,-62731,-62635,-62539,-62443, -62347,-62251,-62156,-62060,-61965,-61870,-61775,-61680, -61585,-61491,-61396,-61302,-61208,-61114,-61020,-60926, -60833,-60739,-60646,-60552,-60459,-60366,-60273,-60181, -60088,-59996,-59903,-59811,-59719,-59627,-59535,-59444, -59352,-59261,-59169,-59078,-58987,-58896,-58805,-58715, -58624,-58534,-58443,-58353,-58263,-58173,-58083,-57994, -57904,-57815,-57725,-57636,-57547,-57458,-57369,-57281, -57192,-57104,-57015,-56927,-56839,-56751,-56663,-56575, -56487,-56400,-56312,-56225,-56138,-56051,-55964,-55877, -55790,-55704,-55617,-55531,-55444,-55358,-55272,-55186, -55100,-55015,-54929,-54843,-54758,-54673,-54587,-54502, -54417,-54333,-54248,-54163,-54079,-53994,-53910,-53826, -53741,-53657,-53574,-53490,-53406,-53322,-53239,-53156, -53072,-52989,-52906,-52823,-52740,-52657,-52575,-52492, -52410,-52327,-52245,-52163,-52081,-51999,-51917,-51835, -51754,-51672,-51591,-51509,-51428,-51347,-51266,-51185, -51104,-51023,-50942,-50862,-50781,-50701,-50621,-50540, -50460,-50380,-50300,-50221,-50141,-50061,-49982,-49902, -49823,-49744,-49664,-49585,-49506,-49427,-49349,-49270, -49191,-49113,-49034,-48956,-48878,-48799,-48721,-48643, -48565,-48488,-48410,-48332,-48255,-48177,-48100,-48022, -47945,-47868,-47791,-47714,-47637,-47560,-47484,-47407, -47331,-47254,-47178,-47102,-47025,-46949,-46873,-46797, -46721,-46646,-46570,-46494,-46419,-46343,-46268,-46193, -46118,-46042,-45967,-45892,-45818,-45743,-45668,-45593, -45519,-45444,-45370,-45296,-45221,-45147,-45073,-44999, -44925,-44851,-44778,-44704,-44630,-44557,-44483,-44410, -44337,-44263,-44190,-44117,-44044,-43971,-43898,-43826, -43753,-43680,-43608,-43535,-43463,-43390,-43318,-43246, -43174,-43102,-43030,-42958,-42886,-42814,-42743,-42671, -42600,-42528,-42457,-42385,-42314,-42243,-42172,-42101, -42030,-41959,-41888,-41817,-41747,-41676,-41605,-41535, -41465,-41394,-41324,-41254,-41184,-41113,-41043,-40973, -40904,-40834,-40764,-40694,-40625,-40555,-40486,-40416, -40347,-40278,-40208,-40139,-40070,-40001,-39932,-39863, -39794,-39726,-39657,-39588,-39520,-39451,-39383,-39314, -39246,-39178,-39110,-39042,-38973,-38905,-38837,-38770, -38702,-38634,-38566,-38499,-38431,-38364,-38296,-38229, -38161,-38094,-38027,-37960,-37893,-37826,-37759,-37692, -37625,-37558,-37491,-37425,-37358,-37291,-37225,-37158, -37092,-37026,-36959,-36893,-36827,-36761,-36695,-36629, -36563,-36497,-36431,-36365,-36300,-36234,-36168,-36103, -36037,-35972,-35907,-35841,-35776,-35711,-35646,-35580, -35515,-35450,-35385,-35321,-35256,-35191,-35126,-35062, -34997,-34932,-34868,-34803,-34739,-34675,-34610,-34546, -34482,-34418,-34354,-34289,-34225,-34162,-34098,-34034, -33970,-33906,-33843,-33779,-33715,-33652,-33588,-33525, -33461,-33398,-33335,-33272,-33208,-33145,-33082,-33019, -32956,-32893,-32830,-32767,-32705,-32642,-32579,-32516, -32454,-32391,-32329,-32266,-32204,-32141,-32079,-32017, -31955,-31892,-31830,-31768,-31706,-31644,-31582,-31520, -31458,-31396,-31335,-31273,-31211,-31150,-31088,-31026, -30965,-30904,-30842,-30781,-30719,-30658,-30597,-30536, -30474,-30413,-30352,-30291,-30230,-30169,-30108,-30048, -29987,-29926,-29865,-29805,-29744,-29683,-29623,-29562, -29502,-29441,-29381,-29321,-29260,-29200,-29140,-29080, -29020,-28959,-28899,-28839,-28779,-28719,-28660,-28600, -28540,-28480,-28420,-28361,-28301,-28241,-28182,-28122, -28063,-28003,-27944,-27884,-27825,-27766,-27707,-27647, -27588,-27529,-27470,-27411,-27352,-27293,-27234,-27175, -27116,-27057,-26998,-26940,-26881,-26822,-26763,-26705, -26646,-26588,-26529,-26471,-26412,-26354,-26295,-26237, -26179,-26120,-26062,-26004,-25946,-25888,-25830,-25772, -25714,-25656,-25598,-25540,-25482,-25424,-25366,-25308, -25251,-25193,-25135,-25078,-25020,-24962,-24905,-24847, -24790,-24732,-24675,-24618,-24560,-24503,-24446,-24389, -24331,-24274,-24217,-24160,-24103,-24046,-23989,-23932, -23875,-23818,-23761,-23704,-23647,-23591,-23534,-23477, -23420,-23364,-23307,-23250,-23194,-23137,-23081,-23024, -22968,-22911,-22855,-22799,-22742,-22686,-22630,-22573, -22517,-22461,-22405,-22349,-22293,-22237,-22181,-22125, -22069,-22013,-21957,-21901,-21845,-21789,-21733,-21678, -21622,-21566,-21510,-21455,-21399,-21343,-21288,-21232, -21177,-21121,-21066,-21010,-20955,-20900,-20844,-20789, -20734,-20678,-20623,-20568,-20513,-20457,-20402,-20347, -20292,-20237,-20182,-20127,-20072,-20017,-19962,-19907, -19852,-19797,-19742,-19688,-19633,-19578,-19523,-19469, -19414,-19359,-19305,-19250,-19195,-19141,-19086,-19032, -18977,-18923,-18868,-18814,-18760,-18705,-18651,-18597, -18542,-18488,-18434,-18380,-18325,-18271,-18217,-18163, -18109,-18055,-18001,-17946,-17892,-17838,-17784,-17731, -17677,-17623,-17569,-17515,-17461,-17407,-17353,-17300, -17246,-17192,-17138,-17085,-17031,-16977,-16924,-16870, -16817,-16763,-16710,-16656,-16603,-16549,-16496,-16442, -16389,-16335,-16282,-16229,-16175,-16122,-16069,-16015, -15962,-15909,-15856,-15802,-15749,-15696,-15643,-15590, -15537,-15484,-15431,-15378,-15325,-15272,-15219,-15166, -15113,-15060,-15007,-14954,-14901,-14848,-14795,-14743, -14690,-14637,-14584,-14531,-14479,-14426,-14373,-14321, -14268,-14215,-14163,-14110,-14057,-14005,-13952,-13900, -13847,-13795,-13742,-13690,-13637,-13585,-13533,-13480, -13428,-13375,-13323,-13271,-13218,-13166,-13114,-13062, -13009,-12957,-12905,-12853,-12800,-12748,-12696,-12644, -12592,-12540,-12488,-12436,-12383,-12331,-12279,-12227, -12175,-12123,-12071,-12019,-11967,-11916,-11864,-11812, -11760,-11708,-11656,-11604,-11552,-11501,-11449,-11397, -11345,-11293,-11242,-11190,-11138,-11086,-11035,-10983, -10931,-10880,-10828,-10777,-10725,-10673,-10622,-10570, -10519,-10467,-10415,-10364,-10312,-10261,-10209,-10158, -10106,-10055,-10004,-9952,-9901,-9849,-9798,-9747, -9695,-9644,-9592,-9541,-9490,-9438,-9387,-9336, -9285,-9233,-9182,-9131,-9080,-9028,-8977,-8926, -8875,-8824,-8772,-8721,-8670,-8619,-8568,-8517, -8466,-8414,-8363,-8312,-8261,-8210,-8159,-8108, -8057,-8006,-7955,-7904,-7853,-7802,-7751,-7700, -7649,-7598,-7547,-7496,-7445,-7395,-7344,-7293, -7242,-7191,-7140,-7089,-7038,-6988,-6937,-6886, -6835,-6784,-6733,-6683,-6632,-6581,-6530,-6480, -6429,-6378,-6327,-6277,-6226,-6175,-6124,-6074, -6023,-5972,-5922,-5871,-5820,-5770,-5719,-5668, -5618,-5567,-5517,-5466,-5415,-5365,-5314,-5264, -5213,-5162,-5112,-5061,-5011,-4960,-4910,-4859, -4808,-4758,-4707,-4657,-4606,-4556,-4505,-4455, -4404,-4354,-4303,-4253,-4202,-4152,-4101,-4051, -4001,-3950,-3900,-3849,-3799,-3748,-3698,-3648, -3597,-3547,-3496,-3446,-3395,-3345,-3295,-3244, -3194,-3144,-3093,-3043,-2992,-2942,-2892,-2841, -2791,-2741,-2690,-2640,-2590,-2539,-2489,-2439, -2388,-2338,-2288,-2237,-2187,-2137,-2086,-2036, -1986,-1935,-1885,-1835,-1784,-1734,-1684,-1633, -1583,-1533,-1483,-1432,-1382,-1332,-1281,-1231, -1181,-1131,-1080,-1030,-980,-929,-879,-829, -779,-728,-678,-628,-578,-527,-477,-427, -376,-326,-276,-226,-175,-125,-75,-25, 25,75,125,175,226,276,326,376, 427,477,527,578,628,678,728,779, 829,879,929,980,1030,1080,1131,1181, 1231,1281,1332,1382,1432,1483,1533,1583, 1633,1684,1734,1784,1835,1885,1935,1986, 2036,2086,2137,2187,2237,2288,2338,2388, 2439,2489,2539,2590,2640,2690,2741,2791, 2841,2892,2942,2992,3043,3093,3144,3194, 3244,3295,3345,3395,3446,3496,3547,3597, 3648,3698,3748,3799,3849,3900,3950,4001, 4051,4101,4152,4202,4253,4303,4354,4404, 4455,4505,4556,4606,4657,4707,4758,4808, 4859,4910,4960,5011,5061,5112,5162,5213, 5264,5314,5365,5415,5466,5517,5567,5618, 5668,5719,5770,5820,5871,5922,5972,6023, 6074,6124,6175,6226,6277,6327,6378,6429, 6480,6530,6581,6632,6683,6733,6784,6835, 6886,6937,6988,7038,7089,7140,7191,7242, 7293,7344,7395,7445,7496,7547,7598,7649, 7700,7751,7802,7853,7904,7955,8006,8057, 8108,8159,8210,8261,8312,8363,8414,8466, 8517,8568,8619,8670,8721,8772,8824,8875, 8926,8977,9028,9080,9131,9182,9233,9285, 9336,9387,9438,9490,9541,9592,9644,9695, 9747,9798,9849,9901,9952,10004,10055,10106, 10158,10209,10261,10312,10364,10415,10467,10519, 10570,10622,10673,10725,10777,10828,10880,10931, 10983,11035,11086,11138,11190,11242,11293,11345, 11397,11449,11501,11552,11604,11656,11708,11760, 11812,11864,11916,11967,12019,12071,12123,12175, 12227,12279,12331,12383,12436,12488,12540,12592, 12644,12696,12748,12800,12853,12905,12957,13009, 13062,13114,13166,13218,13271,13323,13375,13428, 13480,13533,13585,13637,13690,13742,13795,13847, 13900,13952,14005,14057,14110,14163,14215,14268, 14321,14373,14426,14479,14531,14584,14637,14690, 14743,14795,14848,14901,14954,15007,15060,15113, 15166,15219,15272,15325,15378,15431,15484,15537, 15590,15643,15696,15749,15802,15856,15909,15962, 16015,16069,16122,16175,16229,16282,16335,16389, 16442,16496,16549,16603,16656,16710,16763,16817, 16870,16924,16977,17031,17085,17138,17192,17246, 17300,17353,17407,17461,17515,17569,17623,17677, 17731,17784,17838,17892,17946,18001,18055,18109, 18163,18217,18271,18325,18380,18434,18488,18542, 18597,18651,18705,18760,18814,18868,18923,18977, 19032,19086,19141,19195,19250,19305,19359,19414, 19469,19523,19578,19633,19688,19742,19797,19852, 19907,19962,20017,20072,20127,20182,20237,20292, 20347,20402,20457,20513,20568,20623,20678,20734, 20789,20844,20900,20955,21010,21066,21121,21177, 21232,21288,21343,21399,21455,21510,21566,21622, 21678,21733,21789,21845,21901,21957,22013,22069, 22125,22181,22237,22293,22349,22405,22461,22517, 22573,22630,22686,22742,22799,22855,22911,22968, 23024,23081,23137,23194,23250,23307,23364,23420, 23477,23534,23591,23647,23704,23761,23818,23875, 23932,23989,24046,24103,24160,24217,24274,24331, 24389,24446,24503,24560,24618,24675,24732,24790, 24847,24905,24962,25020,25078,25135,25193,25251, 25308,25366,25424,25482,25540,25598,25656,25714, 25772,25830,25888,25946,26004,26062,26120,26179, 26237,26295,26354,26412,26471,26529,26588,26646, 26705,26763,26822,26881,26940,26998,27057,27116, 27175,27234,27293,27352,27411,27470,27529,27588, 27647,27707,27766,27825,27884,27944,28003,28063, 28122,28182,28241,28301,28361,28420,28480,28540, 28600,28660,28719,28779,28839,28899,28959,29020, 29080,29140,29200,29260,29321,29381,29441,29502, 29562,29623,29683,29744,29805,29865,29926,29987, 30048,30108,30169,30230,30291,30352,30413,30474, 30536,30597,30658,30719,30781,30842,30904,30965, 31026,31088,31150,31211,31273,31335,31396,31458, 31520,31582,31644,31706,31768,31830,31892,31955, 32017,32079,32141,32204,32266,32329,32391,32454, 32516,32579,32642,32705,32767,32830,32893,32956, 33019,33082,33145,33208,33272,33335,33398,33461, 33525,33588,33652,33715,33779,33843,33906,33970, 34034,34098,34162,34225,34289,34354,34418,34482, 34546,34610,34675,34739,34803,34868,34932,34997, 35062,35126,35191,35256,35321,35385,35450,35515, 35580,35646,35711,35776,35841,35907,35972,36037, 36103,36168,36234,36300,36365,36431,36497,36563, 36629,36695,36761,36827,36893,36959,37026,37092, 37158,37225,37291,37358,37425,37491,37558,37625, 37692,37759,37826,37893,37960,38027,38094,38161, 38229,38296,38364,38431,38499,38566,38634,38702, 38770,38837,38905,38973,39042,39110,39178,39246, 39314,39383,39451,39520,39588,39657,39726,39794, 39863,39932,40001,40070,40139,40208,40278,40347, 40416,40486,40555,40625,40694,40764,40834,40904, 40973,41043,41113,41184,41254,41324,41394,41465, 41535,41605,41676,41747,41817,41888,41959,42030, 42101,42172,42243,42314,42385,42457,42528,42600, 42671,42743,42814,42886,42958,43030,43102,43174, 43246,43318,43390,43463,43535,43608,43680,43753, 43826,43898,43971,44044,44117,44190,44263,44337, 44410,44483,44557,44630,44704,44778,44851,44925, 44999,45073,45147,45221,45296,45370,45444,45519, 45593,45668,45743,45818,45892,45967,46042,46118, 46193,46268,46343,46419,46494,46570,46646,46721, 46797,46873,46949,47025,47102,47178,47254,47331, 47407,47484,47560,47637,47714,47791,47868,47945, 48022,48100,48177,48255,48332,48410,48488,48565, 48643,48721,48799,48878,48956,49034,49113,49191, 49270,49349,49427,49506,49585,49664,49744,49823, 49902,49982,50061,50141,50221,50300,50380,50460, 50540,50621,50701,50781,50862,50942,51023,51104, 51185,51266,51347,51428,51509,51591,51672,51754, 51835,51917,51999,52081,52163,52245,52327,52410, 52492,52575,52657,52740,52823,52906,52989,53072, 53156,53239,53322,53406,53490,53574,53657,53741, 53826,53910,53994,54079,54163,54248,54333,54417, 54502,54587,54673,54758,54843,54929,55015,55100, 55186,55272,55358,55444,55531,55617,55704,55790, 55877,55964,56051,56138,56225,56312,56400,56487, 56575,56663,56751,56839,56927,57015,57104,57192, 57281,57369,57458,57547,57636,57725,57815,57904, 57994,58083,58173,58263,58353,58443,58534,58624, 58715,58805,58896,58987,59078,59169,59261,59352, 59444,59535,59627,59719,59811,59903,59996,60088, 60181,60273,60366,60459,60552,60646,60739,60833, 60926,61020,61114,61208,61302,61396,61491,61585, 61680,61775,61870,61965,62060,62156,62251,62347, 62443,62539,62635,62731,62828,62924,63021,63118, 63215,63312,63409,63506,63604,63702,63799,63897, 63996,64094,64192,64291,64389,64488,64587,64687, 64786,64885,64985,65085,65185,65285,65385,65485, 65586,65686,65787,65888,65989,66091,66192,66294, 66396,66498,66600,66702,66804,66907,67010,67113, 67216,67319,67422,67526,67629,67733,67837,67942, 68046,68151,68255,68360,68465,68570,68676,68781, 68887,68993,69099,69205,69312,69418,69525,69632, 69739,69846,69954,70061,70169,70277,70385,70494, 70602,70711,70820,70929,71038,71147,71257,71367, 71477,71587,71697,71808,71918,72029,72140,72252, 72363,72475,72587,72699,72811,72923,73036,73149, 73262,73375,73488,73602,73715,73829,73944,74058, 74172,74287,74402,74517,74633,74748,74864,74980, 75096,75213,75329,75446,75563,75680,75797,75915, 76033,76151,76269,76388,76506,76625,76744,76864, 76983,77103,77223,77343,77463,77584,77705,77826, 77947,78068,78190,78312,78434,78557,78679,78802, 78925,79048,79172,79296,79420,79544,79668,79793, 79918,80043,80168,80294,80420,80546,80672,80799, 80925,81053,81180,81307,81435,81563,81691,81820, 81949,82078,82207,82336,82466,82596,82726,82857, 82987,83118,83250,83381,83513,83645,83777,83910, 84043,84176,84309,84443,84576,84710,84845,84980, 85114,85250,85385,85521,85657,85793,85930,86066, 86204,86341,86479,86616,86755,86893,87032,87171, 87310,87450,87590,87730,87871,88011,88152,88294, 88435,88577,88720,88862,89005,89148,89292,89435, 89579,89724,89868,90013,90158,90304,90450,90596, 90742,90889,91036,91184,91332,91480,91628,91777, 91926,92075,92225,92375,92525,92675,92826,92978, 93129,93281,93434,93586,93739,93892,94046,94200, 94354,94509,94664,94819,94975,95131,95287,95444, 95601,95758,95916,96074,96233,96391,96551,96710, 96870,97030,97191,97352,97513,97675,97837,98000, 98163,98326,98489,98653,98818,98982,99148,99313, 99479,99645,99812,99979,100146,100314,100482,100651, 100820,100990,101159,101330,101500,101671,101843,102015, 102187,102360,102533,102706,102880,103054,103229,103404, 103580,103756,103933,104109,104287,104465,104643,104821, 105000,105180,105360,105540,105721,105902,106084,106266, 106449,106632,106816,107000,107184,107369,107555,107741, 107927,108114,108301,108489,108677,108866,109055,109245, 109435,109626,109817,110008,110200,110393,110586,110780, 110974,111169,111364,111560,111756,111952,112150,112347, 112546,112744,112944,113143,113344,113545,113746,113948, 114151,114354,114557,114761,114966,115171,115377,115583, 115790,115998,116206,116414,116623,116833,117044,117254, 117466,117678,117891,118104,118318,118532,118747,118963, 119179,119396,119613,119831,120050,120269,120489,120709, 120930,121152,121374,121597,121821,122045,122270,122496, 122722,122949,123176,123404,123633,123863,124093,124324, 124555,124787,125020,125254,125488,125723,125959,126195, 126432,126669,126908,127147,127387,127627,127869,128111, 128353,128597,128841,129086,129332,129578,129825,130073, 130322,130571,130821,131072,131324,131576,131830,132084, 132339,132594,132851,133108,133366,133625,133884,134145, 134406,134668,134931,135195,135459,135725,135991,136258, 136526,136795,137065,137335,137607,137879,138152,138426, 138701,138977,139254,139532,139810,140090,140370,140651, 140934,141217,141501,141786,142072,142359,142647,142936, 143226,143517,143808,144101,144395,144690,144986,145282, 145580,145879,146179,146480,146782,147084,147388,147693, 148000,148307,148615,148924,149235,149546,149859,150172, 150487,150803,151120,151438,151757,152077,152399,152722, 153045,153370,153697,154024,154352,154682,155013,155345, 155678,156013,156349,156686,157024,157363,157704,158046, 158389,158734,159079,159427,159775,160125,160476,160828, 161182,161537,161893,162251,162610,162970,163332,163695, 164060,164426,164793,165162,165532,165904,166277,166651, 167027,167405,167784,168164,168546,168930,169315,169701, 170089,170479,170870,171263,171657,172053,172451,172850, 173251,173653,174057,174463,174870,175279,175690,176102, 176516,176932,177349,177769,178190,178612,179037,179463, 179891,180321,180753,181186,181622,182059,182498,182939, 183382,183827,184274,184722,185173,185625,186080,186536, 186995,187455,187918,188382,188849,189318,189789,190261, 190736,191213,191693,192174,192658,193143,193631,194122, 194614,195109,195606,196105,196606,197110,197616,198125, 198636,199149,199664,200182,200703,201226,201751,202279, 202809,203342,203878,204416,204956,205500,206045,206594, 207145,207699,208255,208815,209376,209941,210509,211079, 211652,212228,212807,213389,213973,214561,215151,215745, 216341,216941,217544,218149,218758,219370,219985,220603, 221225,221849,222477,223108,223743,224381,225022,225666, 226314,226966,227621,228279,228941,229606,230275,230948, 231624,232304,232988,233676,234367,235062,235761,236463, 237170,237881,238595,239314,240036,240763,241493,242228, 242967,243711,244458,245210,245966,246727,247492,248261, 249035,249813,250596,251384,252176,252973,253774,254581, 255392,256208,257029,257855,258686,259522,260363,261209, 262060,262917,263779,264646,265519,266397,267280,268169, 269064,269965,270871,271782,272700,273624,274553,275489, 276430,277378,278332,279292,280258,281231,282210,283195, 284188,285186,286192,287204,288223,289249,290282,291322, 292369,293423,294485,295554,296630,297714,298805,299904, 301011,302126,303248,304379,305517,306664,307819,308983, 310154,311335,312524,313721,314928,316143,317368,318601, 319844,321097,322358,323629,324910,326201,327502,328812, 330133,331464,332805,334157,335519,336892,338276,339671, 341078,342495,343924,345364,346816,348280,349756,351244, 352744,354257,355783,357321,358872,360436,362013,363604, 365208,366826,368459,370105,371765,373440,375130,376835, 378555,380290,382040,383807,385589,387387,389202,391034, 392882,394747,396630,398530,400448,402384,404338,406311, 408303,410314,412344,414395,416465,418555,420666,422798, 424951,427125,429321,431540,433781,436045,438332,440643, 442978,445337,447720,450129,452564,455024,457511,460024, 462565,465133,467730,470355,473009,475692,478406,481150, 483925,486732,489571,492443,495348,498287,501261,504269, 507313,510394,513512,516667,519861,523094,526366,529680, 533034,536431,539870,543354,546881,550455,554074,557741, 561456,565221,569035,572901,576818,580789,584815,588896, 593033,597229,601483,605798,610174,614613,619117,623686, 628323,633028,637803,642651,647572,652568,657640,662792, 668024,673338,678737,684223,689797,695462,701219,707072, 713023,719074,725227,731486,737853,744331,750922,757631, 764460,771411,778490,785699,793041,800521,808143,815910, 823827,831898,840127,848520,857081,865817,874730,883829, 893117,902602,912289,922186,932298,942633,953199,964003, 975054,986361,997931,1009774,1021901,1034322,1047046,1060087, 1073455,1087164,1101225,1115654,1130465,1145673,1161294,1177345, 1193846,1210813,1228269,1246234,1264730,1283783,1303416,1323658, 1344537,1366084,1388330,1411312,1435065,1459630,1485049,1511367, 1538632,1566898,1596220,1626658,1658278,1691149,1725348,1760956, 1798063,1836758,1877161,1919378,1963536,2009771,2058233,2109087, 2162516,2218719,2277919,2340362,2406322,2476104,2550052,2628549, 2712030,2800983,2895966,2997613,3106651,3223918,3350381,3487165, 3635590,3797206,3973855,4167737,4381502,4618375,4882318,5178251, 5512368,5892567,6329090,6835455,7429880,8137527,8994149,10052327, 11392683,13145455,15535599,18988036,24413316,34178904,56965752,170910304 }; const int finesine[10240] = { 25,75,125,175,226,276,326,376, 427,477,527,578,628,678,728,779, 829,879,929,980,1030,1080,1130,1181, 1231,1281,1331,1382,1432,1482,1532,1583, 1633,1683,1733,1784,1834,1884,1934,1985, 2035,2085,2135,2186,2236,2286,2336,2387, 2437,2487,2537,2587,2638,2688,2738,2788, 2839,2889,2939,2989,3039,3090,3140,3190, 3240,3291,3341,3391,3441,3491,3541,3592, 3642,3692,3742,3792,3843,3893,3943,3993, 4043,4093,4144,4194,4244,4294,4344,4394, 4445,4495,4545,4595,4645,4695,4745,4796, 4846,4896,4946,4996,5046,5096,5146,5197, 5247,5297,5347,5397,5447,5497,5547,5597, 5647,5697,5748,5798,5848,5898,5948,5998, 6048,6098,6148,6198,6248,6298,6348,6398, 6448,6498,6548,6598,6648,6698,6748,6798, 6848,6898,6948,6998,7048,7098,7148,7198, 7248,7298,7348,7398,7448,7498,7548,7598, 7648,7697,7747,7797,7847,7897,7947,7997, 8047,8097,8147,8196,8246,8296,8346,8396, 8446,8496,8545,8595,8645,8695,8745,8794, 8844,8894,8944,8994,9043,9093,9143,9193, 9243,9292,9342,9392,9442,9491,9541,9591, 9640,9690,9740,9790,9839,9889,9939,9988, 10038,10088,10137,10187,10237,10286,10336,10386, 10435,10485,10534,10584,10634,10683,10733,10782, 10832,10882,10931,10981,11030,11080,11129,11179, 11228,11278,11327,11377,11426,11476,11525,11575, 11624,11674,11723,11773,11822,11872,11921,11970, 12020,12069,12119,12168,12218,12267,12316,12366, 12415,12464,12514,12563,12612,12662,12711,12760, 12810,12859,12908,12957,13007,13056,13105,13154, 13204,13253,13302,13351,13401,13450,13499,13548, 13597,13647,13696,13745,13794,13843,13892,13941, 13990,14040,14089,14138,14187,14236,14285,14334, 14383,14432,14481,14530,14579,14628,14677,14726, 14775,14824,14873,14922,14971,15020,15069,15118, 15167,15215,15264,15313,15362,15411,15460,15509, 15557,15606,15655,15704,15753,15802,15850,15899, 15948,15997,16045,16094,16143,16191,16240,16289, 16338,16386,16435,16484,16532,16581,16629,16678, 16727,16775,16824,16872,16921,16970,17018,17067, 17115,17164,17212,17261,17309,17358,17406,17455, 17503,17551,17600,17648,17697,17745,17793,17842, 17890,17939,17987,18035,18084,18132,18180,18228, 18277,18325,18373,18421,18470,18518,18566,18614, 18663,18711,18759,18807,18855,18903,18951,19000, 19048,19096,19144,19192,19240,19288,19336,19384, 19432,19480,19528,19576,19624,19672,19720,19768, 19816,19864,19912,19959,20007,20055,20103,20151, 20199,20246,20294,20342,20390,20438,20485,20533, 20581,20629,20676,20724,20772,20819,20867,20915, 20962,21010,21057,21105,21153,21200,21248,21295, 21343,21390,21438,21485,21533,21580,21628,21675, 21723,21770,21817,21865,21912,21960,22007,22054, 22102,22149,22196,22243,22291,22338,22385,22433, 22480,22527,22574,22621,22668,22716,22763,22810, 22857,22904,22951,22998,23045,23092,23139,23186, 23233,23280,23327,23374,23421,23468,23515,23562, 23609,23656,23703,23750,23796,23843,23890,23937, 23984,24030,24077,24124,24171,24217,24264,24311, 24357,24404,24451,24497,24544,24591,24637,24684, 24730,24777,24823,24870,24916,24963,25009,25056, 25102,25149,25195,25241,25288,25334,25381,25427, 25473,25520,25566,25612,25658,25705,25751,25797, 25843,25889,25936,25982,26028,26074,26120,26166, 26212,26258,26304,26350,26396,26442,26488,26534, 26580,26626,26672,26718,26764,26810,26856,26902, 26947,26993,27039,27085,27131,27176,27222,27268, 27313,27359,27405,27450,27496,27542,27587,27633, 27678,27724,27770,27815,27861,27906,27952,27997, 28042,28088,28133,28179,28224,28269,28315,28360, 28405,28451,28496,28541,28586,28632,28677,28722, 28767,28812,28858,28903,28948,28993,29038,29083, 29128,29173,29218,29263,29308,29353,29398,29443, 29488,29533,29577,29622,29667,29712,29757,29801, 29846,29891,29936,29980,30025,30070,30114,30159, 30204,30248,30293,30337,30382,30426,30471,30515, 30560,30604,30649,30693,30738,30782,30826,30871, 30915,30959,31004,31048,31092,31136,31181,31225, 31269,31313,31357,31402,31446,31490,31534,31578, 31622,31666,31710,31754,31798,31842,31886,31930, 31974,32017,32061,32105,32149,32193,32236,32280, 32324,32368,32411,32455,32499,32542,32586,32630, 32673,32717,32760,32804,32847,32891,32934,32978, 33021,33065,33108,33151,33195,33238,33281,33325, 33368,33411,33454,33498,33541,33584,33627,33670, 33713,33756,33799,33843,33886,33929,33972,34015, 34057,34100,34143,34186,34229,34272,34315,34358, 34400,34443,34486,34529,34571,34614,34657,34699, 34742,34785,34827,34870,34912,34955,34997,35040, 35082,35125,35167,35210,35252,35294,35337,35379, 35421,35464,35506,35548,35590,35633,35675,35717, 35759,35801,35843,35885,35927,35969,36011,36053, 36095,36137,36179,36221,36263,36305,36347,36388, 36430,36472,36514,36555,36597,36639,36681,36722, 36764,36805,36847,36889,36930,36972,37013,37055, 37096,37137,37179,37220,37262,37303,37344,37386, 37427,37468,37509,37551,37592,37633,37674,37715, 37756,37797,37838,37879,37920,37961,38002,38043, 38084,38125,38166,38207,38248,38288,38329,38370, 38411,38451,38492,38533,38573,38614,38655,38695, 38736,38776,38817,38857,38898,38938,38979,39019, 39059,39100,39140,39180,39221,39261,39301,39341, 39382,39422,39462,39502,39542,39582,39622,39662, 39702,39742,39782,39822,39862,39902,39942,39982, 40021,40061,40101,40141,40180,40220,40260,40300, 40339,40379,40418,40458,40497,40537,40576,40616, 40655,40695,40734,40773,40813,40852,40891,40931, 40970,41009,41048,41087,41127,41166,41205,41244, 41283,41322,41361,41400,41439,41478,41517,41556, 41595,41633,41672,41711,41750,41788,41827,41866, 41904,41943,41982,42020,42059,42097,42136,42174, 42213,42251,42290,42328,42366,42405,42443,42481, 42520,42558,42596,42634,42672,42711,42749,42787, 42825,42863,42901,42939,42977,43015,43053,43091, 43128,43166,43204,43242,43280,43317,43355,43393, 43430,43468,43506,43543,43581,43618,43656,43693, 43731,43768,43806,43843,43880,43918,43955,43992, 44029,44067,44104,44141,44178,44215,44252,44289, 44326,44363,44400,44437,44474,44511,44548,44585, 44622,44659,44695,44732,44769,44806,44842,44879, 44915,44952,44989,45025,45062,45098,45135,45171, 45207,45244,45280,45316,45353,45389,45425,45462, 45498,45534,45570,45606,45642,45678,45714,45750, 45786,45822,45858,45894,45930,45966,46002,46037, 46073,46109,46145,46180,46216,46252,46287,46323, 46358,46394,46429,46465,46500,46536,46571,46606, 46642,46677,46712,46747,46783,46818,46853,46888, 46923,46958,46993,47028,47063,47098,47133,47168, 47203,47238,47273,47308,47342,47377,47412,47446, 47481,47516,47550,47585,47619,47654,47688,47723, 47757,47792,47826,47860,47895,47929,47963,47998, 48032,48066,48100,48134,48168,48202,48237,48271, 48305,48338,48372,48406,48440,48474,48508,48542, 48575,48609,48643,48676,48710,48744,48777,48811, 48844,48878,48911,48945,48978,49012,49045,49078, 49112,49145,49178,49211,49244,49278,49311,49344, 49377,49410,49443,49476,49509,49542,49575,49608, 49640,49673,49706,49739,49771,49804,49837,49869, 49902,49935,49967,50000,50032,50065,50097,50129, 50162,50194,50226,50259,50291,50323,50355,50387, 50420,50452,50484,50516,50548,50580,50612,50644, 50675,50707,50739,50771,50803,50834,50866,50898, 50929,50961,50993,51024,51056,51087,51119,51150, 51182,51213,51244,51276,51307,51338,51369,51401, 51432,51463,51494,51525,51556,51587,51618,51649, 51680,51711,51742,51773,51803,51834,51865,51896, 51926,51957,51988,52018,52049,52079,52110,52140, 52171,52201,52231,52262,52292,52322,52353,52383, 52413,52443,52473,52503,52534,52564,52594,52624, 52653,52683,52713,52743,52773,52803,52832,52862, 52892,52922,52951,52981,53010,53040,53069,53099, 53128,53158,53187,53216,53246,53275,53304,53334, 53363,53392,53421,53450,53479,53508,53537,53566, 53595,53624,53653,53682,53711,53739,53768,53797, 53826,53854,53883,53911,53940,53969,53997,54026, 54054,54082,54111,54139,54167,54196,54224,54252, 54280,54308,54337,54365,54393,54421,54449,54477, 54505,54533,54560,54588,54616,54644,54672,54699, 54727,54755,54782,54810,54837,54865,54892,54920, 54947,54974,55002,55029,55056,55084,55111,55138, 55165,55192,55219,55246,55274,55300,55327,55354, 55381,55408,55435,55462,55489,55515,55542,55569, 55595,55622,55648,55675,55701,55728,55754,55781, 55807,55833,55860,55886,55912,55938,55965,55991, 56017,56043,56069,56095,56121,56147,56173,56199, 56225,56250,56276,56302,56328,56353,56379,56404, 56430,56456,56481,56507,56532,56557,56583,56608, 56633,56659,56684,56709,56734,56760,56785,56810, 56835,56860,56885,56910,56935,56959,56984,57009, 57034,57059,57083,57108,57133,57157,57182,57206, 57231,57255,57280,57304,57329,57353,57377,57402, 57426,57450,57474,57498,57522,57546,57570,57594, 57618,57642,57666,57690,57714,57738,57762,57785, 57809,57833,57856,57880,57903,57927,57950,57974, 57997,58021,58044,58067,58091,58114,58137,58160, 58183,58207,58230,58253,58276,58299,58322,58345, 58367,58390,58413,58436,58459,58481,58504,58527, 58549,58572,58594,58617,58639,58662,58684,58706, 58729,58751,58773,58795,58818,58840,58862,58884, 58906,58928,58950,58972,58994,59016,59038,59059, 59081,59103,59125,59146,59168,59190,59211,59233, 59254,59276,59297,59318,59340,59361,59382,59404, 59425,59446,59467,59488,59509,59530,59551,59572, 59593,59614,59635,59656,59677,59697,59718,59739, 59759,59780,59801,59821,59842,59862,59883,59903, 59923,59944,59964,59984,60004,60025,60045,60065, 60085,60105,60125,60145,60165,60185,60205,60225, 60244,60264,60284,60304,60323,60343,60363,60382, 60402,60421,60441,60460,60479,60499,60518,60537, 60556,60576,60595,60614,60633,60652,60671,60690, 60709,60728,60747,60766,60785,60803,60822,60841, 60859,60878,60897,60915,60934,60952,60971,60989, 61007,61026,61044,61062,61081,61099,61117,61135, 61153,61171,61189,61207,61225,61243,61261,61279, 61297,61314,61332,61350,61367,61385,61403,61420, 61438,61455,61473,61490,61507,61525,61542,61559, 61577,61594,61611,61628,61645,61662,61679,61696, 61713,61730,61747,61764,61780,61797,61814,61831, 61847,61864,61880,61897,61913,61930,61946,61963, 61979,61995,62012,62028,62044,62060,62076,62092, 62108,62125,62141,62156,62172,62188,62204,62220, 62236,62251,62267,62283,62298,62314,62329,62345, 62360,62376,62391,62407,62422,62437,62453,62468, 62483,62498,62513,62528,62543,62558,62573,62588, 62603,62618,62633,62648,62662,62677,62692,62706, 62721,62735,62750,62764,62779,62793,62808,62822, 62836,62850,62865,62879,62893,62907,62921,62935, 62949,62963,62977,62991,63005,63019,63032,63046, 63060,63074,63087,63101,63114,63128,63141,63155, 63168,63182,63195,63208,63221,63235,63248,63261, 63274,63287,63300,63313,63326,63339,63352,63365, 63378,63390,63403,63416,63429,63441,63454,63466, 63479,63491,63504,63516,63528,63541,63553,63565, 63578,63590,63602,63614,63626,63638,63650,63662, 63674,63686,63698,63709,63721,63733,63745,63756, 63768,63779,63791,63803,63814,63825,63837,63848, 63859,63871,63882,63893,63904,63915,63927,63938, 63949,63960,63971,63981,63992,64003,64014,64025, 64035,64046,64057,64067,64078,64088,64099,64109, 64120,64130,64140,64151,64161,64171,64181,64192, 64202,64212,64222,64232,64242,64252,64261,64271, 64281,64291,64301,64310,64320,64330,64339,64349, 64358,64368,64377,64387,64396,64405,64414,64424, 64433,64442,64451,64460,64469,64478,64487,64496, 64505,64514,64523,64532,64540,64549,64558,64566, 64575,64584,64592,64601,64609,64617,64626,64634, 64642,64651,64659,64667,64675,64683,64691,64699, 64707,64715,64723,64731,64739,64747,64754,64762, 64770,64777,64785,64793,64800,64808,64815,64822, 64830,64837,64844,64852,64859,64866,64873,64880, 64887,64895,64902,64908,64915,64922,64929,64936, 64943,64949,64956,64963,64969,64976,64982,64989, 64995,65002,65008,65015,65021,65027,65033,65040, 65046,65052,65058,65064,65070,65076,65082,65088, 65094,65099,65105,65111,65117,65122,65128,65133, 65139,65144,65150,65155,65161,65166,65171,65177, 65182,65187,65192,65197,65202,65207,65212,65217, 65222,65227,65232,65237,65242,65246,65251,65256, 65260,65265,65270,65274,65279,65283,65287,65292, 65296,65300,65305,65309,65313,65317,65321,65325, 65329,65333,65337,65341,65345,65349,65352,65356, 65360,65363,65367,65371,65374,65378,65381,65385, 65388,65391,65395,65398,65401,65404,65408,65411, 65414,65417,65420,65423,65426,65429,65431,65434, 65437,65440,65442,65445,65448,65450,65453,65455, 65458,65460,65463,65465,65467,65470,65472,65474, 65476,65478,65480,65482,65484,65486,65488,65490, 65492,65494,65496,65497,65499,65501,65502,65504, 65505,65507,65508,65510,65511,65513,65514,65515, 65516,65518,65519,65520,65521,65522,65523,65524, 65525,65526,65527,65527,65528,65529,65530,65530, 65531,65531,65532,65532,65533,65533,65534,65534, 65534,65535,65535,65535,65535,65535,65535,65535, 65535,65535,65535,65535,65535,65535,65535,65534, 65534,65534,65533,65533,65532,65532,65531,65531, 65530,65530,65529,65528,65527,65527,65526,65525, 65524,65523,65522,65521,65520,65519,65518,65516, 65515,65514,65513,65511,65510,65508,65507,65505, 65504,65502,65501,65499,65497,65496,65494,65492, 65490,65488,65486,65484,65482,65480,65478,65476, 65474,65472,65470,65467,65465,65463,65460,65458, 65455,65453,65450,65448,65445,65442,65440,65437, 65434,65431,65429,65426,65423,65420,65417,65414, 65411,65408,65404,65401,65398,65395,65391,65388, 65385,65381,65378,65374,65371,65367,65363,65360, 65356,65352,65349,65345,65341,65337,65333,65329, 65325,65321,65317,65313,65309,65305,65300,65296, 65292,65287,65283,65279,65274,65270,65265,65260, 65256,65251,65246,65242,65237,65232,65227,65222, 65217,65212,65207,65202,65197,65192,65187,65182, 65177,65171,65166,65161,65155,65150,65144,65139, 65133,65128,65122,65117,65111,65105,65099,65094, 65088,65082,65076,65070,65064,65058,65052,65046, 65040,65033,65027,65021,65015,65008,65002,64995, 64989,64982,64976,64969,64963,64956,64949,64943, 64936,64929,64922,64915,64908,64902,64895,64887, 64880,64873,64866,64859,64852,64844,64837,64830, 64822,64815,64808,64800,64793,64785,64777,64770, 64762,64754,64747,64739,64731,64723,64715,64707, 64699,64691,64683,64675,64667,64659,64651,64642, 64634,64626,64617,64609,64600,64592,64584,64575, 64566,64558,64549,64540,64532,64523,64514,64505, 64496,64487,64478,64469,64460,64451,64442,64433, 64424,64414,64405,64396,64387,64377,64368,64358, 64349,64339,64330,64320,64310,64301,64291,64281, 64271,64261,64252,64242,64232,64222,64212,64202, 64192,64181,64171,64161,64151,64140,64130,64120, 64109,64099,64088,64078,64067,64057,64046,64035, 64025,64014,64003,63992,63981,63971,63960,63949, 63938,63927,63915,63904,63893,63882,63871,63859, 63848,63837,63825,63814,63803,63791,63779,63768, 63756,63745,63733,63721,63709,63698,63686,63674, 63662,63650,63638,63626,63614,63602,63590,63578, 63565,63553,63541,63528,63516,63504,63491,63479, 63466,63454,63441,63429,63416,63403,63390,63378, 63365,63352,63339,63326,63313,63300,63287,63274, 63261,63248,63235,63221,63208,63195,63182,63168, 63155,63141,63128,63114,63101,63087,63074,63060, 63046,63032,63019,63005,62991,62977,62963,62949, 62935,62921,62907,62893,62879,62865,62850,62836, 62822,62808,62793,62779,62764,62750,62735,62721, 62706,62692,62677,62662,62648,62633,62618,62603, 62588,62573,62558,62543,62528,62513,62498,62483, 62468,62453,62437,62422,62407,62391,62376,62360, 62345,62329,62314,62298,62283,62267,62251,62236, 62220,62204,62188,62172,62156,62141,62125,62108, 62092,62076,62060,62044,62028,62012,61995,61979, 61963,61946,61930,61913,61897,61880,61864,61847, 61831,61814,61797,61780,61764,61747,61730,61713, 61696,61679,61662,61645,61628,61611,61594,61577, 61559,61542,61525,61507,61490,61473,61455,61438, 61420,61403,61385,61367,61350,61332,61314,61297, 61279,61261,61243,61225,61207,61189,61171,61153, 61135,61117,61099,61081,61062,61044,61026,61007, 60989,60971,60952,60934,60915,60897,60878,60859, 60841,60822,60803,60785,60766,60747,60728,60709, 60690,60671,60652,60633,60614,60595,60576,60556, 60537,60518,60499,60479,60460,60441,60421,60402, 60382,60363,60343,60323,60304,60284,60264,60244, 60225,60205,60185,60165,60145,60125,60105,60085, 60065,60045,60025,60004,59984,59964,59944,59923, 59903,59883,59862,59842,59821,59801,59780,59759, 59739,59718,59697,59677,59656,59635,59614,59593, 59572,59551,59530,59509,59488,59467,59446,59425, 59404,59382,59361,59340,59318,59297,59276,59254, 59233,59211,59190,59168,59146,59125,59103,59081, 59059,59038,59016,58994,58972,58950,58928,58906, 58884,58862,58840,58818,58795,58773,58751,58729, 58706,58684,58662,58639,58617,58594,58572,58549, 58527,58504,58481,58459,58436,58413,58390,58367, 58345,58322,58299,58276,58253,58230,58207,58183, 58160,58137,58114,58091,58067,58044,58021,57997, 57974,57950,57927,57903,57880,57856,57833,57809, 57785,57762,57738,57714,57690,57666,57642,57618, 57594,57570,57546,57522,57498,57474,57450,57426, 57402,57377,57353,57329,57304,57280,57255,57231, 57206,57182,57157,57133,57108,57083,57059,57034, 57009,56984,56959,56935,56910,56885,56860,56835, 56810,56785,56760,56734,56709,56684,56659,56633, 56608,56583,56557,56532,56507,56481,56456,56430, 56404,56379,56353,56328,56302,56276,56250,56225, 56199,56173,56147,56121,56095,56069,56043,56017, 55991,55965,55938,55912,55886,55860,55833,55807, 55781,55754,55728,55701,55675,55648,55622,55595, 55569,55542,55515,55489,55462,55435,55408,55381, 55354,55327,55300,55274,55246,55219,55192,55165, 55138,55111,55084,55056,55029,55002,54974,54947, 54920,54892,54865,54837,54810,54782,54755,54727, 54699,54672,54644,54616,54588,54560,54533,54505, 54477,54449,54421,54393,54365,54337,54308,54280, 54252,54224,54196,54167,54139,54111,54082,54054, 54026,53997,53969,53940,53911,53883,53854,53826, 53797,53768,53739,53711,53682,53653,53624,53595, 53566,53537,53508,53479,53450,53421,53392,53363, 53334,53304,53275,53246,53216,53187,53158,53128, 53099,53069,53040,53010,52981,52951,52922,52892, 52862,52832,52803,52773,52743,52713,52683,52653, 52624,52594,52564,52534,52503,52473,52443,52413, 52383,52353,52322,52292,52262,52231,52201,52171, 52140,52110,52079,52049,52018,51988,51957,51926, 51896,51865,51834,51803,51773,51742,51711,51680, 51649,51618,51587,51556,51525,51494,51463,51432, 51401,51369,51338,51307,51276,51244,51213,51182, 51150,51119,51087,51056,51024,50993,50961,50929, 50898,50866,50834,50803,50771,50739,50707,50675, 50644,50612,50580,50548,50516,50484,50452,50420, 50387,50355,50323,50291,50259,50226,50194,50162, 50129,50097,50065,50032,50000,49967,49935,49902, 49869,49837,49804,49771,49739,49706,49673,49640, 49608,49575,49542,49509,49476,49443,49410,49377, 49344,49311,49278,49244,49211,49178,49145,49112, 49078,49045,49012,48978,48945,48911,48878,48844, 48811,48777,48744,48710,48676,48643,48609,48575, 48542,48508,48474,48440,48406,48372,48338,48304, 48271,48237,48202,48168,48134,48100,48066,48032, 47998,47963,47929,47895,47860,47826,47792,47757, 47723,47688,47654,47619,47585,47550,47516,47481, 47446,47412,47377,47342,47308,47273,47238,47203, 47168,47133,47098,47063,47028,46993,46958,46923, 46888,46853,46818,46783,46747,46712,46677,46642, 46606,46571,46536,46500,46465,46429,46394,46358, 46323,46287,46252,46216,46180,46145,46109,46073, 46037,46002,45966,45930,45894,45858,45822,45786, 45750,45714,45678,45642,45606,45570,45534,45498, 45462,45425,45389,45353,45316,45280,45244,45207, 45171,45135,45098,45062,45025,44989,44952,44915, 44879,44842,44806,44769,44732,44695,44659,44622, 44585,44548,44511,44474,44437,44400,44363,44326, 44289,44252,44215,44178,44141,44104,44067,44029, 43992,43955,43918,43880,43843,43806,43768,43731, 43693,43656,43618,43581,43543,43506,43468,43430, 43393,43355,43317,43280,43242,43204,43166,43128, 43091,43053,43015,42977,42939,42901,42863,42825, 42787,42749,42711,42672,42634,42596,42558,42520, 42481,42443,42405,42366,42328,42290,42251,42213, 42174,42136,42097,42059,42020,41982,41943,41904, 41866,41827,41788,41750,41711,41672,41633,41595, 41556,41517,41478,41439,41400,41361,41322,41283, 41244,41205,41166,41127,41088,41048,41009,40970, 40931,40891,40852,40813,40773,40734,40695,40655, 40616,40576,40537,40497,40458,40418,40379,40339, 40300,40260,40220,40180,40141,40101,40061,40021, 39982,39942,39902,39862,39822,39782,39742,39702, 39662,39622,39582,39542,39502,39462,39422,39382, 39341,39301,39261,39221,39180,39140,39100,39059, 39019,38979,38938,38898,38857,38817,38776,38736, 38695,38655,38614,38573,38533,38492,38451,38411, 38370,38329,38288,38248,38207,38166,38125,38084, 38043,38002,37961,37920,37879,37838,37797,37756, 37715,37674,37633,37592,37551,37509,37468,37427, 37386,37344,37303,37262,37220,37179,37137,37096, 37055,37013,36972,36930,36889,36847,36805,36764, 36722,36681,36639,36597,36556,36514,36472,36430, 36388,36347,36305,36263,36221,36179,36137,36095, 36053,36011,35969,35927,35885,35843,35801,35759, 35717,35675,35633,35590,35548,35506,35464,35421, 35379,35337,35294,35252,35210,35167,35125,35082, 35040,34997,34955,34912,34870,34827,34785,34742, 34699,34657,34614,34571,34529,34486,34443,34400, 34358,34315,34272,34229,34186,34143,34100,34057, 34015,33972,33929,33886,33843,33799,33756,33713, 33670,33627,33584,33541,33498,33454,33411,33368, 33325,33281,33238,33195,33151,33108,33065,33021, 32978,32934,32891,32847,32804,32760,32717,32673, 32630,32586,32542,32499,32455,32411,32368,32324, 32280,32236,32193,32149,32105,32061,32017,31974, 31930,31886,31842,31798,31754,31710,31666,31622, 31578,31534,31490,31446,31402,31357,31313,31269, 31225,31181,31136,31092,31048,31004,30959,30915, 30871,30826,30782,30738,30693,30649,30604,30560, 30515,30471,30426,30382,30337,30293,30248,30204, 30159,30114,30070,30025,29980,29936,29891,29846, 29801,29757,29712,29667,29622,29577,29533,29488, 29443,29398,29353,29308,29263,29218,29173,29128, 29083,29038,28993,28948,28903,28858,28812,28767, 28722,28677,28632,28586,28541,28496,28451,28405, 28360,28315,28269,28224,28179,28133,28088,28042, 27997,27952,27906,27861,27815,27770,27724,27678, 27633,27587,27542,27496,27450,27405,27359,27313, 27268,27222,27176,27131,27085,27039,26993,26947, 26902,26856,26810,26764,26718,26672,26626,26580, 26534,26488,26442,26396,26350,26304,26258,26212, 26166,26120,26074,26028,25982,25936,25889,25843, 25797,25751,25705,25658,25612,25566,25520,25473, 25427,25381,25334,25288,25241,25195,25149,25102, 25056,25009,24963,24916,24870,24823,24777,24730, 24684,24637,24591,24544,24497,24451,24404,24357, 24311,24264,24217,24171,24124,24077,24030,23984, 23937,23890,23843,23796,23750,23703,23656,23609, 23562,23515,23468,23421,23374,23327,23280,23233, 23186,23139,23092,23045,22998,22951,22904,22857, 22810,22763,22716,22668,22621,22574,22527,22480, 22433,22385,22338,22291,22243,22196,22149,22102, 22054,22007,21960,21912,21865,21817,21770,21723, 21675,21628,21580,21533,21485,21438,21390,21343, 21295,21248,21200,21153,21105,21057,21010,20962, 20915,20867,20819,20772,20724,20676,20629,20581, 20533,20485,20438,20390,20342,20294,20246,20199, 20151,20103,20055,20007,19959,19912,19864,19816, 19768,19720,19672,19624,19576,19528,19480,19432, 19384,19336,19288,19240,19192,19144,19096,19048, 19000,18951,18903,18855,18807,18759,18711,18663, 18614,18566,18518,18470,18421,18373,18325,18277, 18228,18180,18132,18084,18035,17987,17939,17890, 17842,17793,17745,17697,17648,17600,17551,17503, 17455,17406,17358,17309,17261,17212,17164,17115, 17067,17018,16970,16921,16872,16824,16775,16727, 16678,16629,16581,16532,16484,16435,16386,16338, 16289,16240,16191,16143,16094,16045,15997,15948, 15899,15850,15802,15753,15704,15655,15606,15557, 15509,15460,15411,15362,15313,15264,15215,15167, 15118,15069,15020,14971,14922,14873,14824,14775, 14726,14677,14628,14579,14530,14481,14432,14383, 14334,14285,14236,14187,14138,14089,14040,13990, 13941,13892,13843,13794,13745,13696,13646,13597, 13548,13499,13450,13401,13351,13302,13253,13204, 13154,13105,13056,13007,12957,12908,12859,12810, 12760,12711,12662,12612,12563,12514,12464,12415, 12366,12316,12267,12218,12168,12119,12069,12020, 11970,11921,11872,11822,11773,11723,11674,11624, 11575,11525,11476,11426,11377,11327,11278,11228, 11179,11129,11080,11030,10981,10931,10882,10832, 10782,10733,10683,10634,10584,10534,10485,10435, 10386,10336,10286,10237,10187,10137,10088,10038, 9988,9939,9889,9839,9790,9740,9690,9640, 9591,9541,9491,9442,9392,9342,9292,9243, 9193,9143,9093,9043,8994,8944,8894,8844, 8794,8745,8695,8645,8595,8545,8496,8446, 8396,8346,8296,8246,8196,8147,8097,8047, 7997,7947,7897,7847,7797,7747,7697,7648, 7598,7548,7498,7448,7398,7348,7298,7248, 7198,7148,7098,7048,6998,6948,6898,6848, 6798,6748,6698,6648,6598,6548,6498,6448, 6398,6348,6298,6248,6198,6148,6098,6048, 5998,5948,5898,5848,5798,5748,5697,5647, 5597,5547,5497,5447,5397,5347,5297,5247, 5197,5146,5096,5046,4996,4946,4896,4846, 4796,4745,4695,4645,4595,4545,4495,4445, 4394,4344,4294,4244,4194,4144,4093,4043, 3993,3943,3893,3843,3792,3742,3692,3642, 3592,3541,3491,3441,3391,3341,3291,3240, 3190,3140,3090,3039,2989,2939,2889,2839, 2788,2738,2688,2638,2587,2537,2487,2437, 2387,2336,2286,2236,2186,2135,2085,2035, 1985,1934,1884,1834,1784,1733,1683,1633, 1583,1532,1482,1432,1382,1331,1281,1231, 1181,1130,1080,1030,980,929,879,829, 779,728,678,628,578,527,477,427, 376,326,276,226,175,125,75,25, -25,-75,-125,-175,-226,-276,-326,-376, -427,-477,-527,-578,-628,-678,-728,-779, -829,-879,-929,-980,-1030,-1080,-1130,-1181, -1231,-1281,-1331,-1382,-1432,-1482,-1532,-1583, -1633,-1683,-1733,-1784,-1834,-1884,-1934,-1985, -2035,-2085,-2135,-2186,-2236,-2286,-2336,-2387, -2437,-2487,-2537,-2588,-2638,-2688,-2738,-2788, -2839,-2889,-2939,-2989,-3039,-3090,-3140,-3190, -3240,-3291,-3341,-3391,-3441,-3491,-3541,-3592, -3642,-3692,-3742,-3792,-3843,-3893,-3943,-3993, -4043,-4093,-4144,-4194,-4244,-4294,-4344,-4394, -4445,-4495,-4545,-4595,-4645,-4695,-4745,-4796, -4846,-4896,-4946,-4996,-5046,-5096,-5146,-5197, -5247,-5297,-5347,-5397,-5447,-5497,-5547,-5597, -5647,-5697,-5748,-5798,-5848,-5898,-5948,-5998, -6048,-6098,-6148,-6198,-6248,-6298,-6348,-6398, -6448,-6498,-6548,-6598,-6648,-6698,-6748,-6798, -6848,-6898,-6948,-6998,-7048,-7098,-7148,-7198, -7248,-7298,-7348,-7398,-7448,-7498,-7548,-7598, -7648,-7697,-7747,-7797,-7847,-7897,-7947,-7997, -8047,-8097,-8147,-8196,-8246,-8296,-8346,-8396, -8446,-8496,-8545,-8595,-8645,-8695,-8745,-8794, -8844,-8894,-8944,-8994,-9043,-9093,-9143,-9193, -9243,-9292,-9342,-9392,-9442,-9491,-9541,-9591, -9640,-9690,-9740,-9790,-9839,-9889,-9939,-9988, -10038,-10088,-10137,-10187,-10237,-10286,-10336,-10386, -10435,-10485,-10534,-10584,-10634,-10683,-10733,-10782, -10832,-10882,-10931,-10981,-11030,-11080,-11129,-11179, -11228,-11278,-11327,-11377,-11426,-11476,-11525,-11575, -11624,-11674,-11723,-11773,-11822,-11872,-11921,-11970, -12020,-12069,-12119,-12168,-12218,-12267,-12316,-12366, -12415,-12464,-12514,-12563,-12612,-12662,-12711,-12760, -12810,-12859,-12908,-12957,-13007,-13056,-13105,-13154, -13204,-13253,-13302,-13351,-13401,-13450,-13499,-13548, -13597,-13647,-13696,-13745,-13794,-13843,-13892,-13941, -13990,-14040,-14089,-14138,-14187,-14236,-14285,-14334, -14383,-14432,-14481,-14530,-14579,-14628,-14677,-14726, -14775,-14824,-14873,-14922,-14971,-15020,-15069,-15118, -15167,-15215,-15264,-15313,-15362,-15411,-15460,-15509, -15557,-15606,-15655,-15704,-15753,-15802,-15850,-15899, -15948,-15997,-16045,-16094,-16143,-16191,-16240,-16289, -16338,-16386,-16435,-16484,-16532,-16581,-16629,-16678, -16727,-16775,-16824,-16872,-16921,-16970,-17018,-17067, -17115,-17164,-17212,-17261,-17309,-17358,-17406,-17455, -17503,-17551,-17600,-17648,-17697,-17745,-17793,-17842, -17890,-17939,-17987,-18035,-18084,-18132,-18180,-18228, -18277,-18325,-18373,-18421,-18470,-18518,-18566,-18614, -18663,-18711,-18759,-18807,-18855,-18903,-18951,-19000, -19048,-19096,-19144,-19192,-19240,-19288,-19336,-19384, -19432,-19480,-19528,-19576,-19624,-19672,-19720,-19768, -19816,-19864,-19912,-19959,-20007,-20055,-20103,-20151, -20199,-20246,-20294,-20342,-20390,-20438,-20485,-20533, -20581,-20629,-20676,-20724,-20772,-20819,-20867,-20915, -20962,-21010,-21057,-21105,-21153,-21200,-21248,-21295, -21343,-21390,-21438,-21485,-21533,-21580,-21628,-21675, -21723,-21770,-21817,-21865,-21912,-21960,-22007,-22054, -22102,-22149,-22196,-22243,-22291,-22338,-22385,-22433, -22480,-22527,-22574,-22621,-22668,-22716,-22763,-22810, -22857,-22904,-22951,-22998,-23045,-23092,-23139,-23186, -23233,-23280,-23327,-23374,-23421,-23468,-23515,-23562, -23609,-23656,-23703,-23750,-23796,-23843,-23890,-23937, -23984,-24030,-24077,-24124,-24171,-24217,-24264,-24311, -24357,-24404,-24451,-24497,-24544,-24591,-24637,-24684, -24730,-24777,-24823,-24870,-24916,-24963,-25009,-25056, -25102,-25149,-25195,-25241,-25288,-25334,-25381,-25427, -25473,-25520,-25566,-25612,-25658,-25705,-25751,-25797, -25843,-25889,-25936,-25982,-26028,-26074,-26120,-26166, -26212,-26258,-26304,-26350,-26396,-26442,-26488,-26534, -26580,-26626,-26672,-26718,-26764,-26810,-26856,-26902, -26947,-26993,-27039,-27085,-27131,-27176,-27222,-27268, -27313,-27359,-27405,-27450,-27496,-27542,-27587,-27633, -27678,-27724,-27770,-27815,-27861,-27906,-27952,-27997, -28042,-28088,-28133,-28179,-28224,-28269,-28315,-28360, -28405,-28451,-28496,-28541,-28586,-28632,-28677,-28722, -28767,-28812,-28858,-28903,-28948,-28993,-29038,-29083, -29128,-29173,-29218,-29263,-29308,-29353,-29398,-29443, -29488,-29533,-29577,-29622,-29667,-29712,-29757,-29801, -29846,-29891,-29936,-29980,-30025,-30070,-30114,-30159, -30204,-30248,-30293,-30337,-30382,-30426,-30471,-30515, -30560,-30604,-30649,-30693,-30738,-30782,-30826,-30871, -30915,-30959,-31004,-31048,-31092,-31136,-31181,-31225, -31269,-31313,-31357,-31402,-31446,-31490,-31534,-31578, -31622,-31666,-31710,-31754,-31798,-31842,-31886,-31930, -31974,-32017,-32061,-32105,-32149,-32193,-32236,-32280, -32324,-32368,-32411,-32455,-32499,-32542,-32586,-32630, -32673,-32717,-32760,-32804,-32847,-32891,-32934,-32978, -33021,-33065,-33108,-33151,-33195,-33238,-33281,-33325, -33368,-33411,-33454,-33498,-33541,-33584,-33627,-33670, -33713,-33756,-33799,-33843,-33886,-33929,-33972,-34015, -34057,-34100,-34143,-34186,-34229,-34272,-34315,-34358, -34400,-34443,-34486,-34529,-34571,-34614,-34657,-34699, -34742,-34785,-34827,-34870,-34912,-34955,-34997,-35040, -35082,-35125,-35167,-35210,-35252,-35294,-35337,-35379, -35421,-35464,-35506,-35548,-35590,-35633,-35675,-35717, -35759,-35801,-35843,-35885,-35927,-35969,-36011,-36053, -36095,-36137,-36179,-36221,-36263,-36305,-36347,-36388, -36430,-36472,-36514,-36555,-36597,-36639,-36681,-36722, -36764,-36805,-36847,-36889,-36930,-36972,-37013,-37055, -37096,-37137,-37179,-37220,-37262,-37303,-37344,-37386, -37427,-37468,-37509,-37551,-37592,-37633,-37674,-37715, -37756,-37797,-37838,-37879,-37920,-37961,-38002,-38043, -38084,-38125,-38166,-38207,-38248,-38288,-38329,-38370, -38411,-38451,-38492,-38533,-38573,-38614,-38655,-38695, -38736,-38776,-38817,-38857,-38898,-38938,-38979,-39019, -39059,-39100,-39140,-39180,-39221,-39261,-39301,-39341, -39382,-39422,-39462,-39502,-39542,-39582,-39622,-39662, -39702,-39742,-39782,-39822,-39862,-39902,-39942,-39982, -40021,-40061,-40101,-40141,-40180,-40220,-40260,-40299, -40339,-40379,-40418,-40458,-40497,-40537,-40576,-40616, -40655,-40695,-40734,-40773,-40813,-40852,-40891,-40931, -40970,-41009,-41048,-41087,-41127,-41166,-41205,-41244, -41283,-41322,-41361,-41400,-41439,-41478,-41517,-41556, -41595,-41633,-41672,-41711,-41750,-41788,-41827,-41866, -41904,-41943,-41982,-42020,-42059,-42097,-42136,-42174, -42213,-42251,-42290,-42328,-42366,-42405,-42443,-42481, -42520,-42558,-42596,-42634,-42672,-42711,-42749,-42787, -42825,-42863,-42901,-42939,-42977,-43015,-43053,-43091, -43128,-43166,-43204,-43242,-43280,-43317,-43355,-43393, -43430,-43468,-43506,-43543,-43581,-43618,-43656,-43693, -43731,-43768,-43806,-43843,-43880,-43918,-43955,-43992, -44029,-44067,-44104,-44141,-44178,-44215,-44252,-44289, -44326,-44363,-44400,-44437,-44474,-44511,-44548,-44585, -44622,-44659,-44695,-44732,-44769,-44806,-44842,-44879, -44915,-44952,-44989,-45025,-45062,-45098,-45135,-45171, -45207,-45244,-45280,-45316,-45353,-45389,-45425,-45462, -45498,-45534,-45570,-45606,-45642,-45678,-45714,-45750, -45786,-45822,-45858,-45894,-45930,-45966,-46002,-46037, -46073,-46109,-46145,-46180,-46216,-46252,-46287,-46323, -46358,-46394,-46429,-46465,-46500,-46536,-46571,-46606, -46642,-46677,-46712,-46747,-46783,-46818,-46853,-46888, -46923,-46958,-46993,-47028,-47063,-47098,-47133,-47168, -47203,-47238,-47273,-47308,-47342,-47377,-47412,-47446, -47481,-47516,-47550,-47585,-47619,-47654,-47688,-47723, -47757,-47792,-47826,-47860,-47895,-47929,-47963,-47998, -48032,-48066,-48100,-48134,-48168,-48202,-48236,-48271, -48304,-48338,-48372,-48406,-48440,-48474,-48508,-48542, -48575,-48609,-48643,-48676,-48710,-48744,-48777,-48811, -48844,-48878,-48911,-48945,-48978,-49012,-49045,-49078, -49112,-49145,-49178,-49211,-49244,-49278,-49311,-49344, -49377,-49410,-49443,-49476,-49509,-49542,-49575,-49608, -49640,-49673,-49706,-49739,-49771,-49804,-49837,-49869, -49902,-49935,-49967,-50000,-50032,-50065,-50097,-50129, -50162,-50194,-50226,-50259,-50291,-50323,-50355,-50387, -50420,-50452,-50484,-50516,-50548,-50580,-50612,-50644, -50675,-50707,-50739,-50771,-50803,-50834,-50866,-50898, -50929,-50961,-50993,-51024,-51056,-51087,-51119,-51150, -51182,-51213,-51244,-51276,-51307,-51338,-51369,-51401, -51432,-51463,-51494,-51525,-51556,-51587,-51618,-51649, -51680,-51711,-51742,-51773,-51803,-51834,-51865,-51896, -51926,-51957,-51988,-52018,-52049,-52079,-52110,-52140, -52171,-52201,-52231,-52262,-52292,-52322,-52353,-52383, -52413,-52443,-52473,-52503,-52534,-52564,-52594,-52624, -52653,-52683,-52713,-52743,-52773,-52803,-52832,-52862, -52892,-52922,-52951,-52981,-53010,-53040,-53069,-53099, -53128,-53158,-53187,-53216,-53246,-53275,-53304,-53334, -53363,-53392,-53421,-53450,-53479,-53508,-53537,-53566, -53595,-53624,-53653,-53682,-53711,-53739,-53768,-53797, -53826,-53854,-53883,-53911,-53940,-53969,-53997,-54026, -54054,-54082,-54111,-54139,-54167,-54196,-54224,-54252, -54280,-54308,-54337,-54365,-54393,-54421,-54449,-54477, -54505,-54533,-54560,-54588,-54616,-54644,-54672,-54699, -54727,-54755,-54782,-54810,-54837,-54865,-54892,-54920, -54947,-54974,-55002,-55029,-55056,-55084,-55111,-55138, -55165,-55192,-55219,-55246,-55274,-55300,-55327,-55354, -55381,-55408,-55435,-55462,-55489,-55515,-55542,-55569, -55595,-55622,-55648,-55675,-55701,-55728,-55754,-55781, -55807,-55833,-55860,-55886,-55912,-55938,-55965,-55991, -56017,-56043,-56069,-56095,-56121,-56147,-56173,-56199, -56225,-56250,-56276,-56302,-56328,-56353,-56379,-56404, -56430,-56456,-56481,-56507,-56532,-56557,-56583,-56608, -56633,-56659,-56684,-56709,-56734,-56760,-56785,-56810, -56835,-56860,-56885,-56910,-56935,-56959,-56984,-57009, -57034,-57059,-57083,-57108,-57133,-57157,-57182,-57206, -57231,-57255,-57280,-57304,-57329,-57353,-57377,-57402, -57426,-57450,-57474,-57498,-57522,-57546,-57570,-57594, -57618,-57642,-57666,-57690,-57714,-57738,-57762,-57785, -57809,-57833,-57856,-57880,-57903,-57927,-57950,-57974, -57997,-58021,-58044,-58067,-58091,-58114,-58137,-58160, -58183,-58207,-58230,-58253,-58276,-58299,-58322,-58345, -58367,-58390,-58413,-58436,-58459,-58481,-58504,-58527, -58549,-58572,-58594,-58617,-58639,-58662,-58684,-58706, -58729,-58751,-58773,-58795,-58818,-58840,-58862,-58884, -58906,-58928,-58950,-58972,-58994,-59016,-59038,-59059, -59081,-59103,-59125,-59146,-59168,-59190,-59211,-59233, -59254,-59276,-59297,-59318,-59340,-59361,-59382,-59404, -59425,-59446,-59467,-59488,-59509,-59530,-59551,-59572, -59593,-59614,-59635,-59656,-59677,-59697,-59718,-59739, -59759,-59780,-59801,-59821,-59842,-59862,-59883,-59903, -59923,-59944,-59964,-59984,-60004,-60025,-60045,-60065, -60085,-60105,-60125,-60145,-60165,-60185,-60205,-60225, -60244,-60264,-60284,-60304,-60323,-60343,-60363,-60382, -60402,-60421,-60441,-60460,-60479,-60499,-60518,-60537, -60556,-60576,-60595,-60614,-60633,-60652,-60671,-60690, -60709,-60728,-60747,-60766,-60785,-60803,-60822,-60841, -60859,-60878,-60897,-60915,-60934,-60952,-60971,-60989, -61007,-61026,-61044,-61062,-61081,-61099,-61117,-61135, -61153,-61171,-61189,-61207,-61225,-61243,-61261,-61279, -61297,-61314,-61332,-61350,-61367,-61385,-61403,-61420, -61438,-61455,-61473,-61490,-61507,-61525,-61542,-61559, -61577,-61594,-61611,-61628,-61645,-61662,-61679,-61696, -61713,-61730,-61747,-61764,-61780,-61797,-61814,-61831, -61847,-61864,-61880,-61897,-61913,-61930,-61946,-61963, -61979,-61995,-62012,-62028,-62044,-62060,-62076,-62092, -62108,-62125,-62141,-62156,-62172,-62188,-62204,-62220, -62236,-62251,-62267,-62283,-62298,-62314,-62329,-62345, -62360,-62376,-62391,-62407,-62422,-62437,-62453,-62468, -62483,-62498,-62513,-62528,-62543,-62558,-62573,-62588, -62603,-62618,-62633,-62648,-62662,-62677,-62692,-62706, -62721,-62735,-62750,-62764,-62779,-62793,-62808,-62822, -62836,-62850,-62865,-62879,-62893,-62907,-62921,-62935, -62949,-62963,-62977,-62991,-63005,-63019,-63032,-63046, -63060,-63074,-63087,-63101,-63114,-63128,-63141,-63155, -63168,-63182,-63195,-63208,-63221,-63235,-63248,-63261, -63274,-63287,-63300,-63313,-63326,-63339,-63352,-63365, -63378,-63390,-63403,-63416,-63429,-63441,-63454,-63466, -63479,-63491,-63504,-63516,-63528,-63541,-63553,-63565, -63578,-63590,-63602,-63614,-63626,-63638,-63650,-63662, -63674,-63686,-63698,-63709,-63721,-63733,-63745,-63756, -63768,-63779,-63791,-63803,-63814,-63825,-63837,-63848, -63859,-63871,-63882,-63893,-63904,-63915,-63927,-63938, -63949,-63960,-63971,-63981,-63992,-64003,-64014,-64025, -64035,-64046,-64057,-64067,-64078,-64088,-64099,-64109, -64120,-64130,-64140,-64151,-64161,-64171,-64181,-64192, -64202,-64212,-64222,-64232,-64242,-64252,-64261,-64271, -64281,-64291,-64301,-64310,-64320,-64330,-64339,-64349, -64358,-64368,-64377,-64387,-64396,-64405,-64414,-64424, -64433,-64442,-64451,-64460,-64469,-64478,-64487,-64496, -64505,-64514,-64523,-64532,-64540,-64549,-64558,-64566, -64575,-64584,-64592,-64601,-64609,-64617,-64626,-64634, -64642,-64651,-64659,-64667,-64675,-64683,-64691,-64699, -64707,-64715,-64723,-64731,-64739,-64747,-64754,-64762, -64770,-64777,-64785,-64793,-64800,-64808,-64815,-64822, -64830,-64837,-64844,-64852,-64859,-64866,-64873,-64880, -64887,-64895,-64902,-64908,-64915,-64922,-64929,-64936, -64943,-64949,-64956,-64963,-64969,-64976,-64982,-64989, -64995,-65002,-65008,-65015,-65021,-65027,-65033,-65040, -65046,-65052,-65058,-65064,-65070,-65076,-65082,-65088, -65094,-65099,-65105,-65111,-65117,-65122,-65128,-65133, -65139,-65144,-65150,-65155,-65161,-65166,-65171,-65177, -65182,-65187,-65192,-65197,-65202,-65207,-65212,-65217, -65222,-65227,-65232,-65237,-65242,-65246,-65251,-65256, -65260,-65265,-65270,-65274,-65279,-65283,-65287,-65292, -65296,-65300,-65305,-65309,-65313,-65317,-65321,-65325, -65329,-65333,-65337,-65341,-65345,-65349,-65352,-65356, -65360,-65363,-65367,-65371,-65374,-65378,-65381,-65385, -65388,-65391,-65395,-65398,-65401,-65404,-65408,-65411, -65414,-65417,-65420,-65423,-65426,-65429,-65431,-65434, -65437,-65440,-65442,-65445,-65448,-65450,-65453,-65455, -65458,-65460,-65463,-65465,-65467,-65470,-65472,-65474, -65476,-65478,-65480,-65482,-65484,-65486,-65488,-65490, -65492,-65494,-65496,-65497,-65499,-65501,-65502,-65504, -65505,-65507,-65508,-65510,-65511,-65513,-65514,-65515, -65516,-65518,-65519,-65520,-65521,-65522,-65523,-65524, -65525,-65526,-65527,-65527,-65528,-65529,-65530,-65530, -65531,-65531,-65532,-65532,-65533,-65533,-65534,-65534, -65534,-65535,-65535,-65535,-65535,-65535,-65535,-65535, -65535,-65535,-65535,-65535,-65535,-65535,-65535,-65534, -65534,-65534,-65533,-65533,-65532,-65532,-65531,-65531, -65530,-65530,-65529,-65528,-65527,-65527,-65526,-65525, -65524,-65523,-65522,-65521,-65520,-65519,-65518,-65516, -65515,-65514,-65513,-65511,-65510,-65508,-65507,-65505, -65504,-65502,-65501,-65499,-65497,-65496,-65494,-65492, -65490,-65488,-65486,-65484,-65482,-65480,-65478,-65476, -65474,-65472,-65470,-65467,-65465,-65463,-65460,-65458, -65455,-65453,-65450,-65448,-65445,-65442,-65440,-65437, -65434,-65431,-65429,-65426,-65423,-65420,-65417,-65414, -65411,-65408,-65404,-65401,-65398,-65395,-65391,-65388, -65385,-65381,-65378,-65374,-65371,-65367,-65363,-65360, -65356,-65352,-65349,-65345,-65341,-65337,-65333,-65329, -65325,-65321,-65317,-65313,-65309,-65305,-65300,-65296, -65292,-65287,-65283,-65279,-65274,-65270,-65265,-65260, -65256,-65251,-65246,-65242,-65237,-65232,-65227,-65222, -65217,-65212,-65207,-65202,-65197,-65192,-65187,-65182, -65177,-65171,-65166,-65161,-65155,-65150,-65144,-65139, -65133,-65128,-65122,-65117,-65111,-65105,-65099,-65094, -65088,-65082,-65076,-65070,-65064,-65058,-65052,-65046, -65040,-65033,-65027,-65021,-65015,-65008,-65002,-64995, -64989,-64982,-64976,-64969,-64963,-64956,-64949,-64943, -64936,-64929,-64922,-64915,-64908,-64902,-64895,-64887, -64880,-64873,-64866,-64859,-64852,-64844,-64837,-64830, -64822,-64815,-64808,-64800,-64793,-64785,-64777,-64770, -64762,-64754,-64747,-64739,-64731,-64723,-64715,-64707, -64699,-64691,-64683,-64675,-64667,-64659,-64651,-64642, -64634,-64626,-64617,-64609,-64601,-64592,-64584,-64575, -64566,-64558,-64549,-64540,-64532,-64523,-64514,-64505, -64496,-64487,-64478,-64469,-64460,-64451,-64442,-64433, -64424,-64414,-64405,-64396,-64387,-64377,-64368,-64358, -64349,-64339,-64330,-64320,-64310,-64301,-64291,-64281, -64271,-64261,-64252,-64242,-64232,-64222,-64212,-64202, -64192,-64181,-64171,-64161,-64151,-64140,-64130,-64120, -64109,-64099,-64088,-64078,-64067,-64057,-64046,-64035, -64025,-64014,-64003,-63992,-63981,-63971,-63960,-63949, -63938,-63927,-63915,-63904,-63893,-63882,-63871,-63859, -63848,-63837,-63825,-63814,-63803,-63791,-63779,-63768, -63756,-63745,-63733,-63721,-63709,-63698,-63686,-63674, -63662,-63650,-63638,-63626,-63614,-63602,-63590,-63578, -63565,-63553,-63541,-63528,-63516,-63504,-63491,-63479, -63466,-63454,-63441,-63429,-63416,-63403,-63390,-63378, -63365,-63352,-63339,-63326,-63313,-63300,-63287,-63274, -63261,-63248,-63235,-63221,-63208,-63195,-63182,-63168, -63155,-63141,-63128,-63114,-63101,-63087,-63074,-63060, -63046,-63032,-63019,-63005,-62991,-62977,-62963,-62949, -62935,-62921,-62907,-62893,-62879,-62865,-62850,-62836, -62822,-62808,-62793,-62779,-62764,-62750,-62735,-62721, -62706,-62692,-62677,-62662,-62648,-62633,-62618,-62603, -62588,-62573,-62558,-62543,-62528,-62513,-62498,-62483, -62468,-62453,-62437,-62422,-62407,-62391,-62376,-62360, -62345,-62329,-62314,-62298,-62283,-62267,-62251,-62236, -62220,-62204,-62188,-62172,-62156,-62141,-62125,-62108, -62092,-62076,-62060,-62044,-62028,-62012,-61995,-61979, -61963,-61946,-61930,-61913,-61897,-61880,-61864,-61847, -61831,-61814,-61797,-61780,-61764,-61747,-61730,-61713, -61696,-61679,-61662,-61645,-61628,-61611,-61594,-61577, -61559,-61542,-61525,-61507,-61490,-61473,-61455,-61438, -61420,-61403,-61385,-61367,-61350,-61332,-61314,-61297, -61279,-61261,-61243,-61225,-61207,-61189,-61171,-61153, -61135,-61117,-61099,-61081,-61062,-61044,-61026,-61007, -60989,-60971,-60952,-60934,-60915,-60897,-60878,-60859, -60841,-60822,-60803,-60785,-60766,-60747,-60728,-60709, -60690,-60671,-60652,-60633,-60614,-60595,-60576,-60556, -60537,-60518,-60499,-60479,-60460,-60441,-60421,-60402, -60382,-60363,-60343,-60323,-60304,-60284,-60264,-60244, -60225,-60205,-60185,-60165,-60145,-60125,-60105,-60085, -60065,-60045,-60025,-60004,-59984,-59964,-59944,-59923, -59903,-59883,-59862,-59842,-59821,-59801,-59780,-59759, -59739,-59718,-59697,-59677,-59656,-59635,-59614,-59593, -59572,-59551,-59530,-59509,-59488,-59467,-59446,-59425, -59404,-59382,-59361,-59340,-59318,-59297,-59276,-59254, -59233,-59211,-59189,-59168,-59146,-59125,-59103,-59081, -59059,-59038,-59016,-58994,-58972,-58950,-58928,-58906, -58884,-58862,-58840,-58818,-58795,-58773,-58751,-58729, -58706,-58684,-58662,-58639,-58617,-58594,-58572,-58549, -58527,-58504,-58481,-58459,-58436,-58413,-58390,-58367, -58345,-58322,-58299,-58276,-58253,-58230,-58207,-58183, -58160,-58137,-58114,-58091,-58067,-58044,-58021,-57997, -57974,-57950,-57927,-57903,-57880,-57856,-57833,-57809, -57785,-57762,-57738,-57714,-57690,-57666,-57642,-57618, -57594,-57570,-57546,-57522,-57498,-57474,-57450,-57426, -57402,-57377,-57353,-57329,-57304,-57280,-57255,-57231, -57206,-57182,-57157,-57133,-57108,-57083,-57059,-57034, -57009,-56984,-56959,-56935,-56910,-56885,-56860,-56835, -56810,-56785,-56760,-56734,-56709,-56684,-56659,-56633, -56608,-56583,-56557,-56532,-56507,-56481,-56456,-56430, -56404,-56379,-56353,-56328,-56302,-56276,-56250,-56225, -56199,-56173,-56147,-56121,-56095,-56069,-56043,-56017, -55991,-55965,-55938,-55912,-55886,-55860,-55833,-55807, -55781,-55754,-55728,-55701,-55675,-55648,-55622,-55595, -55569,-55542,-55515,-55489,-55462,-55435,-55408,-55381, -55354,-55327,-55300,-55274,-55246,-55219,-55192,-55165, -55138,-55111,-55084,-55056,-55029,-55002,-54974,-54947, -54920,-54892,-54865,-54837,-54810,-54782,-54755,-54727, -54699,-54672,-54644,-54616,-54588,-54560,-54533,-54505, -54477,-54449,-54421,-54393,-54365,-54337,-54308,-54280, -54252,-54224,-54196,-54167,-54139,-54111,-54082,-54054, -54026,-53997,-53969,-53940,-53911,-53883,-53854,-53826, -53797,-53768,-53739,-53711,-53682,-53653,-53624,-53595, -53566,-53537,-53508,-53479,-53450,-53421,-53392,-53363, -53334,-53304,-53275,-53246,-53216,-53187,-53158,-53128, -53099,-53069,-53040,-53010,-52981,-52951,-52922,-52892, -52862,-52832,-52803,-52773,-52743,-52713,-52683,-52653, -52624,-52594,-52564,-52534,-52503,-52473,-52443,-52413, -52383,-52353,-52322,-52292,-52262,-52231,-52201,-52171, -52140,-52110,-52079,-52049,-52018,-51988,-51957,-51926, -51896,-51865,-51834,-51803,-51773,-51742,-51711,-51680, -51649,-51618,-51587,-51556,-51525,-51494,-51463,-51432, -51401,-51369,-51338,-51307,-51276,-51244,-51213,-51182, -51150,-51119,-51087,-51056,-51024,-50993,-50961,-50929, -50898,-50866,-50834,-50803,-50771,-50739,-50707,-50675, -50644,-50612,-50580,-50548,-50516,-50484,-50452,-50420, -50387,-50355,-50323,-50291,-50259,-50226,-50194,-50162, -50129,-50097,-50065,-50032,-50000,-49967,-49935,-49902, -49869,-49837,-49804,-49771,-49739,-49706,-49673,-49640, -49608,-49575,-49542,-49509,-49476,-49443,-49410,-49377, -49344,-49311,-49278,-49244,-49211,-49178,-49145,-49112, -49078,-49045,-49012,-48978,-48945,-48911,-48878,-48844, -48811,-48777,-48744,-48710,-48676,-48643,-48609,-48575, -48542,-48508,-48474,-48440,-48406,-48372,-48338,-48305, -48271,-48237,-48202,-48168,-48134,-48100,-48066,-48032, -47998,-47963,-47929,-47895,-47860,-47826,-47792,-47757, -47723,-47688,-47654,-47619,-47585,-47550,-47516,-47481, -47446,-47412,-47377,-47342,-47307,-47273,-47238,-47203, -47168,-47133,-47098,-47063,-47028,-46993,-46958,-46923, -46888,-46853,-46818,-46783,-46747,-46712,-46677,-46642, -46606,-46571,-46536,-46500,-46465,-46429,-46394,-46358, -46323,-46287,-46251,-46216,-46180,-46145,-46109,-46073, -46037,-46002,-45966,-45930,-45894,-45858,-45822,-45786, -45750,-45714,-45678,-45642,-45606,-45570,-45534,-45498, -45462,-45425,-45389,-45353,-45316,-45280,-45244,-45207, -45171,-45135,-45098,-45062,-45025,-44989,-44952,-44915, -44879,-44842,-44806,-44769,-44732,-44695,-44659,-44622, -44585,-44548,-44511,-44474,-44437,-44400,-44363,-44326, -44289,-44252,-44215,-44178,-44141,-44104,-44067,-44029, -43992,-43955,-43918,-43880,-43843,-43806,-43768,-43731, -43693,-43656,-43618,-43581,-43543,-43506,-43468,-43430, -43393,-43355,-43317,-43280,-43242,-43204,-43166,-43128, -43091,-43053,-43015,-42977,-42939,-42901,-42863,-42825, -42787,-42749,-42711,-42672,-42634,-42596,-42558,-42520, -42481,-42443,-42405,-42366,-42328,-42290,-42251,-42213, -42174,-42136,-42097,-42059,-42020,-41982,-41943,-41904, -41866,-41827,-41788,-41750,-41711,-41672,-41633,-41595, -41556,-41517,-41478,-41439,-41400,-41361,-41322,-41283, -41244,-41205,-41166,-41127,-41087,-41048,-41009,-40970, -40931,-40891,-40852,-40813,-40773,-40734,-40695,-40655, -40616,-40576,-40537,-40497,-40458,-40418,-40379,-40339, -40299,-40260,-40220,-40180,-40141,-40101,-40061,-40021, -39982,-39942,-39902,-39862,-39822,-39782,-39742,-39702, -39662,-39622,-39582,-39542,-39502,-39462,-39422,-39382, -39341,-39301,-39261,-39221,-39180,-39140,-39100,-39059, -39019,-38979,-38938,-38898,-38857,-38817,-38776,-38736, -38695,-38655,-38614,-38573,-38533,-38492,-38451,-38411, -38370,-38329,-38288,-38248,-38207,-38166,-38125,-38084, -38043,-38002,-37961,-37920,-37879,-37838,-37797,-37756, -37715,-37674,-37633,-37592,-37550,-37509,-37468,-37427, -37386,-37344,-37303,-37262,-37220,-37179,-37137,-37096, -37055,-37013,-36972,-36930,-36889,-36847,-36805,-36764, -36722,-36681,-36639,-36597,-36556,-36514,-36472,-36430, -36388,-36347,-36305,-36263,-36221,-36179,-36137,-36095, -36053,-36011,-35969,-35927,-35885,-35843,-35801,-35759, -35717,-35675,-35633,-35590,-35548,-35506,-35464,-35421, -35379,-35337,-35294,-35252,-35210,-35167,-35125,-35082, -35040,-34997,-34955,-34912,-34870,-34827,-34785,-34742, -34699,-34657,-34614,-34571,-34529,-34486,-34443,-34400, -34358,-34315,-34272,-34229,-34186,-34143,-34100,-34057, -34015,-33972,-33929,-33886,-33843,-33799,-33756,-33713, -33670,-33627,-33584,-33541,-33498,-33454,-33411,-33368, -33325,-33281,-33238,-33195,-33151,-33108,-33065,-33021, -32978,-32934,-32891,-32847,-32804,-32760,-32717,-32673, -32630,-32586,-32542,-32499,-32455,-32411,-32368,-32324, -32280,-32236,-32193,-32149,-32105,-32061,-32017,-31974, -31930,-31886,-31842,-31798,-31754,-31710,-31666,-31622, -31578,-31534,-31490,-31446,-31402,-31357,-31313,-31269, -31225,-31181,-31136,-31092,-31048,-31004,-30959,-30915, -30871,-30826,-30782,-30738,-30693,-30649,-30604,-30560, -30515,-30471,-30426,-30382,-30337,-30293,-30248,-30204, -30159,-30114,-30070,-30025,-29980,-29936,-29891,-29846, -29801,-29757,-29712,-29667,-29622,-29577,-29533,-29488, -29443,-29398,-29353,-29308,-29263,-29218,-29173,-29128, -29083,-29038,-28993,-28948,-28903,-28858,-28812,-28767, -28722,-28677,-28632,-28586,-28541,-28496,-28451,-28405, -28360,-28315,-28269,-28224,-28179,-28133,-28088,-28042, -27997,-27952,-27906,-27861,-27815,-27770,-27724,-27678, -27633,-27587,-27542,-27496,-27450,-27405,-27359,-27313, -27268,-27222,-27176,-27131,-27085,-27039,-26993,-26947, -26902,-26856,-26810,-26764,-26718,-26672,-26626,-26580, -26534,-26488,-26442,-26396,-26350,-26304,-26258,-26212, -26166,-26120,-26074,-26028,-25982,-25936,-25889,-25843, -25797,-25751,-25705,-25658,-25612,-25566,-25520,-25473, -25427,-25381,-25334,-25288,-25241,-25195,-25149,-25102, -25056,-25009,-24963,-24916,-24870,-24823,-24777,-24730, -24684,-24637,-24591,-24544,-24497,-24451,-24404,-24357, -24311,-24264,-24217,-24171,-24124,-24077,-24030,-23984, -23937,-23890,-23843,-23796,-23750,-23703,-23656,-23609, -23562,-23515,-23468,-23421,-23374,-23327,-23280,-23233, -23186,-23139,-23092,-23045,-22998,-22951,-22904,-22857, -22810,-22763,-22716,-22668,-22621,-22574,-22527,-22480, -22432,-22385,-22338,-22291,-22243,-22196,-22149,-22102, -22054,-22007,-21960,-21912,-21865,-21817,-21770,-21723, -21675,-21628,-21580,-21533,-21485,-21438,-21390,-21343, -21295,-21248,-21200,-21153,-21105,-21057,-21010,-20962, -20915,-20867,-20819,-20772,-20724,-20676,-20629,-20581, -20533,-20485,-20438,-20390,-20342,-20294,-20246,-20199, -20151,-20103,-20055,-20007,-19959,-19912,-19864,-19816, -19768,-19720,-19672,-19624,-19576,-19528,-19480,-19432, -19384,-19336,-19288,-19240,-19192,-19144,-19096,-19048, -19000,-18951,-18903,-18855,-18807,-18759,-18711,-18663, -18614,-18566,-18518,-18470,-18421,-18373,-18325,-18277, -18228,-18180,-18132,-18084,-18035,-17987,-17939,-17890, -17842,-17793,-17745,-17697,-17648,-17600,-17551,-17503, -17455,-17406,-17358,-17309,-17261,-17212,-17164,-17115, -17067,-17018,-16970,-16921,-16872,-16824,-16775,-16727, -16678,-16629,-16581,-16532,-16484,-16435,-16386,-16338, -16289,-16240,-16191,-16143,-16094,-16045,-15997,-15948, -15899,-15850,-15802,-15753,-15704,-15655,-15606,-15557, -15509,-15460,-15411,-15362,-15313,-15264,-15215,-15167, -15118,-15069,-15020,-14971,-14922,-14873,-14824,-14775, -14726,-14677,-14628,-14579,-14530,-14481,-14432,-14383, -14334,-14285,-14236,-14187,-14138,-14089,-14040,-13990, -13941,-13892,-13843,-13794,-13745,-13696,-13647,-13597, -13548,-13499,-13450,-13401,-13351,-13302,-13253,-13204, -13154,-13105,-13056,-13007,-12957,-12908,-12859,-12810, -12760,-12711,-12662,-12612,-12563,-12514,-12464,-12415, -12366,-12316,-12267,-12217,-12168,-12119,-12069,-12020, -11970,-11921,-11872,-11822,-11773,-11723,-11674,-11624, -11575,-11525,-11476,-11426,-11377,-11327,-11278,-11228, -11179,-11129,-11080,-11030,-10981,-10931,-10882,-10832, -10782,-10733,-10683,-10634,-10584,-10534,-10485,-10435, -10386,-10336,-10286,-10237,-10187,-10137,-10088,-10038, -9988,-9939,-9889,-9839,-9790,-9740,-9690,-9640, -9591,-9541,-9491,-9442,-9392,-9342,-9292,-9243, -9193,-9143,-9093,-9043,-8994,-8944,-8894,-8844, -8794,-8745,-8695,-8645,-8595,-8545,-8496,-8446, -8396,-8346,-8296,-8246,-8196,-8147,-8097,-8047, -7997,-7947,-7897,-7847,-7797,-7747,-7697,-7648, -7598,-7548,-7498,-7448,-7398,-7348,-7298,-7248, -7198,-7148,-7098,-7048,-6998,-6948,-6898,-6848, -6798,-6748,-6698,-6648,-6598,-6548,-6498,-6448, -6398,-6348,-6298,-6248,-6198,-6148,-6098,-6048, -5998,-5948,-5898,-5848,-5798,-5747,-5697,-5647, -5597,-5547,-5497,-5447,-5397,-5347,-5297,-5247, -5197,-5146,-5096,-5046,-4996,-4946,-4896,-4846, -4796,-4745,-4695,-4645,-4595,-4545,-4495,-4445, -4394,-4344,-4294,-4244,-4194,-4144,-4093,-4043, -3993,-3943,-3893,-3843,-3792,-3742,-3692,-3642, -3592,-3541,-3491,-3441,-3391,-3341,-3291,-3240, -3190,-3140,-3090,-3039,-2989,-2939,-2889,-2839, -2788,-2738,-2688,-2638,-2588,-2537,-2487,-2437, -2387,-2336,-2286,-2236,-2186,-2135,-2085,-2035, -1985,-1934,-1884,-1834,-1784,-1733,-1683,-1633, -1583,-1532,-1482,-1432,-1382,-1331,-1281,-1231, -1181,-1130,-1080,-1030,-980,-929,-879,-829, -779,-728,-678,-628,-578,-527,-477,-427, -376,-326,-276,-226,-175,-125,-75,-25, 25,75,125,175,226,276,326,376, 427,477,527,578,628,678,728,779, 829,879,929,980,1030,1080,1130,1181, 1231,1281,1331,1382,1432,1482,1532,1583, 1633,1683,1733,1784,1834,1884,1934,1985, 2035,2085,2135,2186,2236,2286,2336,2387, 2437,2487,2537,2587,2638,2688,2738,2788, 2839,2889,2939,2989,3039,3090,3140,3190, 3240,3291,3341,3391,3441,3491,3542,3592, 3642,3692,3742,3792,3843,3893,3943,3993, 4043,4093,4144,4194,4244,4294,4344,4394, 4445,4495,4545,4595,4645,4695,4745,4796, 4846,4896,4946,4996,5046,5096,5146,5197, 5247,5297,5347,5397,5447,5497,5547,5597, 5647,5697,5747,5798,5848,5898,5948,5998, 6048,6098,6148,6198,6248,6298,6348,6398, 6448,6498,6548,6598,6648,6698,6748,6798, 6848,6898,6948,6998,7048,7098,7148,7198, 7248,7298,7348,7398,7448,7498,7548,7598, 7648,7697,7747,7797,7847,7897,7947,7997, 8047,8097,8147,8196,8246,8296,8346,8396, 8446,8496,8545,8595,8645,8695,8745,8794, 8844,8894,8944,8994,9043,9093,9143,9193, 9243,9292,9342,9392,9442,9491,9541,9591, 9640,9690,9740,9790,9839,9889,9939,9988, 10038,10088,10137,10187,10237,10286,10336,10386, 10435,10485,10534,10584,10634,10683,10733,10782, 10832,10882,10931,10981,11030,11080,11129,11179, 11228,11278,11327,11377,11426,11476,11525,11575, 11624,11674,11723,11773,11822,11872,11921,11970, 12020,12069,12119,12168,12218,12267,12316,12366, 12415,12464,12514,12563,12612,12662,12711,12760, 12810,12859,12908,12957,13007,13056,13105,13154, 13204,13253,13302,13351,13401,13450,13499,13548, 13597,13647,13696,13745,13794,13843,13892,13941, 13990,14040,14089,14138,14187,14236,14285,14334, 14383,14432,14481,14530,14579,14628,14677,14726, 14775,14824,14873,14922,14971,15020,15069,15118, 15167,15215,15264,15313,15362,15411,15460,15509, 15557,15606,15655,15704,15753,15802,15850,15899, 15948,15997,16045,16094,16143,16191,16240,16289, 16338,16386,16435,16484,16532,16581,16629,16678, 16727,16775,16824,16872,16921,16970,17018,17067, 17115,17164,17212,17261,17309,17358,17406,17455, 17503,17551,17600,17648,17697,17745,17793,17842, 17890,17939,17987,18035,18084,18132,18180,18228, 18277,18325,18373,18421,18470,18518,18566,18614, 18663,18711,18759,18807,18855,18903,18951,19000, 19048,19096,19144,19192,19240,19288,19336,19384, 19432,19480,19528,19576,19624,19672,19720,19768, 19816,19864,19912,19959,20007,20055,20103,20151, 20199,20246,20294,20342,20390,20438,20485,20533, 20581,20629,20676,20724,20772,20819,20867,20915, 20962,21010,21057,21105,21153,21200,21248,21295, 21343,21390,21438,21485,21533,21580,21628,21675, 21723,21770,21817,21865,21912,21960,22007,22054, 22102,22149,22196,22243,22291,22338,22385,22432, 22480,22527,22574,22621,22668,22716,22763,22810, 22857,22904,22951,22998,23045,23092,23139,23186, 23233,23280,23327,23374,23421,23468,23515,23562, 23609,23656,23703,23750,23796,23843,23890,23937, 23984,24030,24077,24124,24171,24217,24264,24311, 24357,24404,24451,24497,24544,24591,24637,24684, 24730,24777,24823,24870,24916,24963,25009,25056, 25102,25149,25195,25241,25288,25334,25381,25427, 25473,25520,25566,25612,25658,25705,25751,25797, 25843,25889,25936,25982,26028,26074,26120,26166, 26212,26258,26304,26350,26396,26442,26488,26534, 26580,26626,26672,26718,26764,26810,26856,26902, 26947,26993,27039,27085,27131,27176,27222,27268, 27313,27359,27405,27450,27496,27542,27587,27633, 27678,27724,27770,27815,27861,27906,27952,27997, 28042,28088,28133,28179,28224,28269,28315,28360, 28405,28451,28496,28541,28586,28632,28677,28722, 28767,28812,28858,28903,28948,28993,29038,29083, 29128,29173,29218,29263,29308,29353,29398,29443, 29488,29533,29577,29622,29667,29712,29757,29801, 29846,29891,29936,29980,30025,30070,30114,30159, 30204,30248,30293,30337,30382,30427,30471,30516, 30560,30604,30649,30693,30738,30782,30826,30871, 30915,30959,31004,31048,31092,31136,31181,31225, 31269,31313,31357,31402,31446,31490,31534,31578, 31622,31666,31710,31754,31798,31842,31886,31930, 31974,32017,32061,32105,32149,32193,32236,32280, 32324,32368,32411,32455,32499,32542,32586,32630, 32673,32717,32760,32804,32847,32891,32934,32978, 33021,33065,33108,33151,33195,33238,33281,33325, 33368,33411,33454,33498,33541,33584,33627,33670, 33713,33756,33799,33843,33886,33929,33972,34015, 34057,34100,34143,34186,34229,34272,34315,34358, 34400,34443,34486,34529,34571,34614,34657,34699, 34742,34785,34827,34870,34912,34955,34997,35040, 35082,35125,35167,35210,35252,35294,35337,35379, 35421,35464,35506,35548,35590,35633,35675,35717, 35759,35801,35843,35885,35927,35969,36011,36053, 36095,36137,36179,36221,36263,36305,36347,36388, 36430,36472,36514,36556,36597,36639,36681,36722, 36764,36805,36847,36889,36930,36972,37013,37055, 37096,37137,37179,37220,37262,37303,37344,37386, 37427,37468,37509,37551,37592,37633,37674,37715, 37756,37797,37838,37879,37920,37961,38002,38043, 38084,38125,38166,38207,38248,38288,38329,38370, 38411,38451,38492,38533,38573,38614,38655,38695, 38736,38776,38817,38857,38898,38938,38979,39019, 39059,39100,39140,39180,39221,39261,39301,39341, 39382,39422,39462,39502,39542,39582,39622,39662, 39702,39742,39782,39822,39862,39902,39942,39982, 40021,40061,40101,40141,40180,40220,40260,40299, 40339,40379,40418,40458,40497,40537,40576,40616, 40655,40695,40734,40773,40813,40852,40891,40931, 40970,41009,41048,41087,41127,41166,41205,41244, 41283,41322,41361,41400,41439,41478,41517,41556, 41595,41633,41672,41711,41750,41788,41827,41866, 41904,41943,41982,42020,42059,42097,42136,42174, 42213,42251,42290,42328,42366,42405,42443,42481, 42520,42558,42596,42634,42672,42711,42749,42787, 42825,42863,42901,42939,42977,43015,43053,43091, 43128,43166,43204,43242,43280,43317,43355,43393, 43430,43468,43506,43543,43581,43618,43656,43693, 43731,43768,43806,43843,43880,43918,43955,43992, 44029,44067,44104,44141,44178,44215,44252,44289, 44326,44363,44400,44437,44474,44511,44548,44585, 44622,44659,44695,44732,44769,44806,44842,44879, 44915,44952,44989,45025,45062,45098,45135,45171, 45207,45244,45280,45316,45353,45389,45425,45462, 45498,45534,45570,45606,45642,45678,45714,45750, 45786,45822,45858,45894,45930,45966,46002,46037, 46073,46109,46145,46180,46216,46252,46287,46323, 46358,46394,46429,46465,46500,46536,46571,46606, 46642,46677,46712,46747,46783,46818,46853,46888, 46923,46958,46993,47028,47063,47098,47133,47168, 47203,47238,47273,47308,47342,47377,47412,47446, 47481,47516,47550,47585,47619,47654,47688,47723, 47757,47792,47826,47861,47895,47929,47963,47998, 48032,48066,48100,48134,48168,48202,48237,48271, 48305,48338,48372,48406,48440,48474,48508,48542, 48575,48609,48643,48676,48710,48744,48777,48811, 48844,48878,48911,48945,48978,49012,49045,49078, 49112,49145,49178,49211,49244,49278,49311,49344, 49377,49410,49443,49476,49509,49542,49575,49608, 49640,49673,49706,49739,49771,49804,49837,49869, 49902,49935,49967,50000,50032,50064,50097,50129, 50162,50194,50226,50259,50291,50323,50355,50387, 50420,50452,50484,50516,50548,50580,50612,50644, 50675,50707,50739,50771,50803,50834,50866,50898, 50929,50961,50993,51024,51056,51087,51119,51150, 51182,51213,51244,51276,51307,51338,51369,51401, 51432,51463,51494,51525,51556,51587,51618,51649, 51680,51711,51742,51773,51803,51834,51865,51896, 51926,51957,51988,52018,52049,52079,52110,52140, 52171,52201,52231,52262,52292,52322,52353,52383, 52413,52443,52473,52503,52534,52564,52594,52624, 52653,52683,52713,52743,52773,52803,52832,52862, 52892,52922,52951,52981,53010,53040,53069,53099, 53128,53158,53187,53216,53246,53275,53304,53334, 53363,53392,53421,53450,53479,53508,53537,53566, 53595,53624,53653,53682,53711,53739,53768,53797, 53826,53854,53883,53912,53940,53969,53997,54026, 54054,54082,54111,54139,54167,54196,54224,54252, 54280,54309,54337,54365,54393,54421,54449,54477, 54505,54533,54560,54588,54616,54644,54672,54699, 54727,54755,54782,54810,54837,54865,54892,54920, 54947,54974,55002,55029,55056,55084,55111,55138, 55165,55192,55219,55246,55274,55300,55327,55354, 55381,55408,55435,55462,55489,55515,55542,55569, 55595,55622,55648,55675,55701,55728,55754,55781, 55807,55833,55860,55886,55912,55938,55965,55991, 56017,56043,56069,56095,56121,56147,56173,56199, 56225,56250,56276,56302,56328,56353,56379,56404, 56430,56456,56481,56507,56532,56557,56583,56608, 56633,56659,56684,56709,56734,56760,56785,56810, 56835,56860,56885,56910,56935,56959,56984,57009, 57034,57059,57083,57108,57133,57157,57182,57206, 57231,57255,57280,57304,57329,57353,57377,57402, 57426,57450,57474,57498,57522,57546,57570,57594, 57618,57642,57666,57690,57714,57738,57762,57785, 57809,57833,57856,57880,57903,57927,57950,57974, 57997,58021,58044,58067,58091,58114,58137,58160, 58183,58207,58230,58253,58276,58299,58322,58345, 58367,58390,58413,58436,58459,58481,58504,58527, 58549,58572,58594,58617,58639,58662,58684,58706, 58729,58751,58773,58795,58818,58840,58862,58884, 58906,58928,58950,58972,58994,59016,59038,59059, 59081,59103,59125,59146,59168,59190,59211,59233, 59254,59276,59297,59318,59340,59361,59382,59404, 59425,59446,59467,59488,59509,59530,59551,59572, 59593,59614,59635,59656,59677,59697,59718,59739, 59759,59780,59801,59821,59842,59862,59883,59903, 59923,59944,59964,59984,60004,60025,60045,60065, 60085,60105,60125,60145,60165,60185,60205,60225, 60244,60264,60284,60304,60323,60343,60363,60382, 60402,60421,60441,60460,60479,60499,60518,60537, 60556,60576,60595,60614,60633,60652,60671,60690, 60709,60728,60747,60766,60785,60803,60822,60841, 60859,60878,60897,60915,60934,60952,60971,60989, 61007,61026,61044,61062,61081,61099,61117,61135, 61153,61171,61189,61207,61225,61243,61261,61279, 61297,61314,61332,61350,61367,61385,61403,61420, 61438,61455,61473,61490,61507,61525,61542,61559, 61577,61594,61611,61628,61645,61662,61679,61696, 61713,61730,61747,61764,61780,61797,61814,61831, 61847,61864,61880,61897,61913,61930,61946,61963, 61979,61995,62012,62028,62044,62060,62076,62092, 62108,62125,62141,62156,62172,62188,62204,62220, 62236,62251,62267,62283,62298,62314,62329,62345, 62360,62376,62391,62407,62422,62437,62453,62468, 62483,62498,62513,62528,62543,62558,62573,62588, 62603,62618,62633,62648,62662,62677,62692,62706, 62721,62735,62750,62764,62779,62793,62808,62822, 62836,62850,62865,62879,62893,62907,62921,62935, 62949,62963,62977,62991,63005,63019,63032,63046, 63060,63074,63087,63101,63114,63128,63141,63155, 63168,63182,63195,63208,63221,63235,63248,63261, 63274,63287,63300,63313,63326,63339,63352,63365, 63378,63390,63403,63416,63429,63441,63454,63466, 63479,63491,63504,63516,63528,63541,63553,63565, 63578,63590,63602,63614,63626,63638,63650,63662, 63674,63686,63698,63709,63721,63733,63745,63756, 63768,63779,63791,63803,63814,63825,63837,63848, 63859,63871,63882,63893,63904,63915,63927,63938, 63949,63960,63971,63981,63992,64003,64014,64025, 64035,64046,64057,64067,64078,64088,64099,64109, 64120,64130,64140,64151,64161,64171,64181,64192, 64202,64212,64222,64232,64242,64252,64261,64271, 64281,64291,64301,64310,64320,64330,64339,64349, 64358,64368,64377,64387,64396,64405,64414,64424, 64433,64442,64451,64460,64469,64478,64487,64496, 64505,64514,64523,64532,64540,64549,64558,64566, 64575,64584,64592,64600,64609,64617,64626,64634, 64642,64651,64659,64667,64675,64683,64691,64699, 64707,64715,64723,64731,64739,64747,64754,64762, 64770,64777,64785,64793,64800,64808,64815,64822, 64830,64837,64844,64852,64859,64866,64873,64880, 64887,64895,64902,64908,64915,64922,64929,64936, 64943,64949,64956,64963,64969,64976,64982,64989, 64995,65002,65008,65015,65021,65027,65033,65040, 65046,65052,65058,65064,65070,65076,65082,65088, 65094,65099,65105,65111,65117,65122,65128,65133, 65139,65144,65150,65155,65161,65166,65171,65177, 65182,65187,65192,65197,65202,65207,65212,65217, 65222,65227,65232,65237,65242,65246,65251,65256, 65260,65265,65270,65274,65279,65283,65287,65292, 65296,65300,65305,65309,65313,65317,65321,65325, 65329,65333,65337,65341,65345,65349,65352,65356, 65360,65363,65367,65371,65374,65378,65381,65385, 65388,65391,65395,65398,65401,65404,65408,65411, 65414,65417,65420,65423,65426,65429,65431,65434, 65437,65440,65442,65445,65448,65450,65453,65455, 65458,65460,65463,65465,65467,65470,65472,65474, 65476,65478,65480,65482,65484,65486,65488,65490, 65492,65494,65496,65497,65499,65501,65502,65504, 65505,65507,65508,65510,65511,65513,65514,65515, 65516,65518,65519,65520,65521,65522,65523,65524, 65525,65526,65527,65527,65528,65529,65530,65530, 65531,65531,65532,65532,65533,65533,65534,65534, 65534,65535,65535,65535,65535,65535,65535,65535 }; const fixed_t *finecosine = &finesine[FINEANGLES/4]; const angle_t tantoangle[2049] = { 0,333772,667544,1001315,1335086,1668857,2002626,2336395, 2670163,3003929,3337694,3671457,4005219,4338979,4672736,5006492, 5340245,5673995,6007743,6341488,6675230,7008968,7342704,7676435, 8010164,8343888,8677609,9011325,9345037,9678744,10012447,10346145, 10679838,11013526,11347209,11680887,12014558,12348225,12681885,13015539, 13349187,13682829,14016464,14350092,14683714,15017328,15350936,15684536, 16018129,16351714,16685291,17018860,17352422,17685974,18019518,18353054, 18686582,19020100,19353610,19687110,20020600,20354080,20687552,21021014, 21354466,21687906,22021338,22354758,22688168,23021568,23354956,23688332, 24021698,24355052,24688396,25021726,25355046,25688352,26021648,26354930, 26688200,27021456,27354702,27687932,28021150,28354356,28687548,29020724, 29353888,29687038,30020174,30353296,30686404,31019496,31352574,31685636, 32018684,32351718,32684734,33017736,33350722,33683692,34016648,34349584, 34682508,35015412,35348300,35681172,36014028,36346868,36679688,37012492, 37345276,37678044,38010792,38343524,38676240,39008936,39341612,39674272, 40006912,40339532,40672132,41004716,41337276,41669820,42002344,42334848, 42667332,42999796,43332236,43664660,43997060,44329444,44661800,44994140, 45326456,45658752,45991028,46323280,46655512,46987720,47319908,47652072, 47984212,48316332,48648428,48980500,49312548,49644576,49976580,50308556, 50640512,50972444,51304352,51636236,51968096,52299928,52631740,52963524, 53295284,53627020,53958728,54290412,54622068,54953704,55285308,55616888, 55948444,56279972,56611472,56942948,57274396,57605816,57937212,58268576, 58599916,58931228,59262512,59593768,59924992,60256192,60587364,60918508, 61249620,61580704,61911760,62242788,62573788,62904756,63235692,63566604, 63897480,64228332,64559148,64889940,65220696,65551424,65882120,66212788, 66543420,66874024,67204600,67535136,67865648,68196120,68526568,68856984, 69187360,69517712,69848024,70178304,70508560,70838776,71168960,71499112, 71829224,72159312,72489360,72819376,73149360,73479304,73809216,74139096, 74468936,74798744,75128520,75458264,75787968,76117632,76447264,76776864, 77106424,77435952,77765440,78094888,78424304,78753688,79083032,79412336, 79741608,80070840,80400032,80729192,81058312,81387392,81716432,82045440, 82374408,82703336,83032224,83361080,83689896,84018664,84347400,84676096, 85004760,85333376,85661952,85990488,86318984,86647448,86975864,87304240, 87632576,87960872,88289128,88617344,88945520,89273648,89601736,89929792, 90257792,90585760,90913688,91241568,91569408,91897200,92224960,92552672, 92880336,93207968,93535552,93863088,94190584,94518040,94845448,95172816, 95500136,95827416,96154648,96481832,96808976,97136080,97463136,97790144, 98117112,98444032,98770904,99097736,99424520,99751256,100077944,100404592, 100731192,101057744,101384248,101710712,102037128,102363488,102689808,103016080, 103342312,103668488,103994616,104320696,104646736,104972720,105298656,105624552, 105950392,106276184,106601928,106927624,107253272,107578872,107904416,108229920, 108555368,108880768,109206120,109531416,109856664,110181872,110507016,110832120, 111157168,111482168,111807112,112132008,112456856,112781648,113106392,113431080, 113755720,114080312,114404848,114729328,115053760,115378136,115702464,116026744, 116350960,116675128,116999248,117323312,117647320,117971272,118295176,118619024, 118942816,119266560,119590248,119913880,120237456,120560984,120884456,121207864, 121531224,121854528,122177784,122500976,122824112,123147200,123470224,123793200, 124116120,124438976,124761784,125084528,125407224,125729856,126052432,126374960, 126697424,127019832,127342184,127664472,127986712,128308888,128631008,128953072, 129275080,129597024,129918912,130240744,130562520,130884232,131205888,131527480, 131849016,132170496,132491912,132813272,133134576,133455816,133776992,134098120, 134419184,134740176,135061120,135382000,135702816,136023584,136344272,136664912, 136985488,137306016,137626464,137946864,138267184,138587456,138907664,139227808, 139547904,139867920,140187888,140507776,140827616,141147392,141467104,141786752, 142106336,142425856,142745312,143064720,143384048,143703312,144022512,144341664, 144660736,144979744,145298704,145617584,145936400,146255168,146573856,146892480, 147211040,147529536,147847968,148166336,148484640,148802880,149121056,149439152, 149757200,150075168,150393072,150710912,151028688,151346400,151664048,151981616, 152299136,152616576,152933952,153251264,153568496,153885680,154202784,154519824, 154836784,155153696,155470528,155787296,156104000,156420624,156737200,157053696, 157370112,157686480,158002768,158318976,158635136,158951216,159267232,159583168, 159899040,160214848,160530592,160846256,161161840,161477376,161792832,162108208, 162423520,162738768,163053952,163369040,163684080,163999040,164313936,164628752, 164943504,165258176,165572784,165887312,166201776,166516160,166830480,167144736, 167458912,167773008,168087040,168400992,168714880,169028688,169342432,169656096, 169969696,170283216,170596672,170910032,171223344,171536576,171849728,172162800, 172475808,172788736,173101600,173414384,173727104,174039728,174352288,174664784, 174977200,175289536,175601792,175913984,176226096,176538144,176850096,177161984, 177473792,177785536,178097200,178408784,178720288,179031728,179343088,179654368, 179965568,180276704,180587744,180898720,181209616,181520448,181831184,182141856, 182452448,182762960,183073408,183383760,183694048,184004240,184314368,184624416, 184934400,185244288,185554096,185863840,186173504,186483072,186792576,187102000, 187411344,187720608,188029808,188338912,188647936,188956896,189265760,189574560, 189883264,190191904,190500448,190808928,191117312,191425632,191733872,192042016, 192350096,192658096,192966000,193273840,193581584,193889264,194196848,194504352, 194811792,195119136,195426400,195733584,196040688,196347712,196654656,196961520, 197268304,197574992,197881616,198188144,198494592,198800960,199107248,199413456, 199719584,200025616,200331584,200637456,200943248,201248960,201554576,201860128, 202165584,202470960,202776256,203081456,203386592,203691632,203996592,204301472, 204606256,204910976,205215600,205520144,205824592,206128960,206433248,206737456, 207041584,207345616,207649568,207953424,208257216,208560912,208864512,209168048, 209471488,209774832,210078112,210381296,210684384,210987408,211290336,211593184, 211895936,212198608,212501184,212803680,213106096,213408432,213710672,214012816, 214314880,214616864,214918768,215220576,215522288,215823920,216125472,216426928, 216728304,217029584,217330784,217631904,217932928,218233856,218534704,218835472, 219136144,219436720,219737216,220037632,220337952,220638192,220938336,221238384, 221538352,221838240,222138032,222437728,222737344,223036880,223336304,223635664, 223934912,224234096,224533168,224832160,225131072,225429872,225728608,226027232, 226325776,226624240,226922608,227220880,227519056,227817152,228115168,228413088, 228710912,229008640,229306288,229603840,229901312,230198688,230495968,230793152, 231090256,231387280,231684192,231981024,232277760,232574416,232870960,233167440, 233463808,233760096,234056288,234352384,234648384,234944304,235240128,235535872, 235831504,236127056,236422512,236717888,237013152,237308336,237603424,237898416, 238193328,238488144,238782864,239077488,239372016,239666464,239960816,240255072, 240549232,240843312,241137280,241431168,241724960,242018656,242312256,242605776, 242899200,243192512,243485744,243778896,244071936,244364880,244657744,244950496, 245243168,245535744,245828224,246120608,246412912,246705104,246997216,247289216, 247581136,247872960,248164688,248456320,248747856,249039296,249330640,249621904, 249913056,250204128,250495088,250785968,251076736,251367424,251658016,251948512, 252238912,252529200,252819408,253109520,253399536,253689456,253979280,254269008, 254558640,254848176,255137632,255426976,255716224,256005376,256294432,256583392, 256872256,257161024,257449696,257738272,258026752,258315136,258603424,258891600, 259179696,259467696,259755600,260043392,260331104,260618704,260906224,261193632, 261480960,261768176,262055296,262342320,262629248,262916080,263202816,263489456, 263776000,264062432,264348784,264635024,264921168,265207216,265493168,265779024, 266064784,266350448,266636000,266921472,267206832,267492096,267777264,268062336, 268347312,268632192,268916960,269201632,269486208,269770688,270055072,270339360, 270623552,270907616,271191616,271475488,271759296,272042976,272326560,272610048, 272893440,273176736,273459936,273743040,274026048,274308928,274591744,274874432, 275157024,275439520,275721920,276004224,276286432,276568512,276850528,277132416, 277414240,277695936,277977536,278259040,278540448,278821728,279102944,279384032, 279665056,279945952,280226752,280507456,280788064,281068544,281348960,281629248, 281909472,282189568,282469568,282749440,283029248,283308960,283588544,283868032, 284147424,284426720,284705920,284985024,285264000,285542912,285821696,286100384, 286378976,286657440,286935840,287214112,287492320,287770400,288048384,288326240, 288604032,288881696,289159264,289436768,289714112,289991392,290268576,290545632, 290822592,291099456,291376224,291652896,291929440,292205888,292482272,292758528, 293034656,293310720,293586656,293862496,294138240,294413888,294689440,294964864, 295240192,295515424,295790560,296065600,296340512,296615360,296890080,297164704, 297439200,297713632,297987936,298262144,298536256,298810240,299084160,299357952, 299631648,299905248,300178720,300452128,300725408,300998592,301271680,301544640, 301817536,302090304,302362976,302635520,302908000,303180352,303452608,303724768, 303996800,304268768,304540608,304812320,305083968,305355520,305626944,305898272, 306169472,306440608,306711616,306982528,307253344,307524064,307794656,308065152, 308335552,308605856,308876032,309146112,309416096,309685984,309955744,310225408, 310494976,310764448,311033824,311303072,311572224,311841280,312110208,312379040, 312647776,312916416,313184960,313453376,313721696,313989920,314258016,314526016, 314793920,315061728,315329408,315597024,315864512,316131872,316399168,316666336, 316933408,317200384,317467232,317733984,318000640,318267200,318533632,318799968, 319066208,319332352,319598368,319864288,320130112,320395808,320661408,320926912, 321192320,321457632,321722816,321987904,322252864,322517760,322782528,323047200, 323311744,323576192,323840544,324104800,324368928,324632992,324896928,325160736, 325424448,325688096,325951584,326215008,326478304,326741504,327004608,327267584, 327530464,327793248,328055904,328318496,328580960,328843296,329105568,329367712, 329629760,329891680,330153536,330415264,330676864,330938400,331199808,331461120, 331722304,331983392,332244384,332505280,332766048,333026752,333287296,333547776, 333808128,334068384,334328544,334588576,334848512,335108352,335368064,335627712, 335887200,336146624,336405920,336665120,336924224,337183200,337442112,337700864, 337959552,338218112,338476576,338734944,338993184,339251328,339509376,339767296, 340025120,340282848,340540480,340797984,341055392,341312704,341569888,341826976, 342083968,342340832,342597600,342854272,343110848,343367296,343623648,343879904, 344136032,344392064,344648000,344903808,345159520,345415136,345670656,345926048, 346181344,346436512,346691616,346946592,347201440,347456224,347710880,347965440, 348219872,348474208,348728448,348982592,349236608,349490528,349744320,349998048, 350251648,350505152,350758528,351011808,351264992,351518048,351771040,352023872, 352276640,352529280,352781824,353034272,353286592,353538816,353790944,354042944, 354294880,354546656,354798368,355049952,355301440,355552800,355804096,356055264, 356306304,356557280,356808128,357058848,357309504,357560032,357810464,358060768, 358311008,358561088,358811104,359060992,359310784,359560480,359810048,360059520, 360308896,360558144,360807296,361056352,361305312,361554144,361802880,362051488, 362300032,362548448,362796736,363044960,363293056,363541024,363788928,364036704, 364284384,364531936,364779392,365026752,365274016,365521152,365768192,366015136, 366261952,366508672,366755296,367001792,367248192,367494496,367740704,367986784, 368232768,368478656,368724416,368970080,369215648,369461088,369706432,369951680, 370196800,370441824,370686752,370931584,371176288,371420896,371665408,371909792, 372154080,372398272,372642336,372886304,373130176,373373952,373617600,373861152, 374104608,374347936,374591168,374834304,375077312,375320224,375563040,375805760, 376048352,376290848,376533248,376775520,377017696,377259776,377501728,377743584, 377985344,378227008,378468544,378709984,378951328,379192544,379433664,379674688, 379915584,380156416,380397088,380637696,380878176,381118560,381358848,381599040, 381839104,382079072,382318912,382558656,382798304,383037856,383277280,383516640, 383755840,383994976,384233984,384472896,384711712,384950400,385188992,385427488, 385665888,385904160,386142336,386380384,386618368,386856224,387093984,387331616, 387569152,387806592,388043936,388281152,388518272,388755296,388992224,389229024, 389465728,389702336,389938816,390175200,390411488,390647680,390883744,391119712, 391355584,391591328,391826976,392062528,392297984,392533312,392768544,393003680, 393238720,393473632,393708448,393943168,394177760,394412256,394646656,394880960, 395115136,395349216,395583200,395817088,396050848,396284512,396518080,396751520, 396984864,397218112,397451264,397684288,397917248,398150080,398382784,398615424, 398847936,399080320,399312640,399544832,399776928,400008928,400240832,400472608, 400704288,400935872,401167328,401398720,401629984,401861120,402092192,402323136, 402553984,402784736,403015360,403245888,403476320,403706656,403936896,404167008, 404397024,404626944,404856736,405086432,405316032,405545536,405774912,406004224, 406233408,406462464,406691456,406920320,407149088,407377760,407606336,407834784, 408063136,408291392,408519520,408747584,408975520,409203360,409431072,409658720, 409886240,410113664,410340992,410568192,410795296,411022304,411249216,411476032, 411702720,411929312,412155808,412382176,412608480,412834656,413060736,413286720, 413512576,413738336,413964000,414189568,414415040,414640384,414865632,415090784, 415315840,415540800,415765632,415990368,416215008,416439552,416663968,416888288, 417112512,417336640,417560672,417784576,418008384,418232096,418455712,418679200, 418902624,419125920,419349120,419572192,419795200,420018080,420240864,420463552, 420686144,420908608,421130976,421353280,421575424,421797504,422019488,422241344, 422463104,422684768,422906336,423127776,423349120,423570400,423791520,424012576, 424233536,424454368,424675104,424895744,425116288,425336736,425557056,425777280, 425997408,426217440,426437376,426657184,426876928,427096544,427316064,427535488, 427754784,427974016,428193120,428412128,428631040,428849856,429068544,429287168, 429505664,429724064,429942368,430160576,430378656,430596672,430814560,431032352, 431250048,431467616,431685120,431902496,432119808,432336992,432554080,432771040, 432987936,433204736,433421408,433637984,433854464,434070848,434287104,434503296, 434719360,434935360,435151232,435367008,435582656,435798240,436013696,436229088, 436444352,436659520,436874592,437089568,437304416,437519200,437733856,437948416, 438162880,438377248,438591520,438805696,439019744,439233728,439447584,439661344, 439875008,440088576,440302048,440515392,440728672,440941824,441154880,441367872, 441580736,441793472,442006144,442218720,442431168,442643552,442855808,443067968, 443280032,443492000,443703872,443915648,444127296,444338880,444550336,444761696, 444972992,445184160,445395232,445606176,445817056,446027840,446238496,446449088, 446659552,446869920,447080192,447290400,447500448,447710432,447920320,448130112, 448339776,448549376,448758848,448968224,449177536,449386720,449595808,449804800, 450013664,450222464,450431168,450639776,450848256,451056640,451264960,451473152, 451681248,451889248,452097152,452304960,452512672,452720288,452927808,453135232, 453342528,453549760,453756864,453963904,454170816,454377632,454584384,454791008, 454997536,455203968,455410304,455616544,455822688,456028704,456234656,456440512, 456646240,456851904,457057472,457262912,457468256,457673536,457878688,458083744, 458288736,458493600,458698368,458903040,459107616,459312096,459516480,459720768, 459924960,460129056,460333056,460536960,460740736,460944448,461148064,461351584, 461554976,461758304,461961536,462164640,462367680,462570592,462773440,462976160, 463178816,463381344,463583776,463786144,463988384,464190560,464392608,464594560, 464796448,464998208,465199872,465401472,465602944,465804320,466005600,466206816, 466407904,466608896,466809824,467010624,467211328,467411936,467612480,467812896, 468013216,468213440,468413600,468613632,468813568,469013440,469213184,469412832, 469612416,469811872,470011232,470210528,470409696,470608800,470807776,471006688, 471205472,471404192,471602784,471801312,471999712,472198048,472396288,472594400, 472792448,472990400,473188256,473385984,473583648,473781216,473978688,474176064, 474373344,474570528,474767616,474964608,475161504,475358336,475555040,475751648, 475948192,476144608,476340928,476537184,476733312,476929376,477125344,477321184, 477516960,477712640,477908224,478103712,478299104,478494400,478689600,478884704, 479079744,479274656,479469504,479664224,479858880,480053408,480247872,480442240, 480636512,480830656,481024736,481218752,481412640,481606432,481800128,481993760, 482187264,482380704,482574016,482767264,482960416,483153472,483346432,483539296, 483732064,483924768,484117344,484309856,484502240,484694560,484886784,485078912, 485270944,485462880,485654720,485846464,486038144,486229696,486421184,486612576, 486803840,486995040,487186176,487377184,487568096,487758912,487949664,488140320, 488330880,488521312,488711712,488901984,489092160,489282240,489472256,489662176, 489851968,490041696,490231328,490420896,490610336,490799712,490988960,491178144, 491367232,491556224,491745120,491933920,492122656,492311264,492499808,492688256, 492876608,493064864,493253056,493441120,493629120,493817024,494004832,494192544, 494380160,494567712,494755136,494942496,495129760,495316928,495504000,495691008, 495877888,496064704,496251424,496438048,496624608,496811040,496997408,497183680, 497369856,497555936,497741920,497927840,498113632,498299360,498484992,498670560, 498856000,499041376,499226656,499411840,499596928,499781920,499966848,500151680, 500336416,500521056,500705600,500890080,501074464,501258752,501442944,501627040, 501811072,501995008,502178848,502362592,502546240,502729824,502913312,503096704, 503280000,503463232,503646368,503829408,504012352,504195200,504377984,504560672, 504743264,504925760,505108192,505290496,505472736,505654912,505836960,506018944, 506200832,506382624,506564320,506745952,506927488,507108928,507290272,507471552, 507652736,507833824,508014816,508195744,508376576,508557312,508737952,508918528, 509099008,509279392,509459680,509639904,509820032,510000064,510180000,510359872, 510539648,510719328,510898944,511078432,511257856,511437216,511616448,511795616, 511974688,512153664,512332576,512511392,512690112,512868768,513047296,513225792, 513404160,513582432,513760640,513938784,514116800,514294752,514472608,514650368, 514828064,515005664,515183168,515360608,515537952,515715200,515892352,516069440, 516246432,516423328,516600160,516776896,516953536,517130112,517306592,517482976, 517659264,517835488,518011616,518187680,518363648,518539520,518715296,518891008, 519066624,519242144,519417600,519592960,519768256,519943424,520118528,520293568, 520468480,520643328,520818112,520992800,521167392,521341888,521516320,521690656, 521864896,522039072,522213152,522387168,522561056,522734912,522908640,523082304, 523255872,523429376,523602784,523776096,523949312,524122464,524295552,524468512, 524641440,524814240,524986976,525159616,525332192,525504640,525677056,525849344, 526021568,526193728,526365792,526537760,526709632,526881440,527053152,527224800, 527396352,527567840,527739200,527910528,528081728,528252864,528423936,528594880, 528765760,528936576,529107296,529277920,529448480,529618944,529789344,529959648, 530129856,530300000,530470048,530640000,530809888,530979712,531149440,531319072, 531488608,531658080,531827488,531996800,532166016,532335168,532504224,532673184, 532842080,533010912,533179616,533348288,533516832,533685312,533853728,534022048, 534190272,534358432,534526496,534694496,534862400,535030240,535197984,535365632, 535533216,535700704,535868128,536035456,536202720,536369888,536536992,536704000, 536870912 }; // Now where did these came from? const byte gammatable[5][256] = { { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96, 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112, 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 }, { 2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23, 24,25,26,27,29,30,31,32,33,34,36,37,38,39,40,41, 42,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59, 60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76, 77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92, 93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108, 109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124, 125,126,127,128,129,129,130,131,132,133,134,135,136,137,138,139, 140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154, 155,156,157,158,159,160,161,162,163,163,164,165,166,167,168,169, 170,171,172,173,174,175,175,176,177,178,179,180,181,182,183,184, 185,186,186,187,188,189,190,191,192,193,194,195,196,196,197,198, 199,200,201,202,203,204,205,205,206,207,208,209,210,211,212,213, 214,214,215,216,217,218,219,220,221,222,222,223,224,225,226,227, 228,229,230,230,231,232,233,234,235,236,237,237,238,239,240,241, 242,243,244,245,245,246,247,248,249,250,251,252,252,253,254,255 }, { 4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32, 33,35,36,38,39,40,42,43,45,46,47,48,50,51,52,54, 55,56,57,59,60,61,62,63,65,66,67,68,69,70,72,73, 74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90, 91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107, 108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122, 123,124,125,126,127,128,129,130,131,132,133,133,134,135,136,137, 138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,152, 153,153,154,155,156,157,158,159,160,160,161,162,163,164,165,166, 166,167,168,169,170,171,172,172,173,174,175,176,177,178,178,179, 180,181,182,183,183,184,185,186,187,188,188,189,190,191,192,193, 193,194,195,196,197,197,198,199,200,201,201,202,203,204,205,206, 206,207,208,209,210,210,211,212,213,213,214,215,216,217,217,218, 219,220,221,221,222,223,224,224,225,226,227,228,228,229,230,231, 231,232,233,234,235,235,236,237,238,238,239,240,241,241,242,243, 244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,255 }, { 8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45, 47,49,50,52,53,55,57,58,60,61,63,64,65,67,68,70, 71,72,74,75,76,77,79,80,81,82,84,85,86,87,88,90, 91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107, 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123, 124,125,126,127,128,129,130,131,132,133,134,135,135,136,137,138, 139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152, 153,154,155,155,156,157,158,159,160,160,161,162,163,164,165,165, 166,167,168,169,169,170,171,172,173,173,174,175,176,176,177,178, 179,180,180,181,182,183,183,184,185,186,186,187,188,189,189,190, 191,192,192,193,194,195,195,196,197,197,198,199,200,200,201,202, 202,203,204,205,205,206,207,207,208,209,210,210,211,212,212,213, 214,214,215,216,216,217,218,219,219,220,221,221,222,223,223,224, 225,225,226,227,227,228,229,229,230,231,231,232,233,233,234,235, 235,236,237,237,238,238,239,240,240,241,242,242,243,244,244,245, 246,246,247,247,248,249,249,250,251,251,252,253,253,254,254,255 }, { 16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64, 66,68,69,71,73,75,76,78,80,81,83,84,86,87,89,90, 92,93,94,96,97,98,100,101,102,103,105,106,107,108,109,110, 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128, 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156, 157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169, 169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180, 181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191, 192,193,193,194,195,195,196,196,197,198,198,199,200,200,201,202, 202,203,203,204,205,205,206,207,207,208,208,209,210,210,211,211, 212,213,213,214,214,215,216,216,217,217,218,219,219,220,220,221, 221,222,223,223,224,224,225,225,226,227,227,228,228,229,229,230, 230,231,232,232,233,233,234,234,235,235,236,236,237,237,238,239, 239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247, 247,248,248,249,249,250,250,251,251,252,252,253,254,254,255,255 } }; chocolate-doom-chocolate-doom-2.2.1/src/tables.h000066400000000000000000000045671257432200600215330ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Lookup tables. // Do not try to look them up :-). // In the order of appearance: // // int finetangent[4096] - Tangens LUT. // Should work with BAM fairly well (12 of 16bit, // effectively, by shifting). // // int finesine[10240] - Sine lookup. // Guess what, serves as cosine, too. // Remarkable thing is, how to use BAMs with this? // // int tantoangle[2049] - ArcTan LUT, // maps tan(angle) to angle fast. Gotta search. // #ifndef __TABLES__ #define __TABLES__ #include "doomtype.h" #include "m_fixed.h" #define FINEANGLES 8192 #define FINEMASK (FINEANGLES-1) // 0x100000000 to 0x2000 #define ANGLETOFINESHIFT 19 // Effective size is 10240. extern const fixed_t finesine[5*FINEANGLES/4]; // Re-use data, is just PI/2 pahse shift. extern const fixed_t *finecosine; // Effective size is 4096. extern const fixed_t finetangent[FINEANGLES/2]; // Gamma correction tables. extern const byte gammatable[5][256]; // Binary Angle Measument, BAM. #define ANG45 0x20000000 #define ANG90 0x40000000 #define ANG180 0x80000000 #define ANG270 0xc0000000 #define ANG_MAX 0xffffffff #define ANG1 (ANG45 / 45) #define ANG60 (ANG180 / 3) // Heretic code uses this definition as though it represents one // degree, but it is not! This is actually ~1.40 degrees. #define ANG1_X 0x01000000 #define SLOPERANGE 2048 #define SLOPEBITS 11 #define DBITS (FRACBITS-SLOPEBITS) typedef unsigned angle_t; // Effective size is 2049; // The +1 size is to handle the case when x==y // without additional checking. extern const angle_t tantoangle[SLOPERANGE+1]; // Utility function, // called by R_PointToAngle. int SlopeDiv(unsigned int num, unsigned int den); #endif chocolate-doom-chocolate-doom-2.2.1/src/v_patch.h000066400000000000000000000026761257432200600217040ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Refresh/rendering module, shared data struct definitions. // #ifndef V_PATCH_H #define V_PATCH_H // Patches. // A patch holds one or more columns. // Patches are used for sprites and all masked pictures, // and we compose textures from the TEXTURE1/2 lists // of patches. typedef struct { short width; // bounding box size short height; short leftoffset; // pixels to the left of origin short topoffset; // pixels below the origin int columnofs[8]; // only [width] used // the [0] is &columnofs[width] } PACKEDATTR patch_t; // posts are runs of non masked source pixels typedef struct { byte topdelta; // -1 is the last post in a column byte length; // length data bytes follows } PACKEDATTR post_t; // column_t is a list of 0 or more post_t, (byte)-1 terminated typedef post_t column_t; #endif chocolate-doom-chocolate-doom-2.2.1/src/v_video.c000066400000000000000000000503751257432200600217050ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Gamma correction LUT stuff. // Functions to draw patches (by post) directly to screen. // Functions to blit a block to the screen. // #include #include #include #include "i_system.h" #include "doomtype.h" #include "deh_str.h" #include "i_swap.h" #include "i_video.h" #include "m_bbox.h" #include "m_misc.h" #include "v_video.h" #include "w_wad.h" #include "z_zone.h" #include "config.h" #ifdef HAVE_LIBPNG #include #endif // TODO: There are separate RANGECHECK defines for different games, but this // is common code. Fix this. #define RANGECHECK // Blending table used for fuzzpatch, etc. // Only used in Heretic/Hexen byte *tinttable = NULL; // villsa [STRIFE] Blending table used for Strife byte *xlatab = NULL; // The screen buffer that the v_video.c code draws to. static byte *dest_screen = NULL; int dirtybox[4]; // haleyjd 08/28/10: clipping callback function for patches. // This is needed for Chocolate Strife, which clips patches to the screen. static vpatchclipfunc_t patchclip_callback = NULL; // // V_MarkRect // void V_MarkRect(int x, int y, int width, int height) { // If we are temporarily using an alternate screen, do not // affect the update box. if (dest_screen == I_VideoBuffer) { M_AddToBox (dirtybox, x, y); M_AddToBox (dirtybox, x + width-1, y + height-1); } } // // V_CopyRect // void V_CopyRect(int srcx, int srcy, byte *source, int width, int height, int destx, int desty) { byte *src; byte *dest; #ifdef RANGECHECK if (srcx < 0 || srcx + width > SCREENWIDTH || srcy < 0 || srcy + height > SCREENHEIGHT || destx < 0 || destx + width > SCREENWIDTH || desty < 0 || desty + height > SCREENHEIGHT) { I_Error ("Bad V_CopyRect"); } #endif V_MarkRect(destx, desty, width, height); src = source + SCREENWIDTH * srcy + srcx; dest = dest_screen + SCREENWIDTH * desty + destx; for ( ; height>0 ; height--) { memcpy(dest, src, width); src += SCREENWIDTH; dest += SCREENWIDTH; } } // // V_SetPatchClipCallback // // haleyjd 08/28/10: Added for Strife support. // By calling this function, you can setup runtime error checking for patch // clipping. Strife never caused errors by drawing patches partway off-screen. // Some versions of vanilla DOOM also behaved differently than the default // implementation, so this could possibly be extended to those as well for // accurate emulation. // void V_SetPatchClipCallback(vpatchclipfunc_t func) { patchclip_callback = func; } // // V_DrawPatch // Masks a column based masked pic to the screen. // void V_DrawPatch(int x, int y, patch_t *patch) { int count; int col; column_t *column; byte *desttop; byte *dest; byte *source; int w; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); // haleyjd 08/28/10: Strife needs silent error checking here. if(patchclip_callback) { if(!patchclip_callback(patch, x, y)) return; } #ifdef RANGECHECK if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0 || y + SHORT(patch->height) > SCREENHEIGHT) { I_Error("Bad V_DrawPatch"); } #endif V_MarkRect(x, y, SHORT(patch->width), SHORT(patch->height)); col = 0; desttop = dest_screen + y * SCREENWIDTH + x; w = SHORT(patch->width); for ( ; colcolumnofs[col])); // step through the posts in a column while (column->topdelta != 0xff) { source = (byte *)column + 3; dest = desttop + column->topdelta*SCREENWIDTH; count = column->length; while (count--) { *dest = *source++; dest += SCREENWIDTH; } column = (column_t *)((byte *)column + column->length + 4); } } } // // V_DrawPatchFlipped // Masks a column based masked pic to the screen. // Flips horizontally, e.g. to mirror face. // void V_DrawPatchFlipped(int x, int y, patch_t *patch) { int count; int col; column_t *column; byte *desttop; byte *dest; byte *source; int w; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); // haleyjd 08/28/10: Strife needs silent error checking here. if(patchclip_callback) { if(!patchclip_callback(patch, x, y)) return; } #ifdef RANGECHECK if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0 || y + SHORT(patch->height) > SCREENHEIGHT) { I_Error("Bad V_DrawPatchFlipped"); } #endif V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height)); col = 0; desttop = dest_screen + y * SCREENWIDTH + x; w = SHORT(patch->width); for ( ; colcolumnofs[w-1-col])); // step through the posts in a column while (column->topdelta != 0xff ) { source = (byte *)column + 3; dest = desttop + column->topdelta*SCREENWIDTH; count = column->length; while (count--) { *dest = *source++; dest += SCREENWIDTH; } column = (column_t *)((byte *)column + column->length + 4); } } } // // V_DrawPatchDirect // Draws directly to the screen on the pc. // void V_DrawPatchDirect(int x, int y, patch_t *patch) { V_DrawPatch(x, y, patch); } // // V_DrawTLPatch // // Masks a column based translucent masked pic to the screen. // void V_DrawTLPatch(int x, int y, patch_t * patch) { int count, col; column_t *column; byte *desttop, *dest, *source; int w; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0 || y + SHORT(patch->height) > SCREENHEIGHT) { I_Error("Bad V_DrawTLPatch"); } col = 0; desttop = dest_screen + y * SCREENWIDTH + x; w = SHORT(patch->width); for (; col < w; x++, col++, desttop++) { column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); // step through the posts in a column while (column->topdelta != 0xff) { source = (byte *) column + 3; dest = desttop + column->topdelta * SCREENWIDTH; count = column->length; while (count--) { *dest = tinttable[((*dest) << 8) + *source++]; dest += SCREENWIDTH; } column = (column_t *) ((byte *) column + column->length + 4); } } } // // V_DrawXlaPatch // // villsa [STRIFE] Masks a column based translucent masked pic to the screen. // void V_DrawXlaPatch(int x, int y, patch_t * patch) { int count, col; column_t *column; byte *desttop, *dest, *source; int w; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); if(patchclip_callback) { if(!patchclip_callback(patch, x, y)) return; } col = 0; desttop = dest_screen + y * SCREENWIDTH + x; w = SHORT(patch->width); for(; col < w; x++, col++, desttop++) { column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); // step through the posts in a column while(column->topdelta != 0xff) { source = (byte *) column + 3; dest = desttop + column->topdelta * SCREENWIDTH; count = column->length; while(count--) { *dest = xlatab[*dest + ((*source) << 8)]; source++; dest += SCREENWIDTH; } column = (column_t *) ((byte *) column + column->length + 4); } } } // // V_DrawAltTLPatch // // Masks a column based translucent masked pic to the screen. // void V_DrawAltTLPatch(int x, int y, patch_t * patch) { int count, col; column_t *column; byte *desttop, *dest, *source; int w; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0 || y + SHORT(patch->height) > SCREENHEIGHT) { I_Error("Bad V_DrawAltTLPatch"); } col = 0; desttop = dest_screen + y * SCREENWIDTH + x; w = SHORT(patch->width); for (; col < w; x++, col++, desttop++) { column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); // step through the posts in a column while (column->topdelta != 0xff) { source = (byte *) column + 3; dest = desttop + column->topdelta * SCREENWIDTH; count = column->length; while (count--) { *dest = tinttable[((*dest) << 8) + *source++]; dest += SCREENWIDTH; } column = (column_t *) ((byte *) column + column->length + 4); } } } // // V_DrawShadowedPatch // // Masks a column based masked pic to the screen. // void V_DrawShadowedPatch(int x, int y, patch_t *patch) { int count, col; column_t *column; byte *desttop, *dest, *source; byte *desttop2, *dest2; int w; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0 || y + SHORT(patch->height) > SCREENHEIGHT) { I_Error("Bad V_DrawShadowedPatch"); } col = 0; desttop = dest_screen + y * SCREENWIDTH + x; desttop2 = dest_screen + (y + 2) * SCREENWIDTH + x + 2; w = SHORT(patch->width); for (; col < w; x++, col++, desttop++, desttop2++) { column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); // step through the posts in a column while (column->topdelta != 0xff) { source = (byte *) column + 3; dest = desttop + column->topdelta * SCREENWIDTH; dest2 = desttop2 + column->topdelta * SCREENWIDTH; count = column->length; while (count--) { *dest2 = tinttable[((*dest2) << 8)]; dest2 += SCREENWIDTH; *dest = *source++; dest += SCREENWIDTH; } column = (column_t *) ((byte *) column + column->length + 4); } } } // // Load tint table from TINTTAB lump. // void V_LoadTintTable(void) { tinttable = W_CacheLumpName("TINTTAB", PU_STATIC); } // // V_LoadXlaTable // // villsa [STRIFE] Load xla table from XLATAB lump. // void V_LoadXlaTable(void) { xlatab = W_CacheLumpName("XLATAB", PU_STATIC); } // // V_DrawBlock // Draw a linear block of pixels into the view buffer. // void V_DrawBlock(int x, int y, int width, int height, byte *src) { byte *dest; #ifdef RANGECHECK if (x < 0 || x + width >SCREENWIDTH || y < 0 || y + height > SCREENHEIGHT) { I_Error ("Bad V_DrawBlock"); } #endif V_MarkRect (x, y, width, height); dest = dest_screen + y * SCREENWIDTH + x; while (height--) { memcpy (dest, src, width); src += width; dest += SCREENWIDTH; } } void V_DrawFilledBox(int x, int y, int w, int h, int c) { uint8_t *buf, *buf1; int x1, y1; buf = I_VideoBuffer + SCREENWIDTH * y + x; for (y1 = 0; y1 < h; ++y1) { buf1 = buf; for (x1 = 0; x1 < w; ++x1) { *buf1++ = c; } buf += SCREENWIDTH; } } void V_DrawHorizLine(int x, int y, int w, int c) { uint8_t *buf; int x1; buf = I_VideoBuffer + SCREENWIDTH * y + x; for (x1 = 0; x1 < w; ++x1) { *buf++ = c; } } void V_DrawVertLine(int x, int y, int h, int c) { uint8_t *buf; int y1; buf = I_VideoBuffer + SCREENWIDTH * y + x; for (y1 = 0; y1 < h; ++y1) { *buf = c; buf += SCREENWIDTH; } } void V_DrawBox(int x, int y, int w, int h, int c) { V_DrawHorizLine(x, y, w, c); V_DrawHorizLine(x, y+h-1, w, c); V_DrawVertLine(x, y, h, c); V_DrawVertLine(x+w-1, y, h, c); } // // Draw a "raw" screen (lump containing raw data to blit directly // to the screen) // void V_DrawRawScreen(byte *raw) { memcpy(dest_screen, raw, SCREENWIDTH * SCREENHEIGHT); } // // V_Init // void V_Init (void) { // no-op! // There used to be separate screens that could be drawn to; these are // now handled in the upper layers. } // Set the buffer that the code draws to. void V_UseBuffer(byte *buffer) { dest_screen = buffer; } // Restore screen buffer to the i_video screen buffer. void V_RestoreBuffer(void) { dest_screen = I_VideoBuffer; } // // SCREEN SHOTS // typedef struct { char manufacturer; char version; char encoding; char bits_per_pixel; unsigned short xmin; unsigned short ymin; unsigned short xmax; unsigned short ymax; unsigned short hres; unsigned short vres; unsigned char palette[48]; char reserved; char color_planes; unsigned short bytes_per_line; unsigned short palette_type; char filler[58]; unsigned char data; // unbounded } PACKEDATTR pcx_t; // // WritePCXfile // void WritePCXfile(char *filename, byte *data, int width, int height, byte *palette) { int i; int length; pcx_t* pcx; byte* pack; pcx = Z_Malloc (width*height*2+1000, PU_STATIC, NULL); pcx->manufacturer = 0x0a; // PCX id pcx->version = 5; // 256 color pcx->encoding = 1; // uncompressed pcx->bits_per_pixel = 8; // 256 color pcx->xmin = 0; pcx->ymin = 0; pcx->xmax = SHORT(width-1); pcx->ymax = SHORT(height-1); pcx->hres = SHORT(width); pcx->vres = SHORT(height); memset (pcx->palette,0,sizeof(pcx->palette)); pcx->color_planes = 1; // chunky image pcx->bytes_per_line = SHORT(width); pcx->palette_type = SHORT(2); // not a grey scale memset (pcx->filler,0,sizeof(pcx->filler)); // pack the image pack = &pcx->data; for (i=0 ; i MOUSE_SPEED_BOX_WIDTH - 1) { linelen = MOUSE_SPEED_BOX_WIDTH - 1; } V_DrawHorizLine(box_x + 1, box_y + 4, MOUSE_SPEED_BOX_WIDTH - 2, black); if (linelen < redline_x) { V_DrawHorizLine(box_x + 1, box_y + MOUSE_SPEED_BOX_HEIGHT / 2, linelen, white); } else { V_DrawHorizLine(box_x + 1, box_y + MOUSE_SPEED_BOX_HEIGHT / 2, redline_x, white); V_DrawHorizLine(box_x + redline_x, box_y + MOUSE_SPEED_BOX_HEIGHT / 2, linelen - redline_x, yellow); } // Draw red line V_DrawVertLine(box_x + redline_x, box_y + 1, MOUSE_SPEED_BOX_HEIGHT - 2, red); } chocolate-doom-chocolate-doom-2.2.1/src/v_video.h000066400000000000000000000056661257432200600217150ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Gamma correction LUT. // Functions to draw patches (by post) directly to screen. // Functions to blit a block to the screen. // #ifndef __V_VIDEO__ #define __V_VIDEO__ #include "doomtype.h" // Needed because we are refering to patches. #include "v_patch.h" // // VIDEO // #define CENTERY (SCREENHEIGHT/2) extern int dirtybox[4]; extern byte *tinttable; // haleyjd 08/28/10: implemented for Strife support // haleyjd 08/28/10: Patch clipping callback, implemented to support Choco // Strife. typedef boolean (*vpatchclipfunc_t)(patch_t *, int, int); void V_SetPatchClipCallback(vpatchclipfunc_t func); // Allocates buffer screens, call before R_Init. void V_Init (void); // Draw a block from the specified source screen to the screen. void V_CopyRect(int srcx, int srcy, byte *source, int width, int height, int destx, int desty); void V_DrawPatch(int x, int y, patch_t *patch); void V_DrawPatchFlipped(int x, int y, patch_t *patch); void V_DrawTLPatch(int x, int y, patch_t *patch); void V_DrawAltTLPatch(int x, int y, patch_t * patch); void V_DrawShadowedPatch(int x, int y, patch_t *patch); void V_DrawXlaPatch(int x, int y, patch_t * patch); // villsa [STRIFE] void V_DrawPatchDirect(int x, int y, patch_t *patch); // Draw a linear block of pixels into the view buffer. void V_DrawBlock(int x, int y, int width, int height, byte *src); void V_MarkRect(int x, int y, int width, int height); void V_DrawFilledBox(int x, int y, int w, int h, int c); void V_DrawHorizLine(int x, int y, int w, int c); void V_DrawVertLine(int x, int y, int h, int c); void V_DrawBox(int x, int y, int w, int h, int c); // Draw a raw screen lump void V_DrawRawScreen(byte *raw); // Temporarily switch to using a different buffer to draw graphics, etc. void V_UseBuffer(byte *buffer); // Return to using the normal screen buffer to draw graphics. void V_RestoreBuffer(void); // Save a screenshot of the current screen to a file, named in the // format described in the string passed to the function, eg. // "DOOM%02i.pcx" void V_ScreenShot(char *format); // Load the lookup table for translucency calculations from the TINTTAB // lump. void V_LoadTintTable(void); // villsa [STRIFE] // Load the lookup table for translucency calculations from the XLATAB // lump. void V_LoadXlaTable(void); void V_DrawMouseSpeedBox(int speed); #endif chocolate-doom-chocolate-doom-2.2.1/src/w_checksum.c000066400000000000000000000042531257432200600223740ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Generate a checksum of the WAD directory. // #include #include #include #include "m_misc.h" #include "sha1.h" #include "w_checksum.h" #include "w_wad.h" static wad_file_t **open_wadfiles = NULL; static int num_open_wadfiles = 0; static int GetFileNumber(wad_file_t *handle) { int i; int result; for (i=0; iname, sizeof(buf)); SHA1_UpdateString(sha1_context, buf); SHA1_UpdateInt32(sha1_context, GetFileNumber(lump->wad_file)); SHA1_UpdateInt32(sha1_context, lump->position); SHA1_UpdateInt32(sha1_context, lump->size); } void W_Checksum(sha1_digest_t digest) { sha1_context_t sha1_context; unsigned int i; SHA1_Init(&sha1_context); num_open_wadfiles = 0; // Go through each entry in the WAD directory, adding information // about each entry to the SHA1 hash. for (i=0; i #include "config.h" #include "doomtype.h" #include "m_argv.h" #include "w_file.h" extern wad_file_class_t stdc_wad_file; #ifdef _WIN32 extern wad_file_class_t win32_wad_file; #endif #ifdef HAVE_MMAP extern wad_file_class_t posix_wad_file; #endif static wad_file_class_t *wad_file_classes[] = { #ifdef _WIN32 &win32_wad_file, #endif #ifdef HAVE_MMAP &posix_wad_file, #endif &stdc_wad_file, }; wad_file_t *W_OpenFile(char *path) { wad_file_t *result; int i; //! // Use the OS's virtual memory subsystem to map WAD files // directly into memory. // if (!M_CheckParm("-mmap")) { return stdc_wad_file.OpenFile(path); } // Try all classes in order until we find one that works result = NULL; for (i=0; iOpenFile(path); if (result != NULL) { break; } } return result; } void W_CloseFile(wad_file_t *wad) { wad->file_class->CloseFile(wad); } size_t W_Read(wad_file_t *wad, unsigned int offset, void *buffer, size_t buffer_len) { return wad->file_class->Read(wad, offset, buffer, buffer_len); } chocolate-doom-chocolate-doom-2.2.1/src/w_file.h000066400000000000000000000037571257432200600215260ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // WAD I/O functions. // #ifndef __W_FILE__ #define __W_FILE__ #include #include "doomtype.h" typedef struct _wad_file_s wad_file_t; typedef struct { // Open a file for reading. wad_file_t *(*OpenFile)(char *path); // Close the specified file. void (*CloseFile)(wad_file_t *file); // Read data from the specified position in the file into the // provided buffer. Returns the number of bytes read. size_t (*Read)(wad_file_t *file, unsigned int offset, void *buffer, size_t buffer_len); } wad_file_class_t; struct _wad_file_s { // Class of this file. wad_file_class_t *file_class; // If this is NULL, the file cannot be mapped into memory. If this // is non-NULL, it is a pointer to the mapped file. byte *mapped; // Length of the file, in bytes. unsigned int length; }; // Open the specified file. Returns a pointer to a new wad_file_t // handle for the WAD file, or NULL if it could not be opened. wad_file_t *W_OpenFile(char *path); // Close the specified WAD file. void W_CloseFile(wad_file_t *wad); // Read data from the specified file into the provided buffer. The // data is read from the specified offset from the start of the file. // Returns the number of bytes read. size_t W_Read(wad_file_t *wad, unsigned int offset, void *buffer, size_t buffer_len); #endif /* #ifndef __W_FILE__ */ chocolate-doom-chocolate-doom-2.2.1/src/w_file_posix.c000066400000000000000000000071741257432200600227400ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // WAD I/O functions. // #include "config.h" #ifdef HAVE_MMAP #include #include #include #include #include #include "w_file.h" #include "z_zone.h" typedef struct { wad_file_t wad; int handle; } posix_wad_file_t; extern wad_file_class_t posix_wad_file; static void MapFile(posix_wad_file_t *wad, char *filename) { void *result; int protection; int flags; // Mapped area can be read and written to. Ideally // this should be read-only, as none of the Doom code should // change the WAD files after being read. However, there may // be code lurking in the source that does. protection = PROT_READ|PROT_WRITE; // Writes to the mapped area result in private changes that are // *not* written to disk. flags = MAP_PRIVATE; result = mmap(NULL, wad->wad.length, protection, flags, wad->handle, 0); wad->wad.mapped = result; if (result == NULL) { fprintf(stderr, "W_POSIX_OpenFile: Unable to mmap() %s - %s\n", filename, strerror(errno)); } } unsigned int GetFileLength(int handle) { return lseek(handle, 0, SEEK_END); } static wad_file_t *W_POSIX_OpenFile(char *path) { posix_wad_file_t *result; int handle; handle = open(path, 0); if (handle < 0) { return NULL; } // Create a new posix_wad_file_t to hold the file handle. result = Z_Malloc(sizeof(posix_wad_file_t), PU_STATIC, 0); result->wad.file_class = &posix_wad_file; result->wad.length = GetFileLength(handle); result->handle = handle; // Try to map the file into memory with mmap: MapFile(result, path); return &result->wad; } static void W_POSIX_CloseFile(wad_file_t *wad) { posix_wad_file_t *posix_wad; posix_wad = (posix_wad_file_t *) wad; // If mapped, unmap it. // Close the file close(posix_wad->handle); Z_Free(posix_wad); } // Read data from the specified position in the file into the // provided buffer. Returns the number of bytes read. size_t W_POSIX_Read(wad_file_t *wad, unsigned int offset, void *buffer, size_t buffer_len) { posix_wad_file_t *posix_wad; byte *byte_buffer; size_t bytes_read; int result; posix_wad = (posix_wad_file_t *) wad; // Jump to the specified position in the file. lseek(posix_wad->handle, offset, SEEK_SET); // Read into the buffer. bytes_read = 0; byte_buffer = buffer; while (buffer_len > 0) { result = read(posix_wad->handle, byte_buffer, buffer_len); if (result < 0) { perror("W_POSIX_Read"); break; } else if (result == 0) { break; } // Successfully read some bytes byte_buffer += result; buffer_len -= result; bytes_read += result; } return bytes_read; } wad_file_class_t posix_wad_file = { W_POSIX_OpenFile, W_POSIX_CloseFile, W_POSIX_Read, }; #endif /* #ifdef HAVE_MMAP */ chocolate-doom-chocolate-doom-2.2.1/src/w_file_stdc.c000066400000000000000000000041441257432200600225250ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // WAD I/O functions. // #include #include "m_misc.h" #include "w_file.h" #include "z_zone.h" typedef struct { wad_file_t wad; FILE *fstream; } stdc_wad_file_t; extern wad_file_class_t stdc_wad_file; static wad_file_t *W_StdC_OpenFile(char *path) { stdc_wad_file_t *result; FILE *fstream; fstream = fopen(path, "rb"); if (fstream == NULL) { return NULL; } // Create a new stdc_wad_file_t to hold the file handle. result = Z_Malloc(sizeof(stdc_wad_file_t), PU_STATIC, 0); result->wad.file_class = &stdc_wad_file; result->wad.mapped = NULL; result->wad.length = M_FileLength(fstream); result->fstream = fstream; return &result->wad; } static void W_StdC_CloseFile(wad_file_t *wad) { stdc_wad_file_t *stdc_wad; stdc_wad = (stdc_wad_file_t *) wad; fclose(stdc_wad->fstream); Z_Free(stdc_wad); } // Read data from the specified position in the file into the // provided buffer. Returns the number of bytes read. size_t W_StdC_Read(wad_file_t *wad, unsigned int offset, void *buffer, size_t buffer_len) { stdc_wad_file_t *stdc_wad; size_t result; stdc_wad = (stdc_wad_file_t *) wad; // Jump to the specified position in the file. fseek(stdc_wad->fstream, offset, SEEK_SET); // Read into the buffer. result = fread(buffer, 1, buffer_len, stdc_wad->fstream); return result; } wad_file_class_t stdc_wad_file = { W_StdC_OpenFile, W_StdC_CloseFile, W_StdC_Read, }; chocolate-doom-chocolate-doom-2.2.1/src/w_file_win32.c000066400000000000000000000110151257432200600225250ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // WAD I/O functions. // #include "config.h" #ifdef _WIN32 #include #define WIN32_LEAN_AND_MEAN #include #include "i_system.h" #include "w_file.h" #include "z_zone.h" // This constant doesn't exist in VC6: #ifndef INVALID_SET_FILE_POINTER #define INVALID_SET_FILE_POINTER 0xffffffff #endif typedef struct { wad_file_t wad; HANDLE handle; HANDLE handle_map; } win32_wad_file_t; extern wad_file_class_t win32_wad_file; static void MapFile(win32_wad_file_t *wad, char *filename) { wad->handle_map = CreateFileMapping(wad->handle, NULL, PAGE_WRITECOPY, 0, 0, NULL); if (wad->handle_map == NULL) { fprintf(stderr, "W_Win32_OpenFile: Unable to CreateFileMapping() " "for %s\n", filename); return; } wad->wad.mapped = MapViewOfFile(wad->handle_map, FILE_MAP_COPY, 0, 0, 0); if (wad->wad.mapped == NULL) { fprintf(stderr, "W_Win32_OpenFile: Unable to MapViewOfFile() for %s\n", filename); } } unsigned int GetFileLength(HANDLE handle) { DWORD result; result = SetFilePointer(handle, 0, NULL, FILE_END); if (result == INVALID_SET_FILE_POINTER) { I_Error("W_Win32_OpenFile: Failed to read file length"); } return result; } static wad_file_t *W_Win32_OpenFile(char *path) { win32_wad_file_t *result; wchar_t wpath[MAX_PATH + 1]; HANDLE handle; // Open the file: MultiByteToWideChar(CP_OEMCP, 0, path, strlen(path) + 1, wpath, sizeof(wpath)); handle = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { return NULL; } // Create a new win32_wad_file_t to hold the file handle. result = Z_Malloc(sizeof(win32_wad_file_t), PU_STATIC, 0); result->wad.file_class = &win32_wad_file; result->wad.length = GetFileLength(handle); result->handle = handle; // Try to map the file into memory with mmap: MapFile(result, path); return &result->wad; } static void W_Win32_CloseFile(wad_file_t *wad) { win32_wad_file_t *win32_wad; win32_wad = (win32_wad_file_t *) wad; // If mapped, unmap it. if (win32_wad->wad.mapped != NULL) { UnmapViewOfFile(win32_wad->wad.mapped); } if (win32_wad->handle_map != NULL) { CloseHandle(win32_wad->handle_map); } // Close the file if (win32_wad->handle != NULL) { CloseHandle(win32_wad->handle); } Z_Free(win32_wad); } // Read data from the specified position in the file into the // provided buffer. Returns the number of bytes read. size_t W_Win32_Read(wad_file_t *wad, unsigned int offset, void *buffer, size_t buffer_len) { win32_wad_file_t *win32_wad; DWORD bytes_read; DWORD result; win32_wad = (win32_wad_file_t *) wad; // Jump to the specified position in the file. result = SetFilePointer(win32_wad->handle, offset, NULL, FILE_BEGIN); if (result == INVALID_SET_FILE_POINTER) { I_Error("W_Win32_Read: Failed to set file pointer to %i", offset); } // Read into the buffer. if (!ReadFile(win32_wad->handle, buffer, buffer_len, &bytes_read, NULL)) { I_Error("W_Win32_Read: Error reading from file"); } return bytes_read; } wad_file_class_t win32_wad_file = { W_Win32_OpenFile, W_Win32_CloseFile, W_Win32_Read, }; #endif /* #ifdef _WIN32 */ chocolate-doom-chocolate-doom-2.2.1/src/w_main.c000066400000000000000000000107771257432200600215260ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Common code to parse command line, identifying WAD files to load. // #include "doomfeatures.h" #include "d_iwad.h" #include "m_argv.h" #include "w_main.h" #include "w_merge.h" #include "w_wad.h" #include "z_zone.h" // Parse the command line, merging WAD files that are sppecified. // Returns true if at least one file was added. boolean W_ParseCommandLine(void) { boolean modifiedgame = false; int p; #ifdef FEATURE_WAD_MERGE // Merged PWADs are loaded first, because they are supposed to be // modified IWADs. //! // @arg // @category mod // // Simulates the behavior of deutex's -merge option, merging a PWAD // into the main IWAD. Multiple files may be specified. // p = M_CheckParmWithArgs("-merge", 1); if (p > 0) { for (p = p + 1; p // @category mod // // Simulates the behavior of NWT's -merge option. Multiple files // may be specified. p = M_CheckParmWithArgs("-nwtmerge", 1); if (p > 0) { for (p = p + 1; p // @category mod // // Simulates the behavior of NWT's -af option, merging flats into // the main IWAD directory. Multiple files may be specified. // p = M_CheckParmWithArgs("-af", 1); if (p > 0) { for (p = p + 1; p // @category mod // // Simulates the behavior of NWT's -as option, merging sprites // into the main IWAD directory. Multiple files may be specified. // p = M_CheckParmWithArgs("-as", 1); if (p > 0) { for (p = p + 1; p // @category mod // // Equivalent to "-af -as ". // p = M_CheckParmWithArgs("-aa", 1); if (p > 0) { for (p = p + 1; p // @vanilla // // Load the specified PWAD files. // p = M_CheckParmWithArgs ("-file", 1); if (p) { // the parms after p are wadfile/lump names, // until end of parms or another - preceded parm modifiedgame = true; // homebrew levels while (++p != myargc && myargv[p][0] != '-') { char *filename; filename = D_TryFindWADByName(myargv[p]); printf(" adding %s\n", filename); W_AddFile(filename); } } // W_PrintDirectory(); return modifiedgame; } chocolate-doom-chocolate-doom-2.2.1/src/w_main.h000066400000000000000000000013471257432200600215240ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Common code to parse command line, identifying WAD files to load. // #ifndef W_MAIN_H #define W_MAIN_H boolean W_ParseCommandLine(void); #endif /* #ifndef W_MAIN_H */ chocolate-doom-chocolate-doom-2.2.1/src/w_merge.c000066400000000000000000000406611257432200600216740ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Handles merging of PWADs, similar to deutex's -merge option // // Ideally this should work exactly the same as in deutex, but trying to // read the deutex source code made my brain hurt. // #include #include #include #include #include "doomtype.h" #include "i_system.h" #include "m_misc.h" #include "w_merge.h" #include "w_wad.h" #include "z_zone.h" typedef enum { SECTION_NORMAL, SECTION_FLATS, SECTION_SPRITES, } section_t; typedef struct { lumpinfo_t *lumps; int numlumps; } searchlist_t; typedef struct { char sprname[4]; char frame; lumpinfo_t *angle_lumps[8]; } sprite_frame_t; static searchlist_t iwad; static searchlist_t iwad_sprites; static searchlist_t pwad; static searchlist_t iwad_flats; static searchlist_t pwad_sprites; static searchlist_t pwad_flats; // lumps with these sprites must be replaced in the IWAD static sprite_frame_t *sprite_frames; static int num_sprite_frames; static int sprite_frames_alloced; // Search in a list to find a lump with a particular name // Linear search (slow!) // // Returns -1 if not found static int FindInList(searchlist_t *list, char *name) { int i; for (i=0; inumlumps; ++i) { if (!strncasecmp(list->lumps[i].name, name, 8)) return i; } return -1; } static boolean SetupList(searchlist_t *list, searchlist_t *src_list, char *startname, char *endname, char *startname2, char *endname2) { int startlump, endlump; list->numlumps = 0; startlump = FindInList(src_list, startname); if (startname2 != NULL && startlump < 0) { startlump = FindInList(src_list, startname2); } if (startlump >= 0) { endlump = FindInList(src_list, endname); if (endname2 != NULL && endlump < 0) { endlump = FindInList(src_list, endname2); } if (endlump > startlump) { list->lumps = src_list->lumps + startlump + 1; list->numlumps = endlump - startlump - 1; return true; } } return false; } // Sets up the sprite/flat search lists static void SetupLists(void) { // IWAD if (!SetupList(&iwad_flats, &iwad, "F_START", "F_END", NULL, NULL)) { I_Error("Flats section not found in IWAD"); } if (!SetupList(&iwad_sprites, &iwad, "S_START", "S_END", NULL, NULL)) { I_Error("Sprites section not found in IWAD"); } // PWAD SetupList(&pwad_flats, &pwad, "F_START", "F_END", "FF_START", "FF_END"); SetupList(&pwad_sprites, &pwad, "S_START", "S_END", "SS_START", "SS_END"); } // Initialize the replace list static void InitSpriteList(void) { if (sprite_frames == NULL) { sprite_frames_alloced = 128; sprite_frames = Z_Malloc(sizeof(*sprite_frames) * sprite_frames_alloced, PU_STATIC, NULL); } num_sprite_frames = 0; } static boolean ValidSpriteLumpName(char *name) { if (name[0] == '\0' || name[1] == '\0' || name[2] == '\0' || name[3] == '\0') { return false; } // First frame: if (name[4] == '\0' || !isdigit(name[5])) { return false; } // Second frame (optional): if (name[6] != '\0' && !isdigit(name[7])) { return false; } return true; } // Find a sprite frame static sprite_frame_t *FindSpriteFrame(char *name, int frame) { sprite_frame_t *result; int i; // Search the list and try to find the frame for (i=0; isprname, name, 4) && cur->frame == frame) { return cur; } } // Not found in list; Need to add to the list // Grow list? if (num_sprite_frames >= sprite_frames_alloced) { sprite_frame_t *newframes; newframes = Z_Malloc(sprite_frames_alloced * 2 * sizeof(*sprite_frames), PU_STATIC, NULL); memcpy(newframes, sprite_frames, sprite_frames_alloced * sizeof(*sprite_frames)); Z_Free(sprite_frames); sprite_frames_alloced *= 2; sprite_frames = newframes; } // Add to end of list result = &sprite_frames[num_sprite_frames]; strncpy(result->sprname, name, 4); result->frame = frame; for (i=0; i<8; ++i) result->angle_lumps[i] = NULL; ++num_sprite_frames; return result; } // Check if sprite lump is needed in the new wad static boolean SpriteLumpNeeded(lumpinfo_t *lump) { sprite_frame_t *sprite; int angle_num; int i; if (!ValidSpriteLumpName(lump->name)) { return true; } // check the first frame sprite = FindSpriteFrame(lump->name, lump->name[4]); angle_num = lump->name[5] - '0'; if (angle_num == 0) { // must check all frames for (i=0; i<8; ++i) { if (sprite->angle_lumps[i] == lump) return true; } } else { // check if this lump is being used for this frame if (sprite->angle_lumps[angle_num - 1] == lump) return true; } // second frame if any // no second frame? if (lump->name[6] == '\0') return false; sprite = FindSpriteFrame(lump->name, lump->name[6]); angle_num = lump->name[7] - '0'; if (angle_num == 0) { // must check all frames for (i=0; i<8; ++i) { if (sprite->angle_lumps[i] == lump) return true; } } else { // check if this lump is being used for this frame if (sprite->angle_lumps[angle_num - 1] == lump) return true; } return false; } static void AddSpriteLump(lumpinfo_t *lump) { sprite_frame_t *sprite; int angle_num; int i; if (!ValidSpriteLumpName(lump->name)) { return; } // first angle sprite = FindSpriteFrame(lump->name, lump->name[4]); angle_num = lump->name[5] - '0'; if (angle_num == 0) { for (i=0; i<8; ++i) sprite->angle_lumps[i] = lump; } else { sprite->angle_lumps[angle_num - 1] = lump; } // second angle // no second angle? if (lump->name[6] == '\0') return; sprite = FindSpriteFrame(lump->name, lump->name[6]); angle_num = lump->name[7] - '0'; if (angle_num == 0) { for (i=0; i<8; ++i) sprite->angle_lumps[i] = lump; } else { sprite->angle_lumps[angle_num - 1] = lump; } } // Generate the list. Run at the start, before merging static void GenerateSpriteList(void) { int i; InitSpriteList(); // Add all sprites from the IWAD for (i=0; iname, "F_START", 8)) { current_section = SECTION_FLATS; } else if (!strncasecmp(lump->name, "S_START", 8)) { current_section = SECTION_SPRITES; } newlumps[num_newlumps++] = *lump; break; case SECTION_FLATS: // Have we reached the end of the section? if (!strncasecmp(lump->name, "F_END", 8)) { // Add all new flats from the PWAD to the end // of the section for (n=0; nname); if (lumpindex < 0) { newlumps[num_newlumps++] = *lump; } } break; case SECTION_SPRITES: // Have we reached the end of the section? if (!strncasecmp(lump->name, "S_END", 8)) { // add all the pwad sprites for (n=0; nname, "F_START", 8) || !strncasecmp(lump->name, "FF_START", 8)) { current_section = SECTION_FLATS; } else if (!strncasecmp(lump->name, "S_START", 8) || !strncasecmp(lump->name, "SS_START", 8)) { current_section = SECTION_SPRITES; } else { // Don't include the headers of sections newlumps[num_newlumps++] = *lump; } break; case SECTION_FLATS: // PWAD flats are ignored (already merged) if (!strncasecmp(lump->name, "FF_END", 8) || !strncasecmp(lump->name, "F_END", 8)) { // end of section current_section = SECTION_NORMAL; } break; case SECTION_SPRITES: // PWAD sprites are ignored (already merged) if (!strncasecmp(lump->name, "SS_END", 8) || !strncasecmp(lump->name, "S_END", 8)) { // end of section current_section = SECTION_NORMAL; } break; } } // Switch to the new lumpinfo, and free the old one free(lumpinfo); lumpinfo = newlumps; numlumps = num_newlumps; } void W_PrintDirectory(void) { unsigned int i, n; // debug for (i=0; inumlumps; ++i) { int index; index = FindInList(&pwad, list->lumps[i].name); if (index > 0) { memcpy(&list->lumps[i], &pwad.lumps[index], sizeof(lumpinfo_t)); } } } // Merge sprites and flats in the way NWT does with its -af and -as // command-line options. void W_NWTMergeFile(char *filename, int flags) { int old_numlumps; old_numlumps = numlumps; // Load PWAD if (W_AddFile(filename) == NULL) return; // iwad is at the start, pwad was appended to the end iwad.lumps = lumpinfo; iwad.numlumps = old_numlumps; pwad.lumps = lumpinfo + old_numlumps; pwad.numlumps = numlumps - old_numlumps; // Setup sprite/flat lists SetupLists(); // Merge in flats? if (flags & W_NWT_MERGE_FLATS) { W_NWTAddLumps(&iwad_flats); } // Sprites? if (flags & W_NWT_MERGE_SPRITES) { W_NWTAddLumps(&iwad_sprites); } // Discard the PWAD numlumps = old_numlumps; } // Simulates the NWT -merge command line parameter. What this does is load // a PWAD, then search the IWAD sprites, removing any sprite lumps that also // exist in the PWAD. void W_NWTDashMerge(char *filename) { wad_file_t *wad_file; int old_numlumps; int i; old_numlumps = numlumps; // Load PWAD wad_file = W_AddFile(filename); if (wad_file == NULL) { return; } // iwad is at the start, pwad was appended to the end iwad.lumps = lumpinfo; iwad.numlumps = old_numlumps; pwad.lumps = lumpinfo + old_numlumps; pwad.numlumps = numlumps - old_numlumps; // Setup sprite/flat lists SetupLists(); // Search through the IWAD sprites list. for (i=0; i= 0) { // Replace this entry with an empty string. This is what // nwt -merge does. M_StringCopy(iwad_sprites.lumps[i].name, "", 8); } } // Discard PWAD // The PWAD must now be added in again with -file. numlumps = old_numlumps; W_CloseFile(wad_file); } chocolate-doom-chocolate-doom-2.2.1/src/w_merge.h000066400000000000000000000023041257432200600216710ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Handles merging of PWADs, similar to deutex's -merge option // // Ideally this should work exactly the same as in deutex, but trying to // read the deutex source code made my brain hurt. // #ifndef W_MERGE_H #define W_MERGE_H #define W_NWT_MERGE_SPRITES 0x1 #define W_NWT_MERGE_FLATS 0x2 // Add a new WAD and merge it into the main directory void W_MergeFile(char *filename); // NWT-style merging void W_NWTMergeFile(char *filename, int flags); // Acts the same as NWT's "-merge" option. void W_NWTDashMerge(char *filename); // Debug function that prints the WAD directory. void W_PrintDirectory(void); #endif /* #ifndef W_MERGE_H */ chocolate-doom-chocolate-doom-2.2.1/src/w_wad.c000066400000000000000000000352321257432200600213460ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Handles WAD file header, directory, lump I/O. // #include #include #include #include #include "doomtype.h" #include "config.h" #include "d_iwad.h" #include "i_swap.h" #include "i_system.h" #include "i_video.h" #include "m_misc.h" #include "z_zone.h" #include "w_wad.h" typedef struct { // Should be "IWAD" or "PWAD". char identification[4]; int numlumps; int infotableofs; } PACKEDATTR wadinfo_t; typedef struct { int filepos; int size; char name[8]; } PACKEDATTR filelump_t; // // GLOBALS // // Location of each lump on disk. lumpinfo_t *lumpinfo; unsigned int numlumps = 0; // Hash table for fast lookups static lumpinfo_t **lumphash; // Variables for the reload hack: filename of the PWAD to reload, and the // lumps from WADs before the reload file, so we can resent numlumps and // load the file again. static wad_file_t *reloadhandle = NULL; static char *reloadname = NULL; static int reloadlump = -1; // Hash function used for lump names. unsigned int W_LumpNameHash(const char *s) { // This is the djb2 string hash function, modded to work on strings // that have a maximum length of 8. unsigned int result = 5381; unsigned int i; for (i=0; i < 8 && s[i] != '\0'; ++i) { result = ((result << 5) ^ result ) ^ toupper(s[i]); } return result; } // Increase the size of the lumpinfo[] array to the specified size. static void ExtendLumpInfo(int newnumlumps) { lumpinfo_t *newlumpinfo; unsigned int i; newlumpinfo = calloc(newnumlumps, sizeof(lumpinfo_t)); if (newlumpinfo == NULL) { I_Error ("Couldn't realloc lumpinfo"); } // Copy over lumpinfo_t structures from the old array. If any of // these lumps have been cached, we need to update the user // pointers to the new location. for (i = 0; i < numlumps && i < newnumlumps; ++i) { memcpy(&newlumpinfo[i], &lumpinfo[i], sizeof(lumpinfo_t)); if (newlumpinfo[i].cache != NULL) { Z_ChangeUser(newlumpinfo[i].cache, &newlumpinfo[i].cache); } // We shouldn't be generating a hash table until after all WADs have // been loaded, but just in case... if (lumpinfo[i].next != NULL) { int nextlumpnum = lumpinfo[i].next - lumpinfo; newlumpinfo[i].next = &newlumpinfo[nextlumpnum]; } } // All done. free(lumpinfo); lumpinfo = newlumpinfo; numlumps = newnumlumps; } // // LUMP BASED ROUTINES. // // // W_AddFile // All files are optional, but at least one file must be // found (PWAD, if all required lumps are present). // Files with a .wad extension are wadlink files // with multiple lumps. // Other files are single lumps with the base filename // for the lump name. wad_file_t *W_AddFile (char *filename) { wadinfo_t header; lumpinfo_t *lump_p; unsigned int i; wad_file_t *wad_file; int length; int startlump; filelump_t *fileinfo; filelump_t *filerover; int newnumlumps; // If the filename begins with a ~, it indicates that we should use the // reload hack. if (filename[0] == '~') { if (reloadname != NULL) { I_Error("Prefixing a WAD filename with '~' indicates that the " "WAD should be reloaded\n" "on each level restart, for use by level authors for " "rapid development. You\n" "can only reload one WAD file, and it must be the last " "file in the -file list."); } reloadname = strdup(filename); reloadlump = numlumps; ++filename; } // Open the file and add to directory wad_file = W_OpenFile(filename); if (wad_file == NULL) { printf (" couldn't open %s\n", filename); return NULL; } // If this is the reload file, we need to save the file handle so that we // can close it later on when we do a reload. if (reloadname) { reloadhandle = wad_file; } newnumlumps = numlumps; if (strcasecmp(filename+strlen(filename)-3 , "wad" ) ) { // single lump file // fraggle: Swap the filepos and size here. The WAD directory // parsing code expects a little-endian directory, so will swap // them back. Effectively we're constructing a "fake WAD directory" // here, as it would appear on disk. fileinfo = Z_Malloc(sizeof(filelump_t), PU_STATIC, 0); fileinfo->filepos = LONG(0); fileinfo->size = LONG(wad_file->length); // Name the lump after the base of the filename (without the // extension). M_ExtractFileBase (filename, fileinfo->name); newnumlumps++; } else { // WAD file W_Read(wad_file, 0, &header, sizeof(header)); if (strncmp(header.identification,"IWAD",4)) { // Homebrew levels? if (strncmp(header.identification,"PWAD",4)) { I_Error ("Wad file %s doesn't have IWAD " "or PWAD id\n", filename); } // ???modifiedgame = true; } header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps*sizeof(filelump_t); fileinfo = Z_Malloc(length, PU_STATIC, 0); W_Read(wad_file, header.infotableofs, fileinfo, length); newnumlumps += header.numlumps; } // Increase size of numlumps array to accomodate the new file. startlump = numlumps; ExtendLumpInfo(newnumlumps); lump_p = &lumpinfo[startlump]; filerover = fileinfo; for (i=startlump; iwad_file = wad_file; lump_p->position = LONG(filerover->filepos); lump_p->size = LONG(filerover->size); lump_p->cache = NULL; strncpy(lump_p->name, filerover->name, 8); ++lump_p; ++filerover; } Z_Free(fileinfo); if (lumphash != NULL) { Z_Free(lumphash); lumphash = NULL; } return wad_file; } // // W_NumLumps // int W_NumLumps (void) { return numlumps; } // // W_CheckNumForName // Returns -1 if name not found. // int W_CheckNumForName (char* name) { lumpinfo_t *lump_p; int i; // Do we have a hash table yet? if (lumphash != NULL) { int hash; // We do! Excellent. hash = W_LumpNameHash(name) % numlumps; for (lump_p = lumphash[hash]; lump_p != NULL; lump_p = lump_p->next) { if (!strncasecmp(lump_p->name, name, 8)) { return lump_p - lumpinfo; } } } else { // We don't have a hash table generate yet. Linear search :-( // // scan backwards so patch lump files take precedence for (i=numlumps-1; i >= 0; --i) { if (!strncasecmp(lumpinfo[i].name, name, 8)) { return i; } } } // TFB. Not found. return -1; } // // W_GetNumForName // Calls W_CheckNumForName, but bombs out if not found. // int W_GetNumForName (char* name) { int i; i = W_CheckNumForName (name); if (i < 0) { I_Error ("W_GetNumForName: %s not found!", name); } return i; } // // W_LumpLength // Returns the buffer size needed to load the given lump. // int W_LumpLength (unsigned int lump) { if (lump >= numlumps) { I_Error ("W_LumpLength: %i >= numlumps", lump); } return lumpinfo[lump].size; } // // W_ReadLump // Loads the lump into the given buffer, // which must be >= W_LumpLength(). // void W_ReadLump(unsigned int lump, void *dest) { int c; lumpinfo_t *l; if (lump >= numlumps) { I_Error ("W_ReadLump: %i >= numlumps", lump); } l = lumpinfo+lump; I_BeginRead (); c = W_Read(l->wad_file, l->position, dest, l->size); if (c < l->size) { I_Error ("W_ReadLump: only read %i of %i on lump %i", c, l->size, lump); } I_EndRead (); } // // W_CacheLumpNum // // Load a lump into memory and return a pointer to a buffer containing // the lump data. // // 'tag' is the type of zone memory buffer to allocate for the lump // (usually PU_STATIC or PU_CACHE). If the lump is loaded as // PU_STATIC, it should be released back using W_ReleaseLumpNum // when no longer needed (do not use Z_ChangeTag). // void *W_CacheLumpNum(int lumpnum, int tag) { byte *result; lumpinfo_t *lump; if ((unsigned)lumpnum >= numlumps) { I_Error ("W_CacheLumpNum: %i >= numlumps", lumpnum); } lump = &lumpinfo[lumpnum]; // Get the pointer to return. If the lump is in a memory-mapped // file, we can just return a pointer to within the memory-mapped // region. If the lump is in an ordinary file, we may already // have it cached; otherwise, load it into memory. if (lump->wad_file->mapped != NULL) { // Memory mapped file, return from the mmapped region. result = lump->wad_file->mapped + lump->position; } else if (lump->cache != NULL) { // Already cached, so just switch the zone tag. result = lump->cache; Z_ChangeTag(lump->cache, tag); } else { // Not yet loaded, so load it now lump->cache = Z_Malloc(W_LumpLength(lumpnum), tag, &lump->cache); W_ReadLump (lumpnum, lump->cache); result = lump->cache; } return result; } // // W_CacheLumpName // void *W_CacheLumpName(char *name, int tag) { return W_CacheLumpNum(W_GetNumForName(name), tag); } // // Release a lump back to the cache, so that it can be reused later // without having to read from disk again, or alternatively, discarded // if we run out of memory. // // Back in Vanilla Doom, this was just done using Z_ChangeTag // directly, but now that we have WAD mmap, things are a bit more // complicated ... // void W_ReleaseLumpNum(int lumpnum) { lumpinfo_t *lump; if ((unsigned)lumpnum >= numlumps) { I_Error ("W_ReleaseLumpNum: %i >= numlumps", lumpnum); } lump = &lumpinfo[lumpnum]; if (lump->wad_file->mapped != NULL) { // Memory-mapped file, so nothing needs to be done here. } else { Z_ChangeTag(lump->cache, PU_CACHE); } } void W_ReleaseLumpName(char *name) { W_ReleaseLumpNum(W_GetNumForName(name)); } #if 0 // // W_Profile // int info[2500][10]; int profilecount; void W_Profile (void) { int i; memblock_t* block; void* ptr; char ch; FILE* f; int j; char name[9]; for (i=0 ; itag < PU_PURGELEVEL) ch = 'S'; else ch = 'P'; } info[i][profilecount] = ch; } profilecount++; f = fopen ("waddump.txt","w"); name[8] = 0; for (i=0 ; i 0) { lumphash = Z_Malloc(sizeof(lumpinfo_t *) * numlumps, PU_STATIC, NULL); memset(lumphash, 0, sizeof(lumpinfo_t *) * numlumps); for (i=0; i= 0) { I_Error("\nYou are trying to use a %s IWAD file with " "the %s%s binary.\nThis isn't going to work.\n" "You probably want to use the %s%s binary.", D_SuggestGameName(unique_lumps[i].mission, indetermined), PROGRAM_PREFIX, D_GameMissionString(mission), PROGRAM_PREFIX, D_GameMissionString(unique_lumps[i].mission)); } } } } chocolate-doom-chocolate-doom-2.2.1/src/w_wad.h000066400000000000000000000031371257432200600213520ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // WAD I/O functions. // #ifndef __W_WAD__ #define __W_WAD__ #include #include "doomtype.h" #include "d_mode.h" #include "w_file.h" // // TYPES // // // WADFILE I/O related stuff. // typedef struct lumpinfo_s lumpinfo_t; struct lumpinfo_s { char name[8]; wad_file_t *wad_file; int position; int size; void *cache; // Used for hash table lookups lumpinfo_t *next; }; extern lumpinfo_t *lumpinfo; extern unsigned int numlumps; wad_file_t *W_AddFile (char *filename); void W_Reload (void); int W_CheckNumForName (char* name); int W_GetNumForName (char* name); int W_LumpLength (unsigned int lump); void W_ReadLump (unsigned int lump, void *dest); void* W_CacheLumpNum (int lump, int tag); void* W_CacheLumpName (char* name, int tag); void W_GenerateHashTable(void); extern unsigned int W_LumpNameHash(const char *s); void W_ReleaseLumpNum(int lump); void W_ReleaseLumpName(char *name); void W_CheckCorrectIWAD(GameMission_t mission); #endif chocolate-doom-chocolate-doom-2.2.1/src/z_native.c000066400000000000000000000225101257432200600220570ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Zone Memory Allocation. Neat. // // This is an implementation of the zone memory API which // uses native calls to malloc() and free(). // #include #include #include "z_zone.h" #include "i_system.h" #include "doomtype.h" #define ZONEID 0x1d4a11 typedef struct memblock_s memblock_t; struct memblock_s { int id; // = ZONEID int tag; int size; void **user; memblock_t *prev; memblock_t *next; }; // Linked list of allocated blocks for each tag type static memblock_t *allocated_blocks[PU_NUM_TAGS]; #ifdef TESTING static int test_malloced = 0; void *test_malloc(size_t size) { int *result; if (test_malloced + size > 2 * 1024 * 1024) { return NULL; } test_malloced += size; result = malloc(size + sizeof(int)); *result = size; return result + 1; } void test_free(void *data) { int *i; i = ((int *) data) - 1; test_malloced -= *i; free(i); } #define malloc test_malloc #define free test_free #endif /* #ifdef TESTING */ // Add a block into the linked list for its type. static void Z_InsertBlock(memblock_t *block) { block->prev = NULL; block->next = allocated_blocks[block->tag]; allocated_blocks[block->tag] = block; if (block->next != NULL) { block->next->prev = block; } } // Remove a block from its linked list. static void Z_RemoveBlock(memblock_t *block) { // Unlink from list if (block->prev == NULL) { // Start of list allocated_blocks[block->tag] = block->next; } else { block->prev->next = block->next; } if (block->next != NULL) { block->next->prev = block->prev; } } // // Z_Init // void Z_Init (void) { memset(allocated_blocks, 0, sizeof(allocated_blocks)); printf("zone memory: Using native C allocator.\n"); } // // Z_Free // void Z_Free (void* ptr) { memblock_t* block; block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) { I_Error ("Z_Free: freed a pointer without ZONEID"); } if (block->tag != PU_FREE && block->user != NULL) { // clear the user's mark *block->user = NULL; } Z_RemoveBlock(block); // Free back to system free(block); } // Empty data from the cache list to allocate enough data of the size // required. // // Returns true if any blocks were freed. static boolean ClearCache(int size) { memblock_t *block; memblock_t *next_block; int remaining; block = allocated_blocks[PU_CACHE]; if (block == NULL) { // Cache is already empty. return false; } // Search to the end of the PU_CACHE list. The blocks at the end // of the list are the ones that have been free for longer and // are more likely to be unneeded now. while (block->next != NULL) { block = block->next; } //printf("out of memory; cleaning out the cache: %i\n", test_malloced); // Search backwards through the list freeing blocks until we have // freed the amount of memory required. remaining = size; while (remaining > 0) { if (block == NULL) { // No blocks left to free; we've done our best. break; } next_block = block->prev; Z_RemoveBlock(block); remaining -= block->size; if (block->user) { *block->user = NULL; } free(block); block = next_block; } return true; } // // Z_Malloc // You can pass a NULL user if the tag is < PU_PURGELEVEL. // void *Z_Malloc(int size, int tag, void *user) { memblock_t *newblock; unsigned char *data; void *result; if (tag < 0 || tag >= PU_NUM_TAGS || tag == PU_FREE) { I_Error("Z_Malloc: attempted to allocate a block with an invalid " "tag: %i", tag); } if (user == NULL && tag >= PU_PURGELEVEL) { I_Error ("Z_Malloc: an owner is required for purgable blocks"); } // Malloc a block of the required size newblock = NULL; while (newblock == NULL) { newblock = (memblock_t *) malloc(sizeof(memblock_t) + size); if (newblock == NULL) { if (!ClearCache(sizeof(memblock_t) + size)) { I_Error("Z_Malloc: failed on allocation of %i bytes", size); } } } newblock->tag = tag; // Hook into the linked list for this tag type newblock->id = ZONEID; newblock->user = user; newblock->size = size; Z_InsertBlock(newblock); data = (unsigned char *) newblock; result = data + sizeof(memblock_t); if (user != NULL) { *newblock->user = result; } return result; } // // Z_FreeTags // void Z_FreeTags(int lowtag, int hightag) { int i; for (i=lowtag; i<= hightag; ++i) { memblock_t *block; memblock_t *next; // Free all in this chain for (block=allocated_blocks[i]; block != NULL; ) { next = block->next; // Free this block if (block->user != NULL) { *block->user = NULL; } free(block); // Jump to the next in the chain block = next; } // This chain is empty now allocated_blocks[i] = NULL; } } // // Z_DumpHeap // void Z_DumpHeap(int lowtag, int hightag) { // broken #if 0 memblock_t* block; printf ("zone size: %i location: %p\n", mainzone->size,mainzone); printf ("tag range: %i to %i\n", lowtag, hightag); for (block = mainzone->blocklist.next ; ; block = block->next) { if (block->tag >= lowtag && block->tag <= hightag) printf ("block:%p size:%7i user:%p tag:%3i\n", block, block->size, block->user, block->tag); if (block->next == &mainzone->blocklist) { // all blocks have been hit break; } if ( (byte *)block + block->size != (byte *)block->next) printf ("ERROR: block size does not touch the next block\n"); if ( block->next->prev != block) printf ("ERROR: next block doesn't have proper back link\n"); if (block->tag == PU_FREE && block->next->tag == PU_FREE) printf ("ERROR: two consecutive free blocks\n"); } #endif } // // Z_FileDumpHeap // void Z_FileDumpHeap(FILE *f) { // broken #if 0 memblock_t* block; fprintf (f,"zone size: %i location: %p\n",mainzone->size,mainzone); for (block = mainzone->blocklist.next ; ; block = block->next) { fprintf (f,"block:%p size:%7i user:%p tag:%3i\n", block, block->size, block->user, block->tag); if (block->next == &mainzone->blocklist) { // all blocks have been hit break; } if ( (byte *)block + block->size != (byte *)block->next) fprintf (f,"ERROR: block size does not touch the next block\n"); if ( block->next->prev != block) fprintf (f,"ERROR: next block doesn't have proper back link\n"); if (block->tag == PU_FREE && block->next->tag == PU_FREE) fprintf (f,"ERROR: two consecutive free blocks\n"); } #endif } // // Z_CheckHeap // void Z_CheckHeap (void) { memblock_t *block; memblock_t *prev; int i; // Check all chains for (i=0; inext) { if (block->id != ZONEID) { I_Error("Z_CheckHeap: Block without a ZONEID!"); } if (block->prev != prev) { I_Error("Z_CheckHeap: Doubly-linked list corrupted!"); } prev = block; } } } // // Z_ChangeTag // void Z_ChangeTag2(void *ptr, int tag, char *file, int line) { memblock_t* block; block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) I_Error("%s:%i: Z_ChangeTag: block without a ZONEID!", file, line); if (tag >= PU_PURGELEVEL && block->user == NULL) I_Error("%s:%i: Z_ChangeTag: an owner is required " "for purgable blocks", file, line); // Remove the block from its current list, and rehook it into // its new list. Z_RemoveBlock(block); block->tag = tag; Z_InsertBlock(block); } void Z_ChangeUser(void *ptr, void **user) { memblock_t* block; block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) { I_Error("Z_ChangeUser: Tried to change user for invalid block!"); } block->user = user; *user = ptr; } // // Z_FreeMemory // int Z_FreeMemory(void) { // Limited by the system?? return -1; } unsigned int Z_ZoneSize(void) { return 0; } chocolate-doom-chocolate-doom-2.2.1/src/z_zone.c000066400000000000000000000301551257432200600215500ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Zone Memory Allocation. Neat. // #include #include "doomtype.h" #include "i_system.h" #include "m_argv.h" #include "z_zone.h" // // ZONE MEMORY ALLOCATION // // There is never any space between memblocks, // and there will never be two contiguous free memblocks. // The rover can be left pointing at a non-empty block. // // It is of no value to free a cachable block, // because it will get overwritten automatically if needed. // #define MEM_ALIGN sizeof(void *) #define ZONEID 0x1d4a11 typedef struct memblock_s { int size; // including the header and possibly tiny fragments void** user; int tag; // PU_FREE if this is free int id; // should be ZONEID struct memblock_s* next; struct memblock_s* prev; } memblock_t; typedef struct { // total bytes malloced, including header int size; // start / end cap for linked list memblock_t blocklist; memblock_t* rover; } memzone_t; static memzone_t *mainzone; static boolean zero_on_free; static boolean scan_on_free; // // Z_ClearZone // void Z_ClearZone (memzone_t* zone) { memblock_t* block; // set the entire zone to one free block zone->blocklist.next = zone->blocklist.prev = block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) ); zone->blocklist.user = (void *)zone; zone->blocklist.tag = PU_STATIC; zone->rover = block; block->prev = block->next = &zone->blocklist; // a free block. block->tag = PU_FREE; block->size = zone->size - sizeof(memzone_t); } // // Z_Init // void Z_Init (void) { memblock_t* block; int size; mainzone = (memzone_t *)I_ZoneBase (&size); mainzone->size = size; // set the entire zone to one free block mainzone->blocklist.next = mainzone->blocklist.prev = block = (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) ); mainzone->blocklist.user = (void *)mainzone; mainzone->blocklist.tag = PU_STATIC; mainzone->rover = block; block->prev = block->next = &mainzone->blocklist; // free block block->tag = PU_FREE; block->size = mainzone->size - sizeof(memzone_t); //! // Zone memory debugging flag. If set, memory is zeroed after it is freed // to deliberately break any code that attempts to use it after free. // zero_on_free = M_ParmExists("-zonezero"); //! // Zone memory debugging flag. If set, each time memory is freed, the zone // heap is scanned to look for remaining pointers to the freed block. // scan_on_free = M_ParmExists("-zonescan"); } // Scan the zone heap for pointers within the specified range, and warn about // any remaining pointers. static void ScanForBlock(void *start, void *end) { memblock_t *block; void **mem; int i, len, tag; block = mainzone->blocklist.next; while (block->next != &mainzone->blocklist) { tag = block->tag; if (tag == PU_STATIC || tag == PU_LEVEL || tag == PU_LEVSPEC) { // Scan for pointers on the assumption that pointers are aligned // on word boundaries (word size depending on pointer size): mem = (void **) ((byte *) block + sizeof(memblock_t)); len = (block->size - sizeof(memblock_t)) / sizeof(void *); for (i = 0; i < len; ++i) { if (start <= mem[i] && mem[i] <= end) { fprintf(stderr, "%p has dangling pointer into freed block " "%p (%p -> %p)\n", mem, start, &mem[i], mem[i]); } } } block = block->next; } } // // Z_Free // void Z_Free (void* ptr) { memblock_t* block; memblock_t* other; block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) I_Error ("Z_Free: freed a pointer without ZONEID"); if (block->tag != PU_FREE && block->user != NULL) { // clear the user's mark *block->user = 0; } // mark as free block->tag = PU_FREE; block->user = NULL; block->id = 0; // If the -zonezero flag is provided, we zero out the block on free // to break code that depends on reading freed memory. if (zero_on_free) { memset(ptr, 0, block->size - sizeof(memblock_t)); } if (scan_on_free) { ScanForBlock(ptr, (byte *) ptr + block->size - sizeof(memblock_t)); } other = block->prev; if (other->tag == PU_FREE) { // merge with previous free block other->size += block->size; other->next = block->next; other->next->prev = other; if (block == mainzone->rover) mainzone->rover = other; block = other; } other = block->next; if (other->tag == PU_FREE) { // merge the next free block onto the end block->size += other->size; block->next = other->next; block->next->prev = block; if (other == mainzone->rover) mainzone->rover = block; } } // // Z_Malloc // You can pass a NULL user if the tag is < PU_PURGELEVEL. // #define MINFRAGMENT 64 void* Z_Malloc ( int size, int tag, void* user ) { int extra; memblock_t* start; memblock_t* rover; memblock_t* newblock; memblock_t* base; void *result; size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1); // scan through the block list, // looking for the first free block // of sufficient size, // throwing out any purgable blocks along the way. // account for size of block header size += sizeof(memblock_t); // if there is a free block behind the rover, // back up over them base = mainzone->rover; if (base->prev->tag == PU_FREE) base = base->prev; rover = base; start = base->prev; do { if (rover == start) { // scanned all the way around the list I_Error ("Z_Malloc: failed on allocation of %i bytes", size); } if (rover->tag != PU_FREE) { if (rover->tag < PU_PURGELEVEL) { // hit a block that can't be purged, // so move base past it base = rover = rover->next; } else { // free the rover block (adding the size to base) // the rover can be the base block base = base->prev; Z_Free ((byte *)rover+sizeof(memblock_t)); base = base->next; rover = base->next; } } else { rover = rover->next; } } while (base->tag != PU_FREE || base->size < size); // found a block big enough extra = base->size - size; if (extra > MINFRAGMENT) { // there will be a free fragment after the allocated block newblock = (memblock_t *) ((byte *)base + size ); newblock->size = extra; newblock->tag = PU_FREE; newblock->user = NULL; newblock->prev = base; newblock->next = base->next; newblock->next->prev = newblock; base->next = newblock; base->size = size; } if (user == NULL && tag >= PU_PURGELEVEL) I_Error ("Z_Malloc: an owner is required for purgable blocks"); base->user = user; base->tag = tag; result = (void *) ((byte *)base + sizeof(memblock_t)); if (base->user) { *base->user = result; } // next allocation will start looking here mainzone->rover = base->next; base->id = ZONEID; return result; } // // Z_FreeTags // void Z_FreeTags ( int lowtag, int hightag ) { memblock_t* block; memblock_t* next; for (block = mainzone->blocklist.next ; block != &mainzone->blocklist ; block = next) { // get link before freeing next = block->next; // free block? if (block->tag == PU_FREE) continue; if (block->tag >= lowtag && block->tag <= hightag) Z_Free ( (byte *)block+sizeof(memblock_t)); } } // // Z_DumpHeap // Note: TFileDumpHeap( stdout ) ? // void Z_DumpHeap ( int lowtag, int hightag ) { memblock_t* block; printf ("zone size: %i location: %p\n", mainzone->size,mainzone); printf ("tag range: %i to %i\n", lowtag, hightag); for (block = mainzone->blocklist.next ; ; block = block->next) { if (block->tag >= lowtag && block->tag <= hightag) printf ("block:%p size:%7i user:%p tag:%3i\n", block, block->size, block->user, block->tag); if (block->next == &mainzone->blocklist) { // all blocks have been hit break; } if ( (byte *)block + block->size != (byte *)block->next) printf ("ERROR: block size does not touch the next block\n"); if ( block->next->prev != block) printf ("ERROR: next block doesn't have proper back link\n"); if (block->tag == PU_FREE && block->next->tag == PU_FREE) printf ("ERROR: two consecutive free blocks\n"); } } // // Z_FileDumpHeap // void Z_FileDumpHeap (FILE* f) { memblock_t* block; fprintf (f,"zone size: %i location: %p\n",mainzone->size,mainzone); for (block = mainzone->blocklist.next ; ; block = block->next) { fprintf (f,"block:%p size:%7i user:%p tag:%3i\n", block, block->size, block->user, block->tag); if (block->next == &mainzone->blocklist) { // all blocks have been hit break; } if ( (byte *)block + block->size != (byte *)block->next) fprintf (f,"ERROR: block size does not touch the next block\n"); if ( block->next->prev != block) fprintf (f,"ERROR: next block doesn't have proper back link\n"); if (block->tag == PU_FREE && block->next->tag == PU_FREE) fprintf (f,"ERROR: two consecutive free blocks\n"); } } // // Z_CheckHeap // void Z_CheckHeap (void) { memblock_t* block; for (block = mainzone->blocklist.next ; ; block = block->next) { if (block->next == &mainzone->blocklist) { // all blocks have been hit break; } if ( (byte *)block + block->size != (byte *)block->next) I_Error ("Z_CheckHeap: block size does not touch the next block\n"); if ( block->next->prev != block) I_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); if (block->tag == PU_FREE && block->next->tag == PU_FREE) I_Error ("Z_CheckHeap: two consecutive free blocks\n"); } } // // Z_ChangeTag // void Z_ChangeTag2(void *ptr, int tag, char *file, int line) { memblock_t* block; block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) I_Error("%s:%i: Z_ChangeTag: block without a ZONEID!", file, line); if (tag >= PU_PURGELEVEL && block->user == NULL) I_Error("%s:%i: Z_ChangeTag: an owner is required " "for purgable blocks", file, line); block->tag = tag; } void Z_ChangeUser(void *ptr, void **user) { memblock_t* block; block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) { I_Error("Z_ChangeUser: Tried to change user for invalid block!"); } block->user = user; *user = ptr; } // // Z_FreeMemory // int Z_FreeMemory (void) { memblock_t* block; int free; free = 0; for (block = mainzone->blocklist.next ; block != &mainzone->blocklist; block = block->next) { if (block->tag == PU_FREE || block->tag >= PU_PURGELEVEL) free += block->size; } return free; } unsigned int Z_ZoneSize(void) { return mainzone->size; } chocolate-doom-chocolate-doom-2.2.1/src/z_zone.h000066400000000000000000000040601257432200600215510ustar00rootroot00000000000000// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Zone Memory Allocation, perhaps NeXT ObjectiveC inspired. // Remark: this was the only stuff that, according // to John Carmack, might have been useful for // Quake. // #ifndef __Z_ZONE__ #define __Z_ZONE__ #include // // ZONE MEMORY // PU - purge tags. enum { PU_STATIC = 1, // static entire execution time PU_SOUND, // static while playing PU_MUSIC, // static while playing PU_FREE, // a free block PU_LEVEL, // static until level exited PU_LEVSPEC, // a special thinker in a level // Tags >= PU_PURGELEVEL are purgable whenever needed. PU_PURGELEVEL, PU_CACHE, // Total number of different tag types PU_NUM_TAGS }; void Z_Init (void); void* Z_Malloc (int size, int tag, void *ptr); void Z_Free (void *ptr); void Z_FreeTags (int lowtag, int hightag); void Z_DumpHeap (int lowtag, int hightag); void Z_FileDumpHeap (FILE *f); void Z_CheckHeap (void); void Z_ChangeTag2 (void *ptr, int tag, char *file, int line); void Z_ChangeUser(void *ptr, void **user); int Z_FreeMemory (void); unsigned int Z_ZoneSize(void); // // This is used to get the local FILE:LINE info from CPP // prior to really call the function in question. // #define Z_ChangeTag(p,t) \ Z_ChangeTag2((p), (t), __FILE__, __LINE__) #endif chocolate-doom-chocolate-doom-2.2.1/textscreen/000077500000000000000000000000001257432200600214715ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/textscreen/.gitignore000066400000000000000000000000511257432200600234550ustar00rootroot00000000000000Makefile Makefile.in .deps *.a tags TAGS chocolate-doom-chocolate-doom-2.2.1/textscreen/Doxyfile000066400000000000000000001570461257432200600232140ustar00rootroot00000000000000# Doxyfile 1.5.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "libtextscreen" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, # and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = src/ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = YES #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = DOXYGEN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 1000 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is enabled by default, which results in a transparent # background. Warning: Depending on the platform used, enabling this option # may lead to badly anti-aliased labels on the edges of a graph (i.e. they # become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO chocolate-doom-chocolate-doom-2.2.1/textscreen/Makefile.am000066400000000000000000000030551257432200600235300ustar00rootroot00000000000000 AM_CFLAGS = -I$(top_srcdir)/src CTAGS_ARGS=-I TXT_UNCAST_ARG+ # build this directory before the examples directory. SUBDIRS= . examples noinst_LIBRARIES=libtextscreen.a EXTRA_DIST=Doxyfile libtextscreen_a_SOURCES = \ textscreen.h \ txt_checkbox.c txt_checkbox.h \ txt_desktop.c txt_desktop.h \ txt_dropdown.c txt_dropdown.h \ txt_fileselect.c txt_fileselect.h \ txt_gui.c txt_gui.h \ txt_inputbox.c txt_inputbox.h \ txt_io.c txt_io.h \ txt_main.h \ txt_button.c txt_button.h \ txt_label.c txt_label.h \ txt_radiobutton.c txt_radiobutton.h \ txt_scrollpane.c txt_scrollpane.h \ txt_separator.c txt_separator.h \ txt_spinctrl.c txt_spinctrl.h \ txt_sdl.c txt_sdl.h \ txt_largefont.h \ txt_smallfont.h \ txt_strut.c txt_strut.h \ txt_table.c txt_table.h \ txt_utf8.c txt_utf8.h \ txt_widget.c txt_widget.h \ txt_window.c txt_window.h \ txt_window_action.c txt_window_action.h \ txt_font.h doc: doxygen chocolate-doom-chocolate-doom-2.2.1/textscreen/examples/000077500000000000000000000000001257432200600233075ustar00rootroot00000000000000chocolate-doom-chocolate-doom-2.2.1/textscreen/examples/.gitignore000066400000000000000000000000761257432200600253020ustar00rootroot00000000000000Makefile.in Makefile .deps guitest calculator *.exe tags TAGS chocolate-doom-chocolate-doom-2.2.1/textscreen/examples/Makefile.am000066400000000000000000000004251257432200600253440ustar00rootroot00000000000000 AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/textscreen noinst_PROGRAMS=guitest calculator guitest_LDADD = ../libtextscreen.a @LDFLAGS@ @SDL_LIBS@ guitest_SOURCES = guitest.c calculator_LDADD = ../libtextscreen.a @LDFLAGS@ @SDL_LIBS@ calculator_SOURCES = calculator.c chocolate-doom-chocolate-doom-2.2.1/textscreen/examples/calculator.c000066400000000000000000000077031257432200600256130ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Example program: desktop calculator // #include #include #include #include "textscreen.h" typedef enum { OP_NONE, OP_PLUS, OP_MINUS, OP_MULT, OP_DIV, } operator_t; int starting_input = 0; int input_value = 0; txt_label_t *input_box; int first_operand; operator_t operator = OP_NONE; void UpdateInputBox(void) { char buf[20]; TXT_snprintf(buf, sizeof(buf), " %i", input_value); TXT_SetLabel(input_box, buf); } void InsertNumber(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(value)) { TXT_CAST_ARG(int, value); if (starting_input) { input_value = 0; starting_input = 0; } input_value *= 10; input_value += *value; UpdateInputBox(); } void AddNumberButton(txt_table_t *table, int value) { char buf[10]; int *val_copy; val_copy = malloc(sizeof(int)); *val_copy = value; TXT_snprintf(buf, sizeof(buf), " %i ", value); TXT_AddWidget(table, TXT_NewButton2(buf, InsertNumber, val_copy)); } void Operator(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(op)) { TXT_CAST_ARG(operator_t, op); first_operand = input_value; operator = *op; starting_input = 1; } void AddOperatorButton(txt_table_t *table, char *label, operator_t op) { char buf[10]; operator_t *op_copy; op_copy = malloc(sizeof(operator_t)); *op_copy = op; TXT_snprintf(buf, sizeof(buf), " %s ", label); TXT_AddWidget(table, TXT_NewButton2(buf, Operator, op_copy)); } void Calculate(TXT_UNCAST_ARG(button), void *unused) { switch (operator) { case OP_PLUS: input_value = first_operand + input_value; break; case OP_MINUS: input_value = first_operand - input_value; break; case OP_MULT: input_value = first_operand * input_value; break; case OP_DIV: input_value = first_operand / input_value; break; case OP_NONE: break; } UpdateInputBox(); operator = OP_NONE; starting_input = 1; } void BuildGUI() { txt_window_t *window; txt_table_t *table; window = TXT_NewWindow("Calculator"); input_box = TXT_NewLabel("asdf"); TXT_SetBGColor(input_box, TXT_COLOR_BLACK); TXT_AddWidget(window, input_box); TXT_AddWidget(window, TXT_NewSeparator(NULL)); TXT_AddWidget(window, TXT_NewStrut(0, 1)); table = TXT_NewTable(4); TXT_AddWidget(window, table); TXT_SetWidgetAlign(table, TXT_HORIZ_CENTER); AddNumberButton(table, 7); AddNumberButton(table, 8); AddNumberButton(table, 9); AddOperatorButton(table, "*", OP_MULT); AddNumberButton(table, 4); AddNumberButton(table, 5); AddNumberButton(table, 6); AddOperatorButton(table, "-", OP_MINUS); AddNumberButton(table, 1); AddNumberButton(table, 2); AddNumberButton(table, 3); AddOperatorButton(table, "+", OP_PLUS); AddNumberButton(table, 0); TXT_AddWidget(table, NULL); TXT_AddWidget(table, TXT_NewButton2(" = ", Calculate, NULL)); AddOperatorButton(table, "/", OP_DIV); TXT_AddWidget(window, TXT_NewStrut(0, 1)); UpdateInputBox(); } int main(int argc, char *argv[]) { if (!TXT_Init()) { fprintf(stderr, "Failed to initialise GUI\n"); exit(-1); } TXT_SetDesktopTitle("Calculator demo"); BuildGUI(); TXT_GUIMainLoop(); TXT_Shutdown(); return 0; } chocolate-doom-chocolate-doom-2.2.1/textscreen/examples/guitest.c000066400000000000000000000177011257432200600251450ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Example program: GUI test program // // Demonstrates all the main textscreen widgets in use and shows how // a simple textscreen program can be written. // #include #include #include #include "textscreen.h" enum { RADIO_VALUE_BADGER, RADIO_VALUE_MUSHROOM, RADIO_VALUE_SNAKE, }; char *extensions[] = { "wad", "lmp", "txt", NULL }; char *radio_values[] = { "Badger", "Mushroom", "Snake" }; char *textbox_value = NULL; int numbox_value = 0; int radiobutton_value; char *file_path = NULL; char *dir_path = NULL; txt_label_t *value_label; txt_window_t *firstwin; int cheesy; void ClosePwnBox(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(window)) { TXT_CAST_ARG(txt_window_t, window); TXT_CloseWindow(window); } void PwnBox(TXT_UNCAST_ARG(widget), void *user_data) { txt_window_t *window; txt_window_action_t *close_button; window = TXT_NewWindow("Pwned!"); TXT_AddWidget(window, TXT_NewLabel(" BOOM! HEADSHOT! ")); close_button = TXT_NewWindowAction(KEY_ENTER, "Close"); TXT_SignalConnect(close_button, "pressed", ClosePwnBox, window); TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, close_button); } void UpdateLabel(TXT_UNCAST_ARG(widget), void *user_data) { char buf[40]; TXT_StringCopy(buf, " Current value: ", sizeof(buf)); if (cheesy) { TXT_StringConcat(buf, "Cheesy ", sizeof(buf)); } TXT_StringConcat(buf, radio_values[radiobutton_value], sizeof(buf)); TXT_StringConcat(buf, "\n", sizeof(buf)); TXT_SetLabel(value_label, buf); } void CloseWindow(TXT_UNCAST_ARG(button), void *user_data) { TXT_CloseWindow(firstwin); } void SetupWindow(void) { txt_window_t *window; txt_table_t *table; txt_table_t *rightpane; txt_checkbox_t *cheesy_checkbox; txt_window_action_t *pwn; txt_label_t *toplabel; char buf[100]; int i; window = TXT_NewWindow("Window test"); TXT_SetWindowHelpURL(window, "https://www.youtube.com/watch?v=dQw4w9WgXcQ"); TXT_AddWidget(window, TXT_NewSeparator("Main section")); table = TXT_NewTable(3); toplabel = TXT_NewLabel("This is a multiline label.\n" "A single label object contains \n" "all three of these lines.\n"); TXT_AddWidget(window, toplabel); TXT_SetWidgetAlign(toplabel, TXT_HORIZ_CENTER); //TXT_AddWidget(window, TXT_NewScrollPane(15, 4, table)); TXT_AddWidget(window, table); for (i=0; i<5; ++i) { TXT_snprintf(buf, sizeof(buf), "Option %i in a table:", i + 1); TXT_AddWidget(table, TXT_NewLabel(buf)); TXT_snprintf(buf, sizeof(buf), " Button %i-1 ", i + 1); TXT_AddWidget(table, TXT_NewButton(buf)); TXT_snprintf(buf, sizeof(buf), " Button %i-2 ", i + 1); TXT_AddWidget(table, TXT_NewButton(buf)); } TXT_AddWidget(window, TXT_NewStrut(0, 1)); value_label = TXT_NewLabel(""); TXT_AddWidget(window, value_label); table = TXT_NewTable(2); TXT_AddWidget(window, table); TXT_SetWidgetAlign(table, TXT_HORIZ_CENTER); cheesy_checkbox = TXT_NewCheckBox("Cheesy", &cheesy); TXT_AddWidget(table, cheesy_checkbox); TXT_SignalConnect(cheesy_checkbox, "changed", UpdateLabel, NULL); rightpane = TXT_NewTable(1); TXT_AddWidget(table, rightpane); for (i=0; i<3; ++i) { txt_radiobutton_t *rbut; rbut = TXT_NewRadioButton(radio_values[i], &radiobutton_value, i); TXT_AddWidget(rightpane, rbut); TXT_SignalConnect(rbut, "selected", UpdateLabel, NULL); } UpdateLabel(NULL, NULL); TXT_AddWidget(window, TXT_NewButton2("Close Window", CloseWindow, NULL)); pwn = TXT_NewWindowAction(KEY_F1, "PWN!"); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, pwn); TXT_SignalConnect(pwn, "pressed", PwnBox, NULL); firstwin = window; } void Window2(void) { txt_window_t *window; txt_table_t *table; txt_table_t *unselectable_table; txt_scrollpane_t *scrollpane; window = TXT_NewWindow("Another test"); TXT_SetWindowPosition(window, TXT_HORIZ_RIGHT, TXT_VERT_TOP, TXT_SCREEN_W - 1, 1); TXT_AddWidgets(window, TXT_NewScrollPane(40, 1, TXT_NewLabel("* Unselectable scroll pane *")), unselectable_table = TXT_NewTable(1), NULL); TXT_AddWidget(unselectable_table, TXT_NewLabel("* Unselectable table *")); TXT_AddWidget(unselectable_table, TXT_NewLabel( "This is a UTF-8 string:\n" "\xc3\x80 bient\xc3\xb4t na\xc3\xaet " "\xc3\xa9v\xc3\xaaque \xc3\xa0 l'\xc5\x93uvre p\xc3\xa8re.")); TXT_AddWidget(window, TXT_NewSeparator("Input boxes")); table = TXT_NewTable(2); TXT_AddWidget(window, table); TXT_AddWidgets(table, TXT_NewLabel("String: "), TXT_NewInputBox(&textbox_value, 20), TXT_NewLabel("Int: "), TXT_NewIntInputBox(&numbox_value, 10), TXT_NewLabel("Spin control:"), TXT_NewSpinControl(&numbox_value, 0, 15), TXT_NewLabel("File:"), TXT_NewFileSelector(&file_path, 28, "Select file:", extensions), TXT_NewLabel("Directory:"), TXT_NewFileSelector(&dir_path, 28, "Select directory:", TXT_DIRECTORY), NULL); TXT_AddWidget(window, TXT_NewSeparator("Scroll pane test")); scrollpane = TXT_NewScrollPane(40, 5, TXT_NewLabel( "This is a scrollable pane. The contents\n" "of this box are larger than the box\n" "itself, but it can be scrolled around\n" "to explore the full contents.\n" "\n" "Scrollable panes can be scrolled both\n" "vertically and horizontally. They\n" "can contain any widget. The scroll bars\n" "appear automatically as needed.\n" "\n" "This is a very long line of text that forces a horizontal scrollbar" )); TXT_AddWidget(window, scrollpane); } void ScrollingMenu(void) { txt_window_t *window; txt_button_t *button; txt_table_t *table; window = TXT_NewWindow("Scrollable menu"); table = TXT_NewTable(1); TXT_AddWidgets(table, TXT_NewButton("Configure display"), TXT_NewButton("Configure joystick"), TXT_NewButton("Configure keyboard"), TXT_NewButton("Configure mouse"), TXT_NewButton("Configure sound"), TXT_NewStrut(0, 1), button = TXT_NewButton("Save Parameters and launch DOOM"), TXT_NewStrut(0, 1), TXT_NewButton("Start a network game"), TXT_NewButton("Join a network game"), TXT_NewButton("Multiplayer configuration"), NULL); TXT_SignalConnect(button, "pressed", PwnBox, NULL); TXT_AddWidget(window, TXT_NewScrollPane(0, 6, table)); } int main(int argc, char *argv[]) { if (!TXT_Init()) { fprintf(stderr, "Failed to initialise GUI\n"); exit(-1); } TXT_SetDesktopTitle("Not Chocolate Doom Setup"); ScrollingMenu(); Window2(); SetupWindow(); TXT_GUIMainLoop(); TXT_Shutdown(); return 0; } chocolate-doom-chocolate-doom-2.2.1/textscreen/textscreen.h000066400000000000000000000021061257432200600240250ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TEXTSCREEN_H #define TEXTSCREEN_H #include "../src/doomkeys.h" #include "txt_main.h" #include "txt_button.h" #include "txt_checkbox.h" #include "txt_desktop.h" #include "txt_dropdown.h" #include "txt_fileselect.h" #include "txt_inputbox.h" #include "txt_label.h" #include "txt_radiobutton.h" #include "txt_scrollpane.h" #include "txt_separator.h" #include "txt_spinctrl.h" #include "txt_strut.h" #include "txt_table.h" #include "txt_widget.h" #include "txt_window_action.h" #include "txt_window.h" #endif /* #ifndef TEXTSCREEN_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_button.c000066400000000000000000000051431257432200600240520ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "doomkeys.h" #include "txt_button.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" static void TXT_ButtonSizeCalc(TXT_UNCAST_ARG(button)) { TXT_CAST_ARG(txt_button_t, button); button->widget.w = strlen(button->label); button->widget.h = 1; } static void TXT_ButtonDrawer(TXT_UNCAST_ARG(button)) { TXT_CAST_ARG(txt_button_t, button); int i; int w; w = button->widget.w; TXT_SetWidgetBG(button); TXT_DrawString(button->label); for (i=strlen(button->label); i < w; ++i) { TXT_DrawString(" "); } } static void TXT_ButtonDestructor(TXT_UNCAST_ARG(button)) { TXT_CAST_ARG(txt_button_t, button); free(button->label); } static int TXT_ButtonKeyPress(TXT_UNCAST_ARG(button), int key) { TXT_CAST_ARG(txt_button_t, button); if (key == KEY_ENTER) { TXT_EmitSignal(button, "pressed"); return 1; } return 0; } static void TXT_ButtonMousePress(TXT_UNCAST_ARG(button), int x, int y, int b) { TXT_CAST_ARG(txt_button_t, button); if (b == TXT_MOUSE_LEFT) { // Equivalent to pressing enter TXT_ButtonKeyPress(button, KEY_ENTER); } } txt_widget_class_t txt_button_class = { TXT_AlwaysSelectable, TXT_ButtonSizeCalc, TXT_ButtonDrawer, TXT_ButtonKeyPress, TXT_ButtonDestructor, TXT_ButtonMousePress, NULL, }; void TXT_SetButtonLabel(txt_button_t *button, char *label) { free(button->label); button->label = strdup(label); } txt_button_t *TXT_NewButton(char *label) { txt_button_t *button; button = malloc(sizeof(txt_button_t)); TXT_InitWidget(button, &txt_button_class); button->label = strdup(label); return button; } // Button with a callback set automatically txt_button_t *TXT_NewButton2(char *label, TxtWidgetSignalFunc func, void *user_data) { txt_button_t *button; button = TXT_NewButton(label); TXT_SignalConnect(button, "pressed", func, user_data); return button; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_button.h000066400000000000000000000034461257432200600240630ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_BUTTON_H #define TXT_BUTTON_H /** * @file txt_button.h * * Button widget. */ /** * Button widget. * * A button is a widget that can be selected to perform some action. * When a button is pressed, it emits the "pressed" signal. */ typedef struct txt_button_s txt_button_t; #include "txt_widget.h" struct txt_button_s { txt_widget_t widget; char *label; }; /** * Create a new button widget. * * @param label The label to use on the new button. * @return Pointer to the new button widget. */ txt_button_t *TXT_NewButton(char *label); /** * Create a new button widget, binding the "pressed" signal to a * specified callback function. * * @param label The label to use on the new button. * @param func The callback function to invoke. * @param user_data User-specified pointer to pass to the callback. * @return Pointer to the new button widget. */ txt_button_t *TXT_NewButton2(char *label, TxtWidgetSignalFunc func, void *user_data); /** * Change the label used on a button. * * @param button The button. * @param label The new label. */ void TXT_SetButtonLabel(txt_button_t *button, char *label); #endif /* #ifndef TXT_BUTTON_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_checkbox.c000066400000000000000000000061331257432200600243250ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "doomkeys.h" #include "txt_checkbox.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" static void TXT_CheckBoxSizeCalc(TXT_UNCAST_ARG(checkbox)) { TXT_CAST_ARG(txt_checkbox_t, checkbox); // Minimum width is the string length + right-side space for padding checkbox->widget.w = strlen(checkbox->label) + 5; checkbox->widget.h = 1; } static void TXT_CheckBoxDrawer(TXT_UNCAST_ARG(checkbox)) { TXT_CAST_ARG(txt_checkbox_t, checkbox); txt_saved_colors_t colors; int i; int w; w = checkbox->widget.w; TXT_SaveColors(&colors); TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); TXT_DrawString("("); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); if ((*checkbox->variable != 0) ^ checkbox->inverted) { TXT_DrawString("\x07"); } else { TXT_DrawString(" "); } TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); TXT_DrawString(") "); TXT_RestoreColors(&colors); TXT_SetWidgetBG(checkbox); TXT_DrawString(checkbox->label); for (i=strlen(checkbox->label); i < w-5; ++i) { TXT_DrawString(" "); } } static void TXT_CheckBoxDestructor(TXT_UNCAST_ARG(checkbox)) { TXT_CAST_ARG(txt_checkbox_t, checkbox); free(checkbox->label); } static int TXT_CheckBoxKeyPress(TXT_UNCAST_ARG(checkbox), int key) { TXT_CAST_ARG(txt_checkbox_t, checkbox); if (key == KEY_ENTER || key == ' ') { *checkbox->variable = !*checkbox->variable; TXT_EmitSignal(checkbox, "changed"); return 1; } return 0; } static void TXT_CheckBoxMousePress(TXT_UNCAST_ARG(checkbox), int x, int y, int b) { TXT_CAST_ARG(txt_checkbox_t, checkbox); if (b == TXT_MOUSE_LEFT) { // Equivalent to pressing enter TXT_CheckBoxKeyPress(checkbox, KEY_ENTER); } } txt_widget_class_t txt_checkbox_class = { TXT_AlwaysSelectable, TXT_CheckBoxSizeCalc, TXT_CheckBoxDrawer, TXT_CheckBoxKeyPress, TXT_CheckBoxDestructor, TXT_CheckBoxMousePress, NULL, }; txt_checkbox_t *TXT_NewCheckBox(char *label, int *variable) { txt_checkbox_t *checkbox; checkbox = malloc(sizeof(txt_checkbox_t)); TXT_InitWidget(checkbox, &txt_checkbox_class); checkbox->label = strdup(label); checkbox->variable = variable; checkbox->inverted = 0; return checkbox; } txt_checkbox_t *TXT_NewInvertedCheckBox(char *label, int *variable) { txt_checkbox_t *result; result = TXT_NewCheckBox(label, variable); result->inverted = 1; return result; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_checkbox.h000066400000000000000000000041511257432200600243300ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_CHECKBOX_H #define TXT_CHECKBOX_H /** * @file txt_checkbox.h * * Checkbox widget. */ /** * Checkbox widget. * * A checkbox is used to control boolean values that may be either on * or off. The widget has a label that is displayed to the right of * the checkbox indicator. The widget tracks an integer variable; * if the variable is non-zero, the checkbox is checked, while if it * is zero, the checkbox is unchecked. It is also possible to * create "inverted" checkboxes where this logic is reversed. * * When a checkbox is changed, it emits the "changed" signal. */ typedef struct txt_checkbox_s txt_checkbox_t; #include "txt_widget.h" struct txt_checkbox_s { txt_widget_t widget; char *label; int *variable; int inverted; }; /** * Create a new checkbox. * * @param label The label for the new checkbox. * @param variable Pointer to the variable containing this checkbox's * value. * @return Pointer to the new checkbox. */ txt_checkbox_t *TXT_NewCheckBox(char *label, int *variable); /** * Create a new inverted checkbox. * * An inverted checkbox displays the opposite of a normal checkbox; * where it would be checked, it appears unchecked, and vice-versa. * * @param label The label for the new checkbox. * @param variable Pointer to the variable containing this checkbox's * value. * @return Pointer to the new checkbox. */ txt_checkbox_t *TXT_NewInvertedCheckBox(char *label, int *variable); #endif /* #ifndef TXT_CHECKBOX_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_desktop.c000066400000000000000000000173671257432200600242230ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "doomkeys.h" #include "txt_desktop.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_separator.h" #include "txt_window.h" #define HELP_KEY KEY_F1 #define MAXWINDOWS 128 static char *desktop_title; static txt_window_t *all_windows[MAXWINDOWS]; static int num_windows = 0; static int main_loop_running = 0; static TxtIdleCallback periodic_callback = NULL; static void *periodic_callback_data; static unsigned int periodic_callback_period; void TXT_AddDesktopWindow(txt_window_t *win) { // Previously-top window loses focus: if (num_windows > 0) { TXT_SetWindowFocus(all_windows[num_windows - 1], 0); } all_windows[num_windows] = win; ++num_windows; // New window gains focus: TXT_SetWindowFocus(win, 1); } void TXT_RemoveDesktopWindow(txt_window_t *win) { int from, to; // Window must lose focus if it's being removed: TXT_SetWindowFocus(win, 0); for (from=0, to=0; from 0) { TXT_SetWindowFocus(all_windows[num_windows - 1], 1); } } txt_window_t *TXT_GetActiveWindow(void) { if (num_windows == 0) { return NULL; } return all_windows[num_windows - 1]; } int TXT_RaiseWindow(txt_window_t *window) { int i; for (i = 0; i < num_windows - 1; ++i) { if (all_windows[i] == window) { all_windows[i] = all_windows[i + 1]; all_windows[i + 1] = window; if (i == num_windows - 2) { TXT_SetWindowFocus(all_windows[i], 0); TXT_SetWindowFocus(window, 1); } return 1; } } // Window not in the list, or at the end of the list (top) already. return 0; } int TXT_LowerWindow(txt_window_t *window) { int i; for (i = 0; i < num_windows - 1; ++i) { if (all_windows[i + 1] == window) { all_windows[i + 1] = all_windows[i]; all_windows[i] = window; if (i == num_windows - 2) { TXT_SetWindowFocus(window, 0); TXT_SetWindowFocus(all_windows[i + 1], 1); } return 1; } } // Window not in the list, or at the start of the list (bottom) already. return 0; } static void DrawDesktopBackground(const char *title) { int i; unsigned char *screendata; unsigned char *p; screendata = TXT_GetScreenData(); // Fill the screen with gradient characters p = screendata; for (i=0; i= TXT_SCREEN_W - 9) { fgcolor = TXT_COLOR_GREY; TXT_BGColor(TXT_COLOR_BLACK, 0); } else { fgcolor = TXT_COLOR_BLACK; TXT_BGColor(TXT_COLOR_GREY, 0); } TXT_GotoXY(TXT_SCREEN_W - 9, 0); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_DrawString(" "); TXT_DrawString(keybuf); TXT_FGColor(fgcolor); TXT_DrawString("=Help "); } void TXT_SetDesktopTitle(char *title) { free(desktop_title); desktop_title = strdup(title); TXT_SetWindowTitle(title); } void TXT_DrawDesktop(void) { txt_window_t *active_window; const char *title; int i; TXT_InitClipArea(); if (desktop_title == NULL) title = ""; else title = desktop_title; DrawDesktopBackground(title); active_window = TXT_GetActiveWindow(); if (active_window != NULL && active_window->help_url != NULL) { DrawHelpIndicator(); } for (i=0; i= TXT_SCREEN_W - 9) { DesktopInputEvent(HELP_KEY); } break; case HELP_KEY: active_window = TXT_GetActiveWindow(); if (active_window != NULL) { TXT_OpenWindowHelpURL(active_window); } break; default: break; } } void TXT_DispatchEvents(void) { txt_window_t *active_window; int c; while ((c = TXT_GetChar()) > 0) { active_window = TXT_GetActiveWindow(); if (active_window != NULL && !TXT_WindowKeyPress(active_window, c)) { DesktopInputEvent(c); } } } void TXT_ExitMainLoop(void) { main_loop_running = 0; } void TXT_DrawASCIITable(void) { unsigned char *screendata; char buf[10]; int x, y; int n; screendata = TXT_GetScreenData(); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_BGColor(TXT_COLOR_BLACK, 0); for (y=0; y<16; ++y) { for (x=0; x<16; ++x) { n = y * 16 + x; TXT_GotoXY(x * 5, y); TXT_snprintf(buf, sizeof(buf), "%02x ", n); TXT_Puts(buf); // Write the character directly to the screen memory buffer: screendata[(y * TXT_SCREEN_W + x * 5 + 3) * 2] = n; } } TXT_UpdateScreen(); } void TXT_SetPeriodicCallback(TxtIdleCallback callback, void *user_data, unsigned int period) { periodic_callback = callback; periodic_callback_data = user_data; periodic_callback_period = period; } void TXT_GUIMainLoop(void) { main_loop_running = 1; while (main_loop_running) { TXT_DispatchEvents(); // After the last window is closed, exit the loop if (num_windows <= 0) { TXT_ExitMainLoop(); continue; } TXT_DrawDesktop(); // TXT_DrawASCIITable(); if (periodic_callback == NULL) { TXT_Sleep(0); } else { TXT_Sleep(periodic_callback_period); periodic_callback(periodic_callback_data); } } } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_desktop.h000066400000000000000000000060731257432200600242200ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_DESKTOP_H #define TXT_DESKTOP_H /** * @file txt_desktop.h * * Textscreen desktop. */ #include "txt_window.h" typedef void (*TxtIdleCallback)(void *user_data); void TXT_AddDesktopWindow(txt_window_t *win); void TXT_RemoveDesktopWindow(txt_window_t *win); void TXT_DrawDesktop(void); void TXT_DispatchEvents(void); void TXT_DrawWindow(txt_window_t *window); void TXT_SetWindowFocus(txt_window_t *window, int focused); int TXT_WindowKeyPress(txt_window_t *window, int c); /** * Set the title displayed at the top of the screen. * * @param title The title to display. */ void TXT_SetDesktopTitle(char *title); /** * Exit the currently-running main loop and return from the * @ref TXT_GUIMainLoop function. */ void TXT_ExitMainLoop(void); /** * Start the main event loop. At least one window must have been * opened prior to running this function. When no windows are left * open, the event loop exits. * * It is possible to trigger an exit from this function using the * @ref TXT_ExitMainLoop function. */ void TXT_GUIMainLoop(void); /** * Get the top window on the desktop that is currently receiving * inputs. * * @return The active window, or NULL if no windows are present. */ txt_window_t *TXT_GetActiveWindow(void); /** * Set a callback function to be invoked periodically by the main * loop code. * * @param callback The callback to invoke, or NULL to cancel * an existing callback. * @param user_data Extra data to pass to the callback. * @param period Maximum time between invoking each callback. * eg. a value of 200 will cause the callback * to be invoked at least once every 200ms. */ void TXT_SetPeriodicCallback(TxtIdleCallback callback, void *user_data, unsigned int period); /** * Raise the z-position of the given window relative to other windows. * * @param window The window to raise. * @return Non-zero if the window was raised successfully, * or zero if the window could not be raised further. */ int TXT_RaiseWindow(txt_window_t *window); /** * Lower the z-position of the given window relative to other windows. * * @param window The window to make inactive. * @return Non-zero if the window was lowered successfully, * or zero if the window could not be lowered further. */ int TXT_LowerWindow(txt_window_t *window); #endif /* #ifndef TXT_DESKTOP_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_dropdown.c000066400000000000000000000155511257432200600243770ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "doomkeys.h" #include "txt_button.h" #include "txt_dropdown.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" typedef struct { txt_window_t *window; txt_dropdown_list_t *list; int item; } callback_data_t; // Check if the selected value for a list is valid static int ValidSelection(txt_dropdown_list_t *list) { return *list->variable >= 0 && *list->variable < list->num_values; } // Calculate the Y position for the selector window static int SelectorWindowY(txt_dropdown_list_t *list) { int result; if (ValidSelection(list)) { result = list->widget.y - 1 - *list->variable; } else { result = list->widget.y - 1 - (list->num_values / 2); } // Keep dropdown inside the screen. if (result < 1) { result = 1; } else if (result + list->num_values > (TXT_SCREEN_H - 3)) { result = TXT_SCREEN_H - list->num_values - 3; } return result; } // Called when a button in the selector window is pressed static void ItemSelected(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(callback_data)) { TXT_CAST_ARG(callback_data_t, callback_data); // Set the variable *callback_data->list->variable = callback_data->item; TXT_EmitSignal(callback_data->list, "changed"); // Close the window TXT_CloseWindow(callback_data->window); } // Free callback data when the window is closed static void FreeCallbackData(TXT_UNCAST_ARG(list), TXT_UNCAST_ARG(callback_data)) { TXT_CAST_ARG(callback_data_t, callback_data); free(callback_data); } // Catch presses of escape and close the window. static int SelectorWindowListener(txt_window_t *window, int key, void *user_data) { if (key == KEY_ESCAPE) { TXT_CloseWindow(window); return 1; } return 0; } static int SelectorMouseListener(txt_window_t *window, int x, int y, int b, void *unused) { txt_widget_t *win; win = (txt_widget_t *) window; if (x < win->x || x > win->x + win->w || y < win->y || y > win->y + win->h) { TXT_CloseWindow(window); return 1; } return 0; } // Open the dropdown list window to select an item static void OpenSelectorWindow(txt_dropdown_list_t *list) { txt_window_t *window; int i; // Open a simple window with no title bar or action buttons. window = TXT_NewWindow(NULL); TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, NULL); TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); // Position the window so that the currently selected item appears // over the top of the list widget. TXT_SetWindowPosition(window, TXT_HORIZ_LEFT, TXT_VERT_TOP, list->widget.x - 2, SelectorWindowY(list)); // Add a button to the window for each option in the list. for (i=0; inum_values; ++i) { txt_button_t *button; callback_data_t *data; button = TXT_NewButton(list->values[i]); TXT_AddWidget(window, button); // Callback struct data = malloc(sizeof(callback_data_t)); data->list = list; data->window = window; data->item = i; // When the button is pressed, invoke the button press callback TXT_SignalConnect(button, "pressed", ItemSelected, data); // When the window is closed, free back the callback struct TXT_SignalConnect(window, "closed", FreeCallbackData, data); // Is this the currently-selected value? If so, select the button // in the window as the default. if (i == *list->variable) { TXT_SelectWidget(window, button); } } // Catch presses of escape in this window and close it. TXT_SetKeyListener(window, SelectorWindowListener, NULL); TXT_SetMouseListener(window, SelectorMouseListener, NULL); } static int DropdownListWidth(txt_dropdown_list_t *list) { int i; int result; // Find the maximum string width result = 0; for (i=0; inum_values; ++i) { int w = strlen(list->values[i]); if (w > result) { result = w; } } return result; } static void TXT_DropdownListSizeCalc(TXT_UNCAST_ARG(list)) { TXT_CAST_ARG(txt_dropdown_list_t, list); list->widget.w = DropdownListWidth(list); list->widget.h = 1; } static void TXT_DropdownListDrawer(TXT_UNCAST_ARG(list)) { TXT_CAST_ARG(txt_dropdown_list_t, list); unsigned int i; const char *str; // Set bg/fg text colors. TXT_SetWidgetBG(list); // Select a string to draw from the list, if the current value is // in range. Otherwise fall back to a default. if (ValidSelection(list)) { str = list->values[*list->variable]; } else { str = "???"; } // Draw the string and fill to the end with spaces TXT_DrawString(str); for (i=strlen(str); iwidget.w; ++i) { TXT_DrawString(" "); } } static void TXT_DropdownListDestructor(TXT_UNCAST_ARG(list)) { } static int TXT_DropdownListKeyPress(TXT_UNCAST_ARG(list), int key) { TXT_CAST_ARG(txt_dropdown_list_t, list); if (key == KEY_ENTER) { OpenSelectorWindow(list); return 1; } return 0; } static void TXT_DropdownListMousePress(TXT_UNCAST_ARG(list), int x, int y, int b) { TXT_CAST_ARG(txt_dropdown_list_t, list); // Left mouse click does the same as selecting and pressing enter if (b == TXT_MOUSE_LEFT) { TXT_DropdownListKeyPress(list, KEY_ENTER); } } txt_widget_class_t txt_dropdown_list_class = { TXT_AlwaysSelectable, TXT_DropdownListSizeCalc, TXT_DropdownListDrawer, TXT_DropdownListKeyPress, TXT_DropdownListDestructor, TXT_DropdownListMousePress, NULL, }; txt_dropdown_list_t *TXT_NewDropdownList(int *variable, char **values, int num_values) { txt_dropdown_list_t *list; list = malloc(sizeof(txt_dropdown_list_t)); TXT_InitWidget(list, &txt_dropdown_list_class); list->variable = variable; list->values = values; list->num_values = num_values; return list; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_dropdown.h000066400000000000000000000034461257432200600244040ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_DROPDOWN_H #define TXT_DROPDOWN_H /** * @file txt_dropdown.h * * Dropdown list widget. */ /** * Dropdown list widget. * * A dropdown list allows the user to select from a list of values, * which appears when the list is selected. * * When the value of a dropdown list is changed, the "changed" signal * is emitted. */ typedef struct txt_dropdown_list_s txt_dropdown_list_t; #include "txt_widget.h" // // Drop-down list box. // struct txt_dropdown_list_s { txt_widget_t widget; int *variable; char **values; int num_values; }; /** * Create a new dropdown list widget. * * The parameters specify a list of string labels, and a pointer to an * integer variable. The variable contains the current "value" of the * list, as an index within the list of labels. * * @param variable Pointer to the variable containing the * list's value. * @param values Pointer to an array of strings containing * the labels to use for the list. * @param num_values The number of variables in the list. */ txt_dropdown_list_t *TXT_NewDropdownList(int *variable, char **values, int num_values); #endif /* #ifndef TXT_DROPDOWN_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_fileselect.c000066400000000000000000000376251257432200600246700ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Routines for selecting files. // #include #include #include #include "doomkeys.h" #include "txt_fileselect.h" #include "txt_inputbox.h" #include "txt_main.h" #include "txt_widget.h" struct txt_fileselect_s { txt_widget_t widget; txt_inputbox_t *inputbox; int size; char *prompt; char **extensions; }; // Dummy value to select a directory. char *TXT_DIRECTORY[] = { "__directory__", NULL }; #ifndef _WIN32 #include #include #include #include static char *ExecReadOutput(char **argv) { char *result; int completed; int pid, status, result_len; int pipefd[2]; if (pipe(pipefd) != 0) { return NULL; } pid = fork(); if (pid == 0) { dup2(pipefd[1], fileno(stdout)); execv(argv[0], argv); exit(-1); } fcntl(pipefd[0], F_SETFL, O_NONBLOCK); // Read program output into 'result' string. // Wait until the program has completed and (if it was successful) // a full line has been read. result = NULL; result_len = 0; completed = 0; while (!completed || (status == 0 && (result == NULL || strchr(result, '\n') == NULL))) { char buf[64]; int bytes; if (!completed && waitpid(pid, &status, WNOHANG) != 0) { completed = 1; } bytes = read(pipefd[0], buf, sizeof(buf)); if (bytes < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { status = -1; break; } } else { result = realloc(result, result_len + bytes + 1); memcpy(result + result_len, buf, bytes); result_len += bytes; result[result_len] = '\0'; } usleep(100 * 1000); TXT_Sleep(1); TXT_UpdateScreen(); } close(pipefd[0]); close(pipefd[1]); // Must have a success exit code. if (WEXITSTATUS(status) != 0) { free(result); result = NULL; } // Strip off newline from the end. if (result != NULL && result[result_len - 1] == '\n') { result[result_len - 1] = '\0'; } return result; } #endif // This is currently disabled on Windows because it doesn't work. // Current issues: // * On Windows Vista+ the mouse cursor freezes when the dialog is // opened. This is probably some conflict with SDL (might be // resolved by opening the dialog in a separate thread so that // TXT_UpdateScreen can be run in the background). // * On Windows XP the program exits/crashes when the dialog is // closed. #if defined(_WIN32) int TXT_CanSelectFiles(void) { return 0; } char *TXT_SelectFile(char *window_title, char **extensions) { return NULL; } #elif defined(xxxdisabled_WIN32) // Windows code. Use comdlg32 to pop up a dialog box. #include #include static BOOL (*MyGetOpenFileName)(LPOPENFILENAME) = NULL; static LPITEMIDLIST (*MySHBrowseForFolder)(LPBROWSEINFO) = NULL; static BOOL (*MySHGetPathFromIDList)(LPITEMIDLIST, LPTSTR) = NULL; // Load library functions from DLL files. static int LoadDLLs(void) { HMODULE comdlg32 = LoadLibraryW(L"comdlg32.dll"); HMODULE shell32 = LoadLibraryW(L"shell32.dll"); if (comdlg32 == NULL || shell32 == NULL) { return 0; } MyGetOpenFileName = (void *) GetProcAddress(comdlg32, "GetOpenFileNameA"); MySHBrowseForFolder = (void *) GetProcAddress(shell32, "SHBrowseForFolder"); MySHGetPathFromIDList = (void *) GetProcAddress(shell32, "SHGetPathFromIDList"); return MyGetOpenFileName != NULL && MySHBrowseForFolder != NULL && MySHGetPathFromIDList != NULL; } static int InitLibraries(void) { static int initted = 0, success = 0; if (!initted) { success = LoadDLLs(); initted = 1; } return success; } // Generate the "filter" string from the list of extensions. static char *GenerateFilterString(char **extensions) { unsigned int result_len = 1; unsigned int i; char *result, *out; size_t out_len, offset; if (extensions == NULL) { return NULL; } for (i = 0; extensions[i] != NULL; ++i) { result_len += 16 + strlen(extensions[i]) * 3; } result = malloc(result_len); out = result; out_len = result_len; for (i = 0; extensions[i] != NULL; ++i) { // .wad files (*.wad)\0 offset = TXT_snprintf(out, out_len, "%s files (*.%s)", extensions[i], extensions[i]); out += offset + 1; out_len -= offset + 1; // *.wad\0 offset = TXT_snprintf(out, out_len, "*.%s", extensions[i]); out_len += offset + 1; out_len -= offset + 1; } *out = '\0'; return result; } int TXT_CanSelectFiles(void) { return InitLibraries(); } static char *SelectDirectory(char *window_title) { LPITEMIDLIST pidl; BROWSEINFO bi; char selected[MAX_PATH] = ""; char *result; ZeroMemory(&bi, sizeof(bi)); bi.hwndOwner = NULL; bi.lpszTitle = window_title; bi.pszDisplayName = selected; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; pidl = MySHBrowseForFolder(&bi); result = NULL; if (pidl != NULL) { if (MySHGetPathFromIDList(pidl, selected)) { result = strdup(selected); } // TODO: Free pidl } return result; } char *TXT_SelectFile(char *window_title, char **extensions) { OPENFILENAME fm; char selected[MAX_PATH] = ""; char *filter_string, *result; if (!InitLibraries()) { return NULL; } if (extensions == TXT_DIRECTORY) { return SelectDirectory(window_title); } filter_string = GenerateFilterString(extensions); ZeroMemory(&fm, sizeof(fm)); fm.lStructSize = sizeof(OPENFILENAME); fm.hwndOwner = NULL; fm.lpstrTitle = window_title; fm.lpstrFilter = filter_string; fm.lpstrFile = selected; fm.nMaxFile = MAX_PATH; fm.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; fm.lpstrDefExt = ""; if (!MyGetOpenFileName(&fm)) { result = NULL; } else { result = strdup(selected); } free(filter_string); return result; } #elif defined(__MACOSX__) // Mac OS X code. Popping up a dialog requires Objective C/Cocoa // but we can get away with using AppleScript which avoids adding // an Objective C dependency. This is rather silly. // Printf format string for the "wrapper" portion of the AppleScript: #define APPLESCRIPT_WRAPPER \ "tell application (path to frontmost application as text)\n" \ " set theFile to (%s)\n" \ " copy POSIX path of theFile to stdout\n" \ "end tell\n" static char *EscapedString(char *s) { char *result; char *in, *out; result = malloc(strlen(s) + 3); out = result; *out++ = '\"'; for (in = s; *in != '\0'; ++in) { if (*in == '\"' || *in == '\\') { *out++ = '\\'; } *out++ = *in; } *out++ = '\"'; *out = '\0'; return result; } // Build list of extensions, like: {"wad","lmp","txt"} static char *ExtensionsList(char **extensions) { char *result, *escaped; unsigned int result_len; unsigned int i; if (extensions == NULL) { return NULL; } result_len = 3; for (i = 0; extensions[i] != NULL; ++i) { result_len += 5 + strlen(extensions[i]) * 2; } result = malloc(result_len); TXT_StringCopy(result, "{", result_len); for (i = 0; extensions[i] != NULL; ++i) { escaped = EscapedString(extensions[i]); TXT_StringConcat(result, escaped, result_len); free(escaped); if (extensions[i + 1] != NULL) TXT_StringConcat(result, ",", result_len); } TXT_StringConcat(result, "}", result_len); return result; } static char *GenerateSelector(char *window_title, char **extensions) { char *chooser, *ext_list, *result; unsigned int result_len; result_len = 64; if (extensions == TXT_DIRECTORY) { chooser = "choose folder"; ext_list = NULL; } else { chooser = "choose file"; ext_list = ExtensionsList(extensions); } // Calculate size. if (window_title != NULL) { window_title = EscapedString(window_title); result_len += strlen(window_title); } if (ext_list != NULL) { result_len += strlen(ext_list); } result = malloc(result_len); TXT_StringCopy(result, chooser, result_len); if (window_title != NULL) { TXT_StringConcat(result, " with prompt ", result_len); TXT_StringConcat(result, window_title, result_len); free(window_title); } if (ext_list != NULL) { TXT_StringConcat(result, "of type ", result_len); TXT_StringConcat(result, ext_list, result_len); free(ext_list); } return result; } static char *GenerateAppleScript(char *window_title, char **extensions) { char *selector, *result; size_t result_len; selector = GenerateSelector(window_title, extensions); result_len = strlen(APPLESCRIPT_WRAPPER) + strlen(selector); result = malloc(result_len); TXT_snprintf(result, result_len, APPLESCRIPT_WRAPPER, selector); free(selector); return result; } int TXT_CanSelectFiles(void) { return 1; } char *TXT_SelectFile(char *window_title, char **extensions) { char *argv[4]; char *result, *applescript; applescript = GenerateAppleScript(window_title, extensions); argv[0] = "/usr/bin/osascript"; argv[1] = "-e"; argv[2] = applescript; argv[3] = NULL; result = ExecReadOutput(argv); free(applescript); return result; } #else // Linux version: invoke the Zenity command line program to pop up a // dialog box. This avoids adding Gtk+ as a compile dependency. #define ZENITY_BINARY "/usr/bin/zenity" static unsigned int NumExtensions(char **extensions) { unsigned int result = 0; if (extensions != NULL) { for (result = 0; extensions[result] != NULL; ++result); } return result; } static int ZenityAvailable(void) { return system(ZENITY_BINARY " --help >/dev/null 2>&1") == 0; } int TXT_CanSelectFiles(void) { return ZenityAvailable(); } char *TXT_SelectFile(char *window_title, char **extensions) { unsigned int i; size_t len; char *result; char **argv; int argc; if (!ZenityAvailable()) { return NULL; } argv = calloc(4 + NumExtensions(extensions), sizeof(char *)); argv[0] = ZENITY_BINARY; argv[1] = "--file-selection"; argc = 2; if (window_title != NULL) { len = 10 + strlen(window_title); argv[argc] = malloc(len); TXT_snprintf(argv[argc], len, "--title=%s", window_title); ++argc; } if (extensions == TXT_DIRECTORY) { argv[argc] = strdup("--directory"); ++argc; } else if (extensions != NULL) { for (i = 0; extensions[i] != NULL; ++i) { len = 30 + strlen(extensions[i]) * 2; argv[argc] = malloc(len); TXT_snprintf(argv[argc], len, "--file-filter=.%s | *.%s", extensions[i], extensions[i]); ++argc; } } argv[argc] = NULL; result = ExecReadOutput(argv); for (i = 2; i < argc; ++i) { free(argv[i]); } free(argv); return result; } #endif static void TXT_FileSelectSizeCalc(TXT_UNCAST_ARG(fileselect)) { TXT_CAST_ARG(txt_fileselect_t, fileselect); // Calculate widget size, but override the width to always // be the configured size. TXT_CalcWidgetSize(fileselect->inputbox); fileselect->widget.w = fileselect->size; fileselect->widget.h = fileselect->inputbox->widget.h; } static void TXT_FileSelectDrawer(TXT_UNCAST_ARG(fileselect)) { TXT_CAST_ARG(txt_fileselect_t, fileselect); // Input box widget inherits all the properties of the // file selector. fileselect->inputbox->widget.x = fileselect->widget.x; fileselect->inputbox->widget.y = fileselect->widget.y; fileselect->inputbox->widget.w = fileselect->widget.w; fileselect->inputbox->widget.h = fileselect->widget.h; TXT_DrawWidget(fileselect->inputbox); } static void TXT_FileSelectDestructor(TXT_UNCAST_ARG(fileselect)) { TXT_CAST_ARG(txt_fileselect_t, fileselect); TXT_DestroyWidget(fileselect->inputbox); } static int DoSelectFile(txt_fileselect_t *fileselect) { char *path; char **var; if (TXT_CanSelectFiles()) { path = TXT_SelectFile(fileselect->prompt, fileselect->extensions); // Update inputbox variable. // If cancel was pressed (ie. NULL was returned by TXT_SelectFile) // then reset to empty string, not NULL). if (path == NULL) { path = strdup(""); } var = fileselect->inputbox->value; free(*var); *var = path; return 1; } return 0; } static int TXT_FileSelectKeyPress(TXT_UNCAST_ARG(fileselect), int key) { TXT_CAST_ARG(txt_fileselect_t, fileselect); // When the enter key is pressed, pop up a file selection dialog, // if file selectors work. Allow holding down 'alt' to override // use of the native file selector, so the user can just type a path. if (!fileselect->inputbox->editing && !TXT_GetModifierState(TXT_MOD_ALT) && key == KEY_ENTER) { if (DoSelectFile(fileselect)) { return 1; } } return TXT_WidgetKeyPress(fileselect->inputbox, key); } static void TXT_FileSelectMousePress(TXT_UNCAST_ARG(fileselect), int x, int y, int b) { TXT_CAST_ARG(txt_fileselect_t, fileselect); if (!fileselect->inputbox->editing && !TXT_GetModifierState(TXT_MOD_ALT) && b == TXT_MOUSE_LEFT) { if (DoSelectFile(fileselect)) { return; } } TXT_WidgetMousePress(fileselect->inputbox, x, y, b); } static void TXT_FileSelectFocused(TXT_UNCAST_ARG(fileselect), int focused) { TXT_CAST_ARG(txt_fileselect_t, fileselect); TXT_SetWidgetFocus(fileselect->inputbox, focused); } txt_widget_class_t txt_fileselect_class = { TXT_AlwaysSelectable, TXT_FileSelectSizeCalc, TXT_FileSelectDrawer, TXT_FileSelectKeyPress, TXT_FileSelectDestructor, TXT_FileSelectMousePress, NULL, TXT_FileSelectFocused, }; // If the (inner) inputbox widget is changed, emit a change to the // outer (fileselect) widget. static void InputBoxChanged(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(fileselect)) { TXT_CAST_ARG(txt_fileselect_t, fileselect); TXT_EmitSignal(&fileselect->widget, "changed"); } txt_fileselect_t *TXT_NewFileSelector(char **variable, int size, char *prompt, char **extensions) { txt_fileselect_t *fileselect; fileselect = malloc(sizeof(txt_fileselect_t)); TXT_InitWidget(fileselect, &txt_fileselect_class); fileselect->inputbox = TXT_NewInputBox(variable, 1024); fileselect->inputbox->widget.parent = &fileselect->widget; fileselect->size = size; fileselect->prompt = prompt; fileselect->extensions = extensions; TXT_SignalConnect(fileselect->inputbox, "changed", InputBoxChanged, fileselect); return fileselect; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_fileselect.h000066400000000000000000000044531257432200600246660ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Routines for selecting files, and the txt_fileselect_t widget. // #ifndef TXT_FILESELECT_H #define TXT_FILESELECT_H /** * @file txt_fileselect.h * * File selection widget. */ /** * File selection widget. * * A file selection widget resembles an input box (@ref txt_inputbox_t) * but opens a file selector dialog box when clicked. */ typedef struct txt_fileselect_s txt_fileselect_t; /** * Returns non-zero if a native file selector is available on this * platform. */ int TXT_CanSelectFiles(void); /** * Open a native file selector to select a file. * * @param prompt Pointer to a string containing a prompt to display * in the window. * @param extensions NULL-terminated list of filename extensions for * files that can be selected, or @ref TXT_DIRECTORY * to select directories. */ char *TXT_SelectFile(char *prompt, char **extensions); /** * Create a new txt_fileselect_t widget. * * @param variable Pointer to a char * variable in which the selected * file should be stored. * @param size Width of the file selector widget in characters. * @param prompt Pointer to a string containing a prompt to display * in the file selection window. * @param extensions NULL-terminated list of filename extensions that * can be used for this widget, or @ref TXT_DIRECTORY * to select directories. */ txt_fileselect_t *TXT_NewFileSelector(char **variable, int size, char *prompt, char **extensions); /** * Special value to use for 'extensions' that selects a directory * instead of a file. */ extern char *TXT_DIRECTORY[]; #endif /* #ifndef TXT_FILESELECT_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_font.h000066400000000000000000000636271257432200600235250ustar00rootroot00000000000000// // Copyright (C) 2005-2014 Simon Howard // Copyright (C) 2002-2004 The DOSBox Team // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // VGA font data // Font data is from the DOSBox project (http://dosbox.sourceforge.net/) // #ifndef __FONT_H__ #define __FONT_H__ static unsigned char main_font_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static txt_font_t main_font = { main_font_data, 8, // width 16 // height }; #endif /* __FONT_H__ */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_gui.c000066400000000000000000000255601257432200600233300ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_utf8.h" typedef struct txt_cliparea_s txt_cliparea_t; // Mapping table that converts from the Extended ASCII codes in the // CP437 codepage to Unicode character numbers. static const uint16_t cp437_unicode[] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, // 80-8f 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, // 90-9f 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, // a0-af 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, // b0-bf 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, // c0-cf 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, // d0-df 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, // e0-ef 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, // f0-ff 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0, }; struct txt_cliparea_s { int x1, x2; int y1, y2; txt_cliparea_t *next; }; // Array of border characters for drawing windows. The array looks like this: // // +-++ // | || // +-++ // +-++ static const int borders[4][4] = { {0xda, 0xc4, 0xc2, 0xbf}, {0xb3, ' ', 0xb3, 0xb3}, {0xc3, 0xc4, 0xc5, 0xb4}, {0xc0, 0xc4, 0xc1, 0xd9}, }; static txt_cliparea_t *cliparea = NULL; #define VALID_X(x) ((x) >= cliparea->x1 && (x) < cliparea->x2) #define VALID_Y(y) ((y) >= cliparea->y1 && (y) < cliparea->y2) void TXT_DrawDesktopBackground(const char *title) { int i; unsigned char *screendata; unsigned char *p; screendata = TXT_GetScreenData(); // Fill the screen with gradient characters p = screendata; for (i=0; i 0) { cursor_x += (cursor * (w - 3)) / range; } if (cursor_x > x + w - 2) { cursor_x = x + w - 2; } for (x1=x+1; x1 y + h - 2) { cursor_y = y + h - 2; } if (range > 0) { cursor_y += (cursor * (h - 3)) / range; } for (y1=y+1; y1x1 = 0; cliparea->x2 = TXT_SCREEN_W; cliparea->y1 = 0; cliparea->y2 = TXT_SCREEN_H; cliparea->next = NULL; } } void TXT_PushClipArea(int x1, int x2, int y1, int y2) { txt_cliparea_t *newarea; newarea = malloc(sizeof(txt_cliparea_t)); // Set the new clip area to the intersection of the old // area and the new one. newarea->x1 = cliparea->x1; newarea->x2 = cliparea->x2; newarea->y1 = cliparea->y1; newarea->y2 = cliparea->y2; if (x1 > newarea->x1) newarea->x1 = x1; if (x2 < newarea->x2) newarea->x2 = x2; if (y1 > newarea->y1) newarea->y1 = y1; if (y2 < newarea->y2) newarea->y2 = y2; #if 0 printf("New scrollable area: %i,%i-%i,%i\n", x1, y1, x2, y2); #endif // Hook into the list newarea->next = cliparea; cliparea = newarea; } void TXT_PopClipArea(void) { txt_cliparea_t *next_cliparea; // Never pop the last entry if (cliparea->next == NULL) return; // Unlink the last entry and delete next_cliparea = cliparea->next; free(cliparea); cliparea = next_cliparea; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_gui.h000066400000000000000000000025341257432200600233310ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Text mode emulation in SDL // #ifndef TXT_GUI_H #define TXT_GUI_H #define TXT_INACTIVE_WINDOW_BACKGROUND TXT_COLOR_BLACK #define TXT_ACTIVE_WINDOW_BACKGROUND TXT_COLOR_BLUE #define TXT_HOVER_BACKGROUND TXT_COLOR_CYAN void TXT_DrawDesktopBackground(const char *title); void TXT_DrawWindowFrame(const char *title, int x, int y, int w, int h); void TXT_DrawSeparator(int x, int y, int w); void TXT_DrawString(const char *s); void TXT_DrawUTF8String(const char *s); int TXT_CanDrawCharacter(unsigned int c); void TXT_DrawHorizScrollbar(int x, int y, int w, int cursor, int range); void TXT_DrawVertScrollbar(int x, int y, int h, int cursor, int range); void TXT_InitClipArea(void); void TXT_PushClipArea(int x1, int x2, int y1, int y2); void TXT_PopClipArea(void); #endif /* #ifndef TXT_GUI_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_inputbox.c000066400000000000000000000171471257432200600244160ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include #include "doomkeys.h" #include "txt_inputbox.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_utf8.h" #include "txt_window.h" extern txt_widget_class_t txt_inputbox_class; extern txt_widget_class_t txt_int_inputbox_class; static void SetBufferFromValue(txt_inputbox_t *inputbox) { if (inputbox->widget.widget_class == &txt_inputbox_class) { char **value = (char **) inputbox->value; if (*value != NULL) { TXT_StringCopy(inputbox->buffer, *value, inputbox->size); } else { TXT_StringCopy(inputbox->buffer, "", inputbox->buffer_len); } } else if (inputbox->widget.widget_class == &txt_int_inputbox_class) { int *value = (int *) inputbox->value; TXT_snprintf(inputbox->buffer, inputbox->buffer_len, "%i", *value); } } static void StartEditing(txt_inputbox_t *inputbox) { // Integer input boxes start from an empty buffer: if (inputbox->widget.widget_class == &txt_int_inputbox_class) { TXT_StringCopy(inputbox->buffer, "", inputbox->buffer_len); } else { SetBufferFromValue(inputbox); } inputbox->editing = 1; } static void FinishEditing(txt_inputbox_t *inputbox) { if (!inputbox->editing) { return; } // Save the new value back to the variable. if (inputbox->widget.widget_class == &txt_inputbox_class) { free(*((char **)inputbox->value)); *((char **) inputbox->value) = strdup(inputbox->buffer); } else if (inputbox->widget.widget_class == &txt_int_inputbox_class) { *((int *) inputbox->value) = atoi(inputbox->buffer); } TXT_EmitSignal(&inputbox->widget, "changed"); inputbox->editing = 0; } static void TXT_InputBoxSizeCalc(TXT_UNCAST_ARG(inputbox)) { TXT_CAST_ARG(txt_inputbox_t, inputbox); // Enough space for the box + cursor inputbox->widget.w = inputbox->size + 1; inputbox->widget.h = 1; } static void TXT_InputBoxDrawer(TXT_UNCAST_ARG(inputbox)) { TXT_CAST_ARG(txt_inputbox_t, inputbox); int focused; int i; int chars; int w; focused = inputbox->widget.focused; w = inputbox->widget.w; // Select the background color based on whether we are currently // editing, and if not, whether the widget is focused. if (inputbox->editing && focused) { TXT_BGColor(TXT_COLOR_BLACK, 0); } else { TXT_SetWidgetBG(inputbox); } if (!inputbox->editing) { // If not editing, use the current value from inputbox->value. SetBufferFromValue(inputbox); } // If string size exceeds the widget's width, show only the end. if (TXT_UTF8_Strlen(inputbox->buffer) > w - 1) { TXT_DrawString("\xae"); TXT_DrawUTF8String( TXT_UTF8_SkipChars(inputbox->buffer, TXT_UTF8_Strlen(inputbox->buffer) - w + 2)); chars = w - 1; } else { TXT_DrawUTF8String(inputbox->buffer); chars = TXT_UTF8_Strlen(inputbox->buffer); } if (chars < w && inputbox->editing && focused) { TXT_BGColor(TXT_COLOR_BLACK, 1); TXT_DrawString("_"); ++chars; } for (i=chars; i < w; ++i) { TXT_DrawString(" "); } } static void TXT_InputBoxDestructor(TXT_UNCAST_ARG(inputbox)) { TXT_CAST_ARG(txt_inputbox_t, inputbox); free(inputbox->buffer); } static void Backspace(txt_inputbox_t *inputbox) { unsigned int len; char *p; len = TXT_UTF8_Strlen(inputbox->buffer); if (len > 0) { p = TXT_UTF8_SkipChars(inputbox->buffer, len - 1); *p = '\0'; } } static void AddCharacter(txt_inputbox_t *inputbox, int key) { char *end, *p; if (TXT_UTF8_Strlen(inputbox->buffer) < inputbox->size) { // Add character to the buffer end = inputbox->buffer + strlen(inputbox->buffer); p = TXT_EncodeUTF8(end, key); *p = '\0'; } } static int TXT_InputBoxKeyPress(TXT_UNCAST_ARG(inputbox), int key) { TXT_CAST_ARG(txt_inputbox_t, inputbox); unsigned int c; if (!inputbox->editing) { if (key == KEY_ENTER) { StartEditing(inputbox); return 1; } // Backspace or delete erases the contents of the box. if ((key == KEY_DEL || key == KEY_BACKSPACE) && inputbox->widget.widget_class == &txt_inputbox_class) { free(*((char **)inputbox->value)); *((char **) inputbox->value) = strdup(""); } return 0; } if (key == KEY_ENTER) { FinishEditing(inputbox); } if (key == KEY_ESCAPE) { inputbox->editing = 0; } if (key == KEY_BACKSPACE) { Backspace(inputbox); } c = TXT_KEY_TO_UNICODE(key); // Add character to the buffer, but only if it's a printable character // that we can represent on the screen. if (isprint(c) || (c >= 128 && TXT_CanDrawCharacter(c))) { AddCharacter(inputbox, c); } return 1; } static void TXT_InputBoxMousePress(TXT_UNCAST_ARG(inputbox), int x, int y, int b) { TXT_CAST_ARG(txt_inputbox_t, inputbox); if (b == TXT_MOUSE_LEFT) { // Make mouse clicks start editing the box if (!inputbox->editing) { // Send a simulated keypress to start editing TXT_WidgetKeyPress(inputbox, KEY_ENTER); } } } static void TXT_InputBoxFocused(TXT_UNCAST_ARG(inputbox), int focused) { TXT_CAST_ARG(txt_inputbox_t, inputbox); // Stop editing when we lose focus. if (inputbox->editing && !focused) { FinishEditing(inputbox); } } txt_widget_class_t txt_inputbox_class = { TXT_AlwaysSelectable, TXT_InputBoxSizeCalc, TXT_InputBoxDrawer, TXT_InputBoxKeyPress, TXT_InputBoxDestructor, TXT_InputBoxMousePress, NULL, TXT_InputBoxFocused, }; txt_widget_class_t txt_int_inputbox_class = { TXT_AlwaysSelectable, TXT_InputBoxSizeCalc, TXT_InputBoxDrawer, TXT_InputBoxKeyPress, TXT_InputBoxDestructor, TXT_InputBoxMousePress, NULL, TXT_InputBoxFocused, }; static txt_inputbox_t *NewInputBox(txt_widget_class_t *widget_class, void *value, int size) { txt_inputbox_t *inputbox; inputbox = malloc(sizeof(txt_inputbox_t)); TXT_InitWidget(inputbox, widget_class); inputbox->value = value; inputbox->size = size; // 'size' is the maximum number of characters that can be entered, // but for a UTF-8 string, each character can take up to four // characters. inputbox->buffer_len = size * 4 + 1; inputbox->buffer = malloc(inputbox->buffer_len); inputbox->editing = 0; return inputbox; } txt_inputbox_t *TXT_NewInputBox(char **value, int size) { return NewInputBox(&txt_inputbox_class, value, size); } txt_inputbox_t *TXT_NewIntInputBox(int *value, int size) { return NewInputBox(&txt_int_inputbox_class, value, size); } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_inputbox.h000066400000000000000000000041151257432200600244120ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_INPUTBOX_H #define TXT_INPUTBOX_H /** * @file txt_inputbox.h * * Input box widget. */ /** * Input box widget. * * An input box is a widget that displays a value, which can be * selected to enter a new value. * * Input box widgets can be of an integer or string type. */ typedef struct txt_inputbox_s txt_inputbox_t; #include "txt_widget.h" struct txt_inputbox_s { txt_widget_t widget; char *buffer; size_t buffer_len; unsigned int size; int editing; void *value; }; /** * Create a new input box widget for controlling a string value. * * @param value Pointer to a string variable that contains * a pointer to the current value of the * input box. The value should be allocated * dynamically; when the string is changed it * will be freed and the variable set to point * to the new string value. * @param size Width of the input box, in characters. * @return Pointer to the new input box widget. */ txt_inputbox_t *TXT_NewInputBox(char **value, int size); /** * Create a new input box widget for controlling an integer value. * * @param value Pointer to an integer variable containing * the value of the input box. * @param size Width of the input box, in characters. * @return Pointer to the new input box widget. */ txt_inputbox_t *TXT_NewIntInputBox(int *value, int size); #endif /* #ifndef TXT_INPUTBOX_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_io.c000066400000000000000000000062011257432200600231420ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Text mode I/O functions, similar to C stdio // #include #include #include "txt_io.h" #include "txt_main.h" static int cur_x = 0, cur_y = 0; static txt_color_t fgcolor = TXT_COLOR_GREY; static txt_color_t bgcolor = TXT_COLOR_BLACK; static void NewLine(unsigned char *screendata) { int i; unsigned char *p; cur_x = 0; ++cur_y; if (cur_y >= TXT_SCREEN_H) { // Scroll the screen up cur_y = TXT_SCREEN_H - 1; memmove(screendata, screendata + TXT_SCREEN_W * 2, TXT_SCREEN_W * 2 * (TXT_SCREEN_H -1)); // Clear the bottom line p = screendata + (TXT_SCREEN_H - 1) * 2 * TXT_SCREEN_W; for (i=0; i= TXT_SCREEN_W) { NewLine(screendata); } break; } } void TXT_PutChar(int c) { unsigned char *screen; screen = TXT_GetScreenData(); PutChar(screen, c); } void TXT_Puts(const char *s) { unsigned char *screen; const char *p; screen = TXT_GetScreenData(); for (p=s; *p != '\0'; ++p) { PutChar(screen, *p); } PutChar(screen, '\n'); } void TXT_GotoXY(int x, int y) { cur_x = x; cur_y = y; } void TXT_GetXY(int *x, int *y) { *x = cur_x; *y = cur_y; } void TXT_FGColor(txt_color_t color) { fgcolor = color; } void TXT_BGColor(int color, int blinking) { bgcolor = color; if (blinking) bgcolor |= TXT_COLOR_BLINKING; } void TXT_SaveColors(txt_saved_colors_t *save) { save->bgcolor = bgcolor; save->fgcolor = fgcolor; } void TXT_RestoreColors(txt_saved_colors_t *save) { bgcolor = save->bgcolor; fgcolor = save->fgcolor; } void TXT_ClearScreen(void) { unsigned char *screen; int i; screen = TXT_GetScreenData(); for (i=0; i #include #include "txt_label.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_utf8.h" #include "txt_window.h" static void TXT_LabelSizeCalc(TXT_UNCAST_ARG(label)) { TXT_CAST_ARG(txt_label_t, label); label->widget.w = label->w; label->widget.h = label->h; } static void TXT_LabelDrawer(TXT_UNCAST_ARG(label)) { TXT_CAST_ARG(txt_label_t, label); unsigned int x, y; int origin_x, origin_y; unsigned int align_indent = 0; unsigned int w; w = label->widget.w; if (label->bgcolor >= 0) { TXT_BGColor(label->bgcolor, 0); } if (label->fgcolor >= 0) { TXT_FGColor(label->fgcolor); } TXT_GetXY(&origin_x, &origin_y); for (y=0; yh; ++y) { // Calculate the amount to indent this line due to the align // setting switch (label->widget.align) { case TXT_HORIZ_LEFT: align_indent = 0; break; case TXT_HORIZ_CENTER: align_indent = (label->w - strlen(label->lines[y])) / 2; break; case TXT_HORIZ_RIGHT: align_indent = label->w - strlen(label->lines[y]); break; } // Draw this line TXT_GotoXY(origin_x, origin_y + y); // Gap at the start for (x=0; xlines[y]); x += TXT_UTF8_Strlen(label->lines[y]); // Gap at the end for (; xlabel); free(label->lines); } txt_widget_class_t txt_label_class = { TXT_NeverSelectable, TXT_LabelSizeCalc, TXT_LabelDrawer, NULL, TXT_LabelDestructor, NULL, NULL, }; void TXT_SetLabel(txt_label_t *label, char *value) { char *p; unsigned int y; // Free back the old label free(label->label); free(label->lines); // Set the new value label->label = strdup(value); // Work out how many lines in this label label->h = 1; for (p = value; *p != '\0'; ++p) { if (*p == '\n') { ++label->h; } } // Split into lines label->lines = malloc(sizeof(char *) * label->h); label->lines[0] = label->label; y = 1; for (p = label->label; *p != '\0'; ++p) { if (*p == '\n') { label->lines[y] = p + 1; *p = '\0'; ++y; } } label->w = 0; for (y=0; yh; ++y) { unsigned int line_len; line_len = TXT_UTF8_Strlen(label->lines[y]); if (line_len > label->w) label->w = line_len; } } txt_label_t *TXT_NewLabel(char *text) { txt_label_t *label; label = malloc(sizeof(txt_label_t)); TXT_InitWidget(label, &txt_label_class); label->label = NULL; label->lines = NULL; // Default colors label->bgcolor = -1; label->fgcolor = -1; TXT_SetLabel(label, text); return label; } void TXT_SetFGColor(txt_label_t *label, txt_color_t color) { label->fgcolor = color; } void TXT_SetBGColor(txt_label_t *label, txt_color_t color) { label->bgcolor = color; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_label.h000066400000000000000000000034171257432200600236250ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_LABEL_H #define TXT_LABEL_H /** * @file txt_label.h * * Text label widget. */ /** * Label widget. * * A label widget does nothing except show a text label. */ typedef struct txt_label_s txt_label_t; #include "txt_main.h" #include "txt_widget.h" struct txt_label_s { txt_widget_t widget; char *label; char **lines; unsigned int w, h; int fgcolor; int bgcolor; }; /** * Create a new label widget. * * @param label String to display in the widget. * @return Pointer to the new label widget. */ txt_label_t *TXT_NewLabel(char *label); /** * Set the string displayed in a label widget. * * @param label The widget. * @param value The string to display. */ void TXT_SetLabel(txt_label_t *label, char *value); /** * Set the background color of a label widget. * * @param label The widget. * @param color The background color to use. */ void TXT_SetBGColor(txt_label_t *label, txt_color_t color); /** * Set the foreground color of a label widget. * * @param label The widget. * @param color The foreground color to use. */ void TXT_SetFGColor(txt_label_t *label, txt_color_t color); #endif /* #ifndef TXT_LABEL_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_largefont.h000066400000000000000000003300701257432200600245250ustar00rootroot00000000000000// // Copyright (C) 2005-2014 Simon Howard // Copyright (C) 2002-2004 The DOSBox Team // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // "High resolution" font. // // This is an enhanced version of the 8x16 font from txt_font.h that // has been doubled in size to 16x32, and then manually tweaked. // static uint8_t large_font_data[] = { // 0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x7f, 0xfe, 0xe0, 0x07, 0xc0, 0x03, 0xcc, 0x33, 0xcc, 0x33, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xcf, 0xf3, 0xcf, 0xf3, 0xc7, 0xe3, 0xc3, 0xc3, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, 0x7f, 0xfe, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xcf, 0xf3, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x70, 0x7c, 0xf8, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0x7f, 0xf8, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1f, 0xe0, 0x3f, 0xf0, 0x7f, 0xf8, 0xff, 0xfc, 0xff, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 5: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x7c, 0x3e, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0x7c, 0x3e, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x3b, 0xdc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 9: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, 0x38, 0x1c, 0x30, 0x0c, 0x30, 0x0c, 0x30, 0x0c, 0x30, 0x0c, 0x38, 0x1c, 0x3c, 0x3c, 0x1f, 0xf8, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xe0, 0x07, 0xc3, 0xc3, 0xc7, 0xe3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xc7, 0xe3, 0xc3, 0xc3, 0xe0, 0x07, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 11: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 0x03, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x01, 0xec, 0x03, 0xcc, 0x07, 0x8c, 0x0f, 0x0c, 0x3f, 0xc0, 0x7f, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x7f, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 12: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1f, 0xf8, 0x0f, 0xf0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 13: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x3f, 0x00, 0x7f, 0x00, 0xff, 0x00, 0xff, 0x00, 0xfe, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 14: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x3f, 0xff, 0x3c, 0x0f, 0x3c, 0x0f, 0x3f, 0xff, 0x3f, 0xff, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x1f, 0x3c, 0x3f, 0x7c, 0x3f, 0xfc, 0x3f, 0xfc, 0x3e, 0xfc, 0x1c, 0xf8, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 15: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xc3, 0xc3, 0xf3, 0xcf, 0x3f, 0xfc, 0x0f, 0xf0, 0xfc, 0x3f, 0xfc, 0x3f, 0x0f, 0xf0, 0x3f, 0xfc, 0xf3, 0xcf, 0xc3, 0xc3, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16: 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf8, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, 0xfc, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0xe0, 0x00, 0xc0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 17: 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x3c, 0x00, 0x7c, 0x00, 0xfc, 0x01, 0xfc, 0x03, 0xfc, 0x07, 0xfc, 0x0f, 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x0f, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00, 0xfc, 0x00, 0x7c, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 18: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 19: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x7f, 0xff, 0xe3, 0xcf, 0xe3, 0xcf, 0xe3, 0xcf, 0xe3, 0xcf, 0xe3, 0xcf, 0xe3, 0xcf, 0x7f, 0xcf, 0x3f, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 21: 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x1c, 0x7c, 0x00, 0x3f, 0x00, 0x1f, 0xc0, 0x0f, 0xe0, 0x1c, 0xf0, 0x38, 0x78, 0x70, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x38, 0x78, 0x70, 0x3c, 0xe0, 0x1f, 0xc0, 0x0f, 0xc0, 0x03, 0xf0, 0x00, 0xf8, 0xe0, 0x7c, 0xf0, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 22: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 23: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 25: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 26: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0, 0x00, 0x70, 0xff, 0xf8, 0xff, 0xf8, 0x00, 0x70, 0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 27: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x7f, 0xfc, 0x7f, 0xfc, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 28: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 29: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x0c, 0x30, 0x1c, 0x38, 0x3c, 0x3c, 0x7f, 0xfe, 0x7f, 0xfe, 0x3c, 0x3c, 0x1c, 0x38, 0x0c, 0x30, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 30: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x07, 0x80, 0x07, 0x80, 0x0f, 0xc0, 0x0f, 0xc0, 0x1f, 0xe0, 0x1f, 0xe0, 0x3f, 0xf0, 0x3f, 0xf0, 0x7f, 0xf8, 0x7f, 0xf8, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 31: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x7f, 0xf8, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0, 0x0f, 0xc0, 0x0f, 0xc0, 0x07, 0x80, 0x07, 0x80, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 33: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x07, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 34: 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0x38, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 35: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0xff, 0xfc, 0xff, 0xfc, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0xff, 0xfc, 0xff, 0xfc, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 36: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x1c, 0xf0, 0x0c, 0xf0, 0x0c, 0xf0, 0x00, 0xf0, 0x00, 0x7f, 0xf0, 0x3f, 0xf8, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xc0, 0x3c, 0xc0, 0x3c, 0xe0, 0x3c, 0xf0, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 37: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0c, 0xf0, 0x1c, 0xf0, 0x3c, 0x60, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x18, 0xe0, 0x3c, 0xc0, 0x3c, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 38: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xe0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x1c, 0xe0, 0x0f, 0xc0, 0x0f, 0xc0, 0x3f, 0x0c, 0x7f, 0x1c, 0xf3, 0xf8, 0xf3, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf0, 0x7f, 0xfc, 0x3f, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 39: 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 40: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0xf0, 0x03, 0xc0, 0x07, 0x80, 0x07, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 41: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x80, 0x03, 0xc0, 0x01, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xe0, 0x00, 0xe0, 0x01, 0xe0, 0x03, 0xc0, 0x0f, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 42: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x3c, 0x1e, 0x78, 0x0f, 0xf0, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xf0, 0x0f, 0xf0, 0x1e, 0x78, 0x3c, 0x3c, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 43: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 44: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 45: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 46: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 47: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x00, 0xe0, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 48: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, 0x78, 0x1e, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf1, 0x8f, 0xf3, 0xcf, 0xf3, 0xcf, 0xf1, 0x8f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x78, 0x1e, 0x3c, 0x3c, 0x1f, 0xf8, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 49: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x03, 0xc0, 0x07, 0xc0, 0x0f, 0xc0, 0x1f, 0xc0, 0x3f, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 50: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x3f, 0xf0, 0x70, 0x38, 0xe0, 0x3c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x70, 0x00, 0x70, 0x00, 0xf0, 0x0c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 51: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf8, 0x7c, 0xf0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xf0, 0x3c, 0xf8, 0x7c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 52: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xf0, 0x01, 0xf0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xf0, 0x1e, 0xf0, 0x3c, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x03, 0xfc, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 53: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xf0, 0xff, 0xf8, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 54: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xc0, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xf0, 0xff, 0xf8, 0xf8, 0x7c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf8, 0x7c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 55: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x07, 0x80, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 56: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf8, 0x7c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x3f, 0xf0, 0x3f, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf8, 0x7c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 57: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x7f, 0xfc, 0x3f, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x3f, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 58: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 59: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 60: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 61: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 62: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 63: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x7c, 0x00, 0xf8, 0x01, 0xf0, 0x03, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf1, 0xfc, 0xf3, 0xfc, 0xf3, 0xfc, 0xf3, 0xfc, 0xf3, 0xfc, 0xf3, 0xfc, 0xf3, 0xf8, 0xf1, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x7f, 0xf0, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 65: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1f, 0xe0, 0x3c, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 66: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0xff, 0xf0, 0x3c, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x38, 0x3f, 0xf0, 0x3f, 0xf0, 0x3c, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x38, 0xff, 0xf0, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 67: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x0f, 0xf0, 0x1e, 0x78, 0x3c, 0x3c, 0x78, 0x1c, 0x78, 0x0c, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x78, 0x0c, 0x78, 0x1c, 0x3c, 0x3c, 0x1e, 0x78, 0x0f, 0xf0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 68: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0xff, 0xc0, 0x3d, 0xe0, 0x3c, 0xf0, 0x3c, 0x78, 0x3c, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x38, 0x3c, 0x78, 0x3c, 0xf0, 0x3d, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 69: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x3c, 0x3c, 0x3c, 0x1c, 0x3c, 0x0c, 0x3c, 0x04, 0x3c, 0xc0, 0x3c, 0xc0, 0x3f, 0xc0, 0x3f, 0xc0, 0x3c, 0xc0, 0x3c, 0xc0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x04, 0x3c, 0x0c, 0x3c, 0x1c, 0x3c, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 70: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x3c, 0x3c, 0x3c, 0x1c, 0x3c, 0x0c, 0x3c, 0x04, 0x3c, 0xc0, 0x3c, 0xc0, 0x3f, 0xc0, 0x3f, 0xc0, 0x3c, 0xc0, 0x3c, 0xc0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 71: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x0f, 0xf0, 0x1e, 0x38, 0x3c, 0x1c, 0x78, 0x0c, 0x70, 0x0c, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf3, 0xfc, 0xf3, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0x70, 0x3c, 0x78, 0x3c, 0x3c, 0x3c, 0x1e, 0x7c, 0x0f, 0xec, 0x07, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 73: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0xf0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 74: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 0x03, 0xfc, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x7f, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 75: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3c, 0xfc, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x78, 0x3c, 0xf0, 0x3f, 0xe0, 0x3f, 0xc0, 0x3f, 0xc0, 0x3f, 0xe0, 0x3c, 0xf0, 0x3c, 0x78, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0xfc, 0x3c, 0xfc, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 76: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x04, 0x3c, 0x0c, 0x3c, 0x1c, 0x3c, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 77: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xcf, 0xf1, 0x8f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 78: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3c, 0xf0, 0x3c, 0xf8, 0x3c, 0xfc, 0x3c, 0xfe, 0x3c, 0xff, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf3, 0xfc, 0xf1, 0xfc, 0xf0, 0xfc, 0xf0, 0x7c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 79: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x78, 0x78, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x78, 0x78, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0xff, 0xf0, 0x3c, 0x78, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x78, 0x3f, 0xf0, 0x3f, 0xe0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 81: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf3, 0x3c, 0xf3, 0x3c, 0xf3, 0xfc, 0xf3, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 82: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0xff, 0xf0, 0x3c, 0x38, 0x3c, 0x1c, 0x3c, 0x1c, 0x3c, 0x1c, 0x3c, 0x3c, 0x3c, 0x38, 0x3f, 0xf0, 0x3f, 0xe0, 0x3c, 0xe0, 0x3c, 0x70, 0x3c, 0x38, 0x3c, 0x38, 0x3c, 0x1c, 0x3c, 0x1c, 0x3c, 0x1c, 0x3c, 0x1c, 0xfc, 0x1c, 0xfc, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 83: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x00, 0x3c, 0x00, 0x1f, 0x00, 0x0f, 0xc0, 0x03, 0xf0, 0x00, 0xf8, 0x00, 0x3c, 0x00, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf8, 0x7c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 84: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xcf, 0xe3, 0xc7, 0xc3, 0xc3, 0x83, 0xc1, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 85: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 86: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x78, 0x1e, 0x3c, 0x3c, 0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 87: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf1, 0x8f, 0xf1, 0x8f, 0xf3, 0xcf, 0xf3, 0xcf, 0xf7, 0xef, 0xf7, 0xef, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x78, 0x1e, 0x3c, 0x3c, 0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1e, 0x78, 0x3c, 0x3c, 0x78, 0x1e, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x78, 0x1e, 0x3c, 0x3c, 0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 90: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xe0, 0x1e, 0xc0, 0x3c, 0x80, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xf0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 91: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 92: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x03, 0xf0, 0x03, 0xf0, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 93: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 94: 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x70, 0x38, 0xe0, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 95: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96: 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 97: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x1f, 0xf0, 0x3f, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x79, 0xf0, 0x3f, 0x3c, 0x1e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 98: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x3c, 0xe0, 0x3c, 0x70, 0x3c, 0x38, 0x3c, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x38, 0x3c, 0x38, 0x3f, 0xf0, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 99: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x78, 0x38, 0xf0, 0x3c, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x1c, 0x78, 0x38, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 100: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x03, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x0f, 0xf0, 0x1f, 0xf0, 0x3c, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0x7f, 0xbc, 0x3f, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 101: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x1c, 0xf8, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 102: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x3c, 0x70, 0x3c, 0x30, 0x3c, 0x30, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 103: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1c, 0x3f, 0xbc, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x70, 0xf0, 0x3f, 0xf0, 0x1f, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0xe0, 0xf0, 0x70, 0xf0, 0x3f, 0xc0, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, // 104: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xf0, 0x3d, 0xf8, 0x3f, 0x3c, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0xfc, 0x3c, 0xfc, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 105: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 106: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x1c, 0x38, 0x0f, 0xf0, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, // 107: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x1c, 0x3c, 0x38, 0x3c, 0x70, 0x3c, 0xe0, 0x3d, 0xc0, 0x3f, 0x80, 0x3f, 0x80, 0x3f, 0xc0, 0x3c, 0xe0, 0x3c, 0x70, 0x3c, 0x38, 0x3c, 0x1c, 0xfc, 0x1c, 0xfc, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 108: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 109: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3c, 0xfe, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 110: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe0, 0xf7, 0xf0, 0x3c, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 111: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe0, 0xf7, 0xf0, 0x3e, 0x78, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x78, 0x3f, 0xf0, 0x3f, 0xe0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // 113: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1c, 0x3f, 0xbc, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x78, 0xf0, 0x3f, 0xf0, 0x1f, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x03, 0xfc, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x00, // 114: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0xe0, 0xf3, 0xf0, 0x3f, 0x38, 0x3e, 0x1c, 0x3c, 0x1c, 0x3c, 0x1c, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 115: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0x7c, 0x00, 0x3f, 0x00, 0x0f, 0xc0, 0x03, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 116: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x1c, 0x07, 0x3c, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 117: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf0, 0x7f, 0xbc, 0x3f, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 118: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0x78, 0x1e, 0x3c, 0x3c, 0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 119: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xf8, 0x1f, 0x3c, 0x3c, 0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1e, 0x78, 0x3c, 0x3c, 0x78, 0x1e, 0xf0, 0x0f, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 121: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x70, 0x3c, 0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x70, 0x00, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, // 122: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xf8, 0xe0, 0x70, 0xc0, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x0c, 0xe0, 0x1c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 123: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xfc, 0x01, 0xc0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x3f, 0x00, 0x3f, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 124: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 125: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0xfc, 0x00, 0xfc, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 126: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x3f, 0x3c, 0x73, 0xf0, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 127: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x70, 0x38, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 128: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x0f, 0xf0, 0x1c, 0x38, 0x38, 0x1c, 0x70, 0x0c, 0xf0, 0x0c, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x0c, 0x70, 0x0c, 0x38, 0x1c, 0x1c, 0x38, 0x0f, 0xf0, 0x07, 0xf0, 0x00, 0xf0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x38, 0x3f, 0xf0, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 129: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf0, 0x7f, 0xbc, 0x3f, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 130: 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x1c, 0xf8, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 131: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x1f, 0xf0, 0x3f, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x79, 0xf0, 0x3f, 0x3c, 0x1e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 132: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x1f, 0xf0, 0x3f, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x79, 0xf0, 0x3f, 0x3c, 0x1e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 133: 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x1f, 0xf0, 0x3f, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x79, 0xf0, 0x3f, 0x3c, 0x1e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 134: 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x38, 0x70, 0x38, 0x70, 0x0f, 0xc0, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x1f, 0xf0, 0x3f, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x79, 0xf0, 0x3f, 0x3c, 0x1e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 135: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x0f, 0xf0, 0x1c, 0x38, 0x3c, 0x1c, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x1c, 0x1c, 0x38, 0x0f, 0xf0, 0x07, 0xf0, 0x00, 0xf0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x38, 0x0f, 0xf0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 136: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x1c, 0xf8, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 137: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x1c, 0xf8, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 138: 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x1c, 0xf8, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 139: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 140: 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0e, 0x70, 0x1c, 0x38, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 141: 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 142: 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x70, 0x38, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 143: 0x07, 0x80, 0x0f, 0xc0, 0x38, 0x70, 0x38, 0x70, 0x0f, 0xc0, 0x07, 0x80, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x70, 0x38, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 144: 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x3c, 0x1c, 0x3c, 0x0c, 0x3c, 0x00, 0x3c, 0x00, 0x3f, 0xf0, 0x3f, 0xf0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x0c, 0x3c, 0x1c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 145: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78, 0x1c, 0xfc, 0x0f, 0xce, 0x07, 0xcf, 0x03, 0xcf, 0x03, 0xce, 0x1f, 0xfc, 0x3f, 0xf8, 0x73, 0xc0, 0xe3, 0xc0, 0xe3, 0xe0, 0x73, 0x78, 0x3f, 0x3f, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 146: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x0f, 0xfc, 0x1c, 0xf0, 0x38, 0xf0, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xfc, 0xf0, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 147: 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x70, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 148: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 149: 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 150: 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x1f, 0x80, 0x39, 0xc0, 0x70, 0xe0, 0xe0, 0x70, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf0, 0x7f, 0xbc, 0x3f, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 151: 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf0, 0x7f, 0xbc, 0x3f, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 152: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x70, 0x3c, 0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x70, 0x00, 0xe0, 0x3f, 0xc0, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, // 153: 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x70, 0x38, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x70, 0x38, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 154: 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x70, 0x38, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 155: 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x1f, 0xf8, 0x3f, 0xfc, 0x70, 0x0e, 0xe0, 0x07, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x07, 0x70, 0x0e, 0x3f, 0xfc, 0x1f, 0xf8, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 156: 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x3c, 0x70, 0x3c, 0x30, 0x3c, 0x30, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xfc, 0x1c, 0xfc, 0x38, 0xff, 0xf0, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 157: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x70, 0x0e, 0x38, 0x1c, 0x1c, 0x38, 0x0e, 0x70, 0x07, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 158: 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0xff, 0xf8, 0x3c, 0x3c, 0x3c, 0x1c, 0x3c, 0x1c, 0x3c, 0x3c, 0x3f, 0xf8, 0x3f, 0xf0, 0x3c, 0x0c, 0x3c, 0x1c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0xff, 0x3c, 0xff, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0xff, 0x1f, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 159: 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xfc, 0x01, 0xee, 0x03, 0xc7, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xe3, 0xc0, 0x77, 0x80, 0x3f, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 160: 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x1f, 0xf0, 0x3f, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x79, 0xf0, 0x3f, 0x3c, 0x1e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 161: 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 162: 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3f, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x78, 0x78, 0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 163: 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf0, 0x7f, 0xbc, 0x3f, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 164: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x3f, 0x3c, 0xf3, 0xf0, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe0, 0xf7, 0xf0, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 165: 0x1e, 0x1c, 0x3f, 0x3c, 0xf3, 0xf0, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3c, 0xf0, 0x3c, 0xf8, 0x3c, 0xfc, 0x3c, 0xfe, 0x3c, 0xff, 0x3c, 0xff, 0xbc, 0xf7, 0xfc, 0xf3, 0xfc, 0xf1, 0xfc, 0xf0, 0xfc, 0xf0, 0x7c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 166: 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x0f, 0xf0, 0x1c, 0xf0, 0x38, 0xf0, 0x38, 0xf0, 0x1c, 0xf0, 0x0f, 0xfc, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 167: 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x38, 0x70, 0x1c, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 168: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x00, 0xe0, 0x00, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xf0, 0x3c, 0x7f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 169: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 170: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 171: 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x04, 0xf0, 0x0c, 0xf0, 0x1c, 0xf0, 0x38, 0xf0, 0x70, 0xf0, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x7c, 0xe0, 0xfe, 0xc1, 0xcf, 0x83, 0x8f, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x00, 0xe0, 0x01, 0xff, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 172: 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x04, 0xf0, 0x0c, 0xf0, 0x1c, 0xf0, 0x38, 0xf0, 0x70, 0xf0, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x3c, 0x38, 0x7c, 0x70, 0xfc, 0xe1, 0xbc, 0xc3, 0x3c, 0x86, 0x3c, 0x0f, 0xfc, 0x0f, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 173: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 174: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3c, 0x1e, 0x78, 0x3c, 0xf0, 0x79, 0xe0, 0xf3, 0xc0, 0xf3, 0xc0, 0x79, 0xe0, 0x3c, 0xf0, 0x1e, 0x78, 0x0f, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 175: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0xc0, 0x79, 0xe0, 0x3c, 0xf0, 0x1e, 0x78, 0x0f, 0x3c, 0x0f, 0x3c, 0x1e, 0x78, 0x3c, 0xf0, 0x79, 0xe0, 0xf3, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 176: 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x30, 0x30, 0x30, 0x30, // 177: 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc, // 178: 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, 0xf3, 0xf3, 0xf3, 0xf3, 0x3f, 0x3f, 0x3f, 0x3f, // 179: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 180: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 181: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 182: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0x3c, 0xff, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 183: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 184: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 185: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0x3c, 0xff, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xff, 0x3c, 0xff, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 186: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 187: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x3c, 0x00, 0x3c, 0xff, 0x3c, 0xff, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 188: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0x3c, 0xff, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 189: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 190: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 191: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 192: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xff, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 193: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 194: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 195: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xff, 0x03, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 196: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 197: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 198: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xff, 0x03, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xff, 0x03, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 199: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3f, 0x0f, 0x3f, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 200: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3f, 0x0f, 0x3f, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 201: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x3f, 0x0f, 0x3f, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 202: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0x3f, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 203: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0xff, 0x3f, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 204: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3f, 0x0f, 0x3f, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x3f, 0x0f, 0x3f, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 205: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 206: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0x3f, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0xff, 0x3f, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 207: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 208: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 209: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 210: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 211: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 212: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xff, 0x03, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xff, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 213: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x03, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xff, 0x03, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 214: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 215: 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, 0x0f, 0x3c, // 216: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 217: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 218: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x03, 0xff, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 219: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 220: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 221: 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, // 222: 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, // 223: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 224: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3c, 0x7f, 0x7c, 0xf3, 0xf8, 0xe1, 0xf0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xf0, 0xf3, 0xf8, 0x7f, 0xbc, 0x3f, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 225: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x3f, 0xc0, 0x70, 0xe0, 0x70, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xf1, 0xe0, 0xf3, 0xc0, 0xf3, 0xc0, 0xf1, 0xe0, 0xf0, 0xf0, 0xf0, 0x70, 0xf0, 0x38, 0xf0, 0x38, 0xf0, 0x38, 0xf0, 0x38, 0xf0, 0x78, 0xf0, 0xf0, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 226: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 227: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 228: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0xf0, 0x1c, 0x78, 0x0c, 0x3c, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x78, 0x0c, 0xf0, 0x1c, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 229: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x3f, 0xfc, 0x73, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0x73, 0x80, 0x3f, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 230: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x38, 0x3c, 0x78, 0x3f, 0xf0, 0x3f, 0xe0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x38, 0x00, 0xf0, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 231: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x3f, 0x3c, 0xf3, 0xf0, 0xe3, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 232: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1c, 0x38, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x1c, 0x38, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 233: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x70, 0x38, 0x70, 0x38, 0xe0, 0x1c, 0xe0, 0x1c, 0xff, 0xfc, 0xff, 0xfc, 0xe0, 0x1c, 0xe0, 0x1c, 0x70, 0x38, 0x70, 0x38, 0x38, 0x70, 0x1c, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 234: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xe0, 0x3c, 0xf0, 0x78, 0x78, 0xf0, 0x3c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0x70, 0x38, 0x78, 0x78, 0x38, 0x70, 0x3c, 0xf0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0xfc, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 235: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0xfc, 0x07, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1c, 0x3c, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x1c, 0x38, 0x0f, 0xf0, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 236: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x3f, 0xfc, 0x73, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0xf3, 0xcf, 0x73, 0xcf, 0x3f, 0xfc, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 237: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x1f, 0xf8, 0x3f, 0xfc, 0x70, 0xee, 0xf1, 0xcf, 0xf3, 0xcf, 0xf7, 0x8f, 0xff, 0x0f, 0xff, 0x0e, 0x3f, 0xfc, 0x3f, 0xf8, 0x38, 0x00, 0x30, 0x00, 0x70, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 238: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0xf0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3f, 0xf0, 0x3f, 0xf0, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x07, 0x80, 0x03, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 239: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7f, 0xf8, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 240: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 241: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x3f, 0xfc, 0x3f, 0xfc, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 242: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 243: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01, 0xe0, 0x00, 0xf0, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 244: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xfe, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, // 245: 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0xf3, 0xc0, 0xf3, 0xc0, 0xf3, 0xc0, 0xf3, 0xc0, 0xf3, 0xc0, 0xf3, 0xc0, 0x7f, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 246: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 247: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x3f, 0x3c, 0xf3, 0xf0, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x3f, 0x3c, 0xf3, 0xf0, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 248: 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0f, 0xc0, 0x1c, 0xe0, 0x38, 0x70, 0x38, 0x70, 0x1c, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 249: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 250: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 251: 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0xe0, 0xf0, 0xf0, 0xf0, 0x78, 0xf0, 0x3c, 0xf0, 0x1e, 0xf0, 0x0f, 0xf0, 0x07, 0xf0, 0x03, 0xf0, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 252: 0x00, 0x00, 0x00, 0x00, 0xf3, 0xc0, 0xf7, 0xe0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 253: 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x3f, 0x00, 0x73, 0x80, 0xe3, 0xc0, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0xc0, 0xe0, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 254: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 255: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static txt_font_t large_font = { large_font_data, 16, // width 32 // height }; chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_main.h000066400000000000000000000111361257432200600234670ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Base interface that abstracts the text mode screen. // #ifndef TXT_MAIN_H #define TXT_MAIN_H // For the moment, txt_sdl.c is the only implementation of the base // text mode screen API: #include "txt_sdl.h" // textscreen key values: // Key values are difficult because we have to support multiple conflicting // address spaces. // First, Doom's key constants use 0-127 as ASCII and extra values from // 128-255 to represent special keys. Second, mouse buttons are represented // as buttons. Finally, we want to be able to support Unicode. // // So we define different ranges: // 0-255: Doom key constants, including ASCII. // 256-511: Mouse buttons and other reserved. // >=512: Unicode values greater than 127 are offset up into this range. // Special keypress values that correspond to mouse button clicks #define TXT_MOUSE_BASE 256 #define TXT_MOUSE_LEFT (TXT_MOUSE_BASE + 0) #define TXT_MOUSE_RIGHT (TXT_MOUSE_BASE + 1) #define TXT_MOUSE_MIDDLE (TXT_MOUSE_BASE + 2) #define TXT_MOUSE_SCROLLUP (TXT_MOUSE_BASE + 3) #define TXT_MOUSE_SCROLLDOWN (TXT_MOUSE_BASE + 4) #define TXT_MAX_MOUSE_BUTTONS 16 #define TXT_KEY_TO_MOUSE_BUTTON(x) \ ( (x) >= TXT_MOUSE_BASE \ && (x) < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS ? \ (x) - TXT_MOUSE_BASE : -1 ) // Unicode offset. Unicode values from 128 onwards are offset up into // this range, so TXT_UNICODE_BASE = Unicode character #128, and so on. #define TXT_UNICODE_BASE 512 // Convert a key value to a Unicode character: #define TXT_KEY_TO_UNICODE(x) \ ( (x) < 128 ? (x) : \ (x) >= TXT_UNICODE_BASE ? ((x) - TXT_UNICODE_BASE + 128) : 0 ) // Screen size #define TXT_SCREEN_W 80 #define TXT_SCREEN_H 25 #define TXT_COLOR_BLINKING (1 << 3) typedef enum { TXT_COLOR_BLACK, TXT_COLOR_BLUE, TXT_COLOR_GREEN, TXT_COLOR_CYAN, TXT_COLOR_RED, TXT_COLOR_MAGENTA, TXT_COLOR_BROWN, TXT_COLOR_GREY, TXT_COLOR_DARK_GREY, TXT_COLOR_BRIGHT_BLUE, TXT_COLOR_BRIGHT_GREEN, TXT_COLOR_BRIGHT_CYAN, TXT_COLOR_BRIGHT_RED, TXT_COLOR_BRIGHT_MAGENTA, TXT_COLOR_YELLOW, TXT_COLOR_BRIGHT_WHITE, } txt_color_t; // Modifier keys. typedef enum { TXT_MOD_SHIFT, TXT_MOD_CTRL, TXT_MOD_ALT, TXT_NUM_MODIFIERS } txt_modifier_t; // Initialize the screen // Returns 1 if successful, 0 if failed. int TXT_Init(void); // Shut down text mode emulation void TXT_Shutdown(void); // Get a pointer to the buffer containing the raw screen data. unsigned char *TXT_GetScreenData(void); // Update an area of the screen void TXT_UpdateScreenArea(int x, int y, int w, int h); // Update the whole screen void TXT_UpdateScreen(void); // Read a character from the keyboard int TXT_GetChar(void); // Read the current state of modifier keys that are held down. int TXT_GetModifierState(txt_modifier_t mod); // Provides a short description of a key code, placing into the // provided buffer. void TXT_GetKeyDescription(int key, char *buf, size_t buf_len); // Retrieve the current position of the mouse void TXT_GetMousePosition(int *x, int *y); // Sleep until an event is received or the screen needs updating // Optional timeout in ms (timeout == 0 : sleep forever) void TXT_Sleep(int timeout); // Controls whether keys are returned from TXT_GetChar based on keyboard // mapping, or raw key code. void TXT_EnableKeyMapping(int enable); // Set the window title of the window containing the text mode screen void TXT_SetWindowTitle(char *title); // Safe string copy. void TXT_StringCopy(char *dest, const char *src, size_t dest_len); // Safe string concatenate. void TXT_StringConcat(char *dest, const char *src, size_t dest_len); // Safe version of vsnprintf(). int TXT_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args); // Safe version of snprintf(). int TXT_snprintf(char *buf, size_t buf_len, const char *s, ...); #endif /* #ifndef TXT_MAIN_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_radiobutton.c000066400000000000000000000065151257432200600250750ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "doomkeys.h" #include "txt_radiobutton.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" static void TXT_RadioButtonSizeCalc(TXT_UNCAST_ARG(radiobutton)) { TXT_CAST_ARG(txt_radiobutton_t, radiobutton); // Minimum width is the string length + right-side spaces for padding radiobutton->widget.w = strlen(radiobutton->label) + 5; radiobutton->widget.h = 1; } static void TXT_RadioButtonDrawer(TXT_UNCAST_ARG(radiobutton)) { TXT_CAST_ARG(txt_radiobutton_t, radiobutton); txt_saved_colors_t colors; int i; int w; w = radiobutton->widget.w; TXT_SaveColors(&colors); TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); TXT_DrawString("("); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); if (*radiobutton->variable == radiobutton->value) { TXT_DrawString("\x07"); } else { TXT_DrawString(" "); } TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); TXT_DrawString(") "); TXT_RestoreColors(&colors); TXT_SetWidgetBG(radiobutton); TXT_DrawString(radiobutton->label); for (i=strlen(radiobutton->label); i < w-5; ++i) { TXT_DrawString(" "); } } static void TXT_RadioButtonDestructor(TXT_UNCAST_ARG(radiobutton)) { TXT_CAST_ARG(txt_radiobutton_t, radiobutton); free(radiobutton->label); } static int TXT_RadioButtonKeyPress(TXT_UNCAST_ARG(radiobutton), int key) { TXT_CAST_ARG(txt_radiobutton_t, radiobutton); if (key == KEY_ENTER || key == ' ') { if (*radiobutton->variable != radiobutton->value) { *radiobutton->variable = radiobutton->value; TXT_EmitSignal(radiobutton, "selected"); } return 1; } return 0; } static void TXT_RadioButtonMousePress(TXT_UNCAST_ARG(radiobutton), int x, int y, int b) { TXT_CAST_ARG(txt_radiobutton_t, radiobutton); if (b == TXT_MOUSE_LEFT) { // Equivalent to pressing enter TXT_RadioButtonKeyPress(radiobutton, KEY_ENTER); } } txt_widget_class_t txt_radiobutton_class = { TXT_AlwaysSelectable, TXT_RadioButtonSizeCalc, TXT_RadioButtonDrawer, TXT_RadioButtonKeyPress, TXT_RadioButtonDestructor, TXT_RadioButtonMousePress, NULL, }; txt_radiobutton_t *TXT_NewRadioButton(char *label, int *variable, int value) { txt_radiobutton_t *radiobutton; radiobutton = malloc(sizeof(txt_radiobutton_t)); TXT_InitWidget(radiobutton, &txt_radiobutton_class); radiobutton->label = strdup(label); radiobutton->variable = variable; radiobutton->value = value; return radiobutton; } void TXT_SetRadioButtonLabel(txt_radiobutton_t *radiobutton, char *value) { free(radiobutton->label); radiobutton->label = strdup(value); } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_radiobutton.h000066400000000000000000000044761257432200600251060ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_RADIOBUTTON_H #define TXT_RADIOBUTTON_H /** * @file txt_radiobutton.h * * Radio button widget. */ /** * A radio button widget. * * Radio buttons are typically used in groups, to allow a value to be * selected from a range of options. Each radio button corresponds * to a particular option that may be selected. A radio button * has an indicator to indicate whether it is the currently-selected * value, and a text label. * * Internally, a radio button tracks an integer variable that may take * a range of different values. Each radio button has a particular * value associated with it; if the variable is equal to that value, * the radio button appears selected. If a radio button is pressed * by the user through the GUI, the variable is set to its value. * * When a radio button is selected, the "selected" signal is emitted. */ typedef struct txt_radiobutton_s txt_radiobutton_t; #include "txt_widget.h" struct txt_radiobutton_s { txt_widget_t widget; char *label; int *variable; int value; }; /** * Create a new radio button widget. * * @param label The label to display next to the radio button. * @param variable Pointer to the variable tracking whether this * radio button is selected. * @param value If the variable is equal to this value, the * radio button appears selected. * @return Pointer to the new radio button widget. */ txt_radiobutton_t *TXT_NewRadioButton(char *label, int *variable, int value); /** * Set the label on a radio button. * * @param radiobutton The radio button. * @param value The new label. */ void TXT_SetRadioButtonLabel(txt_radiobutton_t *radiobutton, char *value); #endif /* #ifndef TXT_RADIOBUTTON_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_scrollpane.c000066400000000000000000000341731257432200600247060ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include #include #include "txt_scrollpane.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_table.h" #include "doomkeys.h" #define SCROLLBAR_VERTICAL (1 << 0) #define SCROLLBAR_HORIZONTAL (1 << 1) static int FullWidth(txt_scrollpane_t *scrollpane) { if (scrollpane->child != NULL) { return scrollpane->child->w; } else { return 0; } } static int FullHeight(txt_scrollpane_t *scrollpane) { if (scrollpane->child != NULL) { return scrollpane->child->h; } else { return 0; } } // Calculate which scroll bars the pane needs. static int NeedsScrollbars(txt_scrollpane_t *scrollpane) { int result; result = 0; if (FullWidth(scrollpane) > scrollpane->w) { result |= SCROLLBAR_HORIZONTAL; } if (FullHeight(scrollpane) > scrollpane->h) { result |= SCROLLBAR_VERTICAL; } return result; } // If a scrollbar isn't needed, the scroll position is reset. static void SanityCheckScrollbars(txt_scrollpane_t *scrollpane) { int scrollbars; int max_x, max_y; scrollbars = NeedsScrollbars(scrollpane); if ((scrollbars & SCROLLBAR_HORIZONTAL) == 0) { scrollpane->x = 0; } if ((scrollbars & SCROLLBAR_VERTICAL) == 0) { scrollpane->y = 0; } max_x = FullWidth(scrollpane) - scrollpane->w; max_y = FullHeight(scrollpane) - scrollpane->h; if (scrollpane->x < 0) { scrollpane->x = 0; } else if (scrollpane->x > max_x) { scrollpane->x = max_x; } if (scrollpane->y < 0) { scrollpane->y = 0; } else if (scrollpane->y > max_y) { scrollpane->y = max_y; } } static void TXT_ScrollPaneSizeCalc(TXT_UNCAST_ARG(scrollpane)) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); int scrollbars; if (scrollpane->child != NULL) { TXT_CalcWidgetSize(scrollpane->child); } // Expand as necessary (to ensure that no scrollbars are needed)? if (scrollpane->expand_w) { scrollpane->w = FullWidth(scrollpane); } if (scrollpane->expand_h) { scrollpane->h = FullHeight(scrollpane); } scrollpane->widget.w = scrollpane->w; scrollpane->widget.h = scrollpane->h; // If we have scroll bars, we need to expand slightly to // accomodate them. Eg. if we have a vertical scrollbar, we // need to be an extra character wide. scrollbars = NeedsScrollbars(scrollpane); if (scrollbars & SCROLLBAR_HORIZONTAL) { ++scrollpane->widget.h; } if (scrollbars & SCROLLBAR_VERTICAL) { ++scrollpane->widget.w; } if (scrollpane->child != NULL) { if (scrollpane->child->w < scrollpane->w) { scrollpane->child->w = scrollpane->w; } if (scrollpane->child->h < scrollpane->h) { scrollpane->child->h = scrollpane->h; } } } static void TXT_ScrollPaneDrawer(TXT_UNCAST_ARG(scrollpane)) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); int x1, y1, x2, y2; int scrollbars; // We set a clipping area of the scroll pane. x1 = scrollpane->widget.x, y1 = scrollpane->widget.y, x2 = x1 + scrollpane->w, y2 = y1 + scrollpane->h; scrollbars = NeedsScrollbars(scrollpane); if (scrollbars & SCROLLBAR_HORIZONTAL) { TXT_DrawHorizScrollbar(x1, y1 + scrollpane->h, scrollpane->w, scrollpane->x, FullWidth(scrollpane) - scrollpane->w); } if (scrollbars & SCROLLBAR_VERTICAL) { TXT_DrawVertScrollbar(x1 + scrollpane->w, y1, scrollpane->h, scrollpane->y, FullHeight(scrollpane) - scrollpane->h); } TXT_PushClipArea(x1, x2, y1, y2); // Draw the child widget if (scrollpane->child != NULL) { TXT_DrawWidget(scrollpane->child); } // Restore old clipping area. TXT_PopClipArea(); } static void TXT_ScrollPaneDestructor(TXT_UNCAST_ARG(scrollpane)) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); if (scrollpane->child != NULL) { TXT_DestroyWidget(scrollpane->child); } } static void TXT_ScrollPaneFocused(TXT_UNCAST_ARG(scrollpane), int focused) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); // Whether the child is focused depends only on whether the scroll pane // itself is focused. Pass through focus to the child. if (scrollpane->child != NULL) { TXT_SetWidgetFocus(scrollpane->child, focused); } } // Hack for tables - when browsing a table inside a scroll pane, // automatically scroll the window to show the newly-selected // item. static void ShowSelectedWidget(txt_scrollpane_t *scrollpane) { txt_widget_t *selected; selected = TXT_GetSelectedWidget(scrollpane->child); // Scroll up or down? if (selected->y <= scrollpane->widget.y) { scrollpane->y -= scrollpane->widget.y - selected->y; } else if ((signed) (selected->y + selected->h) > (signed) (scrollpane->widget.y + scrollpane->h)) { scrollpane->y += (selected->y + selected->h) - (scrollpane->widget.y + scrollpane->h); } // Scroll left or right? if (selected->x <= scrollpane->widget.x) { scrollpane->x -= scrollpane->widget.x - selected->x; } else if ((signed) (selected->x + selected->w) > (signed) (scrollpane->widget.x + scrollpane->w)) { scrollpane->x += (selected->x + selected->w) - (scrollpane->widget.x + scrollpane->w); } } // Another hack for tables - when scrolling in 'pages', the normal key press // event does not provide children with enough information to know how far // to move their selection to reach a new page. This function does so. // Note that it *only* affects scrolling in pages, not with arrows! // A side-effect of this, rather than 'pulling' the selection to fit within // the new page, is that we will jump straight over ranges of unselectable // items longer than a page, but that is also true of arrow-key scrolling. // The other unfortunate effect of doing things this way is that page keys // have no effect on tables _not_ in scrollpanes: not even home/end. static int PageSelectedWidget(txt_scrollpane_t *scrollpane, int key) { int pagex = 0; // No page left/right yet, but some keyboards have them int pagey = 0; // Subtract one from the absolute page distance as this is slightly more // intuitive: a page down first jumps to the bottom of the current page, // then proceeds to scroll onwards. switch (key) { case KEY_PGUP: pagey = 1 - scrollpane->h; break; case KEY_PGDN: pagey = scrollpane->h - 1; break; default: // We shouldn't even be in this function return 0; } if (scrollpane->child->widget_class == &txt_table_class) { return TXT_PageTable(scrollpane->child, pagex, pagey); } return 0; } // Interpret arrow key presses as scroll commands static int InterpretScrollKey(txt_scrollpane_t *scrollpane, int key) { int maxy; switch (key) { case KEY_UPARROW: if (scrollpane->y > 0) { --scrollpane->y; return 1; } break; case KEY_DOWNARROW: if (scrollpane->y < FullHeight(scrollpane) - scrollpane->h) { ++scrollpane->y; return 1; } break; case KEY_LEFTARROW: if (scrollpane->x > 0) { --scrollpane->x; return 1; } break; case KEY_RIGHTARROW: if (scrollpane->x < FullWidth(scrollpane) - scrollpane->w) { ++scrollpane->x; return 1; } break; case KEY_PGUP: if (scrollpane->y > 0) { scrollpane->y -= scrollpane->h; if (scrollpane->y < 0) { scrollpane->y = 0; } return 1; } break; case KEY_PGDN: maxy = FullHeight(scrollpane) - scrollpane->h; if (scrollpane->y < maxy) { scrollpane->y += scrollpane->h; if (scrollpane->y > maxy) { scrollpane->y = maxy; } return 1; } break; default: break; } return 0; } static int TXT_ScrollPaneKeyPress(TXT_UNCAST_ARG(scrollpane), int key) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); int result; result = 0; if (scrollpane->child != NULL) { result = TXT_WidgetKeyPress(scrollpane->child, key); // Gross hack - if we're scrolling in a menu with the keyboard, // automatically move the scroll pane to show the new // selected item. if ((key == KEY_UPARROW || key == KEY_DOWNARROW || key == KEY_LEFTARROW || key == KEY_RIGHTARROW || key == KEY_PGUP || key == KEY_PGDN) && scrollpane->child->widget_class == &txt_table_class) { if (PageSelectedWidget(scrollpane, key)) { result = 1; } ShowSelectedWidget(scrollpane); } // If the child widget didn't use the keypress, we can see // if it can be interpreted as a scrolling command. if (result == 0) { result = InterpretScrollKey(scrollpane, key); } } return result; } static void TXT_ScrollPaneMousePress(TXT_UNCAST_ARG(scrollpane), int x, int y, int b) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); int scrollbars; int rel_x, rel_y; scrollbars = NeedsScrollbars(scrollpane); if (b == TXT_MOUSE_SCROLLUP) { if (scrollbars & SCROLLBAR_VERTICAL) { scrollpane->y -= 3; } else if (scrollbars & SCROLLBAR_HORIZONTAL) { scrollpane->x -= 3; } return; } else if (b == TXT_MOUSE_SCROLLDOWN) { if (scrollbars & SCROLLBAR_VERTICAL) { scrollpane->y += 3; } else if (scrollbars & SCROLLBAR_HORIZONTAL) { scrollpane->x += 3; } return; } rel_x = x - scrollpane->widget.x; rel_y = y - scrollpane->widget.y; // Click on the horizontal scrollbar? if ((scrollbars & SCROLLBAR_HORIZONTAL) && rel_y == scrollpane->h) { if (rel_x == 0) { --scrollpane->x; } else if (rel_x == scrollpane->w - 1) { ++scrollpane->x; } else { int range = FullWidth(scrollpane) - scrollpane->w; int bar_max = scrollpane->w - 3; scrollpane->x = ((rel_x - 1) * range + bar_max - 1) / bar_max; } return; } // Click on the vertical scrollbar? if ((scrollbars & SCROLLBAR_VERTICAL) && rel_x == scrollpane->w) { if (rel_y == 0) { --scrollpane->y; } else if (rel_y == scrollpane->h - 1) { ++scrollpane->y; } else { int range = FullHeight(scrollpane) - scrollpane->h; int bar_max = scrollpane->h - 3; scrollpane->y = ((rel_y - 1) * range + bar_max - 1) / bar_max; } return; } if (scrollpane->child != NULL) { TXT_WidgetMousePress(scrollpane->child, x, y, b); } } static void TXT_ScrollPaneLayout(TXT_UNCAST_ARG(scrollpane)) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); SanityCheckScrollbars(scrollpane); // The child widget takes the same position as the scroll pane // itself, but is offset by the scroll position. if (scrollpane->child != NULL) { scrollpane->child->x = scrollpane->widget.x - scrollpane->x; scrollpane->child->y = scrollpane->widget.y - scrollpane->y; TXT_LayoutWidget(scrollpane->child); } } static int TXT_ScrollPaneSelectable(TXT_UNCAST_ARG(scrollpane)) { TXT_CAST_ARG(txt_scrollpane_t, scrollpane); // If scroll bars are displayed, the scroll pane must be selectable // so that we can use the arrow keys to scroll around. if (NeedsScrollbars(scrollpane)) { return 1; } // Otherwise, whether this is selectable depends on the child widget. return TXT_SelectableWidget(scrollpane->child); } txt_widget_class_t txt_scrollpane_class = { TXT_ScrollPaneSelectable, TXT_ScrollPaneSizeCalc, TXT_ScrollPaneDrawer, TXT_ScrollPaneKeyPress, TXT_ScrollPaneDestructor, TXT_ScrollPaneMousePress, TXT_ScrollPaneLayout, TXT_ScrollPaneFocused, }; txt_scrollpane_t *TXT_NewScrollPane(int w, int h, TXT_UNCAST_ARG(target)) { TXT_CAST_ARG(txt_widget_t, target); txt_scrollpane_t *scrollpane; scrollpane = malloc(sizeof(txt_scrollpane_t)); TXT_InitWidget(scrollpane, &txt_scrollpane_class); scrollpane->w = w; scrollpane->h = h; scrollpane->x = 0; scrollpane->y = 0; scrollpane->child = target; scrollpane->expand_w = w <= 0; scrollpane->expand_h = h <= 0; // Set parent pointer for inner widget. target->parent = &scrollpane->widget; return scrollpane; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_scrollpane.h000066400000000000000000000030451257432200600247050ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_SCROLLPANE_H #define TXT_SCROLLPANE_H /** * @file txt_scrollpane.h * * Scrollable pane widget. */ /** * Scrollable pane widget. * * A scrollable pane widget is a widget that contains another widget * that is larger than it. Scroll bars appear on the side to allow * different areas of the contained widget to be seen. */ typedef struct txt_scrollpane_s txt_scrollpane_t; #include "txt_widget.h" struct txt_scrollpane_s { txt_widget_t widget; int w, h; int x, y; int expand_w, expand_h; txt_widget_t *child; }; /** * Create a new scroll pane widget. * * @param w Width of the scroll pane, in characters. * @param h Height of the scroll pane, in lines. * @param target The target widget that the scroll pane will * contain. * @return Pointer to the new scroll pane widget. */ txt_scrollpane_t *TXT_NewScrollPane(int w, int h, TXT_UNCAST_ARG(target)); #endif /* #ifndef TXT_SCROLLPANE_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_sdl.c000066400000000000000000000554421257432200600233300ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Text mode emulation in SDL // #include "SDL.h" #include #include #include #include #include "doomkeys.h" #include "txt_main.h" #include "txt_sdl.h" #if defined(_MSC_VER) && !defined(__cplusplus) #define inline __inline #endif typedef struct { unsigned char *data; unsigned int w; unsigned int h; } txt_font_t; // Fonts: #include "txt_font.h" #include "txt_largefont.h" #include "txt_smallfont.h" // Time between character blinks in ms #define BLINK_PERIOD 250 static SDL_Surface *screen; static SDL_Surface *screenbuffer; static unsigned char *screendata; static int key_mapping = 1; static TxtSDLEventCallbackFunc event_callback; static void *event_callback_data; static int modifier_state[TXT_NUM_MODIFIERS]; // Font we are using: static txt_font_t *font; //#define TANGO #ifndef TANGO static SDL_Color ega_colors[] = { {0x00, 0x00, 0x00, 0x00}, // 0: Black {0x00, 0x00, 0xa8, 0x00}, // 1: Blue {0x00, 0xa8, 0x00, 0x00}, // 2: Green {0x00, 0xa8, 0xa8, 0x00}, // 3: Cyan {0xa8, 0x00, 0x00, 0x00}, // 4: Red {0xa8, 0x00, 0xa8, 0x00}, // 5: Magenta {0xa8, 0x54, 0x00, 0x00}, // 6: Brown {0xa8, 0xa8, 0xa8, 0x00}, // 7: Grey {0x54, 0x54, 0x54, 0x00}, // 8: Dark grey {0x54, 0x54, 0xfe, 0x00}, // 9: Bright blue {0x54, 0xfe, 0x54, 0x00}, // 10: Bright green {0x54, 0xfe, 0xfe, 0x00}, // 11: Bright cyan {0xfe, 0x54, 0x54, 0x00}, // 12: Bright red {0xfe, 0x54, 0xfe, 0x00}, // 13: Bright magenta {0xfe, 0xfe, 0x54, 0x00}, // 14: Yellow {0xfe, 0xfe, 0xfe, 0x00}, // 15: Bright white }; #else // Colors that fit the Tango desktop guidelines: see // http://tango.freedesktop.org/ also // http://uwstopia.nl/blog/2006/07/tango-terminal static SDL_Color ega_colors[] = { {0x2e, 0x34, 0x36, 0x00}, // 0: Black {0x34, 0x65, 0xa4, 0x00}, // 1: Blue {0x4e, 0x9a, 0x06, 0x00}, // 2: Green {0x06, 0x98, 0x9a, 0x00}, // 3: Cyan {0xcc, 0x00, 0x00, 0x00}, // 4: Red {0x75, 0x50, 0x7b, 0x00}, // 5: Magenta {0xc4, 0xa0, 0x00, 0x00}, // 6: Brown {0xd3, 0xd7, 0xcf, 0x00}, // 7: Grey {0x55, 0x57, 0x53, 0x00}, // 8: Dark grey {0x72, 0x9f, 0xcf, 0x00}, // 9: Bright blue {0x8a, 0xe2, 0x34, 0x00}, // 10: Bright green {0x34, 0xe2, 0xe2, 0x00}, // 11: Bright cyan {0xef, 0x29, 0x29, 0x00}, // 12: Bright red {0x34, 0xe2, 0xe2, 0x00}, // 13: Bright magenta {0xfc, 0xe9, 0x4f, 0x00}, // 14: Yellow {0xee, 0xee, 0xec, 0x00}, // 15: Bright white }; #endif #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include // Examine system DPI settings to determine whether to use the large font. static int Win32_UseLargeFont(void) { HDC hdc = GetDC(NULL); int dpix; if (!hdc) { return 0; } dpix = GetDeviceCaps(hdc, LOGPIXELSX); ReleaseDC(NULL, hdc); // 144 is the DPI when using "150%" scaling. If the user has this set // then consider this an appropriate threshold for using the large font. return dpix >= 144; } #endif static txt_font_t *FontForName(char *name) { if (!strcmp(name, "small")) { return &small_font; } else if (!strcmp(name, "normal")) { return &main_font; } else if (!strcmp(name, "large")) { return &large_font; } else { return NULL; } } // // Select the font to use, based on screen resolution // // If the highest screen resolution available is less than // 640x480, use the small font. // static void ChooseFont(void) { const SDL_VideoInfo *info; char *env; // Allow normal selection to be overridden from an environment variable: env = getenv("TEXTSCREEN_FONT"); if (env != NULL) { font = FontForName(env); if (font != NULL) { return; } } // Get desktop resolution: info = SDL_GetVideoInfo(); // If in doubt and we can't get a list, always prefer to // fall back to the normal font: if (info == NULL) { font = &main_font; return; } // On tiny low-res screens (eg. palmtops) use the small font. // If the screen resolution is at least 1920x1080, this is // a modern high-resolution display, and we can use the // large font. if (info->current_w < 640 || info->current_h < 480) { font = &small_font; } #ifdef _WIN32 // On Windows we can use the system DPI settings to make a // more educated guess about whether to use the large font. else if (Win32_UseLargeFont()) { font = &large_font; } #endif // TODO: Detect high DPI on Linux by inquiring about Gtk+ scale // settings. This looks like it should just be a case of shelling // out to invoke the 'gsettings' command, eg. // gsettings get org.gnome.desktop.interface text-scaling-factor // and using large_font if the result is >= 2. else { font = &main_font; } } // // Initialize text mode screen // // Returns 1 if successful, 0 if an error occurred // int TXT_Init(void) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { return 0; } ChooseFont(); // Always create the screen at the native screen depth (bpp=0); // some systems nowadays don't seem to support true 8-bit palettized // screen modes very well and we end up with screwed up colors. screen = SDL_SetVideoMode(TXT_SCREEN_W * font->w, TXT_SCREEN_H * font->h, 0, 0); if (screen == NULL) return 0; // Instead, we draw everything into an intermediate 8-bit surface // the same dimensions as the screen. SDL then takes care of all the // 8->32 bit (or whatever depth) color conversions for us. screenbuffer = SDL_CreateRGBSurface(0, TXT_SCREEN_W * font->w, TXT_SCREEN_H * font->h, 8, 0, 0, 0, 0); SDL_SetColors(screenbuffer, ega_colors, 0, 16); SDL_EnableUNICODE(1); screendata = malloc(TXT_SCREEN_W * TXT_SCREEN_H * 2); memset(screendata, 0, TXT_SCREEN_W * TXT_SCREEN_H * 2); // Ignore all mouse motion events // SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // Repeat key presses so we can hold down arrows to scroll down the // menu, for example. This is what setup.exe does. SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); return 1; } void TXT_Shutdown(void) { free(screendata); screendata = NULL; SDL_FreeSurface(screenbuffer); screenbuffer = NULL; SDL_QuitSubSystem(SDL_INIT_VIDEO); } unsigned char *TXT_GetScreenData(void) { return screendata; } static inline void UpdateCharacter(int x, int y) { unsigned char character; unsigned char *p; unsigned char *s, *s1; unsigned int bit, bytes; int bg, fg; unsigned int x1, y1; p = &screendata[(y * TXT_SCREEN_W + x) * 2]; character = p[0]; fg = p[1] & 0xf; bg = (p[1] >> 4) & 0xf; if (bg & 0x8) { // blinking bg &= ~0x8; if (((SDL_GetTicks() / BLINK_PERIOD) % 2) == 0) { fg = bg; } } // How many bytes per line? bytes = (font->w + 7) / 8; p = &font->data[character * font->h * bytes]; s = ((unsigned char *) screenbuffer->pixels) + (y * font->h * screenbuffer->pitch) + (x * font->w); for (y1=0; y1h; ++y1) { s1 = s; bit = 0; for (x1=0; x1w; ++x1) { if (*p & (1 << (7-bit))) { *s1++ = fg; } else { *s1++ = bg; } ++bit; if (bit == 8) { ++p; bit = 0; } } if (bit != 0) { ++p; } s += screenbuffer->pitch; } } static int LimitToRange(int val, int min, int max) { if (val < min) { return min; } else if (val > max) { return max; } else { return val; } } void TXT_UpdateScreenArea(int x, int y, int w, int h) { SDL_Rect rect; int x1, y1; int x_end; int y_end; x_end = LimitToRange(x + w, 0, TXT_SCREEN_W); y_end = LimitToRange(y + h, 0, TXT_SCREEN_H); x = LimitToRange(x, 0, TXT_SCREEN_W); y = LimitToRange(y, 0, TXT_SCREEN_H); for (y1=y; y1w; rect.y = y * font->h; rect.w = (x_end - x) * font->w; rect.h = (y_end - y) * font->h; SDL_BlitSurface(screenbuffer, &rect, screen, &rect); SDL_UpdateRects(screen, 1, &rect); } void TXT_UpdateScreen(void) { TXT_UpdateScreenArea(0, 0, TXT_SCREEN_W, TXT_SCREEN_H); } void TXT_GetMousePosition(int *x, int *y) { SDL_GetMouseState(x, y); *x /= font->w; *y /= font->h; } // // Translates the SDL key // static int TranslateKey(SDL_keysym *sym) { switch(sym->sym) { case SDLK_LEFT: return KEY_LEFTARROW; case SDLK_RIGHT: return KEY_RIGHTARROW; case SDLK_DOWN: return KEY_DOWNARROW; case SDLK_UP: return KEY_UPARROW; case SDLK_ESCAPE: return KEY_ESCAPE; case SDLK_RETURN: return KEY_ENTER; case SDLK_TAB: return KEY_TAB; case SDLK_F1: return KEY_F1; case SDLK_F2: return KEY_F2; case SDLK_F3: return KEY_F3; case SDLK_F4: return KEY_F4; case SDLK_F5: return KEY_F5; case SDLK_F6: return KEY_F6; case SDLK_F7: return KEY_F7; case SDLK_F8: return KEY_F8; case SDLK_F9: return KEY_F9; case SDLK_F10: return KEY_F10; case SDLK_F11: return KEY_F11; case SDLK_F12: return KEY_F12; case SDLK_PRINT: return KEY_PRTSCR; case SDLK_BACKSPACE: return KEY_BACKSPACE; case SDLK_DELETE: return KEY_DEL; case SDLK_PAUSE: return KEY_PAUSE; case SDLK_LSHIFT: case SDLK_RSHIFT: return KEY_RSHIFT; case SDLK_LCTRL: case SDLK_RCTRL: return KEY_RCTRL; case SDLK_LALT: case SDLK_RALT: case SDLK_LMETA: case SDLK_RMETA: return KEY_RALT; case SDLK_CAPSLOCK: return KEY_CAPSLOCK; case SDLK_SCROLLOCK: return KEY_SCRLCK; case SDLK_HOME: return KEY_HOME; case SDLK_INSERT: return KEY_INS; case SDLK_END: return KEY_END; case SDLK_PAGEUP: return KEY_PGUP; case SDLK_PAGEDOWN: return KEY_PGDN; #ifdef SDL_HAVE_APP_KEYS case SDLK_APP1: return KEY_F1; case SDLK_APP2: return KEY_F2; case SDLK_APP3: return KEY_F3; case SDLK_APP4: return KEY_F4; case SDLK_APP5: return KEY_F5; case SDLK_APP6: return KEY_F6; #endif default: break; } // Returned value is different, depending on whether key mapping is // enabled. Key mapping is preferable most of the time, for typing // in text, etc. However, when we want to read raw keyboard codes // for the setup keyboard configuration dialog, we want the raw // key code. if (key_mapping) { // Unicode characters beyond the ASCII range need to be // mapped up into textscreen's Unicode range. if (sym->unicode < 128) { return sym->unicode; } else { return sym->unicode - 128 + TXT_UNICODE_BASE; } } else { // Keypad mapping is only done when we want a raw value: // most of the time, the keypad should behave as it normally // does. switch (sym->sym) { case SDLK_KP0: return KEYP_0; case SDLK_KP1: return KEYP_1; case SDLK_KP2: return KEYP_2; case SDLK_KP3: return KEYP_3; case SDLK_KP4: return KEYP_4; case SDLK_KP5: return KEYP_5; case SDLK_KP6: return KEYP_6; case SDLK_KP7: return KEYP_7; case SDLK_KP8: return KEYP_8; case SDLK_KP9: return KEYP_9; case SDLK_KP_PERIOD: return KEYP_PERIOD; case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY; case SDLK_KP_PLUS: return KEYP_PLUS; case SDLK_KP_MINUS: return KEYP_MINUS; case SDLK_KP_DIVIDE: return KEYP_DIVIDE; case SDLK_KP_EQUALS: return KEYP_EQUALS; case SDLK_KP_ENTER: return KEYP_ENTER; default: return tolower(sym->sym); } } } // Convert an SDL button index to textscreen button index. // // Note special cases because 2 == mid in SDL, 3 == mid in textscreen/setup static int SDLButtonToTXTButton(int button) { switch (button) { case SDL_BUTTON_LEFT: return TXT_MOUSE_LEFT; case SDL_BUTTON_RIGHT: return TXT_MOUSE_RIGHT; case SDL_BUTTON_MIDDLE: return TXT_MOUSE_MIDDLE; default: return TXT_MOUSE_BASE + button - 1; } } static int MouseHasMoved(void) { static int last_x = 0, last_y = 0; int x, y; TXT_GetMousePosition(&x, &y); if (x != last_x || y != last_y) { last_x = x; last_y = y; return 1; } else { return 0; } } // Examine a key press/release and update the modifier key state // if necessary. static void UpdateModifierState(SDL_keysym *sym, int pressed) { txt_modifier_t mod; switch (sym->sym) { case SDLK_LSHIFT: case SDLK_RSHIFT: mod = TXT_MOD_SHIFT; break; case SDLK_LCTRL: case SDLK_RCTRL: mod = TXT_MOD_CTRL; break; case SDLK_LALT: case SDLK_RALT: case SDLK_LMETA: case SDLK_RMETA: mod = TXT_MOD_ALT; break; default: return; } if (pressed) { ++modifier_state[mod]; } else { --modifier_state[mod]; } } signed int TXT_GetChar(void) { SDL_Event ev; while (SDL_PollEvent(&ev)) { // If there is an event callback, allow it to intercept this // event. if (event_callback != NULL) { if (event_callback(&ev, event_callback_data)) { continue; } } // Process the event. switch (ev.type) { case SDL_MOUSEBUTTONDOWN: if (ev.button.button < TXT_MAX_MOUSE_BUTTONS) { return SDLButtonToTXTButton(ev.button.button); } break; case SDL_KEYDOWN: UpdateModifierState(&ev.key.keysym, 1); return TranslateKey(&ev.key.keysym); case SDL_KEYUP: UpdateModifierState(&ev.key.keysym, 0); break; case SDL_QUIT: // Quit = escape return 27; case SDL_MOUSEMOTION: if (MouseHasMoved()) { return 0; } default: break; } } return -1; } int TXT_GetModifierState(txt_modifier_t mod) { if (mod < TXT_NUM_MODIFIERS) { return modifier_state[mod] > 0; } return 0; } static const char *SpecialKeyName(int key) { switch (key) { case ' ': return "SPACE"; case KEY_RIGHTARROW: return "RIGHT"; case KEY_LEFTARROW: return "LEFT"; case KEY_UPARROW: return "UP"; case KEY_DOWNARROW: return "DOWN"; case KEY_ESCAPE: return "ESC"; case KEY_ENTER: return "ENTER"; case KEY_TAB: return "TAB"; case KEY_F1: return "F1"; case KEY_F2: return "F2"; case KEY_F3: return "F3"; case KEY_F4: return "F4"; case KEY_F5: return "F5"; case KEY_F6: return "F6"; case KEY_F7: return "F7"; case KEY_F8: return "F8"; case KEY_F9: return "F9"; case KEY_F10: return "F10"; case KEY_F11: return "F11"; case KEY_F12: return "F12"; case KEY_BACKSPACE: return "BKSP"; case KEY_PAUSE: return "PAUSE"; case KEY_EQUALS: return "EQUALS"; case KEY_MINUS: return "MINUS"; case KEY_RSHIFT: return "SHIFT"; case KEY_RCTRL: return "CTRL"; case KEY_RALT: return "ALT"; case KEY_CAPSLOCK: return "CAPS"; case KEY_SCRLCK: return "SCRLCK"; case KEY_HOME: return "HOME"; case KEY_END: return "END"; case KEY_PGUP: return "PGUP"; case KEY_PGDN: return "PGDN"; case KEY_INS: return "INS"; case KEY_DEL: return "DEL"; case KEY_PRTSCR: return "PRTSC"; /* case KEYP_0: return "PAD0"; case KEYP_1: return "PAD1"; case KEYP_2: return "PAD2"; case KEYP_3: return "PAD3"; case KEYP_4: return "PAD4"; case KEYP_5: return "PAD5"; case KEYP_6: return "PAD6"; case KEYP_7: return "PAD7"; case KEYP_8: return "PAD8"; case KEYP_9: return "PAD9"; case KEYP_UPARROW: return "PAD_U"; case KEYP_DOWNARROW: return "PAD_D"; case KEYP_LEFTARROW: return "PAD_L"; case KEYP_RIGHTARROW: return "PAD_R"; case KEYP_MULTIPLY: return "PAD*"; case KEYP_PLUS: return "PAD+"; case KEYP_MINUS: return "PAD-"; case KEYP_DIVIDE: return "PAD/"; */ default: return NULL; } } void TXT_GetKeyDescription(int key, char *buf, size_t buf_len) { const char *keyname; keyname = SpecialKeyName(key); if (keyname != NULL) { TXT_StringCopy(buf, keyname, buf_len); } else if (isprint(key)) { TXT_snprintf(buf, buf_len, "%c", toupper(key)); } else { TXT_snprintf(buf, buf_len, "??%i", key); } } // Searches the desktop screen buffer to determine whether there are any // blinking characters. int TXT_ScreenHasBlinkingChars(void) { int x, y; unsigned char *p; // Check all characters in screen buffer for (y=0; y time_to_next_blink) { // Add one so it is always positive timeout = time_to_next_blink + 1; } } if (timeout == 0) { // We can just wait forever until an event occurs SDL_WaitEvent(NULL); } else { // Sit in a busy loop until the timeout expires or we have to // redraw the blinking screen start_time = SDL_GetTicks(); while (SDL_GetTicks() < start_time + timeout) { if (SDL_PollEvent(NULL) != 0) { // Received an event, so stop waiting break; } // Don't hog the CPU SDL_Delay(1); } } } void TXT_EnableKeyMapping(int enable) { key_mapping = enable; } void TXT_SetWindowTitle(char *title) { SDL_WM_SetCaption(title, NULL); } void TXT_SDL_SetEventCallback(TxtSDLEventCallbackFunc callback, void *user_data) { event_callback = callback; event_callback_data = user_data; } // Safe string functions. void TXT_StringCopy(char *dest, const char *src, size_t dest_len) { if (dest_len < 1) { return; } dest[dest_len - 1] = '\0'; strncpy(dest, src, dest_len - 1); } void TXT_StringConcat(char *dest, const char *src, size_t dest_len) { size_t offset; offset = strlen(dest); if (offset > dest_len) { offset = dest_len; } TXT_StringCopy(dest + offset, src, dest_len - offset); } // On Windows, vsnprintf() is _vsnprintf(). #ifdef _WIN32 #if _MSC_VER < 1400 /* not needed for Visual Studio 2008 */ #define vsnprintf _vsnprintf #endif #endif // Safe, portable vsnprintf(). int TXT_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args) { int result; if (buf_len < 1) { return 0; } // Windows (and other OSes?) has a vsnprintf() that doesn't always // append a trailing \0. So we must do it, and write into a buffer // that is one byte shorter; otherwise this function is unsafe. result = vsnprintf(buf, buf_len, s, args); // If truncated, change the final char in the buffer to a \0. // A negative result indicates a truncated buffer on Windows. if (result < 0 || result >= buf_len) { buf[buf_len - 1] = '\0'; result = buf_len - 1; } return result; } // Safe, portable snprintf(). int TXT_snprintf(char *buf, size_t buf_len, const char *s, ...) { va_list args; int result; va_start(args, s); result = TXT_vsnprintf(buf, buf_len, s, args); va_end(args); return result; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_sdl.h000066400000000000000000000025711257432200600233300ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Text mode emulation in SDL // #ifndef TXT_SDL_H #define TXT_SDL_H // The textscreen API itself doesn't need SDL; however, SDL needs its // headers included where main() is defined. #include "SDL.h" // Event callback function type: a function of this type can be used // to intercept events in the textscreen event processing loop. // Returning 1 will cause the event to be eaten; the textscreen code // will not see it. typedef int (*TxtSDLEventCallbackFunc)(SDL_Event *event, void *user_data); // Set a callback function to call in the SDL event loop. Useful for // intercepting events. Pass callback=NULL to clear an existing // callback function. // user_data is a void pointer to be passed to the callback function. void TXT_SDL_SetEventCallback(TxtSDLEventCallbackFunc callback, void *user_data); #endif /* #ifndef TXT_SDL_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_separator.c000066400000000000000000000046611257432200600245430ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "txt_separator.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" static void TXT_SeparatorSizeCalc(TXT_UNCAST_ARG(separator)) { TXT_CAST_ARG(txt_separator_t, separator); if (separator->label != NULL) { // Minimum width is the string length + two spaces for padding separator->widget.w = strlen(separator->label) + 2; } else { separator->widget.w = 0; } separator->widget.h = 1; } static void TXT_SeparatorDrawer(TXT_UNCAST_ARG(separator)) { TXT_CAST_ARG(txt_separator_t, separator); int x, y; int w; w = separator->widget.w; TXT_GetXY(&x, &y); // Draw separator. Go back one character and draw two extra // to overlap the window borders. TXT_DrawSeparator(x-2, y, w + 4); if (separator->label != NULL) { TXT_GotoXY(x, y); TXT_FGColor(TXT_COLOR_BRIGHT_GREEN); TXT_DrawString(" "); TXT_DrawString(separator->label); TXT_DrawString(" "); } } static void TXT_SeparatorDestructor(TXT_UNCAST_ARG(separator)) { TXT_CAST_ARG(txt_separator_t, separator); free(separator->label); } void TXT_SetSeparatorLabel(txt_separator_t *separator, char *label) { free(separator->label); if (label != NULL) { separator->label = strdup(label); } else { separator->label = NULL; } } txt_widget_class_t txt_separator_class = { TXT_NeverSelectable, TXT_SeparatorSizeCalc, TXT_SeparatorDrawer, NULL, TXT_SeparatorDestructor, NULL, NULL, }; txt_separator_t *TXT_NewSeparator(char *label) { txt_separator_t *separator; separator = malloc(sizeof(txt_separator_t)); TXT_InitWidget(separator, &txt_separator_class); separator->label = NULL; TXT_SetSeparatorLabel(separator, label); return separator; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_separator.h000066400000000000000000000031601257432200600245410ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_SEPARATOR_H #define TXT_SEPARATOR_H /** * @file txt_separator.h * * Horizontal separator widget. */ /** * Horizontal separator. * * A horizontal separator appears as a horizontal line divider across * the length of the window in which it is added. An optional label * allows the separator to be used as a section divider for grouping * related controls. */ typedef struct txt_separator_s txt_separator_t; #include "txt_widget.h" struct txt_separator_s { txt_widget_t widget; char *label; }; extern txt_widget_class_t txt_separator_class; /** * Create a new horizontal separator widget. * * @param label Label to display on the separator. If this is * set to NULL, no label is displayed. * @return The new separator widget. */ txt_separator_t *TXT_NewSeparator(char *label); /** * Change the label on a separator. * * @param separator The separator. * @param label The new label. */ void TXT_SetSeparatorLabel(txt_separator_t *separator, char *label); #endif /* #ifndef TXT_SEPARATOR_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_smallfont.h000066400000000000000000002531231257432200600245460ustar00rootroot00000000000000// // Copyright (c) 1999, Thomas A. Fine // // License to copy, modify, and distribute for both commercial and // non-commercial use is herby granted, provided this notice // is preserved. // // Email to my last name at head.cfa.harvard.edu // http://hea-www.harvard.edu/~fine/ // // ---- // // Copyright (C) 2005-2014 Simon Howard // Copyright (C) 2002-2004 The DOSBox Team // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // // Small (4x8) bitmap font for low resolution displays. // // Based on the Atari-Small font by Tom Fine. The original font was standard // ASCII only; this has been extended to the full Extended ASCII range with // scaled-down versions of the full-size DOS font (txt_font.h) // static unsigned char small_font_data[] = { // ------ Characters 0-31 have been remade to match the ------ // DOS control code ASCII characters. // Character 0: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 1: 0x00, // | | 0x00, // | | 0x50, // | # #| 0x00, // | | 0x70, // | ###| 0x20, // | # | 0x00, // | | 0x00, // | | // Character 2: 0x60, // | ## | 0xf0, // |####| 0xa0, // |# # | 0xf0, // |####| 0x80, // |# | 0xd0, // |## #| 0xf0, // |####| 0x60, // | ## | // Character 3: 0x00, // | | 0x00, // | | 0x50, // | # #| 0x70, // | ###| 0x20, // | # | 0x00, // | | 0x00, // | | 0x00, // | | // Character 4: 0x00, // | | 0x00, // | | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0x00, // | | 0x00, // | | 0x00, // | | // Character 5: 0x00, // | | 0x20, // | # | 0x50, // | # #| 0x50, // | # #| 0x20, // | # | 0x70, // | ###| 0x00, // | | 0x00, // | | // Character 6: 0x00, // | | 0x20, // | # | 0x70, // | ###| 0x70, // | ###| 0x20, // | # | 0x70, // | ###| 0x00, // | | 0x00, // | | // Character 7: 0x00, // | | 0x00, // | | 0x00, // | | 0x60, // | ## | 0x60, // | ## | 0x00, // | | 0x00, // | | 0x00, // | | // Character 8: 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0x90, // |# #| 0x90, // |# #| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| // Character 9: 0x00, // | | 0x00, // | | 0x60, // | ## | 0x90, // |# #| 0x90, // |# #| 0x60, // | ## | 0x00, // | | 0x00, // | | // Character 10: 0xf0, // |####| 0xf0, // |####| 0x90, // |# #| 0x60, // | ## | 0x60, // | ## | 0x90, // |# #| 0xf0, // |####| 0xf0, // |####| // Character 11: 0x00, // | | 0x70, // | ###| 0x20, // | # | 0xe0, // |### | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | 0x00, // | | // Character 12: 0x00, // | | 0x60, // | ## | 0x90, // |# #| 0x60, // | ## | 0xf0, // |####| 0x60, // | ## | 0x60, // | ## | 0x00, // | | // Character 13: 0x00, // | | 0x30, // | ##| 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xe0, // |### | 0xc0, // |## | 0x00, // | | // Character 14: 0x00, // | | 0x70, // | ###| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0xd0, // |## #| 0xc0, // |## | 0x00, // | | // Character 15: 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0x40, // | # | // Character 16: 0x00, // | | 0x80, // |# | 0xc0, // |## | 0xe0, // |### | 0xc0, // |## | 0x80, // |# | 0x00, // | | 0x00, // | | // Character 17: 0x00, // | | 0x10, // | #| 0x30, // | ##| 0x70, // | ###| 0x30, // | ##| 0x10, // | #| 0x00, // | | 0x00, // | | // Character 18: 0x00, // | | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0x00, // | | // Character 19: 0x00, // | | 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x00, // | | 0x50, // | # #| 0x00, // | | 0x00, // | | // Character 20: 0x00, // | | 0xf0, // |####| 0x90, // |# #| 0xd0, // |## #| 0x50, // | # #| 0x50, // | # #| 0x00, // | | 0x00, // | | // Character 21: 0x60, // | ## | 0x80, // |# | 0x60, // | ## | 0x90, // |# #| 0x60, // | ## | 0x10, // | #| 0x60, // | ## | 0x00, // | | // Character 22: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0xf0, // |####| 0xf0, // |####| 0x00, // | | 0x00, // | | // Character 23: 0x00, // | | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0xf0, // |####| // Character 24: 0x00, // | | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x00, // | | // Character 25: 0x00, // | | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0x00, // | | // Character 26: 0x00, // | | 0x40, // | # | 0x20, // | # | 0xf0, // |####| 0x20, // | # | 0x40, // | # | 0x00, // | | 0x00, // | | // Character 27: 0x00, // | | 0x20, // | # | 0x40, // | # | 0xf0, // |####| 0x40, // | # | 0x20, // | # | 0x00, // | | 0x00, // | | // Character 28: 0x00, // | | 0x00, // | | 0x00, // | | 0x80, // |# | 0xe0, // |### | 0x00, // | | 0x00, // | | 0x00, // | | // Character 29: 0x00, // | | 0x00, // | | 0xa0, // |# # | 0xf0, // |####| 0xa0, // |# # | 0x00, // | | 0x00, // | | 0x00, // | | // Character 30: 0x00, // | | 0x00, // | | 0x40, // | # | 0xe0, // |### | 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | // Character 31: 0x00, // | | 0x00, // | | 0xf0, // |####| 0xe0, // |### | 0x40, // | # | 0x00, // | | 0x00, // | | 0x00, // | | // ------ Characters 32-127 are from Atari-Small ------ // Character 32: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 33: 0x00, // | | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | 0x40, // | # | 0x00, // | | // Character 34: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 35: 0x00, // | | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0x00, // | | // Character 36: 0x40, // | # | 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0x20, // | # | 0xa0, // |# # | 0x40, // | # | 0x40, // | # | // Character 37: 0x00, // | | 0xa0, // |# # | 0x20, // | # | 0x40, // | # | 0x40, // | # | 0x80, // |# | 0xa0, // |# # | 0x00, // | | // Character 38: 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0x60, // | ## | 0x00, // | | // Character 39: 0x00, // | | 0x40, // | # | 0x40, // | # | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 40: 0x00, // | | 0x20, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x20, // | # | 0x00, // | | // Character 41: 0x00, // | | 0x80, // |# | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x80, // |# | 0x00, // | | // Character 42: 0x00, // | | 0xa0, // |# # | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0xa0, // |# # | 0x00, // | | 0x00, // | | // Character 43: 0x00, // | | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0x00, // | | 0x00, // | | // Character 44: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x40, // | # | 0x40, // | # | 0x80, // |# | // Character 45: 0x00, // | | 0x00, // | | 0x00, // | | 0xe0, // |### | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 46: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 47: 0x00, // | | 0x20, // | # | 0x20, // | # | 0x40, // | # | 0x40, // | # | 0x80, // |# | 0x80, // |# | 0x00, // | | // Character 48: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 49: 0x00, // | | 0x40, // | # | 0xc0, // |## | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 50: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x20, // | # | 0x40, // | # | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 51: 0x00, // | | 0xe0, // |### | 0x20, // | # | 0x40, // | # | 0x20, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 52: 0x00, // | | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0xe0, // |### | 0x20, // | # | 0x20, // | # | 0x00, // | | // Character 53: 0x00, // | | 0xe0, // |### | 0x80, // |# | 0xc0, // |## | 0x20, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 54: 0x00, // | | 0x60, // | ## | 0x80, // |# | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 55: 0x00, // | | 0xe0, // |### | 0x20, // | # | 0x20, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 56: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 57: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0x60, // | ## | 0x20, // | # | 0xc0, // |## | 0x00, // | | // Character 58: 0x00, // | | 0x00, // | | 0x40, // | # | 0x00, // | | 0x00, // | | 0x40, // | # | 0x00, // | | 0x00, // | | // Character 59: 0x00, // | | 0x00, // | | 0x40, // | # | 0x00, // | | 0x00, // | | 0x40, // | # | 0x80, // |# | 0x00, // | | // Character 60: 0x00, // | | 0x00, // | | 0x20, // | # | 0x40, // | # | 0x80, // |# | 0x40, // | # | 0x20, // | # | 0x00, // | | // Character 61: 0x00, // | | 0x00, // | | 0xe0, // |### | 0x00, // | | 0xe0, // |### | 0x00, // | | 0x00, // | | 0x00, // | | // Character 62: 0x00, // | | 0x00, // | | 0x80, // |# | 0x40, // | # | 0x20, // | # | 0x40, // | # | 0x80, // |# | 0x00, // | | // Character 63: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x20, // | # | 0x40, // | # | 0x00, // | | 0x40, // | # | 0x00, // | | // Character 64: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0x80, // |# | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 65: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 66: 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0x00, // | | // Character 67: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x80, // |# | 0x80, // |# | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 68: 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0x00, // | | // Character 69: 0x00, // | | 0xe0, // |### | 0x80, // |# | 0xe0, // |### | 0x80, // |# | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 70: 0x00, // | | 0xe0, // |### | 0x80, // |# | 0xe0, // |### | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x00, // | | // Character 71: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x80, // |# | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 72: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 73: 0x00, // | | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 74: 0x00, // | | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 75: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 76: 0x00, // | | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 77: 0x00, // | | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 78: 0x00, // | | 0x20, // | # | 0xa0, // |# # | 0xe0, // |### | 0xe0, // |### | 0xa0, // |# # | 0x80, // |# | 0x00, // | | // Character 79: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 80: 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0x80, // |# | 0x80, // |# | 0x00, // | | // Character 81: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0x60, // | ## | 0x00, // | | // Character 82: 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 83: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0x20, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 84: 0x00, // | | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 85: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | // Character 86: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 87: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0x00, // | | // Character 88: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 89: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 90: 0x00, // | | 0xe0, // |### | 0x20, // | # | 0x40, // | # | 0x40, // | # | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 91: 0x00, // | | 0x60, // | ## | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x60, // | ## | 0x00, // | | // Character 92: 0x00, // | | 0x80, // |# | 0x80, // |# | 0x40, // | # | 0x40, // | # | 0x20, // | # | 0x20, // | # | 0x00, // | | // Character 93: 0x00, // | | 0xc0, // |## | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0xc0, // |## | 0x00, // | | // Character 94: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 95: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0xf0, // |####| // Character 96: 0x00, // | | 0x80, // |# | 0x40, // | # | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 97: 0x00, // | | 0x00, // | | 0xc0, // |## | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0x60, // | ## | 0x00, // | | // Character 98: 0x00, // | | 0x80, // |# | 0x80, // |# | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0x00, // | | // Character 99: 0x00, // | | 0x00, // | | 0x60, // | ## | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 100: 0x00, // | | 0x20, // | # | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0xa0, // |# # | 0x60, // | ## | 0x00, // | | // Character 101: 0x00, // | | 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 102: 0x00, // | | 0x20, // | # | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 103: 0x00, // | | 0x00, // | | 0x60, // | ## | 0xa0, // |# # | 0xa0, // |# # | 0x60, // | ## | 0x20, // | # | 0xc0, // |## | // Character 104: 0x00, // | | 0x80, // |# | 0x80, // |# | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 105: 0x00, // | | 0x40, // | # | 0x00, // | | 0xc0, // |## | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 106: 0x00, // | | 0x20, // | # | 0x00, // | | 0x60, // | ## | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xc0, // |## | // Character 107: 0x00, // | | 0x80, // |# | 0x80, // |# | 0xa0, // |# # | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 108: 0x00, // | | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 109: 0x00, // | | 0x00, // | | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 110: 0x00, // | | 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 111: 0x00, // | | 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 112: 0x00, // | | 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xc0, // |## | 0x80, // |# | 0x80, // |# | // Character 113: 0x00, // | | 0x00, // | | 0x60, // | ## | 0xa0, // |# # | 0xa0, // |# # | 0x60, // | ## | 0x20, // | # | 0x20, // | # | // Character 114: 0x00, // | | 0x00, // | | 0x60, // | ## | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x00, // | | // Character 115: 0x00, // | | 0x00, // | | 0x60, // | ## | 0x80, // |# | 0x40, // | # | 0x20, // | # | 0xc0, // |## | 0x00, // | | // Character 116: 0x00, // | | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 117: 0x00, // | | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | // Character 118: 0x00, // | | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 119: 0x00, // | | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0x00, // | | // Character 120: 0x00, // | | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 121: 0x00, // | | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x60, // | ## | 0x20, // | # | 0xc0, // |## | // Character 122: 0x00, // | | 0x00, // | | 0xe0, // |### | 0x20, // | # | 0x40, // | # | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 123: 0x20, // | # | 0x40, // | # | 0x40, // | # | 0x80, // |# | 0x40, // | # | 0x40, // | # | 0x20, // | # | 0x00, // | | // Character 124: 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 125: 0x80, // |# | 0x40, // | # | 0x40, // | # | 0x20, // | # | 0x40, // | # | 0x40, // | # | 0x80, // |# | 0x00, // | | // Character 126: 0x00, // | | 0x50, // | # #| 0xa0, // |# # | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 127: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | 0x00, // | | // ------ Characters 128-255 are scaled-down from the full size ------ // DOS font. Some of these have been fixed up, the rest // need to be fixed up :-) // Character 128: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0x80, // |# | 0x80, // |# | 0xa0, // |# # | 0x40, // | # | 0xc0, // |## | // Character 129: 0xa0, // |# # | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | // Character 130: 0x40, // | # | 0x80, // |# | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 131: 0x20, // | # | 0x50, // | # #| 0xc0, // |## | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0x60, // | ## | 0x00, // | | // Character 132: 0xa0, // |# # | 0x00, // | | 0xc0, // |## | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0x60, // | ## | 0x00, // | | // Character 133: 0x40, // | # | 0x20, // | # | 0xc0, // |## | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0x60, // | ## | 0x00, // | | // Character 134: 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0x60, // | ## | 0x00, // | | // Character 135: 0x00, // | | 0x00, // | | 0x60, // | ## | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x60, // | ## | 0xc0, // |## | // Character 136: 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 137: 0xa0, // |# # | 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 138: 0x40, // | # | 0x20, // | # | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 139: 0x00, // | | 0xa0, // |# # | 0x00, // | | 0xc0, // |## | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 140: 0x40, // | # | 0xa0, // |# # | 0x00, // | | 0xc0, // |## | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 141: 0x40, // | # | 0x20, // | # | 0x00, // | | 0xc0, // |## | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 142: 0xa0, // |# # | 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 143: 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 144: 0x20, // | # | 0x40, // | # | 0xe0, // |### | 0x80, // |# | 0xc0, // |## | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 145: 0x00, // | | 0x00, // | | 0xb0, // |# ##| 0x50, // | # #| 0x70, // | ###| 0xa0, // |# # | 0x70, // | ###| 0x00, // | | // Character 146: 0x00, // | | 0x70, // | ###| 0xa0, // |# # | 0xf0, // |####| 0xa0, // |# # | 0xa0, // |# # | 0xb0, // |# ##| 0x00, // | | // Character 147: 0x40, // | # | 0xa0, // |# # | 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 148: 0xa0, // |# # | 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 149: 0x40, // | # | 0x20, // | # | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 150: 0x40, // | # | 0xa0, // |# # | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | // Character 151: 0x40, // | # | 0x20, // | # | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | // Character 152: 0xa0, // |# # | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x60, // | ## | 0x20, // | # | 0xc0, // |## | // Character 153: 0xa0, // |# # | 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 154: 0xa0, // |# # | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | // Character 155: 0x00, // | | 0x40, // | # | 0x60, // | ## | 0x80, // |# | 0x80, // |# | 0x60, // | ## | 0x40, // | # | 0x00, // | | // Character 156: 0x30, // | ##| 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0xf0, // |####| 0x00, // | | // Character 157: 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 158: 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xc0, // |## | 0xa0, // |# # | 0xb0, // |# ##| 0xa0, // |# # | 0x00, // | | // Character 159: 0x10, // | #| 0x20, // | # | 0x20, // | # | 0x70, // | ###| 0x20, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 160: 0x20, // | # | 0x40, // | # | 0xc0, // |## | 0x20, // | # | 0x60, // | ## | 0xa0, // |# # | 0x60, // | ## | 0x00, // | | // Character 161: 0x20, // | # | 0x40, // | # | 0x00, // | | 0xc0, // |## | 0x40, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 162: 0x40, // | # | 0x80, // |# | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 163: 0x20, // | # | 0x40, // | # | 0x00, // | | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xe0, // |### | 0x00, // | | // Character 164: 0x50, // | # #| 0xa0, // |# # | 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 165: 0x50, // | # #| 0xa0, // |# # | 0x00, // | | 0x90, // |# #| 0xd0, // |## #| 0xb0, // |# ##| 0x90, // |# #| 0x00, // | | // Character 166: 0x60, // | ## | 0xa0, // |# # | 0x70, // | ###| 0x00, // | | 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | // Character 167: 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | 0xe0, // |### | 0x00, // | | 0x00, // | | 0x00, // | | // Character 168: 0x00, // | | 0x40, // | # | 0x00, // | | 0x40, // | # | 0x80, // |# | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 169: 0x00, // | | 0x00, // | | 0x00, // | | 0xe0, // |### | 0x80, // |# | 0x80, // |# | 0x00, // | | 0x00, // | | // Character 170: 0x00, // | | 0x00, // | | 0x00, // | | 0x70, // | ###| 0x10, // | #| 0x10, // | #| 0x00, // | | 0x00, // | | // Character 171: 0x80, // |# | 0x80, // |# | 0xa0, // |# # | 0x40, // | # | 0xb0, // |# ##| 0x10, // | #| 0x20, // | # | 0x30, // | ##| // Character 172: 0x80, // |# | 0x80, // |# | 0xa0, // |# # | 0x40, // | # | 0x80, // |# | 0x50, // | # #| 0x70, // | ###| 0x10, // | #| // Character 173: 0x00, // | | 0x40, // | # | 0x00, // | | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x40, // | # | 0x00, // | | // Character 174: 0x00, // | | 0x00, // | | 0x00, // | | 0x50, // | # #| 0xa0, // |# # | 0x50, // | # #| 0x00, // | | 0x00, // | | // Character 175: 0x00, // | | 0x00, // | | 0x00, // | | 0xa0, // |# # | 0x50, // | # #| 0xa0, // |# # | 0x00, // | | 0x00, // | | // Character 176: 0x10, // | #| 0x40, // | # | 0x10, // | #| 0x40, // | # | 0x10, // | #| 0x40, // | # | 0x10, // | #| 0x40, // | # | // Character 177: 0x50, // | # #| 0xa0, // |# # | 0x50, // | # #| 0xa0, // |# # | 0x50, // | # #| 0xa0, // |# # | 0x50, // | # #| 0xa0, // |# # | // Character 178: 0xd0, // |## #| 0x70, // | ###| 0xd0, // |## #| 0x70, // | ###| 0xd0, // |## #| 0x70, // | ###| 0xd0, // |## #| 0x70, // | ###| // Character 179: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 180: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xe0, // |### | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 181: 0x20, // | # | 0x20, // | # | 0xe0, // |### | 0x20, // | # | 0xe0, // |### | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 182: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0xd0, // |## #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 183: 0x00, // | | 0x00, // | | 0x00, // | | 0xf0, // |####| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 184: 0x00, // | | 0x00, // | | 0xe0, // |### | 0x20, // | # | 0xe0, // |### | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 185: 0x50, // | # #| 0x50, // | # #| 0xd0, // |## #| 0x10, // | #| 0xd0, // |## #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 186: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 187: 0x00, // | | 0x00, // | | 0xf0, // |####| 0x10, // | #| 0xd0, // |## #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 188: 0x50, // | # #| 0x50, // | # #| 0xd0, // |## #| 0x10, // | #| 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | // Character 189: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 190: 0x20, // | # | 0x20, // | # | 0xe0, // |### | 0x20, // | # | 0xe0, // |### | 0x00, // | | 0x00, // | | 0x00, // | | // Character 191: 0x00, // | | 0x00, // | | 0x00, // | | 0xe0, // |### | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 192: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x30, // | ##| 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 193: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 194: 0x00, // | | 0x00, // | | 0x00, // | | 0xf0, // |####| 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 195: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x30, // | ##| 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 196: 0x00, // | | 0x00, // | | 0x00, // | | 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 197: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xf0, // |####| 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 198: 0x20, // | # | 0x20, // | # | 0x30, // | ##| 0x20, // | # | 0x30, // | ##| 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 199: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 200: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x40, // | # | 0x70, // | ###| 0x00, // | | 0x00, // | | 0x00, // | | // Character 201: 0x00, // | | 0x00, // | | 0x70, // | ###| 0x40, // | # | 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 202: 0x50, // | # #| 0x50, // | # #| 0xd0, // |## #| 0x00, // | | 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | // Character 203: 0x00, // | | 0x00, // | | 0xf0, // |####| 0x00, // | | 0xd0, // |## #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 204: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 205: 0x00, // | | 0x00, // | | 0xf0, // |####| 0x00, // | | 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | // Character 206: 0x50, // | # #| 0x50, // | # #| 0xd0, // |## #| 0x00, // | | 0xd0, // |## #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 207: 0x20, // | # | 0x20, // | # | 0xf0, // |####| 0x00, // | | 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | // Character 208: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 209: 0x00, // | | 0x00, // | | 0xf0, // |####| 0x00, // | | 0xf0, // |####| 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 210: 0x00, // | | 0x00, // | | 0x00, // | | 0xf0, // |####| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 211: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x70, // | ###| 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 212: 0x20, // | # | 0x20, // | # | 0x30, // | ##| 0x20, // | # | 0x30, // | ##| 0x00, // | | 0x00, // | | 0x00, // | | // Character 213: 0x00, // | | 0x00, // | | 0x30, // | ##| 0x20, // | # | 0x30, // | ##| 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 214: 0x00, // | | 0x00, // | | 0x00, // | | 0x70, // | ###| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 215: 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0xf0, // |####| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| 0x50, // | # #| // Character 216: 0x20, // | # | 0x20, // | # | 0xf0, // |####| 0x20, // | # | 0xf0, // |####| 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 217: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xe0, // |### | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 218: 0x00, // | | 0x00, // | | 0x00, // | | 0x30, // | ##| 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 219: 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| // Character 220: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| // Character 221: 0xc0, // |## | 0xc0, // |## | 0xc0, // |## | 0xc0, // |## | 0xc0, // |## | 0xc0, // |## | 0xc0, // |## | 0xc0, // |## | // Character 222: 0x30, // | ##| 0x30, // | ##| 0x30, // | ##| 0x30, // | ##| 0x30, // | ##| 0x30, // | ##| 0x30, // | ##| 0x30, // | ##| // Character 223: 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 224: 0x00, // | | 0x00, // | | 0x00, // | | 0x50, // | # #| 0xa0, // |# # | 0xa0, // |# # | 0x50, // | # #| 0x00, // | | // Character 225: 0x00, // | | 0xc0, // |## | 0xa0, // |# # | 0xc0, // |## | 0xa0, // |# # | 0x90, // |# #| 0xa0, // |# # | 0x00, // | | // Character 226: 0x00, // | | 0xf0, // |####| 0x90, // |# #| 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x80, // |# | 0x00, // | | // Character 227: 0x00, // | | 0x00, // | | 0xf0, // |####| 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 228: 0x00, // | | 0x00, // | | 0xe0, // |### | 0x80, // |# | 0x40, // | # | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 229: 0x00, // | | 0x00, // | | 0x70, // | ###| 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 230: 0x00, // | | 0x00, // | | 0x50, // | # #| 0x50, // | # #| 0x70, // | ###| 0x40, // | # | 0x80, // |# | 0x00, // | | // Character 231: 0x00, // | | 0x00, // | | 0x50, // | # #| 0xa0, // |# # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x00, // | | // Character 232: 0x00, // | | 0xe0, // |### | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0xe0, // |### | 0x00, // | | // Character 233: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 234: 0x00, // | | 0x60, // | ## | 0x90, // |# #| 0x90, // |# #| 0x60, // | ## | 0x60, // | ## | 0xf0, // |####| 0x00, // | | // Character 235: 0x00, // | | 0x60, // | ## | 0x80, // |# | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | // Character 236: 0x00, // | | 0x00, // | | 0x60, // | ## | 0xb0, // |# ##| 0xd0, // |## #| 0x60, // | ## | 0x00, // | | 0x00, // | | // Character 237: 0x00, // | | 0x10, // | #| 0xf0, // |####| 0x90, // |# #| 0x90, // |# #| 0xf0, // |####| 0x80, // |# | 0x00, // | | // Character 238: 0x00, // | | 0x60, // | ## | 0x80, // |# | 0xe0, // |### | 0x80, // |# | 0x80, // |# | 0x60, // | ## | 0x00, // | | // Character 239: 0x00, // | | 0x40, // | # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | // Character 240: 0x00, // | | 0xe0, // |### | 0x00, // | | 0xe0, // |### | 0x00, // | | 0xe0, // |### | 0x00, // | | 0x00, // | | // Character 241: 0x00, // | | 0x40, // | # | 0xe0, // |### | 0x40, // | # | 0x00, // | | 0xe0, // |### | 0x00, // | | 0x00, // | | // Character 242: 0x00, // | | 0x80, // |# | 0x40, // | # | 0x20, // | # | 0x40, // | # | 0x80, // |# | 0xe0, // |### | 0x00, // | | // Character 243: 0x00, // | | 0x20, // | # | 0x40, // | # | 0x80, // |# | 0x40, // | # | 0x20, // | # | 0xe0, // |### | 0x00, // | | // Character 244: 0x00, // | | 0x10, // | #| 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | // Character 245: 0x20, // | # | 0x20, // | # | 0x20, // | # | 0x20, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | 0x00, // | | // Character 246: 0x00, // | | 0x00, // | | 0x40, // | # | 0x00, // | | 0xe0, // |### | 0x00, // | | 0x40, // | # | 0x00, // | | // Character 247: 0x00, // | | 0x50, // | # #| 0xa0, // |# # | 0x00, // | | 0x50, // | # #| 0xa0, // |# # | 0x00, // | | 0x00, // | | // Character 248: 0x40, // | # | 0xa0, // |# # | 0x40, // | # | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 249: 0x00, // | | 0x00, // | | 0x00, // | | 0x60, // | ## | 0x60, // | ## | 0x00, // | | 0x00, // | | 0x00, // | | // Character 250: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x40, // | # | 0x00, // | | 0x00, // | | 0x00, // | | // Character 251: 0x30, // | ##| 0x20, // | # | 0x20, // | # | 0xa0, // |# # | 0x60, // | ## | 0x20, // | # | 0x00, // | | 0x00, // | | // Character 252: 0xe0, // |### | 0xa0, // |# # | 0xa0, // |# # | 0xa0, // |# # | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 253: 0xc0, // |## | 0x20, // | # | 0x40, // | # | 0xe0, // |### | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | // Character 254: 0x00, // | | 0x00, // | | 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0xf0, // |####| 0x00, // | | 0x00, // | | // Character 255: 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | 0x00, // | | }; static txt_font_t small_font = { small_font_data, 4, // width 8 // height }; chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_spinctrl.c000066400000000000000000000235201257432200600243740ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include #include #include "doomkeys.h" #include "txt_spinctrl.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" // Generate the format string to be used for displaying floats static void FloatFormatString(float step, char *buf, size_t buf_len) { int precision; precision = (int) ceil(-log(step) / log(10)); if (precision > 0) { TXT_snprintf(buf, buf_len, "%%.%if", precision); } else { TXT_StringCopy(buf, "%.1f", buf_len); } } // Number of characters needed to represent a character static unsigned int IntWidth(int val) { char buf[25]; TXT_snprintf(buf, sizeof(buf), "%i", val); return strlen(buf); } static unsigned int FloatWidth(float val, float step) { unsigned int precision; unsigned int result; // Calculate the width of the int value result = IntWidth((int) val); // Add a decimal part if the precision specifies it precision = (unsigned int) ceil(-log(step) / log(10)); if (precision > 0) { result += precision + 1; } return result; } // Returns the minimum width of the input box static unsigned int SpinControlWidth(txt_spincontrol_t *spincontrol) { unsigned int minw, maxw; switch (spincontrol->type) { case TXT_SPINCONTROL_FLOAT: minw = FloatWidth(spincontrol->min.f, spincontrol->step.f); maxw = FloatWidth(spincontrol->max.f, spincontrol->step.f); break; default: case TXT_SPINCONTROL_INT: minw = IntWidth(spincontrol->min.i); maxw = IntWidth(spincontrol->max.i); break; } // Choose the wider of the two values. Add one so that there is always // space for the cursor when editing. if (minw > maxw) { return minw; } else { return maxw; } } static void TXT_SpinControlSizeCalc(TXT_UNCAST_ARG(spincontrol)) { TXT_CAST_ARG(txt_spincontrol_t, spincontrol); spincontrol->widget.w = SpinControlWidth(spincontrol) + 5; spincontrol->widget.h = 1; } static void SetBuffer(txt_spincontrol_t *spincontrol) { char format[25]; switch (spincontrol->type) { case TXT_SPINCONTROL_INT: TXT_snprintf(spincontrol->buffer, spincontrol->buffer_len, "%i", spincontrol->value->i); break; case TXT_SPINCONTROL_FLOAT: FloatFormatString(spincontrol->step.f, format, sizeof(format)); TXT_snprintf(spincontrol->buffer, spincontrol->buffer_len, format, spincontrol->value->f); break; } } static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol)) { TXT_CAST_ARG(txt_spincontrol_t, spincontrol); unsigned int i; unsigned int padding; txt_saved_colors_t colors; int focused; focused = spincontrol->widget.focused; TXT_SaveColors(&colors); TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); TXT_DrawString("\x1b "); TXT_RestoreColors(&colors); // Choose background color if (focused && spincontrol->editing) { TXT_BGColor(TXT_COLOR_BLACK, 0); } else { TXT_SetWidgetBG(spincontrol); } if (!spincontrol->editing) { SetBuffer(spincontrol); } i = 0; padding = spincontrol->widget.w - strlen(spincontrol->buffer) - 4; while (i < padding) { TXT_DrawString(" "); ++i; } TXT_DrawString(spincontrol->buffer); i += strlen(spincontrol->buffer); while (i < spincontrol->widget.w - 4) { TXT_DrawString(" "); ++i; } TXT_RestoreColors(&colors); TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); TXT_DrawString(" \x1a"); } static void TXT_SpinControlDestructor(TXT_UNCAST_ARG(spincontrol)) { TXT_CAST_ARG(txt_spincontrol_t, spincontrol); free(spincontrol->buffer); } static void AddCharacter(txt_spincontrol_t *spincontrol, int key) { if (strlen(spincontrol->buffer) < SpinControlWidth(spincontrol)) { spincontrol->buffer[strlen(spincontrol->buffer) + 1] = '\0'; spincontrol->buffer[strlen(spincontrol->buffer)] = key; } } static void Backspace(txt_spincontrol_t *spincontrol) { if (strlen(spincontrol->buffer) > 0) { spincontrol->buffer[strlen(spincontrol->buffer) - 1] = '\0'; } } static void EnforceLimits(txt_spincontrol_t *spincontrol) { switch (spincontrol->type) { case TXT_SPINCONTROL_INT: if (spincontrol->value->i > spincontrol->max.i) spincontrol->value->i = spincontrol->max.i; else if (spincontrol->value->i < spincontrol->min.i) spincontrol->value->i = spincontrol->min.i; break; case TXT_SPINCONTROL_FLOAT: if (spincontrol->value->f > spincontrol->max.f) spincontrol->value->f = spincontrol->max.f; else if (spincontrol->value->f < spincontrol->min.f) spincontrol->value->f = spincontrol->min.f; break; } } static void FinishEditing(txt_spincontrol_t *spincontrol) { switch (spincontrol->type) { case TXT_SPINCONTROL_INT: spincontrol->value->i = atoi(spincontrol->buffer); break; case TXT_SPINCONTROL_FLOAT: spincontrol->value->f = (float) atof(spincontrol->buffer); break; } spincontrol->editing = 0; EnforceLimits(spincontrol); } static int TXT_SpinControlKeyPress(TXT_UNCAST_ARG(spincontrol), int key) { TXT_CAST_ARG(txt_spincontrol_t, spincontrol); // Enter to enter edit mode if (spincontrol->editing) { if (key == KEY_ENTER) { FinishEditing(spincontrol); return 1; } if (key == KEY_ESCAPE) { // Abort without saving value spincontrol->editing = 0; return 1; } if (isdigit(key) || key == '-' || key == '.') { AddCharacter(spincontrol, key); return 1; } if (key == KEY_BACKSPACE) { Backspace(spincontrol); return 1; } } else { // Non-editing mode if (key == KEY_ENTER) { spincontrol->editing = 1; TXT_StringCopy(spincontrol->buffer, "", spincontrol->buffer_len); return 1; } if (key == KEY_LEFTARROW) { switch (spincontrol->type) { case TXT_SPINCONTROL_INT: spincontrol->value->i -= spincontrol->step.i; break; case TXT_SPINCONTROL_FLOAT: spincontrol->value->f -= spincontrol->step.f; break; } EnforceLimits(spincontrol); return 1; } if (key == KEY_RIGHTARROW) { switch (spincontrol->type) { case TXT_SPINCONTROL_INT: spincontrol->value->i += spincontrol->step.i; break; case TXT_SPINCONTROL_FLOAT: spincontrol->value->f += spincontrol->step.f; break; } EnforceLimits(spincontrol); return 1; } } return 0; } static void TXT_SpinControlMousePress(TXT_UNCAST_ARG(spincontrol), int x, int y, int b) { TXT_CAST_ARG(txt_spincontrol_t, spincontrol); unsigned int rel_x; rel_x = x - spincontrol->widget.x; if (rel_x < 2) { TXT_SpinControlKeyPress(spincontrol, KEY_LEFTARROW); } else if (rel_x >= spincontrol->widget.w - 2) { TXT_SpinControlKeyPress(spincontrol, KEY_RIGHTARROW); } } static void TXT_SpinControlFocused(TXT_UNCAST_ARG(spincontrol), int focused) { TXT_CAST_ARG(txt_spincontrol_t, spincontrol); FinishEditing(spincontrol); } txt_widget_class_t txt_spincontrol_class = { TXT_AlwaysSelectable, TXT_SpinControlSizeCalc, TXT_SpinControlDrawer, TXT_SpinControlKeyPress, TXT_SpinControlDestructor, TXT_SpinControlMousePress, NULL, TXT_SpinControlFocused, }; static txt_spincontrol_t *TXT_BaseSpinControl(void) { txt_spincontrol_t *spincontrol; spincontrol = malloc(sizeof(txt_spincontrol_t)); TXT_InitWidget(spincontrol, &txt_spincontrol_class); spincontrol->buffer_len = 25; spincontrol->buffer = malloc(spincontrol->buffer_len); TXT_StringCopy(spincontrol->buffer, "", spincontrol->buffer_len); spincontrol->editing = 0; return spincontrol; } txt_spincontrol_t *TXT_NewSpinControl(int *value, int min, int max) { txt_spincontrol_t *spincontrol; spincontrol = TXT_BaseSpinControl(); spincontrol->type = TXT_SPINCONTROL_INT; spincontrol->value = (void *) value; spincontrol->min.i = min; spincontrol->max.i = max; spincontrol->step.i = 1; return spincontrol; } txt_spincontrol_t *TXT_NewFloatSpinControl(float *value, float min, float max) { txt_spincontrol_t *spincontrol; spincontrol = TXT_BaseSpinControl(); spincontrol->type = TXT_SPINCONTROL_FLOAT; spincontrol->value = (void *) value; spincontrol->min.f = min; spincontrol->max.f = max; spincontrol->step.f = 0.1f; return spincontrol; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_spinctrl.h000066400000000000000000000041471257432200600244050ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_SPINCONTROL_H #define TXT_SPINCONTROL_H /** * @file txt_spinctrl.h * * Spin control widget. */ /** * Spin control widget. * * A spin control widget works as an input box that can be used to * set numeric values, but also has buttons that allow its value * to be increased or decreased. */ typedef struct txt_spincontrol_s txt_spincontrol_t; typedef enum { TXT_SPINCONTROL_INT, TXT_SPINCONTROL_FLOAT, } txt_spincontrol_type_t; #include "txt_widget.h" struct txt_spincontrol_s { txt_widget_t widget; txt_spincontrol_type_t type; union { float f; int i; } min, max, *value, step; int editing; char *buffer; size_t buffer_len; }; /** * Create a new spin control widget tracking an integer value. * * @param value Pointer to the variable containing the value * displayed in the widget. * @param min Minimum value that may be set. * @param max Maximum value that may be set. * @return Pointer to the new spin control widget. */ txt_spincontrol_t *TXT_NewSpinControl(int *value, int min, int max); /** * Create a new spin control widget tracking a float value. * * @param value Pointer to the variable containing the value * displayed in the widget. * @param min Minimum value that may be set. * @param max Maximum value that may be set. * @return Pointer to the new spin control widget. */ txt_spincontrol_t *TXT_NewFloatSpinControl(float *value, float min, float max); #endif /* #ifndef TXT_SPINCONTROL_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_strut.c000066400000000000000000000030721257432200600237170ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "doomkeys.h" #include "txt_strut.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" static void TXT_StrutSizeCalc(TXT_UNCAST_ARG(strut)) { TXT_CAST_ARG(txt_strut_t, strut); // Minimum width is the string length + two spaces for padding strut->widget.w = strut->width; strut->widget.h = strut->height; } static void TXT_StrutDrawer(TXT_UNCAST_ARG(strut)) { // Nothing is drawn for a strut. } static void TXT_StrutDestructor(TXT_UNCAST_ARG(strut)) { } static int TXT_StrutKeyPress(TXT_UNCAST_ARG(strut), int key) { return 0; } txt_widget_class_t txt_strut_class = { TXT_NeverSelectable, TXT_StrutSizeCalc, TXT_StrutDrawer, TXT_StrutKeyPress, TXT_StrutDestructor, NULL, NULL, }; txt_strut_t *TXT_NewStrut(int width, int height) { txt_strut_t *strut; strut = malloc(sizeof(txt_strut_t)); TXT_InitWidget(strut, &txt_strut_class); strut->width = width; strut->height = height; return strut; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_strut.h000066400000000000000000000023001257432200600237150ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_STRUT_H #define TXT_STRUT_H /** * @file txt_strut.h * * Strut widget. */ /** * Strut widget. * * A strut is a widget that takes up a fixed amount of space. It can * be visualised as a transparent box. Struts are used to provide * spacing between widgets. */ typedef struct txt_strut_s txt_strut_t; #include "txt_widget.h" struct txt_strut_s { txt_widget_t widget; int width; int height; }; /** * Create a new strut. * * @param width Width of the strut, in characters. * @param height Height of the strut, in characters. */ txt_strut_t *TXT_NewStrut(int width, int height); #endif /* #ifndef TXT_STRUT_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_table.c000066400000000000000000000510011257432200600236200ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "doomkeys.h" #include "txt_desktop.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_separator.h" #include "txt_strut.h" #include "txt_table.h" // Remove all entries from a table void TXT_ClearTable(TXT_UNCAST_ARG(table)) { TXT_CAST_ARG(txt_table_t, table); int i; // Free all widgets // Skip over the first (num_columns) widgets in the array, as these // are the column struts used to control column width for (i=table->columns; inum_widgets; ++i) { if (table->widgets[i] != NULL) { TXT_DestroyWidget(table->widgets[i]); } } // Shrink the table to just the column strut widgets table->num_widgets = table->columns; } static void TXT_TableDestructor(TXT_UNCAST_ARG(table)) { TXT_CAST_ARG(txt_table_t, table); TXT_ClearTable(table); } static int TableRows(txt_table_t *table) { return (table->num_widgets + table->columns - 1) / table->columns; } static void CalcRowColSizes(txt_table_t *table, unsigned int *row_heights, unsigned int *col_widths) { int x, y; int rows; txt_widget_t *widget; rows = TableRows(table); memset(col_widths, 0, sizeof(int) * table->columns); for (y=0; ycolumns; ++x) { if (y * table->columns + x >= table->num_widgets) break; widget = table->widgets[y * table->columns + x]; // NULL represents an empty spacer if (widget != NULL) { TXT_CalcWidgetSize(widget); if (widget->h > row_heights[y]) row_heights[y] = widget->h; if (widget->w > col_widths[x]) col_widths[x] = widget->w; } } } } static void TXT_CalcTableSize(TXT_UNCAST_ARG(table)) { TXT_CAST_ARG(txt_table_t, table); unsigned int *column_widths; unsigned int *row_heights; int x, y; int rows; rows = TableRows(table); row_heights = malloc(sizeof(int) * rows); column_widths = malloc(sizeof(int) * table->columns); CalcRowColSizes(table, row_heights, column_widths); table->widget.w = 0; for (x=0; xcolumns; ++x) { table->widget.w += column_widths[x]; } table->widget.h = 0; for (y=0; ywidget.h += row_heights[y]; } free(row_heights); free(column_widths); } void TXT_AddWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_table_t, table); TXT_CAST_ARG(txt_widget_t, widget); if (table->num_widgets > 0) { txt_widget_t *last_widget; last_widget = table->widgets[table->num_widgets - 1]; if (widget != NULL && last_widget != NULL && widget->widget_class == &txt_separator_class && last_widget->widget_class == &txt_separator_class) { // The previous widget added was a separator; replace // it with this one. // // This way, if the first widget added to a window is // a separator, it replaces the "default" separator that // the window itself adds on creation. table->widgets[table->num_widgets - 1] = widget; TXT_DestroyWidget(last_widget); return; } } table->widgets = realloc(table->widgets, sizeof(txt_widget_t *) * (table->num_widgets + 1)); table->widgets[table->num_widgets] = widget; ++table->num_widgets; // Maintain parent pointer. if (widget != NULL) { widget->parent = &table->widget; } } // Add multiple widgets to a table. void TXT_AddWidgets(TXT_UNCAST_ARG(table), ...) { TXT_CAST_ARG(txt_table_t, table); va_list args; txt_widget_t *widget; va_start(args, TXT_UNCAST_ARG_NAME(table)); // Keep adding widgets until a NULL is reached. for (;;) { widget = va_arg(args, txt_widget_t *); if (widget == NULL) { break; } TXT_AddWidget(table, widget); } va_end(args); } static int SelectableCell(txt_table_t *table, int x, int y) { txt_widget_t *widget; int i; if (x < 0 || x >= table->columns) { return 0; } i = y * table->columns + x; if (i >= 0 && i < table->num_widgets) { widget = table->widgets[i]; return widget != NULL && TXT_SelectableWidget(widget) && widget->visible; } return 0; } // Tries to locate a selectable widget in the given row, returning // the column number of the first column available or -1 if none are // available in the given row. // // Starts from start_col, then searches nearby columns. static int FindSelectableColumn(txt_table_t *table, int row, int start_col) { int x; for (x=0; xcolumns; ++x) { // Search to the right if (SelectableCell(table, start_col + x, row)) { return start_col + x; } // Search to the left if (SelectableCell(table, start_col - x, row)) { return start_col - x; } } // None available return -1; } // Change the selected widget. static void ChangeSelection(txt_table_t *table, int x, int y) { txt_widget_t *cur_widget; txt_widget_t *new_widget; int i; // No change? if (x == table->selected_x && y == table->selected_y) { return; } // Unfocus current widget: i = table->selected_y * table->columns + table->selected_x; if (i < table->num_widgets) { cur_widget = table->widgets[i]; if (table->widget.focused && cur_widget != NULL) { TXT_SetWidgetFocus(cur_widget, 0); } } // Focus new widget. new_widget = table->widgets[y * table->columns + x]; table->selected_x = x; table->selected_y = y; if (table->widget.focused && new_widget != NULL) { TXT_SetWidgetFocus(new_widget, 1); } } static int TXT_TableKeyPress(TXT_UNCAST_ARG(table), int key) { TXT_CAST_ARG(txt_table_t, table); int selected; int rows; rows = TableRows(table); // Send to the currently selected widget first selected = table->selected_y * table->columns + table->selected_x; if (selected >= 0 && selected < table->num_widgets) { if (table->widgets[selected] != NULL && TXT_SelectableWidget(table->widgets[selected]) && TXT_WidgetKeyPress(table->widgets[selected], key)) { return 1; } } if (key == KEY_DOWNARROW) { int new_x, new_y; // Move cursor down to the next selectable widget for (new_y = table->selected_y + 1; new_y < rows; ++new_y) { new_x = FindSelectableColumn(table, new_y, table->selected_x); if (new_x >= 0) { // Found a selectable widget in this column! ChangeSelection(table, new_x, new_y); return 1; } } } if (key == KEY_UPARROW) { int new_x, new_y; // Move cursor up to the next selectable widget for (new_y = table->selected_y - 1; new_y >= 0; --new_y) { new_x = FindSelectableColumn(table, new_y, table->selected_x); if (new_x >= 0) { // Found a selectable widget in this column! ChangeSelection(table, new_x, new_y); return 1; } } } if (key == KEY_LEFTARROW) { int new_x; // Move cursor left for (new_x = table->selected_x - 1; new_x >= 0; --new_x) { if (SelectableCell(table, new_x, table->selected_y)) { // Found a selectable widget! ChangeSelection(table, new_x, table->selected_y); return 1; } } } if (key == KEY_RIGHTARROW) { int new_x; // Move cursor left for (new_x = table->selected_x + 1; new_x < table->columns; ++new_x) { if (SelectableCell(table, new_x, table->selected_y)) { // Found a selectable widget! ChangeSelection(table, new_x, table->selected_y); return 1; } } } return 0; } // Check the currently selected widget in the table is valid. static void CheckValidSelection(txt_table_t *table) { int rows; int new_x, new_y; rows = TableRows(table); for (new_y = table->selected_y; new_y < rows; ++new_y) { new_x = FindSelectableColumn(table, new_y, table->selected_x); if (new_x >= 0) { // Found a selectable column. ChangeSelection(table, new_x, new_y); break; } } } static void LayoutCell(txt_table_t *table, int x, int y, int col_width, int draw_x, int draw_y) { txt_widget_t *widget; widget = table->widgets[y * table->columns + x]; // Adjust x position based on alignment property switch (widget->align) { case TXT_HORIZ_LEFT: widget->w = col_width; break; case TXT_HORIZ_CENTER: TXT_CalcWidgetSize(widget); // Separators are always drawn left-aligned. if (widget->widget_class != &txt_separator_class) { draw_x += (col_width - widget->w) / 2; } break; case TXT_HORIZ_RIGHT: TXT_CalcWidgetSize(widget); if (widget->widget_class != &txt_separator_class) { draw_x += col_width - widget->w; } break; } // Set the position for this widget widget->x = draw_x; widget->y = draw_y; // Recursively lay out any widgets contained in the widget TXT_LayoutWidget(widget); } static void TXT_TableLayout(TXT_UNCAST_ARG(table)) { TXT_CAST_ARG(txt_table_t, table); unsigned int *column_widths; unsigned int *row_heights; int draw_x, draw_y; int x, y; int i; int rows; // Work out the column widths and row heights rows = TableRows(table); column_widths = malloc(sizeof(int) * table->columns); row_heights = malloc(sizeof(int) * rows); CalcRowColSizes(table, row_heights, column_widths); // If this table only has one column, expand column size to fit // the display width. Ensures that separators reach the window edges // when drawing windows. if (table->columns == 1) { column_widths[0] = table->widget.w; } // Draw all cells draw_y = table->widget.y; for (y=0; ywidget.x; for (x=0; xcolumns; ++x) { i = y * table->columns + x; if (i >= table->num_widgets) break; if (table->widgets[i] != NULL) { LayoutCell(table, x, y, column_widths[x], draw_x, draw_y); } draw_x += column_widths[x]; } draw_y += row_heights[y]; } free(row_heights); free(column_widths); } static void TXT_TableDrawer(TXT_UNCAST_ARG(table)) { TXT_CAST_ARG(txt_table_t, table); txt_widget_t *widget; int i; // Check the table's current selection points at something valid before // drawing. CheckValidSelection(table); // Draw all cells for (i=0; inum_widgets; ++i) { widget = table->widgets[i]; if (widget != NULL) { TXT_GotoXY(widget->x, widget->y); TXT_DrawWidget(widget); } } } // Responds to mouse presses static void TXT_TableMousePress(TXT_UNCAST_ARG(table), int x, int y, int b) { TXT_CAST_ARG(txt_table_t, table); txt_widget_t *widget; int i; for (i=0; inum_widgets; ++i) { widget = table->widgets[i]; // NULL widgets are spacers if (widget != NULL) { if (x >= widget->x && x < (signed) (widget->x + widget->w) && y >= widget->y && y < (signed) (widget->y + widget->h)) { // This is the widget that was clicked! // Select the cell if the widget is selectable if (TXT_SelectableWidget(widget)) { ChangeSelection(table, i % table->columns, i / table->columns); } // Propagate click TXT_WidgetMousePress(widget, x, y, b); break; } } } } // Determine whether the table is selectable. static int TXT_TableSelectable(TXT_UNCAST_ARG(table)) { TXT_CAST_ARG(txt_table_t, table); int i; // Is the currently-selected cell selectable? if (SelectableCell(table, table->selected_x, table->selected_y)) { return 1; } // Find the first selectable cell and set selected_x, selected_y. for (i = 0; i < table->num_widgets; ++i) { if (table->widgets[i] != NULL && TXT_SelectableWidget(table->widgets[i])) { ChangeSelection(table, i % table->columns, i / table->columns); return 1; } } // No selectable widgets exist within the table. return 0; } // Need to pass through focus changes to the selected child widget. static void TXT_TableFocused(TXT_UNCAST_ARG(table), int focused) { TXT_CAST_ARG(txt_table_t, table); int i; i = table->selected_y * table->columns + table->selected_x; if (i < table->num_widgets) { if (table->widgets[i] != NULL) { TXT_SetWidgetFocus(table->widgets[i], focused); } } } txt_widget_class_t txt_table_class = { TXT_TableSelectable, TXT_CalcTableSize, TXT_TableDrawer, TXT_TableKeyPress, TXT_TableDestructor, TXT_TableMousePress, TXT_TableLayout, TXT_TableFocused, }; void TXT_InitTable(txt_table_t *table, int columns) { int i; TXT_InitWidget(table, &txt_table_class); table->columns = columns; table->widgets = NULL; table->num_widgets = 0; table->selected_x = 0; table->selected_y = 0; // Add a strut for each column at the start of the table. // These are used by the TXT_SetColumnWidths function below: // the struts are created with widths of 0 each, but this // function changes them. for (i=0; iselected_y * table->columns + table->selected_x; result = NULL; if (index >= 0 && index < table->num_widgets) { result = table->widgets[index]; } if (result != NULL && result->widget_class == &txt_table_class) { result = TXT_GetSelectedWidget(result); } return result; } // Selects a given widget in a table, recursively searching any tables // within this table. Returns 1 if successful, 0 if unsuccessful. int TXT_SelectWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_table_t, table); TXT_CAST_ARG(txt_widget_t, widget); int i; for (i=0; inum_widgets; ++i) { if (table->widgets[i] == NULL) { continue; } if (table->widgets[i] == widget) { // Found the item! Select it and return. ChangeSelection(table, i % table->columns, i / table->columns); return 1; } if (table->widgets[i]->widget_class == &txt_table_class) { // This item is a subtable. Recursively search this table. if (TXT_SelectWidget(table->widgets[i], widget)) { // Found it in the subtable. Select this subtable and return. ChangeSelection(table, i % table->columns, i / table->columns); return 1; } } } // Not found. return 0; } // Sets the widths of columns in a table. void TXT_SetColumnWidths(TXT_UNCAST_ARG(table), ...) { TXT_CAST_ARG(txt_table_t, table); va_list args; txt_strut_t *strut; int i; int width; va_start(args, TXT_UNCAST_ARG_NAME(table)); for (i=0; icolumns; ++i) { width = va_arg(args, int); strut = (txt_strut_t *) table->widgets[i]; strut->width = width; } va_end(args); } // Moves the select by at least the given number of characters. // Currently quietly ignores pagex, as we don't use it. int TXT_PageTable(TXT_UNCAST_ARG(table), int pagex, int pagey) { TXT_CAST_ARG(txt_table_t, table); unsigned int *column_widths; unsigned int *row_heights; int rows; int changed = 0; rows = TableRows(table); row_heights = malloc(sizeof(int) * rows); column_widths = malloc(sizeof(int) * table->columns); CalcRowColSizes(table, row_heights, column_widths); if (pagex) { // @todo Jump selection to the left or right as needed } if (pagey) { int new_x, new_y; int distance = 0; int dir; // What direction are we moving? if (pagey > 0) { dir = 1; } else { dir = -1; } // Move the cursor until the desired distance is reached. new_y = table->selected_y; while (new_y >= 0 && new_y < rows) { // We are about to travel a distance equal to the height of the row // we are about to leave. distance += row_heights[new_y]; // *Now* increment the loop. new_y += dir; new_x = FindSelectableColumn(table, new_y, table->selected_x); if (new_x >= 0) { // Found a selectable widget in this column! // Select it anyway in case we don't find something better. ChangeSelection(table, new_x, new_y); changed = 1; // ...but is it far enough away? if (distance >= abs(pagey)) { break; } } } } free(row_heights); free(column_widths); return changed; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_table.h000066400000000000000000000122241257432200600236310ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_TABLE_H #define TXT_TABLE_H /** * @file txt_table.h * * Table widget. */ /** * Table widget. * * A table is a widget that contains other widgets. It may have * multiple columns, in which case the child widgets are laid out * in a grid. Columns automatically grow as necessary, although * minimum column widths can be set using @ref TXT_SetColumnWidths. * * To create a new table, use @ref TXT_NewTable. It is also * possible to use @ref TXT_NewHorizBox to create a table, specifying * widgets to place inside a horizontal list. A vertical list is * possible simply by creating a table containing a single column. */ typedef struct txt_table_s txt_table_t; #include "txt_widget.h" struct txt_table_s { txt_widget_t widget; // Widgets in this table // The widget at (x,y) in the table is widgets[columns * y + x] txt_widget_t **widgets; int num_widgets; // Number of columns int columns; // Currently selected int selected_x; int selected_y; }; extern txt_widget_class_t txt_table_class; void TXT_InitTable(txt_table_t *table, int columns); /** * Create a new table. * * @param columns The number of columns in the new table. * @return Pointer to the new table structure. */ txt_table_t *TXT_NewTable(int columns); /** * Create a table containing the specified widgets packed horizontally, * from left to right. * * The arguments to this function are variable. Each argument must * be a pointer to a widget, and the list is terminated with a * NULL. * * @return Pointer to the new table structure. */ txt_table_t *TXT_NewHorizBox(TXT_UNCAST_ARG(first_widget), ...); /** * Get the currently selected widget within a table. * * This function will recurse through subtables if necessary. * * @param table The table. * @return Pointer to the widget that is currently selected. */ txt_widget_t *TXT_GetSelectedWidget(TXT_UNCAST_ARG(table)); /** * Add a widget to a table. * * Widgets are added to tables horizontally, from left to right. * For example, for a table with three columns, the first call * to this function will add a widget to the first column, the second * call to the second column, the third call to the third column, * and the fourth will return to the first column, starting a new * row. * * For adding many widgets, it may be easier to use * @ref TXT_AddWidgets. * * @param table The table. * @param widget The widget to add. */ void TXT_AddWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget)); /** * Add multiple widgets to a table. * * Widgets are added as described in the documentation for the * @ref TXT_AddWidget function. This function adds multiple * widgets. The number of arguments is variable, and the argument * list must be terminated by a NULL pointer. * * @param table The table. */ void TXT_AddWidgets(TXT_UNCAST_ARG(table), ...); /** * Select the given widget that is contained within the specified * table. * * This function will recursively search through subtables if * necessary. * * @param table The table. * @param widget The widget to select. * @return Non-zero (true) if it has been selected, * or zero (false) if it was not found within * this table. */ int TXT_SelectWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget)); /** * Set the widths of the columns of the table. * * The arguments to this function are variable, and correspond * to the number of columns in the table. For example, if a table * has five columns, the width of each of the five columns must be * specified. * * The width values are in number of characters. * * Note that this function only sets the minimum widths for columns; * if the columns contain widgets that are wider than the widths * specified, they will be larger. * * @param table The table. */ void TXT_SetColumnWidths(TXT_UNCAST_ARG(table), ...); /** * Remove all widgets from a table. * * @param table The table. */ void TXT_ClearTable(TXT_UNCAST_ARG(table)); /** * Hack to move the selection in a table by a 'page', triggered by the * scrollpane. This acts as per the keyboard events for the arrows, but moves * the selection by at least the specified number of characters. * * @param table The table. * @param pagex Minimum distance to move the selection horizontally. * @param pagey Minimum distance to move the selection vertically. * @return Non-zero if the selection has been changed. */ int TXT_PageTable(TXT_UNCAST_ARG(table), int pagex, int pagey); #endif /* #ifndef TXT_TABLE_T */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_utf8.c000066400000000000000000000066041257432200600234300ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "txt_utf8.h" // Encode a Unicode character as UTF-8, storing it in the buffer 'p' // and returning the new, incremented position. char *TXT_EncodeUTF8(char *p, unsigned int c) { if (c < 0x80) // 1 character (ASCII): { p[0] = c; return p + 1; } else if (c < 0x800) // 2 character: { p[0] = 0xc0 | (c >> 6); p[1] = 0x80 | (c & 0x3f); return p + 2; } else if (c < 0x10000) // 3 chacater: { p[0] = 0xe0 | (c >> 12); p[1] = 0x80 | ((c >> 6) & 0x3f); p[2] = 0x80 | (c & 0x3f); return p + 3; } else if (c < 0x200000) // 4 character: { p[0] = 0xf0 | (c >> 18); p[1] = 0x80 | ((c >> 12) & 0x3f); p[2] = 0x80 | ((c >> 6) & 0x3f); p[3] = 0x80 | (c & 0x3f); return p + 4; } else { // Too big! return p; } } // Decode UTF-8 character, incrementing *ptr over the decoded bytes. unsigned int TXT_DecodeUTF8(const char **ptr) { const char *p = *ptr; unsigned int c; // UTF-8 decode. if ((*p & 0x80) == 0) // 1 character (ASCII): { c = *p; *ptr += 1; } else if ((p[0] & 0xe0) == 0xc0 // 2 character: && (p[1] & 0xc0) == 0x80) { c = ((p[0] & 0x1f) << 6) | (p[1] & 0x3f); *ptr += 2; } else if ((p[0] & 0xf0) == 0xe0 // 3 character: && (p[1] & 0xc0) == 0x80 && (p[2] & 0xc0) == 0x80) { c = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f); *ptr += 3; } else if ((p[0] & 0xf8) == 0xf0 // 4 character: && (p[1] & 0xc0) == 0x80 && (p[2] & 0xc0) == 0x80 && (p[3] & 0xc0) == 0x80) { c = ((p[0] & 0x07) << 18) | ((p[1] & 0x3f) << 12) | ((p[2] & 0x3f) << 6) | (p[3] & 0x3f); *ptr += 4; } else { // Decode failure. // Don't bother with 5/6 byte sequences. c = 0; } return c; } // Count the number of characters in a UTF-8 string. unsigned int TXT_UTF8_Strlen(const char *s) { const char *p; unsigned int result = 0; unsigned int c; for (p = s; *p != '\0';) { c = TXT_DecodeUTF8(&p); if (c == 0) { break; } ++result; } return result; } // Skip past the first n characters in a UTF-8 string. char *TXT_UTF8_SkipChars(const char *s, unsigned int n) { unsigned int i; const char *p; p = s; for (i = 0; i < n; ++i) { if (TXT_DecodeUTF8(&p) == 0) { break; } } return (char *) p; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_utf8.h000066400000000000000000000015101257432200600234240ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_UTF8_H #define TXT_UTF8_H #include char *TXT_EncodeUTF8(char *p, unsigned int c); unsigned int TXT_DecodeUTF8(const char **ptr); unsigned int TXT_UTF8_Strlen(const char *s); char *TXT_UTF8_SkipChars(const char *s, unsigned int n); #endif /* #ifndef TXT_UTF8_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_widget.c000066400000000000000000000156361257432200600240320ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include "txt_io.h" #include "txt_widget.h" #include "txt_gui.h" #include "txt_desktop.h" typedef struct { char *signal_name; TxtWidgetSignalFunc func; void *user_data; } txt_callback_t; struct txt_callback_table_s { int refcount; txt_callback_t *callbacks; int num_callbacks; }; txt_callback_table_t *TXT_NewCallbackTable(void) { txt_callback_table_t *table; table = malloc(sizeof(txt_callback_table_t)); table->callbacks = NULL; table->num_callbacks = 0; table->refcount = 1; return table; } void TXT_RefCallbackTable(txt_callback_table_t *table) { ++table->refcount; } void TXT_UnrefCallbackTable(txt_callback_table_t *table) { int i; --table->refcount; if (table->refcount == 0) { // No more references to this table for (i=0; inum_callbacks; ++i) { free(table->callbacks[i].signal_name); } free(table->callbacks); free(table); } } void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class) { TXT_CAST_ARG(txt_widget_t, widget); widget->widget_class = widget_class; widget->callback_table = TXT_NewCallbackTable(); widget->parent = NULL; // Not focused until we hear otherwise. widget->focused = 0; // Visible by default. widget->visible = 1; // Align left by default widget->align = TXT_HORIZ_LEFT; } void TXT_SignalConnect(TXT_UNCAST_ARG(widget), const char *signal_name, TxtWidgetSignalFunc func, void *user_data) { TXT_CAST_ARG(txt_widget_t, widget); txt_callback_table_t *table; txt_callback_t *callback; table = widget->callback_table; // Add a new callback to the table table->callbacks = realloc(table->callbacks, sizeof(txt_callback_t) * (table->num_callbacks + 1)); callback = &table->callbacks[table->num_callbacks]; ++table->num_callbacks; callback->signal_name = strdup(signal_name); callback->func = func; callback->user_data = user_data; } void TXT_EmitSignal(TXT_UNCAST_ARG(widget), const char *signal_name) { TXT_CAST_ARG(txt_widget_t, widget); txt_callback_table_t *table; int i; table = widget->callback_table; // Don't destroy the table while we're searching through it // (one of the callbacks may destroy this window) TXT_RefCallbackTable(table); // Search the table for all callbacks with this name and invoke // the functions. for (i=0; inum_callbacks; ++i) { if (!strcmp(table->callbacks[i].signal_name, signal_name)) { table->callbacks[i].func(widget, table->callbacks[i].user_data); } } // Finished using the table TXT_UnrefCallbackTable(table); } void TXT_CalcWidgetSize(TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_widget_t, widget); widget->widget_class->size_calc(widget); } void TXT_DrawWidget(TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_widget_t, widget); txt_saved_colors_t colors; // The drawing function might change the fg/bg colors, // so make sure we restore them after it's done. TXT_SaveColors(&colors); // For convenience... TXT_GotoXY(widget->x, widget->y); // Call drawer method widget->widget_class->drawer(widget); TXT_RestoreColors(&colors); } void TXT_DestroyWidget(TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_widget_t, widget); widget->widget_class->destructor(widget); TXT_UnrefCallbackTable(widget->callback_table); free(widget); } int TXT_WidgetKeyPress(TXT_UNCAST_ARG(widget), int key) { TXT_CAST_ARG(txt_widget_t, widget); if (widget->widget_class->key_press != NULL) { return widget->widget_class->key_press(widget, key); } return 0; } void TXT_SetWidgetFocus(TXT_UNCAST_ARG(widget), int focused) { TXT_CAST_ARG(txt_widget_t, widget); if (widget == NULL) { return; } if (widget->focused != focused) { widget->focused = focused; if (widget->widget_class->focus_change != NULL) { widget->widget_class->focus_change(widget, focused); } } } void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align) { TXT_CAST_ARG(txt_widget_t, widget); widget->align = horiz_align; } void TXT_WidgetMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) { TXT_CAST_ARG(txt_widget_t, widget); if (widget->widget_class->mouse_press != NULL) { widget->widget_class->mouse_press(widget, x, y, b); } } void TXT_LayoutWidget(TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_widget_t, widget); if (widget->widget_class->layout != NULL) { widget->widget_class->layout(widget); } } int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget)) { return 1; } int TXT_NeverSelectable(TXT_UNCAST_ARG(widget)) { return 0; } int TXT_SelectableWidget(TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_widget_t, widget); if (widget->widget_class->selectable != NULL) { return widget->widget_class->selectable(widget); } else { return 0; } } int TXT_ContainsWidget(TXT_UNCAST_ARG(haystack), TXT_UNCAST_ARG(needle)) { TXT_CAST_ARG(txt_widget_t, haystack); TXT_CAST_ARG(txt_widget_t, needle); while (needle != NULL) { if (needle == haystack) { return 1; } needle = needle->parent; } return 0; } int TXT_HoveringOverWidget(TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_widget_t, widget); txt_window_t *active_window; int x, y; // We can only be hovering over widgets in the active window. active_window = TXT_GetActiveWindow(); if (active_window == NULL || !TXT_ContainsWidget(active_window, widget)) { return 0; } // Is the mouse cursor within the bounds of the widget? TXT_GetMousePosition(&x, &y); return (x >= widget->x && x < widget->x + widget->w && y >= widget->y && y < widget->y + widget->h); } void TXT_SetWidgetBG(TXT_UNCAST_ARG(widget)) { TXT_CAST_ARG(txt_widget_t, widget); if (widget->focused) { TXT_BGColor(TXT_COLOR_GREY, 0); } else if (TXT_HoveringOverWidget(widget)) { TXT_BGColor(TXT_HOVER_BACKGROUND, 0); } else { // Use normal window background. } } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_widget.h000066400000000000000000000122221257432200600240230ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_WIDGET_H #define TXT_WIDGET_H /** * @file txt_widget.h * * Base "widget" GUI component class. */ #ifndef DOXYGEN #define TXT_UNCAST_ARG_NAME(name) uncast_ ## name #define TXT_UNCAST_ARG(name) void * TXT_UNCAST_ARG_NAME(name) #define TXT_CAST_ARG(type, name) type *name = (type *) uncast_ ## name #else #define TXT_UNCAST_ARG(name) txt_widget_t *name #endif typedef enum { TXT_VERT_TOP, TXT_VERT_CENTER, TXT_VERT_BOTTOM, } txt_vert_align_t; typedef enum { TXT_HORIZ_LEFT, TXT_HORIZ_CENTER, TXT_HORIZ_RIGHT, } txt_horiz_align_t; /** * A GUI widget. * * A widget is an individual component of a GUI. Various different widget * types exist. * * Widgets may emit signals. The types of signal emitted by a widget * depend on the type of the widget. It is possible to be notified * when a signal occurs using the @ref TXT_SignalConnect function. */ typedef struct txt_widget_s txt_widget_t; typedef struct txt_widget_class_s txt_widget_class_t; typedef struct txt_callback_table_s txt_callback_table_t; typedef void (*TxtWidgetSizeCalc)(TXT_UNCAST_ARG(widget)); typedef void (*TxtWidgetDrawer)(TXT_UNCAST_ARG(widget)); typedef void (*TxtWidgetDestroy)(TXT_UNCAST_ARG(widget)); typedef int (*TxtWidgetKeyPress)(TXT_UNCAST_ARG(widget), int key); typedef void (*TxtWidgetSignalFunc)(TXT_UNCAST_ARG(widget), void *user_data); typedef void (*TxtMousePressFunc)(TXT_UNCAST_ARG(widget), int x, int y, int b); typedef void (*TxtWidgetLayoutFunc)(TXT_UNCAST_ARG(widget)); typedef int (*TxtWidgetSelectableFunc)(TXT_UNCAST_ARG(widget)); typedef void (*TxtWidgetFocusFunc)(TXT_UNCAST_ARG(widget), int focused); struct txt_widget_class_s { TxtWidgetSelectableFunc selectable; TxtWidgetSizeCalc size_calc; TxtWidgetDrawer drawer; TxtWidgetKeyPress key_press; TxtWidgetDestroy destructor; TxtMousePressFunc mouse_press; TxtWidgetLayoutFunc layout; TxtWidgetFocusFunc focus_change; }; struct txt_widget_s { txt_widget_class_t *widget_class; txt_callback_table_t *callback_table; int visible; txt_horiz_align_t align; int focused; // These are set automatically when the window is drawn and should // not be set manually. int x, y; unsigned int w, h; // Pointer up to parent widget that contains this widget. txt_widget_t *parent; }; void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class); void TXT_CalcWidgetSize(TXT_UNCAST_ARG(widget)); void TXT_DrawWidget(TXT_UNCAST_ARG(widget)); void TXT_EmitSignal(TXT_UNCAST_ARG(widget), const char *signal_name); int TXT_WidgetKeyPress(TXT_UNCAST_ARG(widget), int key); void TXT_WidgetMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b); void TXT_DestroyWidget(TXT_UNCAST_ARG(widget)); void TXT_LayoutWidget(TXT_UNCAST_ARG(widget)); int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget)); int TXT_NeverSelectable(TXT_UNCAST_ARG(widget)); void TXT_SetWidgetFocus(TXT_UNCAST_ARG(widget), int focused); /** * Set a callback function to be invoked when a signal occurs. * * @param widget The widget to watch. * @param signal_name The signal to watch. * @param func The callback function to invoke. * @param user_data User-specified pointer to pass to the callback function. */ void TXT_SignalConnect(TXT_UNCAST_ARG(widget), const char *signal_name, TxtWidgetSignalFunc func, void *user_data); /** * Set the policy for how a widget should be aligned within a table. * By default, widgets are aligned to the left of the column. * * @param widget The widget. * @param horiz_align The alignment to use. */ void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align); /** * Query whether a widget is selectable with the cursor. * * @param widget The widget. * @return Non-zero if the widget is selectable. */ int TXT_SelectableWidget(TXT_UNCAST_ARG(widget)); /** * Query whether the mouse is hovering over the specified widget. * * @param widget The widget. * @return Non-zero if the mouse cursor is over the widget. */ int TXT_HoveringOverWidget(TXT_UNCAST_ARG(widget)); /** * Set the background to draw the specified widget, depending on * whether it is selected and the mouse is hovering over it. * * @param widget The widget. */ void TXT_SetWidgetBG(TXT_UNCAST_ARG(widget)); /** * Query whether the specified widget is contained within another * widget. * * @param haystack The widget that might contain needle. * @param needle The widget being queried. */ int TXT_ContainsWidget(TXT_UNCAST_ARG(haystack), TXT_UNCAST_ARG(needle)); #endif /* #ifndef TXT_WIDGET_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_window.c000066400000000000000000000324101257432200600240430ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include #include "doomkeys.h" #include "txt_label.h" #include "txt_desktop.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_separator.h" #include "txt_window.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #endif void TXT_SetWindowAction(txt_window_t *window, txt_horiz_align_t position, txt_window_action_t *action) { if (window->actions[position] != NULL) { TXT_DestroyWidget(window->actions[position]); } window->actions[position] = action; // Maintain parent pointer. if (action != NULL) { action->widget.parent = &window->table.widget; } } txt_window_t *TXT_NewWindow(char *title) { int i; txt_window_t *win; win = malloc(sizeof(txt_window_t)); TXT_InitTable(&win->table, 1); if (title == NULL) { win->title = NULL; } else { win->title = strdup(title); } win->x = TXT_SCREEN_W / 2; win->y = TXT_SCREEN_H / 2; win->horiz_align = TXT_HORIZ_CENTER; win->vert_align = TXT_VERT_CENTER; win->key_listener = NULL; win->mouse_listener = NULL; win->help_url = NULL; TXT_AddWidget(win, TXT_NewSeparator(NULL)); for (i=0; i<3; ++i) win->actions[i] = NULL; TXT_AddDesktopWindow(win); // Default actions TXT_SetWindowAction(win, TXT_HORIZ_LEFT, TXT_NewWindowEscapeAction(win)); TXT_SetWindowAction(win, TXT_HORIZ_RIGHT, TXT_NewWindowSelectAction(win)); return win; } void TXT_CloseWindow(txt_window_t *window) { int i; TXT_EmitSignal(window, "closed"); TXT_RemoveDesktopWindow(window); free(window->title); // Destroy all actions for (i=0; i<3; ++i) { if (window->actions[i] != NULL) { TXT_DestroyWidget(window->actions[i]); } } // Destroy table and window TXT_DestroyWidget(window); } static void CalcWindowPosition(txt_window_t *window) { switch (window->horiz_align) { case TXT_HORIZ_LEFT: window->window_x = window->x; break; case TXT_HORIZ_CENTER: window->window_x = window->x - (window->window_w / 2); break; case TXT_HORIZ_RIGHT: window->window_x = window->x - (window->window_w - 1); break; } switch (window->vert_align) { case TXT_VERT_TOP: window->window_y = window->y; break; case TXT_VERT_CENTER: window->window_y = window->y - (window->window_h / 2); break; case TXT_VERT_BOTTOM: window->window_y = window->y - (window->window_h - 1); break; } } static void LayoutActionArea(txt_window_t *window) { txt_widget_t *widget; int space_available; int space_left_offset; // We need to calculate the available horizontal space for the center // action widget, so that we can center it within it. // To start with, we have the entire action area available. space_available = window->window_w; space_left_offset = 0; // Left action if (window->actions[TXT_HORIZ_LEFT] != NULL) { widget = (txt_widget_t *) window->actions[TXT_HORIZ_LEFT]; TXT_CalcWidgetSize(widget); widget->x = window->window_x + 1; widget->y = window->window_y + window->window_h - widget->h - 1; // Adjust available space: space_available -= widget->w; space_left_offset += widget->w; } // Draw the right action if (window->actions[TXT_HORIZ_RIGHT] != NULL) { widget = (txt_widget_t *) window->actions[TXT_HORIZ_RIGHT]; TXT_CalcWidgetSize(widget); widget->x = window->window_x + window->window_w - 1 - widget->w; widget->y = window->window_y + window->window_h - widget->h - 1; // Adjust available space: space_available -= widget->w; } // Draw the center action if (window->actions[TXT_HORIZ_CENTER] != NULL) { widget = (txt_widget_t *) window->actions[TXT_HORIZ_CENTER]; TXT_CalcWidgetSize(widget); // The left and right widgets have left a space sandwiched between // them. Center this widget within that space. widget->x = window->window_x + space_left_offset + (space_available - widget->w) / 2; widget->y = window->window_y + window->window_h - widget->h - 1; } } static void DrawActionArea(txt_window_t *window) { int i; for (i=0; i<3; ++i) { if (window->actions[i] != NULL) { TXT_DrawWidget(window->actions[i]); } } } static void CalcActionAreaSize(txt_window_t *window, unsigned int *w, unsigned int *h) { txt_widget_t *widget; int i; *w = 0; *h = 0; // Calculate the width of all the action widgets and use this // to create an overall min. width of the action area for (i=0; i<3; ++i) { widget = (txt_widget_t *) window->actions[i]; if (widget != NULL) { TXT_CalcWidgetSize(widget); *w += widget->w; if (widget->h > *h) { *h = widget->h; } } } } // Sets size and position of all widgets in a window void TXT_LayoutWindow(txt_window_t *window) { txt_widget_t *widgets = (txt_widget_t *) window; unsigned int widgets_w; unsigned int actionarea_w, actionarea_h; // Calculate size of table TXT_CalcWidgetSize(window); // Widgets area: add one character of padding on each side widgets_w = widgets->w + 2; // Calculate the size of the action area // Make window wide enough to action area CalcActionAreaSize(window, &actionarea_w, &actionarea_h); if (actionarea_w > widgets_w) widgets_w = actionarea_w; // Set the window size based on widgets_w window->window_w = widgets_w + 2; window->window_h = widgets->h + 1; // If the window has a title, add an extra two lines if (window->title != NULL) { window->window_h += 2; } // If the window has an action area, add extra lines if (actionarea_h > 0) { window->window_h += actionarea_h + 1; } // Use the x,y position as the centerpoint and find the location to // draw the window. CalcWindowPosition(window); // Set the table size and position widgets->w = widgets_w - 2; // widgets->h (already set) widgets->x = window->window_x + 2; widgets->y = window->window_y; if (window->title != NULL) { widgets->y += 2; } // Layout the table and action area LayoutActionArea(window); TXT_LayoutWidget(widgets); } void TXT_DrawWindow(txt_window_t *window) { txt_widget_t *widgets; TXT_LayoutWindow(window); if (window->table.widget.focused) { TXT_BGColor(TXT_ACTIVE_WINDOW_BACKGROUND, 0); } else { TXT_BGColor(TXT_INACTIVE_WINDOW_BACKGROUND, 0); } TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); // Draw the window TXT_DrawWindowFrame(window->title, window->window_x, window->window_y, window->window_w, window->window_h); // Draw all widgets TXT_DrawWidget(window); // Draw an action area, if we have one widgets = (txt_widget_t *) window; if (widgets->y + widgets->h < window->window_y + window->window_h - 1) { // Separator for action area TXT_DrawSeparator(window->window_x, widgets->y + widgets->h, window->window_w); // Action area at the window bottom DrawActionArea(window); } } void TXT_SetWindowPosition(txt_window_t *window, txt_horiz_align_t horiz_align, txt_vert_align_t vert_align, int x, int y) { window->vert_align = vert_align; window->horiz_align = horiz_align; window->x = x; window->y = y; } static int MouseButtonPress(txt_window_t *window, int b) { int x, y; int i; txt_widget_t *widgets; txt_widget_t *widget; // Lay out the window, set positions and sizes of all widgets TXT_LayoutWindow(window); // Get the current mouse position TXT_GetMousePosition(&x, &y); // Try the mouse button listener // This happens whether it is in the window range or not if (window->mouse_listener != NULL) { // Mouse listener can eat button presses if (window->mouse_listener(window, x, y, b, window->mouse_listener_data)) { return 1; } } // Is it within the table range? widgets = (txt_widget_t *) window; if (x >= widgets->x && x < (signed) (widgets->x + widgets->w) && y >= widgets->y && y < (signed) (widgets->y + widgets->h)) { TXT_WidgetMousePress(window, x, y, b); return 1; } // Was one of the action area buttons pressed? for (i=0; i<3; ++i) { widget = (txt_widget_t *) window->actions[i]; if (widget != NULL && x >= widget->x && x < (signed) (widget->x + widget->w) && y >= widget->y && y < (signed) (widget->y + widget->h)) { int was_focused; // Main table temporarily loses focus when action area button // is clicked. This way, any active input boxes that depend // on having focus will save their values before the // action is performed. was_focused = window->table.widget.focused; TXT_SetWidgetFocus(window, 0); TXT_SetWidgetFocus(window, was_focused); // Pass through mouse press. TXT_WidgetMousePress(widget, x, y, b); return 1; } } return 0; } int TXT_WindowKeyPress(txt_window_t *window, int c) { int i; // Is this a mouse button ? if (c >= TXT_MOUSE_BASE && c < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS) { return MouseButtonPress(window, c); } // Try the window key spy if (window->key_listener != NULL) { // key listener can eat keys if (window->key_listener(window, c, window->key_listener_data)) { return 1; } } // Send to the currently selected widget: if (TXT_WidgetKeyPress(window, c)) { return 1; } // Try all of the action buttons for (i=0; i<3; ++i) { if (window->actions[i] != NULL && TXT_WidgetKeyPress(window->actions[i], c)) { return 1; } } return 0; } void TXT_SetKeyListener(txt_window_t *window, TxtWindowKeyPress key_listener, void *user_data) { window->key_listener = key_listener; window->key_listener_data = user_data; } void TXT_SetMouseListener(txt_window_t *window, TxtWindowMousePress mouse_listener, void *user_data) { window->mouse_listener = mouse_listener; window->mouse_listener_data = user_data; } void TXT_SetWindowFocus(txt_window_t *window, int focused) { TXT_SetWidgetFocus(window, focused); } void TXT_SetWindowHelpURL(txt_window_t *window, char *help_url) { window->help_url = help_url; } #ifdef _WIN32 void TXT_OpenURL(char *url) { ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); } #else void TXT_OpenURL(char *url) { char *cmd; size_t cmd_len; cmd_len = strlen(url) + 30; cmd = malloc(cmd_len); #if defined(__MACOSX__) TXT_snprintf(cmd, cmd_len, "open \"%s\"", url); #else // The Unix situation sucks as usual, but the closest thing to a // standard that exists is the xdg-utils package. if (system("xdg-open --version 2>/dev/null") != 0) { fprintf(stderr, "xdg-utils is not installed. Can't open this URL:\n%s\n", url); return; } TXT_snprintf(cmd, cmd_len, "xdg-open \"%s\"", url); #endif system(cmd); free(cmd); } #endif /* #ifndef _WIN32 */ void TXT_OpenWindowHelpURL(txt_window_t *window) { if (window->help_url != NULL) { TXT_OpenURL(window->help_url); } } txt_window_t *TXT_MessageBox(char *title, char *message, ...) { txt_window_t *window; char buf[256]; va_list args; va_start(args, message); TXT_vsnprintf(buf, sizeof(buf), message, args); va_end(args); window = TXT_NewWindow(title); TXT_AddWidget(window, TXT_NewLabel(buf)); TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TXT_NewWindowEscapeAction(window)); TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); return window; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_window.h000066400000000000000000000147441257432200600240620ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_WINDOW_H #define TXT_WINDOW_H /** * @file txt_window.h * * Windows. */ /** * A window. * * A window contains widgets, and may also be treated as a table * (@ref txt_table_t) containing a single column. * * Windows can be created using @ref TXT_NewWindow and closed using * @ref TXT_CloseWindow. When a window is closed, it emits the * "closed" signal. * * In addition to the widgets within a window, windows also have * a "tray" area at their bottom containing window action widgets. * These widgets allow keyboard shortcuts to trigger common actions. * Each window has three slots for keyboard shortcuts. By default, * the left slot contains an action to close the window when the * escape button is pressed, while the right slot contains an * action to activate the currently-selected widget. */ typedef struct txt_window_s txt_window_t; #include "txt_widget.h" #include "txt_table.h" #include "txt_window_action.h" // Callback function for window key presses typedef int (*TxtWindowKeyPress)(txt_window_t *window, int key, void *user_data); typedef int (*TxtWindowMousePress)(txt_window_t *window, int x, int y, int b, void *user_data); struct txt_window_s { // Base class: all windows are tables with one column. txt_table_t table; // Window title char *title; // Screen coordinates of the window txt_vert_align_t vert_align; txt_horiz_align_t horiz_align; int x, y; // Actions that appear in the box at the bottom of the window txt_window_action_t *actions[3]; // Callback functions to invoke when keys/mouse buttons are pressed TxtWindowKeyPress key_listener; void *key_listener_data; TxtWindowMousePress mouse_listener; void *mouse_listener_data; // These are set automatically when the window is drawn int window_x, window_y; unsigned int window_w, window_h; // URL of a webpage with help about this window. If set, a help key // indicator is shown while this window is active. char *help_url; }; /** * Open a new window. * * @param title Title to display in the titlebar of the new window. * @return Pointer to a new @ref txt_window_t structure * representing the new window. */ txt_window_t *TXT_NewWindow(char *title); /** * Close a window. * * @param window Tine window to close. */ void TXT_CloseWindow(txt_window_t *window); /** * Set the position of a window on the screen. * * The position is specified as a pair of x, y, coordinates on the * screen. These specify the position of a particular point on the * window. The following are some examples: * * * // Centered on the screen: * * TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_CENTER, * TXT_SCREEN_W / 2, TXT_SCREEN_H / 2); * * // Horizontally centered, with top of the window on line 6: * * TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP, * TXT_SCREEN_W / 2, 6); * * // Top-left of window at 20, 6: * * TXT_SetWindowPosition(window, TXT_HORIZ_LEFT, TXT_VERT_TOP, 20, 6); * * * @param window The window. * @param horiz_align Horizontal location on the window for the X * position. * @param vert_align Vertical location on the window for the Y position. * @param x X coordinate (horizontal axis) for window position. * @param y Y coordinate (vertical axis) for window position. */ void TXT_SetWindowPosition(txt_window_t *window, txt_horiz_align_t horiz_align, txt_vert_align_t vert_align, int x, int y); /** * Set a window action for a given window. * * Each window can have up to three window actions, which provide * keyboard shortcuts that can be used within a given window. * * @param window The window. * @param position The window action slot to set (left, center or right). * @param action The window action widget. If this is NULL, any * current window action in the given slot is removed. */ void TXT_SetWindowAction(txt_window_t *window, txt_horiz_align_t position, txt_window_action_t *action); /** * Set a callback function to be invoked whenever a key is pressed within * a window. * * @param window The window. * @param key_listener Callback function. * @param user_data User-specified pointer to pass to the callback * function. */ void TXT_SetKeyListener(txt_window_t *window, TxtWindowKeyPress key_listener, void *user_data); /** * Set a callback function to be invoked whenever a mouse button is pressed * within a window. * * @param window The window. * @param mouse_listener Callback function. * @param user_data User-specified pointer to pass to the callback * function. */ void TXT_SetMouseListener(txt_window_t *window, TxtWindowMousePress mouse_listener, void *user_data); /** * Open a window displaying a message. * * @param title Title of the window. * @param message The message to display in the window. * @return The new window. */ txt_window_t *TXT_MessageBox(char *title, char *message, ...); /** * Set the help URL for the given window. * * @param window The window. * @param help_url String containing URL of the help page for this * window, or NULL to set no help for this window. */ void TXT_SetWindowHelpURL(txt_window_t *window, char *help_url); /** * Open the help URL for the given window, if one is set. * * @param window The window. */ void TXT_OpenWindowHelpURL(txt_window_t *window); #endif /* #ifndef TXT_WINDOW_H */ chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_window_action.c000066400000000000000000000100421257432200600253750ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #include #include #include #include "doomkeys.h" #include "txt_window_action.h" #include "txt_gui.h" #include "txt_io.h" #include "txt_main.h" #include "txt_window.h" static void TXT_WindowActionSizeCalc(TXT_UNCAST_ARG(action)) { TXT_CAST_ARG(txt_window_action_t, action); char buf[10]; TXT_GetKeyDescription(action->key, buf, sizeof(buf)); // Width is label length, plus key description length, plus '=' // and two surrounding spaces. action->widget.w = strlen(action->label) + strlen(buf) + 3; action->widget.h = 1; } static void TXT_WindowActionDrawer(TXT_UNCAST_ARG(action)) { TXT_CAST_ARG(txt_window_action_t, action); char buf[10]; TXT_GetKeyDescription(action->key, buf, sizeof(buf)); if (TXT_HoveringOverWidget(action)) { TXT_BGColor(TXT_COLOR_BLACK, 0); } TXT_DrawString(" "); TXT_FGColor(TXT_COLOR_BRIGHT_GREEN); TXT_DrawString(buf); TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); TXT_DrawString("="); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); TXT_DrawString(action->label); TXT_DrawString(" "); } static void TXT_WindowActionDestructor(TXT_UNCAST_ARG(action)) { TXT_CAST_ARG(txt_window_action_t, action); free(action->label); } static int TXT_WindowActionKeyPress(TXT_UNCAST_ARG(action), int key) { TXT_CAST_ARG(txt_window_action_t, action); if (tolower(key) == tolower(action->key)) { TXT_EmitSignal(action, "pressed"); return 1; } return 0; } static void TXT_WindowActionMousePress(TXT_UNCAST_ARG(action), int x, int y, int b) { TXT_CAST_ARG(txt_window_action_t, action); // Simulate a press of the key if (b == TXT_MOUSE_LEFT) { TXT_WindowActionKeyPress(action, action->key); } } txt_widget_class_t txt_window_action_class = { TXT_AlwaysSelectable, TXT_WindowActionSizeCalc, TXT_WindowActionDrawer, TXT_WindowActionKeyPress, TXT_WindowActionDestructor, TXT_WindowActionMousePress, NULL, }; txt_window_action_t *TXT_NewWindowAction(int key, const char *label) { txt_window_action_t *action; action = malloc(sizeof(txt_window_action_t)); TXT_InitWidget(action, &txt_window_action_class); action->key = key; action->label = strdup(label); return action; } static void WindowCloseCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(window)) { TXT_CAST_ARG(txt_window_t, window); TXT_CloseWindow(window); } static void WindowSelectCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(window)) { TXT_CAST_ARG(txt_window_t, window); TXT_WidgetKeyPress(window, KEY_ENTER); } // An action with the name "close" the closes the window txt_window_action_t *TXT_NewWindowEscapeAction(txt_window_t *window) { txt_window_action_t *action; action = TXT_NewWindowAction(KEY_ESCAPE, "Close"); TXT_SignalConnect(action, "pressed", WindowCloseCallback, window); return action; } // Exactly the same as the above, but the button is named "abort" txt_window_action_t *TXT_NewWindowAbortAction(txt_window_t *window) { txt_window_action_t *action; action = TXT_NewWindowAction(KEY_ESCAPE, "Abort"); TXT_SignalConnect(action, "pressed", WindowCloseCallback, window); return action; } txt_window_action_t *TXT_NewWindowSelectAction(txt_window_t *window) { txt_window_action_t *action; action = TXT_NewWindowAction(KEY_ENTER, "Select"); TXT_SignalConnect(action, "pressed", WindowSelectCallback, window); return action; } chocolate-doom-chocolate-doom-2.2.1/textscreen/txt_window_action.h000066400000000000000000000047511257432200600254140ustar00rootroot00000000000000// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // #ifndef TXT_WINDOW_ACTION_H #define TXT_WINDOW_ACTION_H /** * @file txt_window_action.h * * Window action widget. */ /** * Window action widget. * * A window action is attached to a window and corresponds to a * keyboard shortcut that is active within that window. When the * key is pressed, the action is triggered. * * When a window action is triggered, the "pressed" signal is emitted. */ typedef struct txt_window_action_s txt_window_action_t; #include "txt_widget.h" #include "txt_window.h" struct txt_window_action_s { txt_widget_t widget; char *label; int key; }; /** * Create a new window action. * * @param key The keyboard key that triggers this action. * @param label Label to display for this action in the tray * at the bottom of the window. * @return Pointer to the new window action widget. */ txt_window_action_t *TXT_NewWindowAction(int key, const char *label); /** * Create a new window action that closes the window when the * escape key is pressed. The label "Close" is used. * * @param window The window to close. * @return Pointer to the new window action widget. */ txt_window_action_t *TXT_NewWindowEscapeAction(txt_window_t *window); /** * Create a new window action that closes the window when the * escape key is pressed. The label "Abort" is used. * * @param window The window to close. * @return Pointer to the new window action widget. */ txt_window_action_t *TXT_NewWindowAbortAction(txt_window_t *window); /** * Create a new "select" window action. This does not really do * anything, but reminds the user that "enter" can be pressed to * activate the currently-selected widget. * * @param window The window. * @return Pointer to the new window action widget. */ txt_window_action_t *TXT_NewWindowSelectAction(txt_window_t *window); #endif /* #ifndef TXT_WINDOW_ACTION_H */